);
dependencies = (
186F779114E5A00F00434E1F /* PBXTargetDependency */,
+ C2432A2515C726B50096DB5B /* PBXTargetDependency */,
);
name = Security_executables;
productName = Other;
remoteGlobalIDString = 52200F8F14F2B88000F7F6E7;
remoteInfo = XPCTimeStampingService;
};
+ C2432A0715C7112A0096DB5B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 1879B657146DE756007E536C /* libsecurity_codesigning.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = C209696015BF52040093035F;
+ remoteInfo = gkunpack;
+ };
+ C2432A2415C726B50096DB5B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 1879B657146DE756007E536C /* libsecurity_codesigning.xcodeproj */;
+ proxyType = 1;
+ remoteGlobalIDString = C209695F15BF52040093035F;
+ remoteInfo = gkunpack;
+ };
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
1879B666146DE757007E536C /* libsecurity_codesigning.a */,
1879B66A146DE757007E536C /* libintegrity.a */,
1879B66C146DE757007E536C /* libcodehost.a */,
+ C2432A0815C7112A0096DB5B /* gkunpack */,
);
name = Products;
sourceTree = "<group>";
remoteRef = 52B5A8F5151928B400664F11 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
+ C2432A0815C7112A0096DB5B /* gkunpack */ = {
+ isa = PBXReferenceProxy;
+ fileType = "compiled.mach-o.executable";
+ path = gkunpack;
+ remoteRef = C2432A0715C7112A0096DB5B /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
/* End PBXReferenceProxy section */
/* Begin PBXResourcesBuildPhase section */
name = XPCTimeStampingService;
targetProxy = 529FF21F1523BD7F0029D842 /* PBXContainerItemProxy */;
};
+ C2432A2515C726B50096DB5B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ name = gkunpack;
+ targetProxy = C2432A2415C726B50096DB5B /* PBXContainerItemProxy */;
+ };
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
- <string>55178.0.1</string>
+ <string>55179.1</string>
</dict>
</plist>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
- <string>55178.0.1</string>
+ <string>55179.1</string>
<key>CFBundleShortVersionString</key>
<string>3.0</string>
</dict>
void
Crypt::activate()
{
+ StLock<Mutex> _(mActivateMutex);
if (!mActive)
{
// Key is required unless we have a NULL algorithm (cleartext wrap/unwrap),
Key mKey;
const CssmData *mInitVector;
CSSM_PADDING mPadding;
+ RecursiveMutex mActivateMutex;
};
void Context::deactivate()
{
+ StLock<Mutex> _(mActivateMutex);
if (mActive)
{
mActive = false;
void PassThrough::activate()
{
+ StLock<Mutex> _(mActivateMutex);
if (!mActive) {
check(CSSM_CSP_CreatePassThroughContext(attachment()->handle(), mKey, &mHandle));
mActive = true;
//
void Digest::activate()
{
+ StLock<Mutex> _(mActivateMutex);
if (!mActive) {
check(CSSM_CSP_CreateDigestContext(attachment()->handle(), mAlgorithm, &mHandle));
mActive = true;
void Random::activate()
{
+ StLock<Mutex> _(mActivateMutex);
if (!mActive) {
check(CSSM_CSP_CreateRandomGenContext(attachment()->handle(), mAlgorithm,
mSeed, mSize, &mHandle));
CSSM_CC_HANDLE mHandle; // CSSM CC handle
bool mStaged; // staged in progress
const AccessCredentials *mCred; // if explicitly set
+ RecursiveMutex mActivateMutex;
};
void
CssmImpl::activate()
{
+ StLock<Mutex> _(mActivateMutex);
if (!mActive)
{
// currently, no choices on PVC mode and key hierarchy
void
CssmImpl::deactivate()
{
+ StLock<Mutex> _(mActivateMutex);
if (mActive)
{
mActive = false;
void
ModuleImpl::activate()
{
+ StLock<Mutex> _(mActivateMutex);
if (!mActive)
{
session()->init();
void
ModuleImpl::deactivate()
{
+ StLock<Mutex> _(mActivateMutex);
if (!isIdle())
Error::throwMe(Error::objectBusy);
if (mActive)
void
AttachmentImpl::activate()
{
+ StLock<Mutex> _(mActivateMutex);
if (!mActive)
{
module()->load();
void
AttachmentImpl::deactivate()
{
+ StLock<Mutex> _(mActivateMutex);
if (mActive)
{
mActive = false;
protected:
bool mActive; // loaded, attached, etc.
+ RecursiveMutex mActivateMutex;
mutable Allocator *mAllocator; // allocator hierarchy (NULL => TBD)
template <class Obj> Obj parent() const
check(CSSM_DL_DbOpen(mHandle.DLHandle, mDbName.canonicalName(), dbLocation(),
mAccessRequest, mAccessCredentials,
mOpenParameters, &mHandle.DBHandle));
+
+ StLock<Mutex> _(mActivateMutex);
mActive = true;
if (!mAccessCredentials && mDefaultCredentials)
void
DbImpl::create()
{
+ StLock<Mutex> _(mActivateMutex);
if (mActive)
CssmError::throwMe(CSSMERR_DL_DATASTORE_ALREADY_EXISTS);
void
DbImpl::close()
{
+ StLock<Mutex> _(mActivateMutex);
if (mActive)
{
check(CSSM_DL_DbClose (mHandle));
void
DbImpl::activate()
{
+ StLock<Mutex> _(mActivateMutex);
if (!mActive)
{
if (mDbInfo)
void
DbImpl::deactivate()
{
+ StLock<Mutex> _(mActivateMutex);
if (mActive)
{
mActive = false;
attributes,
data,
unique);
+
+ StLock<Mutex> _(mActivateMutex);
if (result == CSSM_OK)
mActive = true;
else if (data != NULL)
if (result == CSSMERR_DL_ENDOFDATA)
{
+ StLock<Mutex> _(mActivateMutex);
mActive = false;
return false;
}
void
DbDbCursorImpl::deactivate()
{
+ StLock<Mutex> _(mActivateMutex);
if (mActive)
{
mActive = false;
void
DbUniqueRecordImpl::activate()
{
+ StLock<Mutex> _(mActivateMutex);
mActive = true;
}
void
DbUniqueRecordImpl::deactivate()
{
+ StLock<Mutex> _(mActivateMutex);
if (mActive)
{
mActive = false;
CSSM_DB_UNIQUE_RECORD_PTR mUniqueId;
bool mDestroyID;
+ RecursiveMutex mActivateMutex;
};
class DbUniqueRecord : public Object
private:
CSSM_HANDLE mResultsHandle;
+ RecursiveMutex mActivateMutex;
};
} // end namespace CssmClient
void GenerateKey::activate()
{
+ StLock<Mutex> _(mActivateMutex);
if (!mActive)
{
check(CSSM_CSP_CreateKeyGenContext(attachment()->handle(), mAlgorithm,
void
KeyImpl::deleteKey(const CSSM_ACCESS_CREDENTIALS *cred)
{
+ StLock<Mutex> _(mActivateMutex);
if (mActive)
{
mActive=false;
void KeyImpl::activate()
{
+ StLock<Mutex> _(mActivateMutex);
mActive=true;
}
void KeyImpl::deactivate()
{
+ StLock<Mutex> _(mActivateMutex);
if (mActive)
{
mActive=false;
//
void MacContext::activate()
{
+ StLock<Mutex> _(mActivateMutex);
if (!mActive)
{
check(CSSM_CSP_CreateMacContext(attachment()->handle(), mAlgorithm,
void
MultiDLDbDbCursorImpl::activate()
{
+ StLock<Mutex> _(mActivateMutex);
if (!mActive)
{
mListRef = multiDLDb()->listRef();
void
MultiDLDbDbCursorImpl::deactivate()
{
+ StLock<Mutex> _(mActivateMutex);
if (mActive)
{
mActive = false;
//
void SigningContext::activate()
{
+ StLock<Mutex> _(mActivateMutex);
if (!mActive)
{
check(CSSM_CSP_CreateSignatureContext(attachment()->handle(), mAlgorithm,
}
self string type;
-syspolicy*:::assess-outcome-* / arg1 == 1 / { type = "execute"; }
-syspolicy*:::assess-outcome-* / arg1 == 2 / { type = "install"; }
+syspolicy*:::assess-outcome-* { self->type = "???"; }
+syspolicy*:::assess-outcome-* / arg1 == 1 / { self->type = "execute"; }
+syspolicy*:::assess-outcome-* / arg1 == 2 / { self->type = "install"; }
+syspolicy*:::assess-outcome-* / arg1 == 3 / { self->type = "open"; }
syspolicy*:::assess-outcome-accept
{
- printf("accept %s %s;%s", self->type, copyinstr(arg0), copyinstr(arg1));
- self->cdhash = copyin(arg2, 20);
+ printf("accept %s %s;%s", self->type, copyinstr(arg0), copyinstr(arg2));
+ self->cdhash = copyin(arg3, 20);
}
syspolicy*:::assess-outcome-deny
{
- printf("deny %s %s;%s", self->type, copyinstr(arg0), copyinstr(arg1));
- self->cdhash = copyin(arg2, 20);
+ printf("deny %s %s;%s", self->type, copyinstr(arg0), copyinstr(arg2));
+ self->cdhash = copyin(arg3, 20);
}
syspolicy*:::assess-outcome-default
{
- printf("default %s %s;%s", self->type, copyinstr(arg0), copyinstr(arg1));
- self->cdhash = copyin(arg2, 20);
+ printf("default %s %s;%s", self->type, copyinstr(arg0), copyinstr(arg2));
+ self->cdhash = copyin(arg3, 20);
}
syspolicy*:::assess-outcome-unsigned
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Label</key>
+ <string>com.apple.gkreport</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/usr/libexec/gkreport</string>
+ </array>
+ <key>StartCalendarInterval</key>
+ <dict>
+ <key>Minute</key><integer>52</integer>
+ <key>Hour</key><integer>3</integer>
+ <key>WeekDay</key><integer>5</integer>
+ </dict>
+</dict>
+</plist>
authfile = "gke.auth"
sigfile = "gke.dsig"
-
#
# Usage and fail
#
sigsfile = args.output + ".sigs"
+#
+# Augment a snippet record
+#
+def augment(data):
+ for auth in data.authority.values():
+ if auth.path in data.signatures:
+ signature = data.signatures[auth.path].signature.data
+ unpack = subprocess.Popen(["/usr/local/bin/gkunpack"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ (stdout, stderr) = unpack.communicate(input=signature)
+ if stderr:
+ fail("signature unpack failed for %s" % auth.path)
+ auth.screen = stdout.rstrip();
+
+
#
# Start by collecting authority evidence from the authority records
#
for source in args.source:
if source[0] == '+':
data = plistlib.readPlist(source[1:])
+ augment(data)
auth.update(data["authority"])
sigs.update(data["signatures"])
else:
data = plistlib.readPlist(source)
+ augment(data)
auth.update(data["authority"])
if not auth and not args.empty:
--- /dev/null
+#!/bin/bash
+#
+# gkreport - report Gatekeeper state to MessageTracer
+#
+main=$(/usr/sbin/spctl --status)
+gk=$(/usr/sbin/spctl --test-devid-status)
+/usr/bin/syslog -s -k \
+ com.apple.message.domain com.apple.security.assessment.current_state \
+ com.apple.message.signature "$main" \
+ com.apple.message.signature2 "$gk" \
+ Message "Gatekeeper state $main/$gk"
--- /dev/null
+//
+// gkunpack - an ad-hoc tool for unpacking certain binary data from a detached code signature
+//
+// gkunpack <detached_signature_data >prescreen_filter_data
+//
+#include <security_utilities/macho++.h>
+#include <security_codesigning/codedirectory.h>
+#include <security_codesigning/sigblob.h>
+
+using namespace CodeSigning;
+
+
+int main(int argc, const char * argv[])
+{
+ if (const EmbeddedSignatureBlob *top = (const EmbeddedSignatureBlob *)BlobCore::readBlob(stdin)) {
+ if (top->magic() == DetachedSignatureBlob::typeMagic) { // multiple architectures - pick the native one
+ Architecture local = Architecture::local();
+ const EmbeddedSignatureBlob *sig = EmbeddedSignatureBlob::specific(top->find(local.cpuType()));
+ if (!sig)
+ sig = EmbeddedSignatureBlob::specific(top->find(local.cpuType() & ~CPU_ARCH_MASK));
+ top = sig;
+ }
+ if (top)
+ if (const CodeDirectory *cd = top->find<const CodeDirectory>(cdCodeDirectorySlot)) {
+ printf("%s\n", cd->screeningCode().c_str());
+ exit(0);
+ }
+ }
+ fprintf(stderr, "Invalid signature structure\n");
+ exit(1);
+}
errSecCSNoMatches = -67027, /* no matches for search or update operation */
errSecCSFileHardQuarantined = -67026, /* File created by an AppSandbox, exec/open not allowed */
errSecCSOutdated = -67025, /* presented data is out of date */
- errSecCSDbCorrupt = -67024, /* a system database of file is corrupt */
+ errSecCSDbCorrupt = -67024, /* a system database or file is corrupt */
};
//
struct _SecAssessment : private CFRuntimeBase {
public:
- _SecAssessment(CFURLRef p, CFDictionaryRef r) : path(p), result(r) { }
+ _SecAssessment(CFURLRef p, AuthorityType typ, CFDictionaryRef r) : path(p), type(typ), result(r) { }
CFCopyRef<CFURLRef> path;
+ AuthorityType type;
CFRef<CFDictionaryRef> result;
public:
// check the object cache first unless caller denied that or we need extended processing
if (!(flags & (kSecAssessmentFlagRequestOrigin | kSecAssessmentFlagIgnoreCache))) {
if (gDatabase().checkCache(path, type, result))
- return new SecAssessment(path, result.yield());
+ return new SecAssessment(path, type, result.yield());
}
if (flags & kSecAssessmentFlagDirect) {
throw; // let it go as an error
cfadd(result, "{%O=#F}", kSecAssessmentAssessmentVerdict);
}
- return new SecAssessment(path, result.yield());
+ return new SecAssessment(path, type, result.yield());
END_CSAPI_ERRORS1(NULL)
}
-static void traceResult(SecAssessment &assessment, CFDictionaryRef result)
+static void traceResult(SecAssessment &assessment, AuthorityType type, CFDictionaryRef result)
{
if (CFDictionaryGetValue(result, CFSTR("assessment:remote")))
return; // just traced in syspolicyd
MessageTrace trace("com.apple.security.assessment.outcome", NULL);
trace.add("signature2", "bundle:%s", identifier.c_str());
+ trace.add("signature4", "%d", type);
if (CFDictionaryGetValue(result, kSecAssessmentAssessmentVerdict) == kCFBooleanFalse) {
trace.add("signature", "denied:%s", authority.c_str());
trace.add("signature3", sanitized.c_str());
result = adulterated.get();
}
}
- traceResult(assessment, result);
+ traceResult(assessment, assessment.type, result);
return result.yield();
END_CSAPI_ERRORS1(NULL)
CFTemp<CFDictionaryRef> ctx("{%O=%s}", kSecAssessmentUpdateKeyLabel, "Developer ID");
if (CFDictionaryRef result = gEngine().enable(NULL, kAuthorityInvalid, kSecCSDefaultFlags, ctx))
CFRelease(result);
+ MessageTrace trace("com.apple.security.assessment.state", "enable-devid");
+ trace.send("enable Developer ID approval");
return true;
} else if (CFEqual(control, CFSTR("ui-disable-devid"))) {
CFTemp<CFDictionaryRef> ctx("{%O=%s}", kSecAssessmentUpdateKeyLabel, "Developer ID");
if (CFDictionaryRef result = gEngine().disable(NULL, kAuthorityInvalid, kSecCSDefaultFlags, ctx))
CFRelease(result);
+ MessageTrace trace("com.apple.security.assessment.state", "disable-devid");
+ trace.send("disable Developer ID approval");
return true;
} else if (CFEqual(control, CFSTR("ui-get-devid"))) {
CFBooleanRef &result = *(CFBooleanRef*)(arguments);
// or throws if it is not. As a side effect, a successful return sets up the
// cached certificate chain for future use.
// Returns true if the signature is expired (the X.509 sense), false if it's not.
+// Expiration is fatal (throws) if a secure timestamp is included, but not otherwise.
//
bool SecStaticCode::verifySignature()
{
MacOSError::throwMe(result);
}
}
+
+ if (mSigningTimestamp) {
+ CFIndex rootix = CFArrayGetCount(mCertChain);
+ if (SecCertificateRef mainRoot = SecCertificateRef(CFArrayGetValueAtIndex(mCertChain, rootix-1)))
+ if (isAppleCA(mainRoot)) {
+ // impose policy: if the signature itself draws to Apple, then so must the timestamp signature
+ CFRef<CFArrayRef> tsCerts;
+ MacOSError::check(CMSDecoderCopySignerTimestampCertificates(cms, 0, &tsCerts.aref()));
+ CFIndex tsn = CFArrayGetCount(tsCerts);
+ bool good = tsn > 0 && isAppleCA(SecCertificateRef(CFArrayGetValueAtIndex(tsCerts, tsn-1)));
+#ifndef WORKAROUND_12007637
+ // TS certificates are reordered weirdly; check them all
+ for (CFIndex n = 0; n < tsn; n++)
+ if (SecCertificateRef tsRoot = SecCertificateRef(CFArrayGetValueAtIndex(tsCerts, n)))
+ if ((good = isAppleCA(tsRoot))) {
+ secdebug("BUG", "Apple root at TS cert %ld", n);
+ break;
+ }
+#endif //WORKAROUND_12007637
+ if (!good)
+ MacOSError::throwMe(CSSMERR_TP_NOT_TRUSTED);
+ }
+ }
+
return actionData.ActionFlags & CSSM_TP_ACTION_ALLOW_EXPIRED;
}
}
}
+//
+// Turn a hash of canonical type into a hex string
+//
+std::string CodeDirectory::hexHash(const unsigned char *hash) const
+{
+ size_t size = this->hashSize;
+ char result[2*size+1];
+ for (unsigned n = 0; n < size; n++)
+ sprintf(result+2*n, "%02.2x", hash[n]);
+ return result;
+}
+
+
+//
+// Generate a screening code string from a (complete) CodeDirectory.
+// This can be used to make a lightweight pre-screening code from (just) a CodeDirectory.
+//
+std::string CodeDirectory::screeningCode() const
+{
+ if (slotIsPresent(-cdInfoSlot)) // has Info.plist
+ return "I" + hexHash((*this)[-cdInfoSlot]); // use Info.plist hash
+ if (pageSize == 0) // good-enough proxy for "not a Mach-O file"
+ return "M" + hexHash((*this)[0]); // use hash of main executable
+ return "N"; // no suitable screening code
+}
+
+
} // CodeSigning
} // Security
public:
static DynamicHash *hashFor(HashAlgorithm hashType); // create a DynamicHash subclass for (hashType) digests
DynamicHash *getHash() const { return hashFor(this->hashType); } // make one for me
+
+ std::string hexHash(const unsigned char *hash) const; // encode any canonical-type hash as a hex string
protected:
static size_t generateHash(DynamicHash *hash, UnixPlusPlus::FileDesc fd, Hashing::Byte *digest, size_t limit = 0); // hash to count or end of file
static const char *canonicalSlotName(SpecialSlot slot);
static unsigned slotAttributes(SpecialSlot slot);
IFDEBUG(static const char * const debugSlotName[]);
+
+public:
+ //
+ // Canonical screening code. Requires a fully formed CodeDirectory.
+ //
+ std::string screeningCode() const;
};
#include "csutilities.h"
#include <Security/SecCertificatePriv.h>
#include <security_codesigning/requirement.h>
+#include <security_utilities/hashing.h>
#include <security_utilities/debugging.h>
#include <security_utilities/errors.h>
namespace CodeSigning {
+//
+// The (SHA-1) hash of the canonical Apple certificate root anchor
+//
+static const SHA1::Digest gAppleAnchorHash =
+ { 0x61, 0x1e, 0x5b, 0x66, 0x2c, 0x59, 0x3a, 0x08, 0xff, 0x58,
+ 0xd1, 0x4a, 0xe2, 0x24, 0x52, 0xd1, 0x98, 0xdf, 0x6c, 0x60 };
+
+
+
+//
+// Test for the canonical Apple CA certificate
+//
+bool isAppleCA(SecCertificateRef cert)
+{
+ return verifyHash(cert, gAppleAnchorHash);
+}
+
+bool isAppleCA(const Hashing::Byte *sha1)
+{
+ return !memcmp(sha1, gAppleAnchorHash, SHA1::digestLength);
+}
+
+
//
// Calculate the canonical hash of a certificate, given its raw (DER) data.
//
}
+//
+// One-stop hash-certificate-and-compare
+//
+bool verifyHash(SecCertificateRef cert, const Hashing::Byte *digest)
+{
+ SHA1::Digest dig;
+ hashOfCertificate(cert, dig);
+ return !memcmp(dig, digest, SHA1::digestLength);
+}
+
+
//
// Check to see if a certificate contains a particular field, by OID. This works for extensions,
// even ones not recognized by the local CL. It does not return any value, only presence.
namespace CodeSigning {
+//
+// Test for the canonical Apple CA certificate
+//
+bool isAppleCA(SecCertificateRef cert);
+bool isAppleCA(const Hashing::Byte *sha1);
+
+
//
// Calculate canonical hashes of certificate.
// This is simply defined as (always) the SHA1 hash of the DER.
//
void hashOfCertificate(const void *certData, size_t certLength, SHA1::Digest digest);
void hashOfCertificate(SecCertificateRef cert, SHA1::Digest digest);
+bool verifyHash(SecCertificateRef cert, const Hashing::Byte *digest);
//
// Extends to end of file, or (if limit > 0) at most limit bytes.
// Returns number of bytes digested.
//
-template <class _Hash>
-size_t hashFileData(const char *path, _Hash *hasher)
-{
- UnixPlusPlus::AutoFileDesc fd(path);
- return hashFileData(fd, hasher);
-}
-
template <class _Hash>
size_t hashFileData(UnixPlusPlus::FileDesc fd, _Hash *hasher, size_t limit = 0)
{
return total;
}
+template <class _Hash>
+size_t hashFileData(const char *path, _Hash *hasher)
+{
+ UnixPlusPlus::AutoFileDesc fd(path);
+ return hashFileData(fd, hasher);
+}
+
//
// Check to see if a certificate contains a particular field, by OID. This works for extensions,
SHA1::Digest anchorHash;
hashOfCertificate(ctx.cert(Requirement::anchorCert), anchorHash);
- if (!memcmp(anchorHash, Requirement::appleAnchorHash(), SHA1::digestLength)
+ if (isAppleCA(anchorHash)
#if defined(TEST_APPLE_ANCHOR)
|| !memcmp(anchorHash, Requirement::testAppleAnchorHash(), SHA1::digestLength)
#endif
update.bind(":flag") = kAuthorityFlagDefault;
update.execute();
});
+
+ simpleFeature("filter_unsigned",
+ "ALTER TABLE authority ADD COLUMN filter_unsigned TEXT NULL"
+ );
}
CFDictionaryRef values[count];
CFDictionaryGetKeysAndValues(content, (const void **)keys, (const void **)values);
- SQLite::Statement insert(*this, "INSERT INTO authority (type, allow, requirement, label, flags, remarks)"
- " VALUES (:type, 1, :requirement, 'GKE', :flags, :path)");
+ SQLite::Statement insert(*this, "INSERT INTO authority (type, allow, requirement, label, filter_unsigned, flags, remarks)"
+ " VALUES (:type, 1, :requirement, 'GKE', :filter, :flags, :path)");
for (CFIndex n = 0; n < count; n++) {
CFDictionary info(values[n], errSecCSDbCorrupt);
insert.reset();
insert.bind(":type") = cfString(info.get<CFStringRef>(CFSTR("type")));
insert.bind(":path") = cfString(info.get<CFStringRef>(CFSTR("path")));
insert.bind(":requirement") = "cdhash H\"" + cfString(info.get<CFStringRef>(CFSTR("cdhash"))) + "\"";
+ insert.bind(":filter") = cfString(info.get<CFStringRef>(CFSTR("screen")));
insert.bind(":flags") = kAuthorityFlagWhitelist;
insert();
}
#include <security_utilities/unix++.h>
#include <notify.h>
+#include "diskrep.h"
+#include "codedirectory.h"
+#include "csutilities.h"
+#include "StaticCode.h"
+
#include <CoreServices/CoreServicesPriv.h>
#include "SecCodePriv.h"
#undef check // Macro! Yech.
static void authorizeUpdate(SecAssessmentFlags flags, CFDictionaryRef context);
-static void normalizeTarget(CFRef<CFTypeRef> &target, CFDictionary &context, bool signUnsigned = false);
+static void normalizeTarget(CFRef<CFTypeRef> &target, CFDictionary &context, std::string *signUnsigned = NULL);
static bool codeInvalidityExceptions(SecStaticCodeRef code, CFMutableDictionaryRef result);
static CFTypeRef installerPolicy() CF_RETURNS_RETAINED;
//
void PolicyEngine::evaluate(CFURLRef path, AuthorityType type, SecAssessmentFlags flags, CFDictionaryRef context, CFMutableDictionaryRef result)
{
+ // update GKE
+ installExplicitSet(gkeAuthFile, gkeSigsFile);
+
switch (type) {
case kAuthorityExecute:
evaluateCode(path, kAuthorityExecute, flags, context, result);
}
+//
+// Whitelist pre-screen processing.
+// Whitelist-matching unsigned code is expensive since we have to generate a full code signature
+// just to see if we match a whitelist authority entry. This class generates a light(er)-weight
+// prescreen and matches it against a hint in an authority record generated from the (detached recorded)
+// code signature at time of whitelist recording.
+// This is just a heuristic to cheaply rule out guaranteed mismatches. When in doubt, we go ahead
+// and do the full work.
+//
+class WhitelistPrescreen {
+public:
+ WhitelistPrescreen(SecStaticCodeRef code)
+ : mRep(SecStaticCode::requiredStatic(code)->diskRep()) { }
+
+ bool reject(const char *screen, const char *remarks);
+
+private:
+ std::string create(char type, SHA1 &hash);
+
+ RefPointer<DiskRep> mRep; // DiskRep representing the code
+ std::string mScreen; // calculated screen (on demand)
+};
+
+bool WhitelistPrescreen::reject(const char *screen, const char *remarks)
+{
+ if (!screen) { // authority record has no screen to match - apply heuristic
+ if (remarks && mRep->mainExecutablePath() != remarks) // not an allow record (or moved)
+ return true;
+ else
+ return false; // can't rule out; proceed
+ }
+
+ if (mScreen.empty()) {
+ if (CFRef<CFDataRef> info = mRep->component(cdInfoSlot)) {
+ SHA1 hash;
+ hash.update(CFDataGetBytePtr(info), CFDataGetLength(info));
+ mScreen = create('I', hash);
+ } else if (mRep->mainExecutableImage()) {
+ mScreen = "N";
+ } else {
+ SHA1 hash;
+ hashFileData(mRep->mainExecutablePath().c_str(), &hash);
+ mScreen = create('M', hash);
+ }
+ }
+
+ return screen != mScreen;
+}
+
+std::string WhitelistPrescreen::create(char type, SHA1 &hash)
+{
+ SHA1::Digest digest;
+ hash.finish(digest);
+ char buffer[2*SHA1::digestLength + 2] = { type };
+ for (size_t n = 0; n < SHA1::digestLength; n++)
+ sprintf(buffer + 1 + 2*n, "%02.2x", digest[n]);
+ return buffer;
+}
+
+
//
// 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)
+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))
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 FROM scan_authority"
+ "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);
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()));
- OSStatus rc = SecStaticCodeCheckValidity(code, validationFlags, requirement);
+ rc = SecStaticCodeCheckValidity(code, validationFlags, requirement);
- if (rc == errSecCSUnsigned) {
+ // 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);
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)
SYSPOLICY_ASSESS_OUTCOME_BROKEN(cfString(path).c_str(), type, true);
// treat as unsigned to fix problems in the field
case errSecCSUnsigned:
- cfadd(result, "{%O=#F}", kSecAssessmentAssessmentVerdict);
- addAuthority(result, "no usable signature");
+ if (handleUnsignedCode) {
+ cfadd(result, "{%O=#F}", kSecAssessmentAssessmentVerdict);
+ addAuthority(result, "no usable signature");
+ }
return;
case errSecCSReqFailed: // requirement missed, but otherwise okay
continue;
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. Deny by default
+ // no applicable authority (but signed, perhaps temporarily). Deny by default
CFRef<CFDictionaryRef> info;
MacOSError::check(SecCodeCopySigningInformation(code, kSecCSSigningInformation, &info.aref()));
if (flags & kSecAssessmentFlagRequestOrigin) {
} else if (qtn.flag(QTN_FLAG_ASSESSMENT_OK)) {
cfadd(result, "{%O=#T}", kSecAssessmentAssessmentVerdict);
addAuthority(result, "Prior Assessment");
- } else {
- cfadd(result, "{%O=#F}", kSecAssessmentAssessmentVerdict);
- addAuthority(result, "_XProtect");
+ } else if (!overrideAssessment()) { // no need to do more work if we're off
+ try {
+ evaluateCode(path, kAuthorityExecute, flags, context, result, false);
+ } catch (...) {
+ // some documents can't be code signed, so this may be quite benign
+ }
+ if (CFDictionaryGetValue(result, kSecAssessmentAssessmentVerdict) == NULL) { // no code signature to help us out
+ cfadd(result, "{%O=#F}", kSecAssessmentAssessmentVerdict);
+ addAuthority(result, "_XProtect");
+ }
}
addToAuthority(result, kLSDownloadRiskCategoryKey, riskCategory);
return;
CFDictionary ctx(context, errSecCSInvalidAttributeValues);
CFCopyRef<CFTypeRef> target = inTarget;
CFRef<CFDataRef> bookmark = NULL;
+ std::string filter_unsigned;
switch (type) {
case kAuthorityExecute:
- normalizeTarget(target, ctx, true);
+ normalizeTarget(target, ctx, &filter_unsigned);
// bookmarks are untrusted and just a hint to callers
bookmark = ctx.get<CFDataRef>(kSecAssessmentRuleKeyBookmark);
break;
MacOSError::check(SecRequirementCopyString(target.as<SecRequirementRef>(), kSecCSDefaultFlags, &requirementText.aref()));
SQLite::Transaction xact(*this, SQLite3::Transaction::deferred, "add_rule");
SQLite::Statement insert(*this,
- "INSERT INTO authority (type, allow, requirement, priority, label, expires, remarks)"
- " VALUES (:type, :allow, :requirement, :priority, :label, :expires, :remarks);");
+ "INSERT INTO authority (type, allow, requirement, priority, label, expires, filter_unsigned, remarks)"
+ " VALUES (:type, :allow, :requirement, :priority, :label, :expires, :filter_unsigned, :remarks);");
insert.bind(":type").integer(type);
insert.bind(":allow").integer(allow);
insert.bind(":requirement") = requirementText.get();
if (!label.empty())
insert.bind(":label") = label;
insert.bind(":expires") = expires;
+ insert.bind(":filter_unsigned") = filter_unsigned.empty() ? NULL : filter_unsigned.c_str();
if (!remarks.empty())
insert.bind(":remarks") = remarks;
insert.execute();
CFDictionaryRef PolicyEngine::update(CFTypeRef target, SecAssessmentFlags flags, CFDictionaryRef context)
{
+ // update GKE
+ installExplicitSet(gkeAuthFile, gkeSigsFile);
+
AuthorityType type = typeFor(context, kAuthorityInvalid);
CFStringRef edit = CFStringRef(CFDictionaryGetValue(context, kSecAssessmentContextKeyUpdate));
CFDictionaryRef result;
{
CFDictionary ctx(context, errSecCSInvalidAttributeValues);
CFCopyRef<CFTypeRef> target = inTarget;
- normalizeTarget(target, ctx);
+ std::string filter_unsigned; // ignored; used just to trigger ad-hoc signing
+ normalizeTarget(target, ctx, &filter_unsigned);
string label;
if (CFStringRef lab = ctx.get<CFStringRef>(kSecAssessmentUpdateKeyLabel))
//
// Perform common argument normalizations for update operations
//
-static void normalizeTarget(CFRef<CFTypeRef> &target, CFDictionary &context, bool signUnsigned)
+static void normalizeTarget(CFRef<CFTypeRef> &target, CFDictionary &context, std::string *signUnsigned)
{
// turn CFURLs into (designated) SecRequirements
if (target && CFGetTypeID(target) == CFURLGetTypeID()) {
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);
static void addToAuthority(CFMutableDictionaryRef parent, CFStringRef key, CFTypeRef value);
private:
- void evaluateCode(CFURLRef path, AuthorityType type, SecAssessmentFlags flags, CFDictionaryRef context, CFMutableDictionaryRef result);
+ void evaluateCode(CFURLRef path, AuthorityType type, SecAssessmentFlags flags, CFDictionaryRef context, CFMutableDictionaryRef result,
+ bool handleUnsignedCode = true);
void evaluateInstall(CFURLRef path, SecAssessmentFlags flags, CFDictionaryRef context, CFMutableDictionaryRef result);
void evaluateDocOpen(CFURLRef path, SecAssessmentFlags flags, CFDictionaryRef context, CFMutableDictionaryRef result);
bool Requirement::Interpreter::appleAnchored()
{
if (SecCertificateRef cert = mContext->cert(anchorCert))
- if (verifyAnchor(cert, appleAnchorHash())
+ if (isAppleCA(cert)
#if defined(TEST_APPLE_ANCHOR)
|| verifyAnchor(cert, testAppleAnchorHash())
#endif
namespace CodeSigning {
-//
-// The (SHA-1) hash of the canonical Apple certificate root anchor
-//
-static const SHA1::Digest gAppleAnchorHash =
- { 0x61, 0x1e, 0x5b, 0x66, 0x2c, 0x59, 0x3a, 0x08, 0xff, 0x58,
- 0xd1, 0x4a, 0xe2, 0x24, 0x52, 0xd1, 0x98, 0xdf, 0x6c, 0x60 };
-
-
//
// Canonical names for requirement types
//
//
-// Return the hash of the canonical Apple certificate root (anchor).
-// In a special test mode, also return an alternate root hash for testing.
+// Produce the hash of a fake Apple root (only if compiled for internal testing)
//
-const SHA1::Digest &Requirement::appleAnchorHash()
-{
- return gAppleAnchorHash;
-}
-
#if defined(TEST_APPLE_ANCHOR)
const char Requirement::testAppleAnchorEnv[] = "TEST_APPLE_ANCHOR";
// the SHA1 hash of the canonical "Apple Anchor", i.e. the X509 Anchor
// that is considered "Apple's anchor certificate", as defined by hashOfCertificate().
- static const SHA1::Digest &appleAnchorHash();
#if defined(TEST_APPLE_ANCHOR)
static const char testAppleAnchorEnv[];
static const SHA1::Digest &testAppleAnchorHash();
expires FLOAT NOT NULL DEFAULT (5000000), -- expiration of rule authority (Julian date)
priority REAL NOT NULL DEFAULT (0), -- rule priority (full float)
label TEXT NULL, -- text label for authority rule
+ filter_unsigned TEXT NULL, -- prescreen for handling unsigned code
flags INTEGER NOT NULL DEFAULT (0), -- amalgamated binary flags
-- following fields are for documentation only
ctime FLOAT NOT NULL DEFAULT (JULIANDAY('now')), -- rule creation time (Julian)
-- See policydatabase.cpp for upgrade code.
--
INSERT INTO feature (name, value, remarks)
- VALUES ('bookmarkhints', 'value', 'builtin');
+ VALUES ('bookmarkhints', 'present', 'builtin');
INSERT INTO feature (name, value, remarks)
- VALUES ('codesignedpackages', 'value', 'builtin');
+ VALUES ('codesignedpackages', 'present', 'builtin');
+INSERT INTO feature (name, value, remarks)
+ VALUES ('filter_unsigned', 'present', 'builtin');
--
C26AC0F4143BD1C4001C98CE /* CopyFiles */,
C2F24DFE14BCBBF200309FCD /* ShellScript */,
C2578CB11579627200D4FE48 /* CopyFiles */,
+ C25C18CD15CB0C470007A2DE /* CopyFiles */,
+ C25C18D015CB0FB30007A2DE /* CopyFiles */,
);
dependencies = (
);
C250F6C50B5EF4E40076098F /* PBXTargetDependency */,
C2E287430B5D8F9A009336A0 /* PBXTargetDependency */,
C26AC0F2143BD02B001C98CE /* PBXTargetDependency */,
+ C209697015BF53330093035F /* PBXTargetDependency */,
);
name = Everything;
productName = Everything;
18B9658C1472FC9E005A4D2E /* codedirectory.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383170A237F47005C63A2 /* codedirectory.h */; settings = {ATTRIBUTES = (Public, ); }; };
18B965941472FE27005A4D2E /* renum.h in Headers */ = {isa = PBXBuildFile; fileRef = C2EF100F0A49BD89005A44BB /* renum.h */; settings = {ATTRIBUTES = (Public, ); }; };
18B965951472FE30005A4D2E /* cdbuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383150A237F47005C63A2 /* cdbuilder.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ C200424D15D425D9004AE0A1 /* libsecurity_codesigning.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C200424915D425B7004AE0A1 /* libsecurity_codesigning.a */; };
+ C200424E15D425D9004AE0A1 /* libsecurity_utilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C200424A15D425B7004AE0A1 /* libsecurity_utilities.a */; };
C2093AA80BB0948000EB8599 /* reqreader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2093AA60BB0948000EB8599 /* reqreader.cpp */; };
+ C209696415BF52040093035F /* gkunpack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C209696315BF52040093035F /* gkunpack.cpp */; };
C211070A158C1082001D7F76 /* gkmerge in CopyFiles */ = {isa = PBXBuildFile; fileRef = C2110704158BF5C8001D7F76 /* gkmerge */; };
C21CFC5F0A250D1C006CD5B1 /* reqdumper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C21CFC5D0A250D1C006CD5B1 /* reqdumper.cpp */; };
C21EA3DD0AD2F81300E6E31C /* SecCodeSigner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C21EA3DB0AD2F81300E6E31C /* SecCodeSigner.cpp */; };
C24EABAD1421433700C16AA9 /* policydb.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C24EABAC1421433700C16AA9 /* policydb.cpp */; };
C250F6C30B5EF1910076098F /* SecIntegrity.h in Headers */ = {isa = PBXBuildFile; fileRef = C250F6C20B5EF1910076098F /* SecIntegrity.h */; };
C259DFD60AD6D9BA00C9ACC6 /* sigblob.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C259DFD40AD6D9BA00C9ACC6 /* sigblob.cpp */; };
+ C25C18CE15CB0C5C0007A2DE /* gkreport in CopyFiles */ = {isa = PBXBuildFile; fileRef = C25C18C615CB0BC10007A2DE /* gkreport */; };
+ C25C18D115CB0FC30007A2DE /* com.apple.gkreport.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = C25C18CF15CB0FA00007A2DE /* com.apple.gkreport.plist */; };
C26763D714FD9EBE00A46EDF /* drmaker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C26763D514FD9EBE00A46EDF /* drmaker.cpp */; };
C26763D814FD9EBE00A46EDF /* drmaker.h in Headers */ = {isa = PBXBuildFile; fileRef = C26763D614FD9EBE00A46EDF /* drmaker.h */; };
C26AC0F5143BD1C8001C98CE /* SystemPolicy in CopyFiles */ = {isa = PBXBuildFile; fileRef = C26AC0F3143BD1B3001C98CE /* SystemPolicy */; };
remoteGlobalIDString = C26AC7090DAEB3A7005BFB40;
remoteInfo = DTrace;
};
+ C209696F15BF53330093035F /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 4CA1FEAB052A3C3800F22E42 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C209695F15BF52040093035F;
+ remoteInfo = gkunpack;
+ };
C250F6C40B5EF4E40076098F /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 4CA1FEAB052A3C3800F22E42 /* Project object */;
);
runOnlyForDeploymentPostprocessing = 1;
};
+ C25C18CD15CB0C470007A2DE /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/libexec;
+ dstSubfolderSpec = 0;
+ files = (
+ C25C18CE15CB0C5C0007A2DE /* gkreport in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ C25C18D015CB0FB30007A2DE /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /System/Library/LaunchDaemons;
+ dstSubfolderSpec = 0;
+ files = (
+ C25C18D115CB0FC30007A2DE /* com.apple.gkreport.plist in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
C26AC0F4143BD1C4001C98CE /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 8;
184461A1146E9AD100B12992 /* lib.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = lib.xcconfig; sourceTree = "<group>"; };
184461A2146E9AD100B12992 /* release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = release.xcconfig; sourceTree = "<group>"; };
4CA1FEBE052A3C8100F22E42 /* libsecurity_codesigning.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libsecurity_codesigning.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ C200424915D425B7004AE0A1 /* libsecurity_codesigning.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libsecurity_codesigning.a; path = ../../../usr/local/lib/libsecurity_codesigning.a; sourceTree = "<group>"; };
+ C200424A15D425B7004AE0A1 /* libsecurity_utilities.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libsecurity_utilities.a; path = ../../../usr/local/lib/libsecurity_utilities.a; sourceTree = "<group>"; };
C2093AA60BB0948000EB8599 /* reqreader.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = reqreader.cpp; sourceTree = "<group>"; };
C2093AA70BB0948000EB8599 /* reqreader.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = reqreader.h; sourceTree = "<group>"; };
- C2110704158BF5C8001D7F76 /* gkmerge */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; name = gkmerge; path = gke/gkmerge; sourceTree = SOURCE_ROOT; };
+ C209696015BF52040093035F /* gkunpack */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = gkunpack; sourceTree = BUILT_PRODUCTS_DIR; };
+ C209696315BF52040093035F /* gkunpack.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = gkunpack.cpp; sourceTree = "<group>"; };
+ C209697215BF57EB0093035F /* libsecurity_utilities.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libsecurity_utilities.a; sourceTree = "<group>"; };
+ C2110704158BF5C8001D7F76 /* gkmerge */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = gkmerge; sourceTree = "<group>"; };
C21CFC5D0A250D1C006CD5B1 /* reqdumper.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = reqdumper.cpp; sourceTree = "<group>"; };
C21CFC5E0A250D1C006CD5B1 /* reqdumper.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = reqdumper.h; sourceTree = "<group>"; };
C21EA3DB0AD2F81300E6E31C /* SecCodeSigner.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = SecCodeSigner.cpp; sourceTree = "<group>"; };
C24EABAC1421433700C16AA9 /* policydb.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = policydb.cpp; sourceTree = "<group>"; };
C250F6C20B5EF1910076098F /* SecIntegrity.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SecIntegrity.h; sourceTree = "<group>"; };
C250F6C60B5EF5B50076098F /* SecIntegrity.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = SecIntegrity.cpp; sourceTree = "<group>"; };
- C2578CC215798D0F00D4FE48 /* gkclear */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; name = gkclear; path = gke/gkclear; sourceTree = SOURCE_ROOT; };
- C2578CC315798D0F00D4FE48 /* gkgenerate */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; name = gkgenerate; path = gke/gkgenerate; sourceTree = SOURCE_ROOT; };
- C2578CC415798D0F00D4FE48 /* gkrecord */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; name = gkrecord; path = gke/gkrecord; sourceTree = SOURCE_ROOT; };
+ C2578CC215798D0F00D4FE48 /* gkclear */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; path = gkclear; sourceTree = "<group>"; };
+ C2578CC315798D0F00D4FE48 /* gkgenerate */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; path = gkgenerate; sourceTree = "<group>"; };
+ C2578CC415798D0F00D4FE48 /* gkrecord */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; path = gkrecord; sourceTree = "<group>"; };
C259DFD40AD6D9BA00C9ACC6 /* sigblob.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = sigblob.cpp; sourceTree = "<group>"; };
C259DFD50AD6D9BA00C9ACC6 /* sigblob.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = sigblob.h; sourceTree = "<group>"; };
+ C25C18C615CB0BC10007A2DE /* gkreport */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; name = gkreport; path = gke/gkreport; sourceTree = SOURCE_ROOT; };
+ C25C18CF15CB0FA00007A2DE /* com.apple.gkreport.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = com.apple.gkreport.plist; path = gke/com.apple.gkreport.plist; sourceTree = SOURCE_ROOT; };
C26763D514FD9EBE00A46EDF /* drmaker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = drmaker.cpp; sourceTree = "<group>"; };
C26763D614FD9EBE00A46EDF /* drmaker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = drmaker.h; sourceTree = "<group>"; };
C26AC0F3143BD1B3001C98CE /* SystemPolicy */ = {isa = PBXFileReference; lastKnownFileType = text; name = SystemPolicy; path = cstemp/SystemPolicy; sourceTree = BUILT_PRODUCTS_DIR; };
C26B45C00B8A9C00003C0ACA /* ucspc */ = {isa = PBXFileReference; lastKnownFileType = text; name = ucspc; path = cstemp/ucspc; sourceTree = BUILT_PRODUCTS_DIR; };
C27249D2143237CD0058B552 /* syspolicy.sql */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = syspolicy.sql; sourceTree = "<group>"; };
C273601D1432A60B00A9A5FF /* policyengine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = policyengine.h; sourceTree = "<group>"; };
- C27360201432A61900A9A5FF /* policyengine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = policyengine.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
- C273606C1433F09000A9A5FF /* SecAssessment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = SecAssessment.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
+ C27360201432A61900A9A5FF /* policyengine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = policyengine.cpp; sourceTree = "<group>"; };
+ C273606C1433F09000A9A5FF /* SecAssessment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = SecAssessment.cpp; sourceTree = "<group>"; };
C273606D1433F09000A9A5FF /* SecAssessment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = SecAssessment.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
- C27360D41436866C00A9A5FF /* xpcengine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = xpcengine.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
+ C27360D41436866C00A9A5FF /* xpcengine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = xpcengine.cpp; sourceTree = "<group>"; };
C27360D71436868600A9A5FF /* xpcengine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xpcengine.h; sourceTree = "<group>"; };
- C278A19B158AB2C300FA6767 /* gkhandmake */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; name = gkhandmake; path = gke/gkhandmake; sourceTree = SOURCE_ROOT; };
- C278A19C158AB2C300FA6767 /* gklist */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; name = gklist; path = gke/gklist; sourceTree = SOURCE_ROOT; };
+ C278A19B158AB2C300FA6767 /* gkhandmake */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; path = gkhandmake; sourceTree = "<group>"; };
+ C278A19C158AB2C300FA6767 /* gklist */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; path = gklist; sourceTree = "<group>"; };
C28342E40E366E6800E54360 /* csdatabase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = csdatabase.cpp; sourceTree = "<group>"; };
C28342E50E366E6800E54360 /* csdatabase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = csdatabase.h; sourceTree = "<group>"; };
C28342EB0E36719D00E54360 /* detachedrep.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = detachedrep.cpp; sourceTree = "<group>"; };
);
runOnlyForDeploymentPostprocessing = 0;
};
+ C209695D15BF52040093035F /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C200424D15D425D9004AE0A1 /* libsecurity_codesigning.a in Frameworks */,
+ C200424E15D425D9004AE0A1 /* libsecurity_utilities.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
C2BC1F240B580D3A003EC9DC /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
4CA1FEA7052A3C3800F22E42 = {
isa = PBXGroup;
children = (
+ C209697215BF57EB0093035F /* libsecurity_utilities.a */,
182BB4FC146F2823000BF1F3 /* libsecurityd.xcodeproj */,
4C308388053237100028A8C6 /* lib */,
1844619E146E9AD100B12992 /* config */,
4CA1FEBE052A3C8100F22E42 /* libsecurity_codesigning.a */,
C2BC1F260B580D3A003EC9DC /* libintegrity.a */,
C2BC1F2F0B580D4B003EC9DC /* libcodehost.a */,
+ C209696015BF52040093035F /* gkunpack */,
);
name = Products;
sourceTree = "<group>";
C2578CC215798D0F00D4FE48 /* gkclear */,
C2578CC315798D0F00D4FE48 /* gkgenerate */,
C2578CC415798D0F00D4FE48 /* gkrecord */,
+ C25C18C615CB0BC10007A2DE /* gkreport */,
+ C25C18CF15CB0FA00007A2DE /* com.apple.gkreport.plist */,
+ C209696315BF52040093035F /* gkunpack.cpp */,
);
- name = gke;
- path = whitelist;
+ path = gke;
sourceTree = SOURCE_ROOT;
};
C2BC1F370B580DAE003EC9DC /* Static Support */ = {
C2CC30EF0B8519CF005FA59D /* Frameworks */ = {
isa = PBXGroup;
children = (
+ C200424915D425B7004AE0A1 /* libsecurity_codesigning.a */,
+ C200424A15D425B7004AE0A1 /* libsecurity_utilities.a */,
C2CC30A00B8519CC005FA59D /* CoreFoundation.framework */,
);
name = Frameworks;
productReference = 4CA1FEBE052A3C8100F22E42 /* libsecurity_codesigning.a */;
productType = "com.apple.product-type.library.static";
};
+ C209695F15BF52040093035F /* gkunpack */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = C209696B15BF52040093035F /* Build configuration list for PBXNativeTarget "gkunpack" */;
+ buildPhases = (
+ C209695C15BF52040093035F /* Sources */,
+ C209695D15BF52040093035F /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = gkunpack;
+ productName = gkunpack;
+ productReference = C209696015BF52040093035F /* gkunpack */;
+ productType = "com.apple.product-type.tool";
+ };
C2BC1F250B580D3A003EC9DC /* libintegrity */ = {
isa = PBXNativeTarget;
buildConfigurationList = C2BC1F270B580D3F003EC9DC /* Build configuration list for PBXNativeTarget "libintegrity" */;
C2BC1F2E0B580D4B003EC9DC /* libcodehost */,
C26AC7090DAEB3A7005BFB40 /* DTrace */,
C26AC0EB143BCF01001C98CE /* SystemPolicy */,
+ C209695F15BF52040093035F /* gkunpack */,
);
};
/* End PBXProject section */
);
runOnlyForDeploymentPostprocessing = 0;
};
+ C209695C15BF52040093035F /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C209696415BF52040093035F /* gkunpack.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
C2BC1F230B580D3A003EC9DC /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
target = C26AC7090DAEB3A7005BFB40 /* DTrace */;
targetProxy = 1844617C146E9A5200B12992 /* PBXContainerItemProxy */;
};
+ C209697015BF53330093035F /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C209695F15BF52040093035F /* gkunpack */;
+ targetProxy = C209696F15BF53330093035F /* PBXContainerItemProxy */;
+ };
C250F6C50B5EF4E40076098F /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = C2BC1F250B580D3A003EC9DC /* libintegrity */;
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
+ C209696C15BF52040093035F /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD_64_BIT)";
+ CLANG_CXX_LANGUAGE_STANDARD = "compiler-default";
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ MACOSX_DEPLOYMENT_TARGET = 10.8;
+ ONLY_ACTIVE_ARCH = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SKIP_INSTALL = NO;
+ };
+ name = Debug;
+ };
+ C209696D15BF52040093035F /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD_64_BIT)";
+ CLANG_CXX_LANGUAGE_STANDARD = "compiler-default";
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ MACOSX_DEPLOYMENT_TARGET = 10.8;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SKIP_INSTALL = NO;
+ };
+ name = Release;
+ };
C263E67609A2971B000043F1 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 184461A0146E9AD100B12992 /* debug.xcconfig */;
isa = XCBuildConfiguration;
baseConfigurationReference = 184461A1146E9AD100B12992 /* lib.xcconfig */;
buildSettings = {
+ HEADER_SEARCH_PATHS = (
+ "$(PROJECT_DIR)/../include",
+ "$(BUILT_PRODUCTS_DIR)/derived_src",
+ "$(BUILT_PRODUCTS_DIR)",
+ "$(PROJECT_DIR)/lib",
+ /usr/local/include,
+ );
TEMPDIR = "$(BUILT_PRODUCTS_DIR)/cstemp";
};
name = Debug;
isa = XCBuildConfiguration;
baseConfigurationReference = 184461A1146E9AD100B12992 /* lib.xcconfig */;
buildSettings = {
+ HEADER_SEARCH_PATHS = (
+ "$(PROJECT_DIR)/../include",
+ "$(BUILT_PRODUCTS_DIR)/derived_src",
+ "$(BUILT_PRODUCTS_DIR)",
+ "$(PROJECT_DIR)/lib",
+ /usr/local/include,
+ );
TEMPDIR = "$(BUILT_PRODUCTS_DIR)/cstemp";
};
name = Release;
C2E287480B5D8FD8009336A0 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
+ HEADER_SEARCH_PATHS = (
+ "$(PROJECT_DIR)/../include",
+ "$(BUILT_PRODUCTS_DIR)/derived_src",
+ "$(BUILT_PRODUCTS_DIR)",
+ "$(PROJECT_DIR)/lib",
+ /usr/local/include,
+ );
};
name = Debug;
};
C2E2874A0B5D8FD8009336A0 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
+ HEADER_SEARCH_PATHS = (
+ "$(PROJECT_DIR)/../include",
+ "$(BUILT_PRODUCTS_DIR)/derived_src",
+ "$(BUILT_PRODUCTS_DIR)",
+ "$(PROJECT_DIR)/lib",
+ /usr/local/include,
+ );
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
+ C209696B15BF52040093035F /* Build configuration list for PBXNativeTarget "gkunpack" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C209696C15BF52040093035F /* Debug */,
+ C209696D15BF52040093035F /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
C263E67509A2971B000043F1 /* Build configuration list for PBXNativeTarget "libsecurity_codesigning" */ = {
isa = XCConfigurationList;
buildConfigurations = (
if(*numCiphers < numCipherSuites) {
return errSSLBufferOverflow;
}
- memcpy(ciphers, cipherSuites, numCipherSuites * sizeof(SSLCipherSuite));
+ memcpy(ciphers, cipherSuites, numCipherSuites * sizeof(SSLCipherSuite));
*numCiphers = numCipherSuites;
return noErr;
}
{
OSStatus err;
SSLBuffer content;
+ bool decryption_failed_or_bad_record_mac = false;
if ((ctx->readCipher.symCipher->blockSize > 0) &&
((payload->length % ctx->readCipher.symCipher->blockSize) != 0)) {
payload->data, payload->length,
&ctx->readCipher,
ctx)) != 0)
- { SSLFatalSessionAlert(SSL_AlertDecryptError, ctx);
- return errSSLDecryptionFail;
+ {
+ /* note: we no longer send a SSL_AlertDecryptError here;
+ * all subsequent failures result in SSL_AlertBadRecordMac
+ * being sent at the end of the function, to avoid leaking
+ * differences between padding and decryption failures. */
+ decryption_failed_or_bad_record_mac = true;
}
/* Locate content within decrypted payload */
* even size packets...beware... */
if(padSize > payload->length) {
/* This is TLS 1.1 compliant - Do it for all protocols versions */
- SSLFatalSessionAlert(SSL_AlertBadRecordMac, ctx);
sslErrorLog("tls1DecryptRecord: bad padding length (%d)\n",
(unsigned)payload->data[payload->length - 1]);
- return errSSLDecryptionFail;
+ decryption_failed_or_bad_record_mac = true;
}
padChars = payload->data + payload->length - padSize;
while(padChars < (payload->data + payload->length)) {
if(*padChars++ != padSize) {
/* This is TLS 1.1 compliant - Do it for all protocols versions */
- SSLFatalSessionAlert(SSL_AlertBadRecordMac, ctx);
sslErrorLog("tls1DecryptRecord: bad padding value\n");
- return errSSLDecryptionFail;
+ decryption_failed_or_bad_record_mac = true;
}
}
/* Remove block size padding and its one-byte length */
/* Optimize away MAC for null case */
if ((err = SSLVerifyMac(type, &content,
content.data + content.length, ctx)) != 0)
- { SSLFatalSessionAlert(SSL_AlertBadRecordMac, ctx);
- return errSSLBadRecordMac;
+ {
+ decryption_failed_or_bad_record_mac = true;
}
+ if (decryption_failed_or_bad_record_mac) {
+ SSLFatalSessionAlert(SSL_AlertBadRecordMac, ctx);
+ return errSSLDecryptionFail;
+ }
+
*payload = content; /* Modify payload buffer to indicate content length */
return noErr;
void Statement::Binding::operator = (const char *value)
{
- statement.check(::sqlite3_bind_text(statement.sql(), index,
- ::strdup(value), -1, ::free));
+ if (value == NULL)
+ this->null();
+ else
+ statement.check(::sqlite3_bind_text(statement.sql(), index,
+ ::strdup(value), -1, ::free));
}
void Statement::Binding::operator = (const std::string &value)