2 * Copyright (c) 2002-2004,2011-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 // Identity.cpp - Working with Identities
27 #include <security_keychain/Identity.h>
29 #include <security_cdsa_utilities/KeySchema.h>
30 #include <security_keychain/KCCursor.h>
33 #include <Security/SecItem.h>
34 #include <Security/SecItemPriv.h>
35 #include <Security/SecKeychain.h>
37 using namespace KeychainCore
;
39 Identity::Identity(const SecPointer
<KeyItem
> &privateKey
,
40 const SecPointer
<Certificate
> &certificate
) :
41 mPrivateKey(privateKey
->handle()),
42 mCertificate(certificate
)
46 Identity::Identity(SecKeyRef privateKey
,
47 const SecPointer
<Certificate
> &certificate
) :
48 mPrivateKey((SecKeyRef
)CFRetain(privateKey
)),
49 mCertificate(certificate
)
53 Identity::Identity(const StorageManager::KeychainList
&keychains
, const SecPointer
<Certificate
> &certificate
) :
54 mPrivateKey(NULL
), mCertificate(certificate
)
56 // Find a key whose label matches the publicKeyHash of the public key in the certificate.
57 CssmData publicKeyHash
= certificate
->publicKeyHash();
58 CFRef
<CFDataRef
> keyHash
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
,
59 (const UInt8
*)publicKeyHash
.data(),
60 publicKeyHash
.length(),
62 // First, try the new iOS keychain.
64 const void *keys
[] = { kSecClass
, kSecAttrKeyClass
, kSecAttrApplicationLabel
, kSecReturnRef
, kSecUseDataProtectionKeychain
};
65 const void *values
[] = { kSecClassKey
, kSecAttrKeyClassPrivate
, keyHash
, kCFBooleanTrue
, kCFBooleanTrue
};
66 CFRef
<CFDictionaryRef
> query
= CFDictionaryCreate(kCFAllocatorDefault
, keys
, values
,
67 sizeof(keys
) / sizeof(*keys
),
68 &kCFTypeDictionaryKeyCallBacks
,
69 &kCFTypeDictionaryValueCallBacks
);
70 OSStatus status
= SecItemCopyMatching(query
, (CFTypeRef
*)&mPrivateKey
);
71 if (status
== errSecSuccess
) {
75 // Second, try the legacy OS X keychain(s).
78 CFRef
<CFArrayRef
> dynamicKeychains
;
79 SecKeychainCopyDomainSearchList(kSecPreferencesDomainDynamic
, dynamicKeychains
.take());
80 CFRef
<CFMutableArrayRef
> dynamicSearchList
= CFArrayCreateMutable(kCFAllocatorDefault
, (CFIndex
)keychains
.size(), &kCFTypeArrayCallBacks
);
81 CFRef
<CFMutableArrayRef
> searchList
= CFArrayCreateMutable(kCFAllocatorDefault
, (CFIndex
)keychains
.size(), &kCFTypeArrayCallBacks
);
82 for (StorageManager::KeychainList::const_iterator it
= keychains
.begin(), end
= keychains
.end(); it
!= end
; ++it
) {
83 if (dynamicKeychains
&& CFArrayGetCount(dynamicKeychains
) && CFArrayContainsValue(dynamicKeychains
, CFRangeMake(0, CFArrayGetCount(dynamicKeychains
)), **it
)) {
84 CFArrayAppendValue(dynamicSearchList
, **it
);
86 CFArrayAppendValue(searchList
, **it
);
88 const void *keys
[] = { kSecClass
, kSecAttrKeyClass
, kSecAttrApplicationLabel
, kSecReturnRef
, kSecMatchSearchList
};
89 const void *values
[] = { kSecClassKey
, kSecAttrKeyClassPrivate
, keyHash
, kCFBooleanTrue
, searchList
};
90 CFRef
<CFDictionaryRef
> query
= CFDictionaryCreate(kCFAllocatorDefault
, keys
, values
,
91 sizeof(keys
) / sizeof(*keys
),
92 &kCFTypeDictionaryKeyCallBacks
,
93 &kCFTypeDictionaryValueCallBacks
);
94 OSStatus status
= SecItemCopyMatching(query
, (CFTypeRef
*)&mPrivateKey
);
95 if (status
!= errSecSuccess
) {
96 if (CFArrayGetCount(dynamicSearchList
)) {
97 // Legacy way is used for dynamic keychains because SmartCards keychain does not support strict CSSM queries which are generated in SecItemCopyMatching
98 // Find a key whose label matches the publicKeyHash of the public key in the certificate.
99 KCCursor
keyCursor(keychains
, (SecItemClass
) CSSM_DL_DB_RECORD_PRIVATE_KEY
, NULL
);
100 keyCursor
->add(CSSM_DB_EQUAL
, KeySchema::Label
, certificate
->publicKeyHash());
103 if (!keyCursor
->next(key
))
104 MacOSError::throwMe(errSecItemNotFound
);
106 SecPointer
<KeyItem
> keyItem(static_cast<KeyItem
*>(&*key
));
107 mPrivateKey
= keyItem
->handle();
110 MacOSError::throwMe(errSecItemNotFound
);
116 Identity::~Identity() _NOEXCEPT
119 CFRelease(mPrivateKey
);
123 Identity::privateKey() const
125 return SecPointer
<KeyItem
>(KeyItem::required(mPrivateKey
));
128 SecPointer
<Certificate
>
129 Identity::certificate() const
135 Identity::privateKeyRef() const
141 Identity::operator < (const Identity
&other
) const
143 // Certificates in different keychains are considered equal if data is equal
144 return (mCertificate
< other
.mCertificate
);
148 Identity::operator == (const Identity
&other
) const
150 // Certificates in different keychains are considered equal if data is equal;
151 // however, if their keys are in different keychains, the identities should
152 // not be considered equal (according to mb)
153 return (mCertificate
== other
.mCertificate
&& mPrivateKey
== other
.mPrivateKey
);
156 bool Identity::equal(SecCFObject
&other
)
158 // Compare certificates first.
159 if (Identity
*otherIdentity
= dynamic_cast<Identity
*>(&other
)) {
160 Certificate
*pCert
= mCertificate
.get(), *pOtherCert
= otherIdentity
->mCertificate
.get();
161 if (pCert
== NULL
|| pOtherCert
== NULL
) {
162 return pCert
== pOtherCert
;
165 if (pCert
->equal(*pOtherCert
)) {
166 // Compare private keys.
167 if (mPrivateKey
== NULL
|| otherIdentity
->mPrivateKey
== NULL
) {
168 return mPrivateKey
== otherIdentity
->mPrivateKey
;
170 return CFEqual(mPrivateKey
, otherIdentity
->mPrivateKey
);
176 CFHashCode
Identity::hash()
178 CFHashCode result
= SecCFObject::hash();
181 struct keyAndCertHash
187 struct keyAndCertHash hashes
;
188 memset(&hashes
, 0, sizeof(struct keyAndCertHash
));
190 hashes
.keyHash
= CFHash(mPrivateKey
);
192 Certificate
* pCert
= mCertificate
.get();
195 hashes
.certHash
= pCert
->hash();
198 if (hashes
.keyHash
!= 0 || hashes
.certHash
!= 0)
201 CFDataRef temp_data
= CFDataCreateWithBytesNoCopy(NULL
, (const UInt8
*)&hashes
, sizeof(struct keyAndCertHash
), kCFAllocatorNull
);
202 if (NULL
!= temp_data
)
204 result
= CFHash(temp_data
);
205 CFRelease(temp_data
);