static void dumpCode(SecCodeRef code) { CFRef<CFURLRef> path; if (OSStatus rc = SecCodeCopyPath(code, kSecCSDefaultFlags, &path.aref())) Debug::dump("unknown(rc=%d)", int32_t(rc)); else Debug::dump("%s", cfString(path).c_str()); }
// // 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); } } }
// // Take an assessment outcome and record it in the object cache // void PolicyEngine::recordOutcome(SecStaticCodeRef code, bool allow, AuthorityType type, double expires, SQLite::int64 authority) { CFRef<CFDictionaryRef> info; MacOSError::check(SecCodeCopySigningInformation(code, kSecCSDefaultFlags, &info.aref())); CFDataRef cdHash = CFDataRef(CFDictionaryGetValue(info, kSecCodeInfoUnique)); assert(cdHash); // was signed CFRef<CFURLRef> path; MacOSError::check(SecCodeCopyPath(code, kSecCSDefaultFlags, &path.aref())); assert(expires); SQLite::Transaction xact(*this, SQLite3::Transaction::deferred, "caching"); SQLite::Statement insert(*this, "INSERT OR REPLACE INTO object (type, allow, hash, expires, path, authority)" " VALUES (:type, :allow, :hash, :expires, :path," " CASE :authority WHEN 0 THEN (SELECT id FROM authority WHERE label = 'No Matching Rule') ELSE :authority END" " );"); insert.bind(":type").integer(type); insert.bind(":allow").integer(allow); insert.bind(":hash") = cdHash; insert.bind(":expires") = expires; insert.bind(":path") = cfString(path); insert.bind(":authority").integer(authority); insert.execute(); xact.commit(); }
// // OSXCodeWrap // string OSXCodeWrap::canonicalPath() const { CFURLRef path; MacOSError::check(SecCodeCopyPath(mCode, kSecCSDefaultFlags, &path)); return cfStringRelease(path); }
// // Bonus function: get the path out of a SecCodeRef // std::string codePath(SecStaticCodeRef code) { CFRef<CFURLRef> path; MacOSError::check(SecCodeCopyPath(code, kSecCSDefaultFlags, &path.aref())); return cfString(path); }