2 * Copyright (c) 2006-2010 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>
46 namespace CodeSigning
{
52 void SecCodeSigner::Signer::sign(SecCSFlags flags
)
54 rep
= code
->diskRep()->base();
57 PreSigningContext
context(*this);
59 /* If an explicit teamID was passed in it must be
60 the same as what came from the cert */
61 std::string teamIDFromCert
= state
.getTeamIDFromSigner(context
.certs
);
63 if (state
.mPreserveMetadata
& kSecCodeSignerPreserveTeamIdentifier
) {
64 /* If preserving the team identifier, teamID is set previously when the
65 code object is still available */
66 if (!teamIDFromCert
.empty() && teamID
!= teamIDFromCert
)
67 MacOSError::throwMe(errSecCSInvalidFlags
);
69 if (teamIDFromCert
.empty()) {
70 /* state.mTeamID is an explicitly passed teamID */
71 teamID
= state
.mTeamID
;
72 } else if (state
.mTeamID
.empty() || (state
.mTeamID
== teamIDFromCert
)) {
73 /* If there was no explicit team ID set, or the explicit team ID matches
74 what is in the cert, use the team ID from the certificate */
75 teamID
= teamIDFromCert
;
77 /* The caller passed in an explicit team ID that does not match what is
78 in the signing cert, which is an invalid usage */
79 MacOSError::throwMe(errSecCSInvalidFlags
);
83 if (Universal
*fat
= state
.mNoMachO
? NULL
: rep
->mainExecutableImage()) {
84 signMachO(fat
, context
);
86 signArchitectureAgnostic(context
);
92 // Remove any existing code signature from code
94 void SecCodeSigner::Signer::remove(SecCSFlags flags
)
96 // can't remove a detached signature
98 MacOSError::throwMe(errSecCSNotSupported
);
100 rep
= code
->diskRep();
101 if (Universal
*fat
= state
.mNoMachO
? NULL
: rep
->mainExecutableImage()) {
102 // architecture-sensitive removal
103 MachOEditor
editor(rep
->writer(), *fat
, kSecCodeSignatureNoHash
, rep
->mainExecutablePath());
104 editor
.allocate(); // create copy
105 editor
.commit(); // commit change
107 // architecture-agnostic removal
108 RefPointer
<DiskRep::Writer
> writer
= rep
->writer();
116 // Contemplate the object-to-be-signed and set up the Signer state accordingly.
118 void SecCodeSigner::Signer::prepare(SecCSFlags flags
)
120 // make sure the rep passes strict validation
122 rep
->strictValidate(MacOSErrorSet());
124 // get the Info.plist out of the rep for some creative defaulting
125 CFRef
<CFDictionaryRef
> infoDict
;
126 if (CFRef
<CFDataRef
> infoData
= rep
->component(cdInfoSlot
))
127 infoDict
.take(makeCFDictionaryFrom(infoData
));
129 uint32_t inherit
= code
->isSigned() ? state
.mPreserveMetadata
: 0;
131 // work out the canonical identifier
132 identifier
= state
.mIdentifier
;
133 if (identifier
.empty() && (inherit
& kSecCodeSignerPreserveIdentifier
))
134 identifier
= code
->identifier();
135 if (identifier
.empty()) {
136 identifier
= rep
->recommendedIdentifier(state
);
137 if (identifier
.find('.') == string::npos
)
138 identifier
= state
.mIdentifierPrefix
+ identifier
;
139 if (identifier
.find('.') == string::npos
&& state
.isAdhoc())
140 identifier
= identifier
+ "-" + uniqueName();
141 secdebug("signer", "using default identifier=%s", identifier
.c_str());
143 secdebug("signer", "using explicit identifier=%s", identifier
.c_str());
145 teamID
= state
.mTeamID
;
146 if (teamID
.empty() && (inherit
& kSecCodeSignerPreserveTeamIdentifier
)) {
147 const char *c_id
= code
->teamID();
152 entitlements
= state
.mEntitlementData
;
153 if (!entitlements
&& (inherit
& kSecCodeSignerPreserveEntitlements
))
154 entitlements
= code
->component(cdEntitlementSlot
);
156 // work out the CodeDirectory flags word
157 bool haveCdFlags
= false;
158 if (!haveCdFlags
&& state
.mCdFlagsGiven
) {
159 cdFlags
= state
.mCdFlags
;
160 secdebug("signer", "using explicit cdFlags=0x%x", cdFlags
);
166 if (CFTypeRef csflags
= CFDictionaryGetValue(infoDict
, CFSTR("CSFlags"))) {
167 if (CFGetTypeID(csflags
) == CFNumberGetTypeID()) {
168 cdFlags
= cfNumber
<uint32_t>(CFNumberRef(csflags
));
169 secdebug("signer", "using numeric cdFlags=0x%x from Info.plist", cdFlags
);
170 } else if (CFGetTypeID(csflags
) == CFStringGetTypeID()) {
171 cdFlags
= cdTextFlags(cfString(CFStringRef(csflags
)));
172 secdebug("signer", "using text cdFlags=0x%x from Info.plist", cdFlags
);
174 MacOSError::throwMe(errSecCSBadDictionaryFormat
);
178 if (!haveCdFlags
&& (inherit
& kSecCodeSignerPreserveFlags
)) {
179 cdFlags
= code
->codeDirectory(false)->flags
& ~kSecCodeSignatureAdhoc
;
180 secdebug("signer", "using inherited cdFlags=0x%x", cdFlags
);
185 if (state
.mSigner
== SecIdentityRef(kCFNull
)) // ad-hoc signing requested...
186 cdFlags
|= kSecCodeSignatureAdhoc
; // ... so note that
188 // prepare the internal requirements input
189 if (state
.mRequirements
) {
190 if (CFGetTypeID(state
.mRequirements
) == CFDataGetTypeID()) { // binary form
191 const Requirements
*rp
= (const Requirements
*)CFDataGetBytePtr(state
.mRequirements
.as
<CFDataRef
>());
192 if (!rp
->validateBlob())
193 MacOSError::throwMe(errSecCSReqInvalid
);
194 requirements
= rp
->clone();
195 } else if (CFGetTypeID(state
.mRequirements
) == CFStringGetTypeID()) { // text form
196 CFRef
<CFMutableStringRef
> reqText
= CFStringCreateMutableCopy(NULL
, 0, state
.mRequirements
.as
<CFStringRef
>());
197 // substitute $ variable tokens
198 CFRange range
= { 0, CFStringGetLength(reqText
) };
199 CFStringFindAndReplace(reqText
, CFSTR("$self.identifier"), CFTempString(identifier
), range
, 0);
200 requirements
= parseRequirements(cfString(reqText
));
202 MacOSError::throwMe(errSecCSInvalidObjectRef
);
203 } else if (inherit
& kSecCodeSignerPreserveRequirements
)
204 if (const Requirements
*rp
= code
->internalRequirements())
205 requirements
= rp
->clone();
207 // prepare the resource directory, if any
208 string rpath
= rep
->resourcesRootPath();
209 if (!rpath
.empty()) {
210 // explicitly given resource rules always win
211 CFCopyRef
<CFDictionaryRef
> resourceRules
= state
.mResourceRules
;
213 // inherited rules come next (overriding embedded ones!)
214 if (!resourceRules
&& (inherit
& kSecCodeSignerPreserveResourceRules
))
215 if (CFDictionaryRef oldRules
= code
->resourceDictionary(false))
216 resourceRules
= oldRules
;
218 // embedded resource rules come next
219 if (!resourceRules
&& infoDict
)
220 if (CFTypeRef spec
= CFDictionaryGetValue(infoDict
, _kCFBundleResourceSpecificationKey
)) {
221 if (CFGetTypeID(spec
) == CFStringGetTypeID())
222 if (CFRef
<CFDataRef
> data
= cfLoadFile(rpath
+ "/" + cfString(CFStringRef(spec
))))
223 if (CFDictionaryRef dict
= makeCFDictionaryFrom(data
))
224 resourceRules
.take(dict
);
225 if (!resourceRules
) // embedded rules present but unacceptable
226 MacOSError::throwMe(errSecCSResourceRulesInvalid
);
229 // if we got one from anywhere (but the defaults), sanity-check it
231 CFTypeRef rules
= CFDictionaryGetValue(resourceRules
, CFSTR("rules"));
232 if (!rules
|| CFGetTypeID(rules
) != CFDictionaryGetTypeID())
233 MacOSError::throwMe(errSecCSResourceRulesInvalid
);
236 // finally, ask the DiskRep for its default
238 resourceRules
.take(rep
->defaultResourceRules(state
));
240 // resource root can optionally be the canonical bundle path,
241 // but sealed resource paths are always relative to rpath
243 if (state
.signingFlags() & kSecCSSignBundleRoot
)
244 root
= cfStringRelease(rep
->copyCanonicalPath());
246 // build the resource directory
247 buildResources(root
, rpath
, resourceRules
);
250 // screen and set the signing time
251 CFAbsoluteTime now
= CFAbsoluteTimeGetCurrent();
252 if (state
.mSigningTime
== CFDateRef(kCFNull
)) {
253 signingTime
= 0; // no time at all
254 } else if (!state
.mSigningTime
) {
255 signingTime
= now
; // default
257 CFAbsoluteTime time
= CFDateGetAbsoluteTime(state
.mSigningTime
);
258 if (time
> now
) // not allowed to post-date a signature
259 MacOSError::throwMe(errSecCSBadDictionaryFormat
);
263 pagesize
= state
.mPageSize
? cfNumber
<size_t>(state
.mPageSize
) : rep
->pageSize(state
);
265 // Timestamping setup
266 CFRef
<SecIdentityRef
> mTSAuth
; // identity for client-side authentication to the Timestamp server
271 // Collect the resource seal for a program.
272 // This includes both sealed resources and information about nested code.
274 void SecCodeSigner::Signer::buildResources(std::string root
, std::string relBase
, CFDictionaryRef rulesDict
)
276 typedef ResourceBuilder::Rule Rule
;
278 secdebug("codesign", "start building resource directory");
279 __block CFRef
<CFMutableDictionaryRef
> result
= makeCFMutableDictionary();
281 CFDictionaryRef rules
= cfget
<CFDictionaryRef
>(rulesDict
, "rules");
284 CFDictionaryRef files2
= NULL
;
285 if (!(state
.signingFlags() & kSecCSSignV1
)) {
286 CFCopyRef
<CFDictionaryRef
> rules2
= cfget
<CFDictionaryRef
>(rulesDict
, "rules2");
288 // Clone V1 rules and add default nesting rules at weight 0 (overridden by anything in rules).
289 // V1 rules typically do not cover these places so we'll prevail, but if they do, we defer to them.
290 rules2
= cfmake
<CFDictionaryRef
>("{+%O"
291 "'^[^/]+$' = {top=#T, weight=0}" // files directly in Contents
292 "'^(Frameworks|SharedFrameworks|Plugins|Plug-ins|XPCServices|Helpers|MacOS)/' = {nested=#T, weight=0}" // exclude dynamic repositories
295 // build the modern (V2) resource seal
296 __block CFRef
<CFMutableDictionaryRef
> files
= makeCFMutableDictionary();
297 ResourceBuilder
resourceBuilder(root
, relBase
, rules2
, digestAlgorithm(), strict
, MacOSErrorSet());
298 ResourceBuilder
&resources
= resourceBuilder
; // (into block)
299 rep
->adjustResources(resources
);
300 resources
.scan(^(FTSENT
*ent
, uint32_t ruleFlags
, const char *relpath
, Rule
*rule
) {
301 CFRef
<CFMutableDictionaryRef
> seal
;
302 if (ruleFlags
& ResourceBuilder::nested
) {
303 seal
.take(signNested(ent
, relpath
));
304 } else if (ent
->fts_info
== FTS_SL
) {
305 char target
[PATH_MAX
];
306 ssize_t len
= ::readlink(ent
->fts_accpath
, target
, sizeof(target
)-1);
308 UnixError::check(-1);
310 seal
.take(cfmake
<CFMutableDictionaryRef
>("{symlink=%s}", target
));
312 seal
.take(cfmake
<CFMutableDictionaryRef
>("{hash=%O}",
313 CFRef
<CFDataRef
>(resources
.hashFile(ent
->fts_accpath
)).get()));
315 if (ruleFlags
& ResourceBuilder::optional
)
316 CFDictionaryAddValue(seal
, CFSTR("optional"), kCFBooleanTrue
);
318 if ((hash
= CFDictionaryGetValue(seal
, CFSTR("hash"))) && CFDictionaryGetCount(seal
) == 1) // simple form
319 CFDictionaryAddValue(files
, CFTempString(relpath
).get(), hash
);
321 CFDictionaryAddValue(files
, CFTempString(relpath
).get(), seal
.get());
323 CFDictionaryAddValue(result
, CFSTR("rules2"), resourceBuilder
.rules());
325 CFDictionaryAddValue(result
, CFSTR("files2"), files2
);
328 CFDictionaryAddValue(result
, CFSTR("rules"), rules
); // preserve V1 rules in any case
329 if (!(state
.signingFlags() & kSecCSSignNoV1
)) {
330 // build the legacy (V1) resource seal
331 __block CFRef
<CFMutableDictionaryRef
> files
= makeCFMutableDictionary();
332 ResourceBuilder
resourceBuilder(root
, relBase
, rules
, digestAlgorithm(), strict
, MacOSErrorSet());
333 ResourceBuilder
&resources
= resourceBuilder
;
334 rep
->adjustResources(resources
); // DiskRep-specific adjustments
335 resources
.scan(^(FTSENT
*ent
, uint32_t ruleFlags
, const char *relpath
, Rule
*rule
) {
336 if (ent
->fts_info
== FTS_F
) {
337 CFRef
<CFDataRef
> hash
;
338 if (files2
) // try to get the hash from a previously-made version
339 if (CFTypeRef seal
= CFDictionaryGetValue(files2
, CFTempString(relpath
))) {
340 if (CFGetTypeID(seal
) == CFDataGetTypeID())
341 hash
= CFDataRef(seal
);
343 hash
= CFDataRef(CFDictionaryGetValue(CFDictionaryRef(seal
), CFSTR("hash")));
346 hash
.take(resources
.hashFile(ent
->fts_accpath
));
347 if (ruleFlags
== 0) { // default case - plain hash
348 cfadd(files
, "{%s=%O}", relpath
, hash
.get());
349 secdebug("csresource", "%s added simple (rule %p)", relpath
, rule
);
350 } else { // more complicated - use a sub-dictionary
351 cfadd(files
, "{%s={hash=%O,optional=%B}}",
352 relpath
, hash
.get(), ruleFlags
& ResourceBuilder::optional
);
353 secdebug("csresource", "%s added complex (rule %p)", relpath
, rule
);
357 CFDictionaryAddValue(result
, CFSTR("files"), files
.get());
360 resourceDirectory
= result
.get();
361 resourceDictData
.take(makeCFData(resourceDirectory
.get()));
366 // Deal with one piece of nested code
368 CFMutableDictionaryRef
SecCodeSigner::Signer::signNested(FTSENT
*ent
, const char *relpath
)
370 // sign nested code and collect nesting information
372 SecPointer
<SecStaticCode
> code
= new SecStaticCode(DiskRep::bestGuess(ent
->fts_path
));
373 if (state
.signingFlags() & kSecCSSignNestedCode
)
374 this->state
.sign(code
, state
.signingFlags());
375 std::string dr
= Dumper::dump(code
->designatedRequirement());
376 return cfmake
<CFMutableDictionaryRef
>("{requirement=%s,cdhash=%O}",
377 Dumper::dump(code
->designatedRequirement()).c_str(),
379 } catch (const CommonError
&err
) {
380 CSError::throwMe(err
.osStatus(), kSecCFErrorPath
, CFTempURL(relpath
, false, this->code
->resourceBase()));
386 // Sign a Mach-O binary, using liberal dollops of that special Mach-O magic sauce.
387 // Note that this will deal just fine with non-fat Mach-O binaries, but it will
388 // treat them as architectural binaries containing (only) one architecture - that
389 // interpretation is courtesy of the Universal/MachO support classes.
391 void SecCodeSigner::Signer::signMachO(Universal
*fat
, const Requirement::Context
&context
)
393 // Mach-O executable at the core - perform multi-architecture signing
394 auto_ptr
<ArchEditor
> editor(state
.mDetached
395 ? static_cast<ArchEditor
*>(new BlobEditor(*fat
, *this))
396 : new MachOEditor(rep
->writer(), *fat
, this->digestAlgorithm(), rep
->mainExecutablePath()));
397 assert(editor
->count() > 0);
398 if (!editor
->attribute(writerNoGlobal
)) // can store architecture-common components
401 // pass 1: prepare signature blobs and calculate sizes
402 for (MachOEditor::Iterator it
= editor
->begin(); it
!= editor
->end(); ++it
) {
403 MachOEditor::Arch
&arch
= *it
->second
;
404 arch
.source
.reset(fat
->architecture(it
->first
));
405 arch
.ireqs(requirements
, rep
->defaultRequirements(&arch
.architecture
, state
), context
);
406 if (editor
->attribute(writerNoGlobal
)) // can't store globally, add per-arch
408 populate(arch
.cdbuilder
, arch
, arch
.ireqs
,
409 arch
.source
->offset(), arch
.source
->signingExtent());
411 // add identification blob (made from this architecture) only if we're making a detached signature
412 if (state
.mDetached
) {
413 CFRef
<CFDataRef
> identification
= MachORep::identificationFor(arch
.source
.get());
414 arch
.add(cdIdentificationSlot
, BlobWrapper::alloc(
415 CFDataGetBytePtr(identification
), CFDataGetLength(identification
)));
418 // prepare SuperBlob size estimate
419 size_t cdSize
= arch
.cdbuilder
.size(CodeDirectory::currentVersion
);
420 arch
.blobSize
= arch
.size(cdSize
, state
.mCMSSize
, 0);
425 // pass 2: Finish and generate signatures, and write them
426 for (MachOEditor::Iterator it
= editor
->begin(); it
!= editor
->end(); ++it
) {
427 MachOEditor::Arch
&arch
= *it
->second
;
430 // finish CodeDirectory (off new binary) and sign it
431 CodeDirectory
*cd
= arch
.cdbuilder
.build();
432 CFRef
<CFDataRef
> signature
= signCodeDirectory(cd
);
434 // complete the SuperBlob
435 arch
.add(cdCodeDirectorySlot
, cd
); // takes ownership
436 arch
.add(cdSignatureSlot
, BlobWrapper::alloc(
437 CFDataGetBytePtr(signature
), CFDataGetLength(signature
)));
438 if (!state
.mDryRun
) {
439 EmbeddedSignatureBlob
*blob
= arch
.make();
440 editor
->write(arch
, blob
); // takes ownership of blob
444 // done: write edit copy back over the original
451 // Sign a binary that has no notion of architecture.
452 // That currently means anything that isn't Mach-O format.
454 void SecCodeSigner::Signer::signArchitectureAgnostic(const Requirement::Context
&context
)
456 // non-Mach-O executable - single-instance signing
457 RefPointer
<DiskRep::Writer
> writer
= state
.mDetached
?
458 (new DetachedBlobWriter(*this)) : rep
->writer();
459 CodeDirectory::Builder
builder(state
.mDigestAlgorithm
);
460 InternalRequirements ireqs
;
461 ireqs(requirements
, rep
->defaultRequirements(NULL
, state
), context
);
463 populate(builder
, *writer
, ireqs
, rep
->signingBase(), rep
->signingLimit());
465 // add identification blob (made from this architecture) only if we're making a detached signature
466 if (state
.mDetached
) {
467 CFRef
<CFDataRef
> identification
= rep
->identification();
468 writer
->component(cdIdentificationSlot
, identification
);
471 CodeDirectory
*cd
= builder
.build();
472 CFRef
<CFDataRef
> signature
= signCodeDirectory(cd
);
473 if (!state
.mDryRun
) {
474 writer
->codeDirectory(cd
);
475 writer
->signature(signature
);
483 // Global populate - send components to destination buffers ONCE
485 void SecCodeSigner::Signer::populate(DiskRep::Writer
&writer
)
487 if (resourceDirectory
&& !state
.mDryRun
)
488 writer
.component(cdResourceDirSlot
, resourceDictData
);
493 // Per-architecture populate - send components to per-architecture buffers
494 // and populate the CodeDirectory for an architecture. In architecture-agnostic
495 // signing operations, the non-architectural binary is considered one (arbitrary) architecture
496 // for the purposes of this call.
498 void SecCodeSigner::Signer::populate(CodeDirectory::Builder
&builder
, DiskRep::Writer
&writer
,
499 InternalRequirements
&ireqs
, size_t offset
/* = 0 */, size_t length
/* = 0 */)
501 // fill the CodeDirectory
502 builder
.executable(rep
->mainExecutablePath(), pagesize
, offset
, length
);
503 builder
.flags(cdFlags
);
504 builder
.identifier(identifier
);
505 builder
.teamID(teamID
);
507 if (CFRef
<CFDataRef
> data
= rep
->component(cdInfoSlot
))
508 builder
.specialSlot(cdInfoSlot
, data
);
510 CFRef
<CFDataRef
> data
= makeCFData(*ireqs
);
511 writer
.component(cdRequirementsSlot
, data
);
512 builder
.specialSlot(cdRequirementsSlot
, data
);
514 if (resourceDirectory
)
515 builder
.specialSlot(cdResourceDirSlot
, resourceDictData
);
517 if (state
.mApplicationData
)
518 builder
.specialSlot(cdApplicationSlot
, state
.mApplicationData
);
521 writer
.component(cdEntitlementSlot
, entitlements
);
522 builder
.specialSlot(cdEntitlementSlot
, entitlements
);
525 writer
.addDiscretionary(builder
);
528 #include <security_smime/tsaSupport.h>
531 // Generate the CMS signature for a (finished) CodeDirectory.
533 CFDataRef
SecCodeSigner::Signer::signCodeDirectory(const CodeDirectory
*cd
)
535 assert(state
.mSigner
);
536 CFRef
<CFMutableDictionaryRef
> defaultTSContext
= NULL
;
538 // a null signer generates a null signature blob
539 if (state
.mSigner
== SecIdentityRef(kCFNull
))
540 return CFDataCreate(NULL
, NULL
, 0);
542 // generate CMS signature
543 CFRef
<CMSEncoderRef
> cms
;
544 MacOSError::check(CMSEncoderCreate(&cms
.aref()));
545 MacOSError::check(CMSEncoderSetCertificateChainMode(cms
, kCMSCertificateChainWithRoot
));
546 CMSEncoderAddSigners(cms
, state
.mSigner
);
547 MacOSError::check(CMSEncoderSetHasDetachedContent(cms
, true));
550 MacOSError::check(CMSEncoderAddSignedAttributes(cms
, kCMSAttrSigningTime
));
551 MacOSError::check(CMSEncoderSetSigningTime(cms
, signingTime
));
554 MacOSError::check(CMSEncoderUpdateContent(cms
, cd
, cd
->length()));
556 // Set up to call Timestamp server if requested
558 if (state
.mWantTimeStamp
)
560 CFRef
<CFErrorRef
> error
= NULL
;
561 defaultTSContext
= SecCmsTSAGetDefaultContext(&error
.aref());
563 MacOSError::throwMe(errSecDataNotAvailable
);
565 if (state
.mNoTimeStampCerts
|| state
.mTimestampService
) {
566 if (state
.mTimestampService
)
567 CFDictionarySetValue(defaultTSContext
, kTSAContextKeyURL
, state
.mTimestampService
);
568 if (state
.mNoTimeStampCerts
)
569 CFDictionarySetValue(defaultTSContext
, kTSAContextKeyNoCerts
, kCFBooleanTrue
);
572 CmsMessageSetTSAContext(cms
, defaultTSContext
);
576 MacOSError::check(CMSEncoderCopyEncodedContent(cms
, &signature
));
583 // Parse a text of the form
585 // where each flag is the canonical name of a signable CodeDirectory flag.
586 // No abbreviations are allowed, and internally set flags are not accepted.
588 uint32_t SecCodeSigner::Signer::cdTextFlags(std::string text
)
591 for (string::size_type comma
= text
.find(','); ; text
= text
.substr(comma
+1), comma
= text
.find(',')) {
592 string word
= (comma
== string::npos
) ? text
: text
.substr(0, comma
);
593 const SecCodeDirectoryFlagTable
*item
;
594 for (item
= kSecCodeDirectoryFlagTable
; item
->name
; item
++)
595 if (item
->signable
&& word
== item
->name
) {
596 flags
|= item
->value
;
599 if (!item
->name
) // not found
600 MacOSError::throwMe(errSecCSInvalidFlags
);
601 if (comma
== string::npos
) // last word
609 // Generate a unique string from our underlying DiskRep.
610 // We could get 90%+ of the uniquing benefit by just generating
611 // a random string here. Instead, we pick the (hex string encoding of)
612 // the source rep's unique identifier blob. For universal binaries,
613 // this is the canonical local architecture, which is a bit arbitrary.
614 // This provides us with a consistent unique string for all architectures
615 // of a fat binary, *and* (unlike a random string) is reproducible
616 // for identical inputs, even upon resigning.
618 std::string
SecCodeSigner::Signer::uniqueName() const
620 CFRef
<CFDataRef
> identification
= rep
->identification();
621 const UInt8
*ident
= CFDataGetBytePtr(identification
);
622 const CFIndex length
= CFDataGetLength(identification
);
624 for (CFIndex n
= 0; n
< length
; n
++) {
626 snprintf(hex
, sizeof(hex
), "%02x", ident
[n
]);
633 } // end namespace CodeSigning
634 } // end namespace Security