]> git.saurik.com Git - apple/security.git/commitdiff
Security-58286.230.21.tar.gz macos-10142 v58286.230.21
authorApple <opensource@apple.com>
Tue, 26 Mar 2019 22:07:09 +0000 (22:07 +0000)
committerApple <opensource@apple.com>
Tue, 26 Mar 2019 22:07:09 +0000 (22:07 +0000)
108 files changed:
CircleJoinRequested/CircleJoinRequested.m
OSX/SecurityTestsOSX/SecurityTests-Entitlements.plist
OSX/libsecurity_codesigning/lib/SecStaticCode.cpp
OSX/libsecurity_codesigning/lib/SecStaticCode.h
OSX/libsecurity_codesigning/lib/StaticCode.cpp
OSX/libsecurity_keychain/lib/SecKey.cpp
OSX/libsecurity_manifest/lib/AppleManifest.cpp
OSX/libsecurity_manifest/lib/ManifestInternal.cpp
OSX/sec/SOSCircle/SecureObjectSync/SOSFullPeerInfo.m
OSX/sec/Security/Regressions/secitem/si-28-sectrustsettings.h
OSX/sec/Security/Regressions/secitem/si-28-sectrustsettings.m
OSX/sec/Security/Regressions/secitem/si_77_SecAccessControl.c
OSX/sec/Security/SecCertificate.c
OSX/sec/Security/SecCertificateInternal.h
OSX/sec/Security/SecExports.exp-in
OSX/sec/Security/SecFrameworkStrings.h
OSX/sec/Security/SecPolicy.c
OSX/sec/Security/SecPolicyChecks.list
OSX/sec/Security/SecPolicyLeafCallbacks.c
OSX/sec/Security/SecTrust.c
OSX/sec/Security/SecTrustInternal.h
OSX/sec/Security/SecTrustStore.c
OSX/sec/Security/SecTrustStore.h
OSX/sec/Security/SecuritydXPC.c
OSX/sec/Security/Tool/SecurityCommands.h
OSX/sec/Security/Tool/ct_exceptions.m [new file with mode: 0644]
OSX/sec/SecurityTool/entitlements.plist
OSX/sec/ipc/client.c
OSX/sec/ipc/securityd_client.h
OSX/sec/securityd/SecDbItem.c
OSX/sec/securityd/SecItemDb.c
OSX/sec/securityd/SecItemDb.h
OSX/sec/securityd/SecItemServer.c
OSX/sec/securityd/SecPinningDb.m
OSX/sec/securityd/SecPolicyServer.c
OSX/sec/securityd/SecRevocationDb.c
OSX/sec/securityd/SecRevocationDb.h
OSX/sec/securityd/SecTrustServer.c
OSX/sec/securityd/SecTrustStoreServer.c
OSX/sec/securityd/SecTrustStoreServer.h
OSX/sec/securityd/SecTrustStoreServer.m [new file with mode: 0644]
OSX/sec/securityd/spi.c
OSX/shared_regressions/si-82-sectrust-ct-data/AppleISTCA8G1.cer [new file with mode: 0644]
OSX/shared_regressions/si-82-sectrust-ct-data/CTlogs.plist
OSX/shared_regressions/si-82-sectrust-ct-data/GeoTrustPrimaryCAG2.cer [new file with mode: 0644]
OSX/shared_regressions/si-82-sectrust-ct-data/GlobalSignRootCAR2.cer [new file with mode: 0644]
OSX/shared_regressions/si-82-sectrust-ct-data/GoogleIAG3.cer [new file with mode: 0644]
OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_apple_ca.cer [new file with mode: 0644]
OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_apple_root.cer [new file with mode: 0644]
OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_apple_server_after.cer [new file with mode: 0644]
OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_fail_server.cer [new file with mode: 0644]
OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_dn_server.cer [new file with mode: 0644]
OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_dn_server_mismatch.cer [new file with mode: 0644]
OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_dn_subca.cer [new file with mode: 0644]
OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_org_server.cer [new file with mode: 0644]
OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_org_server_mismatch.cer [new file with mode: 0644]
OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_org_subca.cer [new file with mode: 0644]
OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_server.cer [new file with mode: 0644]
OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_server_scts.cer [new file with mode: 0644]
OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_subca.cer [new file with mode: 0644]
OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_root.cer [new file with mode: 0644]
OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_after.cer [new file with mode: 0644]
OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_after_scts.cer [new file with mode: 0644]
OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_before.cer [new file with mode: 0644]
OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_matching_orgs.cer [new file with mode: 0644]
OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_matching_orgs_scts.cer [new file with mode: 0644]
OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_no_orgs.cer [new file with mode: 0644]
OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_nonmatching_orgs.cer [new file with mode: 0644]
OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_partial_orgs.cer [new file with mode: 0644]
OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_unconstrained_subca.cer [new file with mode: 0644]
OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_user_root.cer [new file with mode: 0644]
OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_user_server_after.cer [new file with mode: 0644]
OSX/shared_regressions/si-82-sectrust-ct-data/google.cer [new file with mode: 0644]
OSX/shared_regressions/si-82-sectrust-ct-data/livability.cer [new file with mode: 0644]
OSX/shared_regressions/si-82-sectrust-ct-data/precert.cer [new file with mode: 0644]
OSX/shared_regressions/si-82-sectrust-ct.h [new file with mode: 0644]
OSX/shared_regressions/si-82-sectrust-ct.m
OSX/trustd/iOS/AppleCorporateRootCA.cer [new file with mode: 0644]
OSX/trustd/iOS/AppleCorporateRootCA2.cer [new file with mode: 0644]
OSX/trustd/macOS/entitlements.plist
OSX/trustd/trustd.c
Security.exp-in
Security.xcodeproj/project.pbxproj
keychain/ckks/CKKS.h
keychain/ckks/CKKSCKAccountStateTracker.m
keychain/ckks/CKKSControl.h
keychain/ckks/CKKSControl.m
keychain/ckks/CKKSControlProtocol.h
keychain/ckks/CKKSControlProtocol.m
keychain/ckks/CKKSGroupOperation.m
keychain/ckks/CKKSIncomingQueueOperation.m
keychain/ckks/CKKSKeychainView.h
keychain/ckks/CKKSKeychainView.m
keychain/ckks/CKKSLockStateTracker.m
keychain/ckks/CKKSReachabilityTracker.m
keychain/ckks/CKKSResultOperation.m
keychain/ckks/CKKSViewManager.m
keychain/ckks/CKKSZone.m
keychain/ckks/CKKSZoneChangeFetcher.m
keychain/ckks/tests/CKKSTests+API.m
keychain/ckks/tests/CKKSTests.m
keychain/ckks/tests/MockCloudKit.m
resources/English.lproj/Trust.strings
tests/secdmockaks/secdmockaks.m
trust/SecPolicyPriv.h
trust/SecTrust.h
trust/SecTrustPriv.h
trust/SecTrustSettingsPriv.h

index 1cbf8ad12508239e7e8931d59eecd27aaea70122..3236a2bbabb93e36779a91c643e38e43f3ccf068 100644 (file)
@@ -89,12 +89,6 @@ NSString *rejoinICDPUrl     = @"prefs:root=APPLE_ACCOUNT&aaaction=CDP&command=re
 
 BOOL processRequests(CFErrorRef *error);
 
