Import from 1.9a8 tarball
[mozilla-nss.git] / security / nss / lib / pkcs12 / p12e.c
blobf0fbbcb2e7646e0204ada48c3cdfdc57425a35c4
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
12 * License.
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.
21 * Contributor(s):
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 ***** */
37 #include "nssrenam.h"
38 #include "p12t.h"
39 #include "p12.h"
40 #include "plarena.h"
41 #include "secitem.h"
42 #include "secoid.h"
43 #include "seccomon.h"
44 #include "secport.h"
45 #include "cert.h"
46 #include "secpkcs7.h"
47 #include "secasn1.h"
48 #include "secerr.h"
49 #include "pk11func.h"
50 #include "p12plcy.h"
51 #include "p12local.h"
52 #include "prcpucfg.h"
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;
80 PK11Context * hmacCx;
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
93 * PFX structure.
95 struct SEC_PKCS12SafeInfoStr {
96 PRArenaPool *arena;
98 /* information for setting up password encryption */
99 SECItem pwitem;
100 SECOidTag algorithm;
101 PK11SymKey *encryptionKey;
103 /* how many items have been stored in this safe,
104 * we will skip any safe which does not contain any
105 * items
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 {
119 PRArenaPool *arena;
120 PK11SlotInfo *slot;
121 void *wincx;
123 /* integrity information */
124 PRBool integrityEnabled;
125 PRBool pwdIntegrity;
126 union {
127 struct sec_PKCS12PasswordModeInfo pwdInfo;
128 struct sec_PKCS12PublicKeyModeInfo pubkeyInfo;
129 } integrityInfo;
131 /* helper functions */
132 /* retrieve the password call back */
133 SECKEYGetPasswordKey pwfn;
134 void *pwfnarg;
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;
152 void *outputarg;
155 struct sec_pkcs12_hmac_and_output_info {
156 void *arg;
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 {
164 PRArenaPool *arena;
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;
172 union {
173 struct sec_pkcs12_hmac_and_output_info hmacAndOutputInfo;
174 struct sec_pkcs12_encoder_output encOutput;
175 } output;
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;
187 /* hmac context */
188 PK11Context *hmacCx;
190 /* output buffers */
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
204 * a PKCS 12 blob.
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);
218 if(!arena) {
219 PORT_SetError(SEC_ERROR_NO_MEMORY);
220 return NULL;
223 p12ctxt = (SEC_PKCS12ExportContext *)PORT_ArenaZAlloc(arena,
224 sizeof(SEC_PKCS12ExportContext));
225 if(!p12ctxt) {
226 PORT_SetError(SEC_ERROR_NO_MEMORY);
227 goto loser;
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();
239 return p12ctxt;
241 loser:
242 if(arena) {
243 PORT_FreeArena(arena, PR_TRUE);
246 return NULL;
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.
261 SECStatus
262 SEC_PKCS12AddPasswordIntegrity(SEC_PKCS12ExportContext *p12ctxt,
263 SECItem *pwitem, SECOidTag integAlg)
265 if(!p12ctxt || p12ctxt->integrityEnabled) {
266 return SECFailure;
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);
275 return SECFailure;
277 if(SECITEM_CopyItem(p12ctxt->arena,
278 p12ctxt->integrityInfo.pwdInfo.password, pwitem)
279 != SECSuccess) {
280 PORT_SetError(SEC_ERROR_NO_MEMORY);
281 return SECFailure;
283 p12ctxt->integrityInfo.pwdInfo.algorithm = integAlg;
284 p12ctxt->integrityEnabled = PR_TRUE;
286 return SECSuccess;
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 (?)
300 SECStatus
301 SEC_PKCS12AddPublicKeyIntegrity(SEC_PKCS12ExportContext *p12ctxt,
302 CERTCertificate *cert, CERTCertDBHandle *certDb,
303 SECOidTag algorithm, int keySize)
305 if(!p12ctxt) {
306 return SECFailure;
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;
315 return SECSuccess;
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
323 * keys.
326 /* append the newly created safeInfo to list of safeInfos in the export
327 * context.
329 static SECStatus
330 sec_pkcs12_append_safe_info(SEC_PKCS12ExportContext *p12ctxt, SEC_PKCS12SafeInfo *info)
332 void *mark = NULL, *dummy1 = NULL, *dummy2 = NULL;
334 if(!p12ctxt || !info) {
335 return SECFailure;
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;
348 } else {
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);
360 goto loser;
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);
370 goto loser;
372 p12ctxt->authSafe.encodedSafes[++p12ctxt->authSafe.safeCount] = NULL;
374 PORT_ArenaUnmark(p12ctxt->arena, mark);
375 return SECSuccess;
377 loser:
378 PORT_ArenaRelease(p12ctxt->arena, mark);
379 return SECFailure;
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.
389 SEC_PKCS12SafeInfo *
390 SEC_PKCS12CreatePasswordPrivSafe(SEC_PKCS12ExportContext *p12ctxt,
391 SECItem *pwitem, SECOidTag privAlg)
393 SEC_PKCS12SafeInfo *safeInfo = NULL;
394 void *mark = NULL;
395 PK11SlotInfo *slot = NULL;
396 SECAlgorithmID *algId;
397 SECItem uniPwitem = {siBuffer, NULL, 0};
399 if(!p12ctxt) {
400 return NULL;
403 /* allocate the safe info */
404 mark = PORT_ArenaMark(p12ctxt->arena);
405 safeInfo = (SEC_PKCS12SafeInfo *)PORT_ArenaZAlloc(p12ctxt->arena,
406 sizeof(SEC_PKCS12SafeInfo));
407 if(!safeInfo) {
408 PORT_SetError(SEC_ERROR_NO_MEMORY);
409 PORT_ArenaRelease(p12ctxt->arena, mark);
410 return NULL;
413 safeInfo->itemCount = 0;
415 /* create the encrypted safe */
416 safeInfo->cinfo = SEC_PKCS7CreateEncryptedData(privAlg, 0, p12ctxt->pwfn,
417 p12ctxt->pwfnarg);
418 if(!safeInfo->cinfo) {
419 PORT_SetError(SEC_ERROR_NO_MEMORY);
420 goto loser;
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);
428 goto loser;
430 if(SECITEM_CopyItem(p12ctxt->arena, &safeInfo->pwitem, &uniPwitem) != SECSuccess) {
431 PORT_SetError(SEC_ERROR_NO_MEMORY);
432 goto loser;
435 /* generate the encryption key */
436 slot = PK11_ReferenceSlot(p12ctxt->slot);
437 if(!slot) {
438 slot = PK11_GetInternalKeySlot();
439 if(!slot) {
440 PORT_SetError(SEC_ERROR_NO_MEMORY);
441 goto loser;
445 algId = SEC_PKCS7GetEncryptionAlgorithm(safeInfo->cinfo);
446 safeInfo->encryptionKey = PK11_PBEKeyGen(slot, algId, &uniPwitem,
447 PR_FALSE, p12ctxt->wincx);
448 if(!safeInfo->encryptionKey) {
449 goto loser;
452 safeInfo->arena = p12ctxt->arena;
453 safeInfo->safe = NULL;
454 if(sec_pkcs12_append_safe_info(p12ctxt, safeInfo) != SECSuccess) {
455 goto loser;
458 if(uniPwitem.data) {
459 SECITEM_ZfreeItem(&uniPwitem, PR_FALSE);
461 PORT_ArenaUnmark(p12ctxt->arena, mark);
463 if (slot) {
464 PK11_FreeSlot(slot);
466 return safeInfo;
468 loser:
469 if (slot) {
470 PK11_FreeSlot(slot);
472 if(safeInfo->cinfo) {
473 SEC_PKCS7DestroyContentInfo(safeInfo->cinfo);
476 if(uniPwitem.data) {
477 SECITEM_ZfreeItem(&uniPwitem, PR_FALSE);
480 PORT_ArenaRelease(p12ctxt->arena, mark);
481 return NULL;
484 /* SEC_PKCS12CreateUnencryptedSafe
485 * Creates an unencrypted safe within the export context.
487 * p12ctxt - the export context
489 SEC_PKCS12SafeInfo *
490 SEC_PKCS12CreateUnencryptedSafe(SEC_PKCS12ExportContext *p12ctxt)
492 SEC_PKCS12SafeInfo *safeInfo = NULL;
493 void *mark = NULL;
495 if(!p12ctxt) {
496 return NULL;
499 /* create the safe info */
500 mark = PORT_ArenaMark(p12ctxt->arena);
501 safeInfo = (SEC_PKCS12SafeInfo *)PORT_ArenaZAlloc(p12ctxt->arena,
502 sizeof(SEC_PKCS12SafeInfo));
503 if(!safeInfo) {
504 PORT_ArenaRelease(p12ctxt->arena, mark);
505 PORT_SetError(SEC_ERROR_NO_MEMORY);
506 return NULL;
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);
515 goto loser;
518 if(sec_pkcs12_append_safe_info(p12ctxt, safeInfo) != SECSuccess) {
519 goto loser;
522 PORT_ArenaUnmark(p12ctxt->arena, mark);
523 return safeInfo;
525 loser:
526 if(safeInfo->cinfo) {
527 SEC_PKCS7DestroyContentInfo(safeInfo->cinfo);
530 PORT_ArenaRelease(p12ctxt->arena, mark);
531 return NULL;
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 (?)
544 SEC_PKCS12SafeInfo *
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;
552 void *mark = NULL;
554 if(!p12ctxt || !signer || !recipients || !(*recipients)) {
555 return NULL;
558 /* allocate the safeInfo */
559 mark = PORT_ArenaMark(p12ctxt->arena);
560 safeInfo = (SEC_PKCS12SafeInfo *)PORT_ArenaZAlloc(p12ctxt->arena,
561 sizeof(SEC_PKCS12SafeInfo));
562 if(!safeInfo) {
563 PORT_ArenaRelease(p12ctxt->arena, mark);
564 PORT_SetError(SEC_ERROR_NO_MEMORY);
565 return NULL;
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);
579 goto loser;
582 /* add recipients */
583 if(recipients) {
584 unsigned int i = 0;
585 while(recipients[i] != NULL) {
586 SECStatus rv = SEC_PKCS7AddRecipient(safeInfo->cinfo, recipients[i],
587 certUsageEmailRecipient, certDb);
588 if(rv != SECSuccess) {
589 goto loser;
591 i++;
595 if(sec_pkcs12_append_safe_info(p12ctxt, safeInfo) != SECSuccess) {
596 goto loser;
599 PORT_ArenaUnmark(p12ctxt->arena, mark);
600 return safeInfo;
602 loser:
603 if(safeInfo->cinfo) {
604 SEC_PKCS7DestroyContentInfo(safeInfo->cinfo);
605 safeInfo->cinfo = NULL;
608 PORT_ArenaRelease(p12ctxt->arena, mark);
609 return NULL;
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;
622 if(arena == NULL) {
623 return NULL;
626 /* create the safe contents */
627 safeContents = (sec_PKCS12SafeContents *)PORT_ArenaZAlloc(arena,
628 sizeof(sec_PKCS12SafeContents));
629 if(!safeContents) {
630 PORT_SetError(SEC_ERROR_NO_MEMORY);
631 goto loser;
634 /* set up the internal contents info */
635 safeContents->safeBags = NULL;
636 safeContents->arena = arena;
637 safeContents->bagCount = 0;
639 return safeContents;
641 loser:
642 return NULL;
645 /* appends a safe bag to a safeContents using the specified arena.
647 SECStatus
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) {
655 return SECFailure;
658 mark = PORT_ArenaMark(arena);
659 if(!mark) {
660 PORT_SetError(SEC_ERROR_NO_MEMORY);
661 return SECFailure;
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;
670 } else {
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;
677 if(!dummy) {
678 PORT_ArenaRelease(arena, mark);
679 PORT_SetError(SEC_ERROR_NO_MEMORY);
680 return SECFailure;
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);
689 return SECSuccess;
692 /* appends a safeBag to a specific safeInfo.
694 SECStatus
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) {
702 return SECFailure;
705 if(!safeInfo->safe) {
706 safeInfo->safe = sec_PKCS12CreateSafeContents(p12ctxt->arena);
707 if(!safeInfo->safe) {
708 return SECFailure;
712 dest = safeInfo->safe;
713 rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena, dest, safeBag);
714 if(rv == SECSuccess) {
715 safeInfo->itemCount++;
718 return rv;
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
723 * routine.
725 sec_PKCS12SafeBag *
726 sec_PKCS12CreateSafeBag(SEC_PKCS12ExportContext *p12ctxt, SECOidTag bagType,
727 void *bagData)
729 sec_PKCS12SafeBag *safeBag;
730 PRBool setName = PR_TRUE;
731 void *mark = NULL;
732 SECStatus rv = SECSuccess;
733 SECOidData *oidData = NULL;
735 if(!p12ctxt) {
736 return NULL;
739 mark = PORT_ArenaMark(p12ctxt->arena);
740 if(!mark) {
741 PORT_SetError(SEC_ERROR_NO_MEMORY);
742 return NULL;
745 safeBag = (sec_PKCS12SafeBag *)PORT_ArenaZAlloc(p12ctxt->arena,
746 sizeof(sec_PKCS12SafeBag));
747 if(!safeBag) {
748 PORT_ArenaRelease(p12ctxt->arena, mark);
749 PORT_SetError(SEC_ERROR_NO_MEMORY);
750 return NULL;
753 /* set the bags content based upon bag type */
754 switch(bagType) {
755 case SEC_OID_PKCS12_V1_KEY_BAG_ID:
756 safeBag->safeBagContent.pkcs8KeyBag =
757 (SECKEYPrivateKeyInfo *)bagData;
758 break;
759 case SEC_OID_PKCS12_V1_CERT_BAG_ID:
760 safeBag->safeBagContent.certBag = (sec_PKCS12CertBag *)bagData;
761 break;
762 case SEC_OID_PKCS12_V1_CRL_BAG_ID:
763 safeBag->safeBagContent.crlBag = (sec_PKCS12CRLBag *)bagData;
764 break;
765 case SEC_OID_PKCS12_V1_SECRET_BAG_ID:
766 safeBag->safeBagContent.secretBag = (sec_PKCS12SecretBag *)bagData;
767 break;
768 case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
769 safeBag->safeBagContent.pkcs8ShroudedKeyBag =
770 (SECKEYEncryptedPrivateKeyInfo *)bagData;
771 break;
772 case SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID:
773 safeBag->safeBagContent.safeContents =
774 (sec_PKCS12SafeContents *)bagData;
775 setName = PR_FALSE;
776 break;
777 default:
778 goto loser;
781 oidData = SECOID_FindOIDByTag(bagType);
782 if(oidData) {
783 rv = SECITEM_CopyItem(p12ctxt->arena, &safeBag->safeBagType, &oidData->oid);
784 if(rv != SECSuccess) {
785 PORT_SetError(SEC_ERROR_NO_MEMORY);
786 goto loser;
788 } else {
789 goto loser;
792 safeBag->arena = p12ctxt->arena;
793 PORT_ArenaUnmark(p12ctxt->arena, mark);
795 return safeBag;
797 loser:
798 if(mark) {
799 PORT_ArenaRelease(p12ctxt->arena, mark);
802 return NULL;
805 /* Creates a new certificate bag and returns a pointer to it. If an error
806 * occurs NULL is returned.
808 sec_PKCS12CertBag *
809 sec_PKCS12NewCertBag(PRArenaPool *arena, SECOidTag certType)
811 sec_PKCS12CertBag *certBag = NULL;
812 SECOidData *bagType = NULL;
813 SECStatus rv;
814 void *mark = NULL;
816 if(!arena) {
817 return NULL;
820 mark = PORT_ArenaMark(arena);
821 certBag = (sec_PKCS12CertBag *)PORT_ArenaZAlloc(arena,
822 sizeof(sec_PKCS12CertBag));
823 if(!certBag) {
824 PORT_ArenaRelease(arena, mark);
825 PORT_SetError(SEC_ERROR_NO_MEMORY);
826 return NULL;
829 bagType = SECOID_FindOIDByTag(certType);
830 if(!bagType) {
831 PORT_SetError(SEC_ERROR_NO_MEMORY);
832 goto loser;
835 rv = SECITEM_CopyItem(arena, &certBag->bagID, &bagType->oid);
836 if(rv != SECSuccess) {
837 PORT_SetError(SEC_ERROR_NO_MEMORY);
838 goto loser;
841 PORT_ArenaUnmark(arena, mark);
842 return certBag;
844 loser:
845 PORT_ArenaRelease(arena, mark);
846 return NULL;
849 /* Creates a new CRL bag and returns a pointer to it. If an error
850 * occurs NULL is returned.
852 sec_PKCS12CRLBag *
853 sec_PKCS12NewCRLBag(PRArenaPool *arena, SECOidTag crlType)
855 sec_PKCS12CRLBag *crlBag = NULL;
856 SECOidData *bagType = NULL;
857 SECStatus rv;
858 void *mark = NULL;
860 if(!arena) {
861 return NULL;
864 mark = PORT_ArenaMark(arena);
865 crlBag = (sec_PKCS12CRLBag *)PORT_ArenaZAlloc(arena,
866 sizeof(sec_PKCS12CRLBag));
867 if(!crlBag) {
868 PORT_ArenaRelease(arena, mark);
869 PORT_SetError(SEC_ERROR_NO_MEMORY);
870 return NULL;
873 bagType = SECOID_FindOIDByTag(crlType);
874 if(!bagType) {
875 PORT_SetError(SEC_ERROR_NO_MEMORY);
876 goto loser;
879 rv = SECITEM_CopyItem(arena, &crlBag->bagID, &bagType->oid);
880 if(rv != SECSuccess) {
881 PORT_SetError(SEC_ERROR_NO_MEMORY);
882 goto loser;
885 PORT_ArenaUnmark(arena, mark);
886 return crlBag;
888 loser:
889 PORT_ArenaRelease(arena, mark);
890 return NULL;
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
902 SECStatus
903 sec_PKCS12AddAttributeToBag(SEC_PKCS12ExportContext *p12ctxt,
904 sec_PKCS12SafeBag *safeBag, SECOidTag attrType,
905 SECItem *attrData)
907 sec_PKCS12Attribute *attribute;
908 void *mark = NULL, *dummy = NULL;
909 SECOidData *oiddata = NULL;
910 SECItem unicodeName = { siBuffer, NULL, 0};
911 void *src = NULL;
912 unsigned int nItems = 0;
913 SECStatus rv;
915 if(!safeBag || !p12ctxt) {
916 return SECFailure;
919 mark = PORT_ArenaMark(safeBag->arena);
921 /* allocate the attribute */
922 attribute = (sec_PKCS12Attribute *)PORT_ArenaZAlloc(safeBag->arena,
923 sizeof(sec_PKCS12Attribute));
924 if(!attribute) {
925 PORT_SetError(SEC_ERROR_NO_MEMORY);
926 goto loser;
929 /* set up the attribute */
930 oiddata = SECOID_FindOIDByTag(attrType);
931 if(!oiddata) {
932 PORT_SetError(SEC_ERROR_NO_MEMORY);
933 goto loser;
935 if(SECITEM_CopyItem(p12ctxt->arena, &attribute->attrType, &oiddata->oid) !=
936 SECSuccess) {
937 PORT_SetError(SEC_ERROR_NO_MEMORY);
938 goto loser;
941 nItems = 1;
942 switch(attrType) {
943 case SEC_OID_PKCS9_LOCAL_KEY_ID:
945 src = attrData;
946 break;
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)) {
953 goto loser;
955 src = &unicodeName;
956 break;
958 default:
959 goto loser;
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);
967 goto loser;
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,
974 sizeof(SECItem));
975 if(!attribute->attrValue[0]) {
976 PORT_SetError(SEC_ERROR_NO_MEMORY);
977 goto loser;
979 attribute->attrValue[1] = NULL;
981 rv = SECITEM_CopyItem(p12ctxt->arena, attribute->attrValue[0],
982 (SECItem*)src);
983 if(rv != SECSuccess) {
984 PORT_SetError(SEC_ERROR_NO_MEMORY);
985 goto loser;
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;
994 } else {
995 safeBag->attribs = (sec_PKCS12Attribute **)PORT_ArenaZAlloc(p12ctxt->arena,
996 2 * sizeof(sec_PKCS12Attribute *));
997 dummy = safeBag->attribs;
999 if(!dummy) {
1000 goto loser;
1003 safeBag->attribs[safeBag->nAttribs] = attribute;
1004 safeBag->attribs[++safeBag->nAttribs] = NULL;
1006 PORT_ArenaUnmark(p12ctxt->arena, mark);
1007 return SECSuccess;
1009 loser:
1010 if(mark) {
1011 PORT_ArenaRelease(p12ctxt->arena, mark);
1014 return SECFailure;
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.
1029 SECStatus
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;
1037 void *mark;
1038 SECStatus rv;
1039 SECItem nick = {siBuffer, NULL,0};
1041 if(!p12ctxt || !cert) {
1042 return SECFailure;
1044 mark = PORT_ArenaMark(p12ctxt->arena);
1046 /* allocate the cert bag */
1047 certBag = sec_PKCS12NewCertBag(p12ctxt->arena,
1048 SEC_OID_PKCS9_X509_CERT);
1049 if(!certBag) {
1050 goto loser;
1053 if(SECITEM_CopyItem(p12ctxt->arena, &certBag->value.x509Cert,
1054 &cert->derCert) != SECSuccess) {
1055 PORT_SetError(SEC_ERROR_NO_MEMORY);
1056 goto loser;
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,
1064 certUsageSSLClient,
1065 PR_TRUE);
1066 unsigned int count = 0;
1067 if(!certList) {
1068 PORT_SetError(SEC_ERROR_NO_MEMORY);
1069 goto loser;
1072 /* add cert chain */
1073 for(count = 0; count < (unsigned int)certList->len; count++) {
1074 if(SECITEM_CompareItem(&certList->certs[count], &cert->derCert)
1075 != SECEqual) {
1076 CERTCertificate *tempCert;
1078 /* decode the certificate */
1079 /* XXX
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]);
1091 if(!tempCert) {
1092 CERT_DestroyCertificateList(certList);
1093 goto loser;
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);
1101 goto loser;
1103 CERT_DestroyCertificate(tempCert);
1106 CERT_DestroyCertificateList(certList);
1109 /* if the certificate has a nickname, we will set the friendly name
1110 * to that.
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
1118 * nickname. -javi
1120 char *delimit;
1122 delimit = PORT_Strchr(cert->nickname,':');
1123 if (delimit == NULL) {
1124 nick.data = (unsigned char *)cert->nickname;
1125 nick.len = PORT_Strlen(cert->nickname);
1126 } else {
1127 delimit++;
1128 nick.data = (unsigned char *)PORT_ArenaStrdup(p12ctxt->arena,
1129 delimit);
1130 nick.len = PORT_Strlen(delimit);
1132 } else {
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,
1139 certBag);
1140 if(!safeBag) {
1141 goto loser;
1144 /* add the friendly name and keyId attributes, if necessary */
1145 if(nick.data) {
1146 if(sec_PKCS12AddAttributeToBag(p12ctxt, safeBag,
1147 SEC_OID_PKCS9_FRIENDLY_NAME, &nick)
1148 != SECSuccess) {
1149 goto loser;
1153 if(keyId) {
1154 if(sec_PKCS12AddAttributeToBag(p12ctxt, safeBag, SEC_OID_PKCS9_LOCAL_KEY_ID,
1155 keyId) != SECSuccess) {
1156 goto loser;
1160 /* append the cert safeBag */
1161 if(nestedDest) {
1162 rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena,
1163 (sec_PKCS12SafeContents*)nestedDest,
1164 safeBag);
1165 } else {
1166 rv = sec_pkcs12_append_bag(p12ctxt, safe, safeBag);
1169 if(rv != SECSuccess) {
1170 goto loser;
1173 PORT_ArenaUnmark(p12ctxt->arena, mark);
1174 return SECSuccess;
1176 loser:
1177 if(mark) {
1178 PORT_ArenaRelease(p12ctxt->arena, mark);
1181 return SECFailure;
1184 /* SEC_PKCS12AddEncryptedKey
1185 * Extracts the key associated with a particular certificate and exports
1186 * it.
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
1200 static SECStatus
1201 SEC_PKCS12AddEncryptedKey(SEC_PKCS12ExportContext *p12ctxt,
1202 SECKEYEncryptedPrivateKeyInfo *epki, SEC_PKCS12SafeInfo *safe,
1203 void *nestedDest, SECItem *keyId, SECItem *nickName)
1205 void *mark;
1206 void *keyItem;
1207 SECOidTag keyType;
1208 SECStatus rv = SECFailure;
1209 sec_PKCS12SafeBag *returnBag;
1211 if(!p12ctxt || !safe || !epki) {
1212 return SECFailure;
1215 mark = PORT_ArenaMark(p12ctxt->arena);
1217 keyItem = PORT_ArenaZAlloc(p12ctxt->arena,
1218 sizeof(SECKEYEncryptedPrivateKeyInfo));
1219 if(!keyItem) {
1220 PORT_SetError(SEC_ERROR_NO_MEMORY);
1221 goto loser;
1224 rv = SECKEY_CopyEncryptedPrivateKeyInfo(p12ctxt->arena,
1225 (SECKEYEncryptedPrivateKeyInfo *)keyItem,
1226 epki);
1227 keyType = SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID;
1229 if(rv != SECSuccess) {
1230 goto loser;
1233 /* create the safe bag and set any attributes */
1234 returnBag = sec_PKCS12CreateSafeBag(p12ctxt, keyType, keyItem);
1235 if(!returnBag) {
1236 rv = SECFailure;
1237 goto loser;
1240 if(nickName) {
1241 if(sec_PKCS12AddAttributeToBag(p12ctxt, returnBag,
1242 SEC_OID_PKCS9_FRIENDLY_NAME, nickName)
1243 != SECSuccess) {
1244 goto loser;
1248 if(keyId) {
1249 if(sec_PKCS12AddAttributeToBag(p12ctxt, returnBag,
1250 SEC_OID_PKCS9_LOCAL_KEY_ID,
1251 keyId) != SECSuccess) {
1252 goto loser;
1256 if(nestedDest) {
1257 rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena,
1258 (sec_PKCS12SafeContents*)nestedDest,
1259 returnBag);
1260 } else {
1261 rv = sec_pkcs12_append_bag(p12ctxt, safe, returnBag);
1264 loser:
1266 if (rv != SECSuccess) {
1267 PORT_ArenaRelease(p12ctxt->arena, mark);
1268 } else {
1269 PORT_ArenaUnmark(p12ctxt->arena, mark);
1272 return rv;
1275 /* SEC_PKCS12AddKeyForCert
1276 * Extracts the key associated with a particular certificate and exports
1277 * it.
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
1291 SECStatus
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)
1297 void *mark;
1298 void *keyItem;
1299 SECOidTag keyType;
1300 SECStatus rv = SECFailure;
1301 SECItem nickname = {siBuffer,NULL,0}, uniPwitem = {siBuffer, NULL, 0};
1302 sec_PKCS12SafeBag *returnBag;
1304 if(!p12ctxt || !cert || !safe) {
1305 return SECFailure;
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
1313 if(!shroudKey) {
1315 /* extract the key unencrypted. this will most likely go away */
1316 SECKEYPrivateKeyInfo *pki = PK11_ExportPrivateKeyInfo(cert,
1317 p12ctxt->wincx);
1318 if(!pki) {
1319 PORT_ArenaRelease(p12ctxt->arena, mark);
1320 PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY);
1321 return SECFailure;
1323 keyItem = PORT_ArenaZAlloc(p12ctxt->arena, sizeof(SECKEYPrivateKeyInfo));
1324 if(!keyItem) {
1325 PORT_SetError(SEC_ERROR_NO_MEMORY);
1326 goto loser;
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);
1332 } else {
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);
1341 goto loser;
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();
1347 } else {
1348 slot = PK11_ReferenceSlot(p12ctxt->slot);
1351 epki = PK11_ExportEncryptedPrivateKeyInfo(slot, algorithm,
1352 &uniPwitem, cert, 1,
1353 p12ctxt->wincx);
1354 PK11_FreeSlot(slot);
1356 keyItem = PORT_ArenaZAlloc(p12ctxt->arena,
1357 sizeof(SECKEYEncryptedPrivateKeyInfo));
1358 if(!keyItem) {
1359 PORT_SetError(SEC_ERROR_NO_MEMORY);
1360 goto loser;
1362 if(!epki) {
1363 PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY);
1364 return SECFailure;
1366 rv = SECKEY_CopyEncryptedPrivateKeyInfo(p12ctxt->arena,
1367 (SECKEYEncryptedPrivateKeyInfo *)keyItem,
1368 epki);
1369 keyType = SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID;
1370 SECKEY_DestroyEncryptedPrivateKeyInfo(epki, PR_TRUE);
1373 if(rv != SECSuccess) {
1374 goto loser;
1377 /* if no nickname specified, let's see if the certificate has a
1378 * nickname.
1380 if(!nickName) {
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);
1390 if(!returnBag) {
1391 rv = SECFailure;
1392 goto loser;
1395 if(nickName) {
1396 if(sec_PKCS12AddAttributeToBag(p12ctxt, returnBag,
1397 SEC_OID_PKCS9_FRIENDLY_NAME, nickName)
1398 != SECSuccess) {
1399 goto loser;
1403 if(keyId) {
1404 if(sec_PKCS12AddAttributeToBag(p12ctxt, returnBag, SEC_OID_PKCS9_LOCAL_KEY_ID,
1405 keyId) != SECSuccess) {
1406 goto loser;
1410 if(nestedDest) {
1411 rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena,
1412 (sec_PKCS12SafeContents*)nestedDest,
1413 returnBag);
1414 } else {
1415 rv = sec_pkcs12_append_bag(p12ctxt, safe, returnBag);
1418 loser:
1420 if (rv != SECSuccess) {
1421 PORT_ArenaRelease(p12ctxt->arena, mark);
1422 } else {
1423 PORT_ArenaUnmark(p12ctxt->arena, mark);
1426 return rv;
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
1441 SECStatus
1442 SEC_PKCS12AddDERCertAndEncryptedKey(SEC_PKCS12ExportContext *p12ctxt,
1443 void *certSafe, void *certNestedDest,
1444 SECItem *derCert, void *keySafe,
1445 void *keyNestedDest, SECKEYEncryptedPrivateKeyInfo *epki,
1446 char *nickname)
1448 SECStatus rv = SECFailure;
1449 SGNDigestInfo *digest = NULL;
1450 void *mark = NULL;
1451 CERTCertificate *cert;
1452 SECItem nick = {siBuffer, NULL,0}, *nickPtr = NULL;
1454 if(!p12ctxt || !certSafe || !keySafe || !derCert) {
1455 return SECFailure;
1458 mark = PORT_ArenaMark(p12ctxt->arena);
1460 cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
1461 derCert, NULL, PR_FALSE, PR_FALSE);
1462 if(!cert) {
1463 PORT_ArenaRelease(p12ctxt->arena, mark);
1464 PORT_SetError(SEC_ERROR_NO_MEMORY);
1465 return SECFailure;
1467 cert->nickname = nickname;
1469 /* generate the thumbprint of the cert to use as a keyId */
1470 digest = sec_pkcs12_compute_thumbprint(&cert->derCert);
1471 if(!digest) {
1472 CERT_DestroyCertificate(cert);
1473 return SECFailure;
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) {
1481 goto loser;
1484 if(nickname) {
1485 nick.data = (unsigned char *)nickname;
1486 nick.len = PORT_Strlen(nickname);
1487 nickPtr = &nick;
1488 } else {
1489 nickPtr = NULL;
1492 /* add the key */
1493 rv = SEC_PKCS12AddEncryptedKey(p12ctxt, epki, (SEC_PKCS12SafeInfo*)keySafe,
1494 keyNestedDest, &digest->digest, nickPtr );
1495 if(rv != SECSuccess) {
1496 goto loser;
1499 SGN_DestroyDigestInfo(digest);
1501 PORT_ArenaUnmark(p12ctxt->arena, mark);
1502 return SECSuccess;
1504 loser:
1505 SGN_DestroyDigestInfo(digest);
1506 CERT_DestroyCertificate(cert);
1507 PORT_ArenaRelease(p12ctxt->arena, mark);
1509 return SECFailure;
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
1524 SECStatus
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;
1533 void *mark = NULL;
1535 if(!p12ctxt || !certSafe || !keySafe || !cert) {
1536 return SECFailure;
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);
1543 if(!digest) {
1544 PORT_ArenaRelease(p12ctxt->arena, mark);
1545 return SECFailure;
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) {
1553 goto loser;
1556 /* add the key */
1557 rv = SEC_PKCS12AddKeyForCert(p12ctxt, (SEC_PKCS12SafeInfo*)keySafe,
1558 keyNestedDest, cert,
1559 shroudKey, algorithm, pwitem,
1560 &digest->digest, NULL );
1561 if(rv != SECSuccess) {
1562 goto loser;
1565 SGN_DestroyDigestInfo(digest);
1567 PORT_ArenaUnmark(p12ctxt->arena, mark);
1568 return SECSuccess;
1570 loser:
1571 SGN_DestroyDigestInfo(digest);
1572 PORT_ArenaRelease(p12ctxt->arena, mark);
1574 return SECFailure;
1577 /* SEC_PKCS12CreateNestedSafeContents
1578 * Allows nesting of safe contents to be implemented. No limit imposed on
1579 * depth.
1581 * p12ctxt - the export context
1582 * baseSafe - the base safeInfo
1583 * nestedDest - a parent safeContents (?)
1585 void *
1586 SEC_PKCS12CreateNestedSafeContents(SEC_PKCS12ExportContext *p12ctxt,
1587 void *baseSafe, void *nestedDest)
1589 sec_PKCS12SafeContents *newSafe;
1590 sec_PKCS12SafeBag *safeContentsBag;
1591 void *mark;
1592 SECStatus rv;
1594 if(!p12ctxt || !baseSafe) {
1595 return NULL;
1598 mark = PORT_ArenaMark(p12ctxt->arena);
1600 newSafe = sec_PKCS12CreateSafeContents(p12ctxt->arena);
1601 if(!newSafe) {
1602 PORT_ArenaRelease(p12ctxt->arena, mark);
1603 PORT_SetError(SEC_ERROR_NO_MEMORY);
1604 return NULL;
1607 /* create the safeContents safeBag */
1608 safeContentsBag = sec_PKCS12CreateSafeBag(p12ctxt,
1609 SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID,
1610 newSafe);
1611 if(!safeContentsBag) {
1612 goto loser;
1615 /* append the safeContents to the appropriate area */
1616 if(nestedDest) {
1617 rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena,
1618 (sec_PKCS12SafeContents*)nestedDest,
1619 safeContentsBag);
1620 } else {
1621 rv = sec_pkcs12_append_bag(p12ctxt, (SEC_PKCS12SafeInfo*)baseSafe,
1622 safeContentsBag);
1624 if(rv != SECSuccess) {
1625 goto loser;
1628 PORT_ArenaUnmark(p12ctxt->arena, mark);
1629 return newSafe;
1631 loser:
1632 PORT_ArenaRelease(p12ctxt->arena, mark);
1633 return NULL;
1636 /*********************************
1637 * Encoding routines
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;
1649 SECStatus rv;
1650 SECItem ignore = {0};
1651 void *mark;
1653 if(!p12exp || !p12exp->safeInfos) {
1654 return NULL;
1657 /* check for any empty safes and skip them */
1658 i = nonEmptyCnt = 0;
1659 while(p12exp->safeInfos[i]) {
1660 if(p12exp->safeInfos[i]->itemCount) {
1661 nonEmptyCnt++;
1663 i++;
1665 if(nonEmptyCnt == 0) {
1666 return NULL;
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);
1673 if(!p12enc) {
1674 PORT_SetError(SEC_ERROR_NO_MEMORY);
1675 return NULL;
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);
1686 goto loser;
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) {
1695 SECStatus rv;
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,
1703 NULL,
1704 p12exp->pwfn,
1705 p12exp->pwfnarg);
1706 if(!p12enc->aSafeCinfo) {
1707 goto loser;
1709 if(SEC_PKCS7IncludeCertChain(p12enc->aSafeCinfo,NULL) != SECSuccess) {
1710 goto loser;
1712 rv = SEC_PKCS7AddSigningTime(p12enc->aSafeCinfo);
1713 PORT_Assert(rv == SECSuccess);
1714 } else {
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();
1721 PK11SymKey *symKey;
1722 SECItem *params;
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));
1729 if(!salt) {
1730 PORT_SetError(SEC_ERROR_NO_MEMORY);
1731 goto loser;
1733 if(SECITEM_CopyItem(p12exp->arena, &(p12enc->mac.macSalt), salt)
1734 != SECSuccess) {
1735 PORT_SetError(SEC_ERROR_NO_MEMORY);
1736 goto loser;
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)) {
1743 goto loser;
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) {
1751 case SEC_OID_SHA1:
1752 integrityMech = CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN; break;
1753 case SEC_OID_MD5:
1754 integrityMech = CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN; break;
1755 case SEC_OID_MD2:
1756 integrityMech = CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN; break;
1757 default:
1758 goto loser;
1761 symKey = PK11_KeyGen(NULL, integrityMech, params, 20, NULL);
1762 PK11_DestroyPBEParams(params);
1763 if(!symKey) {
1764 goto loser;
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,
1773 symKey, &ignore);
1775 PK11_FreeSymKey(symKey);
1776 if(!p12enc->hmacCx) {
1777 PORT_SetError(SEC_ERROR_NO_MEMORY);
1778 goto loser;
1780 rv = PK11_DigestBegin(p12enc->hmacCx);
1781 if (rv != SECSuccess)
1782 goto loser;
1786 if(!p12enc->aSafeCinfo) {
1787 goto loser;
1790 PORT_ArenaUnmark(p12exp->arena, mark);
1792 return p12enc;
1794 loser:
1795 if(p12enc) {
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);
1806 return NULL;
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.
1813 static void
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.
1827 static void
1828 sec_P12A1OutputCB_HmacP7Update(void *arg, const char *buf,
1829 unsigned long len,
1830 int depth,
1831 SEC_ASN1EncodingPart data_kind)
1833 sec_pkcs12OutputBuffer * bufcx = (sec_pkcs12OutputBuffer *)arg;
1835 if(!buf || !len)
1836 return;
1838 if (bufcx->hmacCx) {
1839 PK11_DigestOp(bufcx->hmacCx, (unsigned char *)buf, len);
1842 /* buffer */
1843 if (bufcx->numBytes > 0) {
1844 int toCopy;
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)
1849 return;
1850 SEC_PKCS7EncoderUpdate(bufcx->p7eCx, bufcx->buf, bufcx->bufBytes);
1851 bufcx->numBytes = 0;
1852 return;
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;
1858 len -= toCopy;
1859 buf += toCopy;
1861 /* buffer is presently empty */
1862 if (len >= bufcx->bufBytes) {
1863 /* Just pass it through */
1864 SEC_PKCS7EncoderUpdate(bufcx->p7eCx, buf, len);
1865 } else {
1866 /* copy it all into the buffer, and return */
1867 memcpy(bufcx->buf, buf, len);
1868 bufcx->numBytes = len;
1872 void
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.
1884 static void
1885 sec_P12P7OutputCB_CallA1Update(void *arg, const char *buf, unsigned long len)
1887 SEC_ASN1EncoderContext *cx = (SEC_ASN1EncoderContext*)arg;
1889 if (!buf || !len)
1890 return;
1892 SEC_ASN1EncoderUpdate(cx, buf, len);
1896 /* this function encodes content infos which are part of the
1897 * sequence of content infos labeled AuthenticatedSafes
1899 static SECStatus
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) {
1916 return SECSuccess;
1919 cinfo = safeInfo->cinfo;
1920 cinfoType = SEC_PKCS7ContentType(cinfo);
1922 /* determine the safe type and set the appropriate argument */
1923 switch(cinfoType) {
1924 case SEC_OID_PKCS7_DATA:
1925 case SEC_OID_PKCS7_ENVELOPED_DATA:
1926 break;
1927 case SEC_OID_PKCS7_ENCRYPTED_DATA:
1928 bulkKey = safeInfo->encryptionKey;
1929 PK11_SetSymKeyUserData(bulkKey, &safeInfo->pwitem, NULL);
1930 break;
1931 default:
1932 return SECFailure;
1936 /* start the PKCS7 encoder */
1937 innerP7ecx = SEC_PKCS7EncoderStart(cinfo,
1938 sec_P12P7OutputCB_CallA1Update,
1939 p12ecx->middleA1ecx, bulkKey);
1940 if(!innerP7ecx) {
1941 goto loser;
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,
1953 &p12ecx->innerBuf);
1954 if(!innerA1ecx) {
1955 goto loser;
1957 rv = SEC_ASN1EncoderUpdate(innerA1ecx, NULL, 0);
1958 SEC_ASN1EncoderFinish(innerA1ecx);
1959 sec_FlushPkcs12OutputBuffer( &p12ecx->innerBuf);
1960 innerA1ecx = NULL;
1961 if(rv != SECSuccess) {
1962 goto loser;
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);
1971 return SECSuccess;
1973 loser:
1974 if(innerP7ecx) {
1975 SEC_PKCS7EncoderFinish(innerP7ecx, p12ecx->p12exp->pwfn,
1976 p12ecx->p12exp->pwfnarg);
1979 if(innerA1ecx) {
1980 SEC_ASN1EncoderFinish(innerA1ecx);
1982 memset(&p12ecx->innerBuf, 0, sizeof p12ecx->innerBuf);
1983 return SECFailure;
1986 /* finish the HMAC and encode the macData so that it can be
1987 * encoded.
1989 static SECStatus
1990 sec_Pkcs12FinishMac(sec_PKCS12EncoderContext *p12ecx)
1992 SECItem hmac = { siBuffer, NULL, 0 };
1993 SECStatus rv;
1994 SGNDigestInfo *di = NULL;
1995 void *dummy;
1997 if(!p12ecx) {
1998 return SECFailure;
2001 /* make sure we are using password integrity mode */
2002 if(!p12ecx->p12exp->integrityEnabled) {
2003 return SECSuccess;
2006 if(!p12ecx->p12exp->pwdIntegrity) {
2007 return SECSuccess;
2010 /* finish the hmac */
2011 hmac.data = (unsigned char *)PORT_ZAlloc(SHA1_LENGTH);
2012 if(!hmac.data) {
2013 PORT_SetError(SEC_ERROR_NO_MEMORY);
2014 return SECFailure;
2017 rv = PK11_DigestFinal(p12ecx->hmacCx, hmac.data, &hmac.len, SHA1_LENGTH);
2019 if(rv != SECSuccess) {
2020 PORT_SetError(SEC_ERROR_NO_MEMORY);
2021 goto loser;
2024 /* create the digest info */
2025 di = SGN_CreateDigestInfo(p12ecx->p12exp->integrityInfo.pwdInfo.algorithm,
2026 hmac.data, hmac.len);
2027 if(!di) {
2028 PORT_SetError(SEC_ERROR_NO_MEMORY);
2029 rv = SECFailure;
2030 goto loser;
2033 rv = SGN_CopyDigestInfo(p12ecx->arena, &p12ecx->mac.safeMac, di);
2034 if(rv != SECSuccess) {
2035 PORT_SetError(SEC_ERROR_NO_MEMORY);
2036 goto loser;
2039 /* encode the mac data */
2040 dummy = SEC_ASN1EncodeItem(p12ecx->arena, &p12ecx->pfx.encodedMacData,
2041 &p12ecx->mac, sec_PKCS12MacDataTemplate);
2042 if(!dummy) {
2043 PORT_SetError(SEC_ERROR_NO_MEMORY);
2044 rv = SECFailure;
2047 loser:
2048 if(di) {
2049 SGN_DestroyDigestInfo(di);
2051 if(hmac.data) {
2052 SECITEM_ZfreeItem(&hmac, PR_FALSE);
2054 PK11_DestroyContext(p12ecx->hmacCx, PR_TRUE);
2055 p12ecx->hmacCx = NULL;
2057 return rv;
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.
2065 static void
2066 sec_pkcs12_encoder_pfx_notify(void *arg, PRBool before, void *dest, int real_depth)
2068 sec_PKCS12EncoderContext *p12ecx;
2070 if(!before) {
2071 return;
2074 /* look for authenticated safe */
2075 p12ecx = (sec_PKCS12EncoderContext*)arg;
2076 if(dest != &p12ecx->pfx.encodedAuthSafe) {
2077 return;
2080 SEC_ASN1EncoderSetTakeFromBuf(p12ecx->outerA1ecx);
2081 SEC_ASN1EncoderSetStreaming(p12ecx->outerA1ecx);
2082 SEC_ASN1EncoderClearNotifyProc(p12ecx->outerA1ecx);
2085 /* SEC_PKCS12Encode
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.
2094 SECStatus
2095 SEC_PKCS12Encode(SEC_PKCS12ExportContext *p12exp,
2096 SEC_PKCS12EncoderOutputCallback output, void *outputarg)
2098 sec_PKCS12EncoderContext *p12enc;
2099 struct sec_pkcs12_encoder_output outInfo;
2100 SECStatus rv;
2102 if(!p12exp || !output) {
2103 return SECFailure;
2106 /* get the encoder context */
2107 p12enc = sec_pkcs12_encoder_start_context(p12exp);
2108 if(!p12enc) {
2109 return SECFailure;
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,
2119 &outInfo);
2120 if(!p12enc->outerA1ecx) {
2121 PORT_SetError(SEC_ERROR_NO_MEMORY);
2122 rv = SECFailure;
2123 goto loser;
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) {
2130 rv = SECFailure;
2131 goto loser;
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) {
2139 rv = SECFailure;
2140 goto loser;
2143 /* encode asafe */
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) {
2159 rv = SECFailure;
2160 goto loser;
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,
2179 p12exp->pwfnarg);
2180 if(rv != SECSuccess) {
2181 goto loser;
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) {
2190 goto loser;
2193 /* finish encoding the pfx */
2194 rv = SEC_ASN1EncoderUpdate(p12enc->outerA1ecx, NULL, 0);
2196 SEC_ASN1EncoderFinish(p12enc->outerA1ecx);
2198 loser:
2199 return rv;
2202 void
2203 SEC_PKCS12DestroyExportContext(SEC_PKCS12ExportContext *p12ecx)
2205 int i = 0;
2207 if(!p12ecx) {
2208 return;
2211 if(p12ecx->safeInfos) {
2212 i = 0;
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);
2220 i++;
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 {
2234 PRBool error;
2235 SECItem outItem;
2238 static void
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) {
2244 return;
2247 if(!outInfo->outItem.data) {
2248 outInfo->outItem.data = (unsigned char*)PORT_ZAlloc(len);
2249 outInfo->outItem.len = 0;
2250 } else {
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;
2256 return;
2260 PORT_Memcpy(&(outInfo->outItem.data[outInfo->outItem.len]), buf, len);
2261 outInfo->outItem.len += len;
2263 return;
2267 * SEC_PKCS12ExportCertifcateAndKeyUsingPassword
2268 * Exports a certificate/key pair using password-based encryption and
2269 * authentication.
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
2280 SECItem *
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) {
2295 return NULL;
2298 outInfo.error = PR_FALSE;
2299 outInfo.outItem.data = NULL;
2300 outInfo.outItem.len = 0;
2302 p12ecx = SEC_PKCS12CreateExportContext(pwfn, pwfnarg, slot, wincx);
2303 if(!p12ecx) {
2304 return NULL;
2307 /* set up cert safe */
2308 if(encryptCert) {
2309 certSafe = SEC_PKCS12CreatePasswordPrivSafe(p12ecx, pwitem, certEncAlg);
2310 } else {
2311 certSafe = SEC_PKCS12CreateUnencryptedSafe(p12ecx);
2313 if(!certSafe) {
2314 goto loser;
2317 /* set up key safe */
2318 if(shroudKey) {
2319 keySafe = SEC_PKCS12CreateUnencryptedSafe(p12ecx);
2320 } else {
2321 keySafe = certSafe;
2323 if(!keySafe) {
2324 goto loser;
2327 /* add integrity mode */
2328 if(SEC_PKCS12AddPasswordIntegrity(p12ecx, pwitem, integrityAlg)
2329 != SECSuccess) {
2330 goto loser;
2333 /* add cert and key pair */
2334 if(SEC_PKCS12AddCertAndKey(p12ecx, certSafe, NULL, cert, certDb,
2335 keySafe, NULL, shroudKey, pwitem, shroudAlg)
2336 != SECSuccess) {
2337 goto loser;
2340 /* encode the puppy */
2341 if(SEC_PKCS12Encode(p12ecx, sec_pkcs12_in_place_encoder_output, &outInfo)
2342 != SECSuccess) {
2343 goto loser;
2345 if(outInfo.error) {
2346 goto loser;
2349 SEC_PKCS12DestroyExportContext(p12ecx);
2351 returnItem = SECITEM_DupItem(&outInfo.outItem);
2352 SECITEM_ZfreeItem(&outInfo.outItem, PR_FALSE);
2354 return returnItem;
2356 loser:
2357 if(outInfo.outItem.data) {
2358 SECITEM_ZfreeItem(&(outInfo.outItem), PR_TRUE);
2361 if(p12ecx) {
2362 SEC_PKCS12DestroyExportContext(p12ecx);
2365 return NULL;