security/nss/lib/pkcs12/p12e.c

changeset 2
7e26c7da4463
equal deleted inserted replaced
-1:000000000000 0:921be9134053
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 #include "p12t.h"
6 #include "p12.h"
7 #include "plarena.h"
8 #include "secitem.h"
9 #include "secoid.h"
10 #include "seccomon.h"
11 #include "secport.h"
12 #include "cert.h"
13 #include "secpkcs7.h"
14 #include "secasn1.h"
15 #include "secerr.h"
16 #include "pk11func.h"
17 #include "p12plcy.h"
18 #include "p12local.h"
19 #include "prcpucfg.h"
20
21 extern const int NSS_PBE_DEFAULT_ITERATION_COUNT; /* defined in p7create.c */
22
23 /*
24 ** This PKCS12 file encoder uses numerous nested ASN.1 and PKCS7 encoder
25 ** contexts. It can be difficult to keep straight. Here's a picture:
26 **
27 ** "outer" ASN.1 encoder. The output goes to the library caller's CB.
28 ** "middle" PKCS7 encoder. Feeds the "outer" ASN.1 encoder.
29 ** "middle" ASN1 encoder. Encodes the encrypted aSafes.
30 ** Feeds the "middle" P7 encoder above.
31 ** "inner" PKCS7 encoder. Encrypts the "authenticated Safes" (aSafes)
32 ** Feeds the "middle" ASN.1 encoder above.
33 ** "inner" ASN.1 encoder. Encodes the unencrypted aSafes.
34 ** Feeds the "inner" P7 enocder above.
35 **
36 ** Buffering has been added at each point where the output of an ASN.1
37 ** encoder feeds the input of a PKCS7 encoder.
38 */
39
40 /*********************************
41 * Output buffer object, used to buffer output from ASN.1 encoder
42 * before passing data on down to the next PKCS7 encoder.
43 *********************************/
44
45 #define PK12_OUTPUT_BUFFER_SIZE 8192
46
47 struct sec_pkcs12OutputBufferStr {
48 SEC_PKCS7EncoderContext * p7eCx;
49 PK11Context * hmacCx;
50 unsigned int numBytes;
51 unsigned int bufBytes;
52 char buf[PK12_OUTPUT_BUFFER_SIZE];
53 };
54 typedef struct sec_pkcs12OutputBufferStr sec_pkcs12OutputBuffer;
55
56 /*********************************
57 * Structures used in exporting the PKCS 12 blob
58 *********************************/
59
60 /* A SafeInfo is used for each ContentInfo which makes up the
61 * sequence of safes in the AuthenticatedSafe portion of the
62 * PFX structure.
63 */
64 struct SEC_PKCS12SafeInfoStr {
65 PLArenaPool *arena;
66
67 /* information for setting up password encryption */
68 SECItem pwitem;
69 SECOidTag algorithm;
70 PK11SymKey *encryptionKey;
71
72 /* how many items have been stored in this safe,
73 * we will skip any safe which does not contain any
74 * items
75 */
76 unsigned int itemCount;
77
78 /* the content info for the safe */
79 SEC_PKCS7ContentInfo *cinfo;
80
81 sec_PKCS12SafeContents *safe;
82 };
83
84 /* An opaque structure which contains information needed for exporting
85 * certificates and keys through PKCS 12.
86 */
87 struct SEC_PKCS12ExportContextStr {
88 PLArenaPool *arena;
89 PK11SlotInfo *slot;
90 void *wincx;
91
92 /* integrity information */
93 PRBool integrityEnabled;
94 PRBool pwdIntegrity;
95 union {
96 struct sec_PKCS12PasswordModeInfo pwdInfo;
97 struct sec_PKCS12PublicKeyModeInfo pubkeyInfo;
98 } integrityInfo;
99
100 /* helper functions */
101 /* retrieve the password call back */
102 SECKEYGetPasswordKey pwfn;
103 void *pwfnarg;
104
105 /* safe contents bags */
106 SEC_PKCS12SafeInfo **safeInfos;
107 unsigned int safeInfoCount;
108
109 /* the sequence of safes */
110 sec_PKCS12AuthenticatedSafe authSafe;
111
112 /* information needing deletion */
113 CERTCertificate **certList;
114 };
115
116 /* structures for passing information to encoder callbacks when processing
117 * data through the ASN1 engine.
118 */
119 struct sec_pkcs12_encoder_output {
120 SEC_PKCS12EncoderOutputCallback outputfn;
121 void *outputarg;
122 };
123
124 struct sec_pkcs12_hmac_and_output_info {
125 void *arg;
126 struct sec_pkcs12_encoder_output output;
127 };
128
129 /* An encoder context which is used for the actual encoding
130 * portion of PKCS 12.
131 */
132 typedef struct sec_PKCS12EncoderContextStr {
133 PLArenaPool *arena;
134 SEC_PKCS12ExportContext *p12exp;
135
136 /* encoder information - this is set up based on whether
137 * password based or public key pased privacy is being used
138 */
139 SEC_ASN1EncoderContext *outerA1ecx;
140 union {
141 struct sec_pkcs12_hmac_and_output_info hmacAndOutputInfo;
142 struct sec_pkcs12_encoder_output encOutput;
143 } output;
144
145 /* structures for encoding of PFX and MAC */
146 sec_PKCS12PFXItem pfx;
147 sec_PKCS12MacData mac;
148
149 /* authenticated safe encoding tracking information */
150 SEC_PKCS7ContentInfo *aSafeCinfo;
151 SEC_PKCS7EncoderContext *middleP7ecx;
152 SEC_ASN1EncoderContext *middleA1ecx;
153 unsigned int currentSafe;
154
155 /* hmac context */
156 PK11Context *hmacCx;
157
158 /* output buffers */
159 sec_pkcs12OutputBuffer middleBuf;
160 sec_pkcs12OutputBuffer innerBuf;
161
162 } sec_PKCS12EncoderContext;
163
164
165 /*********************************
166 * Export setup routines
167 *********************************/
168
169 /* SEC_PKCS12CreateExportContext
170 * Creates an export context and sets the unicode and password retrieval
171 * callbacks. This is the first call which must be made when exporting
172 * a PKCS 12 blob.
173 *
174 * pwfn, pwfnarg - password retrieval callback and argument. these are
175 * required for password-authentication mode.
176 */
177 SEC_PKCS12ExportContext *
178 SEC_PKCS12CreateExportContext(SECKEYGetPasswordKey pwfn, void *pwfnarg,
179 PK11SlotInfo *slot, void *wincx)
180 {
181 PLArenaPool *arena = NULL;
182 SEC_PKCS12ExportContext *p12ctxt = NULL;
183
184 /* allocate the arena and create the context */
185 arena = PORT_NewArena(4096);
186 if(!arena) {
187 PORT_SetError(SEC_ERROR_NO_MEMORY);
188 return NULL;
189 }
190
191 p12ctxt = (SEC_PKCS12ExportContext *)PORT_ArenaZAlloc(arena,
192 sizeof(SEC_PKCS12ExportContext));
193 if(!p12ctxt) {
194 PORT_SetError(SEC_ERROR_NO_MEMORY);
195 goto loser;
196 }
197
198 /* password callback for key retrieval */
199 p12ctxt->pwfn = pwfn;
200 p12ctxt->pwfnarg = pwfnarg;
201
202 p12ctxt->integrityEnabled = PR_FALSE;
203 p12ctxt->arena = arena;
204 p12ctxt->wincx = wincx;
205 p12ctxt->slot = (slot) ? PK11_ReferenceSlot(slot) : PK11_GetInternalSlot();
206
207 return p12ctxt;
208
209 loser:
210 if(arena) {
211 PORT_FreeArena(arena, PR_TRUE);
212 }
213
214 return NULL;
215 }
216
217 /*
218 * Adding integrity mode
219 */
220
221 /* SEC_PKCS12AddPasswordIntegrity
222 * Add password integrity to the exported data. If an integrity method
223 * has already been set, then return an error.
224 *
225 * p12ctxt - the export context
226 * pwitem - the password for integrity mode
227 * integAlg - the integrity algorithm to use for authentication.
228 */
229 SECStatus
230 SEC_PKCS12AddPasswordIntegrity(SEC_PKCS12ExportContext *p12ctxt,
231 SECItem *pwitem, SECOidTag integAlg)
232 {
233 if(!p12ctxt || p12ctxt->integrityEnabled) {
234 return SECFailure;
235 }
236
237 /* set up integrity information */
238 p12ctxt->pwdIntegrity = PR_TRUE;
239 p12ctxt->integrityInfo.pwdInfo.password =
240 (SECItem*)PORT_ArenaZAlloc(p12ctxt->arena, sizeof(SECItem));
241 if(!p12ctxt->integrityInfo.pwdInfo.password) {
242 PORT_SetError(SEC_ERROR_NO_MEMORY);
243 return SECFailure;
244 }
245 if(SECITEM_CopyItem(p12ctxt->arena,
246 p12ctxt->integrityInfo.pwdInfo.password, pwitem)
247 != SECSuccess) {
248 PORT_SetError(SEC_ERROR_NO_MEMORY);
249 return SECFailure;
250 }
251 p12ctxt->integrityInfo.pwdInfo.algorithm = integAlg;
252 p12ctxt->integrityEnabled = PR_TRUE;
253
254 return SECSuccess;
255 }
256
257 /* SEC_PKCS12AddPublicKeyIntegrity
258 * Add public key integrity to the exported data. If an integrity method
259 * has already been set, then return an error. The certificate must be
260 * allowed to be used as a signing cert.
261 *
262 * p12ctxt - the export context
263 * cert - signer certificate
264 * certDb - the certificate database
265 * algorithm - signing algorithm
266 * keySize - size of the signing key (?)
267 */
268 SECStatus
269 SEC_PKCS12AddPublicKeyIntegrity(SEC_PKCS12ExportContext *p12ctxt,
270 CERTCertificate *cert, CERTCertDBHandle *certDb,
271 SECOidTag algorithm, int keySize)
272 {
273 if(!p12ctxt) {
274 return SECFailure;
275 }
276
277 p12ctxt->integrityInfo.pubkeyInfo.cert = cert;
278 p12ctxt->integrityInfo.pubkeyInfo.certDb = certDb;
279 p12ctxt->integrityInfo.pubkeyInfo.algorithm = algorithm;
280 p12ctxt->integrityInfo.pubkeyInfo.keySize = keySize;
281 p12ctxt->integrityEnabled = PR_TRUE;
282
283 return SECSuccess;
284 }
285
286
287 /*
288 * Adding safes - encrypted (password/public key) or unencrypted
289 * Each of the safe creation routines return an opaque pointer which
290 * are later passed into the routines for exporting certificates and
291 * keys.
292 */
293
294 /* append the newly created safeInfo to list of safeInfos in the export
295 * context.
296 */
297 static SECStatus
298 sec_pkcs12_append_safe_info(SEC_PKCS12ExportContext *p12ctxt, SEC_PKCS12SafeInfo *info)
299 {
300 void *mark = NULL, *dummy1 = NULL, *dummy2 = NULL;
301
302 if(!p12ctxt || !info) {
303 return SECFailure;
304 }
305
306 mark = PORT_ArenaMark(p12ctxt->arena);
307
308 /* if no safeInfos have been set, create the list, otherwise expand it. */
309 if(!p12ctxt->safeInfoCount) {
310 p12ctxt->safeInfos = (SEC_PKCS12SafeInfo **)PORT_ArenaZAlloc(p12ctxt->arena,
311 2 * sizeof(SEC_PKCS12SafeInfo *));
312 dummy1 = p12ctxt->safeInfos;
313 p12ctxt->authSafe.encodedSafes = (SECItem **)PORT_ArenaZAlloc(p12ctxt->arena,
314 2 * sizeof(SECItem *));
315 dummy2 = p12ctxt->authSafe.encodedSafes;
316 } else {
317 dummy1 = PORT_ArenaGrow(p12ctxt->arena, p12ctxt->safeInfos,
318 (p12ctxt->safeInfoCount + 1) * sizeof(SEC_PKCS12SafeInfo *),
319 (p12ctxt->safeInfoCount + 2) * sizeof(SEC_PKCS12SafeInfo *));
320 p12ctxt->safeInfos = (SEC_PKCS12SafeInfo **)dummy1;
321 dummy2 = PORT_ArenaGrow(p12ctxt->arena, p12ctxt->authSafe.encodedSafes,
322 (p12ctxt->authSafe.safeCount + 1) * sizeof(SECItem *),
323 (p12ctxt->authSafe.safeCount + 2) * sizeof(SECItem *));
324 p12ctxt->authSafe.encodedSafes = (SECItem**)dummy2;
325 }
326 if(!dummy1 || !dummy2) {
327 PORT_SetError(SEC_ERROR_NO_MEMORY);
328 goto loser;
329 }
330
331 /* append the new safeInfo and null terminate the list */
332 p12ctxt->safeInfos[p12ctxt->safeInfoCount] = info;
333 p12ctxt->safeInfos[++p12ctxt->safeInfoCount] = NULL;
334 p12ctxt->authSafe.encodedSafes[p12ctxt->authSafe.safeCount] =
335 (SECItem*)PORT_ArenaZAlloc(p12ctxt->arena, sizeof(SECItem));
336 if(!p12ctxt->authSafe.encodedSafes[p12ctxt->authSafe.safeCount]) {
337 PORT_SetError(SEC_ERROR_NO_MEMORY);
338 goto loser;
339 }
340 p12ctxt->authSafe.encodedSafes[++p12ctxt->authSafe.safeCount] = NULL;
341
342 PORT_ArenaUnmark(p12ctxt->arena, mark);
343 return SECSuccess;
344
345 loser:
346 PORT_ArenaRelease(p12ctxt->arena, mark);
347 return SECFailure;
348 }
349
350 /* SEC_PKCS12CreatePasswordPrivSafe
351 * Create a password privacy safe to store exported information in.
352 *
353 * p12ctxt - export context
354 * pwitem - password for encryption
355 * privAlg - pbe algorithm through which encryption is done.
356 */
357 SEC_PKCS12SafeInfo *
358 SEC_PKCS12CreatePasswordPrivSafe(SEC_PKCS12ExportContext *p12ctxt,
359 SECItem *pwitem, SECOidTag privAlg)
360 {
361 SEC_PKCS12SafeInfo *safeInfo = NULL;
362 void *mark = NULL;
363 PK11SlotInfo *slot = NULL;
364 SECAlgorithmID *algId;
365 SECItem uniPwitem = {siBuffer, NULL, 0};
366
367 if(!p12ctxt) {
368 return NULL;
369 }
370
371 /* allocate the safe info */
372 mark = PORT_ArenaMark(p12ctxt->arena);
373 safeInfo = (SEC_PKCS12SafeInfo *)PORT_ArenaZAlloc(p12ctxt->arena,
374 sizeof(SEC_PKCS12SafeInfo));
375 if(!safeInfo) {
376 PORT_SetError(SEC_ERROR_NO_MEMORY);
377 PORT_ArenaRelease(p12ctxt->arena, mark);
378 return NULL;
379 }
380
381 safeInfo->itemCount = 0;
382
383 /* create the encrypted safe */
384 safeInfo->cinfo = SEC_PKCS7CreateEncryptedData(privAlg, 0, p12ctxt->pwfn,
385 p12ctxt->pwfnarg);
386 if(!safeInfo->cinfo) {
387 PORT_SetError(SEC_ERROR_NO_MEMORY);
388 goto loser;
389 }
390 safeInfo->arena = p12ctxt->arena;
391
392 /* convert the password to unicode */
393 if(!sec_pkcs12_convert_item_to_unicode(NULL, &uniPwitem, pwitem,
394 PR_TRUE, PR_TRUE, PR_TRUE)) {
395 PORT_SetError(SEC_ERROR_NO_MEMORY);
396 goto loser;
397 }
398 if(SECITEM_CopyItem(p12ctxt->arena, &safeInfo->pwitem, &uniPwitem) != SECSuccess) {
399 PORT_SetError(SEC_ERROR_NO_MEMORY);
400 goto loser;
401 }
402
403 /* generate the encryption key */
404 slot = PK11_ReferenceSlot(p12ctxt->slot);
405 if(!slot) {
406 slot = PK11_GetInternalKeySlot();
407 if(!slot) {
408 PORT_SetError(SEC_ERROR_NO_MEMORY);
409 goto loser;
410 }
411 }
412
413 algId = SEC_PKCS7GetEncryptionAlgorithm(safeInfo->cinfo);
414 safeInfo->encryptionKey = PK11_PBEKeyGen(slot, algId, &uniPwitem,
415 PR_FALSE, p12ctxt->wincx);
416 if(!safeInfo->encryptionKey) {
417 goto loser;
418 }
419
420 safeInfo->arena = p12ctxt->arena;
421 safeInfo->safe = NULL;
422 if(sec_pkcs12_append_safe_info(p12ctxt, safeInfo) != SECSuccess) {
423 goto loser;
424 }
425
426 if(uniPwitem.data) {
427 SECITEM_ZfreeItem(&uniPwitem, PR_FALSE);
428 }
429 PORT_ArenaUnmark(p12ctxt->arena, mark);
430
431 if (slot) {
432 PK11_FreeSlot(slot);
433 }
434 return safeInfo;
435
436 loser:
437 if (slot) {
438 PK11_FreeSlot(slot);
439 }
440 if(safeInfo->cinfo) {
441 SEC_PKCS7DestroyContentInfo(safeInfo->cinfo);
442 }
443
444 if(uniPwitem.data) {
445 SECITEM_ZfreeItem(&uniPwitem, PR_FALSE);
446 }
447
448 PORT_ArenaRelease(p12ctxt->arena, mark);
449 return NULL;
450 }
451
452 /* SEC_PKCS12CreateUnencryptedSafe
453 * Creates an unencrypted safe within the export context.
454 *
455 * p12ctxt - the export context
456 */
457 SEC_PKCS12SafeInfo *
458 SEC_PKCS12CreateUnencryptedSafe(SEC_PKCS12ExportContext *p12ctxt)
459 {
460 SEC_PKCS12SafeInfo *safeInfo = NULL;
461 void *mark = NULL;
462
463 if(!p12ctxt) {
464 return NULL;
465 }
466
467 /* create the safe info */
468 mark = PORT_ArenaMark(p12ctxt->arena);
469 safeInfo = (SEC_PKCS12SafeInfo *)PORT_ArenaZAlloc(p12ctxt->arena,
470 sizeof(SEC_PKCS12SafeInfo));
471 if(!safeInfo) {
472 PORT_ArenaRelease(p12ctxt->arena, mark);
473 PORT_SetError(SEC_ERROR_NO_MEMORY);
474 return NULL;
475 }
476
477 safeInfo->itemCount = 0;
478
479 /* create the safe content */
480 safeInfo->cinfo = SEC_PKCS7CreateData();
481 if(!safeInfo->cinfo) {
482 PORT_SetError(SEC_ERROR_NO_MEMORY);
483 goto loser;
484 }
485
486 if(sec_pkcs12_append_safe_info(p12ctxt, safeInfo) != SECSuccess) {
487 goto loser;
488 }
489
490 PORT_ArenaUnmark(p12ctxt->arena, mark);
491 return safeInfo;
492
493 loser:
494 if(safeInfo->cinfo) {
495 SEC_PKCS7DestroyContentInfo(safeInfo->cinfo);
496 }
497
498 PORT_ArenaRelease(p12ctxt->arena, mark);
499 return NULL;
500 }
501
502 /* SEC_PKCS12CreatePubKeyEncryptedSafe
503 * Creates a safe which is protected by public key encryption.
504 *
505 * p12ctxt - the export context
506 * certDb - the certificate database
507 * signer - the signer's certificate
508 * recipients - the list of recipient certificates.
509 * algorithm - the encryption algorithm to use
510 * keysize - the algorithms key size (?)
511 */
512 SEC_PKCS12SafeInfo *
513 SEC_PKCS12CreatePubKeyEncryptedSafe(SEC_PKCS12ExportContext *p12ctxt,
514 CERTCertDBHandle *certDb,
515 CERTCertificate *signer,
516 CERTCertificate **recipients,
517 SECOidTag algorithm, int keysize)
518 {
519 SEC_PKCS12SafeInfo *safeInfo = NULL;
520 void *mark = NULL;
521
522 if(!p12ctxt || !signer || !recipients || !(*recipients)) {
523 return NULL;
524 }
525
526 /* allocate the safeInfo */
527 mark = PORT_ArenaMark(p12ctxt->arena);
528 safeInfo = (SEC_PKCS12SafeInfo *)PORT_ArenaZAlloc(p12ctxt->arena,
529 sizeof(SEC_PKCS12SafeInfo));
530 if(!safeInfo) {
531 PORT_ArenaRelease(p12ctxt->arena, mark);
532 PORT_SetError(SEC_ERROR_NO_MEMORY);
533 return NULL;
534 }
535
536 safeInfo->itemCount = 0;
537 safeInfo->arena = p12ctxt->arena;
538
539 /* create the enveloped content info using certUsageEmailSigner currently.
540 * XXX We need to eventually use something other than certUsageEmailSigner
541 */
542 safeInfo->cinfo = SEC_PKCS7CreateEnvelopedData(signer, certUsageEmailSigner,
543 certDb, algorithm, keysize,
544 p12ctxt->pwfn, p12ctxt->pwfnarg);
545 if(!safeInfo->cinfo) {
546 PORT_SetError(SEC_ERROR_NO_MEMORY);
547 goto loser;
548 }
549
550 /* add recipients */
551 if(recipients) {
552 unsigned int i = 0;
553 while(recipients[i] != NULL) {
554 SECStatus rv = SEC_PKCS7AddRecipient(safeInfo->cinfo, recipients[i],
555 certUsageEmailRecipient, certDb);
556 if(rv != SECSuccess) {
557 goto loser;
558 }
559 i++;
560 }
561 }
562
563 if(sec_pkcs12_append_safe_info(p12ctxt, safeInfo) != SECSuccess) {
564 goto loser;
565 }
566
567 PORT_ArenaUnmark(p12ctxt->arena, mark);
568 return safeInfo;
569
570 loser:
571 if(safeInfo->cinfo) {
572 SEC_PKCS7DestroyContentInfo(safeInfo->cinfo);
573 safeInfo->cinfo = NULL;
574 }
575
576 PORT_ArenaRelease(p12ctxt->arena, mark);
577 return NULL;
578 }
579
580 /*********************************
581 * Routines to handle the exporting of the keys and certificates
582 *********************************/
583
584 /* creates a safe contents which safeBags will be appended to */
585 sec_PKCS12SafeContents *
586 sec_PKCS12CreateSafeContents(PLArenaPool *arena)
587 {
588 sec_PKCS12SafeContents *safeContents;
589
590 if(arena == NULL) {
591 return NULL;
592 }
593
594 /* create the safe contents */
595 safeContents = (sec_PKCS12SafeContents *)PORT_ArenaZAlloc(arena,
596 sizeof(sec_PKCS12SafeContents));
597 if(!safeContents) {
598 PORT_SetError(SEC_ERROR_NO_MEMORY);
599 goto loser;
600 }
601
602 /* set up the internal contents info */
603 safeContents->safeBags = NULL;
604 safeContents->arena = arena;
605 safeContents->bagCount = 0;
606
607 return safeContents;
608
609 loser:
610 return NULL;
611 }
612
613 /* appends a safe bag to a safeContents using the specified arena.
614 */
615 SECStatus
616 sec_pkcs12_append_bag_to_safe_contents(PLArenaPool *arena,
617 sec_PKCS12SafeContents *safeContents,
618 sec_PKCS12SafeBag *safeBag)
619 {
620 void *mark = NULL, *dummy = NULL;
621
622 if(!arena || !safeBag || !safeContents) {
623 return SECFailure;
624 }
625
626 mark = PORT_ArenaMark(arena);
627 if(!mark) {
628 PORT_SetError(SEC_ERROR_NO_MEMORY);
629 return SECFailure;
630 }
631
632 /* allocate space for the list, or reallocate to increase space */
633 if(!safeContents->safeBags) {
634 safeContents->safeBags = (sec_PKCS12SafeBag **)PORT_ArenaZAlloc(arena,
635 (2 * sizeof(sec_PKCS12SafeBag *)));
636 dummy = safeContents->safeBags;
637 safeContents->bagCount = 0;
638 } else {
639 dummy = PORT_ArenaGrow(arena, safeContents->safeBags,
640 (safeContents->bagCount + 1) * sizeof(sec_PKCS12SafeBag *),
641 (safeContents->bagCount + 2) * sizeof(sec_PKCS12SafeBag *));
642 safeContents->safeBags = (sec_PKCS12SafeBag **)dummy;
643 }
644
645 if(!dummy) {
646 PORT_ArenaRelease(arena, mark);
647 PORT_SetError(SEC_ERROR_NO_MEMORY);
648 return SECFailure;
649 }
650
651 /* append the bag at the end and null terminate the list */
652 safeContents->safeBags[safeContents->bagCount++] = safeBag;
653 safeContents->safeBags[safeContents->bagCount] = NULL;
654
655 PORT_ArenaUnmark(arena, mark);
656
657 return SECSuccess;
658 }
659
660 /* appends a safeBag to a specific safeInfo.
661 */
662 SECStatus
663 sec_pkcs12_append_bag(SEC_PKCS12ExportContext *p12ctxt,
664 SEC_PKCS12SafeInfo *safeInfo, sec_PKCS12SafeBag *safeBag)
665 {
666 sec_PKCS12SafeContents *dest;
667 SECStatus rv = SECFailure;
668
669 if(!p12ctxt || !safeBag || !safeInfo) {
670 return SECFailure;
671 }
672
673 if(!safeInfo->safe) {
674 safeInfo->safe = sec_PKCS12CreateSafeContents(p12ctxt->arena);
675 if(!safeInfo->safe) {
676 return SECFailure;
677 }
678 }
679
680 dest = safeInfo->safe;
681 rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena, dest, safeBag);
682 if(rv == SECSuccess) {
683 safeInfo->itemCount++;
684 }
685
686 return rv;
687 }
688
689 /* Creates a safeBag of the specified type, and if bagData is specified,
690 * the contents are set. The contents could be set later by the calling
691 * routine.
692 */
693 sec_PKCS12SafeBag *
694 sec_PKCS12CreateSafeBag(SEC_PKCS12ExportContext *p12ctxt, SECOidTag bagType,
695 void *bagData)
696 {
697 sec_PKCS12SafeBag *safeBag;
698 PRBool setName = PR_TRUE;
699 void *mark = NULL;
700 SECStatus rv = SECSuccess;
701 SECOidData *oidData = NULL;
702
703 if(!p12ctxt) {
704 return NULL;
705 }
706
707 mark = PORT_ArenaMark(p12ctxt->arena);
708 if(!mark) {
709 PORT_SetError(SEC_ERROR_NO_MEMORY);
710 return NULL;
711 }
712
713 safeBag = (sec_PKCS12SafeBag *)PORT_ArenaZAlloc(p12ctxt->arena,
714 sizeof(sec_PKCS12SafeBag));
715 if(!safeBag) {
716 PORT_ArenaRelease(p12ctxt->arena, mark);
717 PORT_SetError(SEC_ERROR_NO_MEMORY);
718 return NULL;
719 }
720
721 /* set the bags content based upon bag type */
722 switch(bagType) {
723 case SEC_OID_PKCS12_V1_KEY_BAG_ID:
724 safeBag->safeBagContent.pkcs8KeyBag =
725 (SECKEYPrivateKeyInfo *)bagData;
726 break;
727 case SEC_OID_PKCS12_V1_CERT_BAG_ID:
728 safeBag->safeBagContent.certBag = (sec_PKCS12CertBag *)bagData;
729 break;
730 case SEC_OID_PKCS12_V1_CRL_BAG_ID:
731 safeBag->safeBagContent.crlBag = (sec_PKCS12CRLBag *)bagData;
732 break;
733 case SEC_OID_PKCS12_V1_SECRET_BAG_ID:
734 safeBag->safeBagContent.secretBag = (sec_PKCS12SecretBag *)bagData;
735 break;
736 case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
737 safeBag->safeBagContent.pkcs8ShroudedKeyBag =
738 (SECKEYEncryptedPrivateKeyInfo *)bagData;
739 break;
740 case SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID:
741 safeBag->safeBagContent.safeContents =
742 (sec_PKCS12SafeContents *)bagData;
743 setName = PR_FALSE;
744 break;
745 default:
746 goto loser;
747 }
748
749 oidData = SECOID_FindOIDByTag(bagType);
750 if(oidData) {
751 rv = SECITEM_CopyItem(p12ctxt->arena, &safeBag->safeBagType, &oidData->oid);
752 if(rv != SECSuccess) {
753 PORT_SetError(SEC_ERROR_NO_MEMORY);
754 goto loser;
755 }
756 } else {
757 goto loser;
758 }
759
760 safeBag->arena = p12ctxt->arena;
761 PORT_ArenaUnmark(p12ctxt->arena, mark);
762
763 return safeBag;
764
765 loser:
766 if(mark) {
767 PORT_ArenaRelease(p12ctxt->arena, mark);
768 }
769
770 return NULL;
771 }
772
773 /* Creates a new certificate bag and returns a pointer to it. If an error
774 * occurs NULL is returned.
775 */
776 sec_PKCS12CertBag *
777 sec_PKCS12NewCertBag(PLArenaPool *arena, SECOidTag certType)
778 {
779 sec_PKCS12CertBag *certBag = NULL;
780 SECOidData *bagType = NULL;
781 SECStatus rv;
782 void *mark = NULL;
783
784 if(!arena) {
785 return NULL;
786 }
787
788 mark = PORT_ArenaMark(arena);
789 certBag = (sec_PKCS12CertBag *)PORT_ArenaZAlloc(arena,
790 sizeof(sec_PKCS12CertBag));
791 if(!certBag) {
792 PORT_ArenaRelease(arena, mark);
793 PORT_SetError(SEC_ERROR_NO_MEMORY);
794 return NULL;
795 }
796
797 bagType = SECOID_FindOIDByTag(certType);
798 if(!bagType) {
799 PORT_SetError(SEC_ERROR_NO_MEMORY);
800 goto loser;
801 }
802
803 rv = SECITEM_CopyItem(arena, &certBag->bagID, &bagType->oid);
804 if(rv != SECSuccess) {
805 PORT_SetError(SEC_ERROR_NO_MEMORY);
806 goto loser;
807 }
808
809 PORT_ArenaUnmark(arena, mark);
810 return certBag;
811
812 loser:
813 PORT_ArenaRelease(arena, mark);
814 return NULL;
815 }
816
817 /* Creates a new CRL bag and returns a pointer to it. If an error
818 * occurs NULL is returned.
819 */
820 sec_PKCS12CRLBag *
821 sec_PKCS12NewCRLBag(PLArenaPool *arena, SECOidTag crlType)
822 {
823 sec_PKCS12CRLBag *crlBag = NULL;
824 SECOidData *bagType = NULL;
825 SECStatus rv;
826 void *mark = NULL;
827
828 if(!arena) {
829 return NULL;
830 }
831
832 mark = PORT_ArenaMark(arena);
833 crlBag = (sec_PKCS12CRLBag *)PORT_ArenaZAlloc(arena,
834 sizeof(sec_PKCS12CRLBag));
835 if(!crlBag) {
836 PORT_ArenaRelease(arena, mark);
837 PORT_SetError(SEC_ERROR_NO_MEMORY);
838 return NULL;
839 }
840
841 bagType = SECOID_FindOIDByTag(crlType);
842 if(!bagType) {
843 PORT_SetError(SEC_ERROR_NO_MEMORY);
844 goto loser;
845 }
846
847 rv = SECITEM_CopyItem(arena, &crlBag->bagID, &bagType->oid);
848 if(rv != SECSuccess) {
849 PORT_SetError(SEC_ERROR_NO_MEMORY);
850 goto loser;
851 }
852
853 PORT_ArenaUnmark(arena, mark);
854 return crlBag;
855
856 loser:
857 PORT_ArenaRelease(arena, mark);
858 return NULL;
859 }
860
861 /* sec_PKCS12AddAttributeToBag
862 * adds an attribute to a safeBag. currently, the only attributes supported
863 * are those which are specified within PKCS 12.
864 *
865 * p12ctxt - the export context
866 * safeBag - the safeBag to which attributes are appended
867 * attrType - the attribute type
868 * attrData - the attribute data
869 */
870 SECStatus
871 sec_PKCS12AddAttributeToBag(SEC_PKCS12ExportContext *p12ctxt,
872 sec_PKCS12SafeBag *safeBag, SECOidTag attrType,
873 SECItem *attrData)
874 {
875 sec_PKCS12Attribute *attribute;
876 void *mark = NULL, *dummy = NULL;
877 SECOidData *oiddata = NULL;
878 SECItem unicodeName = { siBuffer, NULL, 0};
879 void *src = NULL;
880 unsigned int nItems = 0;
881 SECStatus rv;
882
883 if(!safeBag || !p12ctxt) {
884 return SECFailure;
885 }
886
887 mark = PORT_ArenaMark(safeBag->arena);
888
889 /* allocate the attribute */
890 attribute = (sec_PKCS12Attribute *)PORT_ArenaZAlloc(safeBag->arena,
891 sizeof(sec_PKCS12Attribute));
892 if(!attribute) {
893 PORT_SetError(SEC_ERROR_NO_MEMORY);
894 goto loser;
895 }
896
897 /* set up the attribute */
898 oiddata = SECOID_FindOIDByTag(attrType);
899 if(!oiddata) {
900 PORT_SetError(SEC_ERROR_NO_MEMORY);
901 goto loser;
902 }
903 if(SECITEM_CopyItem(p12ctxt->arena, &attribute->attrType, &oiddata->oid) !=
904 SECSuccess) {
905 PORT_SetError(SEC_ERROR_NO_MEMORY);
906 goto loser;
907 }
908
909 nItems = 1;
910 switch(attrType) {
911 case SEC_OID_PKCS9_LOCAL_KEY_ID:
912 {
913 src = attrData;
914 break;
915 }
916 case SEC_OID_PKCS9_FRIENDLY_NAME:
917 {
918 if(!sec_pkcs12_convert_item_to_unicode(p12ctxt->arena,
919 &unicodeName, attrData, PR_FALSE,
920 PR_FALSE, PR_TRUE)) {
921 goto loser;
922 }
923 src = &unicodeName;
924 break;
925 }
926 default:
927 goto loser;
928 }
929
930 /* append the attribute to the attribute value list */
931 attribute->attrValue = (SECItem **)PORT_ArenaZAlloc(p12ctxt->arena,
932 ((nItems + 1) * sizeof(SECItem *)));
933 if(!attribute->attrValue) {
934 PORT_SetError(SEC_ERROR_NO_MEMORY);
935 goto loser;
936 }
937
938 /* XXX this will need to be changed if attributes requiring more than
939 * one element are ever used.
940 */
941 attribute->attrValue[0] = (SECItem *)PORT_ArenaZAlloc(p12ctxt->arena,
942 sizeof(SECItem));
943 if(!attribute->attrValue[0]) {
944 PORT_SetError(SEC_ERROR_NO_MEMORY);
945 goto loser;
946 }
947 attribute->attrValue[1] = NULL;
948
949 rv = SECITEM_CopyItem(p12ctxt->arena, attribute->attrValue[0],
950 (SECItem*)src);
951 if(rv != SECSuccess) {
952 PORT_SetError(SEC_ERROR_NO_MEMORY);
953 goto loser;
954 }
955
956 /* append the attribute to the safeBag attributes */
957 if(safeBag->nAttribs) {
958 dummy = PORT_ArenaGrow(p12ctxt->arena, safeBag->attribs,
959 ((safeBag->nAttribs + 1) * sizeof(sec_PKCS12Attribute *)),
960 ((safeBag->nAttribs + 2) * sizeof(sec_PKCS12Attribute *)));
961 safeBag->attribs = (sec_PKCS12Attribute **)dummy;
962 } else {
963 safeBag->attribs = (sec_PKCS12Attribute **)PORT_ArenaZAlloc(p12ctxt->arena,
964 2 * sizeof(sec_PKCS12Attribute *));
965 dummy = safeBag->attribs;
966 }
967 if(!dummy) {
968 goto loser;
969 }
970
971 safeBag->attribs[safeBag->nAttribs] = attribute;
972 safeBag->attribs[++safeBag->nAttribs] = NULL;
973
974 PORT_ArenaUnmark(p12ctxt->arena, mark);
975 return SECSuccess;
976
977 loser:
978 if(mark) {
979 PORT_ArenaRelease(p12ctxt->arena, mark);
980 }
981
982 return SECFailure;
983 }
984
985 /* SEC_PKCS12AddCert
986 * Adds a certificate to the data being exported.
987 *
988 * p12ctxt - the export context
989 * safe - the safeInfo to which the certificate is placed
990 * nestedDest - if the cert is to be placed within a nested safeContents then,
991 * this value is to be specified with the destination
992 * cert - the cert to export
993 * certDb - the certificate database handle
994 * keyId - a unique identifier to associate a certificate/key pair
995 * includeCertChain - PR_TRUE if the certificate chain is to be included.
996 */
997 SECStatus
998 SEC_PKCS12AddCert(SEC_PKCS12ExportContext *p12ctxt, SEC_PKCS12SafeInfo *safe,
999 void *nestedDest, CERTCertificate *cert,
1000 CERTCertDBHandle *certDb, SECItem *keyId,
1001 PRBool includeCertChain)
1002 {
1003 sec_PKCS12CertBag *certBag;
1004 sec_PKCS12SafeBag *safeBag;
1005 void *mark;
1006 SECStatus rv;
1007 SECItem nick = {siBuffer, NULL,0};
1008
1009 if(!p12ctxt || !cert) {
1010 return SECFailure;
1011 }
1012 mark = PORT_ArenaMark(p12ctxt->arena);
1013
1014 /* allocate the cert bag */
1015 certBag = sec_PKCS12NewCertBag(p12ctxt->arena,
1016 SEC_OID_PKCS9_X509_CERT);
1017 if(!certBag) {
1018 goto loser;
1019 }
1020
1021 if(SECITEM_CopyItem(p12ctxt->arena, &certBag->value.x509Cert,
1022 &cert->derCert) != SECSuccess) {
1023 PORT_SetError(SEC_ERROR_NO_MEMORY);
1024 goto loser;
1025 }
1026
1027 /* if the cert chain is to be included, we should only be exporting
1028 * the cert from our internal database.
1029 */
1030 if(includeCertChain) {
1031 CERTCertificateList *certList = CERT_CertChainFromCert(cert,
1032 certUsageSSLClient,
1033 PR_TRUE);
1034 unsigned int count = 0;
1035 if(!certList) {
1036 PORT_SetError(SEC_ERROR_NO_MEMORY);
1037 goto loser;
1038 }
1039
1040 /* add cert chain */
1041 for(count = 0; count < (unsigned int)certList->len; count++) {
1042 if(SECITEM_CompareItem(&certList->certs[count], &cert->derCert)
1043 != SECEqual) {
1044 CERTCertificate *tempCert;
1045
1046 /* decode the certificate */
1047 /* XXX
1048 * This was rather silly. The chain is constructed above
1049 * by finding all of the CERTCertificate's in the database.
1050 * Then the chain is put into a CERTCertificateList, which only
1051 * contains the DER. Finally, the DER was decoded, and the
1052 * decoded cert was sent recursively back to this function.
1053 * Beyond being inefficent, this causes data loss (specifically,
1054 * the nickname). Instead, for 3.4, we'll do a lookup by the
1055 * DER, which should return the cached entry.
1056 */
1057 tempCert = CERT_FindCertByDERCert(CERT_GetDefaultCertDB(),
1058 &certList->certs[count]);
1059 if(!tempCert) {
1060 CERT_DestroyCertificateList(certList);
1061 goto loser;
1062 }
1063
1064 /* add the certificate */
1065 if(SEC_PKCS12AddCert(p12ctxt, safe, nestedDest, tempCert,
1066 certDb, NULL, PR_FALSE) != SECSuccess) {
1067 CERT_DestroyCertificate(tempCert);
1068 CERT_DestroyCertificateList(certList);
1069 goto loser;
1070 }
1071 CERT_DestroyCertificate(tempCert);
1072 }
1073 }
1074 CERT_DestroyCertificateList(certList);
1075 }
1076
1077 /* if the certificate has a nickname, we will set the friendly name
1078 * to that.
1079 */
1080 if(cert->nickname) {
1081 if (cert->slot && !PK11_IsInternal(cert->slot)) {
1082 /*
1083 * The cert is coming off of an external token,
1084 * let's strip the token name from the nickname
1085 * and only add what comes after the colon as the
1086 * nickname. -javi
1087 */
1088 char *delimit;
1089
1090 delimit = PORT_Strchr(cert->nickname,':');
1091 if (delimit == NULL) {
1092 nick.data = (unsigned char *)cert->nickname;
1093 nick.len = PORT_Strlen(cert->nickname);
1094 } else {
1095 delimit++;
1096 nick.data = (unsigned char *)PORT_ArenaStrdup(p12ctxt->arena,
1097 delimit);
1098 nick.len = PORT_Strlen(delimit);
1099 }
1100 } else {
1101 nick.data = (unsigned char *)cert->nickname;
1102 nick.len = PORT_Strlen(cert->nickname);
1103 }
1104 }
1105
1106 safeBag = sec_PKCS12CreateSafeBag(p12ctxt, SEC_OID_PKCS12_V1_CERT_BAG_ID,
1107 certBag);
1108 if(!safeBag) {
1109 goto loser;
1110 }
1111
1112 /* add the friendly name and keyId attributes, if necessary */
1113 if(nick.data) {
1114 if(sec_PKCS12AddAttributeToBag(p12ctxt, safeBag,
1115 SEC_OID_PKCS9_FRIENDLY_NAME, &nick)
1116 != SECSuccess) {
1117 goto loser;
1118 }
1119 }
1120
1121 if(keyId) {
1122 if(sec_PKCS12AddAttributeToBag(p12ctxt, safeBag, SEC_OID_PKCS9_LOCAL_KEY_ID,
1123 keyId) != SECSuccess) {
1124 goto loser;
1125 }
1126 }
1127
1128 /* append the cert safeBag */
1129 if(nestedDest) {
1130 rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena,
1131 (sec_PKCS12SafeContents*)nestedDest,
1132 safeBag);
1133 } else {
1134 rv = sec_pkcs12_append_bag(p12ctxt, safe, safeBag);
1135 }
1136
1137 if(rv != SECSuccess) {
1138 goto loser;
1139 }
1140
1141 PORT_ArenaUnmark(p12ctxt->arena, mark);
1142 return SECSuccess;
1143
1144 loser:
1145 if(mark) {
1146 PORT_ArenaRelease(p12ctxt->arena, mark);
1147 }
1148
1149 return SECFailure;
1150 }
1151
1152 /* SEC_PKCS12AddKeyForCert
1153 * Extracts the key associated with a particular certificate and exports
1154 * it.
1155 *
1156 * p12ctxt - the export context
1157 * safe - the safeInfo to place the key in
1158 * nestedDest - the nested safeContents to place a key
1159 * cert - the certificate which the key belongs to
1160 * shroudKey - encrypt the private key for export. This value should
1161 * always be true. lower level code will not allow the export
1162 * of unencrypted private keys.
1163 * algorithm - the algorithm with which to encrypt the private key
1164 * pwitem - the password to encrypt the private key with
1165 * keyId - the keyID attribute
1166 * nickName - the nickname attribute
1167 */
1168 SECStatus
1169 SEC_PKCS12AddKeyForCert(SEC_PKCS12ExportContext *p12ctxt, SEC_PKCS12SafeInfo *safe,
1170 void *nestedDest, CERTCertificate *cert,
1171 PRBool shroudKey, SECOidTag algorithm, SECItem *pwitem,
1172 SECItem *keyId, SECItem *nickName)
1173 {
1174 void *mark;
1175 void *keyItem;
1176 SECOidTag keyType;
1177 SECStatus rv = SECFailure;
1178 SECItem nickname = {siBuffer,NULL,0}, uniPwitem = {siBuffer, NULL, 0};
1179 sec_PKCS12SafeBag *returnBag;
1180
1181 if(!p12ctxt || !cert || !safe) {
1182 return SECFailure;
1183 }
1184
1185 mark = PORT_ArenaMark(p12ctxt->arena);
1186
1187 /* retrieve the key based upon the type that it is and
1188 * specify the type of safeBag to store the key in
1189 */
1190 if(!shroudKey) {
1191
1192 /* extract the key unencrypted. this will most likely go away */
1193 SECKEYPrivateKeyInfo *pki = PK11_ExportPrivateKeyInfo(cert,
1194 p12ctxt->wincx);
1195 if(!pki) {
1196 PORT_ArenaRelease(p12ctxt->arena, mark);
1197 PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY);
1198 return SECFailure;
1199 }
1200 keyItem = PORT_ArenaZAlloc(p12ctxt->arena, sizeof(SECKEYPrivateKeyInfo));
1201 if(!keyItem) {
1202 PORT_SetError(SEC_ERROR_NO_MEMORY);
1203 goto loser;
1204 }
1205 rv = SECKEY_CopyPrivateKeyInfo(p12ctxt->arena,
1206 (SECKEYPrivateKeyInfo *)keyItem, pki);
1207 keyType = SEC_OID_PKCS12_V1_KEY_BAG_ID;
1208 SECKEY_DestroyPrivateKeyInfo(pki, PR_TRUE);
1209 } else {
1210
1211 /* extract the key encrypted */
1212 SECKEYEncryptedPrivateKeyInfo *epki = NULL;
1213 PK11SlotInfo *slot = NULL;
1214
1215 if(!sec_pkcs12_convert_item_to_unicode(p12ctxt->arena, &uniPwitem,
1216 pwitem, PR_TRUE, PR_TRUE, PR_TRUE)) {
1217 PORT_SetError(SEC_ERROR_NO_MEMORY);
1218 goto loser;
1219 }
1220
1221 /* we want to make sure to take the key out of the key slot */
1222 if(PK11_IsInternal(p12ctxt->slot)) {
1223 slot = PK11_GetInternalKeySlot();
1224 } else {
1225 slot = PK11_ReferenceSlot(p12ctxt->slot);
1226 }
1227
1228 epki = PK11_ExportEncryptedPrivateKeyInfo(slot, algorithm,
1229 &uniPwitem, cert,
1230 NSS_PBE_DEFAULT_ITERATION_COUNT,
1231 p12ctxt->wincx);
1232 PK11_FreeSlot(slot);
1233 if(!epki) {
1234 PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY);
1235 goto loser;
1236 }
1237
1238 keyItem = PORT_ArenaZAlloc(p12ctxt->arena,
1239 sizeof(SECKEYEncryptedPrivateKeyInfo));
1240 if(!keyItem) {
1241 PORT_SetError(SEC_ERROR_NO_MEMORY);
1242 goto loser;
1243 }
1244 rv = SECKEY_CopyEncryptedPrivateKeyInfo(p12ctxt->arena,
1245 (SECKEYEncryptedPrivateKeyInfo *)keyItem,
1246 epki);
1247 keyType = SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID;
1248 SECKEY_DestroyEncryptedPrivateKeyInfo(epki, PR_TRUE);
1249 }
1250
1251 if(rv != SECSuccess) {
1252 goto loser;
1253 }
1254
1255 /* if no nickname specified, let's see if the certificate has a
1256 * nickname.
1257 */
1258 if(!nickName) {
1259 if(cert->nickname) {
1260 nickname.data = (unsigned char *)cert->nickname;
1261 nickname.len = PORT_Strlen(cert->nickname);
1262 nickName = &nickname;
1263 }
1264 }
1265
1266 /* create the safe bag and set any attributes */
1267 returnBag = sec_PKCS12CreateSafeBag(p12ctxt, keyType, keyItem);
1268 if(!returnBag) {
1269 rv = SECFailure;
1270 goto loser;
1271 }
1272
1273 if(nickName) {
1274 if(sec_PKCS12AddAttributeToBag(p12ctxt, returnBag,
1275 SEC_OID_PKCS9_FRIENDLY_NAME, nickName)
1276 != SECSuccess) {
1277 goto loser;
1278 }
1279 }
1280
1281 if(keyId) {
1282 if(sec_PKCS12AddAttributeToBag(p12ctxt, returnBag, SEC_OID_PKCS9_LOCAL_KEY_ID,
1283 keyId) != SECSuccess) {
1284 goto loser;
1285 }
1286 }
1287
1288 if(nestedDest) {
1289 rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena,
1290 (sec_PKCS12SafeContents*)nestedDest,
1291 returnBag);
1292 } else {
1293 rv = sec_pkcs12_append_bag(p12ctxt, safe, returnBag);
1294 }
1295
1296 loser:
1297
1298 if (rv != SECSuccess) {
1299 PORT_ArenaRelease(p12ctxt->arena, mark);
1300 } else {
1301 PORT_ArenaUnmark(p12ctxt->arena, mark);
1302 }
1303
1304 return rv;
1305 }
1306
1307 /* SEC_PKCS12AddCertOrChainAndKey
1308 * Add a certificate and key pair to be exported.
1309 *
1310 * p12ctxt - the export context
1311 * certSafe - the safeInfo where the cert is stored
1312 * certNestedDest - the nested safeContents to store the cert
1313 * keySafe - the safeInfo where the key is stored
1314 * keyNestedDest - the nested safeContents to store the key
1315 * shroudKey - extract the private key encrypted?
1316 * pwitem - the password with which the key is encrypted
1317 * algorithm - the algorithm with which the key is encrypted
1318 * includeCertChain - also add certs from chain to bag.
1319 */
1320 SECStatus
1321 SEC_PKCS12AddCertOrChainAndKey(SEC_PKCS12ExportContext *p12ctxt,
1322 void *certSafe, void *certNestedDest,
1323 CERTCertificate *cert, CERTCertDBHandle *certDb,
1324 void *keySafe, void *keyNestedDest,
1325 PRBool shroudKey, SECItem *pwitem,
1326 SECOidTag algorithm, PRBool includeCertChain)
1327 {
1328 SECStatus rv = SECFailure;
1329 SGNDigestInfo *digest = NULL;
1330 void *mark = NULL;
1331
1332 if(!p12ctxt || !certSafe || !keySafe || !cert) {
1333 return SECFailure;
1334 }
1335
1336 mark = PORT_ArenaMark(p12ctxt->arena);
1337
1338 /* generate the thumbprint of the cert to use as a keyId */
1339 digest = sec_pkcs12_compute_thumbprint(&cert->derCert);
1340 if(!digest) {
1341 PORT_ArenaRelease(p12ctxt->arena, mark);
1342 return SECFailure;
1343 }
1344
1345 /* add the certificate */
1346 rv = SEC_PKCS12AddCert(p12ctxt, (SEC_PKCS12SafeInfo*)certSafe,
1347 (SEC_PKCS12SafeInfo*)certNestedDest, cert, certDb,
1348 &digest->digest, includeCertChain);
1349 if(rv != SECSuccess) {
1350 goto loser;
1351 }
1352
1353 /* add the key */
1354 rv = SEC_PKCS12AddKeyForCert(p12ctxt, (SEC_PKCS12SafeInfo*)keySafe,
1355 keyNestedDest, cert,
1356 shroudKey, algorithm, pwitem,
1357 &digest->digest, NULL );
1358 if(rv != SECSuccess) {
1359 goto loser;
1360 }
1361
1362 SGN_DestroyDigestInfo(digest);
1363
1364 PORT_ArenaUnmark(p12ctxt->arena, mark);
1365 return SECSuccess;
1366
1367 loser:
1368 SGN_DestroyDigestInfo(digest);
1369 PORT_ArenaRelease(p12ctxt->arena, mark);
1370
1371 return SECFailure;
1372 }
1373
1374 /* like SEC_PKCS12AddCertOrChainAndKey, but always adds cert chain */
1375 SECStatus
1376 SEC_PKCS12AddCertAndKey(SEC_PKCS12ExportContext *p12ctxt,
1377 void *certSafe, void *certNestedDest,
1378 CERTCertificate *cert, CERTCertDBHandle *certDb,
1379 void *keySafe, void *keyNestedDest,
1380 PRBool shroudKey, SECItem *pwItem, SECOidTag algorithm)
1381 {
1382 return SEC_PKCS12AddCertOrChainAndKey(p12ctxt, certSafe, certNestedDest,
1383 cert, certDb, keySafe, keyNestedDest, shroudKey, pwItem,
1384 algorithm, PR_TRUE);
1385 }
1386
1387
1388 /* SEC_PKCS12CreateNestedSafeContents
1389 * Allows nesting of safe contents to be implemented. No limit imposed on
1390 * depth.
1391 *
1392 * p12ctxt - the export context
1393 * baseSafe - the base safeInfo
1394 * nestedDest - a parent safeContents (?)
1395 */
1396 void *
1397 SEC_PKCS12CreateNestedSafeContents(SEC_PKCS12ExportContext *p12ctxt,
1398 void *baseSafe, void *nestedDest)
1399 {
1400 sec_PKCS12SafeContents *newSafe;
1401 sec_PKCS12SafeBag *safeContentsBag;
1402 void *mark;
1403 SECStatus rv;
1404
1405 if(!p12ctxt || !baseSafe) {
1406 return NULL;
1407 }
1408
1409 mark = PORT_ArenaMark(p12ctxt->arena);
1410
1411 newSafe = sec_PKCS12CreateSafeContents(p12ctxt->arena);
1412 if(!newSafe) {
1413 PORT_ArenaRelease(p12ctxt->arena, mark);
1414 PORT_SetError(SEC_ERROR_NO_MEMORY);
1415 return NULL;
1416 }
1417
1418 /* create the safeContents safeBag */
1419 safeContentsBag = sec_PKCS12CreateSafeBag(p12ctxt,
1420 SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID,
1421 newSafe);
1422 if(!safeContentsBag) {
1423 goto loser;
1424 }
1425
1426 /* append the safeContents to the appropriate area */
1427 if(nestedDest) {
1428 rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena,
1429 (sec_PKCS12SafeContents*)nestedDest,
1430 safeContentsBag);
1431 } else {
1432 rv = sec_pkcs12_append_bag(p12ctxt, (SEC_PKCS12SafeInfo*)baseSafe,
1433 safeContentsBag);
1434 }
1435 if(rv != SECSuccess) {
1436 goto loser;
1437 }
1438
1439 PORT_ArenaUnmark(p12ctxt->arena, mark);
1440 return newSafe;
1441
1442 loser:
1443 PORT_ArenaRelease(p12ctxt->arena, mark);
1444 return NULL;
1445 }
1446
1447 /*********************************
1448 * Encoding routines
1449 *********************************/
1450
1451 /* Clean up the resources allocated by a sec_PKCS12EncoderContext. */
1452 static void
1453 sec_pkcs12_encoder_destroy_context(sec_PKCS12EncoderContext *p12enc)
1454 {
1455 if(p12enc) {
1456 if(p12enc->outerA1ecx) {
1457 SEC_ASN1EncoderFinish(p12enc->outerA1ecx);
1458 p12enc->outerA1ecx = NULL;
1459 }
1460 if(p12enc->aSafeCinfo) {
1461 SEC_PKCS7DestroyContentInfo(p12enc->aSafeCinfo);
1462 p12enc->aSafeCinfo = NULL;
1463 }
1464 if(p12enc->middleP7ecx) {
1465 SEC_PKCS7EncoderFinish(p12enc->middleP7ecx, p12enc->p12exp->pwfn,
1466 p12enc->p12exp->pwfnarg);
1467 p12enc->middleP7ecx = NULL;
1468 }
1469 if(p12enc->middleA1ecx) {
1470 SEC_ASN1EncoderFinish(p12enc->middleA1ecx);
1471 p12enc->middleA1ecx = NULL;
1472 }
1473 if(p12enc->hmacCx) {
1474 PK11_DestroyContext(p12enc->hmacCx, PR_TRUE);
1475 p12enc->hmacCx = NULL;
1476 }
1477 }
1478 }
1479
1480 /* set up the encoder context based on information in the export context
1481 * and return the newly allocated enocoder context. A return of NULL
1482 * indicates an error occurred.
1483 */
1484 static sec_PKCS12EncoderContext *
1485 sec_pkcs12_encoder_start_context(SEC_PKCS12ExportContext *p12exp)
1486 {
1487 sec_PKCS12EncoderContext *p12enc = NULL;
1488 unsigned int i, nonEmptyCnt;
1489 SECStatus rv;
1490 SECItem ignore = {0};
1491 void *mark;
1492
1493 if(!p12exp || !p12exp->safeInfos) {
1494 return NULL;
1495 }
1496
1497 /* check for any empty safes and skip them */
1498 i = nonEmptyCnt = 0;
1499 while(p12exp->safeInfos[i]) {
1500 if(p12exp->safeInfos[i]->itemCount) {
1501 nonEmptyCnt++;
1502 }
1503 i++;
1504 }
1505 if(nonEmptyCnt == 0) {
1506 return NULL;
1507 }
1508 p12exp->authSafe.encodedSafes[nonEmptyCnt] = NULL;
1509
1510 /* allocate the encoder context */
1511 mark = PORT_ArenaMark(p12exp->arena);
1512 p12enc = PORT_ArenaZNew(p12exp->arena, sec_PKCS12EncoderContext);
1513 if(!p12enc) {
1514 PORT_SetError(SEC_ERROR_NO_MEMORY);
1515 return NULL;
1516 }
1517
1518 p12enc->arena = p12exp->arena;
1519 p12enc->p12exp = p12exp;
1520
1521 /* set up the PFX version and information */
1522 PORT_Memset(&p12enc->pfx, 0, sizeof(sec_PKCS12PFXItem));
1523 if(!SEC_ASN1EncodeInteger(p12exp->arena, &(p12enc->pfx.version),
1524 SEC_PKCS12_VERSION) ) {
1525 PORT_SetError(SEC_ERROR_NO_MEMORY);
1526 goto loser;
1527 }
1528
1529 /* set up the authenticated safe content info based on the
1530 * type of integrity being used. this should be changed to
1531 * enforce integrity mode, but will not be implemented until
1532 * it is confirmed that integrity must be in place
1533 */
1534 if(p12exp->integrityEnabled && !p12exp->pwdIntegrity) {
1535 SECStatus rv;
1536
1537 /* create public key integrity mode */
1538 p12enc->aSafeCinfo = SEC_PKCS7CreateSignedData(
1539 p12exp->integrityInfo.pubkeyInfo.cert,
1540 certUsageEmailSigner,
1541 p12exp->integrityInfo.pubkeyInfo.certDb,
1542 p12exp->integrityInfo.pubkeyInfo.algorithm,
1543 NULL,
1544 p12exp->pwfn,
1545 p12exp->pwfnarg);
1546 if(!p12enc->aSafeCinfo) {
1547 goto loser;
1548 }
1549 if(SEC_PKCS7IncludeCertChain(p12enc->aSafeCinfo,NULL) != SECSuccess) {
1550 goto loser;
1551 }
1552 rv = SEC_PKCS7AddSigningTime(p12enc->aSafeCinfo);
1553 PORT_Assert(rv == SECSuccess);
1554 } else {
1555 p12enc->aSafeCinfo = SEC_PKCS7CreateData();
1556
1557 /* init password pased integrity mode */
1558 if(p12exp->integrityEnabled) {
1559 SECItem pwd = {siBuffer,NULL, 0};
1560 SECItem *salt = sec_pkcs12_generate_salt();
1561 PK11SymKey *symKey;
1562 SECItem *params;
1563 CK_MECHANISM_TYPE integrityMechType;
1564 CK_MECHANISM_TYPE hmacMechType;
1565
1566 /* zero out macData and set values */
1567 PORT_Memset(&p12enc->mac, 0, sizeof(sec_PKCS12MacData));
1568
1569 if(!salt) {
1570 PORT_SetError(SEC_ERROR_NO_MEMORY);
1571 goto loser;
1572 }
1573 if(SECITEM_CopyItem(p12exp->arena, &(p12enc->mac.macSalt), salt)
1574 != SECSuccess) {
1575 /* XXX salt is leaked */
1576 PORT_SetError(SEC_ERROR_NO_MEMORY);
1577 goto loser;
1578 }
1579 if (!SEC_ASN1EncodeInteger(p12exp->arena, &(p12enc->mac.iter),
1580 NSS_PBE_DEFAULT_ITERATION_COUNT)) {
1581 /* XXX salt is leaked */
1582 goto loser;
1583 }
1584
1585 /* generate HMAC key */
1586 if(!sec_pkcs12_convert_item_to_unicode(NULL, &pwd,
1587 p12exp->integrityInfo.pwdInfo.password, PR_TRUE,
1588 PR_TRUE, PR_TRUE)) {
1589 /* XXX salt is leaked */
1590 goto loser;
1591 }
1592 /*
1593 * This code only works with PKCS #12 Mac using PKCS #5 v1
1594 * PBA keygens. PKCS #5 v2 support will require a change to
1595 * the PKCS #12 spec.
1596 */
1597 params = PK11_CreatePBEParams(salt, &pwd,
1598 NSS_PBE_DEFAULT_ITERATION_COUNT);
1599 SECITEM_ZfreeItem(salt, PR_TRUE);
1600 SECITEM_ZfreeItem(&pwd, PR_FALSE);
1601
1602 /* get the PBA Mechanism to generate the key */
1603 switch (p12exp->integrityInfo.pwdInfo.algorithm) {
1604 case SEC_OID_SHA1:
1605 integrityMechType = CKM_PBA_SHA1_WITH_SHA1_HMAC; break;
1606 case SEC_OID_MD5:
1607 integrityMechType = CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN; break;
1608 case SEC_OID_MD2:
1609 integrityMechType = CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN; break;
1610 default:
1611 /* XXX params is leaked */
1612 goto loser;
1613 }
1614
1615 /* generate the key */
1616 symKey = PK11_KeyGen(NULL, integrityMechType, params, 20, NULL);
1617 PK11_DestroyPBEParams(params);
1618 if(!symKey) {
1619 goto loser;
1620 }
1621
1622 /* initialize HMAC */
1623 /* Get the HMAC mechanism from the hash OID */
1624 hmacMechType= sec_pkcs12_algtag_to_mech(
1625 p12exp->integrityInfo.pwdInfo.algorithm);
1626
1627 p12enc->hmacCx = PK11_CreateContextBySymKey( hmacMechType,
1628 CKA_SIGN, symKey, &ignore);
1629
1630 PK11_FreeSymKey(symKey);
1631 if(!p12enc->hmacCx) {
1632 PORT_SetError(SEC_ERROR_NO_MEMORY);
1633 goto loser;
1634 }
1635 rv = PK11_DigestBegin(p12enc->hmacCx);
1636 if (rv != SECSuccess)
1637 goto loser;
1638 }
1639 }
1640
1641 if(!p12enc->aSafeCinfo) {
1642 goto loser;
1643 }
1644
1645 PORT_ArenaUnmark(p12exp->arena, mark);
1646
1647 return p12enc;
1648
1649 loser:
1650 sec_pkcs12_encoder_destroy_context(p12enc);
1651 if (p12exp->arena != NULL)
1652 PORT_ArenaRelease(p12exp->arena, mark);
1653
1654 return NULL;
1655 }
1656
1657 /* The outermost ASN.1 encoder calls this function for output.
1658 ** This function calls back to the library caller's output routine,
1659 ** which typically writes to a PKCS12 file.
1660 */
1661 static void
1662 sec_P12A1OutputCB_Outer(void *arg, const char *buf, unsigned long len,
1663 int depth, SEC_ASN1EncodingPart data_kind)
1664 {
1665 struct sec_pkcs12_encoder_output *output;
1666
1667 output = (struct sec_pkcs12_encoder_output*)arg;
1668 (* output->outputfn)(output->outputarg, buf, len);
1669 }
1670
1671 /* The "middle" and "inner" ASN.1 encoders call this function to output.
1672 ** This function does HMACing, if appropriate, and then buffers the data.
1673 ** The buffered data is eventually passed down to the underlying PKCS7 encoder.
1674 */
1675 static void
1676 sec_P12A1OutputCB_HmacP7Update(void *arg, const char *buf,
1677 unsigned long len,
1678 int depth,
1679 SEC_ASN1EncodingPart data_kind)
1680 {
1681 sec_pkcs12OutputBuffer * bufcx = (sec_pkcs12OutputBuffer *)arg;
1682
1683 if(!buf || !len)
1684 return;
1685
1686 if (bufcx->hmacCx) {
1687 PK11_DigestOp(bufcx->hmacCx, (unsigned char *)buf, len);
1688 }
1689
1690 /* buffer */
1691 if (bufcx->numBytes > 0) {
1692 int toCopy;
1693 if (len + bufcx->numBytes <= bufcx->bufBytes) {
1694 memcpy(bufcx->buf + bufcx->numBytes, buf, len);
1695 bufcx->numBytes += len;
1696 if (bufcx->numBytes < bufcx->bufBytes)
1697 return;
1698 SEC_PKCS7EncoderUpdate(bufcx->p7eCx, bufcx->buf, bufcx->bufBytes);
1699 bufcx->numBytes = 0;
1700 return;
1701 }
1702 toCopy = bufcx->bufBytes - bufcx->numBytes;
1703 memcpy(bufcx->buf + bufcx->numBytes, buf, toCopy);
1704 SEC_PKCS7EncoderUpdate(bufcx->p7eCx, bufcx->buf, bufcx->bufBytes);
1705 bufcx->numBytes = 0;
1706 len -= toCopy;
1707 buf += toCopy;
1708 }
1709 /* buffer is presently empty */
1710 if (len >= bufcx->bufBytes) {
1711 /* Just pass it through */
1712 SEC_PKCS7EncoderUpdate(bufcx->p7eCx, buf, len);
1713 } else {
1714 /* copy it all into the buffer, and return */
1715 memcpy(bufcx->buf, buf, len);
1716 bufcx->numBytes = len;
1717 }
1718 }
1719
1720 void
1721 sec_FlushPkcs12OutputBuffer( sec_pkcs12OutputBuffer * bufcx)
1722 {
1723 if (bufcx->numBytes > 0) {
1724 SEC_PKCS7EncoderUpdate(bufcx->p7eCx, bufcx->buf, bufcx->numBytes);
1725 bufcx->numBytes = 0;
1726 }
1727 }
1728
1729 /* Feeds the output of a PKCS7 encoder into the next outward ASN.1 encoder.
1730 ** This function is used by both the inner and middle PCS7 encoders.
1731 */
1732 static void
1733 sec_P12P7OutputCB_CallA1Update(void *arg, const char *buf, unsigned long len)
1734 {
1735 SEC_ASN1EncoderContext *cx = (SEC_ASN1EncoderContext*)arg;
1736
1737 if (!buf || !len)
1738 return;
1739
1740 SEC_ASN1EncoderUpdate(cx, buf, len);
1741 }
1742
1743
1744 /* this function encodes content infos which are part of the
1745 * sequence of content infos labeled AuthenticatedSafes
1746 */
1747 static SECStatus
1748 sec_pkcs12_encoder_asafe_process(sec_PKCS12EncoderContext *p12ecx)
1749 {
1750 SEC_PKCS7EncoderContext *innerP7ecx;
1751 SEC_PKCS7ContentInfo *cinfo;
1752 PK11SymKey *bulkKey = NULL;
1753 SEC_ASN1EncoderContext *innerA1ecx = NULL;
1754 SECStatus rv = SECSuccess;
1755
1756 if(p12ecx->currentSafe < p12ecx->p12exp->authSafe.safeCount) {
1757 SEC_PKCS12SafeInfo *safeInfo;
1758 SECOidTag cinfoType;
1759
1760 safeInfo = p12ecx->p12exp->safeInfos[p12ecx->currentSafe];
1761
1762 /* skip empty safes */
1763 if(safeInfo->itemCount == 0) {
1764 return SECSuccess;
1765 }
1766
1767 cinfo = safeInfo->cinfo;
1768 cinfoType = SEC_PKCS7ContentType(cinfo);
1769
1770 /* determine the safe type and set the appropriate argument */
1771 switch(cinfoType) {
1772 case SEC_OID_PKCS7_DATA:
1773 case SEC_OID_PKCS7_ENVELOPED_DATA:
1774 break;
1775 case SEC_OID_PKCS7_ENCRYPTED_DATA:
1776 bulkKey = safeInfo->encryptionKey;
1777 PK11_SetSymKeyUserData(bulkKey, &safeInfo->pwitem, NULL);
1778 break;
1779 default:
1780 return SECFailure;
1781
1782 }
1783
1784 /* start the PKCS7 encoder */
1785 innerP7ecx = SEC_PKCS7EncoderStart(cinfo,
1786 sec_P12P7OutputCB_CallA1Update,
1787 p12ecx->middleA1ecx, bulkKey);
1788 if(!innerP7ecx) {
1789 goto loser;
1790 }
1791
1792 /* encode safe contents */
1793 p12ecx->innerBuf.p7eCx = innerP7ecx;
1794 p12ecx->innerBuf.hmacCx = NULL;
1795 p12ecx->innerBuf.numBytes = 0;
1796 p12ecx->innerBuf.bufBytes = sizeof p12ecx->innerBuf.buf;
1797
1798 innerA1ecx = SEC_ASN1EncoderStart(safeInfo->safe,
1799 sec_PKCS12SafeContentsTemplate,
1800 sec_P12A1OutputCB_HmacP7Update,
1801 &p12ecx->innerBuf);
1802 if(!innerA1ecx) {
1803 goto loser;
1804 }
1805 rv = SEC_ASN1EncoderUpdate(innerA1ecx, NULL, 0);
1806 SEC_ASN1EncoderFinish(innerA1ecx);
1807 sec_FlushPkcs12OutputBuffer( &p12ecx->innerBuf);
1808 innerA1ecx = NULL;
1809 if(rv != SECSuccess) {
1810 goto loser;
1811 }
1812
1813
1814 /* finish up safe content info */
1815 rv = SEC_PKCS7EncoderFinish(innerP7ecx, p12ecx->p12exp->pwfn,
1816 p12ecx->p12exp->pwfnarg);
1817 }
1818 memset(&p12ecx->innerBuf, 0, sizeof p12ecx->innerBuf);
1819 return SECSuccess;
1820
1821 loser:
1822 if(innerP7ecx) {
1823 SEC_PKCS7EncoderFinish(innerP7ecx, p12ecx->p12exp->pwfn,
1824 p12ecx->p12exp->pwfnarg);
1825 }
1826
1827 if(innerA1ecx) {
1828 SEC_ASN1EncoderFinish(innerA1ecx);
1829 }
1830 memset(&p12ecx->innerBuf, 0, sizeof p12ecx->innerBuf);
1831 return SECFailure;
1832 }
1833
1834 /* finish the HMAC and encode the macData so that it can be
1835 * encoded.
1836 */
1837 static SECStatus
1838 sec_Pkcs12FinishMac(sec_PKCS12EncoderContext *p12ecx)
1839 {
1840 SECItem hmac = { siBuffer, NULL, 0 };
1841 SECStatus rv;
1842 SGNDigestInfo *di = NULL;
1843 void *dummy;
1844
1845 if(!p12ecx) {
1846 return SECFailure;
1847 }
1848
1849 /* make sure we are using password integrity mode */
1850 if(!p12ecx->p12exp->integrityEnabled) {
1851 return SECSuccess;
1852 }
1853
1854 if(!p12ecx->p12exp->pwdIntegrity) {
1855 return SECSuccess;
1856 }
1857
1858 /* finish the hmac */
1859 hmac.data = (unsigned char *)PORT_ZAlloc(SHA1_LENGTH);
1860 if(!hmac.data) {
1861 PORT_SetError(SEC_ERROR_NO_MEMORY);
1862 return SECFailure;
1863 }
1864
1865 rv = PK11_DigestFinal(p12ecx->hmacCx, hmac.data, &hmac.len, SHA1_LENGTH);
1866
1867 if(rv != SECSuccess) {
1868 PORT_SetError(SEC_ERROR_NO_MEMORY);
1869 goto loser;
1870 }
1871
1872 /* create the digest info */
1873 di = SGN_CreateDigestInfo(p12ecx->p12exp->integrityInfo.pwdInfo.algorithm,
1874 hmac.data, hmac.len);
1875 if(!di) {
1876 PORT_SetError(SEC_ERROR_NO_MEMORY);
1877 rv = SECFailure;
1878 goto loser;
1879 }
1880
1881 rv = SGN_CopyDigestInfo(p12ecx->arena, &p12ecx->mac.safeMac, di);
1882 if(rv != SECSuccess) {
1883 PORT_SetError(SEC_ERROR_NO_MEMORY);
1884 goto loser;
1885 }
1886
1887 /* encode the mac data */
1888 dummy = SEC_ASN1EncodeItem(p12ecx->arena, &p12ecx->pfx.encodedMacData,
1889 &p12ecx->mac, sec_PKCS12MacDataTemplate);
1890 if(!dummy) {
1891 PORT_SetError(SEC_ERROR_NO_MEMORY);
1892 rv = SECFailure;
1893 }
1894
1895 loser:
1896 if(di) {
1897 SGN_DestroyDigestInfo(di);
1898 }
1899 if(hmac.data) {
1900 SECITEM_ZfreeItem(&hmac, PR_FALSE);
1901 }
1902 PK11_DestroyContext(p12ecx->hmacCx, PR_TRUE);
1903 p12ecx->hmacCx = NULL;
1904
1905 return rv;
1906 }
1907
1908 /* pfx notify function for ASN1 encoder.
1909 * We want to stop encoding once we reach the authenticated safe.
1910 * At that point, the encoder will be updated via streaming
1911 * as the authenticated safe is encoded.
1912 */
1913 static void
1914 sec_pkcs12_encoder_pfx_notify(void *arg, PRBool before, void *dest, int real_depth)
1915 {
1916 sec_PKCS12EncoderContext *p12ecx;
1917
1918 if(!before) {
1919 return;
1920 }
1921
1922 /* look for authenticated safe */
1923 p12ecx = (sec_PKCS12EncoderContext*)arg;
1924 if(dest != &p12ecx->pfx.encodedAuthSafe) {
1925 return;
1926 }
1927
1928 SEC_ASN1EncoderSetTakeFromBuf(p12ecx->outerA1ecx);
1929 SEC_ASN1EncoderSetStreaming(p12ecx->outerA1ecx);
1930 SEC_ASN1EncoderClearNotifyProc(p12ecx->outerA1ecx);
1931 }
1932
1933 /* SEC_PKCS12Encode
1934 * Encodes the PFX item and returns it to the output function, via
1935 * callback. the output function must be capable of multiple updates.
1936 *
1937 * p12exp - the export context
1938 * output - the output function callback, will be called more than once,
1939 * must be able to accept streaming data.
1940 * outputarg - argument for the output callback.
1941 */
1942 SECStatus
1943 SEC_PKCS12Encode(SEC_PKCS12ExportContext *p12exp,
1944 SEC_PKCS12EncoderOutputCallback output, void *outputarg)
1945 {
1946 sec_PKCS12EncoderContext *p12enc;
1947 struct sec_pkcs12_encoder_output outInfo;
1948 SECStatus rv;
1949
1950 if(!p12exp || !output) {
1951 return SECFailure;
1952 }
1953
1954 /* get the encoder context */
1955 p12enc = sec_pkcs12_encoder_start_context(p12exp);
1956 if(!p12enc) {
1957 return SECFailure;
1958 }
1959
1960 outInfo.outputfn = output;
1961 outInfo.outputarg = outputarg;
1962
1963 /* set up PFX encoder, the "outer" encoder. Set it for streaming */
1964 p12enc->outerA1ecx = SEC_ASN1EncoderStart(&p12enc->pfx,
1965 sec_PKCS12PFXItemTemplate,
1966 sec_P12A1OutputCB_Outer,
1967 &outInfo);
1968 if(!p12enc->outerA1ecx) {
1969 PORT_SetError(SEC_ERROR_NO_MEMORY);
1970 rv = SECFailure;
1971 goto loser;
1972 }
1973 SEC_ASN1EncoderSetStreaming(p12enc->outerA1ecx);
1974 SEC_ASN1EncoderSetNotifyProc(p12enc->outerA1ecx,
1975 sec_pkcs12_encoder_pfx_notify, p12enc);
1976 rv = SEC_ASN1EncoderUpdate(p12enc->outerA1ecx, NULL, 0);
1977 if(rv != SECSuccess) {
1978 rv = SECFailure;
1979 goto loser;
1980 }
1981
1982 /* set up asafe cinfo - the output of the encoder feeds the PFX encoder */
1983 p12enc->middleP7ecx = SEC_PKCS7EncoderStart(p12enc->aSafeCinfo,
1984 sec_P12P7OutputCB_CallA1Update,
1985 p12enc->outerA1ecx, NULL);
1986 if(!p12enc->middleP7ecx) {
1987 rv = SECFailure;
1988 goto loser;
1989 }
1990
1991 /* encode asafe */
1992 p12enc->middleBuf.p7eCx = p12enc->middleP7ecx;
1993 p12enc->middleBuf.hmacCx = NULL;
1994 p12enc->middleBuf.numBytes = 0;
1995 p12enc->middleBuf.bufBytes = sizeof p12enc->middleBuf.buf;
1996
1997 /* Setup the "inner ASN.1 encoder for Authenticated Safes. */
1998 if(p12enc->p12exp->integrityEnabled &&
1999 p12enc->p12exp->pwdIntegrity) {
2000 p12enc->middleBuf.hmacCx = p12enc->hmacCx;
2001 }
2002 p12enc->middleA1ecx = SEC_ASN1EncoderStart(&p12enc->p12exp->authSafe,
2003 sec_PKCS12AuthenticatedSafeTemplate,
2004 sec_P12A1OutputCB_HmacP7Update,
2005 &p12enc->middleBuf);
2006 if(!p12enc->middleA1ecx) {
2007 rv = SECFailure;
2008 goto loser;
2009 }
2010 SEC_ASN1EncoderSetStreaming(p12enc->middleA1ecx);
2011 SEC_ASN1EncoderSetTakeFromBuf(p12enc->middleA1ecx);
2012
2013 /* encode each of the safes */
2014 while(p12enc->currentSafe != p12enc->p12exp->safeInfoCount) {
2015 sec_pkcs12_encoder_asafe_process(p12enc);
2016 p12enc->currentSafe++;
2017 }
2018 SEC_ASN1EncoderClearTakeFromBuf(p12enc->middleA1ecx);
2019 SEC_ASN1EncoderClearStreaming(p12enc->middleA1ecx);
2020 SEC_ASN1EncoderUpdate(p12enc->middleA1ecx, NULL, 0);
2021 SEC_ASN1EncoderFinish(p12enc->middleA1ecx);
2022 p12enc->middleA1ecx = NULL;
2023
2024 sec_FlushPkcs12OutputBuffer( &p12enc->middleBuf);
2025
2026 /* finish the encoding of the authenticated safes */
2027 rv = SEC_PKCS7EncoderFinish(p12enc->middleP7ecx, p12exp->pwfn,
2028 p12exp->pwfnarg);
2029 p12enc->middleP7ecx = NULL;
2030 if(rv != SECSuccess) {
2031 goto loser;
2032 }
2033
2034 SEC_ASN1EncoderClearTakeFromBuf(p12enc->outerA1ecx);
2035 SEC_ASN1EncoderClearStreaming(p12enc->outerA1ecx);
2036
2037 /* update the mac, if necessary */
2038 rv = sec_Pkcs12FinishMac(p12enc);
2039 if(rv != SECSuccess) {
2040 goto loser;
2041 }
2042
2043 /* finish encoding the pfx */
2044 rv = SEC_ASN1EncoderUpdate(p12enc->outerA1ecx, NULL, 0);
2045
2046 SEC_ASN1EncoderFinish(p12enc->outerA1ecx);
2047 p12enc->outerA1ecx = NULL;
2048
2049 loser:
2050 sec_pkcs12_encoder_destroy_context(p12enc);
2051 return rv;
2052 }
2053
2054 void
2055 SEC_PKCS12DestroyExportContext(SEC_PKCS12ExportContext *p12ecx)
2056 {
2057 int i = 0;
2058
2059 if(!p12ecx) {
2060 return;
2061 }
2062
2063 if(p12ecx->safeInfos) {
2064 i = 0;
2065 while(p12ecx->safeInfos[i] != NULL) {
2066 if(p12ecx->safeInfos[i]->encryptionKey) {
2067 PK11_FreeSymKey(p12ecx->safeInfos[i]->encryptionKey);
2068 }
2069 if(p12ecx->safeInfos[i]->cinfo) {
2070 SEC_PKCS7DestroyContentInfo(p12ecx->safeInfos[i]->cinfo);
2071 }
2072 i++;
2073 }
2074 }
2075
2076 PK11_FreeSlot(p12ecx->slot);
2077
2078 PORT_FreeArena(p12ecx->arena, PR_TRUE);
2079 }

mercurial