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