X-Git-Url: https://git.saurik.com/apple/libsecurity_codesigning.git/blobdiff_plain/d1c1ab47a3465a37e4c243f7a5b11b92737d5b76..refs/heads/master:/lib/StaticCode.cpp diff --git a/lib/StaticCode.cpp b/lib/StaticCode.cpp index 6b33bf6..d86a30b 100644 --- a/lib/StaticCode.cpp +++ b/lib/StaticCode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006-2010 Apple Inc. All Rights Reserved. + * Copyright (c) 2006-2012 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -27,6 +27,7 @@ #include "StaticCode.h" #include "Code.h" #include "reqmaker.h" +#include "drmaker.h" #include "reqdumper.h" #include "sigblob.h" #include "resources.h" @@ -34,6 +35,7 @@ #include "detachedrep.h" #include "csdatabase.h" #include "csutilities.h" +#include "SecCode.h" #include #include #include @@ -42,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -58,7 +61,7 @@ using namespace UnixPlusPlus; // SecStaticCode::SecStaticCode(DiskRep *rep) : mRep(rep), - mValidated(false), mExecutableValidated(false), + mValidated(false), mExecutableValidated(false), mResourcesValidated(false), mResourcesValidContext(NULL), mDesignatedReq(NULL), mGotResourceBase(false), mEvalDetails(NULL) { CODESIGN_STATIC_CREATE(this, rep); @@ -72,6 +75,8 @@ SecStaticCode::SecStaticCode(DiskRep *rep) SecStaticCode::~SecStaticCode() throw() try { ::free(const_cast(mDesignatedReq)); + if (mResourcesValidContext) + delete mResourcesValidContext; } catch (...) { return; } @@ -186,6 +191,11 @@ void SecStaticCode::resetValidity() CODESIGN_EVAL_STATIC_RESET(this); mValidated = false; mExecutableValidated = false; + mResourcesValidated = false; + if (mResourcesValidContext) { + delete mResourcesValidContext; + mResourcesValidContext = NULL; + } mDir = NULL; mSignature = NULL; for (unsigned n = 0; n < cdSlotCount; n++) @@ -303,10 +313,7 @@ void SecStaticCode::validateDirectory() CODESIGN_EVAL_STATIC_DIRECTORY(this); mValidationExpired = verifySignature(); component(cdInfoSlot, errSecCSInfoPlistFailed); // force load of Info Dictionary (if any) - CodeDirectory::SpecialSlot slot = codeDirectory()->nSpecialSlots; - if (slot > cdSlotMax) // might have more special slots than we know about... - slot = cdSlotMax; // ... but only process the ones we understand - for ( ; slot >= 1; --slot) + for (CodeDirectory::SpecialSlot slot = codeDirectory()->maxSpecialSlot(); slot >= 1; --slot) if (mCache[slot]) // if we already loaded that resource... validateComponent(slot); // ... then check it now mValidated = true; // we've done the deed... @@ -332,6 +339,24 @@ void SecStaticCode::validateDirectory() } +// +// Load and validate the CodeDirectory and all components *except* those related to the resource envelope. +// Those latter components are checked by validateResources(). +// +void SecStaticCode::validateNonResourceComponents() +{ + this->validateDirectory(); + for (CodeDirectory::SpecialSlot slot = codeDirectory()->maxSpecialSlot(); slot >= 1; --slot) + switch (slot) { + case cdResourceDirSlot: // validated by validateResources + break; + default: + this->component(slot); // loads and validates + break; + } +} + + // // Get the (signed) signing date from the code signature. // Sadly, we need to validate the signature to get the date (as a side benefit). @@ -346,6 +371,12 @@ CFAbsoluteTime SecStaticCode::signingTime() return mSigningTime; } +CFAbsoluteTime SecStaticCode::signingTimestamp() +{ + validateDirectory(); + return mSigningTimestamp; +} + // // Verify the CMS signature on the CodeDirectory. @@ -373,34 +404,36 @@ bool SecStaticCode::verifySignature() MacOSError::check(CMSDecoderSetDetachedContent(cms, mDir)); MacOSError::check(CMSDecoderFinalizeMessage(cms)); MacOSError::check(CMSDecoderSetSearchKeychain(cms, cfEmptyArray())); + CFRef policy = verificationPolicy(apiFlags()); CMSSignerStatus status; - MacOSError::check(CMSDecoderCopySignerStatus(cms, 0, verificationPolicy(), + MacOSError::check(CMSDecoderCopySignerStatus(cms, 0, policy, false, &status, &mTrust.aref(), NULL)); if (status != kCMSSignerValid) MacOSError::throwMe(errSecCSSignatureFailed); - // get signing date (we've got the decoder handle right here) - mSigningTime = 0; // "not present" marker (nobody could code sign on Jan 1, 2001 :-) - SecCmsMessageRef cmsg; - MacOSError::check(CMSDecoderGetCmsMessage(cms, &cmsg)); - SecCmsSignedDataRef signedData = NULL; - int numContentInfos = SecCmsMessageContentLevelCount(cmsg); - for(int dex = 0; !signedData && dex < numContentInfos; dex++) { - SecCmsContentInfoRef ci = SecCmsMessageContentLevel(cmsg, dex); - SECOidTag tag = SecCmsContentInfoGetContentTypeTag(ci); - switch(tag) { - case SEC_OID_PKCS7_SIGNED_DATA: - if (SecCmsSignedDataRef signedData = SecCmsSignedDataRef(SecCmsContentInfoGetContent(ci))) - if (SecCmsSignerInfoRef signerInfo = SecCmsSignedDataGetSignerInfo(signedData, 0)) - SecCmsSignerInfoGetSigningTime(signerInfo, &mSigningTime); - break; - default: - break; - } - } + // internal signing time (as specified by the signer; optional) + mSigningTime = 0; // "not present" marker (nobody could code sign on Jan 1, 2001 :-) + switch (OSStatus rc = CMSDecoderCopySignerSigningTime(cms, 0, &mSigningTime)) { + case noErr: + case errSecSigningTimeMissing: + break; + default: + MacOSError::throwMe(rc); + } + // certified signing time (as specified by a TSA; optional) + mSigningTimestamp = 0; + switch (OSStatus rc = CMSDecoderCopySignerTimestamp(cms, 0, &mSigningTimestamp)) { + case noErr: + case errSecTimestampMissing: + break; + default: + MacOSError::throwMe(rc); + } + // set up the environment for SecTrust MacOSError::check(SecTrustSetAnchorCertificates(mTrust, cfEmptyArray())); // no anchors + MacOSError::check(SecTrustSetKeychains(mTrust, cfEmptyArray())); // no keychains CSSM_APPLE_TP_ACTION_DATA actionData = { CSSM_APPLE_TP_ACTION_VERSION, // version of data structure CSSM_TP_ACTION_IMPLICIT_ANCHORS // action flags @@ -417,7 +450,6 @@ bool SecStaticCode::verifySignature() CODESIGN_EVAL_STATIC_SIGNATURE_RESULT(this, trustResult, mCertChain ? CFArrayGetCount(mCertChain) : 0); switch (trustResult) { case kSecTrustResultProceed: - case kSecTrustResultConfirm: case kSecTrustResultUnspecified: break; // success case kSecTrustResultDeny: @@ -425,18 +457,19 @@ bool SecStaticCode::verifySignature() case kSecTrustResultInvalid: assert(false); // should never happen MacOSError::throwMe(CSSMERR_TP_NOT_TRUSTED); - case kSecTrustResultRecoverableTrustFailure: - case kSecTrustResultFatalTrustFailure: - case kSecTrustResultOtherError: + default: { OSStatus result; MacOSError::check(SecTrustGetCssmResultCode(mTrust, &result)); - if (((result == CSSMERR_TP_CERT_EXPIRED) || (result == CSSMERR_TP_CERT_NOT_VALID_YET)) - && !(actionData.ActionFlags & CSSM_TP_ACTION_ALLOW_EXPIRED)) { - CODESIGN_EVAL_STATIC_SIGNATURE_EXPIRED(this); - actionData.ActionFlags |= CSSM_TP_ACTION_ALLOW_EXPIRED; // (this also allows postdated certs) - continue; // retry validation - } + // if we have a valid timestamp, CMS validates against (that) signing time and all is well. + // If we don't have one, may validate against *now*, and must be able to tolerate expiration. + if (mSigningTimestamp == 0) // no timestamp available + if (((result == CSSMERR_TP_CERT_EXPIRED) || (result == CSSMERR_TP_CERT_NOT_VALID_YET)) + && !(actionData.ActionFlags & CSSM_TP_ACTION_ALLOW_EXPIRED)) { + CODESIGN_EVAL_STATIC_SIGNATURE_EXPIRED(this); + actionData.ActionFlags |= CSSM_TP_ACTION_ALLOW_EXPIRED; // (this also allows postdated certs) + continue; // retry validation while tolerating expiration + } MacOSError::throwMe(result); } } @@ -447,14 +480,47 @@ bool SecStaticCode::verifySignature() // // Return the TP policy used for signature verification. -// This policy object is cached and reused. +// This may be a simple SecPolicyRef or a CFArray of policies. +// The caller owns the return value. // -SecPolicyRef SecStaticCode::verificationPolicy() +static SecPolicyRef makeCRLPolicy() { - if (!mPolicy) - MacOSError::check(SecPolicyCopy(CSSM_CERT_X_509v3, - &CSSMOID_APPLE_TP_CODE_SIGNING, &mPolicy.aref())); - return mPolicy; + CFRef policy; + MacOSError::check(SecPolicyCopy(CSSM_CERT_X_509v3, &CSSMOID_APPLE_TP_REVOCATION_CRL, &policy.aref())); + CSSM_APPLE_TP_CRL_OPTIONS options; + memset(&options, 0, sizeof(options)); + options.Version = CSSM_APPLE_TP_CRL_OPTS_VERSION; + options.CrlFlags = CSSM_TP_ACTION_FETCH_CRL_FROM_NET | CSSM_TP_ACTION_CRL_SUFFICIENT; + CSSM_DATA optData = { sizeof(options), (uint8 *)&options }; + MacOSError::check(SecPolicySetValue(policy, &optData)); + return policy.yield(); +} + +static SecPolicyRef makeOCSPPolicy() +{ + CFRef policy; + MacOSError::check(SecPolicyCopy(CSSM_CERT_X_509v3, &CSSMOID_APPLE_TP_REVOCATION_OCSP, &policy.aref())); + CSSM_APPLE_TP_OCSP_OPTIONS options; + memset(&options, 0, sizeof(options)); + options.Version = CSSM_APPLE_TP_OCSP_OPTS_VERSION; + options.Flags = CSSM_TP_ACTION_OCSP_SUFFICIENT; + CSSM_DATA optData = { sizeof(options), (uint8 *)&options }; + MacOSError::check(SecPolicySetValue(policy, &optData)); + return policy.yield(); +} + +CFTypeRef SecStaticCode::verificationPolicy(SecCSFlags flags) +{ + CFRef core; + MacOSError::check(SecPolicyCopy(CSSM_CERT_X_509v3, + &CSSMOID_APPLE_TP_CODE_SIGNING, &core.aref())); + if (flags & kSecCSEnforceRevocationChecks) { + CFRef crl = makeCRLPolicy(); + CFRef ocsp = makeOCSPPolicy(); + return makeCFArray(3, core.get(), crl.get(), ocsp.get()); + } else { + return core.yield(); + } } @@ -487,29 +553,43 @@ void SecStaticCode::validateComponent(CodeDirectory::SpecialSlot slot, OSStatus // void SecStaticCode::validateExecutable() { - DTRACK(CODESIGN_EVAL_STATIC_EXECUTABLE, this, - (char*)this->mainExecutablePath().c_str(), codeDirectory()->nCodeSlots); - const CodeDirectory *cd = this->codeDirectory(); - if (!cd) - MacOSError::throwMe(errSecCSUnsigned); - AutoFileDesc fd(mainExecutablePath(), O_RDONLY); - fd.fcntl(F_NOCACHE, true); // turn off page caching (one-pass) - if (Universal *fat = mRep->mainExecutableImage()) - fd.seek(fat->archOffset()); - size_t pageSize = cd->pageSize ? (1 << cd->pageSize) : 0; - size_t remaining = cd->codeLimit; - for (size_t slot = 0; slot < cd->nCodeSlots; ++slot) { - size_t size = min(remaining, pageSize); - if (!cd->validateSlot(fd, size, slot)) { - CODESIGN_EVAL_STATIC_EXECUTABLE_FAIL(this, slot); - mExecutableValidated = true; // we tried - mExecutableValid = false; // it failed - MacOSError::throwMe(errSecCSSignatureFailed); + if (!validatedExecutable()) { + try { + DTRACK(CODESIGN_EVAL_STATIC_EXECUTABLE, this, + (char*)this->mainExecutablePath().c_str(), codeDirectory()->nCodeSlots); + const CodeDirectory *cd = this->codeDirectory(); + if (!cd) + MacOSError::throwMe(errSecCSUnsigned); + AutoFileDesc fd(mainExecutablePath(), O_RDONLY); + fd.fcntl(F_NOCACHE, true); // turn off page caching (one-pass) + if (Universal *fat = mRep->mainExecutableImage()) + fd.seek(fat->archOffset()); + size_t pageSize = cd->pageSize ? (1 << cd->pageSize) : 0; + size_t remaining = cd->codeLimit; + for (size_t slot = 0; slot < cd->nCodeSlots; ++slot) { + size_t size = min(remaining, pageSize); + if (!cd->validateSlot(fd, size, slot)) { + CODESIGN_EVAL_STATIC_EXECUTABLE_FAIL(this, slot); + MacOSError::throwMe(errSecCSSignatureFailed); + } + remaining -= size; + } + mExecutableValidated = true; + mExecutableValidResult = noErr; + } catch (const CommonError &err) { + mExecutableValidated = true; + mExecutableValidResult = err.osStatus(); + throw; + } catch (...) { + secdebug("staticCode", "%p executable validation threw non-common exception", this); + mExecutableValidated = true; + mExecutableValidResult = errSecCSInternalError; + throw; } - remaining -= size; } - mExecutableValidated = true; // we tried - mExecutableValid = true; // it worked + assert(validatedExecutable()); + if (mExecutableValidResult != noErr) + MacOSError::throwMe(mExecutableValidResult); } @@ -522,48 +602,68 @@ void SecStaticCode::validateExecutable() // void SecStaticCode::validateResources() { - // sanity first - CFDictionaryRef sealedResources = resourceDictionary(); - if (this->resourceBase()) // disk has resources - if (sealedResources) - /* go to work below */; - else - MacOSError::throwMe(errSecCSResourcesNotFound); - else // disk has no resources - if (sealedResources) - MacOSError::throwMe(errSecCSResourcesNotFound); - else - return; // no resources, not sealed - fine (no work) - - // found resources, and they are sealed - CFDictionaryRef rules = cfget(sealedResources, "rules"); - CFDictionaryRef files = cfget(sealedResources, "files"); - DTRACK(CODESIGN_EVAL_STATIC_RESOURCES, this, - (char*)this->mainExecutablePath().c_str(), int(CFDictionaryGetCount(files))); - - // make a shallow copy of the ResourceDirectory so we can "check off" what we find - CFRef resourceMap = makeCFMutableDictionary(files); - - // scan through the resources on disk, checking each against the resourceDirectory - CollectingContext ctx(*this); // collect all failures in here - ResourceBuilder resources(cfString(this->resourceBase()), rules, codeDirectory()->hashType); - mRep->adjustResources(resources); - string path; - ResourceBuilder::Rule *rule; - - while (resources.next(path, rule)) { - validateResource(path, ctx); - CFDictionaryRemoveValue(resourceMap, CFTempString(path)); - } - - if (CFDictionaryGetCount(resourceMap) > 0) { - secdebug("staticCode", "%p sealed resource(s) not found in code", this); - CFDictionaryApplyFunction(resourceMap, SecStaticCode::checkOptionalResource, &ctx); + if (!validatedResources()) { + try { + // sanity first + CFDictionaryRef sealedResources = resourceDictionary(); + if (this->resourceBase()) // disk has resources + if (sealedResources) + /* go to work below */; + else + MacOSError::throwMe(errSecCSResourcesNotFound); + else // disk has no resources + if (sealedResources) + MacOSError::throwMe(errSecCSResourcesNotFound); + else + return; // no resources, not sealed - fine (no work) + + // found resources, and they are sealed + CFDictionaryRef rules = cfget(sealedResources, "rules"); + CFDictionaryRef files = cfget(sealedResources, "files"); + DTRACK(CODESIGN_EVAL_STATIC_RESOURCES, this, + (char*)this->mainExecutablePath().c_str(), int(CFDictionaryGetCount(files))); + + // make a shallow copy of the ResourceDirectory so we can "check off" what we find + CFRef resourceMap = makeCFMutableDictionary(files); + + // scan through the resources on disk, checking each against the resourceDirectory + mResourcesValidContext = new CollectingContext(*this); // collect all failures in here + ResourceBuilder resources(cfString(this->resourceBase()), rules, codeDirectory()->hashType); + mRep->adjustResources(resources); + string path; + ResourceBuilder::Rule *rule; + + while (resources.next(path, rule)) { + validateResource(path, *mResourcesValidContext); + CFDictionaryRemoveValue(resourceMap, CFTempString(path)); + } + + if (CFDictionaryGetCount(resourceMap) > 0) { + secdebug("staticCode", "%p sealed resource(s) not found in code", this); + CFDictionaryApplyFunction(resourceMap, SecStaticCode::checkOptionalResource, mResourcesValidContext); + } + + // now check for any errors found in the reporting context + mResourcesValidated = true; + if (mResourcesValidContext->osStatus() != noErr) + mResourcesValidContext->throwMe(); + + } catch (const CommonError &err) { + mResourcesValidated = true; + mResourcesValidResult = err.osStatus(); + throw; + } catch (...) { + secdebug("staticCode", "%p executable validation threw non-common exception", this); + mResourcesValidated = true; + mResourcesValidResult = errSecCSInternalError; + throw; + } } - - // now check for any errors found in the reporting context - if (ctx) - ctx.throwMe(); + assert(validatedResources()); + if (mResourcesValidResult) + MacOSError::throwMe(mResourcesValidResult); + if (mResourcesValidContext->osStatus() != noErr) + mResourcesValidContext->throwMe(); } @@ -571,12 +671,14 @@ void SecStaticCode::checkOptionalResource(CFTypeRef key, CFTypeRef value, void * { CollectingContext *ctx = static_cast(context); ResourceSeal seal(value); - if (!seal.optional()) + if (!seal.optional()) { if (key && CFGetTypeID(key) == CFStringGetTypeID()) { ctx->reportProblem(errSecCSBadResource, kSecCFErrorResourceMissing, CFTempURL(CFStringRef(key), false, ctx->code.resourceBase())); - } else + } else { ctx->reportProblem(errSecCSBadResource, kSecCFErrorResourceSeal, key); + } + } } @@ -778,8 +880,10 @@ const Requirement *SecStaticCode::internalRequirement(SecRequirementType type) // -// Return the Designated Requirement. This can be either explicit in the -// Internal Requirements resource, or implicitly generated. +// Return the Designated Requirement (DR). This can be either explicit in the +// Internal Requirements component, or implicitly generated on demand here. +// Note that an explicit DR may have been implicitly generated at signing time; +// we don't distinguish this case. // const Requirement *SecStaticCode::designatedRequirement() { @@ -794,115 +898,31 @@ const Requirement *SecStaticCode::designatedRequirement() // -// Generate the default (implicit) Designated Requirement for this StaticCode. -// This is a heuristic of sorts, and may change over time (for the better, we hope). -// -// The current logic is this: -// * If the code is ad-hoc signed, use the CodeDirectory hash directory. -// * Otherwise, use the form anchor (anchor) and identifier (CodeDirectory identifier). -// ** If the root CA is Apple's, we use the "anchor apple" construct. Otherwise, -// we default to the leaf (directly signing) certificate. +// Generate the default Designated Requirement (DR) for this StaticCode. +// Ignore any explicit DR it may contain. // const Requirement *SecStaticCode::defaultDesignatedRequirement() { - validateDirectory(); // need the cert chain - Requirement::Maker maker; - - // if this is an ad-hoc (unsigned) object, return a cdhash requirement if (flag(kSecCodeSignatureAdhoc)) { + // adhoc signature: return a plain cdhash requirement + Requirement::Maker maker; SHA1 hash; hash(codeDirectory(), codeDirectory()->length()); SHA1::Digest digest; hash.finish(digest); maker.cdhash(digest); + return maker.make(); } else { - // always require the identifier - maker.put(opAnd); - maker.ident(codeDirectory()->identifier()); - - SHA1::Digest anchorHash; - hashOfCertificate(cert(Requirement::anchorCert), anchorHash); - if (!memcmp(anchorHash, Requirement::appleAnchorHash(), SHA1::digestLength) -#if defined(TEST_APPLE_ANCHOR) - || !memcmp(anchorHash, Requirement::testAppleAnchorHash(), SHA1::digestLength) -#endif - ) - defaultDesignatedAppleAnchor(maker); - else - defaultDesignatedNonAppleAnchor(maker); + // full signature: Gin up full context and let DRMaker do its thing + validateDirectory(); // need the cert chain + Requirement::Context context(this->certificates(), + this->infoDictionary(), + this->entitlements(), + this->identifier(), + this->codeDirectory() + ); + return DRMaker(context).make(); } - - return maker(); -} - -static const uint8_t adcSdkMarker[] = { APPLE_EXTENSION_OID, 2, 1 }; -static const CSSM_DATA adcSdkMarkerOID = { sizeof(adcSdkMarker), (uint8_t *)adcSdkMarker }; - -void SecStaticCode::defaultDesignatedAppleAnchor(Requirement::Maker &maker) -{ - if (isAppleSDKSignature()) { - // get the Common Name DN element for the leaf - CFRef leafCN; - MacOSError::check(SecCertificateCopySubjectComponent(cert(Requirement::leafCert), - &CSSMOID_CommonName, &leafCN.aref())); - - // apple anchor generic and ... - maker.put(opAnd); - maker.anchorGeneric(); // apple generic anchor and... - // ... leaf[subject.CN] = and ... - maker.put(opAnd); - maker.put(opCertField); // certificate - maker.put(0); // leaf - maker.put("subject.CN"); // [subject.CN] - maker.put(matchEqual); // = - maker.putData(leafCN); // - // ... cert 1[field.] exists - maker.put(opCertGeneric); // certificate - maker.put(1); // 1 - maker.putData(adcSdkMarkerOID.Data, adcSdkMarkerOID.Length); // [field.] - maker.put(matchExists); // exists - return; - } - - // otherwise, claim this program for Apple - maker.anchor(); -} - -bool SecStaticCode::isAppleSDKSignature() -{ - if (CFArrayRef certChain = certificates()) // got cert chain - if (CFArrayGetCount(certChain) == 3) // leaf, one intermediate, anchor - if (SecCertificateRef intermediate = cert(1)) // get intermediate - if (certificateHasField(intermediate, CssmOid::overlay(adcSdkMarkerOID))) - return true; - return false; -} - -void SecStaticCode::defaultDesignatedNonAppleAnchor(Requirement::Maker &maker) -{ - // get the Organization DN element for the leaf - CFRef leafOrganization; - MacOSError::check(SecCertificateCopySubjectComponent(cert(Requirement::leafCert), - &CSSMOID_OrganizationName, &leafOrganization.aref())); - - // now step up the cert chain looking for the first cert with a different one - int slot = Requirement::leafCert; // start at leaf - if (leafOrganization) { - while (SecCertificateRef ca = cert(slot+1)) { // NULL if you over-run the anchor slot - CFRef caOrganization; - MacOSError::check(SecCertificateCopySubjectComponent(ca, &CSSMOID_OrganizationName, &caOrganization.aref())); - if (!caOrganization || CFStringCompare(leafOrganization, caOrganization, 0) != kCFCompareEqualTo) - break; - slot++; - } - if (slot == CFArrayGetCount(mCertChain) - 1) // went all the way to the anchor... - slot = Requirement::anchorCert; // ... so say that - } - - // nail the last cert with the leaf's Organization value - SHA1::Digest authorityHash; - hashOfCertificate(cert(slot), authorityHash); - maker.anchor(slot, authorityHash); } @@ -929,7 +949,7 @@ bool SecStaticCode::satisfiesRequirement(const Requirement *req, OSStatus failur { assert(req); validateDirectory(); - return req->validates(Requirement::Context(mCertChain, infoDictionary(), entitlements(), codeDirectory()), failure); + return req->validates(Requirement::Context(mCertChain, infoDictionary(), entitlements(), codeDirectory()->identifier(), codeDirectory()), failure); } void SecStaticCode::validateRequirement(const Requirement *req, OSStatus failure) @@ -995,11 +1015,17 @@ CFDictionaryRef SecStaticCode::signingInformation(SecCSFlags flags) CFDictionaryAddValue(dict, kSecCodeInfoIdentifier, CFTempString(this->identifier())); CFDictionaryAddValue(dict, kSecCodeInfoFormat, CFTempString(this->format())); CFDictionaryAddValue(dict, kSecCodeInfoSource, CFTempString(this->signatureSource())); - if (CFDictionaryRef info = this->infoDictionary()) - CFDictionaryAddValue(dict, kSecCodeInfoPList, info); CFDictionaryAddValue(dict, kSecCodeInfoUnique, this->cdHash()); CFDictionaryAddValue(dict, kSecCodeInfoDigestAlgorithm, CFTempNumber(this->codeDirectory(false)->hashType)); + // + // Deliver any Info.plist only if it looks intact + // + try { + if (CFDictionaryRef info = this->infoDictionary()) + CFDictionaryAddValue(dict, kSecCodeInfoPList, info); + } catch (...) { } // don't deliver Info.plist if questionable + // // kSecCSSigningInformation adds information about signing certificates and chains // @@ -1013,6 +1039,9 @@ CFDictionaryRef SecStaticCode::signingInformation(SecCSFlags flags) if (CFAbsoluteTime time = this->signingTime()) if (CFRef date = CFDateCreate(NULL, time)) CFDictionaryAddValue(dict, kSecCodeInfoTime, date); + if (CFAbsoluteTime time = this->signingTimestamp()) + if (CFRef date = CFDateCreate(NULL, time)) + CFDictionaryAddValue(dict, kSecCodeInfoTimestamp, date); } // @@ -1035,8 +1064,11 @@ CFDictionaryRef SecStaticCode::signingInformation(SecCSFlags flags) CFDictionaryAddValue(dict, kSecCodeInfoImplicitDesignatedRequirement, dreqRef); } - if (CFDataRef ent = this->component(cdEntitlementSlot)) + if (CFDataRef ent = this->component(cdEntitlementSlot)) { CFDictionaryAddValue(dict, kSecCodeInfoEntitlements, ent); + if (CFDictionaryRef entdict = this->entitlements()) + CFDictionaryAddValue(dict, kSecCodeInfoEntitlementsDict, entdict); + } } // @@ -1101,7 +1133,7 @@ void SecStaticCode::CollectingContext::reportProblem(OSStatus rc, CFStringRef ty void SecStaticCode::CollectingContext::throwMe() { assert(mStatus != noErr); - throw CSError(mStatus, mCollection.yield()); + throw CSError(mStatus, mCollection.retain()); }