From 7512f6be898225cd564f3d305c36fa63eca9a60a Mon Sep 17 00:00:00 2001 From: Apple Date: Tue, 26 Mar 2019 22:07:09 +0000 Subject: [PATCH] Security-58286.230.21.tar.gz --- CircleJoinRequested/CircleJoinRequested.m | 15 - .../SecurityTests-Entitlements.plist | 2 + .../lib/SecStaticCode.cpp | 1 + .../lib/SecStaticCode.h | 1 + .../lib/StaticCode.cpp | 4 +- OSX/libsecurity_keychain/lib/SecKey.cpp | 31 +- .../lib/AppleManifest.cpp | 16 +- .../lib/ManifestInternal.cpp | 10 +- .../SecureObjectSync/SOSFullPeerInfo.m | 10 +- .../secitem/si-28-sectrustsettings.h | 240 ++++ .../secitem/si-28-sectrustsettings.m | 1 + .../secitem/si_77_SecAccessControl.c | 14 +- OSX/sec/Security/SecCertificate.c | 24 +- OSX/sec/Security/SecCertificateInternal.h | 2 + OSX/sec/Security/SecExports.exp-in | 13 + OSX/sec/Security/SecFrameworkStrings.h | 3 +- OSX/sec/Security/SecPolicy.c | 3 + OSX/sec/Security/SecPolicyChecks.list | 1 + OSX/sec/Security/SecPolicyLeafCallbacks.c | 2 +- OSX/sec/Security/SecTrust.c | 67 +- OSX/sec/Security/SecTrustInternal.h | 1 + OSX/sec/Security/SecTrustStore.c | 68 +- OSX/sec/Security/SecTrustStore.h | 4 + OSX/sec/Security/SecuritydXPC.c | 10 +- OSX/sec/Security/Tool/SecurityCommands.h | 21 + OSX/sec/Security/Tool/ct_exceptions.m | 331 +++++ OSX/sec/SecurityTool/entitlements.plist | 2 + OSX/sec/ipc/client.c | 9 +- OSX/sec/ipc/securityd_client.h | 10 +- OSX/sec/securityd/SecDbItem.c | 3 + OSX/sec/securityd/SecItemDb.c | 2 +- OSX/sec/securityd/SecItemDb.h | 2 + OSX/sec/securityd/SecItemServer.c | 54 +- OSX/sec/securityd/SecPinningDb.m | 21 +- OSX/sec/securityd/SecPolicyServer.c | 271 +++- OSX/sec/securityd/SecRevocationDb.c | 26 +- OSX/sec/securityd/SecRevocationDb.h | 1 + OSX/sec/securityd/SecTrustServer.c | 4 - OSX/sec/securityd/SecTrustStoreServer.c | 27 +- OSX/sec/securityd/SecTrustStoreServer.h | 3 + OSX/sec/securityd/SecTrustStoreServer.m | 249 ++++ OSX/sec/securityd/spi.c | 5 +- .../si-82-sectrust-ct-data/AppleISTCA8G1.cer | Bin 0 -> 856 bytes .../si-82-sectrust-ct-data/CTlogs.plist | 120 +- .../GeoTrustPrimaryCAG2.cer | Bin 0 -> 690 bytes .../GlobalSignRootCAR2.cer | Bin 0 -> 958 bytes .../si-82-sectrust-ct-data/GoogleIAG3.cer | Bin 0 -> 1120 bytes .../enforcement_apple_ca.cer | Bin 0 -> 1020 bytes .../enforcement_apple_root.cer | Bin 0 -> 1215 bytes .../enforcement_apple_server_after.cer | Bin 0 -> 1221 bytes ...rcement_system_constrained_fail_server.cer | Bin 0 -> 1005 bytes ...cement_system_constrained_no_dn_server.cer | Bin 0 -> 996 bytes ...stem_constrained_no_dn_server_mismatch.cer | Bin 0 -> 1019 bytes ...rcement_system_constrained_no_dn_subca.cer | Bin 0 -> 990 bytes ...ement_system_constrained_no_org_server.cer | Bin 0 -> 997 bytes ...tem_constrained_no_org_server_mismatch.cer | Bin 0 -> 1020 bytes ...cement_system_constrained_no_org_subca.cer | Bin 0 -> 1045 bytes .../enforcement_system_constrained_server.cer | Bin 0 -> 990 bytes ...rcement_system_constrained_server_scts.cer | Bin 0 -> 1263 bytes .../enforcement_system_constrained_subca.cer | Bin 0 -> 1059 bytes .../enforcement_system_root.cer | Bin 0 -> 926 bytes .../enforcement_system_server_after.cer | Bin 0 -> 981 bytes .../enforcement_system_server_after_scts.cer | Bin 0 -> 1279 bytes .../enforcement_system_server_before.cer | Bin 0 -> 982 bytes ...nforcement_system_server_matching_orgs.cer | Bin 0 -> 1059 bytes ...ement_system_server_matching_orgs_scts.cer | Bin 0 -> 1335 bytes .../enforcement_system_server_no_orgs.cer | Bin 0 -> 1000 bytes ...rcement_system_server_nonmatching_orgs.cer | Bin 0 -> 1032 bytes ...enforcement_system_server_partial_orgs.cer | Bin 0 -> 1035 bytes ...enforcement_system_unconstrained_subca.cer | Bin 0 -> 987 bytes .../enforcement_user_root.cer | Bin 0 -> 922 bytes .../enforcement_user_server_after.cer | Bin 0 -> 979 bytes .../si-82-sectrust-ct-data/google.cer | Bin 0 -> 1995 bytes .../si-82-sectrust-ct-data/livability.cer | Bin 0 -> 1087 bytes .../si-82-sectrust-ct-data/precert.cer | Bin 0 -> 1012 bytes OSX/shared_regressions/si-82-sectrust-ct.h | 56 + OSX/shared_regressions/si-82-sectrust-ct.m | 1129 ++++++++++++++++- OSX/trustd/iOS/AppleCorporateRootCA.cer | Bin 0 -> 949 bytes OSX/trustd/iOS/AppleCorporateRootCA2.cer | Bin 0 -> 585 bytes OSX/trustd/macOS/entitlements.plist | 2 + OSX/trustd/trustd.c | 100 +- Security.exp-in | 10 - Security.xcodeproj/project.pbxproj | 59 +- keychain/ckks/CKKS.h | 2 +- keychain/ckks/CKKSCKAccountStateTracker.m | 23 +- keychain/ckks/CKKSControl.h | 2 + keychain/ckks/CKKSControl.m | 18 +- keychain/ckks/CKKSControlProtocol.h | 7 + keychain/ckks/CKKSControlProtocol.m | 2 + keychain/ckks/CKKSGroupOperation.m | 2 +- keychain/ckks/CKKSIncomingQueueOperation.m | 46 +- keychain/ckks/CKKSKeychainView.h | 3 +- keychain/ckks/CKKSKeychainView.m | 77 +- keychain/ckks/CKKSLockStateTracker.m | 2 +- keychain/ckks/CKKSReachabilityTracker.m | 2 +- keychain/ckks/CKKSResultOperation.m | 2 +- keychain/ckks/CKKSViewManager.m | 76 +- keychain/ckks/CKKSZone.m | 2 +- keychain/ckks/CKKSZoneChangeFetcher.m | 2 +- keychain/ckks/tests/CKKSTests+API.m | 30 + keychain/ckks/tests/CKKSTests.m | 24 +- keychain/ckks/tests/MockCloudKit.m | 2 +- resources/English.lproj/Trust.strings | Bin 16128 -> 16552 bytes tests/secdmockaks/secdmockaks.m | 91 +- trust/SecPolicyPriv.h | 5 +- trust/SecTrust.h | 13 + trust/SecTrustPriv.h | 38 +- trust/SecTrustSettingsPriv.h | 30 + 108 files changed, 3225 insertions(+), 336 deletions(-) create mode 100644 OSX/sec/Security/Tool/ct_exceptions.m create mode 100644 OSX/sec/securityd/SecTrustStoreServer.m create mode 100644 OSX/shared_regressions/si-82-sectrust-ct-data/AppleISTCA8G1.cer create mode 100644 OSX/shared_regressions/si-82-sectrust-ct-data/GeoTrustPrimaryCAG2.cer create mode 100644 OSX/shared_regressions/si-82-sectrust-ct-data/GlobalSignRootCAR2.cer create mode 100644 OSX/shared_regressions/si-82-sectrust-ct-data/GoogleIAG3.cer create mode 100644 OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_apple_ca.cer create mode 100644 OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_apple_root.cer create mode 100644 OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_apple_server_after.cer create mode 100644 OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_fail_server.cer create mode 100644 OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_dn_server.cer create mode 100644 OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_dn_server_mismatch.cer create mode 100644 OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_dn_subca.cer create mode 100644 OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_org_server.cer create mode 100644 OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_org_server_mismatch.cer create mode 100644 OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_org_subca.cer create mode 100644 OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_server.cer create mode 100644 OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_server_scts.cer create mode 100644 OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_subca.cer create mode 100644 OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_root.cer create mode 100644 OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_after.cer create mode 100644 OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_after_scts.cer create mode 100644 OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_before.cer create mode 100644 OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_matching_orgs.cer create mode 100644 OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_matching_orgs_scts.cer create mode 100644 OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_no_orgs.cer create mode 100644 OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_nonmatching_orgs.cer create mode 100644 OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_partial_orgs.cer create mode 100644 OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_unconstrained_subca.cer create mode 100644 OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_user_root.cer create mode 100644 OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_user_server_after.cer create mode 100644 OSX/shared_regressions/si-82-sectrust-ct-data/google.cer create mode 100644 OSX/shared_regressions/si-82-sectrust-ct-data/livability.cer create mode 100644 OSX/shared_regressions/si-82-sectrust-ct-data/precert.cer create mode 100644 OSX/shared_regressions/si-82-sectrust-ct.h create mode 100644 OSX/trustd/iOS/AppleCorporateRootCA.cer create mode 100644 OSX/trustd/iOS/AppleCorporateRootCA2.cer diff --git a/CircleJoinRequested/CircleJoinRequested.m b/CircleJoinRequested/CircleJoinRequested.m index 1cbf8ad1..3236a2bb 100644 --- a/CircleJoinRequested/CircleJoinRequested.m +++ b/CircleJoinRequested/CircleJoinRequested.m @@ -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) { diff --git a/OSX/SecurityTestsOSX/SecurityTests-Entitlements.plist b/OSX/SecurityTestsOSX/SecurityTests-Entitlements.plist index 39da8b2f..01ffca58 100644 --- a/OSX/SecurityTestsOSX/SecurityTests-Entitlements.plist +++ b/OSX/SecurityTestsOSX/SecurityTests-Entitlements.plist @@ -24,6 +24,8 @@ application-identifier com.apple.security.regressions + com.apple.application-identifier + com.apple.security.regressions com.apple.private.uninstall.deletion com.apple.private.security.delete.all diff --git a/OSX/libsecurity_codesigning/lib/SecStaticCode.cpp b/OSX/libsecurity_codesigning/lib/SecStaticCode.cpp index 6e54a079..5ee92582 100644 --- a/OSX/libsecurity_codesigning/lib/SecStaticCode.cpp +++ b/OSX/libsecurity_codesigning/lib/SecStaticCode.cpp @@ -123,6 +123,7 @@ OSStatus SecStaticCodeCheckValidityWithErrors(SecStaticCodeRef staticCodeRef, Se | kSecCSRestrictToAppLike | kSecCSUseSoftwareSigningCert | kSecCSValidatePEH + | kSecCSSingleThreaded ); if (errors) diff --git a/OSX/libsecurity_codesigning/lib/SecStaticCode.h b/OSX/libsecurity_codesigning/lib/SecStaticCode.h index 1183adca..b053623e 100644 --- a/OSX/libsecurity_codesigning/lib/SecStaticCode.h +++ b/OSX/libsecurity_codesigning/lib/SecStaticCode.h @@ -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, diff --git a/OSX/libsecurity_codesigning/lib/StaticCode.cpp b/OSX/libsecurity_codesigning/lib/StaticCode.cpp index 7458d53b..74038fcc 100644 --- a/OSX/libsecurity_codesigning/lib/StaticCode.cpp +++ b/OSX/libsecurity_codesigning/lib/StaticCode.cpp @@ -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 { diff --git a/OSX/libsecurity_keychain/lib/SecKey.cpp b/OSX/libsecurity_keychain/lib/SecKey.cpp index bcefe83e..6fb96593 100644 --- a/OSX/libsecurity_keychain/lib/SecKey.cpp +++ b/OSX/libsecurity_keychain/lib/SecKey.cpp @@ -830,10 +830,35 @@ namespace Security { if (key->cdsaKey == NULL) { // Create CDSA key from exported data of existing key. - CFRef keyData = SecKeyCopyExternalRepresentation(key, NULL); CFRef keyAttributes = SecKeyCopyAttributes(key); - if (keyData && keyAttributes) { - key->cdsaKey = SecKeyCreateFromData(keyAttributes, keyData, NULL); + if (keyAttributes) { + CFRef 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 query = CFDictionaryCreate(kCFAllocatorDefault, keys, values, + sizeof(keys) / sizeof(*keys), + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + CFRef identities; + OSStatus status = SecItemCopyMatching(query, (CFTypeRef *)identities.take()); + if (status == errSecSuccess) { + for (int i = 0; i < CFArrayGetCount(identities); ++i) { + CFRef privateKey; + if (SecIdentityCopyPrivateKey((SecIdentityRef)CFArrayGetValueAtIndex(identities, i), privateKey.take()) != errSecSuccess) { + continue; + } + CFRef attrs = SecKeyCopyAttributes(privateKey); + if (CFEqual(CFDictionaryGetValue(attrs, kSecAttrApplicationLabel), pubKeyHash)) { + key->cdsaKey = privateKey.retain(); + break; + } + } + } + } else { + key->cdsaKey = SecKeyCreateFromData(keyAttributes, keyData, NULL); + } } } diff --git a/OSX/libsecurity_manifest/lib/AppleManifest.cpp b/OSX/libsecurity_manifest/lib/AppleManifest.cpp index b1dc1e72..c7d3429f 100644 --- a/OSX/libsecurity_manifest/lib/AppleManifest.cpp +++ b/OSX/libsecurity_manifest/lib/AppleManifest.cpp @@ -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 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; diff --git a/OSX/libsecurity_manifest/lib/ManifestInternal.cpp b/OSX/libsecurity_manifest/lib/ManifestInternal.cpp index c771e478..852639cc 100644 --- a/OSX/libsecurity_manifest/lib/ManifestInternal.cpp +++ b/OSX/libsecurity_manifest/lib/ManifestInternal.cpp @@ -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 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 diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSFullPeerInfo.m b/OSX/sec/SOSCircle/SecureObjectSync/SOSFullPeerInfo.m index 86b33c54..30bf5d7d 100644 --- a/OSX/sec/SOSCircle/SecureObjectSync/SOSFullPeerInfo.m +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSFullPeerInfo.m @@ -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) diff --git a/OSX/sec/Security/Regressions/secitem/si-28-sectrustsettings.h b/OSX/sec/Security/Regressions/secitem/si-28-sectrustsettings.h index 040bd530..e379eb34 100644 --- a/OSX/sec/Security/Regressions/secitem/si-28-sectrustsettings.h +++ b/OSX/sec/Security/Regressions/secitem/si-28-sectrustsettings.h @@ -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 */ diff --git a/OSX/sec/Security/Regressions/secitem/si-28-sectrustsettings.m b/OSX/sec/Security/Regressions/secitem/si-28-sectrustsettings.m index 66aa2eb7..3e24ded8 100644 --- a/OSX/sec/Security/Regressions/secitem/si-28-sectrustsettings.m +++ b/OSX/sec/Security/Regressions/secitem/si-28-sectrustsettings.m @@ -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 diff --git a/OSX/sec/Security/Regressions/secitem/si_77_SecAccessControl.c b/OSX/sec/Security/Regressions/secitem/si_77_SecAccessControl.c index a5ed23cc..ec8251e0 100644 --- a/OSX/sec/Security/Regressions/secitem/si_77_SecAccessControl.c +++ b/OSX/sec/Security/Regressions/secitem/si_77_SecAccessControl.c @@ -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; diff --git a/OSX/sec/Security/SecCertificate.c b/OSX/sec/Security/SecCertificate.c index 1b466635..15302c73 100644 --- a/OSX/sec/Security/SecCertificate.c +++ b/OSX/sec/Security/SecCertificate.c @@ -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, diff --git a/OSX/sec/Security/SecCertificateInternal.h b/OSX/sec/Security/SecCertificateInternal.h index 51d9c7d4..5ad1107a 100644 --- a/OSX/sec/Security/SecCertificateInternal.h +++ b/OSX/sec/Security/SecCertificateInternal.h @@ -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); diff --git a/OSX/sec/Security/SecExports.exp-in b/OSX/sec/Security/SecExports.exp-in index d9f013ec..8f243e70 100644 --- a/OSX/sec/Security/SecExports.exp-in +++ b/OSX/sec/Security/SecExports.exp-in @@ -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 diff --git a/OSX/sec/Security/SecFrameworkStrings.h b/OSX/sec/Security/SecFrameworkStrings.h index 774afb92..10943094 100644 --- a/OSX/sec/Security/SecFrameworkStrings.h +++ b/OSX/sec/Security/SecFrameworkStrings.h @@ -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") diff --git a/OSX/sec/Security/SecPolicy.c b/OSX/sec/Security/SecPolicy.c index 661f3a2f..0b735109 100644 --- a/OSX/sec/Security/SecPolicy.c +++ b/OSX/sec/Security/SecPolicy.c @@ -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); diff --git a/OSX/sec/Security/SecPolicyChecks.list b/OSX/sec/Security/SecPolicyChecks.list index 6d28fd46..5564b41a 100644 --- a/OSX/sec/Security/SecPolicyChecks.list +++ b/OSX/sec/Security/SecPolicyChecks.list @@ -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 ********************* diff --git a/OSX/sec/Security/SecPolicyLeafCallbacks.c b/OSX/sec/Security/SecPolicyLeafCallbacks.c index 843e2fe6..be1d616a 100644 --- a/OSX/sec/Security/SecPolicyLeafCallbacks.c +++ b/OSX/sec/Security/SecPolicyLeafCallbacks.c @@ -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; diff --git a/OSX/sec/Security/SecTrust.c b/OSX/sec/Security/SecTrust.c index 01b079b9..32b66370 100644 --- a/OSX/sec/Security/SecTrust.c +++ b/OSX/sec/Security/SecTrust.c @@ -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)); diff --git a/OSX/sec/Security/SecTrustInternal.h b/OSX/sec/Security/SecTrustInternal.h index fcb0962e..271da23b 100644 --- a/OSX/sec/Security/SecTrustInternal.h +++ b/OSX/sec/Security/SecTrustInternal.h @@ -60,6 +60,7 @@ CFArrayRef SecTrustCopyProperties_ios(SecTrustRef trust); #define kSecTrustEventNameKey "eventName" #define kSecTrustEventAttributesKey "eventAttributes" +#define kSecTrustEventApplicationID "appID" __END_DECLS diff --git a/OSX/sec/Security/SecTrustStore.c b/OSX/sec/Security/SecTrustStore.c index d070c835..e24be104 100644 --- a/OSX/sec/Security/SecTrustStore.c +++ b/OSX/sec/Security/SecTrustStore.c @@ -44,6 +44,7 @@ #include #include #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; +} diff --git a/OSX/sec/Security/SecTrustStore.h b/OSX/sec/Security/SecTrustStore.h index bc47013b..1458137b 100644 --- a/OSX/sec/Security/SecTrustStore.h +++ b/OSX/sec/Security/SecTrustStore.h @@ -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. */ diff --git a/OSX/sec/Security/SecuritydXPC.c b/OSX/sec/Security/SecuritydXPC.c index a9afea35..0f9d04e9 100644 --- a/OSX/sec/Security/SecuritydXPC.c +++ b/OSX/sec/Security/SecuritydXPC.c @@ -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"); } diff --git a/OSX/sec/Security/Tool/SecurityCommands.h b/OSX/sec/Security/Tool/SecurityCommands.h index 675393cf..a49bc614 100644 --- a/OSX/sec/Security/Tool/SecurityCommands.h +++ b/OSX/sec/Security/Tool/SecurityCommands.h @@ -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 index 00000000..fce20101 --- /dev/null +++ b/OSX/sec/Security/Tool/ct_exceptions.m @@ -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 +#include +#include +#include +#include + +#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*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; +} diff --git a/OSX/sec/SecurityTool/entitlements.plist b/OSX/sec/SecurityTool/entitlements.plist index ab650a4a..02f42d08 100644 --- a/OSX/sec/SecurityTool/entitlements.plist +++ b/OSX/sec/SecurityTool/entitlements.plist @@ -15,6 +15,8 @@ application-identifier com.apple.security + com.apple.application-identifier + com.apple.security com.apple.private.keychain.keychaincontrol diff --git a/OSX/sec/ipc/client.c b/OSX/sec/ipc/client.c index c2b1c383..c959b9fe 100644 --- a/OSX/sec/ipc/client.c +++ b/OSX/sec/ipc/client.c @@ -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; diff --git a/OSX/sec/ipc/securityd_client.h b/OSX/sec/ipc/securityd_client.h index 496f67a4..ee7a94c8 100644 --- a/OSX/sec/ipc/securityd_client.h +++ b/OSX/sec/ipc/securityd_client.h @@ -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; diff --git a/OSX/sec/securityd/SecDbItem.c b/OSX/sec/securityd/SecDbItem.c index 2eaffdae..7e25b4d6 100644 --- a/OSX/sec/securityd/SecDbItem.c +++ b/OSX/sec/securityd/SecDbItem.c @@ -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) { diff --git a/OSX/sec/securityd/SecItemDb.c b/OSX/sec/securityd/SecItemDb.c index 54b6f794..4128cafc 100644 --- a/OSX/sec/securityd/SecItemDb.c +++ b/OSX/sec/securityd/SecItemDb.c @@ -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; diff --git a/OSX/sec/securityd/SecItemDb.h b/OSX/sec/securityd/SecItemDb.h index 9cca3299..9cb34658 100644 --- a/OSX/sec/securityd/SecItemDb.h +++ b/OSX/sec/securityd/SecItemDb.h @@ -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 // diff --git a/OSX/sec/securityd/SecItemServer.c b/OSX/sec/securityd/SecItemServer.c index 5520e70d..cd1f60b9 100644 --- a/OSX/sec/securityd/SecItemServer.c +++ b/OSX/sec/securityd/SecItemServer.c @@ -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)); }); } diff --git a/OSX/sec/securityd/SecPinningDb.m b/OSX/sec/securityd/SecPinningDb.m index a93bae98..55ad8f4b 100644 --- a/OSX/sec/securityd/SecPinningDb.m +++ b/OSX/sec/securityd/SecPinningDb.m @@ -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 *)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 *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) { diff --git a/OSX/sec/securityd/SecPolicyServer.c b/OSX/sec/securityd/SecPolicyServer.c index 03366feb..f747bf45 100644 --- a/OSX/sec/securityd/SecPolicyServer.c +++ b/OSX/sec/securityd/SecPolicyServer.c @@ -60,6 +60,7 @@ #include #include #include +#include #include #include #include @@ -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; +} + +/* some Apple servers not getting certs with embedded SCTs + * 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; } diff --git a/OSX/sec/securityd/SecRevocationDb.c b/OSX/sec/securityd/SecRevocationDb.c index 24f0084d..2bdde133 100644 --- a/OSX/sec/securityd/SecRevocationDb.c +++ b/OSX/sec/securityd/SecRevocationDb.c @@ -72,6 +72,7 @@ #include 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() { diff --git a/OSX/sec/securityd/SecRevocationDb.h b/OSX/sec/securityd/SecRevocationDb.h index 709f5274..91f613ac 100644 --- a/OSX/sec/securityd/SecRevocationDb.h +++ b/OSX/sec/securityd/SecRevocationDb.h @@ -158,6 +158,7 @@ void SecRevocationDbComputeAndSetNextUpdateTime(void); void SecRevocationDbInitialize(void); extern const CFStringRef kValidUpdateProdServer; +extern const CFStringRef kValidUpdateSeedServer; extern const CFStringRef kValidUpdateCarryServer; /*! diff --git a/OSX/sec/securityd/SecTrustServer.c b/OSX/sec/securityd/SecTrustServer.c index af70276a..b34972eb 100644 --- a/OSX/sec/securityd/SecTrustServer.c +++ b/OSX/sec/securityd/SecTrustServer.c @@ -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. */ diff --git a/OSX/sec/securityd/SecTrustStoreServer.c b/OSX/sec/securityd/SecTrustStoreServer.c index b288c7af..587dd6c9 100644 --- a/OSX/sec/securityd/SecTrustStoreServer.c +++ b/OSX/sec/securityd/SecTrustStoreServer.c @@ -53,6 +53,10 @@ #include "utilities/SecFileLocations.h" #include #include +#include +#include +#include +#include /* 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), diff --git a/OSX/sec/securityd/SecTrustStoreServer.h b/OSX/sec/securityd/SecTrustStoreServer.h index 1b16a337..eb918965 100644 --- a/OSX/sec/securityd/SecTrustStoreServer.h +++ b/OSX/sec/securityd/SecTrustStoreServer.h @@ -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 index 00000000..27d1ce6c --- /dev/null +++ b/OSX/sec/securityd/SecTrustStoreServer.m @@ -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 +#import +#include +#include +#include +#include +#include +#include +#include +#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 *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, ¬ify_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; + } +} diff --git a/OSX/sec/securityd/spi.c b/OSX/sec/securityd/spi.c index cf2f3d48..f0bc9d8a 100644 --- a/OSX/sec/securityd/spi.c +++ b/OSX/sec/securityd/spi.c @@ -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 index 0000000000000000000000000000000000000000..ebeb137bcfad6bd799f3ae467a5a7288c77f890d GIT binary patch literal 856 zcmXqLVh%BAV!FM6nTe5!NkBMAZ~wu&F%RWFl{u8kKfiCl#m1r4=5fxJg_+r)afTtc z0Vf-CC<~h~Q)sZEn1Kk0!zIk?o|+$0R9al3;F*`KXJ~0)4ie`UHqc1cR4_6yFjqiP zprEVZmS3chSXz>iUzAyunxarzoT`wYms4qIW?%x+$}Fr4*AY;ZnVVQtso?p2{g>z$Ush<7pT|Fz|sH=qQrTP4S`$>BV$ubQ_CoWBtsbkDX_^r z!j1(6IjIVs!66FHjtUka{f34L26A90^N8cH#!%Qm5Tt^OhYPA7Q2InT{7jsi*=9%ocGW}%V$!jZ=%#BVICcNA5 z@zc?iZ@b*%|2$)_Fw*^YszKr8-+~`SlNCE$7dJ6l88k7P83+NLAS=ws_@9NtfDK47 zF)|pKfyCrl^bK?kv=?YDP;XPsC@Cqh($`PdE3V8p%UOTrzRtw$7rrUpQTE|6EsE{CgQ&-C-sJud2fuar&FRW-VL4@%EzQDRun; jdescription Alfa-1 key - - MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEjWLpGNv/x8wCLlZthIDbTKjc - Q8DmAebMeXf1TzPP/7fUxeWV7KJeD5vBWxB0V9wRFasAmYFfcqRD6AMTIW8q - eA== - + MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEjWLpGNv/x8wCLlZthIDbTKjcQ8DmAebMeXf1TzPP/7fUxeWV7KJeD5vBWxB0V9wRFasAmYFfcqRD6AMTIW8qeA== operator Alfa @@ -18,11 +14,7 @@ description Alfa-2 key - - MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEl3VLq871ikjdTDDvr1LhhHKj - 3kOXWrtQoKJ3twK0BRBEj+rV/UZuZRjDNyiLK2mfMJN9TZdjLJphnYYJcstg - SQ== - + MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEl3VLq871ikjdTDDvr1LhhHKj3kOXWrtQoKJ3twK0BRBEj+rV/UZuZRjDNyiLK2mfMJN9TZdjLJphnYYJcstgSQ== operator Alfa @@ -30,11 +22,7 @@ description Bravo-1 key - - MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEXxLKuBw7sGl0/eRfkX4W7MpH - LiK7xB/xkQONXu6cX/IFxMGJ83vbN9NvAbjkiG4D/Pnvrrq9Lb0gWPxovk8u - fA== - + MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEXxLKuBw7sGl0/eRfkX4W7MpHLiK7xB/xkQONXu6cX/IFxMGJ83vbN9NvAbjkiG4D/Pnvrrq9Lb0gWPxovk8ufA== operator Bravo @@ -42,11 +30,7 @@ description Bravo-2 key - - MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpPTIhGHP8AjsFnvCog7JOM43 - uSTkLbeJup8EN+wfhU2X5YJq8mCXXI7+MHyb/ncEYuJp7wg4B7zxhT5KSmIC - sQ== - + MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpPTIhGHP8AjsFnvCog7JOM43uSTkLbeJup8EN+wfhU2X5YJq8mCXXI7+MHyb/ncEYuJp7wg4B7zxhT5KSmICsQ== operator Bravo @@ -54,11 +38,7 @@ description Charlie-1 key - - MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEp/wmWR+YBWqWiCJy/EE7FBe5 - L+CvD3b10ua7BWA95yueo0GVLiw5b3qoNZz23CP+ecw5t4+JFsi/LvL45djj - CA== - + MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEp/wmWR+YBWqWiCJy/EE7FBe5L+CvD3b10ua7BWA95yueo0GVLiw5b3qoNZz23CP+ecw5t4+JFsi/LvL45djjCA== operator Charlie @@ -66,11 +46,7 @@ description Charlie-2 key - - MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFQvCj6M6CQKeyxhK2I/u3ZXq - YXyf5feihb0Sh4fk78GZisbJyivSHfFRmATdpo7T9IOlXExOZc/ZnGwkPHXS - GA== - + MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFQvCj6M6CQKeyxhK2I/u3ZXqYXyf5feihb0Sh4fk78GZisbJyivSHfFRmATdpo7T9IOlXExOZc/ZnGwkPHXSGA== operator Charlie @@ -78,11 +54,7 @@ description Delta-1 key - - MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEey422SB0m/YU5R4km1+gQuRS - HjY7vcTTbUo7Vnehfe2KCW/yY7lJQD4Yv5OJLci8vCWzDAXCprK5ZpbEiQTA - 5g== - + MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEey422SB0m/YU5R4km1+gQuRSHjY7vcTTbUo7Vnehfe2KCW/yY7lJQD4Yv5OJLci8vCWzDAXCprK5ZpbEiQTA5g== operator Delta @@ -90,11 +62,7 @@ description Delta-2 key - - MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEkC23vcfErQghrgdlOPDR7PPK - +8/7FPyQZy09igHW2+eLx0+8e6VhaO1OTn2YL50NBxW2WN1wAhAxBfSPOFD0 - wA== - + MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEkC23vcfErQghrgdlOPDR7PPK+8/7FPyQZy09igHW2+eLx0+8e6VhaO1OTn2YL50NBxW2WN1wAhAxBfSPOFD0wA== operator Delta @@ -102,11 +70,7 @@ description Echo-1 key - - MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEe/QyaSib8V4jhT8vlZTGou9v - pCykmsmyQo/3lNI5tGFSiQWaonjQK/reZBXKpG6lwEblDdAazTCQlpmaOee1 - WA== - + MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEe/QyaSib8V4jhT8vlZTGou9vpCykmsmyQo/3lNI5tGFSiQWaonjQK/reZBXKpG6lwEblDdAazTCQlpmaOee1WA== operator Echo @@ -114,11 +78,7 @@ description Echo-2 key - - MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEcxkV7jZBkfaV6BKH8fIYR/es - 6DoVZYOW75zIzB5vgvHl0uOKpdwaDVhU5KZo/2KebpqpSdLCeKqX+poxUFxX - OA== - + MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEcxkV7jZBkfaV6BKH8fIYR/es6DoVZYOW75zIzB5vgvHl0uOKpdwaDVhU5KZo/2KebpqpSdLCeKqX+poxUFxXOA== operator Echo @@ -126,59 +86,39 @@ description coreos-ct-test log-alpha key - - MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEhcZUhfz61YzwzHJrp4RLcCF/ - V3j+SZYXGXc69qUlq3twpPnAsRpJE1vzZmvqL0Df1t21LqXQK9EgFcIdu2LL - FQ== - + MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEhcZUhfz61YzwzHJrp4RLcCF/V3j+SZYXGXc69qUlq3twpPnAsRpJE1vzZmvqL0Df1t21LqXQK9EgFcIdu2LLFQ== operator coreos-ct-test alpha description - Google's aviator + Google's aviator key - - MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1/TMabLkDpCjiupacAlP7xNi - 0I1JYP8bQFAHDG1xhtolSY1l4QgNRzRrvSe8liE+NPWHdjGxfx3JhTsN9x8/ - 6Q== - + MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1/TMabLkDpCjiupacAlP7xNi0I1JYP8bQFAHDG1xhtolSY1l4QgNRzRrvSe8liE+NPWHdjGxfx3JhTsN9x8/6Q== operator Google description - Google's pilot + Google's pilot key - - MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfahLEimAoz2t01p3uMziiLOl - /fHTDM0YDOhBRuiBARsV4UvxG2LdNgoIGLrtCzWE0J5APC2em4JlvR8EEEFM - oA== - + MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfahLEimAoz2t01p3uMziiLOl/fHTDM0YDOhBRuiBARsV4UvxG2LdNgoIGLrtCzWE0J5APC2em4JlvR8EEEFMoA== operator Google description - Digicert's CT log + Digicert's CT log key - - MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAkbFvhu7gkAW6MHSrBlpE1n4 - +HCFRkC5OLAjgqhkTH+/uzSfSl8ois8ZxAD2NgaTZe1M9akhYlrYkes4JECs - 6A== - + MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAkbFvhu7gkAW6MHSrBlpE1n4+HCFRkC5OLAjgqhkTH+/uzSfSl8ois8ZxAD2NgaTZe1M9akhYlrYkes4JECs6A== operator Digicert - + description Bravo-3 key - - MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAErSVuQLDBj8EWNrGVjb8e1T9d - 83xvvxi5NeWb9wnWrjbHVwXEkLQGAZBQvpWzJ5yFLqmVu40KSy1NmV0i78II - Pg== - + MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAErSVuQLDBj8EWNrGVjb8e1T9d83xvvxi5NeWb9wnWrjbHVwXEkLQGAZBQvpWzJ5yFLqmVu40KSy1NmV0i78IIPg== operator Bravo @@ -186,13 +126,25 @@ description Alfa-3 key - - MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfLrfEFaVzHLuCk+kjWnQCfrQ - YFW73h7tpMEwhfYmL0AKUGVgrgvg3x+D1YSKs/X86dwdg/wyGA3RXU09Mo/M - UQ== - + MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfLrfEFaVzHLuCk+kjWnQCfrQYFW73h7tpMEwhfYmL0AKUGVgrgvg3x+D1YSKs/X86dwdg/wyGA3RXU09Mo/MUQ== operator Alfa + + description + flour + key + MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEgze9Txetn+ojNANjWk8Zrc99TlXCSXgETQAmQDyAZEi0FrIkTYzFL0P6WK/qcb9RmkWNgFOt4CqXrqvVchFdzQ== + operator + flour + + + description + sugar + key + MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE3x/NYxPO1VZFfde5lzkucZIVd403m01F5O3TT8g9qaAEsRUfS9NlspS3pM/ytBtzMFc6oSQj9GFbrvZ68UhG4g== + operator + sugar + 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 index 0000000000000000000000000000000000000000..75dfaf39fddbbd46f687e0324a3a5811372b0e3f GIT binary patch literal 690 zcmXqLVp?a=#ALdFnTe5!Nx){)7Y{CmNB>@{SjQ#U9nLo3V&l+i^EhYA!pv;YIKzRh;S%O`Pt6Z0DlINi@XSlrGqf}?2Z?hF8)zhJDi|3Um@A+t zP|#Iy%P&$$EG@~%FUqV+O;IQj)^y%uOt+RB%o$D#=XC zOinDx%+FJBglI0Q1RCaUWFRNbYhZ3@Xkcmp22tX?#uf&Kh89M~rk19bQG?m(Wd;Il z?BFnFVq|00Ze(FlVoqXU5#9LWFSDrg(>1T#%>|R*UurfBs&x(L_Uf$;v9`*K7iBsS zu1~eA{MUD#I~Un_ zdrXuKc%ydzT7uqQ#l=nr4hHFVzmHFpYDPz}E}G_kLH`6?d!&>ZtZw zcFJ>E+=}HrQG$D_nqKegdAWJbG*$NLUNg1W^|#2C@9*N@%2XpgZO74_RyupG3GI9x zS^MY$TU&gbXVzBBxDJyydn$N1X0+t2IP1M-K`l?E?}r__rxj0K&55pkxInXI;m^xc zJWs16O;p%(m;36?Ge2Lcb7>b(JT_N)&56@59xV8xKcUx3U|cJ ze=wOVaC%qNx%I2BeqY78Dq-)PoALLHRwf9?F)*I=`enc56+5#cQ(x05=0mglnV1xMeab8n24W4^4Mt6mzzAeynAsTIE|W36ZQ`2;UOQa4S2wOv_rG>< zhm3Q@W}aDpUg_B6B})5xYkr;2Dyw#I$IE7hB-d>#IVSI1Y3waA>(Gz(4!_%X3r(aB zhTL+qe{flAb#92#SF5D63i-Px$JdDU|DrA7C*cV9Tr zASvT|K)2_`58WjtVV*}>xB83T%X6u)Y+q5g`*Wql#NA)==N|mfW7-qT`1^3~&i5|4 zm2QT0T>n-!9sK`(b)LeJfRpiaeP@gJ@H}Naxxg{2IQZAnfGv5d{J(u9zWfck*_XNT rg&_aEjvK#aJ-@HIH}$+i#i0bD+o}#dS%2!BEF4mVzRzoXI9U$>x7>1) literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..ffb1a0ff9ae57f1cd25324a04d5bf82fe7937c23 GIT binary patch literal 1120 zcmXqLVu>+mVs=@;%*4pV#LM`2rGd6II z*qB3ExP`^tbMliCbAmI|^Av*e^Gg(*9TjvHf{YA>4Fo|dxP-Y7Dqw=l$btrP;=G3D z24;q)20&n96eZ4UWN2sv=Ng0fHT%r)1 zT2z*qoLX$CYM=~~XBL)$%6sOOq!#6+mMA!umSp4?WtLPbxEmWZF)AT@i;n7 zny>veMLHU|`z_=evLtF`_fEI2sCD%;^LISE=s{VyO@?7*%E`RzfpTew7p3S_9(bO5 zIIJZ&$~pJ+EGC6Z@1-&?ZkSuV=z&&3YJlPS-<$RK3wAi@ZS@r3=gPY?{nvh-`K*@Q z5h3f@roA}Y$0)XEg_N)3(a94R$t~>u^zUGYisxc?@1w$ucbA6?WhQCA{-^Lh^S9N~ z4|SUF-cA$yzEOU`lL@L1jG34j85kEgF@i!$-+&Joq_X^sjQ?3!fa#;nKo-PTWf3zF zVdKzdV`ODzXJ&-6m<)tK(!wC+90qJaiiwc{qJ@t|j76mU(2jsv>1Aabbq}>&XkJja ztZtXLfjmfyGK++PScAyyN9^J0GI9s9*zQGcnWcOGj%1sjfho*y+K(8P>Q!gEuH1yMpi;N76K<3J`Xd3|aEKpsb+@=Usn_QHGsuZkV z4=8M457MK+VqsurV8X_h-pB*Y5e8ZY8ZaA~7{z2jrW6CMgxgk>T999yS(0B=sgInn zfcXWOuoxL+ws%f@68v`eo7*dl80YIOKAXGNNvM4Dj%O#CgAx>~!_|)oZnaP6ov9NY zbxMir?!4Xd-X8Y-Ot#&MEv~Y;U;nSk=scV9=-Rb7heLf@-`|T|He2Fg@YP6EbW+*x zx_QB`4we0}T-)(4ZIaqcnIjfwJ%2g3e~7&n=G%C^{^Oy$8+`vA*2=4ypBM8s$!X@p z?`H2rdUO;XyG@TOXFjmtm{-SN2c`C+D2Z2dmL8Ad=y}4rq;_YEX?&+y7@vc!(2L!s zMQ_)0g!ygQt+#Uali#v-+{q_qdrx#p3qK&TW!i^3I^p&~ENiE(s`b6_iD&*ChZomE Vi+9=FpKzKXT2V0l&|4$9djL9mhAIF6 literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..2cd4bebd152beaa70d254295b8d0b2ddd86f62bc GIT binary patch literal 1020 zcmXqLV*X*!#PnbRGZP~d6NhqU3Cr5k%_0W8Y@Awc9&O)w85y}*84QvPxeYkkm_u3E zgqcEv4TTK^K^!h&F2{m`oKywRyktE?H3JopAh)nAM9?|4s3bEjGdZy&Ge1wkv9u&3 zzbLb$(ooDm1f-5xm=~fhC_leM!P(J3PMp`!#K73V!obkf*uW%8oY%+_iEEH+sBWMN z*2yCW(HWdtRF+xO914uA49rc8 z{0u;GE~X|%MuwegVjE7kuPzjw)OUZC-NT0K!Mm0uoT+Io`fgCe=^xJP_5WeqN$&t* zrj(6)Eln?8X9+wg@k{B~y8AOEuI=~pbr$%g+A;sKLu=VnrN(U`uEn#uAJ6fSYO6XN z_~_QuA4_U)8{Es`J96}E&Wz{FeuXQ@N)}h~olWN7uHK>da8^ds4u_m%F_kp!=bIjd z)IRU9TqNCS$8_29#`JP8Bc5wqT$@>De=N#RULh)%WB!8wcJPF2nlXE_!e_fxaM`K6 znq|N6hW*#uc`I_7w%(m-@n%xklx0VY)h@2%*mNxDd0&}#=Z+BmyazX(Zfm8syNT?c zwj+FZ;IkIt@4O4Qb*`zos93U^iJ6gsadG1^gT}=MvcS-mGW~o`tHl zM`lg7)W4DWTiP+&<@(L+)7Gk-QlGv&K0fEghUgFX?<%PZica3?8Fz~(tt#$%{)gl% zsXa%kLTbbOQ)m6Xb!5|t4LcT|u6^LX!a;P0nB?2&L}2Q;aQ2ebfjX=CN`Ck6fANz# zJNf^G53Zpp#&%bp-pW`Y+*M|ver5j;xw3CR4>P>q*!(IuH^%fhFFWI|ABj8v9i5f! zoY=_xdRKhG+!y&%RJ`w;o3ui2k*UpN&j(`Vi|%Ca?3HlZX*SK-=-BD9nWknp!j8>| sJ)FO^Zt9_{Ra{I8X%&+`r7uzDeZjf+jH02yg1!5;-u1cb#yoQ-0KSccPyhe` literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..8a9ff247419dd22a07c837ba7394aeabdd0f14e2 GIT binary patch literal 1215 zcmXqLV%crb#JqR`GZP~d5E<~YacZ@Bw0-AgWMpM!Fi0}wHsEAq4rO5zW(o~96gCh9 zakzxJ9199^QWZS&lJyML3{*gZ+`_UDLFd$>lFYQsBg2!4D>>yS-j;I@c+L7YuChh5U7`KHvAiEsOqE5wMI&W5Px=0B&b;#hyADPKr1x`dQTTp(jgCTo z!8UtFgP!fq=lSQ_e%AKXkUH`2+}53ZH{)ckownU-we|}?AHyW>jf!G=C0A{DZzqYZ zUR*fIJvj8>dVR;uKYl+hIQwj|k87R0Pjj_t->jT;Rj-bAq&^<-@B zm%W!-{69S|b&uzbviZg$sSC@eoYZAvW@KPo+{9P~43RPeK43h`@-s62XJG-R8#V)e z5MLO?XEk63QUIB4HrbfL%co zBPgB8DzG#$asX{)0b&Md!c0zKWi)8~WT3^yq0I(NqwGwKVsaTJB?ZM+`ugSN<$8&r zl&P1TpQ{gMB`4||G#-X4W-@5pCe^q(C^aWDF)uk)0hmHdGBS%5lHrLqRUxTTAu+E~ zp&+rS1js5bF3n9XR!B@vPAw>b=t%?WNd@6N1&|%Uq@D!K48=g%l*FPGg_6{wT%d-$ z6ouscyp&8(HYirePg5u@PSruNs30Gx7i1YwCER{crYR^&OfJa;IuB@ONosCtUP-YY za{2^jO7!e*{cX?eJDxY@8r; zW8atJ+3zl;@Sm>qH@UIM?q|jS>=W#7YAu_)gB31Y9ND;kmOoeaf9*e!%UL;V#2vx} zUUwk!R<>!CBEM2a=7;zgw~E zguTASugG_6SFxo3)|+Pa2irq$E}yy6$m#cutA+FG76xsX-aFYzMMzw9>OIdRD+ Xyc@&=R&`yy_2kb5PImJRrKO4hMS!&; literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..f91a14eb1ee7e29cada1cc1ed77e338420d38cab GIT binary patch literal 1221 zcmXqLVmWBg#Jq9=GZP~d6Gx=+y347u8-omZ**LY@JlekVGBR?rG8p66s=9Oe7CzfR9=P5Wl8Y&pbffRD{h&!him1L&Dq(Cb3 zi!w_p4TTK^K`OX-xFAM(<|XSHavN}h1lfd{LW2$D#CZ)Z3=ND7jSP)V3=E>gd5sJV z4Gk@!T!R=xWdlWsbEJ}z5{ol)QgusGi%ay1lgsoHLGIH_&dvm5}|<$jZRn#K_NJ(8S2a)WpchuH znTdPfuVXXsYFqtq_L0S@cT?*yNBCqJSlSG+u|a-o6iSZ0*m$A_XFardTbwY=Hs68`CQS>JxP6qdk>86lvQMZx>g;p9XS>;2}YL{U+vwYxZ(SZ7_O6st5z&nC-gjKyY*$~ zIjIWszZ#X*Fr8*II@=dfy3;t#`Rg6a`AeVpNH{L}_}g*nfA3%>W=00a#Z8PQzz``g z-~q;itS}?ve-L8*ZyjBmiyrkhbxQedU8pA1Yn#fXU12S;f!IK?FblTmV_pjw zrNHG0H|yhlb!OMue{{TvyJsN2MAw!1(Da~>9lvdj|L7m;OCDxM`^|As~X?B}_$nL4s&b5oP2%g(&|$H?zh^rmp;KQejec50Pa&nhl)TXf>! z;~VoQ?N}MXlNx;T)J4wYA8qTdTU>bCp;9a3uxD0n-*OMu=8LI<^W}K?(_vs;N&up```@Zr84+ literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..ca3f1f2edb5ca98200438705bcd1d4449535db62 GIT binary patch literal 1005 zcmXqLVt#4R#B^~1GZP~dlL(_WM_O}x!wUA)>2oK!&o`WVdA+^?FB_*;n@8JsUPeZ4 zRtAH3Lv903Hs(+kHesgFU>JvkhsoK|P{=?4B*V_b>0DZnT2zvmmv1O+AP5rU;^A^E zD9A}w@XSlrGn6ur00}bl2s-EI6_*qxX6B`)C$np|3xSyHLsnwJi=FtsQ%FWpeiKnCIzQNP68 zR0X(uN{SWS5;JoQni!RkgMg8hfw_s1p8+V&#ni;e$gp$P`oz1(-e-BP6wy1@aJgc8XvUi`Eu;+U={8oYPAWmdE{5mpz~K^=0AFkXhPXzt(Fn zVmES66=tm1^DF$qshnrsGnZTaUwM>6EQ52#yKQH~vN#uhJ{#ZGIr&hneD1mGe`np6 zH#p_^|H&}DRkkf{zqRY#_Vt!69=EP=cK3ptE02pm zH5TJzjkt01l;VqP{Q0isW(HzD-&i_IXUZ|nU2CGCcjNEnzez3S5mEcS*6uP|KYfy$ zaaG&L|9yLt|E12}y?p*uwufTw7uSBcm>P2WynB9Cok+djp;KQk`@Ioi|5(iu&wAoF zld9pqOG~?MU9DC!`noUD^h%)r#Maivsjh_?A2YPo+}cCq@qGV5g^<6dV$(@PpSUw0&jZ&Zc?w2Mr%eSquA|-kYnS>&w6Q%$DHTuK>b|ab^Gj literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..fde0d0367d87f8706947e1f2f34e4c5af436c8ed GIT binary patch literal 996 zcmXqLVt!!I#B^c-GZP~dlSmQoLZ(QYgBg{s>MQeVE^QZ&W)m{tW#iOp^Jx3d%gD&h z%3zRc$Zf#M#vIDRCd?EX4C8R{FgZIK3KO>~ls|2IeM4eg>d8 z7gG}>Bg5snkG?j~ll|MXtfJ!1Ls_P1Q|FEA=bxE*(CX^Rx<|)$+d0%P2(??KAXWHo zNktz5hdEuhgX}(~@Ve@Do`OdFfjH zlGn0=E{)%B#8sDy&RC=z98z4z(6o5+-zj}8b4^qo8g-5z<JG}&J zCosnaOg?8l)$`j8wi|Mx5`|80PG>)>S}=im;YEFK?E>u&LAy7mY}l3|cKh*WvtQf? z*w=kKTmDnO>Uv29YxN9dKnes|L=A+S1d~hjN>YnU^b$cSOD{P; z7dgs+i4_=Sj10a!tL!c}Uq3eO_4}WvFW$VVbK>014b0g;c86qJ^IbOs&86`j;1*ZXXB>iVytkH{o2*)?E>kmL6wKK4U-KKO@amd4eKq+GgvXC37SN zdyX5PiJxn> Z%oLpT;AhbEzov^GO`6s9VyaG#8UX1qZjt~1 literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..53f7abcf38ca54c739f9a6f46e2be32bec474e58 GIT binary patch literal 1019 zcmXqLV*YN>#B_fFGZP~dlZe{<1AZX}e#s{9PmA$i`aDDMy#I6qUN%mxHjlRNyo`+8 ztPBRJhTI06Y|No7Y{E>T!7vU750kT_p^$+9NQRw<)48-DwWuUBFW*quKoBIx#lz)T zP>_?V;F*`KXQ*Hx2NGoF5qHkdD=sNY%*;zoQ3x(ga&}bk%U5vmGmsPKHMB4^Ff=nT zHvobtFxSY?)WFo(*u*r-pcG~^kv?#NrQo%JZ9cXQ8QD$Dcp_+jT z#6hxtiMgo?$gc7)N>}jBEY3|VNzO26VpKv75Jpx8<|amd2B0_>QxhX2!}@b3hSluq zJ60`mDJ%KeROq*|=TK8!zw>48#D`sNf3$7K$C_CT>((vkZ_J9T(ofjN zlXB{`?DCghNmC1h^yAj=FI7@^V4PsPM&{2-?I+(4ZsyfdE)#zkez$H{#{;$tJGb{< z+VqgMcFsq)>AYNFrB+9B?rF47%$rqSH}#9LIj`B3>{^+7WmDOf)=T!VJ)1D+j9&7} zv=W(1T1BGebIiYR-@P|EjA#1njPj3%zVACBq%4shGW2c#)7 zFYiC)j3kO3(WWDzwGZW2r`(JM(UF40Q_B{;q0{9NQH1EyhMlrb{!?c@8| zq|x5tsJ!VilW;ow!M(e6ZHhwV_lCtbIXfNLl9LoZWeUxwqOz&7V{H!}%x93@J#Dx!{t=hfIlWR@BHJ^z-n0SfCp-76Qi4a~+H1#G z9$yg7_rQVuB I;8ynM09hq+ssI20 literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..4ebf9b0166c2007d4afa9f4e075122db50b08d92 GIT binary patch literal 990 zcmXqLV!mb2#B^u@GZP~dlZe#YY9a9nayNJ8O+V^)`137&`6gZiUN%mxHjlRNyo`+8 ztPBPjhTI06Y|No7Y{E>T!7vU750kT_p^$+9NQRw<)48-DwWuUBFW*quKoBIx#lz)T zP>_?V;F*`KXQ*tT2ohxGk#Y`EaLr50FG^0$P0cG&2(BzHNzGLV%Fiz`kQ3)Mv@kRP zLNgOHW78-g*V4emzyiuONQGHWiAxj=c2w}oS8(w& zXkt`C4g*G32IeM4eg>d87gG}>Bf~?JNzJ}lEV)anD?dvKh?FdAw(Pk*_v|Z|tNs_? zXLUt$tUI@{b7Hkc`h}X7SfTVUKP_%0o!+>m`2e>^#kAX-8l{Z={x@`n2YBl7d^yGW z@;pbaa((ON75rWd&BD4qrMF)(%-OEnDS*B_*PzicYA%qmK{usw&w6%lIfKU zd^JD$iQp5plT*^JtmfYGKJ~of^S6&L*7?M^-G9oJ`sMo5iZn)JzwLf``(hum>mCz5 zGhw%iVf4Bl=4XOIR>$U?*liMi_*0i#*Cjdc_ZNGam>C%u7uOrq8t?-{QdXFS!+?#E z@jnwIg8?^4fS-khnTd(TKo-Q|V-aH!Q7VqNf4Gf1L#<=8>ii=mn-@*2)iaO>Nh`BR z7>G59@ZL^ZvFk(Lr_#d!BK7nQGXiVIp|{Cqv$csGbhOHJbY;O~5=b+f(7arJ;;OSy0#$I{6woCG73 z)UQc{}WxeKpU-egAsKJ#Cr+FB_*;n@8JsUPeZ4 zRtAGKLv903Hs(+kHesgFU>JvkhsoK|P{=?4B*V_b>0DZnT2zvmmv1O+AP5rU;^A^E zD9A}w@XSlrGgLH?2MIFsNI2)`6_*qxX6B`)CU2=6qsvdXlh_;Y;0m0We^9mni6+N8i+&OA>fyoo2r217=tE8C1kHNvNA9?G4eA2 z#krW87#SJ1>~IcWc=uo4CA)@ipNi}EpL}OMnfq|W_G|&}ISJewb$c144}bZ+etO=e zYajfQGc-IINfTdfnpV^^MWZh;vIjk-L;*m3;1X$K^lRAIM8r z$pqi^w>#{rcH`u>C{4NBi<%B;#GO0DacY`8mMn8afohbmKR zS9Metq|Cjmy=&7XbFL%b{=6tT{d7K?>E>mplBNsUd$Jl&U9@B3v(DnPC;xum#!*?j z>9s-iWOV_(qGbYSIfd#y?tJmepB1%od!RzAn3K)yvIONBD`r$aD7*T|wrFR{1D~wW zMIySI(gn5?LUQi^f0wH4F3iNt$iTR`vCp8f8=M|wg;|&k7!0_9;VH|{!otkN-e4dM z;;6Fl7;v$1XtOc0va&NX8pwhK`B=nQL^jWkownqQ&f$vQYAq>WvkynCBqYEILspqZ z!a%G+#J%WOSbIgNZNS}a?~iZK`Y&Aj_O*cwNWUP9sDW^kU~-9GNosM4ULq)I=_Tjq zB1ai8wF0AzkwMcvoGbG1jcktx)RJngCJ~CnfPxBcsCrmjTwU0IEtwLK^ zKwpSfcj2KsMSC;2j@F0EJgP9yaFyOWCFZ1|gQRf=<0pat5|h6l&zh0Aon4dFPxa&2^eDA$;Gv(Lp|90n1yeoIVpLk<;<@&q#=L+x2 zPN?yYSZ6|BM%f_kI=F#?@mywa1 zmBAp*klTQhjX9KsO_(V(7{=k?VRCjf6fzJ1$*}WqI+qrt7L{b?6LJL4wRY63+Q~#U(|FnR%%x3c;mG&W;Lx`3n9;=>~G*yoMHr28Lz^ z<_16z1?CzVni`lI8=II$8I;1TCej_U2GS6Bhy!;;Qvu zd-h(;jIy73JLSGytC#=G?Vj`NcU|z7=HEVNM(Bq-$NZ+edS(3m>z&IJqL%o)>P=>{ zNtA4DII)V+iX~9rfkR#6CF9Ppvu29=!haoZT-e1w=YiAVi_a%HKHaODxnkqljTb*& zvf_1`nt3;P(t@>yztTQ?@6gdbyCFWMaaHDg_F4wBRSkVl*PRo4!5X}u#n?#A_)N{4 zjMnw*cc!GNbS2!*v`Wq0^W1owE{npicxmSV@4r!Tyk|`}voo9xnHQKoV;RSn0~0J{ z`gd#k7C1yPugqA(dt*glK-h23sT0pKd3bQmo%w3f$}jWcqHf*3wM386!l~0(c-!|T z*4(K~%!~|-iyQk48oR;CL{^xE$$-It8yL8<{46ZYOzaH?!XS<+3y%R88;3RZ461|et;u5_?P>Rz_&d)`TGGHPGMj0am&&xSa zb52bbmsHPxqQHMK_u8ZX^;)reXLxnI-}!m@!lu5frxvg6219qMf z&HIWj-qSJnK3O?y_VOTK0hUV5yFSHcEomZkPN%Y7%s#s-Li%F$uQOkqr>@<4!=q<+ zg!b}=+ux@xQvF_lK zU0Rz~I8JeqKD+cy2CIc$knHs{HxI0NW&QrJ?8QAd|M73By!Utej>WshwjWhD@jKRg z{ocA~s}<8qvd@TY_;T>ia`(9g3hm~S-;Y`U-?NiZ{@vT?%aTD#mu9rK&)a!&n(+2W N_vcGDHqG~r1_1lOf@1&x literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..5c4492bc7e184ab3acd5d8bcaf36e0d4fdc172a2 GIT binary patch literal 1045 zcmXqLVi7cGV*0s&nTe5!Nkog!>q-6|rtW#)i**;@sm>APjF&XvW#iOp^Jx3d%gD&h z%3zRT$Zf#M#vIDRCd?EX4C8R{FgZIK3K#M+Lup1^=RS zgC<5LV2_O)2_*zyaDay>dW&fiUxs+wqKAl5h4}J>dHT<~C#LURRxVUkPLE}aPeqdnA3bSw+ zurV_JXJTY9;06isv#>BTF|ioPf;fCEVk{!=MZdz@D?)7p?rwX3e0$b^;o7&a!7(AL z%pzeR)*!-rJ88wP4|$(b)(TJW5_aec_4t`=5D3yQ$Kqw+vB1qhpoy;}wYWqt5tOX- zlJj#7jFuP}=#iEvkRukDx`7c3baRT%>4Yog$Lpjb3MD2f>z=nM6>$#K+&J?GRYD_*w#=)Az5+aks@6Mp?$pQe82<{-MP##b4@^cJG|5dp}sbF5tDa zUr$x-Lwf_yoHyFmnm~vi>k}6%$dBJo?HP7o!w-|nJdb54Lkfi5_ j4p+}>eSs5}@78@Tts-6-Iq&_P?XJsOs~d73FAD(xJlS>d literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..c1958849330b8f71623af0fd4802845e763bbc8e GIT binary patch literal 990 zcmXqLV!mb2#B^u@GZP~dlL+sxs$0+Mmat9ldHN%8)@`x#zZUH^;AP{~YV&CO&dbQi z&B|a9Z^&)H$;KSY!Y0fV8Vuub@Gv<$8VVT*fMnQtIGsxiQj1D5^YRUa4Fo}ATs&Nk z1qC^&3Z8k%dWKR45+Ffl9zo~)yyB9g#LT?Z6ouf@BxgqhIdNV?3qu1#GXrx2Acz8U zjSNiQxhX2 z!*orLRegKAn^Lq$#dM|B>&>AIr}dIwfjK^;}+XLhpv+ zFCX4b>lbH4g*t>C>s!n6=X}b>I)Q(FDs$YnEY^9y+w*y%^cjvLL2q*stGxvu6xpkA zaO~GU6R7%W1AB+I)cvO)dup0r9{aE~<;#he^Ym(Gbn!k;li#__@S?c$s?hnjQ(cV| z&fdSFRAR`;X&L>UU0&wcY`32ZzwYK-{uEo?H^p*E%(9(p)!ILQSS7MJ>(>s+3A@+% zE9*{EpSW7ZcJ5RrW=00a#f^OijosjcAS=wmWWZp+4Gd3NeijyHCiVscVGu`^g~x!4 zjYFG_k(HI5nbANNB*@1i#v*d?&YCZm3~X|?F%}+m+7umAw9Z-5KprHm%pzeR)*zDe z>z@v%1NUR*ZOPx+&HWeTburf)$bb|GvWOZ8Hwh+}=#``vm*^#e(v)6uelBv90h1{( z$`~2k_shonYfSPgd-n6^!#h)+9amZ6b}{4XYGLc>Xiv46h6MG11N~dHm&N{gbMCc6 z{2Z|qalx{x+z4mu_K(V&y6b)}O>WdoRgOS#Y3L@ycu7Pw$Q%ohf&0cj5`3d(UP|H{RUyZGEoJuIDF2srKkzqSB=&5v%&y-`bx|dRu5D{m9CO`|VGb-cwtoj>Jv+ zwaL|Bd*k)X2Q6;po&Tyaqq44RdEJjQzopgY`F^}r_UrG9{J@0yq1GiF`!~-K*k*b% TuIx*Gw|4Hr(8-F={I3B3TO@W= literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..763cd2fd3256cb66f9367b2fed1592590204e5bf GIT binary patch literal 1263 zcmXqLVtH-Q#C&-HGZP~dlSq#DQ}YdFW&W;ZGdw29PW^iSuFnwzUN%mxHjlRNyo`+8 ztPBS6hTI06Y|No7Y{E>T!7vU750kT_p^$+9NQRw<)48-DwWuUBFW*quKoBIx#lz)T zP>_?V;F*`KXDDSL0TN{95p>SaD=sNY%*;zoQ3x(ga&|P36X!LwFf=eUGcY#*f+#T8 z$k5cl)Y#a>G|C_iW+x>MP&AN-I6%TLF*j8K*%jfLB^e6NAqGv1O2~d^WMyD(V&rE4 zigPhFF)}h7Z3)Ucl$z-IL(l!JsN11bjlCU{x)V|^oPQPfs`joT^Y;z!#2j;^^IObZ zeI%t)Rk*%0cqz}_wx;2;&Uvk)0p>n2-d~mey@XTJ`J0JcYvjtp^gt!mgFffu^FF=i z`uIF9huh-E9gR)dOGMVcEqlo*SoiWv(2}wr-EMETZWMVc*w;I4r-5bTq)i2m9EwNQ z#!Y9@$~-J{cj0wL;lM^|CT2zk#>GvH(|{o|37jNkg;|&k7!0_9AuG$z!otkN-e4dM z;;6Fl7;v$1XtOc0va&NX8pwhK`B=nQL@qz>Sn{C8J@k2?)YZcWQ(vyH))E6pjjS?@ zgn?LtNY1Z+I-CyNkD0e6e`h!MUy#?uTyG!)(l5v&Y9QPsm|UV)l3HA%mk3H-ddc~@ zK<6;CaRKdOVZ2t!#KOeV_=TnMBg1=!GKL^-W@o*uT?gK7S?9#6f0*x8`OgjCmXh!(Fue)o1p)sY_!GZ{)5CfOJ0 zYjG>>uPHofVNr1K_d4kfe>|K#b$!&!bw2QJj1B7wwqKks>S`KRYM=)B@3u zDILeMcicK2F8Sf0IGc%$c__%s zP@JdK?)ucs=j{s|!;bVYu2(#(zIkz~>cP7ElLVgfDym3p1Ayg(HdYKZv~b4|6f#W#iOp^Jx3d%gD&h z%3zRT$Zf#M#vIDRCd?EX4C8R{FgZIK3K#M}sCtC1l?- zvNA9?G4eA2#krW87#SH3onTU|YmI#Hh(R=vw`2OhYcFQ9-TceFD%(n{O>zs_Pu=RJlQM()2RJPfs6xc-rUtxBPmbt&q><pS!&I&VUEB-Bw%EVlq2qAu!&T>LclN4p%(wX+7q}>xSMikKu~_bjF=@FXd?zJ! zzc~K2&)ZzLKaVss6f=*8)%GjSTRrjPE2Zsn#*fxJeGAo`VtrnGf6I&LpWFMX)! zy`JKKgTLipQJLhMb#iY0UXwX@WSp@`zRSeS$iTR`@uWfHF#~>JD9Q@6a2T*LGX7^` zWH8_c3GlP9Ff%c+7|4P+d@N!tB00bQ>2Nx5KW5&R{GHw0e?eXsbG?B)NLrai!a%G+ zg!gvRid`S_KBcS`p57(w&=uwq(F`(-XL~Cw1GeqUrB0liC!WoJ?SOq=Nh;# zaW!zJLTW&cZD3jl#x^5^klXtFla^9!#b<6G;aa8IJCW`7$IZ?i^{Ov#@XN7lu~(ee z|MtND;t~7cy>EjytMhqF1UM>P-r=dWUR>og?}o3<@(T^V&VLrDVs3C`#XK?J%k`ng z*Ip)i)Lf1!S@MN1o?*oV=3Q&1ebw*$`l5*?E2iF7GA$$5-JPT70BdlBHRt!s4vGhY zo-v(idMEZYgFEQ@Y6n(xH~)Duft;V`-0kWpI}m-`S=}wL>DssJqU#MJ%|lsct##Pd zrWsRo^=IjMwyun0hVA^8Yc9Agc9@v|Q77%?9@$kZ7H3!L+nn9|-}T$d^|8i(WA86c dmfJR8uIXetAN#^h-|iGYTE2^|a8;9CFaXnVbg}>d literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..9764bea73352fe1390ee8d36efc44260f6f9d26a GIT binary patch literal 926 zcmXqLVxDEt#MHEanTe5!NkqAki{bvl!%w5_3Y~OrvejIQGw?OwW#iOp^Jx3d%gD&h z%3zRT$Zf#M#vIDRCd?EX4C8R{FgZIK3KC)CziP1{dvYO!jU2?{(+;Z@#B$N3Ui7I&|=|y-2>ny!bzB{Wcr) zeN9y1I`X~Dch#bx|C?qmu5&w|tay55Q00 z*Ee$tzL}ZIE-2!8aPWfI4;5pZkKW7X+XiViivL&|9%8)Y!oin@Haf|CeUE(;;p58^s$}vN1CPwj6hG2esAFVcmAi9l5#t$~*EZ%- zECo0A=PpjopYyk$iz9AH;#CHZ^UU8jnEAwAU48K7a@NgVC+~_MbX=A9@0-teCT2zk z#>F-URtDU_XqDw>VF9KmHUl0IN0^1xfSHl;zkw`>$HyYZBEow+X~nJ&d7o0&3QzA6 zcIXQA_?e6xzQAM#3|~fu;JTSf9rypHn0w3Shre#{`jYI;D`<5#Dbc)`f0mlLlKyXt zq~2*q=7$$wKAy`Sealbw-t_Mi*Ge|M6K&33w?R*7i;3;(U6Xd6>#5jh`!U&iufU~> zFOm~=JUaV0~OLJ7K?{ zUD@6LAiMUGjmf{ac3%4{GCjvFcoJizTXOB0qy-BYH~!Vn`#FWnC$>W&=}DMf_CevO zwViww%P(r#Gx2?oka2l?CvIZWhQ~S;g-xGrjb-~E`-||hZd&(3;l?@F*X_O+EayFn dJ{h;Hc;AnCQQ5mH_g-ta?hLnnTfb)QZvcr|U*iA( literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..243e4071754887ab9b00098496f5171e175c4e88 GIT binary patch literal 981 zcmXqLV!mk5#I$n(GZP~dlZb&sfvRuPh31J0I)V@1&ovQKo0o0C%f_kI=F#?@mywa1 zmBApxklTQhjX9KsO_(V(7{=k?VRCjf6fzJ1$*}WqI+qrt7L{b?OBoQtW6k&$8FLv?|zKb&e0c;A(OV_=qkR`0?LZHp7VCk=W( z>+%X&glPYli$kg1j>Pqde&%z#>&JRLEEPWGJ1nhfQ!@|P!c(s<` zJNG3)>t*f~zh5eQ^F|lLx5n8wH_w-K{yY7t!PZbFCxeDZJ74)NV=}$-bdGY)$N!$r zy-z3KGOP{q{8?A>HRGVjR?W~wm9M@&RD5XIb1d-GZXGd>tOak*r%qOMZPyMsu_E`q zXARf74R#0rY%%42w_ed8vbc@Yf90y8uX8ol+zJenWnyMzU|d{bPzFvEvcfD(1`Gz= zz#x_7XJKJxVs9{z1#$RT#8^b8H5Z&`bi2DC{0pCQ{^hldYiFD7H;@NOE3-%#h&71t z-cDMv>qFkBl(oXsyM!IOLOp&agX2e5kVVu$xJfX%M6V>ZxI`}zl$7+6^K+5o2ADd5 zal^>qq;9gqc;d}d#}{vH{g!pa@{x4enaevKSe|M!sPbLbwsYo|eY2%c{^s~s=u-W! zMqT`!{(+`DRpQ>6?R^h=wRcB4maQo4%;|Lfux`%X?KTfrd_5~slJVT|^o)Fdw-SZ6QMsVL^@qWR=wKz@tpHsQ{}K- z?P)SIHSgSwYbh$szB4KM`^4TCZl7EQBnsAqO;1^~@}Kn7gXudHzGXP?%W0c(V6Dfb z4g2*9=E#;fNTqM8*>dnk-VO0~R~OrrvT3ull?3~DdBt98I1wo(%6uoHm literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..2ba760d91af409b5c58eebd1750b431f41ceff08 GIT binary patch literal 1279 zcmXqLV)<>*#Qb;xGZP~dlSo)|oY~jp(6-$L&4m}8Z=E}P`^*FbUN%mxHjlRNyo`+8 ztPBPjhTI06Y|No7Y{E>T!7vU750kT_p^$+9NQRw<)48-DwWuUBFW*quKoBIx#lz)T zP>_?V;F*`KXQ*tT2ohxGk#Y`EaLr50FG^0$P0cG&2(BzHNzGLV%Fiz`kQ3)Mv@kR< zG&3+a0D>qm*T~S+z|`2-#5Bqv8)i8rE>Sa3fw)B0F|8!ENWm>9F*gP;d@0Xkt`C4hcq92IeM4eg>d87gG}>Bg1Wb^#ehVj@~`Evs>Ku)v5=(eJ^$X z$?Lw-9`cAOVH;D7?P}-qx3_$hVLu+?`B-AMm{{gafg9HtjfA&+Qd_-w`Qf)~FXbuD zGHP`YyZZ6^pWXYvZ>(PM|NPdA4?bmVQ7V+5nI+gkOtzDh)?Y{lcJ3x7P0J=r#!vus|* z>q4GQQSaj$+|O2AGm*$MaXgh3#o5yoF8b$+!;y(PA55(u%G%y%VrFDuT-?Ms0~jJx zzzIZFn1#uJ!GIeWyt4c(EX+*o4Fjw%a}0T&yGHX9==D?2lzfhYnU^b$d7O)oh=7w8;THZGuDER5GGnOK-u8o#kLerEW{P{t6% z&Frj~wd=s!E$f_E^$+vCD*w6R+tSiy@_M2hmL>*YWnf@TV`-ld&A`CI%;0X|%B0Bf z%IAfojX*%q#SOZSi+GjA>x6#Y`EsY{dfeF;WltH(xtJ7^5B!}lVY}UOkIm=aoVP18m!c=F%wo?14;dz{Fr7nqNMsh5$VqxhhU@`j!rO0z3% zd=F{p?p>)qWigA;mQ!z^EjjT1B=3<_PRG0Jn*O(j?cMiAa>;)$D~m(-6)qoU_;<^J zpUcx`M?~amhPVfhkIzmCHaz=0U9(e9>Sn*?wmo_s>8;x=xHis}i)CY8&g;o zHu0?NwV1LykZyFW^v?xF5a=K`9t#mmn(WK zzfV^QE--qwRMtr_>)gX*OW>?!t=+WA*KexJzPGx6WYUu8yz4aLtf z%gy5XbMBhY@rR6`y@FTgYn D>qO=H literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..316d95ff67830da0265a342fffd7bc878e401163 GIT binary patch literal 982 zcmXqLV!mY1#I$PxGZP~dlZaaXA>Y_pPTu>BqD!W@9ZNHjnZ{+n%f_kI=F#?@mywa1 zmBApxklTQhjX9KsO_(V(7{=k?VRCjf6fzJ1$*}WqI+qrt7L{b?N77zxqzJlXl>;2!-zW6KD8#v2xFB3D{h*D<@Io zJg4=)(+3S(n!fu--#jG$aredlx1{!N{cpH+(~e(H=5c)SDrLL#OtWH|^IyZM`DUk5 zt1YS)RcsLBy*CH|2tj zcI9H$X!)(T80LLB@L;pHk6_FFb*~-t^jXC;AI&|!Y;pGMO^X&+GKF@Ym}Puvx%#20 zvD~Ev3;6sPzW)$4a5`&p;b5G5$zkptizRpQZM0@$W@KPoTwzcKP8G7kEKCLr2He0f zmE~t)VP;})00*!vABz}^Naj(Cc`kcYnU^b$d7NiR7+7ddW#$rBhi zj12DU)L%DfavGBKF?0-X3>n#WlU3IFid}SN0H2%tkCj-0Zywm5s zx^2~s4P9zxhnD?KF3H{TMvP6@|45|VvV&7>M2w}U)V--Z@RxID_~cue=WBg8%{=Fp z$2)7X>U^$}19NW7{(9v~P}r)YdQ+yp2)T52^@{AWp#0a}byd&bdp)1%Ztx~cejm@g Sx=;z%eS(jJ-*lL-@c{sbU2V?* literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..30b3cb779b8d8303f1d46ab9a32f8f530f4eace2 GIT binary patch literal 1059 zcmXqLVv#p!VrE~!%*4pVB;r1~c?bL1uT>Jl8Lh7Fmz1BztdcR{W#iOp^Jx3d%gD&h z%3#pgV90I2$;KSY!Y0fV8Vuub@Gv<$8VVT*fMnQtIGsxiQj1D5^YRUa4Fo}ATs&Nk z1qC^&3Z8k%dWNzF(hxzB;MC;OqRf&?1=qav%)HdpqRhN>Lm2}pkTf%oaA;m~eqM1& zQ6f+-MIpE}$=T6BPMp`!!qC9b%)s0L2%^ATBSTXIQ)6Qj(%aj?9`NToWJ9Y+L_g zPr&Wjzsnh&R!s3KlAKmEK}=rezE)mq>#loy{)L?qVO@E6_hN_Qe;?o8nfBN-Bl@Z0 zo~;*oZ0FtmZptpqlAYFBBYVN>d&*uzKhxVm%{4IxGY;H!3#(ctf5gW|RbavKs5Ob9 zzKSsu46`i%MpuV!N^iZwRoKAi(s%8*wW+1{qAdn*U60-5G~n>E;W1@< zpS+qFKXHN4emC=143hh~4dg-6$}AEFVhtj~N%Nm<@d-Y+VAhT!`u~saog7pvZXg3v zAjl$WAlxLFT%uQ!T3n)+2uhcF$@#g+Q3g!wz$jy6XfALtJvICFl-B{olPy z=v=D5;M^)$-PkW~5WmrR(ZsARGiH}hd;Rcxt& zf`Xh>1<$->JwsUoX^5amaB6aCQD#Y{f@@xSW?pJ)QD$Dcp^SkPNSc{PI5aOgKd-o? zC=n=^q7Yn~19KB2KLb#li>Zl`kzsqv zxq=r4ALCx#N?JI9ZI??o-|;#7G_6>S-gy3*|9Fq7cJ2oCQ){QW)`}jTlzDSjPPC`y z#-1+8(#8f~5hjhuPg`7;|Mc}Z7qVQHQ~ae~oOXGeR>doGLmQdbwhqaDQ8E_;wukbn z7P7gbq5Se%vJ?=X~>vA z{(SxSs=ign*7wX35l?@t?!30{)mx>HTyv`&WDUAwt^9oUU1T+P^-SK$$-It8yLE>{46ZYOzaH?!XS<+3y%R88;3R< zBP%OAGoyhlNRW?3j77xPq+^F-vHjyP&xEqBs}%+M8yG_kqF0hyT%wl{P|#M1bUrSUVvM}~5SAZ})7y{uga-fmgv#HxRo?^XHF4d0fQE|b?2-LNz<_$mVf zV_Jd+=Q{=l7G?$y12-l`hK4I=pK!#4U40lArImf@ZItNIvi5|~$Awn$mp3K!$7KSQ zJmIgoVZgHZ2kX{Sr}XscffwZEHC<*O&fifwDe+?T-Hi-o43q2&^tHH^_SY1iw6G{R z_`{+|c6_$%0AcLP_TsV6#LJYM{U_r-#%1;xfI`yA?A1@#S< z1m9$_Ni6+(tSF92!L?F!O30pF*5x}sPMJUBc2$nC#1;*4b7?i#<8!oc{mn&Ay}FL|Hc5O{xIA?4*U44wN^vbvS?By5Y=83(nld0o1d15Qk>ek=7Kd0u( zr{jN_96g=C_o*KI665$-NArWE9PH3<=>@qFK+Yk z$Dhki=Db_KRz!BM**C-VO?L$LdNX+4s)ddA@5XZH z)x(l^J0mupnAb1xENYK|Bj1aL`~OZF30>>Eu_5C%r#y$H@0t)W T{gR7L%lXsgLI?D9-tPkdyO!q9 literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..15fb0d2b7e4e0174ddd060a5ecc3263632c5b16a GIT binary patch literal 1000 zcmXqLVt!)K#B^o>GZP~dlSp3ag5&>vZ=0QpS=l!`HouWQMK!~KmyJ`a&7lw-#NJ9igf>V=Ai!w_p6!(4+QnyPbnb_c+mW}` z&bvgioLziqf_qK+_4s%%UHc$GhRHLwy{(!%ueN$(^Q*m){r-!Ugab-KZf#Bs(^Zs| zx8lt`wj$W!9M{Pr0n^0e>>-ZHEQzqN~E1TbmYaAqLXxD(sLQ{RbAPw)$=CA z+fKB3w9HPp@6xFqOzTsu1+KjKWR`trjfvZ$AHO`N1VnTHzT0%p^DOt56sEX$_8XL@ zmaDvz;5YckeogX@-@X6%9t9*&q z>v`MuroFj3kH11aaQF9ZMi)AhSuRV z_dOblW{Ss2yl3)F;9~uH#ctjLtus40GG9pD(7E*5zLjzR=A9puW(r5UTXDbozz{C( zeRb+oi)ME{NN5z^_;m;SFvh-v(2bNKJ9CGxY@o)G7LqE?)I=2Vp?0LqJR A-~a#s literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..8667b539dadbc823e0a713e4027f3a0913e54499 GIT binary patch literal 1032 zcmXqLVqr08VtTWHnTe5!Nu>VV?61o-4jW9nSnt%>St%&D_i2j(FB_*;n@8JsUPeZ4 zRtAH{219NGPB!LH7B*p~&|nycgNMo4(NM@h03^fC!|7aFkXlrdnU`-UY#;~{t88_F0+fuxyvghTU^^Ye;J ziV}fxDGI@*NzRT2a^k#(7KR3fW(MX4KoAAy8X1}zm>L_Km_`|-!5l@T3q=fsAdca7 ztw_uTxzWEU-B7_m4&nxJzx+I1-^7yS44~6MQVPMTMP;c)22G4g$f3i?%D~*j$j<;2 z=VEGNWMnvNVAK^Sw{d!@YVFOc-LLPiw%Y#X@LFfByxeI&Hhr2t*Sbr#fkW*{7Ng^B z*9Lt*RkaU#{U)!sHzi%W`sLSB%i;&2#+Ihu?xM>N#!gOn{#hg`hb#B{-QO2h7X&?u z<2~JWNJwgFWAdxh*BE}ze7jEa-6gsC^1qCWcTL|Hw@i8-S#;t#o8opxi}eQW2g3@4e*_rFgQS&N zBn-qFM1+&(KiT3Fd~U(49Y^&4AKg1Ss8-xS2BbicMbtpJNiexYuOzj&L@yDP`1F$V zbCIJAn4p1C#>mieLzAC>w%_!++LAZ(x5gJe^olR!TyGU=a@DyZtY0feZjtd1_B9u; zy+}A)dHK#EL90dcR;!AC5oOW%Z1(am_rlNO4Nrv&>l|;~dO7>Lm3iKb;tHcM`I6%D z>{n7#UY?3jYO!6xE|tJ-W`B|+_SMO5h5D8UuB9cK>ER*SDhHohCeG`><9a#&|H_a3 z0*-0>zdz5vzwE=Fh$m&rd$?Uqj{KbSdb@8&r+?CZR`q$NjjwHVe2Z4MmV!Z literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..a12aa0b6a5de6a4f6d2aaa2de33a107a797011b9 GIT binary patch literal 1035 zcmXqLVqrIEVtT)TnTe5!Nu*LVHS@*%BdRqai(bz=>8ZPLde{U5UN%mxHjlRNyo`+8 ztPBQ?4TjtXoNUaYENsF|p}{Z?2M?38qoI(207!KNfkiGtSgcIG-6IE$_I|A&z5?*emCglNxe99sc8B z_wngDw-w6s7{reBUD*<;_>;qJ#XIr06YaKf&Ux>!d7@9&v5+Zso<^#Fm6iqfJ z`8eF*Er*Hw#^QiuIcwW_UlwvY^M*^XIV_UNKkAqv>O5iN!sNJBa*Gd3y#AnEW2D=d zX#1M?ao7DdX_$O^MC888@d1A|tUpM`~)iM_!<7{pO!;W6N1{g*PocwKAnBz zxRpkME93snEHTbSVs`JWepUw9rPE-ryTHx3VCf;I*2hbQ<$r~r`Y&JA^g@#5TFdqi zjz-^S_vwCiEBY|uNn*;4XCK4E>f1c8h;iDneOf8o`){6%_-6gzwFh%@f~WoMe|>L4 NiPU1nbvL#y1^_I9d)@#5 literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..c0eb435ca5f86bad2063db88761ee08825ec713c GIT binary patch literal 987 zcmXqLV!m$B#I%0_GZP~dlSs{$#wLsN9_1;DEGy5(1@n0rHY_mUW#iOp^Jx3d%gD&h z%3zRT$Zf#M#vIDRCd?EX4C8R{FgZIK3KJ$i(xS|gN}z+%GxJhYi!$@l4P^|Z zATAXS%}dVDD=sNY1j?l-1eYc`I~p`GDj|mtBP#=Q6C*zZP@IdYiII_ErCi^_S2GW$ z#a-KA{#91s(~CpZ@f?3jlOz1a;}`8TmwQxtP`SZP;ew>;LoMUx;GK5&7k-SYNwarL zXMb{o$1Ks?MXgNanbx<)1IhPfSyaCo%S5tF*qn1{BRlW0RRV55;*Huli z*K$^cb@~m{`#mzHzWKQv4wx3DKb2$sM=sf`mm1beKk43Aw0Z0NX+hpWA2zYyOIbTmnHU)ixIqH^EG*1SOe_YnAPygk7>kH-()=e| ze1gv{n6=}G{{N$UCkNGv8_0vCm02VV#2Q3+ZzrwT^&#(5%39&+UBV7sp&mbzk>dcE zMuBm_$l%Fxv@ieSg%1Y&m9AW6T7`KRCInH`RK3yX2RdwyDeta z{4o17^S?)lL-*NZsna(WTv)XK{mYO)IYOsvc)Kb)`xieq&bTzc!7uOE2gCinPhx(& zZMe{K)!f%;dqB?zwr&wui{>BaUiY7vwIaOuwX9LYL`%NnSYqoCo_=1Uy=o+y+XdGVzFs1GyXW#iOp^Jx3d%gD&h z%3zRY$Zf#M#vIDRCd?EX4C8R{FgZIK3K6C)$T>bAp+f)Y(%IPYQFc$DvP z0?+?**E9Bd{agEG`h8)WeV_O9dTM==^M3jK($9m7qWKp$m?|{cOxam{@0zj03Aiu-ICoD%P`63W2&?8dmM&ZDqSXuWZ-X-59ami+Aj6&J*wMI{~I{V~d7fAaE* zPfy@vOGt%_qyP=Nv7vscaF6tzWIpZm=@6wUoXn?X@pqq0fX)-~Mh+8fv=a2toWNbj)A&+PlG-2e8XXuILeO(##@x&GR0 co@nUmaEJB3zB0aBGB@LznEhVm)APj(0A&wU00000 literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..f1cd405326161b858b88530f1c8aaafaa7958654 GIT binary patch literal 979 zcmXqLVm@!s#I$_@GZP~dlZaWLW9w?~XC-@eow^>Vv~<&|d!ylk9WZ60mkc^MhG zSs4t{47m+B*_cCF*o2uvgJB#F9wui;Lm>kJkPJHyr*mmRYEemMUcRBQfgnhXi-*gx zpdcqz!80#e&rs1o9wf-jBjFsP;F_0~UzD7ho0?am5L%pCq!5&!Ut%C9&TD94Xkch& zU~T{eQDCl-p{aqXv9XD1ltD7gYD(N8XCMP{hp1y(3D9P@oWyhmm&8hi;MAhB)FOi> zMkQqbGqN%;H!<=v0L8hOniv@wo}WtN|GK-&)I^ENwQW1MOW{7@Ge++Z?X~8L<(zq| zS541`z3@5Tw1Xno%u-(zpNL{Khza^XpO-f@X4^TNll4co^F7Pv^*wT6cdu;9K9S<2 zN3G5IZ{zOx_#8|=V;7hS&K_{;TpYLO?`nf3bMMXVdebU! zJ9Wi0^XQecH*JvlK6SA;KdZE5+3gCZ&q-<9<~1G3uUv26o^;Yi;0sgD?V}2rk1j8| zbwtGSYlX&^p!@9-ZB45Le?On&qH_JB^vyHP+H>AmET4Ad{w2BgZ!-`2JP5J8t9Bu3 z--#~=q%` zgPG+M?K_+0D^q!--*&!{QfLV;O`W|aTB4GDNp|^j!xwIcbRK;ddDqF>v(h~LCI8AF zFFEt%mE2z6;c9Qb94_oq`A>N#Pwc^!5B9E;W3SEVu{dD7O!Aw~$K=!JeohIyd4*l5 zD|T+gzKNm5>$93GXV~htsvDnEY+y*&*|X?>pm5oy_Zr@lvQ|x4&{h3-WB9%`J)2y4 z<1)W*eGtpx(SPB=0^LJfUhSIQux{1yi*`Ss@`O+Nm)@?Zd23ne;j_oqz7Dw-v;4o; zj+H;}xx|L-sk`;I=~$HCP9xjJKd+^HGUo6uG-xj2cX%CrmxJx6Tg~~cCl5*59aozx PU|Yax5hrb%bTk+MRGDxe literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..f0e0e6bdf2aa0d2e6b378ac634f8a27364e4386f GIT binary patch literal 1995 zcmZuyZ%ou?7^io=Ka@KG??8rtCjwL0mA9}cBLhTCZbnR81T&1wEWL8q(Q9k3Jz!C% z#axDNh8W`qKTINO;%!b1S%zjpU@pXHWDeOP+p@X%fhA-^=jJ3%_O|!O-px<#?|Gj0 zd4A9DdHNP8mI4v?*8wc4;Il4Ux0kz+_A7dTa;#b)2a z%bY|qoNGHncM-8*%!b7%G&eU9Il!Uuvf0XUpT-=g_yA~wW(#chR-FMcTeTM>Vli$= zL){OL99*|hKUp|4I%6OF$ulMF?aerPpvty?_J_%C!%*b>a(~9yC+_UyXKv3vtzU=L zRv*kivaIRvZ|ef2`R2r+Vrl`3X{%PZuoSfc%xtYNBPNr@h=3)KOkpO1ETX8c~cUiRv3X4o%0q%46? zO2B;~sY=U%LF^O!5>9byzNjW{k|Wt3iJ^j8Oh(*}Q>3B;td=dVBF=Eh_+23x%biN* z^GtjIC&g5QoMLECjes2_=LmGC7^KuAAx_8HOX~m~)PW9B2mG=QFp>^%tPTiCKvIQ| z3P^fMfr*Njpc}PtiZdPrM;M?*iqFm*zE-I{TnR!ZE1BfwNB_ID55J)Jbu0 z31BTwQD+&Fh{RmuGlmrdv?Rhj`V26=EK+`k)8eyK#OgN&ZbJ_*OL9By=6H(dJDDg` zNF-+04n7Z~y)p&a^3jB_p;%Za+6G|SMO6x4IbNcdpj zaxWdCSze&U#8(jiggK=k;S9dOi)y=XO>DXu9>jgD;(X!0WAU`A&e8XzS>*+Js2u%* zI+#vTtgEX_?M1C))uhl`*K6mDfn?<}Q*|?GssVre;y@5|C)fepaSROMm3~PQYAY*+ zPDazO(iaq~Dm^XRJewLl)i@Oq z^9?!J>c&@xAN8+20c@(8gc`B}EeESX*+9uaao80jNWq=_A3xX* zoAQ4$DhQJH#RIy(u<2TQxzyLT@wby#!Kuf#gU`e)}9@^Z=VzS@b?$8YWa_-cORouT=f^L{S-(1UvsVZr(S#qPGf z6&E_|LSv?-f0caxm|Wa-j=J9e-o9ID?mt>je)aZLv!n9P_oHR^zm&!P(t_ehpM6Ko zK;&3n$&VoNbOZa(wXDIBhVqqXB#)?BVX`s@6gPZqyEd};Xgo1=ptL?+qN`_sD*D=i(rY&!~1$&*+T69(8`A!cNz)j^(SO-?i?#ThTu=9w&y zvmzVioGLh0kcYs^ zh!zVuGvoc#x%V!N?VtUAezI-lv?JR1_(1vkJ0HJXp8K@+G z1`Sunp9bFVm{61TjYH#H!-W*S4^sGEa2oVIE)4rc;$X@3>!~G|K-CfV)bwbNm3uKv z-8g;h<@oW2xtrI*aG0{Kr7)|t48uqTWC#?`fT!#FHBD~z`#EDK>R*lgIkf~;X`Mecm73qHQ?8m(aXMH19dC``M`;&6h_E8Qh%)ARtFBzYhI9mFp ziFOOL;VAwpG4}Sv?Wyphd?=+ Zs!iWgS?`lm1DWfY)$SJG(4{Lke*?hrO*#Mo literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..ffaac609d58ed3fffcae9de2a276efd12b4aadf1 GIT binary patch literal 1012 zcmXqLV*X&z#B^f;GZP~dlZcgbiDZ(%QqA@5Cn;F@o+g7 z6y&5Tc;+SR87dnnf&`g)q?|((T=UZMi;`1wQ}ap`f-8$lQgao8^7Bg!2ctX`7)W8+_M-MOfCn~>gyPo{P(A14^!u*^=H zr;?_jWU;;@U`5vVrb{A^+P6;mBb|1o@vX%_#=n0|xNZA)yRpa? zdA!e$zEp8SC-dQj>rAUtP9-F5P+7a=>B9aEyZu`B1fOzVk=vufo@`YhX%Mh~@(MGP z#EYk|&Jf=6dgd|NBaf~cWvF<|dA>W>yt7G4nnjwi`h0t3Myvi`CT2zk#>I_&294bY z+`tf(g{OB3J9LG5{7g0wX5-RkV`O2xR>{P|%*gnkg$bA* zWk9+FSwszln*@_f^h#2TOY{;!DNQdqKNmU5fQc6vWsD5<3D1~jTlW>OJdz;cT4~&Sn2uYr=Vuaqq=gyM)H($6IeDPVxK4<$uPc>e-hmQ|f&VUj20{BIJ$z xg&DIasv5j-_I|HWQ|fRv@{O+U$E7Xb)>|)L`k|nQ>zs1Pe-^G~wj0(?0RVEYb-n-q literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-82-sectrust-ct.h b/OSX/shared_regressions/si-82-sectrust-ct.h new file mode 100644 index 00000000..bc000478 --- /dev/null +++ b/OSX/shared_regressions/si-82-sectrust-ct.h @@ -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 */ diff --git a/OSX/shared_regressions/si-82-sectrust-ct.m b/OSX/shared_regressions/si-82-sectrust-ct.m index 66867cde..35514896 100644 --- a/OSX/shared_regressions/si-82-sectrust-ct.m +++ b/OSX/shared_regressions/si-82-sectrust-ct.m @@ -6,15 +6,26 @@ * */ +#include #include #include #include -#include +#include #include #include #include +#include +#include +#include + +#if TARGET_OS_IPHONE +#include +#else +#include +#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 */ + 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 */ + 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 index 0000000000000000000000000000000000000000..c23d1c46342fd79445a6e3176915432980f34dab GIT binary patch literal 949 zcmXqLV%})b#58jOGZP~d6NkvmY_F^*4hsx;**LY@JlekVGBR?rG8m*8Dj3MIF^94+ z^N2eZ6y&5TIOi7?O0&=iS$Z%O*vz++%dqo*B1S#XfU|%coV06+1211j@~R zd|GUGGyc`r?yP0;&jK&Z4p<=fwRN6nfLCJ0EzRY|McvKss+U*#^)cnoRh_QZ#?y4P zN36~>@$Y}B1-u#$Grq2CE&9CrK}qSE@Dv-JP}Y;Zt2Vzmk<=lobtE#u{NUT{b1zS= z->}qm*MBjiRg>Co?p!EbI(7E+7~QQxr?Rsxug&&0abIo9#LURRxH#D$(Lfd$d9r*g zVk{!23To$C_j#%*Fy1}!?!Rrui3|6?8t{Xpg&7(Dv#=U411SS}kbp9agn?KCb{%{m z1^gf#EWk9$h8zvRln9IlMuuW0uVv*-%O9Q&nm)Hva6$i`&;25dnxB`tinIM-`ILM0 zaQO~~LtIjvMrLN22em%9nD42J7yZsLM^at3!2gc;6r0^DTb}(XoOR{Aj?k_T+xjbJ zuIdr5o5GW29&I`?=vT^OW0RTY3^rT*@{->kmNk!d-EzO_?7vl$Qcmb!)79JfHjCxs zA&*|~EiIOd4Sl~QZ#kT|aH;+!xedp7F0xn|?rHb@p~iigheLDsd|!?aa|ACh)#;tF zQF>$e<;->Sbg!mZM4a5z!m?UG_Efg!($#1F?JoIZ%G{r-#l8Euc$TM0v%#d^>+7ao hxURhXu_oujjV6budLCZ#(Tsuf@)FLqpJJwO0sv50Vdnq< literal 0 HcmV?d00001 diff --git a/OSX/trustd/iOS/AppleCorporateRootCA2.cer b/OSX/trustd/iOS/AppleCorporateRootCA2.cer new file mode 100644 index 0000000000000000000000000000000000000000..e16cc0fba335a9b8003cbd0f66d597df7b8519c4 GIT binary patch literal 585 zcmXqLVsbTTVm!TonTe5!i9^_JDxY|a`CkJrHV&;ek8`#x%*+NEhDrtsY|No7%si5g z1qC^&3eNdO1^GpZC8-KQ`S~RZ&W;L3h6)C9AT``P;?Ai>C7EfN$%!SI`FRSCr6n2p zMVTd)hQbDdAQfCZTo6+{^OE%pxeYi$f^5P}p}_`n;=G1t1{Q|q28Ko!28L1Myv87| z36x7mmy{U@u(5+ffQgZfRlAXeL5Vquf#s#})LBc9G6Zxldvy3-6t6n_yQB5{LJmLB zo}#wVyJwbR%m3mqOUFf9?maPE{_1u5Y@1Lm?uaYtCB`SL%e!MO3jRetGdc8PwnZvW z)^454rZf7g()ib$?r?29$da!pl47{n$-u!t78oG1d@N!tBG=v@Jex9=Kil(G>~mMH z50$SU#l{=(gQSHS8UM4e8ZZMX13r)dKS+QD7>jJkamSp&V35jW$gs$1O^DH)`jQZ_ zbA|d`dt!Y=>w+>4iK<;JoO#G2k&{33m`ALRtPK18?)v>J?VH<}47^&^6Ksr4&ne05 s{W4jlnDMFCb>k^5^>=nU82n*77k;SO)ag`oaLm!XhO$MOx8BYI07i+n^Z)<= literal 0 HcmV?d00001 diff --git a/OSX/trustd/macOS/entitlements.plist b/OSX/trustd/macOS/entitlements.plist index 3dbd2c88..1682ccdd 100644 --- a/OSX/trustd/macOS/entitlements.plist +++ b/OSX/trustd/macOS/entitlements.plist @@ -4,6 +4,8 @@ application-identifier com.apple.trustd + com.apple.application-identifier + com.apple.trustd com.apple.private.necp.match com.apple.private.network.socket-delegate diff --git a/OSX/trustd/trustd.c b/OSX/trustd/trustd.c index a4d137fd..0ccac927 100644 --- a/OSX/trustd/trustd.c +++ b/OSX/trustd/trustd.c @@ -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); } } } diff --git a/Security.exp-in b/Security.exp-in index 80c70e6c..9ffdcdaa 100644 --- a/Security.exp-in +++ b/Security.exp-in @@ -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 diff --git a/Security.xcodeproj/project.pbxproj b/Security.xcodeproj/project.pbxproj index cb162682..b3e41b60 100644 --- a/Security.xcodeproj/project.pbxproj +++ b/Security.xcodeproj/project.pbxproj @@ -1882,6 +1882,8 @@ 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 */; }; @@ -1889,6 +1891,7 @@ 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 */; }; @@ -9981,7 +9984,7 @@ 4C4296300BB0A68200491999 /* SecTrustSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTrustSettings.h; path = trust/SecTrustSettings.h; sourceTree = ""; }; 4C465C7D13AFD82300E841AC /* SecurityDevTests-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "SecurityDevTests-Info.plist"; sourceTree = ""; }; 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 = ""; }; + 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 = ""; }; 4C4CE9120AF81F0E0056B01D /* README */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = README; sourceTree = ""; }; 4C50ACFC1410671D00EE92DE /* DigiNotarCA2007RootCertificate.crt */ = {isa = PBXFileReference; lastKnownFileType = file; path = DigiNotarCA2007RootCertificate.crt; sourceTree = ""; }; @@ -10403,6 +10406,8 @@ D43DBEFA1E99D17300C04AEA /* SecTrustStoreServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTrustStoreServer.h; path = OSX/sec/securityd/SecTrustStoreServer.h; sourceTree = ""; }; D43DDE511F620F09009742A5 /* SecPolicyChecks.list */ = {isa = PBXFileReference; lastKnownFileType = text; path = SecPolicyChecks.list; sourceTree = ""; }; D43DDE581F638061009742A5 /* SecPolicy.list */ = {isa = PBXFileReference; lastKnownFileType = text; path = SecPolicy.list; sourceTree = ""; }; + D442AD62215ADA250050B50F /* AppleCorporateRootCA2.cer */ = {isa = PBXFileReference; lastKnownFileType = file; name = AppleCorporateRootCA2.cer; path = OSX/trustd/iOS/AppleCorporateRootCA2.cer; sourceTree = ""; }; + D442AD68215ADA250050B50F /* AppleCorporateRootCA.cer */ = {isa = PBXFileReference; lastKnownFileType = file; name = AppleCorporateRootCA.cer; path = OSX/trustd/iOS/AppleCorporateRootCA.cer; sourceTree = ""; }; D44D08B420AB890E0023C439 /* Security.apinotes */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Security.apinotes; path = base/Security.apinotes; sourceTree = ""; }; D45068681E948A9E00FA7675 /* entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = entitlements.plist; path = OSX/trustd/macOS/entitlements.plist; sourceTree = ""; }; D45068691E948ACE00FA7675 /* entitlements.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = entitlements.plist; path = OSX/trustd/iOS/entitlements.plist; sourceTree = ""; }; @@ -10416,12 +10421,15 @@ 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 = ""; }; + 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 = ""; }; D479F6E01F980F8F00388D28 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/Trust.strings; sourceTree = ""; }; D47C56AB1DCA831C00E18518 /* lib_ios_x64.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = lib_ios_x64.xcconfig; path = xcconfig/lib_ios_x64.xcconfig; sourceTree = ""; }; 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 = ""; }; D47C56FB1DCA8F4900E18518 /* all_arches.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = all_arches.xcconfig; path = xcconfig/all_arches.xcconfig; sourceTree = ""; }; 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 = ""; }; + D484A1012167D6F8008653A9 /* ct_exceptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ct_exceptions.m; sourceTree = ""; }; D487FBB71DB8357300D4BB0B /* si-29-sectrust-sha1-deprecation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "si-29-sectrust-sha1-deprecation.m"; sourceTree = ""; }; D487FBB91DB835B500D4BB0B /* si-29-sectrust-sha1-deprecation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "si-29-sectrust-sha1-deprecation.h"; sourceTree = ""; }; D48BD193206C47530075DDC9 /* si-35-cms-expiration-time.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "si-35-cms-expiration-time.m"; sourceTree = ""; }; @@ -11243,7 +11251,7 @@ 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 = ""; }; DC52EA8F1D80CC2A00B0A59C /* digest_calc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = digest_calc.c; sourceTree = ""; }; - DC52EA901D80CC2A00B0A59C /* entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = entitlements.plist; sourceTree = ""; }; + 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 = ""; }; DC52EA921D80CC2A00B0A59C /* syncbubble.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = syncbubble.m; sourceTree = ""; }; DC52EA931D80CC2A00B0A59C /* leaks.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = leaks.c; sourceTree = ""; }; @@ -15952,9 +15960,9 @@ 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 */, @@ -17694,10 +17702,10 @@ 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 */, @@ -19628,6 +19636,7 @@ 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 */, @@ -19694,6 +19703,7 @@ DCC78E251D8085FC00865A7C /* show_certificates.c */, D453C38A1FEC669300DE349B /* trust_update.m */, DCC78E261D8085FC00865A7C /* spc.c */, + D484A1012167D6F8008653A9 /* ct_exceptions.m */, ); name = Security/Tool; path = OSX/sec/Security/Tool; @@ -20453,6 +20463,7 @@ D43DBEF71E99D17300C04AEA /* SecTrustServer.c */, D43DBEF81E99D17300C04AEA /* SecTrustServer.h */, D43DBEF91E99D17300C04AEA /* SecTrustStoreServer.c */, + D46B379F2151B6E50083DAAA /* SecTrustStoreServer.m */, D43DBEFA1E99D17300C04AEA /* SecTrustStoreServer.h */, D4961BBD2079423300F16DA7 /* TrustURLSessionDelegate.m */, D4961BC52079426000F16DA7 /* TrustURLSessionDelegate.h */, @@ -20466,6 +20477,8 @@ DCE4E85D1D7A584D00AFB96E /* iOS */ = { isa = PBXGroup; children = ( + D442AD68215ADA250050B50F /* AppleCorporateRootCA.cer */, + D442AD62215ADA250050B50F /* AppleCorporateRootCA2.cer */, D41257EE1E941DA800781F23 /* com.apple.trustd.plist */, D45068691E948ACE00FA7675 /* entitlements.plist */, ); @@ -22468,6 +22481,7 @@ 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 */, @@ -24876,6 +24890,7 @@ D41257CB1E9410A300781F23 /* Sources */, D41257CC1E9410A300781F23 /* Frameworks */, D41257CD1E9410A300781F23 /* Copy LaunchDaemon */, + D442AD70215C39100050B50F /* Install Apple Corporate Roots */, ); buildRules = ( ); @@ -27880,7 +27895,29 @@ ); 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; @@ -29085,6 +29122,7 @@ 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 */, @@ -29917,6 +29955,7 @@ 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 */, @@ -44136,6 +44175,11 @@ 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; @@ -44182,6 +44226,11 @@ 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; diff --git a/keychain/ckks/CKKS.h b/keychain/ckks/CKKS.h index 76050f4f..d6eeb225 100644 --- a/keychain/ckks/CKKS.h +++ b/keychain/ckks/CKKS.h @@ -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); diff --git a/keychain/ckks/CKKSCKAccountStateTracker.m b/keychain/ckks/CKKSCKAccountStateTracker.m index 116c5070..f108eca3 100644 --- a/keychain/ckks/CKKSCKAccountStateTracker.m +++ b/keychain/ckks/CKKSCKAccountStateTracker.m @@ -144,7 +144,7 @@ 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); @@ -188,6 +188,7 @@ dispatch_sync(self.queue, ^{ self.firstCKAccountFetch = true; + secnotice("ckksaccount", "received CK Account info: %@", ckAccountInfo); [self _onqueueUpdateAccountState:ckAccountInfo circle:self.currentCircleStatus deliveredSemaphore:finishedSema]; }); }]; @@ -362,13 +363,14 @@ 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) { @@ -530,6 +532,21 @@ 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:@"", SOSCCGetStatusDescription(self.status), self.error]; diff --git a/keychain/ckks/CKKSControl.h b/keychain/ckks/CKKSControl.h index 7407c313..98849613 100644 --- a/keychain/ckks/CKKSControl.h +++ b/keychain/ckks/CKKSControl.h @@ -42,6 +42,8 @@ typedef NS_ENUM(NSUInteger, CKKSKnownBadState) { - (void)rpcStatus:(NSString* _Nullable)viewName reply:(void (^)(NSArray* _Nullable result, NSError* _Nullable error))reply; +- (void)rpcFastStatus:(NSString* _Nullable)viewName + reply:(void (^)(NSArray* _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; diff --git a/keychain/ckks/CKKSControl.m b/keychain/ckks/CKKSControl.m index f541e02f..1407f25c 100644 --- a/keychain/ckks/CKKSControl.m +++ b/keychain/ckks/CKKSControl.m @@ -57,6 +57,16 @@ }]; } +- (void)rpcFastStatus:(NSString*)viewName reply:(void(^)(NSArray* result, NSError* error)) reply { + [[self.connection remoteObjectProxyWithErrorHandler: ^(NSError* error) { + reply(nil, error); + + }] rpcFastStatus:viewName reply:^(NSArray* result, NSError* error){ + reply(result, error); + }]; +} + + - (void)rpcResetLocal:(NSString*)viewName reply:(void(^)(NSError* error))reply { [[self.connection remoteObjectProxyWithErrorHandler:^(NSError* error) { reply(error); @@ -128,11 +138,9 @@ } - (void)rpcTLKMissing:(NSString*)viewName reply:(void(^)(bool missing))reply { - [self rpcStatus:viewName reply:^(NSArray* results, NSError* blockError) { + [self rpcFastStatus:viewName reply:^(NSArray* results, NSError* blockError) { bool missing = false; - // Until PCS fixes [ 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"]; @@ -152,14 +160,12 @@ } - (void)rpcKnownBadState:(NSString* _Nullable)viewName reply:(void (^)(CKKSKnownBadState))reply { - [self rpcStatus:viewName reply:^(NSArray* results, NSError* blockError) { + [self rpcFastStatus:viewName reply:^(NSArray* 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: CKKS: remove "global" hack from rpcStatus - // Use this hack for(NSDictionary* result in results) { NSString* name = result[@"view"]; NSString* keystate = result[@"keystate"]; diff --git a/keychain/ckks/CKKSControlProtocol.h b/keychain/ckks/CKKSControlProtocol.h index ed1749b6..5b7054ca 100644 --- a/keychain/ckks/CKKSControlProtocol.h +++ b/keychain/ckks/CKKSControlProtocol.h @@ -35,7 +35,14 @@ - (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* 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* 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; diff --git a/keychain/ckks/CKKSControlProtocol.m b/keychain/ckks/CKKSControlProtocol.m index 3821d8b1..de2a7b2b 100644 --- a/keychain/ckks/CKKSControlProtocol.m +++ b/keychain/ckks/CKKSControlProtocol.m @@ -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 diff --git a/keychain/ckks/CKKSGroupOperation.m b/keychain/ckks/CKKSGroupOperation.m index 4ead9621..66a6ba40 100644 --- a/keychain/ckks/CKKSGroupOperation.m +++ b/keychain/ckks/CKKSGroupOperation.m @@ -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:^{ diff --git a/keychain/ckks/CKKSIncomingQueueOperation.m b/keychain/ckks/CKKSIncomingQueueOperation.m index 3f836700..3132c6d0 100644 --- a/keychain/ckks/CKKSIncomingQueueOperation.m +++ b/keychain/ckks/CKKSIncomingQueueOperation.m @@ -332,6 +332,7 @@ } }; + __block bool errored = false; [ckks dispatchSync: ^bool{ if(self.cancelled) { ckksnotice("ckksincoming", ckks, "CKKSIncomingQueueOperation cancelled, quitting"); @@ -399,16 +400,32 @@ } } } + 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 * queueEntries = nil; - NSString* lastMaxUUID = nil; - while(queueEntries == nil || queueEntries.count == SecCKKSIncomingQueueItemsAtOnce) { + while(lastCount == SecCKKSIncomingQueueItemsAtOnce) { + [ckks dispatchSync: ^bool{ + NSArray * 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 @@ -418,19 +435,23 @@ 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; } @@ -438,10 +459,19 @@ 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* newCIPs = [CKKSCurrentItemPointer remoteItemPointers:ckks.zoneID error:&error]; if(error || !newCIPs) { @@ -462,7 +492,7 @@ [self.ckks processIncomingQueueAfterNextUnlock]; } - return ok; + return true; }]; } diff --git a/keychain/ckks/CKKSKeychainView.h b/keychain/ckks/CKKSKeychainView.h index e1f7bf6a..b5ab8e2d 100644 --- a/keychain/ckks/CKKSKeychainView.h +++ b/keychain/ckks/CKKSKeychainView.h @@ -265,8 +265,9 @@ NS_ASSUME_NONNULL_BEGIN @property NSHashTable* 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*)status; +- (NSDictionary*)fastStatus; @end NS_ASSUME_NONNULL_END diff --git a/keychain/ckks/CKKSKeychainView.m b/keychain/ckks/CKKSKeychainView.m index 4a958f08..965c28f2 100644 --- a/keychain/ckks/CKKSKeychainView.m +++ b/keychain/ckks/CKKSKeychainView.m @@ -3448,9 +3448,13 @@ - (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]; @@ -3479,23 +3483,7 @@ [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]), @@ -3509,24 +3497,51 @@ @"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 diff --git a/keychain/ckks/CKKSLockStateTracker.m b/keychain/ckks/CKKSLockStateTracker.m index a0e5b828..8502be87 100644 --- a/keychain/ckks/CKKSLockStateTracker.m +++ b/keychain/ckks/CKKSLockStateTracker.m @@ -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; diff --git a/keychain/ckks/CKKSReachabilityTracker.m b/keychain/ckks/CKKSReachabilityTracker.m index 0317a754..3fd193ac 100644 --- a/keychain/ckks/CKKSReachabilityTracker.m +++ b/keychain/ckks/CKKSReachabilityTracker.m @@ -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, ^{ diff --git a/keychain/ckks/CKKSResultOperation.m b/keychain/ckks/CKKSResultOperation.m index 559adb40..e36f1af6 100644 --- a/keychain/ckks/CKKSResultOperation.m +++ b/keychain/ckks/CKKSResultOperation.m @@ -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; diff --git a/keychain/ckks/CKKSViewManager.m b/keychain/ckks/CKKSViewManager.m index e5a09126..afd9afd2 100644 --- a/keychain/ckks/CKKSViewManager.m +++ b/keychain/ckks/CKKSViewManager.m @@ -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* result, NSError* error)) reply { +- (void)rpcStatus: (NSString*)viewName + global:(bool)reportGlobal + reply:(void(^)(NSArray* 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>* 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>* 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* mutTrustedPeers = [[NSMutableArray alloc] init]; - [peers enumerateObjectsUsingBlock:^(id _Nonnull obj, BOOL * _Nonnull stop) { - [mutTrustedPeers addObject: [obj description]]; - }]; + NSMutableArray* mutTrustedPeers = [[NSMutableArray alloc] init]; + [peers enumerateObjectsUsingBlock:^(id _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* 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* 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]; } } diff --git a/keychain/ckks/CKKSZone.m b/keychain/ckks/CKKSZone.m index 7d47c88d..3a5dda69 100644 --- a/keychain/ckks/CKKSZone.m +++ b/keychain/ckks/CKKSZone.m @@ -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; diff --git a/keychain/ckks/CKKSZoneChangeFetcher.m b/keychain/ckks/CKKSZoneChangeFetcher.m index 95edf9d0..2d60816c 100644 --- a/keychain/ckks/CKKSZoneChangeFetcher.m +++ b/keychain/ckks/CKKSZoneChangeFetcher.m @@ -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]; diff --git a/keychain/ckks/tests/CKKSTests+API.m b/keychain/ckks/tests/CKKSTests+API.m index 7d316458..9fc7a7c9 100644 --- a/keychain/ckks/tests/CKKSTests+API.m +++ b/keychain/ckks/tests/CKKSTests+API.m @@ -1299,12 +1299,42 @@ 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* 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. diff --git a/keychain/ckks/tests/CKKSTests.m b/keychain/ckks/tests/CKKSTests.m index ad6f2966..33ea65b4 100644 --- a/keychain/ckks/tests/CKKSTests.m +++ b/keychain/ckks/tests/CKKSTests.m @@ -528,6 +528,15 @@ [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]; @@ -3604,13 +3613,17 @@ // 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]; @@ -3619,6 +3632,11 @@ 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; diff --git a/keychain/ckks/tests/MockCloudKit.m b/keychain/ckks/tests/MockCloudKit.m index f130b83f..cac58a90 100644 --- a/keychain/ckks/tests/MockCloudKit.m +++ b/keychain/ckks/tests/MockCloudKit.m @@ -581,7 +581,7 @@ _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]; diff --git a/resources/English.lproj/Trust.strings b/resources/English.lproj/Trust.strings index b56f74c86d1d5544478c0f53f85e253d73e818f7..fb6330cfc9dad036f6b46942d162855293f409b1 100644 GIT binary patch delta 106 zcmZpuThYk4;h&*wF+(LoF+&MMDnl-VE|4x_C