-static bool PSKeychainSyncPrimaryAcccountExists(void)
-{
-    ACAccountStore *accountStore = [[ACAccountStore alloc] init];
-    return [accountStore aa_primaryAppleAccount] != NULL;
-}
-
 static void PSKeychainSyncIsUsingICDP(void)
 {
     ACAccountStore *accountStore = [[ACAccountStore alloc] init];
@@ -793,15 +787,6 @@ static bool processEvents()
     CFReleaseNull(error);
     circleStatus = SOSCCThisDeviceIsInCircleNonCached(&error);
 
-    /*
-     * Double check that the account still exists before doing anything rash (like posting a CFU or throw up a dialog)
-     */
-
-    if (!PSKeychainSyncPrimaryAcccountExists()) {
-        secnotice("cjr", "no primary account, bailing");
-        return true;
-    }
-
     if(_isAccountICDP){
         if((circleStatus == kSOSCCError || circleStatus == kSOSCCCircleAbsent || circleStatus == kSOSCCNotInCircle) && _hasPostedFollowupAndStillInError == false) {
             if(circleStatus == kSOSCCError) {
index 39da8b2f24ded81c5b4a45dc4a1bf9853089b0b6..01ffca584b4a48a17efa4c697b6287dac14aebc9 100644 (file)
@@ -24,6 +24,8 @@
        <true/>
        <key>application-identifier</key>
        <string>com.apple.security.regressions</string>
+       <key>com.apple.application-identifier</key>
+       <string>com.apple.security.regressions</string>
        <key>com.apple.private.uninstall.deletion</key>
        <true/>
        <key>com.apple.private.security.delete.all</key>
index 6e54a079abc48049581f914769420e5ccd229014..5ee92582fc5e115e7451b53f9cb8d0377155279e 100644 (file)
@@ -123,6 +123,7 @@ OSStatus SecStaticCodeCheckValidityWithErrors(SecStaticCodeRef staticCodeRef, Se
                | kSecCSRestrictToAppLike
         | kSecCSUseSoftwareSigningCert
            | kSecCSValidatePEH
+               | kSecCSSingleThreaded
        );
 
        if (errors)
index 1183adca446585ca883fc7a3ce1ab7aec0c5219f..b053623ebe1a7fb66b7029cf08ab17123bb51c49 100644 (file)
@@ -180,6 +180,7 @@ CF_ENUM(uint32_t) {
        kSecCSRestrictSidebandData = 1 << 9,
     kSecCSUseSoftwareSigningCert = 1 << 10,
        kSecCSValidatePEH = 1 << 11,
+       kSecCSSingleThreaded = 1 << 12,
 };
 
 OSStatus SecStaticCodeCheckValidity(SecStaticCodeRef staticCode, SecCSFlags flags,
index 7458d53b7233da64d398da1f7de0b848ea1e386b..74038fcc9a25c958338f843957c975d7f0832e8f 100644 (file)
@@ -1220,7 +1220,9 @@ void SecStaticCode::validateResources(SecCSFlags flags)
 
        if (doit) {
                if (mLimitedAsync == NULL) {
-                       mLimitedAsync = new LimitedAsync(diskRep()->fd().mediumType() == kIOPropertyMediumTypeSolidStateKey);
+                       bool runMultiThreaded = ((flags & kSecCSSingleThreaded) == kSecCSSingleThreaded) ? false :
+                                       (diskRep()->fd().mediumType() == kIOPropertyMediumTypeSolidStateKey);
+                       mLimitedAsync = new LimitedAsync(runMultiThreaded);
                }
 
                try {
index bcefe83eea32777457cf92e3f8be17e61b04a8ca..6fb96593e71eb45e30e4345e6681f93a7c96fb66 100644 (file)
@@ -830,10 +830,35 @@ namespace Security {
 
             if (key->cdsaKey == NULL) {
                 // Create CDSA key from exported data of existing key.
-                CFRef<CFDataRef> keyData = SecKeyCopyExternalRepresentation(key, NULL);
                 CFRef<CFDictionaryRef> keyAttributes = SecKeyCopyAttributes(key);
-                if (keyData && keyAttributes) {
-                    key->cdsaKey = SecKeyCreateFromData(keyAttributes, keyData, NULL);
+                if (keyAttributes) {
+                    CFRef<CFDataRef> keyData = SecKeyCopyExternalRepresentation(key, NULL);
+                    if (!keyData) {
+                        CFTypeRef pubKeyHash = CFDictionaryGetValue(keyAttributes, kSecAttrApplicationLabel);
+                        const void *keys[] = { kSecClass, kSecAttrNoLegacy, kSecReturnRef, kSecMatchLimit };
+                        const void *values[] = { kSecClassIdentity, kCFBooleanFalse, kCFBooleanTrue, kSecMatchLimitAll };
+                        CFRef<CFDictionaryRef> query = CFDictionaryCreate(kCFAllocatorDefault, keys, values,
+                                                                          sizeof(keys) / sizeof(*keys),
+                                                                          &kCFTypeDictionaryKeyCallBacks,
+                                                                          &kCFTypeDictionaryValueCallBacks);
+                        CFRef<CFArrayRef> identities;
+                        OSStatus status = SecItemCopyMatching(query, (CFTypeRef *)identities.take());
+                        if (status == errSecSuccess) {
+                            for (int i = 0; i < CFArrayGetCount(identities); ++i) {
+                                CFRef<SecKeyRef> privateKey;
+                                if (SecIdentityCopyPrivateKey((SecIdentityRef)CFArrayGetValueAtIndex(identities, i), privateKey.take()) != errSecSuccess) {
+                                    continue;
+                                }
+                                CFRef<CFDictionaryRef> attrs = SecKeyCopyAttributes(privateKey);
+                                if (CFEqual(CFDictionaryGetValue(attrs, kSecAttrApplicationLabel), pubKeyHash)) {
+                                    key->cdsaKey = privateKey.retain();
+                                    break;
+                                }
+                            }
+                        }
+                    } else {
+                        key->cdsaKey = SecKeyCreateFromData(keyAttributes, keyData, NULL);
+                    }
                 }
             }
 
index b1dc1e727145368bf80a8da1d2975f62e983b05f..c7d3429f576639e753807a7ea2b0d0255b763d2c 100644 (file)
@@ -472,15 +472,15 @@ static u_int16_t ReconstructUInt16 (uint32& finger, const uint8* data)
 static void ReconstructFileSystemHeader (uint32& finger, const uint8* data, FileSystemEntryItem* item)
 {
        // get the number of bytes for the name
-       u_int16_t length = ReconstructUInt16 (finger, data);
-       char name[length + 1];
-       
+    u_int16_t length = ReconstructUInt16 (finger, data);
+    std::vector<char> name(length + 1);
+
        // make a c-string for the name
-       memcpy (name, data + finger, length);
-       name[length] = 0;
-       item->SetName (name);
-       
-       secinfo ("manifest", "    File item name is %s", name);
+    memcpy (name.data(), data + finger, length);
+    name[length] = 0;
+
+    secinfo ("manifest", "    File item name is %s", name.data());
+    item->SetName (name.data());
 
        finger += length;
        
index c771e478bdfa3a50758956c78c73e569713c46bd..852639cc9d041098c88189f140003b8fbd8ae292 100644 (file)
@@ -824,13 +824,13 @@ void ManifestFileItem::ComputeDigestForFile (char* name, SHA1Digest &digest, siz
        if (st.st_size != 0)
        {
                // read the file
-               char buffer[kReadChunkSize];
-               
-               ssize_t bytesRead;
-               while ((bytesRead = read (fileNo, buffer, kReadChunkSize)) != 0)
+        std::vector<char> buffer(kReadChunkSize);
+
+        ssize_t bytesRead;
+        while ((bytesRead = read (fileNo, buffer.data(), kReadChunkSize)) != 0)
                {
                        // digest the read data
-                       CC_SHA1_Update (&digestContext, buffer, (CC_LONG)bytesRead);
+                       CC_SHA1_Update (&digestContext, buffer.data(), (CC_LONG)bytesRead);
                }
                
                // compute the SHA1 hash
index 86b33c54721edeb3f3086737a37ed815a5e7e48b..30bf5d7dcd901467504e3496d27e3433c7f4b421 100644 (file)
@@ -655,13 +655,9 @@ uint8_t* SOSFullPeerInfoEncodeToDER(SOSFullPeerInfoRef peer, CFErrorRef* error,
 
 CFDataRef SOSFullPeerInfoCopyEncodedData(SOSFullPeerInfoRef peer, CFAllocatorRef allocator, CFErrorRef *error)
 {
-    size_t size = SOSFullPeerInfoGetDEREncodedSize(peer, error);
-    if (size == 0)
-        return NULL;
-    uint8_t buffer[size];
-    uint8_t* start = SOSFullPeerInfoEncodeToDER(peer, error, buffer, buffer + sizeof(buffer));
-    CFDataRef result = CFDataCreate(kCFAllocatorDefault, start, size);
-    return result;
+    return CFDataCreateWithDER(kCFAllocatorDefault, SOSFullPeerInfoGetDEREncodedSize(peer, error), ^uint8_t*(size_t size, uint8_t *buffer) {
+        return SOSFullPeerInfoEncodeToDER(peer, error, buffer, (uint8_t *) buffer + size);
+    });
 }
 
 bool SOSFullPeerInfoPromoteToApplication(SOSFullPeerInfoRef fpi, SecKeyRef user_key, CFErrorRef *error)
index 040bd5301b7abf207941490601b48b287123aff5..e379eb3436511927a9cb386bc83e81791fd97366 100644 (file)
@@ -285,4 +285,244 @@ unsigned char _trustSettingsSMIMELeaf[1050]={
     0xFE,0x46,0xEB,0xFE,0x0E,0x11,0xCB,0x34,0x53,0xAB,
 };
 
+/* subject:/CN=Apple Corporate Root CA/OU=Certification Authority/O=Apple Inc./C=US */
+/* issuer :/CN=Apple Corporate Root CA/OU=Certification Authority/O=Apple Inc./C=US */
+uint8_t _corporateRoot[] = {
+    0x30,0x82,0x03,0xB1,0x30,0x82,0x02,0x99,0xA0,0x03,0x02,0x01,0x02,0x02,0x08,0x14,
+    0x99,0x6B,0x4A,0x6A,0xE4,0x40,0xA0,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,
+    0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x66,0x31,0x20,0x30,0x1E,0x06,0x03,0x55,0x04,
+    0x03,0x0C,0x17,0x41,0x70,0x70,0x6C,0x65,0x20,0x43,0x6F,0x72,0x70,0x6F,0x72,0x61,
+    0x74,0x65,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x31,0x20,0x30,0x1E,0x06,0x03,
+    0x55,0x04,0x0B,0x0C,0x17,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,
+    0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x31,0x13,0x30,0x11,
+    0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,
+    0x2E,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x30,0x1E,
+    0x17,0x0D,0x31,0x33,0x30,0x37,0x31,0x36,0x31,0x39,0x32,0x30,0x34,0x35,0x5A,0x17,
+    0x0D,0x32,0x39,0x30,0x37,0x31,0x37,0x31,0x39,0x32,0x30,0x34,0x35,0x5A,0x30,0x66,
+    0x31,0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x03,0x0C,0x17,0x41,0x70,0x70,0x6C,0x65,
+    0x20,0x43,0x6F,0x72,0x70,0x6F,0x72,0x61,0x74,0x65,0x20,0x52,0x6F,0x6F,0x74,0x20,
+    0x43,0x41,0x31,0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x0B,0x0C,0x17,0x43,0x65,0x72,
+    0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,
+    0x72,0x69,0x74,0x79,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,
+    0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,
+    0x04,0x06,0x13,0x02,0x55,0x53,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,
+    0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,
+    0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xB5,0x3B,0xE3,0x9F,0x6A,0x1D,0x0E,0x46,0x51,
+    0x1E,0xD0,0xB5,0x17,0x6B,0x06,0x4B,0x92,0xAF,0x38,0x10,0x25,0xA1,0xEE,0x1E,0x4E,
+    0xEF,0x19,0xE0,0x73,0xB5,0x37,0x33,0x72,0x21,0x21,0xCB,0x62,0x4A,0x3D,0xA9,0x68,
+    0xD8,0x07,0xB4,0xEB,0x8D,0x0A,0xDB,0x30,0x33,0x21,0x2F,0x6F,0xD3,0xF7,0x5D,0xCE,
+    0x20,0x0A,0x04,0xDB,0xFF,0xBF,0x75,0x08,0x42,0x3F,0x3E,0xD8,0xC8,0xEF,0xA4,0xF8,
+    0x56,0x7B,0x13,0x64,0x6B,0xF3,0xA2,0x38,0x10,0xFA,0xEE,0x9D,0x83,0x93,0x1D,0xFB,
+    0xEF,0x13,0x6C,0x38,0x49,0xDD,0xEB,0x71,0xA6,0x92,0x58,0x04,0xDE,0x01,0x41,0x2B,
+    0x99,0x5E,0xBD,0x24,0x3F,0x69,0xA8,0x44,0xF2,0xAA,0x01,0x78,0xB9,0x38,0x06,0x10,
+    0x77,0x36,0xF8,0xF2,0xA3,0x3E,0xD9,0x5F,0xEA,0xF5,0x8B,0x6A,0xA6,0x5F,0xE6,0x51,
+    0xD0,0x9B,0x50,0xA0,0x1E,0xF5,0x85,0x9E,0x49,0x50,0x4A,0x61,0x78,0xDA,0x29,0xA7,
+    0x33,0x72,0x8B,0x83,0xEE,0x7B,0xA7,0x79,0x4E,0x8E,0x02,0x6F,0x9D,0x25,0x97,0x26,
+    0x86,0x0C,0x82,0xC5,0x8C,0x16,0x7E,0x49,0x61,0xFD,0xFF,0x1A,0xA0,0x0D,0x28,0xE1,
+    0x68,0xF5,0xAE,0x85,0x72,0xF3,0xAB,0xE0,0x74,0x75,0xCC,0x57,0x64,0x3C,0x2C,0x55,
+    0x05,0xC9,0x8D,0xAA,0xB3,0xEC,0xC8,0x62,0x88,0x15,0x2A,0xC4,0x59,0x60,0x37,0xC1,
+    0xED,0x6B,0xCE,0xE9,0xCA,0xAF,0xB0,0xA5,0x45,0xBA,0xFF,0x16,0x32,0xAA,0x92,0x86,
+    0xD9,0xB9,0xA1,0x13,0x75,0x95,0x9B,0x97,0x5C,0x2D,0xB5,0x12,0xCA,0x6B,0x6B,0x39,
+    0xD6,0x9B,0x4B,0x34,0x47,0xAB,0x35,0x02,0x03,0x01,0x00,0x01,0xA3,0x63,0x30,0x61,
+    0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x35,0x20,0x26,0xCE,0x85,
+    0xBE,0x49,0x26,0x20,0x01,0xDD,0xC8,0xEE,0xFF,0x3D,0x68,0xC8,0xD0,0xDF,0xF5,0x30,
+    0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,
+    0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x35,0x20,0x26,
+    0xCE,0x85,0xBE,0x49,0x26,0x20,0x01,0xDD,0xC8,0xEE,0xFF,0x3D,0x68,0xC8,0xD0,0xDF,
+    0xF5,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,
+    0x06,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,
+    0x03,0x82,0x01,0x01,0x00,0x73,0x02,0x4A,0xA6,0x77,0x02,0xA7,0xE1,0xCB,0x52,0x97,
+    0x9D,0x89,0x11,0xA0,0x8F,0xBC,0xF3,0x8F,0x14,0x01,0x29,0xF3,0xA5,0x45,0x17,0x06,
+    0xF8,0x04,0xF2,0x6D,0xD5,0xC3,0x77,0xB8,0x00,0xC2,0x0A,0x1A,0x09,0x32,0x36,0x36,
+    0x69,0xC1,0x2A,0xF0,0x44,0x37,0xBC,0x7E,0x5F,0x15,0xF7,0x08,0x9C,0x19,0x27,0x1D,
+    0x70,0x4F,0xDC,0x17,0x94,0x3C,0xBB,0x24,0xB4,0xE6,0xFC,0x71,0x9A,0xD4,0xCF,0x2C,
+    0x12,0xBA,0xF0,0xB6,0x8F,0x78,0x99,0xAA,0x8C,0x17,0x7E,0x94,0x0C,0x6A,0x37,0x5B,
+    0x35,0x91,0x52,0xFA,0x64,0xA3,0x33,0x34,0x99,0x37,0x00,0x3C,0xB4,0x4E,0x6E,0x63,
+    0xED,0xC3,0x1D,0x37,0x5B,0x45,0xB4,0xDF,0x82,0xCD,0xFE,0xAA,0x92,0x64,0xC8,0x2F,
+    0xD6,0x2D,0x2E,0xB1,0xED,0x6A,0x04,0xF1,0xC2,0x48,0x8D,0x4B,0xB4,0x84,0x39,0xA3,
+    0x31,0x4D,0xF6,0x63,0xB4,0xC3,0x6E,0xA1,0xA5,0x2F,0xD2,0x1E,0xB0,0xC6,0x0C,0xD1,
+    0x04,0x3A,0x31,0xBC,0x87,0x49,0xF8,0x26,0x0B,0xD3,0x0C,0x08,0x29,0xBB,0x9F,0x4D,
+    0x08,0xF0,0x9C,0x11,0xD3,0xA5,0x2C,0x8D,0x98,0xB1,0x1B,0xB1,0x57,0xD3,0x69,0xAE,
+    0x9E,0x2D,0xD5,0x64,0x38,0x58,0xC9,0xB2,0x84,0x04,0xAB,0x10,0x1D,0xCA,0x6B,0x29,
+    0xA5,0xAB,0xCC,0xFE,0xBB,0x74,0xF4,0x35,0x03,0x8F,0x65,0x2A,0x0B,0xBB,0xC7,0x17,
+    0x6A,0x49,0x34,0x83,0x30,0x92,0x8D,0xD7,0xAE,0x95,0xD0,0xD7,0x23,0xA7,0xE3,0x29,
+    0x09,0xA1,0xB1,0x34,0xC3,0x95,0x49,0xC3,0xA4,0xF1,0x36,0x00,0x09,0xD3,0xA4,0x09,
+    0xAD,0xF2,0x5C,0x97,0xB2,
+};
+
+/* subject:/CN=Apple Corporate Server CA 1/OU=Certification Authority/O=Apple Inc./C=US */
+/* issuer :/CN=Apple Corporate Root CA/OU=Certification Authority/O=Apple Inc./C=US */
+uint8_t _corporateServerCA[] = {
+    0x30,0x82,0x04,0x40,0x30,0x82,0x03,0x28,0xA0,0x03,0x02,0x01,0x02,0x02,0x08,0x0D,
+    0x5D,0xDF,0x69,0x27,0x9B,0x23,0x11,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,
+    0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x66,0x31,0x20,0x30,0x1E,0x06,0x03,0x55,0x04,
+    0x03,0x0C,0x17,0x41,0x70,0x70,0x6C,0x65,0x20,0x43,0x6F,0x72,0x70,0x6F,0x72,0x61,
+    0x74,0x65,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x31,0x20,0x30,0x1E,0x06,0x03,
+    0x55,0x04,0x0B,0x0C,0x17,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,
+    0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x31,0x13,0x30,0x11,
+    0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,
+    0x2E,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x30,0x1E,
+    0x17,0x0D,0x31,0x34,0x30,0x33,0x32,0x36,0x31,0x36,0x35,0x33,0x33,0x37,0x5A,0x17,
+    0x0D,0x32,0x39,0x30,0x33,0x32,0x36,0x31,0x36,0x35,0x33,0x33,0x37,0x5A,0x30,0x6A,
+    0x31,0x24,0x30,0x22,0x06,0x03,0x55,0x04,0x03,0x0C,0x1B,0x41,0x70,0x70,0x6C,0x65,
+    0x20,0x43,0x6F,0x72,0x70,0x6F,0x72,0x61,0x74,0x65,0x20,0x53,0x65,0x72,0x76,0x65,
+    0x72,0x20,0x43,0x41,0x20,0x31,0x31,0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x0B,0x0C,
+    0x17,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,
+    0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,
+    0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x0B,0x30,
+    0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x30,0x82,0x01,0x22,0x30,0x0D,
+    0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,
+    0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xE3,0xE9,0x68,0xA1,0xE7,
+    0x9B,0xBC,0xF7,0x87,0x48,0x22,0x9B,0x09,0x5F,0xC8,0xC9,0xA6,0x9A,0xCC,0xCD,0x40,
+    0x16,0xF8,0xA1,0xD0,0xF6,0x27,0x15,0x4C,0xE7,0xD3,0xC1,0x6E,0xDF,0x11,0x06,0x9A,
+    0x63,0xC5,0x87,0x55,0xDA,0xDF,0xAF,0x15,0x31,0x98,0x45,0xF4,0x8C,0xC2,0x3C,0x93,
+    0xA2,0x1C,0xC0,0xF0,0x2A,0x77,0xF4,0x19,0x94,0x96,0xF4,0x7B,0x52,0x74,0x84,0x86,
+    0x5A,0x66,0x7D,0x68,0x92,0xA1,0x5E,0xE1,0xA9,0x21,0xE0,0x14,0x38,0x84,0x21,0x32,
+    0x8B,0x21,0x95,0x47,0x27,0x17,0xA0,0xBA,0x7B,0xD7,0xD8,0xD7,0x25,0x20,0x77,0xCB,
+    0x62,0x8B,0xC6,0x0F,0xC1,0x49,0xC6,0x2B,0x42,0xE9,0x02,0x70,0x9E,0x99,0x44,0x77,
+    0x51,0x05,0x62,0x78,0xBC,0xB0,0xD2,0xA7,0xA6,0x91,0x71,0x25,0x58,0x13,0x8D,0x8A,
+    0xC8,0x46,0x41,0xDB,0x89,0x41,0xC5,0x23,0x7D,0x84,0xE9,0x02,0xB0,0x1A,0xF8,0x5D,
+    0x66,0xD0,0xE1,0xE1,0x72,0xF4,0xA4,0x65,0x79,0x97,0x0A,0x7B,0xC0,0xE3,0x24,0x74,
+    0x83,0x4A,0x81,0x5E,0xC3,0xA2,0xBF,0x51,0x32,0x96,0x8F,0x28,0x32,0x08,0x49,0xFB,
+    0x02,0x43,0x62,0x42,0xB3,0x84,0x84,0x30,0x1B,0x28,0xE4,0x05,0xB9,0xBB,0xD6,0xB5,
+    0xC4,0xA2,0xAB,0x8E,0x57,0x53,0x29,0xBC,0x0B,0x4F,0xD6,0x1E,0xA4,0x52,0xDC,0x16,
+    0x1C,0x95,0xC2,0x8D,0x97,0x6B,0xBB,0x3E,0xC8,0x93,0xC7,0x01,0x97,0x1E,0x18,0x09,
+    0x59,0x39,0x0F,0x5D,0x73,0x4E,0xA9,0x8F,0x49,0xFD,0x49,0x16,0xBD,0x25,0xEC,0xD9,
+    0x05,0xEA,0xE3,0xB0,0x04,0x0E,0xD9,0x09,0x9E,0xC0,0xB7,0x02,0x03,0x01,0x00,0x01,
+    0xA3,0x81,0xED,0x30,0x81,0xEA,0x30,0x41,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,
+    0x01,0x01,0x04,0x35,0x30,0x33,0x30,0x31,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,
+    0x30,0x01,0x86,0x25,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x6F,0x63,0x73,0x70,0x2E,
+    0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x2F,0x6F,0x63,0x73,0x70,0x30,0x34,
+    0x2D,0x63,0x6F,0x72,0x70,0x72,0x6F,0x6F,0x74,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,
+    0x04,0x16,0x04,0x14,0xB6,0x23,0xB5,0x5A,0xEB,0x7E,0xEB,0xB6,0xF3,0x28,0x1E,0x04,
+    0xD0,0xAD,0x5C,0x93,0xA9,0xA4,0x9A,0x6D,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,
+    0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,
+    0x04,0x18,0x30,0x16,0x80,0x14,0x35,0x20,0x26,0xCE,0x85,0xBE,0x49,0x26,0x20,0x01,
+    0xDD,0xC8,0xEE,0xFF,0x3D,0x68,0xC8,0xD0,0xDF,0xF5,0x30,0x32,0x06,0x03,0x55,0x1D,
+    0x1F,0x04,0x2B,0x30,0x29,0x30,0x27,0xA0,0x25,0xA0,0x23,0x86,0x21,0x68,0x74,0x74,
+    0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,
+    0x6D,0x2F,0x63,0x6F,0x72,0x70,0x72,0x6F,0x6F,0x74,0x2E,0x63,0x72,0x6C,0x30,0x0E,
+    0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x10,
+    0x06,0x0A,0x2A,0x86,0x48,0x86,0xF7,0x63,0x64,0x06,0x18,0x04,0x04,0x02,0x05,0x00,
+    0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,
+    0x82,0x01,0x01,0x00,0x0D,0x34,0x2F,0xB2,0xC2,0xF1,0xF0,0xDC,0xA2,0x9F,0x8F,0x41,
+    0x9C,0x84,0xCA,0x66,0xDC,0x90,0x9C,0xC4,0x90,0xC9,0xDA,0xD9,0x37,0x4F,0xAE,0xC9,
+    0xD9,0xCF,0xE2,0x4B,0x8E,0x59,0x47,0x9A,0x83,0x32,0xDF,0xA7,0x97,0x45,0x9D,0x1E,
+    0x46,0x58,0x5D,0xD7,0x1C,0x17,0xC5,0x1C,0x9E,0xA2,0x74,0xF6,0x73,0x77,0xF9,0x35,
+    0xAD,0x67,0xC3,0x3C,0xD5,0x87,0x1E,0x96,0x16,0x3D,0x8B,0x40,0x51,0xA8,0x16,0xA0,
+    0x53,0x1C,0xF5,0xCB,0x32,0xC4,0xA8,0xC5,0x2A,0x3A,0x21,0xD9,0xFD,0x51,0x81,0x59,
+    0x6F,0x1B,0xF9,0x40,0x86,0x96,0xCF,0xA0,0x73,0xA3,0x5B,0x60,0x02,0xB6,0x21,0xAD,
+    0x39,0xF5,0xFA,0xFC,0xA8,0x6E,0x34,0x01,0x7C,0x59,0xF3,0x73,0xFC,0xBA,0xBE,0xF4,
+    0x4E,0x16,0x36,0x9E,0x51,0x77,0x80,0xF5,0xA1,0xC7,0xAE,0xFF,0x04,0x71,0x6B,0xB3,
+    0xBE,0x3E,0xA7,0xD1,0x74,0x2B,0x4D,0x58,0x58,0x3B,0x94,0x74,0xA3,0x65,0x27,0xC1,
+    0x74,0xA9,0xD2,0xF9,0x8A,0x81,0xB3,0x47,0xB3,0x06,0x8E,0x9C,0xE6,0x42,0x86,0x77,
+    0xF8,0x96,0x99,0x1F,0xED,0x30,0x8F,0x4B,0xD5,0x0F,0x5E,0x71,0x6C,0xAC,0xDB,0x48,
+    0xE3,0x3C,0x58,0x2B,0xE8,0x9B,0x9E,0x24,0x8A,0x5D,0xCD,0x56,0x5F,0xA9,0x07,0xEA,
+    0xCD,0x2C,0x94,0x3D,0xA7,0x7F,0x1B,0xE8,0x10,0xB8,0xD2,0x1E,0x43,0x5A,0x0D,0x13,
+    0xDA,0xF5,0x3F,0x10,0x9D,0x2D,0x1F,0xE6,0x94,0x11,0x2F,0x40,0xFF,0x5F,0x21,0x96,
+    0x02,0xF0,0x5F,0x54,0x56,0x32,0x90,0xD5,0x67,0xAE,0x29,0x0E,0x22,0x70,0xE3,0x2B,
+    0x7A,0x95,0xC0,0xC7,
+};
+
+/* subject:/CN=bbasile-test.scv.apple.com/OU=management:idms.group.631731/O=Apple Inc./ST=California/C=US */
+/* issuer :/CN=Apple Corporate Server CA 1/OU=Certification Authority/O=Apple Inc./C=US */
+uint8_t _corporateServerCert[] = {
+    0x30,0x82,0x05,0xF4,0x30,0x82,0x04,0xDC,0xA0,0x03,0x02,0x01,0x02,0x02,0x08,0x54,
+    0x32,0x9C,0xE6,0xE6,0xD7,0x87,0x7E,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,
+    0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x6A,0x31,0x24,0x30,0x22,0x06,0x03,0x55,0x04,
+    0x03,0x0C,0x1B,0x41,0x70,0x70,0x6C,0x65,0x20,0x43,0x6F,0x72,0x70,0x6F,0x72,0x61,
+    0x74,0x65,0x20,0x53,0x65,0x72,0x76,0x65,0x72,0x20,0x43,0x41,0x20,0x31,0x31,0x20,
+    0x30,0x1E,0x06,0x03,0x55,0x04,0x0B,0x0C,0x17,0x43,0x65,0x72,0x74,0x69,0x66,0x69,
+    0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,
+    0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,
+    0x20,0x49,0x6E,0x63,0x2E,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,
+    0x55,0x53,0x30,0x1E,0x17,0x0D,0x31,0x38,0x30,0x39,0x32,0x37,0x30,0x34,0x32,0x30,
+    0x34,0x31,0x5A,0x17,0x0D,0x32,0x30,0x31,0x30,0x32,0x36,0x30,0x34,0x32,0x30,0x34,
+    0x31,0x5A,0x30,0x81,0x83,0x31,0x23,0x30,0x21,0x06,0x03,0x55,0x04,0x03,0x0C,0x1A,
+    0x62,0x62,0x61,0x73,0x69,0x6C,0x65,0x2D,0x74,0x65,0x73,0x74,0x2E,0x73,0x63,0x76,
+    0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x31,0x25,0x30,0x23,0x06,0x03,
+    0x55,0x04,0x0B,0x0C,0x1C,0x6D,0x61,0x6E,0x61,0x67,0x65,0x6D,0x65,0x6E,0x74,0x3A,
+    0x69,0x64,0x6D,0x73,0x2E,0x67,0x72,0x6F,0x75,0x70,0x2E,0x36,0x33,0x31,0x37,0x33,
+    0x31,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,
+    0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x0C,
+    0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x0B,0x30,0x09,0x06,
+    0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,
+    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,
+    0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xAF,0x8C,0xB9,0x3F,0x56,0x41,0xF9,
+    0xA5,0x93,0x89,0x95,0x58,0x31,0x90,0x84,0xD5,0x3E,0xBB,0xE4,0x7C,0x68,0xD4,0x5B,
+    0x95,0x97,0x04,0xEF,0xE6,0x3C,0x8E,0x6A,0x98,0xD0,0xAD,0xDD,0x7A,0xF1,0x5E,0x4D,
+    0xCF,0x40,0xEF,0x05,0xF7,0x02,0x8C,0x01,0x0B,0x74,0x9D,0x0C,0x7E,0xD1,0xF8,0x80,
+    0x6E,0xAA,0xBF,0x96,0xB3,0x50,0x8F,0xB4,0x68,0x0C,0xFA,0xD0,0xDB,0xE7,0x93,0xA0,
+    0x6A,0x84,0xF2,0xA3,0x90,0x62,0x54,0xBD,0xB0,0xB3,0x1F,0xD6,0x0E,0xD1,0x2B,0xBA,
+    0x13,0x38,0x0A,0xD1,0x84,0x36,0x75,0x77,0xFB,0x3B,0x1E,0x61,0x1B,0x85,0x22,0xA9,
+    0xF9,0x42,0xD6,0xA2,0x9B,0xCB,0x34,0x76,0xC0,0xAE,0x2B,0xB0,0x64,0x95,0x5B,0xC7,
+    0x61,0x2A,0x0B,0x81,0xE0,0x01,0x34,0xB8,0x50,0xDC,0x26,0x77,0x55,0xF7,0x95,0xE1,
+    0xEC,0x01,0x4F,0xA8,0x0E,0x89,0x25,0xFE,0x8E,0xAB,0x40,0x6E,0x17,0x14,0xAA,0xA8,
+    0x6C,0x79,0x52,0xDC,0xE3,0xDA,0x15,0xBF,0xAF,0x3C,0x96,0x2B,0xA3,0x4D,0xFA,0xC5,
+    0xB5,0x36,0xCD,0x2F,0x88,0xFF,0xD1,0x1E,0xB1,0xE6,0x7C,0x0E,0xBD,0x60,0x0A,0x78,
+    0xF7,0x8A,0x22,0x86,0xAD,0xC7,0x43,0x73,0xD7,0x22,0x64,0x32,0xA8,0xEC,0xEB,0x4F,
+    0x41,0x90,0xCC,0x2F,0xB5,0x1A,0xA4,0xE6,0x91,0x34,0x86,0xCA,0x0A,0x17,0x0B,0x28,
+    0x5F,0x94,0xAE,0x4C,0xDB,0x94,0x7A,0xD9,0xC3,0x4A,0x09,0x11,0xFA,0x33,0x6A,0x99,
+    0x85,0x66,0x12,0x0A,0x70,0x7D,0x99,0x88,0xBE,0xC8,0x4E,0xCF,0x01,0xD8,0xD1,0x54,
+    0x46,0x85,0x66,0x31,0x37,0xB3,0x7E,0x0F,0x45,0x02,0x03,0x01,0x00,0x01,0xA3,0x82,
+    0x02,0x82,0x30,0x82,0x02,0x7E,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,
+    0x04,0x02,0x30,0x00,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,
+    0x14,0xB6,0x23,0xB5,0x5A,0xEB,0x7E,0xEB,0xB6,0xF3,0x28,0x1E,0x04,0xD0,0xAD,0x5C,
+    0x93,0xA9,0xA4,0x9A,0x6D,0x30,0x81,0x83,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,
+    0x01,0x01,0x04,0x77,0x30,0x75,0x30,0x39,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,
+    0x30,0x02,0x86,0x2D,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x65,0x72,0x74,0x73,
+    0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x2F,0x61,0x70,0x70,0x6C,0x65,
+    0x63,0x6F,0x72,0x70,0x73,0x65,0x72,0x76,0x65,0x72,0x63,0x61,0x31,0x2E,0x64,0x65,
+    0x72,0x30,0x38,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x86,0x2C,0x68,
+    0x74,0x74,0x70,0x3A,0x2F,0x2F,0x6F,0x63,0x73,0x70,0x2E,0x61,0x70,0x70,0x6C,0x65,
+    0x2E,0x63,0x6F,0x6D,0x2F,0x6F,0x63,0x73,0x70,0x30,0x33,0x2D,0x63,0x6F,0x72,0x70,
+    0x73,0x65,0x72,0x76,0x65,0x72,0x63,0x61,0x31,0x30,0x34,0x30,0x25,0x06,0x03,0x55,
+    0x1D,0x11,0x04,0x1E,0x30,0x1C,0x82,0x1A,0x62,0x62,0x61,0x73,0x69,0x6C,0x65,0x2D,
+    0x74,0x65,0x73,0x74,0x2E,0x73,0x63,0x76,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,
+    0x6F,0x6D,0x30,0x82,0x01,0x12,0x06,0x03,0x55,0x1D,0x20,0x04,0x82,0x01,0x09,0x30,
+    0x82,0x01,0x05,0x30,0x82,0x01,0x01,0x06,0x0A,0x2A,0x86,0x48,0x86,0xF7,0x63,0x64,
+    0x05,0x0F,0x02,0x30,0x81,0xF2,0x30,0x81,0xA4,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,
+    0x07,0x02,0x02,0x30,0x81,0x97,0x0C,0x81,0x94,0x52,0x65,0x6C,0x69,0x61,0x6E,0x63,
+    0x65,0x20,0x6F,0x6E,0x20,0x74,0x68,0x69,0x73,0x20,0x63,0x65,0x72,0x74,0x69,0x66,
+    0x69,0x63,0x61,0x74,0x65,0x20,0x62,0x79,0x20,0x61,0x6E,0x79,0x20,0x70,0x61,0x72,
+    0x74,0x79,0x20,0x61,0x73,0x73,0x75,0x6D,0x65,0x73,0x20,0x61,0x63,0x63,0x65,0x70,
+    0x74,0x61,0x6E,0x63,0x65,0x20,0x6F,0x66,0x20,0x61,0x6E,0x79,0x20,0x61,0x70,0x70,
+    0x6C,0x69,0x63,0x61,0x62,0x6C,0x65,0x20,0x74,0x65,0x72,0x6D,0x73,0x20,0x61,0x6E,
+    0x64,0x20,0x63,0x6F,0x6E,0x64,0x69,0x74,0x69,0x6F,0x6E,0x73,0x20,0x6F,0x66,0x20,
+    0x75,0x73,0x65,0x20,0x61,0x6E,0x64,0x2F,0x6F,0x72,0x20,0x63,0x65,0x72,0x74,0x69,
+    0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x70,0x72,0x61,0x63,0x74,0x69,0x63,
+    0x65,0x20,0x73,0x74,0x61,0x74,0x65,0x6D,0x65,0x6E,0x74,0x73,0x2E,0x30,0x49,0x06,
+    0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x3D,0x68,0x74,0x74,0x70,0x73,
+    0x3A,0x2F,0x2F,0x63,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x6D,0x61,
+    0x6E,0x61,0x67,0x65,0x72,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x2F,
+    0x23,0x68,0x65,0x6C,0x70,0x2F,0x70,0x6F,0x6C,0x69,0x63,0x69,0x65,0x73,0x2F,0x63,
+    0x6F,0x72,0x70,0x6F,0x72,0x61,0x74,0x65,0x30,0x1D,0x06,0x03,0x55,0x1D,0x25,0x04,
+    0x16,0x30,0x14,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x01,0x06,0x08,0x2B,
+    0x06,0x01,0x05,0x05,0x07,0x03,0x02,0x30,0x3C,0x06,0x03,0x55,0x1D,0x1F,0x04,0x35,
+    0x30,0x33,0x30,0x31,0xA0,0x2F,0xA0,0x2D,0x86,0x2B,0x68,0x74,0x74,0x70,0x3A,0x2F,
+    0x2F,0x63,0x72,0x6C,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x2F,0x61,
+    0x70,0x70,0x6C,0x65,0x63,0x6F,0x72,0x70,0x73,0x65,0x72,0x76,0x65,0x72,0x63,0x61,
+    0x31,0x2E,0x63,0x72,0x6C,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,
+    0x62,0xF3,0x37,0xB1,0x58,0x48,0x8F,0x49,0xEA,0x12,0x39,0x93,0x4C,0x17,0x91,0x07,
+    0x2F,0x71,0x09,0x4B,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,
+    0x03,0x02,0x05,0xA0,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,
+    0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0xE3,0xCE,0x7C,0xAC,0x0A,0xDE,0x21,0xB9,
+    0xB0,0x9E,0x1C,0xE9,0x6B,0xD5,0xBC,0xB7,0x53,0xE7,0x16,0x62,0xB0,0x1D,0x3E,0x53,
+    0xFE,0x47,0x1A,0x1A,0xA3,0x7A,0x69,0xC5,0xC0,0x8B,0xC9,0x0B,0xE1,0xBC,0xF6,0xE6,
+    0xAC,0x7E,0x05,0x60,0xC2,0xC2,0x3C,0xBA,0xB4,0x39,0xF7,0xDD,0xA4,0x60,0xC8,0x5B,
+    0x29,0x90,0x59,0x29,0xCF,0xC1,0x6D,0x38,0x38,0x83,0x81,0xFA,0x8A,0xB6,0x13,0xE6,
+    0xC6,0xDA,0x64,0xD5,0x19,0x40,0x82,0x8C,0x38,0xC9,0xBE,0xC4,0x81,0xBA,0x88,0xC6,
+    0x62,0xEC,0x42,0xED,0xCE,0x22,0xD2,0x52,0xE2,0x96,0x8C,0x3C,0xBC,0xCA,0xD4,0xF0,
+    0xC8,0x24,0x09,0xA1,0xC6,0xD3,0x44,0x4F,0x22,0x36,0xF8,0x6F,0x28,0x20,0x9C,0x0C,
+    0x71,0x10,0xCC,0x13,0x46,0x40,0xCF,0x15,0xF6,0x16,0x59,0xB2,0xC4,0xE6,0xDA,0x3D,
+    0x9C,0xB4,0x01,0x33,0x4E,0x01,0x87,0xFC,0xEB,0x4B,0x45,0x0E,0x6C,0x14,0x93,0x48,
+    0xA0,0x78,0xFA,0x0C,0x01,0xB0,0xEB,0xF1,0x6F,0x7B,0xE9,0xF4,0xED,0x42,0x92,0x07,
+    0x3B,0xFC,0x14,0x15,0x69,0xE7,0x1E,0x33,0xD8,0x7C,0xE1,0xD6,0x37,0xBB,0x13,0x50,
+    0x3E,0x3C,0x4A,0xD4,0x29,0xC7,0x29,0x3B,0x99,0x79,0xD5,0x92,0x96,0x64,0x28,0x0A,
+    0x7A,0x4F,0x8C,0x4A,0x32,0xC6,0x49,0x9D,0x05,0x0E,0x25,0x2F,0x46,0x6D,0x60,0x83,
+    0xA6,0x06,0x05,0x07,0x3F,0x50,0xFF,0x01,0x6C,0x3E,0xE2,0x71,0x09,0x74,0xD2,0x94,
+    0xEB,0x17,0xF4,0xE7,0x2B,0xB0,0xFD,0x41,0x52,0xEF,0x25,0x71,0x9C,0x1C,0x36,0xA6,
+    0x05,0x15,0xA6,0xD5,0x1E,0x23,0xB7,0xC2,
+};
+
 #endif /* si_28_sectrustsettings_h */
index 66aa2eb7daabea07d84dd13c76103da5ac9ec92c..3e24ded89e1e60782214060b5061641eb94d7a04 100644 (file)
@@ -579,6 +579,7 @@ static void test_policy_name_pinning_constraints(void) {
     removeTS(cert0);
 }
 
+
 int si_28_sectrustsettings(int argc, char *const *argv)
 {
     plan_tests(kNumberNoConstraintsTests
index a5ed23cc8138b9ec2b98b131dd16674f3a8d7939..ec8251e0a1d7ffb139de5ef739d714832b21530f 100644 (file)
@@ -361,7 +361,9 @@ static bool aks_consistency_test(bool currentAuthDataFormat, kern_return_t expec
     CFDataRef auth_data = NULL;
     CFMutableDictionaryRef auth_attribs = NULL;
 
-    require_noerr_string(SecRandomCopyBytes(kSecRandomDefault, bulkKeySize, bulkKey), out, "SecRandomCopyBytes failed");
+    OSStatus status = SecRandomCopyBytes(kSecRandomDefault, bulkKeySize, bulkKey);
+    ok_status(status, "SecRandomCopyBytes failed");
+    require_noerr(status, out);
 
     auth_attribs = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
     if (currentAuthDataFormat) {
@@ -371,14 +373,16 @@ static bool aks_consistency_test(bool currentAuthDataFormat, kern_return_t expec
         auth_data = kc_copy_constraints_data(access_control, auth_attribs);
     }
 
-    require_string(aks_crypt_acl(kAKSKeyOpEncrypt, KEYBAG_DEVICE, key_class_dk, bulkKeySize, bulkKey, bulkKeyWrapped,
-                                 auth_data, acm_context, NULL) == kAKSReturnSuccess, out, "kAKSKeyOpEncrypt failed");
+    status = aks_crypt_acl(kAKSKeyOpEncrypt, KEYBAG_DEVICE, key_class_dk, bulkKeySize, bulkKey, bulkKeyWrapped, auth_data, acm_context, NULL);
+    is_status(status, kAKSReturnSuccess, "kAKSKeyOpEncrypt failed");
+    require(status == kAKSReturnSuccess, out);
 
     uint32_t blobLenWrapped = (uint32_t)CFDataGetLength(bulkKeyWrapped);
     const uint8_t *cursor = CFDataGetBytePtr(bulkKeyWrapped);
 
-    require_string(aks_crypt_acl(kAKSKeyOpDecrypt, KEYBAG_DEVICE, key_class_dk, blobLenWrapped, cursor, bulkKeyUnwrapped,
-                                 auth_data, acm_context, NULL) == expectedAksResult, out, "kAKSKeyOpDecrypt finished with unexpected result");
+    status = aks_crypt_acl(kAKSKeyOpDecrypt, KEYBAG_DEVICE, key_class_dk, blobLenWrapped, cursor, bulkKeyUnwrapped, auth_data, acm_context, NULL);
+    is_status(status, expectedAksResult, "kAKSKeyOpDecrypt finished with unexpected result");
+    require(status == expectedAksResult, out);
 
     result = true;
 
index 1b466635be08c9e48f941f223ae251ecc052b50c..15302c731348ab3c5501b845b6aee76e74e72bd4 100644 (file)
@@ -4870,17 +4870,21 @@ static OSStatus appendOrganizationFromX501Name(void *context,
        return errSecSuccess;
 }
 
+CFArrayRef SecCertificateCopyOrganizationFromX501NameContent(const DERItem *nameContent) {
+    CFMutableArrayRef organization = CFArrayCreateMutable(kCFAllocatorDefault,
+                                                          0, &kCFTypeArrayCallBacks);
+    OSStatus status;
+    status = parseX501NameContent(nameContent, organization,
+                                  appendOrganizationFromX501Name, true);
+    if (status || CFArrayGetCount(organization) == 0) {
+        CFRelease(organization);
+        organization = NULL;
+    }
+    return organization;
+}
+
 CFArrayRef SecCertificateCopyOrganization(SecCertificateRef certificate) {
-       CFMutableArrayRef organization = CFArrayCreateMutable(kCFAllocatorDefault,
-               0, &kCFTypeArrayCallBacks);
-       OSStatus status;
-       status = parseX501NameContent(&certificate->_subject, organization,
-        appendOrganizationFromX501Name, true);
-       if (status || CFArrayGetCount(organization) == 0) {
-               CFRelease(organization);
-               organization = NULL;
-       }
-       return organization;
+    return SecCertificateCopyOrganizationFromX501NameContent(&certificate->_subject);
 }
 
 static OSStatus appendOrganizationalUnitFromX501Name(void *context,
index 51d9c7d430635d1dac1c50e6535d0d2bcb8234f3..5ad1107ac692cf5762337e711e1c206ec4109e53 100644 (file)
@@ -184,6 +184,8 @@ OSStatus SecCertificateParseGeneralNameContentProperty(DERTag tag,
 OSStatus SecCertificateParseGeneralNames(const DERItem *generalNames, void *context,
                                          parseGeneralNameCallback callback);
 
+CFArrayRef SecCertificateCopyOrganizationFromX501NameContent(const DERItem *nameContent);
+
 bool SecCertificateIsWeakKey(SecCertificateRef certificate);
 bool SecCertificateIsAtLeastMinKeySize(SecCertificateRef certificate,
                                        CFDictionaryRef keySizes);
index d9f013ecf5ce19698dfd72817e0de83f91b713cf..8f243e706c653dc752e38f224517ab9dda698f4b 100644 (file)
@@ -127,6 +127,8 @@ _kSecPolicyKU_KeyEncipherment
 _kSecPolicyKU_NonRepudiation
 #endif
 
+_SecDNSIsTLD
+
 #undef POLICYCHECKMACRO
 #define __PC_DO_EXPORT_(NAME)
 #define __PC_DO_EXPORT_O(NAME) _SecPolicyCheckCert##NAME
@@ -232,6 +234,7 @@ _SecTrustEvaluateFastAsync
 _SecTrustEvaluateLeafOnly
 _SecTrustEvaluateWithError
 _SecTrustFlushResponseCache
+_SecTrustGetAssetVersionNumber
 _SecTrustGetCertificateAtIndex
 _SecTrustGetCertificateCount
 _SecTrustGetDetails
@@ -245,11 +248,13 @@ _SecTrustGetTrustExceptionsArray
 _SecTrustIsExpiredOnly
 _SecTrustOTAPKIGetUpdatedAsset
 _SecTrustReportTLSAnalytics
+_SecTrustReportNetworkingAnalytics
 _SecTrustSerialize
 _SecTrustSetAnchorCertificates
 _SecTrustSetAnchorCertificatesOnly
 _SecTrustSetExceptions
 _SecTrustSetKeychainsAllowed
+_SecTrustSetNeedsEvaluation
 _SecTrustSetNetworkFetchAllowed
 _SecTrustSetOCSPResponse
 _SecTrustSetPinningException
@@ -317,9 +322,16 @@ _SecTrustStoreCopyAll
 _SecTrustStoreCopyUsageConstraints
 _SecTrustStoreForDomain
 _SecTrustStoreGetSettingsVersionNumber
+_SecTrustStoreGetSettingsAssetVersionNumber
 _SecTrustStoreRemoveCertificate
 _SecTrustStoreSetTrustSettings
 #endif
+_SecTrustStoreSetCTExceptions
+_SecTrustStoreCopyCTExceptions
+_kSecCTExceptionsCAsKey
+_kSecCTExceptionsDomainsKey
+_kSecCTExceptionsHashAlgorithmKey
+_kSecCTExceptionsSPKIHashKey
 
 //
 // Identity
@@ -367,6 +379,7 @@ _SecCertificateCopyNormalizedIssuerSequence
 _SecCertificateCopyNormalizedSubjectSequence
 _SecCertificateCopyNTPrincipalNames
 _SecCertificateCopyOrganization
+_SecCertificateCopyOrganizationFromX501NameContent
 _SecCertificateCopyOrganizationalUnit
 _SecCertificateCopyPrecertTBS
 _SecCertificateCopyProperties
index 774afb92dc43773ca188b1a704bc8c420fd1d32d..10943094c74e2de66479bf10b5de231e7c79f4dd 100644 (file)
@@ -313,10 +313,11 @@ __BEGIN_DECLS
 #define SEC_TRUST_ERROR_UsageConstraints            SecStringWithDefaultValue("User or administrator set certificate as distrusted", "Trust", 0, "User or administrator set certificate as distrusted", "Error for certificates with deny trust settings")
 #define SEC_TRUST_ERROR_SystemTrustedWeakHash       SecStringWithDefaultValue("Signature hash algorithm is not permitted for this use", "Trust", 0, "Signature hash algorithm is not permitted for this use", "Error for system-trust hash algorithm")
 #define SEC_TRUST_ERROR_SystemTrustedWeakKey        SecStringWithDefaultValue("Key size is not permitted for this use", "Trust", 0, "Key size is not permitted for this use", "Error for system-trust key size")
+#define SEC_TRUST_ERROR_SystemTrustedCTRequired     SecStringWithDefaultValue("Certificate Transparency validation required for this use", "Trust", 0, "Certificate Transparency validation required for this use", "Error for system-trust CT requirement")
 #define SEC_TRUST_ERROR_PinningRequired             SecStringWithDefaultValue("Pinning required but not used", "Trust", 0, "Pinning required but not used", "Error for required pinning")
 #define SEC_TRUST_ERROR_Revocation                  SecStringWithDefaultValue("Certificate is revoked", "Trust", 0, "Certificate is revoked", "Error for revocation")
 #define SEC_TRUST_ERROR_RevocationResponseRequired  SecStringWithDefaultValue("Failed to check revocation", "Trust", 0, "Failed to check revocation", "Error for revocation required")
-#define SEC_TRUST_ERROR_CTRequired                  SecStringWithDefaultValue("CT validation required but missing", "Trust", 0, "CT validation required but missing", "Error for missing Certificate Transparency validation")
+#define SEC_TRUST_ERROR_CTRequired                  SecStringWithDefaultValue("Certificate Transparency validation required but missing", "Trust", 0, "Certificate Transparency validation required but missing", "Error for missing Certificate Transparency validation")
 #define SEC_TRUST_ERROR_NoNetworkAccess             SecStringWithDefaultValue("Unexpected error detail", "Trust", 0, "Unexpected error detail", "Error for unexpected error details")
 #define SEC_TRUST_ERROR_ExtendedValidation          SecStringWithDefaultValue("Unexpected error detail", "Trust", 0, "Unexpected error detail", "Error for unexpected error details")
 #define SEC_TRUST_ERROR_RevocationOnline            SecStringWithDefaultValue("Unexpected error detail", "Trust", 0, "Unexpected error detail", "Error for unexpected error details")
index 661f3a2f4607047f4221f24e078563687f6b3ae7..0b735109358d8cec5196c17387f8d19d030a632e 100644 (file)
@@ -1352,6 +1352,9 @@ SecPolicyRef SecPolicyCreateSSL(Boolean server, CFStringRef hostname) {
         CFDictionaryAddValue(options, kSecPolicyCheckSystemTrustedWeakHash, kCFBooleanTrue);
         CFDictionaryAddValue(options, kSecPolicyCheckSystemTrustedWeakKey, kCFBooleanTrue);
         require_quiet(SecPolicyAddPinningRequiredIfInfoSpecified(options), errOut);
+#if !TARGET_OS_BRIDGE
+        CFDictionaryAddValue(options, kSecPolicyCheckSystemTrustedCTRequired, kCFBooleanTrue);
+#endif
     }
 
        set_ssl_ekus(options, server);
index 6d28fd463d89895c339518b9864823fd6d2ad142..5564b41a20e997536c0939ab860a4d140225e7d3 100644 (file)
@@ -86,6 +86,7 @@ POLICYCHECKMACRO(PinningRequired,                R, P, L,  ,  , 0x8001243C, errS
 POLICYCHECKMACRO(Revocation,                     F, V, L,  ,  , 0x8001210C, errSecCertificateRevoked) //CSSMERR_TP_CERT_REVOKED
 POLICYCHECKMACRO(RevocationResponseRequired,     R, P, L,  ,  , 0x80012423, errSecIncompleteCertRevocationCheck) //CSSMERR_APPLETP_INCOMPLETE_REVOCATION_CHECK
 POLICYCHECKMACRO(CTRequired,                     R, T,  ,  ,  , 0x8001212A, errSecNotTrusted) //CSSMERR_TP_NOT_TRUSTED
+POLICYCHECKMACRO(SystemTrustedCTRequired,        R, C,  , A,  , 0x80012114, errSecVerifyActionFailed) //CSSMERR_TP_VERIFY_ACTION_FAILED
 
 /********************************************************
 ******************* Feature Toggles *********************
index 843e2fe6fd7087ec059c32855ee308f203d83fb9..be1d616a460b4242a93820835b33712baf253961 100644 (file)
@@ -158,7 +158,7 @@ bool SecPolicyCheckCertNonEmptySubject(SecCertificateRef cert, CFTypeRef __unuse
    more labels. Use CFNetwork's function for determining if those labels comprise
    a top-level domain. We need to dlopen since CFNetwork is a client of ours. */
 typedef bool (*CFNIsTLD_f)(CFStringRef domain);
-static bool SecDNSIsTLD(CFStringRef reference) {
+bool SecDNSIsTLD(CFStringRef reference) {
     bool result = false; /* fail open for allocation and symbol lookup failures */
     static CFNIsTLD_f CFNIsDomainTopLevelFunctionPtr = NULL;
     static dispatch_once_t onceToken;
index 01b079b987c32dab7934894d3bc50076e3354ea6..32b663701ba4b76ae1762eb2b3d1c0a93e623b03 100644 (file)
@@ -331,7 +331,7 @@ OSStatus SecTrustAddToInputCertificates(SecTrustRef trust, CFTypeRef certificate
     return errSecSuccess;
 }
 
-static void SecTrustSetNeedsEvaluation(SecTrustRef trust) {
+void SecTrustSetNeedsEvaluation(SecTrustRef trust) {
     check(trust);
     if (trust) {
         dispatch_sync(trust->_trustQueue, ^{
@@ -2399,6 +2399,18 @@ uint64_t SecTrustGetTrustStoreVersionNumber(CFErrorRef *error) {
     return num;
 }
 
+uint64_t SecTrustGetAssetVersionNumber(CFErrorRef *error) {
+    do_if_registered(sec_ota_pki_asset_version, error);
+
+    os_activity_t activity = os_activity_create("SecTrustGetAssetVersionNumber", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
+    os_activity_scope(activity);
+
+    uint64_t num = do_ota_pki_op(sec_ota_pki_asset_version_id, error);
+
+    os_release(activity);
+    return num;
+}
+
 uint64_t SecTrustOTAPKIGetUpdatedAsset(CFErrorRef *error) {
        do_if_registered(sec_ota_pki_get_new_asset, error);
 
@@ -2415,13 +2427,13 @@ bool SecTrustReportTLSAnalytics(CFStringRef eventName, xpc_object_t eventAttribu
     if (!eventName || !eventAttributes) {
         return false;
     }
-    do_if_registered(sec_tls_analytics_report, eventName, eventAttributes, error);
+    do_if_registered(sec_networking_analytics_report, eventName, eventAttributes, error);
 
     os_activity_t activity = os_activity_create("SecTrustReportTLSAnalytics", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
     os_activity_scope(activity);
 
     __block bool result = false;
-    securityd_send_sync_and_do(kSecXPCOpTLSAnaltyicsReport, error, ^bool(xpc_object_t message, CFErrorRef *block_error) {
+    securityd_send_sync_and_do(kSecXPCOpNetworkingAnalyticsReport, error, ^bool(xpc_object_t message, CFErrorRef *block_error) {
         if (!SecXPCDictionarySetString(message, kSecTrustEventNameKey, eventName, block_error)) {
             return false;
         }
@@ -2436,6 +2448,53 @@ bool SecTrustReportTLSAnalytics(CFStringRef eventName, xpc_object_t eventAttribu
     return result;
 }
 
+bool SecTrustReportNetworkingAnalytics(const char *eventNameString, xpc_object_t eventAttributes) {
+    if (!eventNameString || !eventAttributes) {
+        return false;
+    }
+
+    CFStringRef eventName = CFStringCreateWithCString(kCFAllocatorDefault, eventNameString, kCFStringEncodingUTF8);
+    if (!eventName) {
+        secerror("CFStringCreateWithCString failed");
+        return false;
+    }
+
+    CFErrorRef error = NULL;
+    if (gTrustd && gTrustd->sec_networking_analytics_report) {
+        bool result = gTrustd->sec_networking_analytics_report(eventName, eventAttributes, &error);
+        if (error != NULL) {
+            secerror("SecTrustReportNetworkingAnalytics failed with error: %d", (int)CFErrorGetCode(error));
+        }
+        CFReleaseNull(eventName);
+        CFReleaseNull(error);
+        return result;
+    }
+
+    os_activity_t activity = os_activity_create("SecTrustReportNetworkingAnalytics", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
+    os_activity_scope(activity);
+
+    __block bool result = false;
+    securityd_send_sync_and_do(kSecXPCOpNetworkingAnalyticsReport, &error, ^bool(xpc_object_t message, CFErrorRef *block_error) {
+        if (!SecXPCDictionarySetString(message, kSecTrustEventNameKey, eventName, block_error)) {
+            return false;
+        }
+        xpc_dictionary_set_value(message, kSecTrustEventAttributesKey, eventAttributes);
+        return true;
+    }, ^bool(xpc_object_t response, CFErrorRef *block_error) {
+        result = SecXPCDictionaryGetBool(response, kSecXPCKeyResult, block_error);
+        return true;
+    });
+
+    if (error != NULL) {
+        secerror("SecTrustReportNetworkingAnalytics failed with error: %d", (int)CFErrorGetCode(error));
+    }
+    CFReleaseNull(error);
+    CFReleaseNull(eventName);
+
+    os_release(activity);
+    return result;
+}
+
 /*
  * This function performs an evaluation of the leaf certificate only, and
  * does so in the process that called it. Its primary use is in SecItemCopyMatching
@@ -2653,7 +2712,7 @@ static OSStatus SecTrustCreateFromPlist(CFPropertyListRef plist, SecTrustRef CF_
         output->_responses = CFRetainSafe(responses);
     }
     SCTs = CFDictionaryGetValue(plist, CFSTR(kSecTrustSCTsKey));
-    if (isArray(responses)) {
+    if (isArray(SCTs)) {
         output->_SCTs = CFRetainSafe(SCTs);
     }
     trustedLogs = CFDictionaryGetValue(plist, CFSTR(kSecTrustTrustedLogsKey));
index fcb0962e361ecee8e25694e967ee5ab3d332c23f..271da23b182796567ad2982a2696604a3d554842 100644 (file)
@@ -60,6 +60,7 @@ CFArrayRef SecTrustCopyProperties_ios(SecTrustRef trust);
 
 #define kSecTrustEventNameKey "eventName"
 #define kSecTrustEventAttributesKey "eventAttributes"
+#define kSecTrustEventApplicationID "appID"
 
 __END_DECLS
 
index d070c8357ca9f0e2b77c6dc02007a026a1037361..e24be104b49a36d85089fa6092f41a378d7eb574 100644 (file)
@@ -44,6 +44,7 @@
 #include <utilities/SecCFError.h>
 #include <utilities/SecCFWrappers.h>
 #include "utilities/SecDb.h"
+#include "SecTrustInternal.h"
 
 static CFStringRef kSecTrustStoreUserName = CFSTR("user");
 
@@ -238,7 +239,6 @@ errOut:
        return status;
 }
 
-
 OSStatus SecTrustStoreGetSettingsVersionNumber(SecTrustSettingsVersionNumber* p_settings_version_number)
 {
     if (NULL == p_settings_version_number) {
@@ -257,6 +257,24 @@ OSStatus SecTrustStoreGetSettingsVersionNumber(SecTrustSettingsVersionNumber* p_
     return status;
 }
 
+OSStatus SecTrustStoreGetSettingsAssetVersionNumber(SecTrustSettingsAssetVersionNumber* p_settings_asset_version_number)
+{
+    if (NULL == p_settings_asset_version_number) {
+        return errSecParam;
+    }
+
+    OSStatus status = errSecSuccess;
+    CFErrorRef error = nil;
+    uint64_t versionNumber = SecTrustGetAssetVersionNumber(&error);
+    *p_settings_asset_version_number = (SecTrustSettingsAssetVersionNumber)versionNumber;
+
+    if (error) {
+        status = (OSStatus)CFErrorGetCode(error);
+    }
+    CFReleaseSafe(error);
+    return status;
+}
+
 static bool string_to_array_error(enum SecXPCOperation op, SecTrustStoreRef ts, CFArrayRef *trustStoreContents, CFErrorRef *error)
 {
     return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
@@ -323,3 +341,51 @@ errOut:
     os_release(activity);
     return status;
 }
+
+#define do_if_registered(sdp, ...) if (gTrustd && gTrustd->sdp) { return gTrustd->sdp(__VA_ARGS__); }
+
+/* MARK: CT Enforcement Exceptions */
+
+const CFStringRef kSecCTExceptionsCAsKey = CFSTR("DisabledForCAs");
+const CFStringRef kSecCTExceptionsDomainsKey = CFSTR("DisabledForDomains");
+const CFStringRef kSecCTExceptionsHashAlgorithmKey = CFSTR("HashAlgorithm");
+const CFStringRef kSecCTExceptionsSPKIHashKey = CFSTR("SubjectPublicKeyInfoHash");
+
+bool SecTrustStoreSetCTExceptions(CFStringRef applicationIdentifier, CFDictionaryRef exceptions, CFErrorRef *error) {
+    do_if_registered(sec_trust_store_set_ct_exceptions, applicationIdentifier, exceptions, error);
+
+    os_activity_t activity = os_activity_create("SecTrustStoreSetCTExceptions", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
+    os_activity_scope(activity);
+
+    __block bool result = false;
+    securityd_send_sync_and_do(kSecXPCOpSetCTExceptions, error, ^bool(xpc_object_t message, CFErrorRef *block_error) {
+        SecXPCDictionarySetPListOptional(message, kSecTrustExceptionsKey, exceptions, block_error);
+        SecXPCDictionarySetStringOptional(message, kSecTrustEventApplicationID, applicationIdentifier, block_error);
+        return true;
+    }, ^bool(xpc_object_t response, CFErrorRef *block_error) {
+        result = SecXPCDictionaryGetBool(response, kSecXPCKeyResult, block_error);
+        return true;
+    });
+
+    os_release(activity);
+    return result;
+}
+
+CFDictionaryRef SecTrustStoreCopyCTExceptions(CFStringRef applicationIdentifier, CFErrorRef *error) {
+    do_if_registered(sec_trust_store_copy_ct_exceptions, applicationIdentifier, error);
+
+    os_activity_t activity = os_activity_create("SecTrustStoreCopyCTExceptions", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
+    os_activity_scope(activity);
+
+    __block CFDictionaryRef result = NULL;
+    securityd_send_sync_and_do(kSecXPCOpCopyCTExceptions, error, ^bool(xpc_object_t message, CFErrorRef *block_error) {
+        SecXPCDictionarySetStringOptional(message, kSecTrustEventApplicationID, applicationIdentifier, block_error);
+        return true;
+    }, ^bool(xpc_object_t response, CFErrorRef *block_error) {
+        (void)SecXPCDictionaryCopyDictionaryOptional(response, kSecTrustExceptionsKey, &result, block_error);
+        return true;
+    });
+
+    os_release(activity);
+    return result;
+}
index bc47013b1f8f838e890872f33fec0930c548c320..1458137b82d0e255557dc67ad7e6dfbc4d61cdbd 100644 (file)
@@ -44,6 +44,8 @@ typedef uint32_t SecTrustStoreDomain;
 
 typedef int32_t SecTrustSettingsVersionNumber;
 
+typedef int32_t SecTrustSettingsAssetVersionNumber;
+
 SecTrustStoreRef SecTrustStoreForDomain(SecTrustStoreDomain domain);
 
 Boolean SecTrustStoreContains(SecTrustStoreRef source,
@@ -59,6 +61,8 @@ OSStatus SecTrustStoreRemoveCertificate(SecTrustStoreRef ts,
 
 OSStatus SecTrustStoreGetSettingsVersionNumber(SecTrustSettingsVersionNumber* p_settings_version_number);
 
+OSStatus SecTrustStoreGetSettingsAssetVersionNumber(SecTrustSettingsAssetVersionNumber* p_settings_asset_version_number);
+
 OSStatus SecTrustStoreCopyAll(SecTrustStoreRef ts, CFArrayRef *CF_RETURNS_RETAINED trustStoreContents);
 
 /* Note that usageConstraints may be NULL on success. */
index a9afea359ef5ad2e9b00a33814e58ccab5fefb27..0f9d04e926558a6e0f71ef1936cb25e45690107a 100644 (file)
@@ -232,6 +232,8 @@ CFStringRef SOSCCGetOperationDescription(enum SecXPCOperation op)
             return CFSTR("keychain_sync_update_message");
         case sec_ota_pki_trust_store_version_id:
             return CFSTR("ota_pki_trust_store_version");
+        case sec_ota_pki_asset_version_id:
+            return CFSTR("ota_pki_asset_version");
         case sec_otr_session_create_remote_id: 
             return CFSTR("otr_session_create_remote");
         case sec_otr_session_process_packet_remote_id: 
@@ -300,8 +302,12 @@ CFStringRef SOSCCGetOperationDescription(enum SecXPCOperation op)
             return CFSTR("KeybagDelete");
         case kSecXPCOpKeychainControlEndpoint:
             return CFSTR("KeychainControlEndpoint");
-        case kSecXPCOpTLSAnaltyicsReport:
-            return CFSTR("TLSAnalyticsReport");
+        case kSecXPCOpNetworkingAnalyticsReport:
+            return CFSTR("NetworkingAnalyticsReport");
+        case kSecXPCOpSetCTExceptions:
+            return CFSTR("SetCTExceptions");
+        case kSecXPCOpCopyCTExceptions:
+            return CFSTR("CopyCTExceptions");
         default:
             return CFSTR("Unknown xpc operation");
     }
index 675393cf74bd99e1b27e6aad00e82c1a44ba690e..a49bc614c9562e1c4c6abc0223cbf382c045d6cc 100644 (file)
@@ -196,3 +196,24 @@ SECURITY_COMMAND("check-trust-update", check_trust_update,
                  "[-s]\n"
                  "    -s Check for Supplementals (Pinning DB and Trusted CT Logs) update\n",
                  "Check for data updates for trust and return current version.")
+
+SECURITY_COMMAND("add-ct-exceptions", add_ct_exceptions,
+                 "[options]\n"
+                 "   -d domain  Domain to add. Can be specified multiple times.\n"
+                 "   -c cert    Cert to add. Can be specified multiple times.\n"
+                 "   -p plist   plist with exceptions to set (resetting existing).\n"
+                 "                 Overrides -d and -c\n"
+                 "                 For detailed specification, see SecTrustSettingsPriv.h.\n"
+                 "   -r which   Reset exceptions for \"domain\", \"cert\", or \"all\".\n"
+                 "                 Overrides -d, -c, and -p\n",
+                 "Set exceptions for Certificate Transparency enforcement")
+
+SECURITY_COMMAND("show-ct-exceptions", show_ct_exceptions,
+                 "[options]\n"
+                 "   -a             Output all combined CT exceptions.\n"
+                 "   -i identifier  Output CT exceptions for specified identifier.\n"
+                 "                      Default is exceptions for this tool. Overridden by -a.\n"
+                 "   -d             Output domain exceptions. Default is both domains and certs.\n"
+                 "   -c             Output certificate exceptions (as SPKI hash).\n"
+                 "                      Default is both domains and certs.\n",
+                 "Display exceptions for Certificate Transparnecy enforcment in json.")
diff --git a/OSX/sec/Security/Tool/ct_exceptions.m b/OSX/sec/Security/Tool/ct_exceptions.m
new file mode 100644 (file)
index 0000000..fce2010
--- /dev/null
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 2018 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@
+ *
+ * ct_exceptions.m
+ */
+
+#import <Foundation/Foundation.h>
+#include <Security/SecTrustSettingsPriv.h>
+#include <Security/SecCertificatePriv.h>
+#include <utilities/fileIo.h>
+#include <utilities/SecCFWrappers.h>
+
+#include "SecurityCommands.h"
+
+NSString* toolAppID = @"com.apple.security";
+
+static int addCertFile(const char *fileName, NSMutableArray *array) {
+    SecCertificateRef certRef = NULL;
+    NSData *data = NULL;
+    unsigned char *buf = NULL;
+    size_t numBytes;
+    int rtn = 0;
+
+    if (readFileSizet(fileName, &buf, &numBytes)) {
+        rtn = -1;
+        goto errOut;
+    }
+
+    data = [NSData dataWithBytes:buf length:numBytes];
+    certRef = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)data);
+    if (!certRef) {
+        certRef = SecCertificateCreateWithPEM(NULL, (__bridge CFDataRef)data);
+        if (!certRef) {
+            rtn = -1;
+            goto errOut;
+        }
+    }
+
+    [array addObject:(__bridge id)certRef];
+
+errOut:
+    /* Cleanup */
+    free(buf);
+    CFReleaseNull(certRef);
+    return rtn;
+}
+
+static int returnCFError(CFErrorRef CF_CONSUMED error) {
+    CFStringRef errorString = CFErrorCopyDescription(error);
+    CFStringPerformWithCString(errorString, ^(const char *utf8Str) {
+        fprintf(stderr, "Failed to copy CT exceptions: %s\n", utf8Str);
+    });
+    CFIndex errCode = CFErrorGetCode(error);
+    CFReleaseNull(error);
+    return (int)errCode;
+}
+
+static int resetExceptions(bool resetCerts, bool resetDomains) {
+    bool result = false;
+    CFErrorRef error = NULL;
+    if (resetCerts) {
+        NSDictionary *resetCertsDict = @{ (__bridge NSString*)kSecCTExceptionsCAsKey: @[] };
+        result = SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)resetCertsDict, &error);
+    }
+    if (!error && resetDomains) {
+        NSDictionary *resetDomainsDict = @{ (__bridge NSString*)kSecCTExceptionsDomainsKey : @[] };
+        result = SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)resetDomainsDict, &error);
+    }
+    if (!result) {
+        return returnCFError(error);
+    }
+    return 0;
+}
+
+static int addExceptions(CFStringRef key, NSArray *newExceptions) {
+    CFErrorRef error = NULL;
+    NSDictionary *currentExceptions = CFBridgingRelease(SecTrustStoreCopyCTExceptions((__bridge CFStringRef)toolAppID, &error));
+    if (!currentExceptions && error) {
+        return returnCFError(error);
+    }
+
+    NSMutableArray *exceptionsForKey = nil;
+    if (currentExceptions && currentExceptions[(__bridge NSString*)key]) {
+        exceptionsForKey = [currentExceptions[(__bridge NSString*)key] mutableCopy];
+        [exceptionsForKey addObjectsFromArray:newExceptions];
+    } else {
+        exceptionsForKey = [newExceptions copy];
+    }
+
+    NSDictionary *newExceptionsDict = @{ (__bridge NSString*)key: exceptionsForKey };
+    bool result = SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)newExceptionsDict, &error);
+    if (!result) {
+        return returnCFError(error);
+    }
+
+    return 0;
+}
+
+int add_ct_exceptions(int argc, char * const *argv) {
+    int arg;
+
+    bool resetDomains = false;
+    bool resetCerts = false;
+
+    NSMutableArray *domains = [NSMutableArray array];
+    NSMutableArray *certs = [NSMutableArray array];
+    NSDictionary *plist = nil;
+
+    /* parse args */
+    if (argc == 1) {
+        return SHOW_USAGE_MESSAGE;
+    }
+
+    while ((arg = getopt(argc, argv, "d:c:r:p:")) != -1) {
+        switch(arg) {
+            case 'd': {
+                NSString *domain = [NSString stringWithCString:optarg encoding:NSUTF8StringEncoding];
+                [domains addObject:domain];
+                break;
+            }
+            case 'c':
+                if (addCertFile(optarg, certs)) {
+                    fprintf(stderr, "Failed to read cert file\n");
+                    return 1;
+                }
+                break;
+            case 'r':
+                if (!strcmp(optarg, "all")) {
+                    resetDomains = true;
+                    resetCerts = true;
+                } else if (!strcmp(optarg, "domain")) {
+                    resetDomains = true;
+                } else if (!strcmp(optarg, "cert")) {
+                    resetCerts = true;
+                } else {
+                    return SHOW_USAGE_MESSAGE;
+                }
+                break;
+            case 'p':
+                plist = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithCString:optarg encoding:NSUTF8StringEncoding]];
+                break;
+            case '?':
+            default:
+                return SHOW_USAGE_MESSAGE;
+        }
+    }
+
+    /* handle reset operation */
+    if (resetCerts || resetDomains) {
+        return resetExceptions(resetCerts, resetDomains);
+    }
+
+    /* set plist */
+    if (plist) {
+        CFErrorRef error = NULL;
+        bool result = SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)plist, &error);
+        if (!result) {
+            return returnCFError(error);
+        } else {
+            return 0;
+        }
+    }
+
+    /* add domains */
+    int status = 0;
+    if ([domains count]) {
+        status = addExceptions(kSecCTExceptionsDomainsKey, domains);
+    }
+    if (status != 0) {
+        fprintf(stderr, "failed to add domain exceptions\n");
+        return status;
+    }
+
+    /* add certs */
+    if ([certs count]) {
+        NSMutableArray<NSDictionary *>*valuesForCAsKey = [NSMutableArray arrayWithCapacity:[certs count]];
+        [certs enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
+            SecCertificateRef cert = (__bridge SecCertificateRef)obj;
+            NSData* hash = CFBridgingRelease(SecCertificateCopySubjectPublicKeyInfoSHA256Digest(cert));
+            NSDictionary *value = @{ (__bridge NSString*)kSecCTExceptionsHashAlgorithmKey:@"sha256",
+                                     (__bridge NSString*)kSecCTExceptionsSPKIHashKey:hash };
+            [valuesForCAsKey addObject:value];
+        }];
+        status = addExceptions(kSecCTExceptionsCAsKey, valuesForCAsKey);
+    }
+    if (status != 0) {
+        fprintf(stderr, "failed to add cert exceptions\n");
+        return status;
+    }
+
+    return 0;
+}
+
+static int printExceptions(CFStringRef key, NSDictionary *allExceptions) {
+    if (!allExceptions || !allExceptions[(__bridge NSString*)key] ||
+        [allExceptions[(__bridge NSString*)key] count] == 0) {
+        CFStringPerformWithCString(key, ^(const char *utf8Str) {
+            fprintf(stdout, "No CT Exceptions for %s\n", utf8Str);
+        });
+        return 0;
+    }
+
+    NSArray *exceptionsForKey = allExceptions[(__bridge NSString*)key];
+    NSMutableString *exceptionsString = [NSMutableString stringWithFormat:@"\t%@ : [",key];
+    [exceptionsForKey enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
+        if ([obj isKindOfClass:[NSString class]]) {
+            if (idx == 0) {
+                [exceptionsString appendFormat:@"\"%@\"",obj];
+            } else {
+                [exceptionsString appendFormat:@", \"%@\"", obj];
+            }
+        } else if ([obj isKindOfClass:[NSDictionary class]]) {
+            if (idx == 0) {
+                [exceptionsString appendString:@"\n\t    "];
+            } else {
+                [exceptionsString appendString:@"\t    "];
+            }
+            [exceptionsString appendFormat:@"\"%@:", obj[(__bridge NSString*)kSecCTExceptionsHashAlgorithmKey]];
+            NSString *hashHex = CFBridgingRelease(CFDataCopyHexString((__bridge CFDataRef)obj[(__bridge NSString*)kSecCTExceptionsSPKIHashKey]));
+            [exceptionsString appendString:hashHex];
+            if ([exceptionsForKey count] == idx + 1) { // last entry
+                [exceptionsString appendString:@"\"\n"];
+            } else {
+                [exceptionsString appendString:@"\",\n"];
+            }
+        }
+    }];
+    [exceptionsString appendString:@"]\n"];
+    CFStringPerformWithCString((__bridge CFStringRef)exceptionsString, ^(const char *utf8Str) {
+        fprintf(stdout, "\n%s\n", utf8Str);
+    });
+
+    return 0;
+}
+
+int show_ct_exceptions(int argc, char * const *argv) {
+    int arg;
+    bool allExceptions = false;
+    NSString *identifier = nil;
+    bool domainExceptions = false;
+    bool certExceptions = false;
+
+    /* parse args */
+    while ((arg = getopt(argc, argv, "ai:dc")) != -1) {
+        switch(arg) {
+            case 'a':
+                allExceptions = true;
+                break;
+            case 'i':
+                identifier = [NSString stringWithCString:optarg encoding:NSUTF8StringEncoding];
+                break;
+            case 'd':
+                domainExceptions = true;
+                break;
+            case 'c':
+                certExceptions = true;
+                break;
+            case '?':
+            default:
+                return SHOW_USAGE_MESSAGE;
+        }
+    }
+
+    if (!domainExceptions && !certExceptions) {
+        /* Nothing specified, show both */
+        domainExceptions = true;
+        certExceptions = true;
+    }
+
+    if (allExceptions) {
+        identifier = nil;
+        fprintf(stdout, "Showing exceptions for all apps\n");
+    } else if (!identifier) {
+        identifier = toolAppID;
+    }
+
+    if (identifier) {
+        CFStringPerformWithCString((__bridge CFStringRef)identifier, ^(const char *utf8Str) {
+            fprintf(stdout, "Showing exceptions for %s\n", utf8Str);
+        });
+    }
+
+    CFErrorRef error = NULL;
+    NSDictionary *results = CFBridgingRelease(SecTrustStoreCopyCTExceptions((__bridge CFStringRef)identifier, &error));
+
+    /* Copy failed, return error */
+    if (!results && error) {
+        return returnCFError(error);
+    }
+
+    /* print domain exceptions */
+    int status = 0;
+    if (domainExceptions) {
+        status = printExceptions(kSecCTExceptionsDomainsKey, results);
+    }
+    if (status != 0) {
+        fprintf(stderr, "failed to print domain exceptions\n");
+        return status;
+    }
+
+    /* print cert exceptions */
+    if (certExceptions) {
+        status = printExceptions(kSecCTExceptionsCAsKey, results);
+    }
+    if (status != 0) {
+        fprintf(stderr, "failed to print cert exceptions\n");
+        return status;
+    }
+
+
+    return 0;
+}
index ab650a4a13c93926fdea7c1cdeca3cd8bb300c9e..02f42d08415aa582d05d45ef212fc30cdb40935a 100644 (file)
@@ -15,6 +15,8 @@
        <true/>
        <key>application-identifier</key>
        <string>com.apple.security</string>
+       <key>com.apple.application-identifier</key>
+       <string>com.apple.security</string>
        <key>com.apple.private.keychain.keychaincontrol</key>
        <true/>
 </dict>
index c2b1c383ec9a45ba8439ee9453a5a3e55134e3a2..c959b9fef78367c9ea9f3b51e6c93239fea269e9 100644 (file)
@@ -77,9 +77,9 @@ static CFArrayRef SecServerCopyAccessGroups(void) {
                                    CFSTR("123456.test.group"),
                                    CFSTR("123456.test.group2"),
                                    CFSTR("com.apple.cfnetwork"),
-#else
-                                   CFSTR("sync"),
+                                   CFSTR("com.apple.bluetooth"),
 #endif
+                                   CFSTR("sync"),
                                    CFSTR("com.apple.security.sos"),
                                    CFSTR("com.apple.security.ckks"),
                                    CFSTR("com.apple.security.sos-usercredential"),
@@ -223,9 +223,12 @@ static bool is_trust_operation(enum SecXPCOperation op) {
         case sec_trust_store_copy_usage_constraints_id:
         case sec_ocsp_cache_flush_id:
         case sec_ota_pki_trust_store_version_id:
+        case sec_ota_pki_asset_version_id:
         case kSecXPCOpOTAGetEscrowCertificates:
         case kSecXPCOpOTAPKIGetNewAsset:
-        case kSecXPCOpTLSAnaltyicsReport:
+        case kSecXPCOpNetworkingAnalyticsReport:
+        case kSecXPCOpSetCTExceptions:
+        case kSecXPCOpCopyCTExceptions:
             return true;
         default:
             break;
index 496f67a424c5e104daac408ea35d0db9deaf1ffc..ee7a94c817dc624343cb816fadd201cbcafab8a8 100644 (file)
@@ -190,6 +190,7 @@ enum SecXPCOperation {
     sec_item_backup_restore_id,
     sec_keychain_sync_update_message_id,
     sec_ota_pki_trust_store_version_id,
+    sec_ota_pki_asset_version_id,
     sec_otr_session_create_remote_id,
     sec_otr_session_process_packet_remote_id,
     kSecXPCOpOTAPKIGetNewAsset,
@@ -306,7 +307,9 @@ enum SecXPCOperation {
     kSecXPCOpBackupKeybagDelete,
     kSecXPCOpSFKeychainEndpoint,
     kSecXPCOpKeychainControlEndpoint,
-    kSecXPCOpTLSAnaltyicsReport,
+    kSecXPCOpNetworkingAnalyticsReport,
+    kSecXPCOpSetCTExceptions,
+    kSecXPCOpCopyCTExceptions,
 };
 
 
@@ -455,12 +458,15 @@ struct trustd {
     bool (*sec_truststore_remove_all)(SecTrustStoreRef ts, CFErrorRef* error);
     SecTrustResultType (*sec_trust_evaluate)(CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly, bool keychainsAllowed, CFArrayRef policies, CFArrayRef responses, CFArrayRef SCTs, CFArrayRef trustedLogs, CFAbsoluteTime verifyTime, __unused CFArrayRef accessGroups, CFArrayRef exceptions, CFArrayRef *details, CFDictionaryRef *info, CFArrayRef *chain, CFErrorRef *error);
     uint64_t (*sec_ota_pki_trust_store_version)(CFErrorRef* error);
+    uint64_t (*sec_ota_pki_asset_version)(CFErrorRef* error);
     CFArrayRef (*ota_CopyEscrowCertificates)(uint32_t escrowRootType, CFErrorRef* error);
     uint64_t (*sec_ota_pki_get_new_asset)(CFErrorRef* error);
     bool (*sec_trust_store_copy_all)(SecTrustStoreRef ts, CFArrayRef *trustStoreContents, CFErrorRef *error);
     bool (*sec_trust_store_copy_usage_constraints)(SecTrustStoreRef ts, CFDataRef digest, CFArrayRef *usageConstraints, CFErrorRef *error);
     bool (*sec_ocsp_cache_flush)(CFErrorRef *error);
-    bool (*sec_tls_analytics_report)(CFStringRef event_name, xpc_object_t tls_analytics_attributes, CFErrorRef *error);
+    bool (*sec_networking_analytics_report)(CFStringRef event_name, xpc_object_t tls_analytics_attributes, CFErrorRef *error);
+    bool (*sec_trust_store_set_ct_exceptions)(CFStringRef appID, CFDictionaryRef exceptions, CFErrorRef *error);
+    CFDictionaryRef (*sec_trust_store_copy_ct_exceptions)(CFStringRef appID, CFErrorRef *error);
 };
 
 extern struct trustd *gTrustd;
index 2eaffdae91be1039e2415684af83b15d624631dc..7e25b4d69ed5b8bc1f633f7426763a3d2d8e8c85 100644 (file)
@@ -1821,6 +1821,9 @@ bool SecDbItemSelect(SecDbQueryRef query, SecDbConnectionRef dbconn, CFErrorRef
             return attr->kind == kSecDbRowIdAttr || attr->kind == kSecDbEncryptedDataAttr || attr->kind == kSecDbSHA1Attr;
         };
     }
+    if (use_attr_in_where == NULL) {
+        use_attr_in_where = ^bool (const SecDbAttr* attr) { return false; };
+    }
     
     CFStringRef sql = SecDbItemCopySelectSQL(query, return_attr, use_attr_in_where, add_where_sql);
     if (sql) {
index 54b6f794f812294cf6062d5e4f791fe7363b7ee4..4128cafcaefd6d93ac0d5069fa3b4779cbe4151d 100644 (file)
@@ -1244,7 +1244,7 @@ matchAnyString(CFStringRef needle, CFStringRef *haystack)
 /* Return true iff the item in question should not be backed up, nor restored,
  but when restoring a backup the original version of the item should be
  added back to the keychain again after the restore completes. */
-static bool SecItemIsSystemBound(CFDictionaryRef item, const SecDbClass *cls, bool multiUser) {
+bool SecItemIsSystemBound(CFDictionaryRef item, const SecDbClass *cls, bool multiUser) {
     CFNumberRef sysb =  CFDictionaryGetValue(item, kSecAttrSysBound);
     if (isNumber(sysb)) {
         int32_t num = 0;
index 9cca329940fb4d1bcb3a969b9d845cc8b5c9e560..9cb346583c3e188795a3548656ee6d0af97fc13e 100644 (file)
@@ -60,6 +60,8 @@ bool SecDbItemQuery(SecDbQueryRef query, CFArrayRef accessGroups, SecDbConnectio
 
 void query_pre_add(Query *q, bool force_date);
 
+bool SecItemIsSystemBound(CFDictionaryRef item, const SecDbClass *cls, bool multiUser);
+
 //
 // MARK: backup restore stuff
 //
index 5520e70d66552de06f5c1e1acdf38e992241edcf..cd1f60b979d01dd5a9e67f6d5fb196cbb6f65dd8 100644 (file)
@@ -2038,18 +2038,58 @@ bool _SecItemUpdateTokenItems(CFStringRef tokenID, CFArrayRef items, SecurityCli
     return ok;
 }
 
-/* AUDIT[securityd](done):
-   No caller provided inputs.
- */
+static bool deleteNonSysboundItemsForItemClass(SecDbConnectionRef dbt, SecDbClass const* class, CFErrorRef* error) {
+    CFMutableDictionaryRef query = CFDictionaryCreateMutableForCFTypes(NULL);
+    CFDictionaryAddValue(query, kSecMatchLimit, kSecMatchLimitAll);
+
+    __block CFErrorRef localError = NULL;
+    SecDbQueryRef q = query_create(class, NULL, query, &localError);
+    if (q == NULL) {    // illegal query or out of memory
+        secerror("SecItemServerDeleteAll: aborting because failed to initialize Query: %@", localError);
+        abort();
+    }
+    SecDbItemSelect(q, dbt, &localError, ^bool(const SecDbAttr *attr) {
+        return (attr->flags & kSecDbInFlag) && !CFEqual(attr->name, CFSTR("data"));
+    }, NULL, NULL, NULL,
+    ^(SecDbItemRef item, bool *stop) {
+        if (!SecItemIsSystemBound(item->attributes, class, false) &&
+            !CFEqual(CFDictionaryGetValue(item->attributes, kSecAttrAccessGroup), CFSTR("com.apple.bluetooth")))
+        {
+            SecDbItemDelete(item, dbt, kCFBooleanFalse, &localError);
+        }
+    });
+    query_destroy(q, &localError);
+
+    if (localError) {
+        if (error) {
+            CFReleaseNull(*error);
+            *error = localError;
+        } else {
+            CFReleaseNull(localError);
+        }
+        return false;
+    }
+    return true;
+}
+
+// Delete all the items except sysbound ones because horrible things happen if you do, like bluetooth devices unpairing
 static bool
 SecItemServerDeleteAll(CFErrorRef *error) {
     secerror("SecItemServerDeleteAll");
     return kc_with_dbt(true, error, ^bool (SecDbConnectionRef dbt) {
         return (kc_transaction(dbt, error, ^bool {
-            return (SecDbExec(dbt, CFSTR("DELETE from genp;"), error) &&
-                    SecDbExec(dbt, CFSTR("DELETE from inet;"), error) &&
-                    SecDbExec(dbt, CFSTR("DELETE from cert;"), error) &&
-                    SecDbExec(dbt, CFSTR("DELETE from keys;"), error));
+            bool ok = true;
+            ok &= SecDbExec(dbt, CFSTR("DELETE FROM genp WHERE sync=1;"), error);
+            ok &= SecDbExec(dbt, CFSTR("DELETE FROM inet WHERE sync=1;"), error);
+            ok &= SecDbExec(dbt, CFSTR("DELETE FROM cert WHERE sync=1;"), error);
+            ok &= SecDbExec(dbt, CFSTR("DELETE FROM keys WHERE sync=1;"), error);
+
+            ok &= deleteNonSysboundItemsForItemClass(dbt, genp_class(), error);
+            ok &= deleteNonSysboundItemsForItemClass(dbt, inet_class(), error);
+            ok &= deleteNonSysboundItemsForItemClass(dbt, cert_class(), error);
+            ok &= deleteNonSysboundItemsForItemClass(dbt, keys_class(), error);
+
+            return ok;
         }) && SecDbExec(dbt, CFSTR("VACUUM;"), error));
     });
 }
index a93bae984dea0b77b7e771a0242db069af966bb9..55ad8f4b49a501b042185759f10386c2c50b94e1 100644 (file)
@@ -333,8 +333,10 @@ static inline bool isNSDictionary(id nsType) {
         ok &= SecDbPerformWrite(self->_db, &error, ^(SecDbConnectionRef dbconn) {
             ok &= [self updateDb:dbconn error:&error pinningList:pinningList updateSchema:NO updateContent:YES];
         });
+#if !TARGET_OS_WATCH
         /* We changed the database, so clear the database cache */
         [self clearCache];
+#endif
     });
 
     if (!ok || error) {
@@ -515,8 +517,10 @@ static void verify_create_path(const char *path)
 - (instancetype) init {
     if (self = [super init]) {
         _queue = dispatch_queue_create("Pinning DB Queue", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
+#if !TARGET_OS_WATCH
         _regexCache = [NSMutableDictionary dictionary];
         _regexCacheLock = OS_UNFAIR_LOCK_INIT;
+#endif
         [self initializedDb];
     }
     return self;
@@ -527,20 +531,26 @@ static void verify_create_path(const char *path)
 }
 
 /* MARK: DB Cache
- * The cache is represented a dictionary defined as { suffix : { regex : resultsDictionary } } */
+ * The cache is represented a dictionary defined as { suffix : { regex : resultsDictionary } }
+ * The cache is not used on watchOS to reduce memory overhead. */
+#if !TARGET_OS_WATCH
 - (void) clearCache {
     os_unfair_lock_lock(&_regexCacheLock);
     self.regexCache = [NSMutableDictionary dictionary];
     os_unfair_lock_unlock(&_regexCacheLock);
 }
+#endif // !TARGET_OS_WATCH
 
+#if !TARGET_OS_WATCH
 - (void) addSuffixToCache:(NSString *)suffix entry:(NSDictionary <NSRegularExpression *, NSDictionary *> *)entry {
     os_unfair_lock_lock(&_regexCacheLock);
     secinfo("SecPinningDb", "adding %llu entries for %@ to cache", (unsigned long long)[entry count], suffix);
     self.regexCache[suffix] = entry;
     os_unfair_lock_unlock(&_regexCacheLock);
 }
+#endif // !TARGET_OS_WATCH
 
+#if !TARGET_OS_WATCH
 /* Because we iterate over all DB entries for a suffix, even if we find a match, we guarantee
  * that the cache, if the cache has an entry for a suffix, it has all the entries for that suffix */
 - (BOOL) queryCacheForSuffix:(NSString *)suffix firstLabel:(NSString *)firstLabel results:(NSDictionary * __autoreleasing *)results{
@@ -574,6 +584,7 @@ static void verify_create_path(const char *path)
 
     return foundSuffix;
 }
+#endif // !TARGET_OS_WATCH
 
 - (BOOL) isPinningDisabled:(NSString * _Nullable)policy {
     static dispatch_once_t once;
@@ -624,18 +635,22 @@ static void verify_create_path(const char *path)
     __block NSString *firstLabel = [domain substringToIndex:firstDot.location];
     __block NSString *suffix = [domain substringFromIndex:(firstDot.location + 1)];
 
+#if !TARGET_OS_WATCH
     /* Search cache */
     NSDictionary *cacheResult = nil;
     if ([self queryCacheForSuffix:suffix firstLabel:firstLabel results:&cacheResult]) {
         return cacheResult;
     }
+#endif
 
     /* Cache miss. Perform SELECT */
     __block bool ok = true;
     __block CFErrorRef error = NULL;
     __block NSMutableArray *resultRules = [NSMutableArray array];
     __block NSString *resultName = nil;
+#if !TARGET_OS_WATCH
     __block NSMutableDictionary <NSRegularExpression *, NSDictionary *> *newCacheEntry = [NSMutableDictionary dictionary];
+#endif
     ok &= SecDbPerformRead(_db, &error, ^(SecDbConnectionRef dbconn) {
         ok &= SecDbWithSQL(dbconn, selectDomainSQL, &error, ^bool(sqlite3_stmt *selectDomain) {
             ok &= SecDbBindText(selectDomain, 1, [suffix UTF8String], [suffix length], SQLITE_TRANSIENT, &error);
@@ -660,10 +675,12 @@ static void verify_create_path(const char *path)
                     id policies = [NSPropertyListSerialization propertyListWithData:xmlPolicies options:0 format:nil error:nil];
                     verify_action(isNSArray(policies), return);
 
+#if !TARGET_OS_WATCH
                     /* Add to cache entry */
                     [newCacheEntry setObject:@{(__bridge NSString*)kSecPinningDbKeyPolicyName:policyNameStr,
                                                (__bridge NSString*)kSecPinningDbKeyRules:policies}
                                       forKey:regularExpression];
+#endif
 
                     /* Match the labelRegex */
                     NSUInteger numMatches = [regularExpression numberOfMatchesInString:firstLabel
@@ -700,10 +717,12 @@ static void verify_create_path(const char *path)
         CFReleaseNull(error);
     }
 
+#if !TARGET_OS_WATCH
     /* Add new cache entry to cache. */
     if ([newCacheEntry count] > 0) {
         [self addSuffixToCache:suffix entry:newCacheEntry];
     }
+#endif
 
     /* Return results if found */
     if ([resultRules count] > 0) {
index 03366feb17f812d29dfe59eb49fcb5dc86a1da05..f747bf4567084c5a4530c95e66d954fab15ffb0c 100644 (file)
@@ -60,6 +60,7 @@
 #include <securityd/SecCertificateServer.h>
 #include <securityd/SecCertificateSource.h>
 #include <securityd/SecOCSPResponse.h>
+#include <securityd/SecTrustStoreServer.h>
 #include <utilities/array_size.h>
 #include <utilities/SecCFWrappers.h>
 #include <utilities/SecAppleAnchorPriv.h>
@@ -1493,6 +1494,13 @@ static CFDictionaryRef getSCTValidatingLog(CFDataRef sct, int entry_type, CFData
         require(!CFDictionaryContainsKey(logData, CFSTR("expiry")), out);
     }
 
+    CFAbsoluteTime sct_time = TimestampToCFAbsoluteTime(timestamp);
+    CFDateRef frozen_date = CFDictionaryGetValue(logData, CFSTR("frozen"));
+    if (frozen_date && (sct_time > CFDateGetAbsoluteTime(frozen_date))) {
+        secerror("Frozen CT log issued SCT after freezing (log=%@)\n", logData);
+        goto out;
+    }
+
     CFDataRef logKeyData = CFDictionaryGetValue(logData, CFSTR("key"));
     require(logKeyData, out); // This failing would be an internal logic error
     pubKey = SecKeyCreateFromSubjectPublicKeyInfoData(kCFAllocatorDefault, logKeyData);
@@ -1506,7 +1514,7 @@ static CFDictionaryRef getSCTValidatingLog(CFDataRef sct, int entry_type, CFData
     algId.parameters.Length = 0;
 
     if(SecKeyDigestAndVerify(pubKey, &algId, signed_data, signed_data_len, signatureData, signatureLen)==0) {
-        *sct_at = TimestampToCFAbsoluteTime(timestamp);
+        *sct_at = sct_time;
         result = logData;
     } else {
         secerror("SCT signature failed (log=%@)\n", logData);
@@ -1595,6 +1603,12 @@ static void SecPolicyCheckCT(SecPVCRef pvc)
     __block CFAbsoluteTime issuanceTime = SecPVCGetVerifyTime(pvc);
     TA_CTFailureReason failureReason = TA_CTNoFailure;
 
+    if (!trustedLogs) {
+        SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef();
+        trustedLogs = SecOTAPKICopyTrustedCTLogs(otapkiref);
+        CFReleaseSafe(otapkiref);
+    }
+
     // This eventually contain list of logs who validated the SCT.
     CFMutableDictionaryRef currentLogsValidatingScts = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
     CFMutableDictionaryRef logsValidatingEmbeddedScts = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
@@ -2076,6 +2090,256 @@ static void SecPolicyCheckPinningRequired(SecPVCRef pvc, CFStringRef key) {
     }
 }
 
+static bool is_configured_test_system_root(SecCertificateRef root) {
+    if (!SecIsInternalRelease()) {
+        return false;
+    }
+    bool result = false;
+    CFDataRef rootHash = SecCertificateCopySHA256Digest(root);
+    CFTypeRef value  = CFPreferencesCopyValue(CFSTR("TestCTRequiredSystemRoot"), CFSTR("com.apple.security"),
+                                              kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
+    require_quiet(isData(value), out);
+    require_quiet(kCFCompareEqualTo == CFDataCompare(rootHash, value), out);
+    result = true;
+
+out:
+    CFReleaseNull(value);
+    CFReleaseNull(rootHash);
+    return result;
+}
+
+static bool is_ct_excepted_domain(CFStringRef hostname, CFStringRef exception) {
+    if (kCFCompareEqualTo == CFStringCompare(exception, hostname, kCFCompareCaseInsensitive)) {
+        /* exact match */
+        return true;
+    } else if (CFStringHasPrefix(exception, CFSTR("."))) {
+        /* subdomains */
+        CFIndex elength = CFStringGetLength(exception);
+        CFIndex hlength = CFStringGetLength(hostname);
+        if (hlength > elength) {
+            CFRange compareRange = { hlength - elength, elength };
+            if (kCFCompareEqualTo == CFStringCompareWithOptions(hostname, exception, compareRange, kCFCompareCaseInsensitive)) {
+                return true;
+            }
+        } else if (hlength + 1 == elength) {
+            CFRange compareRange = { 1, hlength };
+            if (kCFCompareEqualTo == CFStringCompareWithOptions(exception, hostname, compareRange, kCFCompareCaseInsensitive)) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+static OSStatus is_subtree_dn_with_org(void *context, SecCEGeneralNameType gnType, const DERItem *generalName) {
+    if (gnType != GNT_DirectoryName) {
+        return errSecInternal;
+    }
+
+    DERDecodedInfo subtreeName_content;
+    if (DR_Success != DERDecodeItem(generalName, &subtreeName_content) || subtreeName_content.tag != ASN1_CONSTR_SEQUENCE) {
+        return errSecDecode;
+    }
+
+    CFArrayRef subtree_orgs = SecCertificateCopyOrganizationFromX501NameContent(&subtreeName_content.content);
+    if (subtree_orgs) {
+        CFReleaseNull(subtree_orgs);
+        return errSecSuccess;
+    }
+    return errSecInternal;
+}
+
+static bool has_ct_excepted_key(SecCertificatePathVCRef path, CFDictionaryRef exception) {
+    __block bool result = false;
+    CFDataRef exceptionHash = CFDictionaryGetValue(exception, kSecCTExceptionsSPKIHashKey);
+
+    /* exception for a leaf is always allowed */
+    SecCertificateRef leaf = SecCertificatePathVCGetCertificateAtIndex(path, 0);
+    CFDataRef spkiHash = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(leaf);
+    if (CFEqualSafe(exceptionHash, spkiHash)) {
+        result = true;
+    }
+    CFReleaseNull(spkiHash);
+
+    if (result) { return result; }
+
+    /* exceptions for CAs */
+    for (CFIndex certIX = 1; certIX < SecCertificatePathVCGetCount(path); certIX++) {
+        SecCertificateRef ca = SecCertificatePathVCGetCertificateAtIndex(path, certIX);
+
+        spkiHash = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(ca);
+        if (!CFEqualSafe(exceptionHash, spkiHash)) {
+            CFReleaseNull(spkiHash);
+            continue;
+        }
+        CFReleaseNull(spkiHash);
+
+        /* this CA matches but exceptions for CAs have constraints */
+        if (SecCertificateGetPermittedSubtrees(ca)) {
+            /* Constrained CAs have to have a Distinguished Name permitted subtree with an Organization attribute */
+            CFArrayForEach(SecCertificateGetPermittedSubtrees(ca), ^(const void *value) {
+                CFDataRef subtree = (CFDataRef)value;
+                const DERItem general_name = { (unsigned char *)CFDataGetBytePtr(subtree), CFDataGetLength(subtree) };
+                DERDecodedInfo general_name_content;
+                if (DR_Success == DERDecodeItem(&general_name, &general_name_content)) {
+                    OSStatus status = SecCertificateParseGeneralNameContentProperty(general_name_content.tag,
+                                                                                    &general_name_content.content,
+                                                                                    NULL,
+                                                                                    is_subtree_dn_with_org);
+                    if (status == errSecSuccess) {
+                        result = true;
+                    }
+                }
+            });
+        }
+
+        if (!result) {
+            /* The Organization attribute(s) in the CA subject have to exactly match the Organization attribute(s) in the leaf */
+            CFArrayRef leafOrgs = SecCertificateCopyOrganization(leaf);
+            CFArrayRef caOrgs = SecCertificateCopyOrganization(ca);
+            if (caOrgs && leafOrgs && CFEqualSafe(leafOrgs, caOrgs)) {
+                result = true;
+            }
+            CFReleaseNull(leafOrgs);
+            CFReleaseNull(caOrgs);
+        }
+
+        if (result) {
+            break;
+        }
+    }
+
+    return result;
+}
+
+static bool is_ct_excepted(SecPVCRef pvc) {
+    CFDictionaryRef ct_exceptions = _SecTrustStoreCopyCTExceptions(NULL, NULL);
+    if (!ct_exceptions) {
+        return false;
+    }
+
+    __block bool result = false;
+    CFArrayRef domainExceptions = CFDictionaryGetValue(ct_exceptions, kSecCTExceptionsDomainsKey);
+    if (domainExceptions) {
+        SecPolicyRef policy = SecPVCGetPolicy(pvc);
+        CFStringRef hostname = CFDictionaryGetValue(policy->_options, kSecPolicyCheckSSLHostname);
+        if (hostname) {
+            CFArrayForEach(domainExceptions, ^(const void *value) {
+                result = result || is_ct_excepted_domain(hostname, value);
+            });
+        }
+    }
+    if (result) {
+        secinfo("policy", "domain-based CT exception applied");
+        CFReleaseNull(ct_exceptions);
+        return result;
+    }
+
+    CFArrayRef keyExceptions = CFDictionaryGetValue(ct_exceptions, kSecCTExceptionsCAsKey);
+    if (keyExceptions) {
+        __block SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
+        CFArrayForEach(keyExceptions, ^(const void *value) {
+            result = result || has_ct_excepted_key(path, value);
+        });
+    }
+
+    if (result) {
+        secinfo("policy" , "key-based CT exceptions applied");
+    }
+
+    CFReleaseNull(ct_exceptions);
+    return result;
+}
+
+/* <rdar://45466778> some Apple servers not getting certs with embedded SCTs
+ * <rdar://45545270> some Google apps have their own TLS stacks and aren't passing us TLS SCTs */
+static bool is_apple_ca(SecCertificatePathVCRef path) {
+    /* subject:/CN=Apple IST CA 8 - G1/OU=Certification Authority/O=Apple Inc./C=US */
+    /* issuer :/C=US/O=GeoTrust Inc./OU=(c) 2007 GeoTrust Inc. - For authorized use only/CN=GeoTrust Primary Certification Authority - G2 */
+    static const uint8_t appleISTCA8G1_spkiSHA256[] = {
+        0xe2, 0x4f, 0x8e, 0x8c, 0x21, 0x85, 0xda, 0x2f, 0x5e, 0x88, 0xd4, 0x57, 0x9e, 0x81, 0x7c, 0x47,
+        0xbf, 0x6e, 0xaf, 0xbc, 0x85, 0x05, 0xf0, 0xf9, 0x60, 0xfd, 0x5a, 0x0d, 0xf4, 0x47, 0x3a, 0xd3
+    };
+
+    /* subject:/CN=Apple IST CA 2 - G1/OU=Certification Authority/O=Apple Inc./C=US */
+    /* issuer :/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA */
+    static const uint8_t appleISTCA2G1_spkiSHA256[] = {
+        0xb5, 0xcf, 0x82, 0xd4, 0x7e, 0xf9, 0x82, 0x3f, 0x9a, 0xa7, 0x8f, 0x12, 0x31, 0x86, 0xc5, 0x2e,
+        0x88, 0x79, 0xea, 0x84, 0xb0, 0xf8, 0x22, 0xc9, 0x1d, 0x83, 0xe0, 0x42, 0x79, 0xb7, 0x8f, 0xd5
+    };
+
+    /* subject:/C=US/O=Google Trust Services/CN=Google Internet Authority G3 */
+    /* issuer :/OU=GlobalSign Root CA - R2/O=GlobalSign/CN=GlobalSign */
+    static const uint8_t googleIAG3_spkiSHA256[] = {
+        0x7f, 0xc3, 0x67, 0x10, 0x56, 0x71, 0x43, 0x81, 0x31, 0x14, 0xe8, 0x52, 0x37, 0xb1, 0x22, 0x15,
+        0x6b, 0x62, 0xb9, 0xd6, 0x50, 0x54, 0x3d, 0xa8, 0x63, 0xad, 0x2e, 0x6a, 0xe5, 0x7f, 0x9f, 0xbf
+    };
+
+    bool result = false;
+    for (CFIndex certIX = 1; certIX < SecCertificatePathVCGetCount(path); certIX++) {
+        SecCertificateRef ca = SecCertificatePathVCGetCertificateAtIndex(path, certIX);
+
+        CFDataRef caSPKIHash = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(ca);
+        const uint8_t *dp = CFDataGetBytePtr(caSPKIHash);
+        if (dp && (!memcmp(appleISTCA8G1_spkiSHA256, dp, CC_SHA256_DIGEST_LENGTH) ||
+                   !memcmp(appleISTCA2G1_spkiSHA256, dp, CC_SHA256_DIGEST_LENGTH) ||
+                   !memcmp(googleIAG3_spkiSHA256, dp, CC_SHA256_DIGEST_LENGTH))) {
+            result = true;
+        }
+        CFReleaseNull(caSPKIHash);
+        if (result) {
+            break;
+        }
+    }
+    return result;
+}
+
+static void SecPolicyCheckSystemTrustedCTRequired(SecPVCRef pvc) {
+    SecCertificateSourceRef appleAnchorSource = NULL;
+    SecOTAPKIRef otaref = SecOTAPKICopyCurrentOTAPKIRef();
+    SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
+    CFArrayRef trustedLogs = SecPathBuilderCopyTrustedLogs(pvc->builder);
+
+    /* Skip this check if we haven't done the CT checks yet */
+    require_quiet(SecCertificatePathVCIsPathValidated(path), out);
+
+    /* We only enforce this check when all of the following are true:
+     *  0. Not a pinning policy */
+    SecPolicyRef policy = SecPVCGetPolicy(pvc);
+    require_quiet(CFEqualSafe(SecPolicyGetName(policy),kSecPolicyNameSSLServer), out);
+
+    /*  1. Device has checked in to MobileAsset for a current log list within the last 60 days.
+     *     Or the caller passed in the trusted log list. */
+    require_quiet(SecOTAPKIAssetStalenessLessThanSeconds(otaref, kSecOTAPKIAssetStalenessDisable) || trustedLogs, out);
+
+    /*  2. Leaf issuance date is on or after 16 Oct 2018 at 00:00:00 AM UTC */
+    SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
+    require_quiet(SecCertificateNotValidBefore(leaf) >= 561340800.0, out);
+
+    /*  3. Chain is anchored with root in the system anchor source but not the Apple anchor source */
+    CFIndex count = SecPVCGetCertificateCount(pvc);
+    SecCertificateRef root = SecPVCGetCertificateAtIndex(pvc, count - 1);
+    appleAnchorSource = SecMemoryCertificateSourceCreate(SecGetAppleTrustAnchors(false));
+    require_quiet(SecPathBuilderIsAnchored(pvc->builder), out);
+    require_quiet((SecCertificateSourceContains(kSecSystemAnchorSource, root) &&
+                   appleAnchorSource && !SecCertificateSourceContains(appleAnchorSource, root) &&
+                   !is_apple_ca(path)) ||
+                  is_configured_test_system_root(root), out);
+
+    if (!SecCertificatePathVCIsCT(path) && !is_ct_excepted(pvc)) {
+        /* Set failure. By not using the Forced variant, we implicitly check that this
+         * policy had this options set. */
+        SecPVCSetResult(pvc, kSecPolicyCheckSystemTrustedCTRequired, 0, kCFBooleanFalse);
+    }
+
+out:
+    CFReleaseNull(trustedLogs);
+    CFReleaseNull(otaref);
+    if (appleAnchorSource) {
+        SecMemoryCertificateSourceDestroy(appleAnchorSource);
+    }
+}
+
 void SecPolicyServerInitialize(void) {
        gSecPolicyLeafCallbacks = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
                &kCFTypeDictionaryKeyCallBacks, NULL);
@@ -3212,8 +3476,12 @@ void SecPVCPathChecks(SecPVCRef pvc) {
         }
     }
 
+    /* Say that we did the expensive path checks (that we want to skip on the second call) */
+    SecCertificatePathVCSetPathValidated(SecPathBuilderGetPath(pvc->builder));
+
     /* Check that this path meets CT constraints. */
     SecPVCCheckRequireCTConstraints(pvc);
+    SecPolicyCheckSystemTrustedCTRequired(pvc);
 
     /* Check that this path meets known-intermediate constraints. */
     SecPathBuilderCheckKnownIntermediateConstraints(pvc->builder);
@@ -3221,7 +3489,6 @@ void SecPVCPathChecks(SecPVCRef pvc) {
     secdebug("policy", "end %strusted path: %@",
         (SecPVCIsOkResult(pvc) ? "" : "not "), SecPathBuilderGetPath(pvc->builder));
 
-    SecCertificatePathVCSetPathValidated(SecPathBuilderGetPath(pvc->builder));
     return;
 }
 
index 24f0084dbf5d63350194228be9a5ab37ae1c4401..2bdde133b964b6fa69723ab8f8d4adae96bda527 100644 (file)
@@ -72,6 +72,7 @@
 #include <CoreFoundation/CFUtilities.h>
 
 const CFStringRef kValidUpdateProdServer   = CFSTR("valid.apple.com");
+const CFStringRef kValidUpdateSeedServer   = CFSTR("valid.apple.com/seed");
 const CFStringRef kValidUpdateCarryServer  = CFSTR("valid.apple.com/carry");
 
 static CFStringRef kSecPrefsDomain          = CFSTR("com.apple.security");
@@ -686,15 +687,22 @@ static bool SecValidUpdateSchedule(bool updateEnabled, CFStringRef server, CFInd
 }
 
 static CFStringRef SecRevocationDbGetDefaultServer(void) {
-#if RC_SEED_BUILD
-    return kValidUpdateCarryServer;
-#else // !RC_SEED_BUILD
-    CFStringRef defaultServer = kValidUpdateProdServer;
-    if (os_variant_has_internal_diagnostics("com.apple.security")) {
-        defaultServer = kValidUpdateCarryServer;
-    }
-    return defaultServer;
-#endif // !RC_SEED_BUILD
+#if !TARGET_OS_WATCH && !TARGET_OS_BRIDGE
+    #if RC_SEED_BUILD
+        CFStringRef defaultServer = kValidUpdateSeedServer;
+    #else // !RC_SEED_BUILD
+        CFStringRef defaultServer = kValidUpdateProdServer;
+    #endif // !RC_SEED_BUILD
+        if (os_variant_has_internal_diagnostics("com.apple.security")) {
+            defaultServer = kValidUpdateCarryServer;
+        }
+        return defaultServer;
+#else // TARGET_OS_WATCH || TARGET_OS_BRIDGE
+    /* Because watchOS and bridgeOS can't update over the air, we should
+     * always use the prod server so that the valid database built into the
+     * image is used. */
+    return kValidUpdateProdServer;
+#endif
 }
 
 void SecRevocationDbInitialize() {
index 709f527415bef675b5e9c2abaeb3938b466bdeb3..91f613accf881e32af21bf6efbe0d66e34e6b177 100644 (file)
@@ -158,6 +158,7 @@ void SecRevocationDbComputeAndSetNextUpdateTime(void);
 void SecRevocationDbInitialize(void);
 
 extern const CFStringRef kValidUpdateProdServer;
+extern const CFStringRef kValidUpdateSeedServer;
 extern const CFStringRef kValidUpdateCarryServer;
 
 /*!
index af70276a59d3b12b16d5e22a9fb31bc49b7cc6ab..b34972ebd39afb29133c21eefcf6c7ef88250a12 100644 (file)
@@ -308,10 +308,6 @@ static void SecPathBuilderInit(SecPathBuilderRef builder,
 
     if(trustedLogs) {
         builder->trustedLogs = CFRetainSafe(trustedLogs);
-    } else {
-        SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef();
-        builder->trustedLogs = SecOTAPKICopyTrustedCTLogs(otapkiref);
-        CFReleaseSafe(otapkiref);
     }
 
     /* Now let's get the leaf cert and turn it into a path. */
index b288c7afce9ddc2752aa04affe236c90a20ac3d7..587dd6c9737b9cff1e0304d94157c4706a64b0a9 100644 (file)
 #include "utilities/SecFileLocations.h"
 #include <utilities/SecDispatchRelease.h>
 #include <securityd/SecTrustLoggingServer.h>
+#include <os/variant_private.h>
+#include <dirent.h>
+#include <utilities/SecCFWrappers.h>
+#include <utilities/SecInternalReleasePriv.h>
 
 /* uid of the _securityd user. */
 #define SECURTYD_UID 64
@@ -76,13 +80,19 @@ static const char countAllSQL[] = "SELECT COUNT(*) FROM tsettings";
 
 struct __SecTrustStore {
     dispatch_queue_t queue;
-       sqlite3 *s3h;
-       sqlite3_stmt *copyParents;
-       sqlite3_stmt *contains;
-       bool readOnly;
-       bool containsSettings;  // For optimization of high-use calls.
+    sqlite3 *s3h;
+    sqlite3_stmt *copyParents;
+    sqlite3_stmt *contains;
+    bool readOnly;
+    bool containsSettings;  // For optimization of high-use calls.
 };
 
+// MARK: -
+// MARK: Corporate Root functions
+
+// MARK: -
+// MARK: Trust store functions
+
 static int sec_create_path(const char *path)
 {
        char pathbuf[PATH_MAX];
@@ -208,6 +218,7 @@ static SecTrustStoreRef SecTrustStoreCreate(const char *db_name,
         ts->containsSettings = true;
     }
 
+
        return ts;
 
 errOut:
@@ -422,10 +433,10 @@ CFArrayRef SecTrustStoreCopyParents(SecTrustStoreRef ts,
        require(ts, errOutNotLocked);
     dispatch_sync(ts->queue, ^{
         int s3e = SQLITE_OK;
-        require_quiet(ts->containsSettings, ok);
-        CFDataRef issuer;
+        CFDataRef issuer = NULL;
         require(issuer = SecCertificateGetNormalizedIssuerContent(certificate),
-            errOut);
+                errOut);
+        require_quiet(ts->containsSettings, ok);
         /* @@@ Might have to use SQLITE_TRANSIENT */
         require_noerr(s3e = sqlite3_bind_blob_wrapper(ts->copyParents, 1,
             CFDataGetBytePtr(issuer), CFDataGetLength(issuer),
index 1b16a3370cc9f40160f9997003649b003a0ea78e..eb918965c88263ad83cd14773b5f8e6367c20a53 100644 (file)
@@ -54,6 +54,9 @@ bool _SecTrustStoreCopyUsageConstraints(SecTrustStoreRef ts, CFDataRef digest, C
 
 bool _SecTrustStoreCopyAll(SecTrustStoreRef ts, CFArrayRef *trustStoreContents, CFErrorRef *error);
 
+bool _SecTrustStoreSetCTExceptions(CFStringRef appID, CFDictionaryRef exceptions, CFErrorRef *error);
+CF_RETURNS_RETAINED CFDictionaryRef _SecTrustStoreCopyCTExceptions(CFStringRef appID, CFErrorRef *error);
+
 __END_DECLS
 
 #endif /* !_SECURITY_SECTRUSTSTORESERVER_H_ */
diff --git a/OSX/sec/securityd/SecTrustStoreServer.m b/OSX/sec/securityd/SecTrustStoreServer.m
new file mode 100644 (file)
index 0000000..27d1ce6
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2018 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 <AssertMacros.h>
+#import <Foundation/Foundation.h>
+#include <stdatomic.h>
+#include <notify.h>
+#include <Security/Security.h>
+#include <Security/SecTrustSettingsPriv.h>
+#include <Security/SecPolicyPriv.h>
+#include <utilities/SecFileLocations.h>
+#include <utilities/SecCFWrappers.h>
+#import "OTATrustUtilities.h"
+#include "SecTrustStoreServer.h"
+
+typedef bool(*exceptionsArrayValueChecker)(id _Nonnull obj);
+
+static bool checkDomainsValuesCompliance(id _Nonnull obj) {
+    if (![obj isKindOfClass:[NSString class]]) {
+        return false;
+    }
+    if (SecDNSIsTLD((__bridge CFStringRef)obj)) {
+        return false;
+    }
+    return true;
+}
+
+static bool checkCAsValuesCompliance(id _Nonnull obj) {
+    if (![obj isKindOfClass:[NSDictionary class]]) {
+        return false;
+    }
+    if (2 != [(NSDictionary*)obj count]) {
+        return false;
+    }
+    if (nil == ((NSDictionary*)obj)[(__bridge NSString*)kSecCTExceptionsHashAlgorithmKey] ||
+        nil == ((NSDictionary*)obj)[(__bridge NSString*)kSecCTExceptionsSPKIHashKey]) {
+        return false;
+    }
+    if (![((NSDictionary*)obj)[(__bridge NSString*)kSecCTExceptionsHashAlgorithmKey] isKindOfClass:[NSString class]] ||
+        ![((NSDictionary*)obj)[(__bridge NSString*)kSecCTExceptionsSPKIHashKey] isKindOfClass:[NSData class]]) {
+        return false;
+    }
+    if (![((NSDictionary*)obj)[(__bridge NSString*)kSecCTExceptionsHashAlgorithmKey] isEqualToString:@"sha256"]) {
+        return false;
+    }
+    return true;
+}
+
+static bool checkExceptionsValues(NSString *key, id value, exceptionsArrayValueChecker checker, CFErrorRef *error) {
+    if (![value isKindOfClass:[NSArray class]]) {
+        return SecError(errSecParam, error, CFSTR("value for %@ is not an array in exceptions dictionary"), key);
+    }
+
+    __block bool result = true;
+    [(NSArray*)value enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
+        if (!checker(obj)) {
+            result = SecError(errSecParam, error, CFSTR("value %lu for %@ is not the expected type"), (unsigned long)idx, key);
+            *stop = true;
+        }
+    }];
+    return result;
+}
+
+static bool checkInputExceptionsAndSetAppExceptions(NSDictionary *inExceptions, NSMutableDictionary *appExceptions, CFErrorRef *error) {
+    __block bool result = true;
+    [inExceptions enumerateKeysAndObjectsUsingBlock:^(NSString *_Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
+        if ([key isEqualToString:(__bridge NSString*)kSecCTExceptionsDomainsKey]) {
+            if (!checkExceptionsValues(key, obj, checkDomainsValuesCompliance, error)) {
+                *stop = YES;
+                result = false;
+                return;
+            }
+        } else if ([key isEqualToString:(__bridge NSString*)kSecCTExceptionsCAsKey]) {
+            if (!checkExceptionsValues(key, obj, checkCAsValuesCompliance, error)) {
+                *stop = YES;
+                result = false;
+                return;
+            }
+        } else {
+            result = SecError(errSecParam, error, CFSTR("unknown key (%@) in exceptions dictionary"), key);
+            *stop = YES;
+            result = false;
+            return;
+        }
+        if ([(NSArray*)obj count] == 0) {
+            [appExceptions removeObjectForKey:key];
+        } else {
+            appExceptions[key] = obj;
+        }
+    }];
+    return result;
+}
+
+static _Atomic bool gHasCTExceptions = false;
+#define kSecCTExceptionsChanged "com.apple.trustd.ct.exceptions-changed"
+
+bool _SecTrustStoreSetCTExceptions(CFStringRef appID, CFDictionaryRef exceptions, CFErrorRef *error)  {
+    if (!SecOTAPKIIsSystemTrustd()) {
+        return SecError(errSecWrPerm, error, CFSTR("Unable to write CT exceptions from user agent"));
+    }
+
+    if (!appID) {
+        return SecError(errSecParam, error, CFSTR("application-identifier required to set exceptions"));
+    }
+
+    @autoreleasepool {
+#if TARGET_OS_IPHONE
+        NSURL *keychainsDirectory = CFBridgingRelease(SecCopyURLForFileInKeychainDirectory(nil));
+#else
+        NSURL *keychainsDirectory = [NSURL fileURLWithFileSystemRepresentation:"/Library/Keychains/" isDirectory:YES relativeToURL:nil];
+#endif
+        NSURL *ctExceptionsFile = [keychainsDirectory URLByAppendingPathComponent:@"CTExceptions.plist"];
+        NSMutableDictionary *allExceptions = [NSMutableDictionary dictionaryWithContentsOfURL:ctExceptionsFile];
+        NSMutableDictionary *appExceptions = NULL;
+        if (allExceptions && allExceptions[(__bridge NSString*)appID]) {
+            appExceptions = [allExceptions[(__bridge NSString*)appID] mutableCopy];
+        } else {
+            appExceptions = [NSMutableDictionary dictionary];
+            if (!allExceptions) {
+                allExceptions =  [NSMutableDictionary dictionary];
+            }
+        }
+
+        if (exceptions && (CFDictionaryGetCount(exceptions) > 0)) {
+            NSDictionary *inExceptions = (__bridge NSDictionary*)exceptions;
+            if (!checkInputExceptionsAndSetAppExceptions(inExceptions, appExceptions, error)) {
+                return false;
+            }
+        }
+
+        if (!exceptions || [appExceptions count] == 0) {
+            [allExceptions removeObjectForKey:(__bridge NSString*)appID];
+        } else {
+            allExceptions[(__bridge NSString*)appID] = appExceptions;
+        }
+
+        NSError *nserror = nil;
+        if (![allExceptions writeToURL:ctExceptionsFile error:&nserror] && error) {
+            *error = CFRetainSafe((__bridge CFErrorRef)nserror);
+            return false;
+        }
+        atomic_store(&gHasCTExceptions, [allExceptions count] != 0);
+        notify_post(kSecCTExceptionsChanged);
+        return true;
+    }
+}
+
+CFDictionaryRef _SecTrustStoreCopyCTExceptions(CFStringRef appID, CFErrorRef *error) {
+    @autoreleasepool {
+        static int notify_token = 0;
+        int check = 0;
+        if (!SecOTAPKIIsSystemTrustd()) {
+            /* Check whether we got a notification. If we didn't, and there are no exceptions set, return NULL.
+             * Otherwise, we need to read from disk */
+            uint32_t check_status = notify_check(notify_token, &check);
+            if (check_status == NOTIFY_STATUS_OK && check == 0 && !atomic_load(&gHasCTExceptions)) {
+                return NULL;
+            }
+        } else {
+            if (!atomic_load(&gHasCTExceptions)) {
+                return NULL;
+            }
+        }
+
+#if TARGET_OS_IPHONE
+        NSURL *keychainsDirectory = CFBridgingRelease(SecCopyURLForFileInKeychainDirectory(nil));
+#else
+        NSURL *keychainsDirectory = [NSURL fileURLWithFileSystemRepresentation:"/Library/Keychains/" isDirectory:YES relativeToURL:nil];
+#endif
+        NSURL *ctExceptionsFile = [keychainsDirectory URLByAppendingPathComponent:@"CTExceptions.plist"];
+        NSDictionary <NSString*,NSDictionary*> *allExceptions = [NSDictionary dictionaryWithContentsOfURL:ctExceptionsFile];
+
+        /* Set us up for not reading the disk when there are never exceptions */
+        static dispatch_once_t onceToken;
+        dispatch_once(&onceToken, ^{
+            atomic_init(&gHasCTExceptions, allExceptions && [allExceptions count] == 0);
+            if (!SecOTAPKIIsSystemTrustd()) {
+                uint32_t status = notify_register_check(kSecCTExceptionsChanged, &notify_token);
+                if (status == NOTIFY_STATUS_OK) {
+                    status = notify_check(notify_token, NULL);
+                }
+                if (status != NOTIFY_STATUS_OK) {
+                    secerror("failed to establish notification for CT exceptions: %ud", status);
+                    notify_cancel(notify_token);
+                    notify_token = 0;
+                }
+            }
+        });
+
+        if (!allExceptions || [allExceptions count] == 0) {
+            atomic_store(&gHasCTExceptions, false);
+            return NULL;
+        }
+
+        /* If the caller specified an appID, return only the exceptions for that appID */
+        if (appID) {
+            return CFBridgingRetain(allExceptions[(__bridge NSString*)appID]);
+        }
+
+        /* Otherwise, combine all the exceptions into one array */
+        NSMutableArray *domainExceptions = [NSMutableArray array];
+        NSMutableArray *caExceptions = [NSMutableArray array];
+        [allExceptions enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull __unused key, NSDictionary * _Nonnull appExceptions,
+                                                           BOOL * _Nonnull __unused stop) {
+            if (appExceptions[(__bridge NSString*)kSecCTExceptionsDomainsKey] &&
+                checkExceptionsValues((__bridge NSString*)kSecCTExceptionsDomainsKey, appExceptions[(__bridge NSString*)kSecCTExceptionsDomainsKey],
+                                      checkDomainsValuesCompliance, error)) {
+                [domainExceptions addObjectsFromArray:appExceptions[(__bridge NSString*)kSecCTExceptionsDomainsKey]];
+            }
+            if (appExceptions[(__bridge NSString*)kSecCTExceptionsCAsKey] &&
+                checkExceptionsValues((__bridge NSString*)kSecCTExceptionsCAsKey, appExceptions[(__bridge NSString*)kSecCTExceptionsCAsKey],
+                                      checkCAsValuesCompliance, error)) {
+                [caExceptions addObjectsFromArray:appExceptions[(__bridge NSString*)kSecCTExceptionsCAsKey]];
+            }
+        }];
+        NSMutableDictionary *exceptions = [NSMutableDictionary dictionaryWithCapacity:2];
+        if ([domainExceptions count] > 0) {
+            exceptions[(__bridge NSString*)kSecCTExceptionsDomainsKey] = domainExceptions;
+        }
+        if ([caExceptions count] > 0) {
+            exceptions[(__bridge NSString*)kSecCTExceptionsCAsKey] = caExceptions;
+        }
+        if ([exceptions count] > 0) {
+            atomic_store(&gHasCTExceptions, true);
+            return CFBridgingRetain(exceptions);
+        }
+        return NULL;
+    }
+}
index cf2f3d4852777ba43380c2160e8aff25e96d1ea2..f0bc9d8a9ee46a916b72ab3d78df9bb01450ed74 100644 (file)
@@ -152,12 +152,15 @@ static struct trustd trustd_spi = {
     .sec_truststore_remove_all              = _SecTrustStoreRemoveAll,
     .sec_trust_evaluate                     = SecTrustServerEvaluate,
     .sec_ota_pki_trust_store_version        = SecOTAPKIGetCurrentTrustStoreVersion,
+    .sec_ota_pki_asset_version              = SecOTAPKIGetCurrentAssetVersion,
     .ota_CopyEscrowCertificates             = SecOTAPKICopyCurrentEscrowCertificates,
     .sec_ota_pki_get_new_asset              = SecOTAPKISignalNewAsset,
     .sec_trust_store_copy_all               = _SecTrustStoreCopyAll,
     .sec_trust_store_copy_usage_constraints = _SecTrustStoreCopyUsageConstraints,
     .sec_ocsp_cache_flush                   = SecOCSPCacheFlush,
-    .sec_tls_analytics_report               = SecTLSAnalyticsReport,
+    .sec_networking_analytics_report        = SecNetworkingAnalyticsReport,
+    .sec_trust_store_set_ct_exceptions      = _SecTrustStoreSetCTExceptions,
+    .sec_trust_store_copy_ct_exceptions     = _SecTrustStoreCopyCTExceptions,
 };
 #endif
 
diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/AppleISTCA8G1.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/AppleISTCA8G1.cer
new file mode 100644 (file)
index 0000000..ebeb137
Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/AppleISTCA8G1.cer differ
index 31aa569227e032cefcbaf275f4df1be41bc31581..1abc857438aaed86dba1334d114497691d57a10b 100644 (file)
@@ -6,11 +6,7 @@
                <key>description</key>
                <string>Alfa-1</string>
                <key>key</key>
-               <data>
-               MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEjWLpGNv/x8wCLlZthIDbTKjc
-               Q8DmAebMeXf1TzPP/7fUxeWV7KJeD5vBWxB0V9wRFasAmYFfcqRD6AMTIW8q
-               eA==
-               </data>
+               <data>MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEjWLpGNv/x8wCLlZthIDbTKjcQ8DmAebMeXf1TzPP/7fUxeWV7KJeD5vBWxB0V9wRFasAmYFfcqRD6AMTIW8qeA==</data>
                <key>operator</key>
                <string>Alfa</string>
        </dict>
                <key>description</key>
                <string>Alfa-2</string>
                <key>key</key>
-               <data>
-               MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEl3VLq871ikjdTDDvr1LhhHKj
-               3kOXWrtQoKJ3twK0BRBEj+rV/UZuZRjDNyiLK2mfMJN9TZdjLJphnYYJcstg
-               SQ==
-               </data>
+               <data>MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEl3VLq871ikjdTDDvr1LhhHKj3kOXWrtQoKJ3twK0BRBEj+rV/UZuZRjDNyiLK2mfMJN9TZdjLJphnYYJcstgSQ==</data>
                <key>operator</key>
                <string>Alfa</string>
        </dict>
                <key>description</key>
                <string>Bravo-1</string>
                <key>key</key>
-               <data>
-               MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEXxLKuBw7sGl0/eRfkX4W7MpH
-               LiK7xB/xkQONXu6cX/IFxMGJ83vbN9NvAbjkiG4D/Pnvrrq9Lb0gWPxovk8u
-               fA==
-               </data>
+               <data>MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEXxLKuBw7sGl0/eRfkX4W7MpHLiK7xB/xkQONXu6cX/IFxMGJ83vbN9NvAbjkiG4D/Pnvrrq9Lb0gWPxovk8ufA==</data>
                <key>operator</key>
                <string>Bravo</string>
        </dict>
                <key>description</key>
                <string>Bravo-2</string>
                <key>key</key>
-               <data>
-               MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpPTIhGHP8AjsFnvCog7JOM43
-               uSTkLbeJup8EN+wfhU2X5YJq8mCXXI7+MHyb/ncEYuJp7wg4B7zxhT5KSmIC
-               sQ==
-               </data>
+               <data>MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpPTIhGHP8AjsFnvCog7JOM43uSTkLbeJup8EN+wfhU2X5YJq8mCXXI7+MHyb/ncEYuJp7wg4B7zxhT5KSmICsQ==</data>
                <key>operator</key>
                <string>Bravo</string>
        </dict>
                <key>description</key>
                <string>Charlie-1</string>
                <key>key</key>
-               <data>
-               MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEp/wmWR+YBWqWiCJy/EE7FBe5
-               L+CvD3b10ua7BWA95yueo0GVLiw5b3qoNZz23CP+ecw5t4+JFsi/LvL45djj
-               CA==
-               </data>
+               <data>MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEp/wmWR+YBWqWiCJy/EE7FBe5L+CvD3b10ua7BWA95yueo0GVLiw5b3qoNZz23CP+ecw5t4+JFsi/LvL45djjCA==</data>
                <key>operator</key>
                <string>Charlie</string>
        </dict>
                <key>description</key>
                <string>Charlie-2</string>
                <key>key</key>
-               <data>
-               MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFQvCj6M6CQKeyxhK2I/u3ZXq
-               YXyf5feihb0Sh4fk78GZisbJyivSHfFRmATdpo7T9IOlXExOZc/ZnGwkPHXS
-               GA==
-               </data>
+               <data>MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFQvCj6M6CQKeyxhK2I/u3ZXqYXyf5feihb0Sh4fk78GZisbJyivSHfFRmATdpo7T9IOlXExOZc/ZnGwkPHXSGA==</data>
                <key>operator</key>
                <string>Charlie</string>
        </dict>
                <key>description</key>
                <string>Delta-1</string>
                <key>key</key>
-               <data>
-               MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEey422SB0m/YU5R4km1+gQuRS
-               HjY7vcTTbUo7Vnehfe2KCW/yY7lJQD4Yv5OJLci8vCWzDAXCprK5ZpbEiQTA
-               5g==
-               </data>
+               <data>MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEey422SB0m/YU5R4km1+gQuRSHjY7vcTTbUo7Vnehfe2KCW/yY7lJQD4Yv5OJLci8vCWzDAXCprK5ZpbEiQTA5g==</data>
                <key>operator</key>
                <string>Delta</string>
        </dict>
                <key>description</key>
                <string>Delta-2</string>
                <key>key</key>
-               <data>
-               MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEkC23vcfErQghrgdlOPDR7PPK
-               +8/7FPyQZy09igHW2+eLx0+8e6VhaO1OTn2YL50NBxW2WN1wAhAxBfSPOFD0
-               wA==
-               </data>
+               <data>MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEkC23vcfErQghrgdlOPDR7PPK+8/7FPyQZy09igHW2+eLx0+8e6VhaO1OTn2YL50NBxW2WN1wAhAxBfSPOFD0wA==</data>
                <key>operator</key>
                <string>Delta</string>
        </dict>
                <key>description</key>
                <string>Echo-1</string>
                <key>key</key>
-               <data>
-               MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEe/QyaSib8V4jhT8vlZTGou9v
-               pCykmsmyQo/3lNI5tGFSiQWaonjQK/reZBXKpG6lwEblDdAazTCQlpmaOee1
-               WA==
-               </data>
+               <data>MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEe/QyaSib8V4jhT8vlZTGou9vpCykmsmyQo/3lNI5tGFSiQWaonjQK/reZBXKpG6lwEblDdAazTCQlpmaOee1WA==</data>
                <key>operator</key>
                <string>Echo</string>
        </dict>
                <key>description</key>
                <string>Echo-2</string>
                <key>key</key>
-               <data>
-               MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEcxkV7jZBkfaV6BKH8fIYR/es
-               6DoVZYOW75zIzB5vgvHl0uOKpdwaDVhU5KZo/2KebpqpSdLCeKqX+poxUFxX
-               OA==
-               </data>
+               <data>MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEcxkV7jZBkfaV6BKH8fIYR/es6DoVZYOW75zIzB5vgvHl0uOKpdwaDVhU5KZo/2KebpqpSdLCeKqX+poxUFxXOA==</data>
                <key>operator</key>
                <string>Echo</string>
        </dict>
                <key>description</key>
                <string>coreos-ct-test log-alpha</string>
                <key>key</key>
-               <data>
-               MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEhcZUhfz61YzwzHJrp4RLcCF/
-               V3j+SZYXGXc69qUlq3twpPnAsRpJE1vzZmvqL0Df1t21LqXQK9EgFcIdu2LL
-               FQ==
-               </data>
+               <data>MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEhcZUhfz61YzwzHJrp4RLcCF/V3j+SZYXGXc69qUlq3twpPnAsRpJE1vzZmvqL0Df1t21LqXQK9EgFcIdu2LLFQ==</data>
                <key>operator</key>
                <string>coreos-ct-test alpha</string>
        </dict>
        <dict>
                <key>description</key>
-               <string>Google's aviator</string>
+               <string>Google&apos;s aviator</string>
                <key>key</key>
-               <data>
-               MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1/TMabLkDpCjiupacAlP7xNi
-               0I1JYP8bQFAHDG1xhtolSY1l4QgNRzRrvSe8liE+NPWHdjGxfx3JhTsN9x8/
-               6Q==
-               </data>
+               <data>MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1/TMabLkDpCjiupacAlP7xNi0I1JYP8bQFAHDG1xhtolSY1l4QgNRzRrvSe8liE+NPWHdjGxfx3JhTsN9x8/6Q==</data>
                <key>operator</key>
                <string>Google</string>
        </dict>
        <dict>
                <key>description</key>
-               <string>Google's pilot</string>
+               <string>Google&apos;s pilot</string>
                <key>key</key>
-               <data>
-               MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfahLEimAoz2t01p3uMziiLOl
-               /fHTDM0YDOhBRuiBARsV4UvxG2LdNgoIGLrtCzWE0J5APC2em4JlvR8EEEFM
-               oA==
-               </data>
+               <data>MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfahLEimAoz2t01p3uMziiLOl/fHTDM0YDOhBRuiBARsV4UvxG2LdNgoIGLrtCzWE0J5APC2em4JlvR8EEEFMoA==</data>
                <key>operator</key>
                <string>Google</string>
        </dict>
        <dict>
                <key>description</key>
-               <string>Digicert's CT log</string>
+               <string>Digicert&apos;s CT log</string>
                <key>key</key>
-               <data>
-               MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAkbFvhu7gkAW6MHSrBlpE1n4
-               +HCFRkC5OLAjgqhkTH+/uzSfSl8ois8ZxAD2NgaTZe1M9akhYlrYkes4JECs
-               6A==
-               </data>
+               <data>MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAkbFvhu7gkAW6MHSrBlpE1n4+HCFRkC5OLAjgqhkTH+/uzSfSl8ois8ZxAD2NgaTZe1M9akhYlrYkes4JECs6A==</data>
                <key>operator</key>
                <string>Digicert</string>
        </dict>
-        <dict>
+       <dict>
                <key>description</key>
                <string>Bravo-3</string>
                <key>key</key>
-               <data>
-               MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAErSVuQLDBj8EWNrGVjb8e1T9d
-               83xvvxi5NeWb9wnWrjbHVwXEkLQGAZBQvpWzJ5yFLqmVu40KSy1NmV0i78II
-               Pg==
-               </data>
+               <data>MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAErSVuQLDBj8EWNrGVjb8e1T9d83xvvxi5NeWb9wnWrjbHVwXEkLQGAZBQvpWzJ5yFLqmVu40KSy1NmV0i78IIPg==</data>
                <key>operator</key>
                <string>Bravo</string>
        </dict>
                <key>description</key>
                <string>Alfa-3</string>
                <key>key</key>
-               <data>
-               MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfLrfEFaVzHLuCk+kjWnQCfrQ
-               YFW73h7tpMEwhfYmL0AKUGVgrgvg3x+D1YSKs/X86dwdg/wyGA3RXU09Mo/M
-               UQ==
-               </data>
+               <data>MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfLrfEFaVzHLuCk+kjWnQCfrQYFW73h7tpMEwhfYmL0AKUGVgrgvg3x+D1YSKs/X86dwdg/wyGA3RXU09Mo/MUQ==</data>
                <key>operator</key>
                <string>Alfa</string>
        </dict>
+       <dict>
+               <key>description</key>
+               <string>flour</string>
+               <key>key</key>
+               <data>MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEgze9Txetn+ojNANjWk8Zrc99TlXCSXgETQAmQDyAZEi0FrIkTYzFL0P6WK/qcb9RmkWNgFOt4CqXrqvVchFdzQ==</data>
+               <key>operator</key>
+               <string>flour</string>
+       </dict>
+       <dict>
+               <key>description</key>
+               <string>sugar</string>
+               <key>key</key>
+               <data>MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE3x/NYxPO1VZFfde5lzkucZIVd403m01F5O3TT8g9qaAEsRUfS9NlspS3pM/ytBtzMFc6oSQj9GFbrvZ68UhG4g==</data>
+               <key>operator</key>
+               <string>sugar</string>
+       </dict>
 </array>
 </plist>
diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/GeoTrustPrimaryCAG2.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/GeoTrustPrimaryCAG2.cer
new file mode 100644 (file)
index 0000000..75dfaf3
Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/GeoTrustPrimaryCAG2.cer differ
diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/GlobalSignRootCAR2.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/GlobalSignRootCAR2.cer
new file mode 100644 (file)
index 0000000..4d93718
Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/GlobalSignRootCAR2.cer differ
diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/GoogleIAG3.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/GoogleIAG3.cer
new file mode 100644 (file)
index 0000000..ffb1a0f
Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/GoogleIAG3.cer differ
diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_apple_ca.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_apple_ca.cer
new file mode 100644 (file)
index 0000000..2cd4beb
Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_apple_ca.cer differ
diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_apple_root.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_apple_root.cer
new file mode 100644 (file)
index 0000000..8a9ff24
Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_apple_root.cer differ
diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_apple_server_after.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_apple_server_after.cer
new file mode 100644 (file)
index 0000000..f91a14e
Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_apple_server_after.cer differ
diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_fail_server.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_fail_server.cer
new file mode 100644 (file)
index 0000000..ca3f1f2
Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_fail_server.cer differ
diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_dn_server.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_dn_server.cer
new file mode 100644 (file)
index 0000000..fde0d03
Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_dn_server.cer differ
diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_dn_server_mismatch.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_dn_server_mismatch.cer
new file mode 100644 (file)
index 0000000..53f7abc
Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_dn_server_mismatch.cer differ
diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_dn_subca.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_dn_subca.cer
new file mode 100644 (file)
index 0000000..4ebf9b0
Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_dn_subca.cer differ
diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_org_server.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_org_server.cer
new file mode 100644 (file)
index 0000000..f178a08
Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_org_server.cer differ
diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_org_server_mismatch.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_org_server_mismatch.cer
new file mode 100644 (file)
index 0000000..bf53339
Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_org_server_mismatch.cer differ
diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_org_subca.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_org_subca.cer
new file mode 100644 (file)
index 0000000..5c4492b
Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_org_subca.cer differ
diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_server.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_server.cer
new file mode 100644 (file)
index 0000000..c195884
Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_server.cer differ
diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_server_scts.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_server_scts.cer
new file mode 100644 (file)
index 0000000..763cd2f
Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_server_scts.cer differ
diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_subca.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_subca.cer
new file mode 100644 (file)
index 0000000..765c5df
Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_subca.cer differ
diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_root.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_root.cer
new file mode 100644 (file)
index 0000000..9764bea
Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_root.cer differ
diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_after.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_after.cer
new file mode 100644 (file)
index 0000000..243e407
Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_after.cer differ
diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_after_scts.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_after_scts.cer
new file mode 100644 (file)
index 0000000..2ba760d
Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_after_scts.cer differ
diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_before.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_before.cer
new file mode 100644 (file)
index 0000000..316d95f
Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_before.cer differ
diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_matching_orgs.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_matching_orgs.cer
new file mode 100644 (file)
index 0000000..30b3cb7
Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_matching_orgs.cer differ
diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_matching_orgs_scts.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_matching_orgs_scts.cer
new file mode 100644 (file)
index 0000000..bb72980
Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_matching_orgs_scts.cer differ
diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_no_orgs.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_no_orgs.cer
new file mode 100644 (file)
index 0000000..15fb0d2
Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_no_orgs.cer differ
diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_nonmatching_orgs.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_nonmatching_orgs.cer
new file mode 100644 (file)
index 0000000..8667b53
Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_nonmatching_orgs.cer differ
diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_partial_orgs.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_partial_orgs.cer
new file mode 100644 (file)
index 0000000..a12aa0b
Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_partial_orgs.cer differ
diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_unconstrained_subca.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_unconstrained_subca.cer
new file mode 100644 (file)
index 0000000..c0eb435
Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_unconstrained_subca.cer differ
diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_user_root.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_user_root.cer
new file mode 100644 (file)
index 0000000..68dde2c
Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_user_root.cer differ
diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_user_server_after.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_user_server_after.cer
new file mode 100644 (file)
index 0000000..f1cd405
Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_user_server_after.cer differ
diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/google.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/google.cer
new file mode 100644 (file)
index 0000000..f0e0e6b
Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/google.cer differ
diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/livability.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/livability.cer
new file mode 100644 (file)
index 0000000..b6812ae
Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/livability.cer differ
diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/precert.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/precert.cer
new file mode 100644 (file)
index 0000000..ffaac60
Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/precert.cer differ
diff --git a/OSX/shared_regressions/si-82-sectrust-ct.h b/OSX/shared_regressions/si-82-sectrust-ct.h
new file mode 100644 (file)
index 0000000..bc00047
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ *  si-82-sectrust-ct.h
+ *  Security
+ *
+ *  Copyright (c) 2018 Apple Inc. All Rights Reserved.
+ *
+ */
+
+#ifndef si_82_sectrust_ct_h
+#define si_82_sectrust_ct_h
+
+uint8_t _system_after_leafSPKI[] ={
+    0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,
+    0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,
+    0x00,0xBE,0xE1,0x27,0x10,0xB5,0xF8,0x42,0x7D,0xC0,0x4B,0xDD,0x1F,0xEC,0x30,0x36,
+    0x67,0xCD,0x2E,0xD0,0x98,0x2B,0x38,0xC8,0x8D,0xC9,0x30,0x8D,0xF3,0x2D,0x0D,0x12,
+    0x38,0x54,0x2B,0xFF,0x1D,0x0F,0x85,0x95,0xDD,0x8A,0xB2,0xFB,0x99,0x1E,0xFF,0x76,
+    0x45,0x1D,0x97,0x8A,0xE0,0xE9,0x4E,0xB8,0x80,0x4D,0x28,0x74,0x80,0x68,0x97,0xBD,
+    0xB5,0x3D,0xF4,0xA3,0x00,0x20,0x02,0xFC,0x7A,0x4E,0x24,0x3A,0x01,0xDB,0x4A,0x06,
+    0x8D,0x63,0x7B,0xA8,0xD9,0xF8,0x2C,0xE8,0x81,0x5B,0xA5,0x0D,0x86,0xCA,0xE2,0x8C,
+    0x5A,0xE1,0x02,0x83,0x84,0xAA,0xD4,0x7D,0xFA,0xF3,0x13,0x48,0x29,0x43,0xE0,0x55,
+    0x54,0x39,0x4D,0x60,0xA8,0x50,0xBE,0xE1,0x7C,0x04,0x04,0x02,0xE3,0xAB,0x2A,0x11,
+    0xEE,0x47,0xA4,0x52,0xAF,0x1C,0xDC,0x73,0xEF,0xA5,0x1D,0xD9,0xD8,0x8A,0x00,0xF6,
+    0x81,0x9B,0xD9,0xB3,0x9F,0x1D,0x43,0xFD,0x97,0xE5,0x30,0xB5,0x55,0x02,0x42,0x30,
+    0x80,0xE2,0xB9,0xEA,0x4E,0xA6,0x02,0x35,0xDC,0xE5,0x9C,0x23,0x6C,0xF1,0xFF,0x49,
+    0x43,0x8D,0xE5,0x93,0xDA,0x31,0x7D,0x52,0x49,0xF9,0x7E,0x74,0xF5,0x68,0xC1,0x14,
+    0xB5,0x29,0x55,0xA2,0x79,0xEA,0xF5,0xE1,0x21,0xE1,0x31,0x8C,0xC6,0x51,0xCA,0xBB,
+    0x2C,0x16,0x08,0x6A,0xA0,0xEC,0xCF,0x65,0x93,0x21,0x45,0x87,0x2B,0x50,0xC8,0xA8,
+    0x6D,0xEF,0x49,0x7C,0x0A,0xAE,0xB0,0x3E,0xC1,0xFC,0xB4,0x35,0x0B,0xEE,0xAF,0x21,
+    0x30,0x59,0x73,0x86,0x09,0x4F,0xA9,0xAA,0x72,0xF5,0x9D,0x28,0xAC,0xDA,0x51,0x56,
+    0x1D,0x02,0x03,0x01,0x00,0x01,
+};
+
+uint8_t _system_rootSPKI[] ={
+    0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,
+    0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,
+    0x00,0x97,0xC9,0xDC,0xBB,0x2C,0x65,0x53,0xE1,0xE2,0x2C,0xF6,0xA4,0x82,0xF7,0x64,
+    0x44,0xD9,0xF8,0xFC,0xE0,0x3E,0x91,0xAE,0x72,0x6A,0x44,0x7D,0x11,0x49,0x29,0x53,
+    0x72,0xB9,0x81,0x63,0x4D,0x86,0xFF,0x4A,0xDC,0xD7,0xFB,0x0E,0xE5,0x26,0xC5,0xD6,
+    0x6B,0xFA,0xC2,0xC1,0xD3,0x3F,0x14,0x6F,0x30,0x9E,0x5F,0xFC,0xAD,0x4E,0xB3,0x30,
+    0x8E,0xF5,0x61,0x24,0x0A,0xC4,0xF7,0x76,0x4D,0xAA,0xA2,0x52,0xFF,0xB2,0x99,0xA3,
+    0x7E,0x46,0xCF,0x63,0x21,0xCB,0xA9,0x79,0xDA,0x32,0xEF,0x25,0x12,0x90,0x05,0xE7,
+    0x77,0x96,0xC9,0xE1,0xC6,0x92,0x6D,0x32,0xB6,0xDE,0xF4,0xF5,0xFE,0xB4,0xF1,0xE0,
+    0x76,0xEB,0xD9,0x6C,0x70,0xF6,0x36,0x35,0x1D,0xA0,0x72,0x0C,0xE0,0xC1,0xD0,0x16,
+    0xF8,0x24,0x33,0x3C,0xF1,0x4B,0xA6,0x9F,0x3D,0x52,0x29,0x81,0x17,0xF8,0xA5,0x57,
+    0x54,0x33,0xA4,0xD0,0xC1,0xE9,0x31,0x3C,0x2C,0x63,0x0E,0x8E,0xE2,0xF9,0xFC,0xCC,
+    0x9D,0xD8,0x7D,0xB4,0x92,0x80,0x11,0x0A,0xDC,0x52,0xAE,0x00,0x98,0x93,0xB6,0xF8,
+    0xA1,0x76,0x1B,0x81,0x54,0x13,0xC7,0xA6,0x60,0x7A,0x1C,0x6F,0x21,0x51,0xC4,0x9D,
+    0x69,0x17,0xC4,0x8E,0x71,0x2C,0x32,0x30,0x3A,0x6D,0xB9,0x95,0x72,0x01,0xCC,0x3C,
+    0xEB,0x3C,0x37,0x1A,0x04,0x70,0xD8,0xBF,0x6D,0xA3,0x65,0x6F,0x9C,0xFD,0x8F,0x0A,
+    0x08,0x5E,0xA4,0x61,0xD5,0x00,0x48,0xCF,0x03,0xF7,0xB0,0x36,0x4C,0x5E,0xD5,0xAB,
+    0xC1,0xE9,0xA7,0x05,0xB3,0x8A,0xC9,0xDD,0x17,0xC1,0x41,0xAA,0x6E,0xFE,0xF6,0x4C,
+    0xF7,0x02,0x03,0x01,0x00,0x01,
+};
+
+#endif /* si_82_sectrust_ct_h */
index 66867cde7f4c06994293c1963122c29900c5876f..355148964c06a9c8bb965ec63a0925e3f09ef36f 100644 (file)
@@ -6,15 +6,26 @@
  *
  */
 
+#include <AssertMacros.h>
 #include <CoreFoundation/CoreFoundation.h>
 #include <Security/SecCertificatePriv.h>
 #include <Security/SecTrustPriv.h>
-#include <Security/SecPolicy.h>
+#include <Security/SecPolicyPriv.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <utilities/SecCFWrappers.h>
+#include <Security/SecTrustSettings.h>
+#include <Security/SecTrustSettingsPriv.h>
+#include <Security/SecFramework.h>
+
+#if TARGET_OS_IPHONE
+#include <Security/SecTrustStore.h>
+#else
+#include <Security/SecKeychain.h>
+#endif
 
 #include "shared_regressions.h"
+#include "si-82-sectrust-ct.h"
 
 //define this if you want to print clock time of SecTrustEvaluate call.
 //define PRINT_SECTRUST_EVALUATE_TIME
@@ -48,7 +59,10 @@ static void test_ct_trust(CFArrayRef certs, CFArrayRef scts, CFTypeRef ocsprespo
     }
 
     if(scts) {
-        ok_status(SecTrustSetSignedCertificateTimestamps(trust, scts), "set standalone SCTs");;
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunguarded-availability-new"
+        ok_status(SecTrustSetSignedCertificateTimestamps(trust, scts), "set standalone SCTs");
+#pragma clang diagnostic pop
     }
 
     if(trustedLogs) {
@@ -121,6 +135,22 @@ CFDataRef CFDataCreateFromResource(NSString *name)
     return (__bridge_retained CFDataRef) binData;
 }
 
+static CFArrayRef CTTestsCopyTrustedLogs(void) {
+    CFArrayRef trustedLogs=NULL;
+    CFURLRef trustedLogsURL=NULL;
+
+    trustedLogsURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(),
+                                             CFSTR("CTlogs"),
+                                             CFSTR("plist"),
+                                             CFSTR("si-82-sectrust-ct-data"));
+    isnt(trustedLogsURL, NULL, "trustedLogsURL");
+    trustedLogs = (CFArrayRef) CFPropertyListReadFromFile(trustedLogsURL);
+    isnt(trustedLogs, NULL, "trustedLogs");
+
+    CFReleaseNull(trustedLogsURL);
+    return trustedLogs;
+}
+
 static void tests()
 {
     SecCertificateRef certA=NULL, certD=NULL, certF=NULL, certCA_alpha=NULL, certCA_beta=NULL;
@@ -138,16 +168,7 @@ static void tests()
     CFDataRef invalid_ocsp=NULL;
     CFDataRef bad_hash_ocsp=NULL;
 
-    CFArrayRef trustedLogs=NULL;
-    CFURLRef trustedLogsURL=NULL;
-
-    trustedLogsURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(),
-                                             CFSTR("CTlogs"),
-                                             CFSTR("plist"),
-                                             CFSTR("si-82-sectrust-ct-data"));
-    isnt(trustedLogsURL, NULL, "trustedLogsURL");
-    trustedLogs = (CFArrayRef) CFPropertyListReadFromFile(trustedLogsURL);
-    isnt(trustedLogs, NULL, "trustedLogs");
+    CFArrayRef trustedLogs= CTTestsCopyTrustedLogs();
 
     isnt(certCA_alpha = SecCertificateCreateFromResource(@"CA_alpha"), NULL, "create ca-alpha cert");
     isnt(certCA_beta = SecCertificateCreateFromResource(@"CA_beta"), NULL, "create ca-beta cert");
@@ -313,7 +334,6 @@ static void tests()
     CFReleaseSafe(whitelist_00008013_issuer);
     CFReleaseSafe(whitelist_5555bc4f_issuer);
     CFReleaseSafe(whitelist_fff9b5f6_issuer);
-    CFReleaseSafe(trustedLogsURL);
     CFReleaseSafe(trustedLogs);
     CFReleaseSafe(valid_ocsp);
     CFReleaseSafe(invalid_ocsp);
@@ -324,12 +344,1093 @@ static void tests()
 
 }
 
+static void test_sct_serialization(void) {
+    SecCertificateRef certA = NULL, certCA_alpha = NULL, certCA_beta = NULL;
+    CFArrayRef trustedLogs= CTTestsCopyTrustedLogs();
+    SecTrustRef trust = NULL, deserializedTrust = NULL;
+    SecPolicyRef policy = SecPolicyCreateSSL(true, NULL);
+    NSData *proofA_1 = NULL, *proofA_2 = NULL;
+    NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:447450000.0]; // March 7, 2015 at 11:40:00 AM PST
+    CFErrorRef error = NULL;
+
+    isnt(certA = SecCertificateCreateFromResource(@"serverA"), NULL, "create certA");
+    isnt(certCA_alpha = SecCertificateCreateFromResource(@"CA_alpha"), NULL, "create ca-alpha cert");
+    isnt(certCA_beta = SecCertificateCreateFromResource(@"CA_beta"), NULL, "create ca-beta cert");
+
+    NSArray *anchors = @[ (__bridge id)certCA_alpha, (__bridge id)certCA_beta ];
+
+    isnt(proofA_1 = CFBridgingRelease(CFDataCreateFromResource(@"serverA_proof_Alfa_3")), NULL, "creat proofA_1");
+    isnt(proofA_2 = CFBridgingRelease(CFDataCreateFromResource(@"serverA_proof_Bravo_3")), NULL, "creat proofA_2");
+    NSArray *scts = @[ proofA_1, proofA_2 ];
+
+    /* Make a SecTrustRef and then serialize it */
+    ok_status(SecTrustCreateWithCertificates(certA, policy, &trust), "failed to create trust object");
+    ok_status(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), "failed to set anchors");
+    ok_status(SecTrustSetTrustedLogs(trust, trustedLogs), "failed to set trusted logs");
+    ok_status(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), "failed to set verify date");
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunguarded-availability-new"
+    ok_status(SecTrustSetSignedCertificateTimestamps(trust, (__bridge CFArrayRef)scts), "failed to set SCTS");
+#pragma clang diagnostic pop
+
+    NSData *serializedTrust = CFBridgingRelease(SecTrustSerialize(trust, &error));
+    isnt(serializedTrust, NULL, "failed to serialize trust: %@", error);
+
+    /* Evaluate it to make sure it's CT */
+    ok(SecTrustEvaluateWithError(trust, &error), "failed to evaluate trust: %@", error);
+    NSDictionary *results = CFBridgingRelease(SecTrustCopyResult(trust));
+    isnt(results[(__bridge NSString*)kSecTrustCertificateTransparency], NULL, "failed get CT result");
+    ok([results[(__bridge NSString*)kSecTrustCertificateTransparency] boolValue], "CT failed");
+
+    /* Make a new trust object by deserializing the previous trust object */
+    ok(deserializedTrust = SecTrustDeserialize((__bridge CFDataRef)serializedTrust, &error), "failed to deserialize trust: %@", error);
+
+    /* Evaluate the new one to make sure it's CT (because the SCTs were serialized) */
+    ok(SecTrustEvaluateWithError(deserializedTrust, &error), "failed to evaluate trust: %@", error);
+    results = CFBridgingRelease(SecTrustCopyResult(deserializedTrust));
+    isnt(results[(__bridge NSString*)kSecTrustCertificateTransparency], NULL, "failed get CT result");
+    ok([results[(__bridge NSString*)kSecTrustCertificateTransparency] boolValue], "CT failed");
+
+    CFReleaseNull(certA);
+    CFReleaseNull(certCA_alpha);
+    CFReleaseNull(certCA_beta);
+    CFReleaseNull(trustedLogs);
+    CFReleaseNull(policy);
+    CFReleaseNull(trust);
+    CFReleaseNull(deserializedTrust);
+    CFReleaseNull(error);
+}
+
+static void testSetCTExceptions(void) {
+    CFErrorRef error = NULL;
+    const CFStringRef SecurityTestsAppID = CFSTR("com.apple.security.regressions");
+    const CFStringRef AnotherAppID = CFSTR("com.apple.security.not-this-one");
+    CFDictionaryRef copiedExceptions = NULL;
+
+    /* Verify no exceptions set */
+    is(copiedExceptions = SecTrustStoreCopyCTExceptions(NULL, NULL), NULL, "no exceptions set");
+    if (copiedExceptions) {
+        /* If we're starting out with exceptions set, a lot of the following will also fail, so just skip them */
+        CFReleaseNull(copiedExceptions);
+        return;
+    }
+
+    /* Set exceptions with specified AppID */
+    NSDictionary *exceptions1 = @{
+        (__bridge NSString*)kSecCTExceptionsDomainsKey: @[@"test.apple.com", @".test.apple.com"],
+    };
+    ok(SecTrustStoreSetCTExceptions(SecurityTestsAppID, (__bridge CFDictionaryRef)exceptions1, &error),
+       "failed to set exceptions for SecurityTests: %@", error);
+
+    /* Copy all exceptions (with only one set) */
+    ok(copiedExceptions = SecTrustStoreCopyCTExceptions(NULL, &error),
+       "failed to copy all exceptions: %@", error);
+    ok([exceptions1 isEqualToDictionary:(__bridge NSDictionary*)copiedExceptions],
+       "got the wrong exceptions back");
+    CFReleaseNull(copiedExceptions);
+
+    /* Copy this app's exceptions */
+    ok(copiedExceptions = SecTrustStoreCopyCTExceptions(SecurityTestsAppID, &error),
+       "failed to copy SecurityTests' exceptions: %@", error);
+    ok([exceptions1 isEqualToDictionary:(__bridge NSDictionary*)copiedExceptions],
+       "got the wrong exceptions back");
+    CFReleaseNull(copiedExceptions);
+
+    /* Copy a different app's exceptions */
+    is(copiedExceptions = SecTrustStoreCopyCTExceptions(AnotherAppID, &error), NULL,
+       "failed to copy different app's exceptions: %@", error);
+    CFReleaseNull(copiedExceptions);
+
+    /* Set different exceptions with implied AppID */
+    CFDataRef leafHash = SecSHA256DigestCreate(NULL, _system_after_leafSPKI, sizeof(_system_after_leafSPKI));
+    NSDictionary *leafException = @{ (__bridge NSString*)kSecCTExceptionsHashAlgorithmKey : @"sha256",
+                                     (__bridge NSString*)kSecCTExceptionsSPKIHashKey : (__bridge NSData*)leafHash,
+    };
+
+    NSDictionary *exceptions2 = @{
+        (__bridge NSString*)kSecCTExceptionsDomainsKey: @[@".test.apple.com"],
+        (__bridge NSString*)kSecCTExceptionsCAsKey : @[ leafException ]
+    };
+    ok(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)exceptions2, &error),
+       "failed to set exceptions for this app: %@", error);
+
+    /* Ensure exceptions are replaced for SecurityTests */
+    ok(copiedExceptions = SecTrustStoreCopyCTExceptions(SecurityTestsAppID, &error),
+       "failed to copy SecurityTests' exceptions: %@", error);
+    ok([exceptions2 isEqualToDictionary:(__bridge NSDictionary*)copiedExceptions],
+       "got the wrong exceptions back");
+    CFReleaseNull(copiedExceptions);
+
+    /* Set exceptions with a different AppID */
+    CFDataRef rootHash = SecSHA256DigestCreate(NULL, _system_rootSPKI, sizeof(_system_rootSPKI));
+    NSDictionary *rootExceptions =  @{ (__bridge NSString*)kSecCTExceptionsHashAlgorithmKey : @"sha256",
+                                       (__bridge NSString*)kSecCTExceptionsSPKIHashKey : (__bridge NSData*)rootHash,
+    };
+    NSDictionary *exceptions3 = @{
+        (__bridge NSString*)kSecCTExceptionsCAsKey : @[ rootExceptions ]
+    };
+    ok(SecTrustStoreSetCTExceptions(AnotherAppID, (__bridge CFDictionaryRef)exceptions3, &error),
+       "failed to set exceptions for different app: %@", error);
+
+    /* Copy only one of the app's exceptions */
+    ok(copiedExceptions = SecTrustStoreCopyCTExceptions(SecurityTestsAppID, &error),
+       "failed to copy SecurityTests' exceptions: %@", error);
+    ok([exceptions2 isEqualToDictionary:(__bridge NSDictionary*)copiedExceptions],
+       "got the wrong exceptions back");
+    CFReleaseNull(copiedExceptions);
+
+    /* Set empty exceptions */
+    NSDictionary *empty = @{};
+    ok(SecTrustStoreSetCTExceptions(SecurityTestsAppID, (__bridge CFDictionaryRef)empty, &error),
+       "failed to set empty exceptions");
+
+    /* Copy exceptiosn to ensure no change */
+    ok(copiedExceptions = SecTrustStoreCopyCTExceptions(SecurityTestsAppID, &error),
+       "failed to copy SecurityTests' exceptions: %@", error);
+    ok([exceptions2 isEqualToDictionary:(__bridge NSDictionary*)copiedExceptions],
+       "got the wrong exceptions back");
+    CFReleaseNull(copiedExceptions);
+
+    /* Copy all exceptions */
+    ok(copiedExceptions = SecTrustStoreCopyCTExceptions(NULL, &error),
+       "failed to copy all exceptions: %@", error);
+    is(CFDictionaryGetCount(copiedExceptions), 2, "Got the wrong number of all exceptions");
+    NSDictionary *nsCopiedExceptions = CFBridgingRelease(copiedExceptions);
+    NSArray *domainExceptions = nsCopiedExceptions[(__bridge NSString*)kSecCTExceptionsDomainsKey];
+    NSArray *caExceptions = nsCopiedExceptions[(__bridge NSString*)kSecCTExceptionsCAsKey];
+    ok(domainExceptions && caExceptions, "Got both domain and CA exceptions");
+    ok([domainExceptions count] == 1, "Got 1 domain exception");
+    ok([caExceptions count] == 2, "Got 2 CA exceptions");
+    ok([domainExceptions[0] isEqualToString:@".test.apple.com"], "domain exception is .test.apple.com");
+    ok([caExceptions containsObject:leafException] && [caExceptions containsObject:rootExceptions], "got expected leaf and root CA exceptions");
+
+    /* Reset other app's exceptions */
+    ok(SecTrustStoreSetCTExceptions(AnotherAppID, NULL, &error),
+       "failed to reset exceptions for different app: %@", error);
+    ok(copiedExceptions = SecTrustStoreCopyCTExceptions(NULL, &error),
+       "failed to copy all exceptions: %@", error);
+    ok([exceptions2 isEqualToDictionary:(__bridge NSDictionary*)copiedExceptions],
+       "got the wrong exceptions back");
+    CFReleaseNull(copiedExceptions);
+
+#define check_errSecParam \
+    if (error) { \
+        is(CFErrorGetCode(error), errSecParam, "bad input produced unxpected error code: %ld", (long)CFErrorGetCode(error)); \
+    } else { \
+        fail("expected failure to set NULL exceptions"); \
+    }
+
+    /* Set exceptions with bad inputs */
+    NSDictionary *badExceptions = @{
+       (__bridge NSString*)kSecCTExceptionsDomainsKey: @[@"test.apple.com", @".test.apple.com"],
+       @"not a key": @"not a value",
+    };
+    is(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)badExceptions, &error), false,
+       "set exceptions with unknown key");
+    check_errSecParam
+
+    badExceptions = @{ (__bridge NSString*)kSecCTExceptionsDomainsKey:@"test.apple.com" };
+    is(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)badExceptions, &error), false,
+       "set exceptions with bad value");
+    check_errSecParam
+
+    badExceptions = @{ (__bridge NSString*)kSecCTExceptionsDomainsKey: @[ @{} ] };
+    is(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)badExceptions, &error), false,
+       "set exceptions with bad array value");
+    check_errSecParam
+
+    badExceptions = @{ (__bridge NSString*)kSecCTExceptionsCAsKey: @[ @"test.apple.com" ] };
+    is(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)badExceptions, &error), false,
+       "set exceptions with bad array value");
+    check_errSecParam
+
+    badExceptions = @{ (__bridge NSString*)kSecCTExceptionsCAsKey: @[ @{
+      (__bridge NSString*)kSecCTExceptionsHashAlgorithmKey : @"sha256",
+      @"not-a-key" : (__bridge NSData*)rootHash,
+    }] };
+    is(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)badExceptions, &error), false,
+       "set exceptions with bad CA dictionary value");
+    check_errSecParam
+
+    badExceptions = @{ (__bridge NSString*)kSecCTExceptionsCAsKey: @[ @{
+      (__bridge NSString*)kSecCTExceptionsHashAlgorithmKey : @"sha256",
+    }] };
+    is(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)badExceptions, &error), false,
+       "set exceptions with bad CA dictionary value");
+    check_errSecParam
+
+    badExceptions = @{ (__bridge NSString*)kSecCTExceptionsCAsKey: @[ @{
+      (__bridge NSString*)kSecCTExceptionsHashAlgorithmKey : @"sha256",
+      (__bridge NSString*)kSecCTExceptionsSPKIHashKey : (__bridge NSData*)rootHash,
+      @"not-a-key":@"not-a-value"
+    }] };
+    is(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)badExceptions, &error), false,
+       "set exceptions with bad CA dictionary value");
+    check_errSecParam
+
+    badExceptions = @{ (__bridge NSString*)kSecCTExceptionsDomainsKey: @[ @".com" ] };
+    is(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)badExceptions, &error), false,
+       "set exceptions with TLD value");
+    check_errSecParam
+#undef check_errSecParam
+
+    /* Remove exceptions using empty arrays */
+    NSDictionary *emptyArrays = @{
+        (__bridge NSString*)kSecCTExceptionsDomainsKey: @[],
+        (__bridge NSString*)kSecCTExceptionsCAsKey : @[]
+    };
+    ok(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)emptyArrays, &error),
+       "failed to set empty array exceptions for this app: %@", error);
+    is(copiedExceptions = SecTrustStoreCopyCTExceptions(NULL, NULL), NULL, "no exceptions set");
+
+    CFReleaseNull(leafHash);
+    CFReleaseNull(rootHash);
+}
+
+static void setup_for_user_trust(NSArray *in_certs, NSArray **deleteMeCertificates) {
+#if TARGET_OS_OSX
+    /* Since we're putting trust settings in the admin domain,
+     * we need to add the certs to the system keychain. */
+    SecKeychainRef kcRef = NULL;
+    CFArrayRef certRef = NULL;
+    NSDictionary *attrs = nil;
+    NSMutableArray *persistenRefs = nil;
+
+    SecKeychainOpen("/Library/Keychains/System.keychain", &kcRef);
+    if (!kcRef) {
+        return;
+    }
+
+    persistenRefs = [[NSMutableArray alloc] init];
+
+    for (id cert in in_certs) {
+        attrs = @{(__bridge NSString*)kSecValueRef: cert,
+                  (__bridge NSString*)kSecUseKeychain: (__bridge id)kcRef,
+                  (__bridge NSString*)kSecReturnPersistentRef: @YES};
+        if (SecItemAdd((CFDictionaryRef)attrs, (void *)&certRef) == 0)
+            [persistenRefs addObject:(__bridge NSArray *)certRef];
+        CFReleaseNull(certRef);
+    }
+
+    CFReleaseNull(kcRef);
+    *deleteMeCertificates = persistenRefs;
+#endif
+}
+
+static void cleanup_keychain(NSArray *deleteMeCertificates) {
+#if TARGET_OS_OSX
+    if (!deleteMeCertificates) {
+        return;
+    }
+
+    [deleteMeCertificates enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
+        SecItemDelete((CFDictionaryRef)@{ (__bridge NSString*)kSecValuePersistentRef: [obj objectAtIndex:0]});
+    }];
+#endif
+}
+
+static bool set_trust_settings_for_cert(SecCertificateRef cert) {
+    bool ok = false;
+    NSDictionary *settings = nil;
+    if (!SecCertificateIsSelfSignedCA(cert)) {
+        settings = @{ (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustAsRoot)};
+    }
+#if TARGET_OS_IPHONE
+    require_noerr_string(SecTrustStoreSetTrustSettings(SecTrustStoreForDomain(kSecTrustStoreDomainUser), cert,
+                                                       (__bridge CFDictionaryRef)settings),
+                         errOut, "failed to set trust settings");
+#else
+    require_noerr_string(SecTrustSettingsSetTrustSettings(cert, kSecTrustSettingsDomainAdmin,
+                                                          (__bridge CFDictionaryRef)settings),
+                         errOut, "failed to set trust settings");
+    usleep(20000);
+#endif
+    ok = true;
+errOut:
+    return ok;
+}
+
+static bool remove_trust_settings_for_cert(SecCertificateRef cert) {
+    bool ok = false;
+#if TARGET_OS_IPHONE
+    require_noerr_string(SecTrustStoreRemoveCertificate(SecTrustStoreForDomain(kSecTrustStoreDomainUser), cert),
+                         errOut, "failed to remove trust settings");
+#else
+    require_noerr_string(SecTrustSettingsRemoveTrustSettings(cert, kSecTrustSettingsDomainAdmin),
+                         errOut, "failed to remove trust settings");
+#endif
+    ok = true;
+errOut:
+    return ok;
+}
+
+static void test_enforcement(void) {
+    SecCertificateRef system_root = NULL, user_root = NULL;
+    SecCertificateRef system_server_before = NULL, system_server_after = NULL, system_server_after_with_CT = NULL;
+    SecCertificateRef user_server_after = NULL;
+    CFArrayRef trustedLogs = CTTestsCopyTrustedLogs();
+    SecTrustRef trust = NULL;
+    SecPolicyRef policy = SecPolicyCreateSSL(true, CFSTR("ct.test.apple.com"));
+    NSArray *anchors = nil, *keychain_certs = nil;
+    NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:562340800.0]; // October 27, 2018 at 6:46:40 AM PDT
+    CFErrorRef error = nil;
+    CFDataRef exceptions = nil;
+
+    require_action(system_root = SecCertificateCreateFromResource(@"enforcement_system_root"),
+                   errOut, fail("failed to create system root"));
+    require_action(user_root = SecCertificateCreateFromResource(@"enforcement_user_root"),
+                   errOut, fail("failed to create user root"));
+    require_action(system_server_before = SecCertificateCreateFromResource(@"enforcement_system_server_before"),
+                   errOut, fail("failed to create system server cert issued before flag day"));
+    require_action(system_server_after = SecCertificateCreateFromResource(@"enforcement_system_server_after"),
+                   errOut, fail("failed to create system server cert issued after flag day"));
+    require_action(system_server_after_with_CT = SecCertificateCreateFromResource(@"enforcement_system_server_after_scts"),
+                   errOut, fail("failed to create system server cert issued after flag day with SCTs"));
+    require_action(user_server_after = SecCertificateCreateFromResource(@"enforcement_user_server_after"),
+                   errOut, fail("failed to create user server cert issued after flag day"));
+
+    /* set up the user and system roots to be used with trust settings */
+    setup_for_user_trust(@[(__bridge id)system_root, (__bridge id)user_root, (__bridge id)system_server_after],
+                         &keychain_certs);
+    anchors = @[ (__bridge id)system_root ];
+    require_noerr_action(SecTrustCreateWithCertificates(system_server_after, policy, &trust), errOut, fail("failed to create trust"));
+    require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), errOut, fail("failed to set anchors"));
+    require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date"));
+
+#if 0 // Disable this test until we can mock MobileAsset and force asset to be out-of-date
+    // Out-of-date asset, test system cert after date without CT passes
+    ok(SecTrustEvaluateWithError(trust, NULL), "system post-flag-date non-CT cert failed with out-of-date asset");
+#endif
+
+    // test system cert after date without CT fails
+    require_noerr_action(SecTrustSetTrustedLogs(trust, trustedLogs), errOut, fail("failed to set trusted logs")); // set trusted logs to trigger enforcing behavior
+    is(SecTrustEvaluateWithError(trust, &error), false, "system post-flag-date non-CT cert with in-date asset succeeded");
+    if (error) {
+        is(CFErrorGetCode(error), errSecVerifyActionFailed, "got wrong error code for non-ct cert, got %ld, expected %d",
+           (long)CFErrorGetCode(error), errSecVerifyActionFailed);
+    } else {
+        fail("expected trust evaluation to fail and it did not.");
+    }
+
+    // test exceptions for failing cert passes
+    exceptions = SecTrustCopyExceptions(trust);
+    ok(SecTrustSetExceptions(trust, exceptions), "failed to set exceptions for failing non-CT cert");
+    CFReleaseNull(exceptions);
+    ok(SecTrustEvaluateWithError(trust, NULL), "system post-flag-date non-CT cert failed with exceptions set");
+    SecTrustSetExceptions(trust, NULL);
+
+    // test system cert + enterprise anchor after date without CT fails
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnonnull" /* required because of <rdar://32627101> */
+    require_noerr_action(SecTrustSetAnchorCertificates(trust, NULL), errOut, fail("failed to unset anchors"));
+#pragma clang diagnostic pop
+    require_action(set_trust_settings_for_cert(system_root), errOut, fail("failed to set trust settings for system_root"));
+    is(SecTrustEvaluateWithError(trust, &error), false, "system post-flag date non-CT cert with enterprise root trust succeeded");
+    if (error) {
+        is(CFErrorGetCode(error), errSecVerifyActionFailed, "got wrong error code for non-ct cert, got %ld, expected %d",
+           (long)CFErrorGetCode(error), errSecVerifyActionFailed);
+    } else {
+        fail("expected trust evaluation to fail and it did not.");
+    }
+    require_action(remove_trust_settings_for_cert(system_root), errOut, fail("failed to remove trust settings for system_root"));
+
+    // test app anchor for failing cert passes
+    anchors = @[ (__bridge id)system_server_after ];
+    require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), errOut, fail("failed to set anchors"));
+    ok(SecTrustEvaluateWithError(trust, NULL), "system post-flag-date non-CT cert failed with server cert app anchor");
+
+    // test trust settings for failing cert passes
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnonnull" /* required because of <rdar://32627101> */
+    require_noerr_action(SecTrustSetAnchorCertificates(trust, NULL), errOut, fail("failed to remove anchors"));
+#pragma clang diagnostic pop
+    require_action(set_trust_settings_for_cert(system_server_after), errOut, fail("failed to set trust settings for system_server_after"));
+    ok(SecTrustEvaluateWithError(trust, NULL), "system post-flag-date non-CT cert failed with server cert enterprise anchor");
+    require_action(remove_trust_settings_for_cert(system_server_after), errOut, fail("failed to remove trust settings for system_server_after"));
+
+    // EAP, test system cert after date without CT passes
+    anchors = @[ (__bridge id)system_root ];
+    require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), errOut, fail("failed to set anchors"));
+    CFReleaseNull(policy);
+    policy = SecPolicyCreateEAP(true, NULL);
+    require_noerr_action(SecTrustSetPolicies(trust, policy), errOut, fail("failed to set EAP policy"));
+    ok(SecTrustEvaluateWithError(trust, NULL), "system post-flag-date non-CT cert failed with EAP cert");
+
+    // Test pinning policy name
+    CFReleaseNull(policy);
+    policy = SecPolicyCreateSSL(true, CFSTR("ct.test.apple.com"));
+    require_noerr_action(SecTrustSetPolicies(trust, policy), errOut, fail("failed to set SSL policy"));
+    require_noerr_action(SecTrustSetPinningPolicyName(trust, CFSTR("a-policy-name")), errOut, fail("failed to set policy name"));
+    ok(SecTrustEvaluateWithError(trust, NULL), "system post-flag-date non-CT cert failed with pinning policy name");
+    CFReleaseNull(trust);
+
+    // test system cert after date with CT passes
+    require_noerr_action(SecTrustCreateWithCertificates(system_server_after_with_CT, policy, &trust), errOut, fail("failed to create trust"));
+    require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), errOut, fail("failed to set anchors"));
+    require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date"));
+    require_noerr_action(SecTrustSetTrustedLogs(trust, trustedLogs), errOut, fail("failed to set trusted logs"));
+    ok(SecTrustEvaluateWithError(trust, NULL), "system post-flag-date CT cert failed");
+    CFReleaseNull(trust);
+
+    // test system cert before date without CT passes
+    require_noerr_action(SecTrustCreateWithCertificates(system_server_before, policy, &trust), errOut, fail("failed to create trust"));
+    require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), errOut, fail("failed to set anchors"));
+    require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date"));
+    require_noerr_action(SecTrustSetTrustedLogs(trust, trustedLogs), errOut, fail("failed to set trusted logs"));
+    ok(SecTrustEvaluateWithError(trust, NULL), "system pre-flag-date non-CT cert failed");
+    CFReleaseNull(trust);
+
+    // test enterprise (non-public) after date without CT passes
+    require_action(set_trust_settings_for_cert(user_root), errOut, fail("failed to set trust settings for user_root"));
+    require_noerr_action(SecTrustCreateWithCertificates(user_server_after, policy, &trust), errOut, fail("failed to create trust"));
+    require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date"));
+    require_noerr_action(SecTrustSetTrustedLogs(trust, trustedLogs), errOut, fail("failed to set trusted logs"));
+    ok(SecTrustEvaluateWithError(trust, NULL), "non-system post-flag-date non-CT cert failed with enterprise anchor");
+    require_action(remove_trust_settings_for_cert(user_root), errOut, fail("failed to remove trust settings for user_root"));
+
+    // test app anchor (non-public) after date without CT passes
+    anchors = @[ (__bridge id)user_root ];
+    require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), errOut, fail("failed to set anchors"));
+    ok(SecTrustEvaluateWithError(trust, NULL), "non-system post-flag-date non-CT cert failed with app anchor");
+    CFReleaseNull(trust);
+    CFReleaseNull(policy);
+
+errOut:
+    cleanup_keychain(keychain_certs);
+    CFReleaseNull(system_root);
+    CFReleaseNull(user_root);
+    CFReleaseNull(system_server_before);
+    CFReleaseNull(system_server_after);
+    CFReleaseNull(system_server_after_with_CT);
+    CFReleaseNull(user_server_after);
+    CFReleaseNull(trustedLogs);
+    CFReleaseNull(trust);
+    CFReleaseNull(policy);
+}
+
+static void test_apple_enforcement_exceptions(void) {
+    SecCertificateRef appleRoot = NULL, appleServerAuthCA = NULL, apple_server_after = NULL;
+    SecCertificateRef geoTrustRoot = NULL, appleISTCA8G1 = NULL, livability = NULL;
+    CFArrayRef trustedLogs = CTTestsCopyTrustedLogs();
+    SecTrustRef trust = NULL;
+    SecPolicyRef policy = NULL;
+    NSArray *anchors = nil, *certs = nil;
+    NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:562340800.0]; // October 27, 2018 at 6:46:40 AM PDT
+
+    require_action(appleRoot = SecCertificateCreateFromResource(@"enforcement_apple_root"),
+                   errOut, fail("failed to create apple root"));
+    require_action(appleServerAuthCA = SecCertificateCreateFromResource(@"enforcement_apple_ca"),
+                   errOut, fail("failed to create apple server auth CA"));
+    require_action(apple_server_after = SecCertificateCreateFromResource(@"enforcement_apple_server_after"),
+                   errOut, fail("failed to create apple server cert issued after flag day"));
+    require_action(geoTrustRoot = SecCertificateCreateFromResource(@"GeoTrustPrimaryCAG2"),
+                   errOut, fail("failed to create GeoTrust root"));
+    require_action(appleISTCA8G1 = SecCertificateCreateFromResource(@"AppleISTCA8G1"),
+                   errOut, fail("failed to create apple IST CA"));
+    require_action(livability = SecCertificateCreateFromResource(@"livability"),
+                   errOut, fail("failed to create livability cert"));
+
+    // test apple anchor after date without CT passes
+    policy = SecPolicyCreateSSL(true, CFSTR("bbasile-test.scv.apple.com"));
+    certs = @[ (__bridge id)apple_server_after, (__bridge id)appleServerAuthCA ];
+    require_noerr_action(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trust), errOut, fail("failed to create trust"));
+    require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date"));
+    require_noerr_action(SecTrustSetTrustedLogs(trust, trustedLogs), errOut, fail("failed to set trusted logs"));
+    ok(SecTrustEvaluateWithError(trust, NULL), "apple root post-flag-date non-CT cert failed");
+    CFReleaseNull(trust);
+    CFReleaseNull(policy);
+
+    // test apple ca after date without CT passes
+    policy = SecPolicyCreateSSL(true, CFSTR("livability.swe.apple.com"));
+    certs = @[ (__bridge id)livability, (__bridge id)appleISTCA8G1 ];
+    anchors = @[ (__bridge id)geoTrustRoot ];
+    require_noerr_action(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trust), errOut, fail("failed to create trust"));
+    require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date"));
+    require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), errOut, fail("failed to set anchors"));
+    require_noerr_action(SecTrustSetTrustedLogs(trust, trustedLogs), errOut, fail("failed to set trusted logs"));
+    ok(SecTrustEvaluateWithError(trust, NULL), "apple public post-flag-date non-CT cert failed");
+
+errOut:
+    CFReleaseNull(appleRoot);
+    CFReleaseNull(appleServerAuthCA);
+    CFReleaseNull(apple_server_after);
+    CFReleaseNull(geoTrustRoot);
+    CFReleaseNull(appleISTCA8G1);
+    CFReleaseNull(livability);
+    CFReleaseNull(trustedLogs);
+    CFReleaseNull(trust);
+    CFReleaseNull(policy);
+}
+
+static void test_google_enforcement_exception(void) {
+    SecCertificateRef globalSignRoot = NULL, googleIAG3 = NULL, google = NULL;
+    CFArrayRef trustedLogs = CTTestsCopyTrustedLogs();
+    SecTrustRef trust = NULL;
+    SecPolicyRef policy = NULL;
+    NSArray *anchors = nil, *certs = nil;
+    NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:562340800.0]; // October 27, 2018 at 6:46:40 AM PDT
+
+    require_action(globalSignRoot = SecCertificateCreateFromResource(@"GlobalSignRootCAR2"),
+                   errOut, fail("failed to create GlobalSign root"));
+    require_action(googleIAG3 = SecCertificateCreateFromResource(@"GoogleIAG3"),
+                   errOut, fail("failed to create Google IA CA"));
+    require_action(google = SecCertificateCreateFromResource(@"google"),
+                   errOut, fail("failed to create google server cert"));
+
+    // test google ca after date without CT passes
+    policy = SecPolicyCreateSSL(true, CFSTR("www.google.com"));
+    certs = @[ (__bridge id)google, (__bridge id)googleIAG3];
+    anchors = @[ (__bridge id)globalSignRoot ];
+    require_noerr_action(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trust), errOut, fail("failed to create trust"));
+    require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date"));
+    require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), errOut, fail("failed to set anchors"));
+    require_noerr_action(SecTrustSetTrustedLogs(trust, trustedLogs), errOut, fail("failed to set trusted logs"));
+    ok(SecTrustEvaluateWithError(trust, NULL), "google public post-flag-date non-CT cert failed");
+
+errOut:
+    CFReleaseNull(globalSignRoot);
+    CFReleaseNull(googleIAG3);
+    CFReleaseNull(google);
+    CFReleaseNull(trustedLogs);
+    CFReleaseNull(trust);
+    CFReleaseNull(policy);
+}
+
+static void test_precerts_fail(void) {
+    SecCertificateRef precert = NULL, system_root = NULL;
+    SecTrustRef trust = NULL;
+    NSArray *anchors = nil;
+    NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:561540800.0]; // October 18, 2018 at 12:33:20 AM PDT
+    CFErrorRef error = NULL;
+
+    require_action(system_root = SecCertificateCreateFromResource(@"enforcement_system_root"),
+                   errOut, fail("failed to create system root"));
+    require_action(precert = SecCertificateCreateFromResource(@"precert"),
+                   errOut, fail("failed to create precert"));
+
+    anchors = @[(__bridge id)system_root];
+    require_noerr_action(SecTrustCreateWithCertificates(precert, NULL, &trust), errOut, fail("failed to create trust object"));
+    require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), errOut, fail("failed to set anchor certificate"));
+    require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date"));
+
+    is(SecTrustEvaluateWithError(trust, &error), false, "SECURITY: trust evaluation of precert succeeded");
+    if (error) {
+        is(CFErrorGetCode(error), errSecUnknownCriticalExtensionFlag, "got wrong error code for precert, got %ld, expected %d",
+           (long)CFErrorGetCode(error), errSecUnknownCriticalExtensionFlag);
+    } else {
+        fail("expected trust evaluation to fail and it did not.");
+    }
+
+
+errOut:
+    CFReleaseNull(system_root);
+    CFReleaseNull(precert);
+    CFReleaseNull(error);
+}
+
+#define evalTrustExpectingError(errCode, ...) \
+    is(SecTrustEvaluateWithError(trust, &error), false, __VA_ARGS__); \
+    if (error) { \
+        is(CFErrorGetCode(error), errCode, "got wrong error code, got %ld, expected %d", \
+            (long)CFErrorGetCode(error), errCode); \
+    } else { \
+        fail("expected trust evaluation to fail and it did not."); \
+    } \
+    CFReleaseNull(error);
+
+static void test_specific_domain_exceptions(void) {
+    SecCertificateRef system_root = NULL, system_server_after = NULL, system_server_after_with_CT = NULL;
+    CFArrayRef trustedLogs = CTTestsCopyTrustedLogs();
+    SecTrustRef trust = NULL;
+    SecPolicyRef policy = SecPolicyCreateSSL(true, CFSTR("ct.test.apple.com"));
+    NSArray *anchors = nil;
+    NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:562340800.0]; // October 27, 2018 at 6:46:40 AM PDT
+    CFErrorRef error = nil;
+    NSDictionary *exceptions = nil;
+
+    require_action(system_root = SecCertificateCreateFromResource(@"enforcement_system_root"),
+                   errOut, fail("failed to create system root"));
+    require_action(system_server_after = SecCertificateCreateFromResource(@"enforcement_system_server_after"),
+                   errOut, fail("failed to create system server cert issued after flag day"));
+    require_action(system_server_after_with_CT = SecCertificateCreateFromResource(@"enforcement_system_server_after_scts"),
+                   errOut, fail("failed to create system server cert issued after flag day with SCTs"));
+
+    anchors = @[ (__bridge id)system_root ];
+    require_noerr_action(SecTrustCreateWithCertificates(system_server_after, policy, &trust), errOut, fail("failed to create trust"));
+    require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), errOut, fail("failed to set anchors"));
+    require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date"));
+    require_noerr_action(SecTrustSetTrustedLogs(trust, trustedLogs), errOut, fail("failed to set trusted logs")); // set trusted logs to trigger enforcing behavior
+
+    /* superdomain exception without CT fails */
+    exceptions = @{ (__bridge NSString*)kSecCTExceptionsDomainsKey : @[@"test.apple.com"] };
+    ok(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)exceptions, &error), "failed to set exceptions: %@", error);
+    evalTrustExpectingError(errSecVerifyActionFailed, "superdomain exception unexpectedly succeeded");
+
+    /* subdomain exceptions without CT fails */
+    exceptions = @{ (__bridge NSString*)kSecCTExceptionsDomainsKey : @[@"one.ct.test.apple.com"] };
+    ok(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)exceptions, &error), "failed to set exceptions: %@", error);
+    SecTrustSetNeedsEvaluation(trust);
+    evalTrustExpectingError(errSecVerifyActionFailed, "subdomain exception unexpectedly succeeded")
+
+    /* no match without CT fails */
+    exceptions = @{ (__bridge NSString*)kSecCTExceptionsDomainsKey : @[@"example.com"] };
+    ok(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)exceptions, &error), "failed to set exceptions: %@", error);
+    SecTrustSetNeedsEvaluation(trust);
+    evalTrustExpectingError(errSecVerifyActionFailed, "unrelated domain exception unexpectedly succeeded");
+
+    /* matching domain without CT succeeds */
+    exceptions = @{ (__bridge NSString*)kSecCTExceptionsDomainsKey : @[@"ct.test.apple.com"] };
+    ok(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)exceptions, &error), "failed to set exceptions: %@", error);
+    SecTrustSetNeedsEvaluation(trust);
+    is(SecTrustEvaluateWithError(trust, &error), true, "exact match domain exception did not apply");
+
+    /* matching domain with CT succeeds */
+    CFReleaseNull(trust);
+    require_noerr_action(SecTrustCreateWithCertificates(system_server_after_with_CT, policy, &trust), errOut, fail("failed to create trust"));
+    require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), errOut, fail("failed to set anchors"));
+    require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date"));
+    require_noerr_action(SecTrustSetTrustedLogs(trust, trustedLogs), errOut, fail("failed to set trusted logs")); // set trusted logs to trigger enforcing behavior
+    is(SecTrustEvaluateWithError(trust, &error), true, "ct cert should always pass");
+
+    ok(SecTrustStoreSetCTExceptions(NULL, NULL, &error), "failed to reset exceptions: %@", error);
+
+errOut:
+    CFReleaseNull(system_root);
+    CFReleaseNull(system_server_after);
+    CFReleaseNull(system_server_after_with_CT);
+    CFReleaseNull(trust);
+    CFReleaseNull(policy);
+    CFReleaseNull(error);
+    CFReleaseNull(trustedLogs);
+}
+
+static void test_subdomain_exceptions(void) {
+    SecCertificateRef system_root = NULL, system_server_after = NULL, system_server_after_with_CT = NULL;
+    CFArrayRef trustedLogs = CTTestsCopyTrustedLogs();
+    SecTrustRef trust = NULL;
+    SecPolicyRef policy = SecPolicyCreateSSL(true, CFSTR("ct.test.apple.com"));
+    NSArray *anchors = nil;
+    NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:562340800.0]; // October 27, 2018 at 6:46:40 AM PDT
+    CFErrorRef error = nil;
+    NSDictionary *exceptions = nil;
+
+    require_action(system_root = SecCertificateCreateFromResource(@"enforcement_system_root"),
+                   errOut, fail("failed to create system root"));
+    require_action(system_server_after = SecCertificateCreateFromResource(@"enforcement_system_server_after"),
+                   errOut, fail("failed to create system server cert issued after flag day"));
+    require_action(system_server_after_with_CT = SecCertificateCreateFromResource(@"enforcement_system_server_after_scts"),
+                   errOut, fail("failed to create system server cert issued after flag day with SCTs"));
+
+    anchors = @[ (__bridge id)system_root ];
+    require_noerr_action(SecTrustCreateWithCertificates(system_server_after, policy, &trust), errOut, fail("failed to create trust"));
+    require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), errOut, fail("failed to set anchors"));
+    require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date"));
+    require_noerr_action(SecTrustSetTrustedLogs(trust, trustedLogs), errOut, fail("failed to set trusted logs")); // set trusted logs to trigger enforcing behavior
+
+    /* superdomain exception without CT succeeds */
+    exceptions = @{ (__bridge NSString*)kSecCTExceptionsDomainsKey : @[@".test.apple.com"] };
+    ok(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)exceptions, &error), "failed to set exceptions: %@", error);
+    is(SecTrustEvaluateWithError(trust, &error), true, "superdomain exception did not apply");
+
+    /* exact domain exception without CT succeeds */
+    exceptions = @{ (__bridge NSString*)kSecCTExceptionsDomainsKey : @[@".ct.test.apple.com"] };
+    ok(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)exceptions, &error), "failed to set exceptions: %@", error);
+    SecTrustSetNeedsEvaluation(trust);
+    is(SecTrustEvaluateWithError(trust, &error), true, "exact domain exception did not apply");
+
+    /* no match without CT fails */
+    exceptions = @{ (__bridge NSString*)kSecCTExceptionsDomainsKey : @[@".example.com"] };
+    ok(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)exceptions, &error), "failed to set exceptions: %@", error);
+    SecTrustSetNeedsEvaluation(trust);
+    evalTrustExpectingError(errSecVerifyActionFailed, "unrelated domain exception unexpectedly succeeded");
+
+    /* subdomain without CT fails */
+    exceptions = @{ (__bridge NSString*)kSecCTExceptionsDomainsKey : @[@".one.ct.test.apple.com"] };
+    ok(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)exceptions, &error), "failed to set exceptions: %@", error);
+    SecTrustSetNeedsEvaluation(trust);
+    evalTrustExpectingError(errSecVerifyActionFailed, "subdomain exception unexpectedly succeeded");
+
+    ok(SecTrustStoreSetCTExceptions(NULL, NULL, &error), "failed to reset exceptions: %@", error);
+
+errOut:
+    CFReleaseNull(system_root);
+    CFReleaseNull(system_server_after);
+    CFReleaseNull(system_server_after_with_CT);
+    CFReleaseNull(trust);
+    CFReleaseNull(policy);
+    CFReleaseNull(error);
+    CFReleaseNull(trustedLogs);
+}
+
+static void test_mixed_domain_exceptions(void) {
+    SecCertificateRef system_root = NULL, system_server_after = NULL, system_server_after_with_CT = NULL;
+    CFArrayRef trustedLogs = CTTestsCopyTrustedLogs();
+    SecTrustRef trust = NULL;
+    SecPolicyRef policy = SecPolicyCreateSSL(true, CFSTR("ct.test.apple.com"));
+    NSArray *anchors = nil;
+    NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:562340800.0]; // October 27, 2018 at 6:46:40 AM PDT
+    CFErrorRef error = nil;
+    NSDictionary *exceptions = nil;
+
+    require_action(system_root = SecCertificateCreateFromResource(@"enforcement_system_root"),
+                   errOut, fail("failed to create system root"));
+    require_action(system_server_after = SecCertificateCreateFromResource(@"enforcement_system_server_after"),
+                   errOut, fail("failed to create system server cert issued after flag day"));
+    require_action(system_server_after_with_CT = SecCertificateCreateFromResource(@"enforcement_system_server_after_scts"),
+                   errOut, fail("failed to create system server cert issued after flag day with SCTs"));
+
+    anchors = @[ (__bridge id)system_root ];
+    require_noerr_action(SecTrustCreateWithCertificates(system_server_after, policy, &trust), errOut, fail("failed to create trust"));
+    require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), errOut, fail("failed to set anchors"));
+    require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date"));
+    require_noerr_action(SecTrustSetTrustedLogs(trust, trustedLogs), errOut, fail("failed to set trusted logs")); // set trusted logs to trigger enforcing behavior
+
+    /* specific domain exception without CT succeeds */
+    exceptions = @{ (__bridge NSString*)kSecCTExceptionsDomainsKey : @[@"ct.test.apple.com", @".example.com" ] };
+    ok(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)exceptions, &error), "failed to set exceptions: %@", error);
+    is(SecTrustEvaluateWithError(trust, &error), true, "one of exact domain exception did not apply");
+
+    /* super domain exception without CT succeeds */
+    exceptions = @{ (__bridge NSString*)kSecCTExceptionsDomainsKey : @[@".apple.com", @"example.com" ] };
+    ok(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)exceptions, &error), "failed to set exceptions: %@", error);
+    SecTrustSetNeedsEvaluation(trust);
+    is(SecTrustEvaluateWithError(trust, &error), true, "one of superdomain exception did not apply");
+
+    /* both super domain and specific domain exceptions without CT succeeds */
+    exceptions = @{ (__bridge NSString*)kSecCTExceptionsDomainsKey : @[@"ct.test.apple.com", @".apple.com" ] };
+    ok(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)exceptions, &error), "failed to set exceptions: %@", error);
+    SecTrustSetNeedsEvaluation(trust);
+    is(SecTrustEvaluateWithError(trust, &error), true, "both domain exception did not apply");
+
+    /* neither specific domain nor super domain exceptions without CT fails */
+    exceptions = @{ (__bridge NSString*)kSecCTExceptionsDomainsKey : @[@"apple.com", @".example.com" ] };
+    ok(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)exceptions, &error), "failed to set exceptions: %@", error);
+    SecTrustSetNeedsEvaluation(trust);
+    evalTrustExpectingError(errSecVerifyActionFailed, "no match domain unexpectedly succeeded");
+
+    ok(SecTrustStoreSetCTExceptions(NULL, NULL, &error), "failed to reset exceptions: %@", error);
+
+errOut:
+    CFReleaseNull(system_root);
+    CFReleaseNull(system_server_after);
+    CFReleaseNull(system_server_after_with_CT);
+    CFReleaseNull(trust);
+    CFReleaseNull(policy);
+    CFReleaseNull(error);
+    CFReleaseNull(trustedLogs);
+}
+
+
+
+static void test_ct_domain_exceptions(void) {
+    test_specific_domain_exceptions();
+    test_subdomain_exceptions();
+    test_mixed_domain_exceptions();
+}
+
+static void test_ct_leaf_exceptions(void) {
+    SecCertificateRef system_root = NULL, system_server_after = NULL, system_server_after_with_CT = NULL;
+    CFArrayRef trustedLogs = CTTestsCopyTrustedLogs();
+    SecTrustRef trust = NULL;
+    SecPolicyRef policy = SecPolicyCreateSSL(true, CFSTR("ct.test.apple.com"));
+    NSArray *anchors = nil;
+    NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:562340800.0]; // October 27, 2018 at 6:46:40 AM PDT
+    CFErrorRef error = nil;
+    NSDictionary *leafException = nil, *exceptions = nil;
+    NSData *leafHash = nil;
+
+    require_action(system_root = SecCertificateCreateFromResource(@"enforcement_system_root"),
+                   errOut, fail("failed to create system root"));
+    require_action(system_server_after = SecCertificateCreateFromResource(@"enforcement_system_server_after"),
+                   errOut, fail("failed to create system server cert issued after flag day"));
+    require_action(system_server_after_with_CT = SecCertificateCreateFromResource(@"enforcement_system_server_after_scts"),
+                   errOut, fail("failed to create system server cert issued after flag day with SCTs"));
+
+    anchors = @[ (__bridge id)system_root ];
+    require_noerr_action(SecTrustCreateWithCertificates(system_server_after, policy, &trust), errOut, fail("failed to create trust"));
+    require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), errOut, fail("failed to set anchors"));
+    require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date"));
+    require_noerr_action(SecTrustSetTrustedLogs(trust, trustedLogs), errOut, fail("failed to set trusted logs")); // set trusted logs to trigger enforcing behavior
+
+    /* set exception on leaf cert without CT */
+    leafHash = CFBridgingRelease(SecCertificateCopySubjectPublicKeyInfoSHA256Digest(system_server_after));
+    leafException = @{ (__bridge NSString*)kSecCTExceptionsHashAlgorithmKey : @"sha256",
+                   (__bridge NSString*)kSecCTExceptionsSPKIHashKey : leafHash,
+    };
+    exceptions = @{ (__bridge NSString*)kSecCTExceptionsCAsKey : @[ leafException ] };
+    ok(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)exceptions, &error),
+       "failed to set exceptions: %@", error);
+    is(SecTrustEvaluateWithError(trust, &error), true, "leaf public key exception did not apply");
+
+    /* set exception on leaf cert with CT */
+    leafHash = CFBridgingRelease(SecCertificateCopySubjectPublicKeyInfoSHA256Digest(system_server_after_with_CT));
+    leafException = @{ (__bridge NSString*)kSecCTExceptionsHashAlgorithmKey : @"sha256",
+                       (__bridge NSString*)kSecCTExceptionsSPKIHashKey : leafHash,
+                       };
+    exceptions = @{ (__bridge NSString*)kSecCTExceptionsCAsKey : @[ leafException ] };
+    ok(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)exceptions, &error),
+       "failed to set exceptions: %@", error);
+    SecTrustSetNeedsEvaluation(trust);
+    evalTrustExpectingError(errSecVerifyActionFailed, "leaf cert with no public key exceptions succeeded");
+
+    /* matching public key with CT succeeds */
+    CFReleaseNull(trust);
+    require_noerr_action(SecTrustCreateWithCertificates(system_server_after_with_CT, policy, &trust), errOut, fail("failed to create trust"));
+    require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), errOut, fail("failed to set anchors"));
+    require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date"));
+    require_noerr_action(SecTrustSetTrustedLogs(trust, trustedLogs), errOut, fail("failed to set trusted logs")); // set trusted logs to trigger enforcing behavior
+    is(SecTrustEvaluateWithError(trust, &error), true, "ct cert should always pass");
+
+    ok(SecTrustStoreSetCTExceptions(NULL, NULL, &error), "failed to reset exceptions: %@", error);
+
+errOut:
+    CFReleaseNull(system_root);
+    CFReleaseNull(system_server_after);
+    CFReleaseNull(system_server_after_with_CT);
+    CFReleaseNull(trustedLogs);
+    CFReleaseNull(trust);
+    CFReleaseNull(policy);
+    CFReleaseNull(error);
+}
+
+static void test_ct_unconstrained_ca_exceptions(void) {
+    SecCertificateRef root = NULL, subca = NULL;
+    SecCertificateRef server_matching = NULL, server_matching_with_CT = NULL, server_partial = NULL, server_no_match = NULL, server_no_org = NULL;
+    CFArrayRef trustedLogs = CTTestsCopyTrustedLogs();
+    SecTrustRef trust = NULL;
+    SecPolicyRef policy = SecPolicyCreateSSL(true, CFSTR("ct.test.apple.com"));
+    NSArray *anchors = nil, *certs = nil;
+    NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:562340800.0]; // October 27, 2018 at 6:46:40 AM PDT
+    CFErrorRef error = nil;
+    NSDictionary *caException = nil, *exceptions = nil;
+    NSData *caHash = nil;
+
+    require_action(root = SecCertificateCreateFromResource(@"enforcement_system_root"),
+                   errOut, fail("failed to create system root"));
+    require_action(subca = SecCertificateCreateFromResource(@"enforcement_system_unconstrained_subca"),
+                   errOut, fail("failed to create subca"));
+    require_action(server_matching = SecCertificateCreateFromResource(@"enforcement_system_server_matching_orgs"),
+                   errOut, fail("failed to create server cert with matching orgs"));
+    require_action(server_matching_with_CT = SecCertificateCreateFromResource(@"enforcement_system_server_matching_orgs_scts"),
+                   errOut, fail("failed to create server cert with matching orgs and scts"));
+    require_action(server_partial = SecCertificateCreateFromResource(@"enforcement_system_server_partial_orgs"),
+                   errOut, fail("failed to create server cert with partial orgs"));
+    require_action(server_no_match = SecCertificateCreateFromResource(@"enforcement_system_server_nonmatching_orgs"),
+                   errOut, fail("failed to create server cert with non-matching orgs"));
+    require_action(server_no_org = SecCertificateCreateFromResource(@"enforcement_system_server_no_orgs"),
+                   errOut, fail("failed to create server cert with no orgs"));
+
+    anchors = @[ (__bridge id)root ];
+
+#define createTrust(certs) \
+    CFReleaseNull(trust); \
+    require_noerr_action(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trust), errOut, fail("failed to create trust")); \
+    require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), errOut, fail("failed to set anchors")); \
+    require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date")); \
+    require_noerr_action(SecTrustSetTrustedLogs(trust, trustedLogs), errOut, fail("failed to set trusted logs"));
+
+    /* Set exception on the subCA */
+    caHash = CFBridgingRelease(SecCertificateCopySubjectPublicKeyInfoSHA256Digest(subca));
+    caException = @{ (__bridge NSString*)kSecCTExceptionsHashAlgorithmKey : @"sha256",
+                       (__bridge NSString*)kSecCTExceptionsSPKIHashKey : caHash,
+                       };
+    exceptions = @{ (__bridge NSString*)kSecCTExceptionsCAsKey : @[ caException ] };
+    ok(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)exceptions, &error),
+       "failed to set exceptions: %@", error);
+
+    /* Verify that non-CT cert with Orgs matching subCA passes */
+    certs = @[ (__bridge id)server_matching, (__bridge id)subca];
+    createTrust(certs);
+    is(SecTrustEvaluateWithError(trust, &error), true, "matching org subca exception did not apply: %@", error);
+
+    /* Verify that CT cert with Orgs matching subCA passes */
+    certs = @[ (__bridge id)server_matching_with_CT, (__bridge id)subca];
+    createTrust(certs);
+    is(SecTrustEvaluateWithError(trust, &error), true, "CT matching org subca exception did not apply: %@", error);
+
+    /* Verify that non-CT cert with partial Org match fails */
+    certs = @[ (__bridge id)server_partial, (__bridge id)subca];
+    createTrust(certs);
+    evalTrustExpectingError(errSecVerifyActionFailed, "partial matching org leaf succeeded");
+
+    /* Verify that a non-CT cert with non-matching Org fails */
+    certs = @[ (__bridge id)server_no_match, (__bridge id)subca];
+    createTrust(certs);
+    evalTrustExpectingError(errSecVerifyActionFailed, "non-matching org leaf succeeded");
+
+    /* Verify that a non-CT cert with no Org fails */
+    certs = @[ (__bridge id)server_no_org, (__bridge id)subca];
+    createTrust(certs);
+    evalTrustExpectingError(errSecVerifyActionFailed, "no org leaf succeeded");
+
+    ok(SecTrustStoreSetCTExceptions(NULL, NULL, &error), "failed to reset exceptions: %@", error);
+
+#undef createTrust
+
+errOut:
+    CFReleaseNull(root);
+    CFReleaseNull(subca);
+    CFReleaseNull(server_matching);
+    CFReleaseNull(server_matching_with_CT);
+    CFReleaseNull(server_partial);
+    CFReleaseNull(server_no_match);
+    CFReleaseNull(server_no_org);
+    CFReleaseNull(trustedLogs);
+    CFReleaseNull(trust);
+    CFReleaseNull(policy);
+    CFReleaseNull(error);
+}
+
+static void test_ct_constrained_ca_exceptions(void) {
+    SecCertificateRef root = NULL, org_constrained_subca = NULL;
+    SecCertificateRef constraint_pass_server = NULL, constraint_pass_server_ct = NULL, constraint_fail_server = NULL;
+    SecCertificateRef dn_constrained_subca = NULL, dn_constrained_server = NULL, dn_constrained_server_mismatch = NULL;
+    SecCertificateRef dns_constrained_subca = NULL, dns_constrained_server = NULL, dns_constrained_server_mismatch = NULL;
+    CFArrayRef trustedLogs = CTTestsCopyTrustedLogs();
+    SecTrustRef trust = NULL;
+    SecPolicyRef policy = SecPolicyCreateSSL(true, CFSTR("ct.test.apple.com"));
+    NSArray *anchors = nil, *certs = nil;
+    NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:562340800.0]; // October 27, 2018 at 6:46:40 AM PDT
+    CFErrorRef error = nil;
+    NSDictionary *caException = nil, *exceptions = nil;
+    NSMutableArray *caExceptions = [NSMutableArray array];
+    NSData *caHash = nil;
+
+    require_action(root = SecCertificateCreateFromResource(@"enforcement_system_root"),
+                   errOut, fail("failed to create system root"));
+    require_action(org_constrained_subca = SecCertificateCreateFromResource(@"enforcement_system_constrained_subca"),
+                   errOut, fail("failed to create org-constrained subca"));
+    require_action(constraint_pass_server = SecCertificateCreateFromResource(@"enforcement_system_constrained_server"),
+                   errOut, fail("failed to create constrained non-CT leaf"));
+    require_action(constraint_pass_server_ct = SecCertificateCreateFromResource(@"enforcement_system_constrained_server_scts"),
+                   errOut, fail("failed to create constrained CT leaf"));
+    require_action(constraint_fail_server= SecCertificateCreateFromResource(@"enforcement_system_constrained_fail_server"),
+                   errOut, fail("failed to create constraint failure leaf"));
+    require_action(dn_constrained_subca = SecCertificateCreateFromResource(@"enforcement_system_constrained_no_org_subca"),
+                   errOut, fail("failed to create dn-constrained subca"));
+    require_action(dn_constrained_server = SecCertificateCreateFromResource(@"enforcement_system_constrained_no_org_server"),
+                   errOut, fail("failed to create dn-constrained leaf"));
+    require_action(dn_constrained_server_mismatch = SecCertificateCreateFromResource(@"enforcement_system_constrained_no_org_server_mismatch"),
+                   errOut, fail("failed to create dn-constrained leaf with mismatched orgs"));
+    require_action(dns_constrained_subca = SecCertificateCreateFromResource(@"enforcement_system_constrained_no_dn_subca"),
+                   errOut, fail("failed to create dns-constrained subca"));
+    require_action(dns_constrained_server = SecCertificateCreateFromResource(@"enforcement_system_constrained_no_dn_server"),
+                   errOut, fail("failed to create dns-constrained leaf"));
+    require_action(dns_constrained_server_mismatch = SecCertificateCreateFromResource(@"enforcement_system_constrained_no_dn_server_mismatch"),
+                   errOut, fail("failed to create dns-constrained leaf with mismatched orgs"));
+
+    anchors = @[ (__bridge id)root ];
+
+    /* Set exception on the subCAs */
+    caHash = CFBridgingRelease(SecCertificateCopySubjectPublicKeyInfoSHA256Digest(org_constrained_subca));
+    caException = @{ (__bridge NSString*)kSecCTExceptionsHashAlgorithmKey : @"sha256",
+                     (__bridge NSString*)kSecCTExceptionsSPKIHashKey : caHash,
+                     };
+    [caExceptions addObject:caException];
+
+    caHash = CFBridgingRelease(SecCertificateCopySubjectPublicKeyInfoSHA256Digest(dn_constrained_subca));
+    caException = @{ (__bridge NSString*)kSecCTExceptionsHashAlgorithmKey : @"sha256",
+                     (__bridge NSString*)kSecCTExceptionsSPKIHashKey : caHash,
+                     };
+    [caExceptions addObject:caException];
+
+    caHash = CFBridgingRelease(SecCertificateCopySubjectPublicKeyInfoSHA256Digest(dns_constrained_subca));
+    caException = @{ (__bridge NSString*)kSecCTExceptionsHashAlgorithmKey : @"sha256",
+                     (__bridge NSString*)kSecCTExceptionsSPKIHashKey : caHash,
+                     };
+    [caExceptions addObject:caException];
+    exceptions = @{ (__bridge NSString*)kSecCTExceptionsCAsKey : caExceptions };
+    ok(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)exceptions, &error),
+       "failed to set exceptions: %@", error);
+
+#define createTrust(certs) \
+    CFReleaseNull(trust); \
+    require_noerr_action(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trust), errOut, fail("failed to create trust")); \
+    require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), errOut, fail("failed to set anchors")); \
+    require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date")); \
+    require_noerr_action(SecTrustSetTrustedLogs(trust, trustedLogs), errOut, fail("failed to set trusted logs"));
+
+    /* Verify org-constrained non-CT leaf passes */
+    certs = @[ (__bridge id)constraint_pass_server, (__bridge id)org_constrained_subca ];
+    createTrust(certs);
+    is(SecTrustEvaluateWithError(trust, &error), true, "org constrained exception did not apply: %@", error);
+
+    /* Verify org-constrained CT leaf passes */
+    certs = @[ (__bridge id)constraint_pass_server_ct, (__bridge id)org_constrained_subca ];
+    createTrust(certs);
+    is(SecTrustEvaluateWithError(trust, &error), true, "org constrained exception did not apply: %@", error);
+
+    /* Verify org-constrained non-CT leaf with wrong org fails */
+    certs = @[ (__bridge id)constraint_fail_server, (__bridge id)org_constrained_subca ];
+    createTrust(certs);
+    evalTrustExpectingError(errSecInvalidName, "leaf failing name constraints succeeded");
+
+    /* Verify dn-constrained (but not with org) non-CT leaf with matching orgs succeeds */
+    certs = @[ (__bridge id)dn_constrained_server, (__bridge id)dn_constrained_subca ];
+    createTrust(certs);
+    is(SecTrustEvaluateWithError(trust, &error), true, "org match exception did not apply: %@", error);
+
+    /* Verify dn-constrained (but not with org) non-CT leaf without matching orgs fails */
+    certs = @[ (__bridge id)dn_constrained_server_mismatch, (__bridge id)dn_constrained_subca ];
+    createTrust(certs);
+    evalTrustExpectingError(errSecVerifyActionFailed, "dn name constraints with no org succeeded");
+
+    /* Verify dns-constrained (no DN constraints) non-CT leaf with matching orgs succeeds */
+    certs = @[ (__bridge id)dns_constrained_server, (__bridge id)dns_constrained_subca ];
+    createTrust(certs);
+    is(SecTrustEvaluateWithError(trust, &error), true, "org match exception did not apply: %@", error);
+
+    /* Verify dns-constrained (no DN constraints) non-CT leaf without matching orgs fails*/
+    certs = @[ (__bridge id)dns_constrained_server_mismatch, (__bridge id)dns_constrained_subca ];
+    createTrust(certs);
+    evalTrustExpectingError(errSecVerifyActionFailed, "dns name constraints with no DN constraint succeeded");
+
+    ok(SecTrustStoreSetCTExceptions(NULL, NULL, &error), "failed to reset exceptions: %@", error);
+
+#undef createTrust
+
+errOut:
+    CFReleaseNull(root);
+    CFReleaseNull(org_constrained_subca);
+    CFReleaseNull(constraint_pass_server);
+    CFReleaseNull(constraint_pass_server_ct);
+    CFReleaseNull(constraint_fail_server);
+    CFReleaseNull(dn_constrained_subca);
+    CFReleaseNull(dn_constrained_server);
+    CFReleaseNull(dn_constrained_server_mismatch);
+    CFReleaseNull(dns_constrained_subca);
+    CFReleaseNull(dns_constrained_server);
+    CFReleaseNull(dns_constrained_server_mismatch);
+    CFReleaseNull(trustedLogs);
+    CFReleaseNull(trust);
+    CFReleaseNull(policy);
+    CFReleaseNull(error);
+}
+
+static void test_ct_key_exceptions(void) {
+    test_ct_leaf_exceptions();
+    test_ct_unconstrained_ca_exceptions();
+    test_ct_constrained_ca_exceptions();
+}
+
+static void test_ct_exceptions(void) {
+    test_ct_domain_exceptions();
+    test_ct_key_exceptions();
+}
 
 int si_82_sectrust_ct(int argc, char *const *argv)
 {
-       plan_tests(268);
+       plan_tests(432);
 
        tests();
+    test_sct_serialization();
+    testSetCTExceptions();
+    test_enforcement();
+    test_apple_enforcement_exceptions();
+    test_google_enforcement_exception();
+    test_precerts_fail();
+    test_ct_exceptions();
 
        return 0;
 }
