+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;
+ }
+
+ if (mContext->forcePlatform) {
+ return true;
+ }
+
+ 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;
+}
+
+#if WAITING_FOR_LIB_AMFI_INTERFACE
+// These bits are here until we get get a new build alias for libamfi-interface.
+
+#define MAC_AMFI_POLICY_NAME "AMFI"
+
+#define AMFI_SYSCALL_CDHASH_IN_TRUSTCACHE 95
+
+typedef struct amfi_cdhash_in_trustcache_ {
+ uint8_t cdhash[20];
+ uint64_t result;
+} amfi_cdhash_in_trustcache_t;
+
+static int
+__amfi_interface_cdhash_in_trustcache(const uint8_t cdhash[], uint64_t* trustcache_result)
+{
+ amfi_cdhash_in_trustcache_t args;
+ static_assert(AMFI_INTF_CD_HASH_LEN == sizeof(args.cdhash), "Error: cdhash length mismatch");
+ int err;
+ memcpy(args.cdhash, cdhash, sizeof(args.cdhash));
+ args.result = 0;
+ err = __mac_syscall(MAC_AMFI_POLICY_NAME, AMFI_SYSCALL_CDHASH_IN_TRUSTCACHE, &args);
+ if (err) {
+ err = errno;
+ }
+ *trustcache_result = args.result;
+ return err;
+}
+
+static int
+amfi_interface_cdhash_in_trustcache(const uint8_t cdhash[], size_t cdhash_len, uint64_t* trustcache_result)
+{
+ int err = EINVAL;
+
+ if (cdhash == nullptr || cdhash_len != AMFI_INTF_CD_HASH_LEN || trustcache_result == nullptr) {
+ goto lb_end;
+ }
+ *trustcache_result = 0;
+
+ err = __amfi_interface_cdhash_in_trustcache(cdhash, trustcache_result);
+
+lb_end:
+ return err;
+}
+#endif
+
+bool Requirement::Interpreter::inTrustCache()
+{
+ uint64_t result = 0;
+ CFRef<CFDataRef> cdhashRef = mContext->directory->cdhash(true);
+ const uint8_t *cdhash = CFDataGetBytePtr(cdhashRef);
+ size_t cdhash_len = CFDataGetLength(cdhashRef);
+ int err = amfi_interface_cdhash_in_trustcache(cdhash, cdhash_len, &result);
+ return (err == 0) && (result != 0);
+}
+