]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/lib/Identity.cpp
Security-57740.51.3.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / lib / Identity.cpp
1 /*
2 * Copyright (c) 2002-2004,2011-2014 Apple Inc. All Rights Reserved.
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>
31 #include <string.h>
32
33 #include <Security/SecItem.h>
34 #include <Security/SecItemPriv.h>
35 #include <Security/SecKeychain.h>
36
37 using namespace KeychainCore;
38
39 Identity::Identity(const SecPointer<KeyItem> &privateKey,
40 const SecPointer<Certificate> &certificate) :
41 mPrivateKey(privateKey->handle()),
42 mCertificate(certificate)
43 {
44 }
45
46 Identity::Identity(SecKeyRef privateKey,
47 const SecPointer<Certificate> &certificate) :
48 mPrivateKey((SecKeyRef)CFRetain(privateKey)),
49 mCertificate(certificate)
50 {
51 }
52
53 Identity::Identity(const StorageManager::KeychainList &keychains, const SecPointer<Certificate> &certificate) :
54 mPrivateKey(NULL), mCertificate(certificate)
55 {
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.
99 KCCursor keyCursor(keychains, (SecItemClass) CSSM_DL_DB_RECORD_PRIVATE_KEY, NULL);
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 }
114 }
115
116 Identity::~Identity() throw()
117 {
118 if (mPrivateKey)
119 CFRelease(mPrivateKey);
120 }
121
122 SecPointer<KeyItem>
123 Identity::privateKey() const
124 {
125 return SecPointer<KeyItem>(KeyItem::required(mPrivateKey));
126 }
127
128 SecPointer<Certificate>
129 Identity::certificate() const
130 {
131 return mCertificate;
132 }
133
134 SecKeyRef
135 Identity::privateKeyRef() const
136 {
137 return mPrivateKey;
138 }
139
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
156 bool Identity::equal(SecCFObject &other)
157 {
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;
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
190 hashes.keyHash = CFHash(mPrivateKey);
191
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;
210 }
211