]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 | 1 | /* |
d8f41ccd | 2 | * Copyright (c) 2002-2004,2011-2014 Apple Inc. All Rights Reserved. |
b1ab9ed8 A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
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 | |
11 | * file. | |
12 | * | |
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. | |
20 | * | |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | */ | |
23 | ||
24 | // | |
25 | // Identity.cpp - Working with Identities | |
26 | // | |
27 | #include <security_keychain/Identity.h> | |
28 | ||
29 | #include <security_cdsa_utilities/KeySchema.h> | |
30 | #include <security_keychain/KCCursor.h> | |
427c49bc | 31 | #include <string.h> |
b1ab9ed8 | 32 | |
fa7225c8 A |
33 | #include <Security/SecItem.h> |
34 | #include <Security/SecItemPriv.h> | |
35 | #include <Security/SecKeychain.h> | |
36 | ||
b1ab9ed8 A |
37 | using namespace KeychainCore; |
38 | ||
39 | Identity::Identity(const SecPointer<KeyItem> &privateKey, | |
fa7225c8 A |
40 | const SecPointer<Certificate> &certificate) : |
41 | mPrivateKey(privateKey->handle()), | |
42 | mCertificate(certificate) | |
43 | { | |
44 | } | |
45 | ||
46 | Identity::Identity(SecKeyRef privateKey, | |
b1ab9ed8 | 47 | const SecPointer<Certificate> &certificate) : |
fa7225c8 | 48 | mPrivateKey((SecKeyRef)CFRetain(privateKey)), |
b1ab9ed8 A |
49 | mCertificate(certificate) |
50 | { | |
51 | } | |
52 | ||
53 | Identity::Identity(const StorageManager::KeychainList &keychains, const SecPointer<Certificate> &certificate) : | |
fa7225c8 | 54 | mPrivateKey(NULL), mCertificate(certificate) |
b1ab9ed8 | 55 | { |
fa7225c8 A |
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(), | |
61 | kCFAllocatorNull); | |
62 | // First, try the new iOS keychain. | |
63 | { | |
64 | const void *keys[] = { kSecClass, kSecAttrKeyClass, kSecAttrApplicationLabel, kSecReturnRef, kSecAttrNoLegacy }; | |
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) { | |
72 | return; | |
73 | } | |
74 | } | |
75 | // Second, try the legacy OS X keychain(s). | |
76 | { | |
77 | mPrivateKey = NULL; | |
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); | |
85 | } | |
86 | CFArrayAppendValue(searchList, **it); | |
87 | } | |
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. | |
6b200bc3 | 99 | KCCursor keyCursor(keychains, (SecItemClass) CSSM_DL_DB_RECORD_PRIVATE_KEY, NULL); |
fa7225c8 A |
100 | keyCursor->add(CSSM_DB_EQUAL, KeySchema::Label, certificate->publicKeyHash()); |
101 | ||
102 | Item key; | |
103 | if (!keyCursor->next(key)) | |
104 | MacOSError::throwMe(errSecItemNotFound); | |
105 | ||
106 | SecPointer<KeyItem> keyItem(static_cast<KeyItem *>(&*key)); | |
107 | mPrivateKey = keyItem->handle(); | |
108 | } | |
109 | else { | |
110 | MacOSError::throwMe(errSecItemNotFound); | |
111 | } | |
112 | } | |
113 | } | |
b1ab9ed8 A |
114 | } |
115 | ||
116 | Identity::~Identity() throw() | |
117 | { | |
fa7225c8 A |
118 | if (mPrivateKey) |
119 | CFRelease(mPrivateKey); | |
b1ab9ed8 A |
120 | } |
121 | ||
122 | SecPointer<KeyItem> | |
123 | Identity::privateKey() const | |
124 | { | |
fa7225c8 | 125 | return SecPointer<KeyItem>(KeyItem::required(mPrivateKey)); |
b1ab9ed8 A |
126 | } |
127 | ||
128 | SecPointer<Certificate> | |
129 | Identity::certificate() const | |
130 | { | |
131 | return mCertificate; | |
132 | } | |
133 | ||
fa7225c8 A |
134 | SecKeyRef |
135 | Identity::privateKeyRef() const | |
136 | { | |
137 | return mPrivateKey; | |
138 | } | |
139 | ||
b1ab9ed8 A |
140 | bool |
141 | Identity::operator < (const Identity &other) const | |
142 | { | |
143 | // Certificates in different keychains are considered equal if data is equal | |
144 | return (mCertificate < other.mCertificate); | |
145 | } | |
146 | ||
147 | bool | |
148 | Identity::operator == (const Identity &other) const | |
149 | { | |
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); | |
154 | } | |
155 | ||
427c49bc | 156 | bool Identity::equal(SecCFObject &other) |
b1ab9ed8 | 157 | { |
fa7225c8 A |
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; | |
163 | } | |
164 | ||
165 | if (pCert->equal(*pOtherCert)) { | |
166 | // Compare private keys. | |
167 | if (mPrivateKey == NULL || otherIdentity->mPrivateKey == NULL) { | |
168 | return mPrivateKey == otherIdentity->mPrivateKey; | |
169 | } | |
170 | return CFEqual(mPrivateKey, otherIdentity->mPrivateKey); | |
171 | } | |
172 | } | |
173 | return false; | |
427c49bc A |
174 | } |
175 | ||
176 | CFHashCode Identity::hash() | |
177 | { | |
178 | CFHashCode result = SecCFObject::hash(); | |
179 | ||
180 | ||
181 | struct keyAndCertHash | |
182 | { | |
183 | CFHashCode keyHash; | |
184 | CFHashCode certHash; | |
185 | }; | |
186 | ||
187 | struct keyAndCertHash hashes; | |
188 | memset(&hashes, 0, sizeof(struct keyAndCertHash)); | |
189 | ||
fa7225c8 A |
190 | hashes.keyHash = CFHash(mPrivateKey); |
191 | ||
427c49bc A |
192 | Certificate* pCert = mCertificate.get(); |
193 | if (NULL != pCert) | |
194 | { | |
195 | hashes.certHash = pCert->hash(); | |
196 | } | |
197 | ||
198 | if (hashes.keyHash != 0 || hashes.certHash != 0) | |
199 | { | |
200 | ||
201 | CFDataRef temp_data = CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)&hashes, sizeof(struct keyAndCertHash), kCFAllocatorNull); | |
202 | if (NULL != temp_data) | |
203 | { | |
204 | result = CFHash(temp_data); | |
205 | CFRelease(temp_data); | |
206 | } | |
207 | } | |
208 | ||
209 | return result; | |
b1ab9ed8 A |
210 | } |
211 |