CodeSigner.cpp
1 /* 2 * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 // 25 // CodeSigner - SecCodeSigner API objects 26 // 27 #include "CodeSigner.h" 28 #include "signer.h" 29 #include "csdatabase.h" 30 #include "drmaker.h" 31 #include "csutilities.h" 32 #include <security_utilities/unix++.h> 33 #include <security_utilities/unixchild.h> 34 #include <Security/SecCertificate.h> 35 #include <Security/SecCertificatePriv.h> 36 #include <vector> 37 #include <errno.h> 38 39 namespace Security { 40 41 __SEC_CFTYPE(SecIdentity) 42 43 namespace CodeSigning { 44 45 using namespace UnixPlusPlus; 46 47 48 // 49 // A helper for parsing out a CFDictionary signing-data specification 50 // 51 class SecCodeSigner::Parser : CFDictionary { 52 public: 53 Parser(SecCodeSigner &signer, CFDictionaryRef parameters); 54 55 bool getBool(CFStringRef key) const 56 { 57 if (CFBooleanRef flag = get<CFBooleanRef>(key)) 58 return flag == kCFBooleanTrue; 59 else 60 return false; 61 } 62 63 uint32_t parseRuntimeVersion(std::string& runtime) 64 { 65 uint32_t version = 0; 66 char* cursor = const_cast<char*>(runtime.c_str()); 67 char* end = cursor + runtime.length(); 68 char* nxt = NULL; 69 long component = 0; 70 int component_shift = 16; 71 72 // x should convert to 0x00XX0000 73 // x.y should convert to 0x00XXYY00 74 // x.y.z should covert to 0x00XXYYZZ 75 // 0, 0.0, and 0.0.0 are rejected 76 // anything else should be rejected 77 while (cursor < end) { 78 nxt = NULL; 79 errno = 0; 80 component = strtol(cursor, &nxt, 10); 81 if (cursor == nxt || 82 (errno != 0) || 83 (component < 0 || component > UINT8_MAX)) { 84 secdebug("signer", "Runtime version: %s is invalid", runtime.c_str()); 85 MacOSError::throwMe(errSecCSInvalidRuntimeVersion); 86 } 87 version |= (component & 0xff) << component_shift; 88 component_shift -= 8; 89 90 if (*nxt == '\0') { 91 break; 92 } 93 94 if (*nxt != '.' || component_shift < 0 || (nxt + 1) == end) { 95 // Catch a trailing "." 96 secdebug("signer", "Runtime version: %s is invalid", runtime.c_str()); 97 MacOSError::throwMe(errSecCSInvalidRuntimeVersion); 98 } 99 cursor = nxt + 1; 100 } 101 102 if (version == 0) { 103 secdebug("signer","Runtime version: %s is a version of zero", runtime.c_str()); 104 MacOSError::throwMe(errSecCSInvalidRuntimeVersion); 105 } 106 107 return version; 108 } 109 }; 110 111 112 // 113 // Construct a SecCodeSigner 114 // 115 SecCodeSigner::SecCodeSigner(SecCSFlags flags) 116 : mOpFlags(flags), mLimitedAsync(NULL), mRuntimeVersionOverride(0) 117 { 118 } 119 120 121 // 122 // Clean up a SecCodeSigner 123 // 124 SecCodeSigner::~SecCodeSigner() _NOEXCEPT 125 try { 126 delete mLimitedAsync; 127 } catch (...) { 128 return; 129 } 130 131 132 // 133 // Parse an input parameter dictionary and set ready-to-use parameters 134 // 135 void SecCodeSigner::parameters(CFDictionaryRef paramDict) 136 { 137 Parser(*this, paramDict); 138 if (!valid()) 139 MacOSError::throwMe(errSecCSInvalidObjectRef); 140 } 141 142 // 143 // Retrieve the team ID from the signing certificate if and only if 144 // it is an apple developer signing cert 145 // 146 std::string SecCodeSigner::getTeamIDFromSigner(CFArrayRef certs) 147 { 148 if (mSigner && mSigner != SecIdentityRef(kCFNull)) { 149 CFRef<SecCertificateRef> signerCert; 150 MacOSError::check(SecIdentityCopyCertificate(mSigner, &signerCert.aref())); 151 152 /* Make sure the certificate looks like an Apple certificate, because we do not 153 extract the team ID from a non Apple certificate */ 154 if (SecStaticCode::isAppleDeveloperCert(certs)) { 155 CFRef<CFStringRef> teamIDFromCert; 156 157 MacOSError::check(SecCertificateCopySubjectComponent(signerCert.get(), &CSSMOID_OrganizationalUnitName, &teamIDFromCert.aref())); 158 159 if (teamIDFromCert) 160 return cfString(teamIDFromCert); 161 } 162 } 163 164 return ""; 165 } 166 167 // 168 // Roughly check for validity. 169 // This isn't thorough; it just sees if if looks like we've set up the object appropriately. 170 // 171 bool SecCodeSigner::valid() const 172 { 173 if (mOpFlags & (kSecCSRemoveSignature | kSecCSEditSignature)) { 174 return true; 175 } 176 return mSigner; 177 } 178 179 180 // 181 // Sign code 182 // 183 void SecCodeSigner::sign(SecStaticCode *code, SecCSFlags flags) 184 { 185 //Never preserve a linker signature. 186 if (code->isSigned() && 187 (flags & kSecCSSignPreserveSignature) && 188 !code->flag(kSecCodeSignatureLinkerSigned)) { 189 return; 190 } 191 code->setValidationFlags(flags); 192 Signer operation(*this, code); 193 if ((flags | mOpFlags) & kSecCSRemoveSignature) { 194 secinfo("signer", "%p will remove signature from %p", this, code); 195 operation.remove(flags); 196 } else if ((flags | mOpFlags) & kSecCSEditSignature) { 197 secinfo("signer", "%p will edit signature of %p", this, code); 198 operation.edit(flags); 199 } else { 200 if (!valid()) 201 MacOSError::throwMe(errSecCSInvalidObjectRef); 202 secinfo("signer", "%p will sign %p (flags 0x%x)", this, code, flags); 203 operation.sign(flags); 204 } 205 code->resetValidity(); 206 } 207 208 209 // 210 // ReturnDetachedSignature is called by writers or editors that try to return 211 // detached signature data (rather than annotate the target). 212 // 213 void SecCodeSigner::returnDetachedSignature(BlobCore *blob, Signer &signer) 214 { 215 assert(mDetached); 216 if (CFGetTypeID(mDetached) == CFURLGetTypeID()) { 217 // URL to destination file 218 AutoFileDesc fd(cfString(CFURLRef(mDetached.get())), O_WRONLY | O_CREAT | O_TRUNC); 219 fd.writeAll(*blob); 220 } else if (CFGetTypeID(mDetached) == CFDataGetTypeID()) { 221 CFDataAppendBytes(CFMutableDataRef(mDetached.get()), 222 (const UInt8 *)blob, blob->length()); 223 } else if (CFGetTypeID(mDetached) == CFNullGetTypeID()) { 224 SignatureDatabaseWriter db; 225 db.storeCode(blob, signer.path().c_str()); 226 } else 227 assert(false); 228 } 229 230 231 // 232 // The actual parsing operation is done in the Parser class. 233 // 234 // Note that we need to copy or retain all incoming data. The caller has no requirement 235 // to keep the parameters dictionary around. 236 // 237 SecCodeSigner::Parser::Parser(SecCodeSigner &state, CFDictionaryRef parameters) 238 : CFDictionary(parameters, errSecCSBadDictionaryFormat) 239 { 240 CFNumberRef editCpuType = get<CFNumberRef>(kSecCodeSignerEditCpuType); 241 CFNumberRef editCpuSubtype = get<CFNumberRef>(kSecCodeSignerEditCpuSubtype); 242 if (editCpuType != NULL && editCpuSubtype != NULL) { 243 state.mEditArch = Architecture(cfNumber<uint32_t>(editCpuType), 244 cfNumber<uint32_t>(editCpuSubtype)); 245 } 246 247 state.mEditCMS = get<CFDataRef>(kSecCodeSignerEditCMS); 248 249 state.mDryRun = getBool(kSecCodeSignerDryRun); 250 251 state.mSDKRoot = get<CFURLRef>(kSecCodeSignerSDKRoot); 252 253 state.mPreserveAFSC = getBool(kSecCodeSignerPreserveAFSC); 254 255 if (state.mOpFlags & kSecCSEditSignature) { 256 return; 257 /* Everything below this point is irrelevant for 258 * Signature Editing, which does not create any 259 * parts of the signature, only replaces them. 260 */ 261 } 262 263 // the signer may be an identity or null 264 state.mSigner = SecIdentityRef(get<CFTypeRef>(kSecCodeSignerIdentity)); 265 if (state.mSigner) 266 if (CFGetTypeID(state.mSigner) != SecIdentityGetTypeID() && !CFEqual(state.mSigner, kCFNull)) 267 MacOSError::throwMe(errSecCSInvalidObjectRef); 268 269 // the flags need some augmentation 270 if (CFNumberRef flags = get<CFNumberRef>(kSecCodeSignerFlags)) { 271 state.mCdFlagsGiven = true; 272 state.mCdFlags = cfNumber<uint32_t>(flags); 273 } else 274 state.mCdFlagsGiven = false; 275 276 // digest algorithms are specified as a numeric code 277 if (CFCopyRef<CFTypeRef> digestAlgorithms = get<CFTypeRef>(kSecCodeSignerDigestAlgorithm)) { 278 CFRef<CFArrayRef> array = cfArrayize(digestAlgorithms); 279 CFToVector<CodeDirectory::HashAlgorithm, CFNumberRef, cfNumber<CodeDirectory::HashAlgorithm> > digests(array); 280 std::copy(digests.begin(), digests.end(), std::inserter(state.mDigestAlgorithms, state.mDigestAlgorithms.begin())); 281 } 282 283 if (CFNumberRef cmsSize = get<CFNumberRef>(CFSTR("cmssize"))) 284 state.mCMSSize = cfNumber<size_t>(cmsSize); 285 else 286 state.mCMSSize = 18000; // big enough for now, not forever. 287 288 // metadata preservation options 289 if (CFNumberRef preserve = get<CFNumberRef>(kSecCodeSignerPreserveMetadata)) { 290 state.mPreserveMetadata = cfNumber<uint32_t>(preserve); 291 } else 292 state.mPreserveMetadata = 0; 293 294 // signing time can be a CFDateRef or null 295 if (CFTypeRef time = get<CFTypeRef>(kSecCodeSignerSigningTime)) { 296 if (CFGetTypeID(time) == CFDateGetTypeID() || time == kCFNull) 297 state.mSigningTime = CFDateRef(time); 298 else 299 MacOSError::throwMe(errSecCSInvalidObjectRef); 300 } 301 302 if (CFStringRef ident = get<CFStringRef>(kSecCodeSignerIdentifier)) 303 state.mIdentifier = cfString(ident); 304 305 if (CFStringRef teamid = get<CFStringRef>(kSecCodeSignerTeamIdentifier)) 306 state.mTeamID = cfString(teamid); 307 308 if (CFNumberRef platform = get<CFNumberRef>(kSecCodeSignerPlatformIdentifier)) { 309 int64_t ident = cfNumber<int64_t>(platform); 310 if (ident < 0 || ident > maxPlatform) // overflow 311 MacOSError::throwMe(errSecCSInvalidPlatform); 312 state.mPlatform = ident; 313 } 314 315 if (CFStringRef prefix = get<CFStringRef>(kSecCodeSignerIdentifierPrefix)) 316 state.mIdentifierPrefix = cfString(prefix); 317 318 // Requirements can be binary or string (to be compiled). 319 // We must pass them along to the signer for possible text substitution 320 if (CFTypeRef reqs = get<CFTypeRef>(kSecCodeSignerRequirements)) { 321 if (CFGetTypeID(reqs) == CFDataGetTypeID() || CFGetTypeID(reqs) == CFStringGetTypeID()) 322 state.mRequirements = reqs; 323 else 324 MacOSError::throwMe(errSecCSInvalidObjectRef); 325 } else 326 state.mRequirements = NULL; 327 328 state.mNoMachO = getBool(CFSTR("no-macho")); 329 330 state.mPageSize = get<CFNumberRef>(kSecCodeSignerPageSize); 331 332 // detached can be (destination) file URL or (mutable) Data to be appended-to 333 if ((state.mDetached = get<CFTypeRef>(kSecCodeSignerDetached))) { 334 CFTypeID type = CFGetTypeID(state.mDetached); 335 if (type != CFURLGetTypeID() && type != CFDataGetTypeID() && type != CFNullGetTypeID()) 336 MacOSError::throwMe(errSecCSInvalidObjectRef); 337 } 338 339 state.mResourceRules = get<CFDictionaryRef>(kSecCodeSignerResourceRules); 340 341 state.mApplicationData = get<CFDataRef>(kSecCodeSignerApplicationData); 342 state.mEntitlementData = get<CFDataRef>(kSecCodeSignerEntitlements); 343 344 if (CFBooleanRef timestampRequest = get<CFBooleanRef>(kSecCodeSignerRequireTimestamp)) { 345 state.mWantTimeStamp = timestampRequest == kCFBooleanTrue; 346 } else { // pick default 347 state.mWantTimeStamp = false; 348 if (state.mSigner && state.mSigner != SecIdentityRef(kCFNull)) { 349 CFRef<SecCertificateRef> signerCert; 350 MacOSError::check(SecIdentityCopyCertificate(state.mSigner, &signerCert.aref())); 351 if (certificateHasField(signerCert, devIdLeafMarkerOID)) 352 state.mWantTimeStamp = true; 353 } 354 } 355 state.mTimestampAuthentication = get<SecIdentityRef>(kSecCodeSignerTimestampAuthentication); 356 state.mTimestampService = get<CFURLRef>(kSecCodeSignerTimestampServer); 357 state.mNoTimeStampCerts = getBool(kSecCodeSignerTimestampOmitCertificates); 358 359 if (CFStringRef runtimeVersionOverride = get<CFStringRef>(kSecCodeSignerRuntimeVersion)) { 360 std::string runtime = cfString(runtimeVersionOverride); 361 if (runtime.empty()) { 362 MacOSError::throwMe(errSecCSInvalidRuntimeVersion); 363 } 364 state.mRuntimeVersionOverride = parseRuntimeVersion(runtime); 365 } 366 367 // Don't add the adhoc flag, even if no signer identity was specified. 368 // Useful for editing in the CMS at a later point. 369 state.mOmitAdhocFlag = getBool(kSecCodeSignerOmitAdhocFlag); 370 } 371 372 373 } // end namespace CodeSigning 374 } // end namespace Security