#include <Security/SecCertificatePriv.h>
#include <security_utilities/memutils.h>
#include <security_utilities/logging.h>
+#include <sys/csr.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/IOCFUnserialize.h>
#include "csutilities.h"
namespace Security {
Match match(*this);
return certFieldValue(key, match, cert);
}
+#if TARGET_OS_OSX
case opCertGeneric:
{
SecCertificateRef cert = mContext->cert(get<int32_t>());
Match match(*this);
return certFieldPolicy(key, match, cert);
}
+#endif
case opTrustedCert:
return trustedCert(get<int32_t>());
case opTrustedCerts:
}
}
// unrecognized opcode and no way to interpret it
- secdebug("csinterp", "opcode 0x%x cannot be handled; aborting", op);
+ secinfo("csinterp", "opcode 0x%x cannot be handled; aborting", op);
MacOSError::throwMe(errSecCSUnimplemented);
}
}
bool Requirement::Interpreter::certFieldValue(const string &key, const Match &match, SecCertificateRef cert)
{
+// XXX: Not supported on embedded yet due to lack of supporting API
+#if TARGET_OS_OSX
// no cert, no chance
if (cert == NULL)
return false;
{ "subject.UID", &CSSMOID_UserID },
{ NULL, NULL }
};
-
+
// DN-component single-value match
for (const CertField *cf = certFields; cf->name; cf++)
if (cf->name == key) {
CFRef<CFStringRef> value;
- if (OSStatus rc = SecCertificateCopySubjectComponent(cert, cf->oid, &value.aref())) {
- secdebug("csinterp", "cert %p lookup for DN.%s failed rc=%d", cert, key.c_str(), (int)rc);
+ OSStatus rc = SecCertificateCopySubjectComponent(cert, cf->oid, &value.aref());
+ if (rc) {
+ secinfo("csinterp", "cert %p lookup for DN.%s failed rc=%d", cert, key.c_str(), (int)rc);
return false;
}
return match(value);
// email multi-valued match (any of...)
if (key == "email") {
CFRef<CFArrayRef> value;
- if (OSStatus rc = SecCertificateCopyEmailAddresses(cert, &value.aref())) {
- secdebug("csinterp", "cert %p lookup for email failed rc=%d", cert, (int)rc);
+ OSStatus rc = SecCertificateCopyEmailAddresses(cert, &value.aref());
+ if (rc) {
+ secinfo("csinterp", "cert %p lookup for email failed rc=%d", cert, (int)rc);
return false;
}
return match(value);
}
// unrecognized key. Fail but do not abort to promote backward compatibility down the road
- secdebug("csinterp", "cert field notation \"%s\" not understood", key.c_str());
+ secinfo("csinterp", "cert field notation \"%s\" not understood", key.c_str());
+#endif
return false;
}
-
+#if TARGET_OS_OSX
bool Requirement::Interpreter::certFieldGeneric(const string &key, const Match &match, SecCertificateRef cert)
{
// the key is actually a (binary) OID value
{
return cert && certificateHasPolicy(cert, oid) && match(kCFBooleanTrue);
}
-
+#endif
//
// Check the Apple-signed condition
bool Requirement::Interpreter::appleAnchored()
{
if (SecCertificateRef cert = mContext->cert(anchorCert))
- if (isAppleCA(cert)
-#if defined(TEST_APPLE_ANCHOR)
- || verifyAnchor(cert, testAppleAnchorHash())
-#endif
- )
+ if (isAppleCA(cert))
return true;
return false;
}
+static CFStringRef kAMFINVRAMTrustedKeys = CFSTR("AMFITrustedKeys");
+
+CFArrayRef Requirement::Interpreter::getAdditionalTrustedAnchors()
+{
+ __block CFRef<CFMutableArrayRef> keys = makeCFMutableArray(0);
+
+ try {
+ io_registry_entry_t entry = IORegistryEntryFromPath(kIOMasterPortDefault, "IODeviceTree:/options");
+ if (entry == IO_OBJECT_NULL)
+ return NULL;
+
+ CFRef<CFDataRef> configData = (CFDataRef)IORegistryEntryCreateCFProperty(entry, kAMFINVRAMTrustedKeys, kCFAllocatorDefault, 0);
+ IOObjectRelease(entry);
+ if (!configData)
+ return NULL;
+
+ CFRef<CFDictionaryRef> configDict = CFDictionaryRef(IOCFUnserializeWithSize((const char *)CFDataGetBytePtr(configData),
+ (size_t)CFDataGetLength(configData),
+ kCFAllocatorDefault, 0, NULL));
+ if (!configDict)
+ return NULL;
+
+ CFArrayRef trustedKeys = CFArrayRef(CFDictionaryGetValue(configDict, CFSTR("trustedKeys")));
+ if (!trustedKeys && CFGetTypeID(trustedKeys) != CFArrayGetTypeID())
+ return NULL;
+
+ cfArrayApplyBlock(trustedKeys, ^(const void *value) {
+ CFDictionaryRef key = CFDictionaryRef(value);
+ if (!key && CFGetTypeID(key) != CFDictionaryGetTypeID())
+ return;
+
+ CFDataRef hash = CFDataRef(CFDictionaryGetValue(key, CFSTR("certDigest")));
+ if (!hash && CFGetTypeID(hash) != CFDataGetTypeID())
+ return;
+ CFArrayAppendValue(keys, hash);
+ });
+
+ } catch (...) {
+ }
+
+ if (CFArrayGetCount(keys) == 0)
+ return NULL;
+
+ return keys.yield();
+}
+
+bool Requirement::Interpreter::appleLocalAnchored()
+{
+ static CFArrayRef additionalTrustedCertificates = NULL;
+
+ if (csr_check(CSR_ALLOW_APPLE_INTERNAL))
+ return false;
+
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ additionalTrustedCertificates = getAdditionalTrustedAnchors();
+ });
+
+ if (additionalTrustedCertificates == NULL)
+ return false;
+
+ CFRef<CFDataRef> hash = SecCertificateCopySHA256Digest(mContext->cert(leafCert));
+ if (!hash)
+ return false;
+
+ if (CFArrayContainsValue(additionalTrustedCertificates, CFRangeMake(0, CFArrayGetCount(additionalTrustedCertificates)), hash))
+ return true;
+
+ return false;
+}
+
bool Requirement::Interpreter::appleSigned()
{
- if (appleAnchored())
+ if (appleAnchored()) {
if (SecCertificateRef intermed = mContext->cert(-2)) // first intermediate
// first intermediate common name match (exact)
if (certFieldValue("subject.CN", Match(appleIntermediateCN, matchEqual), intermed)
&& certFieldValue("subject.O", Match(appleIntermediateO, matchEqual), intermed))
return true;
+ } else if (appleLocalAnchored()) {
+ return true;
+ }
return false;
}
{
// get certificate bytes
if (cert) {
+ SHA1 hasher;
+#if TARGET_OS_OSX
CSSM_DATA certData;
MacOSError::check(SecCertificateGetData(cert, &certData));
// verify hash
- SHA1 hasher;
hasher(certData.Data, certData.Length);
+#else
+ hasher(SecCertificateGetBytePtr(cert), SecCertificateGetLength(cert));
+#endif
return hasher.verify(digest);
}
return false;
//
SecTrustSettingsResult Requirement::Interpreter::trustSetting(SecCertificateRef cert, bool isAnchor)
{
+ // XXX: Not supported on embedded yet due to lack of supporting API
+#if TARGET_OS_OSX
// the SPI input is the uppercase hex form of the SHA-1 of the certificate...
assert(cert);
SHA1::Digest digest;
::free(errors);
MacOSError::throwMe(rc);
}
+#else
+ return kSecTrustSettingsResultUnspecified;
+#endif
}