Пример #1
0
//
// 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);
		}
	}
}
Пример #2
0
//
// 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;
}