X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5dd5f9ec28f304ca377c42fd7f711d6cf12b90e1..5c19dc3ae3bd8e40a9c028b0deddd50ff337692c:/Security/libsecurity_codesigning/lib/signer.cpp diff --git a/Security/libsecurity_codesigning/lib/signer.cpp b/Security/libsecurity_codesigning/lib/signer.cpp deleted file mode 100644 index 9c8d02fc..00000000 --- a/Security/libsecurity_codesigning/lib/signer.cpp +++ /dev/null @@ -1,668 +0,0 @@ -/* - * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -// -// signer - Signing operation supervisor and controller -// -#include "signer.h" -#include "resources.h" -#include "signerutils.h" -#include "SecCodeSigner.h" -#include -#include -#include -#include -#include -#include "resources.h" -#include "machorep.h" -#include "reqparser.h" -#include "reqdumper.h" -#include "csutilities.h" -#include -#include -#include -#include -#include - -namespace Security { -namespace CodeSigning { - - -// -// Sign some code. -// -void SecCodeSigner::Signer::sign(SecCSFlags flags) -{ - rep = code->diskRep()->base(); - this->prepare(flags); - - PreSigningContext context(*this); - - /* If an explicit teamID was passed in it must be - the same as what came from the cert */ - std::string teamIDFromCert = state.getTeamIDFromSigner(context.certs); - - if (state.mPreserveMetadata & kSecCodeSignerPreserveTeamIdentifier) { - /* If preserving the team identifier, teamID is set previously when the - code object is still available */ - if (!teamIDFromCert.empty() && teamID != teamIDFromCert) - MacOSError::throwMe(errSecCSInvalidFlags); - } else { - if (teamIDFromCert.empty()) { - /* state.mTeamID is an explicitly passed teamID */ - teamID = state.mTeamID; - } else if (state.mTeamID.empty() || (state.mTeamID == teamIDFromCert)) { - /* If there was no explicit team ID set, or the explicit team ID matches - what is in the cert, use the team ID from the certificate */ - teamID = teamIDFromCert; - } else { - /* The caller passed in an explicit team ID that does not match what is - in the signing cert, which is an invalid usage */ - MacOSError::throwMe(errSecCSInvalidFlags); - } - } - - if (Universal *fat = state.mNoMachO ? NULL : rep->mainExecutableImage()) { - signMachO(fat, context); - } else { - signArchitectureAgnostic(context); - } -} - - -// -// Remove any existing code signature from code -// -void SecCodeSigner::Signer::remove(SecCSFlags flags) -{ - // can't remove a detached signature - if (state.mDetached) - MacOSError::throwMe(errSecCSNotSupported); - - rep = code->diskRep(); - if (Universal *fat = state.mNoMachO ? NULL : rep->mainExecutableImage()) { - // architecture-sensitive removal - MachOEditor editor(rep->writer(), *fat, kSecCodeSignatureNoHash, rep->mainExecutablePath()); - editor.allocate(); // create copy - editor.commit(); // commit change - } else { - // architecture-agnostic removal - RefPointer writer = rep->writer(); - writer->remove(); - writer->flush(); - } -} - - -// -// Contemplate the object-to-be-signed and set up the Signer state accordingly. -// -void SecCodeSigner::Signer::prepare(SecCSFlags flags) -{ - // make sure the rep passes strict validation - if (strict) - rep->strictValidate(NULL, MacOSErrorSet()); - - // initialize progress/cancellation state - code->prepareProgress(0); // totally fake workload - we don't know how many files we'll encounter - - // get the Info.plist out of the rep for some creative defaulting - CFRef infoDict; - if (CFRef infoData = rep->component(cdInfoSlot)) - infoDict.take(makeCFDictionaryFrom(infoData)); - - uint32_t inherit = code->isSigned() ? state.mPreserveMetadata : 0; - - // work out the canonical identifier - identifier = state.mIdentifier; - if (identifier.empty() && (inherit & kSecCodeSignerPreserveIdentifier)) - identifier = code->identifier(); - if (identifier.empty()) { - identifier = rep->recommendedIdentifier(state); - if (identifier.find('.') == string::npos) - identifier = state.mIdentifierPrefix + identifier; - if (identifier.find('.') == string::npos && state.isAdhoc()) - identifier = identifier + "-" + uniqueName(); - secdebug("signer", "using default identifier=%s", identifier.c_str()); - } else - secdebug("signer", "using explicit identifier=%s", identifier.c_str()); - - teamID = state.mTeamID; - if (teamID.empty() && (inherit & kSecCodeSignerPreserveTeamIdentifier)) { - const char *c_id = code->teamID(); - if (c_id) - teamID = c_id; - } - - entitlements = state.mEntitlementData; - if (!entitlements && (inherit & kSecCodeSignerPreserveEntitlements)) - entitlements = code->component(cdEntitlementSlot); - - // work out the CodeDirectory flags word - bool haveCdFlags = false; - if (!haveCdFlags && state.mCdFlagsGiven) { - cdFlags = state.mCdFlags; - secdebug("signer", "using explicit cdFlags=0x%x", cdFlags); - haveCdFlags = true; - } - if (!haveCdFlags) { - cdFlags = 0; - if (infoDict) - if (CFTypeRef csflags = CFDictionaryGetValue(infoDict, CFSTR("CSFlags"))) { - if (CFGetTypeID(csflags) == CFNumberGetTypeID()) { - cdFlags = cfNumber(CFNumberRef(csflags)); - secdebug("signer", "using numeric cdFlags=0x%x from Info.plist", cdFlags); - } else if (CFGetTypeID(csflags) == CFStringGetTypeID()) { - cdFlags = cdTextFlags(cfString(CFStringRef(csflags))); - secdebug("signer", "using text cdFlags=0x%x from Info.plist", cdFlags); - } else - MacOSError::throwMe(errSecCSBadDictionaryFormat); - haveCdFlags = true; - } - } - if (!haveCdFlags && (inherit & kSecCodeSignerPreserveFlags)) { - cdFlags = code->codeDirectory(false)->flags & ~kSecCodeSignatureAdhoc; - secdebug("signer", "using inherited cdFlags=0x%x", cdFlags); - haveCdFlags = true; - } - if (!haveCdFlags) - cdFlags = 0; - if (state.mSigner == SecIdentityRef(kCFNull)) // ad-hoc signing requested... - cdFlags |= kSecCodeSignatureAdhoc; // ... so note that - - // prepare the internal requirements input - if (state.mRequirements) { - if (CFGetTypeID(state.mRequirements) == CFDataGetTypeID()) { // binary form - const Requirements *rp = (const Requirements *)CFDataGetBytePtr(state.mRequirements.as()); - if (!rp->validateBlob()) - MacOSError::throwMe(errSecCSReqInvalid); - requirements = rp->clone(); - } else if (CFGetTypeID(state.mRequirements) == CFStringGetTypeID()) { // text form - CFRef reqText = CFStringCreateMutableCopy(NULL, 0, state.mRequirements.as()); - // substitute $ variable tokens - CFRange range = { 0, CFStringGetLength(reqText) }; - CFStringFindAndReplace(reqText, CFSTR("$self.identifier"), CFTempString(identifier), range, 0); - requirements = parseRequirements(cfString(reqText)); - } else - MacOSError::throwMe(errSecCSInvalidObjectRef); - } else if (inherit & kSecCodeSignerPreserveRequirements) - if (const Requirements *rp = code->internalRequirements()) - requirements = rp->clone(); - - // prepare the resource directory, if any - string rpath = rep->resourcesRootPath(); - if (!rpath.empty()) { - // explicitly given resource rules always win - CFCopyRef resourceRules = state.mResourceRules; - - // inherited rules come next (overriding embedded ones!) - if (!resourceRules && (inherit & kSecCodeSignerPreserveResourceRules)) - if (CFDictionaryRef oldRules = code->resourceDictionary(false)) - resourceRules = oldRules; - - // embedded resource rules come next - if (!resourceRules && infoDict) - if (CFTypeRef spec = CFDictionaryGetValue(infoDict, _kCFBundleResourceSpecificationKey)) { - if (CFGetTypeID(spec) == CFStringGetTypeID()) - if (CFRef data = cfLoadFile(rpath + "/" + cfString(CFStringRef(spec)))) - if (CFDictionaryRef dict = makeCFDictionaryFrom(data)) - resourceRules.take(dict); - if (!resourceRules) // embedded rules present but unacceptable - MacOSError::throwMe(errSecCSResourceRulesInvalid); - } - - // if we got one from anywhere (but the defaults), sanity-check it - if (resourceRules) { - CFTypeRef rules = CFDictionaryGetValue(resourceRules, CFSTR("rules")); - if (!rules || CFGetTypeID(rules) != CFDictionaryGetTypeID()) - MacOSError::throwMe(errSecCSResourceRulesInvalid); - } - - // finally, ask the DiskRep for its default - if (!resourceRules) - resourceRules.take(rep->defaultResourceRules(state)); - - // resource root can optionally be the canonical bundle path, - // but sealed resource paths are always relative to rpath - string root = rpath; - if (state.signingFlags() & kSecCSSignBundleRoot) - root = cfStringRelease(rep->copyCanonicalPath()); - - // build the resource directory - buildResources(root, rpath, resourceRules); - } - - // screen and set the signing time - CFAbsoluteTime now = CFAbsoluteTimeGetCurrent(); - if (state.mSigningTime == CFDateRef(kCFNull)) { - signingTime = 0; // no time at all - } else if (!state.mSigningTime) { - signingTime = now; // default - } else { - CFAbsoluteTime time = CFDateGetAbsoluteTime(state.mSigningTime); - if (time > now) // not allowed to post-date a signature - MacOSError::throwMe(errSecCSBadDictionaryFormat); - signingTime = time; - } - - pagesize = state.mPageSize ? cfNumber(state.mPageSize) : rep->pageSize(state); - - // Timestamping setup - CFRef mTSAuth; // identity for client-side authentication to the Timestamp server -} - - -// -// Collect the resource seal for a program. -// This includes both sealed resources and information about nested code. -// -void SecCodeSigner::Signer::buildResources(std::string root, std::string relBase, CFDictionaryRef rulesDict) -{ - typedef ResourceBuilder::Rule Rule; - - secdebug("codesign", "start building resource directory"); - __block CFRef result = makeCFMutableDictionary(); - - CFDictionaryRef rules = cfget(rulesDict, "rules"); - assert(rules); - - if (this->state.mLimitedAsync == NULL) { - this->state.mLimitedAsync = - /* rdar://problem/20299541: Async workers (i.e. parallelization) are currently - * turned off, because the paths for signing code are not ready for it yet. */ - // new LimitedAsync(rep->fd().mediumType() == kIOPropertyMediumTypeSolidStateKey); - new LimitedAsync(false); - } - - CFDictionaryRef files2 = NULL; - if (!(state.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). - // 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 - "}", rules); - } - - Dispatch::Group group; - Dispatch::Group &groupRef = group; // (into block) - - // build the modern (V2) resource seal - __block CFRef files = makeCFMutableDictionary(); - CFMutableDictionaryRef filesRef = files.get(); // (into block) - ResourceBuilder resourceBuilder(root, relBase, rules2, digestAlgorithm(), strict, MacOSErrorSet()); - ResourceBuilder &resources = resourceBuilder; // (into block) - rep->adjustResources(resources); - - resources.scan(^(FTSENT *ent, uint32_t ruleFlags, const std::string relpath, Rule *rule) { - bool isSymlink = (ent->fts_info == FTS_SL); - const std::string path(ent->fts_path); - const std::string accpath(ent->fts_accpath); - this->state.mLimitedAsync->perform(groupRef, ^{ - CFRef seal; - if (ruleFlags & ResourceBuilder::nested) { - seal.take(signNested(path, relpath)); - } else if (isSymlink) { - char target[PATH_MAX]; - ssize_t len = ::readlink(accpath.c_str(), target, sizeof(target)-1); - if (len < 0) - UnixError::check(-1); - target[len] = '\0'; - seal.take(cfmake("{symlink=%s}", target)); - } else { - seal.take(cfmake("{hash=%O}", - CFRef(resources.hashFile(accpath.c_str())).get())); - } - if (ruleFlags & ResourceBuilder::optional) - CFDictionaryAddValue(seal, CFSTR("optional"), kCFBooleanTrue); - CFTypeRef hash; - StLock _(resourceLock); - if ((hash = CFDictionaryGetValue(seal, CFSTR("hash"))) && CFDictionaryGetCount(seal) == 1) // simple form - CFDictionaryAddValue(filesRef, CFTempString(relpath).get(), hash); - else - CFDictionaryAddValue(filesRef, CFTempString(relpath).get(), seal.get()); - code->reportProgress(); - }); - }); - group.wait(); - CFDictionaryAddValue(result, CFSTR("rules2"), resourceBuilder.rules()); - files2 = files; - CFDictionaryAddValue(result, CFSTR("files2"), files2); - } - - CFDictionaryAddValue(result, CFSTR("rules"), rules); // preserve V1 rules in any case - if (!(state.signingFlags() & kSecCSSignNoV1)) { - // build the legacy (V1) resource seal - __block CFRef files = makeCFMutableDictionary(); - ResourceBuilder resourceBuilder(root, relBase, rules, digestAlgorithm(), strict, MacOSErrorSet()); - ResourceBuilder &resources = resourceBuilder; - rep->adjustResources(resources); // DiskRep-specific adjustments - resources.scan(^(FTSENT *ent, uint32_t ruleFlags, std::string relpath, Rule *rule) { - if (ent->fts_info == FTS_F) { - CFRef hash; - if (files2) // try to get the hash from a previously-made version - if (CFTypeRef seal = CFDictionaryGetValue(files2, CFTempString(relpath))) { - if (CFGetTypeID(seal) == CFDataGetTypeID()) - hash = CFDataRef(seal); - else - hash = CFDataRef(CFDictionaryGetValue(CFDictionaryRef(seal), CFSTR("hash"))); - } - if (!hash) - hash.take(resources.hashFile(ent->fts_accpath)); - if (ruleFlags == 0) { // default case - plain hash - cfadd(files, "{%s=%O}", relpath.c_str(), hash.get()); - secdebug("csresource", "%s added simple (rule %p)", relpath.c_str(), rule); - } else { // more complicated - use a sub-dictionary - cfadd(files, "{%s={hash=%O,optional=%B}}", - relpath.c_str(), hash.get(), ruleFlags & ResourceBuilder::optional); - secdebug("csresource", "%s added complex (rule %p)", relpath.c_str(), rule); - } - } - }); - CFDictionaryAddValue(result, CFSTR("files"), files.get()); - } - - resourceDirectory = result.get(); - resourceDictData.take(makeCFData(resourceDirectory.get())); -} - - -// -// Deal with one piece of nested code -// -CFMutableDictionaryRef SecCodeSigner::Signer::signNested(const std::string &path, const std::string &relpath) -{ - // sign nested code and collect nesting information - try { - SecPointer code = new SecStaticCode(DiskRep::bestGuess(path)); - if (state.signingFlags() & kSecCSSignNestedCode) - this->state.sign(code, state.signingFlags()); - std::string dr = Dumper::dump(code->designatedRequirement()); - return cfmake("{requirement=%s,cdhash=%O}", - Dumper::dump(code->designatedRequirement()).c_str(), - code->cdHash()); - } catch (const CommonError &err) { - CSError::throwMe(err.osStatus(), kSecCFErrorPath, CFTempURL(relpath, false, this->code->resourceBase())); - } -} - - -// -// Sign a Mach-O binary, using liberal dollops of that special Mach-O magic sauce. -// Note that this will deal just fine with non-fat Mach-O binaries, but it will -// treat them as architectural binaries containing (only) one architecture - that -// interpretation is courtesy of the Universal/MachO support classes. -// -void SecCodeSigner::Signer::signMachO(Universal *fat, const Requirement::Context &context) -{ - // Mach-O executable at the core - perform multi-architecture signing - auto_ptr editor(state.mDetached - ? static_cast(new BlobEditor(*fat, *this)) - : new MachOEditor(rep->writer(), *fat, this->digestAlgorithm(), rep->mainExecutablePath())); - assert(editor->count() > 0); - if (!editor->attribute(writerNoGlobal)) // can store architecture-common components - populate(*editor); - - // pass 1: prepare signature blobs and calculate sizes - for (MachOEditor::Iterator it = editor->begin(); it != editor->end(); ++it) { - MachOEditor::Arch &arch = *it->second; - arch.source.reset(fat->architecture(it->first)); - - // library validation is not compatible with i386 - if (arch.architecture.cpuType() == CPU_TYPE_I386) { - if (cdFlags & kSecCodeSignatureLibraryValidation) { - MacOSError::throwMe(errSecCSBadLVArch); - } - } - - arch.ireqs(requirements, rep->defaultRequirements(&arch.architecture, state), context); - if (editor->attribute(writerNoGlobal)) // can't store globally, add per-arch - populate(arch); - populate(arch.cdbuilder, arch, arch.ireqs, - arch.source->offset(), arch.source->signingExtent()); - - // add identification blob (made from this architecture) only if we're making a detached signature - if (state.mDetached) { - CFRef identification = MachORep::identificationFor(arch.source.get()); - arch.add(cdIdentificationSlot, BlobWrapper::alloc( - CFDataGetBytePtr(identification), CFDataGetLength(identification))); - } - - // prepare SuperBlob size estimate - size_t cdSize = arch.cdbuilder.size(CodeDirectory::currentVersion); - arch.blobSize = arch.size(cdSize, state.mCMSSize, 0); - } - - editor->allocate(); - - // pass 2: Finish and generate signatures, and write them - for (MachOEditor::Iterator it = editor->begin(); it != editor->end(); ++it) { - MachOEditor::Arch &arch = *it->second; - editor->reset(arch); - - // finish CodeDirectory (off new binary) and sign it - CodeDirectory *cd = arch.cdbuilder.build(); - CFRef signature = signCodeDirectory(cd); - - // complete the SuperBlob - arch.add(cdCodeDirectorySlot, cd); // takes ownership - arch.add(cdSignatureSlot, BlobWrapper::alloc( - CFDataGetBytePtr(signature), CFDataGetLength(signature))); - if (!state.mDryRun) { - EmbeddedSignatureBlob *blob = arch.make(); - editor->write(arch, blob); // takes ownership of blob - } - } - - // done: write edit copy back over the original - if (!state.mDryRun) - editor->commit(); -} - - -// -// Sign a binary that has no notion of architecture. -// That currently means anything that isn't Mach-O format. -// -void SecCodeSigner::Signer::signArchitectureAgnostic(const Requirement::Context &context) -{ - // non-Mach-O executable - single-instance signing - RefPointer writer = state.mDetached ? - (new DetachedBlobWriter(*this)) : rep->writer(); - CodeDirectory::Builder builder(state.mDigestAlgorithm); - InternalRequirements ireqs; - ireqs(requirements, rep->defaultRequirements(NULL, state), context); - populate(*writer); - populate(builder, *writer, ireqs, rep->signingBase(), rep->signingLimit()); - - // add identification blob (made from this architecture) only if we're making a detached signature - if (state.mDetached) { - CFRef identification = rep->identification(); - writer->component(cdIdentificationSlot, identification); - } - - CodeDirectory *cd = builder.build(); - CFRef signature = signCodeDirectory(cd); - if (!state.mDryRun) { - writer->codeDirectory(cd); - writer->signature(signature); - writer->flush(); - } - ::free(cd); -} - - -// -// Global populate - send components to destination buffers ONCE -// -void SecCodeSigner::Signer::populate(DiskRep::Writer &writer) -{ - if (resourceDirectory && !state.mDryRun) - writer.component(cdResourceDirSlot, resourceDictData); -} - - -// -// Per-architecture populate - send components to per-architecture buffers -// and populate the CodeDirectory for an architecture. In architecture-agnostic -// signing operations, the non-architectural binary is considered one (arbitrary) architecture -// for the purposes of this call. -// -void SecCodeSigner::Signer::populate(CodeDirectory::Builder &builder, DiskRep::Writer &writer, - InternalRequirements &ireqs, size_t offset /* = 0 */, size_t length /* = 0 */) -{ - // fill the CodeDirectory - builder.executable(rep->mainExecutablePath(), pagesize, offset, length); - builder.flags(cdFlags); - builder.identifier(identifier); - builder.teamID(teamID); - - if (CFRef data = rep->component(cdInfoSlot)) - builder.specialSlot(cdInfoSlot, data); - if (ireqs) { - CFRef data = makeCFData(*ireqs); - writer.component(cdRequirementsSlot, data); - builder.specialSlot(cdRequirementsSlot, data); - } - if (resourceDirectory) - builder.specialSlot(cdResourceDirSlot, resourceDictData); -#if NOT_YET - if (state.mApplicationData) - builder.specialSlot(cdApplicationSlot, state.mApplicationData); -#endif - if (entitlements) { - writer.component(cdEntitlementSlot, entitlements); - builder.specialSlot(cdEntitlementSlot, entitlements); - } - - writer.addDiscretionary(builder); -} - -#include - -// -// Generate the CMS signature for a (finished) CodeDirectory. -// -CFDataRef SecCodeSigner::Signer::signCodeDirectory(const CodeDirectory *cd) -{ - assert(state.mSigner); - CFRef defaultTSContext = NULL; - - // a null signer generates a null signature blob - if (state.mSigner == SecIdentityRef(kCFNull)) - return CFDataCreate(NULL, NULL, 0); - - // generate CMS signature - CFRef cms; - MacOSError::check(CMSEncoderCreate(&cms.aref())); - MacOSError::check(CMSEncoderSetCertificateChainMode(cms, kCMSCertificateChainWithRoot)); - CMSEncoderAddSigners(cms, state.mSigner); - MacOSError::check(CMSEncoderSetHasDetachedContent(cms, true)); - - if (signingTime) { - MacOSError::check(CMSEncoderAddSignedAttributes(cms, kCMSAttrSigningTime)); - MacOSError::check(CMSEncoderSetSigningTime(cms, signingTime)); - } - - MacOSError::check(CMSEncoderUpdateContent(cms, cd, cd->length())); - - // Set up to call Timestamp server if requested - - if (state.mWantTimeStamp) - { - CFRef error = NULL; - defaultTSContext = SecCmsTSAGetDefaultContext(&error.aref()); - if (error) - MacOSError::throwMe(errSecDataNotAvailable); - - if (state.mNoTimeStampCerts || state.mTimestampService) { - if (state.mTimestampService) - CFDictionarySetValue(defaultTSContext, kTSAContextKeyURL, state.mTimestampService); - if (state.mNoTimeStampCerts) - CFDictionarySetValue(defaultTSContext, kTSAContextKeyNoCerts, kCFBooleanTrue); - } - - CmsMessageSetTSAContext(cms, defaultTSContext); - } - - CFDataRef signature; - MacOSError::check(CMSEncoderCopyEncodedContent(cms, &signature)); - - return signature; -} - - -// -// Parse a text of the form -// flag,...,flag -// where each flag is the canonical name of a signable CodeDirectory flag. -// No abbreviations are allowed, and internally set flags are not accepted. -// -uint32_t SecCodeSigner::Signer::cdTextFlags(std::string text) -{ - uint32_t flags = 0; - for (string::size_type comma = text.find(','); ; text = text.substr(comma+1), comma = text.find(',')) { - string word = (comma == string::npos) ? text : text.substr(0, comma); - const SecCodeDirectoryFlagTable *item; - for (item = kSecCodeDirectoryFlagTable; item->name; item++) - if (item->signable && word == item->name) { - flags |= item->value; - break; - } - if (!item->name) // not found - MacOSError::throwMe(errSecCSInvalidFlags); - if (comma == string::npos) // last word - break; - } - return flags; -} - - -// -// Generate a unique string from our underlying DiskRep. -// We could get 90%+ of the uniquing benefit by just generating -// a random string here. Instead, we pick the (hex string encoding of) -// the source rep's unique identifier blob. For universal binaries, -// this is the canonical local architecture, which is a bit arbitrary. -// This provides us with a consistent unique string for all architectures -// of a fat binary, *and* (unlike a random string) is reproducible -// for identical inputs, even upon resigning. -// -std::string SecCodeSigner::Signer::uniqueName() const -{ - CFRef identification = rep->identification(); - const UInt8 *ident = CFDataGetBytePtr(identification); - const CFIndex length = CFDataGetLength(identification); - string result; - for (CFIndex n = 0; n < length; n++) { - char hex[3]; - snprintf(hex, sizeof(hex), "%02x", ident[n]); - result += hex; - } - return result; -} - - -} // end namespace CodeSigning -} // end namespace Security