p12exp.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:36k
源码类别:

CA认证

开发平台:

WINDOWS

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