1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
50 /* release the memory taken up by the list of nicknames */
52 sec_pkcs12_destroy_nickname_list(SECItem
**nicknames
)
56 if(nicknames
== NULL
) {
60 while(nicknames
[i
] != NULL
) {
61 SECITEM_FreeItem(nicknames
[i
], PR_FALSE
);
68 /* release the memory taken up by the list of certificates */
70 sec_pkcs12_destroy_certificate_list(CERTCertificate
**ref_certs
)
74 if(ref_certs
== NULL
) {
78 while(ref_certs
[i
] != NULL
) {
79 CERT_DestroyCertificate(ref_certs
[i
]);
85 sec_pkcs12_destroy_cinfos_for_cert_bags(SEC_PKCS12CertAndCRLBag
*certBag
)
89 while(certBag
->certAndCRLs
[j
] != NULL
) {
90 SECOidTag certType
= SECOID_FindOIDTag(&certBag
->certAndCRLs
[j
]->BagID
);
91 if(certType
== SEC_OID_PKCS12_X509_CERT_CRL_BAG
) {
92 SEC_PKCS12X509CertCRL
*x509
;
93 x509
= certBag
->certAndCRLs
[j
]->value
.x509
;
94 SEC_PKCS7DestroyContentInfo(&x509
->certOrCRL
);
100 /* destroy all content infos since they were not allocated in common
104 sec_pkcs12_destroy_cert_content_infos(SEC_PKCS12SafeContents
*safe
,
105 SEC_PKCS12Baggage
*baggage
)
109 if((safe
!= NULL
) && (safe
->contents
!= NULL
)) {
111 while(safe
->contents
[i
] != NULL
) {
112 SECOidTag bagType
= SECOID_FindOIDTag(&safe
->contents
[i
]->safeBagType
);
113 if(bagType
== SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID
) {
114 SEC_PKCS12CertAndCRLBag
*certBag
;
115 certBag
= safe
->contents
[i
]->safeContent
.certAndCRLBag
;
116 sec_pkcs12_destroy_cinfos_for_cert_bags(certBag
);
122 if((baggage
!= NULL
) && (baggage
->bags
!= NULL
)) {
124 while(baggage
->bags
[i
] != NULL
) {
125 if(baggage
->bags
[i
]->unencSecrets
!= NULL
) {
127 while(baggage
->bags
[i
]->unencSecrets
[j
] != NULL
) {
129 bagType
= SECOID_FindOIDTag(&baggage
->bags
[i
]->unencSecrets
[j
]->safeBagType
);
130 if(bagType
== SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID
) {
131 SEC_PKCS12CertAndCRLBag
*certBag
;
132 certBag
= baggage
->bags
[i
]->unencSecrets
[j
]->safeContent
.certAndCRLBag
;
133 sec_pkcs12_destroy_cinfos_for_cert_bags(certBag
);
143 /* convert the nickname list from a NULL termincated Char list
144 * to a NULL terminated SECItem list
147 sec_pkcs12_convert_nickname_list(char **nicknames
)
151 PRBool error
= PR_FALSE
;
153 if(nicknames
== NULL
) {
158 while(nicknames
[i
] != NULL
) {
162 /* allocate the space and copy the data */
163 nicks
= (SECItem
**)PORT_ZAlloc(sizeof(SECItem
*) * (i
+ 1));
165 for(j
= 0; ((j
< i
) && (error
== PR_FALSE
)); j
++) {
166 nicks
[j
] = (SECItem
*)PORT_ZAlloc(sizeof(SECItem
));
167 if(nicks
[j
] != NULL
) {
169 (unsigned char *)PORT_ZAlloc(PORT_Strlen(nicknames
[j
])+1);
170 if(nicks
[j
]->data
!= NULL
) {
171 nicks
[j
]->len
= PORT_Strlen(nicknames
[j
]);
172 PORT_Memcpy(nicks
[j
]->data
, nicknames
[j
], nicks
[j
]->len
);
173 nicks
[j
]->data
[nicks
[j
]->len
] = 0;
183 if(error
== PR_TRUE
) {
184 for(i
= 0; i
< j
; i
++) {
185 SECITEM_FreeItem(nicks
[i
], PR_TRUE
);
194 /* package the certificate add_cert into PKCS12 structures,
195 * retrieve the certificate chain for the cert and return
196 * the packaged contents.
197 * poolp -- common memory pool;
198 * add_cert -- certificate to package up
199 * nickname for the certificate
200 * a return of NULL indicates an error
202 static SEC_PKCS12CertAndCRL
*
203 sec_pkcs12_get_cert(PRArenaPool
*poolp
,
204 CERTCertificate
*add_cert
,
207 SEC_PKCS12CertAndCRL
*cert
;
208 SEC_PKCS7ContentInfo
*cinfo
;
213 if((poolp
== NULL
) || (add_cert
== NULL
) || (nickname
== NULL
)) {
216 mark
= PORT_ArenaMark(poolp
);
218 cert
= sec_pkcs12_new_cert_crl(poolp
, SEC_OID_PKCS12_X509_CERT_CRL_BAG
);
221 /* copy the nickname */
222 rv
= SECITEM_CopyItem(poolp
, &cert
->nickname
, nickname
);
223 if(rv
!= SECSuccess
) {
224 PORT_SetError(SEC_ERROR_NO_MEMORY
);
228 /* package the certificate and cert chain into a NULL signer
229 * PKCS 7 SignedData content Info and prepare it for encoding
230 * since we cannot use DER_ANY_TEMPLATE
232 cinfo
= SEC_PKCS7CreateCertsOnly(add_cert
, PR_TRUE
, NULL
);
233 rv
= SEC_PKCS7PrepareForEncode(cinfo
, NULL
, NULL
, NULL
);
235 /* thumbprint the certificate */
236 if((cinfo
!= NULL
) && (rv
== SECSuccess
))
238 PORT_Memcpy(&cert
->value
.x509
->certOrCRL
, cinfo
, sizeof(*cinfo
));
239 t_di
= sec_pkcs12_compute_thumbprint(&add_cert
->derCert
);
243 rv
= SGN_CopyDigestInfo(poolp
, &cert
->value
.x509
->thumbprint
,
245 if(rv
!= SECSuccess
) {
247 PORT_SetError(SEC_ERROR_NO_MEMORY
);
249 SGN_DestroyDigestInfo(t_di
);
258 PORT_ArenaRelease(poolp
, mark
);
260 PORT_ArenaUnmark(poolp
, mark
);
266 /* package the private key associated with the certificate and
267 * return the appropriate PKCS 12 structure
268 * poolp common memory pool
269 * nickname key nickname
270 * cert -- cert to look up
271 * wincx -- window handle
272 * an error is indicated by a return of NULL
274 static SEC_PKCS12PrivateKey
*
275 sec_pkcs12_get_private_key(PRArenaPool
*poolp
,
277 CERTCertificate
*cert
,
280 SECKEYPrivateKeyInfo
*pki
;
281 SEC_PKCS12PrivateKey
*pk
;
285 if((poolp
== NULL
) || (nickname
== NULL
)) {
289 mark
= PORT_ArenaMark(poolp
);
291 /* retrieve key from the data base */
292 pki
= PK11_ExportPrivateKeyInfo(nickname
, cert
, wincx
);
294 PORT_ArenaRelease(poolp
, mark
);
295 PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY
);
299 pk
= (SEC_PKCS12PrivateKey
*)PORT_ArenaZAlloc(poolp
,
300 sizeof(SEC_PKCS12PrivateKey
));
302 rv
= sec_pkcs12_init_pvk_data(poolp
, &pk
->pvkData
);
304 if(rv
== SECSuccess
) {
305 /* copy the key into poolp memory space */
306 rv
= SECKEY_CopyPrivateKeyInfo(poolp
, &pk
->pkcs8data
, pki
);
307 if(rv
== SECSuccess
) {
308 rv
= SECITEM_CopyItem(poolp
, &pk
->pvkData
.nickname
, nickname
);
312 if(rv
!= SECSuccess
) {
313 PORT_SetError(SEC_ERROR_NO_MEMORY
);
317 PORT_SetError(SEC_ERROR_NO_MEMORY
);
320 /* destroy private key, zeroing out data */
321 SECKEY_DestroyPrivateKeyInfo(pki
, PR_TRUE
);
323 PORT_ArenaRelease(poolp
, mark
);
325 PORT_ArenaUnmark(poolp
, mark
);
331 /* get a shrouded key item associated with a certificate
332 * return the appropriate PKCS 12 structure
333 * poolp common memory pool
334 * nickname key nickname
335 * cert -- cert to look up
336 * wincx -- window handle
337 * an error is indicated by a return of NULL
339 static SEC_PKCS12ESPVKItem
*
340 sec_pkcs12_get_shrouded_key(PRArenaPool
*poolp
,
342 CERTCertificate
*cert
,
345 PKCS12UnicodeConvertFunction unicodeFn
,
348 SECKEYEncryptedPrivateKeyInfo
*epki
;
349 SEC_PKCS12ESPVKItem
*pk
;
352 PK11SlotInfo
*slot
= NULL
;
353 PRBool swapUnicodeBytes
= PR_FALSE
;
355 #ifdef IS_LITTLE_ENDIAN
356 swapUnicodeBytes
= PR_TRUE
;
359 if((poolp
== NULL
) || (nickname
== NULL
))
362 mark
= PORT_ArenaMark(poolp
);
364 /* use internal key slot */
365 slot
= PK11_GetInternalKeySlot();
367 /* retrieve encrypted prviate key */
368 epki
= PK11_ExportEncryptedPrivateKeyInfo(slot
, algorithm
, pwitem
,
369 nickname
, cert
, 1, 0, NULL
);
372 PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY
);
373 PORT_ArenaRelease(poolp
, mark
);
377 /* create a private key and store the data into the poolp memory space */
378 pk
= sec_pkcs12_create_espvk(poolp
, SEC_OID_PKCS12_PKCS8_KEY_SHROUDING
);
380 rv
= sec_pkcs12_init_pvk_data(poolp
, &pk
->espvkData
);
381 rv
= SECITEM_CopyItem(poolp
, &pk
->espvkData
.nickname
, nickname
);
382 pk
->espvkCipherText
.pkcs8KeyShroud
=
383 (SECKEYEncryptedPrivateKeyInfo
*)PORT_ArenaZAlloc(poolp
,
384 sizeof(SECKEYEncryptedPrivateKeyInfo
));
385 if((pk
->espvkCipherText
.pkcs8KeyShroud
!= NULL
) && (rv
== SECSuccess
)) {
386 rv
= SECKEY_CopyEncryptedPrivateKeyInfo(poolp
,
387 pk
->espvkCipherText
.pkcs8KeyShroud
, epki
);
388 if(rv
== SECSuccess
) {
389 rv
= (*unicodeFn
)(poolp
, &pk
->espvkData
.uniNickName
, nickname
,
390 PR_TRUE
, swapUnicodeBytes
);
394 if(rv
!= SECSuccess
) {
395 PORT_SetError(SEC_ERROR_NO_MEMORY
);
400 SECKEY_DestroyEncryptedPrivateKeyInfo(epki
, PR_TRUE
);
402 PORT_ArenaRelease(poolp
, mark
);
404 PORT_ArenaUnmark(poolp
, mark
);
410 /* add a thumbprint to a private key associated certs list
411 * pvk is the area where the list is stored
412 * thumb is the thumbprint to copy
413 * a return of SECFailure indicates an error
416 sec_pkcs12_add_thumbprint(SEC_PKCS12PVKSupportingData
*pvk
,
417 SGNDigestInfo
*thumb
)
419 SGNDigestInfo
**thumb_list
= NULL
;
422 SECStatus rv
= SECFailure
;
424 if((pvk
== NULL
) || (thumb
== NULL
)) {
428 mark
= PORT_ArenaMark(pvk
->poolp
);
430 thumb_list
= pvk
->assocCerts
;
431 nthumbs
= pvk
->nThumbs
;
433 /* allocate list space needed -- either growing or allocating
434 * list must be NULL terminated
436 size
= sizeof(SGNDigestInfo
*);
437 dummy
= PORT_ArenaGrow(pvk
->poolp
, thumb_list
, (size
* (nthumbs
+ 1)),
438 (size
* (nthumbs
+ 2)));
441 thumb_list
[nthumbs
] = (SGNDigestInfo
*)PORT_ArenaZAlloc(pvk
->poolp
,
442 sizeof(SGNDigestInfo
));
443 if(thumb_list
[nthumbs
] != NULL
) {
444 SGN_CopyDigestInfo(pvk
->poolp
, thumb_list
[nthumbs
], thumb
);
446 thumb_list
[nthumbs
] = 0;
453 PORT_ArenaRelease(pvk
->poolp
, mark
);
457 pvk
->assocCerts
= thumb_list
;
458 pvk
->nThumbs
= nthumbs
;
460 PORT_ArenaUnmark(pvk
->poolp
, mark
);
464 /* search the list of shrouded keys in the baggage for the desired
465 * name. return a pointer to the item. a return of NULL indicates
466 * that no match was present or that an error occurred.
468 static SEC_PKCS12ESPVKItem
*
469 sec_pkcs12_get_espvk_by_name(SEC_PKCS12Baggage
*luggage
,
472 PRBool found
= PR_FALSE
;
473 SEC_PKCS12ESPVKItem
*espvk
= NULL
;
475 SECComparison rv
= SECEqual
;
477 SEC_PKCS12BaggageItem
*bag
;
479 if((luggage
== NULL
) || (name
== NULL
)) {
484 while((found
== PR_FALSE
) && (i
< luggage
->luggage_size
)) {
486 bag
= luggage
->bags
[i
];
487 while((found
== PR_FALSE
) && (j
< bag
->nEspvks
)) {
488 espvk
= bag
->espvks
[j
];
489 if(espvk
->poolp
== NULL
) {
490 espvk
->poolp
= luggage
->poolp
;
492 t_name
= SECITEM_DupItem(&espvk
->espvkData
.nickname
);
494 rv
= SECITEM_CompareItem(name
, t_name
);
498 SECITEM_FreeItem(t_name
, PR_TRUE
);
500 PORT_SetError(SEC_ERROR_NO_MEMORY
);
508 if(found
!= PR_TRUE
) {
509 PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME
);
516 /* locates a certificate and copies the thumbprint to the
517 * appropriate private key
520 sec_pkcs12_propagate_thumbprints(SECItem
**nicknames
,
521 CERTCertificate
**ref_certs
,
522 SEC_PKCS12SafeContents
*safe
,
523 SEC_PKCS12Baggage
*baggage
)
525 SEC_PKCS12CertAndCRL
*cert
;
526 SEC_PKCS12PrivateKey
*key
;
527 SEC_PKCS12ESPVKItem
*espvk
;
529 PRBool error
= PR_FALSE
;
530 SECStatus rv
= SECFailure
;
532 if((nicknames
== NULL
) || (safe
== NULL
)) {
537 while((nicknames
[i
] != NULL
) && (error
== PR_FALSE
)) {
538 /* process all certs */
539 cert
= (SEC_PKCS12CertAndCRL
*)sec_pkcs12_find_object(safe
, baggage
,
540 SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID
,
543 /* locate key and copy thumbprint */
544 key
= (SEC_PKCS12PrivateKey
*)sec_pkcs12_find_object(safe
, baggage
,
545 SEC_OID_PKCS12_KEY_BAG_ID
,
548 key
->pvkData
.poolp
= key
->poolp
;
549 rv
= sec_pkcs12_add_thumbprint(&key
->pvkData
,
550 &cert
->value
.x509
->thumbprint
);
552 error
= PR_TRUE
; /* XXX Set error? */
555 /* look in the baggage as well...*/
556 if((baggage
!= NULL
) && (error
== PR_FALSE
)) {
557 espvk
= sec_pkcs12_get_espvk_by_name(baggage
, nicknames
[i
]);
559 espvk
->espvkData
.poolp
= espvk
->poolp
;
560 rv
= sec_pkcs12_add_thumbprint(&espvk
->espvkData
,
561 &cert
->value
.x509
->thumbprint
);
563 error
= PR_TRUE
; /* XXX Set error? */
570 if(error
== PR_TRUE
) {
577 /* append a safe bag to the end of the safe contents list */
579 sec_pkcs12_append_safe_bag(SEC_PKCS12SafeContents
*safe
,
580 SEC_PKCS12SafeBag
*bag
)
583 void *mark
= NULL
, *dummy
= NULL
;
585 if((bag
== NULL
) || (safe
== NULL
))
588 mark
= PORT_ArenaMark(safe
->poolp
);
590 size
= (safe
->safe_size
* sizeof(SEC_PKCS12SafeBag
*));
592 if(safe
->safe_size
> 0) {
593 dummy
= (SEC_PKCS12SafeBag
**)PORT_ArenaGrow(safe
->poolp
,
596 (size
+ sizeof(SEC_PKCS12SafeBag
*)));
597 safe
->contents
= dummy
;
599 safe
->contents
= (SEC_PKCS12SafeBag
**)PORT_ArenaZAlloc(safe
->poolp
,
600 (2 * sizeof(SEC_PKCS12SafeBag
*)));
601 dummy
= safe
->contents
;
605 PORT_SetError(SEC_ERROR_NO_MEMORY
);
609 safe
->contents
[safe
->safe_size
] = bag
;
611 safe
->contents
[safe
->safe_size
] = NULL
;
613 PORT_ArenaUnmark(safe
->poolp
, mark
);
617 PORT_ArenaRelease(safe
->poolp
, mark
);
621 /* append a certificate onto the end of a cert bag */
623 sec_pkcs12_append_cert_to_bag(PRArenaPool
*arena
,
624 SEC_PKCS12SafeBag
*safebag
,
625 CERTCertificate
*cert
,
629 void *dummy
= NULL
, *mark
= NULL
;
630 SEC_PKCS12CertAndCRL
*p12cert
;
631 SEC_PKCS12CertAndCRLBag
*bag
;
633 if((arena
== NULL
) || (safebag
== NULL
) ||
634 (cert
== NULL
) || (nickname
== NULL
)) {
638 bag
= safebag
->safeContent
.certAndCRLBag
;
643 mark
= PORT_ArenaMark(arena
);
645 p12cert
= sec_pkcs12_get_cert(arena
, cert
, nickname
);
646 if(p12cert
== NULL
) {
647 PORT_ArenaRelease(bag
->poolp
, mark
);
651 size
= bag
->bag_size
* sizeof(SEC_PKCS12CertAndCRL
*);
652 if(bag
->bag_size
> 0) {
653 dummy
= (SEC_PKCS12CertAndCRL
**)PORT_ArenaGrow(bag
->poolp
,
654 bag
->certAndCRLs
, size
, size
+ sizeof(SEC_PKCS12CertAndCRL
*));
655 bag
->certAndCRLs
= dummy
;
657 bag
->certAndCRLs
= (SEC_PKCS12CertAndCRL
**)PORT_ArenaZAlloc(bag
->poolp
,
658 (2 * sizeof(SEC_PKCS12CertAndCRL
*)));
659 dummy
= bag
->certAndCRLs
;
663 PORT_SetError(SEC_ERROR_NO_MEMORY
);
667 bag
->certAndCRLs
[bag
->bag_size
] = p12cert
;
669 bag
->certAndCRLs
[bag
->bag_size
] = NULL
;
671 PORT_ArenaUnmark(bag
->poolp
, mark
);
675 PORT_ArenaRelease(bag
->poolp
, mark
);
679 /* append a key onto the end of a list of keys in a key bag */
681 sec_pkcs12_append_key_to_bag(SEC_PKCS12SafeBag
*safebag
,
682 SEC_PKCS12PrivateKey
*pk
)
685 SEC_PKCS12PrivateKeyBag
*bag
;
688 if((safebag
== NULL
) || (pk
== NULL
))
691 bag
= safebag
->safeContent
.keyBag
;
696 mark
= PORT_ArenaMark(bag
->poolp
);
698 size
= (bag
->bag_size
* sizeof(SEC_PKCS12PrivateKey
*));
700 if(bag
->bag_size
> 0) {
701 dummy
= (SEC_PKCS12PrivateKey
**)PORT_ArenaGrow(bag
->poolp
,
704 size
+ sizeof(SEC_PKCS12PrivateKey
*));
705 bag
->privateKeys
= dummy
;
707 bag
->privateKeys
= (SEC_PKCS12PrivateKey
**)PORT_ArenaZAlloc(bag
->poolp
,
708 (2 * sizeof(SEC_PKCS12PrivateKey
*)));
709 dummy
= bag
->privateKeys
;
713 PORT_SetError(SEC_ERROR_NO_MEMORY
);
717 bag
->privateKeys
[bag
->bag_size
] = pk
;
719 bag
->privateKeys
[bag
->bag_size
] = NULL
;
721 PORT_ArenaUnmark(bag
->poolp
, mark
);
725 /* XXX Free memory? */
726 PORT_ArenaRelease(bag
->poolp
, mark
);
730 /* append a safe bag to the baggage area */
732 sec_pkcs12_append_unshrouded_bag(SEC_PKCS12BaggageItem
*bag
,
733 SEC_PKCS12SafeBag
*u_bag
)
736 void *mark
= NULL
, *dummy
= NULL
;
738 if((bag
== NULL
) || (u_bag
== NULL
))
741 mark
= PORT_ArenaMark(bag
->poolp
);
743 /* dump things into the first bag */
744 size
= (bag
->nSecrets
+ 1) * sizeof(SEC_PKCS12SafeBag
*);
745 dummy
= PORT_ArenaGrow(bag
->poolp
,
746 bag
->unencSecrets
, size
,
747 size
+ sizeof(SEC_PKCS12SafeBag
*));
748 bag
->unencSecrets
= dummy
;
750 PORT_SetError(SEC_ERROR_NO_MEMORY
);
754 bag
->unencSecrets
[bag
->nSecrets
] = u_bag
;
756 bag
->unencSecrets
[bag
->nSecrets
] = NULL
;
758 PORT_ArenaUnmark(bag
->poolp
, mark
);
762 PORT_ArenaRelease(bag
->poolp
, mark
);
766 /* gather up all certificates and keys and package them up
767 * in the safe, baggage, or both.
768 * nicknames is the list of nicknames and corresponding certs in ref_certs
769 * ref_certs a null terminated list of certificates
770 * rSafe, rBaggage -- return areas for safe and baggage
771 * shroud_keys -- store keys externally
772 * pwitem -- password for computing integrity mac and encrypting contents
773 * wincx -- window handle
775 * if a failure occurs, an error is set and SECFailure returned.
778 sec_pkcs12_package_certs_and_keys(SECItem
**nicknames
,
779 CERTCertificate
**ref_certs
,
780 PRBool unencryptedCerts
,
781 SEC_PKCS12SafeContents
**rSafe
,
782 SEC_PKCS12Baggage
**rBaggage
,
784 SECOidTag shroud_alg
,
786 PKCS12UnicodeConvertFunction unicodeFn
,
789 PRArenaPool
*permArena
;
790 SEC_PKCS12SafeContents
*safe
= NULL
;
791 SEC_PKCS12Baggage
*baggage
= NULL
;
793 SECStatus rv
= SECFailure
;
794 PRBool problem
= PR_FALSE
;
796 SEC_PKCS12ESPVKItem
*espvk
= NULL
;
797 SEC_PKCS12PrivateKey
*pk
= NULL
;
798 CERTCertificate
*add_cert
= NULL
;
799 SEC_PKCS12SafeBag
*certbag
= NULL
, *keybag
= NULL
;
800 SEC_PKCS12BaggageItem
*external_bag
= NULL
;
801 int ncerts
= 0, nkeys
= 0;
804 if((nicknames
== NULL
) || (rSafe
== NULL
) || (rBaggage
== NULL
)) {
811 permArena
= PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE
);
812 if(permArena
== NULL
) {
813 PORT_SetError(SEC_ERROR_NO_MEMORY
);
817 /* allocate structures */
818 safe
= sec_pkcs12_create_safe_contents(permArena
);
820 PORT_SetError(SEC_ERROR_NO_MEMORY
);
825 certbag
= sec_pkcs12_create_safe_bag(permArena
,
826 SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID
);
827 if(certbag
== NULL
) {
832 if(shroud_keys
!= PR_TRUE
) {
833 keybag
= sec_pkcs12_create_safe_bag(permArena
,
834 SEC_OID_PKCS12_KEY_BAG_ID
);
841 if((shroud_keys
== PR_TRUE
) || (unencryptedCerts
== PR_TRUE
)) {
842 baggage
= sec_pkcs12_create_baggage(permArena
);
843 if(baggage
== NULL
) {
847 external_bag
= sec_pkcs12_create_external_bag(baggage
);
850 /* package keys and certs */
852 while((nicknames
[i
] != NULL
) && (problem
== PR_FALSE
)) {
853 if(ref_certs
[i
] != NULL
) {
854 /* append cert to bag o certs */
855 rv
= sec_pkcs12_append_cert_to_bag(permArena
, certbag
,
858 if(rv
== SECFailure
) {
864 if(rv
== SECSuccess
) {
865 /* package up them keys */
866 if(shroud_keys
== PR_TRUE
) {
867 espvk
= sec_pkcs12_get_shrouded_key(permArena
,
874 rv
= sec_pkcs12_append_shrouded_key(external_bag
, espvk
);
875 SECITEM_CopyItem(permArena
, &espvk
->derCert
,
876 &ref_certs
[i
]->derCert
);
881 pk
= sec_pkcs12_get_private_key(permArena
, nicknames
[i
],
882 ref_certs
[i
], wincx
);
884 rv
= sec_pkcs12_append_key_to_bag(keybag
, pk
);
885 SECITEM_CopyItem(permArena
, &espvk
->derCert
,
886 &ref_certs
[i
]->derCert
);
892 if(rv
== SECFailure
) {
899 /* handle only keys here ? */
905 /* let success fall through */
907 if(problem
== PR_FALSE
) {
908 /* if we have certs, we want to append the cert bag to the
912 if(unencryptedCerts
!= PR_TRUE
) {
913 rv
= sec_pkcs12_append_safe_bag(safe
, certbag
);
915 rv
= sec_pkcs12_append_unshrouded_bag(external_bag
, certbag
);
921 /* append key bag, if they are stored in safe contents */
922 if((rv
== SECSuccess
) && (shroud_keys
== PR_FALSE
) && (nkeys
> 0)) {
923 rv
= sec_pkcs12_append_safe_bag(safe
, keybag
);
929 /* if baggage not used, NULLify it */
930 if((shroud_keys
== PR_TRUE
) || (unencryptedCerts
== PR_TRUE
)) {
931 if(((unencryptedCerts
== PR_TRUE
) && (ncerts
== 0)) &&
932 ((shroud_keys
== PR_TRUE
) && (nkeys
== 0)))
938 if((problem
== PR_TRUE
) || (rv
== SECFailure
)) {
939 PORT_FreeArena(permArena
, PR_TRUE
);
951 /* DER encode the safe contents and return a SECItem. if an error
952 * occurs, NULL is returned.
955 sec_pkcs12_encode_safe_contents(SEC_PKCS12SafeContents
*safe
)
957 SECItem
*dsafe
= NULL
, *tsafe
;
965 /* rv = sec_pkcs12_prepare_for_der_code_safe(safe, PR_TRUE);
966 if(rv != SECSuccess) {
967 PORT_SetError(SEC_ERROR_NO_MEMORY);
971 arena
= PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE
);
973 PORT_SetError(SEC_ERROR_NO_MEMORY
);
977 tsafe
= (SECItem
*)PORT_ArenaZAlloc(arena
, sizeof(SECItem
));
979 dummy
= SEC_ASN1EncodeItem(arena
, tsafe
, safe
,
980 SEC_PKCS12SafeContentsTemplate
);
982 dsafe
= SECITEM_DupItem(tsafe
);
984 PORT_SetError(SEC_ERROR_NO_MEMORY
);
987 PORT_SetError(SEC_ERROR_NO_MEMORY
);
990 PORT_FreeArena(arena
, PR_TRUE
);
995 /* prepare the authenicated safe for encoding and encode it.
996 * baggage is copied to the appropriate area, safe is encoded and
997 * encrypted. the version and transport mode are set on the asafe.
998 * the whole ball of wax is then der encoded and packaged up into
1000 * safe -- container of certs and keys, is encrypted.
1001 * baggage -- container of certs and keys, keys assumed to be encrypted by
1002 * another method, certs are in the clear
1003 * algorithm -- algorithm by which to encrypt safe
1004 * pwitem -- password for encryption
1005 * wincx - window handle
1007 * return of NULL is an error condition.
1009 static SEC_PKCS7ContentInfo
*
1010 sec_pkcs12_get_auth_safe(SEC_PKCS12SafeContents
*safe
,
1011 SEC_PKCS12Baggage
*baggage
,
1012 SECOidTag algorithm
,
1014 PKCS12UnicodeConvertFunction unicodeFn
,
1017 SECItem
*src
= NULL
, *dest
= NULL
, *psalt
= NULL
;
1019 SEC_PKCS12AuthenticatedSafe
*asafe
;
1020 SEC_PKCS7ContentInfo
*safe_cinfo
= NULL
;
1021 SEC_PKCS7ContentInfo
*asafe_cinfo
= NULL
;
1023 SECStatus rv
= SECSuccess
;
1024 PRBool swapUnicodeBytes
= PR_FALSE
;
1026 #ifdef IS_LITTLE_ENDIAN
1027 swapUnicodeBytes
= PR_TRUE
;
1030 if(((safe
!= NULL
) && (pwitem
== NULL
)) && (baggage
== NULL
))
1033 poolp
= PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE
);
1035 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1039 /* prepare authenticated safe for encode */
1040 asafe
= sec_pkcs12_new_asafe(poolp
);
1044 dummy
= SEC_ASN1EncodeInteger(asafe
->poolp
, &asafe
->version
,
1045 SEC_PKCS12_PFX_VERSION
);
1047 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1052 /* generate the privacy salt used to create virtual pwd */
1053 psalt
= sec_pkcs12_generate_salt();
1055 rv
= SECITEM_CopyItem(asafe
->poolp
, &asafe
->privacySalt
,
1057 if(rv
== SECSuccess
) {
1058 asafe
->privacySalt
.len
*= 8;
1061 SECITEM_ZfreeItem(psalt
, PR_TRUE
);
1062 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1067 if((psalt
== NULL
) || (rv
== SECFailure
)) {
1068 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1073 /* package up safe contents */
1076 safe_cinfo
= SEC_PKCS7CreateEncryptedData(algorithm
, NULL
, wincx
);
1077 if((safe_cinfo
!= NULL
) && (safe
->safe_size
> 0)) {
1078 /* encode the safe and encrypt the contents of the
1081 src
= sec_pkcs12_encode_safe_contents(safe
);
1084 rv
= SEC_PKCS7SetContent(safe_cinfo
, (char *)src
->data
, src
->len
);
1085 SECITEM_ZfreeItem(src
, PR_TRUE
);
1086 if(rv
== SECSuccess
) {
1088 vpwd
= sec_pkcs12_create_virtual_password(pwitem
, psalt
,
1089 unicodeFn
, swapUnicodeBytes
);
1091 rv
= SEC_PKCS7EncryptContents(NULL
, safe_cinfo
,
1093 SECITEM_ZfreeItem(vpwd
, PR_TRUE
);
1096 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1099 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1104 } else if(safe
->safe_size
> 0) {
1105 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1108 /* case where there is NULL content in the safe contents */
1109 rv
= SEC_PKCS7SetContent(safe_cinfo
, NULL
, 0);
1110 if(rv
!= SECFailure
) {
1111 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1115 if(rv
!= SECSuccess
) {
1116 SEC_PKCS7DestroyContentInfo(safe_cinfo
);
1121 asafe
->safe
= safe_cinfo
;
1123 PORT_Memcpy(&asafe->safe, safe_cinfo, sizeof(*safe_cinfo));
1127 /* copy the baggage to the authenticated safe baggage if present */
1128 if(baggage
!= NULL
) {
1129 PORT_Memcpy(&asafe
->baggage
, baggage
, sizeof(*baggage
));
1132 /* encode authenticated safe and store it in a Data content info */
1133 dest
= (SECItem
*)PORT_ArenaZAlloc(poolp
, sizeof(SECItem
));
1135 dummy
= SEC_ASN1EncodeItem(poolp
, dest
, asafe
,
1136 SEC_PKCS12AuthenticatedSafeTemplate
);
1138 asafe_cinfo
= SEC_PKCS7CreateData();
1139 if(asafe_cinfo
!= NULL
) {
1140 rv
= SEC_PKCS7SetContent(asafe_cinfo
,
1143 if(rv
!= SECSuccess
) {
1144 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1145 SEC_PKCS7DestroyContentInfo(asafe_cinfo
);
1150 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1157 PORT_FreeArena(poolp
, PR_TRUE
);
1158 if(safe_cinfo
!= NULL
) {
1159 SEC_PKCS7DestroyContentInfo(safe_cinfo
);
1162 SECITEM_ZfreeItem(psalt
, PR_TRUE
);
1165 if(rv
== SECFailure
) {
1172 /* generates the PFX and computes the mac on the authenticated safe
1173 * NULL implies an error
1175 static SEC_PKCS12PFXItem
*
1176 sec_pkcs12_get_pfx(SEC_PKCS7ContentInfo
*cinfo
,
1178 SECItem
*pwitem
, PKCS12UnicodeConvertFunction unicodeFn
)
1180 SECItem
*dest
= NULL
, *mac
= NULL
, *salt
= NULL
, *key
= NULL
;
1181 SEC_PKCS12PFXItem
*pfx
;
1182 SECStatus rv
= SECFailure
;
1185 PRBool swapUnicodeBytes
= PR_FALSE
;
1187 #ifdef IS_LITTLE_ENDIAN
1188 swapUnicodeBytes
= PR_TRUE
;
1191 if((cinfo
== NULL
) || ((do_mac
== PR_TRUE
) && (pwitem
== NULL
))) {
1195 /* allocate new pfx structure */
1196 pfx
= sec_pkcs12_new_pfx();
1198 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1202 PORT_Memcpy(&pfx
->authSafe
, cinfo
, sizeof(*cinfo
));
1203 if(do_mac
== PR_TRUE
) {
1205 /* salt for computing mac */
1206 salt
= sec_pkcs12_generate_salt();
1208 rv
= SECITEM_CopyItem(pfx
->poolp
, &pfx
->macData
.macSalt
, salt
);
1209 pfx
->macData
.macSalt
.len
*= 8;
1211 vpwd
= sec_pkcs12_create_virtual_password(pwitem
, salt
,
1212 unicodeFn
, swapUnicodeBytes
);
1217 key
= sec_pkcs12_generate_key_from_password(SEC_OID_SHA1
,
1219 SECITEM_ZfreeItem(vpwd
, PR_TRUE
);
1222 if((key
!= NULL
) && (rv
== SECSuccess
)) {
1223 dest
= SEC_PKCS7GetContent(cinfo
);
1226 /* compute mac on data -- for password integrity mode */
1227 mac
= sec_pkcs12_generate_mac(key
, dest
, PR_FALSE
);
1229 di
= SGN_CreateDigestInfo(SEC_OID_SHA1
,
1230 mac
->data
, mac
->len
);
1232 rv
= SGN_CopyDigestInfo(pfx
->poolp
,
1233 &pfx
->macData
.safeMac
, di
);
1234 SGN_DestroyDigestInfo(di
);
1236 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1238 SECITEM_ZfreeItem(mac
, PR_TRUE
);
1244 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1249 SECITEM_ZfreeItem(key
, PR_TRUE
);
1251 SECITEM_ZfreeItem(salt
, PR_TRUE
);
1255 if(rv
== SECFailure
) {
1256 SEC_PKCS12DestroyPFX(pfx
);
1263 /* der encode the pfx */
1265 sec_pkcs12_encode_pfx(SEC_PKCS12PFXItem
*pfx
)
1274 dest
= (SECItem
*)PORT_ZAlloc(sizeof(SECItem
));
1276 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1280 dummy
= SEC_ASN1EncodeItem(NULL
, dest
, pfx
, SEC_PKCS12PFXItemTemplate
);
1282 PORT_SetError(SEC_ERROR_NO_MEMORY
);
1283 SECITEM_ZfreeItem(dest
, PR_TRUE
);
1291 SEC_PKCS12GetPFX(char **nicknames
,
1292 CERTCertificate
**ref_certs
,
1294 SEC_PKCS5GetPBEPassword pbef
,
1296 PKCS12UnicodeConvertFunction unicodeFn
,
1299 SECItem
**nicks
= NULL
;
1300 SEC_PKCS12PFXItem
*pfx
= NULL
;
1301 SEC_PKCS12Baggage
*baggage
= NULL
;
1302 SEC_PKCS12SafeContents
*safe
= NULL
;
1303 SEC_PKCS7ContentInfo
*cinfo
= NULL
;
1304 SECStatus rv
= SECFailure
;
1305 SECItem
*dest
= NULL
, *pwitem
= NULL
;
1306 PRBool problem
= PR_FALSE
;
1307 PRBool unencryptedCerts
;
1308 SECOidTag shroud_alg
, safe_alg
;
1310 /* how should we encrypt certs ? */
1311 unencryptedCerts
= !SEC_PKCS12IsEncryptionAllowed();
1312 if(!unencryptedCerts
) {
1313 safe_alg
= SEC_PKCS12GetPreferredEncryptionAlgorithm();
1314 if(safe_alg
== SEC_OID_UNKNOWN
) {
1315 safe_alg
= SEC_PKCS12GetStrongestAllowedAlgorithm();
1317 if(safe_alg
== SEC_OID_UNKNOWN
) {
1318 unencryptedCerts
= PR_TRUE
;
1319 /* for export where no encryption is allowed, we still need
1320 * to encrypt the NULL contents per the spec. encrypted info
1321 * is known plaintext, so it shouldn't be a problem.
1323 safe_alg
= SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC
;
1326 /* for export where no encryption is allowed, we still need
1327 * to encrypt the NULL contents per the spec. encrypted info
1328 * is known plaintext, so it shouldn't be a problem.
1330 safe_alg
= SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC
;
1333 /* keys are always stored with triple DES */
1334 shroud_alg
= SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC
;
1336 /* check for FIPS, if so, do not encrypt certs */
1337 if(PK11_IsFIPS() && !unencryptedCerts
) {
1338 unencryptedCerts
= PR_TRUE
;
1341 if((nicknames
== NULL
) || (pbef
== NULL
) || (ref_certs
== NULL
)) {
1348 pwitem
= (*pbef
)(pbearg
);
1349 if(pwitem
== NULL
) {
1353 nicks
= sec_pkcs12_convert_nickname_list(nicknames
);
1355 /* get safe and baggage */
1356 rv
= sec_pkcs12_package_certs_and_keys(nicks
, ref_certs
, unencryptedCerts
,
1357 &safe
, &baggage
, shroud_keys
,
1358 shroud_alg
, pwitem
, unicodeFn
, wincx
);
1359 if(rv
== SECFailure
) {
1363 if((safe
!= NULL
) && (problem
== PR_FALSE
)) {
1364 /* copy thumbprints */
1365 rv
= sec_pkcs12_propagate_thumbprints(nicks
, ref_certs
, safe
, baggage
);
1367 /* package everything up into AuthenticatedSafe */
1368 cinfo
= sec_pkcs12_get_auth_safe(safe
, baggage
,
1369 safe_alg
, pwitem
, unicodeFn
, wincx
);
1371 sec_pkcs12_destroy_cert_content_infos(safe
, baggage
);
1373 /* get the pfx and mac it */
1375 pfx
= sec_pkcs12_get_pfx(cinfo
, PR_TRUE
, pwitem
, unicodeFn
);
1377 dest
= sec_pkcs12_encode_pfx(pfx
);
1378 SEC_PKCS12DestroyPFX(pfx
);
1380 SEC_PKCS7DestroyContentInfo(cinfo
);
1384 PORT_FreeArena(safe
->poolp
, PR_TRUE
);
1388 PORT_FreeArena(safe
->poolp
, PR_TRUE
);
1394 sec_pkcs12_destroy_nickname_list(nicks
);
1397 if(ref_certs
!= NULL
) {
1398 sec_pkcs12_destroy_certificate_list(ref_certs
);
1401 if(pwitem
!= NULL
) {
1402 SECITEM_ZfreeItem(pwitem
, PR_TRUE
);
1405 if(problem
== PR_TRUE
) {