2  * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   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 
  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. 
  21  * @APPLE_LICENSE_HEADER_END@ 
  25 // signer - Signing operation supervisor and controller 
  28 #include "resources.h" 
  29 #include "signerutils.h" 
  30 #include "SecCodeSigner.h" 
  31 #include <Security/SecIdentity.h> 
  32 #include <Security/CMSEncoder.h> 
  33 #include <Security/CMSPrivate.h> 
  34 #include <Security/CSCommonPriv.h> 
  35 #include <CoreFoundation/CFBundlePriv.h> 
  36 #include "resources.h" 
  38 #include "reqparser.h" 
  39 #include "reqdumper.h" 
  40 #include "csutilities.h" 
  41 #include <security_utilities/unix++.h> 
  42 #include <security_utilities/unixchild.h> 
  43 #include <security_utilities/cfmunge.h> 
  44 #include <security_utilities/dispatch.h> 
  45 #include <IOKit/storage/IOStorageDeviceCharacteristics.h> 
  48 namespace CodeSigning 
{ 
  54 void SecCodeSigner::Signer::sign(SecCSFlags flags
) 
  56         rep 
= code
->diskRep()->base(); 
  59         PreSigningContext 
context(*this); 
  61         considerTeamID(context
); 
  63         if (Universal 
*fat 
= state
.mNoMachO 
? NULL 
: rep
->mainExecutableImage()) { 
  64                 signMachO(fat
, context
); 
  66                 signArchitectureAgnostic(context
); 
  71 void SecCodeSigner::Signer::considerTeamID(const PreSigningContext
& context
) 
  73         /* If an explicit teamID was passed in it must be 
  74          the same as what came from the cert */ 
  75         std::string teamIDFromCert 
= state
.getTeamIDFromSigner(context
.certs
); 
  77         if (state
.mPreserveMetadata 
& kSecCodeSignerPreserveTeamIdentifier
) { 
  78                 /* If preserving the team identifier, teamID is set previously when the 
  79                  code object is still available */ 
  80                 if (!teamIDFromCert
.empty() && teamID 
!= teamIDFromCert
) 
  81                         MacOSError::throwMe(errSecCSInvalidFlags
); 
  83                 if (teamIDFromCert
.empty()) { 
  84                         /* state.mTeamID is an explicitly passed teamID */ 
  85                         teamID 
= state
.mTeamID
; 
  86                 } else if (state
.mTeamID
.empty() || (state
.mTeamID 
== teamIDFromCert
)) { 
  87                         /* If there was no explicit team ID set, or the explicit team ID matches 
  88                          what is in the cert, use the team ID from the certificate */ 
  89                         teamID 
= teamIDFromCert
; 
  91                         /* The caller passed in an explicit team ID that does not match what is 
  92                          in the signing cert, which is an invalid usage */ 
  93                         MacOSError::throwMe(errSecCSInvalidFlags
); 
 100 // Remove any existing code signature from code 
 102 void SecCodeSigner::Signer::remove(SecCSFlags flags
) 
 104         // can't remove a detached signature 
 106                 MacOSError::throwMe(errSecCSNotSupported
); 
 108         rep 
= code
->diskRep(); 
 109         if (Universal 
*fat 
= state
.mNoMachO 
? NULL 
: rep
->mainExecutableImage()) { 
 110                 // architecture-sensitive removal 
 111                 MachOEditor 
editor(rep
->writer(), *fat
, digestAlgorithms(), rep
->mainExecutablePath()); 
 112                 editor
.allocate();              // create copy 
 113                 editor
.commit();                // commit change 
 115                 // architecture-agnostic removal 
 116                 RefPointer
<DiskRep::Writer
> writer 
= rep
->writer(); 
 124 // Contemplate the object-to-be-signed and set up the Signer state accordingly. 
 126 void SecCodeSigner::Signer::prepare(SecCSFlags flags
) 
 128         // make sure the rep passes strict validation 
 130                 rep
->strictValidate(NULL
, MacOSErrorSet(), flags 
| (kSecCSQuickCheck
|kSecCSRestrictSidebandData
)); 
 132         // initialize progress/cancellation state 
 133         code
->prepareProgress(0);                       // totally fake workload - we don't know how many files we'll encounter 
 135         // get the Info.plist out of the rep for some creative defaulting 
 136         CFRef
<CFDictionaryRef
> infoDict
; 
 137         if (CFRef
<CFDataRef
> infoData 
= rep
->component(cdInfoSlot
)) 
 138                 infoDict
.take(makeCFDictionaryFrom(infoData
)); 
 140         uint32_t inherit 
= code
->isSigned() ? state
.mPreserveMetadata 
: 0; 
 142         // work out the canonical identifier 
 143         identifier 
= state
.mIdentifier
; 
 144         if (identifier
.empty() && (inherit 
& kSecCodeSignerPreserveIdentifier
)) 
 145                 identifier 
= code
->identifier(); 
 146         if (identifier
.empty()) { 
 147                 identifier 
= rep
->recommendedIdentifier(*this); 
 148                 if (identifier
.find('.') == string::npos
) 
 149                         identifier 
= state
.mIdentifierPrefix 
+ identifier
; 
 150                 if (identifier
.find('.') == string::npos 
&& isAdhoc()) 
 151                         identifier 
= identifier 
+ "-" + uniqueName(); 
 152                 secinfo("signer", "using default identifier=%s", identifier
.c_str()); 
 154                 secinfo("signer", "using explicit identifier=%s", identifier
.c_str()); 
 156         teamID 
= state
.mTeamID
; 
 157         if (teamID
.empty() && (inherit 
& kSecCodeSignerPreserveTeamIdentifier
)) { 
 158                 const char *c_id 
= code
->teamID(); 
 163         // Digest algorithms: explicit or preserved. Subject to diskRep defaults or final default later. 
 164         hashAlgorithms 
= state
.mDigestAlgorithms
; 
 165         if (hashAlgorithms
.empty() && (inherit 
& kSecCodeSignerPreserveDigestAlgorithm
)) 
 166                 hashAlgorithms 
= code
->hashAlgorithms(); 
 168         entitlements 
= state
.mEntitlementData
; 
 169         if (!entitlements 
&& (inherit 
& kSecCodeSignerPreserveEntitlements
)) 
 170                 entitlements 
= code
->component(cdEntitlementSlot
); 
 172         // work out the CodeDirectory flags word 
 173         bool haveCdFlags 
= false; 
 174         if (!haveCdFlags 
&& state
.mCdFlagsGiven
) { 
 175                 cdFlags 
= state
.mCdFlags
; 
 176                 secinfo("signer", "using explicit cdFlags=0x%x", cdFlags
); 
 182                         if (CFTypeRef csflags 
= CFDictionaryGetValue(infoDict
, CFSTR("CSFlags"))) { 
 183                                 if (CFGetTypeID(csflags
) == CFNumberGetTypeID()) { 
 184                                         cdFlags 
= cfNumber
<uint32_t>(CFNumberRef(csflags
)); 
 185                                         secinfo("signer", "using numeric cdFlags=0x%x from Info.plist", cdFlags
); 
 186                                 } else if (CFGetTypeID(csflags
) == CFStringGetTypeID()) { 
 187                                         cdFlags 
= cdTextFlags(cfString(CFStringRef(csflags
))); 
 188                                         secinfo("signer", "using text cdFlags=0x%x from Info.plist", cdFlags
); 
 190                                         MacOSError::throwMe(errSecCSBadDictionaryFormat
); 
 194         if (!haveCdFlags 
&& (inherit 
& kSecCodeSignerPreserveFlags
)) { 
 195                 cdFlags 
= code
->codeDirectory(false)->flags 
& ~kSecCodeSignatureAdhoc
; 
 196                 secinfo("signer", "using inherited cdFlags=0x%x", cdFlags
); 
 201         if (state
.mSigner 
== SecIdentityRef(kCFNull
))   // ad-hoc signing requested... 
 202                 cdFlags 
|= kSecCodeSignatureAdhoc
;      // ... so note that 
 204         // prepare the internal requirements input 
 205         if (state
.mRequirements
) { 
 206                 if (CFGetTypeID(state
.mRequirements
) == CFDataGetTypeID()) {            // binary form 
 207                         const Requirements 
*rp 
= (const Requirements 
*)CFDataGetBytePtr(state
.mRequirements
.as
<CFDataRef
>()); 
 208                         if (!rp
->validateBlob()) 
 209                                 MacOSError::throwMe(errSecCSReqInvalid
); 
 210                         requirements 
= rp
->clone(); 
 211                 } else if (CFGetTypeID(state
.mRequirements
) == CFStringGetTypeID()) { // text form 
 212                         CFRef
<CFMutableStringRef
> reqText 
= CFStringCreateMutableCopy(NULL
, 0, state
.mRequirements
.as
<CFStringRef
>()); 
 213                         // substitute $ variable tokens 
 214                         CFRange range 
= { 0, CFStringGetLength(reqText
) }; 
 215                         CFStringFindAndReplace(reqText
, CFSTR("$self.identifier"), CFTempString(identifier
), range
, 0); 
 216                         requirements 
= parseRequirements(cfString(reqText
)); 
 218                         MacOSError::throwMe(errSecCSInvalidObjectRef
); 
 219         } else if (inherit 
& kSecCodeSignerPreserveRequirements
) 
 220                 if (const Requirements 
*rp 
= code
->internalRequirements()) 
 221                         requirements 
= rp
->clone(); 
 223         // prepare the resource directory, if any 
 224         string rpath 
= rep
->resourcesRootPath(); 
 226         CFCopyRef
<CFDictionaryRef
> resourceRules
; 
 227         if (!rpath
.empty()) { 
 228                 // explicitly given resource rules always win 
 229                 resourceRules 
= state
.mResourceRules
; 
 231                 // inherited rules come next (overriding embedded ones!) 
 232                 if (!resourceRules 
&& (inherit 
& kSecCodeSignerPreserveResourceRules
)) 
 233                         if (CFDictionaryRef oldRules 
= code
->resourceDictionary(false)) 
 234                                 resourceRules 
= oldRules
; 
 236                 // embedded resource rules come next 
 237                 if (!resourceRules 
&& infoDict
) 
 238                         if (CFTypeRef spec 
= CFDictionaryGetValue(infoDict
, _kCFBundleResourceSpecificationKey
)) { 
 239                                 if (CFGetTypeID(spec
) == CFStringGetTypeID()) 
 240                                         if (CFRef
<CFDataRef
> data 
= cfLoadFile(rpath 
+ "/" + cfString(CFStringRef(spec
)))) 
 241                                                 if (CFDictionaryRef dict 
= makeCFDictionaryFrom(data
)) 
 242                                                         resourceRules
.take(dict
); 
 243                                 if (!resourceRules
)     // embedded rules present but unacceptable 
 244                                         MacOSError::throwMe(errSecCSResourceRulesInvalid
); 
 247                 // if we got one from anywhere (but the defaults), sanity-check it 
 249                         CFTypeRef rules 
= CFDictionaryGetValue(resourceRules
, CFSTR("rules")); 
 250                         if (!rules 
|| CFGetTypeID(rules
) != CFDictionaryGetTypeID()) 
 251                                 MacOSError::throwMe(errSecCSResourceRulesInvalid
); 
 254                 // finally, ask the DiskRep for its default 
 256                         resourceRules
.take(rep
->defaultResourceRules(*this)); 
 258                 // resource root can optionally be the canonical bundle path, 
 259                 // but sealed resource paths are always relative to rpath 
 261                 if (signingFlags() & kSecCSSignBundleRoot
) 
 262                         rrpath 
= cfStringRelease(rep
->copyCanonicalPath()); 
 265         // screen and set the signing time 
 266         if (state
.mSigningTime 
== CFDateRef(kCFNull
)) { 
 267                 emitSigningTime 
= false;                // no time at all 
 268         } else if (!state
.mSigningTime
) { 
 269                 emitSigningTime 
= true; 
 270                 signingTime 
= 0;                        // wall clock, established later 
 272                 CFAbsoluteTime time 
= CFDateGetAbsoluteTime(state
.mSigningTime
); 
 273                 if (time 
> CFAbsoluteTimeGetCurrent())  // not allowed to post-date a signature 
 274                         MacOSError::throwMe(errSecCSBadDictionaryFormat
); 
 275                 emitSigningTime 
= true; 
 279         pagesize 
= state
.mPageSize 
? cfNumber
<size_t>(state
.mPageSize
) : rep
->pageSize(*this); 
 281         // Allow the DiskRep to modify the signing parameters. This sees explicit and inherited values but not defaults. 
 282         rep
->prepareForSigning(*this); 
 284         // apply some defaults after diskRep intervention 
 285         if (hashAlgorithms
.empty()) {   // default to SHA256 + SHA-1 
 286                 hashAlgorithms
.insert(kSecCodeSignatureHashSHA1
); 
 287                 hashAlgorithms
.insert(kSecCodeSignatureHashSHA256
); 
 290         // build the resource directory (once and for all, using the digests determined above) 
 291         if (!rpath
.empty()) { 
 292                 buildResources(rrpath
, rpath
, resourceRules
); 
 298 // Collect the resource seal for a program. 
 299 // This includes both sealed resources and information about nested code. 
 301 void SecCodeSigner::Signer::buildResources(std::string root
, std::string relBase
, CFDictionaryRef rulesDict
) 
 303         typedef ResourceBuilder::Rule Rule
; 
 305         secinfo("codesign", "start building resource directory"); 
 306         __block CFRef
<CFMutableDictionaryRef
> result 
= makeCFMutableDictionary(); 
 308         CFDictionaryRef rules 
= cfget
<CFDictionaryRef
>(rulesDict
, "rules"); 
 311         if (this->state
.mLimitedAsync 
== NULL
) { 
 312                 this->state
.mLimitedAsync 
= 
 313                         /* rdar://problem/20299541: Async workers (i.e. parallelization) are currently 
 314                          * turned off, because the paths for signing code are not ready for it yet. */ 
 315                         // new LimitedAsync(rep->fd().mediumType() == kIOPropertyMediumTypeSolidStateKey); 
 316                         new LimitedAsync(false); 
 319         CFDictionaryRef files2 
= NULL
; 
 320         if (!(signingFlags() & kSecCSSignV1
)) { 
 321                 CFCopyRef
<CFDictionaryRef
> rules2 
= cfget
<CFDictionaryRef
>(rulesDict
, "rules2"); 
 323                         // Clone V1 rules and add default nesting rules at weight 0 (overridden by anything in rules). 
 324                         // V1 rules typically do not cover these places so we'll prevail, but if they do, we defer to them. 
 325                         rules2 
= cfmake
<CFDictionaryRef
>("{+%O" 
 326                                 "'^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/' = {nested=#T, weight=0}" // exclude dynamic repositories 
 330                 Dispatch::Group group
; 
 331                 Dispatch::Group 
&groupRef 
= group
;  // (into block) 
 333                 // build the modern (V2) resource seal 
 334                 __block CFRef
<CFMutableDictionaryRef
> files 
= makeCFMutableDictionary(); 
 335                 CFMutableDictionaryRef filesRef 
= files
.get();  // (into block) 
 336                 ResourceBuilder 
resourceBuilder(root
, relBase
, rules2
, strict
, MacOSErrorSet()); 
 337                 ResourceBuilder 
&resources 
= resourceBuilder
;   // (into block) 
 338                 rep
->adjustResources(resources
); 
 340                 resources
.scan(^(FTSENT 
*ent
, uint32_t ruleFlags
, const std::string relpath
, Rule 
*rule
) { 
 341                         bool isSymlink 
= (ent
->fts_info 
== FTS_SL
); 
 342                         const std::string 
path(ent
->fts_path
); 
 343                         const std::string 
accpath(ent
->fts_accpath
); 
 344                         this->state
.mLimitedAsync
->perform(groupRef
, ^{ 
 345                                 CFRef
<CFMutableDictionaryRef
> seal
; 
 346                                 if (ruleFlags 
& ResourceBuilder::nested
) { 
 347                                         seal
.take(signNested(path
, relpath
)); 
 348                                 } else if (isSymlink
) { 
 349                                         char target
[PATH_MAX
]; 
 350                                         ssize_t len 
= ::readlink(accpath
.c_str(), target
, sizeof(target
)-1); 
 352                                                 UnixError::check(-1); 
 354                                         seal
.take(cfmake
<CFMutableDictionaryRef
>("{symlink=%s}", target
)); 
 356                                         seal
.take(resources
.hashFile(accpath
.c_str(), digestAlgorithms(), signingFlags() & kSecCSSignStrictPreflight
)); 
 358                                 if (ruleFlags 
& ResourceBuilder::optional
) 
 359                                         CFDictionaryAddValue(seal
, CFSTR("optional"), kCFBooleanTrue
); 
 361                                 StLock
<Mutex
> _(resourceLock
); 
 362                                 if ((hash 
= CFDictionaryGetValue(seal
, CFSTR("hash"))) && CFDictionaryGetCount(seal
) == 1) // simple form 
 363                                         CFDictionaryAddValue(filesRef
, CFTempString(relpath
).get(), hash
); 
 365                                         CFDictionaryAddValue(filesRef
, CFTempString(relpath
).get(), seal
.get()); 
 366                                 code
->reportProgress(); 
 370                 CFDictionaryAddValue(result
, CFSTR("rules2"), resourceBuilder
.rules()); 
 372                 CFDictionaryAddValue(result
, CFSTR("files2"), files2
); 
 375         CFDictionaryAddValue(result
, CFSTR("rules"), rules
);    // preserve V1 rules in any case 
 376         if (!(signingFlags() & kSecCSSignNoV1
)) { 
 377                 // build the legacy (V1) resource seal 
 378                 __block CFRef
<CFMutableDictionaryRef
> files 
= makeCFMutableDictionary(); 
 379                 ResourceBuilder 
resourceBuilder(root
, relBase
, rules
, strict
, MacOSErrorSet()); 
 380                 ResourceBuilder 
&resources 
= resourceBuilder
; 
 381                 rep
->adjustResources(resources
);        // DiskRep-specific adjustments 
 382                 resources
.scan(^(FTSENT 
*ent
, uint32_t ruleFlags
, std::string relpath
, Rule 
*rule
) { 
 383                         if (ent
->fts_info 
== FTS_F
) { 
 384                                 CFRef
<CFDataRef
> hash
; 
 385                                 if (files2
)     // try to get the hash from a previously-made version 
 386                                         if (CFTypeRef seal 
= CFDictionaryGetValue(files2
, CFTempString(relpath
))) { 
 387                                                 if (CFGetTypeID(seal
) == CFDataGetTypeID()) 
 388                                                         hash 
= CFDataRef(seal
); 
 390                                                         hash 
= CFDataRef(CFDictionaryGetValue(CFDictionaryRef(seal
), CFSTR("hash"))); 
 393                                         hash
.take(resources
.hashFile(ent
->fts_accpath
, kSecCodeSignatureHashSHA1
)); 
 394                                 if (ruleFlags 
== 0) {   // default case - plain hash 
 395                                         cfadd(files
, "{%s=%O}", relpath
.c_str(), hash
.get()); 
 396                                         secinfo("csresource", "%s added simple (rule %p)", relpath
.c_str(), rule
); 
 397                                 } else {        // more complicated - use a sub-dictionary 
 398                                         cfadd(files
, "{%s={hash=%O,optional=%B}}", 
 399                                                 relpath
.c_str(), hash
.get(), ruleFlags 
& ResourceBuilder::optional
); 
 400                                         secinfo("csresource", "%s added complex (rule %p)", relpath
.c_str(), rule
); 
 404                 CFDictionaryAddValue(result
, CFSTR("files"), files
.get()); 
 407         resourceDirectory 
= result
.get(); 
 408         resourceDictData
.take(makeCFData(resourceDirectory
.get())); 
 413 // Deal with one piece of nested code 
 415 CFMutableDictionaryRef 
SecCodeSigner::Signer::signNested(const std::string 
&path
, const std::string 
&relpath
) 
 417         // sign nested code and collect nesting information 
 419                 SecPointer
<SecStaticCode
> code 
= new SecStaticCode(DiskRep::bestGuess(path
)); 
 420                 if (signingFlags() & kSecCSSignNestedCode
) 
 421                         this->state
.sign(code
, signingFlags()); 
 422                 std::string dr 
= Dumper::dump(code
->designatedRequirement()); 
 423                 if (CFDataRef hash 
= code
->cdHash()) 
 424                         return cfmake
<CFMutableDictionaryRef
>("{requirement=%s,cdhash=%O}", 
 425                                 Dumper::dump(code
->designatedRequirement()).c_str(), 
 427                 MacOSError::throwMe(errSecCSUnsigned
); 
 428         } catch (const CommonError 
&err
) { 
 429                 CSError::throwMe(err
.osStatus(), kSecCFErrorPath
, CFTempURL(relpath
, false, this->code
->resourceBase())); 
 435 // Sign a Mach-O binary, using liberal dollops of that special Mach-O magic sauce. 
 436 // Note that this will deal just fine with non-fat Mach-O binaries, but it will 
 437 // treat them as architectural binaries containing (only) one architecture - that 
 438 // interpretation is courtesy of the Universal/MachO support classes. 
 440 void SecCodeSigner::Signer::signMachO(Universal 
*fat
, const Requirement::Context 
&context
) 
 442         // Mach-O executable at the core - perform multi-architecture signing 
 443         RefPointer
<DiskRep::Writer
> writer 
= rep
->writer(); 
 444         auto_ptr
<ArchEditor
> editor(state
.mDetached
 
 445                 ? static_cast<ArchEditor 
*>(new BlobEditor(*fat
, *this)) 
 446                 : new MachOEditor(writer
, *fat
, this->digestAlgorithms(), rep
->mainExecutablePath())); 
 447         assert(editor
->count() > 0); 
 448         if (!editor
->attribute(writerNoGlobal
)) // can store architecture-common components 
 451         // pass 1: prepare signature blobs and calculate sizes 
 452         for (MachOEditor::Iterator it 
= editor
->begin(); it 
!= editor
->end(); ++it
) { 
 453                 MachOEditor::Arch 
&arch 
= *it
->second
; 
 454                 arch
.source
.reset(fat
->architecture(it
->first
)); 
 456                 // library validation is not compatible with i386 
 457                 if (arch
.architecture
.cpuType() == CPU_TYPE_I386
) { 
 458                         if (cdFlags 
& kSecCodeSignatureLibraryValidation
) { 
 459                                 MacOSError::throwMe(errSecCSBadLVArch
); 
 463                 arch
.ireqs(requirements
, rep
->defaultRequirements(&arch
.architecture
, *this), context
); 
 464                 if (editor
->attribute(writerNoGlobal
))  // can't store globally, add per-arch 
 466                 for (auto type 
= digestAlgorithms().begin(); type 
!= digestAlgorithms().end(); ++type
) { 
 467                         arch
.eachDigest(^(CodeDirectory::Builder
& builder
) { 
 468                                 populate(builder
, arch
, arch
.ireqs
, 
 469                                                  arch
.source
->offset(), arch
.source
->signingExtent(), unsigned(digestAlgorithms().size()-1)); 
 473                 // add identification blob (made from this architecture) only if we're making a detached signature 
 474                 if (state
.mDetached
) { 
 475                         CFRef
<CFDataRef
> identification 
= MachORep::identificationFor(arch
.source
.get()); 
 476                         arch
.add(cdIdentificationSlot
, BlobWrapper::alloc( 
 477                                 CFDataGetBytePtr(identification
), CFDataGetLength(identification
))); 
 480                 // prepare SuperBlob size estimate 
 481                 __block 
std::vector
<size_t> sizes
; 
 482                 arch
.eachDigest(^(CodeDirectory::Builder
& builder
){ 
 483                         sizes
.push_back(builder
.size(CodeDirectory::currentVersion
)); 
 485                 arch
.blobSize 
= arch
.size(sizes
, state
.mCMSSize
, 0); 
 490         // pass 2: Finish and generate signatures, and write them 
 491         for (MachOEditor::Iterator it 
= editor
->begin(); it 
!= editor
->end(); ++it
) { 
 492                 MachOEditor::Arch 
&arch 
= *it
->second
; 
 495                 // finish CodeDirectories (off new binary) and sign it 
 496                 __block CodeDirectorySet cdSet
; 
 497                 arch
.eachDigest(^(CodeDirectory::Builder 
&builder
) { 
 498                         CodeDirectory 
*cd 
= builder
.build(); 
 501                 CFRef
<CFArrayRef
> hashes 
= cdSet
.hashBag(); 
 502                 CFTemp
<CFDictionaryRef
> hashDict("{cdhashes=%O}", hashes
.get()); 
 503                 CFRef
<CFDataRef
> hashBag 
= makeCFData(hashDict
.get()); 
 504                 CFRef
<CFDataRef
> signature 
= signCodeDirectory(cdSet
.primary(), hashBag
); 
 506                 // complete the SuperBlob 
 507                 cdSet
.populate(&arch
); 
 508                 arch
.add(cdSignatureSlot
, BlobWrapper::alloc( 
 509                         CFDataGetBytePtr(signature
), CFDataGetLength(signature
))); 
 510                 if (!state
.mDryRun
) { 
 511                         EmbeddedSignatureBlob 
*blob 
= arch
.make(); 
 512                         editor
->write(arch
, blob
);      // takes ownership of blob 
 516         // done: write edit copy back over the original 
 517         if (!state
.mDryRun
) { 
 524 // Sign a binary that has no notion of architecture. 
 525 // That currently means anything that isn't Mach-O format. 
 527 void SecCodeSigner::Signer::signArchitectureAgnostic(const Requirement::Context 
&context
) 
 529         // non-Mach-O executable - single-instance signing 
 530         RefPointer
<DiskRep::Writer
> writer 
= state
.mDetached 
? 
 531                 (new DetachedBlobWriter(*this)) : rep
->writer(); 
 533         CodeDirectorySet cdSet
; 
 534         for (auto type 
= digestAlgorithms().begin(); type 
!= digestAlgorithms().end(); ++type
) { 
 535                 CodeDirectory::Builder 
builder(*type
); 
 536                 InternalRequirements ireqs
; 
 537                 ireqs(requirements
, rep
->defaultRequirements(NULL
, *this), context
); 
 539                 populate(builder
, *writer
, ireqs
, rep
->signingBase(), rep
->signingLimit(), unsigned(digestAlgorithms().size()-1)); 
 541                 CodeDirectory 
*cd 
= builder
.build(); 
 546         // add identification blob (made from this architecture) only if we're making a detached signature 
 547         if (state
.mDetached
) { 
 548                 CFRef
<CFDataRef
> identification 
= rep
->identification(); 
 549                 writer
->component(cdIdentificationSlot
, identification
); 
 552         // write out all CodeDirectories 
 554                 cdSet
.populate(writer
); 
 556         CFRef
<CFArrayRef
> hashes 
= cdSet
.hashBag(); 
 557         CFTemp
<CFDictionaryRef
> hashDict("{cdhashes=%O}", hashes
.get()); 
 558         CFRef
<CFDataRef
> hashBag 
= makeCFData(hashDict
.get()); 
 559         CFRef
<CFDataRef
> signature 
= signCodeDirectory(cdSet
.primary(), hashBag
); 
 560         writer
->signature(signature
); 
 568 // Global populate - send components to destination buffers ONCE 
 570 void SecCodeSigner::Signer::populate(DiskRep::Writer 
&writer
) 
 572         if (resourceDirectory 
&& !state
.mDryRun
) 
 573                 writer
.component(cdResourceDirSlot
, resourceDictData
); 
 578 // Per-architecture populate - send components to per-architecture buffers 
 579 // and populate the CodeDirectory for an architecture. In architecture-agnostic 
 580 // signing operations, the non-architectural binary is considered one (arbitrary) architecture 
 581 // for the purposes of this call. 
 583 void SecCodeSigner::Signer::populate(CodeDirectory::Builder 
&builder
, DiskRep::Writer 
&writer
, 
 584         InternalRequirements 
&ireqs
, size_t offset
, size_t length
, unsigned alternateDigestCount
) 
 586         // fill the CodeDirectory 
 587         builder
.executable(rep
->mainExecutablePath(), pagesize
, offset
, length
); 
 588         builder
.flags(cdFlags
); 
 589         builder
.identifier(identifier
); 
 590         builder
.teamID(teamID
); 
 591         builder
.platform(state
.mPlatform
); 
 593         if (CFRef
<CFDataRef
> data 
= rep
->component(cdInfoSlot
)) 
 594                 builder
.specialSlot(cdInfoSlot
, data
); 
 596                 CFRef
<CFDataRef
> data 
= makeCFData(*ireqs
); 
 597                 writer
.component(cdRequirementsSlot
, data
); 
 598                 builder
.specialSlot(cdRequirementsSlot
, data
); 
 600         if (resourceDirectory
) 
 601                 builder
.specialSlot(cdResourceDirSlot
, resourceDictData
); 
 603                 writer
.component(cdEntitlementSlot
, entitlements
); 
 604                 builder
.specialSlot(cdEntitlementSlot
, entitlements
); 
 606         if (CFRef
<CFDataRef
> repSpecific 
= rep
->component(cdRepSpecificSlot
)) 
 607                 builder
.specialSlot(cdRepSpecificSlot
, repSpecific
); 
 609         writer
.addDiscretionary(builder
); 
 611 #if 0 // rdar://problem/25720754 
 612         if ((signingFlags() & (kSecCSSignOpaque
|kSecCSSignV1
)) == 0 && builder
.hashType() != kSecCodeSignatureHashSHA1
) { 
 613                 // calculate sorted list of top SuperBlob keys in this EmbeddedSignatureBlob (if any) 
 614                 // (but not for opaque or V1 construction, which must remain bit-for-bit compatible) 
 615                 std::vector
<Endian
<uint32_t> > slotVector
; 
 616                 slotVector
.push_back(cdCodeDirectorySlot
);      // mandatory 
 617                 std::set
<CodeDirectory::Slot
> filledSlots 
= builder
.filledSpecialSlots(); 
 618                 filledSlots
.insert(cdTopDirectorySlot
);         // will be added below 
 619                 copy(filledSlots
.begin(), filledSlots
.end(), back_inserter(slotVector
)); 
 620                 for (unsigned n 
= 0; n 
< alternateDigestCount
; n
++) 
 621                         slotVector
.push_back(cdAlternateCodeDirectorySlots 
+ n
); 
 622                 slotVector
.push_back(cdSignatureSlot
); 
 623                 CFTempData 
cfSlotVector(&slotVector
[0], slotVector
.size() * sizeof(slotVector
[0])); 
 624                 writer
.component(cdTopDirectorySlot
, cfSlotVector
); 
 625                 builder
.specialSlot(cdTopDirectorySlot
, cfSlotVector
); 
 631 #include <security_smime/tsaSupport.h> 
 634 // Generate the CMS signature for a (finished) CodeDirectory. 
 636 CFDataRef 
SecCodeSigner::Signer::signCodeDirectory(const CodeDirectory 
*cd
, CFDataRef hashBag
) 
 638         assert(state
.mSigner
); 
 639         CFRef
<CFMutableDictionaryRef
> defaultTSContext 
= NULL
; 
 641         // a null signer generates a null signature blob 
 642         if (state
.mSigner 
== SecIdentityRef(kCFNull
)) 
 643                 return CFDataCreate(NULL
, NULL
, 0); 
 645         // generate CMS signature 
 646         CFRef
<CMSEncoderRef
> cms
; 
 647         MacOSError::check(CMSEncoderCreate(&cms
.aref())); 
 648         MacOSError::check(CMSEncoderSetCertificateChainMode(cms
, kCMSCertificateChainWithRoot
)); 
 649         CMSEncoderAddSigners(cms
, state
.mSigner
); 
 650         CMSEncoderSetSignerAlgorithm(cms
, kCMSEncoderDigestAlgorithmSHA256
); 
 651         MacOSError::check(CMSEncoderSetHasDetachedContent(cms
, true)); 
 653         if (emitSigningTime
) { 
 654                 MacOSError::check(CMSEncoderAddSignedAttributes(cms
, kCMSAttrSigningTime
)); 
 655                 CFAbsoluteTime time 
= signingTime 
? signingTime 
: CFAbsoluteTimeGetCurrent(); 
 656                 MacOSError::check(CMSEncoderSetSigningTime(cms
, time
)); 
 660                 MacOSError::check(CMSEncoderAddSignedAttributes(cms
, kCMSAttrAppleCodesigningHashAgility
)); 
 661                 MacOSError::check(CMSEncoderSetAppleCodesigningHashAgility(cms
, hashBag
)); 
 664         MacOSError::check(CMSEncoderUpdateContent(cms
, cd
, cd
->length())); 
 666     // Set up to call Timestamp server if requested 
 667     if (state
.mWantTimeStamp
) 
 669         CFRef
<CFErrorRef
> error 
= NULL
; 
 670         defaultTSContext 
= SecCmsTSAGetDefaultContext(&error
.aref()); 
 672             MacOSError::throwMe(errSecDataNotAvailable
); 
 674         if (state
.mNoTimeStampCerts 
|| state
.mTimestampService
) { 
 675             if (state
.mTimestampService
) 
 676                 CFDictionarySetValue(defaultTSContext
, kTSAContextKeyURL
, state
.mTimestampService
); 
 677             if (state
.mNoTimeStampCerts
) 
 678                 CFDictionarySetValue(defaultTSContext
, kTSAContextKeyNoCerts
, kCFBooleanTrue
); 
 681                 CmsMessageSetTSAContext(cms
, defaultTSContext
); 
 685         MacOSError::check(CMSEncoderCopyEncodedContent(cms
, &signature
)); 
 692 // Our DiskRep::signingContext methods communicate with the signing subsystem 
 693 // in terms those callers can easily understand. 
 695 string 
SecCodeSigner::Signer::sdkPath(const std::string 
&path
) const 
 697         assert(path
[0] == '/'); // need absolute path here 
 699                 return cfString(state
.mSDKRoot
) + path
; 
 704 bool SecCodeSigner::Signer::isAdhoc() const 
 706         return state
.mSigner 
== SecIdentityRef(kCFNull
); 
 709 SecCSFlags 
SecCodeSigner::Signer::signingFlags() const 
 711         return state
.mOpFlags
; 
 716 // Parse a text of the form 
 718 // where each flag is the canonical name of a signable CodeDirectory flag. 
 719 // No abbreviations are allowed, and internally set flags are not accepted. 
 721 uint32_t SecCodeSigner::Signer::cdTextFlags(std::string text
) 
 724         for (string::size_type comma 
= text
.find(','); ; text 
= text
.substr(comma
+1), comma 
= text
.find(',')) { 
 725                 string word 
= (comma 
== string::npos
) ? text 
: text
.substr(0, comma
); 
 726                 const SecCodeDirectoryFlagTable 
*item
; 
 727                 for (item 
= kSecCodeDirectoryFlagTable
; item
->name
; item
++) 
 728                         if (item
->signable 
&& word 
== item
->name
) { 
 729                                 flags 
|= item
->value
; 
 732                 if (!item
->name
)        // not found 
 733                         MacOSError::throwMe(errSecCSInvalidFlags
); 
 734                 if (comma 
== string::npos
)      // last word 
 742 // Generate a unique string from our underlying DiskRep. 
 743 // We could get 90%+ of the uniquing benefit by just generating 
 744 // a random string here. Instead, we pick the (hex string encoding of) 
 745 // the source rep's unique identifier blob. For universal binaries, 
 746 // this is the canonical local architecture, which is a bit arbitrary. 
 747 // This provides us with a consistent unique string for all architectures 
 748 // of a fat binary, *and* (unlike a random string) is reproducible 
 749 // for identical inputs, even upon resigning. 
 751 std::string 
SecCodeSigner::Signer::uniqueName() const 
 753         CFRef
<CFDataRef
> identification 
= rep
->identification(); 
 754         const UInt8 
*ident 
= CFDataGetBytePtr(identification
); 
 755         const CFIndex length 
= CFDataGetLength(identification
); 
 757         for (CFIndex n 
= 0; n 
< length
; n
++) { 
 759                 snprintf(hex
, sizeof(hex
), "%02x", ident
[n
]); 
 766 } // end namespace CodeSigning 
 767 } // end namespace Security