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];
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) {
<true/>
<key>application-identifier</key>
<string>com.apple.security.regressions</string>
+ <key>com.apple.application-identifier</key>
+ <string>com.apple.security.regressions</string>
<key>com.apple.private.uninstall.deletion</key>
<true/>
<key>com.apple.private.security.delete.all</key>
| kSecCSRestrictToAppLike
| kSecCSUseSoftwareSigningCert
| kSecCSValidatePEH
+ | kSecCSSingleThreaded
);
if (errors)
kSecCSRestrictSidebandData = 1 << 9,
kSecCSUseSoftwareSigningCert = 1 << 10,
kSecCSValidatePEH = 1 << 11,
+ kSecCSSingleThreaded = 1 << 12,
};
OSStatus SecStaticCodeCheckValidity(SecStaticCodeRef staticCode, 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 {
if (key->cdsaKey == NULL) {
// Create CDSA key from exported data of existing key.
- CFRef<CFDataRef> keyData = SecKeyCopyExternalRepresentation(key, NULL);
CFRef<CFDictionaryRef> keyAttributes = SecKeyCopyAttributes(key);
- if (keyData && keyAttributes) {
- key->cdsaKey = SecKeyCreateFromData(keyAttributes, keyData, NULL);
+ if (keyAttributes) {
+ CFRef<CFDataRef> keyData = SecKeyCopyExternalRepresentation(key, NULL);
+ if (!keyData) {
+ CFTypeRef pubKeyHash = CFDictionaryGetValue(keyAttributes, kSecAttrApplicationLabel);
+ const void *keys[] = { kSecClass, kSecAttrNoLegacy, kSecReturnRef, kSecMatchLimit };
+ const void *values[] = { kSecClassIdentity, kCFBooleanFalse, kCFBooleanTrue, kSecMatchLimitAll };
+ CFRef<CFDictionaryRef> query = CFDictionaryCreate(kCFAllocatorDefault, keys, values,
+ sizeof(keys) / sizeof(*keys),
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ CFRef<CFArrayRef> identities;
+ OSStatus status = SecItemCopyMatching(query, (CFTypeRef *)identities.take());
+ if (status == errSecSuccess) {
+ for (int i = 0; i < CFArrayGetCount(identities); ++i) {
+ CFRef<SecKeyRef> privateKey;
+ if (SecIdentityCopyPrivateKey((SecIdentityRef)CFArrayGetValueAtIndex(identities, i), privateKey.take()) != errSecSuccess) {
+ continue;
+ }
+ CFRef<CFDictionaryRef> attrs = SecKeyCopyAttributes(privateKey);
+ if (CFEqual(CFDictionaryGetValue(attrs, kSecAttrApplicationLabel), pubKeyHash)) {
+ key->cdsaKey = privateKey.retain();
+ break;
+ }
+ }
+ }
+ } else {
+ key->cdsaKey = SecKeyCreateFromData(keyAttributes, keyData, NULL);
+ }
}
}
static void ReconstructFileSystemHeader (uint32& finger, const uint8* data, FileSystemEntryItem* item)
{
// get the number of bytes for the name
- u_int16_t length = ReconstructUInt16 (finger, data);
- char name[length + 1];
-
+ u_int16_t length = ReconstructUInt16 (finger, data);
+ std::vector<char> name(length + 1);
+
// make a c-string for the name
- memcpy (name, data + finger, length);
- name[length] = 0;
- item->SetName (name);
-
- secinfo ("manifest", " File item name is %s", name);
+ memcpy (name.data(), data + finger, length);
+ name[length] = 0;
+
+ secinfo ("manifest", " File item name is %s", name.data());
+ item->SetName (name.data());
finger += length;
if (st.st_size != 0)
{
// read the file
- char buffer[kReadChunkSize];
-
- ssize_t bytesRead;
- while ((bytesRead = read (fileNo, buffer, kReadChunkSize)) != 0)
+ std::vector<char> buffer(kReadChunkSize);
+
+ ssize_t bytesRead;
+ while ((bytesRead = read (fileNo, buffer.data(), kReadChunkSize)) != 0)
{
// digest the read data
- CC_SHA1_Update (&digestContext, buffer, (CC_LONG)bytesRead);
+ CC_SHA1_Update (&digestContext, buffer.data(), (CC_LONG)bytesRead);
}
// compute the SHA1 hash
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)
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 */
removeTS(cert0);
}
+
int si_28_sectrustsettings(int argc, char *const *argv)
{
plan_tests(kNumberNoConstraintsTests
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) {
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;
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,
OSStatus SecCertificateParseGeneralNames(const DERItem *generalNames, void *context,
parseGeneralNameCallback callback);
+CFArrayRef SecCertificateCopyOrganizationFromX501NameContent(const DERItem *nameContent);
+
bool SecCertificateIsWeakKey(SecCertificateRef certificate);
bool SecCertificateIsAtLeastMinKeySize(SecCertificateRef certificate,
CFDictionaryRef keySizes);
_kSecPolicyKU_NonRepudiation
#endif
+_SecDNSIsTLD
+
#undef POLICYCHECKMACRO
#define __PC_DO_EXPORT_(NAME)
#define __PC_DO_EXPORT_O(NAME) _SecPolicyCheckCert##NAME
_SecTrustEvaluateLeafOnly
_SecTrustEvaluateWithError
_SecTrustFlushResponseCache
+_SecTrustGetAssetVersionNumber
_SecTrustGetCertificateAtIndex
_SecTrustGetCertificateCount
_SecTrustGetDetails
_SecTrustIsExpiredOnly
_SecTrustOTAPKIGetUpdatedAsset
_SecTrustReportTLSAnalytics
+_SecTrustReportNetworkingAnalytics
_SecTrustSerialize
_SecTrustSetAnchorCertificates
_SecTrustSetAnchorCertificatesOnly
_SecTrustSetExceptions
_SecTrustSetKeychainsAllowed
+_SecTrustSetNeedsEvaluation
_SecTrustSetNetworkFetchAllowed
_SecTrustSetOCSPResponse
_SecTrustSetPinningException
_SecTrustStoreCopyUsageConstraints
_SecTrustStoreForDomain
_SecTrustStoreGetSettingsVersionNumber
+_SecTrustStoreGetSettingsAssetVersionNumber
_SecTrustStoreRemoveCertificate
_SecTrustStoreSetTrustSettings
#endif
+_SecTrustStoreSetCTExceptions
+_SecTrustStoreCopyCTExceptions
+_kSecCTExceptionsCAsKey
+_kSecCTExceptionsDomainsKey
+_kSecCTExceptionsHashAlgorithmKey
+_kSecCTExceptionsSPKIHashKey
//
// Identity
_SecCertificateCopyNormalizedSubjectSequence
_SecCertificateCopyNTPrincipalNames
_SecCertificateCopyOrganization
+_SecCertificateCopyOrganizationFromX501NameContent
_SecCertificateCopyOrganizationalUnit
_SecCertificateCopyPrecertTBS
_SecCertificateCopyProperties
#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")
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);
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 *********************
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;
return errSecSuccess;
}
-static void SecTrustSetNeedsEvaluation(SecTrustRef trust) {
+void SecTrustSetNeedsEvaluation(SecTrustRef trust) {
check(trust);
if (trust) {
dispatch_sync(trust->_trustQueue, ^{
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);
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;
}
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
output->_responses = CFRetainSafe(responses);
}
SCTs = CFDictionaryGetValue(plist, CFSTR(kSecTrustSCTsKey));
- if (isArray(responses)) {
+ if (isArray(SCTs)) {
output->_SCTs = CFRetainSafe(SCTs);
}
trustedLogs = CFDictionaryGetValue(plist, CFSTR(kSecTrustTrustedLogsKey));
#define kSecTrustEventNameKey "eventName"
#define kSecTrustEventAttributesKey "eventAttributes"
+#define kSecTrustEventApplicationID "appID"
__END_DECLS
#include <utilities/SecCFError.h>
#include <utilities/SecCFWrappers.h>
#include "utilities/SecDb.h"
+#include "SecTrustInternal.h"
static CFStringRef kSecTrustStoreUserName = CFSTR("user");
return status;
}
-
OSStatus SecTrustStoreGetSettingsVersionNumber(SecTrustSettingsVersionNumber* p_settings_version_number)
{
if (NULL == p_settings_version_number) {
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) {
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;
+}
typedef int32_t SecTrustSettingsVersionNumber;
+typedef int32_t SecTrustSettingsAssetVersionNumber;
+
SecTrustStoreRef SecTrustStoreForDomain(SecTrustStoreDomain domain);
Boolean SecTrustStoreContains(SecTrustStoreRef source,
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. */
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:
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");
}
"[-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.")
--- /dev/null
+/*
+ * Copyright (c) 2018 Apple Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ *
+ * ct_exceptions.m
+ */
+
+#import <Foundation/Foundation.h>
+#include <Security/SecTrustSettingsPriv.h>
+#include <Security/SecCertificatePriv.h>
+#include <utilities/fileIo.h>
+#include <utilities/SecCFWrappers.h>
+
+#include "SecurityCommands.h"
+
+NSString* toolAppID = @"com.apple.security";
+
+static int addCertFile(const char *fileName, NSMutableArray *array) {
+ SecCertificateRef certRef = NULL;
+ NSData *data = NULL;
+ unsigned char *buf = NULL;
+ size_t numBytes;
+ int rtn = 0;
+
+ if (readFileSizet(fileName, &buf, &numBytes)) {
+ rtn = -1;
+ goto errOut;
+ }
+
+ data = [NSData dataWithBytes:buf length:numBytes];
+ certRef = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)data);
+ if (!certRef) {
+ certRef = SecCertificateCreateWithPEM(NULL, (__bridge CFDataRef)data);
+ if (!certRef) {
+ rtn = -1;
+ goto errOut;
+ }
+ }
+
+ [array addObject:(__bridge id)certRef];
+
+errOut:
+ /* Cleanup */
+ free(buf);
+ CFReleaseNull(certRef);
+ return rtn;
+}
+
+static int returnCFError(CFErrorRef CF_CONSUMED error) {
+ CFStringRef errorString = CFErrorCopyDescription(error);
+ CFStringPerformWithCString(errorString, ^(const char *utf8Str) {
+ fprintf(stderr, "Failed to copy CT exceptions: %s\n", utf8Str);
+ });
+ CFIndex errCode = CFErrorGetCode(error);
+ CFReleaseNull(error);
+ return (int)errCode;
+}
+
+static int resetExceptions(bool resetCerts, bool resetDomains) {
+ bool result = false;
+ CFErrorRef error = NULL;
+ if (resetCerts) {
+ NSDictionary *resetCertsDict = @{ (__bridge NSString*)kSecCTExceptionsCAsKey: @[] };
+ result = SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)resetCertsDict, &error);
+ }
+ if (!error && resetDomains) {
+ NSDictionary *resetDomainsDict = @{ (__bridge NSString*)kSecCTExceptionsDomainsKey : @[] };
+ result = SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)resetDomainsDict, &error);
+ }
+ if (!result) {
+ return returnCFError(error);
+ }
+ return 0;
+}
+
+static int addExceptions(CFStringRef key, NSArray *newExceptions) {
+ CFErrorRef error = NULL;
+ NSDictionary *currentExceptions = CFBridgingRelease(SecTrustStoreCopyCTExceptions((__bridge CFStringRef)toolAppID, &error));
+ if (!currentExceptions && error) {
+ return returnCFError(error);
+ }
+
+ NSMutableArray *exceptionsForKey = nil;
+ if (currentExceptions && currentExceptions[(__bridge NSString*)key]) {
+ exceptionsForKey = [currentExceptions[(__bridge NSString*)key] mutableCopy];
+ [exceptionsForKey addObjectsFromArray:newExceptions];
+ } else {
+ exceptionsForKey = [newExceptions copy];
+ }
+
+ NSDictionary *newExceptionsDict = @{ (__bridge NSString*)key: exceptionsForKey };
+ bool result = SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)newExceptionsDict, &error);
+ if (!result) {
+ return returnCFError(error);
+ }
+
+ return 0;
+}
+
+int add_ct_exceptions(int argc, char * const *argv) {
+ int arg;
+
+ bool resetDomains = false;
+ bool resetCerts = false;
+
+ NSMutableArray *domains = [NSMutableArray array];
+ NSMutableArray *certs = [NSMutableArray array];
+ NSDictionary *plist = nil;
+
+ /* parse args */
+ if (argc == 1) {
+ return SHOW_USAGE_MESSAGE;
+ }
+
+ while ((arg = getopt(argc, argv, "d:c:r:p:")) != -1) {
+ switch(arg) {
+ case 'd': {
+ NSString *domain = [NSString stringWithCString:optarg encoding:NSUTF8StringEncoding];
+ [domains addObject:domain];
+ break;
+ }
+ case 'c':
+ if (addCertFile(optarg, certs)) {
+ fprintf(stderr, "Failed to read cert file\n");
+ return 1;
+ }
+ break;
+ case 'r':
+ if (!strcmp(optarg, "all")) {
+ resetDomains = true;
+ resetCerts = true;
+ } else if (!strcmp(optarg, "domain")) {
+ resetDomains = true;
+ } else if (!strcmp(optarg, "cert")) {
+ resetCerts = true;
+ } else {
+ return SHOW_USAGE_MESSAGE;
+ }
+ break;
+ case 'p':
+ plist = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithCString:optarg encoding:NSUTF8StringEncoding]];
+ break;
+ case '?':
+ default:
+ return SHOW_USAGE_MESSAGE;
+ }
+ }
+
+ /* handle reset operation */
+ if (resetCerts || resetDomains) {
+ return resetExceptions(resetCerts, resetDomains);
+ }
+
+ /* set plist */
+ if (plist) {
+ CFErrorRef error = NULL;
+ bool result = SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)plist, &error);
+ if (!result) {
+ return returnCFError(error);
+ } else {
+ return 0;
+ }
+ }
+
+ /* add domains */
+ int status = 0;
+ if ([domains count]) {
+ status = addExceptions(kSecCTExceptionsDomainsKey, domains);
+ }
+ if (status != 0) {
+ fprintf(stderr, "failed to add domain exceptions\n");
+ return status;
+ }
+
+ /* add certs */
+ if ([certs count]) {
+ NSMutableArray<NSDictionary *>*valuesForCAsKey = [NSMutableArray arrayWithCapacity:[certs count]];
+ [certs enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
+ SecCertificateRef cert = (__bridge SecCertificateRef)obj;
+ NSData* hash = CFBridgingRelease(SecCertificateCopySubjectPublicKeyInfoSHA256Digest(cert));
+ NSDictionary *value = @{ (__bridge NSString*)kSecCTExceptionsHashAlgorithmKey:@"sha256",
+ (__bridge NSString*)kSecCTExceptionsSPKIHashKey:hash };
+ [valuesForCAsKey addObject:value];
+ }];
+ status = addExceptions(kSecCTExceptionsCAsKey, valuesForCAsKey);
+ }
+ if (status != 0) {
+ fprintf(stderr, "failed to add cert exceptions\n");
+ return status;
+ }
+
+ return 0;
+}
+
+static int printExceptions(CFStringRef key, NSDictionary *allExceptions) {
+ if (!allExceptions || !allExceptions[(__bridge NSString*)key] ||
+ [allExceptions[(__bridge NSString*)key] count] == 0) {
+ CFStringPerformWithCString(key, ^(const char *utf8Str) {
+ fprintf(stdout, "No CT Exceptions for %s\n", utf8Str);
+ });
+ return 0;
+ }
+
+ NSArray *exceptionsForKey = allExceptions[(__bridge NSString*)key];
+ NSMutableString *exceptionsString = [NSMutableString stringWithFormat:@"\t%@ : [",key];
+ [exceptionsForKey enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
+ if ([obj isKindOfClass:[NSString class]]) {
+ if (idx == 0) {
+ [exceptionsString appendFormat:@"\"%@\"",obj];
+ } else {
+ [exceptionsString appendFormat:@", \"%@\"", obj];
+ }
+ } else if ([obj isKindOfClass:[NSDictionary class]]) {
+ if (idx == 0) {
+ [exceptionsString appendString:@"\n\t "];
+ } else {
+ [exceptionsString appendString:@"\t "];
+ }
+ [exceptionsString appendFormat:@"\"%@:", obj[(__bridge NSString*)kSecCTExceptionsHashAlgorithmKey]];
+ NSString *hashHex = CFBridgingRelease(CFDataCopyHexString((__bridge CFDataRef)obj[(__bridge NSString*)kSecCTExceptionsSPKIHashKey]));
+ [exceptionsString appendString:hashHex];
+ if ([exceptionsForKey count] == idx + 1) { // last entry
+ [exceptionsString appendString:@"\"\n"];
+ } else {
+ [exceptionsString appendString:@"\",\n"];
+ }
+ }
+ }];
+ [exceptionsString appendString:@"]\n"];
+ CFStringPerformWithCString((__bridge CFStringRef)exceptionsString, ^(const char *utf8Str) {
+ fprintf(stdout, "\n%s\n", utf8Str);
+ });
+
+ return 0;
+}
+
+int show_ct_exceptions(int argc, char * const *argv) {
+ int arg;
+ bool allExceptions = false;
+ NSString *identifier = nil;
+ bool domainExceptions = false;
+ bool certExceptions = false;
+
+ /* parse args */
+ while ((arg = getopt(argc, argv, "ai:dc")) != -1) {
+ switch(arg) {
+ case 'a':
+ allExceptions = true;
+ break;
+ case 'i':
+ identifier = [NSString stringWithCString:optarg encoding:NSUTF8StringEncoding];
+ break;
+ case 'd':
+ domainExceptions = true;
+ break;
+ case 'c':
+ certExceptions = true;
+ break;
+ case '?':
+ default:
+ return SHOW_USAGE_MESSAGE;
+ }
+ }
+
+ if (!domainExceptions && !certExceptions) {
+ /* Nothing specified, show both */
+ domainExceptions = true;
+ certExceptions = true;
+ }
+
+ if (allExceptions) {
+ identifier = nil;
+ fprintf(stdout, "Showing exceptions for all apps\n");
+ } else if (!identifier) {
+ identifier = toolAppID;
+ }
+
+ if (identifier) {
+ CFStringPerformWithCString((__bridge CFStringRef)identifier, ^(const char *utf8Str) {
+ fprintf(stdout, "Showing exceptions for %s\n", utf8Str);
+ });
+ }
+
+ CFErrorRef error = NULL;
+ NSDictionary *results = CFBridgingRelease(SecTrustStoreCopyCTExceptions((__bridge CFStringRef)identifier, &error));
+
+ /* Copy failed, return error */
+ if (!results && error) {
+ return returnCFError(error);
+ }
+
+ /* print domain exceptions */
+ int status = 0;
+ if (domainExceptions) {
+ status = printExceptions(kSecCTExceptionsDomainsKey, results);
+ }
+ if (status != 0) {
+ fprintf(stderr, "failed to print domain exceptions\n");
+ return status;
+ }
+
+ /* print cert exceptions */
+ if (certExceptions) {
+ status = printExceptions(kSecCTExceptionsCAsKey, results);
+ }
+ if (status != 0) {
+ fprintf(stderr, "failed to print cert exceptions\n");
+ return status;
+ }
+
+
+ return 0;
+}
<true/>
<key>application-identifier</key>
<string>com.apple.security</string>
+ <key>com.apple.application-identifier</key>
+ <string>com.apple.security</string>
<key>com.apple.private.keychain.keychaincontrol</key>
<true/>
</dict>
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"),
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;
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,
kSecXPCOpBackupKeybagDelete,
kSecXPCOpSFKeychainEndpoint,
kSecXPCOpKeychainControlEndpoint,
- kSecXPCOpTLSAnaltyicsReport,
+ kSecXPCOpNetworkingAnalyticsReport,
+ kSecXPCOpSetCTExceptions,
+ kSecXPCOpCopyCTExceptions,
};
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;
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) {
/* 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;
void query_pre_add(Query *q, bool force_date);
+bool SecItemIsSystemBound(CFDictionaryRef item, const SecDbClass *cls, bool multiUser);
+
//
// MARK: backup restore stuff
//
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));
});
}
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) {
- (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;
}
/* MARK: DB Cache
- * The cache is represented a dictionary defined as { suffix : { regex : resultsDictionary } } */
+ * The cache is represented a dictionary defined as { suffix : { regex : resultsDictionary } }
+ * The cache is not used on watchOS to reduce memory overhead. */
+#if !TARGET_OS_WATCH
- (void) clearCache {
os_unfair_lock_lock(&_regexCacheLock);
self.regexCache = [NSMutableDictionary dictionary];
os_unfair_lock_unlock(&_regexCacheLock);
}
+#endif // !TARGET_OS_WATCH
+#if !TARGET_OS_WATCH
- (void) addSuffixToCache:(NSString *)suffix entry:(NSDictionary <NSRegularExpression *, NSDictionary *> *)entry {
os_unfair_lock_lock(&_regexCacheLock);
secinfo("SecPinningDb", "adding %llu entries for %@ to cache", (unsigned long long)[entry count], suffix);
self.regexCache[suffix] = entry;
os_unfair_lock_unlock(&_regexCacheLock);
}
+#endif // !TARGET_OS_WATCH
+#if !TARGET_OS_WATCH
/* Because we iterate over all DB entries for a suffix, even if we find a match, we guarantee
* that the cache, if the cache has an entry for a suffix, it has all the entries for that suffix */
- (BOOL) queryCacheForSuffix:(NSString *)suffix firstLabel:(NSString *)firstLabel results:(NSDictionary * __autoreleasing *)results{
return foundSuffix;
}
+#endif // !TARGET_OS_WATCH
- (BOOL) isPinningDisabled:(NSString * _Nullable)policy {
static dispatch_once_t once;
__block NSString *firstLabel = [domain substringToIndex:firstDot.location];
__block NSString *suffix = [domain substringFromIndex:(firstDot.location + 1)];
+#if !TARGET_OS_WATCH
/* Search cache */
NSDictionary *cacheResult = nil;
if ([self queryCacheForSuffix:suffix firstLabel:firstLabel results:&cacheResult]) {
return cacheResult;
}
+#endif
/* Cache miss. Perform SELECT */
__block bool ok = true;
__block CFErrorRef error = NULL;
__block NSMutableArray *resultRules = [NSMutableArray array];
__block NSString *resultName = nil;
+#if !TARGET_OS_WATCH
__block NSMutableDictionary <NSRegularExpression *, NSDictionary *> *newCacheEntry = [NSMutableDictionary dictionary];
+#endif
ok &= SecDbPerformRead(_db, &error, ^(SecDbConnectionRef dbconn) {
ok &= SecDbWithSQL(dbconn, selectDomainSQL, &error, ^bool(sqlite3_stmt *selectDomain) {
ok &= SecDbBindText(selectDomain, 1, [suffix UTF8String], [suffix length], SQLITE_TRANSIENT, &error);
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
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) {
#include <securityd/SecCertificateServer.h>
#include <securityd/SecCertificateSource.h>
#include <securityd/SecOCSPResponse.h>
+#include <securityd/SecTrustStoreServer.h>
#include <utilities/array_size.h>
#include <utilities/SecCFWrappers.h>
#include <utilities/SecAppleAnchorPriv.h>
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);
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);
__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);
}
}
+static bool is_configured_test_system_root(SecCertificateRef root) {
+ if (!SecIsInternalRelease()) {
+ return false;
+ }
+ bool result = false;
+ CFDataRef rootHash = SecCertificateCopySHA256Digest(root);
+ CFTypeRef value = CFPreferencesCopyValue(CFSTR("TestCTRequiredSystemRoot"), CFSTR("com.apple.security"),
+ kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
+ require_quiet(isData(value), out);
+ require_quiet(kCFCompareEqualTo == CFDataCompare(rootHash, value), out);
+ result = true;
+
+out:
+ CFReleaseNull(value);
+ CFReleaseNull(rootHash);
+ return result;
+}
+
+static bool is_ct_excepted_domain(CFStringRef hostname, CFStringRef exception) {
+ if (kCFCompareEqualTo == CFStringCompare(exception, hostname, kCFCompareCaseInsensitive)) {
+ /* exact match */
+ return true;
+ } else if (CFStringHasPrefix(exception, CFSTR("."))) {
+ /* subdomains */
+ CFIndex elength = CFStringGetLength(exception);
+ CFIndex hlength = CFStringGetLength(hostname);
+ if (hlength > elength) {
+ CFRange compareRange = { hlength - elength, elength };
+ if (kCFCompareEqualTo == CFStringCompareWithOptions(hostname, exception, compareRange, kCFCompareCaseInsensitive)) {
+ return true;
+ }
+ } else if (hlength + 1 == elength) {
+ CFRange compareRange = { 1, hlength };
+ if (kCFCompareEqualTo == CFStringCompareWithOptions(exception, hostname, compareRange, kCFCompareCaseInsensitive)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static OSStatus is_subtree_dn_with_org(void *context, SecCEGeneralNameType gnType, const DERItem *generalName) {
+ if (gnType != GNT_DirectoryName) {
+ return errSecInternal;
+ }
+
+ DERDecodedInfo subtreeName_content;
+ if (DR_Success != DERDecodeItem(generalName, &subtreeName_content) || subtreeName_content.tag != ASN1_CONSTR_SEQUENCE) {
+ return errSecDecode;
+ }
+
+ CFArrayRef subtree_orgs = SecCertificateCopyOrganizationFromX501NameContent(&subtreeName_content.content);
+ if (subtree_orgs) {
+ CFReleaseNull(subtree_orgs);
+ return errSecSuccess;
+ }
+ return errSecInternal;
+}
+
+static bool has_ct_excepted_key(SecCertificatePathVCRef path, CFDictionaryRef exception) {
+ __block bool result = false;
+ CFDataRef exceptionHash = CFDictionaryGetValue(exception, kSecCTExceptionsSPKIHashKey);
+
+ /* exception for a leaf is always allowed */
+ SecCertificateRef leaf = SecCertificatePathVCGetCertificateAtIndex(path, 0);
+ CFDataRef spkiHash = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(leaf);
+ if (CFEqualSafe(exceptionHash, spkiHash)) {
+ result = true;
+ }
+ CFReleaseNull(spkiHash);
+
+ if (result) { return result; }
+
+ /* exceptions for CAs */
+ for (CFIndex certIX = 1; certIX < SecCertificatePathVCGetCount(path); certIX++) {
+ SecCertificateRef ca = SecCertificatePathVCGetCertificateAtIndex(path, certIX);
+
+ spkiHash = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(ca);
+ if (!CFEqualSafe(exceptionHash, spkiHash)) {
+ CFReleaseNull(spkiHash);
+ continue;
+ }
+ CFReleaseNull(spkiHash);
+
+ /* this CA matches but exceptions for CAs have constraints */
+ if (SecCertificateGetPermittedSubtrees(ca)) {
+ /* Constrained CAs have to have a Distinguished Name permitted subtree with an Organization attribute */
+ CFArrayForEach(SecCertificateGetPermittedSubtrees(ca), ^(const void *value) {
+ CFDataRef subtree = (CFDataRef)value;
+ const DERItem general_name = { (unsigned char *)CFDataGetBytePtr(subtree), CFDataGetLength(subtree) };
+ DERDecodedInfo general_name_content;
+ if (DR_Success == DERDecodeItem(&general_name, &general_name_content)) {
+ OSStatus status = SecCertificateParseGeneralNameContentProperty(general_name_content.tag,
+ &general_name_content.content,
+ NULL,
+ is_subtree_dn_with_org);
+ if (status == errSecSuccess) {
+ result = true;
+ }
+ }
+ });
+ }
+
+ if (!result) {
+ /* The Organization attribute(s) in the CA subject have to exactly match the Organization attribute(s) in the leaf */
+ CFArrayRef leafOrgs = SecCertificateCopyOrganization(leaf);
+ CFArrayRef caOrgs = SecCertificateCopyOrganization(ca);
+ if (caOrgs && leafOrgs && CFEqualSafe(leafOrgs, caOrgs)) {
+ result = true;
+ }
+ CFReleaseNull(leafOrgs);
+ CFReleaseNull(caOrgs);
+ }
+
+ if (result) {
+ break;
+ }
+ }
+
+ return result;
+}
+
+static bool is_ct_excepted(SecPVCRef pvc) {
+ CFDictionaryRef ct_exceptions = _SecTrustStoreCopyCTExceptions(NULL, NULL);
+ if (!ct_exceptions) {
+ return false;
+ }
+
+ __block bool result = false;
+ CFArrayRef domainExceptions = CFDictionaryGetValue(ct_exceptions, kSecCTExceptionsDomainsKey);
+ if (domainExceptions) {
+ SecPolicyRef policy = SecPVCGetPolicy(pvc);
+ CFStringRef hostname = CFDictionaryGetValue(policy->_options, kSecPolicyCheckSSLHostname);
+ if (hostname) {
+ CFArrayForEach(domainExceptions, ^(const void *value) {
+ result = result || is_ct_excepted_domain(hostname, value);
+ });
+ }
+ }
+ if (result) {
+ secinfo("policy", "domain-based CT exception applied");
+ CFReleaseNull(ct_exceptions);
+ return result;
+ }
+
+ CFArrayRef keyExceptions = CFDictionaryGetValue(ct_exceptions, kSecCTExceptionsCAsKey);
+ if (keyExceptions) {
+ __block SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
+ CFArrayForEach(keyExceptions, ^(const void *value) {
+ result = result || has_ct_excepted_key(path, value);
+ });
+ }
+
+ if (result) {
+ secinfo("policy" , "key-based CT exceptions applied");
+ }
+
+ CFReleaseNull(ct_exceptions);
+ return result;
+}
+
+/* <rdar://45466778> some Apple servers not getting certs with embedded SCTs
+ * <rdar://45545270> some Google apps have their own TLS stacks and aren't passing us TLS SCTs */
+static bool is_apple_ca(SecCertificatePathVCRef path) {
+ /* subject:/CN=Apple IST CA 8 - G1/OU=Certification Authority/O=Apple Inc./C=US */
+ /* issuer :/C=US/O=GeoTrust Inc./OU=(c) 2007 GeoTrust Inc. - For authorized use only/CN=GeoTrust Primary Certification Authority - G2 */
+ static const uint8_t appleISTCA8G1_spkiSHA256[] = {
+ 0xe2, 0x4f, 0x8e, 0x8c, 0x21, 0x85, 0xda, 0x2f, 0x5e, 0x88, 0xd4, 0x57, 0x9e, 0x81, 0x7c, 0x47,
+ 0xbf, 0x6e, 0xaf, 0xbc, 0x85, 0x05, 0xf0, 0xf9, 0x60, 0xfd, 0x5a, 0x0d, 0xf4, 0x47, 0x3a, 0xd3
+ };
+
+ /* subject:/CN=Apple IST CA 2 - G1/OU=Certification Authority/O=Apple Inc./C=US */
+ /* issuer :/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA */
+ static const uint8_t appleISTCA2G1_spkiSHA256[] = {
+ 0xb5, 0xcf, 0x82, 0xd4, 0x7e, 0xf9, 0x82, 0x3f, 0x9a, 0xa7, 0x8f, 0x12, 0x31, 0x86, 0xc5, 0x2e,
+ 0x88, 0x79, 0xea, 0x84, 0xb0, 0xf8, 0x22, 0xc9, 0x1d, 0x83, 0xe0, 0x42, 0x79, 0xb7, 0x8f, 0xd5
+ };
+
+ /* subject:/C=US/O=Google Trust Services/CN=Google Internet Authority G3 */
+ /* issuer :/OU=GlobalSign Root CA - R2/O=GlobalSign/CN=GlobalSign */
+ static const uint8_t googleIAG3_spkiSHA256[] = {
+ 0x7f, 0xc3, 0x67, 0x10, 0x56, 0x71, 0x43, 0x81, 0x31, 0x14, 0xe8, 0x52, 0x37, 0xb1, 0x22, 0x15,
+ 0x6b, 0x62, 0xb9, 0xd6, 0x50, 0x54, 0x3d, 0xa8, 0x63, 0xad, 0x2e, 0x6a, 0xe5, 0x7f, 0x9f, 0xbf
+ };
+
+ bool result = false;
+ for (CFIndex certIX = 1; certIX < SecCertificatePathVCGetCount(path); certIX++) {
+ SecCertificateRef ca = SecCertificatePathVCGetCertificateAtIndex(path, certIX);
+
+ CFDataRef caSPKIHash = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(ca);
+ const uint8_t *dp = CFDataGetBytePtr(caSPKIHash);
+ if (dp && (!memcmp(appleISTCA8G1_spkiSHA256, dp, CC_SHA256_DIGEST_LENGTH) ||
+ !memcmp(appleISTCA2G1_spkiSHA256, dp, CC_SHA256_DIGEST_LENGTH) ||
+ !memcmp(googleIAG3_spkiSHA256, dp, CC_SHA256_DIGEST_LENGTH))) {
+ result = true;
+ }
+ CFReleaseNull(caSPKIHash);
+ if (result) {
+ break;
+ }
+ }
+ return result;
+}
+
+static void SecPolicyCheckSystemTrustedCTRequired(SecPVCRef pvc) {
+ SecCertificateSourceRef appleAnchorSource = NULL;
+ SecOTAPKIRef otaref = SecOTAPKICopyCurrentOTAPKIRef();
+ SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
+ CFArrayRef trustedLogs = SecPathBuilderCopyTrustedLogs(pvc->builder);
+
+ /* Skip this check if we haven't done the CT checks yet */
+ require_quiet(SecCertificatePathVCIsPathValidated(path), out);
+
+ /* We only enforce this check when all of the following are true:
+ * 0. Not a pinning policy */
+ SecPolicyRef policy = SecPVCGetPolicy(pvc);
+ require_quiet(CFEqualSafe(SecPolicyGetName(policy),kSecPolicyNameSSLServer), out);
+
+ /* 1. Device has checked in to MobileAsset for a current log list within the last 60 days.
+ * Or the caller passed in the trusted log list. */
+ require_quiet(SecOTAPKIAssetStalenessLessThanSeconds(otaref, kSecOTAPKIAssetStalenessDisable) || trustedLogs, out);
+
+ /* 2. Leaf issuance date is on or after 16 Oct 2018 at 00:00:00 AM UTC */
+ SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
+ require_quiet(SecCertificateNotValidBefore(leaf) >= 561340800.0, out);
+
+ /* 3. Chain is anchored with root in the system anchor source but not the Apple anchor source */
+ CFIndex count = SecPVCGetCertificateCount(pvc);
+ SecCertificateRef root = SecPVCGetCertificateAtIndex(pvc, count - 1);
+ appleAnchorSource = SecMemoryCertificateSourceCreate(SecGetAppleTrustAnchors(false));
+ require_quiet(SecPathBuilderIsAnchored(pvc->builder), out);
+ require_quiet((SecCertificateSourceContains(kSecSystemAnchorSource, root) &&
+ appleAnchorSource && !SecCertificateSourceContains(appleAnchorSource, root) &&
+ !is_apple_ca(path)) ||
+ is_configured_test_system_root(root), out);
+
+ if (!SecCertificatePathVCIsCT(path) && !is_ct_excepted(pvc)) {
+ /* Set failure. By not using the Forced variant, we implicitly check that this
+ * policy had this options set. */
+ SecPVCSetResult(pvc, kSecPolicyCheckSystemTrustedCTRequired, 0, kCFBooleanFalse);
+ }
+
+out:
+ CFReleaseNull(trustedLogs);
+ CFReleaseNull(otaref);
+ if (appleAnchorSource) {
+ SecMemoryCertificateSourceDestroy(appleAnchorSource);
+ }
+}
+
void SecPolicyServerInitialize(void) {
gSecPolicyLeafCallbacks = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks, NULL);
}
}
+ /* 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);
secdebug("policy", "end %strusted path: %@",
(SecPVCIsOkResult(pvc) ? "" : "not "), SecPathBuilderGetPath(pvc->builder));
- SecCertificatePathVCSetPathValidated(SecPathBuilderGetPath(pvc->builder));
return;
}
#include <CoreFoundation/CFUtilities.h>
const CFStringRef kValidUpdateProdServer = CFSTR("valid.apple.com");
+const CFStringRef kValidUpdateSeedServer = CFSTR("valid.apple.com/seed");
const CFStringRef kValidUpdateCarryServer = CFSTR("valid.apple.com/carry");
static CFStringRef kSecPrefsDomain = CFSTR("com.apple.security");
}
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() {
void SecRevocationDbInitialize(void);
extern const CFStringRef kValidUpdateProdServer;
+extern const CFStringRef kValidUpdateSeedServer;
extern const CFStringRef kValidUpdateCarryServer;
/*!
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. */
#include "utilities/SecFileLocations.h"
#include <utilities/SecDispatchRelease.h>
#include <securityd/SecTrustLoggingServer.h>
+#include <os/variant_private.h>
+#include <dirent.h>
+#include <utilities/SecCFWrappers.h>
+#include <utilities/SecInternalReleasePriv.h>
/* uid of the _securityd user. */
#define SECURTYD_UID 64
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];
ts->containsSettings = true;
}
+
return ts;
errOut:
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),
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_ */
--- /dev/null
+/*
+ * Copyright (c) 2018 Apple Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <AssertMacros.h>
+#import <Foundation/Foundation.h>
+#include <stdatomic.h>
+#include <notify.h>
+#include <Security/Security.h>
+#include <Security/SecTrustSettingsPriv.h>
+#include <Security/SecPolicyPriv.h>
+#include <utilities/SecFileLocations.h>
+#include <utilities/SecCFWrappers.h>
+#import "OTATrustUtilities.h"
+#include "SecTrustStoreServer.h"
+
+typedef bool(*exceptionsArrayValueChecker)(id _Nonnull obj);
+
+static bool checkDomainsValuesCompliance(id _Nonnull obj) {
+ if (![obj isKindOfClass:[NSString class]]) {
+ return false;
+ }
+ if (SecDNSIsTLD((__bridge CFStringRef)obj)) {
+ return false;
+ }
+ return true;
+}
+
+static bool checkCAsValuesCompliance(id _Nonnull obj) {
+ if (![obj isKindOfClass:[NSDictionary class]]) {
+ return false;
+ }
+ if (2 != [(NSDictionary*)obj count]) {
+ return false;
+ }
+ if (nil == ((NSDictionary*)obj)[(__bridge NSString*)kSecCTExceptionsHashAlgorithmKey] ||
+ nil == ((NSDictionary*)obj)[(__bridge NSString*)kSecCTExceptionsSPKIHashKey]) {
+ return false;
+ }
+ if (![((NSDictionary*)obj)[(__bridge NSString*)kSecCTExceptionsHashAlgorithmKey] isKindOfClass:[NSString class]] ||
+ ![((NSDictionary*)obj)[(__bridge NSString*)kSecCTExceptionsSPKIHashKey] isKindOfClass:[NSData class]]) {
+ return false;
+ }
+ if (![((NSDictionary*)obj)[(__bridge NSString*)kSecCTExceptionsHashAlgorithmKey] isEqualToString:@"sha256"]) {
+ return false;
+ }
+ return true;
+}
+
+static bool checkExceptionsValues(NSString *key, id value, exceptionsArrayValueChecker checker, CFErrorRef *error) {
+ if (![value isKindOfClass:[NSArray class]]) {
+ return SecError(errSecParam, error, CFSTR("value for %@ is not an array in exceptions dictionary"), key);
+ }
+
+ __block bool result = true;
+ [(NSArray*)value enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
+ if (!checker(obj)) {
+ result = SecError(errSecParam, error, CFSTR("value %lu for %@ is not the expected type"), (unsigned long)idx, key);
+ *stop = true;
+ }
+ }];
+ return result;
+}
+
+static bool checkInputExceptionsAndSetAppExceptions(NSDictionary *inExceptions, NSMutableDictionary *appExceptions, CFErrorRef *error) {
+ __block bool result = true;
+ [inExceptions enumerateKeysAndObjectsUsingBlock:^(NSString *_Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
+ if ([key isEqualToString:(__bridge NSString*)kSecCTExceptionsDomainsKey]) {
+ if (!checkExceptionsValues(key, obj, checkDomainsValuesCompliance, error)) {
+ *stop = YES;
+ result = false;
+ return;
+ }
+ } else if ([key isEqualToString:(__bridge NSString*)kSecCTExceptionsCAsKey]) {
+ if (!checkExceptionsValues(key, obj, checkCAsValuesCompliance, error)) {
+ *stop = YES;
+ result = false;
+ return;
+ }
+ } else {
+ result = SecError(errSecParam, error, CFSTR("unknown key (%@) in exceptions dictionary"), key);
+ *stop = YES;
+ result = false;
+ return;
+ }
+ if ([(NSArray*)obj count] == 0) {
+ [appExceptions removeObjectForKey:key];
+ } else {
+ appExceptions[key] = obj;
+ }
+ }];
+ return result;
+}
+
+static _Atomic bool gHasCTExceptions = false;
+#define kSecCTExceptionsChanged "com.apple.trustd.ct.exceptions-changed"
+
+bool _SecTrustStoreSetCTExceptions(CFStringRef appID, CFDictionaryRef exceptions, CFErrorRef *error) {
+ if (!SecOTAPKIIsSystemTrustd()) {
+ return SecError(errSecWrPerm, error, CFSTR("Unable to write CT exceptions from user agent"));
+ }
+
+ if (!appID) {
+ return SecError(errSecParam, error, CFSTR("application-identifier required to set exceptions"));
+ }
+
+ @autoreleasepool {
+#if TARGET_OS_IPHONE
+ NSURL *keychainsDirectory = CFBridgingRelease(SecCopyURLForFileInKeychainDirectory(nil));
+#else
+ NSURL *keychainsDirectory = [NSURL fileURLWithFileSystemRepresentation:"/Library/Keychains/" isDirectory:YES relativeToURL:nil];
+#endif
+ NSURL *ctExceptionsFile = [keychainsDirectory URLByAppendingPathComponent:@"CTExceptions.plist"];
+ NSMutableDictionary *allExceptions = [NSMutableDictionary dictionaryWithContentsOfURL:ctExceptionsFile];
+ NSMutableDictionary *appExceptions = NULL;
+ if (allExceptions && allExceptions[(__bridge NSString*)appID]) {
+ appExceptions = [allExceptions[(__bridge NSString*)appID] mutableCopy];
+ } else {
+ appExceptions = [NSMutableDictionary dictionary];
+ if (!allExceptions) {
+ allExceptions = [NSMutableDictionary dictionary];
+ }
+ }
+
+ if (exceptions && (CFDictionaryGetCount(exceptions) > 0)) {
+ NSDictionary *inExceptions = (__bridge NSDictionary*)exceptions;
+ if (!checkInputExceptionsAndSetAppExceptions(inExceptions, appExceptions, error)) {
+ return false;
+ }
+ }
+
+ if (!exceptions || [appExceptions count] == 0) {
+ [allExceptions removeObjectForKey:(__bridge NSString*)appID];
+ } else {
+ allExceptions[(__bridge NSString*)appID] = appExceptions;
+ }
+
+ NSError *nserror = nil;
+ if (![allExceptions writeToURL:ctExceptionsFile error:&nserror] && error) {
+ *error = CFRetainSafe((__bridge CFErrorRef)nserror);
+ return false;
+ }
+ atomic_store(&gHasCTExceptions, [allExceptions count] != 0);
+ notify_post(kSecCTExceptionsChanged);
+ return true;
+ }
+}
+
+CFDictionaryRef _SecTrustStoreCopyCTExceptions(CFStringRef appID, CFErrorRef *error) {
+ @autoreleasepool {
+ static int notify_token = 0;
+ int check = 0;
+ if (!SecOTAPKIIsSystemTrustd()) {
+ /* Check whether we got a notification. If we didn't, and there are no exceptions set, return NULL.
+ * Otherwise, we need to read from disk */
+ uint32_t check_status = notify_check(notify_token, &check);
+ if (check_status == NOTIFY_STATUS_OK && check == 0 && !atomic_load(&gHasCTExceptions)) {
+ return NULL;
+ }
+ } else {
+ if (!atomic_load(&gHasCTExceptions)) {
+ return NULL;
+ }
+ }
+
+#if TARGET_OS_IPHONE
+ NSURL *keychainsDirectory = CFBridgingRelease(SecCopyURLForFileInKeychainDirectory(nil));
+#else
+ NSURL *keychainsDirectory = [NSURL fileURLWithFileSystemRepresentation:"/Library/Keychains/" isDirectory:YES relativeToURL:nil];
+#endif
+ NSURL *ctExceptionsFile = [keychainsDirectory URLByAppendingPathComponent:@"CTExceptions.plist"];
+ NSDictionary <NSString*,NSDictionary*> *allExceptions = [NSDictionary dictionaryWithContentsOfURL:ctExceptionsFile];
+
+ /* Set us up for not reading the disk when there are never exceptions */
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ atomic_init(&gHasCTExceptions, allExceptions && [allExceptions count] == 0);
+ if (!SecOTAPKIIsSystemTrustd()) {
+ uint32_t status = notify_register_check(kSecCTExceptionsChanged, ¬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;
+ }
+}
.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
<key>description</key>
<string>Alfa-1</string>
<key>key</key>
- <data>
- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEjWLpGNv/x8wCLlZthIDbTKjc
- Q8DmAebMeXf1TzPP/7fUxeWV7KJeD5vBWxB0V9wRFasAmYFfcqRD6AMTIW8q
- eA==
- </data>
+ <data>MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEjWLpGNv/x8wCLlZthIDbTKjcQ8DmAebMeXf1TzPP/7fUxeWV7KJeD5vBWxB0V9wRFasAmYFfcqRD6AMTIW8qeA==</data>
<key>operator</key>
<string>Alfa</string>
</dict>
<key>description</key>
<string>Alfa-2</string>
<key>key</key>
- <data>
- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEl3VLq871ikjdTDDvr1LhhHKj
- 3kOXWrtQoKJ3twK0BRBEj+rV/UZuZRjDNyiLK2mfMJN9TZdjLJphnYYJcstg
- SQ==
- </data>
+ <data>MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEl3VLq871ikjdTDDvr1LhhHKj3kOXWrtQoKJ3twK0BRBEj+rV/UZuZRjDNyiLK2mfMJN9TZdjLJphnYYJcstgSQ==</data>
<key>operator</key>
<string>Alfa</string>
</dict>
<key>description</key>
<string>Bravo-1</string>
<key>key</key>
- <data>
- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEXxLKuBw7sGl0/eRfkX4W7MpH
- LiK7xB/xkQONXu6cX/IFxMGJ83vbN9NvAbjkiG4D/Pnvrrq9Lb0gWPxovk8u
- fA==
- </data>
+ <data>MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEXxLKuBw7sGl0/eRfkX4W7MpHLiK7xB/xkQONXu6cX/IFxMGJ83vbN9NvAbjkiG4D/Pnvrrq9Lb0gWPxovk8ufA==</data>
<key>operator</key>
<string>Bravo</string>
</dict>
<key>description</key>
<string>Bravo-2</string>
<key>key</key>
- <data>
- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpPTIhGHP8AjsFnvCog7JOM43
- uSTkLbeJup8EN+wfhU2X5YJq8mCXXI7+MHyb/ncEYuJp7wg4B7zxhT5KSmIC
- sQ==
- </data>
+ <data>MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpPTIhGHP8AjsFnvCog7JOM43uSTkLbeJup8EN+wfhU2X5YJq8mCXXI7+MHyb/ncEYuJp7wg4B7zxhT5KSmICsQ==</data>
<key>operator</key>
<string>Bravo</string>
</dict>
<key>description</key>
<string>Charlie-1</string>
<key>key</key>
- <data>
- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEp/wmWR+YBWqWiCJy/EE7FBe5
- L+CvD3b10ua7BWA95yueo0GVLiw5b3qoNZz23CP+ecw5t4+JFsi/LvL45djj
- CA==
- </data>
+ <data>MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEp/wmWR+YBWqWiCJy/EE7FBe5L+CvD3b10ua7BWA95yueo0GVLiw5b3qoNZz23CP+ecw5t4+JFsi/LvL45djjCA==</data>
<key>operator</key>
<string>Charlie</string>
</dict>
<key>description</key>
<string>Charlie-2</string>
<key>key</key>
- <data>
- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFQvCj6M6CQKeyxhK2I/u3ZXq
- YXyf5feihb0Sh4fk78GZisbJyivSHfFRmATdpo7T9IOlXExOZc/ZnGwkPHXS
- GA==
- </data>
+ <data>MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFQvCj6M6CQKeyxhK2I/u3ZXqYXyf5feihb0Sh4fk78GZisbJyivSHfFRmATdpo7T9IOlXExOZc/ZnGwkPHXSGA==</data>
<key>operator</key>
<string>Charlie</string>
</dict>
<key>description</key>
<string>Delta-1</string>
<key>key</key>
- <data>
- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEey422SB0m/YU5R4km1+gQuRS
- HjY7vcTTbUo7Vnehfe2KCW/yY7lJQD4Yv5OJLci8vCWzDAXCprK5ZpbEiQTA
- 5g==
- </data>
+ <data>MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEey422SB0m/YU5R4km1+gQuRSHjY7vcTTbUo7Vnehfe2KCW/yY7lJQD4Yv5OJLci8vCWzDAXCprK5ZpbEiQTA5g==</data>
<key>operator</key>
<string>Delta</string>
</dict>
<key>description</key>
<string>Delta-2</string>
<key>key</key>
- <data>
- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEkC23vcfErQghrgdlOPDR7PPK
- +8/7FPyQZy09igHW2+eLx0+8e6VhaO1OTn2YL50NBxW2WN1wAhAxBfSPOFD0
- wA==
- </data>
+ <data>MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEkC23vcfErQghrgdlOPDR7PPK+8/7FPyQZy09igHW2+eLx0+8e6VhaO1OTn2YL50NBxW2WN1wAhAxBfSPOFD0wA==</data>
<key>operator</key>
<string>Delta</string>
</dict>
<key>description</key>
<string>Echo-1</string>
<key>key</key>
- <data>
- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEe/QyaSib8V4jhT8vlZTGou9v
- pCykmsmyQo/3lNI5tGFSiQWaonjQK/reZBXKpG6lwEblDdAazTCQlpmaOee1
- WA==
- </data>
+ <data>MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEe/QyaSib8V4jhT8vlZTGou9vpCykmsmyQo/3lNI5tGFSiQWaonjQK/reZBXKpG6lwEblDdAazTCQlpmaOee1WA==</data>
<key>operator</key>
<string>Echo</string>
</dict>
<key>description</key>
<string>Echo-2</string>
<key>key</key>
- <data>
- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEcxkV7jZBkfaV6BKH8fIYR/es
- 6DoVZYOW75zIzB5vgvHl0uOKpdwaDVhU5KZo/2KebpqpSdLCeKqX+poxUFxX
- OA==
- </data>
+ <data>MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEcxkV7jZBkfaV6BKH8fIYR/es6DoVZYOW75zIzB5vgvHl0uOKpdwaDVhU5KZo/2KebpqpSdLCeKqX+poxUFxXOA==</data>
<key>operator</key>
<string>Echo</string>
</dict>
<key>description</key>
<string>coreos-ct-test log-alpha</string>
<key>key</key>
- <data>
- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEhcZUhfz61YzwzHJrp4RLcCF/
- V3j+SZYXGXc69qUlq3twpPnAsRpJE1vzZmvqL0Df1t21LqXQK9EgFcIdu2LL
- FQ==
- </data>
+ <data>MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEhcZUhfz61YzwzHJrp4RLcCF/V3j+SZYXGXc69qUlq3twpPnAsRpJE1vzZmvqL0Df1t21LqXQK9EgFcIdu2LLFQ==</data>
<key>operator</key>
<string>coreos-ct-test alpha</string>
</dict>
<dict>
<key>description</key>
- <string>Google's aviator</string>
+ <string>Google's aviator</string>
<key>key</key>
- <data>
- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1/TMabLkDpCjiupacAlP7xNi
- 0I1JYP8bQFAHDG1xhtolSY1l4QgNRzRrvSe8liE+NPWHdjGxfx3JhTsN9x8/
- 6Q==
- </data>
+ <data>MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1/TMabLkDpCjiupacAlP7xNi0I1JYP8bQFAHDG1xhtolSY1l4QgNRzRrvSe8liE+NPWHdjGxfx3JhTsN9x8/6Q==</data>
<key>operator</key>
<string>Google</string>
</dict>
<dict>
<key>description</key>
- <string>Google's pilot</string>
+ <string>Google's pilot</string>
<key>key</key>
- <data>
- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfahLEimAoz2t01p3uMziiLOl
- /fHTDM0YDOhBRuiBARsV4UvxG2LdNgoIGLrtCzWE0J5APC2em4JlvR8EEEFM
- oA==
- </data>
+ <data>MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfahLEimAoz2t01p3uMziiLOl/fHTDM0YDOhBRuiBARsV4UvxG2LdNgoIGLrtCzWE0J5APC2em4JlvR8EEEFMoA==</data>
<key>operator</key>
<string>Google</string>
</dict>
<dict>
<key>description</key>
- <string>Digicert's CT log</string>
+ <string>Digicert's CT log</string>
<key>key</key>
- <data>
- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAkbFvhu7gkAW6MHSrBlpE1n4
- +HCFRkC5OLAjgqhkTH+/uzSfSl8ois8ZxAD2NgaTZe1M9akhYlrYkes4JECs
- 6A==
- </data>
+ <data>MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAkbFvhu7gkAW6MHSrBlpE1n4+HCFRkC5OLAjgqhkTH+/uzSfSl8ois8ZxAD2NgaTZe1M9akhYlrYkes4JECs6A==</data>
<key>operator</key>
<string>Digicert</string>
</dict>
- <dict>
+ <dict>
<key>description</key>
<string>Bravo-3</string>
<key>key</key>
- <data>
- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAErSVuQLDBj8EWNrGVjb8e1T9d
- 83xvvxi5NeWb9wnWrjbHVwXEkLQGAZBQvpWzJ5yFLqmVu40KSy1NmV0i78II
- Pg==
- </data>
+ <data>MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAErSVuQLDBj8EWNrGVjb8e1T9d83xvvxi5NeWb9wnWrjbHVwXEkLQGAZBQvpWzJ5yFLqmVu40KSy1NmV0i78IIPg==</data>
<key>operator</key>
<string>Bravo</string>
</dict>
<key>description</key>
<string>Alfa-3</string>
<key>key</key>
- <data>
- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfLrfEFaVzHLuCk+kjWnQCfrQ
- YFW73h7tpMEwhfYmL0AKUGVgrgvg3x+D1YSKs/X86dwdg/wyGA3RXU09Mo/M
- UQ==
- </data>
+ <data>MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfLrfEFaVzHLuCk+kjWnQCfrQYFW73h7tpMEwhfYmL0AKUGVgrgvg3x+D1YSKs/X86dwdg/wyGA3RXU09Mo/MUQ==</data>
<key>operator</key>
<string>Alfa</string>
</dict>
+ <dict>
+ <key>description</key>
+ <string>flour</string>
+ <key>key</key>
+ <data>MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEgze9Txetn+ojNANjWk8Zrc99TlXCSXgETQAmQDyAZEi0FrIkTYzFL0P6WK/qcb9RmkWNgFOt4CqXrqvVchFdzQ==</data>
+ <key>operator</key>
+ <string>flour</string>
+ </dict>
+ <dict>
+ <key>description</key>
+ <string>sugar</string>
+ <key>key</key>
+ <data>MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE3x/NYxPO1VZFfde5lzkucZIVd403m01F5O3TT8g9qaAEsRUfS9NlspS3pM/ytBtzMFc6oSQj9GFbrvZ68UhG4g==</data>
+ <key>operator</key>
+ <string>sugar</string>
+ </dict>
</array>
</plist>
--- /dev/null
+/*
+ * 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 */
*
*/
+#include <AssertMacros.h>
#include <CoreFoundation/CoreFoundation.h>
#include <Security/SecCertificatePriv.h>
#include <Security/SecTrustPriv.h>
-#include <Security/SecPolicy.h>
+#include <Security/SecPolicyPriv.h>
#include <stdlib.h>
#include <unistd.h>
#include <utilities/SecCFWrappers.h>
+#include <Security/SecTrustSettings.h>
+#include <Security/SecTrustSettingsPriv.h>
+#include <Security/SecFramework.h>
+
+#if TARGET_OS_IPHONE
+#include <Security/SecTrustStore.h>
+#else
+#include <Security/SecKeychain.h>
+#endif
#include "shared_regressions.h"
+#include "si-82-sectrust-ct.h"
//define this if you want to print clock time of SecTrustEvaluate call.
//define PRINT_SECTRUST_EVALUATE_TIME
}
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) {
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;
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");
CFReleaseSafe(whitelist_00008013_issuer);
CFReleaseSafe(whitelist_5555bc4f_issuer);
CFReleaseSafe(whitelist_fff9b5f6_issuer);
- CFReleaseSafe(trustedLogsURL);
CFReleaseSafe(trustedLogs);
CFReleaseSafe(valid_ocsp);
CFReleaseSafe(invalid_ocsp);
}
+static void test_sct_serialization(void) {
+ SecCertificateRef certA = NULL, certCA_alpha = NULL, certCA_beta = NULL;
+ CFArrayRef trustedLogs= CTTestsCopyTrustedLogs();
+ SecTrustRef trust = NULL, deserializedTrust = NULL;
+ SecPolicyRef policy = SecPolicyCreateSSL(true, NULL);
+ NSData *proofA_1 = NULL, *proofA_2 = NULL;
+ NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:447450000.0]; // March 7, 2015 at 11:40:00 AM PST
+ CFErrorRef error = NULL;
+
+ isnt(certA = SecCertificateCreateFromResource(@"serverA"), NULL, "create certA");
+ isnt(certCA_alpha = SecCertificateCreateFromResource(@"CA_alpha"), NULL, "create ca-alpha cert");
+ isnt(certCA_beta = SecCertificateCreateFromResource(@"CA_beta"), NULL, "create ca-beta cert");
+
+ NSArray *anchors = @[ (__bridge id)certCA_alpha, (__bridge id)certCA_beta ];
+
+ isnt(proofA_1 = CFBridgingRelease(CFDataCreateFromResource(@"serverA_proof_Alfa_3")), NULL, "creat proofA_1");
+ isnt(proofA_2 = CFBridgingRelease(CFDataCreateFromResource(@"serverA_proof_Bravo_3")), NULL, "creat proofA_2");
+ NSArray *scts = @[ proofA_1, proofA_2 ];
+
+ /* Make a SecTrustRef and then serialize it */
+ ok_status(SecTrustCreateWithCertificates(certA, policy, &trust), "failed to create trust object");
+ ok_status(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), "failed to set anchors");
+ ok_status(SecTrustSetTrustedLogs(trust, trustedLogs), "failed to set trusted logs");
+ ok_status(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), "failed to set verify date");
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunguarded-availability-new"
+ ok_status(SecTrustSetSignedCertificateTimestamps(trust, (__bridge CFArrayRef)scts), "failed to set SCTS");
+#pragma clang diagnostic pop
+
+ NSData *serializedTrust = CFBridgingRelease(SecTrustSerialize(trust, &error));
+ isnt(serializedTrust, NULL, "failed to serialize trust: %@", error);
+
+ /* Evaluate it to make sure it's CT */
+ ok(SecTrustEvaluateWithError(trust, &error), "failed to evaluate trust: %@", error);
+ NSDictionary *results = CFBridgingRelease(SecTrustCopyResult(trust));
+ isnt(results[(__bridge NSString*)kSecTrustCertificateTransparency], NULL, "failed get CT result");
+ ok([results[(__bridge NSString*)kSecTrustCertificateTransparency] boolValue], "CT failed");
+
+ /* Make a new trust object by deserializing the previous trust object */
+ ok(deserializedTrust = SecTrustDeserialize((__bridge CFDataRef)serializedTrust, &error), "failed to deserialize trust: %@", error);
+
+ /* Evaluate the new one to make sure it's CT (because the SCTs were serialized) */
+ ok(SecTrustEvaluateWithError(deserializedTrust, &error), "failed to evaluate trust: %@", error);
+ results = CFBridgingRelease(SecTrustCopyResult(deserializedTrust));
+ isnt(results[(__bridge NSString*)kSecTrustCertificateTransparency], NULL, "failed get CT result");
+ ok([results[(__bridge NSString*)kSecTrustCertificateTransparency] boolValue], "CT failed");
+
+ CFReleaseNull(certA);
+ CFReleaseNull(certCA_alpha);
+ CFReleaseNull(certCA_beta);
+ CFReleaseNull(trustedLogs);
+ CFReleaseNull(policy);
+ CFReleaseNull(trust);
+ CFReleaseNull(deserializedTrust);
+ CFReleaseNull(error);
+}
+
+static void testSetCTExceptions(void) {
+ CFErrorRef error = NULL;
+ const CFStringRef SecurityTestsAppID = CFSTR("com.apple.security.regressions");
+ const CFStringRef AnotherAppID = CFSTR("com.apple.security.not-this-one");
+ CFDictionaryRef copiedExceptions = NULL;
+
+ /* Verify no exceptions set */
+ is(copiedExceptions = SecTrustStoreCopyCTExceptions(NULL, NULL), NULL, "no exceptions set");
+ if (copiedExceptions) {
+ /* If we're starting out with exceptions set, a lot of the following will also fail, so just skip them */
+ CFReleaseNull(copiedExceptions);
+ return;
+ }
+
+ /* Set exceptions with specified AppID */
+ NSDictionary *exceptions1 = @{
+ (__bridge NSString*)kSecCTExceptionsDomainsKey: @[@"test.apple.com", @".test.apple.com"],
+ };
+ ok(SecTrustStoreSetCTExceptions(SecurityTestsAppID, (__bridge CFDictionaryRef)exceptions1, &error),
+ "failed to set exceptions for SecurityTests: %@", error);
+
+ /* Copy all exceptions (with only one set) */
+ ok(copiedExceptions = SecTrustStoreCopyCTExceptions(NULL, &error),
+ "failed to copy all exceptions: %@", error);
+ ok([exceptions1 isEqualToDictionary:(__bridge NSDictionary*)copiedExceptions],
+ "got the wrong exceptions back");
+ CFReleaseNull(copiedExceptions);
+
+ /* Copy this app's exceptions */
+ ok(copiedExceptions = SecTrustStoreCopyCTExceptions(SecurityTestsAppID, &error),
+ "failed to copy SecurityTests' exceptions: %@", error);
+ ok([exceptions1 isEqualToDictionary:(__bridge NSDictionary*)copiedExceptions],
+ "got the wrong exceptions back");
+ CFReleaseNull(copiedExceptions);
+
+ /* Copy a different app's exceptions */
+ is(copiedExceptions = SecTrustStoreCopyCTExceptions(AnotherAppID, &error), NULL,
+ "failed to copy different app's exceptions: %@", error);
+ CFReleaseNull(copiedExceptions);
+
+ /* Set different exceptions with implied AppID */
+ CFDataRef leafHash = SecSHA256DigestCreate(NULL, _system_after_leafSPKI, sizeof(_system_after_leafSPKI));
+ NSDictionary *leafException = @{ (__bridge NSString*)kSecCTExceptionsHashAlgorithmKey : @"sha256",
+ (__bridge NSString*)kSecCTExceptionsSPKIHashKey : (__bridge NSData*)leafHash,
+ };
+
+ NSDictionary *exceptions2 = @{
+ (__bridge NSString*)kSecCTExceptionsDomainsKey: @[@".test.apple.com"],
+ (__bridge NSString*)kSecCTExceptionsCAsKey : @[ leafException ]
+ };
+ ok(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)exceptions2, &error),
+ "failed to set exceptions for this app: %@", error);
+
+ /* Ensure exceptions are replaced for SecurityTests */
+ ok(copiedExceptions = SecTrustStoreCopyCTExceptions(SecurityTestsAppID, &error),
+ "failed to copy SecurityTests' exceptions: %@", error);
+ ok([exceptions2 isEqualToDictionary:(__bridge NSDictionary*)copiedExceptions],
+ "got the wrong exceptions back");
+ CFReleaseNull(copiedExceptions);
+
+ /* Set exceptions with a different AppID */
+ CFDataRef rootHash = SecSHA256DigestCreate(NULL, _system_rootSPKI, sizeof(_system_rootSPKI));
+ NSDictionary *rootExceptions = @{ (__bridge NSString*)kSecCTExceptionsHashAlgorithmKey : @"sha256",
+ (__bridge NSString*)kSecCTExceptionsSPKIHashKey : (__bridge NSData*)rootHash,
+ };
+ NSDictionary *exceptions3 = @{
+ (__bridge NSString*)kSecCTExceptionsCAsKey : @[ rootExceptions ]
+ };
+ ok(SecTrustStoreSetCTExceptions(AnotherAppID, (__bridge CFDictionaryRef)exceptions3, &error),
+ "failed to set exceptions for different app: %@", error);
+
+ /* Copy only one of the app's exceptions */
+ ok(copiedExceptions = SecTrustStoreCopyCTExceptions(SecurityTestsAppID, &error),
+ "failed to copy SecurityTests' exceptions: %@", error);
+ ok([exceptions2 isEqualToDictionary:(__bridge NSDictionary*)copiedExceptions],
+ "got the wrong exceptions back");
+ CFReleaseNull(copiedExceptions);
+
+ /* Set empty exceptions */
+ NSDictionary *empty = @{};
+ ok(SecTrustStoreSetCTExceptions(SecurityTestsAppID, (__bridge CFDictionaryRef)empty, &error),
+ "failed to set empty exceptions");
+
+ /* Copy exceptiosn to ensure no change */
+ ok(copiedExceptions = SecTrustStoreCopyCTExceptions(SecurityTestsAppID, &error),
+ "failed to copy SecurityTests' exceptions: %@", error);
+ ok([exceptions2 isEqualToDictionary:(__bridge NSDictionary*)copiedExceptions],
+ "got the wrong exceptions back");
+ CFReleaseNull(copiedExceptions);
+
+ /* Copy all exceptions */
+ ok(copiedExceptions = SecTrustStoreCopyCTExceptions(NULL, &error),
+ "failed to copy all exceptions: %@", error);
+ is(CFDictionaryGetCount(copiedExceptions), 2, "Got the wrong number of all exceptions");
+ NSDictionary *nsCopiedExceptions = CFBridgingRelease(copiedExceptions);
+ NSArray *domainExceptions = nsCopiedExceptions[(__bridge NSString*)kSecCTExceptionsDomainsKey];
+ NSArray *caExceptions = nsCopiedExceptions[(__bridge NSString*)kSecCTExceptionsCAsKey];
+ ok(domainExceptions && caExceptions, "Got both domain and CA exceptions");
+ ok([domainExceptions count] == 1, "Got 1 domain exception");
+ ok([caExceptions count] == 2, "Got 2 CA exceptions");
+ ok([domainExceptions[0] isEqualToString:@".test.apple.com"], "domain exception is .test.apple.com");
+ ok([caExceptions containsObject:leafException] && [caExceptions containsObject:rootExceptions], "got expected leaf and root CA exceptions");
+
+ /* Reset other app's exceptions */
+ ok(SecTrustStoreSetCTExceptions(AnotherAppID, NULL, &error),
+ "failed to reset exceptions for different app: %@", error);
+ ok(copiedExceptions = SecTrustStoreCopyCTExceptions(NULL, &error),
+ "failed to copy all exceptions: %@", error);
+ ok([exceptions2 isEqualToDictionary:(__bridge NSDictionary*)copiedExceptions],
+ "got the wrong exceptions back");
+ CFReleaseNull(copiedExceptions);
+
+#define check_errSecParam \
+ if (error) { \
+ is(CFErrorGetCode(error), errSecParam, "bad input produced unxpected error code: %ld", (long)CFErrorGetCode(error)); \
+ } else { \
+ fail("expected failure to set NULL exceptions"); \
+ }
+
+ /* Set exceptions with bad inputs */
+ NSDictionary *badExceptions = @{
+ (__bridge NSString*)kSecCTExceptionsDomainsKey: @[@"test.apple.com", @".test.apple.com"],
+ @"not a key": @"not a value",
+ };
+ is(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)badExceptions, &error), false,
+ "set exceptions with unknown key");
+ check_errSecParam
+
+ badExceptions = @{ (__bridge NSString*)kSecCTExceptionsDomainsKey:@"test.apple.com" };
+ is(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)badExceptions, &error), false,
+ "set exceptions with bad value");
+ check_errSecParam
+
+ badExceptions = @{ (__bridge NSString*)kSecCTExceptionsDomainsKey: @[ @{} ] };
+ is(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)badExceptions, &error), false,
+ "set exceptions with bad array value");
+ check_errSecParam
+
+ badExceptions = @{ (__bridge NSString*)kSecCTExceptionsCAsKey: @[ @"test.apple.com" ] };
+ is(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)badExceptions, &error), false,
+ "set exceptions with bad array value");
+ check_errSecParam
+
+ badExceptions = @{ (__bridge NSString*)kSecCTExceptionsCAsKey: @[ @{
+ (__bridge NSString*)kSecCTExceptionsHashAlgorithmKey : @"sha256",
+ @"not-a-key" : (__bridge NSData*)rootHash,
+ }] };
+ is(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)badExceptions, &error), false,
+ "set exceptions with bad CA dictionary value");
+ check_errSecParam
+
+ badExceptions = @{ (__bridge NSString*)kSecCTExceptionsCAsKey: @[ @{
+ (__bridge NSString*)kSecCTExceptionsHashAlgorithmKey : @"sha256",
+ }] };
+ is(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)badExceptions, &error), false,
+ "set exceptions with bad CA dictionary value");
+ check_errSecParam
+
+ badExceptions = @{ (__bridge NSString*)kSecCTExceptionsCAsKey: @[ @{
+ (__bridge NSString*)kSecCTExceptionsHashAlgorithmKey : @"sha256",
+ (__bridge NSString*)kSecCTExceptionsSPKIHashKey : (__bridge NSData*)rootHash,
+ @"not-a-key":@"not-a-value"
+ }] };
+ is(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)badExceptions, &error), false,
+ "set exceptions with bad CA dictionary value");
+ check_errSecParam
+
+ badExceptions = @{ (__bridge NSString*)kSecCTExceptionsDomainsKey: @[ @".com" ] };
+ is(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)badExceptions, &error), false,
+ "set exceptions with TLD value");
+ check_errSecParam
+#undef check_errSecParam
+
+ /* Remove exceptions using empty arrays */
+ NSDictionary *emptyArrays = @{
+ (__bridge NSString*)kSecCTExceptionsDomainsKey: @[],
+ (__bridge NSString*)kSecCTExceptionsCAsKey : @[]
+ };
+ ok(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)emptyArrays, &error),
+ "failed to set empty array exceptions for this app: %@", error);
+ is(copiedExceptions = SecTrustStoreCopyCTExceptions(NULL, NULL), NULL, "no exceptions set");
+
+ CFReleaseNull(leafHash);
+ CFReleaseNull(rootHash);
+}
+
+static void setup_for_user_trust(NSArray *in_certs, NSArray **deleteMeCertificates) {
+#if TARGET_OS_OSX
+ /* Since we're putting trust settings in the admin domain,
+ * we need to add the certs to the system keychain. */
+ SecKeychainRef kcRef = NULL;
+ CFArrayRef certRef = NULL;
+ NSDictionary *attrs = nil;
+ NSMutableArray *persistenRefs = nil;
+
+ SecKeychainOpen("/Library/Keychains/System.keychain", &kcRef);
+ if (!kcRef) {
+ return;
+ }
+
+ persistenRefs = [[NSMutableArray alloc] init];
+
+ for (id cert in in_certs) {
+ attrs = @{(__bridge NSString*)kSecValueRef: cert,
+ (__bridge NSString*)kSecUseKeychain: (__bridge id)kcRef,
+ (__bridge NSString*)kSecReturnPersistentRef: @YES};
+ if (SecItemAdd((CFDictionaryRef)attrs, (void *)&certRef) == 0)
+ [persistenRefs addObject:(__bridge NSArray *)certRef];
+ CFReleaseNull(certRef);
+ }
+
+ CFReleaseNull(kcRef);
+ *deleteMeCertificates = persistenRefs;
+#endif
+}
+
+static void cleanup_keychain(NSArray *deleteMeCertificates) {
+#if TARGET_OS_OSX
+ if (!deleteMeCertificates) {
+ return;
+ }
+
+ [deleteMeCertificates enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
+ SecItemDelete((CFDictionaryRef)@{ (__bridge NSString*)kSecValuePersistentRef: [obj objectAtIndex:0]});
+ }];
+#endif
+}
+
+static bool set_trust_settings_for_cert(SecCertificateRef cert) {
+ bool ok = false;
+ NSDictionary *settings = nil;
+ if (!SecCertificateIsSelfSignedCA(cert)) {
+ settings = @{ (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustAsRoot)};
+ }
+#if TARGET_OS_IPHONE
+ require_noerr_string(SecTrustStoreSetTrustSettings(SecTrustStoreForDomain(kSecTrustStoreDomainUser), cert,
+ (__bridge CFDictionaryRef)settings),
+ errOut, "failed to set trust settings");
+#else
+ require_noerr_string(SecTrustSettingsSetTrustSettings(cert, kSecTrustSettingsDomainAdmin,
+ (__bridge CFDictionaryRef)settings),
+ errOut, "failed to set trust settings");
+ usleep(20000);
+#endif
+ ok = true;
+errOut:
+ return ok;
+}
+
+static bool remove_trust_settings_for_cert(SecCertificateRef cert) {
+ bool ok = false;
+#if TARGET_OS_IPHONE
+ require_noerr_string(SecTrustStoreRemoveCertificate(SecTrustStoreForDomain(kSecTrustStoreDomainUser), cert),
+ errOut, "failed to remove trust settings");
+#else
+ require_noerr_string(SecTrustSettingsRemoveTrustSettings(cert, kSecTrustSettingsDomainAdmin),
+ errOut, "failed to remove trust settings");
+#endif
+ ok = true;
+errOut:
+ return ok;
+}
+
+static void test_enforcement(void) {
+ SecCertificateRef system_root = NULL, user_root = NULL;
+ SecCertificateRef system_server_before = NULL, system_server_after = NULL, system_server_after_with_CT = NULL;
+ SecCertificateRef user_server_after = NULL;
+ CFArrayRef trustedLogs = CTTestsCopyTrustedLogs();
+ SecTrustRef trust = NULL;
+ SecPolicyRef policy = SecPolicyCreateSSL(true, CFSTR("ct.test.apple.com"));
+ NSArray *anchors = nil, *keychain_certs = nil;
+ NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:562340800.0]; // October 27, 2018 at 6:46:40 AM PDT
+ CFErrorRef error = nil;
+ CFDataRef exceptions = nil;
+
+ require_action(system_root = SecCertificateCreateFromResource(@"enforcement_system_root"),
+ errOut, fail("failed to create system root"));
+ require_action(user_root = SecCertificateCreateFromResource(@"enforcement_user_root"),
+ errOut, fail("failed to create user root"));
+ require_action(system_server_before = SecCertificateCreateFromResource(@"enforcement_system_server_before"),
+ errOut, fail("failed to create system server cert issued before flag day"));
+ require_action(system_server_after = SecCertificateCreateFromResource(@"enforcement_system_server_after"),
+ errOut, fail("failed to create system server cert issued after flag day"));
+ require_action(system_server_after_with_CT = SecCertificateCreateFromResource(@"enforcement_system_server_after_scts"),
+ errOut, fail("failed to create system server cert issued after flag day with SCTs"));
+ require_action(user_server_after = SecCertificateCreateFromResource(@"enforcement_user_server_after"),
+ errOut, fail("failed to create user server cert issued after flag day"));
+
+ /* set up the user and system roots to be used with trust settings */
+ setup_for_user_trust(@[(__bridge id)system_root, (__bridge id)user_root, (__bridge id)system_server_after],
+ &keychain_certs);
+ anchors = @[ (__bridge id)system_root ];
+ require_noerr_action(SecTrustCreateWithCertificates(system_server_after, policy, &trust), errOut, fail("failed to create trust"));
+ require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), errOut, fail("failed to set anchors"));
+ require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date"));
+
+#if 0 // Disable this test until we can mock MobileAsset and force asset to be out-of-date
+ // Out-of-date asset, test system cert after date without CT passes
+ ok(SecTrustEvaluateWithError(trust, NULL), "system post-flag-date non-CT cert failed with out-of-date asset");
+#endif
+
+ // test system cert after date without CT fails
+ require_noerr_action(SecTrustSetTrustedLogs(trust, trustedLogs), errOut, fail("failed to set trusted logs")); // set trusted logs to trigger enforcing behavior
+ is(SecTrustEvaluateWithError(trust, &error), false, "system post-flag-date non-CT cert with in-date asset succeeded");
+ if (error) {
+ is(CFErrorGetCode(error), errSecVerifyActionFailed, "got wrong error code for non-ct cert, got %ld, expected %d",
+ (long)CFErrorGetCode(error), errSecVerifyActionFailed);
+ } else {
+ fail("expected trust evaluation to fail and it did not.");
+ }
+
+ // test exceptions for failing cert passes
+ exceptions = SecTrustCopyExceptions(trust);
+ ok(SecTrustSetExceptions(trust, exceptions), "failed to set exceptions for failing non-CT cert");
+ CFReleaseNull(exceptions);
+ ok(SecTrustEvaluateWithError(trust, NULL), "system post-flag-date non-CT cert failed with exceptions set");
+ SecTrustSetExceptions(trust, NULL);
+
+ // test system cert + enterprise anchor after date without CT fails
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnonnull" /* required because of <rdar://32627101> */
+ require_noerr_action(SecTrustSetAnchorCertificates(trust, NULL), errOut, fail("failed to unset anchors"));
+#pragma clang diagnostic pop
+ require_action(set_trust_settings_for_cert(system_root), errOut, fail("failed to set trust settings for system_root"));
+ is(SecTrustEvaluateWithError(trust, &error), false, "system post-flag date non-CT cert with enterprise root trust succeeded");
+ if (error) {
+ is(CFErrorGetCode(error), errSecVerifyActionFailed, "got wrong error code for non-ct cert, got %ld, expected %d",
+ (long)CFErrorGetCode(error), errSecVerifyActionFailed);
+ } else {
+ fail("expected trust evaluation to fail and it did not.");
+ }
+ require_action(remove_trust_settings_for_cert(system_root), errOut, fail("failed to remove trust settings for system_root"));
+
+ // test app anchor for failing cert passes
+ anchors = @[ (__bridge id)system_server_after ];
+ require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), errOut, fail("failed to set anchors"));
+ ok(SecTrustEvaluateWithError(trust, NULL), "system post-flag-date non-CT cert failed with server cert app anchor");
+
+ // test trust settings for failing cert passes
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnonnull" /* required because of <rdar://32627101> */
+ require_noerr_action(SecTrustSetAnchorCertificates(trust, NULL), errOut, fail("failed to remove anchors"));
+#pragma clang diagnostic pop
+ require_action(set_trust_settings_for_cert(system_server_after), errOut, fail("failed to set trust settings for system_server_after"));
+ ok(SecTrustEvaluateWithError(trust, NULL), "system post-flag-date non-CT cert failed with server cert enterprise anchor");
+ require_action(remove_trust_settings_for_cert(system_server_after), errOut, fail("failed to remove trust settings for system_server_after"));
+
+ // EAP, test system cert after date without CT passes
+ anchors = @[ (__bridge id)system_root ];
+ require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), errOut, fail("failed to set anchors"));
+ CFReleaseNull(policy);
+ policy = SecPolicyCreateEAP(true, NULL);
+ require_noerr_action(SecTrustSetPolicies(trust, policy), errOut, fail("failed to set EAP policy"));
+ ok(SecTrustEvaluateWithError(trust, NULL), "system post-flag-date non-CT cert failed with EAP cert");
+
+ // Test pinning policy name
+ CFReleaseNull(policy);
+ policy = SecPolicyCreateSSL(true, CFSTR("ct.test.apple.com"));
+ require_noerr_action(SecTrustSetPolicies(trust, policy), errOut, fail("failed to set SSL policy"));
+ require_noerr_action(SecTrustSetPinningPolicyName(trust, CFSTR("a-policy-name")), errOut, fail("failed to set policy name"));
+ ok(SecTrustEvaluateWithError(trust, NULL), "system post-flag-date non-CT cert failed with pinning policy name");
+ CFReleaseNull(trust);
+
+ // test system cert after date with CT passes
+ require_noerr_action(SecTrustCreateWithCertificates(system_server_after_with_CT, policy, &trust), errOut, fail("failed to create trust"));
+ require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), errOut, fail("failed to set anchors"));
+ require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date"));
+ require_noerr_action(SecTrustSetTrustedLogs(trust, trustedLogs), errOut, fail("failed to set trusted logs"));
+ ok(SecTrustEvaluateWithError(trust, NULL), "system post-flag-date CT cert failed");
+ CFReleaseNull(trust);
+
+ // test system cert before date without CT passes
+ require_noerr_action(SecTrustCreateWithCertificates(system_server_before, policy, &trust), errOut, fail("failed to create trust"));
+ require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), errOut, fail("failed to set anchors"));
+ require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date"));
+ require_noerr_action(SecTrustSetTrustedLogs(trust, trustedLogs), errOut, fail("failed to set trusted logs"));
+ ok(SecTrustEvaluateWithError(trust, NULL), "system pre-flag-date non-CT cert failed");
+ CFReleaseNull(trust);
+
+ // test enterprise (non-public) after date without CT passes
+ require_action(set_trust_settings_for_cert(user_root), errOut, fail("failed to set trust settings for user_root"));
+ require_noerr_action(SecTrustCreateWithCertificates(user_server_after, policy, &trust), errOut, fail("failed to create trust"));
+ require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date"));
+ require_noerr_action(SecTrustSetTrustedLogs(trust, trustedLogs), errOut, fail("failed to set trusted logs"));
+ ok(SecTrustEvaluateWithError(trust, NULL), "non-system post-flag-date non-CT cert failed with enterprise anchor");
+ require_action(remove_trust_settings_for_cert(user_root), errOut, fail("failed to remove trust settings for user_root"));
+
+ // test app anchor (non-public) after date without CT passes
+ anchors = @[ (__bridge id)user_root ];
+ require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), errOut, fail("failed to set anchors"));
+ ok(SecTrustEvaluateWithError(trust, NULL), "non-system post-flag-date non-CT cert failed with app anchor");
+ CFReleaseNull(trust);
+ CFReleaseNull(policy);
+
+errOut:
+ cleanup_keychain(keychain_certs);
+ CFReleaseNull(system_root);
+ CFReleaseNull(user_root);
+ CFReleaseNull(system_server_before);
+ CFReleaseNull(system_server_after);
+ CFReleaseNull(system_server_after_with_CT);
+ CFReleaseNull(user_server_after);
+ CFReleaseNull(trustedLogs);
+ CFReleaseNull(trust);
+ CFReleaseNull(policy);
+}
+
+static void test_apple_enforcement_exceptions(void) {
+ SecCertificateRef appleRoot = NULL, appleServerAuthCA = NULL, apple_server_after = NULL;
+ SecCertificateRef geoTrustRoot = NULL, appleISTCA8G1 = NULL, livability = NULL;
+ CFArrayRef trustedLogs = CTTestsCopyTrustedLogs();
+ SecTrustRef trust = NULL;
+ SecPolicyRef policy = NULL;
+ NSArray *anchors = nil, *certs = nil;
+ NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:562340800.0]; // October 27, 2018 at 6:46:40 AM PDT
+
+ require_action(appleRoot = SecCertificateCreateFromResource(@"enforcement_apple_root"),
+ errOut, fail("failed to create apple root"));
+ require_action(appleServerAuthCA = SecCertificateCreateFromResource(@"enforcement_apple_ca"),
+ errOut, fail("failed to create apple server auth CA"));
+ require_action(apple_server_after = SecCertificateCreateFromResource(@"enforcement_apple_server_after"),
+ errOut, fail("failed to create apple server cert issued after flag day"));
+ require_action(geoTrustRoot = SecCertificateCreateFromResource(@"GeoTrustPrimaryCAG2"),
+ errOut, fail("failed to create GeoTrust root"));
+ require_action(appleISTCA8G1 = SecCertificateCreateFromResource(@"AppleISTCA8G1"),
+ errOut, fail("failed to create apple IST CA"));
+ require_action(livability = SecCertificateCreateFromResource(@"livability"),
+ errOut, fail("failed to create livability cert"));
+
+ // test apple anchor after date without CT passes
+ policy = SecPolicyCreateSSL(true, CFSTR("bbasile-test.scv.apple.com"));
+ certs = @[ (__bridge id)apple_server_after, (__bridge id)appleServerAuthCA ];
+ require_noerr_action(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trust), errOut, fail("failed to create trust"));
+ require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date"));
+ require_noerr_action(SecTrustSetTrustedLogs(trust, trustedLogs), errOut, fail("failed to set trusted logs"));
+ ok(SecTrustEvaluateWithError(trust, NULL), "apple root post-flag-date non-CT cert failed");
+ CFReleaseNull(trust);
+ CFReleaseNull(policy);
+
+ // test apple ca after date without CT passes
+ policy = SecPolicyCreateSSL(true, CFSTR("livability.swe.apple.com"));
+ certs = @[ (__bridge id)livability, (__bridge id)appleISTCA8G1 ];
+ anchors = @[ (__bridge id)geoTrustRoot ];
+ require_noerr_action(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trust), errOut, fail("failed to create trust"));
+ require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date"));
+ require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), errOut, fail("failed to set anchors"));
+ require_noerr_action(SecTrustSetTrustedLogs(trust, trustedLogs), errOut, fail("failed to set trusted logs"));
+ ok(SecTrustEvaluateWithError(trust, NULL), "apple public post-flag-date non-CT cert failed");
+
+errOut:
+ CFReleaseNull(appleRoot);
+ CFReleaseNull(appleServerAuthCA);
+ CFReleaseNull(apple_server_after);
+ CFReleaseNull(geoTrustRoot);
+ CFReleaseNull(appleISTCA8G1);
+ CFReleaseNull(livability);
+ CFReleaseNull(trustedLogs);
+ CFReleaseNull(trust);
+ CFReleaseNull(policy);
+}
+
+static void test_google_enforcement_exception(void) {
+ SecCertificateRef globalSignRoot = NULL, googleIAG3 = NULL, google = NULL;
+ CFArrayRef trustedLogs = CTTestsCopyTrustedLogs();
+ SecTrustRef trust = NULL;
+ SecPolicyRef policy = NULL;
+ NSArray *anchors = nil, *certs = nil;
+ NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:562340800.0]; // October 27, 2018 at 6:46:40 AM PDT
+
+ require_action(globalSignRoot = SecCertificateCreateFromResource(@"GlobalSignRootCAR2"),
+ errOut, fail("failed to create GlobalSign root"));
+ require_action(googleIAG3 = SecCertificateCreateFromResource(@"GoogleIAG3"),
+ errOut, fail("failed to create Google IA CA"));
+ require_action(google = SecCertificateCreateFromResource(@"google"),
+ errOut, fail("failed to create google server cert"));
+
+ // test google ca after date without CT passes
+ policy = SecPolicyCreateSSL(true, CFSTR("www.google.com"));
+ certs = @[ (__bridge id)google, (__bridge id)googleIAG3];
+ anchors = @[ (__bridge id)globalSignRoot ];
+ require_noerr_action(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trust), errOut, fail("failed to create trust"));
+ require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date"));
+ require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), errOut, fail("failed to set anchors"));
+ require_noerr_action(SecTrustSetTrustedLogs(trust, trustedLogs), errOut, fail("failed to set trusted logs"));
+ ok(SecTrustEvaluateWithError(trust, NULL), "google public post-flag-date non-CT cert failed");
+
+errOut:
+ CFReleaseNull(globalSignRoot);
+ CFReleaseNull(googleIAG3);
+ CFReleaseNull(google);
+ CFReleaseNull(trustedLogs);
+ CFReleaseNull(trust);
+ CFReleaseNull(policy);
+}
+
+static void test_precerts_fail(void) {
+ SecCertificateRef precert = NULL, system_root = NULL;
+ SecTrustRef trust = NULL;
+ NSArray *anchors = nil;
+ NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:561540800.0]; // October 18, 2018 at 12:33:20 AM PDT
+ CFErrorRef error = NULL;
+
+ require_action(system_root = SecCertificateCreateFromResource(@"enforcement_system_root"),
+ errOut, fail("failed to create system root"));
+ require_action(precert = SecCertificateCreateFromResource(@"precert"),
+ errOut, fail("failed to create precert"));
+
+ anchors = @[(__bridge id)system_root];
+ require_noerr_action(SecTrustCreateWithCertificates(precert, NULL, &trust), errOut, fail("failed to create trust object"));
+ require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), errOut, fail("failed to set anchor certificate"));
+ require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date"));
+
+ is(SecTrustEvaluateWithError(trust, &error), false, "SECURITY: trust evaluation of precert succeeded");
+ if (error) {
+ is(CFErrorGetCode(error), errSecUnknownCriticalExtensionFlag, "got wrong error code for precert, got %ld, expected %d",
+ (long)CFErrorGetCode(error), errSecUnknownCriticalExtensionFlag);
+ } else {
+ fail("expected trust evaluation to fail and it did not.");
+ }
+
+
+errOut:
+ CFReleaseNull(system_root);
+ CFReleaseNull(precert);
+ CFReleaseNull(error);
+}
+
+#define evalTrustExpectingError(errCode, ...) \
+ is(SecTrustEvaluateWithError(trust, &error), false, __VA_ARGS__); \
+ if (error) { \
+ is(CFErrorGetCode(error), errCode, "got wrong error code, got %ld, expected %d", \
+ (long)CFErrorGetCode(error), errCode); \
+ } else { \
+ fail("expected trust evaluation to fail and it did not."); \
+ } \
+ CFReleaseNull(error);
+
+static void test_specific_domain_exceptions(void) {
+ SecCertificateRef system_root = NULL, system_server_after = NULL, system_server_after_with_CT = NULL;
+ CFArrayRef trustedLogs = CTTestsCopyTrustedLogs();
+ SecTrustRef trust = NULL;
+ SecPolicyRef policy = SecPolicyCreateSSL(true, CFSTR("ct.test.apple.com"));
+ NSArray *anchors = nil;
+ NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:562340800.0]; // October 27, 2018 at 6:46:40 AM PDT
+ CFErrorRef error = nil;
+ NSDictionary *exceptions = nil;
+
+ require_action(system_root = SecCertificateCreateFromResource(@"enforcement_system_root"),
+ errOut, fail("failed to create system root"));
+ require_action(system_server_after = SecCertificateCreateFromResource(@"enforcement_system_server_after"),
+ errOut, fail("failed to create system server cert issued after flag day"));
+ require_action(system_server_after_with_CT = SecCertificateCreateFromResource(@"enforcement_system_server_after_scts"),
+ errOut, fail("failed to create system server cert issued after flag day with SCTs"));
+
+ anchors = @[ (__bridge id)system_root ];
+ require_noerr_action(SecTrustCreateWithCertificates(system_server_after, policy, &trust), errOut, fail("failed to create trust"));
+ require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), errOut, fail("failed to set anchors"));
+ require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date"));
+ require_noerr_action(SecTrustSetTrustedLogs(trust, trustedLogs), errOut, fail("failed to set trusted logs")); // set trusted logs to trigger enforcing behavior
+
+ /* superdomain exception without CT fails */
+ exceptions = @{ (__bridge NSString*)kSecCTExceptionsDomainsKey : @[@"test.apple.com"] };
+ ok(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)exceptions, &error), "failed to set exceptions: %@", error);
+ evalTrustExpectingError(errSecVerifyActionFailed, "superdomain exception unexpectedly succeeded");
+
+ /* subdomain exceptions without CT fails */
+ exceptions = @{ (__bridge NSString*)kSecCTExceptionsDomainsKey : @[@"one.ct.test.apple.com"] };
+ ok(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)exceptions, &error), "failed to set exceptions: %@", error);
+ SecTrustSetNeedsEvaluation(trust);
+ evalTrustExpectingError(errSecVerifyActionFailed, "subdomain exception unexpectedly succeeded")
+
+ /* no match without CT fails */
+ exceptions = @{ (__bridge NSString*)kSecCTExceptionsDomainsKey : @[@"example.com"] };
+ ok(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)exceptions, &error), "failed to set exceptions: %@", error);
+ SecTrustSetNeedsEvaluation(trust);
+ evalTrustExpectingError(errSecVerifyActionFailed, "unrelated domain exception unexpectedly succeeded");
+
+ /* matching domain without CT succeeds */
+ exceptions = @{ (__bridge NSString*)kSecCTExceptionsDomainsKey : @[@"ct.test.apple.com"] };
+ ok(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)exceptions, &error), "failed to set exceptions: %@", error);
+ SecTrustSetNeedsEvaluation(trust);
+ is(SecTrustEvaluateWithError(trust, &error), true, "exact match domain exception did not apply");
+
+ /* matching domain with CT succeeds */
+ CFReleaseNull(trust);
+ require_noerr_action(SecTrustCreateWithCertificates(system_server_after_with_CT, policy, &trust), errOut, fail("failed to create trust"));
+ require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), errOut, fail("failed to set anchors"));
+ require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date"));
+ require_noerr_action(SecTrustSetTrustedLogs(trust, trustedLogs), errOut, fail("failed to set trusted logs")); // set trusted logs to trigger enforcing behavior
+ is(SecTrustEvaluateWithError(trust, &error), true, "ct cert should always pass");
+
+ ok(SecTrustStoreSetCTExceptions(NULL, NULL, &error), "failed to reset exceptions: %@", error);
+
+errOut:
+ CFReleaseNull(system_root);
+ CFReleaseNull(system_server_after);
+ CFReleaseNull(system_server_after_with_CT);
+ CFReleaseNull(trust);
+ CFReleaseNull(policy);
+ CFReleaseNull(error);
+ CFReleaseNull(trustedLogs);
+}
+
+static void test_subdomain_exceptions(void) {
+ SecCertificateRef system_root = NULL, system_server_after = NULL, system_server_after_with_CT = NULL;
+ CFArrayRef trustedLogs = CTTestsCopyTrustedLogs();
+ SecTrustRef trust = NULL;
+ SecPolicyRef policy = SecPolicyCreateSSL(true, CFSTR("ct.test.apple.com"));
+ NSArray *anchors = nil;
+ NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:562340800.0]; // October 27, 2018 at 6:46:40 AM PDT
+ CFErrorRef error = nil;
+ NSDictionary *exceptions = nil;
+
+ require_action(system_root = SecCertificateCreateFromResource(@"enforcement_system_root"),
+ errOut, fail("failed to create system root"));
+ require_action(system_server_after = SecCertificateCreateFromResource(@"enforcement_system_server_after"),
+ errOut, fail("failed to create system server cert issued after flag day"));
+ require_action(system_server_after_with_CT = SecCertificateCreateFromResource(@"enforcement_system_server_after_scts"),
+ errOut, fail("failed to create system server cert issued after flag day with SCTs"));
+
+ anchors = @[ (__bridge id)system_root ];
+ require_noerr_action(SecTrustCreateWithCertificates(system_server_after, policy, &trust), errOut, fail("failed to create trust"));
+ require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), errOut, fail("failed to set anchors"));
+ require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date"));
+ require_noerr_action(SecTrustSetTrustedLogs(trust, trustedLogs), errOut, fail("failed to set trusted logs")); // set trusted logs to trigger enforcing behavior
+
+ /* superdomain exception without CT succeeds */
+ exceptions = @{ (__bridge NSString*)kSecCTExceptionsDomainsKey : @[@".test.apple.com"] };
+ ok(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)exceptions, &error), "failed to set exceptions: %@", error);
+ is(SecTrustEvaluateWithError(trust, &error), true, "superdomain exception did not apply");
+
+ /* exact domain exception without CT succeeds */
+ exceptions = @{ (__bridge NSString*)kSecCTExceptionsDomainsKey : @[@".ct.test.apple.com"] };
+ ok(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)exceptions, &error), "failed to set exceptions: %@", error);
+ SecTrustSetNeedsEvaluation(trust);
+ is(SecTrustEvaluateWithError(trust, &error), true, "exact domain exception did not apply");
+
+ /* no match without CT fails */
+ exceptions = @{ (__bridge NSString*)kSecCTExceptionsDomainsKey : @[@".example.com"] };
+ ok(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)exceptions, &error), "failed to set exceptions: %@", error);
+ SecTrustSetNeedsEvaluation(trust);
+ evalTrustExpectingError(errSecVerifyActionFailed, "unrelated domain exception unexpectedly succeeded");
+
+ /* subdomain without CT fails */
+ exceptions = @{ (__bridge NSString*)kSecCTExceptionsDomainsKey : @[@".one.ct.test.apple.com"] };
+ ok(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)exceptions, &error), "failed to set exceptions: %@", error);
+ SecTrustSetNeedsEvaluation(trust);
+ evalTrustExpectingError(errSecVerifyActionFailed, "subdomain exception unexpectedly succeeded");
+
+ ok(SecTrustStoreSetCTExceptions(NULL, NULL, &error), "failed to reset exceptions: %@", error);
+
+errOut:
+ CFReleaseNull(system_root);
+ CFReleaseNull(system_server_after);
+ CFReleaseNull(system_server_after_with_CT);
+ CFReleaseNull(trust);
+ CFReleaseNull(policy);
+ CFReleaseNull(error);
+ CFReleaseNull(trustedLogs);
+}
+
+static void test_mixed_domain_exceptions(void) {
+ SecCertificateRef system_root = NULL, system_server_after = NULL, system_server_after_with_CT = NULL;
+ CFArrayRef trustedLogs = CTTestsCopyTrustedLogs();
+ SecTrustRef trust = NULL;
+ SecPolicyRef policy = SecPolicyCreateSSL(true, CFSTR("ct.test.apple.com"));
+ NSArray *anchors = nil;
+ NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:562340800.0]; // October 27, 2018 at 6:46:40 AM PDT
+ CFErrorRef error = nil;
+ NSDictionary *exceptions = nil;
+
+ require_action(system_root = SecCertificateCreateFromResource(@"enforcement_system_root"),
+ errOut, fail("failed to create system root"));
+ require_action(system_server_after = SecCertificateCreateFromResource(@"enforcement_system_server_after"),
+ errOut, fail("failed to create system server cert issued after flag day"));
+ require_action(system_server_after_with_CT = SecCertificateCreateFromResource(@"enforcement_system_server_after_scts"),
+ errOut, fail("failed to create system server cert issued after flag day with SCTs"));
+
+ anchors = @[ (__bridge id)system_root ];
+ require_noerr_action(SecTrustCreateWithCertificates(system_server_after, policy, &trust), errOut, fail("failed to create trust"));
+ require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), errOut, fail("failed to set anchors"));
+ require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date"));
+ require_noerr_action(SecTrustSetTrustedLogs(trust, trustedLogs), errOut, fail("failed to set trusted logs")); // set trusted logs to trigger enforcing behavior
+
+ /* specific domain exception without CT succeeds */
+ exceptions = @{ (__bridge NSString*)kSecCTExceptionsDomainsKey : @[@"ct.test.apple.com", @".example.com" ] };
+ ok(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)exceptions, &error), "failed to set exceptions: %@", error);
+ is(SecTrustEvaluateWithError(trust, &error), true, "one of exact domain exception did not apply");
+
+ /* super domain exception without CT succeeds */
+ exceptions = @{ (__bridge NSString*)kSecCTExceptionsDomainsKey : @[@".apple.com", @"example.com" ] };
+ ok(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)exceptions, &error), "failed to set exceptions: %@", error);
+ SecTrustSetNeedsEvaluation(trust);
+ is(SecTrustEvaluateWithError(trust, &error), true, "one of superdomain exception did not apply");
+
+ /* both super domain and specific domain exceptions without CT succeeds */
+ exceptions = @{ (__bridge NSString*)kSecCTExceptionsDomainsKey : @[@"ct.test.apple.com", @".apple.com" ] };
+ ok(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)exceptions, &error), "failed to set exceptions: %@", error);
+ SecTrustSetNeedsEvaluation(trust);
+ is(SecTrustEvaluateWithError(trust, &error), true, "both domain exception did not apply");
+
+ /* neither specific domain nor super domain exceptions without CT fails */
+ exceptions = @{ (__bridge NSString*)kSecCTExceptionsDomainsKey : @[@"apple.com", @".example.com" ] };
+ ok(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)exceptions, &error), "failed to set exceptions: %@", error);
+ SecTrustSetNeedsEvaluation(trust);
+ evalTrustExpectingError(errSecVerifyActionFailed, "no match domain unexpectedly succeeded");
+
+ ok(SecTrustStoreSetCTExceptions(NULL, NULL, &error), "failed to reset exceptions: %@", error);
+
+errOut:
+ CFReleaseNull(system_root);
+ CFReleaseNull(system_server_after);
+ CFReleaseNull(system_server_after_with_CT);
+ CFReleaseNull(trust);
+ CFReleaseNull(policy);
+ CFReleaseNull(error);
+ CFReleaseNull(trustedLogs);
+}
+
+
+
+static void test_ct_domain_exceptions(void) {
+ test_specific_domain_exceptions();
+ test_subdomain_exceptions();
+ test_mixed_domain_exceptions();
+}
+
+static void test_ct_leaf_exceptions(void) {
+ SecCertificateRef system_root = NULL, system_server_after = NULL, system_server_after_with_CT = NULL;
+ CFArrayRef trustedLogs = CTTestsCopyTrustedLogs();
+ SecTrustRef trust = NULL;
+ SecPolicyRef policy = SecPolicyCreateSSL(true, CFSTR("ct.test.apple.com"));
+ NSArray *anchors = nil;
+ NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:562340800.0]; // October 27, 2018 at 6:46:40 AM PDT
+ CFErrorRef error = nil;
+ NSDictionary *leafException = nil, *exceptions = nil;
+ NSData *leafHash = nil;
+
+ require_action(system_root = SecCertificateCreateFromResource(@"enforcement_system_root"),
+ errOut, fail("failed to create system root"));
+ require_action(system_server_after = SecCertificateCreateFromResource(@"enforcement_system_server_after"),
+ errOut, fail("failed to create system server cert issued after flag day"));
+ require_action(system_server_after_with_CT = SecCertificateCreateFromResource(@"enforcement_system_server_after_scts"),
+ errOut, fail("failed to create system server cert issued after flag day with SCTs"));
+
+ anchors = @[ (__bridge id)system_root ];
+ require_noerr_action(SecTrustCreateWithCertificates(system_server_after, policy, &trust), errOut, fail("failed to create trust"));
+ require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), errOut, fail("failed to set anchors"));
+ require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date"));
+ require_noerr_action(SecTrustSetTrustedLogs(trust, trustedLogs), errOut, fail("failed to set trusted logs")); // set trusted logs to trigger enforcing behavior
+
+ /* set exception on leaf cert without CT */
+ leafHash = CFBridgingRelease(SecCertificateCopySubjectPublicKeyInfoSHA256Digest(system_server_after));
+ leafException = @{ (__bridge NSString*)kSecCTExceptionsHashAlgorithmKey : @"sha256",
+ (__bridge NSString*)kSecCTExceptionsSPKIHashKey : leafHash,
+ };
+ exceptions = @{ (__bridge NSString*)kSecCTExceptionsCAsKey : @[ leafException ] };
+ ok(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)exceptions, &error),
+ "failed to set exceptions: %@", error);
+ is(SecTrustEvaluateWithError(trust, &error), true, "leaf public key exception did not apply");
+
+ /* set exception on leaf cert with CT */
+ leafHash = CFBridgingRelease(SecCertificateCopySubjectPublicKeyInfoSHA256Digest(system_server_after_with_CT));
+ leafException = @{ (__bridge NSString*)kSecCTExceptionsHashAlgorithmKey : @"sha256",
+ (__bridge NSString*)kSecCTExceptionsSPKIHashKey : leafHash,
+ };
+ exceptions = @{ (__bridge NSString*)kSecCTExceptionsCAsKey : @[ leafException ] };
+ ok(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)exceptions, &error),
+ "failed to set exceptions: %@", error);
+ SecTrustSetNeedsEvaluation(trust);
+ evalTrustExpectingError(errSecVerifyActionFailed, "leaf cert with no public key exceptions succeeded");
+
+ /* matching public key with CT succeeds */
+ CFReleaseNull(trust);
+ require_noerr_action(SecTrustCreateWithCertificates(system_server_after_with_CT, policy, &trust), errOut, fail("failed to create trust"));
+ require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), errOut, fail("failed to set anchors"));
+ require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date"));
+ require_noerr_action(SecTrustSetTrustedLogs(trust, trustedLogs), errOut, fail("failed to set trusted logs")); // set trusted logs to trigger enforcing behavior
+ is(SecTrustEvaluateWithError(trust, &error), true, "ct cert should always pass");
+
+ ok(SecTrustStoreSetCTExceptions(NULL, NULL, &error), "failed to reset exceptions: %@", error);
+
+errOut:
+ CFReleaseNull(system_root);
+ CFReleaseNull(system_server_after);
+ CFReleaseNull(system_server_after_with_CT);
+ CFReleaseNull(trustedLogs);
+ CFReleaseNull(trust);
+ CFReleaseNull(policy);
+ CFReleaseNull(error);
+}
+
+static void test_ct_unconstrained_ca_exceptions(void) {
+ SecCertificateRef root = NULL, subca = NULL;
+ SecCertificateRef server_matching = NULL, server_matching_with_CT = NULL, server_partial = NULL, server_no_match = NULL, server_no_org = NULL;
+ CFArrayRef trustedLogs = CTTestsCopyTrustedLogs();
+ SecTrustRef trust = NULL;
+ SecPolicyRef policy = SecPolicyCreateSSL(true, CFSTR("ct.test.apple.com"));
+ NSArray *anchors = nil, *certs = nil;
+ NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:562340800.0]; // October 27, 2018 at 6:46:40 AM PDT
+ CFErrorRef error = nil;
+ NSDictionary *caException = nil, *exceptions = nil;
+ NSData *caHash = nil;
+
+ require_action(root = SecCertificateCreateFromResource(@"enforcement_system_root"),
+ errOut, fail("failed to create system root"));
+ require_action(subca = SecCertificateCreateFromResource(@"enforcement_system_unconstrained_subca"),
+ errOut, fail("failed to create subca"));
+ require_action(server_matching = SecCertificateCreateFromResource(@"enforcement_system_server_matching_orgs"),
+ errOut, fail("failed to create server cert with matching orgs"));
+ require_action(server_matching_with_CT = SecCertificateCreateFromResource(@"enforcement_system_server_matching_orgs_scts"),
+ errOut, fail("failed to create server cert with matching orgs and scts"));
+ require_action(server_partial = SecCertificateCreateFromResource(@"enforcement_system_server_partial_orgs"),
+ errOut, fail("failed to create server cert with partial orgs"));
+ require_action(server_no_match = SecCertificateCreateFromResource(@"enforcement_system_server_nonmatching_orgs"),
+ errOut, fail("failed to create server cert with non-matching orgs"));
+ require_action(server_no_org = SecCertificateCreateFromResource(@"enforcement_system_server_no_orgs"),
+ errOut, fail("failed to create server cert with no orgs"));
+
+ anchors = @[ (__bridge id)root ];
+
+#define createTrust(certs) \
+ CFReleaseNull(trust); \
+ require_noerr_action(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trust), errOut, fail("failed to create trust")); \
+ require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), errOut, fail("failed to set anchors")); \
+ require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date")); \
+ require_noerr_action(SecTrustSetTrustedLogs(trust, trustedLogs), errOut, fail("failed to set trusted logs"));
+
+ /* Set exception on the subCA */
+ caHash = CFBridgingRelease(SecCertificateCopySubjectPublicKeyInfoSHA256Digest(subca));
+ caException = @{ (__bridge NSString*)kSecCTExceptionsHashAlgorithmKey : @"sha256",
+ (__bridge NSString*)kSecCTExceptionsSPKIHashKey : caHash,
+ };
+ exceptions = @{ (__bridge NSString*)kSecCTExceptionsCAsKey : @[ caException ] };
+ ok(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)exceptions, &error),
+ "failed to set exceptions: %@", error);
+
+ /* Verify that non-CT cert with Orgs matching subCA passes */
+ certs = @[ (__bridge id)server_matching, (__bridge id)subca];
+ createTrust(certs);
+ is(SecTrustEvaluateWithError(trust, &error), true, "matching org subca exception did not apply: %@", error);
+
+ /* Verify that CT cert with Orgs matching subCA passes */
+ certs = @[ (__bridge id)server_matching_with_CT, (__bridge id)subca];
+ createTrust(certs);
+ is(SecTrustEvaluateWithError(trust, &error), true, "CT matching org subca exception did not apply: %@", error);
+
+ /* Verify that non-CT cert with partial Org match fails */
+ certs = @[ (__bridge id)server_partial, (__bridge id)subca];
+ createTrust(certs);
+ evalTrustExpectingError(errSecVerifyActionFailed, "partial matching org leaf succeeded");
+
+ /* Verify that a non-CT cert with non-matching Org fails */
+ certs = @[ (__bridge id)server_no_match, (__bridge id)subca];
+ createTrust(certs);
+ evalTrustExpectingError(errSecVerifyActionFailed, "non-matching org leaf succeeded");
+
+ /* Verify that a non-CT cert with no Org fails */
+ certs = @[ (__bridge id)server_no_org, (__bridge id)subca];
+ createTrust(certs);
+ evalTrustExpectingError(errSecVerifyActionFailed, "no org leaf succeeded");
+
+ ok(SecTrustStoreSetCTExceptions(NULL, NULL, &error), "failed to reset exceptions: %@", error);
+
+#undef createTrust
+
+errOut:
+ CFReleaseNull(root);
+ CFReleaseNull(subca);
+ CFReleaseNull(server_matching);
+ CFReleaseNull(server_matching_with_CT);
+ CFReleaseNull(server_partial);
+ CFReleaseNull(server_no_match);
+ CFReleaseNull(server_no_org);
+ CFReleaseNull(trustedLogs);
+ CFReleaseNull(trust);
+ CFReleaseNull(policy);
+ CFReleaseNull(error);
+}
+
+static void test_ct_constrained_ca_exceptions(void) {
+ SecCertificateRef root = NULL, org_constrained_subca = NULL;
+ SecCertificateRef constraint_pass_server = NULL, constraint_pass_server_ct = NULL, constraint_fail_server = NULL;
+ SecCertificateRef dn_constrained_subca = NULL, dn_constrained_server = NULL, dn_constrained_server_mismatch = NULL;
+ SecCertificateRef dns_constrained_subca = NULL, dns_constrained_server = NULL, dns_constrained_server_mismatch = NULL;
+ CFArrayRef trustedLogs = CTTestsCopyTrustedLogs();
+ SecTrustRef trust = NULL;
+ SecPolicyRef policy = SecPolicyCreateSSL(true, CFSTR("ct.test.apple.com"));
+ NSArray *anchors = nil, *certs = nil;
+ NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:562340800.0]; // October 27, 2018 at 6:46:40 AM PDT
+ CFErrorRef error = nil;
+ NSDictionary *caException = nil, *exceptions = nil;
+ NSMutableArray *caExceptions = [NSMutableArray array];
+ NSData *caHash = nil;
+
+ require_action(root = SecCertificateCreateFromResource(@"enforcement_system_root"),
+ errOut, fail("failed to create system root"));
+ require_action(org_constrained_subca = SecCertificateCreateFromResource(@"enforcement_system_constrained_subca"),
+ errOut, fail("failed to create org-constrained subca"));
+ require_action(constraint_pass_server = SecCertificateCreateFromResource(@"enforcement_system_constrained_server"),
+ errOut, fail("failed to create constrained non-CT leaf"));
+ require_action(constraint_pass_server_ct = SecCertificateCreateFromResource(@"enforcement_system_constrained_server_scts"),
+ errOut, fail("failed to create constrained CT leaf"));
+ require_action(constraint_fail_server= SecCertificateCreateFromResource(@"enforcement_system_constrained_fail_server"),
+ errOut, fail("failed to create constraint failure leaf"));
+ require_action(dn_constrained_subca = SecCertificateCreateFromResource(@"enforcement_system_constrained_no_org_subca"),
+ errOut, fail("failed to create dn-constrained subca"));
+ require_action(dn_constrained_server = SecCertificateCreateFromResource(@"enforcement_system_constrained_no_org_server"),
+ errOut, fail("failed to create dn-constrained leaf"));
+ require_action(dn_constrained_server_mismatch = SecCertificateCreateFromResource(@"enforcement_system_constrained_no_org_server_mismatch"),
+ errOut, fail("failed to create dn-constrained leaf with mismatched orgs"));
+ require_action(dns_constrained_subca = SecCertificateCreateFromResource(@"enforcement_system_constrained_no_dn_subca"),
+ errOut, fail("failed to create dns-constrained subca"));
+ require_action(dns_constrained_server = SecCertificateCreateFromResource(@"enforcement_system_constrained_no_dn_server"),
+ errOut, fail("failed to create dns-constrained leaf"));
+ require_action(dns_constrained_server_mismatch = SecCertificateCreateFromResource(@"enforcement_system_constrained_no_dn_server_mismatch"),
+ errOut, fail("failed to create dns-constrained leaf with mismatched orgs"));
+
+ anchors = @[ (__bridge id)root ];
+
+ /* Set exception on the subCAs */
+ caHash = CFBridgingRelease(SecCertificateCopySubjectPublicKeyInfoSHA256Digest(org_constrained_subca));
+ caException = @{ (__bridge NSString*)kSecCTExceptionsHashAlgorithmKey : @"sha256",
+ (__bridge NSString*)kSecCTExceptionsSPKIHashKey : caHash,
+ };
+ [caExceptions addObject:caException];
+
+ caHash = CFBridgingRelease(SecCertificateCopySubjectPublicKeyInfoSHA256Digest(dn_constrained_subca));
+ caException = @{ (__bridge NSString*)kSecCTExceptionsHashAlgorithmKey : @"sha256",
+ (__bridge NSString*)kSecCTExceptionsSPKIHashKey : caHash,
+ };
+ [caExceptions addObject:caException];
+
+ caHash = CFBridgingRelease(SecCertificateCopySubjectPublicKeyInfoSHA256Digest(dns_constrained_subca));
+ caException = @{ (__bridge NSString*)kSecCTExceptionsHashAlgorithmKey : @"sha256",
+ (__bridge NSString*)kSecCTExceptionsSPKIHashKey : caHash,
+ };
+ [caExceptions addObject:caException];
+ exceptions = @{ (__bridge NSString*)kSecCTExceptionsCAsKey : caExceptions };
+ ok(SecTrustStoreSetCTExceptions(NULL, (__bridge CFDictionaryRef)exceptions, &error),
+ "failed to set exceptions: %@", error);
+
+#define createTrust(certs) \
+ CFReleaseNull(trust); \
+ require_noerr_action(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trust), errOut, fail("failed to create trust")); \
+ require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), errOut, fail("failed to set anchors")); \
+ require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date")); \
+ require_noerr_action(SecTrustSetTrustedLogs(trust, trustedLogs), errOut, fail("failed to set trusted logs"));
+
+ /* Verify org-constrained non-CT leaf passes */
+ certs = @[ (__bridge id)constraint_pass_server, (__bridge id)org_constrained_subca ];
+ createTrust(certs);
+ is(SecTrustEvaluateWithError(trust, &error), true, "org constrained exception did not apply: %@", error);
+
+ /* Verify org-constrained CT leaf passes */
+ certs = @[ (__bridge id)constraint_pass_server_ct, (__bridge id)org_constrained_subca ];
+ createTrust(certs);
+ is(SecTrustEvaluateWithError(trust, &error), true, "org constrained exception did not apply: %@", error);
+
+ /* Verify org-constrained non-CT leaf with wrong org fails */
+ certs = @[ (__bridge id)constraint_fail_server, (__bridge id)org_constrained_subca ];
+ createTrust(certs);
+ evalTrustExpectingError(errSecInvalidName, "leaf failing name constraints succeeded");
+
+ /* Verify dn-constrained (but not with org) non-CT leaf with matching orgs succeeds */
+ certs = @[ (__bridge id)dn_constrained_server, (__bridge id)dn_constrained_subca ];
+ createTrust(certs);
+ is(SecTrustEvaluateWithError(trust, &error), true, "org match exception did not apply: %@", error);
+
+ /* Verify dn-constrained (but not with org) non-CT leaf without matching orgs fails */
+ certs = @[ (__bridge id)dn_constrained_server_mismatch, (__bridge id)dn_constrained_subca ];
+ createTrust(certs);
+ evalTrustExpectingError(errSecVerifyActionFailed, "dn name constraints with no org succeeded");
+
+ /* Verify dns-constrained (no DN constraints) non-CT leaf with matching orgs succeeds */
+ certs = @[ (__bridge id)dns_constrained_server, (__bridge id)dns_constrained_subca ];
+ createTrust(certs);
+ is(SecTrustEvaluateWithError(trust, &error), true, "org match exception did not apply: %@", error);
+
+ /* Verify dns-constrained (no DN constraints) non-CT leaf without matching orgs fails*/
+ certs = @[ (__bridge id)dns_constrained_server_mismatch, (__bridge id)dns_constrained_subca ];
+ createTrust(certs);
+ evalTrustExpectingError(errSecVerifyActionFailed, "dns name constraints with no DN constraint succeeded");
+
+ ok(SecTrustStoreSetCTExceptions(NULL, NULL, &error), "failed to reset exceptions: %@", error);
+
+#undef createTrust
+
+errOut:
+ CFReleaseNull(root);
+ CFReleaseNull(org_constrained_subca);
+ CFReleaseNull(constraint_pass_server);
+ CFReleaseNull(constraint_pass_server_ct);
+ CFReleaseNull(constraint_fail_server);
+ CFReleaseNull(dn_constrained_subca);
+ CFReleaseNull(dn_constrained_server);
+ CFReleaseNull(dn_constrained_server_mismatch);
+ CFReleaseNull(dns_constrained_subca);
+ CFReleaseNull(dns_constrained_server);
+ CFReleaseNull(dns_constrained_server_mismatch);
+ CFReleaseNull(trustedLogs);
+ CFReleaseNull(trust);
+ CFReleaseNull(policy);
+ CFReleaseNull(error);
+}
+
+static void test_ct_key_exceptions(void) {
+ test_ct_leaf_exceptions();
+ test_ct_unconstrained_ca_exceptions();
+ test_ct_constrained_ca_exceptions();
+}
+
+static void test_ct_exceptions(void) {
+ test_ct_domain_exceptions();
+ test_ct_key_exceptions();
+}
int si_82_sectrust_ct(int argc, char *const *argv)
{
- plan_tests(268);
+ plan_tests(432);
tests();
+ test_sct_serialization();
+ testSetCTExceptions();
+ test_enforcement();
+ test_apple_enforcement_exceptions();
+ test_google_enforcement_exception();
+ test_precerts_fail();
+ test_ct_exceptions();
return 0;
}
<dict>
<key>application-identifier</key>
<string>com.apple.trustd</string>
+ <key>com.apple.application-identifier</key>
+ <string>com.apple.trustd</string>
<key>com.apple.private.necp.match</key>
<true/>
<key>com.apple.private.network.socket-delegate</key>
.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) {
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) {
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) {
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);
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;
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) {
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);
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;
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 = {
.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) {
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;
}
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);
}
}
}
_SecDERItemCopyOIDDecimalRepresentation
_SecDigestCreate
-#if TARGET_OS_IPHONE
_SecFrameworkCopyResourceContents
_SecFrameworkCopyResourceURL
-#endif
_SecCopyErrorMessageString
_SecPKCS12Import
_SecRandomCopyBytes
-#if TARGET_OS_IPHONE
_SecSHA1DigestCreate
-#endif
_SecTaskCopySigningIdentifier
_SecTaskCopyValueForEntitlement
_SecTaskCopyValuesForEntitlements
#endif
// SecFramework.h
-#if TARGET_OS_IPHONE
_SecOSStatusWith
_SecSHA256DigestCreate
_SecSHA256DigestCreateFromData
-#endif
-#if TARGET_OS_OSX
-_SecSHA256DigestCreate
-_SecSHA256DigestCreateFromData
-#endif
_secLogObjForScope
_secLogObjForCFScope
D465131A2097FF2E005D93FE /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6CF4A0EB1E4549F300ECD7B5 /* Main.storyboard */; };
D465131B2097FF2E005D93FE /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6CF4A0EE1E4549F300ECD7B5 /* Assets.xcassets */; };
D465131C2097FF2E005D93FE /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6CF4A0F01E4549F300ECD7B5 /* LaunchScreen.storyboard */; };
+ D46A6C09215336BC008ABF6A /* SecFramework.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C0B906C0ACCBD240077CD03 /* SecFramework.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ D46B37A62151B7950083DAAA /* SecTrustStoreServer.m in Sources */ = {isa = PBXBuildFile; fileRef = D46B379F2151B6E50083DAAA /* SecTrustStoreServer.m */; };
D479F6E21F980FAB00388D28 /* Trust.strings in Resources */ = {isa = PBXBuildFile; fileRef = D479F6DF1F980F8F00388D28 /* Trust.strings */; };
D479F6E31F981FD600388D28 /* OID.strings in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4C198F1F0ACDB4BF00AAB142 /* OID.strings */; };
D479F6E41F981FD600388D28 /* Certificate.strings in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4C198F1D0ACDB4BF00AAB142 /* Certificate.strings */; };
D47CA65D1EB036450038E2BB /* libMobileGestalt.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = D47CA65C1EB036450038E2BB /* libMobileGestalt.dylib */; };
D47E69401E92F75D002C8CF6 /* si-61-pkcs12.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DD91D8085FC00865A7C /* si-61-pkcs12.c */; };
D47F514C1C3B812500A7CEFE /* SecCFAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = D47F514B1C3B812500A7CEFE /* SecCFAllocator.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ D484A1072167D707008653A9 /* ct_exceptions.m in Sources */ = {isa = PBXBuildFile; fileRef = D484A1012167D6F8008653A9 /* ct_exceptions.m */; };
D487B9821DFA28DB000410A1 /* SecInternalReleasePriv.h in Headers */ = {isa = PBXBuildFile; fileRef = DC0BCC771D8C68CF00070CB0 /* SecInternalReleasePriv.h */; settings = {ATTRIBUTES = (Private, ); }; };
D487B9881DFA2902000410A1 /* SecInternalReleasePriv.h in Headers */ = {isa = PBXBuildFile; fileRef = DC0BCC771D8C68CF00070CB0 /* SecInternalReleasePriv.h */; settings = {ATTRIBUTES = (Private, ); }; };
D487FBB81DB8357300D4BB0B /* si-29-sectrust-sha1-deprecation.m in Sources */ = {isa = PBXBuildFile; fileRef = D487FBB71DB8357300D4BB0B /* si-29-sectrust-sha1-deprecation.m */; };
4C4296300BB0A68200491999 /* SecTrustSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTrustSettings.h; path = trust/SecTrustSettings.h; sourceTree = "<group>"; };
4C465C7D13AFD82300E841AC /* SecurityDevTests-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "SecurityDevTests-Info.plist"; sourceTree = "<group>"; };
4C47FA8D20A51DC700384CB6 /* AppleFSCompression.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppleFSCompression.framework; path = System/Library/PrivateFrameworks/AppleFSCompression.framework; sourceTree = SDKROOT; };
- 4C4CB7100DDA44900026B660 /* entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = entitlements.plist; sourceTree = "<group>"; };
+ 4C4CB7100DDA44900026B660 /* entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = entitlements.plist; path = SecurityTool/entitlements.plist; sourceTree = SOURCE_ROOT; };
4C4CE9070AF81ED80056B01D /* TODO */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = TODO; sourceTree = "<group>"; };
4C4CE9120AF81F0E0056B01D /* README */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
4C50ACFC1410671D00EE92DE /* DigiNotarCA2007RootCertificate.crt */ = {isa = PBXFileReference; lastKnownFileType = file; path = DigiNotarCA2007RootCertificate.crt; sourceTree = "<group>"; };
D43DBEFA1E99D17300C04AEA /* SecTrustStoreServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTrustStoreServer.h; path = OSX/sec/securityd/SecTrustStoreServer.h; sourceTree = "<group>"; };
D43DDE511F620F09009742A5 /* SecPolicyChecks.list */ = {isa = PBXFileReference; lastKnownFileType = text; path = SecPolicyChecks.list; sourceTree = "<group>"; };
D43DDE581F638061009742A5 /* SecPolicy.list */ = {isa = PBXFileReference; lastKnownFileType = text; path = SecPolicy.list; sourceTree = "<group>"; };
+ D442AD62215ADA250050B50F /* AppleCorporateRootCA2.cer */ = {isa = PBXFileReference; lastKnownFileType = file; name = AppleCorporateRootCA2.cer; path = OSX/trustd/iOS/AppleCorporateRootCA2.cer; sourceTree = "<group>"; };
+ D442AD68215ADA250050B50F /* AppleCorporateRootCA.cer */ = {isa = PBXFileReference; lastKnownFileType = file; name = AppleCorporateRootCA.cer; path = OSX/trustd/iOS/AppleCorporateRootCA.cer; sourceTree = "<group>"; };
D44D08B420AB890E0023C439 /* Security.apinotes */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Security.apinotes; path = base/Security.apinotes; sourceTree = "<group>"; };
D45068681E948A9E00FA7675 /* entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = entitlements.plist; path = OSX/trustd/macOS/entitlements.plist; sourceTree = "<group>"; };
D45068691E948ACE00FA7675 /* entitlements.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = entitlements.plist; path = OSX/trustd/iOS/entitlements.plist; sourceTree = "<group>"; };
D46246C31F9AEA5200D63882 /* libDER.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libDER.a; path = usr/local/lib/security_libDER/libDER.a; sourceTree = SDKROOT; };
D46246CE1F9AEAE300D63882 /* libDER.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libDER.a; path = usr/local/lib/security_libDER/libDER.a; sourceTree = SDKROOT; };
D46513072097954B005D93FE /* si-23-sectrust-ocsp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "si-23-sectrust-ocsp.h"; sourceTree = "<group>"; };
+ D46A6BF121531F77008ABF6A /* si-82-sectrust-ct.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "si-82-sectrust-ct.h"; path = "OSX/shared_regressions/si-82-sectrust-ct.h"; sourceTree = SOURCE_ROOT; };
+ D46B379F2151B6E50083DAAA /* SecTrustStoreServer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SecTrustStoreServer.m; path = OSX/sec/securityd/SecTrustStoreServer.m; sourceTree = "<group>"; };
D479F6E01F980F8F00388D28 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/Trust.strings; sourceTree = "<group>"; };
D47C56AB1DCA831C00E18518 /* lib_ios_x64.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = lib_ios_x64.xcconfig; path = xcconfig/lib_ios_x64.xcconfig; sourceTree = "<group>"; };
D47C56AF1DCA841D00E18518 /* lib_ios_x64_shim.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = lib_ios_x64_shim.xcconfig; path = xcconfig/lib_ios_x64_shim.xcconfig; sourceTree = "<group>"; };
D47C56FB1DCA8F4900E18518 /* all_arches.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = all_arches.xcconfig; path = xcconfig/all_arches.xcconfig; sourceTree = "<group>"; };
D47CA65C1EB036450038E2BB /* libMobileGestalt.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libMobileGestalt.dylib; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS11.0.Internal.sdk/usr/lib/libMobileGestalt.dylib; sourceTree = DEVELOPER_DIR; };
D47F514B1C3B812500A7CEFE /* SecCFAllocator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecCFAllocator.h; sourceTree = "<group>"; };
+ D484A1012167D6F8008653A9 /* ct_exceptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ct_exceptions.m; sourceTree = "<group>"; };
D487FBB71DB8357300D4BB0B /* si-29-sectrust-sha1-deprecation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "si-29-sectrust-sha1-deprecation.m"; sourceTree = "<group>"; };
D487FBB91DB835B500D4BB0B /* si-29-sectrust-sha1-deprecation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "si-29-sectrust-sha1-deprecation.h"; sourceTree = "<group>"; };
D48BD193206C47530075DDC9 /* si-35-cms-expiration-time.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "si-35-cms-expiration-time.m"; sourceTree = "<group>"; };
DC52EA4C1D80CB7000B0A59C /* libSecurityTool.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libSecurityTool.a; sourceTree = BUILT_PRODUCTS_DIR; };
DC52EA8E1D80CC2A00B0A59C /* builtin_commands.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = builtin_commands.h; sourceTree = "<group>"; };
DC52EA8F1D80CC2A00B0A59C /* digest_calc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = digest_calc.c; sourceTree = "<group>"; };
- DC52EA901D80CC2A00B0A59C /* entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = entitlements.plist; sourceTree = "<group>"; };
+ DC52EA901D80CC2A00B0A59C /* entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = entitlements.plist; path = OSX/sec/SecurityTool/entitlements.plist; sourceTree = SOURCE_ROOT; };
DC52EA911D80CC2A00B0A59C /* whoami.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = whoami.m; sourceTree = "<group>"; };
DC52EA921D80CC2A00B0A59C /* syncbubble.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = syncbubble.m; sourceTree = "<group>"; };
DC52EA931D80CC2A00B0A59C /* leaks.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = leaks.c; sourceTree = "<group>"; };
isa = PBXGroup;
children = (
DCE4E6A71D7A38C000AFB96E /* security2.1 */,
+ DC52EA901D80CC2A00B0A59C /* entitlements.plist */,
E78A9AD81D34959200006B5B /* NSFileHandle+Formatting.h */,
E78A9AD91D34959200006B5B /* NSFileHandle+Formatting.m */,
- 4C4CB7100DDA44900026B660 /* entitlements.plist */,
E7104A0B169E171900DB0045 /* security_tool_commands.c */,
D453C47F1FFD857400DE349B /* security_tool_commands.h */,
E7FEFB80169E26E200E18152 /* sub_commands.h */,
DC52EA9B1D80CC2A00B0A59C /* SecurityTool iOS */ = {
isa = PBXGroup;
children = (
+ 4C4CB7100DDA44900026B660 /* entitlements.plist */,
DCC78E211D8085FC00865A7C /* keychain_backup.c */,
DC52EA8E1D80CC2A00B0A59C /* builtin_commands.h */,
DC52EA8F1D80CC2A00B0A59C /* digest_calc.c */,
- DC52EA901D80CC2A00B0A59C /* entitlements.plist */,
DC52EA911D80CC2A00B0A59C /* whoami.m */,
EB48C19E1E573EDC00EC5E57 /* sos.m */,
DC52EA921D80CC2A00B0A59C /* syncbubble.m */,
DCC78E021D8085FC00865A7C /* si-80-empty-data.c */,
DCC78E031D8085FC00865A7C /* si-82-seccertificate-ct.c */,
DCC78E041D8085FC00865A7C /* si-82-sectrust-ct.m */,
+ D46A6BF121531F77008ABF6A /* si-82-sectrust-ct.h */,
DCC78E051D8085FC00865A7C /* si-82-token-ag.c */,
DCC78E061D8085FC00865A7C /* si-83-seccertificate-sighashalg.c */,
BE6215BD1DB6E69100961E15 /* si-84-sectrust-allowlist.m */,
DCC78E251D8085FC00865A7C /* show_certificates.c */,
D453C38A1FEC669300DE349B /* trust_update.m */,
DCC78E261D8085FC00865A7C /* spc.c */,
+ D484A1012167D6F8008653A9 /* ct_exceptions.m */,
);
name = Security/Tool;
path = OSX/sec/Security/Tool;
D43DBEF71E99D17300C04AEA /* SecTrustServer.c */,
D43DBEF81E99D17300C04AEA /* SecTrustServer.h */,
D43DBEF91E99D17300C04AEA /* SecTrustStoreServer.c */,
+ D46B379F2151B6E50083DAAA /* SecTrustStoreServer.m */,
D43DBEFA1E99D17300C04AEA /* SecTrustStoreServer.h */,
D4961BBD2079423300F16DA7 /* TrustURLSessionDelegate.m */,
D4961BC52079426000F16DA7 /* TrustURLSessionDelegate.h */,
DCE4E85D1D7A584D00AFB96E /* iOS */ = {
isa = PBXGroup;
children = (
+ D442AD68215ADA250050B50F /* AppleCorporateRootCA.cer */,
+ D442AD62215ADA250050B50F /* AppleCorporateRootCA2.cer */,
D41257EE1E941DA800781F23 /* com.apple.trustd.plist */,
D45068691E948ACE00FA7675 /* entitlements.plist */,
);
EB10A3FC2035789B00E84270 /* OTConstants.h in Headers */,
DC1787591D7790B600B50D50 /* CMSPrivate.h in Headers */,
DC1785881D778B8000B50D50 /* CSCommon.h in Headers */,
+ D46A6C09215336BC008ABF6A /* SecFramework.h in Headers */,
DC17874E1D7790A500B50D50 /* CSCommonPriv.h in Headers */,
DC1785A51D778D0D00B50D50 /* CipherSuite.h in Headers */,
DC1785871D778B8000B50D50 /* CodeSigning.h in Headers */,
D41257CB1E9410A300781F23 /* Sources */,
D41257CC1E9410A300781F23 /* Frameworks */,
D41257CD1E9410A300781F23 /* Copy LaunchDaemon */,
+ D442AD70215C39100050B50F /* Install Apple Corporate Roots */,
);
buildRules = (
);
);
runOnlyForDeploymentPostprocessing = 1;
shellPath = /bin/sh;
- shellScript = "PLIST_FILE_NAME=com.apple.security.cloudkeychainproxy3\nFILE_TO_COPY=${PROJECT_DIR}/KVSKeychainSyncingProxy/${PLIST_FILE_NAME}.ios.plist\n\nif [ ${PLATFORM_NAME} = \"macosx\" ]\nthen\nFILE_TO_COPY=${PROJECT_DIR}/KVSKeychainSyncingProxy/${PLIST_FILE_NAME}.osx.plist\nfi\n\ncp ${FILE_TO_COPY} ${INSTALL_ROOT}/${INSTALL_DAEMON_AGENT_DIR}/${PLIST_FILE_NAME}.plist";
+ shellScript = "PLIST_FILE_NAME=com.apple.security.cloudkeychainproxy3\nFILE_TO_COPY=${PROJECT_DIR}/KVSKeychainSyncingProxy/${PLIST_FILE_NAME}.ios.plist\n\nif [ ${PLATFORM_NAME} = \"macosx\" ]\nthen\nFILE_TO_COPY=${PROJECT_DIR}/KVSKeychainSyncingProxy/${PLIST_FILE_NAME}.osx.plist\nfi\n\ncp ${FILE_TO_COPY} ${INSTALL_ROOT}/${INSTALL_DAEMON_AGENT_DIR}/${PLIST_FILE_NAME}.plist\n";
+ };
+ D442AD70215C39100050B50F /* Install Apple Corporate Roots */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputFileListPaths = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/OSX/trustd/iOS/AppleCorporateRootCA.cer",
+ "$(SRCROOT)/OSX/trustd/iOS/AppleCorporateRootCA2.cer",
+ );
+ name = "Install Apple Corporate Roots";
+ outputFileListPaths = (
+ );
+ outputPaths = (
+ "$(DSTROOT)/AppleInternal/Library/Security/AppleCorporateRootCA.cer",
+ "$(DSTROOT)/AppleInternal/Library/Security/AppleCorporateRootCA2.cer",
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "ditto ${SRCROOT}/OSX/trustd/iOS/AppleCorporateRootCA.cer ${DSTROOT}/AppleInternal/Library/Security/\nditto ${SRCROOT}/OSX/trustd/iOS/AppleCorporateRootCA2.cer ${DSTROOT}/AppleInternal/Library/Security/\nchown -R root:wheel ${DSTROOT}/AppleInternal/Library/Security/\n";
};
D4C263C41F8FEAA8001317EA /* Run Script Generate Error Strings */ = {
isa = PBXShellScriptBuildPhase;
D43DBF071E99D1CA00C04AEA /* SecPinningDb.m in Sources */,
D43DBF081E99D1CA00C04AEA /* SecPolicyServer.c in Sources */,
D43DBF091E99D1CA00C04AEA /* SecRevocationDb.c in Sources */,
+ D46B37A62151B7950083DAAA /* SecTrustStoreServer.m in Sources */,
D43DBF0A1E99D1CA00C04AEA /* SecRevocationServer.c in Sources */,
D43DBF0B1E99D1CA00C04AEA /* SecTrustLoggingServer.m in Sources */,
D4961BC42079424200F16DA7 /* TrustURLSessionDelegate.m in Sources */,
DC52EC191D80CF4C00B0A59C /* keychain_find.m in Sources */,
DC52EC181D80CF4700B0A59C /* log_control.c in Sources */,
DC52EC171D80CF4200B0A59C /* pkcs12_util.c in Sources */,
+ D484A1072167D707008653A9 /* ct_exceptions.m in Sources */,
DC52EC161D80CF3B00B0A59C /* scep.c in Sources */,
DC52EC151D80CF0B00B0A59C /* show_certificates.c in Sources */,
DC52EC141D80CF0500B0A59C /* spc.c in Sources */,
COMBINE_HIDPI_IMAGES = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
GCC_DYNAMIC_NO_PIC = NO;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "NO_SERVER=1",
+ "FAKE_KEYSTORE=1",
+ "$(inherited)",
+ );
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
INFOPLIST_FILE = tests/secdmockaks/Info.plist;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
ENABLE_NS_ASSERTIONS = NO;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "NO_SERVER=1",
+ "FAKE_KEYSTORE=1",
+ "$(inherited)",
+ );
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
INFOPLIST_FILE = tests/secdmockaks/Info.plist;
/* Queue limits: these should likely be configurable via plist */
#define SecCKKSOutgoingQueueItemsAtOnce 100
-#define SecCKKSIncomingQueueItemsAtOnce 10
+#define SecCKKSIncomingQueueItemsAtOnce 50
// Utility functions
NSString* SecCKKSHostOSVersion(void);
if(listener && !alreadyRegisteredListener) {
NSString* queueName = [NSString stringWithFormat: @"ck-account-state-%@", listener];
- dispatch_queue_t objQueue = dispatch_queue_create([queueName UTF8String], DISPATCH_QUEUE_SERIAL);
+ dispatch_queue_t objQueue = dispatch_queue_create([queueName UTF8String], DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
[self.changeListeners setObject: listener forKey: objQueue];
secinfo("ckksaccount", "adding a new listener: %@", listener);
dispatch_sync(self.queue, ^{
self.firstCKAccountFetch = true;
+ secnotice("ckksaccount", "received CK Account info: %@", ckAccountInfo);
[self _onqueueUpdateAccountState:ckAccountInfo circle:self.currentCircleStatus deliveredSemaphore:finishedSema];
});
}];
return;
}
- if(![self.currentCKAccountInfo isEqual: ckAccountInfo]) {
+ if((self.currentCKAccountInfo == nil && ckAccountInfo != nil) ||
+ ![self.currentCKAccountInfo isEqual: ckAccountInfo]) {
secnotice("ckksaccount", "moving to CK Account info: %@", ckAccountInfo);
self.currentCKAccountInfo = ckAccountInfo;
[self _onqueueUpdateCKDeviceID: ckAccountInfo];
}
- if(self.currentCircleStatus.status != sosstatus.status) {
+ if(![self.currentCircleStatus isEqual:sosstatus]) {
secnotice("ckksaccount", "moving to circle status: %@", sosstatus);
self.currentCircleStatus = sosstatus;
if (sosstatus.status == kSOSCCInCircle) {
return self;
}
+- (BOOL)isEqual:(id)object
+{
+ if(![object isKindOfClass:[SOSAccountStatus class]]) {
+ return NO;
+ }
+
+ if(object == nil) {
+ return NO;
+ }
+
+ SOSAccountStatus* obj = (SOSAccountStatus*) object;
+ return self.status == obj.status &&
+ ((self.error == nil && obj.error == nil) || [self.error isEqual:obj.error]);
+}
+
- (NSString*)description
{
return [NSString stringWithFormat:@"<SOSStatus: %@ (%@)>", SOSCCGetStatusDescription(self.status), self.error];
- (void)rpcStatus:(NSString* _Nullable)viewName
reply:(void (^)(NSArray<NSDictionary*>* _Nullable result, NSError* _Nullable error))reply;
+- (void)rpcFastStatus:(NSString* _Nullable)viewName
+ reply:(void (^)(NSArray<NSDictionary*>* _Nullable result, NSError* _Nullable error))reply;
- (void)rpcResetLocal:(NSString* _Nullable)viewName reply:(void (^)(NSError* _Nullable error))reply;
- (void)rpcResetCloudKit:(NSString* _Nullable)viewName reply:(void (^)(NSError* _Nullable error))reply __deprecated_msg("use rpcResetCloudKit:reason:reply:");
- (void)rpcResetCloudKit:(NSString* _Nullable)viewName reason:(NSString *)reason reply:(void (^)(NSError* _Nullable error))reply;
}];
}
+- (void)rpcFastStatus:(NSString*)viewName reply:(void(^)(NSArray<NSDictionary*>* result, NSError* error)) reply {
+ [[self.connection remoteObjectProxyWithErrorHandler: ^(NSError* error) {
+ reply(nil, error);
+
+ }] rpcFastStatus:viewName reply:^(NSArray<NSDictionary*>* result, NSError* error){
+ reply(result, error);
+ }];
+}
+
+
- (void)rpcResetLocal:(NSString*)viewName reply:(void(^)(NSError* error))reply {
[[self.connection remoteObjectProxyWithErrorHandler:^(NSError* error) {
reply(error);
}
- (void)rpcTLKMissing:(NSString*)viewName reply:(void(^)(bool missing))reply {
- [self rpcStatus:viewName reply:^(NSArray<NSDictionary*>* results, NSError* blockError) {
+ [self rpcFastStatus:viewName reply:^(NSArray<NSDictionary*>* results, NSError* blockError) {
bool missing = false;
- // Until PCS fixes [<rdar://problem/35103941> PCS: Remove PCS's use of CKKSControlProtocol], we can't add things to the protocol
- // Use this hack
for(NSDictionary* result in results) {
NSString* name = result[@"view"];
NSString* keystate = result[@"keystate"];
}
- (void)rpcKnownBadState:(NSString* _Nullable)viewName reply:(void (^)(CKKSKnownBadState))reply {
- [self rpcStatus:viewName reply:^(NSArray<NSDictionary*>* results, NSError* blockError) {
+ [self rpcFastStatus:viewName reply:^(NSArray<NSDictionary*>* results, NSError* blockError) {
bool tlkMissing = false;
bool waitForUnlock = false;
CKKSKnownBadState response = CKKSKnownStatePossiblyGood;
- // We can now change this hack, but this change needs to be addition-only: <rdar://problem/36356681> CKKS: remove "global" hack from rpcStatus
- // Use this hack
for(NSDictionary* result in results) {
NSString* name = result[@"view"];
NSString* keystate = result[@"keystate"];
- (void)rpcResetCloudKit: (NSString*)viewName reason:(NSString *)reason reply: (void(^)(NSError* result)) reply;
- (void)rpcResync:(NSString*)viewName reply: (void(^)(NSError* result)) reply;
- (void)rpcResyncLocal:(NSString*)viewName reply:(void(^)(NSError* result))reply;
+/**
+ * Fetch status for the CKKS zones. If NULL is passed in a viewname, all zones are fetched.
+ */
- (void)rpcStatus:(NSString*)viewName reply: (void(^)(NSArray<NSDictionary*>* result, NSError* error)) reply;
+/**
+ * Same as rpcStatus:reply: but avoid expensive operations (and thus don't report them). fastStatus doesn't include global status.
+ */
+- (void)rpcFastStatus:(NSString*)viewName reply: (void(^)(NSArray<NSDictionary*>* result, NSError* error)) reply;
- (void)rpcFetchAndProcessChanges:(NSString*)viewName reply: (void(^)(NSError* result)) reply;
- (void)rpcFetchAndProcessClassAChanges:(NSString*)viewName reply: (void(^)(NSError* result)) reply;
- (void)rpcPushOutgoingChanges:(NSString*)viewName reply: (void(^)(NSError* result)) reply;
[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
_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:^{
}
};
+ __block bool errored = false;
[ckks dispatchSync: ^bool{
if(self.cancelled) {
ckksnotice("ckksincoming", ckks, "CKKSIncomingQueueOperation cancelled, quitting");
}
}
}
+ errored = !ok;
+ return ok;
+ }];
+
+ if(errored) {
+ ckksnotice("ckksincoming", ckks, "Early-exiting from IncomingQueueOperation");
+ return;
+ }
+
+ // Now for the tricky bit: take and drop the account queue for each batch of queue entries
+ // This is for peak memory concerns, but also to allow keychain API clients to make changes while we're processing many items
+ // Note that IncomingQueueOperations are no longer transactional: they can partially succeed. This might make them harder to reason about.
+ __block NSUInteger lastCount = SecCKKSIncomingQueueItemsAtOnce;
+ __block NSString* lastMaxUUID = nil;
- // Iterate through all incoming queue entries a chunk at a time (for peak memory concerns)
- NSArray<CKKSIncomingQueueEntry*> * queueEntries = nil;
- NSString* lastMaxUUID = nil;
- while(queueEntries == nil || queueEntries.count == SecCKKSIncomingQueueItemsAtOnce) {
+ while(lastCount == SecCKKSIncomingQueueItemsAtOnce) {
+ [ckks dispatchSync: ^bool{
+ NSArray<CKKSIncomingQueueEntry*> * queueEntries = nil;
if(self.cancelled) {
ckksnotice("ckksincoming", ckks, "CKKSIncomingQueueOperation cancelled, quitting");
+ errored = true;
return false;
}
+ NSError* error = nil;
+
queueEntries = [CKKSIncomingQueueEntry fetch: SecCKKSIncomingQueueItemsAtOnce
startingAtUUID:lastMaxUUID
state:SecCKKSStateNew
if(error != nil) {
ckkserror("ckksincoming", ckks, "Error fetching incoming queue records: %@", error);
self.error = error;
+ errored = true;
return false;
}
+ lastCount = queueEntries.count;
+
if([queueEntries count] == 0) {
// Nothing to do! exit.
ckksnotice("ckksincoming", ckks, "Nothing in incoming queue to process");
- break;
+ return true;
}
[CKKSPowerCollection CKKSPowerEvent:kCKKSPowerEventOutgoingQueue zone:ckks.zoneName count:[queueEntries count]];
if (![self processQueueEntries:queueEntries withManifest:ckks.latestManifest egoManifest:ckks.egoManifest]) {
ckksnotice("ckksincoming", ckks, "processQueueEntries didn't complete successfully");
+ errored = true;
return false;
}
for(CKKSIncomingQueueEntry* iqe in queueEntries) {
lastMaxUUID = ([lastMaxUUID compare:iqe.uuid] == NSOrderedDescending) ? lastMaxUUID : iqe.uuid;
};
+ return true;
+ }];
+
+ if(errored) {
+ ckksnotice("ckksincoming", ckks, "Early-exiting from IncomingQueueOperation");
+ return;
}
+ }
- // Process other queues: CKKSCurrentItemPointers
- ckksnotice("ckksincoming", ckks, "Processed %lu items in incoming queue (%lu errors)", (unsigned long)self.successfulItemsProcessed, (unsigned long)self.errorItemsProcessed);
+ ckksnotice("ckksincoming", ckks, "Processed %lu items in incoming queue (%lu errors)", (unsigned long)self.successfulItemsProcessed, (unsigned long)self.errorItemsProcessed);
+
+ [ckks dispatchSync: ^bool{
+ NSError* error = nil;
NSArray<CKKSCurrentItemPointer*>* newCIPs = [CKKSCurrentItemPointer remoteItemPointers:ckks.zoneID error:&error];
if(error || !newCIPs) {
[self.ckks processIncomingQueueAfterNextUnlock];
}
- return ok;
+ return true;
}];
}
@property NSHashTable<CKKSOutgoingQueueOperation*>* outgoingQueueOperations;
@property CKKSScanLocalItemsOperation* initialScanOperation;
-// Returns the current state of this view
+// Returns the current state of this view, fastStatus is the same, but as name promise, no expensive calculations
- (NSDictionary<NSString*, NSString*>*)status;
+- (NSDictionary<NSString*, NSString*>*)fastStatus;
@end
NS_ASSUME_NONNULL_END
- (NSDictionary*)status {
#define stringify(obj) CKKSNilToNSNull([obj description])
#define boolstr(obj) (!!(obj) ? @"yes" : @"no")
- __block NSDictionary* ret = nil;
+ __block NSMutableDictionary* ret = nil;
__block NSError* error = nil;
- CKKSManifest* manifest = [CKKSManifest latestTrustedManifestForZone:self.zoneName error:&error];
+ CKKSManifest* manifest = nil;
+
+ ret = [[self fastStatus] mutableCopy];
+
+ manifest = [CKKSManifest latestTrustedManifestForZone:self.zoneName error:&error];
[self dispatchSync: ^bool {
CKKSCurrentKeySet* keyset = [[CKKSCurrentKeySet alloc] initForZone:self.zoneID];
[mutTLKShares addObject: [obj description]];
}];
-
- ret = @{
- @"view": CKKSNilToNSNull(self.zoneName),
- @"ckaccountstatus": self.accountStatus == CKAccountStatusCouldNotDetermine ? @"could not determine" :
- self.accountStatus == CKAccountStatusAvailable ? @"logged in" :
- self.accountStatus == CKAccountStatusRestricted ? @"restricted" :
- self.accountStatus == CKAccountStatusNoAccount ? @"logged out" : @"unknown",
- @"lockstatetracker": stringify(self.lockStateTracker),
- @"accounttracker": stringify(self.accountTracker),
- @"fetcher": stringify(self.zoneChangeFetcher),
- @"zoneCreated": boolstr(self.zoneCreated),
- @"zoneCreatedError": stringify(self.zoneCreatedError),
- @"zoneSubscribed": boolstr(self.zoneSubscribed),
- @"zoneSubscribedError": stringify(self.zoneSubscribedError),
- @"zoneInitializeScheduler": stringify(self.initializeScheduler),
- @"keystate": CKKSNilToNSNull(self.keyHierarchyState),
- @"keyStateError": stringify(self.keyHierarchyError),
+ [ret addEntriesFromDictionary:@{
@"statusError": stringify(error),
@"oqe": CKKSNilToNSNull([CKKSOutgoingQueueEntry countsByStateInZone:self.zoneID error:&error]),
@"iqe": CKKSNilToNSNull([CKKSIncomingQueueEntry countsByStateInZone:self.zoneID error:&error]),
@"currentTLKPtr": CKKSNilToNSNull(keyset.currentTLKPointer.currentKeyUUID),
@"currentClassAPtr": CKKSNilToNSNull(keyset.currentClassAPointer.currentKeyUUID),
@"currentClassCPtr": CKKSNilToNSNull(keyset.currentClassCPointer.currentKeyUUID),
- @"currentManifestGen": CKKSNilToNSNull(manifestGeneration),
-
-
- @"zoneSetupOperation": stringify(self.zoneSetupOperation),
- @"keyStateOperation": stringify(self.keyStateMachineOperation),
- @"lastIncomingQueueOperation": stringify(self.lastIncomingQueueOperation),
- @"lastNewTLKOperation": stringify(self.lastNewTLKOperation),
- @"lastOutgoingQueueOperation": stringify(self.lastOutgoingQueueOperation),
- @"lastProcessReceivedKeysOperation": stringify(self.lastProcessReceivedKeysOperation),
- @"lastReencryptOutgoingItemsOperation":stringify(self.lastReencryptOutgoingItemsOperation),
- @"lastScanLocalItemsOperation": stringify(self.lastScanLocalItemsOperation),
- };
+ @"currentManifestGen": CKKSNilToNSNull(manifestGeneration),
+ }];
return false;
}];
return ret;
}
+- (NSDictionary*)fastStatus {
+
+ __block NSDictionary* ret = nil;
+
+ [self dispatchSync: ^bool {
+
+ ret = @{
+ @"view": CKKSNilToNSNull(self.zoneName),
+ @"ckaccountstatus": self.accountStatus == CKAccountStatusCouldNotDetermine ? @"could not determine" :
+ self.accountStatus == CKAccountStatusAvailable ? @"logged in" :
+ self.accountStatus == CKAccountStatusRestricted ? @"restricted" :
+ self.accountStatus == CKAccountStatusNoAccount ? @"logged out" : @"unknown",
+ @"lockstatetracker": stringify(self.lockStateTracker),
+ @"accounttracker": stringify(self.accountTracker),
+ @"fetcher": stringify(self.zoneChangeFetcher),
+ @"zoneCreated": boolstr(self.zoneCreated),
+ @"zoneCreatedError": stringify(self.zoneCreatedError),
+ @"zoneSubscribed": boolstr(self.zoneSubscribed),
+ @"zoneSubscribedError": stringify(self.zoneSubscribedError),
+ @"zoneInitializeScheduler": stringify(self.initializeScheduler),
+ @"keystate": CKKSNilToNSNull(self.keyHierarchyState),
+ @"keyStateError": stringify(self.keyHierarchyError),
+ @"statusError": [NSNull null],
+
+ @"zoneSetupOperation": stringify(self.zoneSetupOperation),
+ @"keyStateOperation": stringify(self.keyStateMachineOperation),
+ @"lastIncomingQueueOperation": stringify(self.lastIncomingQueueOperation),
+ @"lastNewTLKOperation": stringify(self.lastNewTLKOperation),
+ @"lastOutgoingQueueOperation": stringify(self.lastOutgoingQueueOperation),
+ @"lastProcessReceivedKeysOperation": stringify(self.lastProcessReceivedKeysOperation),
+ @"lastReencryptOutgoingItemsOperation":stringify(self.lastReencryptOutgoingItemsOperation),
+ @"lastScanLocalItemsOperation": stringify(self.lastScanLocalItemsOperation),
+ };
+ return false;
+ }];
+ return ret;
+}
#endif /* OCTAGON */
@end
- (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;
- (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, ^{
_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;
// 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) {
[op timeout:120*NSEC_PER_SEC];
}
-- (void)rpcStatus: (NSString*)viewName reply: (void(^)(NSArray<NSDictionary*>* result, NSError* error)) reply {
+- (void)rpcStatus: (NSString*)viewName
+ global:(bool)reportGlobal
+ reply:(void(^)(NSArray<NSDictionary*>* result, NSError* error)) reply
+ viewBlock:(NSDictionary * (^)(CKKSKeychainView* view))viewBlock
+{
NSMutableArray* a = [[NSMutableArray alloc] init];
// Now, query the views about their status
CKKSResultOperation* statusOp = [CKKSResultOperation named:@"status-rpc" withBlock:^{
__strong __typeof(self) strongSelf = weakSelf;
- // The first element is always the current global state (non-view-specific)
- NSError* selfPeersError = nil;
- CKKSSelves* selves = [strongSelf fetchSelfPeers:&selfPeersError];
- NSError* trustedPeersError = nil;
- NSSet<id<CKKSPeer>>* peers = [strongSelf fetchTrustedPeers:&trustedPeersError];
+ if (reportGlobal) {
+ // The first element is always the current global state (non-view-specific)
+ NSError* selfPeersError = nil;
+ CKKSSelves* selves = [strongSelf fetchSelfPeers:&selfPeersError];
+ NSError* trustedPeersError = nil;
+ NSSet<id<CKKSPeer>>* peers = [strongSelf fetchTrustedPeers:&trustedPeersError];
- // Get account state, even wait for it a little
- [self.accountTracker.ckdeviceIDInitialized wait:1*NSEC_PER_SEC];
- NSString *deviceID = self.accountTracker.ckdeviceID;
- NSError *deviceIDError = self.accountTracker.ckdeviceIDError;
+ // Get account state, even wait for it a little
+ [self.accountTracker.ckdeviceIDInitialized wait:1*NSEC_PER_SEC];
+ NSString *deviceID = self.accountTracker.ckdeviceID;
+ NSError *deviceIDError = self.accountTracker.ckdeviceIDError;
- NSMutableArray<NSString*>* mutTrustedPeers = [[NSMutableArray alloc] init];
- [peers enumerateObjectsUsingBlock:^(id<CKKSPeer> _Nonnull obj, BOOL * _Nonnull stop) {
- [mutTrustedPeers addObject: [obj description]];
- }];
+ NSMutableArray<NSString*>* mutTrustedPeers = [[NSMutableArray alloc] init];
+ [peers enumerateObjectsUsingBlock:^(id<CKKSPeer> _Nonnull obj, BOOL * _Nonnull stop) {
+ [mutTrustedPeers addObject: [obj description]];
+ }];
#define stringify(obj) CKKSNilToNSNull([obj description])
- NSDictionary* global = @{
- @"view": @"global",
- @"selfPeers": stringify(selves),
- @"selfPeersError": CKKSNilToNSNull(selfPeersError),
- @"trustedPeers": CKKSNilToNSNull(mutTrustedPeers),
- @"trustedPeersError": CKKSNilToNSNull(trustedPeersError),
- @"reachability": strongSelf.reachabilityTracker.currentReachability ? @"network" : @"no-network",
- @"ckdeviceID": CKKSNilToNSNull(deviceID),
- @"ckdeviceIDError": CKKSNilToNSNull(deviceIDError),
- };
- [a addObject: global];
+ NSDictionary* global = @{
+ @"view": @"global",
+ @"selfPeers": stringify(selves),
+ @"selfPeersError": CKKSNilToNSNull(selfPeersError),
+ @"trustedPeers": CKKSNilToNSNull(mutTrustedPeers),
+ @"trustedPeersError": CKKSNilToNSNull(trustedPeersError),
+ @"reachability": strongSelf.reachabilityTracker.currentReachability ? @"network" : @"no-network",
+ @"ckdeviceID": CKKSNilToNSNull(deviceID),
+ @"ckdeviceIDError": CKKSNilToNSNull(deviceIDError),
+ };
+ [a addObject: global];
+ }
for(CKKSKeychainView* view in actualViews) {
ckksnotice("ckks", view, "Fetching status for %@", view.zoneName);
- NSDictionary* status = [view status];
+ NSDictionary* status = viewBlock(view);
ckksinfo("ckks", view, "Status is %@", status);
if(status) {
[a addObject: status];
return;
}
+- (void)rpcStatus:(NSString*)viewName reply:(void (^)(NSArray<NSDictionary*>* result, NSError* error))reply
+{
+ [self rpcStatus:viewName global:true reply:reply viewBlock:^NSDictionary *(CKKSKeychainView *view) {
+ return [view status];
+ }];
+}
+
+- (void)rpcFastStatus:(NSString*)viewName reply:(void (^)(NSArray<NSDictionary*>* result, NSError* error))reply
+{
+ [self rpcStatus:viewName global:false reply:reply viewBlock:^NSDictionary *(CKKSKeychainView *view) {
+ return [view fastStatus];
+ }];
+}
+
- (void)rpcFetchAndProcessChanges:(NSString*)viewName reply: (void(^)(NSError* result))reply {
[self rpcFetchAndProcessChanges:viewName classA:false reply: (void(^)(NSError* result))reply];
}
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];
}
}
_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;
_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];
XCTAssertNotNil(keychainStatus, "Should have received at least one zone status back");
XCTAssertEqualObjects(keychainStatus[@"view"], @"keychain", "Should have received status for the keychain view");
XCTAssertEqualObjects(keychainStatus[@"keystate"], SecCKKSZoneKeyStateReady, "Should be in 'ready' status");
+ XCTAssertNotNil(keychainStatus[@"ckmirror"], "Status should have any ckmirror");
[callbackOccurs fulfill];
}];
[self waitForExpectations:@[callbackOccurs] timeout:20];
}
+- (void)testRpcFastStatus {
+ [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test.
+
+ [self startCKKSSubsystem];
+
+ // Let things shake themselves out.
+ OCMVerifyAllWithDelay(self.mockDatabase, 20);
+ XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], "Key state should return to 'ready'");
+ [self waitForCKModifications];
+
+ XCTestExpectation* callbackOccurs = [self expectationWithDescription:@"callback-occurs"];
+ [self.ckksControl rpcFastStatus:@"keychain" reply:^(NSArray<NSDictionary*>* result, NSError* error) {
+ XCTAssertNil(error, "should be no error fetching status for keychain");
+
+ // Ugly "global" hack
+ XCTAssertEqual(result.count, 1u, "Should have received one result dictionaries back");
+ NSDictionary* keychainStatus = result[0];
+
+ XCTAssertNotNil(keychainStatus, "Should have received at least one zone status back");
+ XCTAssertEqualObjects(keychainStatus[@"view"], @"keychain", "Should have received status for the keychain view");
+ XCTAssertEqualObjects(keychainStatus[@"keystate"], SecCKKSZoneKeyStateReady, "Should be in 'ready' status");
+ XCTAssertNil(keychainStatus[@"ckmirror"], "fastStatus should not have any ckmirror");
+ [callbackOccurs fulfill];
+ }];
+
+ [self waitForExpectations:@[callbackOccurs] timeout:20];
+}
+
+
- (void)testRpcStatusWaitsForAccountDetermination {
[self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test.
[self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D10" withAccount:@"account10"]];
[self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D11" withAccount:@"account11"]];
+ for(int i = 12; i < 100; i++) {
+ @autoreleasepool {
+ NSString* recordName = [NSString stringWithFormat:@"7B598D31-F9C5-481E-98AC-%012d", i];
+ NSString* account = [NSString stringWithFormat:@"account%d", i];
+
+ [self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName:recordName withAccount:account]];
+ }
+ }
+
// Trigger a notification (with hilariously fake data)
[self.keychainView notifyZoneChange:nil];
// test starts as if a previously logged-in device has just rebooted
self.aksLockState = true;
self.accountStatus = CKAccountStatusAvailable;
- self.circleStatus = [[SOSAccountStatus alloc] init:kSOSCCError error:[NSError errorWithDomain:(__bridge id)kSOSErrorDomain code:kSOSErrorNotReady description:@"fake error: device is locked, so SOS doesn't know if it's in-circle"]];
+ // This is the original state of the account tracker
+ self.circleStatus = [[SOSAccountStatus alloc] init:kSOSCCError error:nil];
[self.accountStateTracker notifyCircleStatusChangeAndWaitForSignal];
- XCTAssertNil(self.accountStateTracker.currentAccountError, "Account tracker error should not yet exist");
- XCTAssertEqual(self.accountStateTracker.currentAccountError.code, CKKSAccountStatusUnknown, "Account tracker error should just be 'no account'");
+ // And this is what the first circle status fetch will actually return
+ self.circleStatus = [[SOSAccountStatus alloc] init:kSOSCCError error:[NSError errorWithDomain:(__bridge id)kSOSErrorDomain code:kSOSErrorNotReady description:@"fake error: device is locked, so SOS doesn't know if it's in-circle"]];
+ [self.accountStateTracker notifyCircleStatusChangeAndWaitForSignal];
+ XCTAssertNil(self.accountStateTracker.currentAccountError, "Account tracker error should not yet exist");
+ XCTAssertEqual(self.accountStateTracker.currentComputedAccountStatus, CKKSAccountStatusUnknown, "Account tracker status should just be 'no account'");
XCTAssertNotEqual(0, [self.keychainView.accountStateKnown wait:50*NSEC_PER_MSEC], "CKKS shouldn't know the account state yet");
[self startCKKSSubsystem];
XCTAssertNotEqual(0, [self.keychainView.loggedIn wait:100*NSEC_PER_MSEC], "'login' event shouldn't have happened");
XCTAssertNotEqual(0, [self.keychainView.accountStateKnown wait:50*NSEC_PER_MSEC], "CKKS shouldn't know the account state yet");
+ // And assume another CK status change
+ [self.accountStateTracker notifyCKAccountStatusChangeAndWaitForSignal];
+ XCTAssertEqual(self.accountStateTracker.currentComputedAccountStatus, CKKSAccountStatusUnknown, "Account tracker status should just be 'no account'");
+ XCTAssertNotEqual(0, [self.keychainView.accountStateKnown wait:50*NSEC_PER_MSEC], "CKKS shouldn't know the account state yet");
+
[self expectCKModifyKeyRecords: 3 currentKeyPointerRecords: 3 tlkShareRecords: 1 zoneID:self.keychainZoneID];
self.aksLockState = false;
_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];
(id)kSecAttrNoLegacy : @(YES)
};
OSStatus result = SecItemAdd((__bridge CFDictionaryRef)item, NULL);
- XCTAssertEqual(result, 0, @"failed to add test item to keychain: %u", n);
+ XCTAssertEqual(result, errSecSuccess, @"failed to add test item to keychain: %u", n);
}
}
(id)kSecAttrNoLegacy : @(YES)
};
OSStatus result = SecItemCopyMatching((__bridge CFDictionaryRef)item, NULL);
- XCTAssertEqual(result, 0, @"failed to find test item to keychain: %u", n);
+ XCTAssertEqual(result, errSecSuccess, @"failed to find test item to keychain: %u", n);
}
}
+- (void)testSecItemServerDeleteAll
+{
+ // BT root key, should not be deleted
+ NSMutableDictionary* bt = [@{
+ (id)kSecClass : (id)kSecClassGenericPassword,
+ (id)kSecAttrAccessGroup : @"com.apple.bluetooth",
+ (id)kSecAttrService : @"BluetoothGlobal",
+ (id)kSecAttrAccessible : (id)kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate,
+ (id)kSecAttrSynchronizable : @(NO),
+ (id)kSecValueData : [@"btkey" dataUsingEncoding:NSUTF8StringEncoding],
+ } mutableCopy];
+
+ // lockdown-identities, should not be deleted
+ NSMutableDictionary* ld = [@{
+ (id)kSecClass : (id)kSecClassKey,
+ (id)kSecAttrAccessGroup : @"lockdown-identities",
+ (id)kSecAttrLabel : @"com.apple.lockdown.identity.activation",
+ (id)kSecAttrAccessible : (id)kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate,
+ (id)kSecAttrSynchronizable : @(NO),
+ (id)kSecValueData : [@"ldkey" dataUsingEncoding:NSUTF8StringEncoding],
+ } mutableCopy];
+
+ // general nonsyncable item, should be deleted
+ NSMutableDictionary* s0 = [@{
+ (id)kSecClass : (id)kSecClassGenericPassword,
+ (id)kSecAttrService : @"NonsyncableService",
+ (id)kSecAttrSynchronizable : @(NO),
+ (id)kSecValueData : [@"s0pwd" dataUsingEncoding:NSUTF8StringEncoding],
+ } mutableCopy];
+
+ // general syncable item, should be deleted
+ NSMutableDictionary* s1 = [@{
+ (id)kSecClass : (id)kSecClassGenericPassword,
+ (id)kSecAttrService : @"SyncableService",
+ (id)kSecAttrSynchronizable : @(YES),
+ (id)kSecValueData : [@"s0pwd" dataUsingEncoding:NSUTF8StringEncoding],
+ } mutableCopy];
+
+ // Insert all items
+ OSStatus status;
+ status = SecItemAdd((__bridge CFDictionaryRef)bt, NULL);
+ XCTAssertEqual(status, errSecSuccess, "failed to add bt item to keychain");
+ status = SecItemAdd((__bridge CFDictionaryRef)ld, NULL);
+ XCTAssertEqual(status, errSecSuccess, "failed to add ld item to keychain");
+ status = SecItemAdd((__bridge CFDictionaryRef)s0, NULL);
+ XCTAssertEqual(status, errSecSuccess, "failed to add s0 item to keychain");
+ status = SecItemAdd((__bridge CFDictionaryRef)s1, NULL);
+ XCTAssertEqual(status, errSecSuccess, "failed to add s1 item to keychain");
+
+ // Make sure they exist now
+ bt[(id)kSecValueData] = nil;
+ ld[(id)kSecValueData] = nil;
+ s0[(id)kSecValueData] = nil;
+ s1[(id)kSecValueData] = nil;
+ status = SecItemCopyMatching((__bridge CFDictionaryRef)bt, NULL);
+ XCTAssertEqual(status, errSecSuccess, "failed to find bt item in keychain");
+ status = SecItemCopyMatching((__bridge CFDictionaryRef)ld, NULL);
+ XCTAssertEqual(status, errSecSuccess, "failed to find ld item in keychain");
+ status = SecItemCopyMatching((__bridge CFDictionaryRef)s0, NULL);
+ XCTAssertEqual(status, errSecSuccess, "failed to find s0 item in keychain");
+ status = SecItemCopyMatching((__bridge CFDictionaryRef)s1, NULL);
+ XCTAssertEqual(status, errSecSuccess, "failed to find s1 item in keychain");
+
+ // Nuke the keychain
+ CFErrorRef error = NULL;
+ _SecItemDeleteAll(&error);
+ XCTAssertEqual(error, NULL, "_SecItemDeleteAll returned an error: %@", error);
+ CFReleaseNull(error);
+
+ // Does the function work properly with an error pre-set?
+ error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainOSStatus, errSecItemNotFound, NULL);
+ _SecItemDeleteAll(&error);
+ XCTAssertEqual(CFErrorGetDomain(error), kCFErrorDomainOSStatus);
+ XCTAssertEqual(CFErrorGetCode(error), errSecItemNotFound);
+ CFReleaseNull(error);
+
+ // Check the relevant items are missing
+ status = SecItemCopyMatching((__bridge CFDictionaryRef)bt, NULL);
+ XCTAssertEqual(status, errSecSuccess, "failed to find bt item in keychain");
+ status = SecItemCopyMatching((__bridge CFDictionaryRef)ld, NULL);
+ XCTAssertEqual(status, errSecSuccess, "failed to find ld item in keychain");
+ status = SecItemCopyMatching((__bridge CFDictionaryRef)s0, NULL);
+ XCTAssertEqual(status, errSecItemNotFound, "unexpectedly found s0 item in keychain");
+ status = SecItemCopyMatching((__bridge CFDictionaryRef)s1, NULL);
+ XCTAssertEqual(status, errSecItemNotFound, "unexpectedly found s1 item in keychain");
+}
+
- (void)createManyKeys
{
unsigned n;
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;
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;
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;
void SecPolicySetOptionsValue(SecPolicyRef policy, CFStringRef key, CFTypeRef value);
+bool SecDNSIsTLD(CFStringRef reference);
+
CF_IMPLICIT_BRIDGING_DISABLED
CF_ASSUME_NONNULL_END
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
*/
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.
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.
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
#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
/*