security/nss/lib/pkcs12/p12exp.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

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;
  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;
  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;
  1028 	    else {
  1029 		SECITEM_ZfreeItem(psalt, PR_TRUE);
  1030 		PORT_SetError(SEC_ERROR_NO_MEMORY);
  1031 		goto loser;
  1035 	if((psalt == NULL) || (rv == SECFailure)) {
  1036 	    PORT_SetError(SEC_ERROR_NO_MEMORY);
  1037 	    rv = SECFailure;
  1038 	    goto loser;
  1041 	/* package up safe contents */
  1042 	if(safe != NULL) 
  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);
  1066 		    } else {
  1067 			PORT_SetError(SEC_ERROR_NO_MEMORY);
  1069 		} else {
  1070 		    rv = SECFailure;
  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);
  1083 	    if(rv != SECSuccess) {
  1084 		SEC_PKCS7DestroyContentInfo(safe_cinfo);
  1085 		safe_cinfo = NULL;
  1086 		goto loser;
  1089 	    asafe->safe = safe_cinfo;	
  1090 	    /*
  1091 	    PORT_Memcpy(&asafe->safe, safe_cinfo, sizeof(*safe_cinfo));
  1092 	    */
  1095 	/* copy the baggage to the authenticated safe baggage if present */
  1096 	if(baggage != NULL) {
  1097 	    PORT_Memcpy(&asafe->baggage, baggage, sizeof(*baggage));
  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;
  1117 	    } else {
  1118 		PORT_SetError(SEC_ERROR_NO_MEMORY);
  1119 		rv = SECFailure;
  1124 loser:
  1125     PORT_FreeArena(poolp, PR_TRUE);
  1126     if(safe_cinfo != NULL) {
  1127     	SEC_PKCS7DestroyContentInfo(safe_cinfo);
  1129     if(psalt != NULL) {
  1130 	SECITEM_ZfreeItem(psalt, PR_TRUE);
  1133     if(rv == SECFailure) {
  1134 	return NULL;
  1137     return asafe_cinfo;
  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)
  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;
  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;
  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);
  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);
  1206 			SECITEM_ZfreeItem(mac, PR_TRUE);
  1208 		} else {
  1209 		    rv = SECFailure;
  1211 	    } else {
  1212 		PORT_SetError(SEC_ERROR_NO_MEMORY);
  1213 		rv = SECFailure;
  1216 	    if(key != NULL) {
  1217 		SECITEM_ZfreeItem(key, PR_TRUE);
  1219 	    SECITEM_ZfreeItem(salt, PR_TRUE);
  1223     if(rv == SECFailure) {
  1224 	SEC_PKCS12DestroyPFX(pfx);
  1225 	pfx = NULL;
  1228     return pfx;
  1231 /* der encode the pfx */
  1232 static SECItem *
  1233 sec_pkcs12_encode_pfx(SEC_PKCS12PFXItem *pfx)
  1235     SECItem *dest;
  1236     void *dummy;
  1238     if(pfx == NULL) {
  1239 	return NULL;
  1242     dest = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
  1243     if(dest == NULL) {
  1244 	PORT_SetError(SEC_ERROR_NO_MEMORY);
  1245 	return NULL;
  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;
  1255     return dest;
  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)
  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();
  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;
  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;
  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;
  1309     if((nicknames == NULL) || (pbef == NULL) || (ref_certs == NULL)) {
  1310 	problem = PR_TRUE;
  1311 	goto loser;
  1315     /* get password */
  1316     pwitem = (*pbef)(pbearg);
  1317     if(pwitem == NULL) {
  1318 	problem = PR_TRUE;
  1319 	goto loser;
  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;
  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);
  1348 	    SEC_PKCS7DestroyContentInfo(cinfo);
  1351 	if(safe != NULL) {
  1352 	    PORT_FreeArena(safe->poolp, PR_TRUE);
  1354     } else {
  1355 	if(safe != NULL) {
  1356 	    PORT_FreeArena(safe->poolp, PR_TRUE);
  1360 loser:
  1361     if(nicks != NULL) {
  1362 	sec_pkcs12_destroy_nickname_list(nicks);
  1365     if(ref_certs != NULL) {
  1366 	sec_pkcs12_destroy_certificate_list(ref_certs);
  1369     if(pwitem != NULL) {
  1370 	SECITEM_ZfreeItem(pwitem, PR_TRUE);
  1373     if(problem == PR_TRUE) {
  1374 	dest = NULL;
  1377     return dest;

mercurial