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
); 
 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                 secdebug("signer", "using default identifier=%s", identifier
.c_str()); 
 154                 secdebug("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                 secdebug("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                                         secdebug("signer", "using numeric cdFlags=0x%x from Info.plist", cdFlags
); 
 186                                 } else if (CFGetTypeID(csflags
) == CFStringGetTypeID()) { 
 187                                         cdFlags 
= cdTextFlags(cfString(CFStringRef(csflags
))); 
 188                                         secdebug("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                 secdebug("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         CFAbsoluteTime now 
= CFAbsoluteTimeGetCurrent(); 
 267         if (state
.mSigningTime 
== CFDateRef(kCFNull
)) { 
 268                 signingTime 
= 0;                // no time at all 
 269         } else if (!state
.mSigningTime
) { 
 270                 signingTime 
= now
;              // default 
 272                 CFAbsoluteTime time 
= CFDateGetAbsoluteTime(state
.mSigningTime
); 
 273                 if (time 
> now
) // not allowed to post-date a signature 
 274                         MacOSError::throwMe(errSecCSBadDictionaryFormat
); 
 278         pagesize 
= state
.mPageSize 
? cfNumber
<size_t>(state
.mPageSize
) : rep
->pageSize(*this); 
 280         // Allow the DiskRep to modify the signing parameters. This sees explicit and inherited values but not defaults. 
 281         rep
->prepareForSigning(*this); 
 283         // apply some defaults after diskRep intervention 
 284         if (hashAlgorithms
.empty()) {   // default to SHA256 + SHA-1 
 285                 hashAlgorithms
.insert(kSecCodeSignatureHashSHA1
); 
 286                 hashAlgorithms
.insert(kSecCodeSignatureHashSHA256
); 
 289         // build the resource directory (once and for all, using the digests determined above) 
 290         if (!rpath
.empty()) { 
 291                 buildResources(rrpath
, rpath
, resourceRules
); 
 297 // Collect the resource seal for a program. 
 298 // This includes both sealed resources and information about nested code. 
 300 void SecCodeSigner::Signer::buildResources(std::string root
, std::string relBase
, CFDictionaryRef rulesDict
) 
 302         typedef ResourceBuilder::Rule Rule
; 
 304         secdebug("codesign", "start building resource directory"); 
 305         __block CFRef
<CFMutableDictionaryRef
> result 
= makeCFMutableDictionary(); 
 307         CFDictionaryRef rules 
= cfget
<CFDictionaryRef
>(rulesDict
, "rules"); 
 310         if (this->state
.mLimitedAsync 
== NULL
) { 
 311                 this->state
.mLimitedAsync 
= 
 312                         /* rdar://problem/20299541: Async workers (i.e. parallelization) are currently 
 313                          * turned off, because the paths for signing code are not ready for it yet. */ 
 314                         // new LimitedAsync(rep->fd().mediumType() == kIOPropertyMediumTypeSolidStateKey); 
 315                         new LimitedAsync(false); 
 318         CFDictionaryRef files2 
= NULL
; 
 319         if (!(signingFlags() & kSecCSSignV1
)) { 
 320                 CFCopyRef
<CFDictionaryRef
> rules2 
= cfget
<CFDictionaryRef
>(rulesDict
, "rules2"); 
 322                         // Clone V1 rules and add default nesting rules at weight 0 (overridden by anything in rules). 
 323                         // V1 rules typically do not cover these places so we'll prevail, but if they do, we defer to them. 
 324                         rules2 
= cfmake
<CFDictionaryRef
>("{+%O" 
 325                                 "'^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/' = {nested=#T, weight=0}" // exclude dynamic repositories 
 329                 Dispatch::Group group
; 
 330                 Dispatch::Group 
&groupRef 
= group
;  // (into block) 
 332                 // build the modern (V2) resource seal 
 333                 __block CFRef
<CFMutableDictionaryRef
> files 
= makeCFMutableDictionary(); 
 334                 CFMutableDictionaryRef filesRef 
= files
.get();  // (into block) 
 335                 ResourceBuilder 
resourceBuilder(root
, relBase
, rules2
, strict
, MacOSErrorSet()); 
 336                 ResourceBuilder 
&resources 
= resourceBuilder
;   // (into block) 
 337                 rep
->adjustResources(resources
); 
 339                 resources
.scan(^(FTSENT 
*ent
, uint32_t ruleFlags
, const std::string relpath
, Rule 
*rule
) { 
 340                         bool isSymlink 
= (ent
->fts_info 
== FTS_SL
); 
 341                         const std::string 
path(ent
->fts_path
); 
 342                         const std::string 
accpath(ent
->fts_accpath
); 
 343                         this->state
.mLimitedAsync
->perform(groupRef
, ^{ 
 344                                 CFRef
<CFMutableDictionaryRef
> seal
; 
 345                                 if (ruleFlags 
& ResourceBuilder::nested
) { 
 346                                         seal
.take(signNested(path
, relpath
)); 
 347                                 } else if (isSymlink
) { 
 348                                         char target
[PATH_MAX
]; 
 349                                         ssize_t len 
= ::readlink(accpath
.c_str(), target
, sizeof(target
)-1); 
 351                                                 UnixError::check(-1); 
 353                                         seal
.take(cfmake
<CFMutableDictionaryRef
>("{symlink=%s}", target
)); 
 355                                         seal
.take(resources
.hashFile(accpath
.c_str(), digestAlgorithms())); 
 357                                 if (ruleFlags 
& ResourceBuilder::optional
) 
 358                                         CFDictionaryAddValue(seal
, CFSTR("optional"), kCFBooleanTrue
); 
 360                                 StLock
<Mutex
> _(resourceLock
); 
 361                                 if ((hash 
= CFDictionaryGetValue(seal
, CFSTR("hash"))) && CFDictionaryGetCount(seal
) == 1) // simple form 
 362                                         CFDictionaryAddValue(filesRef
, CFTempString(relpath
).get(), hash
); 
 364                                         CFDictionaryAddValue(filesRef
, CFTempString(relpath
).get(), seal
.get()); 
 365                                 code
->reportProgress(); 
 369                 CFDictionaryAddValue(result
, CFSTR("rules2"), resourceBuilder
.rules()); 
 371                 CFDictionaryAddValue(result
, CFSTR("files2"), files2
); 
 374         CFDictionaryAddValue(result
, CFSTR("rules"), rules
);    // preserve V1 rules in any case 
 375         if (!(signingFlags() & kSecCSSignNoV1
)) { 
 376                 // build the legacy (V1) resource seal 
 377                 __block CFRef
<CFMutableDictionaryRef
> files 
= makeCFMutableDictionary(); 
 378                 ResourceBuilder 
resourceBuilder(root
, relBase
, rules
, strict
, MacOSErrorSet()); 
 379                 ResourceBuilder 
&resources 
= resourceBuilder
; 
 380                 rep
->adjustResources(resources
);        // DiskRep-specific adjustments 
 381                 resources
.scan(^(FTSENT 
*ent
, uint32_t ruleFlags
, std::string relpath
, Rule 
*rule
) { 
 382                         if (ent
->fts_info 
== FTS_F
) { 
 383                                 CFRef
<CFDataRef
> hash
; 
 384                                 if (files2
)     // try to get the hash from a previously-made version 
 385                                         if (CFTypeRef seal 
= CFDictionaryGetValue(files2
, CFTempString(relpath
))) { 
 386                                                 if (CFGetTypeID(seal
) == CFDataGetTypeID()) 
 387                                                         hash 
= CFDataRef(seal
); 
 389                                                         hash 
= CFDataRef(CFDictionaryGetValue(CFDictionaryRef(seal
), CFSTR("hash"))); 
 392                                         hash
.take(resources
.hashFile(ent
->fts_accpath
, kSecCodeSignatureHashSHA1
)); 
 393                                 if (ruleFlags 
== 0) {   // default case - plain hash 
 394                                         cfadd(files
, "{%s=%O}", relpath
.c_str(), hash
.get()); 
 395                                         secdebug("csresource", "%s added simple (rule %p)", relpath
.c_str(), rule
); 
 396                                 } else {        // more complicated - use a sub-dictionary 
 397                                         cfadd(files
, "{%s={hash=%O,optional=%B}}", 
 398                                                 relpath
.c_str(), hash
.get(), ruleFlags 
& ResourceBuilder::optional
); 
 399                                         secdebug("csresource", "%s added complex (rule %p)", relpath
.c_str(), rule
); 
 403                 CFDictionaryAddValue(result
, CFSTR("files"), files
.get()); 
 406         resourceDirectory 
= result
.get(); 
 407         resourceDictData
.take(makeCFData(resourceDirectory
.get())); 
 412 // Deal with one piece of nested code 
 414 CFMutableDictionaryRef 
SecCodeSigner::Signer::signNested(const std::string 
&path
, const std::string 
&relpath
) 
 416         // sign nested code and collect nesting information 
 418                 SecPointer
<SecStaticCode
> code 
= new SecStaticCode(DiskRep::bestGuess(path
)); 
 419                 if (signingFlags() & kSecCSSignNestedCode
) 
 420                         this->state
.sign(code
, signingFlags()); 
 421                 std::string dr 
= Dumper::dump(code
->designatedRequirement()); 
 422                 return cfmake
<CFMutableDictionaryRef
>("{requirement=%s,cdhash=%O}", 
 423                         Dumper::dump(code
->designatedRequirement()).c_str(), 
 425         } catch (const CommonError 
&err
) { 
 426                 CSError::throwMe(err
.osStatus(), kSecCFErrorPath
, CFTempURL(relpath
, false, this->code
->resourceBase())); 
 432 // Sign a Mach-O binary, using liberal dollops of that special Mach-O magic sauce. 
 433 // Note that this will deal just fine with non-fat Mach-O binaries, but it will 
 434 // treat them as architectural binaries containing (only) one architecture - that 
 435 // interpretation is courtesy of the Universal/MachO support classes. 
 437 void SecCodeSigner::Signer::signMachO(Universal 
*fat
, const Requirement::Context 
&context
) 
 439         // Mach-O executable at the core - perform multi-architecture signing 
 440         auto_ptr
<ArchEditor
> editor(state
.mDetached
 
 441                 ? static_cast<ArchEditor 
*>(new BlobEditor(*fat
, *this)) 
 442                 : new MachOEditor(rep
->writer(), *fat
, this->digestAlgorithms(), rep
->mainExecutablePath())); 
 443         assert(editor
->count() > 0); 
 444         if (!editor
->attribute(writerNoGlobal
)) // can store architecture-common components 
 447         // pass 1: prepare signature blobs and calculate sizes 
 448         for (MachOEditor::Iterator it 
= editor
->begin(); it 
!= editor
->end(); ++it
) { 
 449                 MachOEditor::Arch 
&arch 
= *it
->second
; 
 450                 arch
.source
.reset(fat
->architecture(it
->first
)); 
 452                 // library validation is not compatible with i386 
 453                 if (arch
.architecture
.cpuType() == CPU_TYPE_I386
) { 
 454                         if (cdFlags 
& kSecCodeSignatureLibraryValidation
) { 
 455                                 MacOSError::throwMe(errSecCSBadLVArch
); 
 459                 arch
.ireqs(requirements
, rep
->defaultRequirements(&arch
.architecture
, *this), context
); 
 460                 if (editor
->attribute(writerNoGlobal
))  // can't store globally, add per-arch 
 462                 for (auto type 
= digestAlgorithms().begin(); type 
!= digestAlgorithms().end(); ++type
) { 
 463                         arch
.eachDigest(^(CodeDirectory::Builder
& builder
) { 
 464                                 populate(builder
, arch
, arch
.ireqs
, 
 465                                                  arch
.source
->offset(), arch
.source
->signingExtent(), unsigned(digestAlgorithms().size()-1)); 
 469                 // add identification blob (made from this architecture) only if we're making a detached signature 
 470                 if (state
.mDetached
) { 
 471                         CFRef
<CFDataRef
> identification 
= MachORep::identificationFor(arch
.source
.get()); 
 472                         arch
.add(cdIdentificationSlot
, BlobWrapper::alloc( 
 473                                 CFDataGetBytePtr(identification
), CFDataGetLength(identification
))); 
 476                 // prepare SuperBlob size estimate 
 477                 __block 
std::vector
<size_t> sizes
; 
 478                 arch
.eachDigest(^(CodeDirectory::Builder
& builder
){ 
 479                         sizes
.push_back(builder
.size(CodeDirectory::currentVersion
)); 
 481                 arch
.blobSize 
= arch
.size(sizes
, state
.mCMSSize
, 0); 
 486         // pass 2: Finish and generate signatures, and write them 
 487         for (MachOEditor::Iterator it 
= editor
->begin(); it 
!= editor
->end(); ++it
) { 
 488                 MachOEditor::Arch 
&arch 
= *it
->second
; 
 491                 // finish CodeDirectories (off new binary) and sign it 
 492                 __block CodeDirectorySet cdSet
; 
 493                 arch
.eachDigest(^(CodeDirectory::Builder 
&builder
) { 
 494                         CodeDirectory 
*cd 
= builder
.build(); 
 497                 CFRef
<CFArrayRef
> hashes 
= cdSet
.hashBag(); 
 498                 CFTemp
<CFDictionaryRef
> hashDict("{cdhashes=%O}", hashes
.get()); 
 499                 CFRef
<CFDataRef
> hashBag 
= makeCFData(hashDict
.get()); 
 500                 CFRef
<CFDataRef
> signature 
= signCodeDirectory(cdSet
.primary(), hashBag
); 
 502                 // complete the SuperBlob 
 503                 cdSet
.populate(&arch
); 
 504                 arch
.add(cdSignatureSlot
, BlobWrapper::alloc( 
 505                         CFDataGetBytePtr(signature
), CFDataGetLength(signature
))); 
 506                 if (!state
.mDryRun
) { 
 507                         EmbeddedSignatureBlob 
*blob 
= arch
.make(); 
 508                         editor
->write(arch
, blob
);      // takes ownership of blob 
 512         // done: write edit copy back over the original 
 519 // Sign a binary that has no notion of architecture. 
 520 // That currently means anything that isn't Mach-O format. 
 522 void SecCodeSigner::Signer::signArchitectureAgnostic(const Requirement::Context 
&context
) 
 524         // non-Mach-O executable - single-instance signing 
 525         RefPointer
<DiskRep::Writer
> writer 
= state
.mDetached 
? 
 526                 (new DetachedBlobWriter(*this)) : rep
->writer(); 
 528         CodeDirectorySet cdSet
; 
 529         for (auto type 
= digestAlgorithms().begin(); type 
!= digestAlgorithms().end(); ++type
) { 
 530                 CodeDirectory::Builder 
builder(*type
); 
 531                 InternalRequirements ireqs
; 
 532                 ireqs(requirements
, rep
->defaultRequirements(NULL
, *this), context
); 
 534                 populate(builder
, *writer
, ireqs
, rep
->signingBase(), rep
->signingLimit(), unsigned(digestAlgorithms().size()-1)); 
 536                 CodeDirectory 
*cd 
= builder
.build(); 
 541         // add identification blob (made from this architecture) only if we're making a detached signature 
 542         if (state
.mDetached
) { 
 543                 CFRef
<CFDataRef
> identification 
= rep
->identification(); 
 544                 writer
->component(cdIdentificationSlot
, identification
); 
 547         // write out all CodeDirectories 
 548         cdSet
.populate(writer
); 
 551         CFRef
<CFArrayRef
> hashes 
= cdSet
.hashBag(); 
 552         CFTemp
<CFDictionaryRef
> hashDict("{cdhashes=%O}", hashes
.get()); 
 553         CFRef
<CFDataRef
> hashBag 
= makeCFData(hashDict
.get()); 
 554         CFRef
<CFDataRef
> signature 
= signCodeDirectory(cdSet
.primary(), hashBag
); 
 555         writer
->signature(signature
); 
 560 // Global populate - send components to destination buffers ONCE 
 562 void SecCodeSigner::Signer::populate(DiskRep::Writer 
&writer
) 
 564         if (resourceDirectory 
&& !state
.mDryRun
) 
 565                 writer
.component(cdResourceDirSlot
, resourceDictData
); 
 570 // Per-architecture populate - send components to per-architecture buffers 
 571 // and populate the CodeDirectory for an architecture. In architecture-agnostic 
 572 // signing operations, the non-architectural binary is considered one (arbitrary) architecture 
 573 // for the purposes of this call. 
 575 void SecCodeSigner::Signer::populate(CodeDirectory::Builder 
&builder
, DiskRep::Writer 
&writer
, 
 576         InternalRequirements 
&ireqs
, size_t offset
, size_t length
, unsigned alternateDigestCount
) 
 578         // fill the CodeDirectory 
 579         builder
.executable(rep
->mainExecutablePath(), pagesize
, offset
, length
); 
 580         builder
.flags(cdFlags
); 
 581         builder
.identifier(identifier
); 
 582         builder
.teamID(teamID
); 
 583         builder
.platform(state
.mPlatform
); 
 585         if (CFRef
<CFDataRef
> data 
= rep
->component(cdInfoSlot
)) 
 586                 builder
.specialSlot(cdInfoSlot
, data
); 
 588                 CFRef
<CFDataRef
> data 
= makeCFData(*ireqs
); 
 589                 writer
.component(cdRequirementsSlot
, data
); 
 590                 builder
.specialSlot(cdRequirementsSlot
, data
); 
 592         if (resourceDirectory
) 
 593                 builder
.specialSlot(cdResourceDirSlot
, resourceDictData
); 
 595                 writer
.component(cdEntitlementSlot
, entitlements
); 
 596                 builder
.specialSlot(cdEntitlementSlot
, entitlements
); 
 598         if (CFRef
<CFDataRef
> repSpecific 
= rep
->component(cdRepSpecificSlot
)) 
 599                 builder
.specialSlot(cdRepSpecificSlot
, repSpecific
); 
 601         writer
.addDiscretionary(builder
); 
 603         if ((signingFlags() & (kSecCSSignOpaque
|kSecCSSignV1
)) == 0) { 
 604                 // calculate sorted list of top SuperBlob keys in this EmbeddedSignatureBlob (if any) 
 605                 // (but not for opaque or V1 construction, which must remain bit-for-bit compatible) 
 606                 std::vector
<Endian
<uint32_t> > slotVector
; 
 607                 slotVector
.push_back(cdCodeDirectorySlot
);      // mandatory 
 608                 std::set
<CodeDirectory::Slot
> filledSlots 
= builder
.filledSpecialSlots(); 
 609                 filledSlots
.insert(cdTopDirectorySlot
);         // will be added below 
 610                 copy(filledSlots
.begin(), filledSlots
.end(), back_inserter(slotVector
)); 
 611                 for (unsigned n 
= 0; n 
< alternateDigestCount
; n
++) 
 612                         slotVector
.push_back(cdAlternateCodeDirectorySlots 
+ n
); 
 613                 slotVector
.push_back(cdSignatureSlot
); 
 614                 CFTempData 
cfSlotVector(&slotVector
[0], slotVector
.size() * sizeof(slotVector
[0])); 
 615                 writer
.component(cdTopDirectorySlot
, cfSlotVector
); 
 616                 builder
.specialSlot(cdTopDirectorySlot
, cfSlotVector
); 
 621 #include <security_smime/tsaSupport.h> 
 624 // Generate the CMS signature for a (finished) CodeDirectory. 
 626 CFDataRef 
SecCodeSigner::Signer::signCodeDirectory(const CodeDirectory 
*cd
, CFDataRef hashBag
) 
 628         assert(state
.mSigner
); 
 629         CFRef
<CFMutableDictionaryRef
> defaultTSContext 
= NULL
; 
 631         // a null signer generates a null signature blob 
 632         if (state
.mSigner 
== SecIdentityRef(kCFNull
)) 
 633                 return CFDataCreate(NULL
, NULL
, 0); 
 635         // generate CMS signature 
 636         CFRef
<CMSEncoderRef
> cms
; 
 637         MacOSError::check(CMSEncoderCreate(&cms
.aref())); 
 638         MacOSError::check(CMSEncoderSetCertificateChainMode(cms
, kCMSCertificateChainWithRoot
)); 
 639         CMSEncoderAddSigners(cms
, state
.mSigner
); 
 640         CMSEncoderSetSignerAlgorithm(cms
, kCMSEncoderDigestAlgorithmSHA256
); 
 641         MacOSError::check(CMSEncoderSetHasDetachedContent(cms
, true)); 
 644                 MacOSError::check(CMSEncoderAddSignedAttributes(cms
, kCMSAttrSigningTime
)); 
 645                 MacOSError::check(CMSEncoderSetSigningTime(cms
, signingTime
)); 
 649                 MacOSError::check(CMSEncoderAddSignedAttributes(cms
, kCMSAttrAppleCodesigningHashAgility
)); 
 650                 MacOSError::check(CMSEncoderSetAppleCodesigningHashAgility(cms
, hashBag
)); 
 653         MacOSError::check(CMSEncoderUpdateContent(cms
, cd
, cd
->length())); 
 655     // Set up to call Timestamp server if requested 
 656     if (state
.mWantTimeStamp
) 
 658         CFRef
<CFErrorRef
> error 
= NULL
; 
 659         defaultTSContext 
= SecCmsTSAGetDefaultContext(&error
.aref()); 
 661             MacOSError::throwMe(errSecDataNotAvailable
); 
 663         if (state
.mNoTimeStampCerts 
|| state
.mTimestampService
) { 
 664             if (state
.mTimestampService
) 
 665                 CFDictionarySetValue(defaultTSContext
, kTSAContextKeyURL
, state
.mTimestampService
); 
 666             if (state
.mNoTimeStampCerts
) 
 667                 CFDictionarySetValue(defaultTSContext
, kTSAContextKeyNoCerts
, kCFBooleanTrue
); 
 670                 CmsMessageSetTSAContext(cms
, defaultTSContext
); 
 674         MacOSError::check(CMSEncoderCopyEncodedContent(cms
, &signature
)); 
 681 // Our DiskRep::signingContext methods communicate with the signing subsystem 
 682 // in terms those callers can easily understand. 
 684 string 
SecCodeSigner::Signer::sdkPath(const std::string 
&path
) const 
 686         assert(path
[0] == '/'); // need absolute path here 
 688                 return cfString(state
.mSDKRoot
) + path
; 
 693 bool SecCodeSigner::Signer::isAdhoc() const 
 695         return state
.mSigner 
== SecIdentityRef(kCFNull
); 
 698 SecCSFlags 
SecCodeSigner::Signer::signingFlags() const 
 700         return state
.mOpFlags
; 
 705 // Parse a text of the form 
 707 // where each flag is the canonical name of a signable CodeDirectory flag. 
 708 // No abbreviations are allowed, and internally set flags are not accepted. 
 710 uint32_t SecCodeSigner::Signer::cdTextFlags(std::string text
) 
 713         for (string::size_type comma 
= text
.find(','); ; text 
= text
.substr(comma
+1), comma 
= text
.find(',')) { 
 714                 string word 
= (comma 
== string::npos
) ? text 
: text
.substr(0, comma
); 
 715                 const SecCodeDirectoryFlagTable 
*item
; 
 716                 for (item 
= kSecCodeDirectoryFlagTable
; item
->name
; item
++) 
 717                         if (item
->signable 
&& word 
== item
->name
) { 
 718                                 flags 
|= item
->value
; 
 721                 if (!item
->name
)        // not found 
 722                         MacOSError::throwMe(errSecCSInvalidFlags
); 
 723                 if (comma 
== string::npos
)      // last word 
 731 // Generate a unique string from our underlying DiskRep. 
 732 // We could get 90%+ of the uniquing benefit by just generating 
 733 // a random string here. Instead, we pick the (hex string encoding of) 
 734 // the source rep's unique identifier blob. For universal binaries, 
 735 // this is the canonical local architecture, which is a bit arbitrary. 
 736 // This provides us with a consistent unique string for all architectures 
 737 // of a fat binary, *and* (unlike a random string) is reproducible 
 738 // for identical inputs, even upon resigning. 
 740 std::string 
SecCodeSigner::Signer::uniqueName() const 
 742         CFRef
<CFDataRef
> identification 
= rep
->identification(); 
 743         const UInt8 
*ident 
= CFDataGetBytePtr(identification
); 
 744         const CFIndex length 
= CFDataGetLength(identification
); 
 746         for (CFIndex n 
= 0; n 
< length
; n
++) { 
 748                 snprintf(hex
, sizeof(hex
), "%02x", ident
[n
]); 
 755 } // end namespace CodeSigning 
 756 } // end namespace Security