/ OSX / libsecurity_codesigning / lib / signer.cpp
signer.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  // signer - Signing operation supervisor and controller
  26  //
  27  #include "bundlediskrep.h"
  28  #include "der_plist.h"
  29  #include "signer.h"
  30  #include "resources.h"
  31  #include "signerutils.h"
  32  #include "SecCodeSigner.h"
  33  #include <Security/SecIdentity.h>
  34  #include <Security/CMSEncoder.h>
  35  #include <Security/CMSPrivate.h>
  36  #include <Security/CSCommonPriv.h>
  37  #include <CoreFoundation/CFBundlePriv.h>
  38  #include "resources.h"
  39  #include "machorep.h"
  40  #include "reqparser.h"
  41  #include "reqdumper.h"
  42  #include "csutilities.h"
  43  #include <security_utilities/unix++.h>
  44  #include <security_utilities/unixchild.h>
  45  #include <security_utilities/cfmunge.h>
  46  #include <security_utilities/dispatch.h>
  47  #include <IOKit/storage/IOStorageDeviceCharacteristics.h>
  48  
  49  namespace Security {
  50  namespace CodeSigning {
  51  
  52  
  53  //
  54  // Sign some code.
  55  //
  56  void SecCodeSigner::Signer::sign(SecCSFlags flags)
  57  {
  58  	rep = code->diskRep()->base();
  59  	this->prepare(flags);
  60  
  61  	PreSigningContext context(*this);
  62  
  63  	considerTeamID(context);
  64  
  65  	if (Universal *fat = state.mNoMachO ? NULL : rep->mainExecutableImage()) {
  66  		signMachO(fat, context);
  67  	} else {
  68  		signArchitectureAgnostic(context);
  69  	}
  70  }
  71  	
  72  	
  73  void SecCodeSigner::Signer::considerTeamID(const PreSigningContext& context)
  74  {
  75  	/* If an explicit teamID was passed in it must be
  76  	 the same as what came from the cert */
  77  	std::string teamIDFromCert = state.getTeamIDFromSigner(context.certs);
  78  	
  79  	if (state.mPreserveMetadata & kSecCodeSignerPreserveTeamIdentifier) {
  80  		/* If preserving the team identifier, teamID is set previously when the
  81  		 code object is still available */
  82  		if (!teamIDFromCert.empty() && teamID != teamIDFromCert)
  83  			MacOSError::throwMe(errSecCSInvalidFlags);
  84  	} else {
  85  		if (teamIDFromCert.empty()) {
  86  			/* state.mTeamID is an explicitly passed teamID */
  87  			teamID = state.mTeamID;
  88  		} else if (state.mTeamID.empty() || (state.mTeamID == teamIDFromCert)) {
  89  			/* If there was no explicit team ID set, or the explicit team ID matches
  90  			 what is in the cert, use the team ID from the certificate */
  91  			teamID = teamIDFromCert;
  92  		} else {
  93  			/* The caller passed in an explicit team ID that does not match what is
  94  			 in the signing cert, which is an invalid usage */
  95  			MacOSError::throwMe(errSecCSInvalidFlags);
  96  		}
  97  	}
  98  }
  99  	
 100  
 101  //
 102  // Remove any existing code signature from code
 103  //
 104  void SecCodeSigner::Signer::remove(SecCSFlags flags)
 105  {
 106  	// can't remove a detached signature
 107  	if (state.mDetached)
 108  		MacOSError::throwMe(errSecCSNotSupported);
 109  
 110  	rep = code->diskRep();
 111  
 112  	if (state.mPreserveAFSC)
 113  		rep->writer()->setPreserveAFSC(state.mPreserveAFSC);
 114  
 115  	if (Universal *fat = state.mNoMachO ? NULL : rep->mainExecutableImage()) {
 116  		// architecture-sensitive removal
 117  		MachOEditor editor(rep->writer(), *fat, digestAlgorithms(), rep->mainExecutablePath());
 118  		editor.allocate();		// create copy
 119  		editor.commit();		// commit change
 120  	} else {
 121  		// architecture-agnostic removal
 122  		RefPointer<DiskRep::Writer> writer = rep->writer();
 123  		writer->remove();
 124  		writer->flush();
 125  	}
 126  }
 127  
 128  
 129  //
 130  // Contemplate the object-to-be-signed and set up the Signer state accordingly.
 131  //
 132  void SecCodeSigner::Signer::prepare(SecCSFlags flags)
 133  {
 134  	// make sure the rep passes strict validation
 135  	if (strict)
 136  		rep->strictValidate(NULL, MacOSErrorSet(), flags | (kSecCSQuickCheck|kSecCSRestrictSidebandData));
 137  	
 138  	// initialize progress/cancellation state
 139  	code->prepareProgress(0);			// totally fake workload - we don't know how many files we'll encounter
 140  
 141  	// get the Info.plist out of the rep for some creative defaulting
 142  	CFRef<CFDictionaryRef> infoDict;
 143  	if (CFRef<CFDataRef> infoData = rep->component(cdInfoSlot))
 144  		infoDict.take(makeCFDictionaryFrom(infoData));
 145  	
 146  	uint32_t inherit = 0;
 147  
 148  	if (code->isSigned() && (code->codeDirectory(false)->flags & kSecCodeSignatureLinkerSigned) == 0) {
 149  		inherit = state.mPreserveMetadata;
 150  	}
 151  
 152  	// work out the canonical identifier
 153  	identifier = state.mIdentifier;
 154  	if (identifier.empty() && (inherit & kSecCodeSignerPreserveIdentifier)) {
 155  		identifier = code->identifier();
 156  	}
 157  	if (identifier.empty()) {
 158  		identifier = rep->recommendedIdentifier(*this);
 159  		if (identifier.find('.') == string::npos)
 160  			identifier = state.mIdentifierPrefix + identifier;
 161  		if (identifier.find('.') == string::npos && isAdhoc())
 162  			identifier = identifier + "-" + uniqueName();
 163  		secinfo("signer", "using default identifier=%s", identifier.c_str());
 164  	} else
 165  		secinfo("signer", "using explicit identifier=%s", identifier.c_str());
 166  
 167  	teamID = state.mTeamID;
 168  	if (teamID.empty() && (inherit & kSecCodeSignerPreserveTeamIdentifier)) {
 169  		const char *c_id = code->teamID();
 170  		if (c_id)
 171  			teamID = c_id;
 172  	}
 173  	
 174  	// Digest algorithms: explicit or preserved. Subject to diskRep defaults or final default later.
 175  	hashAlgorithms = state.mDigestAlgorithms;
 176  	if (hashAlgorithms.empty() && (inherit & kSecCodeSignerPreserveDigestAlgorithm))
 177  		hashAlgorithms = code->hashAlgorithms();
 178  	
 179  	entitlements = state.mEntitlementData;
 180  	if (!entitlements && (inherit & kSecCodeSignerPreserveEntitlements))
 181  		entitlements = code->component(cdEntitlementSlot);
 182  	
 183  	// work out the CodeDirectory flags word
 184  	bool haveCdFlags = false;
 185  	if (!haveCdFlags && state.mCdFlagsGiven) {
 186  		cdFlags = state.mCdFlags;
 187  		secinfo("signer", "using explicit cdFlags=0x%x", cdFlags);
 188  		haveCdFlags = true;
 189  	}
 190  	if (!haveCdFlags) {
 191  		cdFlags = 0;
 192  		if (infoDict)
 193  			if (CFTypeRef csflags = CFDictionaryGetValue(infoDict, CFSTR("CSFlags"))) {
 194  				if (CFGetTypeID(csflags) == CFNumberGetTypeID()) {
 195  					cdFlags = cfNumber<uint32_t>(CFNumberRef(csflags));
 196  					secinfo("signer", "using numeric cdFlags=0x%x from Info.plist", cdFlags);
 197  				} else if (CFGetTypeID(csflags) == CFStringGetTypeID()) {
 198  					cdFlags = cdTextFlags(cfString(CFStringRef(csflags)));
 199  					secinfo("signer", "using text cdFlags=0x%x from Info.plist", cdFlags);
 200  				} else
 201  					MacOSError::throwMe(errSecCSBadDictionaryFormat);
 202  				haveCdFlags = true;
 203  			}
 204  	}
 205  	if (!haveCdFlags && (inherit & kSecCodeSignerPreserveFlags)) {
 206  		cdFlags = code->codeDirectory(false)->flags & ~kSecCodeSignatureAdhoc;
 207  		secinfo("signer", "using inherited cdFlags=0x%x", cdFlags);
 208  		haveCdFlags = true;
 209  	}
 210  	if (!haveCdFlags)
 211  		cdFlags = 0;
 212  	if ((state.mSigner == SecIdentityRef(kCFNull)) &&
 213  		!state.mOmitAdhocFlag)	// ad-hoc signing requested...
 214  		cdFlags |= kSecCodeSignatureAdhoc;	// ... so note that
 215  
 216  	// prepare the internal requirements input
 217  	if (state.mRequirements) {
 218  		if (CFGetTypeID(state.mRequirements) == CFDataGetTypeID()) {		// binary form
 219  			const Requirements *rp = (const Requirements *)CFDataGetBytePtr(state.mRequirements.as<CFDataRef>());
 220  			if (!rp->validateBlob())
 221  				MacOSError::throwMe(errSecCSReqInvalid);
 222  			requirements = rp->clone();
 223  		} else if (CFGetTypeID(state.mRequirements) == CFStringGetTypeID()) { // text form
 224  			CFRef<CFMutableStringRef> reqText = CFStringCreateMutableCopy(NULL, 0, state.mRequirements.as<CFStringRef>());
 225  			// substitute $ variable tokens
 226  			CFRange range = { 0, CFStringGetLength(reqText) };
 227  			CFStringFindAndReplace(reqText, CFSTR("$self.identifier"), CFTempString(identifier), range, 0);
 228  			requirements = parseRequirements(cfString(reqText));
 229  		} else
 230  			MacOSError::throwMe(errSecCSInvalidObjectRef);
 231  	} else if (inherit & kSecCodeSignerPreserveRequirements)
 232  		if (const Requirements *rp = code->internalRequirements())
 233  			requirements = rp->clone();
 234  	
 235  	// prepare the resource directory, if any
 236  	string rpath = rep->resourcesRootPath();
 237  	string rrpath;
 238  	CFCopyRef<CFDictionaryRef> resourceRules;
 239  	if (!rpath.empty()) {
 240  		// explicitly given resource rules always win
 241  		resourceRules = state.mResourceRules;
 242  		
 243  		// inherited rules come next (overriding embedded ones!)
 244  		if (!resourceRules && (inherit & kSecCodeSignerPreserveResourceRules))
 245  			if (CFDictionaryRef oldRules = code->resourceDictionary(false))
 246  				resourceRules = oldRules;
 247  		
 248  		// embedded resource rules come next
 249  		if (!resourceRules && infoDict)
 250  			if (CFTypeRef spec = CFDictionaryGetValue(infoDict, _kCFBundleResourceSpecificationKey)) {
 251  				if (CFGetTypeID(spec) == CFStringGetTypeID())
 252  					if (CFRef<CFDataRef> data = cfLoadFile(rpath + "/" + cfString(CFStringRef(spec))))
 253  						if (CFDictionaryRef dict = makeCFDictionaryFrom(data))
 254  							resourceRules.take(dict);
 255  				if (!resourceRules)	// embedded rules present but unacceptable
 256  					MacOSError::throwMe(errSecCSResourceRulesInvalid);
 257  			}
 258  		
 259  		// if we got one from anywhere (but the defaults), sanity-check it
 260  		if (resourceRules) {
 261  			CFTypeRef rules = CFDictionaryGetValue(resourceRules, CFSTR("rules"));
 262  			if (!rules || CFGetTypeID(rules) != CFDictionaryGetTypeID())
 263  				MacOSError::throwMe(errSecCSResourceRulesInvalid);
 264  		}
 265  
 266  		// finally, ask the DiskRep for its default
 267  		if (!resourceRules)
 268  			resourceRules.take(rep->defaultResourceRules(*this));
 269  
 270  		// resource root can optionally be the canonical bundle path,
 271  		// but sealed resource paths are always relative to rpath
 272  		rrpath = rpath;
 273  		if (signingFlags() & kSecCSSignBundleRoot)
 274  			rrpath = cfStringRelease(rep->copyCanonicalPath());
 275  	}
 276  	
 277  	// screen and set the signing time
 278  	if (state.mSigningTime == CFDateRef(kCFNull)) {
 279  		emitSigningTime = false;		// no time at all
 280  	} else if (!state.mSigningTime) {
 281  		emitSigningTime = true;
 282  		signingTime = 0;			// wall clock, established later
 283  	} else {
 284  		CFAbsoluteTime time = CFDateGetAbsoluteTime(state.mSigningTime);
 285  		if (time > CFAbsoluteTimeGetCurrent())	// not allowed to post-date a signature
 286  			MacOSError::throwMe(errSecCSBadDictionaryFormat);
 287  		emitSigningTime = true;
 288  		signingTime = time;
 289  	}
 290  	
 291  	pagesize = state.mPageSize ? cfNumber<size_t>(state.mPageSize) : rep->pageSize(*this);
 292  	
 293  	// Allow the DiskRep to modify the signing parameters. This sees explicit and inherited values but not defaults.
 294  	rep->prepareForSigning(*this);
 295  	
 296  	// apply some defaults after diskRep intervention
 297  	if (hashAlgorithms.empty()) {	// default to SHA256 + SHA-1
 298  		hashAlgorithms.insert(kSecCodeSignatureHashSHA1);
 299  		hashAlgorithms.insert(kSecCodeSignatureHashSHA256);
 300  	}
 301  	
 302  	// build the resource directory (once and for all, using the digests determined above)
 303  	if (!rpath.empty()) {
 304  		buildResources(rrpath, rpath, resourceRules);
 305  	}
 306  
 307  	
 308  	
 309  	if (inherit & kSecCodeSignerPreservePEH) {
 310  		/* We need at least one architecture in all cases because we index our
 311  		 * PreEncryptionMaps by architecture. However, only machOs have any
 312  		 * architecture at all, for generic targets there will just be one
 313  		 * PreEncryptionHashMap.
 314  		 * So if the main executable is not a machO, we just choose the local
 315  		 * (signer's) main architecture as dummy value for the first element in our pair. */
 316  		preEncryptMainArch = (code->diskRep()->mainExecutableIsMachO() ?
 317  							  code->diskRep()->mainExecutableImage()->bestNativeArch() :
 318  							   Architecture::local());
 319  
 320  		addPreEncryptHashes(preEncryptHashMaps[preEncryptMainArch], code);
 321  		
 322  		code->handleOtherArchitectures(^(Security::CodeSigning::SecStaticCode *subcode) {
 323  			Universal *fat = subcode->diskRep()->mainExecutableImage();
 324  			assert(fat && fat->narrowed());	// handleOtherArchitectures gave us a focused architecture slice.
 325  			Architecture arch = fat->bestNativeArch();	// actually, only architecture for this slice.
 326  			addPreEncryptHashes(preEncryptHashMaps[arch], subcode);
 327  		});
 328  	}
 329  
 330  	if (inherit & kSecCodeSignerPreserveRuntime) {
 331  		/* We need at least one architecture in all cases because we index our
 332  		 * RuntimeVersionMaps by architecture. However, only machOs have any
 333  		 * architecture at all, for generic targets there will just be one
 334  		 * RuntimeVersionMap.
 335  		 * So if the main executable is not a machO, we just choose the local
 336  		 * (signer's) main architecture as dummy value for the first element in our pair. */
 337  		runtimeVersionMainArch = (code->diskRep()->mainExecutableIsMachO() ?
 338  							  code->diskRep()->mainExecutableImage()->bestNativeArch() :
 339  							  Architecture::local());
 340  
 341  		addRuntimeVersions(runtimeVersionMap[runtimeVersionMainArch], code);
 342  
 343  		code->handleOtherArchitectures(^(Security::CodeSigning::SecStaticCode *subcode) {
 344  			Universal *fat = subcode->diskRep()->mainExecutableImage();
 345  			assert(fat && fat->narrowed());	// handleOtherArchitectures gave us a focused architecture slice.
 346  			Architecture arch = fat->bestNativeArch();	// actually, only architecture for this slice.
 347  			addRuntimeVersions(runtimeVersionMap[arch], subcode);
 348  		});
 349  	}
 350  }
 351  
 352  void SecCodeSigner::Signer::addPreEncryptHashes(PreEncryptHashMap &map, SecStaticCode const *code) {
 353  	SecStaticCode::CodeDirectoryMap const *cds = code->codeDirectories();
 354  	
 355  	if (cds != NULL) {
 356  		for(auto const& pair : *cds) {
 357  			CodeDirectory::HashAlgorithm const alg = pair.first;
 358  			CFDataRef const cddata = pair.second;
 359  			
 360  			CodeDirectory const * cd =
 361  			reinterpret_cast<const CodeDirectory *>(CFDataGetBytePtr(cddata));
 362  			if (cd->preEncryptHashes() != NULL) {
 363  				CFRef<CFDataRef> preEncrypt = makeCFData(cd->preEncryptHashes(),
 364  														 cd->nCodeSlots * cd->hashSize);
 365  				map[alg] = preEncrypt;
 366  			}
 367  		}
 368  	}
 369  }
 370  
 371  void SecCodeSigner::Signer::addRuntimeVersions(RuntimeVersionMap &map, const SecStaticCode *code)
 372  {
 373  	SecStaticCode::CodeDirectoryMap const *cds = code->codeDirectories();
 374  
 375  	if (cds != NULL) {
 376  		for(auto const& pair : *cds) {
 377  			CodeDirectory::HashAlgorithm const alg = pair.first;
 378  			CFDataRef const cddata = pair.second;
 379  
 380  			CodeDirectory const * cd =
 381  			reinterpret_cast<const CodeDirectory *>(CFDataGetBytePtr(cddata));
 382  			if (cd->runtimeVersion()) {
 383  				map[alg] = cd->runtimeVersion();
 384  			}
 385  		}
 386  	}
 387  }
 388  
 389  //
 390  // Collect the resource seal for a program.
 391  // This includes both sealed resources and information about nested code.
 392  //
 393  void SecCodeSigner::Signer::buildResources(std::string root, std::string relBase, CFDictionaryRef rulesDict)
 394  {
 395  	typedef ResourceBuilder::Rule Rule;
 396  	
 397  	secinfo("codesign", "start building resource directory");
 398  	__block CFRef<CFMutableDictionaryRef> result = makeCFMutableDictionary();
 399  	
 400  	CFDictionaryRef rules = cfget<CFDictionaryRef>(rulesDict, "rules");
 401  	assert(rules);
 402  
 403  	if (this->state.mLimitedAsync == NULL) {
 404  		this->state.mLimitedAsync =
 405  			/* rdar://problem/20299541: Async workers (i.e. parallelization) are currently
 406  			 * turned off, because the paths for signing code are not ready for it yet. */
 407  			// new LimitedAsync(rep->fd().mediumType() == kIOPropertyMediumTypeSolidStateKey);
 408  			new LimitedAsync(false);
 409  	}
 410  
 411  	CFDictionaryRef files2 = NULL;
 412  	if (!(signingFlags() & kSecCSSignV1)) {
 413  		CFCopyRef<CFDictionaryRef> rules2 = cfget<CFDictionaryRef>(rulesDict, "rules2");
 414  		if (!rules2) {
 415  			// Clone V1 rules and add default nesting rules at weight 0 (overridden by anything in rules,
 416  			// because the default weight, according to ResourceBuilder::addRule(), is 1).
 417  			// V1 rules typically do not cover these places so we'll prevail, but if they do, we defer to them.
 418  			rules2.take(cfmake<CFDictionaryRef>("{+%O"
 419  				"'^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/' = {nested=#T, weight=0}" // exclude dynamic repositories
 420  			"}", rules));
 421  		}
 422  
 423  		Dispatch::Group group;
 424  		Dispatch::Group &groupRef = group;  // (into block)
 425  
 426  		// build the modern (V2) resource seal
 427  		__block CFRef<CFMutableDictionaryRef> files = makeCFMutableDictionary();
 428  		CFMutableDictionaryRef filesRef = files.get();	// (into block)
 429  		ResourceBuilder resourceBuilder(root, relBase, rules2, strict, MacOSErrorSet());
 430  		ResourceBuilder	&resources = resourceBuilder;	// (into block)
 431  		rep->adjustResources(resources);
 432  
 433  		resources.scan(^(FTSENT *ent, uint32_t ruleFlags, const std::string relpath, Rule *rule) {
 434  			bool isSymlink = (ent->fts_info == FTS_SL);
 435  			bool isNested = (ruleFlags & ResourceBuilder::nested);
 436  			const std::string path(ent->fts_path);
 437  			const std::string accpath(ent->fts_accpath);
 438  			this->state.mLimitedAsync->perform(groupRef, ^{
 439  				CFRef<CFMutableDictionaryRef> seal;
 440  				if (isNested) {
 441  					seal.take(signNested(path, relpath));
 442  				} else if (isSymlink) {
 443  					char target[PATH_MAX];
 444  					ssize_t len = ::readlink(accpath.c_str(), target, sizeof(target)-1);
 445  					if (len < 0)
 446  						UnixError::check(-1);
 447  					target[len] = '\0';
 448  					seal.take(cfmake<CFMutableDictionaryRef>("{symlink=%s}", target));
 449  				} else {
 450  					seal.take(resources.hashFile(accpath.c_str(), digestAlgorithms(), signingFlags() & kSecCSSignStrictPreflight));
 451  				}
 452  				if (seal.get() == NULL) {
 453  					secerror("Failed to generate sealed resource: %d, %d, %s", isNested, isSymlink, accpath.c_str());
 454  					MacOSError::throwMe(errSecCSBadResource);
 455  				}
 456  				if (ruleFlags & ResourceBuilder::optional)
 457  					CFDictionaryAddValue(seal, CFSTR("optional"), kCFBooleanTrue);
 458  				CFTypeRef hash;
 459  				StLock<Mutex> _(resourceLock);
 460  				if ((hash = CFDictionaryGetValue(seal, CFSTR("hash"))) && CFDictionaryGetCount(seal) == 1) // simple form
 461  					CFDictionaryAddValue(filesRef, CFTempString(relpath).get(), hash);
 462  				else
 463  					CFDictionaryAddValue(filesRef, CFTempString(relpath).get(), seal.get());
 464  				code->reportProgress();
 465  			});
 466  		});
 467  		group.wait();
 468  		CFDictionaryAddValue(result, CFSTR("rules2"), resourceBuilder.rules());
 469  		files2 = files;
 470  		CFDictionaryAddValue(result, CFSTR("files2"), files2);
 471  	}
 472  	
 473  	CFDictionaryAddValue(result, CFSTR("rules"), rules);	// preserve V1 rules in any case
 474  	if (!(signingFlags() & kSecCSSignNoV1)) {
 475  		// build the legacy (V1) resource seal
 476  		__block CFRef<CFMutableDictionaryRef> files = makeCFMutableDictionary();
 477  		ResourceBuilder resourceBuilder(root, relBase, rules, strict, MacOSErrorSet());
 478  		ResourceBuilder	&resources = resourceBuilder;
 479  		rep->adjustResources(resources);	// DiskRep-specific adjustments
 480  		resources.scan(^(FTSENT *ent, uint32_t ruleFlags, std::string relpath, Rule *rule) {
 481  			if (ent->fts_info == FTS_F) {
 482  				CFRef<CFDataRef> hash;
 483  				if (files2)	// try to get the hash from a previously-made version
 484  					if (CFTypeRef seal = CFDictionaryGetValue(files2, CFTempString(relpath))) {
 485  						if (CFGetTypeID(seal) == CFDataGetTypeID())
 486  							hash = CFDataRef(seal);
 487  						else
 488  							hash = CFDataRef(CFDictionaryGetValue(CFDictionaryRef(seal), CFSTR("hash")));
 489  					}
 490  				if (!hash)
 491  					hash.take(resources.hashFile(ent->fts_accpath, kSecCodeSignatureHashSHA1));
 492  				// The user controlled rule flag is a runtime only flag and shouldn't cause use of a more
 493  				// complex resource serialization as doing so would break serialized adhoc opaque hashes.
 494  				if ((ruleFlags & ~ResourceBuilder::user_controlled) == 0) {	// default case - plain hash
 495  					cfadd(files, "{%s=%O}", relpath.c_str(), hash.get());
 496  					secinfo("csresource", "%s added simple (rule %p)", relpath.c_str(), rule);
 497  				} else {	// more complicated - use a sub-dictionary
 498  					cfadd(files, "{%s={hash=%O,optional=%B}}",
 499  						relpath.c_str(), hash.get(), ruleFlags & ResourceBuilder::optional);
 500  					secinfo("csresource", "%s added complex (rule %p)", relpath.c_str(), rule);
 501  				}
 502  			}
 503  		});
 504  		CFDictionaryAddValue(result, CFSTR("files"), files.get());
 505  	}
 506  	
 507  	resourceDirectory = result.get();
 508  	resourceDictData.take(makeCFData(resourceDirectory.get()));
 509  }
 510  
 511  
 512  //
 513  // Deal with one piece of nested code
 514  //
 515  CFMutableDictionaryRef SecCodeSigner::Signer::signNested(const std::string &path, const std::string &relpath)
 516  {
 517  	// sign nested code and collect nesting information
 518  	try {
 519  		SecPointer<SecStaticCode> code = new SecStaticCode(DiskRep::bestGuess(path));
 520  		if (signingFlags() & kSecCSSignNestedCode)
 521  			this->state.sign(code, signingFlags());
 522  		std::string dr = Dumper::dump(code->designatedRequirement());
 523  		if (CFDataRef hash = code->cdHash())
 524  			return cfmake<CFMutableDictionaryRef>("{requirement=%s,cdhash=%O}",
 525  				Dumper::dump(code->designatedRequirement()).c_str(),
 526  				hash);
 527  		MacOSError::throwMe(errSecCSUnsigned);
 528  	} catch (const CommonError &err) {
 529  		CSError::throwMe(err.osStatus(), kSecCFErrorPath, CFTempURL(relpath, false, this->code->resourceBase()));
 530  	}
 531  }
 532  
 533  
 534  //
 535  // Sign a Mach-O binary, using liberal dollops of that special Mach-O magic sauce.
 536  // Note that this will deal just fine with non-fat Mach-O binaries, but it will
 537  // treat them as architectural binaries containing (only) one architecture - that
 538  // interpretation is courtesy of the Universal/MachO support classes.
 539  //
 540  void SecCodeSigner::Signer::signMachO(Universal *fat, const Requirement::Context &context)
 541  {
 542  	// Mach-O executable at the core - perform multi-architecture signing
 543  	RefPointer<DiskRep::Writer> writer = rep->writer();
 544  
 545  	if (state.mPreserveAFSC)
 546  		writer->setPreserveAFSC(state.mPreserveAFSC);
 547  
 548  	unique_ptr<ArchEditor> editor(state.mDetached
 549  		? static_cast<ArchEditor *>(new BlobEditor(*fat, *this))
 550  		: new MachOEditor(writer, *fat, this->digestAlgorithms(), rep->mainExecutablePath()));
 551  	assert(editor->count() > 0);
 552  	if (!editor->attribute(writerNoGlobal))	// can store architecture-common components
 553  		populate(*editor);
 554  	
 555  	// pass 1: prepare signature blobs and calculate sizes
 556  	for (MachOEditor::Iterator it = editor->begin(); it != editor->end(); ++it) {
 557  		MachOEditor::Arch &arch = *it->second;
 558  		arch.source.reset(fat->architecture(it->first));
 559  		
 560  		// library validation is not compatible with i386
 561  		if (arch.architecture.cpuType() == CPU_TYPE_I386) {
 562  			if (cdFlags & kSecCodeSignatureLibraryValidation) {
 563  				MacOSError::throwMe(errSecCSBadLVArch);
 564  			}
 565  		}
 566  		
 567  		bool generateEntitlementDER = false;
 568  		if (signingFlags() & kSecCSSignGenerateEntitlementDER) {
 569  			generateEntitlementDER = true;
 570  		} else {
 571  			uint32_t platform = arch.source->platform();
 572  			switch (platform) {
 573  				case PLATFORM_WATCHOS:
 574  				case PLATFORM_BRIDGEOS:
 575  					generateEntitlementDER = false;
 576  					break;
 577  				default:
 578  					generateEntitlementDER = true;
 579  					break;
 580  			}
 581  		}
 582  
 583  		bool mainBinary = arch.source.get()->type() == MH_EXECUTE;
 584  
 585  		uint32_t runtimeVersion = 0;
 586  		if (cdFlags & kSecCodeSignatureRuntime) {
 587  			runtimeVersion = state.mRuntimeVersionOverride ? state.mRuntimeVersionOverride : arch.source.get()->sdkVersion();
 588  		}
 589  
 590  		arch.ireqs(requirements, rep->defaultRequirements(&arch.architecture, *this), context);
 591  		if (editor->attribute(writerNoGlobal))	// can't store globally, add per-arch
 592  			populate(arch);
 593  		for (auto type = digestAlgorithms().begin(); type != digestAlgorithms().end(); ++type) {
 594  			uint32_t runtimeVersionToUse = runtimeVersion;
 595  			if ((cdFlags & kSecCodeSignatureRuntime) && runtimeVersionMap.count(arch.architecture)) {
 596  				if (runtimeVersionMap[arch.architecture].count(*type)) {
 597  					runtimeVersionToUse = runtimeVersionMap[arch.architecture][*type];
 598  				}
 599  			}
 600  			arch.eachDigest(^(CodeDirectory::Builder& builder) {
 601  				populate(builder, arch, arch.ireqs,
 602  						 arch.source->offset(), arch.source->signingExtent(),
 603  						 mainBinary, rep->execSegBase(&(arch.architecture)), rep->execSegLimit(&(arch.architecture)),
 604  						 unsigned(digestAlgorithms().size()-1),
 605  						 preEncryptHashMaps[arch.architecture], runtimeVersionToUse, generateEntitlementDER);
 606  			});
 607  		}
 608  	
 609  		// add identification blob (made from this architecture) only if we're making a detached signature
 610  		if (state.mDetached) {
 611  			CFRef<CFDataRef> identification = MachORep::identificationFor(arch.source.get());
 612  			arch.add(cdIdentificationSlot, BlobWrapper::alloc(
 613  				CFDataGetBytePtr(identification), CFDataGetLength(identification)));
 614  		}
 615  		
 616  		// prepare SuperBlob size estimate
 617  		__block std::vector<size_t> sizes;
 618  		arch.eachDigest(^(CodeDirectory::Builder& builder){
 619  			sizes.push_back(builder.size(CodeDirectory::currentVersion));
 620  		});
 621  		arch.blobSize = arch.size(sizes, state.mCMSSize, 0);
 622  	}
 623  	
 624  	editor->allocate();
 625  	
 626  	// pass 2: Finish and generate signatures, and write them
 627  	for (MachOEditor::Iterator it = editor->begin(); it != editor->end(); ++it) {
 628  		MachOEditor::Arch &arch = *it->second;
 629  		editor->reset(arch);
 630  
 631  		// finish CodeDirectories (off new binary) and sign it
 632  		__block CodeDirectorySet cdSet;
 633  		arch.eachDigest(^(CodeDirectory::Builder &builder) {
 634  			CodeDirectory *cd = builder.build();
 635  			cdSet.add(cd);
 636  		});
 637  
 638  		CFRef<CFDictionaryRef> hashDict = cdSet.hashDict();
 639  		CFRef<CFArrayRef> hashList = cdSet.hashList();
 640  		CFRef<CFDataRef> signature = signCodeDirectory(cdSet.primary(), hashDict, hashList);
 641  		
 642  		// complete the SuperBlob
 643  		cdSet.populate(&arch);
 644  		arch.add(cdSignatureSlot, BlobWrapper::alloc(
 645  			CFDataGetBytePtr(signature), CFDataGetLength(signature)));
 646  		if (!state.mDryRun) {
 647  			EmbeddedSignatureBlob *blob = arch.make();
 648  			editor->write(arch, blob);	// takes ownership of blob
 649  		}
 650  	}
 651  	
 652  	// done: write edit copy back over the original
 653  	if (!state.mDryRun) {
 654  		editor->commit();
 655  	}
 656  }
 657  
 658  
 659  //
 660  // Sign a binary that has no notion of architecture.
 661  // That currently means anything that isn't Mach-O format.
 662  //
 663  void SecCodeSigner::Signer::signArchitectureAgnostic(const Requirement::Context &context)
 664  {
 665  	// non-Mach-O executable - single-instance signing
 666  	RefPointer<DiskRep::Writer> writer = state.mDetached ?
 667  		(new DetachedBlobWriter(*this)) : rep->writer();
 668  
 669  	if(state.mPreserveAFSC)
 670  		writer->setPreserveAFSC(state.mPreserveAFSC);
 671  
 672  	CodeDirectorySet cdSet;
 673  
 674  	for (auto type = digestAlgorithms().begin(); type != digestAlgorithms().end(); ++type) {
 675  		CodeDirectory::Builder builder(*type);
 676  		InternalRequirements ireqs;
 677  		ireqs(requirements, rep->defaultRequirements(NULL, *this), context);
 678  		populate(*writer);
 679  		populate(builder, *writer, ireqs, rep->signingBase(), rep->signingLimit(),
 680  				 false,		// only machOs can currently be main binaries
 681  				 rep->execSegBase(NULL), rep->execSegLimit(NULL),
 682  				 unsigned(digestAlgorithms().size()-1),
 683  				 preEncryptHashMaps[preEncryptMainArch], // Only one map, the default.
 684  				 (cdFlags & kSecCodeSignatureRuntime) ? state.mRuntimeVersionOverride : 0,
 685  				 signingFlags() & kSecCSSignGenerateEntitlementDER);
 686  		
 687  		CodeDirectory *cd = builder.build();
 688  		if (!state.mDryRun)
 689  			cdSet.add(cd);
 690  	}
 691  	
 692  	// add identification blob (made from this architecture) only if we're making a detached signature
 693  	if (state.mDetached) {
 694  		CFRef<CFDataRef> identification = rep->identification();
 695  		writer->component(cdIdentificationSlot, identification);
 696  	}
 697  
 698  	// write out all CodeDirectories
 699  	if (!state.mDryRun)
 700  		cdSet.populate(writer);
 701  
 702  	CFRef<CFDictionaryRef> hashDict = cdSet.hashDict();
 703  	CFRef<CFArrayRef> hashList = cdSet.hashList();
 704  	CFRef<CFDataRef> signature = signCodeDirectory(cdSet.primary(), hashDict, hashList);
 705  	writer->signature(signature);
 706  	
 707  	// commit to storage
 708  	writer->flush();
 709  }
 710  
 711  
 712  //
 713  // Global populate - send components to destination buffers ONCE
 714  //
 715  void SecCodeSigner::Signer::populate(DiskRep::Writer &writer)
 716  {
 717  	if (resourceDirectory && !state.mDryRun)
 718  		writer.component(cdResourceDirSlot, resourceDictData);
 719  }
 720  
 721  
 722  //
 723  // Per-architecture populate - send components to per-architecture buffers
 724  // and populate the CodeDirectory for an architecture. In architecture-agnostic
 725  // signing operations, the non-architectural binary is considered one (arbitrary) architecture
 726  // for the purposes of this call.
 727  //
 728  void SecCodeSigner::Signer::populate(CodeDirectory::Builder &builder, DiskRep::Writer &writer,
 729  									 InternalRequirements &ireqs, size_t offset, size_t length,
 730  									 bool mainBinary, size_t execSegBase, size_t execSegLimit,
 731  									 unsigned alternateDigestCount,
 732  									 PreEncryptHashMap const &preEncryptHashMap,
 733  									 uint32_t runtimeVersion, bool generateEntitlementDER)
 734  {
 735  	// fill the CodeDirectory
 736  	builder.executable(rep->mainExecutablePath(), pagesize, offset, length);
 737  	builder.flags(cdFlags);
 738  	builder.identifier(identifier);
 739  	builder.teamID(teamID);
 740  	builder.platform(state.mPlatform);
 741  	builder.execSeg(execSegBase, execSegLimit, mainBinary ? kSecCodeExecSegMainBinary : 0);
 742  	builder.generatePreEncryptHashes(signingFlags() & kSecCSSignGeneratePEH);
 743  	builder.preservePreEncryptHashMap(preEncryptHashMap);
 744  	builder.runTimeVersion(runtimeVersion);
 745  
 746  	if (CFRef<CFDataRef> data = rep->component(cdInfoSlot))
 747  		builder.specialSlot(cdInfoSlot, data);
 748  	if (ireqs) {
 749  		CFRef<CFDataRef> data = makeCFData(*ireqs);
 750  		writer.component(cdRequirementsSlot, data);
 751  		builder.specialSlot(cdRequirementsSlot, data);
 752  	}
 753  	if (resourceDirectory)
 754  		builder.specialSlot(cdResourceDirSlot, resourceDictData);
 755  	if (entitlements) {
 756  		writer.component(cdEntitlementSlot, entitlements);
 757  		builder.specialSlot(cdEntitlementSlot, entitlements);
 758  
 759  		if (mainBinary) {
 760  			CFRef<CFDataRef> entitlementDER;
 761  			uint64_t execSegFlags = 0;
 762  			cookEntitlements(entitlements, generateEntitlementDER,
 763  							 &execSegFlags, &entitlementDER.aref());
 764  
 765  			if (generateEntitlementDER) {
 766  				writer.component(cdEntitlementDERSlot, entitlementDER);
 767  				builder.specialSlot(cdEntitlementDERSlot, entitlementDER);
 768  			}
 769  
 770  			builder.addExecSegFlags(execSegFlags);
 771  		}
 772  	}
 773  	if (CFRef<CFDataRef> repSpecific = rep->component(cdRepSpecificSlot))
 774  		builder.specialSlot(cdRepSpecificSlot, repSpecific);
 775  	
 776  	writer.addDiscretionary(builder);
 777  	
 778  #if 0 // rdar://problem/25720754
 779  	if ((signingFlags() & (kSecCSSignOpaque|kSecCSSignV1)) == 0 && builder.hashType() != kSecCodeSignatureHashSHA1) {
 780  		// calculate sorted list of top SuperBlob keys in this EmbeddedSignatureBlob (if any)
 781  		// (but not for opaque or V1 construction, which must remain bit-for-bit compatible)
 782  		std::vector<Endian<uint32_t> > slotVector;
 783  		slotVector.push_back(cdCodeDirectorySlot);	// mandatory
 784  		std::set<CodeDirectory::Slot> filledSlots = builder.filledSpecialSlots();
 785  		filledSlots.insert(cdTopDirectorySlot);		// will be added below
 786  		copy(filledSlots.begin(), filledSlots.end(), back_inserter(slotVector));
 787  		for (unsigned n = 0; n < alternateDigestCount; n++)
 788  			slotVector.push_back(cdAlternateCodeDirectorySlots + n);
 789  		slotVector.push_back(cdSignatureSlot);
 790  		CFTempData cfSlotVector(&slotVector[0], slotVector.size() * sizeof(slotVector[0]));
 791  		writer.component(cdTopDirectorySlot, cfSlotVector);
 792  		builder.specialSlot(cdTopDirectorySlot, cfSlotVector);
 793  	}
 794  #endif
 795  }
 796  
 797  	
 798  #include <security_smime/tsaSupport.h>
 799  
 800  //
 801  // Generate the CMS signature for a (finished) CodeDirectory.
 802  //
 803  CFDataRef SecCodeSigner::Signer::signCodeDirectory(const CodeDirectory *cd,
 804  												   CFDictionaryRef hashDict,
 805  												   CFArrayRef hashList)
 806  {
 807  	assert(state.mSigner);
 808  	CFRef<CFMutableDictionaryRef> defaultTSContext = NULL;
 809      
 810  	// a null signer generates a null signature blob
 811  	if (state.mSigner == SecIdentityRef(kCFNull))
 812  		return CFDataCreate(NULL, NULL, 0);
 813  	
 814  	// generate CMS signature
 815  	CFRef<CMSEncoderRef> cms;
 816  	MacOSError::check(CMSEncoderCreate(&cms.aref()));
 817  	MacOSError::check(CMSEncoderSetCertificateChainMode(cms, kCMSCertificateChainWithRootOrFail));
 818  	CMSEncoderAddSigners(cms, state.mSigner);
 819  	CMSEncoderSetSignerAlgorithm(cms, kCMSEncoderDigestAlgorithmSHA256);
 820  	MacOSError::check(CMSEncoderSetHasDetachedContent(cms, true));
 821  	
 822  	if (emitSigningTime) {
 823  		MacOSError::check(CMSEncoderAddSignedAttributes(cms, kCMSAttrSigningTime));
 824  		CFAbsoluteTime time = signingTime ? signingTime : CFAbsoluteTimeGetCurrent();
 825  		MacOSError::check(CMSEncoderSetSigningTime(cms, time));
 826  	}
 827  	
 828  	if (hashDict != NULL) {
 829  		assert(hashList != NULL);
 830  
 831  		// V2 Hash Agility
 832  
 833  		MacOSError::check(CMSEncoderAddSignedAttributes(cms, kCMSAttrAppleCodesigningHashAgilityV2));
 834  		MacOSError::check(CMSEncoderSetAppleCodesigningHashAgilityV2(cms, hashDict));
 835  
 836  		// V1 Hash Agility
 837  
 838  		CFTemp<CFDictionaryRef> hashDict("{cdhashes=%O}", hashList);
 839  		CFRef<CFDataRef> hashAgilityV1Attribute = makeCFData(hashDict.get());
 840  
 841  		MacOSError::check(CMSEncoderAddSignedAttributes(cms, kCMSAttrAppleCodesigningHashAgility));
 842  		MacOSError::check(CMSEncoderSetAppleCodesigningHashAgility(cms, hashAgilityV1Attribute));
 843  	}
 844  	
 845  	MacOSError::check(CMSEncoderUpdateContent(cms, cd, cd->length()));
 846      
 847      // Set up to call Timestamp server if requested
 848      if (state.mWantTimeStamp)
 849      {
 850          CFRef<CFErrorRef> error = NULL;
 851          defaultTSContext = SecCmsTSAGetDefaultContext(&error.aref());
 852          if (error)
 853              MacOSError::throwMe(errSecDataNotAvailable);
 854              
 855          if (state.mNoTimeStampCerts || state.mTimestampService) {
 856              if (state.mTimestampService)
 857                  CFDictionarySetValue(defaultTSContext, kTSAContextKeyURL, state.mTimestampService);
 858              if (state.mNoTimeStampCerts)
 859                  CFDictionarySetValue(defaultTSContext, kTSAContextKeyNoCerts, kCFBooleanTrue);
 860  		}
 861              
 862  		CmsMessageSetTSAContext(cms, defaultTSContext);
 863      }
 864  	
 865  	CFDataRef signature;
 866  	MacOSError::check(CMSEncoderCopyEncodedContent(cms, &signature));
 867  
 868  	return signature;
 869  }
 870  	
 871  	
 872  //
 873  // Our DiskRep::signingContext methods communicate with the signing subsystem
 874  // in terms those callers can easily understand.
 875  //
 876  string SecCodeSigner::Signer::sdkPath(const std::string &path) const
 877  {
 878  	assert(path[0] == '/');	// need absolute path here
 879  	if (state.mSDKRoot)
 880  		return cfString(state.mSDKRoot) + path;
 881  	else
 882  		return path;
 883  }
 884  
 885  bool SecCodeSigner::Signer::isAdhoc() const
 886  {
 887  	return state.mSigner == SecIdentityRef(kCFNull);
 888  }
 889  
 890  SecCSFlags SecCodeSigner::Signer::signingFlags() const
 891  {
 892  	return state.mOpFlags;
 893  }
 894  
 895  
 896  //
 897  // Parse a text of the form
 898  //	flag,...,flag
 899  // where each flag is the canonical name of a signable CodeDirectory flag.
 900  // No abbreviations are allowed, and internally set flags are not accepted.
 901  //
 902  uint32_t SecCodeSigner::Signer::cdTextFlags(std::string text)
 903  {
 904  	uint32_t flags = 0;
 905  	for (string::size_type comma = text.find(','); ; text = text.substr(comma+1), comma = text.find(',')) {
 906  		string word = (comma == string::npos) ? text : text.substr(0, comma);
 907  		const SecCodeDirectoryFlagTable *item;
 908  		for (item = kSecCodeDirectoryFlagTable; item->name; item++)
 909  			if (item->signable && word == item->name) {
 910  				flags |= item->value;
 911  				break;
 912  			}
 913  		if (!item->name)	// not found
 914  			MacOSError::throwMe(errSecCSInvalidFlags);
 915  		if (comma == string::npos)	// last word
 916  			break;
 917  	}
 918  	return flags;
 919  }
 920  
 921  
 922  //
 923  // Generate a unique string from our underlying DiskRep.
 924  // We could get 90%+ of the uniquing benefit by just generating
 925  // a random string here. Instead, we pick the (hex string encoding of)
 926  // the source rep's unique identifier blob. For universal binaries,
 927  // this is the canonical local architecture, which is a bit arbitrary.
 928  // This provides us with a consistent unique string for all architectures
 929  // of a fat binary, *and* (unlike a random string) is reproducible
 930  // for identical inputs, even upon resigning.
 931  //
 932  std::string SecCodeSigner::Signer::uniqueName() const
 933  {
 934  	CFRef<CFDataRef> identification = rep->identification();
 935  	const UInt8 *ident = CFDataGetBytePtr(identification);
 936  	const CFIndex length = CFDataGetLength(identification);
 937  	string result;
 938  	for (CFIndex n = 0; n < length; n++) {
 939  		char hex[3];
 940  		snprintf(hex, sizeof(hex), "%02x", ident[n]);
 941  		result += hex;
 942  	}
 943  	return result;
 944  }
 945  
 946  bool SecCodeSigner::Signer::booleanEntitlement(CFDictionaryRef entDict, CFStringRef key) {
 947  	CFBooleanRef entValue = (CFBooleanRef)CFDictionaryGetValue(entDict, key);
 948  
 949  	if (entValue == NULL || CFGetTypeID(entValue) != CFBooleanGetTypeID()) {
 950  		return false;
 951  	}
 952  
 953  	return CFBooleanGetValue(entValue);
 954  }
 955  
 956  void SecCodeSigner::Signer::cookEntitlements(CFDataRef entitlements, bool generateDER,
 957  											 uint64_t *execSegFlags, CFDataRef *entitlementDER)
 958  {
 959  	if (!entitlements) {
 960  		return; // nothing to do.
 961  	}
 962  
 963  	EntitlementDERBlob *derBlob = NULL;
 964  
 965  	try {
 966  		const EntitlementBlob *blob = reinterpret_cast<const EntitlementBlob *>(CFDataGetBytePtr(entitlements));
 967  
 968  		if (blob == NULL || !blob->validateBlob(CFDataGetLength(entitlements))) {
 969  			MacOSError::throwMe(errSecCSInvalidEntitlements);
 970  		}
 971  
 972  		CFRef<CFDictionaryRef> entDict = blob->entitlements();
 973  
 974  		if (generateDER) {
 975  			CFRef<CFErrorRef> error = NULL;
 976  			size_t const der_size = der_sizeof_plist(entDict, &error.aref());
 977  
 978  			if (der_size == 0) {
 979  				secerror("Getting DER size for entitlement plist failed: %@", error.get());
 980  				MacOSError::throwMe(errSecCSInvalidEntitlements);
 981  			}
 982  
 983  			derBlob = EntitlementDERBlob::alloc(der_size);
 984  
 985  			if (derBlob == NULL) {
 986  				secerror("Cannot allocate buffer for DER entitlements of size %zu", der_size);
 987  				MacOSError::throwMe(errSecCSInvalidEntitlements);
 988  			}
 989  			uint8_t * const der_end = derBlob->der() + der_size;
 990  			uint8_t * const der_start = der_encode_plist(entDict, &error.aref(), derBlob->der(), der_end);
 991  
 992  			if (der_start != derBlob->der()) {
 993  				secerror("Entitlement DER start mismatch (%zu)", (size_t)(der_start - derBlob->der()));
 994  				free(derBlob);
 995  				MacOSError::throwMe(errSecCSInvalidEntitlements);
 996  			}
 997  
 998  			*entitlementDER = makeCFData(derBlob, derBlob->length());
 999  			free(derBlob);
1000  			derBlob = NULL;
1001  		}
1002  
1003  		if (execSegFlags != NULL) {
1004  			uint64_t flags = 0;
1005  
1006  			flags |= booleanEntitlement(entDict, CFSTR("get-task-allow")) ? kSecCodeExecSegAllowUnsigned : 0;
1007  			flags |= booleanEntitlement(entDict, CFSTR("run-unsigned-code")) ? kSecCodeExecSegAllowUnsigned : 0;
1008  			flags |= booleanEntitlement(entDict, CFSTR("com.apple.private.cs.debugger")) ? kSecCodeExecSegDebugger : 0;
1009  			flags |= booleanEntitlement(entDict, CFSTR("dynamic-codesigning")) ? kSecCodeExecSegJit : 0;
1010  			flags |= booleanEntitlement(entDict, CFSTR("com.apple.private.skip-library-validation")) ? kSecCodeExecSegSkipLibraryVal : 0;
1011  			flags |= booleanEntitlement(entDict, CFSTR("com.apple.private.amfi.can-load-cdhash")) ? kSecCodeExecSegCanLoadCdHash : 0;
1012  			flags |= booleanEntitlement(entDict, CFSTR("com.apple.private.amfi.can-execute-cdhash")) ? kSecCodeExecSegCanExecCdHash : 0;
1013  
1014  			*execSegFlags = flags;
1015  		}
1016  
1017  	} catch (const CommonError &err) {
1018  		free(derBlob);
1019  		// Not fatal if we're not asked to generate DER entitlements.
1020  
1021  		secwarning("failed to parse entitlements: %s", err.what());
1022  		if (generateDER) {
1023  			throw;
1024  		}
1025  	}
1026  }
1027  
1028  //// Signature Editing
1029  	
1030  void SecCodeSigner::Signer::edit(SecCSFlags flags)
1031  {
1032  	rep = code->diskRep()->base();
1033  	
1034  	Universal *fat = state.mNoMachO ? NULL : rep->mainExecutableImage();
1035  	
1036  	prepareForEdit(flags);
1037  	
1038  	if (fat != NULL) {
1039  		editMachO(fat);
1040  	} else {
1041  		editArchitectureAgnostic();
1042  	}
1043  }
1044  
1045  EditableDiskRep *SecCodeSigner::Signer::editMainExecutableRep(DiskRep *rep)
1046  {
1047  	EditableDiskRep *mainExecRep = NULL;
1048  	BundleDiskRep *bundleDiskRep = dynamic_cast<BundleDiskRep*>(rep);
1049  	
1050  	if (bundleDiskRep) {
1051  		mainExecRep = dynamic_cast<EditableDiskRep*>(bundleDiskRep->mainExecRep());
1052  	}
1053  	
1054  	return mainExecRep;
1055  }
1056  	
1057  void SecCodeSigner::Signer::prepareForEdit(SecCSFlags flags) {
1058  	setDigestAlgorithms(code->hashAlgorithms());
1059  	
1060  	Universal *machO = (code->diskRep()->mainExecutableIsMachO() ?
1061  						code->diskRep()->mainExecutableImage() : NULL);
1062  	
1063  	/* We need at least one architecture in all cases because we index our
1064  	 * RawComponentMaps by architecture. However, only machOs have any
1065  	 * architecture at all, for generic targets there will just be one
1066  	 * RawComponentMap.
1067  	 * So if the main executable is not a machO, we just choose the local
1068  	 * (signer's) main architecture as dummy value for the first element in our pair. */
1069  	editMainArch = (machO != NULL ? machO->bestNativeArch() : Architecture::local());
1070  
1071  	if (machO != NULL) {
1072  		if (machO->narrowed()) {
1073  			/* --arch gives us a narrowed SecStaticCode, but because
1074  			 * codesign_allocate always creates or replaces signatures
1075  			 * for all slices, we must operate on the universal
1076  			 * SecStaticCode. Instead, we provide --edit-arch to specify
1077  			 * which slices to edit, the others have their code signature
1078  			 * copied without modifications.
1079  			 */
1080  			MacOSError::throwMe(errSecCSNotSupported,
1081  								"Signature editing must be performed on universal binary instead of narrow slice (using --edit-arch instead of --arch).");
1082  		}
1083  
1084  		if (state.mEditArch && !machO->isUniversal()) {
1085  			MacOSError::throwMe(errSecCSInvalidFlags,
1086  								"--edit-arch is only valid for universal binaries.");
1087  		}
1088  		
1089  		if (state.mEditCMS && machO->isUniversal() && !state.mEditArch) {
1090  			/* Each slice has its own distinct code signature,
1091  			 * so a CMS blob is only valid for its one slice.
1092  			 * Therefore, replacing all CMS blobs in all slices
1093  			 * with the same blob is rather nonsensical, and we refuse.
1094  			 *
1095  			 * (Universal binaries with only one slice can exist,
1096  			 * and in that case the slice to operate on would be
1097  			 * umambiguous, but we are not treating those binaries
1098  			 * specially and still want --edit-arch for consistency.)
1099  			 */
1100  			MacOSError::throwMe(errSecCSNotSupported,
1101  								"CMS editing must be performed on specific slice (specified with --edit-arch).");
1102  		}
1103  	}
1104  	
1105  	void (^editArch)(SecStaticCode *code, Architecture arch) =
1106  	^(SecStaticCode *code, Architecture arch) {
1107  		EditableDiskRep *editRep = dynamic_cast<EditableDiskRep *>(code->diskRep());
1108  		
1109  		if (editRep == NULL) {
1110  			MacOSError::throwMe(errSecCSNotSupported,
1111  								"Signature editing not supported for code of this type.");
1112  		}
1113  		
1114  		EditableDiskRep *mainExecRep = editMainExecutableRep(code->diskRep());
1115  		
1116  		if (mainExecRep != NULL) {
1117  			// Delegate editing to the main executable if it is an EditableDiskRep.
1118  			//(Which is the case for machOs.)
1119  			editRep = mainExecRep;
1120  		}
1121  
1122  		editComponents[arch] = std::make_unique<RawComponentMap>(editRep->createRawComponents());
1123  		
1124  		if (!state.mEditArch || arch == state.mEditArch) {
1125  			if (state.mEditCMS) {
1126  				CFDataRef cms = state.mEditCMS.get();
1127  				(*editComponents[arch])[cdSignatureSlot] = cms;
1128  			}
1129  		}
1130  	};
1131  	
1132  	editArch(code, editMainArch);
1133  	
1134  	code->handleOtherArchitectures(^(Security::CodeSigning::SecStaticCode *subcode) {
1135  		Universal *fat = subcode->diskRep()->mainExecutableImage();
1136  		assert(fat && fat->narrowed());	// handleOtherArchitectures gave us a focused architecture slice.
1137  		Architecture arch = fat->bestNativeArch();	// actually, only architecture for this slice.
1138  		editArch(subcode, arch);
1139  	});
1140  	
1141  	/* The resource dictionary is special, because it is
1142  	 * considered "global" instead of per architecture.
1143  	 * For editing, that means it's usually not embedded
1144  	 * in the main executable's signature if it exists,
1145  	 * but in the containing disk rep (e.g. the
1146  	 * CodeResources file if the rep is a Bundle).
1147  	 */
1148  	resourceDictData = rep->component(cdResourceDirSlot);
1149  }
1150  	
1151  void SecCodeSigner::Signer::editMachO(Universal *fat) {
1152  	// Mach-O executable at the core - perform multi-architecture signature editing
1153  	RefPointer<DiskRep::Writer> writer = rep->writer();
1154  	
1155  	if (state.mPreserveAFSC)
1156  		writer->setPreserveAFSC(state.mPreserveAFSC);
1157  	
1158  	unique_ptr<ArchEditor> editor(new MachOEditor(writer, *fat,
1159  												  this->digestAlgorithms(),
1160  												  rep->mainExecutablePath()));
1161  	assert(editor->count() > 0);
1162  	
1163  	if (resourceDictData && !editor->attribute(writerNoGlobal)) {
1164  		// For when the resource dict is "global", e.g. for bundles.
1165  		editor->component(cdResourceDirSlot, resourceDictData);
1166  	}
1167  	
1168  	for (MachOEditor::Iterator it = editor->begin(); it != editor->end(); ++it) {
1169  		MachOEditor::Arch &arch = *it->second;
1170  		arch.source.reset(fat->architecture(it->first)); // transfer ownership
1171  		
1172  		if (resourceDictData && editor->attribute(writerNoGlobal)) {
1173  			// Technically possible to embed a resource dict in the embedded sig.
1174  			arch.component(cdResourceDirSlot, resourceDictData);
1175  		}
1176  		
1177  		for (auto const &entry : *editComponents[arch.architecture]) {
1178  			CodeDirectory::Slot slot = entry.first;
1179  			CFDataRef data = entry.second.get();
1180  			arch.component(slot, data);
1181  		}
1182  		
1183  		/* We must preserve the original superblob's size, as the size is
1184  		 * also in the macho's load commands, which are itself covered
1185  		 * by the signature. */
1186  		arch.blobSize = arch.source->signingLength();
1187  	}
1188  	
1189  	editor->allocate();
1190  	
1191  	for (MachOEditor::Iterator it = editor->begin(); it != editor->end(); ++it) {
1192  		MachOEditor::Arch &arch = *it->second;
1193  		editor->reset(arch);
1194  		
1195  		if (!state.mDryRun) {
1196  			EmbeddedSignatureBlob *blob = arch.make();
1197  			editor->write(arch, blob);	// takes ownership of blob
1198  		}
1199  	}
1200  	
1201  	if (!state.mDryRun) {
1202  		editor->commit();
1203  	}
1204  
1205  }
1206  
1207  void SecCodeSigner::Signer::editArchitectureAgnostic()
1208  {
1209  	if (state.mDryRun) {
1210  		return;
1211  
1212  	}
1213  	// non-Mach-O executable - single-instance signature editing
1214  	RefPointer<DiskRep::Writer> writer = rep->writer();
1215  	
1216  	if(state.mPreserveAFSC)
1217  		writer->setPreserveAFSC(state.mPreserveAFSC);
1218  	
1219  	for (auto const &entry : *editComponents[editMainArch]) {
1220  		CodeDirectory::Slot slot = entry.first;
1221  		CFDataRef data = entry.second.get();
1222  		
1223  		writer->component(slot, data);
1224  	}
1225  
1226  	// commit to storage
1227  	writer->flush();
1228  }
1229  
1230  } // end namespace CodeSigning
1231  } // end namespace Security