X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/6b200bc335dc93c5516ccb52f14bd896d8c7fad7..7e6b461318c8a779d91381531435a68ee4e8b6ed:/OSX/libsecurity_codesigning/lib/signer.cpp diff --git a/OSX/libsecurity_codesigning/lib/signer.cpp b/OSX/libsecurity_codesigning/lib/signer.cpp index e03321cc..89279238 100644 --- a/OSX/libsecurity_codesigning/lib/signer.cpp +++ b/OSX/libsecurity_codesigning/lib/signer.cpp @@ -24,6 +24,8 @@ // // signer - Signing operation supervisor and controller // +#include "bundlediskrep.h" +#include "der_plist.h" #include "signer.h" #include "resources.h" #include "signerutils.h" @@ -106,6 +108,10 @@ void SecCodeSigner::Signer::remove(SecCSFlags flags) MacOSError::throwMe(errSecCSNotSupported); rep = code->diskRep(); + + if (state.mPreserveAFSC) + rep->writer()->setPreserveAFSC(state.mPreserveAFSC); + if (Universal *fat = state.mNoMachO ? NULL : rep->mainExecutableImage()) { // architecture-sensitive removal MachOEditor editor(rep->writer(), *fat, digestAlgorithms(), rep->mainExecutablePath()); @@ -168,6 +174,8 @@ void SecCodeSigner::Signer::prepare(SecCSFlags flags) entitlements = state.mEntitlementData; if (!entitlements && (inherit & kSecCodeSignerPreserveEntitlements)) entitlements = code->component(cdEntitlementSlot); + + generateEntitlementDER = signingFlags() & kSecCSSignGenerateEntitlementDER; // work out the CodeDirectory flags word bool haveCdFlags = false; @@ -198,7 +206,8 @@ void SecCodeSigner::Signer::prepare(SecCSFlags flags) } if (!haveCdFlags) cdFlags = 0; - if (state.mSigner == SecIdentityRef(kCFNull)) // ad-hoc signing requested... + if ((state.mSigner == SecIdentityRef(kCFNull)) && + !state.mOmitAdhocFlag) // ad-hoc signing requested... cdFlags |= kSecCodeSignatureAdhoc; // ... so note that // prepare the internal requirements input @@ -291,8 +300,88 @@ void SecCodeSigner::Signer::prepare(SecCSFlags flags) if (!rpath.empty()) { buildResources(rrpath, rpath, resourceRules); } + + + + if (inherit & kSecCodeSignerPreservePEH) { + /* We need at least one architecture in all cases because we index our + * PreEncryptionMaps by architecture. However, only machOs have any + * architecture at all, for generic targets there will just be one + * PreEncryptionHashMap. + * So if the main executable is not a machO, we just choose the local + * (signer's) main architecture as dummy value for the first element in our pair. */ + preEncryptMainArch = (code->diskRep()->mainExecutableIsMachO() ? + code->diskRep()->mainExecutableImage()->bestNativeArch() : + Architecture::local()); + + addPreEncryptHashes(preEncryptHashMaps[preEncryptMainArch], code); + + code->handleOtherArchitectures(^(Security::CodeSigning::SecStaticCode *subcode) { + Universal *fat = subcode->diskRep()->mainExecutableImage(); + assert(fat && fat->narrowed()); // handleOtherArchitectures gave us a focused architecture slice. + Architecture arch = fat->bestNativeArch(); // actually, only architecture for this slice. + addPreEncryptHashes(preEncryptHashMaps[arch], subcode); + }); + } + + if (inherit & kSecCodeSignerPreserveRuntime) { + /* We need at least one architecture in all cases because we index our + * RuntimeVersionMaps by architecture. However, only machOs have any + * architecture at all, for generic targets there will just be one + * RuntimeVersionMap. + * So if the main executable is not a machO, we just choose the local + * (signer's) main architecture as dummy value for the first element in our pair. */ + runtimeVersionMainArch = (code->diskRep()->mainExecutableIsMachO() ? + code->diskRep()->mainExecutableImage()->bestNativeArch() : + Architecture::local()); + + addRuntimeVersions(runtimeVersionMap[runtimeVersionMainArch], code); + + code->handleOtherArchitectures(^(Security::CodeSigning::SecStaticCode *subcode) { + Universal *fat = subcode->diskRep()->mainExecutableImage(); + assert(fat && fat->narrowed()); // handleOtherArchitectures gave us a focused architecture slice. + Architecture arch = fat->bestNativeArch(); // actually, only architecture for this slice. + addRuntimeVersions(runtimeVersionMap[arch], subcode); + }); + } } +void SecCodeSigner::Signer::addPreEncryptHashes(PreEncryptHashMap &map, SecStaticCode const *code) { + SecStaticCode::CodeDirectoryMap const *cds = code->codeDirectories(); + + if (cds != NULL) { + for(auto const& pair : *cds) { + CodeDirectory::HashAlgorithm const alg = pair.first; + CFDataRef const cddata = pair.second; + + CodeDirectory const * cd = + reinterpret_cast(CFDataGetBytePtr(cddata)); + if (cd->preEncryptHashes() != NULL) { + CFRef preEncrypt = makeCFData(cd->preEncryptHashes(), + cd->nCodeSlots * cd->hashSize); + map[alg] = preEncrypt; + } + } + } +} + +void SecCodeSigner::Signer::addRuntimeVersions(RuntimeVersionMap &map, const SecStaticCode *code) +{ + SecStaticCode::CodeDirectoryMap const *cds = code->codeDirectories(); + + if (cds != NULL) { + for(auto const& pair : *cds) { + CodeDirectory::HashAlgorithm const alg = pair.first; + CFDataRef const cddata = pair.second; + + CodeDirectory const * cd = + reinterpret_cast(CFDataGetBytePtr(cddata)); + if (cd->runtimeVersion()) { + map[alg] = cd->runtimeVersion(); + } + } + } +} // // Collect the resource seal for a program. @@ -320,7 +409,8 @@ void SecCodeSigner::Signer::buildResources(std::string root, std::string relBase if (!(signingFlags() & kSecCSSignV1)) { CFCopyRef rules2 = cfget(rulesDict, "rules2"); if (!rules2) { - // Clone V1 rules and add default nesting rules at weight 0 (overridden by anything in rules). + // Clone V1 rules and add default nesting rules at weight 0 (overridden by anything in rules, + // because the default weight, according to ResourceBuilder::addRule(), is 1). // V1 rules typically do not cover these places so we'll prevail, but if they do, we defer to them. rules2 = cfmake("{+%O" "'^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/' = {nested=#T, weight=0}" // exclude dynamic repositories @@ -441,6 +531,10 @@ void SecCodeSigner::Signer::signMachO(Universal *fat, const Requirement::Context { // Mach-O executable at the core - perform multi-architecture signing RefPointer writer = rep->writer(); + + if (state.mPreserveAFSC) + writer->setPreserveAFSC(state.mPreserveAFSC); + auto_ptr editor(state.mDetached ? static_cast(new BlobEditor(*fat, *this)) : new MachOEditor(writer, *fat, this->digestAlgorithms(), rep->mainExecutablePath())); @@ -459,14 +553,30 @@ void SecCodeSigner::Signer::signMachO(Universal *fat, const Requirement::Context MacOSError::throwMe(errSecCSBadLVArch); } } - + + bool mainBinary = arch.source.get()->type() == MH_EXECUTE; + + uint32_t runtimeVersion = 0; + if (cdFlags & kSecCodeSignatureRuntime) { + runtimeVersion = state.mRuntimeVersionOverride ? state.mRuntimeVersionOverride : arch.source.get()->sdkVersion(); + } + arch.ireqs(requirements, rep->defaultRequirements(&arch.architecture, *this), context); if (editor->attribute(writerNoGlobal)) // can't store globally, add per-arch populate(arch); for (auto type = digestAlgorithms().begin(); type != digestAlgorithms().end(); ++type) { + uint32_t runtimeVersionToUse = runtimeVersion; + if ((cdFlags & kSecCodeSignatureRuntime) && runtimeVersionMap.count(arch.architecture)) { + if (runtimeVersionMap[arch.architecture].count(*type)) { + runtimeVersionToUse = runtimeVersionMap[arch.architecture][*type]; + } + } arch.eachDigest(^(CodeDirectory::Builder& builder) { populate(builder, arch, arch.ireqs, - arch.source->offset(), arch.source->signingExtent(), unsigned(digestAlgorithms().size()-1)); + arch.source->offset(), arch.source->signingExtent(), + mainBinary, rep->execSegBase(&(arch.architecture)), rep->execSegLimit(&(arch.architecture)), + unsigned(digestAlgorithms().size()-1), + preEncryptHashMaps[arch.architecture], runtimeVersionToUse); }); } @@ -498,10 +608,10 @@ void SecCodeSigner::Signer::signMachO(Universal *fat, const Requirement::Context CodeDirectory *cd = builder.build(); cdSet.add(cd); }); - CFRef hashes = cdSet.hashBag(); - CFTemp hashDict("{cdhashes=%O}", hashes.get()); - CFRef hashBag = makeCFData(hashDict.get()); - CFRef signature = signCodeDirectory(cdSet.primary(), hashBag); + + CFRef hashDict = cdSet.hashDict(); + CFRef hashList = cdSet.hashList(); + CFRef signature = signCodeDirectory(cdSet.primary(), hashDict, hashList); // complete the SuperBlob cdSet.populate(&arch); @@ -529,14 +639,23 @@ void SecCodeSigner::Signer::signArchitectureAgnostic(const Requirement::Context // non-Mach-O executable - single-instance signing RefPointer writer = state.mDetached ? (new DetachedBlobWriter(*this)) : rep->writer(); - + + if(state.mPreserveAFSC) + writer->setPreserveAFSC(state.mPreserveAFSC); + CodeDirectorySet cdSet; + for (auto type = digestAlgorithms().begin(); type != digestAlgorithms().end(); ++type) { CodeDirectory::Builder builder(*type); InternalRequirements ireqs; ireqs(requirements, rep->defaultRequirements(NULL, *this), context); populate(*writer); - populate(builder, *writer, ireqs, rep->signingBase(), rep->signingLimit(), unsigned(digestAlgorithms().size()-1)); + populate(builder, *writer, ireqs, rep->signingBase(), rep->signingLimit(), + false, // only machOs can currently be main binaries + rep->execSegBase(NULL), rep->execSegLimit(NULL), + unsigned(digestAlgorithms().size()-1), + preEncryptHashMaps[preEncryptMainArch], // Only one map, the default. + (cdFlags & kSecCodeSignatureRuntime) ? state.mRuntimeVersionOverride : 0); CodeDirectory *cd = builder.build(); if (!state.mDryRun) @@ -553,10 +672,9 @@ void SecCodeSigner::Signer::signArchitectureAgnostic(const Requirement::Context if (!state.mDryRun) cdSet.populate(writer); - CFRef hashes = cdSet.hashBag(); - CFTemp hashDict("{cdhashes=%O}", hashes.get()); - CFRef hashBag = makeCFData(hashDict.get()); - CFRef signature = signCodeDirectory(cdSet.primary(), hashBag); + CFRef hashDict = cdSet.hashDict(); + CFRef hashList = cdSet.hashList(); + CFRef signature = signCodeDirectory(cdSet.primary(), hashDict, hashList); writer->signature(signature); // commit to storage @@ -581,7 +699,11 @@ void SecCodeSigner::Signer::populate(DiskRep::Writer &writer) // for the purposes of this call. // void SecCodeSigner::Signer::populate(CodeDirectory::Builder &builder, DiskRep::Writer &writer, - InternalRequirements &ireqs, size_t offset, size_t length, unsigned alternateDigestCount) + InternalRequirements &ireqs, size_t offset, size_t length, + bool mainBinary, size_t execSegBase, size_t execSegLimit, + unsigned alternateDigestCount, + PreEncryptHashMap const &preEncryptHashMap, + uint32_t runtimeVersion) { // fill the CodeDirectory builder.executable(rep->mainExecutablePath(), pagesize, offset, length); @@ -589,6 +711,10 @@ void SecCodeSigner::Signer::populate(CodeDirectory::Builder &builder, DiskRep::W builder.identifier(identifier); builder.teamID(teamID); builder.platform(state.mPlatform); + builder.execSeg(execSegBase, execSegLimit, mainBinary ? kSecCodeExecSegMainBinary : 0); + builder.generatePreEncryptHashes(signingFlags() & kSecCSSignGeneratePEH); + builder.preservePreEncryptHashMap(preEncryptHashMap); + builder.runTimeVersion(runtimeVersion); if (CFRef data = rep->component(cdInfoSlot)) builder.specialSlot(cdInfoSlot, data); @@ -602,6 +728,20 @@ void SecCodeSigner::Signer::populate(CodeDirectory::Builder &builder, DiskRep::W if (entitlements) { writer.component(cdEntitlementSlot, entitlements); builder.specialSlot(cdEntitlementSlot, entitlements); + + if (mainBinary) { + CFRef entitlementDER; + uint64_t execSegFlags = 0; + cookEntitlements(entitlements, generateEntitlementDER, + &execSegFlags, &entitlementDER.aref()); + + if (generateEntitlementDER) { + writer.component(cdEntitlementDERSlot, entitlementDER); + builder.specialSlot(cdEntitlementDERSlot, entitlementDER); + } + + builder.addExecSegFlags(execSegFlags); + } } if (CFRef repSpecific = rep->component(cdRepSpecificSlot)) builder.specialSlot(cdRepSpecificSlot, repSpecific); @@ -633,7 +773,9 @@ void SecCodeSigner::Signer::populate(CodeDirectory::Builder &builder, DiskRep::W // // Generate the CMS signature for a (finished) CodeDirectory. // -CFDataRef SecCodeSigner::Signer::signCodeDirectory(const CodeDirectory *cd, CFDataRef hashBag) +CFDataRef SecCodeSigner::Signer::signCodeDirectory(const CodeDirectory *cd, + CFDictionaryRef hashDict, + CFArrayRef hashList) { assert(state.mSigner); CFRef defaultTSContext = NULL; @@ -645,7 +787,7 @@ CFDataRef SecCodeSigner::Signer::signCodeDirectory(const CodeDirectory *cd, CFDa // generate CMS signature CFRef cms; MacOSError::check(CMSEncoderCreate(&cms.aref())); - MacOSError::check(CMSEncoderSetCertificateChainMode(cms, kCMSCertificateChainWithRoot)); + MacOSError::check(CMSEncoderSetCertificateChainMode(cms, kCMSCertificateChainWithRootOrFail)); CMSEncoderAddSigners(cms, state.mSigner); CMSEncoderSetSignerAlgorithm(cms, kCMSEncoderDigestAlgorithmSHA256); MacOSError::check(CMSEncoderSetHasDetachedContent(cms, true)); @@ -656,9 +798,21 @@ CFDataRef SecCodeSigner::Signer::signCodeDirectory(const CodeDirectory *cd, CFDa MacOSError::check(CMSEncoderSetSigningTime(cms, time)); } - if (hashBag) { + if (hashDict != NULL) { + assert(hashList != NULL); + + // V2 Hash Agility + + MacOSError::check(CMSEncoderAddSignedAttributes(cms, kCMSAttrAppleCodesigningHashAgilityV2)); + MacOSError::check(CMSEncoderSetAppleCodesigningHashAgilityV2(cms, hashDict)); + + // V1 Hash Agility + + CFTemp hashDict("{cdhashes=%O}", hashList); + CFRef hashAgilityV1Attribute = makeCFData(hashDict.get()); + MacOSError::check(CMSEncoderAddSignedAttributes(cms, kCMSAttrAppleCodesigningHashAgility)); - MacOSError::check(CMSEncoderSetAppleCodesigningHashAgility(cms, hashBag)); + MacOSError::check(CMSEncoderSetAppleCodesigningHashAgility(cms, hashAgilityV1Attribute)); } MacOSError::check(CMSEncoderUpdateContent(cms, cd, cd->length())); @@ -762,6 +916,289 @@ std::string SecCodeSigner::Signer::uniqueName() const return result; } +bool SecCodeSigner::Signer::booleanEntitlement(CFDictionaryRef entDict, CFStringRef key) { + CFBooleanRef entValue = (CFBooleanRef)CFDictionaryGetValue(entDict, key); + + if (entValue == NULL || CFGetTypeID(entValue) != CFBooleanGetTypeID()) { + return false; + } + + return CFBooleanGetValue(entValue); +} + +void SecCodeSigner::Signer::cookEntitlements(CFDataRef entitlements, bool generateDER, + uint64_t *execSegFlags, CFDataRef *entitlementDER) +{ + if (!entitlements) { + return; // nothing to do. + } + + EntitlementDERBlob *derBlob = NULL; + + try { + const EntitlementBlob *blob = reinterpret_cast(CFDataGetBytePtr(entitlements)); + + if (blob == NULL || !blob->validateBlob(CFDataGetLength(entitlements))) { + MacOSError::throwMe(errSecCSInvalidEntitlements); + } + + CFRef entDict = blob->entitlements(); + + if (generateDER) { + CFRef error = NULL; + size_t const der_size = der_sizeof_plist(entDict, &error.aref()); + + if (der_size == 0) { + secerror("Getting DER size for entitlement plist failed: %@", error.get()); + MacOSError::throwMe(errSecCSInvalidEntitlements); + } + + derBlob = EntitlementDERBlob::alloc(der_size); + + if (derBlob == NULL) { + secerror("Cannot allocate buffer for DER entitlements of size %zu", der_size); + MacOSError::throwMe(errSecCSInvalidEntitlements); + } + uint8_t * const der_end = derBlob->der() + der_size; + uint8_t * const der_start = der_encode_plist(entDict, &error.aref(), derBlob->der(), der_end); + + if (der_start != derBlob->der()) { + secerror("Entitlement DER start mismatch (%zu)", (size_t)(der_start - derBlob->der())); + free(derBlob); + MacOSError::throwMe(errSecCSInvalidEntitlements); + } + + *entitlementDER = makeCFData(derBlob, derBlob->length()); + free(derBlob); + derBlob = NULL; + } + + if (execSegFlags != NULL) { + uint64_t flags = 0; + + flags |= booleanEntitlement(entDict, CFSTR("get-task-allow")) ? kSecCodeExecSegAllowUnsigned : 0; + flags |= booleanEntitlement(entDict, CFSTR("run-unsigned-code")) ? kSecCodeExecSegAllowUnsigned : 0; + flags |= booleanEntitlement(entDict, CFSTR("com.apple.private.cs.debugger")) ? kSecCodeExecSegDebugger : 0; + flags |= booleanEntitlement(entDict, CFSTR("dynamic-codesigning")) ? kSecCodeExecSegJit : 0; + flags |= booleanEntitlement(entDict, CFSTR("com.apple.private.skip-library-validation")) ? kSecCodeExecSegSkipLibraryVal : 0; + flags |= booleanEntitlement(entDict, CFSTR("com.apple.private.amfi.can-load-cdhash")) ? kSecCodeExecSegCanLoadCdHash : 0; + flags |= booleanEntitlement(entDict, CFSTR("com.apple.private.amfi.can-execute-cdhash")) ? kSecCodeExecSegCanExecCdHash : 0; + + *execSegFlags = flags; + } + + } catch (const CommonError &err) { + free(derBlob); + // Not fatal if we're not asked to generate DER entitlements. + + secwarning("failed to parse entitlements: %s", err.what()); + if (generateDER) { + throw; + } + } +} + +//// Signature Editing + +void SecCodeSigner::Signer::edit(SecCSFlags flags) +{ + rep = code->diskRep()->base(); + + Universal *fat = state.mNoMachO ? NULL : rep->mainExecutableImage(); + + prepareForEdit(flags); + + if (fat != NULL) { + editMachO(fat); + } else { + editArchitectureAgnostic(); + } +} + +EditableDiskRep *SecCodeSigner::Signer::editMainExecutableRep(DiskRep *rep) +{ + EditableDiskRep *mainExecRep = NULL; + BundleDiskRep *bundleDiskRep = dynamic_cast(rep); + + if (bundleDiskRep) { + mainExecRep = dynamic_cast(bundleDiskRep->mainExecRep()); + } + + return mainExecRep; +} + +void SecCodeSigner::Signer::prepareForEdit(SecCSFlags flags) { + setDigestAlgorithms(code->hashAlgorithms()); + + Universal *machO = (code->diskRep()->mainExecutableIsMachO() ? + code->diskRep()->mainExecutableImage() : NULL); + + /* We need at least one architecture in all cases because we index our + * RawComponentMaps by architecture. However, only machOs have any + * architecture at all, for generic targets there will just be one + * RawComponentMap. + * So if the main executable is not a machO, we just choose the local + * (signer's) main architecture as dummy value for the first element in our pair. */ + editMainArch = (machO != NULL ? machO->bestNativeArch() : Architecture::local()); + + if (machO != NULL) { + if (machO->narrowed()) { + /* --arch gives us a narrowed SecStaticCode, but because + * codesign_allocate always creates or replaces signatures + * for all slices, we must operate on the universal + * SecStaticCode. Instead, we provide --edit-arch to specify + * which slices to edit, the others have their code signature + * copied without modifications. + */ + MacOSError::throwMe(errSecCSNotSupported, + "Signature editing must be performed on universal binary instead of narrow slice (using --edit-arch instead of --arch)."); + } + + if (state.mEditArch && !machO->isUniversal()) { + MacOSError::throwMe(errSecCSInvalidFlags, + "--edit-arch is only valid for universal binaries."); + } + + if (state.mEditCMS && machO->isUniversal() && !state.mEditArch) { + /* Each slice has its own distinct code signature, + * so a CMS blob is only valid for its one slice. + * Therefore, replacing all CMS blobs in all slices + * with the same blob is rather nonsensical, and we refuse. + * + * (Universal binaries with only one slice can exist, + * and in that case the slice to operate on would be + * umambiguous, but we are not treating those binaries + * specially and still want --edit-arch for consistency.) + */ + MacOSError::throwMe(errSecCSNotSupported, + "CMS editing must be performed on specific slice (specified with --edit-arch)."); + } + } + + void (^editArch)(SecStaticCode *code, Architecture arch) = + ^(SecStaticCode *code, Architecture arch) { + EditableDiskRep *editRep = dynamic_cast(code->diskRep()); + + if (editRep == NULL) { + MacOSError::throwMe(errSecCSNotSupported, + "Signature editing not supported for code of this type."); + } + + EditableDiskRep *mainExecRep = editMainExecutableRep(code->diskRep()); + + if (mainExecRep != NULL) { + // Delegate editing to the main executable if it is an EditableDiskRep. + //(Which is the case for machOs.) + editRep = mainExecRep; + } + + editComponents[arch] = std::make_unique(editRep->createRawComponents()); + + if (!state.mEditArch || arch == state.mEditArch) { + if (state.mEditCMS) { + CFDataRef cms = state.mEditCMS.get(); + (*editComponents[arch])[cdSignatureSlot] = cms; + } + } + }; + + editArch(code, editMainArch); + + code->handleOtherArchitectures(^(Security::CodeSigning::SecStaticCode *subcode) { + Universal *fat = subcode->diskRep()->mainExecutableImage(); + assert(fat && fat->narrowed()); // handleOtherArchitectures gave us a focused architecture slice. + Architecture arch = fat->bestNativeArch(); // actually, only architecture for this slice. + editArch(subcode, arch); + }); + + /* The resource dictionary is special, because it is + * considered "global" instead of per architecture. + * For editing, that means it's usually not embedded + * in the main executable's signature if it exists, + * but in the containing disk rep (e.g. the + * CodeResources file if the rep is a Bundle). + */ + resourceDictData = rep->component(cdResourceDirSlot); +} + +void SecCodeSigner::Signer::editMachO(Universal *fat) { + // Mach-O executable at the core - perform multi-architecture signature editing + RefPointer writer = rep->writer(); + + if (state.mPreserveAFSC) + writer->setPreserveAFSC(state.mPreserveAFSC); + + unique_ptr editor(new MachOEditor(writer, *fat, + this->digestAlgorithms(), + rep->mainExecutablePath())); + assert(editor->count() > 0); + + if (resourceDictData && !editor->attribute(writerNoGlobal)) { + // For when the resource dict is "global", e.g. for bundles. + editor->component(cdResourceDirSlot, resourceDictData); + } + + for (MachOEditor::Iterator it = editor->begin(); it != editor->end(); ++it) { + MachOEditor::Arch &arch = *it->second; + arch.source.reset(fat->architecture(it->first)); // transfer ownership + + if (resourceDictData && editor->attribute(writerNoGlobal)) { + // Technically possible to embed a resource dict in the embedded sig. + arch.component(cdResourceDirSlot, resourceDictData); + } + + for (auto const &entry : *editComponents[arch.architecture]) { + CodeDirectory::Slot slot = entry.first; + CFDataRef data = entry.second.get(); + arch.component(slot, data); + } + + /* We must preserve the original superblob's size, as the size is + * also in the macho's load commands, which are itself covered + * by the signature. */ + arch.blobSize = arch.source->signingLength(); + } + + editor->allocate(); + + for (MachOEditor::Iterator it = editor->begin(); it != editor->end(); ++it) { + MachOEditor::Arch &arch = *it->second; + editor->reset(arch); + + if (!state.mDryRun) { + EmbeddedSignatureBlob *blob = arch.make(); + editor->write(arch, blob); // takes ownership of blob + } + } + + if (!state.mDryRun) { + editor->commit(); + } + +} + +void SecCodeSigner::Signer::editArchitectureAgnostic() +{ + if (state.mDryRun) { + return; + + } + // non-Mach-O executable - single-instance signature editing + RefPointer writer = rep->writer(); + + if(state.mPreserveAFSC) + writer->setPreserveAFSC(state.mPreserveAFSC); + + for (auto const &entry : *editComponents[editMainArch]) { + CodeDirectory::Slot slot = entry.first; + CFDataRef data = entry.second.get(); + + writer->component(slot, data); + } + + // commit to storage + writer->flush(); +} } // end namespace CodeSigning } // end namespace Security