]> git.saurik.com Git - apple/security.git/blobdiff - OSX/libsecurity_keychain/lib/Identity.cpp
Security-58286.260.20.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / lib / Identity.cpp
index 826ed985a39787964b755156827b9ea1915e0e03..52be5fece8a4b4fe7e1cd43a614f6262c7cbbd0b 100644 (file)
 #include <security_keychain/KCCursor.h>
 #include <string.h>
 
+#include <Security/SecItem.h>
+#include <Security/SecItemPriv.h>
+#include <Security/SecKeychain.h>
+
 using namespace KeychainCore;
 
 Identity::Identity(const SecPointer<KeyItem> &privateKey,
+                   const SecPointer<Certificate> &certificate) :
+    mPrivateKey(privateKey->handle()),
+    mCertificate(certificate)
+{
+}
+
+Identity::Identity(SecKeyRef privateKey,
                const SecPointer<Certificate> &certificate) :
-       mPrivateKey(privateKey),
+       mPrivateKey((SecKeyRef)CFRetain(privateKey)),
        mCertificate(certificate)
 {
 }
 
 Identity::Identity(const StorageManager::KeychainList &keychains, const SecPointer<Certificate> &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> keyItem(static_cast<KeyItem *>(&*key));
-       mPrivateKey = keyItem;
+    // 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, kSecAttrNoLegacy };
+        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);
+            }
+        }
+    }
 }
 
 Identity::~Identity() throw()
 {
+    if (mPrivateKey)
+        CFRelease(mPrivateKey);
 }
 
 SecPointer<KeyItem>
 Identity::privateKey() const
 {
-       return mPrivateKey;
+       return SecPointer<KeyItem>(KeyItem::required(mPrivateKey));
 }
 
 SecPointer<Certificate>
@@ -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<Identity *>(&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)
        {