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 ***** */
55 ** This PKCS12 file encoder uses numerous nested ASN.1 and PKCS7 encoder
56 ** contexts. It can be difficult to keep straight. Here's a picture:
58 ** "outer" ASN.1 encoder. The output goes to the library caller's CB.
59 ** "middle" PKCS7 encoder. Feeds the "outer" ASN.1 encoder.
60 ** "middle" ASN1 encoder. Encodes the encrypted aSafes.
61 ** Feeds the "middle" P7 encoder above.
62 ** "inner" PKCS7 encoder. Encrypts the "authenticated Safes" (aSafes)
63 ** Feeds the "middle" ASN.1 encoder above.
64 ** "inner" ASN.1 encoder. Encodes the unencrypted aSafes.
65 ** Feeds the "inner" P7 enocder above.
67 ** Buffering has been added at each point where the output of an ASN.1
68 ** encoder feeds the input of a PKCS7 encoder.
71 /*********************************
72 * Output buffer object, used to buffer output from ASN.1 encoder
73 * before passing data on down to the next PKCS7 encoder.
74 *********************************/
76 #define PK12_OUTPUT_BUFFER_SIZE 8192
78 struct sec_pkcs12OutputBufferStr
{
79 SEC_PKCS7EncoderContext
* p7eCx
;
81 unsigned int numBytes
;
82 unsigned int bufBytes
;
83 char buf
[PK12_OUTPUT_BUFFER_SIZE
];
85 typedef struct sec_pkcs12OutputBufferStr sec_pkcs12OutputBuffer
;
87 /*********************************
88 * Structures used in exporting the PKCS 12 blob
89 *********************************/
91 /* A SafeInfo is used for each ContentInfo which makes up the
92 * sequence of safes in the AuthenticatedSafe portion of the
95 struct SEC_PKCS12SafeInfoStr
{
98 /* information for setting up password encryption */
101 PK11SymKey
*encryptionKey
;
103 /* how many items have been stored in this safe,
104 * we will skip any safe which does not contain any
107 unsigned int itemCount
;
109 /* the content info for the safe */
110 SEC_PKCS7ContentInfo
*cinfo
;
112 sec_PKCS12SafeContents
*safe
;
115 /* An opaque structure which contains information needed for exporting
116 * certificates and keys through PKCS 12.
118 struct SEC_PKCS12ExportContextStr
{
123 /* integrity information */
124 PRBool integrityEnabled
;
127 struct sec_PKCS12PasswordModeInfo pwdInfo
;
128 struct sec_PKCS12PublicKeyModeInfo pubkeyInfo
;
131 /* helper functions */
132 /* retrieve the password call back */
133 SECKEYGetPasswordKey pwfn
;
136 /* safe contents bags */
137 SEC_PKCS12SafeInfo
**safeInfos
;
138 unsigned int safeInfoCount
;
140 /* the sequence of safes */
141 sec_PKCS12AuthenticatedSafe authSafe
;
143 /* information needing deletion */
144 CERTCertificate
**certList
;
147 /* structures for passing information to encoder callbacks when processing
148 * data through the ASN1 engine.
150 struct sec_pkcs12_encoder_output
{
151 SEC_PKCS12EncoderOutputCallback outputfn
;
155 struct sec_pkcs12_hmac_and_output_info
{
157 struct sec_pkcs12_encoder_output output
;
160 /* An encoder context which is used for the actual encoding
161 * portion of PKCS 12.
163 typedef struct sec_PKCS12EncoderContextStr
{
165 SEC_PKCS12ExportContext
*p12exp
;
166 PK11SymKey
*encryptionKey
;
168 /* encoder information - this is set up based on whether
169 * password based or public key pased privacy is being used
171 SEC_ASN1EncoderContext
*outerA1ecx
;
173 struct sec_pkcs12_hmac_and_output_info hmacAndOutputInfo
;
174 struct sec_pkcs12_encoder_output encOutput
;
177 /* structures for encoding of PFX and MAC */
178 sec_PKCS12PFXItem pfx
;
179 sec_PKCS12MacData mac
;
181 /* authenticated safe encoding tracking information */
182 SEC_PKCS7ContentInfo
*aSafeCinfo
;
183 SEC_PKCS7EncoderContext
*middleP7ecx
;
184 SEC_ASN1EncoderContext
*middleA1ecx
;
185 unsigned int currentSafe
;
191 sec_pkcs12OutputBuffer middleBuf
;
192 sec_pkcs12OutputBuffer innerBuf
;
194 } sec_PKCS12EncoderContext
;
197 /*********************************
198 * Export setup routines
199 *********************************/
201 /* SEC_PKCS12CreateExportContext
202 * Creates an export context and sets the unicode and password retrieval
203 * callbacks. This is the first call which must be made when exporting
206 * pwfn, pwfnarg - password retrieval callback and argument. these are
207 * required for password-authentication mode.
209 SEC_PKCS12ExportContext
*
210 SEC_PKCS12CreateExportContext(SECKEYGetPasswordKey pwfn
, void *pwfnarg
,
211 PK11SlotInfo
*slot
, void *wincx
)
213 PRArenaPool
*arena
= NULL
;
214 SEC_PKCS12ExportContext
*p12ctxt
= NULL
;
216 /* allocate the arena and create the context */
217 arena
= PORT_NewArena(4096);
219 PORT_SetError(SEC_ERROR_NO_MEMORY
);
223 p12ctxt
= (SEC_PKCS12ExportContext
*)PORT_ArenaZAlloc(arena
,
224 sizeof(SEC_PKCS12ExportContext
));
226 PORT_SetError(SEC_ERROR_NO_MEMORY
);
230 /* password callback for key retrieval */
231 p12ctxt
->pwfn
= pwfn
;
232 p12ctxt
->pwfnarg
= pwfnarg
;
234 p12ctxt
->integrityEnabled
= PR_FALSE
;
235 p12ctxt
->arena
= arena
;
236 p12ctxt
->wincx
= wincx
;
237 p12ctxt
->slot
= (slot
) ? PK11_ReferenceSlot(slot
) : PK11_GetInternalSlot();
243 PORT_FreeArena(arena
, PR_TRUE
);
250 * Adding integrity mode
253 /* SEC_PKCS12AddPasswordIntegrity
254 * Add password integrity to the exported data. If an integrity method
255 * has already been set, then return an error.
257 * p12ctxt - the export context
258 * pwitem - the password for integrity mode
259 * integAlg - the integrity algorithm to use for authentication.
262 SEC_PKCS12AddPasswordIntegrity(SEC_PKCS12ExportContext
*p12ctxt
,
263 SECItem
*pwitem
, SECOidTag integAlg
)
265 if(!p12ctxt
|| p12ctxt
->integrityEnabled
) {
269 /* set up integrity information */
270 p12ctxt
->pwdIntegrity
= PR_TRUE
;
271 p12ctxt
->integrityInfo
.pwdInfo
.password
=
272 (SECItem
*)PORT_ArenaZAlloc(p12ctxt
->arena
, sizeof(SECItem
));
273 if(!p12ctxt
->integrityInfo
.pwdInfo
.password
) {
274 PORT_SetError(SEC_ERROR_NO_MEMORY
);
277 if(SECITEM_CopyItem(p12ctxt
->arena
,
278 p12ctxt
->integrityInfo
.pwdInfo
.password
, pwitem
)
280 PORT_SetError(SEC_ERROR_NO_MEMORY
);
283 p12ctxt
->integrityInfo
.pwdInfo
.algorithm
= integAlg
;
284 p12ctxt
->integrityEnabled
= PR_TRUE
;
289 /* SEC_PKCS12AddPublicKeyIntegrity
290 * Add public key integrity to the exported data. If an integrity method
291 * has already been set, then return an error. The certificate must be
292 * allowed to be used as a signing cert.
294 * p12ctxt - the export context
295 * cert - signer certificate
296 * certDb - the certificate database
297 * algorithm - signing algorithm
298 * keySize - size of the signing key (?)
301 SEC_PKCS12AddPublicKeyIntegrity(SEC_PKCS12ExportContext
*p12ctxt
,
302 CERTCertificate
*cert
, CERTCertDBHandle
*certDb
,
303 SECOidTag algorithm
, int keySize
)
309 p12ctxt
->integrityInfo
.pubkeyInfo
.cert
= cert
;
310 p12ctxt
->integrityInfo
.pubkeyInfo
.certDb
= certDb
;
311 p12ctxt
->integrityInfo
.pubkeyInfo
.algorithm
= algorithm
;
312 p12ctxt
->integrityInfo
.pubkeyInfo
.keySize
= keySize
;
313 p12ctxt
->integrityEnabled
= PR_TRUE
;
320 * Adding safes - encrypted (password/public key) or unencrypted
321 * Each of the safe creation routines return an opaque pointer which
322 * are later passed into the routines for exporting certificates and
326 /* append the newly created safeInfo to list of safeInfos in the export
330 sec_pkcs12_append_safe_info(SEC_PKCS12ExportContext
*p12ctxt
, SEC_PKCS12SafeInfo
*info
)
332 void *mark
= NULL
, *dummy1
= NULL
, *dummy2
= NULL
;
334 if(!p12ctxt
|| !info
) {
338 mark
= PORT_ArenaMark(p12ctxt
->arena
);
340 /* if no safeInfos have been set, create the list, otherwise expand it. */
341 if(!p12ctxt
->safeInfoCount
) {
342 p12ctxt
->safeInfos
= (SEC_PKCS12SafeInfo
**)PORT_ArenaZAlloc(p12ctxt
->arena
,
343 2 * sizeof(SEC_PKCS12SafeInfo
*));
344 dummy1
= p12ctxt
->safeInfos
;
345 p12ctxt
->authSafe
.encodedSafes
= (SECItem
**)PORT_ArenaZAlloc(p12ctxt
->arena
,
346 2 * sizeof(SECItem
*));
347 dummy2
= p12ctxt
->authSafe
.encodedSafes
;
349 dummy1
= PORT_ArenaGrow(p12ctxt
->arena
, p12ctxt
->safeInfos
,
350 (p12ctxt
->safeInfoCount
+ 1) * sizeof(SEC_PKCS12SafeInfo
*),
351 (p12ctxt
->safeInfoCount
+ 2) * sizeof(SEC_PKCS12SafeInfo
*));
352 p12ctxt
->safeInfos
= (SEC_PKCS12SafeInfo
**)dummy1
;
353 dummy2
= PORT_ArenaGrow(p12ctxt
->arena
, p12ctxt
->authSafe
.encodedSafes
,
354 (p12ctxt
->authSafe
.safeCount
+ 1) * sizeof(SECItem
*),
355 (p12ctxt
->authSafe
.safeCount
+ 2) * sizeof(SECItem
*));
356 p12ctxt
->authSafe
.encodedSafes
= (SECItem
**)dummy2
;
358 if(!dummy1
|| !dummy2
) {
359 PORT_SetError(SEC_ERROR_NO_MEMORY
);
363 /* append the new safeInfo and null terminate the list */
364 p12ctxt
->safeInfos
[p12ctxt
->safeInfoCount
] = info
;
365 p12ctxt
->safeInfos
[++p12ctxt
->safeInfoCount
] = NULL
;
366 p12ctxt
->authSafe
.encodedSafes
[p12ctxt
->authSafe
.safeCount
] =
367 (SECItem
*)PORT_ArenaZAlloc(p12ctxt
->arena
, sizeof(SECItem
));
368 if(!p12ctxt
->authSafe
.encodedSafes
[p12ctxt
->authSafe
.safeCount
]) {
369 PORT_SetError(SEC_ERROR_NO_MEMORY
);
372 p12ctxt
->authSafe
.encodedSafes
[++p12ctxt
->authSafe
.safeCount
] = NULL
;
374 PORT_ArenaUnmark(p12ctxt
->arena
, mark
);
378 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
382 /* SEC_PKCS12CreatePasswordPrivSafe
383 * Create a password privacy safe to store exported information in.
385 * p12ctxt - export context
386 * pwitem - password for encryption
387 * privAlg - pbe algorithm through which encryption is done.
390 SEC_PKCS12CreatePasswordPrivSafe(SEC_PKCS12ExportContext
*p12ctxt
,
391 SECItem
*pwitem
, SECOidTag privAlg
)
393 SEC_PKCS12SafeInfo
*safeInfo
= NULL
;
395 PK11SlotInfo
*slot
= NULL
;
396 SECAlgorithmID
*algId
;
397 SECItem uniPwitem
= {siBuffer
, NULL
, 0};
403 /* allocate the safe info */
404 mark
= PORT_ArenaMark(p12ctxt
->arena
);
405 safeInfo
= (SEC_PKCS12SafeInfo
*)PORT_ArenaZAlloc(p12ctxt
->arena
,
406 sizeof(SEC_PKCS12SafeInfo
));
408 PORT_SetError(SEC_ERROR_NO_MEMORY
);
409 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
413 safeInfo
->itemCount
= 0;
415 /* create the encrypted safe */
416 safeInfo
->cinfo
= SEC_PKCS7CreateEncryptedData(privAlg
, 0, p12ctxt
->pwfn
,
418 if(!safeInfo
->cinfo
) {
419 PORT_SetError(SEC_ERROR_NO_MEMORY
);
422 safeInfo
->arena
= p12ctxt
->arena
;
424 /* convert the password to unicode */
425 if(!sec_pkcs12_convert_item_to_unicode(NULL
, &uniPwitem
, pwitem
,
426 PR_TRUE
, PR_TRUE
, PR_TRUE
)) {
427 PORT_SetError(SEC_ERROR_NO_MEMORY
);
430 if(SECITEM_CopyItem(p12ctxt
->arena
, &safeInfo
->pwitem
, &uniPwitem
) != SECSuccess
) {
431 PORT_SetError(SEC_ERROR_NO_MEMORY
);
435 /* generate the encryption key */
436 slot
= PK11_ReferenceSlot(p12ctxt
->slot
);
438 slot
= PK11_GetInternalKeySlot();
440 PORT_SetError(SEC_ERROR_NO_MEMORY
);
445 algId
= SEC_PKCS7GetEncryptionAlgorithm(safeInfo
->cinfo
);
446 safeInfo
->encryptionKey
= PK11_PBEKeyGen(slot
, algId
, &uniPwitem
,
447 PR_FALSE
, p12ctxt
->wincx
);
448 if(!safeInfo
->encryptionKey
) {
452 safeInfo
->arena
= p12ctxt
->arena
;
453 safeInfo
->safe
= NULL
;
454 if(sec_pkcs12_append_safe_info(p12ctxt
, safeInfo
) != SECSuccess
) {
459 SECITEM_ZfreeItem(&uniPwitem
, PR_FALSE
);
461 PORT_ArenaUnmark(p12ctxt
->arena
, mark
);
472 if(safeInfo
->cinfo
) {
473 SEC_PKCS7DestroyContentInfo(safeInfo
->cinfo
);
477 SECITEM_ZfreeItem(&uniPwitem
, PR_FALSE
);
480 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
484 /* SEC_PKCS12CreateUnencryptedSafe
485 * Creates an unencrypted safe within the export context.
487 * p12ctxt - the export context
490 SEC_PKCS12CreateUnencryptedSafe(SEC_PKCS12ExportContext
*p12ctxt
)
492 SEC_PKCS12SafeInfo
*safeInfo
= NULL
;
499 /* create the safe info */
500 mark
= PORT_ArenaMark(p12ctxt
->arena
);
501 safeInfo
= (SEC_PKCS12SafeInfo
*)PORT_ArenaZAlloc(p12ctxt
->arena
,
502 sizeof(SEC_PKCS12SafeInfo
));
504 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
505 PORT_SetError(SEC_ERROR_NO_MEMORY
);
509 safeInfo
->itemCount
= 0;
511 /* create the safe content */
512 safeInfo
->cinfo
= SEC_PKCS7CreateData();
513 if(!safeInfo
->cinfo
) {
514 PORT_SetError(SEC_ERROR_NO_MEMORY
);
518 if(sec_pkcs12_append_safe_info(p12ctxt
, safeInfo
) != SECSuccess
) {
522 PORT_ArenaUnmark(p12ctxt
->arena
, mark
);
526 if(safeInfo
->cinfo
) {
527 SEC_PKCS7DestroyContentInfo(safeInfo
->cinfo
);
530 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
534 /* SEC_PKCS12CreatePubKeyEncryptedSafe
535 * Creates a safe which is protected by public key encryption.
537 * p12ctxt - the export context
538 * certDb - the certificate database
539 * signer - the signer's certificate
540 * recipients - the list of recipient certificates.
541 * algorithm - the encryption algorithm to use
542 * keysize - the algorithms key size (?)
545 SEC_PKCS12CreatePubKeyEncryptedSafe(SEC_PKCS12ExportContext
*p12ctxt
,
546 CERTCertDBHandle
*certDb
,
547 CERTCertificate
*signer
,
548 CERTCertificate
**recipients
,
549 SECOidTag algorithm
, int keysize
)
551 SEC_PKCS12SafeInfo
*safeInfo
= NULL
;
554 if(!p12ctxt
|| !signer
|| !recipients
|| !(*recipients
)) {
558 /* allocate the safeInfo */
559 mark
= PORT_ArenaMark(p12ctxt
->arena
);
560 safeInfo
= (SEC_PKCS12SafeInfo
*)PORT_ArenaZAlloc(p12ctxt
->arena
,
561 sizeof(SEC_PKCS12SafeInfo
));
563 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
564 PORT_SetError(SEC_ERROR_NO_MEMORY
);
568 safeInfo
->itemCount
= 0;
569 safeInfo
->arena
= p12ctxt
->arena
;
571 /* create the enveloped content info using certUsageEmailSigner currently.
572 * XXX We need to eventually use something other than certUsageEmailSigner
574 safeInfo
->cinfo
= SEC_PKCS7CreateEnvelopedData(signer
, certUsageEmailSigner
,
575 certDb
, algorithm
, keysize
,
576 p12ctxt
->pwfn
, p12ctxt
->pwfnarg
);
577 if(!safeInfo
->cinfo
) {
578 PORT_SetError(SEC_ERROR_NO_MEMORY
);
585 while(recipients
[i
] != NULL
) {
586 SECStatus rv
= SEC_PKCS7AddRecipient(safeInfo
->cinfo
, recipients
[i
],
587 certUsageEmailRecipient
, certDb
);
588 if(rv
!= SECSuccess
) {
595 if(sec_pkcs12_append_safe_info(p12ctxt
, safeInfo
) != SECSuccess
) {
599 PORT_ArenaUnmark(p12ctxt
->arena
, mark
);
603 if(safeInfo
->cinfo
) {
604 SEC_PKCS7DestroyContentInfo(safeInfo
->cinfo
);
605 safeInfo
->cinfo
= NULL
;
608 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
612 /*********************************
613 * Routines to handle the exporting of the keys and certificates
614 *********************************/
616 /* creates a safe contents which safeBags will be appended to */
617 sec_PKCS12SafeContents
*
618 sec_PKCS12CreateSafeContents(PRArenaPool
*arena
)
620 sec_PKCS12SafeContents
*safeContents
;
626 /* create the safe contents */
627 safeContents
= (sec_PKCS12SafeContents
*)PORT_ArenaZAlloc(arena
,
628 sizeof(sec_PKCS12SafeContents
));
630 PORT_SetError(SEC_ERROR_NO_MEMORY
);
634 /* set up the internal contents info */
635 safeContents
->safeBags
= NULL
;
636 safeContents
->arena
= arena
;
637 safeContents
->bagCount
= 0;
645 /* appends a safe bag to a safeContents using the specified arena.
648 sec_pkcs12_append_bag_to_safe_contents(PRArenaPool
*arena
,
649 sec_PKCS12SafeContents
*safeContents
,
650 sec_PKCS12SafeBag
*safeBag
)
652 void *mark
= NULL
, *dummy
= NULL
;
654 if(!arena
|| !safeBag
|| !safeContents
) {
658 mark
= PORT_ArenaMark(arena
);
660 PORT_SetError(SEC_ERROR_NO_MEMORY
);
664 /* allocate space for the list, or reallocate to increase space */
665 if(!safeContents
->safeBags
) {
666 safeContents
->safeBags
= (sec_PKCS12SafeBag
**)PORT_ArenaZAlloc(arena
,
667 (2 * sizeof(sec_PKCS12SafeBag
*)));
668 dummy
= safeContents
->safeBags
;
669 safeContents
->bagCount
= 0;
671 dummy
= PORT_ArenaGrow(arena
, safeContents
->safeBags
,
672 (safeContents
->bagCount
+ 1) * sizeof(sec_PKCS12SafeBag
*),
673 (safeContents
->bagCount
+ 2) * sizeof(sec_PKCS12SafeBag
*));
674 safeContents
->safeBags
= (sec_PKCS12SafeBag
**)dummy
;
678 PORT_ArenaRelease(arena
, mark
);
679 PORT_SetError(SEC_ERROR_NO_MEMORY
);
683 /* append the bag at the end and null terminate the list */
684 safeContents
->safeBags
[safeContents
->bagCount
++] = safeBag
;
685 safeContents
->safeBags
[safeContents
->bagCount
] = NULL
;
687 PORT_ArenaUnmark(arena
, mark
);
692 /* appends a safeBag to a specific safeInfo.
695 sec_pkcs12_append_bag(SEC_PKCS12ExportContext
*p12ctxt
,
696 SEC_PKCS12SafeInfo
*safeInfo
, sec_PKCS12SafeBag
*safeBag
)
698 sec_PKCS12SafeContents
*dest
;
699 SECStatus rv
= SECFailure
;
701 if(!p12ctxt
|| !safeBag
|| !safeInfo
) {
705 if(!safeInfo
->safe
) {
706 safeInfo
->safe
= sec_PKCS12CreateSafeContents(p12ctxt
->arena
);
707 if(!safeInfo
->safe
) {
712 dest
= safeInfo
->safe
;
713 rv
= sec_pkcs12_append_bag_to_safe_contents(p12ctxt
->arena
, dest
, safeBag
);
714 if(rv
== SECSuccess
) {
715 safeInfo
->itemCount
++;
721 /* Creates a safeBag of the specified type, and if bagData is specified,
722 * the contents are set. The contents could be set later by the calling
726 sec_PKCS12CreateSafeBag(SEC_PKCS12ExportContext
*p12ctxt
, SECOidTag bagType
,
729 sec_PKCS12SafeBag
*safeBag
;
730 PRBool setName
= PR_TRUE
;
732 SECStatus rv
= SECSuccess
;
733 SECOidData
*oidData
= NULL
;
739 mark
= PORT_ArenaMark(p12ctxt
->arena
);
741 PORT_SetError(SEC_ERROR_NO_MEMORY
);
745 safeBag
= (sec_PKCS12SafeBag
*)PORT_ArenaZAlloc(p12ctxt
->arena
,
746 sizeof(sec_PKCS12SafeBag
));
748 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
749 PORT_SetError(SEC_ERROR_NO_MEMORY
);
753 /* set the bags content based upon bag type */
755 case SEC_OID_PKCS12_V1_KEY_BAG_ID
:
756 safeBag
->safeBagContent
.pkcs8KeyBag
=
757 (SECKEYPrivateKeyInfo
*)bagData
;
759 case SEC_OID_PKCS12_V1_CERT_BAG_ID
:
760 safeBag
->safeBagContent
.certBag
= (sec_PKCS12CertBag
*)bagData
;
762 case SEC_OID_PKCS12_V1_CRL_BAG_ID
:
763 safeBag
->safeBagContent
.crlBag
= (sec_PKCS12CRLBag
*)bagData
;
765 case SEC_OID_PKCS12_V1_SECRET_BAG_ID
:
766 safeBag
->safeBagContent
.secretBag
= (sec_PKCS12SecretBag
*)bagData
;
768 case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID
:
769 safeBag
->safeBagContent
.pkcs8ShroudedKeyBag
=
770 (SECKEYEncryptedPrivateKeyInfo
*)bagData
;
772 case SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID
:
773 safeBag
->safeBagContent
.safeContents
=
774 (sec_PKCS12SafeContents
*)bagData
;
781 oidData
= SECOID_FindOIDByTag(bagType
);
783 rv
= SECITEM_CopyItem(p12ctxt
->arena
, &safeBag
->safeBagType
, &oidData
->oid
);
784 if(rv
!= SECSuccess
) {
785 PORT_SetError(SEC_ERROR_NO_MEMORY
);
792 safeBag
->arena
= p12ctxt
->arena
;
793 PORT_ArenaUnmark(p12ctxt
->arena
, mark
);
799 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
805 /* Creates a new certificate bag and returns a pointer to it. If an error
806 * occurs NULL is returned.
809 sec_PKCS12NewCertBag(PRArenaPool
*arena
, SECOidTag certType
)
811 sec_PKCS12CertBag
*certBag
= NULL
;
812 SECOidData
*bagType
= NULL
;
820 mark
= PORT_ArenaMark(arena
);
821 certBag
= (sec_PKCS12CertBag
*)PORT_ArenaZAlloc(arena
,
822 sizeof(sec_PKCS12CertBag
));
824 PORT_ArenaRelease(arena
, mark
);
825 PORT_SetError(SEC_ERROR_NO_MEMORY
);
829 bagType
= SECOID_FindOIDByTag(certType
);
831 PORT_SetError(SEC_ERROR_NO_MEMORY
);
835 rv
= SECITEM_CopyItem(arena
, &certBag
->bagID
, &bagType
->oid
);
836 if(rv
!= SECSuccess
) {
837 PORT_SetError(SEC_ERROR_NO_MEMORY
);
841 PORT_ArenaUnmark(arena
, mark
);
845 PORT_ArenaRelease(arena
, mark
);
849 /* Creates a new CRL bag and returns a pointer to it. If an error
850 * occurs NULL is returned.
853 sec_PKCS12NewCRLBag(PRArenaPool
*arena
, SECOidTag crlType
)
855 sec_PKCS12CRLBag
*crlBag
= NULL
;
856 SECOidData
*bagType
= NULL
;
864 mark
= PORT_ArenaMark(arena
);
865 crlBag
= (sec_PKCS12CRLBag
*)PORT_ArenaZAlloc(arena
,
866 sizeof(sec_PKCS12CRLBag
));
868 PORT_ArenaRelease(arena
, mark
);
869 PORT_SetError(SEC_ERROR_NO_MEMORY
);
873 bagType
= SECOID_FindOIDByTag(crlType
);
875 PORT_SetError(SEC_ERROR_NO_MEMORY
);
879 rv
= SECITEM_CopyItem(arena
, &crlBag
->bagID
, &bagType
->oid
);
880 if(rv
!= SECSuccess
) {
881 PORT_SetError(SEC_ERROR_NO_MEMORY
);
885 PORT_ArenaUnmark(arena
, mark
);
889 PORT_ArenaRelease(arena
, mark
);
893 /* sec_PKCS12AddAttributeToBag
894 * adds an attribute to a safeBag. currently, the only attributes supported
895 * are those which are specified within PKCS 12.
897 * p12ctxt - the export context
898 * safeBag - the safeBag to which attributes are appended
899 * attrType - the attribute type
900 * attrData - the attribute data
903 sec_PKCS12AddAttributeToBag(SEC_PKCS12ExportContext
*p12ctxt
,
904 sec_PKCS12SafeBag
*safeBag
, SECOidTag attrType
,
907 sec_PKCS12Attribute
*attribute
;
908 void *mark
= NULL
, *dummy
= NULL
;
909 SECOidData
*oiddata
= NULL
;
910 SECItem unicodeName
= { siBuffer
, NULL
, 0};
912 unsigned int nItems
= 0;
915 if(!safeBag
|| !p12ctxt
) {
919 mark
= PORT_ArenaMark(safeBag
->arena
);
921 /* allocate the attribute */
922 attribute
= (sec_PKCS12Attribute
*)PORT_ArenaZAlloc(safeBag
->arena
,
923 sizeof(sec_PKCS12Attribute
));
925 PORT_SetError(SEC_ERROR_NO_MEMORY
);
929 /* set up the attribute */
930 oiddata
= SECOID_FindOIDByTag(attrType
);
932 PORT_SetError(SEC_ERROR_NO_MEMORY
);
935 if(SECITEM_CopyItem(p12ctxt
->arena
, &attribute
->attrType
, &oiddata
->oid
) !=
937 PORT_SetError(SEC_ERROR_NO_MEMORY
);
943 case SEC_OID_PKCS9_LOCAL_KEY_ID
:
948 case SEC_OID_PKCS9_FRIENDLY_NAME
:
950 if(!sec_pkcs12_convert_item_to_unicode(p12ctxt
->arena
,
951 &unicodeName
, attrData
, PR_FALSE
,
952 PR_FALSE
, PR_TRUE
)) {
962 /* append the attribute to the attribute value list */
963 attribute
->attrValue
= (SECItem
**)PORT_ArenaZAlloc(p12ctxt
->arena
,
964 ((nItems
+ 1) * sizeof(SECItem
*)));
965 if(!attribute
->attrValue
) {
966 PORT_SetError(SEC_ERROR_NO_MEMORY
);
970 /* XXX this will need to be changed if attributes requiring more than
971 * one element are ever used.
973 attribute
->attrValue
[0] = (SECItem
*)PORT_ArenaZAlloc(p12ctxt
->arena
,
975 if(!attribute
->attrValue
[0]) {
976 PORT_SetError(SEC_ERROR_NO_MEMORY
);
979 attribute
->attrValue
[1] = NULL
;
981 rv
= SECITEM_CopyItem(p12ctxt
->arena
, attribute
->attrValue
[0],
983 if(rv
!= SECSuccess
) {
984 PORT_SetError(SEC_ERROR_NO_MEMORY
);
988 /* append the attribute to the safeBag attributes */
989 if(safeBag
->nAttribs
) {
990 dummy
= PORT_ArenaGrow(p12ctxt
->arena
, safeBag
->attribs
,
991 ((safeBag
->nAttribs
+ 1) * sizeof(sec_PKCS12Attribute
*)),
992 ((safeBag
->nAttribs
+ 2) * sizeof(sec_PKCS12Attribute
*)));
993 safeBag
->attribs
= (sec_PKCS12Attribute
**)dummy
;
995 safeBag
->attribs
= (sec_PKCS12Attribute
**)PORT_ArenaZAlloc(p12ctxt
->arena
,
996 2 * sizeof(sec_PKCS12Attribute
*));
997 dummy
= safeBag
->attribs
;
1003 safeBag
->attribs
[safeBag
->nAttribs
] = attribute
;
1004 safeBag
->attribs
[++safeBag
->nAttribs
] = NULL
;
1006 PORT_ArenaUnmark(p12ctxt
->arena
, mark
);
1011 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
1017 /* SEC_PKCS12AddCert
1018 * Adds a certificate to the data being exported.
1020 * p12ctxt - the export context
1021 * safe - the safeInfo to which the certificate is placed
1022 * nestedDest - if the cert is to be placed within a nested safeContents then,
1023 * this value is to be specified with the destination
1024 * cert - the cert to export
1025 * certDb - the certificate database handle
1026 * keyId - a unique identifier to associate a certificate/key pair
1027 * includeCertChain - PR_TRUE if the certificate chain is to be included.
1030 SEC_PKCS12AddCert(SEC_PKCS12ExportContext
*p12ctxt
, SEC_PKCS12SafeInfo
*safe
,
1031 void *nestedDest
, CERTCertificate
*cert
,
1032 CERTCertDBHandle
*certDb
, SECItem
*keyId
,
1033 PRBool includeCertChain
)
1035 sec_PKCS12CertBag
*certBag
;
1036 sec_PKCS12SafeBag
*safeBag
;
1039 SECItem nick
= {siBuffer
, NULL
,0};
1041 if(!p12ctxt
|| !cert
) {
1044 mark
= PORT_ArenaMark(p12ctxt
->arena
);
1046 /* allocate the cert bag */
1047 certBag
= sec_PKCS12NewCertBag(p12ctxt
->arena
,
1048 SEC_OID_PKCS9_X509_CERT
);
1053 if(SECITEM_CopyItem(p12ctxt
->arena
, &certBag
->value
.x509Cert
,
1054 &cert
->derCert
) != SECSuccess
) {
1055 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1059 /* if the cert chain is to be included, we should only be exporting
1060 * the cert from our internal database.
1062 if(includeCertChain
) {
1063 CERTCertificateList
*certList
= CERT_CertChainFromCert(cert
,
1066 unsigned int count
= 0;
1068 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1072 /* add cert chain */
1073 for(count
= 0; count
< (unsigned int)certList
->len
; count
++) {
1074 if(SECITEM_CompareItem(&certList
->certs
[count
], &cert
->derCert
)
1076 CERTCertificate
*tempCert
;
1078 /* decode the certificate */
1080 * This was rather silly. The chain is constructed above
1081 * by finding all of the CERTCertificate's in the database.
1082 * Then the chain is put into a CERTCertificateList, which only
1083 * contains the DER. Finally, the DER was decoded, and the
1084 * decoded cert was sent recursively back to this function.
1085 * Beyond being inefficent, this causes data loss (specifically,
1086 * the nickname). Instead, for 3.4, we'll do a lookup by the
1087 * DER, which should return the cached entry.
1089 tempCert
= CERT_FindCertByDERCert(CERT_GetDefaultCertDB(),
1090 &certList
->certs
[count
]);
1092 CERT_DestroyCertificateList(certList
);
1096 /* add the certificate */
1097 if(SEC_PKCS12AddCert(p12ctxt
, safe
, nestedDest
, tempCert
,
1098 certDb
, NULL
, PR_FALSE
) != SECSuccess
) {
1099 CERT_DestroyCertificate(tempCert
);
1100 CERT_DestroyCertificateList(certList
);
1103 CERT_DestroyCertificate(tempCert
);
1106 CERT_DestroyCertificateList(certList
);
1109 /* if the certificate has a nickname, we will set the friendly name
1112 if(cert
->nickname
) {
1113 if (cert
->slot
&& !PK11_IsInternal(cert
->slot
)) {
1115 * The cert is coming off of an external token,
1116 * let's strip the token name from the nickname
1117 * and only add what comes after the colon as the
1122 delimit
= PORT_Strchr(cert
->nickname
,':');
1123 if (delimit
== NULL
) {
1124 nick
.data
= (unsigned char *)cert
->nickname
;
1125 nick
.len
= PORT_Strlen(cert
->nickname
);
1128 nick
.data
= (unsigned char *)PORT_ArenaStrdup(p12ctxt
->arena
,
1130 nick
.len
= PORT_Strlen(delimit
);
1133 nick
.data
= (unsigned char *)cert
->nickname
;
1134 nick
.len
= PORT_Strlen(cert
->nickname
);
1138 safeBag
= sec_PKCS12CreateSafeBag(p12ctxt
, SEC_OID_PKCS12_V1_CERT_BAG_ID
,
1144 /* add the friendly name and keyId attributes, if necessary */
1146 if(sec_PKCS12AddAttributeToBag(p12ctxt
, safeBag
,
1147 SEC_OID_PKCS9_FRIENDLY_NAME
, &nick
)
1154 if(sec_PKCS12AddAttributeToBag(p12ctxt
, safeBag
, SEC_OID_PKCS9_LOCAL_KEY_ID
,
1155 keyId
) != SECSuccess
) {
1160 /* append the cert safeBag */
1162 rv
= sec_pkcs12_append_bag_to_safe_contents(p12ctxt
->arena
,
1163 (sec_PKCS12SafeContents
*)nestedDest
,
1166 rv
= sec_pkcs12_append_bag(p12ctxt
, safe
, safeBag
);
1169 if(rv
!= SECSuccess
) {
1173 PORT_ArenaUnmark(p12ctxt
->arena
, mark
);
1178 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
1184 /* SEC_PKCS12AddEncryptedKey
1185 * Extracts the key associated with a particular certificate and exports
1188 * p12ctxt - the export context
1189 * safe - the safeInfo to place the key in
1190 * nestedDest - the nested safeContents to place a key
1191 * cert - the certificate which the key belongs to
1192 * shroudKey - encrypt the private key for export. This value should
1193 * always be true. lower level code will not allow the export
1194 * of unencrypted private keys.
1195 * algorithm - the algorithm with which to encrypt the private key
1196 * pwitem - the password to encrypted the private key with
1197 * keyId - the keyID attribute
1198 * nickName - the nickname attribute
1201 SEC_PKCS12AddEncryptedKey(SEC_PKCS12ExportContext
*p12ctxt
,
1202 SECKEYEncryptedPrivateKeyInfo
*epki
, SEC_PKCS12SafeInfo
*safe
,
1203 void *nestedDest
, SECItem
*keyId
, SECItem
*nickName
)
1208 SECStatus rv
= SECFailure
;
1209 sec_PKCS12SafeBag
*returnBag
;
1211 if(!p12ctxt
|| !safe
|| !epki
) {
1215 mark
= PORT_ArenaMark(p12ctxt
->arena
);
1217 keyItem
= PORT_ArenaZAlloc(p12ctxt
->arena
,
1218 sizeof(SECKEYEncryptedPrivateKeyInfo
));
1220 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1224 rv
= SECKEY_CopyEncryptedPrivateKeyInfo(p12ctxt
->arena
,
1225 (SECKEYEncryptedPrivateKeyInfo
*)keyItem
,
1227 keyType
= SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID
;
1229 if(rv
!= SECSuccess
) {
1233 /* create the safe bag and set any attributes */
1234 returnBag
= sec_PKCS12CreateSafeBag(p12ctxt
, keyType
, keyItem
);
1241 if(sec_PKCS12AddAttributeToBag(p12ctxt
, returnBag
,
1242 SEC_OID_PKCS9_FRIENDLY_NAME
, nickName
)
1249 if(sec_PKCS12AddAttributeToBag(p12ctxt
, returnBag
,
1250 SEC_OID_PKCS9_LOCAL_KEY_ID
,
1251 keyId
) != SECSuccess
) {
1257 rv
= sec_pkcs12_append_bag_to_safe_contents(p12ctxt
->arena
,
1258 (sec_PKCS12SafeContents
*)nestedDest
,
1261 rv
= sec_pkcs12_append_bag(p12ctxt
, safe
, returnBag
);
1266 if (rv
!= SECSuccess
) {
1267 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
1269 PORT_ArenaUnmark(p12ctxt
->arena
, mark
);
1275 /* SEC_PKCS12AddKeyForCert
1276 * Extracts the key associated with a particular certificate and exports
1279 * p12ctxt - the export context
1280 * safe - the safeInfo to place the key in
1281 * nestedDest - the nested safeContents to place a key
1282 * cert - the certificate which the key belongs to
1283 * shroudKey - encrypt the private key for export. This value should
1284 * always be true. lower level code will not allow the export
1285 * of unencrypted private keys.
1286 * algorithm - the algorithm with which to encrypt the private key
1287 * pwitem - the password to encrypt the private key with
1288 * keyId - the keyID attribute
1289 * nickName - the nickname attribute
1292 SEC_PKCS12AddKeyForCert(SEC_PKCS12ExportContext
*p12ctxt
, SEC_PKCS12SafeInfo
*safe
,
1293 void *nestedDest
, CERTCertificate
*cert
,
1294 PRBool shroudKey
, SECOidTag algorithm
, SECItem
*pwitem
,
1295 SECItem
*keyId
, SECItem
*nickName
)
1300 SECStatus rv
= SECFailure
;
1301 SECItem nickname
= {siBuffer
,NULL
,0}, uniPwitem
= {siBuffer
, NULL
, 0};
1302 sec_PKCS12SafeBag
*returnBag
;
1304 if(!p12ctxt
|| !cert
|| !safe
) {
1308 mark
= PORT_ArenaMark(p12ctxt
->arena
);
1310 /* retrieve the key based upon the type that it is and
1311 * specify the type of safeBag to store the key in
1315 /* extract the key unencrypted. this will most likely go away */
1316 SECKEYPrivateKeyInfo
*pki
= PK11_ExportPrivateKeyInfo(cert
,
1319 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
1320 PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY
);
1323 keyItem
= PORT_ArenaZAlloc(p12ctxt
->arena
, sizeof(SECKEYPrivateKeyInfo
));
1325 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1328 rv
= SECKEY_CopyPrivateKeyInfo(p12ctxt
->arena
,
1329 (SECKEYPrivateKeyInfo
*)keyItem
, pki
);
1330 keyType
= SEC_OID_PKCS12_V1_KEY_BAG_ID
;
1331 SECKEY_DestroyPrivateKeyInfo(pki
, PR_TRUE
);
1334 /* extract the key encrypted */
1335 SECKEYEncryptedPrivateKeyInfo
*epki
= NULL
;
1336 PK11SlotInfo
*slot
= NULL
;
1338 if(!sec_pkcs12_convert_item_to_unicode(p12ctxt
->arena
, &uniPwitem
,
1339 pwitem
, PR_TRUE
, PR_TRUE
, PR_TRUE
)) {
1340 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1344 /* we want to make sure to take the key out of the key slot */
1345 if(PK11_IsInternal(p12ctxt
->slot
)) {
1346 slot
= PK11_GetInternalKeySlot();
1348 slot
= PK11_ReferenceSlot(p12ctxt
->slot
);
1351 epki
= PK11_ExportEncryptedPrivateKeyInfo(slot
, algorithm
,
1352 &uniPwitem
, cert
, 1,
1354 PK11_FreeSlot(slot
);
1356 keyItem
= PORT_ArenaZAlloc(p12ctxt
->arena
,
1357 sizeof(SECKEYEncryptedPrivateKeyInfo
));
1359 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1363 PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY
);
1366 rv
= SECKEY_CopyEncryptedPrivateKeyInfo(p12ctxt
->arena
,
1367 (SECKEYEncryptedPrivateKeyInfo
*)keyItem
,
1369 keyType
= SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID
;
1370 SECKEY_DestroyEncryptedPrivateKeyInfo(epki
, PR_TRUE
);
1373 if(rv
!= SECSuccess
) {
1377 /* if no nickname specified, let's see if the certificate has a
1381 if(cert
->nickname
) {
1382 nickname
.data
= (unsigned char *)cert
->nickname
;
1383 nickname
.len
= PORT_Strlen(cert
->nickname
);
1384 nickName
= &nickname
;
1388 /* create the safe bag and set any attributes */
1389 returnBag
= sec_PKCS12CreateSafeBag(p12ctxt
, keyType
, keyItem
);
1396 if(sec_PKCS12AddAttributeToBag(p12ctxt
, returnBag
,
1397 SEC_OID_PKCS9_FRIENDLY_NAME
, nickName
)
1404 if(sec_PKCS12AddAttributeToBag(p12ctxt
, returnBag
, SEC_OID_PKCS9_LOCAL_KEY_ID
,
1405 keyId
) != SECSuccess
) {
1411 rv
= sec_pkcs12_append_bag_to_safe_contents(p12ctxt
->arena
,
1412 (sec_PKCS12SafeContents
*)nestedDest
,
1415 rv
= sec_pkcs12_append_bag(p12ctxt
, safe
, returnBag
);
1420 if (rv
!= SECSuccess
) {
1421 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
1423 PORT_ArenaUnmark(p12ctxt
->arena
, mark
);
1429 /* SEC_PKCS12AddCertAndEncryptedKey
1430 * Add a certificate and key pair to be exported.
1432 * p12ctxt - the export context
1433 * certSafe - the safeInfo where the cert is stored
1434 * certNestedDest - the nested safeContents to store the cert
1435 * keySafe - the safeInfo where the key is stored
1436 * keyNestedDest - the nested safeContents to store the key
1437 * shroudKey - extract the private key encrypted?
1438 * pwitem - the password with which the key is encrypted
1439 * algorithm - the algorithm with which the key is encrypted
1442 SEC_PKCS12AddDERCertAndEncryptedKey(SEC_PKCS12ExportContext
*p12ctxt
,
1443 void *certSafe
, void *certNestedDest
,
1444 SECItem
*derCert
, void *keySafe
,
1445 void *keyNestedDest
, SECKEYEncryptedPrivateKeyInfo
*epki
,
1448 SECStatus rv
= SECFailure
;
1449 SGNDigestInfo
*digest
= NULL
;
1451 CERTCertificate
*cert
;
1452 SECItem nick
= {siBuffer
, NULL
,0}, *nickPtr
= NULL
;
1454 if(!p12ctxt
|| !certSafe
|| !keySafe
|| !derCert
) {
1458 mark
= PORT_ArenaMark(p12ctxt
->arena
);
1460 cert
= CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
1461 derCert
, NULL
, PR_FALSE
, PR_FALSE
);
1463 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
1464 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1467 cert
->nickname
= nickname
;
1469 /* generate the thumbprint of the cert to use as a keyId */
1470 digest
= sec_pkcs12_compute_thumbprint(&cert
->derCert
);
1472 CERT_DestroyCertificate(cert
);
1476 /* add the certificate */
1477 rv
= SEC_PKCS12AddCert(p12ctxt
, (SEC_PKCS12SafeInfo
*)certSafe
,
1478 certNestedDest
, cert
, NULL
,
1479 &digest
->digest
, PR_FALSE
);
1480 if(rv
!= SECSuccess
) {
1485 nick
.data
= (unsigned char *)nickname
;
1486 nick
.len
= PORT_Strlen(nickname
);
1493 rv
= SEC_PKCS12AddEncryptedKey(p12ctxt
, epki
, (SEC_PKCS12SafeInfo
*)keySafe
,
1494 keyNestedDest
, &digest
->digest
, nickPtr
);
1495 if(rv
!= SECSuccess
) {
1499 SGN_DestroyDigestInfo(digest
);
1501 PORT_ArenaUnmark(p12ctxt
->arena
, mark
);
1505 SGN_DestroyDigestInfo(digest
);
1506 CERT_DestroyCertificate(cert
);
1507 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
1512 /* SEC_PKCS12AddCertAndKey
1513 * Add a certificate and key pair to be exported.
1515 * p12ctxt - the export context
1516 * certSafe - the safeInfo where the cert is stored
1517 * certNestedDest - the nested safeContents to store the cert
1518 * keySafe - the safeInfo where the key is stored
1519 * keyNestedDest - the nested safeContents to store the key
1520 * shroudKey - extract the private key encrypted?
1521 * pwitem - the password with which the key is encrypted
1522 * algorithm - the algorithm with which the key is encrypted
1525 SEC_PKCS12AddCertAndKey(SEC_PKCS12ExportContext
*p12ctxt
,
1526 void *certSafe
, void *certNestedDest
,
1527 CERTCertificate
*cert
, CERTCertDBHandle
*certDb
,
1528 void *keySafe
, void *keyNestedDest
,
1529 PRBool shroudKey
, SECItem
*pwitem
, SECOidTag algorithm
)
1531 SECStatus rv
= SECFailure
;
1532 SGNDigestInfo
*digest
= NULL
;
1535 if(!p12ctxt
|| !certSafe
|| !keySafe
|| !cert
) {
1539 mark
= PORT_ArenaMark(p12ctxt
->arena
);
1541 /* generate the thumbprint of the cert to use as a keyId */
1542 digest
= sec_pkcs12_compute_thumbprint(&cert
->derCert
);
1544 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
1548 /* add the certificate */
1549 rv
= SEC_PKCS12AddCert(p12ctxt
, (SEC_PKCS12SafeInfo
*)certSafe
,
1550 (SEC_PKCS12SafeInfo
*)certNestedDest
, cert
, certDb
,
1551 &digest
->digest
, PR_TRUE
);
1552 if(rv
!= SECSuccess
) {
1557 rv
= SEC_PKCS12AddKeyForCert(p12ctxt
, (SEC_PKCS12SafeInfo
*)keySafe
,
1558 keyNestedDest
, cert
,
1559 shroudKey
, algorithm
, pwitem
,
1560 &digest
->digest
, NULL
);
1561 if(rv
!= SECSuccess
) {
1565 SGN_DestroyDigestInfo(digest
);
1567 PORT_ArenaUnmark(p12ctxt
->arena
, mark
);
1571 SGN_DestroyDigestInfo(digest
);
1572 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
1577 /* SEC_PKCS12CreateNestedSafeContents
1578 * Allows nesting of safe contents to be implemented. No limit imposed on
1581 * p12ctxt - the export context
1582 * baseSafe - the base safeInfo
1583 * nestedDest - a parent safeContents (?)
1586 SEC_PKCS12CreateNestedSafeContents(SEC_PKCS12ExportContext
*p12ctxt
,
1587 void *baseSafe
, void *nestedDest
)
1589 sec_PKCS12SafeContents
*newSafe
;
1590 sec_PKCS12SafeBag
*safeContentsBag
;
1594 if(!p12ctxt
|| !baseSafe
) {
1598 mark
= PORT_ArenaMark(p12ctxt
->arena
);
1600 newSafe
= sec_PKCS12CreateSafeContents(p12ctxt
->arena
);
1602 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
1603 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1607 /* create the safeContents safeBag */
1608 safeContentsBag
= sec_PKCS12CreateSafeBag(p12ctxt
,
1609 SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID
,
1611 if(!safeContentsBag
) {
1615 /* append the safeContents to the appropriate area */
1617 rv
= sec_pkcs12_append_bag_to_safe_contents(p12ctxt
->arena
,
1618 (sec_PKCS12SafeContents
*)nestedDest
,
1621 rv
= sec_pkcs12_append_bag(p12ctxt
, (SEC_PKCS12SafeInfo
*)baseSafe
,
1624 if(rv
!= SECSuccess
) {
1628 PORT_ArenaUnmark(p12ctxt
->arena
, mark
);
1632 PORT_ArenaRelease(p12ctxt
->arena
, mark
);
1636 /*********************************
1638 *********************************/
1640 /* set up the encoder context based on information in the export context
1641 * and return the newly allocated enocoder context. A return of NULL
1642 * indicates an error occurred.
1644 sec_PKCS12EncoderContext
*
1645 sec_pkcs12_encoder_start_context(SEC_PKCS12ExportContext
*p12exp
)
1647 sec_PKCS12EncoderContext
*p12enc
= NULL
;
1648 unsigned int i
, nonEmptyCnt
;
1650 SECItem ignore
= {0};
1653 if(!p12exp
|| !p12exp
->safeInfos
) {
1657 /* check for any empty safes and skip them */
1658 i
= nonEmptyCnt
= 0;
1659 while(p12exp
->safeInfos
[i
]) {
1660 if(p12exp
->safeInfos
[i
]->itemCount
) {
1665 if(nonEmptyCnt
== 0) {
1668 p12exp
->authSafe
.encodedSafes
[nonEmptyCnt
] = NULL
;
1670 /* allocate the encoder context */
1671 mark
= PORT_ArenaMark(p12exp
->arena
);
1672 p12enc
= PORT_ArenaZNew(p12exp
->arena
, sec_PKCS12EncoderContext
);
1674 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1678 p12enc
->arena
= p12exp
->arena
;
1679 p12enc
->p12exp
= p12exp
;
1681 /* set up the PFX version and information */
1682 PORT_Memset(&p12enc
->pfx
, 0, sizeof(sec_PKCS12PFXItem
));
1683 if(!SEC_ASN1EncodeInteger(p12exp
->arena
, &(p12enc
->pfx
.version
),
1684 SEC_PKCS12_VERSION
) ) {
1685 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1689 /* set up the authenticated safe content info based on the
1690 * type of integrity being used. this should be changed to
1691 * enforce integrity mode, but will not be implemented until
1692 * it is confirmed that integrity must be in place
1694 if(p12exp
->integrityEnabled
&& !p12exp
->pwdIntegrity
) {
1697 /* create public key integrity mode */
1698 p12enc
->aSafeCinfo
= SEC_PKCS7CreateSignedData(
1699 p12exp
->integrityInfo
.pubkeyInfo
.cert
,
1700 certUsageEmailSigner
,
1701 p12exp
->integrityInfo
.pubkeyInfo
.certDb
,
1702 p12exp
->integrityInfo
.pubkeyInfo
.algorithm
,
1706 if(!p12enc
->aSafeCinfo
) {
1709 if(SEC_PKCS7IncludeCertChain(p12enc
->aSafeCinfo
,NULL
) != SECSuccess
) {
1712 rv
= SEC_PKCS7AddSigningTime(p12enc
->aSafeCinfo
);
1713 PORT_Assert(rv
== SECSuccess
);
1715 p12enc
->aSafeCinfo
= SEC_PKCS7CreateData();
1717 /* init password pased integrity mode */
1718 if(p12exp
->integrityEnabled
) {
1719 SECItem pwd
= {siBuffer
,NULL
, 0};
1720 SECItem
*salt
= sec_pkcs12_generate_salt();
1723 CK_MECHANISM_TYPE integrityMech
;
1724 CK_MECHANISM_TYPE hmacMech
;
1726 /* zero out macData and set values */
1727 PORT_Memset(&p12enc
->mac
, 0, sizeof(sec_PKCS12MacData
));
1730 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1733 if(SECITEM_CopyItem(p12exp
->arena
, &(p12enc
->mac
.macSalt
), salt
)
1735 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1739 /* generate HMAC key */
1740 if(!sec_pkcs12_convert_item_to_unicode(NULL
, &pwd
,
1741 p12exp
->integrityInfo
.pwdInfo
.password
, PR_TRUE
,
1742 PR_TRUE
, PR_TRUE
)) {
1746 params
= PK11_CreatePBEParams(salt
, &pwd
, 1);
1747 SECITEM_ZfreeItem(salt
, PR_TRUE
);
1748 SECITEM_ZfreeItem(&pwd
, PR_FALSE
);
1750 switch (p12exp
->integrityInfo
.pwdInfo
.algorithm
) {
1752 integrityMech
= CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN
; break;
1754 integrityMech
= CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN
; break;
1756 integrityMech
= CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN
; break;
1761 symKey
= PK11_KeyGen(NULL
, integrityMech
, params
, 20, NULL
);
1762 PK11_DestroyPBEParams(params
);
1767 /* initialize hmac */
1768 /* XXX NBB, why is this mech different than the one above? */
1769 hmacMech
= sec_pkcs12_algtag_to_mech(
1770 p12exp
->integrityInfo
.pwdInfo
.algorithm
);
1772 p12enc
->hmacCx
= PK11_CreateContextBySymKey( hmacMech
, CKA_SIGN
,
1775 PK11_FreeSymKey(symKey
);
1776 if(!p12enc
->hmacCx
) {
1777 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1780 rv
= PK11_DigestBegin(p12enc
->hmacCx
);
1781 if (rv
!= SECSuccess
)
1786 if(!p12enc
->aSafeCinfo
) {
1790 PORT_ArenaUnmark(p12exp
->arena
, mark
);
1796 if(p12enc
->aSafeCinfo
) {
1797 SEC_PKCS7DestroyContentInfo(p12enc
->aSafeCinfo
);
1799 if(p12enc
->hmacCx
) {
1800 PK11_DestroyContext(p12enc
->hmacCx
, PR_TRUE
);
1803 if (p12exp
->arena
!= NULL
)
1804 PORT_ArenaRelease(p12exp
->arena
, mark
);
1809 /* The outermost ASN.1 encoder calls this function for output.
1810 ** This function calls back to the library caller's output routine,
1811 ** which typically writes to a PKCS12 file.
1814 sec_P12A1OutputCB_Outer(void *arg
, const char *buf
, unsigned long len
,
1815 int depth
, SEC_ASN1EncodingPart data_kind
)
1817 struct sec_pkcs12_encoder_output
*output
;
1819 output
= (struct sec_pkcs12_encoder_output
*)arg
;
1820 (* output
->outputfn
)(output
->outputarg
, buf
, len
);
1823 /* The "middle" and "inner" ASN.1 encoders call this function to output.
1824 ** This function does HMACing, if appropriate, and then buffers the data.
1825 ** The buffered data is eventually passed down to the underlying PKCS7 encoder.
1828 sec_P12A1OutputCB_HmacP7Update(void *arg
, const char *buf
,
1831 SEC_ASN1EncodingPart data_kind
)
1833 sec_pkcs12OutputBuffer
* bufcx
= (sec_pkcs12OutputBuffer
*)arg
;
1838 if (bufcx
->hmacCx
) {
1839 PK11_DigestOp(bufcx
->hmacCx
, (unsigned char *)buf
, len
);
1843 if (bufcx
->numBytes
> 0) {
1845 if (len
+ bufcx
->numBytes
<= bufcx
->bufBytes
) {
1846 memcpy(bufcx
->buf
+ bufcx
->numBytes
, buf
, len
);
1847 bufcx
->numBytes
+= len
;
1848 if (bufcx
->numBytes
< bufcx
->bufBytes
)
1850 SEC_PKCS7EncoderUpdate(bufcx
->p7eCx
, bufcx
->buf
, bufcx
->bufBytes
);
1851 bufcx
->numBytes
= 0;
1854 toCopy
= bufcx
->bufBytes
- bufcx
->numBytes
;
1855 memcpy(bufcx
->buf
+ bufcx
->numBytes
, buf
, toCopy
);
1856 SEC_PKCS7EncoderUpdate(bufcx
->p7eCx
, bufcx
->buf
, bufcx
->bufBytes
);
1857 bufcx
->numBytes
= 0;
1861 /* buffer is presently empty */
1862 if (len
>= bufcx
->bufBytes
) {
1863 /* Just pass it through */
1864 SEC_PKCS7EncoderUpdate(bufcx
->p7eCx
, buf
, len
);
1866 /* copy it all into the buffer, and return */
1867 memcpy(bufcx
->buf
, buf
, len
);
1868 bufcx
->numBytes
= len
;
1873 sec_FlushPkcs12OutputBuffer( sec_pkcs12OutputBuffer
* bufcx
)
1875 if (bufcx
->numBytes
> 0) {
1876 SEC_PKCS7EncoderUpdate(bufcx
->p7eCx
, bufcx
->buf
, bufcx
->numBytes
);
1877 bufcx
->numBytes
= 0;
1881 /* Feeds the output of a PKCS7 encoder into the next outward ASN.1 encoder.
1882 ** This function is used by both the inner and middle PCS7 encoders.
1885 sec_P12P7OutputCB_CallA1Update(void *arg
, const char *buf
, unsigned long len
)
1887 SEC_ASN1EncoderContext
*cx
= (SEC_ASN1EncoderContext
*)arg
;
1892 SEC_ASN1EncoderUpdate(cx
, buf
, len
);
1896 /* this function encodes content infos which are part of the
1897 * sequence of content infos labeled AuthenticatedSafes
1900 sec_pkcs12_encoder_asafe_process(sec_PKCS12EncoderContext
*p12ecx
)
1902 SEC_PKCS7EncoderContext
*innerP7ecx
;
1903 SEC_PKCS7ContentInfo
*cinfo
;
1904 PK11SymKey
*bulkKey
= NULL
;
1905 SEC_ASN1EncoderContext
*innerA1ecx
= NULL
;
1906 SECStatus rv
= SECSuccess
;
1908 if(p12ecx
->currentSafe
< p12ecx
->p12exp
->authSafe
.safeCount
) {
1909 SEC_PKCS12SafeInfo
*safeInfo
;
1910 SECOidTag cinfoType
;
1912 safeInfo
= p12ecx
->p12exp
->safeInfos
[p12ecx
->currentSafe
];
1914 /* skip empty safes */
1915 if(safeInfo
->itemCount
== 0) {
1919 cinfo
= safeInfo
->cinfo
;
1920 cinfoType
= SEC_PKCS7ContentType(cinfo
);
1922 /* determine the safe type and set the appropriate argument */
1924 case SEC_OID_PKCS7_DATA
:
1925 case SEC_OID_PKCS7_ENVELOPED_DATA
:
1927 case SEC_OID_PKCS7_ENCRYPTED_DATA
:
1928 bulkKey
= safeInfo
->encryptionKey
;
1929 PK11_SetSymKeyUserData(bulkKey
, &safeInfo
->pwitem
, NULL
);
1936 /* start the PKCS7 encoder */
1937 innerP7ecx
= SEC_PKCS7EncoderStart(cinfo
,
1938 sec_P12P7OutputCB_CallA1Update
,
1939 p12ecx
->middleA1ecx
, bulkKey
);
1944 /* encode safe contents */
1945 p12ecx
->innerBuf
.p7eCx
= innerP7ecx
;
1946 p12ecx
->innerBuf
.hmacCx
= NULL
;
1947 p12ecx
->innerBuf
.numBytes
= 0;
1948 p12ecx
->innerBuf
.bufBytes
= sizeof p12ecx
->innerBuf
.buf
;
1950 innerA1ecx
= SEC_ASN1EncoderStart(safeInfo
->safe
,
1951 sec_PKCS12SafeContentsTemplate
,
1952 sec_P12A1OutputCB_HmacP7Update
,
1957 rv
= SEC_ASN1EncoderUpdate(innerA1ecx
, NULL
, 0);
1958 SEC_ASN1EncoderFinish(innerA1ecx
);
1959 sec_FlushPkcs12OutputBuffer( &p12ecx
->innerBuf
);
1961 if(rv
!= SECSuccess
) {
1966 /* finish up safe content info */
1967 rv
= SEC_PKCS7EncoderFinish(innerP7ecx
, p12ecx
->p12exp
->pwfn
,
1968 p12ecx
->p12exp
->pwfnarg
);
1970 memset(&p12ecx
->innerBuf
, 0, sizeof p12ecx
->innerBuf
);
1975 SEC_PKCS7EncoderFinish(innerP7ecx
, p12ecx
->p12exp
->pwfn
,
1976 p12ecx
->p12exp
->pwfnarg
);
1980 SEC_ASN1EncoderFinish(innerA1ecx
);
1982 memset(&p12ecx
->innerBuf
, 0, sizeof p12ecx
->innerBuf
);
1986 /* finish the HMAC and encode the macData so that it can be
1990 sec_Pkcs12FinishMac(sec_PKCS12EncoderContext
*p12ecx
)
1992 SECItem hmac
= { siBuffer
, NULL
, 0 };
1994 SGNDigestInfo
*di
= NULL
;
2001 /* make sure we are using password integrity mode */
2002 if(!p12ecx
->p12exp
->integrityEnabled
) {
2006 if(!p12ecx
->p12exp
->pwdIntegrity
) {
2010 /* finish the hmac */
2011 hmac
.data
= (unsigned char *)PORT_ZAlloc(SHA1_LENGTH
);
2013 PORT_SetError(SEC_ERROR_NO_MEMORY
);
2017 rv
= PK11_DigestFinal(p12ecx
->hmacCx
, hmac
.data
, &hmac
.len
, SHA1_LENGTH
);
2019 if(rv
!= SECSuccess
) {
2020 PORT_SetError(SEC_ERROR_NO_MEMORY
);
2024 /* create the digest info */
2025 di
= SGN_CreateDigestInfo(p12ecx
->p12exp
->integrityInfo
.pwdInfo
.algorithm
,
2026 hmac
.data
, hmac
.len
);
2028 PORT_SetError(SEC_ERROR_NO_MEMORY
);
2033 rv
= SGN_CopyDigestInfo(p12ecx
->arena
, &p12ecx
->mac
.safeMac
, di
);
2034 if(rv
!= SECSuccess
) {
2035 PORT_SetError(SEC_ERROR_NO_MEMORY
);
2039 /* encode the mac data */
2040 dummy
= SEC_ASN1EncodeItem(p12ecx
->arena
, &p12ecx
->pfx
.encodedMacData
,
2041 &p12ecx
->mac
, sec_PKCS12MacDataTemplate
);
2043 PORT_SetError(SEC_ERROR_NO_MEMORY
);
2049 SGN_DestroyDigestInfo(di
);
2052 SECITEM_ZfreeItem(&hmac
, PR_FALSE
);
2054 PK11_DestroyContext(p12ecx
->hmacCx
, PR_TRUE
);
2055 p12ecx
->hmacCx
= NULL
;
2060 /* pfx notify function for ASN1 encoder.
2061 * We want to stop encoding once we reach the authenticated safe.
2062 * At that point, the encoder will be updated via streaming
2063 * as the authenticated safe is encoded.
2066 sec_pkcs12_encoder_pfx_notify(void *arg
, PRBool before
, void *dest
, int real_depth
)
2068 sec_PKCS12EncoderContext
*p12ecx
;
2074 /* look for authenticated safe */
2075 p12ecx
= (sec_PKCS12EncoderContext
*)arg
;
2076 if(dest
!= &p12ecx
->pfx
.encodedAuthSafe
) {
2080 SEC_ASN1EncoderSetTakeFromBuf(p12ecx
->outerA1ecx
);
2081 SEC_ASN1EncoderSetStreaming(p12ecx
->outerA1ecx
);
2082 SEC_ASN1EncoderClearNotifyProc(p12ecx
->outerA1ecx
);
2086 * Encodes the PFX item and returns it to the output function, via
2087 * callback. the output function must be capable of multiple updates.
2089 * p12exp - the export context
2090 * output - the output function callback, will be called more than once,
2091 * must be able to accept streaming data.
2092 * outputarg - argument for the output callback.
2095 SEC_PKCS12Encode(SEC_PKCS12ExportContext
*p12exp
,
2096 SEC_PKCS12EncoderOutputCallback output
, void *outputarg
)
2098 sec_PKCS12EncoderContext
*p12enc
;
2099 struct sec_pkcs12_encoder_output outInfo
;
2102 if(!p12exp
|| !output
) {
2106 /* get the encoder context */
2107 p12enc
= sec_pkcs12_encoder_start_context(p12exp
);
2112 outInfo
.outputfn
= output
;
2113 outInfo
.outputarg
= outputarg
;
2115 /* set up PFX encoder, the "outer" encoder. Set it for streaming */
2116 p12enc
->outerA1ecx
= SEC_ASN1EncoderStart(&p12enc
->pfx
,
2117 sec_PKCS12PFXItemTemplate
,
2118 sec_P12A1OutputCB_Outer
,
2120 if(!p12enc
->outerA1ecx
) {
2121 PORT_SetError(SEC_ERROR_NO_MEMORY
);
2125 SEC_ASN1EncoderSetStreaming(p12enc
->outerA1ecx
);
2126 SEC_ASN1EncoderSetNotifyProc(p12enc
->outerA1ecx
,
2127 sec_pkcs12_encoder_pfx_notify
, p12enc
);
2128 rv
= SEC_ASN1EncoderUpdate(p12enc
->outerA1ecx
, NULL
, 0);
2129 if(rv
!= SECSuccess
) {
2134 /* set up asafe cinfo - the output of the encoder feeds the PFX encoder */
2135 p12enc
->middleP7ecx
= SEC_PKCS7EncoderStart(p12enc
->aSafeCinfo
,
2136 sec_P12P7OutputCB_CallA1Update
,
2137 p12enc
->outerA1ecx
, NULL
);
2138 if(!p12enc
->middleP7ecx
) {
2144 p12enc
->middleBuf
.p7eCx
= p12enc
->middleP7ecx
;
2145 p12enc
->middleBuf
.hmacCx
= NULL
;
2146 p12enc
->middleBuf
.numBytes
= 0;
2147 p12enc
->middleBuf
.bufBytes
= sizeof p12enc
->middleBuf
.buf
;
2149 /* Setup the "inner ASN.1 encoder for Authenticated Safes. */
2150 if(p12enc
->p12exp
->integrityEnabled
&&
2151 p12enc
->p12exp
->pwdIntegrity
) {
2152 p12enc
->middleBuf
.hmacCx
= p12enc
->hmacCx
;
2154 p12enc
->middleA1ecx
= SEC_ASN1EncoderStart(&p12enc
->p12exp
->authSafe
,
2155 sec_PKCS12AuthenticatedSafeTemplate
,
2156 sec_P12A1OutputCB_HmacP7Update
,
2157 &p12enc
->middleBuf
);
2158 if(!p12enc
->middleA1ecx
) {
2162 SEC_ASN1EncoderSetStreaming(p12enc
->middleA1ecx
);
2163 SEC_ASN1EncoderSetTakeFromBuf(p12enc
->middleA1ecx
);
2165 /* encode each of the safes */
2166 while(p12enc
->currentSafe
!= p12enc
->p12exp
->safeInfoCount
) {
2167 sec_pkcs12_encoder_asafe_process(p12enc
);
2168 p12enc
->currentSafe
++;
2170 SEC_ASN1EncoderClearTakeFromBuf(p12enc
->middleA1ecx
);
2171 SEC_ASN1EncoderClearStreaming(p12enc
->middleA1ecx
);
2172 SEC_ASN1EncoderUpdate(p12enc
->middleA1ecx
, NULL
, 0);
2173 SEC_ASN1EncoderFinish(p12enc
->middleA1ecx
);
2175 sec_FlushPkcs12OutputBuffer( &p12enc
->middleBuf
);
2177 /* finish the encoding of the authenticated safes */
2178 rv
= SEC_PKCS7EncoderFinish(p12enc
->middleP7ecx
, p12exp
->pwfn
,
2180 if(rv
!= SECSuccess
) {
2184 SEC_ASN1EncoderClearTakeFromBuf(p12enc
->outerA1ecx
);
2185 SEC_ASN1EncoderClearStreaming(p12enc
->outerA1ecx
);
2187 /* update the mac, if necessary */
2188 rv
= sec_Pkcs12FinishMac(p12enc
);
2189 if(rv
!= SECSuccess
) {
2193 /* finish encoding the pfx */
2194 rv
= SEC_ASN1EncoderUpdate(p12enc
->outerA1ecx
, NULL
, 0);
2196 SEC_ASN1EncoderFinish(p12enc
->outerA1ecx
);
2203 SEC_PKCS12DestroyExportContext(SEC_PKCS12ExportContext
*p12ecx
)
2211 if(p12ecx
->safeInfos
) {
2213 while(p12ecx
->safeInfos
[i
] != NULL
) {
2214 if(p12ecx
->safeInfos
[i
]->encryptionKey
) {
2215 PK11_FreeSymKey(p12ecx
->safeInfos
[i
]->encryptionKey
);
2217 if(p12ecx
->safeInfos
[i
]->cinfo
) {
2218 SEC_PKCS7DestroyContentInfo(p12ecx
->safeInfos
[i
]->cinfo
);
2224 PK11_FreeSlot(p12ecx
->slot
);
2226 PORT_FreeArena(p12ecx
->arena
, PR_TRUE
);
2230 /*********************************
2231 * All-in-one routines for exporting certificates
2232 *********************************/
2233 struct inPlaceEncodeInfo
{
2239 sec_pkcs12_in_place_encoder_output(void *arg
, const char *buf
, unsigned long len
)
2241 struct inPlaceEncodeInfo
*outInfo
= (struct inPlaceEncodeInfo
*)arg
;
2243 if(!outInfo
|| !len
|| outInfo
->error
) {
2247 if(!outInfo
->outItem
.data
) {
2248 outInfo
->outItem
.data
= (unsigned char*)PORT_ZAlloc(len
);
2249 outInfo
->outItem
.len
= 0;
2251 if(!PORT_Realloc(&(outInfo
->outItem
.data
), (outInfo
->outItem
.len
+ len
))) {
2252 SECITEM_ZfreeItem(&(outInfo
->outItem
), PR_FALSE
);
2253 outInfo
->outItem
.data
= NULL
;
2254 PORT_SetError(SEC_ERROR_NO_MEMORY
);
2255 outInfo
->error
= PR_TRUE
;
2260 PORT_Memcpy(&(outInfo
->outItem
.data
[outInfo
->outItem
.len
]), buf
, len
);
2261 outInfo
->outItem
.len
+= len
;
2267 * SEC_PKCS12ExportCertifcateAndKeyUsingPassword
2268 * Exports a certificate/key pair using password-based encryption and
2271 * pwfn, pwfnarg - password function and argument for the key database
2272 * cert - the certificate to export
2273 * certDb - certificate database
2274 * pwitem - the password to use
2275 * shroudKey - encrypt the key externally,
2276 * keyShroudAlg - encryption algorithm for key
2277 * encryptionAlg - the algorithm with which data is encrypted
2278 * integrityAlg - the algorithm for integrity
2281 SEC_PKCS12ExportCertificateAndKeyUsingPassword(
2282 SECKEYGetPasswordKey pwfn
, void *pwfnarg
,
2283 CERTCertificate
*cert
, PK11SlotInfo
*slot
,
2284 CERTCertDBHandle
*certDb
, SECItem
*pwitem
,
2285 PRBool shroudKey
, SECOidTag shroudAlg
,
2286 PRBool encryptCert
, SECOidTag certEncAlg
,
2287 SECOidTag integrityAlg
, void *wincx
)
2289 struct inPlaceEncodeInfo outInfo
;
2290 SEC_PKCS12ExportContext
*p12ecx
= NULL
;
2291 SEC_PKCS12SafeInfo
*keySafe
, *certSafe
;
2292 SECItem
*returnItem
= NULL
;
2294 if(!cert
|| !pwitem
|| !slot
) {
2298 outInfo
.error
= PR_FALSE
;
2299 outInfo
.outItem
.data
= NULL
;
2300 outInfo
.outItem
.len
= 0;
2302 p12ecx
= SEC_PKCS12CreateExportContext(pwfn
, pwfnarg
, slot
, wincx
);
2307 /* set up cert safe */
2309 certSafe
= SEC_PKCS12CreatePasswordPrivSafe(p12ecx
, pwitem
, certEncAlg
);
2311 certSafe
= SEC_PKCS12CreateUnencryptedSafe(p12ecx
);
2317 /* set up key safe */
2319 keySafe
= SEC_PKCS12CreateUnencryptedSafe(p12ecx
);
2327 /* add integrity mode */
2328 if(SEC_PKCS12AddPasswordIntegrity(p12ecx
, pwitem
, integrityAlg
)
2333 /* add cert and key pair */
2334 if(SEC_PKCS12AddCertAndKey(p12ecx
, certSafe
, NULL
, cert
, certDb
,
2335 keySafe
, NULL
, shroudKey
, pwitem
, shroudAlg
)
2340 /* encode the puppy */
2341 if(SEC_PKCS12Encode(p12ecx
, sec_pkcs12_in_place_encoder_output
, &outInfo
)
2349 SEC_PKCS12DestroyExportContext(p12ecx
);
2351 returnItem
= SECITEM_DupItem(&outInfo
.outItem
);
2352 SECITEM_ZfreeItem(&outInfo
.outItem
, PR_FALSE
);
2357 if(outInfo
.outItem
.data
) {
2358 SECITEM_ZfreeItem(&(outInfo
.outItem
), PR_TRUE
);
2362 SEC_PKCS12DestroyExportContext(p12ecx
);