From: Apple Date: Tue, 26 Mar 2019 22:07:09 +0000 (+0000) Subject: Security-58286.230.21.tar.gz X-Git-Tag: macos-10142^0 X-Git-Url: https://git.saurik.com/apple/security.git/commitdiff_plain/7512f6be898225cd564f3d305c36fa63eca9a60a Security-58286.230.21.tar.gz --- 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 00000000..ebeb137b Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/AppleISTCA8G1.cer differ diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/CTlogs.plist b/OSX/shared_regressions/si-82-sectrust-ct-data/CTlogs.plist index 31aa5692..1abc8574 100644 --- a/OSX/shared_regressions/si-82-sectrust-ct-data/CTlogs.plist +++ b/OSX/shared_regressions/si-82-sectrust-ct-data/CTlogs.plist @@ -6,11 +6,7 @@ description 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 00000000..75dfaf39 Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/GeoTrustPrimaryCAG2.cer differ diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/GlobalSignRootCAR2.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/GlobalSignRootCAR2.cer new file mode 100644 index 00000000..4d937187 Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/GlobalSignRootCAR2.cer differ diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/GoogleIAG3.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/GoogleIAG3.cer new file mode 100644 index 00000000..ffb1a0ff Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/GoogleIAG3.cer differ diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_apple_ca.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_apple_ca.cer new file mode 100644 index 00000000..2cd4bebd Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_apple_ca.cer differ diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_apple_root.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_apple_root.cer new file mode 100644 index 00000000..8a9ff247 Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_apple_root.cer differ diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_apple_server_after.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_apple_server_after.cer new file mode 100644 index 00000000..f91a14eb Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_apple_server_after.cer differ diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_fail_server.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_fail_server.cer new file mode 100644 index 00000000..ca3f1f2e Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_fail_server.cer differ diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_dn_server.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_dn_server.cer new file mode 100644 index 00000000..fde0d036 Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_dn_server.cer differ diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_dn_server_mismatch.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_dn_server_mismatch.cer new file mode 100644 index 00000000..53f7abcf Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_dn_server_mismatch.cer differ diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_dn_subca.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_dn_subca.cer new file mode 100644 index 00000000..4ebf9b01 Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_dn_subca.cer differ diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_org_server.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_org_server.cer new file mode 100644 index 00000000..f178a088 Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_org_server.cer differ diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_org_server_mismatch.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_org_server_mismatch.cer new file mode 100644 index 00000000..bf53339c Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_org_server_mismatch.cer differ diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_org_subca.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_org_subca.cer new file mode 100644 index 00000000..5c4492bc Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_no_org_subca.cer differ diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_server.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_server.cer new file mode 100644 index 00000000..c1958849 Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_server.cer differ diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_server_scts.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_server_scts.cer new file mode 100644 index 00000000..763cd2fd Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_server_scts.cer differ diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_subca.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_subca.cer new file mode 100644 index 00000000..765c5dfd Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_constrained_subca.cer differ diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_root.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_root.cer new file mode 100644 index 00000000..9764bea7 Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_root.cer differ diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_after.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_after.cer new file mode 100644 index 00000000..243e4071 Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_after.cer differ diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_after_scts.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_after_scts.cer new file mode 100644 index 00000000..2ba760d9 Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_after_scts.cer differ diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_before.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_before.cer new file mode 100644 index 00000000..316d95ff Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_before.cer differ diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_matching_orgs.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_matching_orgs.cer new file mode 100644 index 00000000..30b3cb77 Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_matching_orgs.cer differ diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_matching_orgs_scts.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_matching_orgs_scts.cer new file mode 100644 index 00000000..bb729800 Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_matching_orgs_scts.cer differ diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_no_orgs.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_no_orgs.cer new file mode 100644 index 00000000..15fb0d2b Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_no_orgs.cer differ diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_nonmatching_orgs.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_nonmatching_orgs.cer new file mode 100644 index 00000000..8667b539 Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_nonmatching_orgs.cer differ diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_partial_orgs.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_partial_orgs.cer new file mode 100644 index 00000000..a12aa0b6 Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_server_partial_orgs.cer differ diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_unconstrained_subca.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_unconstrained_subca.cer new file mode 100644 index 00000000..c0eb435c Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_system_unconstrained_subca.cer differ diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_user_root.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_user_root.cer new file mode 100644 index 00000000..68dde2c9 Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_user_root.cer differ diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_user_server_after.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_user_server_after.cer new file mode 100644 index 00000000..f1cd4053 Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/enforcement_user_server_after.cer differ diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/google.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/google.cer new file mode 100644 index 00000000..f0e0e6bd Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/google.cer differ diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/livability.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/livability.cer new file mode 100644 index 00000000..b6812aef Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/livability.cer differ diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/precert.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/precert.cer new file mode 100644 index 00000000..ffaac609 Binary files /dev/null and b/OSX/shared_regressions/si-82-sectrust-ct-data/precert.cer differ diff --git a/OSX/shared_regressions/si-82-sectrust-ct.h b/OSX/shared_regressions/si-82-sectrust-ct.h new file mode 100644 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 00000000..c23d1c46 Binary files /dev/null and b/OSX/trustd/iOS/AppleCorporateRootCA.cer differ diff --git a/OSX/trustd/iOS/AppleCorporateRootCA2.cer b/OSX/trustd/iOS/AppleCorporateRootCA2.cer new file mode 100644 index 00000000..e16cc0fb Binary files /dev/null and b/OSX/trustd/iOS/AppleCorporateRootCA2.cer differ 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 b56f74c8..fb6330cf 100644 Binary files a/resources/English.lproj/Trust.strings and b/resources/English.lproj/Trust.strings differ diff --git a/tests/secdmockaks/secdmockaks.m b/tests/secdmockaks/secdmockaks.m index da508f25..50457bf2 100644 --- a/tests/secdmockaks/secdmockaks.m +++ b/tests/secdmockaks/secdmockaks.m @@ -146,7 +146,7 @@ (id)kSecAttrNoLegacy : @(YES) }; OSStatus result = SecItemAdd((__bridge CFDictionaryRef)item, NULL); - XCTAssertEqual(result, 0, @"failed to add test item to keychain: %u", n); + XCTAssertEqual(result, errSecSuccess, @"failed to add test item to keychain: %u", n); } } @@ -161,10 +161,97 @@ (id)kSecAttrNoLegacy : @(YES) }; OSStatus result = SecItemCopyMatching((__bridge CFDictionaryRef)item, NULL); - XCTAssertEqual(result, 0, @"failed to find test item to keychain: %u", n); + XCTAssertEqual(result, errSecSuccess, @"failed to find test item to keychain: %u", n); } } +- (void)testSecItemServerDeleteAll +{ + // BT root key, should not be deleted + NSMutableDictionary* bt = [@{ + (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccessGroup : @"com.apple.bluetooth", + (id)kSecAttrService : @"BluetoothGlobal", + (id)kSecAttrAccessible : (id)kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate, + (id)kSecAttrSynchronizable : @(NO), + (id)kSecValueData : [@"btkey" dataUsingEncoding:NSUTF8StringEncoding], + } mutableCopy]; + + // lockdown-identities, should not be deleted + NSMutableDictionary* ld = [@{ + (id)kSecClass : (id)kSecClassKey, + (id)kSecAttrAccessGroup : @"lockdown-identities", + (id)kSecAttrLabel : @"com.apple.lockdown.identity.activation", + (id)kSecAttrAccessible : (id)kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate, + (id)kSecAttrSynchronizable : @(NO), + (id)kSecValueData : [@"ldkey" dataUsingEncoding:NSUTF8StringEncoding], + } mutableCopy]; + + // general nonsyncable item, should be deleted + NSMutableDictionary* s0 = [@{ + (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrService : @"NonsyncableService", + (id)kSecAttrSynchronizable : @(NO), + (id)kSecValueData : [@"s0pwd" dataUsingEncoding:NSUTF8StringEncoding], + } mutableCopy]; + + // general syncable item, should be deleted + NSMutableDictionary* s1 = [@{ + (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrService : @"SyncableService", + (id)kSecAttrSynchronizable : @(YES), + (id)kSecValueData : [@"s0pwd" dataUsingEncoding:NSUTF8StringEncoding], + } mutableCopy]; + + // Insert all items + OSStatus status; + status = SecItemAdd((__bridge CFDictionaryRef)bt, NULL); + XCTAssertEqual(status, errSecSuccess, "failed to add bt item to keychain"); + status = SecItemAdd((__bridge CFDictionaryRef)ld, NULL); + XCTAssertEqual(status, errSecSuccess, "failed to add ld item to keychain"); + status = SecItemAdd((__bridge CFDictionaryRef)s0, NULL); + XCTAssertEqual(status, errSecSuccess, "failed to add s0 item to keychain"); + status = SecItemAdd((__bridge CFDictionaryRef)s1, NULL); + XCTAssertEqual(status, errSecSuccess, "failed to add s1 item to keychain"); + + // Make sure they exist now + bt[(id)kSecValueData] = nil; + ld[(id)kSecValueData] = nil; + s0[(id)kSecValueData] = nil; + s1[(id)kSecValueData] = nil; + status = SecItemCopyMatching((__bridge CFDictionaryRef)bt, NULL); + XCTAssertEqual(status, errSecSuccess, "failed to find bt item in keychain"); + status = SecItemCopyMatching((__bridge CFDictionaryRef)ld, NULL); + XCTAssertEqual(status, errSecSuccess, "failed to find ld item in keychain"); + status = SecItemCopyMatching((__bridge CFDictionaryRef)s0, NULL); + XCTAssertEqual(status, errSecSuccess, "failed to find s0 item in keychain"); + status = SecItemCopyMatching((__bridge CFDictionaryRef)s1, NULL); + XCTAssertEqual(status, errSecSuccess, "failed to find s1 item in keychain"); + + // Nuke the keychain + CFErrorRef error = NULL; + _SecItemDeleteAll(&error); + XCTAssertEqual(error, NULL, "_SecItemDeleteAll returned an error: %@", error); + CFReleaseNull(error); + + // Does the function work properly with an error pre-set? + error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainOSStatus, errSecItemNotFound, NULL); + _SecItemDeleteAll(&error); + XCTAssertEqual(CFErrorGetDomain(error), kCFErrorDomainOSStatus); + XCTAssertEqual(CFErrorGetCode(error), errSecItemNotFound); + CFReleaseNull(error); + + // Check the relevant items are missing + status = SecItemCopyMatching((__bridge CFDictionaryRef)bt, NULL); + XCTAssertEqual(status, errSecSuccess, "failed to find bt item in keychain"); + status = SecItemCopyMatching((__bridge CFDictionaryRef)ld, NULL); + XCTAssertEqual(status, errSecSuccess, "failed to find ld item in keychain"); + status = SecItemCopyMatching((__bridge CFDictionaryRef)s0, NULL); + XCTAssertEqual(status, errSecItemNotFound, "unexpectedly found s0 item in keychain"); + status = SecItemCopyMatching((__bridge CFDictionaryRef)s1, NULL); + XCTAssertEqual(status, errSecItemNotFound, "unexpectedly found s1 item in keychain"); +} + - (void)createManyKeys { unsigned n; diff --git a/trust/SecPolicyPriv.h b/trust/SecPolicyPriv.h index e7e6fbee..0fd731f1 100644 --- a/trust/SecPolicyPriv.h +++ b/trust/SecPolicyPriv.h @@ -1831,6 +1831,7 @@ extern const CFStringRef kSecPolicyCheckBlackListedLeaf; extern const CFStringRef kSecPolicyCheckCertificatePolicy; extern const CFStringRef kSecPolicyCheckChainLength; extern const CFStringRef kSecPolicyCheckCriticalExtensions; +extern const CFStringRef kSecPolicyCheckCTRequired; extern const CFStringRef kSecPolicyCheckEAPTrustedServerNames; extern const CFStringRef kSecPolicyCheckEmail; extern const CFStringRef kSecPolicyCheckExtendedKeyUsage; @@ -1867,6 +1868,7 @@ extern const CFStringRef kSecPolicyCheckSubjectCommonNamePrefix; extern const CFStringRef kSecPolicyCheckSubjectCommonNameTEST; extern const CFStringRef kSecPolicyCheckSubjectOrganization; extern const CFStringRef kSecPolicyCheckSubjectOrganizationalUnit; +extern const CFStringRef kSecPolicyCheckSystemTrustedCTRequired; extern const CFStringRef kSecPolicyCheckSystemTrustedWeakHash; extern const CFStringRef kSecPolicyCheckSystemTrustedWeakKey; extern const CFStringRef kSecPolicyCheckTemporalValidity; @@ -1874,7 +1876,6 @@ extern const CFStringRef kSecPolicyCheckUsageConstraints; extern const CFStringRef kSecPolicyCheckValidRoot; extern const CFStringRef kSecPolicyCheckWeakKeySize; extern const CFStringRef kSecPolicyCheckWeakSignature; -extern const CFStringRef kSecPolicyCheckCTRequired; /* Special option for checking Apple Anchors */ extern const CFStringRef kSecPolicyAppleAnchorIncludeTestRoots; @@ -1933,6 +1934,8 @@ __nullable CFArrayRef SecPolicyXPCArrayCopyArray(xpc_object_t xpc_policies, CFEr void SecPolicySetOptionsValue(SecPolicyRef policy, CFStringRef key, CFTypeRef value); +bool SecDNSIsTLD(CFStringRef reference); + CF_IMPLICIT_BRIDGING_DISABLED CF_ASSUME_NONNULL_END diff --git a/trust/SecTrust.h b/trust/SecTrust.h index e1eada2c..439750e8 100644 --- a/trust/SecTrust.h +++ b/trust/SecTrust.h @@ -546,6 +546,19 @@ CFDictionaryRef SecTrustCopyResult(SecTrustRef trust) OSStatus SecTrustSetOCSPResponse(SecTrustRef trust, CFTypeRef __nullable responseData) __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); +/*! + @function SecTrustSignedCertificateTimestamps + @abstract Attach SignedCertificateTimestamp data to a trust object. + @param trust A reference to a trust object. + @param sctArray is a CFArray of CFData objects each containing a SCT (per RFC 6962). + @result A result code. See "Security Error Codes" (SecBase.h). + @discussion Allows the caller to provide SCT data (which may be + obtained during a TLS/SSL handshake, per RFC 6962) as input to a trust + evaluation. + */ +OSStatus SecTrustSetSignedCertificateTimestamps(SecTrustRef trust, CFArrayRef __nullable sctArray) + API_AVAILABLE(macos(10.14.2), ios(12.1.1), tvos(12.1.1), watchos(5.1.1)); + CF_IMPLICIT_BRIDGING_DISABLED CF_ASSUME_NONNULL_END diff --git a/trust/SecTrustPriv.h b/trust/SecTrustPriv.h index 58656527..9cbd5421 100644 --- a/trust/SecTrustPriv.h +++ b/trust/SecTrustPriv.h @@ -254,6 +254,14 @@ CFStringRef SecTrustCopyFailureDescription(SecTrustRef trust); */ uint64_t SecTrustGetTrustStoreVersionNumber(CFErrorRef _Nullable * _Nullable CF_RETURNS_RETAINED error); +/* + @function SecTrustGetAssetVersionNumber + @abstract Ask trustd what asset version it is using. + @param error A returned error if trustd failed to answer. + @result The current version of the asset. 0 upon failure. + */ +uint64_t SecTrustGetAssetVersionNumber(CFErrorRef _Nullable * _Nullable CF_RETURNS_RETAINED error); + /* @function SecTrustOTAPKIGetUpdatedAsset @abstract Trigger trustd to fetch a new trust supplementals asset right now. @@ -276,18 +284,6 @@ uint64_t SecTrustOTAPKIGetUpdatedAsset(CFErrorRef _Nullable * _Nullable CF_RETUR Boolean SecTrustFlushResponseCache(CFErrorRef _Nullable * _Nullable CF_RETURNS_RETAINED error) __OSX_AVAILABLE(10.13.4) __IOS_AVAILABLE(11.3) __TVOS_AVAILABLE(11.3) __WATCHOS_AVAILABLE(4.3); -/*! - @function SecTrustSignedCertificateTimestampList - @abstract Attach SignedCertificateTimestampList data to a trust object. - @param trust A reference to a trust object. - @param sctArray is a CFArray of CFData objects each containing a SCT (per RFC 6962). - @result A result code. See "Security Error Codes" (SecBase.h). - @discussion Allows the caller to provide SCT data (which may be - obtained during a TLS/SSL handshake, per RFC 6962) as input to a trust - evaluation. - */ -OSStatus SecTrustSetSignedCertificateTimestamps(SecTrustRef trust, CFArrayRef sctArray); - /*! @function SecTrustSetTrustedLogs @abstract Sets the trusted CT logs for a given trust. @@ -438,6 +434,24 @@ OSStatus SecTrustEvaluateFastAsync(SecTrustRef trust, dispatch_queue_t queue, Se bool SecTrustReportTLSAnalytics(CFStringRef eventName, xpc_object_t eventAttributes, CFErrorRef _Nullable * _Nullable CF_RETURNS_RETAINED error) __API_AVAILABLE(macos(10.13.4), ios(11.3), tvos(11.3), watchos(4.3)); +/*! + @function SecTrustReportNetworkingAnalytics + @discussion This function MUST NOT be called outside of the networking stack. + */ +bool SecTrustReportNetworkingAnalytics(const char *eventName, xpc_object_t eventAttributes) +__API_AVAILABLE(macos(10.14.1), ios(12.1), tvos(12.1), watchos(5.1)); + +/*! + @function SecTrustSetNeedsEvaluation + @abstract Reset the evaluation state of the trust object + @param trust Trust object to reset + @discussion Calling this will reset the trust object so that the next time SecTrustEvaluate* + is called, a new trust evaluation is performed. SecTrustSet* interfaces implicitly call this, + so this function is only necessary if you've made system configuration changes (like trust + settings) that don't impact the trust object itself. + */ +void SecTrustSetNeedsEvaluation(SecTrustRef trust); + CF_IMPLICIT_BRIDGING_DISABLED CF_ASSUME_NONNULL_END diff --git a/trust/SecTrustSettingsPriv.h b/trust/SecTrustSettingsPriv.h index 89feb679..469fda9c 100644 --- a/trust/SecTrustSettingsPriv.h +++ b/trust/SecTrustSettingsPriv.h @@ -50,6 +50,36 @@ __BEGIN_DECLS #define kSecTrustSettingsPolicyName CFSTR("kSecTrustSettingsPolicyName") #define kSecTrustSettingsPolicyOptions CFSTR("kSecTrustSettingsPolicyOptions") +extern const CFStringRef kSecCTExceptionsCAsKey; +extern const CFStringRef kSecCTExceptionsDomainsKey; +extern const CFStringRef kSecCTExceptionsHashAlgorithmKey; +extern const CFStringRef kSecCTExceptionsSPKIHashKey; + +/* + @function SecTrustStoreSetCTExceptions + @abstract Set the certificate transparency enforcement exceptions + @param applicationIdentifier Identifier for the caller. If null, the application-identifier will be read from the callers entitlements. + @param exceptions Dictionary of exceptions to set for this application. These exceptions replace existing exceptions for the keys in the dictionary. Exceptions for omitted keys are not affected. Null removes all exceptions for this application. See the discussion sections below for a complete overview of options. + @param error Upon failure describes cause of the failure. + @result boolean indicating success of the operation. If false, error will be filled in with a description of the error. + @discussions An exceptions dictionary has two optional keys: + kSecCTExceptionsDomainsKey takes an array of strings. These strings are the domains that are excluded from enforcing CT. A leading "." is supported to signify subdomains. Wildcard domains are not supported. + kSecCTExceptionsCAsKey takes an array of dictionaries. Each dictionary has two required keys: + kSecCTExceptionsHashAlgorithmKey takes a string indicating the hash algorithm. Currenlty only "sha256" is supported. + kSecCTExceptionsSPKIHashKey takes a data containing hash of a certificates SubjectPublicKeyInfo. + */ +bool SecTrustStoreSetCTExceptions(CFStringRef applicationIdentifier, CFDictionaryRef exceptions, CFErrorRef *error); + +/* + @function SecTrustStoreCopyCTExceptions + @abstract Return the certificate transparency enforcement exceptions + @param applicationIdentifier Identifier for the caller's exceptions to fetch. If null, all set exceptions will be returned (regardless of which caller set them). + @param error Upon failure describes cause of the failure. + @result The dictionary of currently set exceptions. Null if none exist or upon failure. + @discussion The returned exceptions dictionary has the same options as input exceptions. See the discussion of SecTrustStoreSetCTExceptions. + */ +CF_RETURNS_RETAINED CFDictionaryRef SecTrustStoreCopyCTExceptions(CFStringRef applicationIdentifier, CFErrorRef *error); + #if SEC_OS_OSX /*