X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/libsecurity_codesigning/lib/opaquewhitelist.cpp diff --git a/libsecurity_codesigning/lib/opaquewhitelist.cpp b/libsecurity_codesigning/lib/opaquewhitelist.cpp deleted file mode 100644 index ae5b6e2a..00000000 --- a/libsecurity_codesigning/lib/opaquewhitelist.cpp +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright (c) 2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -#include "opaquewhitelist.h" -#include "csutilities.h" -#include "StaticCode.h" -#include -#include -#include -#include -#include -#include -#include - -namespace Security { -namespace CodeSigning { - -using namespace SQLite; - - -static void traceHash(MessageTrace &trace, const char *key, CFDataRef hash); -static void attachOpaque(SecStaticCodeRef code); - - -// -// Open the database -// -OpaqueWhitelist::OpaqueWhitelist(const char *path, int flags) - : SQLite::Database(path ? path : opaqueDatabase, flags) -{ - SQLite::Statement createConditions(*this, - "CREATE TABLE IF NOT EXISTS conditions (" - " label text," - " weight real not null unique," - " source text," - " identifier text," - " version text," - " conditions text not null);" - ); - createConditions.execute(); - -} - -OpaqueWhitelist::~OpaqueWhitelist() -{ /* virtual */ } - - -// -// Check if a code object is whitelisted -// -bool OpaqueWhitelist::contains(SecStaticCodeRef codeRef, OSStatus reason, bool trace) -{ - // make our own copy of the code object, so we can poke at it without disturbing the original - SecPointer code = new SecStaticCode(SecStaticCode::requiredStatic(codeRef)->diskRep()); - - CFCopyRef current = code->cdHash(); // current cdhash - CFDataRef opaque = NULL; // holds computed opaque cdhash - bool match = false; // holds final result - - if (!current) - return false; // unsigned - - // collect auxiliary information for trace - CFRef info; - std::string team = ""; - CFStringRef cfVersion = NULL, cfShortVersion = NULL, cfExecutable = NULL; - if (errSecSuccess == SecCodeCopySigningInformation(code->handle(false), kSecCSSigningInformation, &info.aref())) { - if (CFStringRef cfTeam = CFStringRef(CFDictionaryGetValue(info, kSecCodeInfoTeamIdentifier))) - team = cfString(cfTeam); - if (CFDictionaryRef infoPlist = CFDictionaryRef(CFDictionaryGetValue(info, kSecCodeInfoPList))) { - if (CFTypeRef version = CFDictionaryGetValue(infoPlist, kCFBundleVersionKey)) - if (CFGetTypeID(version) == CFStringGetTypeID()) - cfVersion = CFStringRef(version); - if (CFTypeRef shortVersion = CFDictionaryGetValue(infoPlist, _kCFBundleShortVersionStringKey)) - if (CFGetTypeID(shortVersion) == CFStringGetTypeID()) - cfShortVersion = CFStringRef(shortVersion); - if (CFTypeRef executable = CFDictionaryGetValue(infoPlist, kCFBundleExecutableKey)) - if (CFGetTypeID(executable) == CFStringGetTypeID()) - cfExecutable = CFStringRef(executable); - } - } - - // compute and attach opaque signature - attachOpaque(code->handle(false)); - opaque = code->cdHash(); - - // lookup current cdhash in whitelist - SQLite::Statement lookup(*this, "SELECT opaque FROM whitelist WHERE current=:current"); - lookup.bind(":current") = current.get(); - while (lookup.nextRow()) { - CFRef expected = lookup[0].data(); - if (CFEqual(opaque, expected)) { - match = true; // actual opaque cdhash matches expected - break; - } - } - - if (trace) { - // send a trace indicating the result - MessageTrace trace("com.apple.security.assessment.whitelist2", code->identifier().c_str()); - traceHash(trace, "signature2", current); - traceHash(trace, "signature3", opaque); - trace.add("result", match ? "pass" : "fail"); - trace.add("reason", "%d", reason); - if (!team.empty()) - trace.add("teamid", "%s", team.c_str()); - if (cfVersion) - trace.add("version", "%s", cfString(cfVersion).c_str()); - if (cfShortVersion) - trace.add("version2", "%s", cfString(cfShortVersion).c_str()); - if (cfExecutable) - trace.add("execname", "%s", cfString(cfExecutable).c_str()); - trace.send(""); - } - - return match; -} - - -// -// Obtain special validation conditions for a static code, based on database configuration. -// -CFDictionaryRef OpaqueWhitelist::validationConditionsFor(SecStaticCodeRef code) -{ - // figure out which team key to use - std::string team = "UNKNOWN"; - CFStringRef cfId = NULL; - CFStringRef cfVersion = NULL; - CFRef info; // holds lifetimes for the above - if (errSecSuccess == SecCodeCopySigningInformation(code, kSecCSSigningInformation, &info.aref())) { - if (CFStringRef cfTeam = CFStringRef(CFDictionaryGetValue(info, kSecCodeInfoTeamIdentifier))) - team = cfString(cfTeam); - cfId = CFStringRef(CFDictionaryGetValue(info, kSecCodeInfoIdentifier)); - if (CFDictionaryRef infoPlist = CFDictionaryRef(CFDictionaryGetValue(info, kSecCodeInfoPList))) - if (CFTypeRef version = CFDictionaryGetValue(infoPlist, _kCFBundleShortVersionStringKey)) - if (CFGetTypeID(version) == CFStringGetTypeID()) - cfVersion = CFStringRef(version); - } - if (cfId == NULL) // unsigned; punt - return NULL; - - // find the highest weight matching condition. We perform no merging and the heaviest rule wins - SQLite::Statement matches(*this, - "SELECT conditions FROM conditions" - " WHERE (source = :source or source IS NULL)" - " AND (identifier = :identifier or identifier is NULL)" - " AND ((:version IS NULL AND version IS NULL) OR (version = :version OR version IS NULL))" - " ORDER BY weight DESC" - " LIMIT 1" - ); - matches.bind(":source") = team; - matches.bind(":identifier") = cfString(cfId); - if (cfVersion) - matches.bind(":version") = cfString(cfVersion); - if (matches.nextRow()) { - CFTemp conditions((const char*)matches[0]); - return conditions.yield(); - } - // no matches - return NULL; -} - - -// -// Convert a SHA1 hash to hex and add to a trace -// -static void traceHash(MessageTrace &trace, const char *key, CFDataRef hash) -{ - if (CFDataGetLength(hash) != sizeof(SHA1::Digest)) { - trace.add(key, "(unknown format)"); - } else { - const UInt8 *bytes = CFDataGetBytePtr(hash); - char s[2 * SHA1::digestLength + 1]; - for (unsigned n = 0; n < SHA1::digestLength; n++) - sprintf(&s[2*n], "%2.2x", bytes[n]); - trace.add(key, s); - } -} - - -// -// Add a code object to the whitelist -// -void OpaqueWhitelist::add(SecStaticCodeRef codeRef) -{ - // make our own copy of the code object - SecPointer code = new SecStaticCode(SecStaticCode::requiredStatic(codeRef)->diskRep()); - - CFCopyRef current = code->cdHash(); - attachOpaque(code->handle(false)); // compute and attach an opaque signature - CFDataRef opaque = code->cdHash(); - - SQLite::Statement insert(*this, "INSERT OR REPLACE INTO whitelist (current,opaque) VALUES (:current, :opaque)"); - insert.bind(":current") = current.get(); - insert.bind(":opaque") = opaque; - insert.execute(); -} - - -// -// Generate and attach an ad-hoc opaque signature -// -static void attachOpaque(SecStaticCodeRef code) -{ - CFTemp rules("{" // same resource rules as used for collection - "rules={" - "'^.*' = #T" - "'^Info\\.plist$' = {omit=#T,weight=10}" - "},rules2={" - "'^(Frameworks|SharedFrameworks|Plugins|Plug-ins|XPCServices|Helpers|MacOS)/' = {nested=#T, weight=0}" - "'^.*' = #T" - "'^Info\\.plist$' = {omit=#T,weight=10}" - "'^[^/]+$' = {top=#T, weight=0}" - "}" - "}"); - - CFRef signature = CFDataCreateMutable(NULL, 0); - CFTemp arguments("{%O=%O, %O=#N, %O=%O}", - kSecCodeSignerDetached, signature.get(), - kSecCodeSignerIdentity, /* kCFNull, */ - kSecCodeSignerResourceRules, rules.get()); - CFRef signer; - SecCSFlags flags = kSecCSSignOpaque | kSecCSSignNoV1 | kSecCSSignBundleRoot; - MacOSError::check(SecCodeSignerCreate(arguments, flags, &signer.aref())); - MacOSError::check(SecCodeSignerAddSignature(signer, code, kSecCSDefaultFlags)); - MacOSError::check(SecCodeSetDetachedSignature(code, signature, kSecCSDefaultFlags)); -} - - -} // end namespace CodeSigning -} // end namespace Security