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