// // 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); } } }
// // Create a Verifier from a code object. // // This does not add any auxiliary information blobs. You can do that // by calling add() after construction, of course. // OSXVerifier::OSXVerifier(OSXCode *code) { mPath = code->canonicalPath(); secdebug("codesign", "building verifier for %s", mPath.c_str()); // build new-style verifier CFRef<SecStaticCodeRef> staticCode = code->codeRef(); switch (OSStatus rc = SecCodeCopyDesignatedRequirement(staticCode, kSecCSDefaultFlags, &mRequirement.aref())) { case noErr: secdebug("codesign", " is signed; canonical requirement loaded"); break; case errSecCSUnsigned: secdebug("codesign", " is unsigned; no requirement"); break; default: MacOSError::throwMe(rc); } // build old-style verifier makeLegacyHash(code, mLegacyHash); secdebug("codesign", " hash generated"); }
bool PolicyEngine::temporarySigning(SecStaticCodeRef code, AuthorityType type, CFURLRef path, SecAssessmentFlags matchFlags) { if (matchFlags == 0) { // playback; consult authority table for matches DiskRep *rep = SecStaticCode::requiredStatic(code)->diskRep(); std::string screen; if (CFRef<CFDataRef> info = rep->component(cdInfoSlot)) { SHA1 hash; hash.update(CFDataGetBytePtr(info), CFDataGetLength(info)); screen = createWhitelistScreen('I', hash); } else if (rep->mainExecutableImage()) { screen = "N"; } else { SHA1 hash; hashFileData(rep->mainExecutablePath().c_str(), &hash); screen = createWhitelistScreen('M', hash); } SQLite::Statement query(*this, "SELECT flags FROM authority " "WHERE type = :type" " AND NOT flags & :flag" " AND CASE WHEN filter_unsigned IS NULL THEN remarks = :remarks ELSE filter_unsigned = :screen END"); query.bind(":type").integer(type); query.bind(":flag").integer(kAuthorityFlagDefault); query.bind(":screen") = screen; query.bind(":remarks") = cfString(path); if (!query.nextRow()) // guaranteed no matching rule return false; matchFlags = SQLite3::int64(query[0]); } 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, (matchFlags & kAuthorityFlagWhitelistV2) ? kSecCSSignOpaque : kSecCSSignV1, &signer.aref())); MacOSError::check(SecCodeSignerAddSignature(signer, code, kSecCSDefaultFlags)); MacOSError::check(SecCodeSetDetachedSignature(code, signature, kSecCSDefaultFlags)); SecRequirementRef dr = NULL; SecCodeCopyDesignatedRequirement(code, kSecCSDefaultFlags, &dr); CFStringRef drs = NULL; SecRequirementCopyString(dr, kSecCSDefaultFlags, &drs); // 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); } return true; // it worked; we're now (well) signed } catch (...) { } return false; }