Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
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/. */
5 #include "plarena.h"
6 #include "secitem.h"
7 #include "secoid.h"
8 #include "seccomon.h"
9 #include "secport.h"
10 #include "cert.h"
11 #include "pkcs12.h"
12 #include "p12local.h"
13 #include "secpkcs7.h"
14 #include "secasn1.h"
15 #include "secerr.h"
16 #include "p12plcy.h"
18 /* release the memory taken up by the list of nicknames */
19 static void
20 sec_pkcs12_destroy_nickname_list(SECItem **nicknames)
21 {
22 int i = 0;
24 if(nicknames == NULL) {
25 return;
26 }
28 while(nicknames[i] != NULL) {
29 SECITEM_FreeItem(nicknames[i], PR_FALSE);
30 i++;
31 }
33 PORT_Free(nicknames);
34 }
36 /* release the memory taken up by the list of certificates */
37 static void
38 sec_pkcs12_destroy_certificate_list(CERTCertificate **ref_certs)
39 {
40 int i = 0;
42 if(ref_certs == NULL) {
43 return;
44 }
46 while(ref_certs[i] != NULL) {
47 CERT_DestroyCertificate(ref_certs[i]);
48 i++;
49 }
50 }
52 static void
53 sec_pkcs12_destroy_cinfos_for_cert_bags(SEC_PKCS12CertAndCRLBag *certBag)
54 {
55 int j = 0;
56 j = 0;
57 while(certBag->certAndCRLs[j] != NULL) {
58 SECOidTag certType = SECOID_FindOIDTag(&certBag->certAndCRLs[j]->BagID);
59 if(certType == SEC_OID_PKCS12_X509_CERT_CRL_BAG) {
60 SEC_PKCS12X509CertCRL *x509;
61 x509 = certBag->certAndCRLs[j]->value.x509;
62 SEC_PKCS7DestroyContentInfo(&x509->certOrCRL);
63 }
64 j++;
65 }
66 }
68 /* destroy all content infos since they were not allocated in common
69 * pool
70 */
71 static void
72 sec_pkcs12_destroy_cert_content_infos(SEC_PKCS12SafeContents *safe,
73 SEC_PKCS12Baggage *baggage)
74 {
75 int i, j;
77 if((safe != NULL) && (safe->contents != NULL)) {
78 i = 0;
79 while(safe->contents[i] != NULL) {
80 SECOidTag bagType = SECOID_FindOIDTag(&safe->contents[i]->safeBagType);
81 if(bagType == SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID) {
82 SEC_PKCS12CertAndCRLBag *certBag;
83 certBag = safe->contents[i]->safeContent.certAndCRLBag;
84 sec_pkcs12_destroy_cinfos_for_cert_bags(certBag);
85 }
86 i++;
87 }
88 }
90 if((baggage != NULL) && (baggage->bags != NULL)) {
91 i = 0;
92 while(baggage->bags[i] != NULL) {
93 if(baggage->bags[i]->unencSecrets != NULL) {
94 j = 0;
95 while(baggage->bags[i]->unencSecrets[j] != NULL) {
96 SECOidTag bagType;
97 bagType = SECOID_FindOIDTag(&baggage->bags[i]->unencSecrets[j]->safeBagType);
98 if(bagType == SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID) {
99 SEC_PKCS12CertAndCRLBag *certBag;
100 certBag = baggage->bags[i]->unencSecrets[j]->safeContent.certAndCRLBag;
101 sec_pkcs12_destroy_cinfos_for_cert_bags(certBag);
102 }
103 j++;
104 }
105 }
106 i++;
107 }
108 }
109 }
111 /* convert the nickname list from a NULL termincated Char list
112 * to a NULL terminated SECItem list
113 */
114 static SECItem **
115 sec_pkcs12_convert_nickname_list(char **nicknames)
116 {
117 SECItem **nicks;
118 int i, j;
119 PRBool error = PR_FALSE;
121 if(nicknames == NULL) {
122 return NULL;
123 }
125 i = j = 0;
126 while(nicknames[i] != NULL) {
127 i++;
128 }
130 /* allocate the space and copy the data */
131 nicks = (SECItem **)PORT_ZAlloc(sizeof(SECItem *) * (i + 1));
132 if(nicks != NULL) {
133 for(j = 0; ((j < i) && (error == PR_FALSE)); j++) {
134 nicks[j] = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
135 if(nicks[j] != NULL) {
136 nicks[j]->data =
137 (unsigned char *)PORT_ZAlloc(PORT_Strlen(nicknames[j])+1);
138 if(nicks[j]->data != NULL) {
139 nicks[j]->len = PORT_Strlen(nicknames[j]);
140 PORT_Memcpy(nicks[j]->data, nicknames[j], nicks[j]->len);
141 nicks[j]->data[nicks[j]->len] = 0;
142 } else {
143 error = PR_TRUE;
144 }
145 } else {
146 error = PR_TRUE;
147 }
148 }
149 }
151 if(error == PR_TRUE) {
152 for(i = 0; i < j; i++) {
153 SECITEM_FreeItem(nicks[i], PR_TRUE);
154 }
155 PORT_Free(nicks);
156 nicks = NULL;
157 }
159 return nicks;
160 }
162 /* package the certificate add_cert into PKCS12 structures,
163 * retrieve the certificate chain for the cert and return
164 * the packaged contents.
165 * poolp -- common memory pool;
166 * add_cert -- certificate to package up
167 * nickname for the certificate
168 * a return of NULL indicates an error
169 */
170 static SEC_PKCS12CertAndCRL *
171 sec_pkcs12_get_cert(PLArenaPool *poolp,
172 CERTCertificate *add_cert,
173 SECItem *nickname)
174 {
175 SEC_PKCS12CertAndCRL *cert;
176 SEC_PKCS7ContentInfo *cinfo;
177 SGNDigestInfo *t_di;
178 void *mark;
179 SECStatus rv;
181 if((poolp == NULL) || (add_cert == NULL) || (nickname == NULL)) {
182 return NULL;
183 }
184 mark = PORT_ArenaMark(poolp);
186 cert = sec_pkcs12_new_cert_crl(poolp, SEC_OID_PKCS12_X509_CERT_CRL_BAG);
187 if(cert != NULL) {
189 /* copy the nickname */
190 rv = SECITEM_CopyItem(poolp, &cert->nickname, nickname);
191 if(rv != SECSuccess) {
192 PORT_SetError(SEC_ERROR_NO_MEMORY);
193 cert = NULL;
194 } else {
196 /* package the certificate and cert chain into a NULL signer
197 * PKCS 7 SignedData content Info and prepare it for encoding
198 * since we cannot use DER_ANY_TEMPLATE
199 */
200 cinfo = SEC_PKCS7CreateCertsOnly(add_cert, PR_TRUE, NULL);
201 rv = SEC_PKCS7PrepareForEncode(cinfo, NULL, NULL, NULL);
203 /* thumbprint the certificate */
204 if((cinfo != NULL) && (rv == SECSuccess))
205 {
206 PORT_Memcpy(&cert->value.x509->certOrCRL, cinfo, sizeof(*cinfo));
207 t_di = sec_pkcs12_compute_thumbprint(&add_cert->derCert);
208 if(t_di != NULL)
209 {
210 /* test */
211 rv = SGN_CopyDigestInfo(poolp, &cert->value.x509->thumbprint,
212 t_di);
213 if(rv != SECSuccess) {
214 cert = NULL;
215 PORT_SetError(SEC_ERROR_NO_MEMORY);
216 }
217 SGN_DestroyDigestInfo(t_di);
218 }
219 else
220 cert = NULL;
221 }
222 }
223 }
225 if (cert == NULL) {
226 PORT_ArenaRelease(poolp, mark);
227 } else {
228 PORT_ArenaUnmark(poolp, mark);
229 }
231 return cert;
232 }
234 /* package the private key associated with the certificate and
235 * return the appropriate PKCS 12 structure
236 * poolp common memory pool
237 * nickname key nickname
238 * cert -- cert to look up
239 * wincx -- window handle
240 * an error is indicated by a return of NULL
241 */
242 static SEC_PKCS12PrivateKey *
243 sec_pkcs12_get_private_key(PLArenaPool *poolp,
244 SECItem *nickname,
245 CERTCertificate *cert,
246 void *wincx)
247 {
248 SECKEYPrivateKeyInfo *pki;
249 SEC_PKCS12PrivateKey *pk;
250 SECStatus rv;
251 void *mark;
253 if((poolp == NULL) || (nickname == NULL)) {
254 return NULL;
255 }
257 mark = PORT_ArenaMark(poolp);
259 /* retrieve key from the data base */
260 pki = PK11_ExportPrivateKeyInfo(nickname, cert, wincx);
261 if(pki == NULL) {
262 PORT_ArenaRelease(poolp, mark);
263 PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY);
264 return NULL;
265 }
267 pk = (SEC_PKCS12PrivateKey *)PORT_ArenaZAlloc(poolp,
268 sizeof(SEC_PKCS12PrivateKey));
269 if(pk != NULL) {
270 rv = sec_pkcs12_init_pvk_data(poolp, &pk->pvkData);
272 if(rv == SECSuccess) {
273 /* copy the key into poolp memory space */
274 rv = SECKEY_CopyPrivateKeyInfo(poolp, &pk->pkcs8data, pki);
275 if(rv == SECSuccess) {
276 rv = SECITEM_CopyItem(poolp, &pk->pvkData.nickname, nickname);
277 }
278 }
280 if(rv != SECSuccess) {
281 PORT_SetError(SEC_ERROR_NO_MEMORY);
282 pk = NULL;
283 }
284 } else {
285 PORT_SetError(SEC_ERROR_NO_MEMORY);
286 }
288 /* destroy private key, zeroing out data */
289 SECKEY_DestroyPrivateKeyInfo(pki, PR_TRUE);
290 if (pk == NULL) {
291 PORT_ArenaRelease(poolp, mark);
292 } else {
293 PORT_ArenaUnmark(poolp, mark);
294 }
296 return pk;
297 }
299 /* get a shrouded key item associated with a certificate
300 * return the appropriate PKCS 12 structure
301 * poolp common memory pool
302 * nickname key nickname
303 * cert -- cert to look up
304 * wincx -- window handle
305 * an error is indicated by a return of NULL
306 */
307 static SEC_PKCS12ESPVKItem *
308 sec_pkcs12_get_shrouded_key(PLArenaPool *poolp,
309 SECItem *nickname,
310 CERTCertificate *cert,
311 SECOidTag algorithm,
312 SECItem *pwitem,
313 PKCS12UnicodeConvertFunction unicodeFn,
314 void *wincx)
315 {
316 SECKEYEncryptedPrivateKeyInfo *epki;
317 SEC_PKCS12ESPVKItem *pk;
318 void *mark;
319 SECStatus rv;
320 PK11SlotInfo *slot = NULL;
321 PRBool swapUnicodeBytes = PR_FALSE;
323 #ifdef IS_LITTLE_ENDIAN
324 swapUnicodeBytes = PR_TRUE;
325 #endif
327 if((poolp == NULL) || (nickname == NULL))
328 return NULL;
330 mark = PORT_ArenaMark(poolp);
332 /* use internal key slot */
333 slot = PK11_GetInternalKeySlot();
335 /* retrieve encrypted prviate key */
336 epki = PK11_ExportEncryptedPrivateKeyInfo(slot, algorithm, pwitem,
337 nickname, cert, 1, 0, NULL);
338 PK11_FreeSlot(slot);
339 if(epki == NULL) {
340 PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY);
341 PORT_ArenaRelease(poolp, mark);
342 return NULL;
343 }
345 /* create a private key and store the data into the poolp memory space */
346 pk = sec_pkcs12_create_espvk(poolp, SEC_OID_PKCS12_PKCS8_KEY_SHROUDING);
347 if(pk != NULL) {
348 rv = sec_pkcs12_init_pvk_data(poolp, &pk->espvkData);
349 rv = SECITEM_CopyItem(poolp, &pk->espvkData.nickname, nickname);
350 pk->espvkCipherText.pkcs8KeyShroud =
351 (SECKEYEncryptedPrivateKeyInfo *)PORT_ArenaZAlloc(poolp,
352 sizeof(SECKEYEncryptedPrivateKeyInfo));
353 if((pk->espvkCipherText.pkcs8KeyShroud != NULL) && (rv == SECSuccess)) {
354 rv = SECKEY_CopyEncryptedPrivateKeyInfo(poolp,
355 pk->espvkCipherText.pkcs8KeyShroud, epki);
356 if(rv == SECSuccess) {
357 rv = (*unicodeFn)(poolp, &pk->espvkData.uniNickName, nickname,
358 PR_TRUE, swapUnicodeBytes);
359 }
360 }
362 if(rv != SECSuccess) {
363 PORT_SetError(SEC_ERROR_NO_MEMORY);
364 pk = NULL;
365 }
366 }
368 SECKEY_DestroyEncryptedPrivateKeyInfo(epki, PR_TRUE);
369 if(pk == NULL) {
370 PORT_ArenaRelease(poolp, mark);
371 } else {
372 PORT_ArenaUnmark(poolp, mark);
373 }
375 return pk;
376 }
378 /* add a thumbprint to a private key associated certs list
379 * pvk is the area where the list is stored
380 * thumb is the thumbprint to copy
381 * a return of SECFailure indicates an error
382 */
383 static SECStatus
384 sec_pkcs12_add_thumbprint(SEC_PKCS12PVKSupportingData *pvk,
385 SGNDigestInfo *thumb)
386 {
387 SGNDigestInfo **thumb_list = NULL;
388 int nthumbs, size;
389 void *mark, *dummy;
390 SECStatus rv = SECFailure;
392 if((pvk == NULL) || (thumb == NULL)) {
393 return SECFailure;
394 }
396 mark = PORT_ArenaMark(pvk->poolp);
398 thumb_list = pvk->assocCerts;
399 nthumbs = pvk->nThumbs;
401 /* allocate list space needed -- either growing or allocating
402 * list must be NULL terminated
403 */
404 size = sizeof(SGNDigestInfo *);
405 dummy = PORT_ArenaGrow(pvk->poolp, thumb_list, (size * (nthumbs + 1)),
406 (size * (nthumbs + 2)));
407 thumb_list = dummy;
408 if(dummy != NULL) {
409 thumb_list[nthumbs] = (SGNDigestInfo *)PORT_ArenaZAlloc(pvk->poolp,
410 sizeof(SGNDigestInfo));
411 if(thumb_list[nthumbs] != NULL) {
412 SGN_CopyDigestInfo(pvk->poolp, thumb_list[nthumbs], thumb);
413 nthumbs += 1;
414 thumb_list[nthumbs] = 0;
415 } else {
416 dummy = NULL;
417 }
418 }
420 if(dummy == NULL) {
421 PORT_ArenaRelease(pvk->poolp, mark);
422 return SECFailure;
423 }
425 pvk->assocCerts = thumb_list;
426 pvk->nThumbs = nthumbs;
428 PORT_ArenaUnmark(pvk->poolp, mark);
429 return SECSuccess;
430 }
432 /* search the list of shrouded keys in the baggage for the desired
433 * name. return a pointer to the item. a return of NULL indicates
434 * that no match was present or that an error occurred.
435 */
436 static SEC_PKCS12ESPVKItem *
437 sec_pkcs12_get_espvk_by_name(SEC_PKCS12Baggage *luggage,
438 SECItem *name)
439 {
440 PRBool found = PR_FALSE;
441 SEC_PKCS12ESPVKItem *espvk = NULL;
442 int i, j;
443 SECComparison rv = SECEqual;
444 SECItem *t_name;
445 SEC_PKCS12BaggageItem *bag;
447 if((luggage == NULL) || (name == NULL)) {
448 return NULL;
449 }
451 i = 0;
452 while((found == PR_FALSE) && (i < luggage->luggage_size)) {
453 j = 0;
454 bag = luggage->bags[i];
455 while((found == PR_FALSE) && (j < bag->nEspvks)) {
456 espvk = bag->espvks[j];
457 if(espvk->poolp == NULL) {
458 espvk->poolp = luggage->poolp;
459 }
460 t_name = SECITEM_DupItem(&espvk->espvkData.nickname);
461 if(t_name != NULL) {
462 rv = SECITEM_CompareItem(name, t_name);
463 if(rv == SECEqual) {
464 found = PR_TRUE;
465 }
466 SECITEM_FreeItem(t_name, PR_TRUE);
467 } else {
468 PORT_SetError(SEC_ERROR_NO_MEMORY);
469 return NULL;
470 }
471 j++;
472 }
473 i++;
474 }
476 if(found != PR_TRUE) {
477 PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME);
478 return NULL;
479 }
481 return espvk;
482 }
484 /* locates a certificate and copies the thumbprint to the
485 * appropriate private key
486 */
487 static SECStatus
488 sec_pkcs12_propagate_thumbprints(SECItem **nicknames,
489 CERTCertificate **ref_certs,
490 SEC_PKCS12SafeContents *safe,
491 SEC_PKCS12Baggage *baggage)
492 {
493 SEC_PKCS12CertAndCRL *cert;
494 SEC_PKCS12PrivateKey *key;
495 SEC_PKCS12ESPVKItem *espvk;
496 int i;
497 PRBool error = PR_FALSE;
498 SECStatus rv = SECFailure;
500 if((nicknames == NULL) || (safe == NULL)) {
501 return SECFailure;
502 }
504 i = 0;
505 while((nicknames[i] != NULL) && (error == PR_FALSE)) {
506 /* process all certs */
507 cert = (SEC_PKCS12CertAndCRL *)sec_pkcs12_find_object(safe, baggage,
508 SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID,
509 nicknames[i], NULL);
510 if(cert != NULL) {
511 /* locate key and copy thumbprint */
512 key = (SEC_PKCS12PrivateKey *)sec_pkcs12_find_object(safe, baggage,
513 SEC_OID_PKCS12_KEY_BAG_ID,
514 nicknames[i], NULL);
515 if(key != NULL) {
516 key->pvkData.poolp = key->poolp;
517 rv = sec_pkcs12_add_thumbprint(&key->pvkData,
518 &cert->value.x509->thumbprint);
519 if(rv == SECFailure)
520 error = PR_TRUE; /* XXX Set error? */
521 }
523 /* look in the baggage as well...*/
524 if((baggage != NULL) && (error == PR_FALSE)) {
525 espvk = sec_pkcs12_get_espvk_by_name(baggage, nicknames[i]);
526 if(espvk != NULL) {
527 espvk->espvkData.poolp = espvk->poolp;
528 rv = sec_pkcs12_add_thumbprint(&espvk->espvkData,
529 &cert->value.x509->thumbprint);
530 if(rv == SECFailure)
531 error = PR_TRUE; /* XXX Set error? */
532 }
533 }
534 }
535 i++;
536 }
538 if(error == PR_TRUE) {
539 return SECFailure;
540 }
542 return SECSuccess;
543 }
545 /* append a safe bag to the end of the safe contents list */
546 SECStatus
547 sec_pkcs12_append_safe_bag(SEC_PKCS12SafeContents *safe,
548 SEC_PKCS12SafeBag *bag)
549 {
550 int size;
551 void *mark = NULL, *dummy = NULL;
553 if((bag == NULL) || (safe == NULL))
554 return SECFailure;
556 mark = PORT_ArenaMark(safe->poolp);
558 size = (safe->safe_size * sizeof(SEC_PKCS12SafeBag *));
560 if(safe->safe_size > 0) {
561 dummy = (SEC_PKCS12SafeBag **)PORT_ArenaGrow(safe->poolp,
562 safe->contents,
563 size,
564 (size + sizeof(SEC_PKCS12SafeBag *)));
565 safe->contents = dummy;
566 } else {
567 safe->contents = (SEC_PKCS12SafeBag **)PORT_ArenaZAlloc(safe->poolp,
568 (2 * sizeof(SEC_PKCS12SafeBag *)));
569 dummy = safe->contents;
570 }
572 if(dummy == NULL) {
573 PORT_SetError(SEC_ERROR_NO_MEMORY);
574 goto loser;
575 }
577 safe->contents[safe->safe_size] = bag;
578 safe->safe_size++;
579 safe->contents[safe->safe_size] = NULL;
581 PORT_ArenaUnmark(safe->poolp, mark);
582 return SECSuccess;
584 loser:
585 PORT_ArenaRelease(safe->poolp, mark);
586 return SECFailure;
587 }
589 /* append a certificate onto the end of a cert bag */
590 static SECStatus
591 sec_pkcs12_append_cert_to_bag(PLArenaPool *arena,
592 SEC_PKCS12SafeBag *safebag,
593 CERTCertificate *cert,
594 SECItem *nickname)
595 {
596 int size;
597 void *dummy = NULL, *mark = NULL;
598 SEC_PKCS12CertAndCRL *p12cert;
599 SEC_PKCS12CertAndCRLBag *bag;
601 if((arena == NULL) || (safebag == NULL) ||
602 (cert == NULL) || (nickname == NULL)) {
603 return SECFailure;
604 }
606 bag = safebag->safeContent.certAndCRLBag;
607 if(bag == NULL) {
608 return SECFailure;
609 }
611 mark = PORT_ArenaMark(arena);
613 p12cert = sec_pkcs12_get_cert(arena, cert, nickname);
614 if(p12cert == NULL) {
615 PORT_ArenaRelease(bag->poolp, mark);
616 return SECFailure;
617 }
619 size = bag->bag_size * sizeof(SEC_PKCS12CertAndCRL *);
620 if(bag->bag_size > 0) {
621 dummy = (SEC_PKCS12CertAndCRL **)PORT_ArenaGrow(bag->poolp,
622 bag->certAndCRLs, size, size + sizeof(SEC_PKCS12CertAndCRL *));
623 bag->certAndCRLs = dummy;
624 } else {
625 bag->certAndCRLs = (SEC_PKCS12CertAndCRL **)PORT_ArenaZAlloc(bag->poolp,
626 (2 * sizeof(SEC_PKCS12CertAndCRL *)));
627 dummy = bag->certAndCRLs;
628 }
630 if(dummy == NULL) {
631 PORT_SetError(SEC_ERROR_NO_MEMORY);
632 goto loser;
633 }
635 bag->certAndCRLs[bag->bag_size] = p12cert;
636 bag->bag_size++;
637 bag->certAndCRLs[bag->bag_size] = NULL;
639 PORT_ArenaUnmark(bag->poolp, mark);
640 return SECSuccess;
642 loser:
643 PORT_ArenaRelease(bag->poolp, mark);
644 return SECFailure;
645 }
647 /* append a key onto the end of a list of keys in a key bag */
648 SECStatus
649 sec_pkcs12_append_key_to_bag(SEC_PKCS12SafeBag *safebag,
650 SEC_PKCS12PrivateKey *pk)
651 {
652 void *mark, *dummy;
653 SEC_PKCS12PrivateKeyBag *bag;
654 int size;
656 if((safebag == NULL) || (pk == NULL))
657 return SECFailure;
659 bag = safebag->safeContent.keyBag;
660 if(bag == NULL) {
661 return SECFailure;
662 }
664 mark = PORT_ArenaMark(bag->poolp);
666 size = (bag->bag_size * sizeof(SEC_PKCS12PrivateKey *));
668 if(bag->bag_size > 0) {
669 dummy = (SEC_PKCS12PrivateKey **)PORT_ArenaGrow(bag->poolp,
670 bag->privateKeys,
671 size,
672 size + sizeof(SEC_PKCS12PrivateKey *));
673 bag->privateKeys = dummy;
674 } else {
675 bag->privateKeys = (SEC_PKCS12PrivateKey **)PORT_ArenaZAlloc(bag->poolp,
676 (2 * sizeof(SEC_PKCS12PrivateKey *)));
677 dummy = bag->privateKeys;
678 }
680 if(dummy == NULL) {
681 PORT_SetError(SEC_ERROR_NO_MEMORY);
682 goto loser;
683 }
685 bag->privateKeys[bag->bag_size] = pk;
686 bag->bag_size++;
687 bag->privateKeys[bag->bag_size] = NULL;
689 PORT_ArenaUnmark(bag->poolp, mark);
690 return SECSuccess;
692 loser:
693 /* XXX Free memory? */
694 PORT_ArenaRelease(bag->poolp, mark);
695 return SECFailure;
696 }
698 /* append a safe bag to the baggage area */
699 static SECStatus
700 sec_pkcs12_append_unshrouded_bag(SEC_PKCS12BaggageItem *bag,
701 SEC_PKCS12SafeBag *u_bag)
702 {
703 int size;
704 void *mark = NULL, *dummy = NULL;
706 if((bag == NULL) || (u_bag == NULL))
707 return SECFailure;
709 mark = PORT_ArenaMark(bag->poolp);
711 /* dump things into the first bag */
712 size = (bag->nSecrets + 1) * sizeof(SEC_PKCS12SafeBag *);
713 dummy = PORT_ArenaGrow(bag->poolp,
714 bag->unencSecrets, size,
715 size + sizeof(SEC_PKCS12SafeBag *));
716 bag->unencSecrets = dummy;
717 if(dummy == NULL) {
718 PORT_SetError(SEC_ERROR_NO_MEMORY);
719 goto loser;
720 }
722 bag->unencSecrets[bag->nSecrets] = u_bag;
723 bag->nSecrets++;
724 bag->unencSecrets[bag->nSecrets] = NULL;
726 PORT_ArenaUnmark(bag->poolp, mark);
727 return SECSuccess;
729 loser:
730 PORT_ArenaRelease(bag->poolp, mark);
731 return SECFailure;
732 }
734 /* gather up all certificates and keys and package them up
735 * in the safe, baggage, or both.
736 * nicknames is the list of nicknames and corresponding certs in ref_certs
737 * ref_certs a null terminated list of certificates
738 * rSafe, rBaggage -- return areas for safe and baggage
739 * shroud_keys -- store keys externally
740 * pwitem -- password for computing integrity mac and encrypting contents
741 * wincx -- window handle
742 *
743 * if a failure occurs, an error is set and SECFailure returned.
744 */
745 static SECStatus
746 sec_pkcs12_package_certs_and_keys(SECItem **nicknames,
747 CERTCertificate **ref_certs,
748 PRBool unencryptedCerts,
749 SEC_PKCS12SafeContents **rSafe,
750 SEC_PKCS12Baggage **rBaggage,
751 PRBool shroud_keys,
752 SECOidTag shroud_alg,
753 SECItem *pwitem,
754 PKCS12UnicodeConvertFunction unicodeFn,
755 void *wincx)
756 {
757 PLArenaPool *permArena;
758 SEC_PKCS12SafeContents *safe = NULL;
759 SEC_PKCS12Baggage *baggage = NULL;
761 SECStatus rv = SECFailure;
762 PRBool problem = PR_FALSE;
764 SEC_PKCS12ESPVKItem *espvk = NULL;
765 SEC_PKCS12PrivateKey *pk = NULL;
766 CERTCertificate *add_cert = NULL;
767 SEC_PKCS12SafeBag *certbag = NULL, *keybag = NULL;
768 SEC_PKCS12BaggageItem *external_bag = NULL;
769 int ncerts = 0, nkeys = 0;
770 int i;
772 if((nicknames == NULL) || (rSafe == NULL) || (rBaggage == NULL)) {
773 return SECFailure;
774 }
776 *rBaggage = baggage;
777 *rSafe = safe;
779 permArena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
780 if(permArena == NULL) {
781 PORT_SetError(SEC_ERROR_NO_MEMORY);
782 return SECFailure;
783 }
785 /* allocate structures */
786 safe = sec_pkcs12_create_safe_contents(permArena);
787 if(safe == NULL) {
788 PORT_SetError(SEC_ERROR_NO_MEMORY);
789 rv = SECFailure;
790 goto loser;
791 }
793 certbag = sec_pkcs12_create_safe_bag(permArena,
794 SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID);
795 if(certbag == NULL) {
796 rv = SECFailure;
797 goto loser;
798 }
800 if(shroud_keys != PR_TRUE) {
801 keybag = sec_pkcs12_create_safe_bag(permArena,
802 SEC_OID_PKCS12_KEY_BAG_ID);
803 if(keybag == NULL) {
804 rv = SECFailure;
805 goto loser;
806 }
807 }
809 if((shroud_keys == PR_TRUE) || (unencryptedCerts == PR_TRUE)) {
810 baggage = sec_pkcs12_create_baggage(permArena);
811 if(baggage == NULL) {
812 rv = SECFailure;
813 goto loser;
814 }
815 external_bag = sec_pkcs12_create_external_bag(baggage);
816 }
818 /* package keys and certs */
819 i = 0;
820 while((nicknames[i] != NULL) && (problem == PR_FALSE)) {
821 if(ref_certs[i] != NULL) {
822 /* append cert to bag o certs */
823 rv = sec_pkcs12_append_cert_to_bag(permArena, certbag,
824 ref_certs[i],
825 nicknames[i]);
826 if(rv == SECFailure) {
827 problem = PR_FALSE;
828 } else {
829 ncerts++;
830 }
832 if(rv == SECSuccess) {
833 /* package up them keys */
834 if(shroud_keys == PR_TRUE) {
835 espvk = sec_pkcs12_get_shrouded_key(permArena,
836 nicknames[i],
837 ref_certs[i],
838 shroud_alg,
839 pwitem, unicodeFn,
840 wincx);
841 if(espvk != NULL) {
842 rv = sec_pkcs12_append_shrouded_key(external_bag, espvk);
843 SECITEM_CopyItem(permArena, &espvk->derCert,
844 &ref_certs[i]->derCert);
845 } else {
846 rv = SECFailure;
847 }
848 } else {
849 pk = sec_pkcs12_get_private_key(permArena, nicknames[i],
850 ref_certs[i], wincx);
851 if(pk != NULL) {
852 rv = sec_pkcs12_append_key_to_bag(keybag, pk);
853 SECITEM_CopyItem(permArena, &espvk->derCert,
854 &ref_certs[i]->derCert);
855 } else {
856 rv = SECFailure;
857 }
858 }
860 if(rv == SECFailure) {
861 problem = PR_TRUE;
862 } else {
863 nkeys++;
864 }
865 }
866 } else {
867 /* handle only keys here ? */
868 problem = PR_TRUE;
869 }
870 i++;
871 }
873 /* let success fall through */
874 loser:
875 if(problem == PR_FALSE) {
876 /* if we have certs, we want to append the cert bag to the
877 * appropriate area
878 */
879 if(ncerts > 0) {
880 if(unencryptedCerts != PR_TRUE) {
881 rv = sec_pkcs12_append_safe_bag(safe, certbag);
882 } else {
883 rv = sec_pkcs12_append_unshrouded_bag(external_bag, certbag);
884 }
885 } else {
886 rv = SECSuccess;
887 }
889 /* append key bag, if they are stored in safe contents */
890 if((rv == SECSuccess) && (shroud_keys == PR_FALSE) && (nkeys > 0)) {
891 rv = sec_pkcs12_append_safe_bag(safe, keybag);
892 }
893 } else {
894 rv = SECFailure;
895 }
897 /* if baggage not used, NULLify it */
898 if((shroud_keys == PR_TRUE) || (unencryptedCerts == PR_TRUE)) {
899 if(((unencryptedCerts == PR_TRUE) && (ncerts == 0)) &&
900 ((shroud_keys == PR_TRUE) && (nkeys == 0)))
901 baggage = NULL;
902 } else {
903 baggage = NULL;
904 }
906 if((problem == PR_TRUE) || (rv == SECFailure)) {
907 PORT_FreeArena(permArena, PR_TRUE);
908 rv = SECFailure;
909 baggage = NULL;
910 safe = NULL;
911 }
913 *rBaggage = baggage;
914 *rSafe = safe;
916 return rv;
917 }
919 /* DER encode the safe contents and return a SECItem. if an error
920 * occurs, NULL is returned.
921 */
922 static SECItem *
923 sec_pkcs12_encode_safe_contents(SEC_PKCS12SafeContents *safe)
924 {
925 SECItem *dsafe = NULL, *tsafe;
926 void *dummy = NULL;
927 PLArenaPool *arena;
929 if(safe == NULL) {
930 return NULL;
931 }
933 /* rv = sec_pkcs12_prepare_for_der_code_safe(safe, PR_TRUE);
934 if(rv != SECSuccess) {
935 PORT_SetError(SEC_ERROR_NO_MEMORY);
936 return NULL;
937 }*/
939 arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
940 if(arena == NULL) {
941 PORT_SetError(SEC_ERROR_NO_MEMORY);
942 return NULL;
943 }
945 tsafe = (SECItem *)PORT_ArenaZAlloc(arena, sizeof(SECItem));
946 if(tsafe != NULL) {
947 dummy = SEC_ASN1EncodeItem(arena, tsafe, safe,
948 SEC_PKCS12SafeContentsTemplate);
949 if(dummy != NULL) {
950 dsafe = SECITEM_DupItem(tsafe);
951 } else {
952 PORT_SetError(SEC_ERROR_NO_MEMORY);
953 }
954 } else {
955 PORT_SetError(SEC_ERROR_NO_MEMORY);
956 }
958 PORT_FreeArena(arena, PR_TRUE);
960 return dsafe;
961 }
963 /* prepare the authenicated safe for encoding and encode it.
964 * baggage is copied to the appropriate area, safe is encoded and
965 * encrypted. the version and transport mode are set on the asafe.
966 * the whole ball of wax is then der encoded and packaged up into
967 * data content info
968 * safe -- container of certs and keys, is encrypted.
969 * baggage -- container of certs and keys, keys assumed to be encrypted by
970 * another method, certs are in the clear
971 * algorithm -- algorithm by which to encrypt safe
972 * pwitem -- password for encryption
973 * wincx - window handle
974 *
975 * return of NULL is an error condition.
976 */
977 static SEC_PKCS7ContentInfo *
978 sec_pkcs12_get_auth_safe(SEC_PKCS12SafeContents *safe,
979 SEC_PKCS12Baggage *baggage,
980 SECOidTag algorithm,
981 SECItem *pwitem,
982 PKCS12UnicodeConvertFunction unicodeFn,
983 void *wincx)
984 {
985 SECItem *src = NULL, *dest = NULL, *psalt = NULL;
986 PLArenaPool *poolp;
987 SEC_PKCS12AuthenticatedSafe *asafe;
988 SEC_PKCS7ContentInfo *safe_cinfo = NULL;
989 SEC_PKCS7ContentInfo *asafe_cinfo = NULL;
990 void *dummy;
991 SECStatus rv = SECSuccess;
992 PRBool swapUnicodeBytes = PR_FALSE;
994 #ifdef IS_LITTLE_ENDIAN
995 swapUnicodeBytes = PR_TRUE;
996 #endif
998 if(((safe != NULL) && (pwitem == NULL)) && (baggage == NULL))
999 return NULL;
1001 poolp = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
1002 if(poolp == NULL) {
1003 PORT_SetError(SEC_ERROR_NO_MEMORY);
1004 return NULL;
1005 }
1007 /* prepare authenticated safe for encode */
1008 asafe = sec_pkcs12_new_asafe(poolp);
1009 if(asafe != NULL) {
1011 /* set version */
1012 dummy = SEC_ASN1EncodeInteger(asafe->poolp, &asafe->version,
1013 SEC_PKCS12_PFX_VERSION);
1014 if(dummy == NULL) {
1015 PORT_SetError(SEC_ERROR_NO_MEMORY);
1016 rv = SECFailure;
1017 goto loser;
1018 }
1020 /* generate the privacy salt used to create virtual pwd */
1021 psalt = sec_pkcs12_generate_salt();
1022 if(psalt != NULL) {
1023 rv = SECITEM_CopyItem(asafe->poolp, &asafe->privacySalt,
1024 psalt);
1025 if(rv == SECSuccess) {
1026 asafe->privacySalt.len *= 8;
1027 }
1028 else {
1029 SECITEM_ZfreeItem(psalt, PR_TRUE);
1030 PORT_SetError(SEC_ERROR_NO_MEMORY);
1031 goto loser;
1032 }
1033 }
1035 if((psalt == NULL) || (rv == SECFailure)) {
1036 PORT_SetError(SEC_ERROR_NO_MEMORY);
1037 rv = SECFailure;
1038 goto loser;
1039 }
1041 /* package up safe contents */
1042 if(safe != NULL)
1043 {
1044 safe_cinfo = SEC_PKCS7CreateEncryptedData(algorithm, NULL, wincx);
1045 if((safe_cinfo != NULL) && (safe->safe_size > 0)) {
1046 /* encode the safe and encrypt the contents of the
1047 * content info
1048 */
1049 src = sec_pkcs12_encode_safe_contents(safe);
1051 if(src != NULL) {
1052 rv = SEC_PKCS7SetContent(safe_cinfo, (char *)src->data, src->len);
1053 SECITEM_ZfreeItem(src, PR_TRUE);
1054 if(rv == SECSuccess) {
1055 SECItem *vpwd;
1056 vpwd = sec_pkcs12_create_virtual_password(pwitem, psalt,
1057 unicodeFn, swapUnicodeBytes);
1058 if(vpwd != NULL) {
1059 rv = SEC_PKCS7EncryptContents(NULL, safe_cinfo,
1060 vpwd, wincx);
1061 SECITEM_ZfreeItem(vpwd, PR_TRUE);
1062 } else {
1063 rv = SECFailure;
1064 PORT_SetError(SEC_ERROR_NO_MEMORY);
1065 }
1066 } else {
1067 PORT_SetError(SEC_ERROR_NO_MEMORY);
1068 }
1069 } else {
1070 rv = SECFailure;
1071 }
1072 } else if(safe->safe_size > 0) {
1073 PORT_SetError(SEC_ERROR_NO_MEMORY);
1074 goto loser;
1075 } else {
1076 /* case where there is NULL content in the safe contents */
1077 rv = SEC_PKCS7SetContent(safe_cinfo, NULL, 0);
1078 if(rv != SECFailure) {
1079 PORT_SetError(SEC_ERROR_NO_MEMORY);
1080 }
1081 }
1083 if(rv != SECSuccess) {
1084 SEC_PKCS7DestroyContentInfo(safe_cinfo);
1085 safe_cinfo = NULL;
1086 goto loser;
1087 }
1089 asafe->safe = safe_cinfo;
1090 /*
1091 PORT_Memcpy(&asafe->safe, safe_cinfo, sizeof(*safe_cinfo));
1092 */
1093 }
1095 /* copy the baggage to the authenticated safe baggage if present */
1096 if(baggage != NULL) {
1097 PORT_Memcpy(&asafe->baggage, baggage, sizeof(*baggage));
1098 }
1100 /* encode authenticated safe and store it in a Data content info */
1101 dest = (SECItem *)PORT_ArenaZAlloc(poolp, sizeof(SECItem));
1102 if(dest != NULL) {
1103 dummy = SEC_ASN1EncodeItem(poolp, dest, asafe,
1104 SEC_PKCS12AuthenticatedSafeTemplate);
1105 if(dummy != NULL) {
1106 asafe_cinfo = SEC_PKCS7CreateData();
1107 if(asafe_cinfo != NULL) {
1108 rv = SEC_PKCS7SetContent(asafe_cinfo,
1109 (char *)dest->data,
1110 dest->len);
1111 if(rv != SECSuccess) {
1112 PORT_SetError(SEC_ERROR_NO_MEMORY);
1113 SEC_PKCS7DestroyContentInfo(asafe_cinfo);
1114 asafe_cinfo = NULL;
1115 }
1116 }
1117 } else {
1118 PORT_SetError(SEC_ERROR_NO_MEMORY);
1119 rv = SECFailure;
1120 }
1121 }
1122 }
1124 loser:
1125 PORT_FreeArena(poolp, PR_TRUE);
1126 if(safe_cinfo != NULL) {
1127 SEC_PKCS7DestroyContentInfo(safe_cinfo);
1128 }
1129 if(psalt != NULL) {
1130 SECITEM_ZfreeItem(psalt, PR_TRUE);
1131 }
1133 if(rv == SECFailure) {
1134 return NULL;
1135 }
1137 return asafe_cinfo;
1138 }
1140 /* generates the PFX and computes the mac on the authenticated safe
1141 * NULL implies an error
1142 */
1143 static SEC_PKCS12PFXItem *
1144 sec_pkcs12_get_pfx(SEC_PKCS7ContentInfo *cinfo,
1145 PRBool do_mac,
1146 SECItem *pwitem, PKCS12UnicodeConvertFunction unicodeFn)
1147 {
1148 SECItem *dest = NULL, *mac = NULL, *salt = NULL, *key = NULL;
1149 SEC_PKCS12PFXItem *pfx;
1150 SECStatus rv = SECFailure;
1151 SGNDigestInfo *di;
1152 SECItem *vpwd;
1153 PRBool swapUnicodeBytes = PR_FALSE;
1155 #ifdef IS_LITTLE_ENDIAN
1156 swapUnicodeBytes = PR_TRUE;
1157 #endif
1159 if((cinfo == NULL) || ((do_mac == PR_TRUE) && (pwitem == NULL))) {
1160 return NULL;
1161 }
1163 /* allocate new pfx structure */
1164 pfx = sec_pkcs12_new_pfx();
1165 if(pfx == NULL) {
1166 PORT_SetError(SEC_ERROR_NO_MEMORY);
1167 return NULL;
1168 }
1170 PORT_Memcpy(&pfx->authSafe, cinfo, sizeof(*cinfo));
1171 if(do_mac == PR_TRUE) {
1173 /* salt for computing mac */
1174 salt = sec_pkcs12_generate_salt();
1175 if(salt != NULL) {
1176 rv = SECITEM_CopyItem(pfx->poolp, &pfx->macData.macSalt, salt);
1177 pfx->macData.macSalt.len *= 8;
1179 vpwd = sec_pkcs12_create_virtual_password(pwitem, salt,
1180 unicodeFn, swapUnicodeBytes);
1181 if(vpwd == NULL) {
1182 rv = SECFailure;
1183 key = NULL;
1184 } else {
1185 key = sec_pkcs12_generate_key_from_password(SEC_OID_SHA1,
1186 salt, vpwd);
1187 SECITEM_ZfreeItem(vpwd, PR_TRUE);
1188 }
1190 if((key != NULL) && (rv == SECSuccess)) {
1191 dest = SEC_PKCS7GetContent(cinfo);
1192 if(dest != NULL) {
1194 /* compute mac on data -- for password integrity mode */
1195 mac = sec_pkcs12_generate_mac(key, dest, PR_FALSE);
1196 if(mac != NULL) {
1197 di = SGN_CreateDigestInfo(SEC_OID_SHA1,
1198 mac->data, mac->len);
1199 if(di != NULL) {
1200 rv = SGN_CopyDigestInfo(pfx->poolp,
1201 &pfx->macData.safeMac, di);
1202 SGN_DestroyDigestInfo(di);
1203 } else {
1204 PORT_SetError(SEC_ERROR_NO_MEMORY);
1205 }
1206 SECITEM_ZfreeItem(mac, PR_TRUE);
1207 }
1208 } else {
1209 rv = SECFailure;
1210 }
1211 } else {
1212 PORT_SetError(SEC_ERROR_NO_MEMORY);
1213 rv = SECFailure;
1214 }
1216 if(key != NULL) {
1217 SECITEM_ZfreeItem(key, PR_TRUE);
1218 }
1219 SECITEM_ZfreeItem(salt, PR_TRUE);
1220 }
1221 }
1223 if(rv == SECFailure) {
1224 SEC_PKCS12DestroyPFX(pfx);
1225 pfx = NULL;
1226 }
1228 return pfx;
1229 }
1231 /* der encode the pfx */
1232 static SECItem *
1233 sec_pkcs12_encode_pfx(SEC_PKCS12PFXItem *pfx)
1234 {
1235 SECItem *dest;
1236 void *dummy;
1238 if(pfx == NULL) {
1239 return NULL;
1240 }
1242 dest = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
1243 if(dest == NULL) {
1244 PORT_SetError(SEC_ERROR_NO_MEMORY);
1245 return NULL;
1246 }
1248 dummy = SEC_ASN1EncodeItem(NULL, dest, pfx, SEC_PKCS12PFXItemTemplate);
1249 if(dummy == NULL) {
1250 PORT_SetError(SEC_ERROR_NO_MEMORY);
1251 SECITEM_ZfreeItem(dest, PR_TRUE);
1252 dest = NULL;
1253 }
1255 return dest;
1256 }
1258 SECItem *
1259 SEC_PKCS12GetPFX(char **nicknames,
1260 CERTCertificate **ref_certs,
1261 PRBool shroud_keys,
1262 SEC_PKCS5GetPBEPassword pbef,
1263 void *pbearg,
1264 PKCS12UnicodeConvertFunction unicodeFn,
1265 void *wincx)
1266 {
1267 SECItem **nicks = NULL;
1268 SEC_PKCS12PFXItem *pfx = NULL;
1269 SEC_PKCS12Baggage *baggage = NULL;
1270 SEC_PKCS12SafeContents *safe = NULL;
1271 SEC_PKCS7ContentInfo *cinfo = NULL;
1272 SECStatus rv = SECFailure;
1273 SECItem *dest = NULL, *pwitem = NULL;
1274 PRBool problem = PR_FALSE;
1275 PRBool unencryptedCerts;
1276 SECOidTag shroud_alg, safe_alg;
1278 /* how should we encrypt certs ? */
1279 unencryptedCerts = !SEC_PKCS12IsEncryptionAllowed();
1280 if(!unencryptedCerts) {
1281 safe_alg = SEC_PKCS12GetPreferredEncryptionAlgorithm();
1282 if(safe_alg == SEC_OID_UNKNOWN) {
1283 safe_alg = SEC_PKCS12GetStrongestAllowedAlgorithm();
1284 }
1285 if(safe_alg == SEC_OID_UNKNOWN) {
1286 unencryptedCerts = PR_TRUE;
1287 /* for export where no encryption is allowed, we still need
1288 * to encrypt the NULL contents per the spec. encrypted info
1289 * is known plaintext, so it shouldn't be a problem.
1290 */
1291 safe_alg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC;
1292 }
1293 } else {
1294 /* for export where no encryption is allowed, we still need
1295 * to encrypt the NULL contents per the spec. encrypted info
1296 * is known plaintext, so it shouldn't be a problem.
1297 */
1298 safe_alg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC;
1299 }
1301 /* keys are always stored with triple DES */
1302 shroud_alg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC;
1304 /* check for FIPS, if so, do not encrypt certs */
1305 if(PK11_IsFIPS() && !unencryptedCerts) {
1306 unencryptedCerts = PR_TRUE;
1307 }
1309 if((nicknames == NULL) || (pbef == NULL) || (ref_certs == NULL)) {
1310 problem = PR_TRUE;
1311 goto loser;
1312 }
1315 /* get password */
1316 pwitem = (*pbef)(pbearg);
1317 if(pwitem == NULL) {
1318 problem = PR_TRUE;
1319 goto loser;
1320 }
1321 nicks = sec_pkcs12_convert_nickname_list(nicknames);
1323 /* get safe and baggage */
1324 rv = sec_pkcs12_package_certs_and_keys(nicks, ref_certs, unencryptedCerts,
1325 &safe, &baggage, shroud_keys,
1326 shroud_alg, pwitem, unicodeFn, wincx);
1327 if(rv == SECFailure) {
1328 problem = PR_TRUE;
1329 }
1331 if((safe != NULL) && (problem == PR_FALSE)) {
1332 /* copy thumbprints */
1333 rv = sec_pkcs12_propagate_thumbprints(nicks, ref_certs, safe, baggage);
1335 /* package everything up into AuthenticatedSafe */
1336 cinfo = sec_pkcs12_get_auth_safe(safe, baggage,
1337 safe_alg, pwitem, unicodeFn, wincx);
1339 sec_pkcs12_destroy_cert_content_infos(safe, baggage);
1341 /* get the pfx and mac it */
1342 if(cinfo != NULL) {
1343 pfx = sec_pkcs12_get_pfx(cinfo, PR_TRUE, pwitem, unicodeFn);
1344 if(pfx != NULL) {
1345 dest = sec_pkcs12_encode_pfx(pfx);
1346 SEC_PKCS12DestroyPFX(pfx);
1347 }
1348 SEC_PKCS7DestroyContentInfo(cinfo);
1349 }
1351 if(safe != NULL) {
1352 PORT_FreeArena(safe->poolp, PR_TRUE);
1353 }
1354 } else {
1355 if(safe != NULL) {
1356 PORT_FreeArena(safe->poolp, PR_TRUE);
1357 }
1358 }
1360 loser:
1361 if(nicks != NULL) {
1362 sec_pkcs12_destroy_nickname_list(nicks);
1363 }
1365 if(ref_certs != NULL) {
1366 sec_pkcs12_destroy_certificate_list(ref_certs);
1367 }
1369 if(pwitem != NULL) {
1370 SECITEM_ZfreeItem(pwitem, PR_TRUE);
1371 }
1373 if(problem == PR_TRUE) {
1374 dest = NULL;
1375 }
1377 return dest;
1378 }