]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/Security/SecImportExportAgg.cpp
7c14cfcae926c047e70f5b8d770146676b10445e
[apple/security.git] / OSX / libsecurity_keychain / Security / SecImportExportAgg.cpp
1 /*
2 * Copyright (c) 2004,2011,2013-2015 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 * SecImportExportAgg.cpp - private routines used by SecImportExport.h for
24 * aggregate (PKCS12 and PKCS7) conversion.
25 */
26
27 #include "SecImportExportAgg.h"
28 #include "SecExternalRep.h"
29 #include "SecImportExportUtils.h"
30 #include "SecNetscapeTemplates.h"
31 #include "Certificate.h"
32 #include <security_pkcs12/SecPkcs12.h>
33 #include <Security/SecBase.h>
34 #include <Security/SecCmsDecoder.h>
35 #include <Security/SecCmsEncoder.h>
36 #include <Security/SecCmsMessage.h>
37 #include <Security/SecCmsContentInfo.h>
38 #include <Security/SecCmsSignedData.h>
39 #include <security_asn1/SecNssCoder.h>
40 #include <security_asn1/nssUtils.h>
41 #include <security_cdsa_utils/cuCdsaUtils.h>
42 #include <security_keychain/Globals.h>
43 #include <Security/SecCertificatePriv.h>
44 #include <Security/SecIdentityPriv.h>
45 #include <Security/SecKeyPriv.h>
46
47 using namespace Security;
48 using namespace KeychainCore;
49
50 #pragma mark --- Aggregate Export routines ---
51
52 OSStatus impExpPkcs12Export(
53 CFArrayRef exportReps, // SecExportReps
54 SecItemImportExportFlags flags, // kSecItemPemArmour, etc.
55 const SecKeyImportExportParameters *keyParams, // optional
56 CFMutableDataRef outData) // output appended here
57 {
58 SecPkcs12CoderRef p12Coder;
59 OSStatus ortn = errSecSuccess;
60 CFMutableArrayRef exportItems; // SecKeychainItemRefs
61 CFDataRef tmpData = NULL;
62 CSSM_CSP_HANDLE cspHand;
63 CSSM_KEY *passKey = NULL;
64 CFStringRef phraseStr = NULL;
65
66 if( (keyParams == NULL) ||
67 ( (keyParams->passphrase == NULL) &&
68 !(keyParams->flags & kSecKeySecurePassphrase) ) ) {
69 /* passphrase mandatory */
70 return errSecPassphraseRequired;
71 }
72 CFIndex numReps = CFArrayGetCount(exportReps);
73 if(numReps == 0) {
74 SecImpExpDbg("impExpPkcs12Export: no items to export");
75 return errSecItemNotFound;
76 }
77
78 /*
79 * Build an array of SecKeychainItemRefs.
80 *
81 * Keychain is inferred from the objects to be exported. Some may be
82 * floating certs with no keychain.
83 */
84 exportItems = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
85 SecKeychainRef kcRef = nil;
86 for(CFIndex dex=0; dex<numReps; dex++) {
87 SecExportRep *exportRep =
88 (SecExportRep *)CFArrayGetValueAtIndex(exportReps, dex);
89 SecKeychainItemRef kcItemRef = (SecKeychainItemRef)exportRep->kcItem();
90 CFArrayAppendValue(exportItems, kcItemRef);
91 if(kcRef == nil) {
92 SecKeychainItemCopyKeychain(kcItemRef, &kcRef);
93 /* ignore error - we do this 'til we get a kcRef */
94 }
95 }
96
97 /* Set up a PKCS12 encoder */
98 ortn = SecPkcs12CoderCreate(&p12Coder);
99 if(ortn) {
100 return ortn;
101 }
102 /* subsequent errors to errOut: */
103
104 ortn = SecPkcs12SetKeychain(p12Coder, kcRef);
105 if(ortn) {
106 goto errOut;
107 }
108
109 /* We need a CSPDL handle for possible secure passphrase acquisition */
110 ortn = SecKeychainGetCSPHandle(kcRef, &cspHand);
111 if(ortn) {
112 SecImpExpDbg("SecKeychainGetCSPHandle error");
113 goto errOut;
114 }
115
116 /* explicit passphrase, or get one ourself? */
117 ortn = impExpPassphraseCommon(keyParams, cspHand, SPF_String,
118 VP_Export, (CFTypeRef *)&phraseStr, &passKey);
119 if(ortn) {
120 goto errOut;
121 }
122 if(phraseStr != NULL) {
123 ortn = SecPkcs12SetMACPassphrase(p12Coder, phraseStr);
124 CFRelease(phraseStr);
125 if(ortn) {
126 SecImpExpDbg("SecPkcs12SetMACPassphrase error");
127 goto errOut;
128 }
129 }
130 else {
131 assert(passKey != NULL);
132 ortn = SecPkcs12SetMACPassKey(p12Coder, passKey);
133 if(ortn) {
134 SecImpExpDbg("SecPkcs12SetMACPassphrase error");
135 goto errOut;
136 }
137 }
138
139 ortn = SecPkcs12ExportKeychainItems(p12Coder, exportItems);
140 if(ortn) {
141 SecImpExpDbg("impExpPkcs12Export: SecPkcs12ExportKeychainItems failure");
142 goto errOut;
143 }
144
145 /* GO */
146 ortn = SecPkcs12Encode(p12Coder, &tmpData);
147 if(ortn) {
148 SecImpExpDbg("impExpPkcs12Export: SecPkcs12Encode failure");
149 goto errOut;
150 }
151
152 /* append encoded data to output */
153 CFDataAppendBytes(outData, CFDataGetBytePtr(tmpData), CFDataGetLength(tmpData));
154
155 errOut:
156 SecPkcs12CoderRelease(p12Coder);
157 if(passKey != NULL) {
158 CSSM_FreeKey(cspHand, NULL, passKey, CSSM_FALSE);
159 free(passKey);
160 }
161 if(kcRef) {
162 CFRelease(kcRef);
163 }
164 if(exportItems) {
165 CFRelease(exportItems);
166 }
167 if(tmpData) {
168 CFRelease(tmpData);
169 }
170 return ortn;
171 }
172
173 OSStatus impExpPkcs7Export(
174 CFArrayRef exportReps, // SecExportReps
175 SecItemImportExportFlags flags, // kSecItemPemArmour, etc.
176 const SecKeyImportExportParameters *keyParams, // optional
177 CFMutableDataRef outData) // output appended here
178 {
179 SecCmsSignedDataRef sigd = NULL;
180 SecCertificateRef certRef;
181 OSStatus ortn;
182 CFIndex numCerts = CFArrayGetCount(exportReps);
183 SecExportRep *exportRep;
184 SecCmsContentInfoRef cinfo = NULL;
185 SecArenaPoolRef arena = NULL;
186 SecCmsEncoderRef ecx;
187 CSSM_DATA output = { 0, NULL };
188
189 if(numCerts == 0) {
190 SecImpExpDbg("impExpPkcs7Export: no certs to export");
191 return errSecSuccess;
192 }
193
194 /* create the message object */
195 SecCmsMessageRef cmsg = SecCmsMessageCreate(NULL);
196 if(cmsg == NULL) {
197 SecImpExpDbg("impExpPkcs7Export: SecCmsMessageCreate failure");
198 return errSecInternalComponent;
199 }
200
201 /* get first cert */
202 exportRep = (SecExportRep *)CFArrayGetValueAtIndex(exportReps, 0);
203 assert(exportRep != NULL);
204 if(exportRep->externType() != kSecItemTypeCertificate) {
205 SecImpExpDbg("impExpPkcs7Export: non-cert item");
206 ortn = errSecParam;
207 goto errOut;
208 }
209 certRef = (SecCertificateRef)exportRep->kcItem();
210
211 /* build chain of objects: message->signedData->data */
212 sigd = SecCmsSignedDataCreateCertsOnly(cmsg, certRef, false);
213 if(sigd == NULL) {
214 SecImpExpDbg("impExpPkcs7Export: SecCmsSignedDataCreateCertsOnly failure");
215 ortn = errSecInternalComponent;
216 goto errOut;
217 }
218
219 for (CFIndex dex=1; dex<numCerts; dex++) {
220 exportRep = (SecExportRep *)CFArrayGetValueAtIndex(exportReps, dex);
221 assert(exportRep != NULL);
222 if(exportRep->externType() != kSecItemTypeCertificate) {
223 SecImpExpDbg("impExpPkcs7Export: non-cert item");
224 ortn = errSecParam;
225 goto errOut;
226 }
227 certRef = (SecCertificateRef)exportRep->kcItem();
228 ortn = SecCmsSignedDataAddCertChain(sigd, certRef);
229 if(ortn) {
230 SecImpExpDbg("impExpPkcs7Export: SecCmsSignedDataAddCertChain error");
231 goto errOut;
232 }
233 }
234
235 cinfo = SecCmsMessageGetContentInfo(cmsg);
236 if(cinfo == NULL) {
237 SecImpExpDbg("impExpPkcs7Export: SecCmsMessageGetContentInfo returned NULL");
238 ortn = errSecInternalComponent;
239 goto errOut;
240 }
241 ortn = SecCmsContentInfoSetContentSignedData(cmsg, cinfo, sigd);
242 if(ortn) {
243 SecImpExpDbg("impExpPkcs7Export: SecCmsContentInfoSetContentSignedData error");
244 goto errOut;
245 }
246 cinfo = SecCmsSignedDataGetContentInfo(sigd);
247 if(cinfo == NULL) {
248 SecImpExpDbg("impExpPkcs7Export: SecCmsSignedDataGetContentInfo returned NULL");
249 ortn = errSecInternalComponent;
250 goto errOut;
251 }
252 ortn = SecCmsContentInfoSetContentData(cmsg, cinfo, NULL,
253 false /* FIXME - what's this? */);
254 if(ortn) {
255 SecImpExpDbg("impExpPkcs7Export: SecCmsContentInfoSetContentData error");
256 goto errOut;
257 }
258
259 /* Now encode it */
260 ortn = SecArenaPoolCreate(1024, &arena);
261 if(ortn) {
262 SecImpExpDbg("impExpPkcs7Export: SecArenaPoolCreate error");
263 goto errOut;
264 }
265 ortn = SecCmsEncoderCreate(cmsg,
266 NULL, NULL, /* DER output callback */
267 &output, arena, /* destination storage */
268 NULL, NULL, /* password callback */
269 NULL, NULL, /* decrypt key callback */
270 NULL, NULL,
271 &ecx ); /* detached digests */
272 if(ortn) {
273 SecImpExpDbg("impExpPkcs7Export: SecCmsEncoderCreate error");
274 goto errOut;
275 }
276 ortn = SecCmsEncoderFinish(ecx);
277 if(ortn) {
278 SecImpExpDbg("impExpPkcs7Export: SecCmsEncoderFinish returned NULL");
279 goto errOut;
280 }
281
282 /* append encoded data to output */
283 CFDataAppendBytes(outData, output.Data, output.Length);
284
285
286 errOut:
287 if(cmsg != NULL) {
288 SecCmsMessageDestroy(cmsg);
289 }
290 if(arena != NULL) {
291 SecArenaPoolFree(arena, false);
292 }
293 return ortn;
294 }
295
296 #pragma mark --- Aggregate Import routines ---
297
298 /*
299 * For all of these, if a cspHand is specified instead of a keychain,
300 * the cspHand MUST be a CSPDL handle, not a raw CSP handle.
301 */
302 OSStatus impExpPkcs12Import(
303 CFDataRef inData,
304 SecItemImportExportFlags flags,
305 const SecKeyImportExportParameters *keyParams, // optional
306 ImpPrivKeyImportState &keyImportState, // IN/OUT
307
308 /* caller must supply one of these */
309 SecKeychainRef importKeychain, // optional
310 CSSM_CSP_HANDLE cspHand, // required
311 CFMutableArrayRef outArray) // optional, append here
312 {
313 SecPkcs12CoderRef p12Coder = NULL;
314 OSStatus ortn;
315 CFIndex numCerts;
316 CFIndex numKeys;
317 CFIndex dex;
318 CFMutableArrayRef privKeys = NULL;
319 CSSM_KEY *passKey = NULL;
320 CFStringRef phraseStr = NULL;
321
322 /*
323 * Optional private key attrs.
324 * Although the PKCS12 library has its own defaults for these, we'll
325 * set them explicitly to the defaults specified in our API if the
326 * caller doesn't specify any.
327 */
328 CSSM_KEYUSE keyUsage = CSSM_KEYUSE_ANY;
329 CSSM_KEYATTR_FLAGS keyAttrs = CSSM_KEYATTR_SENSITIVE | CSSM_KEYATTR_EXTRACTABLE |
330 CSSM_KEYATTR_RETURN_REF;
331
332 if( (keyParams == NULL) ||
333 ( (keyParams->passphrase == NULL) &&
334 !(keyParams->flags & kSecKeySecurePassphrase) ) ) {
335 /* passphrase mandatory */
336 return errSecPassphraseRequired;
337 }
338
339 /*
340 * Set up a P12 decoder.
341 */
342 ortn = SecPkcs12CoderCreate(&p12Coder);
343 if(ortn) {
344 SecImpExpDbg("SecPkcs12CoderCreate error");
345 return ortn;
346 }
347 /* subsequent errors to errOut: */
348
349 CSSM_CL_HANDLE clHand = cuClStartup();
350 CSSM_CSP_HANDLE rawCspHand = cuCspStartup(CSSM_TRUE); // for CL
351 if((clHand == 0) || (rawCspHand == 0)) {
352 return CSSMERR_CSSM_ADDIN_LOAD_FAILED;
353 }
354
355 assert(cspHand != CSSM_INVALID_HANDLE);
356 if(importKeychain != NULL) {
357 ortn = SecPkcs12SetKeychain(p12Coder, importKeychain);
358 if(ortn) {
359 SecImpExpDbg("SecPkcs12SetKeychain error");
360 goto errOut;
361 }
362 }
363 else {
364 if(cspHand == CSSM_INVALID_HANDLE) {
365 ortn = errSecParam;
366 goto errOut;
367 }
368 ortn = SecPkcs12SetCspHandle(p12Coder, cspHand);
369 if(ortn) {
370 SecImpExpDbg("SecPkcs12SetCspHandle error");
371 goto errOut;
372 }
373 }
374
375 /* explicit passphrase, or get one ourself? */
376 ortn = impExpPassphraseCommon(keyParams, cspHand, SPF_String,
377 VP_Import, (CFTypeRef *)&phraseStr, &passKey);
378 if(ortn) {
379 goto errOut;
380 }
381 if(phraseStr != NULL) {
382 ortn = SecPkcs12SetMACPassphrase(p12Coder, phraseStr);
383 CFRelease(phraseStr);
384 if(ortn) {
385 SecImpExpDbg("SecPkcs12SetMACPassphrase error");
386 goto errOut;
387 }
388 }
389 else {
390 assert(passKey != NULL);
391 ortn = SecPkcs12SetMACPassKey(p12Coder, passKey);
392 if(ortn) {
393 SecImpExpDbg("SecPkcs12SetMACPassphrase error");
394 goto errOut;
395 }
396 }
397
398 if(keyImportState != PIS_NoLimit) {
399 bool foundOneKey = false;
400
401 /* allow either zero or one more private key */
402 if(keyImportState == PIS_NoMore) {
403 foundOneKey = true;
404 }
405 ortn = SecPkcs12LimitPrivateKeyImport(p12Coder, foundOneKey);
406 if(ortn) {
407 SecImpExpDbg("SecPkcs12LimitPrivateKeyImport error");
408 goto errOut;
409 }
410 }
411
412 if(keyParams != NULL) {
413 if(keyParams->keyUsage != 0) {
414 keyUsage = keyParams->keyUsage;
415 }
416 if(keyParams->keyAttributes != 0) {
417 keyAttrs = keyParams->keyAttributes;
418 }
419 if(keyParams->flags & kSecKeyNoAccessControl) {
420 ortn = SecPkcs12SetAccess(p12Coder, NULL);
421 if(ortn) {
422 SecImpExpDbg("SecPkcs12SetAccess error");
423 goto errOut;
424 }
425 }
426 else if(keyParams->accessRef != NULL) {
427 ortn = SecPkcs12SetAccess(p12Coder, keyParams->accessRef);
428 if(ortn) {
429 SecImpExpDbg("SecPkcs12SetAccess error");
430 goto errOut;
431 }
432 }
433 /* else default ACL */
434 }
435 ortn = SecPkcs12SetKeyUsage(p12Coder, keyUsage);
436 if(ortn) {
437 SecImpExpDbg("SecPkcs12SetKeyUsage error");
438 goto errOut;
439 }
440 ortn = SecPkcs12SetKeyAttrs(p12Coder, keyAttrs);
441 if(ortn) {
442 SecImpExpDbg("SecPkcs12SetKeyAttrs error");
443 goto errOut;
444 }
445
446 /* GO */
447 ortn = SecPkcs12Decode(p12Coder, inData);
448 if(ortn) {
449 SecImpExpDbg("SecPkcs12Decode error");
450 goto errOut;
451 }
452
453 /*
454 * About to process SecKeychainItemRefs.
455 * This whole mess is irrelevant if the caller doesn't
456 * want an array of SecKeychainItemRefs.
457 */
458 if(outArray == NULL) {
459 goto errOut;
460 }
461
462 ortn = SecPkcs12CertificateCount(p12Coder, &numCerts);
463 if(ortn) {
464 SecImpExpDbg("SecPkcs12CertificateCount error");
465 goto errOut;
466 }
467 ortn = SecPkcs12PrivateKeyCount(p12Coder, &numKeys);
468 if(ortn) {
469 SecImpExpDbg("SecPkcs12PrivateKeyCount error");
470 goto errOut;
471 }
472
473 /*
474 * Match up certs and keys to create SecIdentityRefs.
475 * First create a temporary array of the private keys
476 * found by the P12 module.
477 *
478 * FIXME we're working with a P12 module which can not
479 * vend SecKeyRefs.....this will hopefully, eventually,
480 * change.
481 */
482 privKeys = CFArrayCreateMutable(NULL, numKeys, NULL);
483 for(dex=0; dex<numKeys; dex++) {
484 CSSM_KEY_PTR privKey;
485 ortn = SecPkcs12GetCssmPrivateKey(p12Coder,
486 dex, &privKey, NULL, NULL, NULL);
487 CFArrayAppendValue(privKeys, privKey);
488 }
489
490 /*
491 * Now go through all certs, searching for a matching private
492 * key. When we find a match we try to create an identity from the
493 * cert, which might fail for a number of reasons, currently including
494 * the fact that there is no way to create an identity with a key
495 * which does not reside on a keychain. (Such is the case here when
496 * caller has not specified a keychain.) If that works we skip the
497 * cert, delete that key from the privKeys array, and append the
498 * indentity to outArray. If no identity is found we append the
499 * cert to outArray. At the end of this loop, remaining
500 * items in privKeys (of which there will typically be none) are
501 * also appended to outArray.
502 */
503 for(dex=0; dex<numCerts; dex++) {
504 SecCertificateRef certRef = NULL; // created by P12
505 SecCertificateRef importedCertRef = NULL; // owned by Sec layer
506 SecCertificateRef itemImplRef = NULL; // temp, retained by us
507 CSSM_KEY_PTR pubKey = NULL; // mallocd by CL
508 CSSM_KEY_PTR privKey = NULL; // owned by P12
509 CSSM_DATA certData; // owned by Sec layer
510 CSSM_DATA pubKeyDigest = {0, NULL}; // mallocd by CSP
511 CSSM_DATA privKeyDigest = {0, NULL}; // mallocd by CSP
512 bool foundIdentity = false;
513
514 ortn = SecPkcs12CopyCertificate(p12Coder, dex, &certRef,
515 NULL, NULL, NULL);
516 if(ortn) {
517 /* should never happen */
518 SecImpExpDbg("SecPkcs12CopyCertificate error");
519 goto errOut;
520 }
521 /* subsequent errors in this loop to loopEnd: */
522
523 if(importKeychain == NULL) {
524 /* Skip the Identity match - just return keys and certs */
525 goto loopEnd;
526 }
527
528 /* the SecPkcs12CopyCertificate function returns a floating
529 * certificate without a keychain. We must update it now that
530 * it has been added to importKeychain.
531 */
532 {
533 StorageManager::KeychainList keychains;
534 globals().storageManager.optionalSearchList(importKeychain, keychains);
535 #if SECTRUST_OSX
536 /* Convert unified SecCertificateRef to an ItemImpl instance */
537 itemImplRef = SecCertificateCreateItemImplInstance(certRef);
538 #else
539 itemImplRef = (SecCertificateRef)((certRef) ? CFRetain(certRef) : NULL);
540 #endif
541 SecPointer<Certificate> cert = Certificate::required(itemImplRef);
542 CFRelease(itemImplRef);
543 itemImplRef = NULL;
544 importedCertRef = cert->findInKeychain(keychains)->handle();
545 #if SECTRUST_OSX
546 if (importedCertRef) {
547 SecCertificateRef tmpRef = SecCertificateCreateFromItemImplInstance(importedCertRef);
548 CFRelease(importedCertRef);
549 importedCertRef = tmpRef;
550 }
551 #endif
552 }
553 /* Get digest of this cert's public key */
554 ortn = SecCertificateGetData(importedCertRef, &certData);
555 if(ortn) {
556 SecImpExpDbg("SecCertificateGetData error");
557 goto loopEnd;
558 }
559 ortn = CSSM_CL_CertGetKeyInfo(clHand, &certData, &pubKey);
560 if(ortn) {
561 SecImpExpDbg("SecCertificateGetData error");
562 goto loopEnd;
563 }
564 ortn = impExpKeyDigest(rawCspHand, pubKey, &pubKeyDigest);
565 if(ortn) {
566 goto loopEnd;
567 }
568
569 /*
570 * Now search for a private key with this same digest
571 */
572 numKeys = CFArrayGetCount(privKeys);
573 for(CFIndex privDex=0; privDex<numKeys; privDex++) {
574 privKey = (CSSM_KEY_PTR)CFArrayGetValueAtIndex(privKeys, privDex);
575 assert(privKey != NULL);
576 ortn = impExpKeyDigest(cspHand, privKey, &privKeyDigest);
577 if(ortn) {
578 goto loopEnd;
579 }
580 CSSM_BOOL digestMatch = cuCompareCssmData(&pubKeyDigest, &privKeyDigest);
581 impExpFreeCssmMemory(cspHand, privKeyDigest.Data);
582 if(digestMatch) {
583 /*
584 * MATCH: try to cook up Identity.
585 * TBD: I expect some work will be needed here when
586 * Sec layer can handle floating keys. One thing
587 * that would be nice would be if we could create an identity
588 * FROM a given SecCertRef and a SecKeyRef, even if
589 * the SecKeyRef is floating.
590 *
591 * NOTE: you might think that we could do a
592 * SecIdentityCreateWithCertificate() before, or even without,
593 * doing a digest match....but that could "work" without
594 * us having imported any keys at all, if the appropriate
595 * private key were already there. Doing the digest match
596 * guarantees the uniqueness of the key item in the DB.
597 */
598 SecIdentityRef idRef = NULL;
599 ortn = SecIdentityCreateWithCertificate(importKeychain,
600 importedCertRef, &idRef);
601 if(ortn == errSecSuccess) {
602 /*
603 * Got one!
604 *
605 * -- add Identity to outArray
606 * -- remove privKey from privKeys array
607 * -- skip to next cert
608 */
609 SecImpExpDbg("P12Import: generating a SecIdentityRef");
610 assert(outArray != NULL);
611 CFArrayAppendValue(outArray, idRef);
612 CFRelease(idRef); // array holds only ref
613 idRef = NULL;
614 CFArrayRemoveValueAtIndex(privKeys, privDex);
615 foundIdentity = true;
616 goto loopEnd;
617 } /* ID create worked, else try next key */
618 } /* digest match */
619 } /* searching thru privKeys */
620 loopEnd:
621 /* free resources allocated in this loop */
622 assert(certRef != NULL);
623 if(!foundIdentity ) {
624 /* No private key for this cert: give to caller */
625 assert(outArray != NULL);
626 CFArrayAppendValue(outArray, certRef);
627 }
628 CFRelease(certRef); // outArray holds only ref
629 certRef = NULL;
630 if (importedCertRef) {
631 CFRelease(importedCertRef);
632 importedCertRef = NULL;
633 }
634 if(pubKey != NULL) {
635 /* technically invalid, the CL used some CSP handle we
636 * don't have access to to get this... */
637 CSSM_FreeKey(rawCspHand, NULL, pubKey, CSSM_FALSE);
638 impExpFreeCssmMemory(clHand, pubKey);
639 pubKey = NULL;
640 }
641 if(pubKeyDigest.Data != NULL) {
642 impExpFreeCssmMemory(rawCspHand, pubKeyDigest.Data);
643 pubKeyDigest.Data = NULL;
644 }
645 if(ortn) {
646 goto errOut;
647 }
648 }
649
650 errOut:
651 /*
652 * One last thing: pass any remaining (non-identity) keys to caller.
653 * For now, the keys are CSSM_KEYs owned by the P12 coder object, we
654 * don't have to release them. When P12 can vend SecKeyRefs, we release the
655 * keys here.
656 */
657
658 /*
659 The code below has no net effect, except for generating a leak. This was
660 found while investigating
661 <rdar://problem/8799913> SecItemImport() leaking
662 Code like this will need to be added when we return SecIdentityRefs in
663 the "in memory" case (destKeychain = NULL). Currently, when importing to
664 a physical keychain, the returned item array contains SecIdentityRefs,
665 whereas the "in memory" case returns SecCertificateRefs. See
666 <rdar://problem/8862809> ER: SecItemImport should return SecIdentityRefs in the "in memory" case
667
668 */
669 #if 0
670 if(privKeys) {
671 if(ortn == errSecSuccess) { // TBD OR keys are SecKeyRefs
672 numKeys = CFArrayGetCount(privKeys);
673 for(dex=0; dex<numKeys; dex++) {
674 SecKeyRef keyRef;
675 CSSM_KEY_PTR privKey =
676 (CSSM_KEY_PTR)CFArrayGetValueAtIndex(privKeys, dex);
677 assert(privKey != NULL);
678 if(ortn == errSecSuccess) {
679 /* only do this on complete success so far */
680 ortn = SecKeyCreateWithCSSMKey(privKey, &keyRef);
681 if(ortn) {
682 SecImpExpDbg("SecKeyCreateWithCSSMKey error");
683 }
684 /* keep going for CFRelease */
685 if (keyRef)
686 CFRelease(keyRef);
687 }
688 /* TBD CFRelease the SecKeyRef */
689 } /* for each privKey */
690 } /* success so far */
691 }
692 #endif
693
694 SecPkcs12CoderRelease(p12Coder);
695 if(passKey != NULL) {
696 CSSM_FreeKey(cspHand, NULL, passKey, CSSM_FALSE);
697 free(passKey);
698 }
699 if(privKeys != NULL) {
700 CFRelease(privKeys);
701 }
702 if(clHand != 0) {
703 cuClDetachUnload(clHand);
704 }
705 if(rawCspHand != 0) {
706 cuCspDetachUnload(rawCspHand, CSSM_TRUE);
707 }
708 return ortn;
709 }
710
711 OSStatus impExpPkcs7Import(
712 CFDataRef inData,
713 SecItemImportExportFlags flags,
714 const SecKeyImportExportParameters *keyParams, // optional
715 SecKeychainRef importKeychain, // optional
716 CFMutableArrayRef outArray) // optional, append here
717 {
718 SecCmsDecoderRef decoderContext;
719 SecCmsMessageRef cmsMessage = NULL;
720 SecCmsContentInfoRef contentInfo;
721 SecCmsSignedDataRef signedData;
722 int contentLevelCount;
723 int i;
724 SECOidTag contentTypeTag;
725 OSStatus result;
726 OSStatus ourRtn = errSecSuccess;
727
728 /* decode the message */
729 result = SecCmsDecoderCreate (NULL, NULL, NULL, NULL, NULL, NULL, NULL, &decoderContext);
730 if (result != 0) {
731 ourRtn = result;
732 goto errOut;
733 }
734 result = SecCmsDecoderUpdate(decoderContext, CFDataGetBytePtr(inData),
735 CFDataGetLength(inData));
736 if (result != 0) {
737 /* any useful status here? */
738 SecImpExpDbg("SecCmsDecoderUpdate error");
739 ourRtn = errSecUnknownFormat;
740 SecCmsDecoderDestroy(decoderContext);
741 goto errOut;
742 }
743
744 ourRtn = SecCmsDecoderFinish(decoderContext, &cmsMessage);
745 if (ourRtn) {
746 SecImpExpDbg("SecCmsDecoderFinish error");
747 ourRtn = errSecUnknownFormat;
748 goto errOut;
749 }
750
751 // process the results
752 contentLevelCount = SecCmsMessageContentLevelCount (cmsMessage);
753
754 for (i = 0; i < contentLevelCount; ++i)
755 {
756 // get content information
757 contentInfo = SecCmsMessageContentLevel (cmsMessage, i);
758 contentTypeTag = SecCmsContentInfoGetContentTypeTag (contentInfo);
759
760 switch (contentTypeTag)
761 {
762 case SEC_OID_PKCS7_SIGNED_DATA:
763 {
764 /* I guess this the only interesting field */
765 signedData =
766 (SecCmsSignedDataRef) SecCmsContentInfoGetContent (contentInfo);
767 if (signedData == NULL) {
768 SecImpExpDbg("SecCmsContentInfoGetContent returned NULL");
769 ourRtn = errSecUnknownFormat;
770 goto errOut;
771 }
772
773 // import the certificates
774 CSSM_DATA **outCerts = SecCmsSignedDataGetCertificateList(signedData);
775 if(outCerts == NULL) {
776 SecImpExpDbg("SecCmsSignedDataGetCertificateList returned NULL");
777 ourRtn = errSecUnknownFormat;
778 goto errOut;
779 }
780
781 /* Returned value is NULL-terminated array */
782 unsigned count = 0;
783 CSSM_DATA **array = outCerts;
784 if (array) {
785 while (*array++) {
786 count++;
787 }
788 }
789 if(count == 0) {
790 SecImpExpDbg("No certs found in apparently good PKCS7 blob");
791 goto errOut;
792 }
793
794 for(unsigned dex=0; dex<count; dex++) {
795 ourRtn = impExpImportCertCommon(outCerts[dex], importKeychain,
796 outArray);
797 if(ourRtn) {
798 goto errOut;
799 }
800 }
801 break;
802 }
803 default:
804 break;
805 }
806 }
807 errOut:
808 if(cmsMessage) {
809 SecCmsMessageDestroy(cmsMessage);
810 }
811 return ourRtn;
812
813 }
814
815 /*
816 * Import a netscape-cert-sequence. Suitable for low-cost guessing when neither
817 * importKeychain nor outArray is specified.
818 */
819 OSStatus impExpNetscapeCertImport(
820 CFDataRef inData,
821 SecItemImportExportFlags flags,
822 const SecKeyImportExportParameters *keyParams, // optional
823 SecKeychainRef importKeychain, // optional
824 CFMutableArrayRef outArray) // optional, append here
825 {
826 SecNssCoder coder;
827 NetscapeCertSequence certSeq;
828
829 /* DER-decode */
830 memset(&certSeq, 0, sizeof(certSeq));
831 PRErrorCode perr = coder.decode(CFDataGetBytePtr(inData),
832 CFDataGetLength(inData),
833 NetscapeCertSequenceTemplate,
834 &certSeq);
835 if(perr) {
836 SecImpExpDbg("impExpNetscapeCertImport: DER decode failure");
837 return errSecUnknownFormat;
838 }
839
840 /* verify (contentType == netscape-cert-sequence) */
841 if(!cuCompareOid(&CSSMOID_NetscapeCertSequence, &certSeq.contentType)) {
842 SecImpExpDbg("impExpNetscapeCertImport: OID mismatch");
843 return errSecUnknownFormat;
844 }
845
846 /* Extract certs in CSSM_DATA form, return to caller */
847 unsigned numCerts = nssArraySize((const void **)certSeq.certs);
848 for(unsigned i=0; i<numCerts; i++) {
849 CSSM_DATA *cert = certSeq.certs[i];
850 OSStatus ortn = impExpImportCertCommon(cert, importKeychain, outArray);
851 if(ortn) {
852 return ortn;
853 }
854 }
855 return errSecSuccess;
856 }
857
858 #pragma mark --- Utilities ---
859
860 OSStatus impExpImportCertCommon(
861 const CSSM_DATA *cdata,
862 SecKeychainRef importKeychain, // optional
863 CFMutableArrayRef outArray) // optional, append here
864 {
865 OSStatus ortn = errSecSuccess;
866 SecCertificateRef certRef;
867
868 if (!cdata)
869 return errSecUnsupportedFormat;
870
871 CFDataRef data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)cdata->Data, (CFIndex)cdata->Length, kCFAllocatorNull);
872 /* Pass kCFAllocatorNull as bytesDeallocator to assure the bytes aren't freed */
873 if (!data)
874 return errSecUnsupportedFormat;
875
876 certRef = SecCertificateCreateWithData(kCFAllocatorDefault, data);
877 CFRelease(data); /* certRef has its own copy of the data now */
878 if(!certRef) {
879 SecImpExpDbg("impExpHandleCert error\n");
880 return errSecUnsupportedFormat;
881 }
882
883 if(importKeychain != NULL) {
884 ortn = SecCertificateAddToKeychain(certRef, importKeychain);
885 if(ortn) {
886 SecImpExpDbg("SecCertificateAddToKeychain error\n");
887 CFRelease(certRef);
888 return ortn;
889 }
890 }
891 if(outArray != NULL) {
892 CFArrayAppendValue(outArray, certRef);
893 }
894 CFRelease(certRef);
895 return ortn;
896 }
897