2 * Copyright (c) 2004,2011,2013-2015 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@
23 * SecImportExportAgg.cpp - private routines used by SecImportExport.h for
24 * aggregate (PKCS12 and PKCS7) conversion.
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>
47 using namespace Security
;
48 using namespace KeychainCore
;
50 #pragma mark --- Aggregate Export routines ---
52 OSStatus
impExpPkcs12Export(
53 CFArrayRef exportReps
, // SecExportReps
54 SecItemImportExportFlags flags
, // kSecItemPemArmour, etc.
55 const SecKeyImportExportParameters
*keyParams
, // optional
56 CFMutableDataRef outData
) // output appended here
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
;
66 if( (keyParams
== NULL
) ||
67 ( (keyParams
->passphrase
== NULL
) &&
68 !(keyParams
->flags
& kSecKeySecurePassphrase
) ) ) {
69 /* passphrase mandatory */
70 return errSecPassphraseRequired
;
72 CFIndex numReps
= CFArrayGetCount(exportReps
);
74 SecImpExpDbg("impExpPkcs12Export: no items to export");
75 return errSecItemNotFound
;
79 * Build an array of SecKeychainItemRefs.
81 * Keychain is inferred from the objects to be exported. Some may be
82 * floating certs with no keychain.
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
);
92 SecKeychainItemCopyKeychain(kcItemRef
, &kcRef
);
93 /* ignore error - we do this 'til we get a kcRef */
97 /* Set up a PKCS12 encoder */
98 ortn
= SecPkcs12CoderCreate(&p12Coder
);
102 /* subsequent errors to errOut: */
104 ortn
= SecPkcs12SetKeychain(p12Coder
, kcRef
);
109 /* We need a CSPDL handle for possible secure passphrase acquisition */
110 ortn
= SecKeychainGetCSPHandle(kcRef
, &cspHand
);
112 SecImpExpDbg("SecKeychainGetCSPHandle error");
116 /* explicit passphrase, or get one ourself? */
117 ortn
= impExpPassphraseCommon(keyParams
, cspHand
, SPF_String
,
118 VP_Export
, (CFTypeRef
*)&phraseStr
, &passKey
);
122 if(phraseStr
!= NULL
) {
123 ortn
= SecPkcs12SetMACPassphrase(p12Coder
, phraseStr
);
124 CFRelease(phraseStr
);
126 SecImpExpDbg("SecPkcs12SetMACPassphrase error");
131 assert(passKey
!= NULL
);
132 ortn
= SecPkcs12SetMACPassKey(p12Coder
, passKey
);
134 SecImpExpDbg("SecPkcs12SetMACPassphrase error");
139 ortn
= SecPkcs12ExportKeychainItems(p12Coder
, exportItems
);
141 SecImpExpDbg("impExpPkcs12Export: SecPkcs12ExportKeychainItems failure");
146 ortn
= SecPkcs12Encode(p12Coder
, &tmpData
);
148 SecImpExpDbg("impExpPkcs12Export: SecPkcs12Encode failure");
152 /* append encoded data to output */
153 CFDataAppendBytes(outData
, CFDataGetBytePtr(tmpData
), CFDataGetLength(tmpData
));
156 SecPkcs12CoderRelease(p12Coder
);
157 if(passKey
!= NULL
) {
158 CSSM_FreeKey(cspHand
, NULL
, passKey
, CSSM_FALSE
);
165 CFRelease(exportItems
);
173 OSStatus
impExpPkcs7Export(
174 CFArrayRef exportReps
, // SecExportReps
175 SecItemImportExportFlags flags
, // kSecItemPemArmour, etc.
176 const SecKeyImportExportParameters
*keyParams
, // optional
177 CFMutableDataRef outData
) // output appended here
179 SecCmsSignedDataRef sigd
= NULL
;
180 SecCertificateRef certRef
;
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
};
190 SecImpExpDbg("impExpPkcs7Export: no certs to export");
191 return errSecSuccess
;
194 /* create the message object */
195 SecCmsMessageRef cmsg
= SecCmsMessageCreate(NULL
);
197 SecImpExpDbg("impExpPkcs7Export: SecCmsMessageCreate failure");
198 return errSecInternalComponent
;
202 exportRep
= (SecExportRep
*)CFArrayGetValueAtIndex(exportReps
, 0);
203 assert(exportRep
!= NULL
);
204 if(exportRep
->externType() != kSecItemTypeCertificate
) {
205 SecImpExpDbg("impExpPkcs7Export: non-cert item");
209 certRef
= (SecCertificateRef
)exportRep
->kcItem();
211 /* build chain of objects: message->signedData->data */
212 sigd
= SecCmsSignedDataCreateCertsOnly(cmsg
, certRef
, false);
214 SecImpExpDbg("impExpPkcs7Export: SecCmsSignedDataCreateCertsOnly failure");
215 ortn
= errSecInternalComponent
;
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");
227 certRef
= (SecCertificateRef
)exportRep
->kcItem();
228 ortn
= SecCmsSignedDataAddCertChain(sigd
, certRef
);
230 SecImpExpDbg("impExpPkcs7Export: SecCmsSignedDataAddCertChain error");
235 cinfo
= SecCmsMessageGetContentInfo(cmsg
);
237 SecImpExpDbg("impExpPkcs7Export: SecCmsMessageGetContentInfo returned NULL");
238 ortn
= errSecInternalComponent
;
241 ortn
= SecCmsContentInfoSetContentSignedData(cmsg
, cinfo
, sigd
);
243 SecImpExpDbg("impExpPkcs7Export: SecCmsContentInfoSetContentSignedData error");
246 cinfo
= SecCmsSignedDataGetContentInfo(sigd
);
248 SecImpExpDbg("impExpPkcs7Export: SecCmsSignedDataGetContentInfo returned NULL");
249 ortn
= errSecInternalComponent
;
252 ortn
= SecCmsContentInfoSetContentData(cmsg
, cinfo
, NULL
,
253 false /* FIXME - what's this? */);
255 SecImpExpDbg("impExpPkcs7Export: SecCmsContentInfoSetContentData error");
260 ortn
= SecArenaPoolCreate(1024, &arena
);
262 SecImpExpDbg("impExpPkcs7Export: SecArenaPoolCreate error");
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 */
271 &ecx
); /* detached digests */
273 SecImpExpDbg("impExpPkcs7Export: SecCmsEncoderCreate error");
276 ortn
= SecCmsEncoderFinish(ecx
);
278 SecImpExpDbg("impExpPkcs7Export: SecCmsEncoderFinish returned NULL");
282 /* append encoded data to output */
283 CFDataAppendBytes(outData
, output
.Data
, output
.Length
);
288 SecCmsMessageDestroy(cmsg
);
291 SecArenaPoolFree(arena
, false);
296 #pragma mark --- Aggregate Import routines ---
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.
302 OSStatus
impExpPkcs12Import(
304 SecItemImportExportFlags flags
,
305 const SecKeyImportExportParameters
*keyParams
, // optional
306 ImpPrivKeyImportState
&keyImportState
, // IN/OUT
308 /* caller must supply one of these */
309 SecKeychainRef importKeychain
, // optional
310 CSSM_CSP_HANDLE cspHand
, // required
311 CFMutableArrayRef outArray
) // optional, append here
313 SecPkcs12CoderRef p12Coder
= NULL
;
318 CFMutableArrayRef privKeys
= NULL
;
319 CSSM_KEY
*passKey
= NULL
;
320 CFStringRef phraseStr
= NULL
;
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.
328 CSSM_KEYUSE keyUsage
= CSSM_KEYUSE_ANY
;
329 CSSM_KEYATTR_FLAGS keyAttrs
= CSSM_KEYATTR_SENSITIVE
| CSSM_KEYATTR_EXTRACTABLE
|
330 CSSM_KEYATTR_RETURN_REF
;
332 if( (keyParams
== NULL
) ||
333 ( (keyParams
->passphrase
== NULL
) &&
334 !(keyParams
->flags
& kSecKeySecurePassphrase
) ) ) {
335 /* passphrase mandatory */
336 return errSecPassphraseRequired
;
340 * Set up a P12 decoder.
342 ortn
= SecPkcs12CoderCreate(&p12Coder
);
344 SecImpExpDbg("SecPkcs12CoderCreate error");
347 /* subsequent errors to errOut: */
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
;
355 assert(cspHand
!= CSSM_INVALID_HANDLE
);
356 if(importKeychain
!= NULL
) {
357 ortn
= SecPkcs12SetKeychain(p12Coder
, importKeychain
);
359 SecImpExpDbg("SecPkcs12SetKeychain error");
364 if(cspHand
== CSSM_INVALID_HANDLE
) {
368 ortn
= SecPkcs12SetCspHandle(p12Coder
, cspHand
);
370 SecImpExpDbg("SecPkcs12SetCspHandle error");
375 /* explicit passphrase, or get one ourself? */
376 ortn
= impExpPassphraseCommon(keyParams
, cspHand
, SPF_String
,
377 VP_Import
, (CFTypeRef
*)&phraseStr
, &passKey
);
381 if(phraseStr
!= NULL
) {
382 ortn
= SecPkcs12SetMACPassphrase(p12Coder
, phraseStr
);
383 CFRelease(phraseStr
);
385 SecImpExpDbg("SecPkcs12SetMACPassphrase error");
390 assert(passKey
!= NULL
);
391 ortn
= SecPkcs12SetMACPassKey(p12Coder
, passKey
);
393 SecImpExpDbg("SecPkcs12SetMACPassphrase error");
398 if(keyImportState
!= PIS_NoLimit
) {
399 bool foundOneKey
= false;
401 /* allow either zero or one more private key */
402 if(keyImportState
== PIS_NoMore
) {
405 ortn
= SecPkcs12LimitPrivateKeyImport(p12Coder
, foundOneKey
);
407 SecImpExpDbg("SecPkcs12LimitPrivateKeyImport error");
412 if(keyParams
!= NULL
) {
413 if(keyParams
->keyUsage
!= 0) {
414 keyUsage
= keyParams
->keyUsage
;
416 if(keyParams
->keyAttributes
!= 0) {
417 keyAttrs
= keyParams
->keyAttributes
;
419 if(keyParams
->flags
& kSecKeyNoAccessControl
) {
420 ortn
= SecPkcs12SetAccess(p12Coder
, NULL
);
422 SecImpExpDbg("SecPkcs12SetAccess error");
426 else if(keyParams
->accessRef
!= NULL
) {
427 ortn
= SecPkcs12SetAccess(p12Coder
, keyParams
->accessRef
);
429 SecImpExpDbg("SecPkcs12SetAccess error");
433 /* else default ACL */
435 ortn
= SecPkcs12SetKeyUsage(p12Coder
, keyUsage
);
437 SecImpExpDbg("SecPkcs12SetKeyUsage error");
440 ortn
= SecPkcs12SetKeyAttrs(p12Coder
, keyAttrs
);
442 SecImpExpDbg("SecPkcs12SetKeyAttrs error");
447 ortn
= SecPkcs12Decode(p12Coder
, inData
);
449 SecImpExpDbg("SecPkcs12Decode error");
454 * About to process SecKeychainItemRefs.
455 * This whole mess is irrelevant if the caller doesn't
456 * want an array of SecKeychainItemRefs.
458 if(outArray
== NULL
) {
462 ortn
= SecPkcs12CertificateCount(p12Coder
, &numCerts
);
464 SecImpExpDbg("SecPkcs12CertificateCount error");
467 ortn
= SecPkcs12PrivateKeyCount(p12Coder
, &numKeys
);
469 SecImpExpDbg("SecPkcs12PrivateKeyCount error");
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.
478 * FIXME we're working with a P12 module which can not
479 * vend SecKeyRefs.....this will hopefully, eventually,
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
);
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.
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;
514 ortn
= SecPkcs12CopyCertificate(p12Coder
, dex
, &certRef
,
517 /* should never happen */
518 SecImpExpDbg("SecPkcs12CopyCertificate error");
521 /* subsequent errors in this loop to loopEnd: */
523 if(importKeychain
== NULL
) {
524 /* Skip the Identity match - just return keys and certs */
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.
533 StorageManager::KeychainList keychains
;
534 globals().storageManager
.optionalSearchList(importKeychain
, keychains
);
536 /* Convert unified SecCertificateRef to an ItemImpl instance */
537 itemImplRef
= SecCertificateCreateItemImplInstance(certRef
);
539 itemImplRef
= (SecCertificateRef
)((certRef
) ? CFRetain(certRef
) : NULL
);
541 SecPointer
<Certificate
> cert
= Certificate::required(itemImplRef
);
542 CFRelease(itemImplRef
);
544 importedCertRef
= cert
->findInKeychain(keychains
)->handle();
546 if (importedCertRef
) {
547 SecCertificateRef tmpRef
= SecCertificateCreateFromItemImplInstance(importedCertRef
);
548 CFRelease(importedCertRef
);
549 importedCertRef
= tmpRef
;
553 /* Get digest of this cert's public key */
554 ortn
= SecCertificateGetData(importedCertRef
, &certData
);
556 SecImpExpDbg("SecCertificateGetData error");
559 ortn
= CSSM_CL_CertGetKeyInfo(clHand
, &certData
, &pubKey
);
561 SecImpExpDbg("SecCertificateGetData error");
564 ortn
= impExpKeyDigest(rawCspHand
, pubKey
, &pubKeyDigest
);
570 * Now search for a private key with this same digest
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
);
580 CSSM_BOOL digestMatch
= cuCompareCssmData(&pubKeyDigest
, &privKeyDigest
);
581 impExpFreeCssmMemory(cspHand
, privKeyDigest
.Data
);
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.
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.
598 SecIdentityRef idRef
= NULL
;
599 ortn
= SecIdentityCreateWithCertificate(importKeychain
,
600 importedCertRef
, &idRef
);
601 if(ortn
== errSecSuccess
) {
605 * -- add Identity to outArray
606 * -- remove privKey from privKeys array
607 * -- skip to next cert
609 SecImpExpDbg("P12Import: generating a SecIdentityRef");
610 assert(outArray
!= NULL
);
611 CFArrayAppendValue(outArray
, idRef
);
612 CFRelease(idRef
); // array holds only ref
614 CFArrayRemoveValueAtIndex(privKeys
, privDex
);
615 foundIdentity
= true;
617 } /* ID create worked, else try next key */
619 } /* searching thru privKeys */
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
);
628 CFRelease(certRef
); // outArray holds only ref
630 if (importedCertRef
) {
631 CFRelease(importedCertRef
);
632 importedCertRef
= 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
);
641 if(pubKeyDigest
.Data
!= NULL
) {
642 impExpFreeCssmMemory(rawCspHand
, pubKeyDigest
.Data
);
643 pubKeyDigest
.Data
= NULL
;
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
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
671 if(ortn
== errSecSuccess
) { // TBD OR keys are SecKeyRefs
672 numKeys
= CFArrayGetCount(privKeys
);
673 for(dex
=0; dex
<numKeys
; dex
++) {
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
);
682 SecImpExpDbg("SecKeyCreateWithCSSMKey error");
684 /* keep going for CFRelease */
688 /* TBD CFRelease the SecKeyRef */
689 } /* for each privKey */
690 } /* success so far */
694 SecPkcs12CoderRelease(p12Coder
);
695 if(passKey
!= NULL
) {
696 CSSM_FreeKey(cspHand
, NULL
, passKey
, CSSM_FALSE
);
699 if(privKeys
!= NULL
) {
703 cuClDetachUnload(clHand
);
705 if(rawCspHand
!= 0) {
706 cuCspDetachUnload(rawCspHand
, CSSM_TRUE
);
711 OSStatus
impExpPkcs7Import(
713 SecItemImportExportFlags flags
,
714 const SecKeyImportExportParameters
*keyParams
, // optional
715 SecKeychainRef importKeychain
, // optional
716 CFMutableArrayRef outArray
) // optional, append here
718 SecCmsDecoderRef decoderContext
;
719 SecCmsMessageRef cmsMessage
= NULL
;
720 SecCmsContentInfoRef contentInfo
;
721 SecCmsSignedDataRef signedData
;
722 int contentLevelCount
;
724 SECOidTag contentTypeTag
;
726 OSStatus ourRtn
= errSecSuccess
;
728 /* decode the message */
729 result
= SecCmsDecoderCreate (NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &decoderContext
);
734 result
= SecCmsDecoderUpdate(decoderContext
, CFDataGetBytePtr(inData
),
735 CFDataGetLength(inData
));
737 /* any useful status here? */
738 SecImpExpDbg("SecCmsDecoderUpdate error");
739 ourRtn
= errSecUnknownFormat
;
740 SecCmsDecoderDestroy(decoderContext
);
744 ourRtn
= SecCmsDecoderFinish(decoderContext
, &cmsMessage
);
746 SecImpExpDbg("SecCmsDecoderFinish error");
747 ourRtn
= errSecUnknownFormat
;
751 // process the results
752 contentLevelCount
= SecCmsMessageContentLevelCount (cmsMessage
);
754 for (i
= 0; i
< contentLevelCount
; ++i
)
756 // get content information
757 contentInfo
= SecCmsMessageContentLevel (cmsMessage
, i
);
758 contentTypeTag
= SecCmsContentInfoGetContentTypeTag (contentInfo
);
760 switch (contentTypeTag
)
762 case SEC_OID_PKCS7_SIGNED_DATA
:
764 /* I guess this the only interesting field */
766 (SecCmsSignedDataRef
) SecCmsContentInfoGetContent (contentInfo
);
767 if (signedData
== NULL
) {
768 SecImpExpDbg("SecCmsContentInfoGetContent returned NULL");
769 ourRtn
= errSecUnknownFormat
;
773 // import the certificates
774 CSSM_DATA
**outCerts
= SecCmsSignedDataGetCertificateList(signedData
);
775 if(outCerts
== NULL
) {
776 SecImpExpDbg("SecCmsSignedDataGetCertificateList returned NULL");
777 ourRtn
= errSecUnknownFormat
;
781 /* Returned value is NULL-terminated array */
783 CSSM_DATA
**array
= outCerts
;
790 SecImpExpDbg("No certs found in apparently good PKCS7 blob");
794 for(unsigned dex
=0; dex
<count
; dex
++) {
795 ourRtn
= impExpImportCertCommon(outCerts
[dex
], importKeychain
,
809 SecCmsMessageDestroy(cmsMessage
);
816 * Import a netscape-cert-sequence. Suitable for low-cost guessing when neither
817 * importKeychain nor outArray is specified.
819 OSStatus
impExpNetscapeCertImport(
821 SecItemImportExportFlags flags
,
822 const SecKeyImportExportParameters
*keyParams
, // optional
823 SecKeychainRef importKeychain
, // optional
824 CFMutableArrayRef outArray
) // optional, append here
827 NetscapeCertSequence certSeq
;
830 memset(&certSeq
, 0, sizeof(certSeq
));
831 PRErrorCode perr
= coder
.decode(CFDataGetBytePtr(inData
),
832 CFDataGetLength(inData
),
833 NetscapeCertSequenceTemplate
,
836 SecImpExpDbg("impExpNetscapeCertImport: DER decode failure");
837 return errSecUnknownFormat
;
840 /* verify (contentType == netscape-cert-sequence) */
841 if(!cuCompareOid(&CSSMOID_NetscapeCertSequence
, &certSeq
.contentType
)) {
842 SecImpExpDbg("impExpNetscapeCertImport: OID mismatch");
843 return errSecUnknownFormat
;
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
);
855 return errSecSuccess
;
858 #pragma mark --- Utilities ---
860 OSStatus
impExpImportCertCommon(
861 const CSSM_DATA
*cdata
,
862 SecKeychainRef importKeychain
, // optional
863 CFMutableArrayRef outArray
) // optional, append here
865 OSStatus ortn
= errSecSuccess
;
866 SecCertificateRef certRef
;
869 return errSecUnsupportedFormat
;
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 */
874 return errSecUnsupportedFormat
;
876 certRef
= SecCertificateCreateWithData(kCFAllocatorDefault
, data
);
877 CFRelease(data
); /* certRef has its own copy of the data now */
879 SecImpExpDbg("impExpHandleCert error\n");
880 return errSecUnsupportedFormat
;
883 if(importKeychain
!= NULL
) {
884 ortn
= SecCertificateAddToKeychain(certRef
, importKeychain
);
886 SecImpExpDbg("SecCertificateAddToKeychain error\n");
891 if(outArray
!= NULL
) {
892 CFArrayAppendValue(outArray
, certRef
);