X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5c19dc3ae3bd8e40a9c028b0deddd50ff337692c..7e6b461318c8a779d91381531435a68ee4e8b6ed:/OSX/libsecurity_keychain/lib/Identity.cpp diff --git a/OSX/libsecurity_keychain/lib/Identity.cpp b/OSX/libsecurity_keychain/lib/Identity.cpp index 826ed985..85b0636d 100644 --- a/OSX/libsecurity_keychain/lib/Identity.cpp +++ b/OSX/libsecurity_keychain/lib/Identity.cpp @@ -30,38 +30,99 @@ #include #include +#include +#include +#include + using namespace KeychainCore; Identity::Identity(const SecPointer &privateKey, + const SecPointer &certificate) : + mPrivateKey(privateKey->handle()), + mCertificate(certificate) +{ +} + +Identity::Identity(SecKeyRef privateKey, const SecPointer &certificate) : - mPrivateKey(privateKey), + mPrivateKey((SecKeyRef)CFRetain(privateKey)), mCertificate(certificate) { } Identity::Identity(const StorageManager::KeychainList &keychains, const SecPointer &certificate) : - mCertificate(certificate) + mPrivateKey(NULL), mCertificate(certificate) { - // Find a key whose label matches the publicKeyHash of the public key in the certificate. - KCCursor keyCursor(keychains, 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(static_cast(&*key)); - mPrivateKey = keyItem; + // Find a key whose label matches the publicKeyHash of the public key in the certificate. + CssmData publicKeyHash = certificate->publicKeyHash(); + CFRef 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 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 dynamicKeychains; + SecKeychainCopyDomainSearchList(kSecPreferencesDomainDynamic, dynamicKeychains.take()); + CFRef dynamicSearchList = CFArrayCreateMutable(kCFAllocatorDefault, (CFIndex)keychains.size(), &kCFTypeArrayCallBacks); + CFRef 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 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(static_cast(&*key)); + mPrivateKey = keyItem->handle(); + } + else { + MacOSError::throwMe(errSecItemNotFound); + } + } + } } Identity::~Identity() throw() { + if (mPrivateKey) + CFRelease(mPrivateKey); } SecPointer Identity::privateKey() const { - return mPrivateKey; + return SecPointer(KeyItem::required(mPrivateKey)); } SecPointer @@ -70,6 +131,12 @@ Identity::certificate() const return mCertificate; } +SecKeyRef +Identity::privateKeyRef() const +{ + return mPrivateKey; +} + bool Identity::operator < (const Identity &other) const { @@ -88,9 +155,22 @@ Identity::operator == (const Identity &other) const bool Identity::equal(SecCFObject &other) { - CFHashCode this_hash = hash(); - CFHashCode other_hash = other.hash(); - return (this_hash == other_hash); + // Compare certificates first. + if (Identity *otherIdentity = dynamic_cast(&other)) { + Certificate *pCert = mCertificate.get(), *pOtherCert = otherIdentity->mCertificate.get(); + if (pCert == NULL || pOtherCert == NULL) { + return pCert == pOtherCert; + } + + if (pCert->equal(*pOtherCert)) { + // Compare private keys. + if (mPrivateKey == NULL || otherIdentity->mPrivateKey == NULL) { + return mPrivateKey == otherIdentity->mPrivateKey; + } + return CFEqual(mPrivateKey, otherIdentity->mPrivateKey); + } + } + return false; } CFHashCode Identity::hash() @@ -107,12 +187,8 @@ CFHashCode Identity::hash() struct keyAndCertHash hashes; memset(&hashes, 0, sizeof(struct keyAndCertHash)); - KeyItem* pKeyItem = mPrivateKey.get(); - if (NULL != pKeyItem) - { - hashes.keyHash = pKeyItem->hash(); - } - + hashes.keyHash = CFHash(mPrivateKey); + Certificate* pCert = mCertificate.get(); if (NULL != pCert) {