void Bundle::resources(vector<string> &paths, const char *type, const char *subdir) { CFRef<CFArrayRef> cfList = CFBundleCopyResourceURLsOfType(cfBundle(), CFTempString(type), CFTempString(subdir)); CFIndex size = CFArrayGetCount(cfList); paths.reserve(size); for (CFIndex n = 0; n < size; n++) paths.push_back(cfString(CFURLRef(CFArrayGetValueAtIndex(cfList, n)))); }
// // Perform common argument normalizations for update operations // static void normalizeTarget(CFRef<CFTypeRef> &target, CFDictionary &context, std::string *signUnsigned) { // turn CFURLs into (designated) SecRequirements if (target && CFGetTypeID(target) == CFURLGetTypeID()) { CFRef<SecStaticCodeRef> code; MacOSError::check(SecStaticCodeCreateWithPath(target.as<CFURLRef>(), kSecCSDefaultFlags, &code.aref())); switch (OSStatus rc = SecCodeCopyDesignatedRequirement(code, kSecCSDefaultFlags, (SecRequirementRef *)&target.aref())) { case noErr: { // use the *default* DR to avoid unreasonably wide DRs opening up Gatekeeper to attack CFRef<CFDictionaryRef> info; MacOSError::check(SecCodeCopySigningInformation(code, kSecCSRequirementInformation, &info.aref())); target = CFDictionaryGetValue(info, kSecCodeInfoImplicitDesignatedRequirement); } break; case errSecCSUnsigned: if (signUnsigned) { // Ad-hoc sign the code temporarily so we can get its code requirement CFRef<CFDataRef> signature = CFDataCreateMutable(NULL, 0); CFRef<SecCodeSignerRef> signer; CFTemp<CFDictionaryRef> arguments("{%O=%O, %O=#N}", kSecCodeSignerDetached, signature.get(), kSecCodeSignerIdentity); MacOSError::check(SecCodeSignerCreate(arguments, kSecCSDefaultFlags, &signer.aref())); MacOSError::check(SecCodeSignerAddSignature(signer, code, kSecCSDefaultFlags)); MacOSError::check(SecCodeSetDetachedSignature(code, signature, kSecCSDefaultFlags)); MacOSError::check(SecCodeCopyDesignatedRequirement(code, kSecCSDefaultFlags, (SecRequirementRef *)&target.aref())); CFRef<CFDictionaryRef> info; MacOSError::check(SecCodeCopySigningInformation(code, kSecCSInternalInformation, &info.aref())); if (CFDataRef cdData = CFDataRef(CFDictionaryGetValue(info, kSecCodeInfoCodeDirectory))) *signUnsigned = ((const CodeDirectory *)CFDataGetBytePtr(cdData))->screeningCode(); break; } MacOSError::check(rc); case errSecCSSignatureFailed: // recover certain cases of broken signatures (well, try) if (codeInvalidityExceptions(code, NULL)) { // Ad-hoc sign the code in place (requiring a writable subject). This requires root privileges. CFRef<SecCodeSignerRef> signer; CFTemp<CFDictionaryRef> arguments("{%O=#N}", kSecCodeSignerIdentity); MacOSError::check(SecCodeSignerCreate(arguments, kSecCSDefaultFlags, &signer.aref())); MacOSError::check(SecCodeSignerAddSignature(signer, code, kSecCSDefaultFlags)); MacOSError::check(SecCodeCopyDesignatedRequirement(code, kSecCSDefaultFlags, (SecRequirementRef *)&target.aref())); break; } MacOSError::check(rc); default: MacOSError::check(rc); } if (context.get(kSecAssessmentUpdateKeyRemarks) == NULL) { // no explicit remarks; add one with the path CFRef<CFURLRef> path; MacOSError::check(SecCodeCopyPath(code, kSecCSDefaultFlags, &path.aref())); CFMutableDictionaryRef dict = makeCFMutableDictionary(context.get()); CFDictionaryAddValue(dict, kSecAssessmentUpdateKeyRemarks, CFTempString(cfString(path))); context.take(dict); } } }
CFDictionaryRef PolicyEngine::find(CFTypeRef target, AuthorityType type, SecAssessmentFlags flags, CFDictionaryRef context) { SQLite::Statement query(*this); selectRules(query, "SELECT scan_authority.id, scan_authority.type, scan_authority.requirement, scan_authority.allow, scan_authority.label, scan_authority.priority, scan_authority.remarks, scan_authority.expires, scan_authority.disabled, bookmarkhints.bookmark FROM scan_authority LEFT OUTER JOIN bookmarkhints ON scan_authority.id = bookmarkhints.authority", "scan_authority", target, type, flags, context, " ORDER BY priority DESC"); CFRef<CFMutableArrayRef> found = makeCFMutableArray(0); while (query.nextRow()) { SQLite::int64 id = query[0]; int type = int(query[1]); const char *requirement = query[2]; int allow = int(query[3]); const char *label = query[4]; double priority = query[5]; const char *remarks = query[6]; double expires = query[7]; int disabled = int(query[8]); CFRef<CFDataRef> bookmark = query[9].data(); CFRef<CFMutableDictionaryRef> rule = makeCFMutableDictionary(5, kSecAssessmentRuleKeyID, CFTempNumber(id).get(), kSecAssessmentRuleKeyType, CFRef<CFStringRef>(typeNameFor(type)).get(), kSecAssessmentRuleKeyRequirement, CFTempString(requirement).get(), kSecAssessmentRuleKeyAllow, allow ? kCFBooleanTrue : kCFBooleanFalse, kSecAssessmentRuleKeyPriority, CFTempNumber(priority).get() ); if (label) CFDictionaryAddValue(rule, kSecAssessmentRuleKeyLabel, CFTempString(label)); if (remarks) CFDictionaryAddValue(rule, kSecAssessmentRuleKeyRemarks, CFTempString(remarks)); if (expires != never) CFDictionaryAddValue(rule, kSecAssessmentRuleKeyExpires, CFRef<CFDateRef>(julianToDate(expires))); if (disabled) CFDictionaryAddValue(rule, kSecAssessmentRuleKeyDisabled, CFTempNumber(disabled)); if (bookmark) CFDictionaryAddValue(rule, kSecAssessmentRuleKeyBookmark, bookmark); CFArrayAppendValue(found, rule); } if (CFArrayGetCount(found) == 0) MacOSError::throwMe(errSecCSNoMatches); return cfmake<CFDictionaryRef>("{%O=%O}", kSecAssessmentUpdateKeyFound, found.get()); }
string Bundle::resource(const char *name, const char *type, const char *subdir) { return cfStringRelease(CFBundleCopyResourceURL(cfBundle(), CFTempString(name), CFTempString(type), CFTempString(subdir))); }
CFTypeRef Bundle::infoPlistItem(const char *name) const { return CFBundleGetValueForInfoDictionaryKey(cfBundle(), CFTempString(name)); }
// // Installer archive. // Hybrid policy: If we detect an installer signature, use and validate that. // If we don't, check for a code signature instead. // void PolicyEngine::evaluateInstall(CFURLRef path, SecAssessmentFlags flags, CFDictionaryRef context, CFMutableDictionaryRef result) { const AuthorityType type = kAuthorityInstall; Xar xar(cfString(path).c_str()); if (!xar) { // follow the code signing path evaluateCode(path, type, flags, context, result); return; } SQLite3::int64 latentID = 0; // first (highest priority) disabled matching ID std::string latentLabel; // ... and associated label, if any if (!xar.isSigned()) { // unsigned xar if (SYSPOLICY_ASSESS_OUTCOME_UNSIGNED_ENABLED()) SYSPOLICY_ASSESS_OUTCOME_UNSIGNED(cfString(path).c_str(), type); cfadd(result, "{%O=%B}", kSecAssessmentAssessmentVerdict, false); addAuthority(result, "no usable signature"); return; } if (CFRef<CFArrayRef> certs = xar.copyCertChain()) { CFRef<CFTypeRef> policy = installerPolicy(); CFRef<SecTrustRef> trust; MacOSError::check(SecTrustCreateWithCertificates(certs, policy, &trust.aref())); // MacOSError::check(SecTrustSetAnchorCertificates(trust, cfEmptyArray())); // no anchors MacOSError::check(SecTrustSetOptions(trust, kSecTrustOptionAllowExpired | kSecTrustOptionImplicitAnchors)); SecTrustResultType trustResult; MacOSError::check(SecTrustEvaluate(trust, &trustResult)); CFRef<CFArrayRef> chain; CSSM_TP_APPLE_EVIDENCE_INFO *info; MacOSError::check(SecTrustGetResult(trust, &trustResult, &chain.aref(), &info)); if (flags & kSecAssessmentFlagRequestOrigin) setOrigin(chain, result); switch (trustResult) { case kSecTrustResultProceed: case kSecTrustResultUnspecified: break; default: { OSStatus rc; MacOSError::check(SecTrustGetCssmResultCode(trust, &rc)); MacOSError::throwMe(rc); } } SQLite::Statement query(*this, "SELECT allow, requirement, id, label, flags, disabled FROM scan_authority" " WHERE type = :type" " ORDER BY priority DESC;"); query.bind(":type").integer(type); while (query.nextRow()) { bool allow = int(query[0]); const char *reqString = query[1]; SQLite3::int64 id = query[2]; const char *label = query[3]; //sqlite_uint64 ruleFlags = query[4]; SQLite3::int64 disabled = query[5]; CFRef<SecRequirementRef> requirement; MacOSError::check(SecRequirementCreateWithString(CFTempString(reqString), kSecCSDefaultFlags, &requirement.aref())); switch (OSStatus rc = SecRequirementEvaluate(requirement, chain, NULL, kSecCSDefaultFlags)) { case noErr: // success break; case errSecCSReqFailed: // requirement missed, but otherwise okay continue; default: // broken in some way; all tests will fail like this so bail out MacOSError::throwMe(rc); } if (disabled) { if (latentID == 0) { latentID = id; if (label) latentLabel = label; } continue; // the loop } if (SYSPOLICY_ASSESS_OUTCOME_ACCEPT_ENABLED() || SYSPOLICY_ASSESS_OUTCOME_DENY_ENABLED()) { if (allow) SYSPOLICY_ASSESS_OUTCOME_ACCEPT(cfString(path).c_str(), type, label, NULL); else SYSPOLICY_ASSESS_OUTCOME_DENY(cfString(path).c_str(), type, label, NULL); } // not adding to the object cache - we could, but it's not likely to be worth it cfadd(result, "{%O=%B}", kSecAssessmentAssessmentVerdict, allow); addAuthority(result, label, id); return; } } if (SYSPOLICY_ASSESS_OUTCOME_DEFAULT_ENABLED()) SYSPOLICY_ASSESS_OUTCOME_DEFAULT(cfString(path).c_str(), type, latentLabel.c_str(), NULL); // no applicable authority. Deny by default cfadd(result, "{%O=#F}", kSecAssessmentAssessmentVerdict); addAuthority(result, latentLabel.c_str(), latentID); }
// // Executable code. // Read from disk, evaluate properly, cache as indicated. The whole thing, so far. // void PolicyEngine::evaluateCode(CFURLRef path, AuthorityType type, SecAssessmentFlags flags, CFDictionaryRef context, CFMutableDictionaryRef result, bool handleUnsignedCode /* = true */) { FileQuarantine qtn(cfString(path).c_str()); if (qtn.flag(QTN_FLAG_HARD)) MacOSError::throwMe(errSecCSFileHardQuarantined); CFRef<SecStaticCodeRef> code; MacOSError::check(SecStaticCodeCreateWithPath(path, kSecCSDefaultFlags, &code.aref())); OSStatus rc = noErr; // last validation error const SecCSFlags validationFlags = kSecCSEnforceRevocationChecks; WhitelistPrescreen whitelistScreen(code); // pre-screening filter for whitelist pre-screening (only) SQLite::Statement query(*this, "SELECT allow, requirement, id, label, expires, flags, disabled, filter_unsigned, remarks FROM scan_authority" " WHERE type = :type" " ORDER BY priority DESC;"); query.bind(":type").integer(type); SQLite3::int64 latentID = 0; // first (highest priority) disabled matching ID std::string latentLabel; // ... and associated label, if any while (query.nextRow()) { bool allow = int(query[0]); const char *reqString = query[1]; SQLite3::int64 id = query[2]; const char *label = query[3]; double expires = query[4]; sqlite3_int64 ruleFlags = query[5]; SQLite3::int64 disabled = query[6]; const char *filter = query[7]; const char *remarks = query[8]; CFRef<SecRequirementRef> requirement; MacOSError::check(SecRequirementCreateWithString(CFTempString(reqString), kSecCSDefaultFlags, &requirement.aref())); rc = SecStaticCodeCheckValidity(code, validationFlags, requirement); // ad-hoc sign unsigned code, skip of Gatekeeper is off or the rule is disabled; but always do it for whitelist recording if (rc == errSecCSUnsigned && handleUnsignedCode && (!(disabled || overrideAssessment()) || SYSPOLICY_RECORDER_MODE_ENABLED())) { if (!SYSPOLICY_RECORDER_MODE_ENABLED()) { // apply whitelist pre-screening to speed things up for non-matches if (ruleFlags & kAuthorityFlagDefault) // can't ever match standard rules with unsigned code continue; if (whitelistScreen.reject(filter, remarks)) // apply whitelist pre-filter continue; } try { // ad-hoc sign the code and attach the signature CFRef<CFDataRef> signature = CFDataCreateMutable(NULL, 0); CFTemp<CFDictionaryRef> arguments("{%O=%O, %O=#N}", kSecCodeSignerDetached, signature.get(), kSecCodeSignerIdentity); CFRef<SecCodeSignerRef> signer; MacOSError::check(SecCodeSignerCreate(arguments, kSecCSDefaultFlags, &signer.aref())); MacOSError::check(SecCodeSignerAddSignature(signer, code, kSecCSDefaultFlags)); MacOSError::check(SecCodeSetDetachedSignature(code, signature, kSecCSDefaultFlags)); // if we're in GKE recording mode, save that signature and report its location if (SYSPOLICY_RECORDER_MODE_ENABLED()) { int status = recorder_code_unable; // ephemeral signature (not recorded) if (geteuid() == 0) { CFRef<CFUUIDRef> uuid = CFUUIDCreate(NULL); std::string sigfile = RECORDER_DIR + cfStringRelease(CFUUIDCreateString(NULL, uuid)) + ".tsig"; try { UnixPlusPlus::AutoFileDesc fd(sigfile, O_WRONLY | O_CREAT); fd.write(CFDataGetBytePtr(signature), CFDataGetLength(signature)); status = recorder_code_adhoc; // recorded signature SYSPOLICY_RECORDER_MODE_ADHOC_PATH(cfString(path).c_str(), type, sigfile.c_str()); } catch (...) { } } // now report the D probe itself CFRef<CFDictionaryRef> info; MacOSError::check(SecCodeCopySigningInformation(code, kSecCSDefaultFlags, &info.aref())); CFDataRef cdhash = CFDataRef(CFDictionaryGetValue(info, kSecCodeInfoUnique)); SYSPOLICY_RECORDER_MODE(cfString(path).c_str(), type, "", cdhash ? CFDataGetBytePtr(cdhash) : NULL, status); } // rerun the validation to update state rc = SecStaticCodeCheckValidity(code, validationFlags | kSecCSBasicValidateOnly, requirement); } catch (...) { } } switch (rc) { case noErr: // well signed and satisfies requirement... break; // ... continue below case errSecCSSignatureFailed: if (!codeInvalidityExceptions(code, result)) { if (SYSPOLICY_ASSESS_OUTCOME_BROKEN_ENABLED()) SYSPOLICY_ASSESS_OUTCOME_BROKEN(cfString(path).c_str(), type, false); MacOSError::throwMe(rc); } if (SYSPOLICY_ASSESS_OUTCOME_BROKEN_ENABLED()) SYSPOLICY_ASSESS_OUTCOME_BROKEN(cfString(path).c_str(), type, true); // treat as unsigned to fix problems in the field case errSecCSUnsigned: if (handleUnsignedCode) { cfadd(result, "{%O=#F}", kSecAssessmentAssessmentVerdict); addAuthority(result, "no usable signature"); } return; case errSecCSReqFailed: // requirement missed, but otherwise okay continue; default: // broken in some way; all tests will fail like this so bail out MacOSError::throwMe(rc); } if (disabled) { if (latentID == 0) { latentID = id; if (label) latentLabel = label; } continue; // the loop } CFRef<CFDictionaryRef> info; // as needed if (flags & kSecAssessmentFlagRequestOrigin) { if (!info) MacOSError::check(SecCodeCopySigningInformation(code, kSecCSSigningInformation, &info.aref())); if (CFArrayRef chain = CFArrayRef(CFDictionaryGetValue(info, kSecCodeInfoCertificates))) setOrigin(chain, result); } if (!(ruleFlags & kAuthorityFlagInhibitCache) && !(flags & kSecAssessmentFlagNoCache)) { // cache inhibit if (!info) MacOSError::check(SecCodeCopySigningInformation(code, kSecCSSigningInformation, &info.aref())); if (SecTrustRef trust = SecTrustRef(CFDictionaryGetValue(info, kSecCodeInfoTrust))) { CFRef<CFDictionaryRef> xinfo; MacOSError::check(SecTrustCopyExtendedResult(trust, &xinfo.aref())); if (CFDateRef limit = CFDateRef(CFDictionaryGetValue(xinfo, kSecTrustExpirationDate))) { this->recordOutcome(code, allow, type, min(expires, dateToJulian(limit)), id); } } } if (allow) { if (SYSPOLICY_ASSESS_OUTCOME_ACCEPT_ENABLED()) { if (!info) MacOSError::check(SecCodeCopySigningInformation(code, kSecCSSigningInformation, &info.aref())); CFDataRef cdhash = CFDataRef(CFDictionaryGetValue(info, kSecCodeInfoUnique)); SYSPOLICY_ASSESS_OUTCOME_ACCEPT(cfString(path).c_str(), type, label, cdhash ? CFDataGetBytePtr(cdhash) : NULL); } } else { if (SYSPOLICY_ASSESS_OUTCOME_DENY_ENABLED() || SYSPOLICY_RECORDER_MODE_ENABLED()) { if (!info) MacOSError::check(SecCodeCopySigningInformation(code, kSecCSSigningInformation, &info.aref())); CFDataRef cdhash = CFDataRef(CFDictionaryGetValue(info, kSecCodeInfoUnique)); std::string cpath = cfString(path); const void *hashp = cdhash ? CFDataGetBytePtr(cdhash) : NULL; SYSPOLICY_ASSESS_OUTCOME_DENY(cpath.c_str(), type, label, hashp); SYSPOLICY_RECORDER_MODE(cpath.c_str(), type, label, hashp, recorder_code_untrusted); } } cfadd(result, "{%O=%B}", kSecAssessmentAssessmentVerdict, allow); addAuthority(result, label, id); return; } if (rc == errSecCSUnsigned) { // skipped all applicable rules due to pre-screening cfadd(result, "{%O=#F}", kSecAssessmentAssessmentVerdict); addAuthority(result, "no usable signature"); return; } // no applicable authority (but signed, perhaps temporarily). Deny by default CFRef<CFDictionaryRef> info; MacOSError::check(SecCodeCopySigningInformation(code, kSecCSSigningInformation, &info.aref())); if (flags & kSecAssessmentFlagRequestOrigin) { if (CFArrayRef chain = CFArrayRef(CFDictionaryGetValue(info, kSecCodeInfoCertificates))) setOrigin(chain, result); } if (SYSPOLICY_ASSESS_OUTCOME_DEFAULT_ENABLED() || SYSPOLICY_RECORDER_MODE_ENABLED()) { CFDataRef cdhash = CFDataRef(CFDictionaryGetValue(info, kSecCodeInfoUnique)); const void *hashp = cdhash ? CFDataGetBytePtr(cdhash) : NULL; std::string cpath = cfString(path); SYSPOLICY_ASSESS_OUTCOME_DEFAULT(cpath.c_str(), type, latentLabel.c_str(), hashp); SYSPOLICY_RECORDER_MODE(cpath.c_str(), type, latentLabel.c_str(), hashp, 0); } if (!(flags & kSecAssessmentFlagNoCache)) this->recordOutcome(code, false, type, this->julianNow() + NEGATIVE_HOLD, latentID); cfadd(result, "{%O=%B}", kSecAssessmentAssessmentVerdict, false); addAuthority(result, latentLabel.c_str(), latentID); }
void PolicyEngine::evaluateCodeItem(SecStaticCodeRef code, CFURLRef path, AuthorityType type, SecAssessmentFlags flags, bool nested, CFMutableDictionaryRef result) { SQLite::Statement query(*this, "SELECT allow, requirement, id, label, expires, flags, disabled, filter_unsigned, remarks FROM scan_authority" " WHERE type = :type" " ORDER BY priority DESC;"); query.bind(":type").integer(type); SQLite3::int64 latentID = 0; // first (highest priority) disabled matching ID std::string latentLabel; // ... and associated label, if any while (query.nextRow()) { bool allow = int(query[0]); const char *reqString = query[1]; SQLite3::int64 id = query[2]; const char *label = query[3]; double expires = query[4]; sqlite3_int64 ruleFlags = query[5]; SQLite3::int64 disabled = query[6]; // const char *filter = query[7]; // const char *remarks = query[8]; CFRef<SecRequirementRef> requirement; MacOSError::check(SecRequirementCreateWithString(CFTempString(reqString), kSecCSDefaultFlags, &requirement.aref())); switch (OSStatus rc = SecStaticCodeCheckValidity(code, kSecCSBasicValidateOnly, requirement)) { case errSecSuccess: break; // rule match; process below case errSecCSReqFailed: continue; // rule does not apply case errSecCSVetoed: return; // nested code has failed to pass default: MacOSError::throwMe(rc); // general error; pass to caller } // if this rule is disabled, skip it but record the first matching one for posterity if (disabled && latentID == 0) { latentID = id; latentLabel = label ? label : ""; continue; } // current rule is first rule (in priority order) that matched. Apply it if (nested) // success, nothing to record return; CFRef<CFDictionaryRef> info; // as needed if (flags & kSecAssessmentFlagRequestOrigin) { if (!info) MacOSError::check(SecCodeCopySigningInformation(code, kSecCSSigningInformation, &info.aref())); if (CFArrayRef chain = CFArrayRef(CFDictionaryGetValue(info, kSecCodeInfoCertificates))) setOrigin(chain, result); } if (!(ruleFlags & kAuthorityFlagInhibitCache) && !(flags & kSecAssessmentFlagNoCache)) { // cache inhibit if (!info) MacOSError::check(SecCodeCopySigningInformation(code, kSecCSSigningInformation, &info.aref())); if (SecTrustRef trust = SecTrustRef(CFDictionaryGetValue(info, kSecCodeInfoTrust))) { CFRef<CFDictionaryRef> xinfo; MacOSError::check(SecTrustCopyExtendedResult(trust, &xinfo.aref())); if (CFDateRef limit = CFDateRef(CFDictionaryGetValue(xinfo, kSecTrustExpirationDate))) { this->recordOutcome(code, allow, type, min(expires, dateToJulian(limit)), id); } } } if (allow) { if (SYSPOLICY_ASSESS_OUTCOME_ACCEPT_ENABLED()) { if (!info) MacOSError::check(SecCodeCopySigningInformation(code, kSecCSSigningInformation, &info.aref())); CFDataRef cdhash = CFDataRef(CFDictionaryGetValue(info, kSecCodeInfoUnique)); SYSPOLICY_ASSESS_OUTCOME_ACCEPT(cfString(path).c_str(), type, label, cdhash ? CFDataGetBytePtr(cdhash) : NULL); } } else { if (SYSPOLICY_ASSESS_OUTCOME_DENY_ENABLED() || SYSPOLICY_RECORDER_MODE_ENABLED()) { if (!info) MacOSError::check(SecCodeCopySigningInformation(code, kSecCSSigningInformation, &info.aref())); CFDataRef cdhash = CFDataRef(CFDictionaryGetValue(info, kSecCodeInfoUnique)); std::string cpath = cfString(path); const void *hashp = cdhash ? CFDataGetBytePtr(cdhash) : NULL; SYSPOLICY_ASSESS_OUTCOME_DENY(cpath.c_str(), type, label, hashp); SYSPOLICY_RECORDER_MODE(cpath.c_str(), type, label, hashp, recorder_code_untrusted); } } cfadd(result, "{%O=%B}", kSecAssessmentAssessmentVerdict, allow); addAuthority(flags, result, label, id); return; } // no applicable authority (but signed, perhaps temporarily). Deny by default CFRef<CFDictionaryRef> info; MacOSError::check(SecCodeCopySigningInformation(code, kSecCSSigningInformation, &info.aref())); if (flags & kSecAssessmentFlagRequestOrigin) { if (CFArrayRef chain = CFArrayRef(CFDictionaryGetValue(info, kSecCodeInfoCertificates))) setOrigin(chain, result); } if (SYSPOLICY_ASSESS_OUTCOME_DEFAULT_ENABLED() || SYSPOLICY_RECORDER_MODE_ENABLED()) { CFDataRef cdhash = CFDataRef(CFDictionaryGetValue(info, kSecCodeInfoUnique)); const void *hashp = cdhash ? CFDataGetBytePtr(cdhash) : NULL; std::string cpath = cfString(path); SYSPOLICY_ASSESS_OUTCOME_DEFAULT(cpath.c_str(), type, latentLabel.c_str(), hashp); SYSPOLICY_RECORDER_MODE(cpath.c_str(), type, latentLabel.c_str(), hashp, 0); } if (!(flags & kSecAssessmentFlagNoCache)) this->recordOutcome(code, false, type, this->julianNow() + NEGATIVE_HOLD, latentID); cfadd(result, "{%O=%B}", kSecAssessmentAssessmentVerdict, false); addAuthority(flags, result, latentLabel.c_str(), latentID); }