diff --git a/OSX/trustd/iOS/AppleCorporateRootCA.cer b/OSX/trustd/iOS/AppleCorporateRootCA.cer
new file mode 100644 (file)
index 0000000..c23d1c4
Binary files /dev/null and b/OSX/trustd/iOS/AppleCorporateRootCA.cer differ
diff --git a/OSX/trustd/iOS/AppleCorporateRootCA2.cer b/OSX/trustd/iOS/AppleCorporateRootCA2.cer
new file mode 100644 (file)
index 0000000..e16cc0f
Binary files /dev/null and b/OSX/trustd/iOS/AppleCorporateRootCA2.cer differ
index 3dbd2c8878fa7d6181263e56ff16c39b9207abec..1682ccddabb6967b33032f8d85fd07f25fe35bc3 100644 (file)
@@ -4,6 +4,8 @@
 <dict>
        <key>application-identifier</key>
        <string>com.apple.trustd</string>
+       <key>com.apple.application-identifier</key>
+       <string>com.apple.trustd</string>
        <key>com.apple.private.necp.match</key>
        <true/>
        <key>com.apple.private.network.socket-delegate</key>
index a4d137fda023983652409d224803ed8536380e98..0ccac927e338fb7118fbb0dd86be32125b280dd4 100644 (file)
@@ -74,12 +74,15 @@ static struct trustd trustd_spi = {
     .sec_truststore_remove_all              = _SecTrustStoreRemoveAll,
     .sec_trust_evaluate                     = SecTrustServerEvaluate,
     .sec_ota_pki_trust_store_version        = SecOTAPKIGetCurrentTrustStoreVersion,
+    .sec_ota_pki_asset_version              = SecOTAPKIGetCurrentAssetVersion,
     .ota_CopyEscrowCertificates             = SecOTAPKICopyCurrentEscrowCertificates,
     .sec_ota_pki_get_new_asset              = SecOTAPKISignalNewAsset,
     .sec_trust_store_copy_all               = _SecTrustStoreCopyAll,
     .sec_trust_store_copy_usage_constraints = _SecTrustStoreCopyUsageConstraints,
     .sec_ocsp_cache_flush                   = SecOCSPCacheFlush,
-    .sec_tls_analytics_report               = SecTLSAnalyticsReport,
+    .sec_networking_analytics_report        = SecNetworkingAnalyticsReport,
+    .sec_trust_store_set_ct_exceptions      = _SecTrustStoreSetCTExceptions,
+    .sec_trust_store_copy_ct_exceptions     = _SecTrustStoreCopyCTExceptions,
 };
 
 static bool SecXPCDictionarySetChainOptional(xpc_object_t message, const char *key, CFArrayRef path, CFErrorRef *error) {
@@ -168,7 +171,8 @@ static SecTrustStoreRef SecXPCDictionaryGetTrustStore(xpc_object_t message, cons
     return ts;
 }
 
-static bool SecXPCTrustStoreContains(xpc_object_t event, xpc_object_t reply, CFErrorRef *error) {
+static bool SecXPCTrustStoreContains(SecurityClient * __unused client, xpc_object_t event,
+                                     xpc_object_t reply, CFErrorRef *error) {
     bool result = false;
     SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, error);
     if (ts) {
@@ -185,7 +189,8 @@ static bool SecXPCTrustStoreContains(xpc_object_t event, xpc_object_t reply, CFE
     return result;
 }
 
-static bool SecXPCTrustStoreSetTrustSettings(xpc_object_t event, xpc_object_t reply, CFErrorRef *error) {
+static bool SecXPCTrustStoreSetTrustSettings(SecurityClient * __unused client, xpc_object_t event,
+                                             xpc_object_t reply, CFErrorRef *error) {
     bool noError = false;
     SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, error);
     if (ts) {
@@ -204,7 +209,8 @@ static bool SecXPCTrustStoreSetTrustSettings(xpc_object_t event, xpc_object_t re
     return noError;
 }
 
-static bool SecXPCTrustStoreRemoveCertificate(xpc_object_t event, xpc_object_t reply, CFErrorRef *error) {
+static bool SecXPCTrustStoreRemoveCertificate(SecurityClient * __unused client, xpc_object_t event,
+                                              xpc_object_t reply, CFErrorRef *error) {
     SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, error);
     if (ts) {
         CFDataRef digest = SecXPCDictionaryCopyData(event, kSecXPCKeyDigest, error);
@@ -218,7 +224,8 @@ static bool SecXPCTrustStoreRemoveCertificate(xpc_object_t event, xpc_object_t r
     return false;
 }
 
-static bool SecXPCTrustStoreCopyAll(xpc_object_t event, xpc_object_t reply, CFErrorRef *error) {
+static bool SecXPCTrustStoreCopyAll(SecurityClient * __unused client, xpc_object_t event,
+                                    xpc_object_t reply, CFErrorRef *error) {
     SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, error);
     if (ts) {
         CFArrayRef trustStoreContents = NULL;
@@ -231,7 +238,8 @@ static bool SecXPCTrustStoreCopyAll(xpc_object_t event, xpc_object_t reply, CFEr
     return false;
 }
 
-static bool SecXPCTrustStoreCopyUsageConstraints(xpc_object_t event, xpc_object_t reply, CFErrorRef *error) {
+static bool SecXPCTrustStoreCopyUsageConstraints(SecurityClient * __unused client, xpc_object_t event,
+                                                 xpc_object_t reply, CFErrorRef *error) {
     bool result = false;
     SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, error);
     if (ts) {
@@ -249,19 +257,28 @@ static bool SecXPCTrustStoreCopyUsageConstraints(xpc_object_t event, xpc_object_
     return result;
 }
 
-static bool SecXPC_OCSPCacheFlush(xpc_object_t __unused event, xpc_object_t __unused reply, CFErrorRef *error) {
+static bool SecXPC_OCSPCacheFlush(SecurityClient * __unused client, xpc_object_t __unused event,
+                                  xpc_object_t __unused reply, CFErrorRef *error) {
     if(SecOCSPCacheFlush(error)) {
         return true;
     }
     return false;
 }
 
-static bool SecXPC_OTAPKI_GetAssetVersion(xpc_object_t __unused event, xpc_object_t reply, CFErrorRef *error) {
+static bool SecXPC_OTAPKI_GetCurrentTrustStoreVersion(SecurityClient * __unused client, xpc_object_t __unused event,
+                                          xpc_object_t reply, CFErrorRef *error) {
     xpc_dictionary_set_uint64(reply, kSecXPCKeyResult, SecOTAPKIGetCurrentTrustStoreVersion(error));
     return true;
 }
 
-static bool SecXPC_OTAPKI_GetEscrowCertificates(xpc_object_t event, xpc_object_t reply, CFErrorRef *error) {
+static bool SecXPC_OTAPKI_GetCurrentAssetVersion(SecurityClient * __unused client, xpc_object_t __unused event,
+                                                      xpc_object_t reply, CFErrorRef *error) {
+    xpc_dictionary_set_uint64(reply, kSecXPCKeyResult, SecOTAPKIGetCurrentAssetVersion(error));
+    return true;
+}
+
+static bool SecXPC_OTAPKI_GetEscrowCertificates(SecurityClient * __unused client, xpc_object_t event,
+                                                xpc_object_t reply, CFErrorRef *error) {
     bool result = false;
     uint32_t escrowRootType = (uint32_t)xpc_dictionary_get_uint64(event, "escrowType");
     CFArrayRef array = SecOTAPKICopyCurrentEscrowCertificates(escrowRootType, error);
@@ -275,24 +292,53 @@ static bool SecXPC_OTAPKI_GetEscrowCertificates(xpc_object_t event, xpc_object_t
     return result;
 }
 
-static bool SecXPC_OTAPKI_GetNewAsset(xpc_object_t __unused event, xpc_object_t reply, CFErrorRef *error) {
+static bool SecXPC_OTAPKI_GetNewAsset(SecurityClient * __unused client, xpc_object_t __unused event,
+                                      xpc_object_t reply, CFErrorRef *error) {
     xpc_dictionary_set_uint64(reply, kSecXPCKeyResult, SecOTAPKISignalNewAsset(error));
     return true;
 }
 
-static bool SecXPC_TLS_AnalyticsReport(xpc_object_t event, xpc_object_t reply, CFErrorRef *error) {
+static bool SecXPC_Networking_AnalyticsReport(SecurityClient * __unused client, xpc_object_t event,
+                                       xpc_object_t reply, CFErrorRef *error) {
     xpc_object_t attributes = xpc_dictionary_get_dictionary(event, kSecTrustEventAttributesKey);
     CFStringRef eventName = SecXPCDictionaryCopyString(event, kSecTrustEventNameKey, error);
     bool result = false;
     if (attributes && eventName) {
-        result = SecTLSAnalyticsReport(eventName, attributes, error);
+        result = SecNetworkingAnalyticsReport(eventName, attributes, error);
     }
     xpc_dictionary_set_bool(reply, kSecXPCKeyResult, result);
     CFReleaseNull(eventName);
     return result;
 }
 
-typedef bool(*SecXPCOperationHandler)(xpc_object_t event, xpc_object_t reply, CFErrorRef *error);
+static bool SecXPCTrustStoreSetCTExceptions(SecurityClient *client, xpc_object_t event,
+                                            xpc_object_t reply, CFErrorRef *error) {
+    CFStringRef appID = NULL;
+    CFDictionaryRef exceptions = NULL;
+    if (!SecXPCDictionaryCopyStringOptional(event, kSecTrustEventApplicationID, &appID, error) || !appID) {
+        /* We always want to set the app ID with the exceptions */
+        appID = SecTaskCopyApplicationIdentifier(client->task);
+    }
+    (void)SecXPCDictionaryCopyDictionaryOptional(event, kSecTrustExceptionsKey, &exceptions, error);
+    bool result = _SecTrustStoreSetCTExceptions(appID, exceptions, error);
+    xpc_dictionary_set_bool(reply, kSecXPCKeyResult, result);
+    CFReleaseNull(exceptions);
+    CFReleaseNull(appID);
+    return false;
+}
+
+static bool SecXPCTrustStoreCopyCTExceptions(SecurityClient * __unused client, xpc_object_t event,
+                                             xpc_object_t reply, CFErrorRef *error) {
+    CFStringRef appID = NULL;
+    (void)SecXPCDictionaryCopyStringOptional(event, kSecTrustEventApplicationID, &appID, error);
+    CFDictionaryRef exceptions = _SecTrustStoreCopyCTExceptions(appID, error);
+    SecXPCDictionarySetPListOptional(reply, kSecTrustExceptionsKey, exceptions, error);
+    CFReleaseNull(exceptions);
+    CFReleaseNull(appID);
+    return false;
+}
+
+typedef bool(*SecXPCOperationHandler)(SecurityClient *client, xpc_object_t event, xpc_object_t reply, CFErrorRef *error);
 
 typedef struct {
     CFStringRef entitlement;
@@ -307,9 +353,12 @@ struct trustd_operations {
     SecXPCServerOperation trust_store_copy_usage_constraints;
     SecXPCServerOperation ocsp_cache_flush;
     SecXPCServerOperation ota_pki_trust_store_version;
+    SecXPCServerOperation ota_pki_asset_version;
     SecXPCServerOperation ota_pki_get_escrow_certs;
     SecXPCServerOperation ota_pki_get_new_asset;
-    SecXPCServerOperation tls_analytics_report;
+    SecXPCServerOperation networking_analytics_report;
+    SecXPCServerOperation trust_store_set_ct_exceptions;
+    SecXPCServerOperation trust_store_copy_ct_exceptions;
 };
 
 static struct trustd_operations trustd_ops = {
@@ -319,10 +368,13 @@ static struct trustd_operations trustd_ops = {
     .trust_store_copy_all = { kSecEntitlementModifyAnchorCertificates, SecXPCTrustStoreCopyAll },
     .trust_store_copy_usage_constraints = { kSecEntitlementModifyAnchorCertificates, SecXPCTrustStoreCopyUsageConstraints },
     .ocsp_cache_flush = { NULL, SecXPC_OCSPCacheFlush },
-    .ota_pki_trust_store_version = { NULL, SecXPC_OTAPKI_GetAssetVersion },
+    .ota_pki_trust_store_version = { NULL, SecXPC_OTAPKI_GetCurrentTrustStoreVersion },
+    .ota_pki_asset_version = { NULL, SecXPC_OTAPKI_GetCurrentAssetVersion },
     .ota_pki_get_escrow_certs = { NULL, SecXPC_OTAPKI_GetEscrowCertificates },
     .ota_pki_get_new_asset = { NULL, SecXPC_OTAPKI_GetNewAsset },
-    .tls_analytics_report = { NULL, SecXPC_TLS_AnalyticsReport },
+    .networking_analytics_report = { NULL, SecXPC_Networking_AnalyticsReport },
+    .trust_store_set_ct_exceptions = {kSecEntitlementModifyAnchorCertificates, SecXPCTrustStoreSetCTExceptions },
+    .trust_store_copy_ct_exceptions = {kSecEntitlementModifyAnchorCertificates, SecXPCTrustStoreCopyCTExceptions }
 };
 
 static void trustd_xpc_dictionary_handler(const xpc_connection_t connection, xpc_object_t event) {
@@ -446,14 +498,24 @@ static void trustd_xpc_dictionary_handler(const xpc_connection_t connection, xpc
                 case sec_ota_pki_trust_store_version_id:
                     server_op = &trustd_ops.ota_pki_trust_store_version;
                     break;
+                case sec_ota_pki_asset_version_id:
+                    server_op = &trustd_ops.ota_pki_asset_version;
+                    break;
                 case kSecXPCOpOTAGetEscrowCertificates:
                     server_op = &trustd_ops.ota_pki_get_escrow_certs;
                     break;
                 case kSecXPCOpOTAPKIGetNewAsset:
                     server_op = &trustd_ops.ota_pki_get_new_asset;
                     break;
-                case kSecXPCOpTLSAnaltyicsReport:
-                    server_op = &trustd_ops.tls_analytics_report;
+                case kSecXPCOpNetworkingAnalyticsReport:
+                    server_op = &trustd_ops.networking_analytics_report;
+                    break;
+                case kSecXPCOpSetCTExceptions:
+                    server_op = &trustd_ops.trust_store_set_ct_exceptions;
+                    break;
+                case kSecXPCOpCopyCTExceptions:
+                    server_op = &trustd_ops.trust_store_copy_ct_exceptions;
+                    break;
                 default:
                     break;
             }
@@ -463,7 +525,7 @@ static void trustd_xpc_dictionary_handler(const xpc_connection_t connection, xpc
                     entitled = EntitlementPresentAndTrue(operation, client.task, server_op->entitlement, &error);
                 }
                 if (entitled) {
-                    (void)server_op->handler(event, replyMessage, &error);
+                    (void)server_op->handler(&client, event, replyMessage, &error);
                 }
             }
         }
index 80c70e6caf066391403b8299bab1565b09130421..9ffdcdaab3b9325f1fcf2bf87e98c8febf7a6930 100644 (file)
@@ -347,17 +347,13 @@ __SecSetSecuritydTargetUID
 
 _SecDERItemCopyOIDDecimalRepresentation
 _SecDigestCreate
-#if TARGET_OS_IPHONE
 _SecFrameworkCopyResourceContents
 _SecFrameworkCopyResourceURL
-#endif
 _SecCopyErrorMessageString
 
 _SecPKCS12Import
 _SecRandomCopyBytes
-#if TARGET_OS_IPHONE
 _SecSHA1DigestCreate
-#endif
 _SecTaskCopySigningIdentifier
 _SecTaskCopyValueForEntitlement
 _SecTaskCopyValuesForEntitlements
@@ -1925,15 +1921,9 @@ _CopyCurrentScopePlist
 #endif
 
 // SecFramework.h
-#if TARGET_OS_IPHONE
 _SecOSStatusWith
 _SecSHA256DigestCreate
 _SecSHA256DigestCreateFromData
-#endif
-#if TARGET_OS_OSX
-_SecSHA256DigestCreate
-_SecSHA256DigestCreateFromData
-#endif
 
 _secLogObjForScope
 _secLogObjForCFScope
index cb162682e9115f5c39b20b73b7817a788ed1edae..b3e41b60e886842db66447f8bd46e72dcbea787f 100644 (file)
                D465131A2097FF2E005D93FE /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6CF4A0EB1E4549F300ECD7B5 /* Main.storyboard */; };
                D465131B2097FF2E005D93FE /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6CF4A0EE1E4549F300ECD7B5 /* Assets.xcassets */; };
                D465131C2097FF2E005D93FE /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6CF4A0F01E4549F300ECD7B5 /* LaunchScreen.storyboard */; };
+               D46A6C09215336BC008ABF6A /* SecFramework.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C0B906C0ACCBD240077CD03 /* SecFramework.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               D46B37A62151B7950083DAAA /* SecTrustStoreServer.m in Sources */ = {isa = PBXBuildFile; fileRef = D46B379F2151B6E50083DAAA /* SecTrustStoreServer.m */; };
                D479F6E21F980FAB00388D28 /* Trust.strings in Resources */ = {isa = PBXBuildFile; fileRef = D479F6DF1F980F8F00388D28 /* Trust.strings */; };
                D479F6E31F981FD600388D28 /* OID.strings in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4C198F1F0ACDB4BF00AAB142 /* OID.strings */; };
                D479F6E41F981FD600388D28 /* Certificate.strings in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4C198F1D0ACDB4BF00AAB142 /* Certificate.strings */; };
                D47CA65D1EB036450038E2BB /* libMobileGestalt.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = D47CA65C1EB036450038E2BB /* libMobileGestalt.dylib */; };
                D47E69401E92F75D002C8CF6 /* si-61-pkcs12.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DD91D8085FC00865A7C /* si-61-pkcs12.c */; };
                D47F514C1C3B812500A7CEFE /* SecCFAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = D47F514B1C3B812500A7CEFE /* SecCFAllocator.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               D484A1072167D707008653A9 /* ct_exceptions.m in Sources */ = {isa = PBXBuildFile; fileRef = D484A1012167D6F8008653A9 /* ct_exceptions.m */; };
                D487B9821DFA28DB000410A1 /* SecInternalReleasePriv.h in Headers */ = {isa = PBXBuildFile; fileRef = DC0BCC771D8C68CF00070CB0 /* SecInternalReleasePriv.h */; settings = {ATTRIBUTES = (Private, ); }; };
                D487B9881DFA2902000410A1 /* SecInternalReleasePriv.h in Headers */ = {isa = PBXBuildFile; fileRef = DC0BCC771D8C68CF00070CB0 /* SecInternalReleasePriv.h */; settings = {ATTRIBUTES = (Private, ); }; };
                D487FBB81DB8357300D4BB0B /* si-29-sectrust-sha1-deprecation.m in Sources */ = {isa = PBXBuildFile; fileRef = D487FBB71DB8357300D4BB0B /* si-29-sectrust-sha1-deprecation.m */; };
                4C4296300BB0A68200491999 /* SecTrustSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTrustSettings.h; path = trust/SecTrustSettings.h; sourceTree = "<group>"; };
                4C465C7D13AFD82300E841AC /* SecurityDevTests-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "SecurityDevTests-Info.plist"; sourceTree = "<group>"; };
                4C47FA8D20A51DC700384CB6 /* AppleFSCompression.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppleFSCompression.framework; path = System/Library/PrivateFrameworks/AppleFSCompression.framework; sourceTree = SDKROOT; };
-               4C4CB7100DDA44900026B660 /* entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = entitlements.plist; sourceTree = "<group>"; };
+               4C4CB7100DDA44900026B660 /* entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = entitlements.plist; path = SecurityTool/entitlements.plist; sourceTree = SOURCE_ROOT; };
                4C4CE9070AF81ED80056B01D /* TODO */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = TODO; sourceTree = "<group>"; };
                4C4CE9120AF81F0E0056B01D /* README */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
                4C50ACFC1410671D00EE92DE /* DigiNotarCA2007RootCertificate.crt */ = {isa = PBXFileReference; lastKnownFileType = file; path = DigiNotarCA2007RootCertificate.crt; sourceTree = "<group>"; };
                D43DBEFA1E99D17300C04AEA /* SecTrustStoreServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTrustStoreServer.h; path = OSX/sec/securityd/SecTrustStoreServer.h; sourceTree = "<group>"; };
                D43DDE511F620F09009742A5 /* SecPolicyChecks.list */ = {isa = PBXFileReference; lastKnownFileType = text; path = SecPolicyChecks.list; sourceTree = "<group>"; };
                D43DDE581F638061009742A5 /* SecPolicy.list */ = {isa = PBXFileReference; lastKnownFileType = text; path = SecPolicy.list; sourceTree = "<group>"; };
+               D442AD62215ADA250050B50F /* AppleCorporateRootCA2.cer */ = {isa = PBXFileReference; lastKnownFileType = file; name = AppleCorporateRootCA2.cer; path = OSX/trustd/iOS/AppleCorporateRootCA2.cer; sourceTree = "<group>"; };
+               D442AD68215ADA250050B50F /* AppleCorporateRootCA.cer */ = {isa = PBXFileReference; lastKnownFileType = file; name = AppleCorporateRootCA.cer; path = OSX/trustd/iOS/AppleCorporateRootCA.cer; sourceTree = "<group>"; };
                D44D08B420AB890E0023C439 /* Security.apinotes */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Security.apinotes; path = base/Security.apinotes; sourceTree = "<group>"; };
                D45068681E948A9E00FA7675 /* entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = entitlements.plist; path = OSX/trustd/macOS/entitlements.plist; sourceTree = "<group>"; };
                D45068691E948ACE00FA7675 /* entitlements.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = entitlements.plist; path = OSX/trustd/iOS/entitlements.plist; sourceTree = "<group>"; };
                D46246C31F9AEA5200D63882 /* libDER.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libDER.a; path = usr/local/lib/security_libDER/libDER.a; sourceTree = SDKROOT; };
                D46246CE1F9AEAE300D63882 /* libDER.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libDER.a; path = usr/local/lib/security_libDER/libDER.a; sourceTree = SDKROOT; };
                D46513072097954B005D93FE /* si-23-sectrust-ocsp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "si-23-sectrust-ocsp.h"; sourceTree = "<group>"; };
+               D46A6BF121531F77008ABF6A /* si-82-sectrust-ct.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "si-82-sectrust-ct.h"; path = "OSX/shared_regressions/si-82-sectrust-ct.h"; sourceTree = SOURCE_ROOT; };
+               D46B379F2151B6E50083DAAA /* SecTrustStoreServer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SecTrustStoreServer.m; path = OSX/sec/securityd/SecTrustStoreServer.m; sourceTree = "<group>"; };
                D479F6E01F980F8F00388D28 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/Trust.strings; sourceTree = "<group>"; };
                D47C56AB1DCA831C00E18518 /* lib_ios_x64.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = lib_ios_x64.xcconfig; path = xcconfig/lib_ios_x64.xcconfig; sourceTree = "<group>"; };
                D47C56AF1DCA841D00E18518 /* lib_ios_x64_shim.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = lib_ios_x64_shim.xcconfig; path = xcconfig/lib_ios_x64_shim.xcconfig; sourceTree = "<group>"; };
                D47C56FB1DCA8F4900E18518 /* all_arches.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = all_arches.xcconfig; path = xcconfig/all_arches.xcconfig; sourceTree = "<group>"; };
                D47CA65C1EB036450038E2BB /* libMobileGestalt.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libMobileGestalt.dylib; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS11.0.Internal.sdk/usr/lib/libMobileGestalt.dylib; sourceTree = DEVELOPER_DIR; };
                D47F514B1C3B812500A7CEFE /* SecCFAllocator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecCFAllocator.h; sourceTree = "<group>"; };
+               D484A1012167D6F8008653A9 /* ct_exceptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ct_exceptions.m; sourceTree = "<group>"; };
                D487FBB71DB8357300D4BB0B /* si-29-sectrust-sha1-deprecation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "si-29-sectrust-sha1-deprecation.m"; sourceTree = "<group>"; };
                D487FBB91DB835B500D4BB0B /* si-29-sectrust-sha1-deprecation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "si-29-sectrust-sha1-deprecation.h"; sourceTree = "<group>"; };
                D48BD193206C47530075DDC9 /* si-35-cms-expiration-time.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "si-35-cms-expiration-time.m"; sourceTree = "<group>"; };
                DC52EA4C1D80CB7000B0A59C /* libSecurityTool.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libSecurityTool.a; sourceTree = BUILT_PRODUCTS_DIR; };
                DC52EA8E1D80CC2A00B0A59C /* builtin_commands.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = builtin_commands.h; sourceTree = "<group>"; };
                DC52EA8F1D80CC2A00B0A59C /* digest_calc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = digest_calc.c; sourceTree = "<group>"; };
-               DC52EA901D80CC2A00B0A59C /* entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = entitlements.plist; sourceTree = "<group>"; };
+               DC52EA901D80CC2A00B0A59C /* entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = entitlements.plist; path = OSX/sec/SecurityTool/entitlements.plist; sourceTree = SOURCE_ROOT; };
                DC52EA911D80CC2A00B0A59C /* whoami.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = whoami.m; sourceTree = "<group>"; };
                DC52EA921D80CC2A00B0A59C /* syncbubble.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = syncbubble.m; sourceTree = "<group>"; };
                DC52EA931D80CC2A00B0A59C /* leaks.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = leaks.c; sourceTree = "<group>"; };
                        isa = PBXGroup;
                        children = (
                                DCE4E6A71D7A38C000AFB96E /* security2.1 */,
+                               DC52EA901D80CC2A00B0A59C /* entitlements.plist */,
                                E78A9AD81D34959200006B5B /* NSFileHandle+Formatting.h */,
                                E78A9AD91D34959200006B5B /* NSFileHandle+Formatting.m */,
-                               4C4CB7100DDA44900026B660 /* entitlements.plist */,
                                E7104A0B169E171900DB0045 /* security_tool_commands.c */,
                                D453C47F1FFD857400DE349B /* security_tool_commands.h */,
                                E7FEFB80169E26E200E18152 /* sub_commands.h */,
                DC52EA9B1D80CC2A00B0A59C /* SecurityTool iOS */ = {
                        isa = PBXGroup;
                        children = (
+                               4C4CB7100DDA44900026B660 /* entitlements.plist */,
                                DCC78E211D8085FC00865A7C /* keychain_backup.c */,
                                DC52EA8E1D80CC2A00B0A59C /* builtin_commands.h */,
                                DC52EA8F1D80CC2A00B0A59C /* digest_calc.c */,
-                               DC52EA901D80CC2A00B0A59C /* entitlements.plist */,
                                DC52EA911D80CC2A00B0A59C /* whoami.m */,
                                EB48C19E1E573EDC00EC5E57 /* sos.m */,
                                DC52EA921D80CC2A00B0A59C /* syncbubble.m */,
                                DCC78E021D8085FC00865A7C /* si-80-empty-data.c */,
                                DCC78E031D8085FC00865A7C /* si-82-seccertificate-ct.c */,
                                DCC78E041D8085FC00865A7C /* si-82-sectrust-ct.m */,
+                               D46A6BF121531F77008ABF6A /* si-82-sectrust-ct.h */,
                                DCC78E051D8085FC00865A7C /* si-82-token-ag.c */,
                                DCC78E061D8085FC00865A7C /* si-83-seccertificate-sighashalg.c */,
                                BE6215BD1DB6E69100961E15 /* si-84-sectrust-allowlist.m */,
                                DCC78E251D8085FC00865A7C /* show_certificates.c */,
                                D453C38A1FEC669300DE349B /* trust_update.m */,
                                DCC78E261D8085FC00865A7C /* spc.c */,
+                               D484A1012167D6F8008653A9 /* ct_exceptions.m */,
                        );
                        name = Security/Tool;
                        path = OSX/sec/Security/Tool;
                                D43DBEF71E99D17300C04AEA /* SecTrustServer.c */,
                                D43DBEF81E99D17300C04AEA /* SecTrustServer.h */,
                                D43DBEF91E99D17300C04AEA /* SecTrustStoreServer.c */,
+                               D46B379F2151B6E50083DAAA /* SecTrustStoreServer.m */,
                                D43DBEFA1E99D17300C04AEA /* SecTrustStoreServer.h */,
                                D4961BBD2079423300F16DA7 /* TrustURLSessionDelegate.m */,
                                D4961BC52079426000F16DA7 /* TrustURLSessionDelegate.h */,
                DCE4E85D1D7A584D00AFB96E /* iOS */ = {
                        isa = PBXGroup;
                        children = (
+                               D442AD68215ADA250050B50F /* AppleCorporateRootCA.cer */,
+                               D442AD62215ADA250050B50F /* AppleCorporateRootCA2.cer */,
                                D41257EE1E941DA800781F23 /* com.apple.trustd.plist */,
                                D45068691E948ACE00FA7675 /* entitlements.plist */,
                        );
                                EB10A3FC2035789B00E84270 /* OTConstants.h in Headers */,
                                DC1787591D7790B600B50D50 /* CMSPrivate.h in Headers */,
                                DC1785881D778B8000B50D50 /* CSCommon.h in Headers */,
+                               D46A6C09215336BC008ABF6A /* SecFramework.h in Headers */,
                                DC17874E1D7790A500B50D50 /* CSCommonPriv.h in Headers */,
                                DC1785A51D778D0D00B50D50 /* CipherSuite.h in Headers */,
                                DC1785871D778B8000B50D50 /* CodeSigning.h in Headers */,
                                D41257CB1E9410A300781F23 /* Sources */,
                                D41257CC1E9410A300781F23 /* Frameworks */,
                                D41257CD1E9410A300781F23 /* Copy LaunchDaemon */,
+                               D442AD70215C39100050B50F /* Install Apple Corporate Roots */,
                        );
                        buildRules = (
                        );
                        );
                        runOnlyForDeploymentPostprocessing = 1;
                        shellPath = /bin/sh;
-                       shellScript = "PLIST_FILE_NAME=com.apple.security.cloudkeychainproxy3\nFILE_TO_COPY=${PROJECT_DIR}/KVSKeychainSyncingProxy/${PLIST_FILE_NAME}.ios.plist\n\nif [ ${PLATFORM_NAME} = \"macosx\" ]\nthen\nFILE_TO_COPY=${PROJECT_DIR}/KVSKeychainSyncingProxy/${PLIST_FILE_NAME}.osx.plist\nfi\n\ncp ${FILE_TO_COPY} ${INSTALL_ROOT}/${INSTALL_DAEMON_AGENT_DIR}/${PLIST_FILE_NAME}.plist";
+                       shellScript = "PLIST_FILE_NAME=com.apple.security.cloudkeychainproxy3\nFILE_TO_COPY=${PROJECT_DIR}/KVSKeychainSyncingProxy/${PLIST_FILE_NAME}.ios.plist\n\nif [ ${PLATFORM_NAME} = \"macosx\" ]\nthen\nFILE_TO_COPY=${PROJECT_DIR}/KVSKeychainSyncingProxy/${PLIST_FILE_NAME}.osx.plist\nfi\n\ncp ${FILE_TO_COPY} ${INSTALL_ROOT}/${INSTALL_DAEMON_AGENT_DIR}/${PLIST_FILE_NAME}.plist\n";
+               };
+               D442AD70215C39100050B50F /* Install Apple Corporate Roots */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 8;
+                       files = (
+                       );
+                       inputFileListPaths = (
+                       );
+                       inputPaths = (
+                               "$(SRCROOT)/OSX/trustd/iOS/AppleCorporateRootCA.cer",
+                               "$(SRCROOT)/OSX/trustd/iOS/AppleCorporateRootCA2.cer",
+                       );
+                       name = "Install Apple Corporate Roots";
+                       outputFileListPaths = (
+                       );
+                       outputPaths = (
+                               "$(DSTROOT)/AppleInternal/Library/Security/AppleCorporateRootCA.cer",
+                               "$(DSTROOT)/AppleInternal/Library/Security/AppleCorporateRootCA2.cer",
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+                       shellPath = /bin/sh;
+                       shellScript = "ditto ${SRCROOT}/OSX/trustd/iOS/AppleCorporateRootCA.cer ${DSTROOT}/AppleInternal/Library/Security/\nditto ${SRCROOT}/OSX/trustd/iOS/AppleCorporateRootCA2.cer ${DSTROOT}/AppleInternal/Library/Security/\nchown -R root:wheel ${DSTROOT}/AppleInternal/Library/Security/\n";
                };
                D4C263C41F8FEAA8001317EA /* Run Script Generate Error Strings */ = {
                        isa = PBXShellScriptBuildPhase;
                                D43DBF071E99D1CA00C04AEA /* SecPinningDb.m in Sources */,
                                D43DBF081E99D1CA00C04AEA /* SecPolicyServer.c in Sources */,
                                D43DBF091E99D1CA00C04AEA /* SecRevocationDb.c in Sources */,
+                               D46B37A62151B7950083DAAA /* SecTrustStoreServer.m in Sources */,
                                D43DBF0A1E99D1CA00C04AEA /* SecRevocationServer.c in Sources */,
                                D43DBF0B1E99D1CA00C04AEA /* SecTrustLoggingServer.m in Sources */,
                                D4961BC42079424200F16DA7 /* TrustURLSessionDelegate.m in Sources */,
                                DC52EC191D80CF4C00B0A59C /* keychain_find.m in Sources */,
                                DC52EC181D80CF4700B0A59C /* log_control.c in Sources */,
                                DC52EC171D80CF4200B0A59C /* pkcs12_util.c in Sources */,
+                               D484A1072167D707008653A9 /* ct_exceptions.m in Sources */,
                                DC52EC161D80CF3B00B0A59C /* scep.c in Sources */,
                                DC52EC151D80CF0B00B0A59C /* show_certificates.c in Sources */,
                                DC52EC141D80CF0500B0A59C /* spc.c in Sources */,
                                COMBINE_HIDPI_IMAGES = YES;
                                DEBUG_INFORMATION_FORMAT = dwarf;
                                GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "NO_SERVER=1",
+                                       "FAKE_KEYSTORE=1",
+                                       "$(inherited)",
+                               );
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
                                INFOPLIST_FILE = tests/secdmockaks/Info.plist;
                                COMBINE_HIDPI_IMAGES = YES;
                                COPY_PHASE_STRIP = NO;
                                ENABLE_NS_ASSERTIONS = NO;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "NO_SERVER=1",
+                                       "FAKE_KEYSTORE=1",
+                                       "$(inherited)",
+                               );
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
                                INFOPLIST_FILE = tests/secdmockaks/Info.plist;
index 76050f4f2bfa54e358a123b09a3d48d13f3728f7..d6eeb2256e3512472001a0283875d54343a863ac 100644 (file)
@@ -234,7 +234,7 @@ extern NSString* const CKKSServerExtensionErrorDomain;
 
 /* Queue limits: these should likely be configurable via plist */
 #define SecCKKSOutgoingQueueItemsAtOnce 100
-#define SecCKKSIncomingQueueItemsAtOnce 10
+#define SecCKKSIncomingQueueItemsAtOnce 50
 
 // Utility functions
 NSString* SecCKKSHostOSVersion(void);
index 116c5070878656fe45833f940358fe7de069239b..f108eca33926f1bdb08d554fb780818b3576d419 100644 (file)
         if(listener && !alreadyRegisteredListener) {
             NSString* queueName = [NSString stringWithFormat: @"ck-account-state-%@", listener];
 
-            dispatch_queue_t objQueue = dispatch_queue_create([queueName UTF8String], DISPATCH_QUEUE_SERIAL);
+            dispatch_queue_t objQueue = dispatch_queue_create([queueName UTF8String], DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
             [self.changeListeners setObject: listener forKey: objQueue];
 
             secinfo("ckksaccount", "adding a new listener: %@", listener);
 
         dispatch_sync(self.queue, ^{
             self.firstCKAccountFetch = true;
+            secnotice("ckksaccount", "received CK Account info: %@", ckAccountInfo);
             [self _onqueueUpdateAccountState:ckAccountInfo circle:self.currentCircleStatus deliveredSemaphore:finishedSema];
         });
     }];
         return;
     }
 
-    if(![self.currentCKAccountInfo isEqual: ckAccountInfo]) {
+    if((self.currentCKAccountInfo == nil && ckAccountInfo != nil) ||
+       ![self.currentCKAccountInfo isEqual: ckAccountInfo]) {
         secnotice("ckksaccount", "moving to CK Account info: %@", ckAccountInfo);
         self.currentCKAccountInfo = ckAccountInfo;
 
         [self _onqueueUpdateCKDeviceID: ckAccountInfo];
     }
-    if(self.currentCircleStatus.status != sosstatus.status) {
+    if(![self.currentCircleStatus isEqual:sosstatus]) {
         secnotice("ckksaccount", "moving to circle status: %@", sosstatus);
         self.currentCircleStatus = sosstatus;
         if (sosstatus.status == kSOSCCInCircle) {
     return self;
 }
 
+- (BOOL)isEqual:(id)object
+{
+    if(![object isKindOfClass:[SOSAccountStatus class]]) {
+        return NO;
+    }
+
+    if(object == nil) {
+        return NO;
+    }
+
+    SOSAccountStatus* obj = (SOSAccountStatus*) object;
+    return self.status == obj.status &&
+            ((self.error == nil && obj.error == nil) || [self.error isEqual:obj.error]);
+}
+
 - (NSString*)description
 {
     return [NSString stringWithFormat:@"<SOSStatus: %@ (%@)>", SOSCCGetStatusDescription(self.status), self.error];
index 7407c313c43e4de2b541c1582013c4eb524dedd5..98849613d0f36feca85697ee18221f9f5c8a1cdf 100644 (file)
@@ -42,6 +42,8 @@ typedef NS_ENUM(NSUInteger, CKKSKnownBadState) {
 
 - (void)rpcStatus:(NSString* _Nullable)viewName
             reply:(void (^)(NSArray<NSDictionary*>* _Nullable result, NSError* _Nullable error))reply;
+- (void)rpcFastStatus:(NSString* _Nullable)viewName
+                reply:(void (^)(NSArray<NSDictionary*>* _Nullable result, NSError* _Nullable error))reply;
 - (void)rpcResetLocal:(NSString* _Nullable)viewName reply:(void (^)(NSError* _Nullable error))reply;
 - (void)rpcResetCloudKit:(NSString* _Nullable)viewName reply:(void (^)(NSError* _Nullable error))reply __deprecated_msg("use rpcResetCloudKit:reason:reply:");
 - (void)rpcResetCloudKit:(NSString* _Nullable)viewName reason:(NSString *)reason reply:(void (^)(NSError* _Nullable error))reply;
index f541e02fdab363de37a526141c40a620d18e48f1..1407f25c1dede85984979e5445c3bff244015359 100644 (file)
     }];
 }
 
+- (void)rpcFastStatus:(NSString*)viewName reply:(void(^)(NSArray<NSDictionary*>* result, NSError* error)) reply {
+    [[self.connection remoteObjectProxyWithErrorHandler: ^(NSError* error) {
+        reply(nil, error);
+
+    }] rpcFastStatus:viewName reply:^(NSArray<NSDictionary*>* result, NSError* error){
+        reply(result, error);
+    }];
+}
+
+
 - (void)rpcResetLocal:(NSString*)viewName reply:(void(^)(NSError* error))reply {
     [[self.connection remoteObjectProxyWithErrorHandler:^(NSError* error) {
         reply(error);
 }
 
 - (void)rpcTLKMissing:(NSString*)viewName reply:(void(^)(bool missing))reply {
-    [self rpcStatus:viewName reply:^(NSArray<NSDictionary*>* results, NSError* blockError) {
+    [self rpcFastStatus:viewName reply:^(NSArray<NSDictionary*>* results, NSError* blockError) {
         bool missing = false;
 
-        // Until PCS fixes [<rdar://problem/35103941> PCS: Remove PCS's use of CKKSControlProtocol], we can't add things to the protocol
-        // Use this hack
         for(NSDictionary* result in results) {
             NSString* name = result[@"view"];
             NSString* keystate = result[@"keystate"];
 }
 
 - (void)rpcKnownBadState:(NSString* _Nullable)viewName reply:(void (^)(CKKSKnownBadState))reply {
-    [self rpcStatus:viewName reply:^(NSArray<NSDictionary*>* results, NSError* blockError) {
+    [self rpcFastStatus:viewName reply:^(NSArray<NSDictionary*>* results, NSError* blockError) {
         bool tlkMissing = false;
         bool waitForUnlock = false;
 
         CKKSKnownBadState response = CKKSKnownStatePossiblyGood;
 
-        // We can now change this hack, but this change needs to be addition-only: <rdar://problem/36356681> CKKS: remove "global" hack from rpcStatus
-        // Use this hack
         for(NSDictionary* result in results) {
             NSString* name = result[@"view"];
             NSString* keystate = result[@"keystate"];
index ed1749b673a40e1745abc44698bca3bcc8db90d8..5b7054cafd37fecf19786ece06076ee5f9634af6 100644 (file)
 - (void)rpcResetCloudKit: (NSString*)viewName reason:(NSString *)reason reply: (void(^)(NSError* result)) reply;
 - (void)rpcResync:(NSString*)viewName reply: (void(^)(NSError* result)) reply;
 - (void)rpcResyncLocal:(NSString*)viewName reply:(void(^)(NSError* result))reply;
+/**
+ * Fetch status for the CKKS zones. If NULL is passed in a viewname, all zones are fetched.
+ */
 - (void)rpcStatus:(NSString*)viewName reply: (void(^)(NSArray<NSDictionary*>* result, NSError* error)) reply;
+/**
+ * Same as rpcStatus:reply: but avoid expensive operations (and thus don't report them). fastStatus doesn't include global status.
+ */
+- (void)rpcFastStatus:(NSString*)viewName reply: (void(^)(NSArray<NSDictionary*>* result, NSError* error)) reply;
 - (void)rpcFetchAndProcessChanges:(NSString*)viewName reply: (void(^)(NSError* result)) reply;
 - (void)rpcFetchAndProcessClassAChanges:(NSString*)viewName reply: (void(^)(NSError* result)) reply;
 - (void)rpcPushOutgoingChanges:(NSString*)viewName reply: (void(^)(NSError* result)) reply;
index 3821d8b145d6045fa05fed88ed23a963967c36ec..de2a7b2b015f0493514546fb9857334d01413486 100644 (file)
@@ -99,11 +99,13 @@ NSXPCInterface* CKKSSetupControlProtocol(NSXPCInterface* interface) {
         [interface setClasses:errClasses forSelector:@selector(rpcResync:reply:)                       argumentIndex:0 ofReply:YES];
         [interface setClasses:errClasses forSelector:@selector(rpcStatus:reply:)                       argumentIndex:0 ofReply:YES];
         [interface setClasses:errClasses forSelector:@selector(rpcStatus:reply:)                       argumentIndex:1 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(rpcFastStatus:reply:)                   argumentIndex:1 ofReply:YES];
         [interface setClasses:errClasses forSelector:@selector(rpcFetchAndProcessChanges:reply:)       argumentIndex:0 ofReply:YES];
         [interface setClasses:errClasses forSelector:@selector(rpcFetchAndProcessClassAChanges:reply:) argumentIndex:0 ofReply:YES];
         [interface setClasses:errClasses forSelector:@selector(rpcPushOutgoingChanges:reply:)          argumentIndex:0 ofReply:YES];
         [interface setClasses:errClasses forSelector:@selector(rpcGetCKDeviceIDWithReply:)             argumentIndex:0 ofReply:YES];
     }
+
     @catch(NSException* e) {
         secerror("CKKSSetupControlProtocol failed, continuing, but you might crash later: %@", e);
 #if DEBUG
index 4ead9621c6ee45c822297032a6972b1fdc1fc7be..66a6ba402d007b13d00ba3e89efefa85d63ee9f2 100644 (file)
@@ -46,7 +46,7 @@
         _operationQueue = [[NSOperationQueue alloc] init];
         _internalSuccesses = [[NSMutableArray alloc] init];
 
-        _queue = dispatch_queue_create("CKKSGroupOperationDispatchQueue", DISPATCH_QUEUE_SERIAL);
+        _queue = dispatch_queue_create("CKKSGroupOperationDispatchQueue", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
 
         // At start, we'll call this method (for subclasses)
         _startOperation = [NSBlockOperation blockOperationWithBlock:^{
index 3f8367004adc105a22f4c40f45e53ec6a8c1d026..3132c6d0fc7f675ec1af0d8f38c2badaf25b0849 100644 (file)
         }
     };
 
+    __block bool errored = false;
     [ckks dispatchSync: ^bool{
         if(self.cancelled) {
             ckksnotice("ckksincoming", ckks, "CKKSIncomingQueueOperation cancelled, quitting");
                 }
             }
         }
+        errored = !ok;
+        return ok;
+    }];
+
+    if(errored) {
+        ckksnotice("ckksincoming", ckks, "Early-exiting from IncomingQueueOperation");
+        return;
+    }
+
+    // Now for the tricky bit: take and drop the account queue for each batch of queue entries
+    // This is for peak memory concerns, but also to allow keychain API clients to make changes while we're processing many items
+    // Note that IncomingQueueOperations are no longer transactional: they can partially succeed. This might make them harder to reason about.
+    __block NSUInteger lastCount = SecCKKSIncomingQueueItemsAtOnce;
+    __block NSString* lastMaxUUID = nil;
 
-        // Iterate through all incoming queue entries a chunk at a time (for peak memory concerns)
-        NSArray<CKKSIncomingQueueEntry*> * queueEntries = nil;
-        NSString* lastMaxUUID = nil;
-        while(queueEntries == nil || queueEntries.count == SecCKKSIncomingQueueItemsAtOnce) {
+    while(lastCount == SecCKKSIncomingQueueItemsAtOnce) {
+        [ckks dispatchSync: ^bool{
+            NSArray<CKKSIncomingQueueEntry*> * queueEntries = nil;
             if(self.cancelled) {
                 ckksnotice("ckksincoming", ckks, "CKKSIncomingQueueOperation cancelled, quitting");
+                errored = true;
                 return false;
             }
 
+            NSError* error = nil;
+
             queueEntries = [CKKSIncomingQueueEntry fetch: SecCKKSIncomingQueueItemsAtOnce
                                           startingAtUUID:lastMaxUUID
                                                    state:SecCKKSStateNew
             if(error != nil) {
                 ckkserror("ckksincoming", ckks, "Error fetching incoming queue records: %@", error);
                 self.error = error;
+                errored = true;
                 return false;
             }
 
+            lastCount = queueEntries.count;
+
             if([queueEntries count] == 0) {
                 // Nothing to do! exit.
                 ckksnotice("ckksincoming", ckks, "Nothing in incoming queue to process");
-                break;
+                return true;
             }
 
             [CKKSPowerCollection CKKSPowerEvent:kCKKSPowerEventOutgoingQueue zone:ckks.zoneName count:[queueEntries count]];
 
             if (![self processQueueEntries:queueEntries withManifest:ckks.latestManifest egoManifest:ckks.egoManifest]) {
                 ckksnotice("ckksincoming", ckks, "processQueueEntries didn't complete successfully");
+                errored = true;
                 return false;
             }
 
             for(CKKSIncomingQueueEntry* iqe in queueEntries) {
                 lastMaxUUID = ([lastMaxUUID compare:iqe.uuid] == NSOrderedDescending) ? lastMaxUUID : iqe.uuid;
             };
+            return true;
+        }];
+
+        if(errored) {
+            ckksnotice("ckksincoming", ckks, "Early-exiting from IncomingQueueOperation");
+            return;
         }
+    }
 
-        // Process other queues: CKKSCurrentItemPointers
-        ckksnotice("ckksincoming", ckks, "Processed %lu items in incoming queue (%lu errors)", (unsigned long)self.successfulItemsProcessed, (unsigned long)self.errorItemsProcessed);
+    ckksnotice("ckksincoming", ckks, "Processed %lu items in incoming queue (%lu errors)", (unsigned long)self.successfulItemsProcessed, (unsigned long)self.errorItemsProcessed);
+
+    [ckks dispatchSync: ^bool{
+        NSError* error = nil;
 
         NSArray<CKKSCurrentItemPointer*>* newCIPs = [CKKSCurrentItemPointer remoteItemPointers:ckks.zoneID error:&error];
         if(error || !newCIPs) {
             [self.ckks processIncomingQueueAfterNextUnlock];
         }
 
-        return ok;
+        return true;
     }];
 }
 
index e1f7bf6a33f9e0aabdd287d61c946d99cb2920d5..b5ab8e2dccb6bcc113e6e45a934641b7a3083b3b 100644 (file)
@@ -265,8 +265,9 @@ NS_ASSUME_NONNULL_BEGIN
 @property NSHashTable<CKKSOutgoingQueueOperation*>* outgoingQueueOperations;
 @property CKKSScanLocalItemsOperation* initialScanOperation;
 
-// Returns the current state of this view
+// Returns the current state of this view, fastStatus is the same, but as name promise, no expensive calculations
 - (NSDictionary<NSString*, NSString*>*)status;
+- (NSDictionary<NSString*, NSString*>*)fastStatus;
 @end
 
 NS_ASSUME_NONNULL_END
index 4a958f083669a97e8e65cfa78610bdad9b5a00e7..965c28f212bccd6b7e5a9c1468872a4b3b1685f3 100644 (file)
 - (NSDictionary*)status {
 #define stringify(obj) CKKSNilToNSNull([obj description])
 #define boolstr(obj) (!!(obj) ? @"yes" : @"no")
-    __block NSDictionary* ret = nil;
+    __block NSMutableDictionary* ret = nil;
     __block NSError* error = nil;
-    CKKSManifest* manifest = [CKKSManifest latestTrustedManifestForZone:self.zoneName error:&error];
+    CKKSManifest* manifest = nil;
+
+    ret = [[self fastStatus] mutableCopy];
+
+    manifest = [CKKSManifest latestTrustedManifestForZone:self.zoneName error:&error];
     [self dispatchSync: ^bool {
 
         CKKSCurrentKeySet* keyset = [[CKKSCurrentKeySet alloc] initForZone:self.zoneID];
             [mutTLKShares addObject: [obj description]];
         }];
 
-
-        ret = @{
-                 @"view":                CKKSNilToNSNull(self.zoneName),
-                 @"ckaccountstatus":     self.accountStatus == CKAccountStatusCouldNotDetermine ? @"could not determine" :
-                                         self.accountStatus == CKAccountStatusAvailable         ? @"logged in" :
-                                         self.accountStatus == CKAccountStatusRestricted        ? @"restricted" :
-                                         self.accountStatus == CKAccountStatusNoAccount         ? @"logged out" : @"unknown",
-                 @"lockstatetracker":    stringify(self.lockStateTracker),
-                 @"accounttracker":      stringify(self.accountTracker),
-                 @"fetcher":             stringify(self.zoneChangeFetcher),
-                 @"zoneCreated":         boolstr(self.zoneCreated),
-                 @"zoneCreatedError":    stringify(self.zoneCreatedError),
-                 @"zoneSubscribed":      boolstr(self.zoneSubscribed),
-                 @"zoneSubscribedError": stringify(self.zoneSubscribedError),
-                 @"zoneInitializeScheduler": stringify(self.initializeScheduler),
-                 @"keystate":            CKKSNilToNSNull(self.keyHierarchyState),
-                 @"keyStateError":       stringify(self.keyHierarchyError),
+        [ret addEntriesFromDictionary:@{
                  @"statusError":         stringify(error),
                  @"oqe":                 CKKSNilToNSNull([CKKSOutgoingQueueEntry countsByStateInZone:self.zoneID error:&error]),
                  @"iqe":                 CKKSNilToNSNull([CKKSIncomingQueueEntry countsByStateInZone:self.zoneID error:&error]),
                  @"currentTLKPtr":       CKKSNilToNSNull(keyset.currentTLKPointer.currentKeyUUID),
                  @"currentClassAPtr":    CKKSNilToNSNull(keyset.currentClassAPointer.currentKeyUUID),
                  @"currentClassCPtr":    CKKSNilToNSNull(keyset.currentClassCPointer.currentKeyUUID),
-                 @"currentManifestGen":   CKKSNilToNSNull(manifestGeneration),
-
-
-                 @"zoneSetupOperation":                 stringify(self.zoneSetupOperation),
-                 @"keyStateOperation":                  stringify(self.keyStateMachineOperation),
-                 @"lastIncomingQueueOperation":         stringify(self.lastIncomingQueueOperation),
-                 @"lastNewTLKOperation":                stringify(self.lastNewTLKOperation),
-                 @"lastOutgoingQueueOperation":         stringify(self.lastOutgoingQueueOperation),
-                 @"lastProcessReceivedKeysOperation":   stringify(self.lastProcessReceivedKeysOperation),
-                 @"lastReencryptOutgoingItemsOperation":stringify(self.lastReencryptOutgoingItemsOperation),
-                 @"lastScanLocalItemsOperation":        stringify(self.lastScanLocalItemsOperation),
-                 };
+                 @"currentManifestGen":  CKKSNilToNSNull(manifestGeneration),
+            }];
         return false;
     }];
     return ret;
 }
 
+- (NSDictionary*)fastStatus {
+
+    __block NSDictionary* ret = nil;
+
+    [self dispatchSync: ^bool {
+
+        ret = @{
+            @"view":                CKKSNilToNSNull(self.zoneName),
+            @"ckaccountstatus":     self.accountStatus == CKAccountStatusCouldNotDetermine ? @"could not determine" :
+                self.accountStatus == CKAccountStatusAvailable         ? @"logged in" :
+                self.accountStatus == CKAccountStatusRestricted        ? @"restricted" :
+                self.accountStatus == CKAccountStatusNoAccount         ? @"logged out" : @"unknown",
+            @"lockstatetracker":    stringify(self.lockStateTracker),
+            @"accounttracker":      stringify(self.accountTracker),
+            @"fetcher":             stringify(self.zoneChangeFetcher),
+            @"zoneCreated":         boolstr(self.zoneCreated),
+            @"zoneCreatedError":    stringify(self.zoneCreatedError),
+            @"zoneSubscribed":      boolstr(self.zoneSubscribed),
+            @"zoneSubscribedError": stringify(self.zoneSubscribedError),
+            @"zoneInitializeScheduler": stringify(self.initializeScheduler),
+            @"keystate":            CKKSNilToNSNull(self.keyHierarchyState),
+            @"keyStateError":       stringify(self.keyHierarchyError),
+            @"statusError":         [NSNull null],
+
+            @"zoneSetupOperation":                 stringify(self.zoneSetupOperation),
+            @"keyStateOperation":                  stringify(self.keyStateMachineOperation),
+            @"lastIncomingQueueOperation":         stringify(self.lastIncomingQueueOperation),
+            @"lastNewTLKOperation":                stringify(self.lastNewTLKOperation),
+            @"lastOutgoingQueueOperation":         stringify(self.lastOutgoingQueueOperation),
+            @"lastProcessReceivedKeysOperation":   stringify(self.lastProcessReceivedKeysOperation),
+            @"lastReencryptOutgoingItemsOperation":stringify(self.lastReencryptOutgoingItemsOperation),
+            @"lastScanLocalItemsOperation":        stringify(self.lastScanLocalItemsOperation),
+        };
+        return false;
+    }];
 
+    return ret;
+}
 
 #endif /* OCTAGON */
 @end
index a0e5b82890bc093d892a133013f1a5c141dbb9d7..8502be8798a366b611dd2add9f70bed585ecb9a0 100644 (file)
@@ -46,7 +46,7 @@
 
 - (instancetype)init {
     if((self = [super init])) {
-        _queue = dispatch_queue_create("lock-state-tracker", DISPATCH_QUEUE_SERIAL);
+        _queue = dispatch_queue_create("lock-state-tracker", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
         _operationQueue = [[NSOperationQueue alloc] init];
 
         _isLocked = true;
index 0317a754cfe6310698f0630ad9d2ef68f61c2c3a..3fd193ac0079b0b01730500046bfaf1fe931828e 100644 (file)
@@ -61,7 +61,7 @@ callout(SCNetworkReachabilityRef reachability,
 
 - (instancetype)init {
     if((self = [super init])) {
-        _queue = dispatch_queue_create("reachabiltity-tracker", DISPATCH_QUEUE_SERIAL);
+        _queue = dispatch_queue_create("reachabiltity-tracker", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
         _operationQueue = [[NSOperationQueue alloc] init];
 
         dispatch_sync(_queue, ^{
index 559adb406d2ded68833abbbc9028dd6bc022c4a3..e36f1af68e3aeb334ca3f61ae1e3d3044eeddc06 100644 (file)
@@ -42,7 +42,7 @@
         _error = nil;
         _successDependencies = [[NSMutableArray alloc] init];
         _timeoutCanOccur = true;
-        _timeoutQueue = dispatch_queue_create("result-operation-timeout", DISPATCH_QUEUE_SERIAL);
+        _timeoutQueue = dispatch_queue_create("result-operation-timeout", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
         _completionHandlerDidRunCondition = [[CKKSCondition alloc] init];
 
         __weak __typeof(self) weakSelf = self;
index e5a091263bfa30031e28446b55967fc37f2ab36b..afd9afd2e9270e63f209c11a425a5bb22d315aae 100644 (file)
@@ -277,7 +277,7 @@ dispatch_once_t globalZoneStateQueueOnce;
 // Lazy-load it here.
 - (CKKSRateLimiter*)getGlobalRateLimiter {
     dispatch_once(&globalZoneStateQueueOnce, ^{
-        globalZoneStateQueue = dispatch_queue_create("CKKS global zone state", DISPATCH_QUEUE_SERIAL);
+        globalZoneStateQueue = dispatch_queue_create("CKKS global zone state", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
     });
 
     if(_globalRateLimiter != nil) {
@@ -805,7 +805,11 @@ dispatch_once_t globalZoneStateQueueOnce;
     [op timeout:120*NSEC_PER_SEC];
 }
 
-- (void)rpcStatus: (NSString*)viewName reply: (void(^)(NSArray<NSDictionary*>* result, NSError* error)) reply {
+- (void)rpcStatus: (NSString*)viewName
+           global:(bool)reportGlobal
+            reply:(void(^)(NSArray<NSDictionary*>* result, NSError* error)) reply
+        viewBlock:(NSDictionary * (^)(CKKSKeychainView* view))viewBlock
+{
     NSMutableArray* a = [[NSMutableArray alloc] init];
 
     // Now, query the views about their status
@@ -820,38 +824,40 @@ dispatch_once_t globalZoneStateQueueOnce;
     CKKSResultOperation* statusOp = [CKKSResultOperation named:@"status-rpc" withBlock:^{
         __strong __typeof(self) strongSelf = weakSelf;
 
-        // The first element is always the current global state (non-view-specific)
-        NSError* selfPeersError = nil;
-        CKKSSelves* selves = [strongSelf fetchSelfPeers:&selfPeersError];
-        NSError* trustedPeersError = nil;
-        NSSet<id<CKKSPeer>>* peers = [strongSelf fetchTrustedPeers:&trustedPeersError];
+        if (reportGlobal) {
+            // The first element is always the current global state (non-view-specific)
+            NSError* selfPeersError = nil;
+            CKKSSelves* selves = [strongSelf fetchSelfPeers:&selfPeersError];
+            NSError* trustedPeersError = nil;
+            NSSet<id<CKKSPeer>>* peers = [strongSelf fetchTrustedPeers:&trustedPeersError];
 
-        // Get account state, even wait for it a little
-        [self.accountTracker.ckdeviceIDInitialized wait:1*NSEC_PER_SEC];
-        NSString *deviceID = self.accountTracker.ckdeviceID;
-        NSError *deviceIDError = self.accountTracker.ckdeviceIDError;
+            // Get account state, even wait for it a little
+            [self.accountTracker.ckdeviceIDInitialized wait:1*NSEC_PER_SEC];
+            NSString *deviceID = self.accountTracker.ckdeviceID;
+            NSError *deviceIDError = self.accountTracker.ckdeviceIDError;
 
-        NSMutableArray<NSString*>* mutTrustedPeers = [[NSMutableArray alloc] init];
-        [peers enumerateObjectsUsingBlock:^(id<CKKSPeer>  _Nonnull obj, BOOL * _Nonnull stop) {
-            [mutTrustedPeers addObject: [obj description]];
-        }];
+            NSMutableArray<NSString*>* mutTrustedPeers = [[NSMutableArray alloc] init];
+            [peers enumerateObjectsUsingBlock:^(id<CKKSPeer>  _Nonnull obj, BOOL * _Nonnull stop) {
+                [mutTrustedPeers addObject: [obj description]];
+            }];
 
 #define stringify(obj) CKKSNilToNSNull([obj description])
-        NSDictionary* global = @{
-                                 @"view":                @"global",
-                                 @"selfPeers":           stringify(selves),
-                                 @"selfPeersError":      CKKSNilToNSNull(selfPeersError),
-                                 @"trustedPeers":        CKKSNilToNSNull(mutTrustedPeers),
-                                 @"trustedPeersError":   CKKSNilToNSNull(trustedPeersError),
-                                 @"reachability":        strongSelf.reachabilityTracker.currentReachability ? @"network" : @"no-network",
-                                 @"ckdeviceID":          CKKSNilToNSNull(deviceID),
-                                 @"ckdeviceIDError":     CKKSNilToNSNull(deviceIDError),
-        };
-        [a addObject: global];
+            NSDictionary* global = @{
+                                     @"view":                @"global",
+                                     @"selfPeers":           stringify(selves),
+                                     @"selfPeersError":      CKKSNilToNSNull(selfPeersError),
+                                     @"trustedPeers":        CKKSNilToNSNull(mutTrustedPeers),
+                                     @"trustedPeersError":   CKKSNilToNSNull(trustedPeersError),
+                                     @"reachability":        strongSelf.reachabilityTracker.currentReachability ? @"network" : @"no-network",
+                                     @"ckdeviceID":          CKKSNilToNSNull(deviceID),
+                                     @"ckdeviceIDError":     CKKSNilToNSNull(deviceIDError),
+                                     };
+            [a addObject: global];
+        }
 
         for(CKKSKeychainView* view in actualViews) {
             ckksnotice("ckks", view, "Fetching status for %@", view.zoneName);
-            NSDictionary* status = [view status];
+            NSDictionary* status = viewBlock(view);
             ckksinfo("ckks", view, "Status is %@", status);
             if(status) {
                 [a addObject: status];
@@ -879,6 +885,20 @@ dispatch_once_t globalZoneStateQueueOnce;
     return;
 }
 
+- (void)rpcStatus:(NSString*)viewName reply:(void (^)(NSArray<NSDictionary*>* result, NSError* error))reply
+{
+    [self rpcStatus:viewName global:true reply:reply viewBlock:^NSDictionary *(CKKSKeychainView *view) {
+        return [view status];
+    }];
+}
+
+- (void)rpcFastStatus:(NSString*)viewName reply:(void (^)(NSArray<NSDictionary*>* result, NSError* error))reply
+{
+    [self rpcStatus:viewName global:false reply:reply viewBlock:^NSDictionary *(CKKSKeychainView *view) {
+        return [view fastStatus];
+    }];
+}
+
 - (void)rpcFetchAndProcessChanges:(NSString*)viewName reply: (void(^)(NSError* result))reply {
     [self rpcFetchAndProcessChanges:viewName classA:false reply: (void(^)(NSError* result))reply];
 }
@@ -1246,7 +1266,7 @@ dispatch_once_t globalZoneStateQueueOnce;
         if(listener && !alreadyRegisteredListener) {
             NSString* queueName = [NSString stringWithFormat: @"ck-peer-change-%@", listener];
 
-            dispatch_queue_t objQueue = dispatch_queue_create([queueName UTF8String], DISPATCH_QUEUE_SERIAL);
+            dispatch_queue_t objQueue = dispatch_queue_create([queueName UTF8String], DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
             [self.peerChangeListeners setObject: listener forKey: objQueue];
         }
     }
index 7d47c88dc8d03ec08c5d79e775f5459ce6b04216..3a5dda69e02988753d869a4bab22d1995fb78cb5 100644 (file)
@@ -92,7 +92,7 @@
         _modifyRecordZonesOperationClass = modifyRecordZonesOperationClass;
         _apsConnectionClass = apsConnectionClass;
 
-        _queue = dispatch_queue_create([[NSString stringWithFormat:@"CKKSQueue.%@.zone.%@", container.containerIdentifier, zoneName] UTF8String], DISPATCH_QUEUE_SERIAL);
+        _queue = dispatch_queue_create([[NSString stringWithFormat:@"CKKSQueue.%@.zone.%@", container.containerIdentifier, zoneName] UTF8String], DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
         _operationQueue = [[NSOperationQueue alloc] init];
     }
     return self;
index 95edf9d0ed0739e77e74fb85faa775b0dada0089..2d60816ca9ace93509a3a2739aaf8e6576e8483b 100644 (file)
@@ -120,7 +120,7 @@ CKKSFetchBecause* const CKKSFetchBecauseResync = (CKKSFetchBecause*) @"resync";
         _clientMap = [NSMapTable strongToWeakObjectsMapTable];
 
         _name = @"zone-change-fetcher";
-        _queue = dispatch_queue_create([_name UTF8String], DISPATCH_QUEUE_SERIAL);
+        _queue = dispatch_queue_create([_name UTF8String], DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
         _operationQueue = [[NSOperationQueue alloc] init];
         _successfulFetchDependency = [self createSuccesfulFetchDependency];
 
index 7d31645897e82f29da5f3739e762a076d83ce1cd..9fc7a7c90961a9774b5b01232fb398add843d1e3 100644 (file)
         XCTAssertNotNil(keychainStatus, "Should have received at least one zone status back");
         XCTAssertEqualObjects(keychainStatus[@"view"], @"keychain", "Should have received status for the keychain view");
         XCTAssertEqualObjects(keychainStatus[@"keystate"], SecCKKSZoneKeyStateReady, "Should be in 'ready' status");
+        XCTAssertNotNil(keychainStatus[@"ckmirror"], "Status should have any ckmirror");
         [callbackOccurs fulfill];
     }];
 
     [self waitForExpectations:@[callbackOccurs] timeout:20];
 }
 
+- (void)testRpcFastStatus {
+    [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test.
+
+    [self startCKKSSubsystem];
+
+    // Let things shake themselves out.
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], "Key state should return to 'ready'");
+    [self waitForCKModifications];
+
+    XCTestExpectation* callbackOccurs = [self expectationWithDescription:@"callback-occurs"];
+    [self.ckksControl rpcFastStatus:@"keychain" reply:^(NSArray<NSDictionary*>* result, NSError* error) {
+        XCTAssertNil(error, "should be no error fetching status for keychain");
+
+        // Ugly "global" hack
+        XCTAssertEqual(result.count, 1u, "Should have received one result dictionaries back");
+        NSDictionary* keychainStatus = result[0];
+
+        XCTAssertNotNil(keychainStatus, "Should have received at least one zone status back");
+        XCTAssertEqualObjects(keychainStatus[@"view"], @"keychain", "Should have received status for the keychain view");
+        XCTAssertEqualObjects(keychainStatus[@"keystate"], SecCKKSZoneKeyStateReady, "Should be in 'ready' status");
+        XCTAssertNil(keychainStatus[@"ckmirror"], "fastStatus should not have any ckmirror");
+        [callbackOccurs fulfill];
+    }];
+
+    [self waitForExpectations:@[callbackOccurs] timeout:20];
+}
+
+
 - (void)testRpcStatusWaitsForAccountDetermination {
     [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test.
 
index ad6f29665dc8caa77dd3b164833389023190bac9..33ea65b40ff4e7c757f17f30695efd32f139a6ed 100644 (file)
     [self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D10" withAccount:@"account10"]];
     [self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D11" withAccount:@"account11"]];
 
+    for(int i = 12; i < 100; i++) {
+        @autoreleasepool {
+            NSString* recordName = [NSString stringWithFormat:@"7B598D31-F9C5-481E-98AC-%012d", i];
+            NSString* account = [NSString stringWithFormat:@"account%d", i];
+
+            [self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName:recordName withAccount:account]];
+        }
+    }
+
     // Trigger a notification (with hilariously fake data)
     [self.keychainView notifyZoneChange:nil];
 
     // test starts as if a previously logged-in device has just rebooted
     self.aksLockState = true;
     self.accountStatus = CKAccountStatusAvailable;
-    self.circleStatus = [[SOSAccountStatus alloc] init:kSOSCCError error:[NSError errorWithDomain:(__bridge id)kSOSErrorDomain code:kSOSErrorNotReady description:@"fake error: device is locked, so SOS doesn't know if it's in-circle"]];
 
+    // This is the original state of the account tracker
+    self.circleStatus = [[SOSAccountStatus alloc] init:kSOSCCError error:nil];
     [self.accountStateTracker notifyCircleStatusChangeAndWaitForSignal];
 
-    XCTAssertNil(self.accountStateTracker.currentAccountError, "Account tracker error should not yet exist");
-    XCTAssertEqual(self.accountStateTracker.currentAccountError.code, CKKSAccountStatusUnknown, "Account tracker error should just be 'no account'");
+    // And this is what the first circle status fetch will actually return
+    self.circleStatus = [[SOSAccountStatus alloc] init:kSOSCCError error:[NSError errorWithDomain:(__bridge id)kSOSErrorDomain code:kSOSErrorNotReady description:@"fake error: device is locked, so SOS doesn't know if it's in-circle"]];
+    [self.accountStateTracker notifyCircleStatusChangeAndWaitForSignal];
 
+    XCTAssertNil(self.accountStateTracker.currentAccountError, "Account tracker error should not yet exist");
+    XCTAssertEqual(self.accountStateTracker.currentComputedAccountStatus, CKKSAccountStatusUnknown, "Account tracker status should just be 'no account'");
     XCTAssertNotEqual(0, [self.keychainView.accountStateKnown wait:50*NSEC_PER_MSEC], "CKKS shouldn't know the account state yet");
 
     [self startCKKSSubsystem];
     XCTAssertNotEqual(0, [self.keychainView.loggedIn wait:100*NSEC_PER_MSEC], "'login' event shouldn't have happened");
     XCTAssertNotEqual(0, [self.keychainView.accountStateKnown wait:50*NSEC_PER_MSEC], "CKKS shouldn't know the account state yet");
 
+    // And assume another CK status change
+    [self.accountStateTracker notifyCKAccountStatusChangeAndWaitForSignal];
+    XCTAssertEqual(self.accountStateTracker.currentComputedAccountStatus, CKKSAccountStatusUnknown, "Account tracker status should just be 'no account'");
+    XCTAssertNotEqual(0, [self.keychainView.accountStateKnown wait:50*NSEC_PER_MSEC], "CKKS shouldn't know the account state yet");
+
     [self expectCKModifyKeyRecords: 3 currentKeyPointerRecords: 3 tlkShareRecords: 1 zoneID:self.keychainZoneID];
 
     self.aksLockState = false;
index f130b83fc90fff5c8ee67379a458ac9bc3a8528a..cac58a90bd331aa241d74426addc10b8d3811836 100644 (file)
 
         _fetchErrors = [[NSMutableArray alloc] init];
 
-        _queue = dispatch_queue_create("fake-ckzone", DISPATCH_QUEUE_SERIAL);
+        _queue = dispatch_queue_create("fake-ckzone", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
 
         dispatch_sync(_queue, ^{
             [self _onqueueRollChangeToken];
index b56f74c86d1d5544478c0f53f85e253d73e818f7..fb6330cfc9dad036f6b46942d162855293f409b1 100644 (file)
Binary files a/resources/English.lproj/Trust.strings and b/resources/English.lproj/Trust.strings differ
index da508f259330b3a9923cd35d59cbaf5426ce9131..50457bf2e731f7ec10a3b8ee806591aae2c00bf7 100644 (file)
             (id)kSecAttrNoLegacy : @(YES)
         };
         OSStatus result = SecItemAdd((__bridge CFDictionaryRef)item, NULL);
-        XCTAssertEqual(result, 0, @"failed to add test item to keychain: %u", n);
+        XCTAssertEqual(result, errSecSuccess, @"failed to add test item to keychain: %u", n);
     }
 }
 
                                (id)kSecAttrNoLegacy : @(YES)
                                };
         OSStatus result = SecItemCopyMatching((__bridge CFDictionaryRef)item, NULL);
-        XCTAssertEqual(result, 0, @"failed to find test item to keychain: %u", n);
+        XCTAssertEqual(result, errSecSuccess, @"failed to find test item to keychain: %u", n);
     }
 }
 
+- (void)testSecItemServerDeleteAll
+{
+    // BT root key, should not be deleted
+    NSMutableDictionary* bt = [@{
+                                 (id)kSecClass : (id)kSecClassGenericPassword,
+                                 (id)kSecAttrAccessGroup : @"com.apple.bluetooth",
+                                 (id)kSecAttrService : @"BluetoothGlobal",
+                                 (id)kSecAttrAccessible : (id)kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate,
+                                 (id)kSecAttrSynchronizable : @(NO),
+                                 (id)kSecValueData : [@"btkey" dataUsingEncoding:NSUTF8StringEncoding],
+                                 } mutableCopy];
+
+    // lockdown-identities, should not be deleted
+    NSMutableDictionary* ld = [@{
+                                 (id)kSecClass : (id)kSecClassKey,
+                                 (id)kSecAttrAccessGroup : @"lockdown-identities",
+                                 (id)kSecAttrLabel : @"com.apple.lockdown.identity.activation",
+                                 (id)kSecAttrAccessible : (id)kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate,
+                                 (id)kSecAttrSynchronizable : @(NO),
+                                 (id)kSecValueData : [@"ldkey" dataUsingEncoding:NSUTF8StringEncoding],
+                                 } mutableCopy];
+
+    // general nonsyncable item, should be deleted
+    NSMutableDictionary* s0 = [@{
+                                 (id)kSecClass : (id)kSecClassGenericPassword,
+                                 (id)kSecAttrService : @"NonsyncableService",
+                                 (id)kSecAttrSynchronizable : @(NO),
+                                 (id)kSecValueData : [@"s0pwd" dataUsingEncoding:NSUTF8StringEncoding],
+                                 } mutableCopy];
+
+    // general syncable item, should be deleted
+    NSMutableDictionary* s1 = [@{
+                                 (id)kSecClass : (id)kSecClassGenericPassword,
+                                 (id)kSecAttrService : @"SyncableService",
+                                 (id)kSecAttrSynchronizable : @(YES),
+                                 (id)kSecValueData : [@"s0pwd" dataUsingEncoding:NSUTF8StringEncoding],
+                                 } mutableCopy];
+
+    // Insert all items
+    OSStatus status;
+    status = SecItemAdd((__bridge CFDictionaryRef)bt, NULL);
+    XCTAssertEqual(status, errSecSuccess, "failed to add bt item to keychain");
+    status = SecItemAdd((__bridge CFDictionaryRef)ld, NULL);
+    XCTAssertEqual(status, errSecSuccess, "failed to add ld item to keychain");
+    status = SecItemAdd((__bridge CFDictionaryRef)s0, NULL);
+    XCTAssertEqual(status, errSecSuccess, "failed to add s0 item to keychain");
+    status = SecItemAdd((__bridge CFDictionaryRef)s1, NULL);
+    XCTAssertEqual(status, errSecSuccess, "failed to add s1 item to keychain");
+
+    // Make sure they exist now
+    bt[(id)kSecValueData] = nil;
+    ld[(id)kSecValueData] = nil;
+    s0[(id)kSecValueData] = nil;
+    s1[(id)kSecValueData] = nil;
+    status = SecItemCopyMatching((__bridge CFDictionaryRef)bt, NULL);
+    XCTAssertEqual(status, errSecSuccess, "failed to find bt item in keychain");
+    status = SecItemCopyMatching((__bridge CFDictionaryRef)ld, NULL);
+    XCTAssertEqual(status, errSecSuccess, "failed to find ld item in keychain");
+    status = SecItemCopyMatching((__bridge CFDictionaryRef)s0, NULL);
+    XCTAssertEqual(status, errSecSuccess, "failed to find s0 item in keychain");
+    status = SecItemCopyMatching((__bridge CFDictionaryRef)s1, NULL);
+    XCTAssertEqual(status, errSecSuccess, "failed to find s1 item in keychain");
+
+    // Nuke the keychain
+    CFErrorRef error = NULL;
+    _SecItemDeleteAll(&error);
+    XCTAssertEqual(error, NULL, "_SecItemDeleteAll returned an error: %@", error);
+    CFReleaseNull(error);
+
+    // Does the function work properly with an error pre-set?
+    error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainOSStatus, errSecItemNotFound, NULL);
+    _SecItemDeleteAll(&error);
+    XCTAssertEqual(CFErrorGetDomain(error), kCFErrorDomainOSStatus);
+    XCTAssertEqual(CFErrorGetCode(error), errSecItemNotFound);
+    CFReleaseNull(error);
+
+    // Check the relevant items are missing
+    status = SecItemCopyMatching((__bridge CFDictionaryRef)bt, NULL);
+    XCTAssertEqual(status, errSecSuccess, "failed to find bt item in keychain");
+    status = SecItemCopyMatching((__bridge CFDictionaryRef)ld, NULL);
+    XCTAssertEqual(status, errSecSuccess, "failed to find ld item in keychain");
+    status = SecItemCopyMatching((__bridge CFDictionaryRef)s0, NULL);
+    XCTAssertEqual(status, errSecItemNotFound, "unexpectedly found s0 item in keychain");
+    status = SecItemCopyMatching((__bridge CFDictionaryRef)s1, NULL);
+    XCTAssertEqual(status, errSecItemNotFound, "unexpectedly found s1 item in keychain");
+}
+
 - (void)createManyKeys
 {
     unsigned n;
index e7e6fbeeeb4de0bc6ea78369d1df381f54ac7cb9..0fd731f1587362deabf23d379828474d71e14646 100644 (file)
@@ -1831,6 +1831,7 @@ extern const CFStringRef kSecPolicyCheckBlackListedLeaf;
 extern const CFStringRef kSecPolicyCheckCertificatePolicy;
 extern const CFStringRef kSecPolicyCheckChainLength;
 extern const CFStringRef kSecPolicyCheckCriticalExtensions;
+extern const CFStringRef kSecPolicyCheckCTRequired;
 extern const CFStringRef kSecPolicyCheckEAPTrustedServerNames;
 extern const CFStringRef kSecPolicyCheckEmail;
 extern const CFStringRef kSecPolicyCheckExtendedKeyUsage;
@@ -1867,6 +1868,7 @@ extern const CFStringRef kSecPolicyCheckSubjectCommonNamePrefix;
 extern const CFStringRef kSecPolicyCheckSubjectCommonNameTEST;
 extern const CFStringRef kSecPolicyCheckSubjectOrganization;
 extern const CFStringRef kSecPolicyCheckSubjectOrganizationalUnit;
+extern const CFStringRef kSecPolicyCheckSystemTrustedCTRequired;
 extern const CFStringRef kSecPolicyCheckSystemTrustedWeakHash;
 extern const CFStringRef kSecPolicyCheckSystemTrustedWeakKey;
 extern const CFStringRef kSecPolicyCheckTemporalValidity;
@@ -1874,7 +1876,6 @@ extern const CFStringRef kSecPolicyCheckUsageConstraints;
 extern const CFStringRef kSecPolicyCheckValidRoot;
 extern const CFStringRef kSecPolicyCheckWeakKeySize;
 extern const CFStringRef kSecPolicyCheckWeakSignature;
-extern const CFStringRef kSecPolicyCheckCTRequired;
 
 /*  Special option for checking Apple Anchors */
 extern const CFStringRef kSecPolicyAppleAnchorIncludeTestRoots;
@@ -1933,6 +1934,8 @@ __nullable CFArrayRef SecPolicyXPCArrayCopyArray(xpc_object_t xpc_policies, CFEr
 
 void SecPolicySetOptionsValue(SecPolicyRef policy, CFStringRef key, CFTypeRef value);
 
+bool SecDNSIsTLD(CFStringRef reference);
+
 CF_IMPLICIT_BRIDGING_DISABLED
 CF_ASSUME_NONNULL_END
 
index e1eada2c1b2196bd2e815ed0edd4aca8c57dfdf6..439750e804e336ecb8ba5dc4253f62f49cb23ce6 100644 (file)
@@ -546,6 +546,19 @@ CFDictionaryRef SecTrustCopyResult(SecTrustRef trust)
 OSStatus SecTrustSetOCSPResponse(SecTrustRef trust, CFTypeRef __nullable responseData)
     __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0);
 
+/*!
+     @function SecTrustSignedCertificateTimestamps
+     @abstract Attach SignedCertificateTimestamp data to a trust object.
+     @param trust A reference to a trust object.
+     @param sctArray is a CFArray of CFData objects each containing a SCT (per RFC 6962).
+     @result A result code. See "Security Error Codes" (SecBase.h).
+     @discussion Allows the caller to provide SCT data (which may be
+     obtained during a TLS/SSL handshake, per RFC 6962) as input to a trust
+     evaluation.
+ */
+OSStatus SecTrustSetSignedCertificateTimestamps(SecTrustRef trust, CFArrayRef __nullable sctArray)
+    API_AVAILABLE(macos(10.14.2), ios(12.1.1), tvos(12.1.1), watchos(5.1.1));
+
 CF_IMPLICIT_BRIDGING_DISABLED
 CF_ASSUME_NONNULL_END
 
index 58656527664bf80184489e7bf7b2c49b7e56c724..9cbd5421d315a7535e13c5287d1f835cca4d5fe7 100644 (file)
@@ -254,6 +254,14 @@ CFStringRef SecTrustCopyFailureDescription(SecTrustRef trust);
  */
 uint64_t SecTrustGetTrustStoreVersionNumber(CFErrorRef _Nullable * _Nullable CF_RETURNS_RETAINED error);
 
+/*
+ @function SecTrustGetAssetVersionNumber
+ @abstract Ask trustd what asset version it is using.
+ @param error A returned error if trustd failed to answer.
+ @result The current version of the asset. 0 upon failure.
+ */
+uint64_t SecTrustGetAssetVersionNumber(CFErrorRef _Nullable * _Nullable CF_RETURNS_RETAINED error);
+
 /*
  @function SecTrustOTAPKIGetUpdatedAsset
  @abstract Trigger trustd to fetch a new trust supplementals asset right now.
@@ -276,18 +284,6 @@ uint64_t SecTrustOTAPKIGetUpdatedAsset(CFErrorRef _Nullable * _Nullable CF_RETUR
 Boolean SecTrustFlushResponseCache(CFErrorRef _Nullable * _Nullable CF_RETURNS_RETAINED error)
     __OSX_AVAILABLE(10.13.4) __IOS_AVAILABLE(11.3) __TVOS_AVAILABLE(11.3) __WATCHOS_AVAILABLE(4.3);
 
-/*!
- @function SecTrustSignedCertificateTimestampList
- @abstract Attach SignedCertificateTimestampList data to a trust object.
- @param trust A reference to a trust object.
- @param sctArray is a CFArray of CFData objects each containing a SCT (per RFC 6962).
- @result A result code. See "Security Error Codes" (SecBase.h).
- @discussion Allows the caller to provide SCT data (which may be
- obtained during a TLS/SSL handshake, per RFC 6962) as input to a trust
- evaluation.
- */
-OSStatus SecTrustSetSignedCertificateTimestamps(SecTrustRef trust, CFArrayRef sctArray);
-
 /*!
  @function SecTrustSetTrustedLogs
  @abstract Sets the trusted CT logs for a given trust.
@@ -438,6 +434,24 @@ OSStatus SecTrustEvaluateFastAsync(SecTrustRef trust, dispatch_queue_t queue, Se
 bool SecTrustReportTLSAnalytics(CFStringRef eventName, xpc_object_t eventAttributes, CFErrorRef _Nullable * _Nullable CF_RETURNS_RETAINED error)
     __API_AVAILABLE(macos(10.13.4), ios(11.3), tvos(11.3), watchos(4.3));
 
+/*!
+ @function SecTrustReportNetworkingAnalytics
+ @discussion This function MUST NOT be called outside of the networking stack.
+ */
+bool SecTrustReportNetworkingAnalytics(const char *eventName, xpc_object_t eventAttributes)
+__API_AVAILABLE(macos(10.14.1), ios(12.1), tvos(12.1), watchos(5.1));
+
+/*!
+ @function SecTrustSetNeedsEvaluation
+ @abstract Reset the evaluation state of the trust object
+ @param trust Trust object to reset
+ @discussion Calling this will reset the trust object so that the next time SecTrustEvaluate*
+ is called, a new trust evaluation is performed. SecTrustSet* interfaces implicitly call this,
+ so this function is only necessary if you've made system configuration changes (like trust
+ settings) that don't impact the trust object itself.
+ */
+void SecTrustSetNeedsEvaluation(SecTrustRef trust);
+
 CF_IMPLICIT_BRIDGING_DISABLED
 CF_ASSUME_NONNULL_END
 
index 89feb679bbd60d56529132c37e1a0267427df9e7..469fda9c645125e2121bd6a02313aa902aafd5fe 100644 (file)
@@ -50,6 +50,36 @@ __BEGIN_DECLS
 #define kSecTrustSettingsPolicyName               CFSTR("kSecTrustSettingsPolicyName")
 #define kSecTrustSettingsPolicyOptions            CFSTR("kSecTrustSettingsPolicyOptions")
 
+extern const CFStringRef kSecCTExceptionsCAsKey;
+extern const CFStringRef kSecCTExceptionsDomainsKey;
+extern const CFStringRef kSecCTExceptionsHashAlgorithmKey;
+extern const CFStringRef kSecCTExceptionsSPKIHashKey;
+
+/*
+ @function SecTrustStoreSetCTExceptions
+ @abstract Set the certificate transparency enforcement exceptions
+ @param applicationIdentifier Identifier for the caller. If null, the application-identifier will be read from the callers entitlements.
+ @param exceptions Dictionary of exceptions to set for this application. These exceptions replace existing exceptions for the keys in the dictionary. Exceptions for omitted keys are not affected. Null removes all exceptions for this application. See the discussion sections below for a complete overview of options.
+ @param error Upon failure describes cause of the failure.
+ @result boolean indicating success of the operation. If false, error will be filled in with a description of the error.
+ @discussions An exceptions dictionary has two optional keys:
+ kSecCTExceptionsDomainsKey takes an array of strings. These strings are the domains that are excluded from enforcing CT. A leading "." is supported to signify subdomains. Wildcard domains are not supported.
+ kSecCTExceptionsCAsKey takes an array of dictionaries. Each dictionary has two required keys:
+    kSecCTExceptionsHashAlgorithmKey takes a string indicating the hash algorithm. Currenlty only "sha256" is supported.
+    kSecCTExceptionsSPKIHashKey takes a data containing hash of a certificates SubjectPublicKeyInfo.
+ */
+bool SecTrustStoreSetCTExceptions(CFStringRef applicationIdentifier, CFDictionaryRef exceptions, CFErrorRef *error);
+
+/*
+ @function SecTrustStoreCopyCTExceptions
+ @abstract Return the certificate transparency enforcement exceptions
+ @param applicationIdentifier Identifier for the caller's exceptions to fetch. If null, all set exceptions will be returned (regardless of which caller set them).
+ @param error Upon failure describes cause of the failure.
+ @result The dictionary of currently set exceptions. Null if none exist or upon failure.
+ @discussion The returned exceptions dictionary has the same options as input exceptions. See the discussion of SecTrustStoreSetCTExceptions.
+ */
+CF_RETURNS_RETAINED CFDictionaryRef SecTrustStoreCopyCTExceptions(CFStringRef applicationIdentifier, CFErrorRef *error);
+
 #if SEC_OS_OSX
 
 /*