2 * Copyright (c) 2004 Apple Computer, 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 <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
33 #include <security_pkcs12/SecPkcs12.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/SecIdentityPriv.h>
44 #include <Security/SecKeyPriv.h>
46 using namespace Security
;
47 using namespace KeychainCore
;
49 #pragma mark --- Aggregate Export routines ---
51 OSStatus
impExpPkcs12Export(
52 CFArrayRef exportReps
, // SecExportReps
53 SecItemImportExportFlags flags
, // kSecItemPemArmour, etc.
54 const SecKeyImportExportParameters
*keyParams
, // optional
55 CFMutableDataRef outData
) // output appended here
57 SecPkcs12CoderRef p12Coder
;
58 OSStatus ortn
= noErr
;
59 CFMutableArrayRef exportItems
; // SecKeychainItemRefs
60 CFDataRef tmpData
= NULL
;
61 CSSM_CSP_HANDLE cspHand
;
62 CSSM_KEY
*passKey
= NULL
;
63 CFStringRef phraseStr
= NULL
;
65 if( (keyParams
== NULL
) ||
66 ( (keyParams
->passphrase
== NULL
) &&
67 !(keyParams
->flags
& kSecKeySecurePassphrase
) ) ) {
68 /* passphrase mandatory */
69 return errSecPassphraseRequired
;
71 CFIndex numReps
= CFArrayGetCount(exportReps
);
73 SecImpExpDbg("impExpPkcs12Export: no items to export");
74 return errSecItemNotFound
;
78 * Build an array of SecKeychainItemRefs.
80 * Keychain is inferred from the objects to be exported. Some may be
81 * floating certs with no keychain.
83 exportItems
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
84 SecKeychainRef kcRef
= nil
;
85 for(CFIndex dex
=0; dex
<numReps
; dex
++) {
86 SecExportRep
*exportRep
=
87 (SecExportRep
*)CFArrayGetValueAtIndex(exportReps
, dex
);
88 SecKeychainItemRef kcItemRef
= (SecKeychainItemRef
)exportRep
->kcItem();
89 CFArrayAppendValue(exportItems
, kcItemRef
);
91 SecKeychainItemCopyKeychain(kcItemRef
, &kcRef
);
92 /* ignore error - we do this 'til we get a kcRef */
96 /* Set up a PKCS12 encoder */
97 ortn
= SecPkcs12CoderCreate(&p12Coder
);
101 /* subsequent errors to errOut: */
103 ortn
= SecPkcs12SetKeychain(p12Coder
, kcRef
);
108 /* We need a CSPDL handle for possible secure passphrase acquisition */
109 ortn
= SecKeychainGetCSPHandle(kcRef
, &cspHand
);
111 SecImpExpDbg("SecKeychainGetCSPHandle error");
115 /* explicit passphrase, or get one ourself? */
116 ortn
= impExpPassphraseCommon(keyParams
, cspHand
, SPF_String
,
117 VP_Export
, (CFTypeRef
*)&phraseStr
, &passKey
);
121 if(phraseStr
!= NULL
) {
122 ortn
= SecPkcs12SetMACPassphrase(p12Coder
, phraseStr
);
123 CFRelease(phraseStr
);
125 SecImpExpDbg("SecPkcs12SetMACPassphrase error");
130 assert(passKey
!= NULL
);
131 ortn
= SecPkcs12SetMACPassKey(p12Coder
, passKey
);
133 SecImpExpDbg("SecPkcs12SetMACPassphrase error");
138 ortn
= SecPkcs12ExportKeychainItems(p12Coder
, exportItems
);
140 SecImpExpDbg("impExpPkcs12Export: SecPkcs12ExportKeychainItems failure");
145 ortn
= SecPkcs12Encode(p12Coder
, &tmpData
);
147 SecImpExpDbg("impExpPkcs12Export: SecPkcs12Encode failure");
151 /* append encoded data to output */
152 CFDataAppendBytes(outData
, CFDataGetBytePtr(tmpData
), CFDataGetLength(tmpData
));
155 SecPkcs12CoderRelease(p12Coder
);
156 if(passKey
!= NULL
) {
157 CSSM_FreeKey(cspHand
, NULL
, passKey
, CSSM_FALSE
);
164 CFRelease(exportItems
);
172 OSStatus
impExpPkcs7Export(
173 CFArrayRef exportReps
, // SecExportReps
174 SecItemImportExportFlags flags
, // kSecItemPemArmour, etc.
175 const SecKeyImportExportParameters
*keyParams
, // optional
176 CFMutableDataRef outData
) // output appended here
178 SecCmsSignedDataRef sigd
= NULL
;
179 SecCertificateRef certRef
;
181 CFIndex numCerts
= CFArrayGetCount(exportReps
);
182 SecExportRep
*exportRep
;
183 SecCmsContentInfoRef cinfo
= NULL
;
184 SecArenaPoolRef arena
= NULL
;
185 SecCmsEncoderRef ecx
;
186 CSSM_DATA output
= { 0, NULL
};
189 SecImpExpDbg("impExpPkcs7Export: no certs to export");
193 /* create the message object */
194 SecCmsMessageRef cmsg
= SecCmsMessageCreate(NULL
);
196 SecImpExpDbg("impExpPkcs7Export: SecCmsMessageCreate failure");
197 return internalComponentErr
;
201 exportRep
= (SecExportRep
*)CFArrayGetValueAtIndex(exportReps
, 0);
202 assert(exportRep
!= NULL
);
203 if(exportRep
->externType() != kSecItemTypeCertificate
) {
204 SecImpExpDbg("impExpPkcs7Export: non-cert item");
208 certRef
= (SecCertificateRef
)exportRep
->kcItem();
210 /* build chain of objects: message->signedData->data */
211 sigd
= SecCmsSignedDataCreateCertsOnly(cmsg
, certRef
, false);
213 SecImpExpDbg("impExpPkcs7Export: SecCmsSignedDataCreateCertsOnly failure");
214 ortn
= internalComponentErr
;
218 for (CFIndex dex
=1; dex
<numCerts
; dex
++) {
219 exportRep
= (SecExportRep
*)CFArrayGetValueAtIndex(exportReps
, dex
);
220 assert(exportRep
!= NULL
);
221 if(exportRep
->externType() != kSecItemTypeCertificate
) {
222 SecImpExpDbg("impExpPkcs7Export: non-cert item");
226 certRef
= (SecCertificateRef
)exportRep
->kcItem();
227 ortn
= SecCmsSignedDataAddCertChain(sigd
, certRef
);
229 SecImpExpDbg("impExpPkcs7Export: SecCmsSignedDataAddCertChain error");
234 cinfo
= SecCmsMessageGetContentInfo(cmsg
);
236 SecImpExpDbg("impExpPkcs7Export: SecCmsMessageGetContentInfo returned NULL");
237 ortn
= internalComponentErr
;
240 ortn
= SecCmsContentInfoSetContentSignedData(cmsg
, cinfo
, sigd
);
242 SecImpExpDbg("impExpPkcs7Export: SecCmsContentInfoSetContentSignedData error");
245 cinfo
= SecCmsSignedDataGetContentInfo(sigd
);
247 SecImpExpDbg("impExpPkcs7Export: SecCmsSignedDataGetContentInfo returned NULL");
248 ortn
= internalComponentErr
;
251 ortn
= SecCmsContentInfoSetContentData(cmsg
, cinfo
, NULL
,
252 false /* FIXME - what's this? */);
254 SecImpExpDbg("impExpPkcs7Export: SecCmsContentInfoSetContentData error");
259 ortn
= SecArenaPoolCreate(1024, &arena
);
261 SecImpExpDbg("impExpPkcs7Export: SecArenaPoolCreate error");
264 ortn
= SecCmsEncoderCreate(cmsg
,
265 NULL
, NULL
, /* DER output callback */
266 &output
, arena
, /* destination storage */
267 NULL
, NULL
, /* password callback */
268 NULL
, NULL
, /* decrypt key callback */
270 &ecx
); /* detached digests */
272 SecImpExpDbg("impExpPkcs7Export: SecCmsEncoderCreate error");
275 ortn
= SecCmsEncoderFinish(ecx
);
277 SecImpExpDbg("impExpPkcs7Export: SecCmsEncoderFinish returned NULL");
281 /* append encoded data to output */
282 CFDataAppendBytes(outData
, output
.Data
, output
.Length
);
287 SecCmsMessageDestroy(cmsg
);
290 SecArenaPoolFree(arena
, false);
295 #pragma mark --- Aggregate Import routines ---
298 * For all of these, if a cspHand is specified instead of a keychain,
299 * the cspHand MUST be a CSPDL handle, not a raw CSP handle.
301 OSStatus
impExpPkcs12Import(
303 SecItemImportExportFlags flags
,
304 const SecKeyImportExportParameters
*keyParams
, // optional
305 ImpPrivKeyImportState
&keyImportState
, // IN/OUT
307 /* caller must supply one of these */
308 SecKeychainRef importKeychain
, // optional
309 CSSM_CSP_HANDLE cspHand
, // required
310 CFMutableArrayRef outArray
) // optional, append here
312 SecPkcs12CoderRef p12Coder
= NULL
;
317 CFMutableArrayRef privKeys
= NULL
;
318 CSSM_KEY
*passKey
= NULL
;
319 CFStringRef phraseStr
= NULL
;
322 * Optional private key attrs.
323 * Although the PKCS12 library has its own defaults for these, we'll
324 * set them explicitly to the defaults specified in our API if the
325 * caller doesn't specify any.
327 CSSM_KEYUSE keyUsage
= CSSM_KEYUSE_ANY
;
328 CSSM_KEYATTR_FLAGS keyAttrs
= CSSM_KEYATTR_SENSITIVE
| CSSM_KEYATTR_EXTRACTABLE
|
329 CSSM_KEYATTR_RETURN_REF
;
331 if( (keyParams
== NULL
) ||
332 ( (keyParams
->passphrase
== NULL
) &&
333 !(keyParams
->flags
& kSecKeySecurePassphrase
) ) ) {
334 /* passphrase mandatory */
335 return errSecPassphraseRequired
;
339 * Set up a P12 decoder.
341 ortn
= SecPkcs12CoderCreate(&p12Coder
);
343 SecImpExpDbg("SecPkcs12CoderCreate error");
346 /* subsequent errors to errOut: */
348 CSSM_CL_HANDLE clHand
= cuClStartup();
349 CSSM_CSP_HANDLE rawCspHand
= cuCspStartup(CSSM_TRUE
); // for CL
350 if((clHand
== 0) || (rawCspHand
== 0)) {
351 return CSSMERR_CSSM_ADDIN_LOAD_FAILED
;
354 assert(cspHand
!= CSSM_INVALID_HANDLE
);
355 if(importKeychain
!= NULL
) {
356 ortn
= SecPkcs12SetKeychain(p12Coder
, importKeychain
);
358 SecImpExpDbg("SecPkcs12SetKeychain error");
363 if(cspHand
== CSSM_INVALID_HANDLE
) {
367 ortn
= SecPkcs12SetCspHandle(p12Coder
, cspHand
);
369 SecImpExpDbg("SecPkcs12SetCspHandle error");
374 /* explicit passphrase, or get one ourself? */
375 ortn
= impExpPassphraseCommon(keyParams
, cspHand
, SPF_String
,
376 VP_Import
, (CFTypeRef
*)&phraseStr
, &passKey
);
380 if(phraseStr
!= NULL
) {
381 ortn
= SecPkcs12SetMACPassphrase(p12Coder
, phraseStr
);
382 CFRelease(phraseStr
);
384 SecImpExpDbg("SecPkcs12SetMACPassphrase error");
389 assert(passKey
!= NULL
);
390 ortn
= SecPkcs12SetMACPassKey(p12Coder
, passKey
);
392 SecImpExpDbg("SecPkcs12SetMACPassphrase error");
397 if(keyImportState
!= PIS_NoLimit
) {
398 bool foundOneKey
= false;
400 /* allow either zero or one more private key */
401 if(keyImportState
== PIS_NoMore
) {
404 ortn
= SecPkcs12LimitPrivateKeyImport(p12Coder
, foundOneKey
);
406 SecImpExpDbg("SecPkcs12LimitPrivateKeyImport error");
411 if(keyParams
!= NULL
) {
412 if(keyParams
->keyUsage
!= 0) {
413 keyUsage
= keyParams
->keyUsage
;
415 if(keyParams
->keyAttributes
!= 0) {
416 keyAttrs
= keyParams
->keyAttributes
;
418 if(keyParams
->flags
& kSecKeyNoAccessControl
) {
419 ortn
= SecPkcs12SetAccess(p12Coder
, NULL
);
421 SecImpExpDbg("SecPkcs12SetAccess error");
425 else if(keyParams
->accessRef
!= NULL
) {
426 ortn
= SecPkcs12SetAccess(p12Coder
, keyParams
->accessRef
);
428 SecImpExpDbg("SecPkcs12SetAccess error");
432 /* else default ACL */
434 ortn
= SecPkcs12SetKeyUsage(p12Coder
, keyUsage
);
436 SecImpExpDbg("SecPkcs12SetKeyUsage error");
439 ortn
= SecPkcs12SetKeyAttrs(p12Coder
, keyAttrs
);
441 SecImpExpDbg("SecPkcs12SetKeyAttrs error");
446 ortn
= SecPkcs12Decode(p12Coder
, inData
);
448 SecImpExpDbg("SecPkcs12Decode error");
453 * About to process SecKeychainItemRefs.
454 * This whole mess is irrelevant if the caller doesn't
455 * want an array of SecKeychainItemRefs.
457 if(outArray
== NULL
) {
461 ortn
= SecPkcs12CertificateCount(p12Coder
, &numCerts
);
463 SecImpExpDbg("SecPkcs12CertificateCount error");
466 ortn
= SecPkcs12PrivateKeyCount(p12Coder
, &numKeys
);
468 SecImpExpDbg("SecPkcs12PrivateKeyCount error");
473 * Match up certs and keys to create SecIdentityRefs.
474 * First create a temporary array of the private keys
475 * found by the P12 module.
477 * FIXME we're working with a P12 module which can not
478 * vend SecKeyRefs.....this will hopefully, eventually,
481 privKeys
= CFArrayCreateMutable(NULL
, numKeys
, NULL
);
482 for(dex
=0; dex
<numKeys
; dex
++) {
483 CSSM_KEY_PTR privKey
;
484 ortn
= SecPkcs12GetCssmPrivateKey(p12Coder
,
485 dex
, &privKey
, NULL
, NULL
, NULL
);
486 CFArrayAppendValue(privKeys
, privKey
);
490 * Now go through all certs, searching for a matching private
491 * key. When we find a match we try to create an identity from the
492 * cert, which might fail for a number of reasons, currently including
493 * the fact that there is no way to create an identity with a key
494 * which does not reside on a keychain. (Such is the case here when
495 * caller has not specified a keychain.) If that works we skip the
496 * cert, delete that key from the privKeys array, and append the
497 * indentity to outArray. If no identity is found we append the
498 * cert to outArray. At the end of this loop, remaining
499 * items in privKeys (of which there will typically be none) are
500 * also appended to outArray.
502 for(dex
=0; dex
<numCerts
; dex
++) {
503 SecCertificateRef certRef
= NULL
; // created by P12
504 SecCertificateRef importedCertRef
= NULL
; // owned by Sec layer
505 CSSM_KEY_PTR pubKey
= NULL
; // mallocd by CL
506 CSSM_KEY_PTR privKey
= NULL
; // owned by P12
507 CSSM_DATA certData
; // owned by Sec layer
508 CSSM_DATA pubKeyDigest
= {0, NULL
}; // mallocd by CSP
509 CSSM_DATA privKeyDigest
= {0, NULL
}; // mallocd by CSP
510 bool foundIdentity
= false;
512 ortn
= SecPkcs12CopyCertificate(p12Coder
, dex
, &certRef
,
515 /* should never happen */
516 SecImpExpDbg("SecPkcs12CopyCertificate error");
519 /* subsequent errors in this loop to loopEnd: */
521 if(importKeychain
== NULL
) {
522 /* Skip the Identity match - just return keys and certs */
526 /* the SecPkcs12CopyCertificate function returns a floating
527 * certificate without a keychain. We must update it now that
528 * it has been added to importKeychain.
531 StorageManager::KeychainList keychains
;
532 globals().storageManager
.optionalSearchList(importKeychain
, keychains
);
533 SecPointer
<Certificate
> cert
= Certificate::required(certRef
);
534 importedCertRef
= cert
->findInKeychain(keychains
)->handle();
537 /* Get digest of this cert's public key */
538 ortn
= SecCertificateGetData(importedCertRef
, &certData
);
540 SecImpExpDbg("SecCertificateGetData error");
543 ortn
= CSSM_CL_CertGetKeyInfo(clHand
, &certData
, &pubKey
);
545 SecImpExpDbg("SecCertificateGetData error");
548 ortn
= impExpKeyDigest(rawCspHand
, pubKey
, &pubKeyDigest
);
554 * Now search for a private key with this same digest
556 numKeys
= CFArrayGetCount(privKeys
);
557 for(CFIndex privDex
=0; privDex
<numKeys
; privDex
++) {
558 privKey
= (CSSM_KEY_PTR
)CFArrayGetValueAtIndex(privKeys
, privDex
);
559 assert(privKey
!= NULL
);
560 ortn
= impExpKeyDigest(cspHand
, privKey
, &privKeyDigest
);
564 CSSM_BOOL digestMatch
= cuCompareCssmData(&pubKeyDigest
, &privKeyDigest
);
565 impExpFreeCssmMemory(cspHand
, privKeyDigest
.Data
);
568 * MATCH: try to cook up Identity.
569 * TBD: I expect some work will be needed here when
570 * Sec layer can handle floating keys. One thing
571 * that would be nice would be if we could create an identity
572 * FROM a given SecCertRef and a SecKeyRef, even if
573 * the SecKeyRef is floating.
575 * NOTE: you might think that we could do a
576 * SecIdentityCreateWithCertificate() before, or even without,
577 * doing a digest match....but that could "work" without
578 * us having imported any keys at all, if the appropriate
579 * private key were already there. Doing the digest match
580 * guarantees the uniqueness of the key item in the DB.
582 SecIdentityRef idRef
= NULL
;
583 ortn
= SecIdentityCreateWithCertificate(importKeychain
,
584 importedCertRef
, &idRef
);
589 * -- add Identity to outArray
590 * -- remove privKey from privKeys array
591 * -- skip to next cert
593 SecImpExpDbg("P12Import: generating a SecIdentityRef");
594 assert(outArray
!= NULL
);
595 CFArrayAppendValue(outArray
, idRef
);
596 CFRelease(idRef
); // array holds only ref
598 CFArrayRemoveValueAtIndex(privKeys
, privDex
);
599 foundIdentity
= true;
601 } /* ID create worked, else try next key */
603 } /* searching thru privKeys */
605 /* free resources allocated in this loop */
606 assert(certRef
!= NULL
);
607 if(!foundIdentity
) {
608 /* No private key for this cert: give to caller */
609 assert(outArray
!= NULL
);
610 CFArrayAppendValue(outArray
, certRef
);
612 CFRelease(certRef
); // outArray holds only ref
614 if (importedCertRef
) {
615 CFRelease(importedCertRef
);
616 importedCertRef
= NULL
;
619 /* technically invalid, the CL used some CSP handle we
620 * don't have access to to get this... */
621 CSSM_FreeKey(rawCspHand
, NULL
, pubKey
, CSSM_FALSE
);
622 impExpFreeCssmMemory(clHand
, pubKey
);
625 if(pubKeyDigest
.Data
!= NULL
) {
626 impExpFreeCssmMemory(rawCspHand
, pubKeyDigest
.Data
);
627 pubKeyDigest
.Data
= NULL
;
636 * One last thing: pass any remaining (non-identity) keys to caller.
637 * For now, the keys are CSSM_KEYs owned by the P12 coder object, we
638 * don't have to release them. When P12 can vend SecKeyRefs, we release the
643 The code below has no net effect, except for generating a leak. This was
644 found while investigating
645 <rdar://problem/8799913> SecItemImport() leaking
646 Code like this will need to be added when we return SecIdentityRefs in
647 the "in memory" case (destKeychain = NULL). Currently, when importing to
648 a physical keychain, the returned item array contains SecIdentityRefs,
649 whereas the "in memory" case returns SecCertificateRefs. See
650 <rdar://problem/8862809> ER: SecItemImport should return SecIdentityRefs in the "in memory" case
655 if(ortn
== noErr
) { // TBD OR keys are SecKeyRefs
656 numKeys
= CFArrayGetCount(privKeys
);
657 for(dex
=0; dex
<numKeys
; dex
++) {
659 CSSM_KEY_PTR privKey
=
660 (CSSM_KEY_PTR
)CFArrayGetValueAtIndex(privKeys
, dex
);
661 assert(privKey
!= NULL
);
663 /* only do this on complete success so far */
664 ortn
= SecKeyCreateWithCSSMKey(privKey
, &keyRef
);
666 SecImpExpDbg("SecKeyCreateWithCSSMKey error");
668 /* keep going for CFRelease */
672 /* TBD CFRelease the SecKeyRef */
673 } /* for each privKey */
674 } /* success so far */
678 SecPkcs12CoderRelease(p12Coder
);
679 if(passKey
!= NULL
) {
680 CSSM_FreeKey(cspHand
, NULL
, passKey
, CSSM_FALSE
);
683 if(privKeys
!= NULL
) {
687 cuClDetachUnload(clHand
);
689 if(rawCspHand
!= 0) {
690 cuCspDetachUnload(rawCspHand
, CSSM_TRUE
);
695 OSStatus
impExpPkcs7Import(
697 SecItemImportExportFlags flags
,
698 const SecKeyImportExportParameters
*keyParams
, // optional
699 SecKeychainRef importKeychain
, // optional
700 CFMutableArrayRef outArray
) // optional, append here
702 SecCmsDecoderRef decoderContext
;
703 SecCmsMessageRef cmsMessage
= NULL
;
704 SecCmsContentInfoRef contentInfo
;
705 SecCmsSignedDataRef signedData
;
706 int contentLevelCount
;
708 SECOidTag contentTypeTag
;
710 OSStatus ourRtn
= noErr
;
712 /* decode the message */
713 result
= SecCmsDecoderCreate (NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &decoderContext
);
718 result
= SecCmsDecoderUpdate(decoderContext
, CFDataGetBytePtr(inData
),
719 CFDataGetLength(inData
));
721 /* any useful status here? */
722 SecImpExpDbg("SecCmsDecoderUpdate error");
723 ourRtn
= errSecUnknownFormat
;
724 SecCmsDecoderDestroy(decoderContext
);
728 ourRtn
= SecCmsDecoderFinish(decoderContext
, &cmsMessage
);
730 SecImpExpDbg("SecCmsDecoderFinish error");
731 ourRtn
= errSecUnknownFormat
;
735 // process the results
736 contentLevelCount
= SecCmsMessageContentLevelCount (cmsMessage
);
738 for (i
= 0; i
< contentLevelCount
; ++i
)
740 // get content information
741 contentInfo
= SecCmsMessageContentLevel (cmsMessage
, i
);
742 contentTypeTag
= SecCmsContentInfoGetContentTypeTag (contentInfo
);
744 switch (contentTypeTag
)
746 case SEC_OID_PKCS7_SIGNED_DATA
:
748 /* I guess this the only interesting field */
750 (SecCmsSignedDataRef
) SecCmsContentInfoGetContent (contentInfo
);
751 if (signedData
== NULL
) {
752 SecImpExpDbg("SecCmsContentInfoGetContent returned NULL");
753 ourRtn
= errSecUnknownFormat
;
757 // import the certificates
758 CSSM_DATA
**outCerts
= SecCmsSignedDataGetCertificateList(signedData
);
759 if(outCerts
== NULL
) {
760 SecImpExpDbg("SecCmsSignedDataGetCertificateList returned NULL");
761 ourRtn
= errSecUnknownFormat
;
765 /* Returned value is NULL-terminated array */
767 CSSM_DATA
**array
= outCerts
;
774 SecImpExpDbg("No certs found in apparently good PKCS7 blob");
778 for(unsigned dex
=0; dex
<count
; dex
++) {
779 ourRtn
= impExpImportCertCommon(outCerts
[dex
], importKeychain
,
793 SecCmsMessageDestroy(cmsMessage
);
800 * Import a netscape-cert-sequence. Suitable for low-cost guessing when neither
801 * importKeychain nor outArray is specified.
803 OSStatus
impExpNetscapeCertImport(
805 SecItemImportExportFlags flags
,
806 const SecKeyImportExportParameters
*keyParams
, // optional
807 SecKeychainRef importKeychain
, // optional
808 CFMutableArrayRef outArray
) // optional, append here
811 NetscapeCertSequence certSeq
;
814 memset(&certSeq
, 0, sizeof(certSeq
));
815 PRErrorCode perr
= coder
.decode(CFDataGetBytePtr(inData
),
816 CFDataGetLength(inData
),
817 NetscapeCertSequenceTemplate
,
820 SecImpExpDbg("impExpNetscapeCertImport: DER decode failure");
821 return errSecUnknownFormat
;
824 /* verify (contentType == netscape-cert-sequence) */
825 if(!cuCompareOid(&CSSMOID_NetscapeCertSequence
, &certSeq
.contentType
)) {
826 SecImpExpDbg("impExpNetscapeCertImport: OID mismatch");
827 return errSecUnknownFormat
;
830 /* Extract certs in CSSM_DATA form, return to caller */
831 unsigned numCerts
= nssArraySize((const void **)certSeq
.certs
);
832 for(unsigned i
=0; i
<numCerts
; i
++) {
833 CSSM_DATA
*cert
= certSeq
.certs
[i
];
834 OSStatus ortn
= impExpImportCertCommon(cert
, importKeychain
, outArray
);
842 #pragma mark --- Utilities ---
844 OSStatus
impExpImportCertCommon(
845 const CSSM_DATA
*cdata
,
846 SecKeychainRef importKeychain
, // optional
847 CFMutableArrayRef outArray
) // optional, append here
849 OSStatus ortn
= noErr
;
850 SecCertificateRef certRef
;
853 return errSecUnsupportedFormat
;
855 CFDataRef data
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, (const UInt8
*)cdata
->Data
, (CFIndex
)cdata
->Length
, kCFAllocatorNull
);
856 /* Pass kCFAllocatorNull as bytesDeallocator to assure the bytes aren't freed */
858 return errSecUnsupportedFormat
;
860 certRef
= SecCertificateCreateWithData(kCFAllocatorDefault
, data
);
861 CFRelease(data
); /* certRef has its own copy of the data now */
863 SecImpExpDbg("impExpHandleCert error\n");
864 return errSecUnsupportedFormat
;
867 if(importKeychain
!= NULL
) {
868 ortn
= SecCertificateAddToKeychain(certRef
, importKeychain
);
870 SecImpExpDbg("SecCertificateAddToKeychain error\n");
875 if(outArray
!= NULL
) {
876 CFArrayAppendValue(outArray
, certRef
);