[nss] Import Firefox 3.0 beta 5 tarball
[mozilla-nss.git] / security / nss / lib / pkcs12 / p12e.c
blobb84ac58e74d263983b5f46f9792baacd988afd6e
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 "p12t.h"
38 #include "p12.h"
39 #include "plarena.h"
40 #include "secitem.h"
41 #include "secoid.h"
42 #include "seccomon.h"
43 #include "secport.h"
44 #include "cert.h"
45 #include "secpkcs7.h"
46 #include "secasn1.h"
47 #include "secerr.h"
48 #include "pk11func.h"
49 #include "p12plcy.h"
50 #include "p12local.h"
51 #include "prcpucfg.h"
54 ** This PKCS12 file encoder uses numerous nested ASN.1 and PKCS7 encoder
55 ** contexts. It can be difficult to keep straight. Here's a picture:
57 ** "outer" ASN.1 encoder. The output goes to the library caller's CB.
58 ** "middle" PKCS7 encoder. Feeds the "outer" ASN.1 encoder.
59 ** "middle" ASN1 encoder. Encodes the encrypted aSafes.
60 ** Feeds the "middle" P7 encoder above.
61 ** "inner" PKCS7 encoder. Encrypts the "authenticated Safes" (aSafes)
62 ** Feeds the "middle" ASN.1 encoder above.
63 ** "inner" ASN.1 encoder. Encodes the unencrypted aSafes.
64 ** Feeds the "inner" P7 enocder above.
66 ** Buffering has been added at each point where the output of an ASN.1
67 ** encoder feeds the input of a PKCS7 encoder.
70 /*********************************
71 * Output buffer object, used to buffer output from ASN.1 encoder
72 * before passing data on down to the next PKCS7 encoder.
73 *********************************/
75 #define PK12_OUTPUT_BUFFER_SIZE 8192
77 struct sec_pkcs12OutputBufferStr {
78 SEC_PKCS7EncoderContext * p7eCx;
79 PK11Context * hmacCx;
80 unsigned int numBytes;
81 unsigned int bufBytes;
82 char buf[PK12_OUTPUT_BUFFER_SIZE];
84 typedef struct sec_pkcs12OutputBufferStr sec_pkcs12OutputBuffer;
86 /*********************************
87 * Structures used in exporting the PKCS 12 blob
88 *********************************/
90 /* A SafeInfo is used for each ContentInfo which makes up the
91 * sequence of safes in the AuthenticatedSafe portion of the
92 * PFX structure.
94 struct SEC_PKCS12SafeInfoStr {
95 PRArenaPool *arena;
97 /* information for setting up password encryption */
98 SECItem pwitem;
99 SECOidTag algorithm;
100 PK11SymKey *encryptionKey;
102 /* how many items have been stored in this safe,
103 * we will skip any safe which does not contain any
104 * items
106 unsigned int itemCount;
108 /* the content info for the safe */
109 SEC_PKCS7ContentInfo *cinfo;
111 sec_PKCS12SafeContents *safe;
114 /* An opaque structure which contains information needed for exporting
115 * certificates and keys through PKCS 12.
117 struct SEC_PKCS12ExportContextStr {
118 PRArenaPool *arena;
119 PK11SlotInfo *slot;
120 void *wincx;
122 /* integrity information */
123 PRBool integrityEnabled;
124 PRBool pwdIntegrity;
125 union {
126 struct sec_PKCS12PasswordModeInfo pwdInfo;
127 struct sec_PKCS12PublicKeyModeInfo pubkeyInfo;
128 } integrityInfo;
130 /* helper functions */
131 /* retrieve the password call back */
132 SECKEYGetPasswordKey pwfn;
133 void *pwfnarg;
135 /* safe contents bags */
136 SEC_PKCS12SafeInfo **safeInfos;
137 unsigned int safeInfoCount;
139 /* the sequence of safes */
140 sec_PKCS12AuthenticatedSafe authSafe;
142 /* information needing deletion */
143 CERTCertificate **certList;
146 /* structures for passing information to encoder callbacks when processing
147 * data through the ASN1 engine.
149 struct sec_pkcs12_encoder_output {
150 SEC_PKCS12EncoderOutputCallback outputfn;
151 void *outputarg;
154 struct sec_pkcs12_hmac_and_output_info {
155 void *arg;
156 struct sec_pkcs12_encoder_output output;
159 /* An encoder context which is used for the actual encoding
160 * portion of PKCS 12.
162 typedef struct sec_PKCS12EncoderContextStr {
163 PRArenaPool *arena;
164 SEC_PKCS12ExportContext *p12exp;
165 PK11SymKey *encryptionKey;
167 /* encoder information - this is set up based on whether
168 * password based or public key pased privacy is being used
170 SEC_ASN1EncoderContext *outerA1ecx;
171 union {
172 struct sec_pkcs12_hmac_and_output_info hmacAndOutputInfo;
173 struct sec_pkcs12_encoder_output encOutput;
174 } output;
176 /* structures for encoding of PFX and MAC */
177 sec_PKCS12PFXItem pfx;
178 sec_PKCS12MacData mac;
180 /* authenticated safe encoding tracking information */
181 SEC_PKCS7ContentInfo *aSafeCinfo;
182 SEC_PKCS7EncoderContext *middleP7ecx;
183 SEC_ASN1EncoderContext *middleA1ecx;
184 unsigned int currentSafe;
186 /* hmac context */
187 PK11Context *hmacCx;
189 /* output buffers */
190 sec_pkcs12OutputBuffer middleBuf;
191 sec_pkcs12OutputBuffer innerBuf;
193 } sec_PKCS12EncoderContext;
196 /*********************************
197 * Export setup routines
198 *********************************/
200 /* SEC_PKCS12CreateExportContext
201 * Creates an export context and sets the unicode and password retrieval
202 * callbacks. This is the first call which must be made when exporting
203 * a PKCS 12 blob.
205 * pwfn, pwfnarg - password retrieval callback and argument. these are
206 * required for password-authentication mode.
208 SEC_PKCS12ExportContext *
209 SEC_PKCS12CreateExportContext(SECKEYGetPasswordKey pwfn, void *pwfnarg,
210 PK11SlotInfo *slot, void *wincx)
212 PRArenaPool *arena = NULL;
213 SEC_PKCS12ExportContext *p12ctxt = NULL;
215 /* allocate the arena and create the context */
216 arena = PORT_NewArena(4096);
217 if(!arena) {
218 PORT_SetError(SEC_ERROR_NO_MEMORY);
219 return NULL;
222 p12ctxt = (SEC_PKCS12ExportContext *)PORT_ArenaZAlloc(arena,
223 sizeof(SEC_PKCS12ExportContext));
224 if(!p12ctxt) {
225 PORT_SetError(SEC_ERROR_NO_MEMORY);
226 goto loser;
229 /* password callback for key retrieval */
230 p12ctxt->pwfn = pwfn;
231 p12ctxt->pwfnarg = pwfnarg;
233 p12ctxt->integrityEnabled = PR_FALSE;
234 p12ctxt->arena = arena;
235 p12ctxt->wincx = wincx;
236 p12ctxt->slot = (slot) ? PK11_ReferenceSlot(slot) : PK11_GetInternalSlot();
238 return p12ctxt;
240 loser:
241 if(arena) {
242 PORT_FreeArena(arena, PR_TRUE);
245 return NULL;
249 * Adding integrity mode
252 /* SEC_PKCS12AddPasswordIntegrity
253 * Add password integrity to the exported data. If an integrity method
254 * has already been set, then return an error.
256 * p12ctxt - the export context
257 * pwitem - the password for integrity mode
258 * integAlg - the integrity algorithm to use for authentication.
260 SECStatus
261 SEC_PKCS12AddPasswordIntegrity(SEC_PKCS12ExportContext *p12ctxt,
262 SECItem *pwitem, SECOidTag integAlg)
264 if(!p12ctxt || p12ctxt->integrityEnabled) {
265 return SECFailure;
268 /* set up integrity information */
269 p12ctxt->pwdIntegrity = PR_TRUE;
270 p12ctxt->integrityInfo.pwdInfo.password =
271 (SECItem*)PORT_ArenaZAlloc(p12ctxt->arena, sizeof(SECItem));
272 if(!p12ctxt->integrityInfo.pwdInfo.password) {
273 PORT_SetError(SEC_ERROR_NO_MEMORY);
274 return SECFailure;
276 if(SECITEM_CopyItem(p12ctxt->arena,
277 p12ctxt->integrityInfo.pwdInfo.password, pwitem)
278 != SECSuccess) {
279 PORT_SetError(SEC_ERROR_NO_MEMORY);
280 return SECFailure;
282 p12ctxt->integrityInfo.pwdInfo.algorithm = integAlg;
283 p12ctxt->integrityEnabled = PR_TRUE;
285 return SECSuccess;
288 /* SEC_PKCS12AddPublicKeyIntegrity
289 * Add public key integrity to the exported data. If an integrity method
290 * has already been set, then return an error. The certificate must be
291 * allowed to be used as a signing cert.
293 * p12ctxt - the export context
294 * cert - signer certificate
295 * certDb - the certificate database
296 * algorithm - signing algorithm
297 * keySize - size of the signing key (?)
299 SECStatus
300 SEC_PKCS12AddPublicKeyIntegrity(SEC_PKCS12ExportContext *p12ctxt,
301 CERTCertificate *cert, CERTCertDBHandle *certDb,
302 SECOidTag algorithm, int keySize)
304 if(!p12ctxt) {
305 return SECFailure;
308 p12ctxt->integrityInfo.pubkeyInfo.cert = cert;
309 p12ctxt->integrityInfo.pubkeyInfo.certDb = certDb;
310 p12ctxt->integrityInfo.pubkeyInfo.algorithm = algorithm;
311 p12ctxt->integrityInfo.pubkeyInfo.keySize = keySize;
312 p12ctxt->integrityEnabled = PR_TRUE;
314 return SECSuccess;
319 * Adding safes - encrypted (password/public key) or unencrypted
320 * Each of the safe creation routines return an opaque pointer which
321 * are later passed into the routines for exporting certificates and
322 * keys.
325 /* append the newly created safeInfo to list of safeInfos in the export
326 * context.
328 static SECStatus
329 sec_pkcs12_append_safe_info(SEC_PKCS12ExportContext *p12ctxt, SEC_PKCS12SafeInfo *info)
331 void *mark = NULL, *dummy1 = NULL, *dummy2 = NULL;
333 if(!p12ctxt || !info) {
334 return SECFailure;
337 mark = PORT_ArenaMark(p12ctxt->arena);
339 /* if no safeInfos have been set, create the list, otherwise expand it. */
340 if(!p12ctxt->safeInfoCount) {
341 p12ctxt->safeInfos = (SEC_PKCS12SafeInfo **)PORT_ArenaZAlloc(p12ctxt->arena,
342 2 * sizeof(SEC_PKCS12SafeInfo *));
343 dummy1 = p12ctxt->safeInfos;
344 p12ctxt->authSafe.encodedSafes = (SECItem **)PORT_ArenaZAlloc(p12ctxt->arena,
345 2 * sizeof(SECItem *));
346 dummy2 = p12ctxt->authSafe.encodedSafes;
347 } else {
348 dummy1 = PORT_ArenaGrow(p12ctxt->arena, p12ctxt->safeInfos,
349 (p12ctxt->safeInfoCount + 1) * sizeof(SEC_PKCS12SafeInfo *),
350 (p12ctxt->safeInfoCount + 2) * sizeof(SEC_PKCS12SafeInfo *));
351 p12ctxt->safeInfos = (SEC_PKCS12SafeInfo **)dummy1;
352 dummy2 = PORT_ArenaGrow(p12ctxt->arena, p12ctxt->authSafe.encodedSafes,
353 (p12ctxt->authSafe.safeCount + 1) * sizeof(SECItem *),
354 (p12ctxt->authSafe.safeCount + 2) * sizeof(SECItem *));
355 p12ctxt->authSafe.encodedSafes = (SECItem**)dummy2;
357 if(!dummy1 || !dummy2) {
358 PORT_SetError(SEC_ERROR_NO_MEMORY);
359 goto loser;
362 /* append the new safeInfo and null terminate the list */
363 p12ctxt->safeInfos[p12ctxt->safeInfoCount] = info;
364 p12ctxt->safeInfos[++p12ctxt->safeInfoCount] = NULL;
365 p12ctxt->authSafe.encodedSafes[p12ctxt->authSafe.safeCount] =
366 (SECItem*)PORT_ArenaZAlloc(p12ctxt->arena, sizeof(SECItem));
367 if(!p12ctxt->authSafe.encodedSafes[p12ctxt->authSafe.safeCount]) {
368 PORT_SetError(SEC_ERROR_NO_MEMORY);
369 goto loser;
371 p12ctxt->authSafe.encodedSafes[++p12ctxt->authSafe.safeCount] = NULL;
373 PORT_ArenaUnmark(p12ctxt->arena, mark);
374 return SECSuccess;
376 loser:
377 PORT_ArenaRelease(p12ctxt->arena, mark);
378 return SECFailure;
381 /* SEC_PKCS12CreatePasswordPrivSafe
382 * Create a password privacy safe to store exported information in.
384 * p12ctxt - export context
385 * pwitem - password for encryption
386 * privAlg - pbe algorithm through which encryption is done.
388 SEC_PKCS12SafeInfo *
389 SEC_PKCS12CreatePasswordPrivSafe(SEC_PKCS12ExportContext *p12ctxt,
390 SECItem *pwitem, SECOidTag privAlg)
392 SEC_PKCS12SafeInfo *safeInfo = NULL;
393 void *mark = NULL;
394 PK11SlotInfo *slot = NULL;
395 SECAlgorithmID *algId;
396 SECItem uniPwitem = {siBuffer, NULL, 0};
398 if(!p12ctxt) {
399 return NULL;
402 /* allocate the safe info */
403 mark = PORT_ArenaMark(p12ctxt->arena);
404 safeInfo = (SEC_PKCS12SafeInfo *)PORT_ArenaZAlloc(p12ctxt->arena,
405 sizeof(SEC_PKCS12SafeInfo));
406 if(!safeInfo) {
407 PORT_SetError(SEC_ERROR_NO_MEMORY);
408 PORT_ArenaRelease(p12ctxt->arena, mark);
409 return NULL;
412 safeInfo->itemCount = 0;
414 /* create the encrypted safe */
415 safeInfo->cinfo = SEC_PKCS7CreateEncryptedData(privAlg, 0, p12ctxt->pwfn,
416 p12ctxt->pwfnarg);
417 if(!safeInfo->cinfo) {
418 PORT_SetError(SEC_ERROR_NO_MEMORY);
419 goto loser;
421 safeInfo->arena = p12ctxt->arena;
423 /* convert the password to unicode */
424 if(!sec_pkcs12_convert_item_to_unicode(NULL, &uniPwitem, pwitem,
425 PR_TRUE, PR_TRUE, PR_TRUE)) {
426 PORT_SetError(SEC_ERROR_NO_MEMORY);
427 goto loser;
429 if(SECITEM_CopyItem(p12ctxt->arena, &safeInfo->pwitem, &uniPwitem) != SECSuccess) {
430 PORT_SetError(SEC_ERROR_NO_MEMORY);
431 goto loser;
434 /* generate the encryption key */
435 slot = PK11_ReferenceSlot(p12ctxt->slot);
436 if(!slot) {
437 slot = PK11_GetInternalKeySlot();
438 if(!slot) {
439 PORT_SetError(SEC_ERROR_NO_MEMORY);
440 goto loser;
444 algId = SEC_PKCS7GetEncryptionAlgorithm(safeInfo->cinfo);
445 safeInfo->encryptionKey = PK11_PBEKeyGen(slot, algId, &uniPwitem,
446 PR_FALSE, p12ctxt->wincx);
447 if(!safeInfo->encryptionKey) {
448 goto loser;
451 safeInfo->arena = p12ctxt->arena;
452 safeInfo->safe = NULL;
453 if(sec_pkcs12_append_safe_info(p12ctxt, safeInfo) != SECSuccess) {
454 goto loser;
457 if(uniPwitem.data) {
458 SECITEM_ZfreeItem(&uniPwitem, PR_FALSE);
460 PORT_ArenaUnmark(p12ctxt->arena, mark);
462 if (slot) {
463 PK11_FreeSlot(slot);
465 return safeInfo;
467 loser:
468 if (slot) {
469 PK11_FreeSlot(slot);
471 if(safeInfo->cinfo) {
472 SEC_PKCS7DestroyContentInfo(safeInfo->cinfo);
475 if(uniPwitem.data) {
476 SECITEM_ZfreeItem(&uniPwitem, PR_FALSE);
479 PORT_ArenaRelease(p12ctxt->arena, mark);
480 return NULL;
483 /* SEC_PKCS12CreateUnencryptedSafe
484 * Creates an unencrypted safe within the export context.
486 * p12ctxt - the export context
488 SEC_PKCS12SafeInfo *
489 SEC_PKCS12CreateUnencryptedSafe(SEC_PKCS12ExportContext *p12ctxt)
491 SEC_PKCS12SafeInfo *safeInfo = NULL;
492 void *mark = NULL;
494 if(!p12ctxt) {
495 return NULL;
498 /* create the safe info */
499 mark = PORT_ArenaMark(p12ctxt->arena);
500 safeInfo = (SEC_PKCS12SafeInfo *)PORT_ArenaZAlloc(p12ctxt->arena,
501 sizeof(SEC_PKCS12SafeInfo));
502 if(!safeInfo) {
503 PORT_ArenaRelease(p12ctxt->arena, mark);
504 PORT_SetError(SEC_ERROR_NO_MEMORY);
505 return NULL;
508 safeInfo->itemCount = 0;
510 /* create the safe content */
511 safeInfo->cinfo = SEC_PKCS7CreateData();
512 if(!safeInfo->cinfo) {
513 PORT_SetError(SEC_ERROR_NO_MEMORY);
514 goto loser;
517 if(sec_pkcs12_append_safe_info(p12ctxt, safeInfo) != SECSuccess) {
518 goto loser;
521 PORT_ArenaUnmark(p12ctxt->arena, mark);
522 return safeInfo;
524 loser:
525 if(safeInfo->cinfo) {
526 SEC_PKCS7DestroyContentInfo(safeInfo->cinfo);
529 PORT_ArenaRelease(p12ctxt->arena, mark);
530 return NULL;
533 /* SEC_PKCS12CreatePubKeyEncryptedSafe
534 * Creates a safe which is protected by public key encryption.
536 * p12ctxt - the export context
537 * certDb - the certificate database
538 * signer - the signer's certificate
539 * recipients - the list of recipient certificates.
540 * algorithm - the encryption algorithm to use
541 * keysize - the algorithms key size (?)
543 SEC_PKCS12SafeInfo *
544 SEC_PKCS12CreatePubKeyEncryptedSafe(SEC_PKCS12ExportContext *p12ctxt,
545 CERTCertDBHandle *certDb,
546 CERTCertificate *signer,
547 CERTCertificate **recipients,
548 SECOidTag algorithm, int keysize)
550 SEC_PKCS12SafeInfo *safeInfo = NULL;
551 void *mark = NULL;
553 if(!p12ctxt || !signer || !recipients || !(*recipients)) {
554 return NULL;
557 /* allocate the safeInfo */
558 mark = PORT_ArenaMark(p12ctxt->arena);
559 safeInfo = (SEC_PKCS12SafeInfo *)PORT_ArenaZAlloc(p12ctxt->arena,
560 sizeof(SEC_PKCS12SafeInfo));
561 if(!safeInfo) {
562 PORT_ArenaRelease(p12ctxt->arena, mark);
563 PORT_SetError(SEC_ERROR_NO_MEMORY);
564 return NULL;
567 safeInfo->itemCount = 0;
568 safeInfo->arena = p12ctxt->arena;
570 /* create the enveloped content info using certUsageEmailSigner currently.
571 * XXX We need to eventually use something other than certUsageEmailSigner
573 safeInfo->cinfo = SEC_PKCS7CreateEnvelopedData(signer, certUsageEmailSigner,
574 certDb, algorithm, keysize,
575 p12ctxt->pwfn, p12ctxt->pwfnarg);
576 if(!safeInfo->cinfo) {
577 PORT_SetError(SEC_ERROR_NO_MEMORY);
578 goto loser;
581 /* add recipients */
582 if(recipients) {
583 unsigned int i = 0;
584 while(recipients[i] != NULL) {
585 SECStatus rv = SEC_PKCS7AddRecipient(safeInfo->cinfo, recipients[i],
586 certUsageEmailRecipient, certDb);
587 if(rv != SECSuccess) {
588 goto loser;
590 i++;
594 if(sec_pkcs12_append_safe_info(p12ctxt, safeInfo) != SECSuccess) {
595 goto loser;
598 PORT_ArenaUnmark(p12ctxt->arena, mark);
599 return safeInfo;
601 loser:
602 if(safeInfo->cinfo) {
603 SEC_PKCS7DestroyContentInfo(safeInfo->cinfo);
604 safeInfo->cinfo = NULL;
607 PORT_ArenaRelease(p12ctxt->arena, mark);
608 return NULL;
611 /*********************************
612 * Routines to handle the exporting of the keys and certificates
613 *********************************/
615 /* creates a safe contents which safeBags will be appended to */
616 sec_PKCS12SafeContents *
617 sec_PKCS12CreateSafeContents(PRArenaPool *arena)
619 sec_PKCS12SafeContents *safeContents;
621 if(arena == NULL) {
622 return NULL;
625 /* create the safe contents */
626 safeContents = (sec_PKCS12SafeContents *)PORT_ArenaZAlloc(arena,
627 sizeof(sec_PKCS12SafeContents));
628 if(!safeContents) {
629 PORT_SetError(SEC_ERROR_NO_MEMORY);
630 goto loser;
633 /* set up the internal contents info */
634 safeContents->safeBags = NULL;
635 safeContents->arena = arena;
636 safeContents->bagCount = 0;
638 return safeContents;
640 loser:
641 return NULL;
644 /* appends a safe bag to a safeContents using the specified arena.
646 SECStatus
647 sec_pkcs12_append_bag_to_safe_contents(PRArenaPool *arena,
648 sec_PKCS12SafeContents *safeContents,
649 sec_PKCS12SafeBag *safeBag)
651 void *mark = NULL, *dummy = NULL;
653 if(!arena || !safeBag || !safeContents) {
654 return SECFailure;
657 mark = PORT_ArenaMark(arena);
658 if(!mark) {
659 PORT_SetError(SEC_ERROR_NO_MEMORY);
660 return SECFailure;
663 /* allocate space for the list, or reallocate to increase space */
664 if(!safeContents->safeBags) {
665 safeContents->safeBags = (sec_PKCS12SafeBag **)PORT_ArenaZAlloc(arena,
666 (2 * sizeof(sec_PKCS12SafeBag *)));
667 dummy = safeContents->safeBags;
668 safeContents->bagCount = 0;
669 } else {
670 dummy = PORT_ArenaGrow(arena, safeContents->safeBags,
671 (safeContents->bagCount + 1) * sizeof(sec_PKCS12SafeBag *),
672 (safeContents->bagCount + 2) * sizeof(sec_PKCS12SafeBag *));
673 safeContents->safeBags = (sec_PKCS12SafeBag **)dummy;
676 if(!dummy) {
677 PORT_ArenaRelease(arena, mark);
678 PORT_SetError(SEC_ERROR_NO_MEMORY);
679 return SECFailure;
682 /* append the bag at the end and null terminate the list */
683 safeContents->safeBags[safeContents->bagCount++] = safeBag;
684 safeContents->safeBags[safeContents->bagCount] = NULL;
686 PORT_ArenaUnmark(arena, mark);
688 return SECSuccess;
691 /* appends a safeBag to a specific safeInfo.
693 SECStatus
694 sec_pkcs12_append_bag(SEC_PKCS12ExportContext *p12ctxt,
695 SEC_PKCS12SafeInfo *safeInfo, sec_PKCS12SafeBag *safeBag)
697 sec_PKCS12SafeContents *dest;
698 SECStatus rv = SECFailure;
700 if(!p12ctxt || !safeBag || !safeInfo) {
701 return SECFailure;
704 if(!safeInfo->safe) {
705 safeInfo->safe = sec_PKCS12CreateSafeContents(p12ctxt->arena);
706 if(!safeInfo->safe) {
707 return SECFailure;
711 dest = safeInfo->safe;
712 rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena, dest, safeBag);
713 if(rv == SECSuccess) {
714 safeInfo->itemCount++;
717 return rv;
720 /* Creates a safeBag of the specified type, and if bagData is specified,
721 * the contents are set. The contents could be set later by the calling
722 * routine.
724 sec_PKCS12SafeBag *
725 sec_PKCS12CreateSafeBag(SEC_PKCS12ExportContext *p12ctxt, SECOidTag bagType,
726 void *bagData)
728 sec_PKCS12SafeBag *safeBag;
729 PRBool setName = PR_TRUE;
730 void *mark = NULL;
731 SECStatus rv = SECSuccess;
732 SECOidData *oidData = NULL;
734 if(!p12ctxt) {
735 return NULL;
738 mark = PORT_ArenaMark(p12ctxt->arena);
739 if(!mark) {
740 PORT_SetError(SEC_ERROR_NO_MEMORY);
741 return NULL;
744 safeBag = (sec_PKCS12SafeBag *)PORT_ArenaZAlloc(p12ctxt->arena,
745 sizeof(sec_PKCS12SafeBag));
746 if(!safeBag) {
747 PORT_ArenaRelease(p12ctxt->arena, mark);
748 PORT_SetError(SEC_ERROR_NO_MEMORY);
749 return NULL;
752 /* set the bags content based upon bag type */
753 switch(bagType) {
754 case SEC_OID_PKCS12_V1_KEY_BAG_ID:
755 safeBag->safeBagContent.pkcs8KeyBag =
756 (SECKEYPrivateKeyInfo *)bagData;
757 break;
758 case SEC_OID_PKCS12_V1_CERT_BAG_ID:
759 safeBag->safeBagContent.certBag = (sec_PKCS12CertBag *)bagData;
760 break;
761 case SEC_OID_PKCS12_V1_CRL_BAG_ID:
762 safeBag->safeBagContent.crlBag = (sec_PKCS12CRLBag *)bagData;
763 break;
764 case SEC_OID_PKCS12_V1_SECRET_BAG_ID:
765 safeBag->safeBagContent.secretBag = (sec_PKCS12SecretBag *)bagData;
766 break;
767 case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
768 safeBag->safeBagContent.pkcs8ShroudedKeyBag =
769 (SECKEYEncryptedPrivateKeyInfo *)bagData;
770 break;
771 case SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID:
772 safeBag->safeBagContent.safeContents =
773 (sec_PKCS12SafeContents *)bagData;
774 setName = PR_FALSE;
775 break;
776 default:
777 goto loser;
780 oidData = SECOID_FindOIDByTag(bagType);
781 if(oidData) {
782 rv = SECITEM_CopyItem(p12ctxt->arena, &safeBag->safeBagType, &oidData->oid);
783 if(rv != SECSuccess) {
784 PORT_SetError(SEC_ERROR_NO_MEMORY);
785 goto loser;
787 } else {
788 goto loser;
791 safeBag->arena = p12ctxt->arena;
792 PORT_ArenaUnmark(p12ctxt->arena, mark);
794 return safeBag;
796 loser:
797 if(mark) {
798 PORT_ArenaRelease(p12ctxt->arena, mark);
801 return NULL;
804 /* Creates a new certificate bag and returns a pointer to it. If an error
805 * occurs NULL is returned.
807 sec_PKCS12CertBag *
808 sec_PKCS12NewCertBag(PRArenaPool *arena, SECOidTag certType)
810 sec_PKCS12CertBag *certBag = NULL;
811 SECOidData *bagType = NULL;
812 SECStatus rv;
813 void *mark = NULL;
815 if(!arena) {
816 return NULL;
819 mark = PORT_ArenaMark(arena);
820 certBag = (sec_PKCS12CertBag *)PORT_ArenaZAlloc(arena,
821 sizeof(sec_PKCS12CertBag));
822 if(!certBag) {
823 PORT_ArenaRelease(arena, mark);
824 PORT_SetError(SEC_ERROR_NO_MEMORY);
825 return NULL;
828 bagType = SECOID_FindOIDByTag(certType);
829 if(!bagType) {
830 PORT_SetError(SEC_ERROR_NO_MEMORY);
831 goto loser;
834 rv = SECITEM_CopyItem(arena, &certBag->bagID, &bagType->oid);
835 if(rv != SECSuccess) {
836 PORT_SetError(SEC_ERROR_NO_MEMORY);
837 goto loser;
840 PORT_ArenaUnmark(arena, mark);
841 return certBag;
843 loser:
844 PORT_ArenaRelease(arena, mark);
845 return NULL;
848 /* Creates a new CRL bag and returns a pointer to it. If an error
849 * occurs NULL is returned.
851 sec_PKCS12CRLBag *
852 sec_PKCS12NewCRLBag(PRArenaPool *arena, SECOidTag crlType)
854 sec_PKCS12CRLBag *crlBag = NULL;
855 SECOidData *bagType = NULL;
856 SECStatus rv;
857 void *mark = NULL;
859 if(!arena) {
860 return NULL;
863 mark = PORT_ArenaMark(arena);
864 crlBag = (sec_PKCS12CRLBag *)PORT_ArenaZAlloc(arena,
865 sizeof(sec_PKCS12CRLBag));
866 if(!crlBag) {
867 PORT_ArenaRelease(arena, mark);
868 PORT_SetError(SEC_ERROR_NO_MEMORY);
869 return NULL;
872 bagType = SECOID_FindOIDByTag(crlType);
873 if(!bagType) {
874 PORT_SetError(SEC_ERROR_NO_MEMORY);
875 goto loser;
878 rv = SECITEM_CopyItem(arena, &crlBag->bagID, &bagType->oid);
879 if(rv != SECSuccess) {
880 PORT_SetError(SEC_ERROR_NO_MEMORY);
881 goto loser;
884 PORT_ArenaUnmark(arena, mark);
885 return crlBag;
887 loser:
888 PORT_ArenaRelease(arena, mark);
889 return NULL;
892 /* sec_PKCS12AddAttributeToBag
893 * adds an attribute to a safeBag. currently, the only attributes supported
894 * are those which are specified within PKCS 12.
896 * p12ctxt - the export context
897 * safeBag - the safeBag to which attributes are appended
898 * attrType - the attribute type
899 * attrData - the attribute data
901 SECStatus
902 sec_PKCS12AddAttributeToBag(SEC_PKCS12ExportContext *p12ctxt,
903 sec_PKCS12SafeBag *safeBag, SECOidTag attrType,
904 SECItem *attrData)
906 sec_PKCS12Attribute *attribute;
907 void *mark = NULL, *dummy = NULL;
908 SECOidData *oiddata = NULL;
909 SECItem unicodeName = { siBuffer, NULL, 0};
910 void *src = NULL;
911 unsigned int nItems = 0;
912 SECStatus rv;
914 if(!safeBag || !p12ctxt) {
915 return SECFailure;
918 mark = PORT_ArenaMark(safeBag->arena);
920 /* allocate the attribute */
921 attribute = (sec_PKCS12Attribute *)PORT_ArenaZAlloc(safeBag->arena,
922 sizeof(sec_PKCS12Attribute));
923 if(!attribute) {
924 PORT_SetError(SEC_ERROR_NO_MEMORY);
925 goto loser;
928 /* set up the attribute */
929 oiddata = SECOID_FindOIDByTag(attrType);
930 if(!oiddata) {
931 PORT_SetError(SEC_ERROR_NO_MEMORY);
932 goto loser;
934 if(SECITEM_CopyItem(p12ctxt->arena, &attribute->attrType, &oiddata->oid) !=
935 SECSuccess) {
936 PORT_SetError(SEC_ERROR_NO_MEMORY);
937 goto loser;
940 nItems = 1;
941 switch(attrType) {
942 case SEC_OID_PKCS9_LOCAL_KEY_ID:
944 src = attrData;
945 break;
947 case SEC_OID_PKCS9_FRIENDLY_NAME:
949 if(!sec_pkcs12_convert_item_to_unicode(p12ctxt->arena,
950 &unicodeName, attrData, PR_FALSE,
951 PR_FALSE, PR_TRUE)) {
952 goto loser;
954 src = &unicodeName;
955 break;
957 default:
958 goto loser;
961 /* append the attribute to the attribute value list */
962 attribute->attrValue = (SECItem **)PORT_ArenaZAlloc(p12ctxt->arena,
963 ((nItems + 1) * sizeof(SECItem *)));
964 if(!attribute->attrValue) {
965 PORT_SetError(SEC_ERROR_NO_MEMORY);
966 goto loser;
969 /* XXX this will need to be changed if attributes requiring more than
970 * one element are ever used.
972 attribute->attrValue[0] = (SECItem *)PORT_ArenaZAlloc(p12ctxt->arena,
973 sizeof(SECItem));
974 if(!attribute->attrValue[0]) {
975 PORT_SetError(SEC_ERROR_NO_MEMORY);
976 goto loser;
978 attribute->attrValue[1] = NULL;
980 rv = SECITEM_CopyItem(p12ctxt->arena, attribute->attrValue[0],
981 (SECItem*)src);
982 if(rv != SECSuccess) {
983 PORT_SetError(SEC_ERROR_NO_MEMORY);
984 goto loser;
987 /* append the attribute to the safeBag attributes */
988 if(safeBag->nAttribs) {
989 dummy = PORT_ArenaGrow(p12ctxt->arena, safeBag->attribs,
990 ((safeBag->nAttribs + 1) * sizeof(sec_PKCS12Attribute *)),
991 ((safeBag->nAttribs + 2) * sizeof(sec_PKCS12Attribute *)));
992 safeBag->attribs = (sec_PKCS12Attribute **)dummy;
993 } else {
994 safeBag->attribs = (sec_PKCS12Attribute **)PORT_ArenaZAlloc(p12ctxt->arena,
995 2 * sizeof(sec_PKCS12Attribute *));
996 dummy = safeBag->attribs;
998 if(!dummy) {
999 goto loser;
1002 safeBag->attribs[safeBag->nAttribs] = attribute;
1003 safeBag->attribs[++safeBag->nAttribs] = NULL;
1005 PORT_ArenaUnmark(p12ctxt->arena, mark);
1006 return SECSuccess;
1008 loser:
1009 if(mark) {
1010 PORT_ArenaRelease(p12ctxt->arena, mark);
1013 return SECFailure;
1016 /* SEC_PKCS12AddCert
1017 * Adds a certificate to the data being exported.
1019 * p12ctxt - the export context
1020 * safe - the safeInfo to which the certificate is placed
1021 * nestedDest - if the cert is to be placed within a nested safeContents then,
1022 * this value is to be specified with the destination
1023 * cert - the cert to export
1024 * certDb - the certificate database handle
1025 * keyId - a unique identifier to associate a certificate/key pair
1026 * includeCertChain - PR_TRUE if the certificate chain is to be included.
1028 SECStatus
1029 SEC_PKCS12AddCert(SEC_PKCS12ExportContext *p12ctxt, SEC_PKCS12SafeInfo *safe,
1030 void *nestedDest, CERTCertificate *cert,
1031 CERTCertDBHandle *certDb, SECItem *keyId,
1032 PRBool includeCertChain)
1034 sec_PKCS12CertBag *certBag;
1035 sec_PKCS12SafeBag *safeBag;
1036 void *mark;
1037 SECStatus rv;
1038 SECItem nick = {siBuffer, NULL,0};
1040 if(!p12ctxt || !cert) {
1041 return SECFailure;
1043 mark = PORT_ArenaMark(p12ctxt->arena);
1045 /* allocate the cert bag */
1046 certBag = sec_PKCS12NewCertBag(p12ctxt->arena,
1047 SEC_OID_PKCS9_X509_CERT);
1048 if(!certBag) {
1049 goto loser;
1052 if(SECITEM_CopyItem(p12ctxt->arena, &certBag->value.x509Cert,
1053 &cert->derCert) != SECSuccess) {
1054 PORT_SetError(SEC_ERROR_NO_MEMORY);
1055 goto loser;
1058 /* if the cert chain is to be included, we should only be exporting
1059 * the cert from our internal database.
1061 if(includeCertChain) {
1062 CERTCertificateList *certList = CERT_CertChainFromCert(cert,
1063 certUsageSSLClient,
1064 PR_TRUE);
1065 unsigned int count = 0;
1066 if(!certList) {
1067 PORT_SetError(SEC_ERROR_NO_MEMORY);
1068 goto loser;
1071 /* add cert chain */
1072 for(count = 0; count < (unsigned int)certList->len; count++) {
1073 if(SECITEM_CompareItem(&certList->certs[count], &cert->derCert)
1074 != SECEqual) {
1075 CERTCertificate *tempCert;
1077 /* decode the certificate */
1078 /* XXX
1079 * This was rather silly. The chain is constructed above
1080 * by finding all of the CERTCertificate's in the database.
1081 * Then the chain is put into a CERTCertificateList, which only
1082 * contains the DER. Finally, the DER was decoded, and the
1083 * decoded cert was sent recursively back to this function.
1084 * Beyond being inefficent, this causes data loss (specifically,
1085 * the nickname). Instead, for 3.4, we'll do a lookup by the
1086 * DER, which should return the cached entry.
1088 tempCert = CERT_FindCertByDERCert(CERT_GetDefaultCertDB(),
1089 &certList->certs[count]);
1090 if(!tempCert) {
1091 CERT_DestroyCertificateList(certList);
1092 goto loser;
1095 /* add the certificate */
1096 if(SEC_PKCS12AddCert(p12ctxt, safe, nestedDest, tempCert,
1097 certDb, NULL, PR_FALSE) != SECSuccess) {
1098 CERT_DestroyCertificate(tempCert);
1099 CERT_DestroyCertificateList(certList);
1100 goto loser;
1102 CERT_DestroyCertificate(tempCert);
1105 CERT_DestroyCertificateList(certList);
1108 /* if the certificate has a nickname, we will set the friendly name
1109 * to that.
1111 if(cert->nickname) {
1112 if (cert->slot && !PK11_IsInternal(cert->slot)) {
1114 * The cert is coming off of an external token,
1115 * let's strip the token name from the nickname
1116 * and only add what comes after the colon as the
1117 * nickname. -javi
1119 char *delimit;
1121 delimit = PORT_Strchr(cert->nickname,':');
1122 if (delimit == NULL) {
1123 nick.data = (unsigned char *)cert->nickname;
1124 nick.len = PORT_Strlen(cert->nickname);
1125 } else {
1126 delimit++;
1127 nick.data = (unsigned char *)PORT_ArenaStrdup(p12ctxt->arena,
1128 delimit);
1129 nick.len = PORT_Strlen(delimit);
1131 } else {
1132 nick.data = (unsigned char *)cert->nickname;
1133 nick.len = PORT_Strlen(cert->nickname);
1137 safeBag = sec_PKCS12CreateSafeBag(p12ctxt, SEC_OID_PKCS12_V1_CERT_BAG_ID,
1138 certBag);
1139 if(!safeBag) {
1140 goto loser;
1143 /* add the friendly name and keyId attributes, if necessary */
1144 if(nick.data) {
1145 if(sec_PKCS12AddAttributeToBag(p12ctxt, safeBag,
1146 SEC_OID_PKCS9_FRIENDLY_NAME, &nick)
1147 != SECSuccess) {
1148 goto loser;
1152 if(keyId) {
1153 if(sec_PKCS12AddAttributeToBag(p12ctxt, safeBag, SEC_OID_PKCS9_LOCAL_KEY_ID,
1154 keyId) != SECSuccess) {
1155 goto loser;
1159 /* append the cert safeBag */
1160 if(nestedDest) {
1161 rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena,
1162 (sec_PKCS12SafeContents*)nestedDest,
1163 safeBag);
1164 } else {
1165 rv = sec_pkcs12_append_bag(p12ctxt, safe, safeBag);
1168 if(rv != SECSuccess) {
1169 goto loser;
1172 PORT_ArenaUnmark(p12ctxt->arena, mark);
1173 return SECSuccess;
1175 loser:
1176 if(mark) {
1177 PORT_ArenaRelease(p12ctxt->arena, mark);
1180 return SECFailure;
1183 /* SEC_PKCS12AddEncryptedKey
1184 * Extracts the key associated with a particular certificate and exports
1185 * it.
1187 * p12ctxt - the export context
1188 * safe - the safeInfo to place the key in
1189 * nestedDest - the nested safeContents to place a key
1190 * cert - the certificate which the key belongs to
1191 * shroudKey - encrypt the private key for export. This value should
1192 * always be true. lower level code will not allow the export
1193 * of unencrypted private keys.
1194 * algorithm - the algorithm with which to encrypt the private key
1195 * pwitem - the password to encrypted the private key with
1196 * keyId - the keyID attribute
1197 * nickName - the nickname attribute
1199 static SECStatus
1200 SEC_PKCS12AddEncryptedKey(SEC_PKCS12ExportContext *p12ctxt,
1201 SECKEYEncryptedPrivateKeyInfo *epki, SEC_PKCS12SafeInfo *safe,
1202 void *nestedDest, SECItem *keyId, SECItem *nickName)
1204 void *mark;
1205 void *keyItem;
1206 SECOidTag keyType;
1207 SECStatus rv = SECFailure;
1208 sec_PKCS12SafeBag *returnBag;
1210 if(!p12ctxt || !safe || !epki) {
1211 return SECFailure;
1214 mark = PORT_ArenaMark(p12ctxt->arena);
1216 keyItem = PORT_ArenaZAlloc(p12ctxt->arena,
1217 sizeof(SECKEYEncryptedPrivateKeyInfo));
1218 if(!keyItem) {
1219 PORT_SetError(SEC_ERROR_NO_MEMORY);
1220 goto loser;
1223 rv = SECKEY_CopyEncryptedPrivateKeyInfo(p12ctxt->arena,
1224 (SECKEYEncryptedPrivateKeyInfo *)keyItem,
1225 epki);
1226 keyType = SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID;
1228 if(rv != SECSuccess) {
1229 goto loser;
1232 /* create the safe bag and set any attributes */
1233 returnBag = sec_PKCS12CreateSafeBag(p12ctxt, keyType, keyItem);
1234 if(!returnBag) {
1235 rv = SECFailure;
1236 goto loser;
1239 if(nickName) {
1240 if(sec_PKCS12AddAttributeToBag(p12ctxt, returnBag,
1241 SEC_OID_PKCS9_FRIENDLY_NAME, nickName)
1242 != SECSuccess) {
1243 goto loser;
1247 if(keyId) {
1248 if(sec_PKCS12AddAttributeToBag(p12ctxt, returnBag,
1249 SEC_OID_PKCS9_LOCAL_KEY_ID,
1250 keyId) != SECSuccess) {
1251 goto loser;
1255 if(nestedDest) {
1256 rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena,
1257 (sec_PKCS12SafeContents*)nestedDest,
1258 returnBag);
1259 } else {
1260 rv = sec_pkcs12_append_bag(p12ctxt, safe, returnBag);
1263 loser:
1265 if (rv != SECSuccess) {
1266 PORT_ArenaRelease(p12ctxt->arena, mark);
1267 } else {
1268 PORT_ArenaUnmark(p12ctxt->arena, mark);
1271 return rv;
1274 /* SEC_PKCS12AddKeyForCert
1275 * Extracts the key associated with a particular certificate and exports
1276 * it.
1278 * p12ctxt - the export context
1279 * safe - the safeInfo to place the key in
1280 * nestedDest - the nested safeContents to place a key
1281 * cert - the certificate which the key belongs to
1282 * shroudKey - encrypt the private key for export. This value should
1283 * always be true. lower level code will not allow the export
1284 * of unencrypted private keys.
1285 * algorithm - the algorithm with which to encrypt the private key
1286 * pwitem - the password to encrypt the private key with
1287 * keyId - the keyID attribute
1288 * nickName - the nickname attribute
1290 SECStatus
1291 SEC_PKCS12AddKeyForCert(SEC_PKCS12ExportContext *p12ctxt, SEC_PKCS12SafeInfo *safe,
1292 void *nestedDest, CERTCertificate *cert,
1293 PRBool shroudKey, SECOidTag algorithm, SECItem *pwitem,
1294 SECItem *keyId, SECItem *nickName)
1296 void *mark;
1297 void *keyItem;
1298 SECOidTag keyType;
1299 SECStatus rv = SECFailure;
1300 SECItem nickname = {siBuffer,NULL,0}, uniPwitem = {siBuffer, NULL, 0};
1301 sec_PKCS12SafeBag *returnBag;
1303 if(!p12ctxt || !cert || !safe) {
1304 return SECFailure;
1307 mark = PORT_ArenaMark(p12ctxt->arena);
1309 /* retrieve the key based upon the type that it is and
1310 * specify the type of safeBag to store the key in
1312 if(!shroudKey) {
1314 /* extract the key unencrypted. this will most likely go away */
1315 SECKEYPrivateKeyInfo *pki = PK11_ExportPrivateKeyInfo(cert,
1316 p12ctxt->wincx);
1317 if(!pki) {
1318 PORT_ArenaRelease(p12ctxt->arena, mark);
1319 PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY);
1320 return SECFailure;
1322 keyItem = PORT_ArenaZAlloc(p12ctxt->arena, sizeof(SECKEYPrivateKeyInfo));
1323 if(!keyItem) {
1324 PORT_SetError(SEC_ERROR_NO_MEMORY);
1325 goto loser;
1327 rv = SECKEY_CopyPrivateKeyInfo(p12ctxt->arena,
1328 (SECKEYPrivateKeyInfo *)keyItem, pki);
1329 keyType = SEC_OID_PKCS12_V1_KEY_BAG_ID;
1330 SECKEY_DestroyPrivateKeyInfo(pki, PR_TRUE);
1331 } else {
1333 /* extract the key encrypted */
1334 SECKEYEncryptedPrivateKeyInfo *epki = NULL;
1335 PK11SlotInfo *slot = NULL;
1337 if(!sec_pkcs12_convert_item_to_unicode(p12ctxt->arena, &uniPwitem,
1338 pwitem, PR_TRUE, PR_TRUE, PR_TRUE)) {
1339 PORT_SetError(SEC_ERROR_NO_MEMORY);
1340 goto loser;
1343 /* we want to make sure to take the key out of the key slot */
1344 if(PK11_IsInternal(p12ctxt->slot)) {
1345 slot = PK11_GetInternalKeySlot();
1346 } else {
1347 slot = PK11_ReferenceSlot(p12ctxt->slot);
1350 epki = PK11_ExportEncryptedPrivateKeyInfo(slot, algorithm,
1351 &uniPwitem, cert, 1,
1352 p12ctxt->wincx);
1353 PK11_FreeSlot(slot);
1355 keyItem = PORT_ArenaZAlloc(p12ctxt->arena,
1356 sizeof(SECKEYEncryptedPrivateKeyInfo));
1357 if(!keyItem) {
1358 PORT_SetError(SEC_ERROR_NO_MEMORY);
1359 goto loser;
1361 if(!epki) {
1362 PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY);
1363 return SECFailure;
1365 rv = SECKEY_CopyEncryptedPrivateKeyInfo(p12ctxt->arena,
1366 (SECKEYEncryptedPrivateKeyInfo *)keyItem,
1367 epki);
1368 keyType = SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID;
1369 SECKEY_DestroyEncryptedPrivateKeyInfo(epki, PR_TRUE);
1372 if(rv != SECSuccess) {
1373 goto loser;
1376 /* if no nickname specified, let's see if the certificate has a
1377 * nickname.
1379 if(!nickName) {
1380 if(cert->nickname) {
1381 nickname.data = (unsigned char *)cert->nickname;
1382 nickname.len = PORT_Strlen(cert->nickname);
1383 nickName = &nickname;
1387 /* create the safe bag and set any attributes */
1388 returnBag = sec_PKCS12CreateSafeBag(p12ctxt, keyType, keyItem);
1389 if(!returnBag) {
1390 rv = SECFailure;
1391 goto loser;
1394 if(nickName) {
1395 if(sec_PKCS12AddAttributeToBag(p12ctxt, returnBag,
1396 SEC_OID_PKCS9_FRIENDLY_NAME, nickName)
1397 != SECSuccess) {
1398 goto loser;
1402 if(keyId) {
1403 if(sec_PKCS12AddAttributeToBag(p12ctxt, returnBag, SEC_OID_PKCS9_LOCAL_KEY_ID,
1404 keyId) != SECSuccess) {
1405 goto loser;
1409 if(nestedDest) {
1410 rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena,
1411 (sec_PKCS12SafeContents*)nestedDest,
1412 returnBag);
1413 } else {
1414 rv = sec_pkcs12_append_bag(p12ctxt, safe, returnBag);
1417 loser:
1419 if (rv != SECSuccess) {
1420 PORT_ArenaRelease(p12ctxt->arena, mark);
1421 } else {
1422 PORT_ArenaUnmark(p12ctxt->arena, mark);
1425 return rv;
1428 /* SEC_PKCS12AddCertAndEncryptedKey
1429 * Add a certificate and key pair to be exported.
1431 * p12ctxt - the export context
1432 * certSafe - the safeInfo where the cert is stored
1433 * certNestedDest - the nested safeContents to store the cert
1434 * keySafe - the safeInfo where the key is stored
1435 * keyNestedDest - the nested safeContents to store the key
1436 * shroudKey - extract the private key encrypted?
1437 * pwitem - the password with which the key is encrypted
1438 * algorithm - the algorithm with which the key is encrypted
1440 SECStatus
1441 SEC_PKCS12AddDERCertAndEncryptedKey(SEC_PKCS12ExportContext *p12ctxt,
1442 void *certSafe, void *certNestedDest,
1443 SECItem *derCert, void *keySafe,
1444 void *keyNestedDest, SECKEYEncryptedPrivateKeyInfo *epki,
1445 char *nickname)
1447 SECStatus rv = SECFailure;
1448 SGNDigestInfo *digest = NULL;
1449 void *mark = NULL;
1450 CERTCertificate *cert;
1451 SECItem nick = {siBuffer, NULL,0}, *nickPtr = NULL;
1453 if(!p12ctxt || !certSafe || !keySafe || !derCert) {
1454 return SECFailure;
1457 mark = PORT_ArenaMark(p12ctxt->arena);
1459 cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
1460 derCert, NULL, PR_FALSE, PR_FALSE);
1461 if(!cert) {
1462 PORT_ArenaRelease(p12ctxt->arena, mark);
1463 PORT_SetError(SEC_ERROR_NO_MEMORY);
1464 return SECFailure;
1466 cert->nickname = nickname;
1468 /* generate the thumbprint of the cert to use as a keyId */
1469 digest = sec_pkcs12_compute_thumbprint(&cert->derCert);
1470 if(!digest) {
1471 CERT_DestroyCertificate(cert);
1472 return SECFailure;
1475 /* add the certificate */
1476 rv = SEC_PKCS12AddCert(p12ctxt, (SEC_PKCS12SafeInfo*)certSafe,
1477 certNestedDest, cert, NULL,
1478 &digest->digest, PR_FALSE);
1479 if(rv != SECSuccess) {
1480 goto loser;
1483 if(nickname) {
1484 nick.data = (unsigned char *)nickname;
1485 nick.len = PORT_Strlen(nickname);
1486 nickPtr = &nick;
1487 } else {
1488 nickPtr = NULL;
1491 /* add the key */
1492 rv = SEC_PKCS12AddEncryptedKey(p12ctxt, epki, (SEC_PKCS12SafeInfo*)keySafe,
1493 keyNestedDest, &digest->digest, nickPtr );
1494 if(rv != SECSuccess) {
1495 goto loser;
1498 SGN_DestroyDigestInfo(digest);
1500 PORT_ArenaUnmark(p12ctxt->arena, mark);
1501 return SECSuccess;
1503 loser:
1504 SGN_DestroyDigestInfo(digest);
1505 CERT_DestroyCertificate(cert);
1506 PORT_ArenaRelease(p12ctxt->arena, mark);
1508 return SECFailure;
1511 /* SEC_PKCS12AddCertAndKey
1512 * Add a certificate and key pair to be exported.
1514 * p12ctxt - the export context
1515 * certSafe - the safeInfo where the cert is stored
1516 * certNestedDest - the nested safeContents to store the cert
1517 * keySafe - the safeInfo where the key is stored
1518 * keyNestedDest - the nested safeContents to store the key
1519 * shroudKey - extract the private key encrypted?
1520 * pwitem - the password with which the key is encrypted
1521 * algorithm - the algorithm with which the key is encrypted
1523 SECStatus
1524 SEC_PKCS12AddCertAndKey(SEC_PKCS12ExportContext *p12ctxt,
1525 void *certSafe, void *certNestedDest,
1526 CERTCertificate *cert, CERTCertDBHandle *certDb,
1527 void *keySafe, void *keyNestedDest,
1528 PRBool shroudKey, SECItem *pwitem, SECOidTag algorithm)
1530 SECStatus rv = SECFailure;
1531 SGNDigestInfo *digest = NULL;
1532 void *mark = NULL;
1534 if(!p12ctxt || !certSafe || !keySafe || !cert) {
1535 return SECFailure;
1538 mark = PORT_ArenaMark(p12ctxt->arena);
1540 /* generate the thumbprint of the cert to use as a keyId */
1541 digest = sec_pkcs12_compute_thumbprint(&cert->derCert);
1542 if(!digest) {
1543 PORT_ArenaRelease(p12ctxt->arena, mark);
1544 return SECFailure;
1547 /* add the certificate */
1548 rv = SEC_PKCS12AddCert(p12ctxt, (SEC_PKCS12SafeInfo*)certSafe,
1549 (SEC_PKCS12SafeInfo*)certNestedDest, cert, certDb,
1550 &digest->digest, PR_TRUE);
1551 if(rv != SECSuccess) {
1552 goto loser;
1555 /* add the key */
1556 rv = SEC_PKCS12AddKeyForCert(p12ctxt, (SEC_PKCS12SafeInfo*)keySafe,
1557 keyNestedDest, cert,
1558 shroudKey, algorithm, pwitem,
1559 &digest->digest, NULL );
1560 if(rv != SECSuccess) {
1561 goto loser;
1564 SGN_DestroyDigestInfo(digest);
1566 PORT_ArenaUnmark(p12ctxt->arena, mark);
1567 return SECSuccess;
1569 loser:
1570 SGN_DestroyDigestInfo(digest);
1571 PORT_ArenaRelease(p12ctxt->arena, mark);
1573 return SECFailure;
1576 /* SEC_PKCS12CreateNestedSafeContents
1577 * Allows nesting of safe contents to be implemented. No limit imposed on
1578 * depth.
1580 * p12ctxt - the export context
1581 * baseSafe - the base safeInfo
1582 * nestedDest - a parent safeContents (?)
1584 void *
1585 SEC_PKCS12CreateNestedSafeContents(SEC_PKCS12ExportContext *p12ctxt,
1586 void *baseSafe, void *nestedDest)
1588 sec_PKCS12SafeContents *newSafe;
1589 sec_PKCS12SafeBag *safeContentsBag;
1590 void *mark;
1591 SECStatus rv;
1593 if(!p12ctxt || !baseSafe) {
1594 return NULL;
1597 mark = PORT_ArenaMark(p12ctxt->arena);
1599 newSafe = sec_PKCS12CreateSafeContents(p12ctxt->arena);
1600 if(!newSafe) {
1601 PORT_ArenaRelease(p12ctxt->arena, mark);
1602 PORT_SetError(SEC_ERROR_NO_MEMORY);
1603 return NULL;
1606 /* create the safeContents safeBag */
1607 safeContentsBag = sec_PKCS12CreateSafeBag(p12ctxt,
1608 SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID,
1609 newSafe);
1610 if(!safeContentsBag) {
1611 goto loser;
1614 /* append the safeContents to the appropriate area */
1615 if(nestedDest) {
1616 rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena,
1617 (sec_PKCS12SafeContents*)nestedDest,
1618 safeContentsBag);
1619 } else {
1620 rv = sec_pkcs12_append_bag(p12ctxt, (SEC_PKCS12SafeInfo*)baseSafe,
1621 safeContentsBag);
1623 if(rv != SECSuccess) {
1624 goto loser;
1627 PORT_ArenaUnmark(p12ctxt->arena, mark);
1628 return newSafe;
1630 loser:
1631 PORT_ArenaRelease(p12ctxt->arena, mark);
1632 return NULL;
1635 /*********************************
1636 * Encoding routines
1637 *********************************/
1639 /* set up the encoder context based on information in the export context
1640 * and return the newly allocated enocoder context. A return of NULL
1641 * indicates an error occurred.
1643 sec_PKCS12EncoderContext *
1644 sec_pkcs12_encoder_start_context(SEC_PKCS12ExportContext *p12exp)
1646 sec_PKCS12EncoderContext *p12enc = NULL;
1647 unsigned int i, nonEmptyCnt;
1648 SECStatus rv;
1649 SECItem ignore = {0};
1650 void *mark;
1652 if(!p12exp || !p12exp->safeInfos) {
1653 return NULL;
1656 /* check for any empty safes and skip them */
1657 i = nonEmptyCnt = 0;
1658 while(p12exp->safeInfos[i]) {
1659 if(p12exp->safeInfos[i]->itemCount) {
1660 nonEmptyCnt++;
1662 i++;
1664 if(nonEmptyCnt == 0) {
1665 return NULL;
1667 p12exp->authSafe.encodedSafes[nonEmptyCnt] = NULL;
1669 /* allocate the encoder context */
1670 mark = PORT_ArenaMark(p12exp->arena);
1671 p12enc = PORT_ArenaZNew(p12exp->arena, sec_PKCS12EncoderContext);
1672 if(!p12enc) {
1673 PORT_SetError(SEC_ERROR_NO_MEMORY);
1674 return NULL;
1677 p12enc->arena = p12exp->arena;
1678 p12enc->p12exp = p12exp;
1680 /* set up the PFX version and information */
1681 PORT_Memset(&p12enc->pfx, 0, sizeof(sec_PKCS12PFXItem));
1682 if(!SEC_ASN1EncodeInteger(p12exp->arena, &(p12enc->pfx.version),
1683 SEC_PKCS12_VERSION) ) {
1684 PORT_SetError(SEC_ERROR_NO_MEMORY);
1685 goto loser;
1688 /* set up the authenticated safe content info based on the
1689 * type of integrity being used. this should be changed to
1690 * enforce integrity mode, but will not be implemented until
1691 * it is confirmed that integrity must be in place
1693 if(p12exp->integrityEnabled && !p12exp->pwdIntegrity) {
1694 SECStatus rv;
1696 /* create public key integrity mode */
1697 p12enc->aSafeCinfo = SEC_PKCS7CreateSignedData(
1698 p12exp->integrityInfo.pubkeyInfo.cert,
1699 certUsageEmailSigner,
1700 p12exp->integrityInfo.pubkeyInfo.certDb,
1701 p12exp->integrityInfo.pubkeyInfo.algorithm,
1702 NULL,
1703 p12exp->pwfn,
1704 p12exp->pwfnarg);
1705 if(!p12enc->aSafeCinfo) {
1706 goto loser;
1708 if(SEC_PKCS7IncludeCertChain(p12enc->aSafeCinfo,NULL) != SECSuccess) {
1709 goto loser;
1711 rv = SEC_PKCS7AddSigningTime(p12enc->aSafeCinfo);
1712 PORT_Assert(rv == SECSuccess);
1713 } else {
1714 p12enc->aSafeCinfo = SEC_PKCS7CreateData();
1716 /* init password pased integrity mode */
1717 if(p12exp->integrityEnabled) {
1718 SECItem pwd = {siBuffer,NULL, 0};
1719 SECItem *salt = sec_pkcs12_generate_salt();
1720 PK11SymKey *symKey;
1721 SECItem *params;
1722 CK_MECHANISM_TYPE integrityMechType;
1723 CK_MECHANISM_TYPE hmacMechType;
1725 /* zero out macData and set values */
1726 PORT_Memset(&p12enc->mac, 0, sizeof(sec_PKCS12MacData));
1728 if(!salt) {
1729 PORT_SetError(SEC_ERROR_NO_MEMORY);
1730 goto loser;
1732 if(SECITEM_CopyItem(p12exp->arena, &(p12enc->mac.macSalt), salt)
1733 != SECSuccess) {
1734 PORT_SetError(SEC_ERROR_NO_MEMORY);
1735 goto loser;
1738 /* generate HMAC key */
1739 if(!sec_pkcs12_convert_item_to_unicode(NULL, &pwd,
1740 p12exp->integrityInfo.pwdInfo.password, PR_TRUE,
1741 PR_TRUE, PR_TRUE)) {
1742 goto loser;
1745 * This code only works with PKCS #12 Mac using PKCS #5 v1
1746 * PBA keygens. PKCS #5 v2 support will require a change to
1747 * the PKCS #12 spec.
1749 params = PK11_CreatePBEParams(salt, &pwd, 1);
1750 SECITEM_ZfreeItem(salt, PR_TRUE);
1751 SECITEM_ZfreeItem(&pwd, PR_FALSE);
1753 /* get the PBA Mechanism to generate the key */
1754 switch (p12exp->integrityInfo.pwdInfo.algorithm) {
1755 case SEC_OID_SHA1:
1756 integrityMechType = CKM_PBA_SHA1_WITH_SHA1_HMAC; break;
1757 case SEC_OID_MD5:
1758 integrityMechType = CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN; break;
1759 case SEC_OID_MD2:
1760 integrityMechType = CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN; break;
1761 default:
1762 goto loser;
1765 /* generate the key */
1766 symKey = PK11_KeyGen(NULL, integrityMechType, params, 20, NULL);
1767 PK11_DestroyPBEParams(params);
1768 if(!symKey) {
1769 goto loser;
1772 /* initialize HMAC */
1773 /* Get the HMAC mechanism from the hash OID */
1774 hmacMechType= sec_pkcs12_algtag_to_mech(
1775 p12exp->integrityInfo.pwdInfo.algorithm);
1777 p12enc->hmacCx = PK11_CreateContextBySymKey( hmacMechType,
1778 CKA_SIGN, symKey, &ignore);
1780 PK11_FreeSymKey(symKey);
1781 if(!p12enc->hmacCx) {
1782 PORT_SetError(SEC_ERROR_NO_MEMORY);
1783 goto loser;
1785 rv = PK11_DigestBegin(p12enc->hmacCx);
1786 if (rv != SECSuccess)
1787 goto loser;
1791 if(!p12enc->aSafeCinfo) {
1792 goto loser;
1795 PORT_ArenaUnmark(p12exp->arena, mark);
1797 return p12enc;
1799 loser:
1800 if(p12enc) {
1801 if(p12enc->aSafeCinfo) {
1802 SEC_PKCS7DestroyContentInfo(p12enc->aSafeCinfo);
1804 if(p12enc->hmacCx) {
1805 PK11_DestroyContext(p12enc->hmacCx, PR_TRUE);
1808 if (p12exp->arena != NULL)
1809 PORT_ArenaRelease(p12exp->arena, mark);
1811 return NULL;
1814 /* The outermost ASN.1 encoder calls this function for output.
1815 ** This function calls back to the library caller's output routine,
1816 ** which typically writes to a PKCS12 file.
1818 static void
1819 sec_P12A1OutputCB_Outer(void *arg, const char *buf, unsigned long len,
1820 int depth, SEC_ASN1EncodingPart data_kind)
1822 struct sec_pkcs12_encoder_output *output;
1824 output = (struct sec_pkcs12_encoder_output*)arg;
1825 (* output->outputfn)(output->outputarg, buf, len);
1828 /* The "middle" and "inner" ASN.1 encoders call this function to output.
1829 ** This function does HMACing, if appropriate, and then buffers the data.
1830 ** The buffered data is eventually passed down to the underlying PKCS7 encoder.
1832 static void
1833 sec_P12A1OutputCB_HmacP7Update(void *arg, const char *buf,
1834 unsigned long len,
1835 int depth,
1836 SEC_ASN1EncodingPart data_kind)
1838 sec_pkcs12OutputBuffer * bufcx = (sec_pkcs12OutputBuffer *)arg;
1840 if(!buf || !len)
1841 return;
1843 if (bufcx->hmacCx) {
1844 PK11_DigestOp(bufcx->hmacCx, (unsigned char *)buf, len);
1847 /* buffer */
1848 if (bufcx->numBytes > 0) {
1849 int toCopy;
1850 if (len + bufcx->numBytes <= bufcx->bufBytes) {
1851 memcpy(bufcx->buf + bufcx->numBytes, buf, len);
1852 bufcx->numBytes += len;
1853 if (bufcx->numBytes < bufcx->bufBytes)
1854 return;
1855 SEC_PKCS7EncoderUpdate(bufcx->p7eCx, bufcx->buf, bufcx->bufBytes);
1856 bufcx->numBytes = 0;
1857 return;
1859 toCopy = bufcx->bufBytes - bufcx->numBytes;
1860 memcpy(bufcx->buf + bufcx->numBytes, buf, toCopy);
1861 SEC_PKCS7EncoderUpdate(bufcx->p7eCx, bufcx->buf, bufcx->bufBytes);
1862 bufcx->numBytes = 0;
1863 len -= toCopy;
1864 buf += toCopy;
1866 /* buffer is presently empty */
1867 if (len >= bufcx->bufBytes) {
1868 /* Just pass it through */
1869 SEC_PKCS7EncoderUpdate(bufcx->p7eCx, buf, len);
1870 } else {
1871 /* copy it all into the buffer, and return */
1872 memcpy(bufcx->buf, buf, len);
1873 bufcx->numBytes = len;
1877 void
1878 sec_FlushPkcs12OutputBuffer( sec_pkcs12OutputBuffer * bufcx)
1880 if (bufcx->numBytes > 0) {
1881 SEC_PKCS7EncoderUpdate(bufcx->p7eCx, bufcx->buf, bufcx->numBytes);
1882 bufcx->numBytes = 0;
1886 /* Feeds the output of a PKCS7 encoder into the next outward ASN.1 encoder.
1887 ** This function is used by both the inner and middle PCS7 encoders.
1889 static void
1890 sec_P12P7OutputCB_CallA1Update(void *arg, const char *buf, unsigned long len)
1892 SEC_ASN1EncoderContext *cx = (SEC_ASN1EncoderContext*)arg;
1894 if (!buf || !len)
1895 return;
1897 SEC_ASN1EncoderUpdate(cx, buf, len);
1901 /* this function encodes content infos which are part of the
1902 * sequence of content infos labeled AuthenticatedSafes
1904 static SECStatus
1905 sec_pkcs12_encoder_asafe_process(sec_PKCS12EncoderContext *p12ecx)
1907 SEC_PKCS7EncoderContext *innerP7ecx;
1908 SEC_PKCS7ContentInfo *cinfo;
1909 PK11SymKey *bulkKey = NULL;
1910 SEC_ASN1EncoderContext *innerA1ecx = NULL;
1911 SECStatus rv = SECSuccess;
1913 if(p12ecx->currentSafe < p12ecx->p12exp->authSafe.safeCount) {
1914 SEC_PKCS12SafeInfo *safeInfo;
1915 SECOidTag cinfoType;
1917 safeInfo = p12ecx->p12exp->safeInfos[p12ecx->currentSafe];
1919 /* skip empty safes */
1920 if(safeInfo->itemCount == 0) {
1921 return SECSuccess;
1924 cinfo = safeInfo->cinfo;
1925 cinfoType = SEC_PKCS7ContentType(cinfo);
1927 /* determine the safe type and set the appropriate argument */
1928 switch(cinfoType) {
1929 case SEC_OID_PKCS7_DATA:
1930 case SEC_OID_PKCS7_ENVELOPED_DATA:
1931 break;
1932 case SEC_OID_PKCS7_ENCRYPTED_DATA:
1933 bulkKey = safeInfo->encryptionKey;
1934 PK11_SetSymKeyUserData(bulkKey, &safeInfo->pwitem, NULL);
1935 break;
1936 default:
1937 return SECFailure;
1941 /* start the PKCS7 encoder */
1942 innerP7ecx = SEC_PKCS7EncoderStart(cinfo,
1943 sec_P12P7OutputCB_CallA1Update,
1944 p12ecx->middleA1ecx, bulkKey);
1945 if(!innerP7ecx) {
1946 goto loser;
1949 /* encode safe contents */
1950 p12ecx->innerBuf.p7eCx = innerP7ecx;
1951 p12ecx->innerBuf.hmacCx = NULL;
1952 p12ecx->innerBuf.numBytes = 0;
1953 p12ecx->innerBuf.bufBytes = sizeof p12ecx->innerBuf.buf;
1955 innerA1ecx = SEC_ASN1EncoderStart(safeInfo->safe,
1956 sec_PKCS12SafeContentsTemplate,
1957 sec_P12A1OutputCB_HmacP7Update,
1958 &p12ecx->innerBuf);
1959 if(!innerA1ecx) {
1960 goto loser;
1962 rv = SEC_ASN1EncoderUpdate(innerA1ecx, NULL, 0);
1963 SEC_ASN1EncoderFinish(innerA1ecx);
1964 sec_FlushPkcs12OutputBuffer( &p12ecx->innerBuf);
1965 innerA1ecx = NULL;
1966 if(rv != SECSuccess) {
1967 goto loser;
1971 /* finish up safe content info */
1972 rv = SEC_PKCS7EncoderFinish(innerP7ecx, p12ecx->p12exp->pwfn,
1973 p12ecx->p12exp->pwfnarg);
1975 memset(&p12ecx->innerBuf, 0, sizeof p12ecx->innerBuf);
1976 return SECSuccess;
1978 loser:
1979 if(innerP7ecx) {
1980 SEC_PKCS7EncoderFinish(innerP7ecx, p12ecx->p12exp->pwfn,
1981 p12ecx->p12exp->pwfnarg);
1984 if(innerA1ecx) {
1985 SEC_ASN1EncoderFinish(innerA1ecx);
1987 memset(&p12ecx->innerBuf, 0, sizeof p12ecx->innerBuf);
1988 return SECFailure;
1991 /* finish the HMAC and encode the macData so that it can be
1992 * encoded.
1994 static SECStatus
1995 sec_Pkcs12FinishMac(sec_PKCS12EncoderContext *p12ecx)
1997 SECItem hmac = { siBuffer, NULL, 0 };
1998 SECStatus rv;
1999 SGNDigestInfo *di = NULL;
2000 void *dummy;
2002 if(!p12ecx) {
2003 return SECFailure;
2006 /* make sure we are using password integrity mode */
2007 if(!p12ecx->p12exp->integrityEnabled) {
2008 return SECSuccess;
2011 if(!p12ecx->p12exp->pwdIntegrity) {
2012 return SECSuccess;
2015 /* finish the hmac */
2016 hmac.data = (unsigned char *)PORT_ZAlloc(SHA1_LENGTH);
2017 if(!hmac.data) {
2018 PORT_SetError(SEC_ERROR_NO_MEMORY);
2019 return SECFailure;
2022 rv = PK11_DigestFinal(p12ecx->hmacCx, hmac.data, &hmac.len, SHA1_LENGTH);
2024 if(rv != SECSuccess) {
2025 PORT_SetError(SEC_ERROR_NO_MEMORY);
2026 goto loser;
2029 /* create the digest info */
2030 di = SGN_CreateDigestInfo(p12ecx->p12exp->integrityInfo.pwdInfo.algorithm,
2031 hmac.data, hmac.len);
2032 if(!di) {
2033 PORT_SetError(SEC_ERROR_NO_MEMORY);
2034 rv = SECFailure;
2035 goto loser;
2038 rv = SGN_CopyDigestInfo(p12ecx->arena, &p12ecx->mac.safeMac, di);
2039 if(rv != SECSuccess) {
2040 PORT_SetError(SEC_ERROR_NO_MEMORY);
2041 goto loser;
2044 /* encode the mac data */
2045 dummy = SEC_ASN1EncodeItem(p12ecx->arena, &p12ecx->pfx.encodedMacData,
2046 &p12ecx->mac, sec_PKCS12MacDataTemplate);
2047 if(!dummy) {
2048 PORT_SetError(SEC_ERROR_NO_MEMORY);
2049 rv = SECFailure;
2052 loser:
2053 if(di) {
2054 SGN_DestroyDigestInfo(di);
2056 if(hmac.data) {
2057 SECITEM_ZfreeItem(&hmac, PR_FALSE);
2059 PK11_DestroyContext(p12ecx->hmacCx, PR_TRUE);
2060 p12ecx->hmacCx = NULL;
2062 return rv;
2065 /* pfx notify function for ASN1 encoder.
2066 * We want to stop encoding once we reach the authenticated safe.
2067 * At that point, the encoder will be updated via streaming
2068 * as the authenticated safe is encoded.
2070 static void
2071 sec_pkcs12_encoder_pfx_notify(void *arg, PRBool before, void *dest, int real_depth)
2073 sec_PKCS12EncoderContext *p12ecx;
2075 if(!before) {
2076 return;
2079 /* look for authenticated safe */
2080 p12ecx = (sec_PKCS12EncoderContext*)arg;
2081 if(dest != &p12ecx->pfx.encodedAuthSafe) {
2082 return;
2085 SEC_ASN1EncoderSetTakeFromBuf(p12ecx->outerA1ecx);
2086 SEC_ASN1EncoderSetStreaming(p12ecx->outerA1ecx);
2087 SEC_ASN1EncoderClearNotifyProc(p12ecx->outerA1ecx);
2090 /* SEC_PKCS12Encode
2091 * Encodes the PFX item and returns it to the output function, via
2092 * callback. the output function must be capable of multiple updates.
2094 * p12exp - the export context
2095 * output - the output function callback, will be called more than once,
2096 * must be able to accept streaming data.
2097 * outputarg - argument for the output callback.
2099 SECStatus
2100 SEC_PKCS12Encode(SEC_PKCS12ExportContext *p12exp,
2101 SEC_PKCS12EncoderOutputCallback output, void *outputarg)
2103 sec_PKCS12EncoderContext *p12enc;
2104 struct sec_pkcs12_encoder_output outInfo;
2105 SECStatus rv;
2107 if(!p12exp || !output) {
2108 return SECFailure;
2111 /* get the encoder context */
2112 p12enc = sec_pkcs12_encoder_start_context(p12exp);
2113 if(!p12enc) {
2114 return SECFailure;
2117 outInfo.outputfn = output;
2118 outInfo.outputarg = outputarg;
2120 /* set up PFX encoder, the "outer" encoder. Set it for streaming */
2121 p12enc->outerA1ecx = SEC_ASN1EncoderStart(&p12enc->pfx,
2122 sec_PKCS12PFXItemTemplate,
2123 sec_P12A1OutputCB_Outer,
2124 &outInfo);
2125 if(!p12enc->outerA1ecx) {
2126 PORT_SetError(SEC_ERROR_NO_MEMORY);
2127 rv = SECFailure;
2128 goto loser;
2130 SEC_ASN1EncoderSetStreaming(p12enc->outerA1ecx);
2131 SEC_ASN1EncoderSetNotifyProc(p12enc->outerA1ecx,
2132 sec_pkcs12_encoder_pfx_notify, p12enc);
2133 rv = SEC_ASN1EncoderUpdate(p12enc->outerA1ecx, NULL, 0);
2134 if(rv != SECSuccess) {
2135 rv = SECFailure;
2136 goto loser;
2139 /* set up asafe cinfo - the output of the encoder feeds the PFX encoder */
2140 p12enc->middleP7ecx = SEC_PKCS7EncoderStart(p12enc->aSafeCinfo,
2141 sec_P12P7OutputCB_CallA1Update,
2142 p12enc->outerA1ecx, NULL);
2143 if(!p12enc->middleP7ecx) {
2144 rv = SECFailure;
2145 goto loser;
2148 /* encode asafe */
2149 p12enc->middleBuf.p7eCx = p12enc->middleP7ecx;
2150 p12enc->middleBuf.hmacCx = NULL;
2151 p12enc->middleBuf.numBytes = 0;
2152 p12enc->middleBuf.bufBytes = sizeof p12enc->middleBuf.buf;
2154 /* Setup the "inner ASN.1 encoder for Authenticated Safes. */
2155 if(p12enc->p12exp->integrityEnabled &&
2156 p12enc->p12exp->pwdIntegrity) {
2157 p12enc->middleBuf.hmacCx = p12enc->hmacCx;
2159 p12enc->middleA1ecx = SEC_ASN1EncoderStart(&p12enc->p12exp->authSafe,
2160 sec_PKCS12AuthenticatedSafeTemplate,
2161 sec_P12A1OutputCB_HmacP7Update,
2162 &p12enc->middleBuf);
2163 if(!p12enc->middleA1ecx) {
2164 rv = SECFailure;
2165 goto loser;
2167 SEC_ASN1EncoderSetStreaming(p12enc->middleA1ecx);
2168 SEC_ASN1EncoderSetTakeFromBuf(p12enc->middleA1ecx);
2170 /* encode each of the safes */
2171 while(p12enc->currentSafe != p12enc->p12exp->safeInfoCount) {
2172 sec_pkcs12_encoder_asafe_process(p12enc);
2173 p12enc->currentSafe++;
2175 SEC_ASN1EncoderClearTakeFromBuf(p12enc->middleA1ecx);
2176 SEC_ASN1EncoderClearStreaming(p12enc->middleA1ecx);
2177 SEC_ASN1EncoderUpdate(p12enc->middleA1ecx, NULL, 0);
2178 SEC_ASN1EncoderFinish(p12enc->middleA1ecx);
2180 sec_FlushPkcs12OutputBuffer( &p12enc->middleBuf);
2182 /* finish the encoding of the authenticated safes */
2183 rv = SEC_PKCS7EncoderFinish(p12enc->middleP7ecx, p12exp->pwfn,
2184 p12exp->pwfnarg);
2185 if(rv != SECSuccess) {
2186 goto loser;
2189 SEC_ASN1EncoderClearTakeFromBuf(p12enc->outerA1ecx);
2190 SEC_ASN1EncoderClearStreaming(p12enc->outerA1ecx);
2192 /* update the mac, if necessary */
2193 rv = sec_Pkcs12FinishMac(p12enc);
2194 if(rv != SECSuccess) {
2195 goto loser;
2198 /* finish encoding the pfx */
2199 rv = SEC_ASN1EncoderUpdate(p12enc->outerA1ecx, NULL, 0);
2201 SEC_ASN1EncoderFinish(p12enc->outerA1ecx);
2203 loser:
2204 return rv;
2207 void
2208 SEC_PKCS12DestroyExportContext(SEC_PKCS12ExportContext *p12ecx)
2210 int i = 0;
2212 if(!p12ecx) {
2213 return;
2216 if(p12ecx->safeInfos) {
2217 i = 0;
2218 while(p12ecx->safeInfos[i] != NULL) {
2219 if(p12ecx->safeInfos[i]->encryptionKey) {
2220 PK11_FreeSymKey(p12ecx->safeInfos[i]->encryptionKey);
2222 if(p12ecx->safeInfos[i]->cinfo) {
2223 SEC_PKCS7DestroyContentInfo(p12ecx->safeInfos[i]->cinfo);
2225 i++;
2229 PK11_FreeSlot(p12ecx->slot);
2231 PORT_FreeArena(p12ecx->arena, PR_TRUE);
2235 /*********************************
2236 * All-in-one routines for exporting certificates
2237 *********************************/
2238 struct inPlaceEncodeInfo {
2239 PRBool error;
2240 SECItem outItem;
2243 static void
2244 sec_pkcs12_in_place_encoder_output(void *arg, const char *buf, unsigned long len)
2246 struct inPlaceEncodeInfo *outInfo = (struct inPlaceEncodeInfo*)arg;
2248 if(!outInfo || !len || outInfo->error) {
2249 return;
2252 if(!outInfo->outItem.data) {
2253 outInfo->outItem.data = (unsigned char*)PORT_ZAlloc(len);
2254 outInfo->outItem.len = 0;
2255 } else {
2256 if(!PORT_Realloc(&(outInfo->outItem.data), (outInfo->outItem.len + len))) {
2257 SECITEM_ZfreeItem(&(outInfo->outItem), PR_FALSE);
2258 outInfo->outItem.data = NULL;
2259 PORT_SetError(SEC_ERROR_NO_MEMORY);
2260 outInfo->error = PR_TRUE;
2261 return;
2265 PORT_Memcpy(&(outInfo->outItem.data[outInfo->outItem.len]), buf, len);
2266 outInfo->outItem.len += len;
2268 return;
2272 * SEC_PKCS12ExportCertifcateAndKeyUsingPassword
2273 * Exports a certificate/key pair using password-based encryption and
2274 * authentication.
2276 * pwfn, pwfnarg - password function and argument for the key database
2277 * cert - the certificate to export
2278 * certDb - certificate database
2279 * pwitem - the password to use
2280 * shroudKey - encrypt the key externally,
2281 * keyShroudAlg - encryption algorithm for key
2282 * encryptionAlg - the algorithm with which data is encrypted
2283 * integrityAlg - the algorithm for integrity
2285 SECItem *
2286 SEC_PKCS12ExportCertificateAndKeyUsingPassword(
2287 SECKEYGetPasswordKey pwfn, void *pwfnarg,
2288 CERTCertificate *cert, PK11SlotInfo *slot,
2289 CERTCertDBHandle *certDb, SECItem *pwitem,
2290 PRBool shroudKey, SECOidTag shroudAlg,
2291 PRBool encryptCert, SECOidTag certEncAlg,
2292 SECOidTag integrityAlg, void *wincx)
2294 struct inPlaceEncodeInfo outInfo;
2295 SEC_PKCS12ExportContext *p12ecx = NULL;
2296 SEC_PKCS12SafeInfo *keySafe, *certSafe;
2297 SECItem *returnItem = NULL;
2299 if(!cert || !pwitem || !slot) {
2300 return NULL;
2303 outInfo.error = PR_FALSE;
2304 outInfo.outItem.data = NULL;
2305 outInfo.outItem.len = 0;
2307 p12ecx = SEC_PKCS12CreateExportContext(pwfn, pwfnarg, slot, wincx);
2308 if(!p12ecx) {
2309 return NULL;
2312 /* set up cert safe */
2313 if(encryptCert) {
2314 certSafe = SEC_PKCS12CreatePasswordPrivSafe(p12ecx, pwitem, certEncAlg);
2315 } else {
2316 certSafe = SEC_PKCS12CreateUnencryptedSafe(p12ecx);
2318 if(!certSafe) {
2319 goto loser;
2322 /* set up key safe */
2323 if(shroudKey) {
2324 keySafe = SEC_PKCS12CreateUnencryptedSafe(p12ecx);
2325 } else {
2326 keySafe = certSafe;
2328 if(!keySafe) {
2329 goto loser;
2332 /* add integrity mode */
2333 if(SEC_PKCS12AddPasswordIntegrity(p12ecx, pwitem, integrityAlg)
2334 != SECSuccess) {
2335 goto loser;
2338 /* add cert and key pair */
2339 if(SEC_PKCS12AddCertAndKey(p12ecx, certSafe, NULL, cert, certDb,
2340 keySafe, NULL, shroudKey, pwitem, shroudAlg)
2341 != SECSuccess) {
2342 goto loser;
2345 /* encode the puppy */
2346 if(SEC_PKCS12Encode(p12ecx, sec_pkcs12_in_place_encoder_output, &outInfo)
2347 != SECSuccess) {
2348 goto loser;
2350 if(outInfo.error) {
2351 goto loser;
2354 SEC_PKCS12DestroyExportContext(p12ecx);
2356 returnItem = SECITEM_DupItem(&outInfo.outItem);
2357 SECITEM_ZfreeItem(&outInfo.outItem, PR_FALSE);
2359 return returnItem;
2361 loser:
2362 if(outInfo.outItem.data) {
2363 SECITEM_ZfreeItem(&(outInfo.outItem), PR_TRUE);
2366 if(p12ecx) {
2367 SEC_PKCS12DestroyExportContext(p12ecx);
2370 return NULL;