]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_pkcs12/lib/pkcs12Keychain.cpp
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / libsecurity_pkcs12 / lib / pkcs12Keychain.cpp
1 /*
2 * Copyright (c) 2003-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 * pkcs12Keychain.h - P12Coder keychain-related functions.
26 */
27
28 #include "pkcs12Coder.h"
29 #include "pkcs12Templates.h"
30 #include "pkcs12Utils.h"
31 #include "pkcs12Debug.h"
32 #include "pkcs12Crypto.h"
33 #include "SecCFRelease.h"
34 #include <Security/cssmerr.h>
35 #include <security_cdsa_utils/cuDbUtils.h> // cuAddCrlToDb()
36 #include <security_asn1/nssUtils.h>
37 #include <security_cdsa_utilities/KeySchema.h> /* private API */
38 #include <security_keychain/SecImportExportCrypto.h> /* private API */
39
40 /*
41 * Store the results of a successful decode in app-specified
42 * keychain per mImportFlags. Also assign public key hash attributes to any
43 * private keys found.
44 */
45 void P12Coder::storeDecodeResults()
46 {
47 assert(mKeychain != NULL);
48 assert(mDlDbHand.DLHandle != 0);
49 if(mImportFlags & kSecImportKeys) {
50 setPrivateKeyHashes();
51 }
52 if(mImportFlags & kSecImportCertificates) {
53 for(unsigned dex=0; dex<numCerts(); dex++) {
54 P12CertBag *certBag = mCerts[dex];
55 SecCertificateRef secCert = certBag->getSecCert();
56 OSStatus ortn = SecCertificateAddToKeychain(secCert, mKeychain);
57 CFRelease(secCert);
58 switch(ortn) {
59 case errSecSuccess: // normal
60 p12DecodeLog("cert added to keychain");
61 break;
62 case errSecDuplicateItem: // dup cert, OK< skip
63 p12DecodeLog("skipping dup cert");
64 break;
65 default:
66 p12ErrorLog("SecCertificateAddToKeychain failure\n");
67 MacOSError::throwMe(ortn);
68 }
69 }
70 }
71
72 if(mImportFlags & kSecImportCRLs) {
73 for(unsigned dex=0; dex<numCrls(); dex++) {
74 P12CrlBag *crlBag = mCrls[dex];
75 CSSM_RETURN crtn = cuAddCrlToDb(mDlDbHand,
76 clHand(),
77 &crlBag->crlData(),
78 NULL); // no URI known
79 switch(crtn) {
80 case CSSM_OK: // normal
81 p12DecodeLog("CRL added to keychain");
82 break;
83 case CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA: // dup, ignore
84 p12DecodeLog("skipping dup CRL");
85 break;
86 default:
87 p12LogCssmError("Error adding CRL to keychain", crtn);
88 CssmError::throwMe(crtn);
89 }
90 }
91 }
92
93 /* If all of that succeeded, post notification for imported keys */
94 if(mImportFlags & kSecImportKeys) {
95 notifyKeyImport();
96 }
97 }
98
99 /*
100 * Assign appropriate public key hash attribute to each
101 * private key.
102 */
103 void P12Coder::setPrivateKeyHashes()
104 {
105 CSSM_KEY_PTR newKey;
106
107 for(unsigned dex=0; dex<numKeys(); dex++) {
108 P12KeyBag *keyBag = mKeys[dex];
109
110 CSSM_DATA newLabel = {0, NULL};
111 CFStringRef friendlyName = keyBag->friendlyName();
112 newKey = NULL;
113 CSSM_RETURN crtn = p12SetPubKeyHash(mCspHand,
114 mDlDbHand,
115 keyBag->label(),
116 p12StringToUtf8(friendlyName, mCoder),
117 mCoder,
118 newLabel,
119 newKey);
120 if(friendlyName) {
121 CFRelease(friendlyName);
122 }
123 switch(crtn) {
124 case CSSM_OK:
125 /* update key's label in case we have to delete on error */
126 keyBag->setLabel(newLabel);
127 p12DecodeLog("set pub key hash for private key");
128 break;
129 case CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA:
130 /*
131 * Special case: update keyBag's CSSM_KEY and proceed without error
132 */
133 p12DecodeLog("ignoring dup private key");
134 assert(newKey != NULL);
135 keyBag->setKey(newKey);
136 keyBag->dupKey(true);
137 /* update key's label in case we have to delete on error */
138 keyBag->setLabel(newLabel);
139 break;
140 default:
141 p12ErrorLog("p12SetPubKeyHash failure\n");
142 CssmError::throwMe(crtn);
143 }
144 }
145 }
146
147 /*
148 * Post keychain notification for imported keys.
149 */
150 void P12Coder::notifyKeyImport()
151 {
152 if(mKeychain == NULL) {
153 /* Can't notify if user only gave us DLDB */
154 return;
155 }
156 for(unsigned dex=0; dex<numKeys(); dex++) {
157 P12KeyBag *keyBag = mKeys[dex];
158 if(keyBag->dupKey()) {
159 /* no notification for keys we merely looked up */
160 continue;
161 }
162 CssmData &labelData = CssmData::overlay(keyBag->label());
163 OSStatus ortn = impExpKeyNotify(mKeychain, labelData, *keyBag->key());
164 if(ortn) {
165 p12ErrorLog("notifyKeyImport: impExpKeyNotify returned %ld\n", (unsigned long)ortn);
166 MacOSError::throwMe(ortn);
167 }
168 }
169 }
170
171 /*
172 * Given a P12KeyBag, find a matching P12CertBag. Keys and certs
173 * "match" if their localKeyIds match. Returns NULL if not found.
174 */
175 P12CertBag *P12Coder::findCertForKey(
176 P12KeyBag *keyBag)
177 {
178 assert(keyBag != NULL);
179 CSSM_DATA &keyKeyId = keyBag->localKeyIdCssm();
180
181 for(unsigned dex=0; dex<numCerts(); dex++) {
182 P12CertBag *certBag = mCerts[dex];
183 CSSM_DATA &certKeyId = certBag->localKeyIdCssm();
184 if(nssCompareCssmData(&keyKeyId, &certKeyId)) {
185 p12DecodeLog("findCertForKey SUCCESS");
186 return certBag;
187 }
188 }
189 p12DecodeLog("findCertForKey FAILURE");
190 return NULL;
191 }
192
193 /*
194 * Export items specified as SecKeychainItemRefs.
195 */
196 void P12Coder::exportKeychainItems(
197 CFArrayRef items)
198 {
199 assert(items != NULL);
200 CFIndex numItems = CFArrayGetCount(items);
201 for(CFIndex dex=0; dex<numItems; dex++) {
202 const void *item = CFArrayGetValueAtIndex(items, dex);
203 if(item == NULL) {
204 p12ErrorLog("exportKeychainItems: NULL item\n");
205 MacOSError::throwMe(errSecParam);
206 }
207 CFTypeID itemType = CFGetTypeID(item);
208 if(itemType == SecCertificateGetTypeID()) {
209 addSecCert((SecCertificateRef)item);
210 }
211 else if(itemType == SecKeyGetTypeID()) {
212 addSecKey((SecKeyRef)item);
213 }
214 else {
215 p12ErrorLog("exportKeychainItems: unknown item\n");
216 MacOSError::throwMe(errSecParam);
217 }
218 }
219 }
220
221 /*
222 * Gross kludge to work around the fact that SecKeyRefs have no attributes which
223 * are visible at the Sec layer. Not only are the attribute names we happen
224 * to know about (Label, PrintName) not publically visible anywhere in the
225 * system, but the *format* of the attr names for SecKeyRefs differs from
226 * the format of all other SecKeychainItems (NAME_AS_STRING for SecKeys,
227 * NAME_AS_INTEGER for everything else).
228 *
229 * So. We use the privately accessible schema definition table for
230 * keys to map from the attr name strings we happen to know about to a
231 * totally private name-as-int index which we can then use in the
232 * SecKeychainItemCopyAttributesAndData mechanism.
233 *
234 * This will go away if SecKeyRef defines its actual attrs as strings, AND
235 * the SecKeychainSearch mechanism knows to specify attr names for SecKeyRefs
236 * as strings rather than integers.
237 */
238 static OSStatus attrNameToInt(
239 const char *name,
240 UInt32 *attrInt)
241 {
242 const CSSM_DB_SCHEMA_ATTRIBUTE_INFO *attrList =
243 KeySchema::KeySchemaAttributeList;
244 unsigned numAttrs = KeySchema::KeySchemaAttributeCount;
245 for(unsigned dex=0; dex<numAttrs; dex++) {
246 const CSSM_DB_SCHEMA_ATTRIBUTE_INFO *info = &attrList[dex];
247 if(!strcmp(name, info->AttributeName)) {
248 *attrInt = info->AttributeId;
249 return errSecSuccess;
250 }
251 }
252 return errSecParam;
253 }
254
255 void P12Coder::addSecKey(
256 SecKeyRef keyRef)
257 {
258 /* get the cert's attrs (not data) */
259
260 /*
261 * Convert the attr name strings we happen to know about to
262 * unknowable name-as-int values.
263 */
264 UInt32 printNameTag;
265 OSStatus ortn = attrNameToInt(P12_KEY_ATTR_PRINT_NAME, &printNameTag);
266 if(ortn) {
267 p12ErrorLog("addSecKey: problem looking up key attr name\n");
268 MacOSError::throwMe(ortn);
269 }
270 UInt32 labelHashTag;
271 ortn = attrNameToInt(P12_KEY_ATTR_LABEL_AND_HASH, &labelHashTag);
272 if(ortn) {
273 p12ErrorLog("addSecKey: problem looking up key attr name\n");
274 MacOSError::throwMe(ortn);
275 }
276
277 UInt32 tags[2];
278 tags[0] = printNameTag;
279 tags[1] = labelHashTag;
280
281 /* I don't know what the format field is for */
282 SecKeychainAttributeInfo attrInfo;
283 attrInfo.count = 2;
284 attrInfo.tag = tags;
285 attrInfo.format = NULL; // ???
286
287 /* FIXME header says this is an IN/OUT param, but it's not */
288 SecKeychainAttributeList *attrList = NULL;
289
290 ortn = SecKeychainItemCopyAttributesAndData(
291 (SecKeychainItemRef)keyRef,
292 &attrInfo,
293 NULL, // itemClass
294 &attrList,
295 NULL, // don't need the data
296 NULL);
297 if(ortn) {
298 p12ErrorLog("addSecKey: SecKeychainItemCopyAttributesAndData "
299 "error\n");
300 MacOSError::throwMe(ortn);
301 }
302
303 /* Snag the attrs, convert to something useful */
304 CFStringRef friendName = NULL;
305 CFDataRef localKeyId = NULL;
306 for(unsigned i=0; i<attrList->count; i++) {
307 SecKeychainAttribute *attr = &attrList->attr[i];
308 if(attr->tag == printNameTag) {
309 CFReleaseNull(friendName);
310 friendName = CFStringCreateWithBytes(NULL,
311 (UInt8 *)attr->data, attr->length,
312 kCFStringEncodingUTF8, false);
313 }
314 else if(attr->tag == labelHashTag) {
315 CFReleaseNull(localKeyId);
316 localKeyId = CFDataCreate(NULL, (UInt8 *)attr->data, attr->length);
317 }
318 else {
319 p12ErrorLog("addSecKey: unexpected attr tag\n");
320 MacOSError::throwMe(errSecParam);
321
322 }
323 }
324
325 /*
326 * Infer the CSP associated with this key.
327 * FIXME: this should be an attribute of the SecKeyRef itself,
328 * not inferred from the keychain it happens to be living on
329 * (SecKeyRefs should not have to be attached to Keychains at
330 * this point).
331 */
332 SecKeychainRef kcRef;
333 ortn = SecKeychainItemCopyKeychain((SecKeychainItemRef)keyRef, &kcRef);
334 if(ortn) {
335 p12ErrorLog("addSecKey: SecKeychainItemCopyKeychain returned %d\n", (int)ortn);
336 MacOSError::throwMe(ortn);
337 }
338 CSSM_CSP_HANDLE cspHand;
339 ortn = SecKeychainGetCSPHandle(kcRef, &cspHand);
340 if(ortn) {
341 p12ErrorLog("addSecKey: SecKeychainGetCSPHandle returned %d\n", (int)ortn);
342 MacOSError::throwMe(ortn);
343 }
344 CFRelease(kcRef);
345
346 /* and the CSSM_KEY itself */
347 const CSSM_KEY *cssmKey;
348 ortn = SecKeyGetCSSMKey(keyRef, &cssmKey);
349 if(ortn) {
350 p12ErrorLog("addSecKey: SecKeyGetCSSMKey returned %d\n", (int)ortn);
351 MacOSError::throwMe(ortn);
352 }
353
354 /* Cook up a key bag and save it */
355 P12KeyBag *keyBag = new P12KeyBag(cssmKey,
356 cspHand,
357 friendName, localKeyId,
358 NULL, // other attrs
359 mCoder,
360 keyRef);
361 addKey(keyBag);
362 SecKeychainItemFreeAttributesAndData(attrList, NULL);
363 if(friendName) {
364 CFRelease(friendName);
365 }
366 if(localKeyId) {
367 CFRelease(localKeyId);
368 }
369 }
370
371 void P12Coder::addSecCert(
372 SecCertificateRef certRef)
373 {
374 /* get the cert's attrs and data */
375 /* I don't know what the format field is for */
376 SecKeychainAttributeInfo attrInfo;
377 attrInfo.count = 2;
378 UInt32 tags[2] = {kSecLabelItemAttr, kSecPublicKeyHashItemAttr};
379 attrInfo.tag = tags;
380 attrInfo.format = NULL; // ???
381
382 /* FIXME header says this is an IN/OUT param, but it's not */
383 SecKeychainAttributeList *attrList = NULL;
384 UInt32 certLen;
385 void *certData;
386
387 OSStatus ortn = SecKeychainItemCopyAttributesAndData(
388 (SecKeychainItemRef)certRef,
389 &attrInfo,
390 NULL, // itemClass
391 &attrList,
392 &certLen,
393 &certData);
394 if(ortn) {
395 p12ErrorLog("addSecCert: SecKeychainItemCopyAttributesAndData "
396 "error\n");
397 MacOSError::throwMe(ortn);
398 }
399
400 /* Snag the attrs, convert to something useful */
401 CFStringRef friendName = NULL;
402 CFDataRef localKeyId = NULL;
403 for(unsigned i=0; i<attrList->count; i++) {
404 SecKeychainAttribute *attr = &attrList->attr[i];
405 switch(attr->tag) {
406 case kSecPublicKeyHashItemAttr:
407 CFReleaseNull(localKeyId);
408 localKeyId = CFDataCreate(NULL, (UInt8 *)attr->data, attr->length);
409 break;
410 case kSecLabelItemAttr:
411 CFReleaseNull(friendName);
412 /* FIXME: always in UTF8? */
413 friendName = CFStringCreateWithBytes(NULL,
414 (UInt8 *)attr->data, attr->length, kCFStringEncodingUTF8,
415 false);
416 break;
417 default:
418 SecKeychainItemFreeAttributesAndData(attrList, certData);
419 CFReleaseNull(friendName);
420 CFReleaseNull(localKeyId);
421 p12ErrorLog("addSecCert: unexpected attr tag\n");
422 MacOSError::throwMe(errSecParam);
423
424 }
425 }
426
427 /* Cook up a cert bag and save it */
428 CSSM_DATA cData = {certLen, (uint8 *)certData};
429 P12CertBag *certBag = new P12CertBag(CT_X509, cData, friendName,
430 localKeyId, NULL, mCoder);
431 addCert(certBag);
432 SecKeychainItemFreeAttributesAndData(attrList, certData);
433 if(friendName) {
434 CFRelease(friendName);
435 }
436 if(localKeyId) {
437 CFRelease(localKeyId);
438 }
439 }
440
441 /*
442 * Delete anything stored in a keychain during decode, called on
443 * decode error.
444 * Currently the only thing we have to deal with is private keys,
445 * since certs and CRLs don't get stored until the end of a successful
446 * decode.
447 */
448 void P12Coder::deleteDecodedItems()
449 {
450 if(!(mImportFlags & kSecImportKeys)) {
451 /* no keys stored, done */
452 return;
453 }
454 if(mDlDbHand.DLHandle == 0) {
455 /* no keychain, done */
456 return;
457 }
458
459 unsigned nKeys = numKeys();
460 for(unsigned dex=0; dex<nKeys; dex++) {
461 P12KeyBag *keyBag = mKeys[dex];
462 p12DeleteKey(mDlDbHand, keyBag->label());
463 }
464
465 }
466