1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
54 ** This PKCS12 file encoder uses numerous nested ASN.1 and PKCS7 encoder
55 ** contexts. It can be difficult to keep straight. Here's a picture:
57 ** "outer" ASN.1 encoder. The output goes to the library caller's CB.
58 ** "middle" PKCS7 encoder. Feeds the "outer" ASN.1 encoder.
59 ** "middle" ASN1 encoder. Encodes the encrypted aSafes.
60 ** Feeds the "middle" P7 encoder above.
61 ** "inner" PKCS7 encoder. Encrypts the "authenticated Safes" (aSafes)
62 ** Feeds the "middle" ASN.1 encoder above.
63 ** "inner" ASN.1 encoder. Encodes the unencrypted aSafes.
64 ** Feeds the "inner" P7 enocder above.
66 ** Buffering has been added at each point where the output of an ASN.1
67 ** encoder feeds the input of a PKCS7 encoder.
70 /*********************************
71 * Output buffer object, used to buffer output from ASN.1 encoder
72 * before passing data on down to the next PKCS7 encoder.
73 *********************************/
75 #define PK12_OUTPUT_BUFFER_SIZE 8192
77 struct sec_pkcs12OutputBufferStr
{
78 SEC_PKCS7EncoderContext
* p7eCx
;
80 unsigned int numBytes
;
81 unsigned int bufBytes
;
82 char buf
[PK12_OUTPUT_BUFFER_SIZE
];
84 typedef struct sec_pkcs12OutputBufferStr sec_pkcs12OutputBuffer
;
86 /*********************************
87 * Structures used in exporting the PKCS 12 blob
88 *********************************/
90 /* A SafeInfo is used for each ContentInfo which makes up the
91 * sequence of safes in the AuthenticatedSafe portion of the
94 struct SEC_PKCS12SafeInfoStr
{
97 /* information for setting up password encryption */
100 PK11SymKey
*encryptionKey
;
102 /* how many items have been stored in this safe,
103 * we will skip any safe which does not contain any
106 unsigned int itemCount
;
108 /* the content info for the safe */
109 SEC_PKCS7ContentInfo
*cinfo
;
111 sec_PKCS12SafeContents
*safe
;
114 /* An opaque structure which contains information needed for exporting
115 * certificates and keys through PKCS 12.
117 struct SEC_PKCS12ExportContextStr
{
122 /* integrity information */
123 PRBool integrityEnabled
;
126 struct sec_PKCS12PasswordModeInfo pwdInfo
;
127 struct sec_PKCS12PublicKeyModeInfo pubkeyInfo
;
130 /* helper functions */
131 /* retrieve the password call back */
132 SECKEYGetPasswordKey pwfn
;
135 /* safe contents bags */
136 SEC_PKCS12SafeInfo
**safeInfos
;
137 unsigned int safeInfoCount
;
139 /* the sequence of safes */
140 sec_PKCS12AuthenticatedSafe authSafe
;
142 /* information needing deletion */
143 CERTCertificate
**certList
;
146 /* structures for passing information to encoder callbacks when processing
147 * data through the ASN1 engine.
149 struct sec_pkcs12_encoder_output
{
150 SEC_PKCS12EncoderOutputCallback outputfn
;
154 struct sec_pkcs12_hmac_and_output_info
{
156 struct sec_pkcs12_encoder_output output
;
159 /* An encoder context which is used for the actual encoding
160 * portion of PKCS 12.
162 typedef struct sec_PKCS12EncoderContextStr
{
164 SEC_PKCS12ExportContext
*p12exp
;
165 PK11SymKey
*encryptionKey
;
167 /* encoder information - this is set up based on whether
168 * password based or public key pased privacy is being used
170 SEC_ASN1EncoderContext
*outerA1ecx
;
172 struct sec_pkcs12_hmac_and_output_info hmacAndOutputInfo
;
173 struct sec_pkcs12_encoder_output encOutput
;
176 /* structures for encoding of PFX and MAC */
177 sec_PKCS12PFXItem pfx
;
178 sec_PKCS12MacData mac
;
180 /* authenticated safe encoding tracking information */
181 SEC_PKCS7ContentInfo
*aSafeCinfo
;
182 SEC_PKCS7EncoderContext
*middleP7ecx
;
183 SEC_ASN1EncoderContext
*middleA1ecx
;
184 unsigned int currentSafe
;
190 sec_pkcs12OutputBuffer middleBuf
;
191 sec_pkcs12OutputBuffer innerBuf
;
193 } sec_PKCS12EncoderContext
;
196 /*********************************
197 * Export setup routines
198 *********************************/
200 /* SEC_PKCS12CreateExportContext
201 * Creates an export context and sets the unicode and password retrieval
202 * callbacks. This is the first call which must be made when exporting
205 * pwfn, pwfnarg - password retrieval callback and argument. these are
206 * required for password-authentication mode.
208 SEC_PKCS12ExportContext
*
209 SEC_PKCS12CreateExportContext(SECKEYGetPasswordKey pwfn
, void *pwfnarg
,
210 PK11SlotInfo
*slot
, void *wincx
)
212 PRArenaPool
*arena
= NULL
;
213 SEC_PKCS12ExportContext
*p12ctxt
= NULL
;
215 /* allocate the arena and create the context */
216 arena
= PORT_NewArena(4096);
218 PORT_SetError(SEC_ERROR_NO_MEMORY
);
222 p12ctxt
= (SEC_PKCS12ExportContext
*)PORT_ArenaZAlloc(arena
,
223 sizeof(SEC_PKCS12ExportContext
));
225 PORT_SetError(SEC_ERROR_NO_MEMORY
);
229 /* password callback for key retrieval */
230 p12ctxt
->pwfn
= pwfn
;
231 p12ctxt
->pwfnarg
= pwfnarg
;
233 p12ctxt
->integrityEnabled
= PR_FALSE
;
234 p12ctxt
->arena
= arena
;
235 p12ctxt
->wincx
= wincx
;
236 p12ctxt
->slot
= (slot
) ? PK11_ReferenceSlot(slot
) : PK11_GetInternalSlot();
242 PORT_FreeArena(arena
, PR_TRUE
);
249 * Adding integrity mode
252 /* SEC_PKCS12AddPasswordIntegrity
253 * Add password integrity to the exported data. If an integrity method
254 * has already been set, then return an error.
256 * p12ctxt - the export context
257 * pwitem - the password for integrity mode
258 * integAlg - the integrity algorithm to use for authentication.
261 SEC_PKCS12AddPasswordIntegrity(SEC_PKCS12ExportContext
*p12ctxt
,
262 SECItem
*pwitem
, SECOidTag integAlg
)
264 if(!p12ctxt
|| p12ctxt
->integrityEnabled
) {
268 /* set up integrity information */
269 p12ctxt
->pwdIntegrity
= PR_TRUE
;
270 p12ctxt
->integrityInfo
.pwdInfo
.password
=
271 (SECItem
*)PORT_ArenaZAlloc(p12ctxt
->arena
, sizeof(SECItem
));
272 if(!p12ctxt
->integrityInfo
.pwdInfo
.password
) {
273 PORT_SetError(SEC_ERROR_NO_MEMORY
);
276 if(SECITEM_CopyItem(p12ctxt
->arena
,
277 p12ctxt
->integrityInfo
.pwdInfo
.password
, pwitem
)
279 PORT_SetError(SEC_ERROR_NO_MEMORY
);
282 p12ctxt
->integrityInfo
.pwdInfo
.algorithm
= integAlg
;
283 p12ctxt
->integrityEnabled
= PR_TRUE
;
288 /* SEC_PKCS12AddPublicKeyIntegrity
289 * Add public key integrity to the exported data. If an integrity method
290 * has already been set, then return an error. The certificate must be
291 * allowed to be used as a signing cert.
293 * p12ctxt - the export context
294 * cert - signer certificate
295 * certDb - the certificate database
296 * algorithm - signing algorithm
297 * keySize - size of the signing key (?)
300 SEC_PKCS12AddPublicKeyIntegrity(SEC_PKCS12ExportContext
*p12ctxt
,
301 CERTCertificate
*cert
, CERTCertDBHandle
*certDb
,
302 SECOidTag algorithm
, int keySize
)
308 p12ctxt
->integrityInfo
.pubkeyInfo
.cert
= cert
;
309 p12ctxt
->integrityInfo
.pubkeyInfo
.certDb
= certDb
;
310 p12ctxt
->integrityInfo
.pubkeyInfo
.algorithm
= algorithm
;
311 p12ctxt
->integrityInfo
.pubkeyInfo
.keySize
= keySize
;
312 p12ctxt
->integrityEnabled
= PR_TRUE
;
319 * Adding safes - encrypted (password/public key) or unencrypted
320 * Each of the safe creation routines return an opaque pointer which
321 * are later passed into the routines for exporting certificates and
325 /* append the newly created safeInfo to list of safeInfos in the export
329 sec_pkcs12_append_safe_info(SEC_PKCS12ExportContext
*p12ctxt
, SEC_PKCS12SafeInfo
*info
)
331 void *mark
= NULL
, *dummy1
= NULL
, *dummy2
= NULL
;
333 if(!p12ctxt
|| !info
) {
337 mark
= PORT_ArenaMark(p12ctxt
->arena
);
339 /* if no safeInfos have been set, create the list, otherwise expand it. */
340 if(!p12ctxt
->safeInfoCount
) {
341 p12ctxt
->safeInfos
= (SEC_PKCS12SafeInfo
**)PORT_ArenaZAlloc(p12ctxt
->arena
,
342 2 * sizeof(SEC_PKCS12SafeInfo
*));
343 dummy1
= p12ctxt
->safeInfos
;
344 p12ctxt
->authSafe
.encodedSafes
= (SECItem
**)PORT_ArenaZAlloc(p12ctxt
->arena
,
345 2 * sizeof(SECItem
*));
346 dummy2
= p12ctxt
->authSafe
.encodedSafes
;
348 dummy1
= PORT_ArenaGrow(p12ctxt
->arena
, p12ctxt
->safeInfos
,
349 (p12ctxt
->safeInfoCount
+ 1) * sizeof(SEC_PKCS12SafeInfo
*),
350 (p12ctxt
->safeInfoCount
+ 2) * sizeof(SEC_PKCS12SafeInfo
*));
351 p12ctxt
->safeInfos
= (SEC_PKCS12SafeInfo
**)dummy1
;
352 dummy2
= PORT_ArenaGrow(p12ctxt
->arena
, p12ctxt
->authSafe
.encodedSafes
,
353 (p12ctxt
->authSafe
.safeCount
+ 1) * sizeof(SECItem
*),
354 (p12ctxt
->authSafe
.safeCount
+ 2) * sizeof(SECItem
*));
355 p12ctxt
->authSafe
.encodedSafes
= (SECItem
**)dummy2
;
357 if(!dummy1
|| !dummy2
) {
358 PORT_SetError(SEC_ERROR_NO_MEMORY
);
362 /* append the new safeInfo and null terminate the list */
363 p12ctxt
->safeInfos
[p12ctxt
->safeInfoCount
] = info
;
364 p12ctxt
->safeInfos
[++p12ctxt
->safeInfoCount
] = NULL
;
365 p12ctxt
->authSafe
.encodedSafes
[p12ctxt
->authSafe
.safeCount
] =
366 (SECItem
*)PORT_ArenaZAlloc(p12ctxt
->arena
, sizeof(SECItem
));
367 if(!p12ctxt
->authSafe
.encodedSafes
[p12ctxt
->authSafe
.safeCount
]) {
368 PORT_SetError(SEC_ERROR_NO_MEMORY
);
371 p12ctxt
->authSafe
.encodedSafes
[++p12ctxt
->authSafe
.safeCount
] = NULL
;
373 PORT_ArenaUnmark(p12ctxt
->arena
, mark
);
377 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
381 /* SEC_PKCS12CreatePasswordPrivSafe
382 * Create a password privacy safe to store exported information in.
384 * p12ctxt - export context
385 * pwitem - password for encryption
386 * privAlg - pbe algorithm through which encryption is done.
389 SEC_PKCS12CreatePasswordPrivSafe(SEC_PKCS12ExportContext
*p12ctxt
,
390 SECItem
*pwitem
, SECOidTag privAlg
)
392 SEC_PKCS12SafeInfo
*safeInfo
= NULL
;
394 PK11SlotInfo
*slot
= NULL
;
395 SECAlgorithmID
*algId
;
396 SECItem uniPwitem
= {siBuffer
, NULL
, 0};
402 /* allocate the safe info */
403 mark
= PORT_ArenaMark(p12ctxt
->arena
);
404 safeInfo
= (SEC_PKCS12SafeInfo
*)PORT_ArenaZAlloc(p12ctxt
->arena
,
405 sizeof(SEC_PKCS12SafeInfo
));
407 PORT_SetError(SEC_ERROR_NO_MEMORY
);
408 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
412 safeInfo
->itemCount
= 0;
414 /* create the encrypted safe */
415 safeInfo
->cinfo
= SEC_PKCS7CreateEncryptedData(privAlg
, 0, p12ctxt
->pwfn
,
417 if(!safeInfo
->cinfo
) {
418 PORT_SetError(SEC_ERROR_NO_MEMORY
);
421 safeInfo
->arena
= p12ctxt
->arena
;
423 /* convert the password to unicode */
424 if(!sec_pkcs12_convert_item_to_unicode(NULL
, &uniPwitem
, pwitem
,
425 PR_TRUE
, PR_TRUE
, PR_TRUE
)) {
426 PORT_SetError(SEC_ERROR_NO_MEMORY
);
429 if(SECITEM_CopyItem(p12ctxt
->arena
, &safeInfo
->pwitem
, &uniPwitem
) != SECSuccess
) {
430 PORT_SetError(SEC_ERROR_NO_MEMORY
);
434 /* generate the encryption key */
435 slot
= PK11_ReferenceSlot(p12ctxt
->slot
);
437 slot
= PK11_GetInternalKeySlot();
439 PORT_SetError(SEC_ERROR_NO_MEMORY
);
444 algId
= SEC_PKCS7GetEncryptionAlgorithm(safeInfo
->cinfo
);
445 safeInfo
->encryptionKey
= PK11_PBEKeyGen(slot
, algId
, &uniPwitem
,
446 PR_FALSE
, p12ctxt
->wincx
);
447 if(!safeInfo
->encryptionKey
) {
451 safeInfo
->arena
= p12ctxt
->arena
;
452 safeInfo
->safe
= NULL
;
453 if(sec_pkcs12_append_safe_info(p12ctxt
, safeInfo
) != SECSuccess
) {
458 SECITEM_ZfreeItem(&uniPwitem
, PR_FALSE
);
460 PORT_ArenaUnmark(p12ctxt
->arena
, mark
);
471 if(safeInfo
->cinfo
) {
472 SEC_PKCS7DestroyContentInfo(safeInfo
->cinfo
);
476 SECITEM_ZfreeItem(&uniPwitem
, PR_FALSE
);
479 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
483 /* SEC_PKCS12CreateUnencryptedSafe
484 * Creates an unencrypted safe within the export context.
486 * p12ctxt - the export context
489 SEC_PKCS12CreateUnencryptedSafe(SEC_PKCS12ExportContext
*p12ctxt
)
491 SEC_PKCS12SafeInfo
*safeInfo
= NULL
;
498 /* create the safe info */
499 mark
= PORT_ArenaMark(p12ctxt
->arena
);
500 safeInfo
= (SEC_PKCS12SafeInfo
*)PORT_ArenaZAlloc(p12ctxt
->arena
,
501 sizeof(SEC_PKCS12SafeInfo
));
503 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
504 PORT_SetError(SEC_ERROR_NO_MEMORY
);
508 safeInfo
->itemCount
= 0;
510 /* create the safe content */
511 safeInfo
->cinfo
= SEC_PKCS7CreateData();
512 if(!safeInfo
->cinfo
) {
513 PORT_SetError(SEC_ERROR_NO_MEMORY
);
517 if(sec_pkcs12_append_safe_info(p12ctxt
, safeInfo
) != SECSuccess
) {
521 PORT_ArenaUnmark(p12ctxt
->arena
, mark
);
525 if(safeInfo
->cinfo
) {
526 SEC_PKCS7DestroyContentInfo(safeInfo
->cinfo
);
529 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
533 /* SEC_PKCS12CreatePubKeyEncryptedSafe
534 * Creates a safe which is protected by public key encryption.
536 * p12ctxt - the export context
537 * certDb - the certificate database
538 * signer - the signer's certificate
539 * recipients - the list of recipient certificates.
540 * algorithm - the encryption algorithm to use
541 * keysize - the algorithms key size (?)
544 SEC_PKCS12CreatePubKeyEncryptedSafe(SEC_PKCS12ExportContext
*p12ctxt
,
545 CERTCertDBHandle
*certDb
,
546 CERTCertificate
*signer
,
547 CERTCertificate
**recipients
,
548 SECOidTag algorithm
, int keysize
)
550 SEC_PKCS12SafeInfo
*safeInfo
= NULL
;
553 if(!p12ctxt
|| !signer
|| !recipients
|| !(*recipients
)) {
557 /* allocate the safeInfo */
558 mark
= PORT_ArenaMark(p12ctxt
->arena
);
559 safeInfo
= (SEC_PKCS12SafeInfo
*)PORT_ArenaZAlloc(p12ctxt
->arena
,
560 sizeof(SEC_PKCS12SafeInfo
));
562 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
563 PORT_SetError(SEC_ERROR_NO_MEMORY
);
567 safeInfo
->itemCount
= 0;
568 safeInfo
->arena
= p12ctxt
->arena
;
570 /* create the enveloped content info using certUsageEmailSigner currently.
571 * XXX We need to eventually use something other than certUsageEmailSigner
573 safeInfo
->cinfo
= SEC_PKCS7CreateEnvelopedData(signer
, certUsageEmailSigner
,
574 certDb
, algorithm
, keysize
,
575 p12ctxt
->pwfn
, p12ctxt
->pwfnarg
);
576 if(!safeInfo
->cinfo
) {
577 PORT_SetError(SEC_ERROR_NO_MEMORY
);
584 while(recipients
[i
] != NULL
) {
585 SECStatus rv
= SEC_PKCS7AddRecipient(safeInfo
->cinfo
, recipients
[i
],
586 certUsageEmailRecipient
, certDb
);
587 if(rv
!= SECSuccess
) {
594 if(sec_pkcs12_append_safe_info(p12ctxt
, safeInfo
) != SECSuccess
) {
598 PORT_ArenaUnmark(p12ctxt
->arena
, mark
);
602 if(safeInfo
->cinfo
) {
603 SEC_PKCS7DestroyContentInfo(safeInfo
->cinfo
);
604 safeInfo
->cinfo
= NULL
;
607 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
611 /*********************************
612 * Routines to handle the exporting of the keys and certificates
613 *********************************/
615 /* creates a safe contents which safeBags will be appended to */
616 sec_PKCS12SafeContents
*
617 sec_PKCS12CreateSafeContents(PRArenaPool
*arena
)
619 sec_PKCS12SafeContents
*safeContents
;
625 /* create the safe contents */
626 safeContents
= (sec_PKCS12SafeContents
*)PORT_ArenaZAlloc(arena
,
627 sizeof(sec_PKCS12SafeContents
));
629 PORT_SetError(SEC_ERROR_NO_MEMORY
);
633 /* set up the internal contents info */
634 safeContents
->safeBags
= NULL
;
635 safeContents
->arena
= arena
;
636 safeContents
->bagCount
= 0;
644 /* appends a safe bag to a safeContents using the specified arena.
647 sec_pkcs12_append_bag_to_safe_contents(PRArenaPool
*arena
,
648 sec_PKCS12SafeContents
*safeContents
,
649 sec_PKCS12SafeBag
*safeBag
)
651 void *mark
= NULL
, *dummy
= NULL
;
653 if(!arena
|| !safeBag
|| !safeContents
) {
657 mark
= PORT_ArenaMark(arena
);
659 PORT_SetError(SEC_ERROR_NO_MEMORY
);
663 /* allocate space for the list, or reallocate to increase space */
664 if(!safeContents
->safeBags
) {
665 safeContents
->safeBags
= (sec_PKCS12SafeBag
**)PORT_ArenaZAlloc(arena
,
666 (2 * sizeof(sec_PKCS12SafeBag
*)));
667 dummy
= safeContents
->safeBags
;
668 safeContents
->bagCount
= 0;
670 dummy
= PORT_ArenaGrow(arena
, safeContents
->safeBags
,
671 (safeContents
->bagCount
+ 1) * sizeof(sec_PKCS12SafeBag
*),
672 (safeContents
->bagCount
+ 2) * sizeof(sec_PKCS12SafeBag
*));
673 safeContents
->safeBags
= (sec_PKCS12SafeBag
**)dummy
;
677 PORT_ArenaRelease(arena
, mark
);
678 PORT_SetError(SEC_ERROR_NO_MEMORY
);
682 /* append the bag at the end and null terminate the list */
683 safeContents
->safeBags
[safeContents
->bagCount
++] = safeBag
;
684 safeContents
->safeBags
[safeContents
->bagCount
] = NULL
;
686 PORT_ArenaUnmark(arena
, mark
);
691 /* appends a safeBag to a specific safeInfo.
694 sec_pkcs12_append_bag(SEC_PKCS12ExportContext
*p12ctxt
,
695 SEC_PKCS12SafeInfo
*safeInfo
, sec_PKCS12SafeBag
*safeBag
)
697 sec_PKCS12SafeContents
*dest
;
698 SECStatus rv
= SECFailure
;
700 if(!p12ctxt
|| !safeBag
|| !safeInfo
) {
704 if(!safeInfo
->safe
) {
705 safeInfo
->safe
= sec_PKCS12CreateSafeContents(p12ctxt
->arena
);
706 if(!safeInfo
->safe
) {
711 dest
= safeInfo
->safe
;
712 rv
= sec_pkcs12_append_bag_to_safe_contents(p12ctxt
->arena
, dest
, safeBag
);
713 if(rv
== SECSuccess
) {
714 safeInfo
->itemCount
++;
720 /* Creates a safeBag of the specified type, and if bagData is specified,
721 * the contents are set. The contents could be set later by the calling
725 sec_PKCS12CreateSafeBag(SEC_PKCS12ExportContext
*p12ctxt
, SECOidTag bagType
,
728 sec_PKCS12SafeBag
*safeBag
;
729 PRBool setName
= PR_TRUE
;
731 SECStatus rv
= SECSuccess
;
732 SECOidData
*oidData
= NULL
;
738 mark
= PORT_ArenaMark(p12ctxt
->arena
);
740 PORT_SetError(SEC_ERROR_NO_MEMORY
);
744 safeBag
= (sec_PKCS12SafeBag
*)PORT_ArenaZAlloc(p12ctxt
->arena
,
745 sizeof(sec_PKCS12SafeBag
));
747 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
748 PORT_SetError(SEC_ERROR_NO_MEMORY
);
752 /* set the bags content based upon bag type */
754 case SEC_OID_PKCS12_V1_KEY_BAG_ID
:
755 safeBag
->safeBagContent
.pkcs8KeyBag
=
756 (SECKEYPrivateKeyInfo
*)bagData
;
758 case SEC_OID_PKCS12_V1_CERT_BAG_ID
:
759 safeBag
->safeBagContent
.certBag
= (sec_PKCS12CertBag
*)bagData
;
761 case SEC_OID_PKCS12_V1_CRL_BAG_ID
:
762 safeBag
->safeBagContent
.crlBag
= (sec_PKCS12CRLBag
*)bagData
;
764 case SEC_OID_PKCS12_V1_SECRET_BAG_ID
:
765 safeBag
->safeBagContent
.secretBag
= (sec_PKCS12SecretBag
*)bagData
;
767 case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID
:
768 safeBag
->safeBagContent
.pkcs8ShroudedKeyBag
=
769 (SECKEYEncryptedPrivateKeyInfo
*)bagData
;
771 case SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID
:
772 safeBag
->safeBagContent
.safeContents
=
773 (sec_PKCS12SafeContents
*)bagData
;
780 oidData
= SECOID_FindOIDByTag(bagType
);
782 rv
= SECITEM_CopyItem(p12ctxt
->arena
, &safeBag
->safeBagType
, &oidData
->oid
);
783 if(rv
!= SECSuccess
) {
784 PORT_SetError(SEC_ERROR_NO_MEMORY
);
791 safeBag
->arena
= p12ctxt
->arena
;
792 PORT_ArenaUnmark(p12ctxt
->arena
, mark
);
798 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
804 /* Creates a new certificate bag and returns a pointer to it. If an error
805 * occurs NULL is returned.
808 sec_PKCS12NewCertBag(PRArenaPool
*arena
, SECOidTag certType
)
810 sec_PKCS12CertBag
*certBag
= NULL
;
811 SECOidData
*bagType
= NULL
;
819 mark
= PORT_ArenaMark(arena
);
820 certBag
= (sec_PKCS12CertBag
*)PORT_ArenaZAlloc(arena
,
821 sizeof(sec_PKCS12CertBag
));
823 PORT_ArenaRelease(arena
, mark
);
824 PORT_SetError(SEC_ERROR_NO_MEMORY
);
828 bagType
= SECOID_FindOIDByTag(certType
);
830 PORT_SetError(SEC_ERROR_NO_MEMORY
);
834 rv
= SECITEM_CopyItem(arena
, &certBag
->bagID
, &bagType
->oid
);
835 if(rv
!= SECSuccess
) {
836 PORT_SetError(SEC_ERROR_NO_MEMORY
);
840 PORT_ArenaUnmark(arena
, mark
);
844 PORT_ArenaRelease(arena
, mark
);
848 /* Creates a new CRL bag and returns a pointer to it. If an error
849 * occurs NULL is returned.
852 sec_PKCS12NewCRLBag(PRArenaPool
*arena
, SECOidTag crlType
)
854 sec_PKCS12CRLBag
*crlBag
= NULL
;
855 SECOidData
*bagType
= NULL
;
863 mark
= PORT_ArenaMark(arena
);
864 crlBag
= (sec_PKCS12CRLBag
*)PORT_ArenaZAlloc(arena
,
865 sizeof(sec_PKCS12CRLBag
));
867 PORT_ArenaRelease(arena
, mark
);
868 PORT_SetError(SEC_ERROR_NO_MEMORY
);
872 bagType
= SECOID_FindOIDByTag(crlType
);
874 PORT_SetError(SEC_ERROR_NO_MEMORY
);
878 rv
= SECITEM_CopyItem(arena
, &crlBag
->bagID
, &bagType
->oid
);
879 if(rv
!= SECSuccess
) {
880 PORT_SetError(SEC_ERROR_NO_MEMORY
);
884 PORT_ArenaUnmark(arena
, mark
);
888 PORT_ArenaRelease(arena
, mark
);
892 /* sec_PKCS12AddAttributeToBag
893 * adds an attribute to a safeBag. currently, the only attributes supported
894 * are those which are specified within PKCS 12.
896 * p12ctxt - the export context
897 * safeBag - the safeBag to which attributes are appended
898 * attrType - the attribute type
899 * attrData - the attribute data
902 sec_PKCS12AddAttributeToBag(SEC_PKCS12ExportContext
*p12ctxt
,
903 sec_PKCS12SafeBag
*safeBag
, SECOidTag attrType
,
906 sec_PKCS12Attribute
*attribute
;
907 void *mark
= NULL
, *dummy
= NULL
;
908 SECOidData
*oiddata
= NULL
;
909 SECItem unicodeName
= { siBuffer
, NULL
, 0};
911 unsigned int nItems
= 0;
914 if(!safeBag
|| !p12ctxt
) {
918 mark
= PORT_ArenaMark(safeBag
->arena
);
920 /* allocate the attribute */
921 attribute
= (sec_PKCS12Attribute
*)PORT_ArenaZAlloc(safeBag
->arena
,
922 sizeof(sec_PKCS12Attribute
));
924 PORT_SetError(SEC_ERROR_NO_MEMORY
);
928 /* set up the attribute */
929 oiddata
= SECOID_FindOIDByTag(attrType
);
931 PORT_SetError(SEC_ERROR_NO_MEMORY
);
934 if(SECITEM_CopyItem(p12ctxt
->arena
, &attribute
->attrType
, &oiddata
->oid
) !=
936 PORT_SetError(SEC_ERROR_NO_MEMORY
);
942 case SEC_OID_PKCS9_LOCAL_KEY_ID
:
947 case SEC_OID_PKCS9_FRIENDLY_NAME
:
949 if(!sec_pkcs12_convert_item_to_unicode(p12ctxt
->arena
,
950 &unicodeName
, attrData
, PR_FALSE
,
951 PR_FALSE
, PR_TRUE
)) {
961 /* append the attribute to the attribute value list */
962 attribute
->attrValue
= (SECItem
**)PORT_ArenaZAlloc(p12ctxt
->arena
,
963 ((nItems
+ 1) * sizeof(SECItem
*)));
964 if(!attribute
->attrValue
) {
965 PORT_SetError(SEC_ERROR_NO_MEMORY
);
969 /* XXX this will need to be changed if attributes requiring more than
970 * one element are ever used.
972 attribute
->attrValue
[0] = (SECItem
*)PORT_ArenaZAlloc(p12ctxt
->arena
,
974 if(!attribute
->attrValue
[0]) {
975 PORT_SetError(SEC_ERROR_NO_MEMORY
);
978 attribute
->attrValue
[1] = NULL
;
980 rv
= SECITEM_CopyItem(p12ctxt
->arena
, attribute
->attrValue
[0],
982 if(rv
!= SECSuccess
) {
983 PORT_SetError(SEC_ERROR_NO_MEMORY
);
987 /* append the attribute to the safeBag attributes */
988 if(safeBag
->nAttribs
) {
989 dummy
= PORT_ArenaGrow(p12ctxt
->arena
, safeBag
->attribs
,
990 ((safeBag
->nAttribs
+ 1) * sizeof(sec_PKCS12Attribute
*)),
991 ((safeBag
->nAttribs
+ 2) * sizeof(sec_PKCS12Attribute
*)));
992 safeBag
->attribs
= (sec_PKCS12Attribute
**)dummy
;
994 safeBag
->attribs
= (sec_PKCS12Attribute
**)PORT_ArenaZAlloc(p12ctxt
->arena
,
995 2 * sizeof(sec_PKCS12Attribute
*));
996 dummy
= safeBag
->attribs
;
1002 safeBag
->attribs
[safeBag
->nAttribs
] = attribute
;
1003 safeBag
->attribs
[++safeBag
->nAttribs
] = NULL
;
1005 PORT_ArenaUnmark(p12ctxt
->arena
, mark
);
1010 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
1016 /* SEC_PKCS12AddCert
1017 * Adds a certificate to the data being exported.
1019 * p12ctxt - the export context
1020 * safe - the safeInfo to which the certificate is placed
1021 * nestedDest - if the cert is to be placed within a nested safeContents then,
1022 * this value is to be specified with the destination
1023 * cert - the cert to export
1024 * certDb - the certificate database handle
1025 * keyId - a unique identifier to associate a certificate/key pair
1026 * includeCertChain - PR_TRUE if the certificate chain is to be included.
1029 SEC_PKCS12AddCert(SEC_PKCS12ExportContext
*p12ctxt
, SEC_PKCS12SafeInfo
*safe
,
1030 void *nestedDest
, CERTCertificate
*cert
,
1031 CERTCertDBHandle
*certDb
, SECItem
*keyId
,
1032 PRBool includeCertChain
)
1034 sec_PKCS12CertBag
*certBag
;
1035 sec_PKCS12SafeBag
*safeBag
;
1038 SECItem nick
= {siBuffer
, NULL
,0};
1040 if(!p12ctxt
|| !cert
) {
1043 mark
= PORT_ArenaMark(p12ctxt
->arena
);
1045 /* allocate the cert bag */
1046 certBag
= sec_PKCS12NewCertBag(p12ctxt
->arena
,
1047 SEC_OID_PKCS9_X509_CERT
);
1052 if(SECITEM_CopyItem(p12ctxt
->arena
, &certBag
->value
.x509Cert
,
1053 &cert
->derCert
) != SECSuccess
) {
1054 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1058 /* if the cert chain is to be included, we should only be exporting
1059 * the cert from our internal database.
1061 if(includeCertChain
) {
1062 CERTCertificateList
*certList
= CERT_CertChainFromCert(cert
,
1065 unsigned int count
= 0;
1067 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1071 /* add cert chain */
1072 for(count
= 0; count
< (unsigned int)certList
->len
; count
++) {
1073 if(SECITEM_CompareItem(&certList
->certs
[count
], &cert
->derCert
)
1075 CERTCertificate
*tempCert
;
1077 /* decode the certificate */
1079 * This was rather silly. The chain is constructed above
1080 * by finding all of the CERTCertificate's in the database.
1081 * Then the chain is put into a CERTCertificateList, which only
1082 * contains the DER. Finally, the DER was decoded, and the
1083 * decoded cert was sent recursively back to this function.
1084 * Beyond being inefficent, this causes data loss (specifically,
1085 * the nickname). Instead, for 3.4, we'll do a lookup by the
1086 * DER, which should return the cached entry.
1088 tempCert
= CERT_FindCertByDERCert(CERT_GetDefaultCertDB(),
1089 &certList
->certs
[count
]);
1091 CERT_DestroyCertificateList(certList
);
1095 /* add the certificate */
1096 if(SEC_PKCS12AddCert(p12ctxt
, safe
, nestedDest
, tempCert
,
1097 certDb
, NULL
, PR_FALSE
) != SECSuccess
) {
1098 CERT_DestroyCertificate(tempCert
);
1099 CERT_DestroyCertificateList(certList
);
1102 CERT_DestroyCertificate(tempCert
);
1105 CERT_DestroyCertificateList(certList
);
1108 /* if the certificate has a nickname, we will set the friendly name
1111 if(cert
->nickname
) {
1112 if (cert
->slot
&& !PK11_IsInternal(cert
->slot
)) {
1114 * The cert is coming off of an external token,
1115 * let's strip the token name from the nickname
1116 * and only add what comes after the colon as the
1121 delimit
= PORT_Strchr(cert
->nickname
,':');
1122 if (delimit
== NULL
) {
1123 nick
.data
= (unsigned char *)cert
->nickname
;
1124 nick
.len
= PORT_Strlen(cert
->nickname
);
1127 nick
.data
= (unsigned char *)PORT_ArenaStrdup(p12ctxt
->arena
,
1129 nick
.len
= PORT_Strlen(delimit
);
1132 nick
.data
= (unsigned char *)cert
->nickname
;
1133 nick
.len
= PORT_Strlen(cert
->nickname
);
1137 safeBag
= sec_PKCS12CreateSafeBag(p12ctxt
, SEC_OID_PKCS12_V1_CERT_BAG_ID
,
1143 /* add the friendly name and keyId attributes, if necessary */
1145 if(sec_PKCS12AddAttributeToBag(p12ctxt
, safeBag
,
1146 SEC_OID_PKCS9_FRIENDLY_NAME
, &nick
)
1153 if(sec_PKCS12AddAttributeToBag(p12ctxt
, safeBag
, SEC_OID_PKCS9_LOCAL_KEY_ID
,
1154 keyId
) != SECSuccess
) {
1159 /* append the cert safeBag */
1161 rv
= sec_pkcs12_append_bag_to_safe_contents(p12ctxt
->arena
,
1162 (sec_PKCS12SafeContents
*)nestedDest
,
1165 rv
= sec_pkcs12_append_bag(p12ctxt
, safe
, safeBag
);
1168 if(rv
!= SECSuccess
) {
1172 PORT_ArenaUnmark(p12ctxt
->arena
, mark
);
1177 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
1183 /* SEC_PKCS12AddEncryptedKey
1184 * Extracts the key associated with a particular certificate and exports
1187 * p12ctxt - the export context
1188 * safe - the safeInfo to place the key in
1189 * nestedDest - the nested safeContents to place a key
1190 * cert - the certificate which the key belongs to
1191 * shroudKey - encrypt the private key for export. This value should
1192 * always be true. lower level code will not allow the export
1193 * of unencrypted private keys.
1194 * algorithm - the algorithm with which to encrypt the private key
1195 * pwitem - the password to encrypted the private key with
1196 * keyId - the keyID attribute
1197 * nickName - the nickname attribute
1200 SEC_PKCS12AddEncryptedKey(SEC_PKCS12ExportContext
*p12ctxt
,
1201 SECKEYEncryptedPrivateKeyInfo
*epki
, SEC_PKCS12SafeInfo
*safe
,
1202 void *nestedDest
, SECItem
*keyId
, SECItem
*nickName
)
1207 SECStatus rv
= SECFailure
;
1208 sec_PKCS12SafeBag
*returnBag
;
1210 if(!p12ctxt
|| !safe
|| !epki
) {
1214 mark
= PORT_ArenaMark(p12ctxt
->arena
);
1216 keyItem
= PORT_ArenaZAlloc(p12ctxt
->arena
,
1217 sizeof(SECKEYEncryptedPrivateKeyInfo
));
1219 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1223 rv
= SECKEY_CopyEncryptedPrivateKeyInfo(p12ctxt
->arena
,
1224 (SECKEYEncryptedPrivateKeyInfo
*)keyItem
,
1226 keyType
= SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID
;
1228 if(rv
!= SECSuccess
) {
1232 /* create the safe bag and set any attributes */
1233 returnBag
= sec_PKCS12CreateSafeBag(p12ctxt
, keyType
, keyItem
);
1240 if(sec_PKCS12AddAttributeToBag(p12ctxt
, returnBag
,
1241 SEC_OID_PKCS9_FRIENDLY_NAME
, nickName
)
1248 if(sec_PKCS12AddAttributeToBag(p12ctxt
, returnBag
,
1249 SEC_OID_PKCS9_LOCAL_KEY_ID
,
1250 keyId
) != SECSuccess
) {
1256 rv
= sec_pkcs12_append_bag_to_safe_contents(p12ctxt
->arena
,
1257 (sec_PKCS12SafeContents
*)nestedDest
,
1260 rv
= sec_pkcs12_append_bag(p12ctxt
, safe
, returnBag
);
1265 if (rv
!= SECSuccess
) {
1266 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
1268 PORT_ArenaUnmark(p12ctxt
->arena
, mark
);
1274 /* SEC_PKCS12AddKeyForCert
1275 * Extracts the key associated with a particular certificate and exports
1278 * p12ctxt - the export context
1279 * safe - the safeInfo to place the key in
1280 * nestedDest - the nested safeContents to place a key
1281 * cert - the certificate which the key belongs to
1282 * shroudKey - encrypt the private key for export. This value should
1283 * always be true. lower level code will not allow the export
1284 * of unencrypted private keys.
1285 * algorithm - the algorithm with which to encrypt the private key
1286 * pwitem - the password to encrypt the private key with
1287 * keyId - the keyID attribute
1288 * nickName - the nickname attribute
1291 SEC_PKCS12AddKeyForCert(SEC_PKCS12ExportContext
*p12ctxt
, SEC_PKCS12SafeInfo
*safe
,
1292 void *nestedDest
, CERTCertificate
*cert
,
1293 PRBool shroudKey
, SECOidTag algorithm
, SECItem
*pwitem
,
1294 SECItem
*keyId
, SECItem
*nickName
)
1299 SECStatus rv
= SECFailure
;
1300 SECItem nickname
= {siBuffer
,NULL
,0}, uniPwitem
= {siBuffer
, NULL
, 0};
1301 sec_PKCS12SafeBag
*returnBag
;
1303 if(!p12ctxt
|| !cert
|| !safe
) {
1307 mark
= PORT_ArenaMark(p12ctxt
->arena
);
1309 /* retrieve the key based upon the type that it is and
1310 * specify the type of safeBag to store the key in
1314 /* extract the key unencrypted. this will most likely go away */
1315 SECKEYPrivateKeyInfo
*pki
= PK11_ExportPrivateKeyInfo(cert
,
1318 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
1319 PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY
);
1322 keyItem
= PORT_ArenaZAlloc(p12ctxt
->arena
, sizeof(SECKEYPrivateKeyInfo
));
1324 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1327 rv
= SECKEY_CopyPrivateKeyInfo(p12ctxt
->arena
,
1328 (SECKEYPrivateKeyInfo
*)keyItem
, pki
);
1329 keyType
= SEC_OID_PKCS12_V1_KEY_BAG_ID
;
1330 SECKEY_DestroyPrivateKeyInfo(pki
, PR_TRUE
);
1333 /* extract the key encrypted */
1334 SECKEYEncryptedPrivateKeyInfo
*epki
= NULL
;
1335 PK11SlotInfo
*slot
= NULL
;
1337 if(!sec_pkcs12_convert_item_to_unicode(p12ctxt
->arena
, &uniPwitem
,
1338 pwitem
, PR_TRUE
, PR_TRUE
, PR_TRUE
)) {
1339 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1343 /* we want to make sure to take the key out of the key slot */
1344 if(PK11_IsInternal(p12ctxt
->slot
)) {
1345 slot
= PK11_GetInternalKeySlot();
1347 slot
= PK11_ReferenceSlot(p12ctxt
->slot
);
1350 epki
= PK11_ExportEncryptedPrivateKeyInfo(slot
, algorithm
,
1351 &uniPwitem
, cert
, 1,
1353 PK11_FreeSlot(slot
);
1355 keyItem
= PORT_ArenaZAlloc(p12ctxt
->arena
,
1356 sizeof(SECKEYEncryptedPrivateKeyInfo
));
1358 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1362 PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY
);
1365 rv
= SECKEY_CopyEncryptedPrivateKeyInfo(p12ctxt
->arena
,
1366 (SECKEYEncryptedPrivateKeyInfo
*)keyItem
,
1368 keyType
= SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID
;
1369 SECKEY_DestroyEncryptedPrivateKeyInfo(epki
, PR_TRUE
);
1372 if(rv
!= SECSuccess
) {
1376 /* if no nickname specified, let's see if the certificate has a
1380 if(cert
->nickname
) {
1381 nickname
.data
= (unsigned char *)cert
->nickname
;
1382 nickname
.len
= PORT_Strlen(cert
->nickname
);
1383 nickName
= &nickname
;
1387 /* create the safe bag and set any attributes */
1388 returnBag
= sec_PKCS12CreateSafeBag(p12ctxt
, keyType
, keyItem
);
1395 if(sec_PKCS12AddAttributeToBag(p12ctxt
, returnBag
,
1396 SEC_OID_PKCS9_FRIENDLY_NAME
, nickName
)
1403 if(sec_PKCS12AddAttributeToBag(p12ctxt
, returnBag
, SEC_OID_PKCS9_LOCAL_KEY_ID
,
1404 keyId
) != SECSuccess
) {
1410 rv
= sec_pkcs12_append_bag_to_safe_contents(p12ctxt
->arena
,
1411 (sec_PKCS12SafeContents
*)nestedDest
,
1414 rv
= sec_pkcs12_append_bag(p12ctxt
, safe
, returnBag
);
1419 if (rv
!= SECSuccess
) {
1420 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
1422 PORT_ArenaUnmark(p12ctxt
->arena
, mark
);
1428 /* SEC_PKCS12AddCertAndEncryptedKey
1429 * Add a certificate and key pair to be exported.
1431 * p12ctxt - the export context
1432 * certSafe - the safeInfo where the cert is stored
1433 * certNestedDest - the nested safeContents to store the cert
1434 * keySafe - the safeInfo where the key is stored
1435 * keyNestedDest - the nested safeContents to store the key
1436 * shroudKey - extract the private key encrypted?
1437 * pwitem - the password with which the key is encrypted
1438 * algorithm - the algorithm with which the key is encrypted
1441 SEC_PKCS12AddDERCertAndEncryptedKey(SEC_PKCS12ExportContext
*p12ctxt
,
1442 void *certSafe
, void *certNestedDest
,
1443 SECItem
*derCert
, void *keySafe
,
1444 void *keyNestedDest
, SECKEYEncryptedPrivateKeyInfo
*epki
,
1447 SECStatus rv
= SECFailure
;
1448 SGNDigestInfo
*digest
= NULL
;
1450 CERTCertificate
*cert
;
1451 SECItem nick
= {siBuffer
, NULL
,0}, *nickPtr
= NULL
;
1453 if(!p12ctxt
|| !certSafe
|| !keySafe
|| !derCert
) {
1457 mark
= PORT_ArenaMark(p12ctxt
->arena
);
1459 cert
= CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
1460 derCert
, NULL
, PR_FALSE
, PR_FALSE
);
1462 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
1463 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1466 cert
->nickname
= nickname
;
1468 /* generate the thumbprint of the cert to use as a keyId */
1469 digest
= sec_pkcs12_compute_thumbprint(&cert
->derCert
);
1471 CERT_DestroyCertificate(cert
);
1475 /* add the certificate */
1476 rv
= SEC_PKCS12AddCert(p12ctxt
, (SEC_PKCS12SafeInfo
*)certSafe
,
1477 certNestedDest
, cert
, NULL
,
1478 &digest
->digest
, PR_FALSE
);
1479 if(rv
!= SECSuccess
) {
1484 nick
.data
= (unsigned char *)nickname
;
1485 nick
.len
= PORT_Strlen(nickname
);
1492 rv
= SEC_PKCS12AddEncryptedKey(p12ctxt
, epki
, (SEC_PKCS12SafeInfo
*)keySafe
,
1493 keyNestedDest
, &digest
->digest
, nickPtr
);
1494 if(rv
!= SECSuccess
) {
1498 SGN_DestroyDigestInfo(digest
);
1500 PORT_ArenaUnmark(p12ctxt
->arena
, mark
);
1504 SGN_DestroyDigestInfo(digest
);
1505 CERT_DestroyCertificate(cert
);
1506 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
1511 /* SEC_PKCS12AddCertAndKey
1512 * Add a certificate and key pair to be exported.
1514 * p12ctxt - the export context
1515 * certSafe - the safeInfo where the cert is stored
1516 * certNestedDest - the nested safeContents to store the cert
1517 * keySafe - the safeInfo where the key is stored
1518 * keyNestedDest - the nested safeContents to store the key
1519 * shroudKey - extract the private key encrypted?
1520 * pwitem - the password with which the key is encrypted
1521 * algorithm - the algorithm with which the key is encrypted
1524 SEC_PKCS12AddCertAndKey(SEC_PKCS12ExportContext
*p12ctxt
,
1525 void *certSafe
, void *certNestedDest
,
1526 CERTCertificate
*cert
, CERTCertDBHandle
*certDb
,
1527 void *keySafe
, void *keyNestedDest
,
1528 PRBool shroudKey
, SECItem
*pwitem
, SECOidTag algorithm
)
1530 SECStatus rv
= SECFailure
;
1531 SGNDigestInfo
*digest
= NULL
;
1534 if(!p12ctxt
|| !certSafe
|| !keySafe
|| !cert
) {
1538 mark
= PORT_ArenaMark(p12ctxt
->arena
);
1540 /* generate the thumbprint of the cert to use as a keyId */
1541 digest
= sec_pkcs12_compute_thumbprint(&cert
->derCert
);
1543 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
1547 /* add the certificate */
1548 rv
= SEC_PKCS12AddCert(p12ctxt
, (SEC_PKCS12SafeInfo
*)certSafe
,
1549 (SEC_PKCS12SafeInfo
*)certNestedDest
, cert
, certDb
,
1550 &digest
->digest
, PR_TRUE
);
1551 if(rv
!= SECSuccess
) {
1556 rv
= SEC_PKCS12AddKeyForCert(p12ctxt
, (SEC_PKCS12SafeInfo
*)keySafe
,
1557 keyNestedDest
, cert
,
1558 shroudKey
, algorithm
, pwitem
,
1559 &digest
->digest
, NULL
);
1560 if(rv
!= SECSuccess
) {
1564 SGN_DestroyDigestInfo(digest
);
1566 PORT_ArenaUnmark(p12ctxt
->arena
, mark
);
1570 SGN_DestroyDigestInfo(digest
);
1571 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
1576 /* SEC_PKCS12CreateNestedSafeContents
1577 * Allows nesting of safe contents to be implemented. No limit imposed on
1580 * p12ctxt - the export context
1581 * baseSafe - the base safeInfo
1582 * nestedDest - a parent safeContents (?)
1585 SEC_PKCS12CreateNestedSafeContents(SEC_PKCS12ExportContext
*p12ctxt
,
1586 void *baseSafe
, void *nestedDest
)
1588 sec_PKCS12SafeContents
*newSafe
;
1589 sec_PKCS12SafeBag
*safeContentsBag
;
1593 if(!p12ctxt
|| !baseSafe
) {
1597 mark
= PORT_ArenaMark(p12ctxt
->arena
);
1599 newSafe
= sec_PKCS12CreateSafeContents(p12ctxt
->arena
);
1601 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
1602 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1606 /* create the safeContents safeBag */
1607 safeContentsBag
= sec_PKCS12CreateSafeBag(p12ctxt
,
1608 SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID
,
1610 if(!safeContentsBag
) {
1614 /* append the safeContents to the appropriate area */
1616 rv
= sec_pkcs12_append_bag_to_safe_contents(p12ctxt
->arena
,
1617 (sec_PKCS12SafeContents
*)nestedDest
,
1620 rv
= sec_pkcs12_append_bag(p12ctxt
, (SEC_PKCS12SafeInfo
*)baseSafe
,
1623 if(rv
!= SECSuccess
) {
1627 PORT_ArenaUnmark(p12ctxt
->arena
, mark
);
1631 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
1635 /*********************************
1637 *********************************/
1639 /* set up the encoder context based on information in the export context
1640 * and return the newly allocated enocoder context. A return of NULL
1641 * indicates an error occurred.
1643 sec_PKCS12EncoderContext
*
1644 sec_pkcs12_encoder_start_context(SEC_PKCS12ExportContext
*p12exp
)
1646 sec_PKCS12EncoderContext
*p12enc
= NULL
;
1647 unsigned int i
, nonEmptyCnt
;
1649 SECItem ignore
= {0};
1652 if(!p12exp
|| !p12exp
->safeInfos
) {
1656 /* check for any empty safes and skip them */
1657 i
= nonEmptyCnt
= 0;
1658 while(p12exp
->safeInfos
[i
]) {
1659 if(p12exp
->safeInfos
[i
]->itemCount
) {
1664 if(nonEmptyCnt
== 0) {
1667 p12exp
->authSafe
.encodedSafes
[nonEmptyCnt
] = NULL
;
1669 /* allocate the encoder context */
1670 mark
= PORT_ArenaMark(p12exp
->arena
);
1671 p12enc
= PORT_ArenaZNew(p12exp
->arena
, sec_PKCS12EncoderContext
);
1673 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1677 p12enc
->arena
= p12exp
->arena
;
1678 p12enc
->p12exp
= p12exp
;
1680 /* set up the PFX version and information */
1681 PORT_Memset(&p12enc
->pfx
, 0, sizeof(sec_PKCS12PFXItem
));
1682 if(!SEC_ASN1EncodeInteger(p12exp
->arena
, &(p12enc
->pfx
.version
),
1683 SEC_PKCS12_VERSION
) ) {
1684 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1688 /* set up the authenticated safe content info based on the
1689 * type of integrity being used. this should be changed to
1690 * enforce integrity mode, but will not be implemented until
1691 * it is confirmed that integrity must be in place
1693 if(p12exp
->integrityEnabled
&& !p12exp
->pwdIntegrity
) {
1696 /* create public key integrity mode */
1697 p12enc
->aSafeCinfo
= SEC_PKCS7CreateSignedData(
1698 p12exp
->integrityInfo
.pubkeyInfo
.cert
,
1699 certUsageEmailSigner
,
1700 p12exp
->integrityInfo
.pubkeyInfo
.certDb
,
1701 p12exp
->integrityInfo
.pubkeyInfo
.algorithm
,
1705 if(!p12enc
->aSafeCinfo
) {
1708 if(SEC_PKCS7IncludeCertChain(p12enc
->aSafeCinfo
,NULL
) != SECSuccess
) {
1711 rv
= SEC_PKCS7AddSigningTime(p12enc
->aSafeCinfo
);
1712 PORT_Assert(rv
== SECSuccess
);
1714 p12enc
->aSafeCinfo
= SEC_PKCS7CreateData();
1716 /* init password pased integrity mode */
1717 if(p12exp
->integrityEnabled
) {
1718 SECItem pwd
= {siBuffer
,NULL
, 0};
1719 SECItem
*salt
= sec_pkcs12_generate_salt();
1722 CK_MECHANISM_TYPE integrityMechType
;
1723 CK_MECHANISM_TYPE hmacMechType
;
1725 /* zero out macData and set values */
1726 PORT_Memset(&p12enc
->mac
, 0, sizeof(sec_PKCS12MacData
));
1729 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1732 if(SECITEM_CopyItem(p12exp
->arena
, &(p12enc
->mac
.macSalt
), salt
)
1734 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1738 /* generate HMAC key */
1739 if(!sec_pkcs12_convert_item_to_unicode(NULL
, &pwd
,
1740 p12exp
->integrityInfo
.pwdInfo
.password
, PR_TRUE
,
1741 PR_TRUE
, PR_TRUE
)) {
1745 * This code only works with PKCS #12 Mac using PKCS #5 v1
1746 * PBA keygens. PKCS #5 v2 support will require a change to
1747 * the PKCS #12 spec.
1749 params
= PK11_CreatePBEParams(salt
, &pwd
, 1);
1750 SECITEM_ZfreeItem(salt
, PR_TRUE
);
1751 SECITEM_ZfreeItem(&pwd
, PR_FALSE
);
1753 /* get the PBA Mechanism to generate the key */
1754 switch (p12exp
->integrityInfo
.pwdInfo
.algorithm
) {
1756 integrityMechType
= CKM_PBA_SHA1_WITH_SHA1_HMAC
; break;
1758 integrityMechType
= CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN
; break;
1760 integrityMechType
= CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN
; break;
1765 /* generate the key */
1766 symKey
= PK11_KeyGen(NULL
, integrityMechType
, params
, 20, NULL
);
1767 PK11_DestroyPBEParams(params
);
1772 /* initialize HMAC */
1773 /* Get the HMAC mechanism from the hash OID */
1774 hmacMechType
= sec_pkcs12_algtag_to_mech(
1775 p12exp
->integrityInfo
.pwdInfo
.algorithm
);
1777 p12enc
->hmacCx
= PK11_CreateContextBySymKey( hmacMechType
,
1778 CKA_SIGN
, symKey
, &ignore
);
1780 PK11_FreeSymKey(symKey
);
1781 if(!p12enc
->hmacCx
) {
1782 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1785 rv
= PK11_DigestBegin(p12enc
->hmacCx
);
1786 if (rv
!= SECSuccess
)
1791 if(!p12enc
->aSafeCinfo
) {
1795 PORT_ArenaUnmark(p12exp
->arena
, mark
);
1801 if(p12enc
->aSafeCinfo
) {
1802 SEC_PKCS7DestroyContentInfo(p12enc
->aSafeCinfo
);
1804 if(p12enc
->hmacCx
) {
1805 PK11_DestroyContext(p12enc
->hmacCx
, PR_TRUE
);
1808 if (p12exp
->arena
!= NULL
)
1809 PORT_ArenaRelease(p12exp
->arena
, mark
);
1814 /* The outermost ASN.1 encoder calls this function for output.
1815 ** This function calls back to the library caller's output routine,
1816 ** which typically writes to a PKCS12 file.
1819 sec_P12A1OutputCB_Outer(void *arg
, const char *buf
, unsigned long len
,
1820 int depth
, SEC_ASN1EncodingPart data_kind
)
1822 struct sec_pkcs12_encoder_output
*output
;
1824 output
= (struct sec_pkcs12_encoder_output
*)arg
;
1825 (* output
->outputfn
)(output
->outputarg
, buf
, len
);
1828 /* The "middle" and "inner" ASN.1 encoders call this function to output.
1829 ** This function does HMACing, if appropriate, and then buffers the data.
1830 ** The buffered data is eventually passed down to the underlying PKCS7 encoder.
1833 sec_P12A1OutputCB_HmacP7Update(void *arg
, const char *buf
,
1836 SEC_ASN1EncodingPart data_kind
)
1838 sec_pkcs12OutputBuffer
* bufcx
= (sec_pkcs12OutputBuffer
*)arg
;
1843 if (bufcx
->hmacCx
) {
1844 PK11_DigestOp(bufcx
->hmacCx
, (unsigned char *)buf
, len
);
1848 if (bufcx
->numBytes
> 0) {
1850 if (len
+ bufcx
->numBytes
<= bufcx
->bufBytes
) {
1851 memcpy(bufcx
->buf
+ bufcx
->numBytes
, buf
, len
);
1852 bufcx
->numBytes
+= len
;
1853 if (bufcx
->numBytes
< bufcx
->bufBytes
)
1855 SEC_PKCS7EncoderUpdate(bufcx
->p7eCx
, bufcx
->buf
, bufcx
->bufBytes
);
1856 bufcx
->numBytes
= 0;
1859 toCopy
= bufcx
->bufBytes
- bufcx
->numBytes
;
1860 memcpy(bufcx
->buf
+ bufcx
->numBytes
, buf
, toCopy
);
1861 SEC_PKCS7EncoderUpdate(bufcx
->p7eCx
, bufcx
->buf
, bufcx
->bufBytes
);
1862 bufcx
->numBytes
= 0;
1866 /* buffer is presently empty */
1867 if (len
>= bufcx
->bufBytes
) {
1868 /* Just pass it through */
1869 SEC_PKCS7EncoderUpdate(bufcx
->p7eCx
, buf
, len
);
1871 /* copy it all into the buffer, and return */
1872 memcpy(bufcx
->buf
, buf
, len
);
1873 bufcx
->numBytes
= len
;
1878 sec_FlushPkcs12OutputBuffer( sec_pkcs12OutputBuffer
* bufcx
)
1880 if (bufcx
->numBytes
> 0) {
1881 SEC_PKCS7EncoderUpdate(bufcx
->p7eCx
, bufcx
->buf
, bufcx
->numBytes
);
1882 bufcx
->numBytes
= 0;
1886 /* Feeds the output of a PKCS7 encoder into the next outward ASN.1 encoder.
1887 ** This function is used by both the inner and middle PCS7 encoders.
1890 sec_P12P7OutputCB_CallA1Update(void *arg
, const char *buf
, unsigned long len
)
1892 SEC_ASN1EncoderContext
*cx
= (SEC_ASN1EncoderContext
*)arg
;
1897 SEC_ASN1EncoderUpdate(cx
, buf
, len
);
1901 /* this function encodes content infos which are part of the
1902 * sequence of content infos labeled AuthenticatedSafes
1905 sec_pkcs12_encoder_asafe_process(sec_PKCS12EncoderContext
*p12ecx
)
1907 SEC_PKCS7EncoderContext
*innerP7ecx
;
1908 SEC_PKCS7ContentInfo
*cinfo
;
1909 PK11SymKey
*bulkKey
= NULL
;
1910 SEC_ASN1EncoderContext
*innerA1ecx
= NULL
;
1911 SECStatus rv
= SECSuccess
;
1913 if(p12ecx
->currentSafe
< p12ecx
->p12exp
->authSafe
.safeCount
) {
1914 SEC_PKCS12SafeInfo
*safeInfo
;
1915 SECOidTag cinfoType
;
1917 safeInfo
= p12ecx
->p12exp
->safeInfos
[p12ecx
->currentSafe
];
1919 /* skip empty safes */
1920 if(safeInfo
->itemCount
== 0) {
1924 cinfo
= safeInfo
->cinfo
;
1925 cinfoType
= SEC_PKCS7ContentType(cinfo
);
1927 /* determine the safe type and set the appropriate argument */
1929 case SEC_OID_PKCS7_DATA
:
1930 case SEC_OID_PKCS7_ENVELOPED_DATA
:
1932 case SEC_OID_PKCS7_ENCRYPTED_DATA
:
1933 bulkKey
= safeInfo
->encryptionKey
;
1934 PK11_SetSymKeyUserData(bulkKey
, &safeInfo
->pwitem
, NULL
);
1941 /* start the PKCS7 encoder */
1942 innerP7ecx
= SEC_PKCS7EncoderStart(cinfo
,
1943 sec_P12P7OutputCB_CallA1Update
,
1944 p12ecx
->middleA1ecx
, bulkKey
);
1949 /* encode safe contents */
1950 p12ecx
->innerBuf
.p7eCx
= innerP7ecx
;
1951 p12ecx
->innerBuf
.hmacCx
= NULL
;
1952 p12ecx
->innerBuf
.numBytes
= 0;
1953 p12ecx
->innerBuf
.bufBytes
= sizeof p12ecx
->innerBuf
.buf
;
1955 innerA1ecx
= SEC_ASN1EncoderStart(safeInfo
->safe
,
1956 sec_PKCS12SafeContentsTemplate
,
1957 sec_P12A1OutputCB_HmacP7Update
,
1962 rv
= SEC_ASN1EncoderUpdate(innerA1ecx
, NULL
, 0);
1963 SEC_ASN1EncoderFinish(innerA1ecx
);
1964 sec_FlushPkcs12OutputBuffer( &p12ecx
->innerBuf
);
1966 if(rv
!= SECSuccess
) {
1971 /* finish up safe content info */
1972 rv
= SEC_PKCS7EncoderFinish(innerP7ecx
, p12ecx
->p12exp
->pwfn
,
1973 p12ecx
->p12exp
->pwfnarg
);
1975 memset(&p12ecx
->innerBuf
, 0, sizeof p12ecx
->innerBuf
);
1980 SEC_PKCS7EncoderFinish(innerP7ecx
, p12ecx
->p12exp
->pwfn
,
1981 p12ecx
->p12exp
->pwfnarg
);
1985 SEC_ASN1EncoderFinish(innerA1ecx
);
1987 memset(&p12ecx
->innerBuf
, 0, sizeof p12ecx
->innerBuf
);
1991 /* finish the HMAC and encode the macData so that it can be
1995 sec_Pkcs12FinishMac(sec_PKCS12EncoderContext
*p12ecx
)
1997 SECItem hmac
= { siBuffer
, NULL
, 0 };
1999 SGNDigestInfo
*di
= NULL
;
2006 /* make sure we are using password integrity mode */
2007 if(!p12ecx
->p12exp
->integrityEnabled
) {
2011 if(!p12ecx
->p12exp
->pwdIntegrity
) {
2015 /* finish the hmac */
2016 hmac
.data
= (unsigned char *)PORT_ZAlloc(SHA1_LENGTH
);
2018 PORT_SetError(SEC_ERROR_NO_MEMORY
);
2022 rv
= PK11_DigestFinal(p12ecx
->hmacCx
, hmac
.data
, &hmac
.len
, SHA1_LENGTH
);
2024 if(rv
!= SECSuccess
) {
2025 PORT_SetError(SEC_ERROR_NO_MEMORY
);
2029 /* create the digest info */
2030 di
= SGN_CreateDigestInfo(p12ecx
->p12exp
->integrityInfo
.pwdInfo
.algorithm
,
2031 hmac
.data
, hmac
.len
);
2033 PORT_SetError(SEC_ERROR_NO_MEMORY
);
2038 rv
= SGN_CopyDigestInfo(p12ecx
->arena
, &p12ecx
->mac
.safeMac
, di
);
2039 if(rv
!= SECSuccess
) {
2040 PORT_SetError(SEC_ERROR_NO_MEMORY
);
2044 /* encode the mac data */
2045 dummy
= SEC_ASN1EncodeItem(p12ecx
->arena
, &p12ecx
->pfx
.encodedMacData
,
2046 &p12ecx
->mac
, sec_PKCS12MacDataTemplate
);
2048 PORT_SetError(SEC_ERROR_NO_MEMORY
);
2054 SGN_DestroyDigestInfo(di
);
2057 SECITEM_ZfreeItem(&hmac
, PR_FALSE
);
2059 PK11_DestroyContext(p12ecx
->hmacCx
, PR_TRUE
);
2060 p12ecx
->hmacCx
= NULL
;
2065 /* pfx notify function for ASN1 encoder.
2066 * We want to stop encoding once we reach the authenticated safe.
2067 * At that point, the encoder will be updated via streaming
2068 * as the authenticated safe is encoded.
2071 sec_pkcs12_encoder_pfx_notify(void *arg
, PRBool before
, void *dest
, int real_depth
)
2073 sec_PKCS12EncoderContext
*p12ecx
;
2079 /* look for authenticated safe */
2080 p12ecx
= (sec_PKCS12EncoderContext
*)arg
;
2081 if(dest
!= &p12ecx
->pfx
.encodedAuthSafe
) {
2085 SEC_ASN1EncoderSetTakeFromBuf(p12ecx
->outerA1ecx
);
2086 SEC_ASN1EncoderSetStreaming(p12ecx
->outerA1ecx
);
2087 SEC_ASN1EncoderClearNotifyProc(p12ecx
->outerA1ecx
);
2091 * Encodes the PFX item and returns it to the output function, via
2092 * callback. the output function must be capable of multiple updates.
2094 * p12exp - the export context
2095 * output - the output function callback, will be called more than once,
2096 * must be able to accept streaming data.
2097 * outputarg - argument for the output callback.
2100 SEC_PKCS12Encode(SEC_PKCS12ExportContext
*p12exp
,
2101 SEC_PKCS12EncoderOutputCallback output
, void *outputarg
)
2103 sec_PKCS12EncoderContext
*p12enc
;
2104 struct sec_pkcs12_encoder_output outInfo
;
2107 if(!p12exp
|| !output
) {
2111 /* get the encoder context */
2112 p12enc
= sec_pkcs12_encoder_start_context(p12exp
);
2117 outInfo
.outputfn
= output
;
2118 outInfo
.outputarg
= outputarg
;
2120 /* set up PFX encoder, the "outer" encoder. Set it for streaming */
2121 p12enc
->outerA1ecx
= SEC_ASN1EncoderStart(&p12enc
->pfx
,
2122 sec_PKCS12PFXItemTemplate
,
2123 sec_P12A1OutputCB_Outer
,
2125 if(!p12enc
->outerA1ecx
) {
2126 PORT_SetError(SEC_ERROR_NO_MEMORY
);
2130 SEC_ASN1EncoderSetStreaming(p12enc
->outerA1ecx
);
2131 SEC_ASN1EncoderSetNotifyProc(p12enc
->outerA1ecx
,
2132 sec_pkcs12_encoder_pfx_notify
, p12enc
);
2133 rv
= SEC_ASN1EncoderUpdate(p12enc
->outerA1ecx
, NULL
, 0);
2134 if(rv
!= SECSuccess
) {
2139 /* set up asafe cinfo - the output of the encoder feeds the PFX encoder */
2140 p12enc
->middleP7ecx
= SEC_PKCS7EncoderStart(p12enc
->aSafeCinfo
,
2141 sec_P12P7OutputCB_CallA1Update
,
2142 p12enc
->outerA1ecx
, NULL
);
2143 if(!p12enc
->middleP7ecx
) {
2149 p12enc
->middleBuf
.p7eCx
= p12enc
->middleP7ecx
;
2150 p12enc
->middleBuf
.hmacCx
= NULL
;
2151 p12enc
->middleBuf
.numBytes
= 0;
2152 p12enc
->middleBuf
.bufBytes
= sizeof p12enc
->middleBuf
.buf
;
2154 /* Setup the "inner ASN.1 encoder for Authenticated Safes. */
2155 if(p12enc
->p12exp
->integrityEnabled
&&
2156 p12enc
->p12exp
->pwdIntegrity
) {
2157 p12enc
->middleBuf
.hmacCx
= p12enc
->hmacCx
;
2159 p12enc
->middleA1ecx
= SEC_ASN1EncoderStart(&p12enc
->p12exp
->authSafe
,
2160 sec_PKCS12AuthenticatedSafeTemplate
,
2161 sec_P12A1OutputCB_HmacP7Update
,
2162 &p12enc
->middleBuf
);
2163 if(!p12enc
->middleA1ecx
) {
2167 SEC_ASN1EncoderSetStreaming(p12enc
->middleA1ecx
);
2168 SEC_ASN1EncoderSetTakeFromBuf(p12enc
->middleA1ecx
);
2170 /* encode each of the safes */
2171 while(p12enc
->currentSafe
!= p12enc
->p12exp
->safeInfoCount
) {
2172 sec_pkcs12_encoder_asafe_process(p12enc
);
2173 p12enc
->currentSafe
++;
2175 SEC_ASN1EncoderClearTakeFromBuf(p12enc
->middleA1ecx
);
2176 SEC_ASN1EncoderClearStreaming(p12enc
->middleA1ecx
);
2177 SEC_ASN1EncoderUpdate(p12enc
->middleA1ecx
, NULL
, 0);
2178 SEC_ASN1EncoderFinish(p12enc
->middleA1ecx
);
2180 sec_FlushPkcs12OutputBuffer( &p12enc
->middleBuf
);
2182 /* finish the encoding of the authenticated safes */
2183 rv
= SEC_PKCS7EncoderFinish(p12enc
->middleP7ecx
, p12exp
->pwfn
,
2185 if(rv
!= SECSuccess
) {
2189 SEC_ASN1EncoderClearTakeFromBuf(p12enc
->outerA1ecx
);
2190 SEC_ASN1EncoderClearStreaming(p12enc
->outerA1ecx
);
2192 /* update the mac, if necessary */
2193 rv
= sec_Pkcs12FinishMac(p12enc
);
2194 if(rv
!= SECSuccess
) {
2198 /* finish encoding the pfx */
2199 rv
= SEC_ASN1EncoderUpdate(p12enc
->outerA1ecx
, NULL
, 0);
2201 SEC_ASN1EncoderFinish(p12enc
->outerA1ecx
);
2208 SEC_PKCS12DestroyExportContext(SEC_PKCS12ExportContext
*p12ecx
)
2216 if(p12ecx
->safeInfos
) {
2218 while(p12ecx
->safeInfos
[i
] != NULL
) {
2219 if(p12ecx
->safeInfos
[i
]->encryptionKey
) {
2220 PK11_FreeSymKey(p12ecx
->safeInfos
[i
]->encryptionKey
);
2222 if(p12ecx
->safeInfos
[i
]->cinfo
) {
2223 SEC_PKCS7DestroyContentInfo(p12ecx
->safeInfos
[i
]->cinfo
);
2229 PK11_FreeSlot(p12ecx
->slot
);
2231 PORT_FreeArena(p12ecx
->arena
, PR_TRUE
);
2235 /*********************************
2236 * All-in-one routines for exporting certificates
2237 *********************************/
2238 struct inPlaceEncodeInfo
{
2244 sec_pkcs12_in_place_encoder_output(void *arg
, const char *buf
, unsigned long len
)
2246 struct inPlaceEncodeInfo
*outInfo
= (struct inPlaceEncodeInfo
*)arg
;
2248 if(!outInfo
|| !len
|| outInfo
->error
) {
2252 if(!outInfo
->outItem
.data
) {
2253 outInfo
->outItem
.data
= (unsigned char*)PORT_ZAlloc(len
);
2254 outInfo
->outItem
.len
= 0;
2256 if(!PORT_Realloc(&(outInfo
->outItem
.data
), (outInfo
->outItem
.len
+ len
))) {
2257 SECITEM_ZfreeItem(&(outInfo
->outItem
), PR_FALSE
);
2258 outInfo
->outItem
.data
= NULL
;
2259 PORT_SetError(SEC_ERROR_NO_MEMORY
);
2260 outInfo
->error
= PR_TRUE
;
2265 PORT_Memcpy(&(outInfo
->outItem
.data
[outInfo
->outItem
.len
]), buf
, len
);
2266 outInfo
->outItem
.len
+= len
;
2272 * SEC_PKCS12ExportCertifcateAndKeyUsingPassword
2273 * Exports a certificate/key pair using password-based encryption and
2276 * pwfn, pwfnarg - password function and argument for the key database
2277 * cert - the certificate to export
2278 * certDb - certificate database
2279 * pwitem - the password to use
2280 * shroudKey - encrypt the key externally,
2281 * keyShroudAlg - encryption algorithm for key
2282 * encryptionAlg - the algorithm with which data is encrypted
2283 * integrityAlg - the algorithm for integrity
2286 SEC_PKCS12ExportCertificateAndKeyUsingPassword(
2287 SECKEYGetPasswordKey pwfn
, void *pwfnarg
,
2288 CERTCertificate
*cert
, PK11SlotInfo
*slot
,
2289 CERTCertDBHandle
*certDb
, SECItem
*pwitem
,
2290 PRBool shroudKey
, SECOidTag shroudAlg
,
2291 PRBool encryptCert
, SECOidTag certEncAlg
,
2292 SECOidTag integrityAlg
, void *wincx
)
2294 struct inPlaceEncodeInfo outInfo
;
2295 SEC_PKCS12ExportContext
*p12ecx
= NULL
;
2296 SEC_PKCS12SafeInfo
*keySafe
, *certSafe
;
2297 SECItem
*returnItem
= NULL
;
2299 if(!cert
|| !pwitem
|| !slot
) {
2303 outInfo
.error
= PR_FALSE
;
2304 outInfo
.outItem
.data
= NULL
;
2305 outInfo
.outItem
.len
= 0;
2307 p12ecx
= SEC_PKCS12CreateExportContext(pwfn
, pwfnarg
, slot
, wincx
);
2312 /* set up cert safe */
2314 certSafe
= SEC_PKCS12CreatePasswordPrivSafe(p12ecx
, pwitem
, certEncAlg
);
2316 certSafe
= SEC_PKCS12CreateUnencryptedSafe(p12ecx
);
2322 /* set up key safe */
2324 keySafe
= SEC_PKCS12CreateUnencryptedSafe(p12ecx
);
2332 /* add integrity mode */
2333 if(SEC_PKCS12AddPasswordIntegrity(p12ecx
, pwitem
, integrityAlg
)
2338 /* add cert and key pair */
2339 if(SEC_PKCS12AddCertAndKey(p12ecx
, certSafe
, NULL
, cert
, certDb
,
2340 keySafe
, NULL
, shroudKey
, pwitem
, shroudAlg
)
2345 /* encode the puppy */
2346 if(SEC_PKCS12Encode(p12ecx
, sec_pkcs12_in_place_encoder_output
, &outInfo
)
2354 SEC_PKCS12DestroyExportContext(p12ecx
);
2356 returnItem
= SECITEM_DupItem(&outInfo
.outItem
);
2357 SECITEM_ZfreeItem(&outInfo
.outItem
, PR_FALSE
);
2362 if(outInfo
.outItem
.data
) {
2363 SECITEM_ZfreeItem(&(outInfo
.outItem
), PR_TRUE
);
2367 SEC_PKCS12DestroyExportContext(p12ecx
);