+ // Find a key whose label matches the publicKeyHash of the public key in the certificate.
+ CssmData publicKeyHash = certificate->publicKeyHash();
+ CFRef<CFDataRef> keyHash = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
+ (const UInt8 *)publicKeyHash.data(),
+ publicKeyHash.length(),
+ kCFAllocatorNull);
+ // First, try the new iOS keychain.
+ {
+ const void *keys[] = { kSecClass, kSecAttrKeyClass, kSecAttrApplicationLabel, kSecReturnRef, kSecUseDataProtectionKeychain };
+ const void *values[] = { kSecClassKey, kSecAttrKeyClassPrivate, keyHash, kCFBooleanTrue, kCFBooleanTrue };
+ CFRef<CFDictionaryRef> query = CFDictionaryCreate(kCFAllocatorDefault, keys, values,
+ sizeof(keys) / sizeof(*keys),
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ OSStatus status = SecItemCopyMatching(query, (CFTypeRef *)&mPrivateKey);
+ if (status == errSecSuccess) {
+ return;
+ }
+ }
+ // Second, try the legacy OS X keychain(s).
+ {
+ mPrivateKey = NULL;
+ CFRef<CFArrayRef> dynamicKeychains;
+ SecKeychainCopyDomainSearchList(kSecPreferencesDomainDynamic, dynamicKeychains.take());
+ CFRef<CFMutableArrayRef> dynamicSearchList = CFArrayCreateMutable(kCFAllocatorDefault, (CFIndex)keychains.size(), &kCFTypeArrayCallBacks);
+ CFRef<CFMutableArrayRef> searchList = CFArrayCreateMutable(kCFAllocatorDefault, (CFIndex)keychains.size(), &kCFTypeArrayCallBacks);
+ for (StorageManager::KeychainList::const_iterator it = keychains.begin(), end = keychains.end(); it != end; ++it) {
+ if (dynamicKeychains && CFArrayGetCount(dynamicKeychains) && CFArrayContainsValue(dynamicKeychains, CFRangeMake(0, CFArrayGetCount(dynamicKeychains)), **it)) {
+ CFArrayAppendValue(dynamicSearchList, **it);
+ }
+ CFArrayAppendValue(searchList, **it);
+ }
+ const void *keys[] = { kSecClass, kSecAttrKeyClass, kSecAttrApplicationLabel, kSecReturnRef, kSecMatchSearchList };
+ const void *values[] = { kSecClassKey, kSecAttrKeyClassPrivate, keyHash, kCFBooleanTrue, searchList };
+ CFRef<CFDictionaryRef> query = CFDictionaryCreate(kCFAllocatorDefault, keys, values,
+ sizeof(keys) / sizeof(*keys),
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ OSStatus status = SecItemCopyMatching(query, (CFTypeRef *)&mPrivateKey);
+ if (status != errSecSuccess) {
+ if (CFArrayGetCount(dynamicSearchList)) {
+ // Legacy way is used for dynamic keychains because SmartCards keychain does not support strict CSSM queries which are generated in SecItemCopyMatching
+ // Find a key whose label matches the publicKeyHash of the public key in the certificate.
+ KCCursor keyCursor(keychains, (SecItemClass) CSSM_DL_DB_RECORD_PRIVATE_KEY, NULL);
+ keyCursor->add(CSSM_DB_EQUAL, KeySchema::Label, certificate->publicKeyHash());
+
+ Item key;
+ if (!keyCursor->next(key))
+ MacOSError::throwMe(errSecItemNotFound);
+
+ SecPointer<KeyItem> keyItem(static_cast<KeyItem *>(&*key));
+ mPrivateKey = keyItem->handle();
+ }
+ else {
+ MacOSError::throwMe(errSecItemNotFound);
+ }
+ }
+ }