PageRenderTime 83ms CodeModel.GetById 17ms app.highlight 57ms RepoModel.GetById 1ms app.codeStats 0ms

/security/nss/lib/pkcs12/p12exp.c

http://github.com/zpao/v8monkey
C | 1410 lines | 1047 code | 178 blank | 185 comment | 413 complexity | 7a80aab65d5cf42829d9b970698e49b1 MD5 | raw file
   1/* ***** BEGIN LICENSE BLOCK *****
   2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
   3 *
   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/
   8 *
   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
  12 * License.
  13 *
  14 * The Original Code is the Netscape security libraries.
  15 *
  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.
  20 *
  21 * Contributor(s):
  22 *
  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.
  34 *
  35 * ***** END LICENSE BLOCK ***** */
  36
  37#include "plarena.h"
  38#include "secitem.h"
  39#include "secoid.h"
  40#include "seccomon.h"
  41#include "secport.h"
  42#include "cert.h"
  43#include "pkcs12.h"
  44#include "p12local.h"
  45#include "secpkcs7.h"
  46#include "secasn1.h"
  47#include "secerr.h"
  48#include "p12plcy.h"
  49
  50/* release the memory taken up by the list of nicknames */
  51static void
  52sec_pkcs12_destroy_nickname_list(SECItem **nicknames)
  53{
  54    int i = 0;
  55
  56    if(nicknames == NULL) {
  57	return;
  58    }
  59
  60    while(nicknames[i] != NULL) {
  61	SECITEM_FreeItem(nicknames[i], PR_FALSE);
  62	i++;
  63    }
  64
  65    PORT_Free(nicknames);
  66}
  67   
  68/* release the memory taken up by the list of certificates */ 
  69static void
  70sec_pkcs12_destroy_certificate_list(CERTCertificate **ref_certs)
  71{
  72    int i = 0;
  73
  74    if(ref_certs == NULL) {
  75	return;
  76    }
  77
  78    while(ref_certs[i] != NULL) {
  79	CERT_DestroyCertificate(ref_certs[i]);
  80	i++;
  81    }
  82}
  83
  84static void
  85sec_pkcs12_destroy_cinfos_for_cert_bags(SEC_PKCS12CertAndCRLBag *certBag)
  86{
  87    int j = 0;
  88    j = 0;
  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);
  95	}
  96	j++;
  97    }
  98}
  99
 100/* destroy all content infos since they were not allocated in common
 101 * pool
 102 */
 103static void
 104sec_pkcs12_destroy_cert_content_infos(SEC_PKCS12SafeContents *safe,
 105				      SEC_PKCS12Baggage *baggage)
 106{
 107    int i, j;
 108
 109    if((safe != NULL) && (safe->contents != NULL)) {
 110	i = 0;
 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);
 117	    }
 118	    i++;
 119	}
 120    }
 121
 122    if((baggage != NULL) && (baggage->bags != NULL)) {
 123	i = 0;
 124	while(baggage->bags[i] != NULL) { 
 125	    if(baggage->bags[i]->unencSecrets != NULL) {
 126		j = 0;
 127		while(baggage->bags[i]->unencSecrets[j] != NULL) {
 128		    SECOidTag bagType;
 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);
 134		    }
 135		    j++;
 136		}
 137	    }
 138	    i++;
 139	}
 140    }
 141}
 142
 143/* convert the nickname list from a NULL termincated Char list
 144 * to a NULL terminated SECItem list
 145 */
 146static SECItem **
 147sec_pkcs12_convert_nickname_list(char **nicknames)
 148{
 149    SECItem **nicks;
 150    int i, j;
 151    PRBool error = PR_FALSE;
 152
 153    if(nicknames == NULL) {
 154	return NULL;
 155    }
 156
 157    i = j = 0;
 158    while(nicknames[i] != NULL) {
 159	i++;
 160    }
 161
 162    /* allocate the space and copy the data */	
 163    nicks = (SECItem **)PORT_ZAlloc(sizeof(SECItem *) * (i + 1));
 164    if(nicks != NULL) {
 165	for(j = 0; ((j < i) && (error == PR_FALSE)); j++) {
 166	    nicks[j] = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
 167	    if(nicks[j] != NULL) {
 168		nicks[j]->data = 
 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;
 174		} else {
 175		    error = PR_TRUE;
 176		}
 177	    } else {
 178	       error = PR_TRUE;
 179	    }
 180	}
 181    }
 182
 183    if(error == PR_TRUE) {
 184        for(i = 0; i < j; i++) { 
 185	    SECITEM_FreeItem(nicks[i], PR_TRUE);
 186	}
 187	PORT_Free(nicks);
 188	nicks = NULL;
 189    }
 190
 191    return nicks;
 192}
 193
 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
 201 */
 202static SEC_PKCS12CertAndCRL *
 203sec_pkcs12_get_cert(PRArenaPool *poolp,
 204		       CERTCertificate *add_cert, 
 205		       SECItem *nickname)
 206{
 207    SEC_PKCS12CertAndCRL *cert;
 208    SEC_PKCS7ContentInfo *cinfo;
 209    SGNDigestInfo *t_di;
 210    void *mark;
 211    SECStatus rv;
 212
 213    if((poolp == NULL) || (add_cert == NULL) || (nickname == NULL)) {
 214    	return NULL;
 215    }
 216    mark = PORT_ArenaMark(poolp);
 217
 218    cert = sec_pkcs12_new_cert_crl(poolp, SEC_OID_PKCS12_X509_CERT_CRL_BAG);
 219    if(cert != NULL) {
 220
 221	/* copy the nickname */
 222	rv = SECITEM_CopyItem(poolp, &cert->nickname, nickname);
 223	if(rv != SECSuccess) {
 224	    PORT_SetError(SEC_ERROR_NO_MEMORY);
 225	    cert = NULL;
 226	} else {
 227
 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
 231	     */
 232	    cinfo = SEC_PKCS7CreateCertsOnly(add_cert, PR_TRUE, NULL);
 233	    rv = SEC_PKCS7PrepareForEncode(cinfo, NULL, NULL, NULL);
 234
 235	    /* thumbprint the certificate */
 236	    if((cinfo != NULL) && (rv == SECSuccess))
 237	    {
 238		PORT_Memcpy(&cert->value.x509->certOrCRL, cinfo, sizeof(*cinfo));
 239		t_di = sec_pkcs12_compute_thumbprint(&add_cert->derCert);
 240		if(t_di != NULL)
 241		{
 242		    /* test */
 243		    rv = SGN_CopyDigestInfo(poolp, &cert->value.x509->thumbprint,
 244		    			    t_di);
 245		    if(rv != SECSuccess) {
 246			cert = NULL;
 247			PORT_SetError(SEC_ERROR_NO_MEMORY);
 248		    }
 249		    SGN_DestroyDigestInfo(t_di);
 250		}
 251		else
 252		    cert = NULL;
 253	    }
 254	}
 255    }
 256
 257    if (cert == NULL) {
 258	PORT_ArenaRelease(poolp, mark);
 259    } else {
 260	PORT_ArenaUnmark(poolp, mark);
 261    }
 262
 263    return cert;
 264}
 265
 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
 273 */
 274static SEC_PKCS12PrivateKey *
 275sec_pkcs12_get_private_key(PRArenaPool *poolp,
 276			   SECItem *nickname,
 277			   CERTCertificate *cert,
 278			   void *wincx)
 279{
 280    SECKEYPrivateKeyInfo *pki;
 281    SEC_PKCS12PrivateKey *pk;
 282    SECStatus rv;
 283    void *mark;
 284
 285    if((poolp == NULL) || (nickname == NULL)) {
 286	return NULL;
 287    }
 288
 289    mark = PORT_ArenaMark(poolp);
 290
 291    /* retrieve key from the data base */
 292    pki = PK11_ExportPrivateKeyInfo(nickname, cert, wincx);
 293    if(pki == NULL) {
 294	PORT_ArenaRelease(poolp, mark);
 295	PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY);
 296	return NULL;
 297    }
 298
 299    pk = (SEC_PKCS12PrivateKey *)PORT_ArenaZAlloc(poolp,
 300						  sizeof(SEC_PKCS12PrivateKey));
 301    if(pk != NULL) {
 302	rv = sec_pkcs12_init_pvk_data(poolp, &pk->pvkData);
 303
 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);
 309	    }
 310	}
 311
 312	if(rv != SECSuccess) {
 313	    PORT_SetError(SEC_ERROR_NO_MEMORY);
 314	    pk = NULL;
 315	}
 316    } else {
 317	PORT_SetError(SEC_ERROR_NO_MEMORY); 
 318    }
 319
 320    /* destroy private key, zeroing out data */
 321    SECKEY_DestroyPrivateKeyInfo(pki, PR_TRUE);
 322    if (pk == NULL) {
 323	PORT_ArenaRelease(poolp, mark);
 324    } else {
 325	PORT_ArenaUnmark(poolp, mark);
 326    }
 327
 328    return pk;
 329}
 330
 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
 338 */
 339static SEC_PKCS12ESPVKItem *
 340sec_pkcs12_get_shrouded_key(PRArenaPool *poolp,
 341			    SECItem *nickname,
 342			    CERTCertificate *cert,
 343			    SECOidTag algorithm, 
 344			    SECItem *pwitem,
 345			    PKCS12UnicodeConvertFunction unicodeFn,
 346			    void *wincx)
 347{
 348    SECKEYEncryptedPrivateKeyInfo *epki;
 349    SEC_PKCS12ESPVKItem *pk;
 350    void *mark;
 351    SECStatus rv;
 352    PK11SlotInfo *slot = NULL;
 353    PRBool swapUnicodeBytes = PR_FALSE;
 354
 355#ifdef IS_LITTLE_ENDIAN
 356    swapUnicodeBytes = PR_TRUE;
 357#endif
 358
 359    if((poolp == NULL) || (nickname == NULL))
 360	return NULL;
 361
 362    mark = PORT_ArenaMark(poolp);
 363
 364    /* use internal key slot */
 365    slot = PK11_GetInternalKeySlot();
 366
 367    /* retrieve encrypted prviate key */
 368    epki = PK11_ExportEncryptedPrivateKeyInfo(slot, algorithm, pwitem, 
 369    					      nickname, cert, 1, 0, NULL);
 370    PK11_FreeSlot(slot);
 371    if(epki == NULL) {
 372	PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY);
 373	PORT_ArenaRelease(poolp, mark);
 374	return NULL;
 375    }
 376
 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);
 379    if(pk != NULL) {
 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);
 391	    }
 392	}
 393
 394	if(rv != SECSuccess) {
 395	    PORT_SetError(SEC_ERROR_NO_MEMORY);
 396	    pk = NULL;
 397	}
 398    }
 399
 400    SECKEY_DestroyEncryptedPrivateKeyInfo(epki, PR_TRUE);
 401    if(pk == NULL) {
 402	PORT_ArenaRelease(poolp, mark);
 403    } else {
 404	PORT_ArenaUnmark(poolp, mark);
 405    }
 406	
 407    return pk;
 408}
 409
 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 
 414 */
 415static SECStatus 
 416sec_pkcs12_add_thumbprint(SEC_PKCS12PVKSupportingData *pvk,
 417			  SGNDigestInfo *thumb)
 418{
 419    SGNDigestInfo **thumb_list = NULL;
 420    int nthumbs, size;
 421    void *mark, *dummy;
 422    SECStatus rv = SECFailure;
 423
 424    if((pvk == NULL) || (thumb == NULL)) {
 425	return SECFailure;
 426    }
 427
 428    mark = PORT_ArenaMark(pvk->poolp);
 429
 430    thumb_list = pvk->assocCerts;
 431    nthumbs = pvk->nThumbs;
 432
 433    /* allocate list space needed -- either growing or allocating 
 434     * list must be NULL terminated 
 435     */
 436    size = sizeof(SGNDigestInfo *);
 437    dummy = PORT_ArenaGrow(pvk->poolp, thumb_list, (size * (nthumbs + 1)),
 438    			   (size * (nthumbs + 2)));
 439    thumb_list = dummy;
 440    if(dummy != NULL) {
 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);
 445	    nthumbs += 1;
 446	    thumb_list[nthumbs] = 0;
 447	} else {
 448	    dummy = NULL;
 449	}
 450    }
 451
 452    if(dummy == NULL) {
 453    	PORT_ArenaRelease(pvk->poolp, mark);
 454	return SECFailure;
 455    } 
 456
 457    pvk->assocCerts = thumb_list;
 458    pvk->nThumbs = nthumbs;
 459
 460    PORT_ArenaUnmark(pvk->poolp, mark);
 461    return SECSuccess;
 462}
 463
 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.
 467 */
 468static SEC_PKCS12ESPVKItem *
 469sec_pkcs12_get_espvk_by_name(SEC_PKCS12Baggage *luggage, 
 470			     SECItem *name)
 471{
 472    PRBool found = PR_FALSE;
 473    SEC_PKCS12ESPVKItem *espvk = NULL;
 474    int i, j;
 475    SECComparison rv = SECEqual;
 476    SECItem *t_name;
 477    SEC_PKCS12BaggageItem *bag;
 478
 479    if((luggage == NULL) || (name == NULL)) {
 480	return NULL;
 481    }
 482
 483    i = 0;
 484    while((found == PR_FALSE) && (i < luggage->luggage_size)) {
 485	j = 0;
 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;
 491	    }
 492	    t_name = SECITEM_DupItem(&espvk->espvkData.nickname);
 493	    if(t_name != NULL) {
 494		rv = SECITEM_CompareItem(name, t_name);
 495		if(rv == SECEqual) {
 496		    found = PR_TRUE;
 497		}
 498		SECITEM_FreeItem(t_name, PR_TRUE);
 499	    } else {
 500		PORT_SetError(SEC_ERROR_NO_MEMORY);
 501		return NULL;
 502	    }
 503	    j++;
 504	}
 505	i++;
 506    }
 507
 508    if(found != PR_TRUE) {
 509	PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME);
 510	return NULL;
 511    }
 512
 513    return espvk;
 514}
 515
 516/* locates a certificate and copies the thumbprint to the
 517 * appropriate private key
 518 */
 519static SECStatus 
 520sec_pkcs12_propagate_thumbprints(SECItem **nicknames,
 521				 CERTCertificate **ref_certs,
 522				 SEC_PKCS12SafeContents *safe,
 523				 SEC_PKCS12Baggage *baggage)
 524{
 525    SEC_PKCS12CertAndCRL *cert;
 526    SEC_PKCS12PrivateKey *key;
 527    SEC_PKCS12ESPVKItem *espvk;
 528    int i;
 529    PRBool error = PR_FALSE;
 530    SECStatus rv = SECFailure;
 531
 532    if((nicknames == NULL) || (safe == NULL)) {
 533	return SECFailure;
 534    }
 535
 536    i = 0;
 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,
 541					nicknames[i], NULL);
 542	if(cert != NULL) {
 543	    /* locate key and copy thumbprint */
 544	    key = (SEC_PKCS12PrivateKey *)sec_pkcs12_find_object(safe, baggage,
 545	    				SEC_OID_PKCS12_KEY_BAG_ID,
 546	    				nicknames[i], NULL);
 547	    if(key != NULL) {
 548		key->pvkData.poolp = key->poolp;
 549		rv = sec_pkcs12_add_thumbprint(&key->pvkData, 
 550			&cert->value.x509->thumbprint);
 551		if(rv == SECFailure)
 552		    error = PR_TRUE;  /* XXX Set error? */
 553	    }
 554
 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]);
 558		if(espvk != NULL) {
 559		    espvk->espvkData.poolp = espvk->poolp;
 560		    rv = sec_pkcs12_add_thumbprint(&espvk->espvkData,
 561			&cert->value.x509->thumbprint);
 562		    if(rv == SECFailure)
 563			error = PR_TRUE;  /* XXX Set error? */
 564		}
 565	    }
 566	}
 567	i++;
 568    }
 569
 570    if(error == PR_TRUE) {
 571	return SECFailure;
 572    }
 573
 574    return SECSuccess;
 575}
 576
 577/* append a safe bag to the end of the safe contents list */
 578SECStatus 
 579sec_pkcs12_append_safe_bag(SEC_PKCS12SafeContents *safe,
 580			   SEC_PKCS12SafeBag *bag)
 581{
 582    int size;
 583    void *mark = NULL, *dummy = NULL;
 584
 585    if((bag == NULL) || (safe == NULL))
 586	return SECFailure;
 587
 588    mark = PORT_ArenaMark(safe->poolp);
 589
 590    size = (safe->safe_size * sizeof(SEC_PKCS12SafeBag *));
 591    
 592    if(safe->safe_size > 0) {
 593	dummy = (SEC_PKCS12SafeBag **)PORT_ArenaGrow(safe->poolp, 
 594	    				safe->contents, 
 595	    				size, 
 596	    				(size + sizeof(SEC_PKCS12SafeBag *)));
 597	safe->contents = dummy;
 598    } else {
 599	safe->contents = (SEC_PKCS12SafeBag **)PORT_ArenaZAlloc(safe->poolp, 
 600	    (2 * sizeof(SEC_PKCS12SafeBag *)));
 601	dummy = safe->contents;
 602    }
 603
 604    if(dummy == NULL) {
 605	PORT_SetError(SEC_ERROR_NO_MEMORY);
 606	goto loser;
 607    }
 608
 609    safe->contents[safe->safe_size] = bag;
 610    safe->safe_size++;
 611    safe->contents[safe->safe_size] = NULL;
 612
 613    PORT_ArenaUnmark(safe->poolp, mark);
 614    return SECSuccess;
 615
 616loser:
 617    PORT_ArenaRelease(safe->poolp, mark);
 618    return SECFailure;
 619}
 620
 621/* append a certificate onto the end of a cert bag */
 622static SECStatus 
 623sec_pkcs12_append_cert_to_bag(PRArenaPool *arena,
 624			      SEC_PKCS12SafeBag *safebag,
 625			      CERTCertificate *cert,
 626			      SECItem *nickname)
 627{
 628    int size;
 629    void *dummy = NULL, *mark = NULL;
 630    SEC_PKCS12CertAndCRL *p12cert;
 631    SEC_PKCS12CertAndCRLBag *bag;
 632
 633    if((arena == NULL) || (safebag == NULL) || 
 634    	(cert == NULL) || (nickname == NULL)) {
 635	return SECFailure;
 636    }
 637
 638    bag = safebag->safeContent.certAndCRLBag;
 639    if(bag == NULL) {
 640	return SECFailure;
 641    }
 642
 643    mark = PORT_ArenaMark(arena);
 644
 645    p12cert = sec_pkcs12_get_cert(arena, cert, nickname);
 646    if(p12cert == NULL) {
 647	PORT_ArenaRelease(bag->poolp, mark);
 648	return SECFailure;
 649    }
 650
 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;
 656    } else {
 657	bag->certAndCRLs = (SEC_PKCS12CertAndCRL **)PORT_ArenaZAlloc(bag->poolp,
 658	    (2 * sizeof(SEC_PKCS12CertAndCRL *)));
 659	dummy = bag->certAndCRLs;
 660    }
 661
 662    if(dummy == NULL) {
 663	PORT_SetError(SEC_ERROR_NO_MEMORY);
 664	goto loser;
 665    }
 666
 667    bag->certAndCRLs[bag->bag_size] = p12cert;
 668    bag->bag_size++;
 669    bag->certAndCRLs[bag->bag_size] = NULL;
 670
 671    PORT_ArenaUnmark(bag->poolp, mark);
 672    return SECSuccess;
 673
 674loser:
 675    PORT_ArenaRelease(bag->poolp, mark);
 676    return SECFailure;
 677}
 678
 679/* append a key onto the end of a list of keys in a key bag */
 680SECStatus 
 681sec_pkcs12_append_key_to_bag(SEC_PKCS12SafeBag *safebag,
 682			     SEC_PKCS12PrivateKey *pk)
 683{
 684    void *mark, *dummy;
 685    SEC_PKCS12PrivateKeyBag *bag;
 686    int size;
 687
 688    if((safebag == NULL) || (pk == NULL))
 689	return SECFailure;
 690
 691    bag = safebag->safeContent.keyBag;
 692    if(bag == NULL) {
 693	return SECFailure;
 694    }
 695
 696    mark = PORT_ArenaMark(bag->poolp);
 697
 698    size = (bag->bag_size * sizeof(SEC_PKCS12PrivateKey *));
 699
 700    if(bag->bag_size > 0) {
 701	dummy = (SEC_PKCS12PrivateKey **)PORT_ArenaGrow(bag->poolp,
 702					bag->privateKeys, 
 703					size, 
 704					size + sizeof(SEC_PKCS12PrivateKey *));
 705	bag->privateKeys = dummy;
 706    } else {
 707	bag->privateKeys = (SEC_PKCS12PrivateKey **)PORT_ArenaZAlloc(bag->poolp,
 708	    (2 * sizeof(SEC_PKCS12PrivateKey *)));
 709	dummy = bag->privateKeys;
 710    }
 711
 712    if(dummy == NULL) {
 713	PORT_SetError(SEC_ERROR_NO_MEMORY);
 714	goto loser;
 715    }
 716
 717    bag->privateKeys[bag->bag_size] = pk;
 718    bag->bag_size++;
 719    bag->privateKeys[bag->bag_size] = NULL;
 720
 721    PORT_ArenaUnmark(bag->poolp, mark);
 722    return SECSuccess;
 723
 724loser:
 725    /* XXX Free memory? */
 726    PORT_ArenaRelease(bag->poolp, mark);
 727    return SECFailure;
 728}
 729
 730/* append a safe bag to the baggage area */
 731static SECStatus 
 732sec_pkcs12_append_unshrouded_bag(SEC_PKCS12BaggageItem *bag,
 733				 SEC_PKCS12SafeBag *u_bag)
 734{
 735    int size;
 736    void *mark = NULL, *dummy = NULL;
 737
 738    if((bag == NULL) || (u_bag == NULL))
 739	return SECFailure;
 740
 741    mark = PORT_ArenaMark(bag->poolp);
 742
 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;
 749    if(dummy == NULL) {
 750	PORT_SetError(SEC_ERROR_NO_MEMORY);
 751	goto loser;
 752    }
 753
 754    bag->unencSecrets[bag->nSecrets] = u_bag;
 755    bag->nSecrets++;
 756    bag->unencSecrets[bag->nSecrets] = NULL;
 757
 758    PORT_ArenaUnmark(bag->poolp, mark);
 759    return SECSuccess;
 760
 761loser:
 762    PORT_ArenaRelease(bag->poolp, mark);
 763    return SECFailure;
 764}
 765
 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
 774 *
 775 * if a failure occurs, an error is set and SECFailure returned.
 776 */
 777static SECStatus
 778sec_pkcs12_package_certs_and_keys(SECItem **nicknames,
 779				  CERTCertificate **ref_certs,
 780				  PRBool unencryptedCerts,
 781				  SEC_PKCS12SafeContents **rSafe,
 782				  SEC_PKCS12Baggage **rBaggage,
 783				  PRBool shroud_keys, 
 784				  SECOidTag shroud_alg,
 785				  SECItem *pwitem,
 786				  PKCS12UnicodeConvertFunction unicodeFn,
 787				  void *wincx)
 788{
 789    PRArenaPool *permArena;
 790    SEC_PKCS12SafeContents *safe = NULL;
 791    SEC_PKCS12Baggage *baggage = NULL;
 792
 793    SECStatus rv = SECFailure;
 794    PRBool problem = PR_FALSE;
 795
 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;
 802    int i;
 803
 804    if((nicknames == NULL) || (rSafe == NULL) || (rBaggage == NULL)) {
 805	return SECFailure;
 806    }
 807	
 808    *rBaggage = baggage;
 809    *rSafe = safe;
 810
 811    permArena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
 812    if(permArena == NULL) {
 813	PORT_SetError(SEC_ERROR_NO_MEMORY);
 814	return SECFailure;
 815     }
 816
 817    /* allocate structures */
 818    safe = sec_pkcs12_create_safe_contents(permArena);
 819    if(safe == NULL) {
 820	PORT_SetError(SEC_ERROR_NO_MEMORY);
 821	rv = SECFailure;
 822	goto loser;
 823    }
 824
 825    certbag = sec_pkcs12_create_safe_bag(permArena, 
 826					 SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID);
 827    if(certbag == NULL) {
 828	rv = SECFailure;
 829	goto loser;
 830    }
 831
 832    if(shroud_keys != PR_TRUE) {
 833	keybag = sec_pkcs12_create_safe_bag(permArena, 
 834					    SEC_OID_PKCS12_KEY_BAG_ID);
 835	if(keybag == NULL) {
 836	    rv = SECFailure;
 837	    goto loser;
 838	}
 839    }
 840
 841    if((shroud_keys == PR_TRUE) || (unencryptedCerts == PR_TRUE)) {
 842	baggage = sec_pkcs12_create_baggage(permArena);
 843    	if(baggage == NULL) {
 844	    rv = SECFailure;
 845	    goto loser;
 846	}
 847	external_bag = sec_pkcs12_create_external_bag(baggage);
 848    }
 849
 850    /* package keys and certs */
 851    i = 0;
 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, 
 856	    				       ref_certs[i],
 857	    				       nicknames[i]);
 858	    if(rv == SECFailure) {
 859		problem = PR_FALSE;
 860	    } else {
 861		ncerts++;
 862	    }
 863
 864	    if(rv == SECSuccess) {
 865		/* package up them keys */
 866		if(shroud_keys == PR_TRUE) {
 867	    	    espvk = sec_pkcs12_get_shrouded_key(permArena, 
 868							nicknames[i],
 869	    	    					ref_certs[i],
 870							shroud_alg, 
 871							pwitem, unicodeFn,
 872							wincx);
 873		    if(espvk != NULL) {
 874			rv = sec_pkcs12_append_shrouded_key(external_bag, espvk);
 875			SECITEM_CopyItem(permArena, &espvk->derCert,
 876					 &ref_certs[i]->derCert);
 877		    } else {
 878			rv = SECFailure;
 879		    }
 880		} else {
 881		    pk = sec_pkcs12_get_private_key(permArena, nicknames[i], 
 882		    				    ref_certs[i], wincx);
 883		    if(pk != NULL) {
 884			rv = sec_pkcs12_append_key_to_bag(keybag, pk);
 885			SECITEM_CopyItem(permArena, &espvk->derCert,
 886					 &ref_certs[i]->derCert);
 887		    } else {
 888			rv = SECFailure;
 889		    }
 890		}
 891	
 892		if(rv == SECFailure) {
 893		    problem = PR_TRUE;
 894		} else {
 895		    nkeys++;
 896		}
 897	    }
 898	} else {
 899	    /* handle only keys here ? */
 900	    problem = PR_TRUE;
 901	}
 902	i++;
 903    }
 904
 905    /* let success fall through */
 906loser:
 907    if(problem == PR_FALSE) {
 908	/* if we have certs, we want to append the cert bag to the 
 909	 * appropriate area 
 910	 */
 911	if(ncerts > 0) {
 912	    if(unencryptedCerts != PR_TRUE) {
 913		rv = sec_pkcs12_append_safe_bag(safe, certbag);
 914	    } else {
 915		rv = sec_pkcs12_append_unshrouded_bag(external_bag, certbag);
 916	    }
 917	} else {
 918	    rv = SECSuccess;
 919	}
 920
 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);
 924	}
 925    } else {
 926	rv = SECFailure;
 927    }
 928
 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)))
 933		baggage = NULL;
 934    } else {
 935	baggage = NULL;
 936    }
 937
 938    if((problem == PR_TRUE) || (rv == SECFailure)) {
 939	PORT_FreeArena(permArena, PR_TRUE);
 940	rv = SECFailure;
 941	baggage = NULL;
 942	safe = NULL;
 943    }
 944
 945    *rBaggage = baggage;
 946    *rSafe = safe;
 947
 948    return rv;
 949}
 950
 951/* DER encode the safe contents and return a SECItem.  if an error
 952 * occurs, NULL is returned.
 953 */
 954static SECItem *
 955sec_pkcs12_encode_safe_contents(SEC_PKCS12SafeContents *safe)
 956{
 957    SECItem *dsafe = NULL, *tsafe;
 958    void *dummy = NULL;
 959    PRArenaPool *arena;
 960
 961    if(safe == NULL) {
 962	return NULL;
 963    }
 964
 965/*    rv = sec_pkcs12_prepare_for_der_code_safe(safe, PR_TRUE);
 966    if(rv != SECSuccess) {
 967	PORT_SetError(SEC_ERROR_NO_MEMORY);
 968	return NULL;
 969    }*/
 970
 971    arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
 972    if(arena == NULL) {
 973	PORT_SetError(SEC_ERROR_NO_MEMORY);
 974	return NULL;
 975    }
 976
 977    tsafe = (SECItem *)PORT_ArenaZAlloc(arena, sizeof(SECItem));
 978    if(tsafe != NULL) {
 979	dummy = SEC_ASN1EncodeItem(arena, tsafe, safe, 
 980	    SEC_PKCS12SafeContentsTemplate);
 981	if(dummy != NULL) {
 982	    dsafe = SECITEM_DupItem(tsafe);
 983	} else {
 984	    PORT_SetError(SEC_ERROR_NO_MEMORY);
 985	}
 986    } else {
 987	PORT_SetError(SEC_ERROR_NO_MEMORY);
 988    }
 989
 990    PORT_FreeArena(arena, PR_TRUE);
 991
 992    return dsafe;
 993}
 994
 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
 999 *   data content info 
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
1006 *
1007 * return of NULL is an error condition.
1008 */
1009static SEC_PKCS7ContentInfo *
1010sec_pkcs12_get_auth_safe(SEC_PKCS12SafeContents *safe, 
1011			 SEC_PKCS12Baggage *baggage,  
1012			 SECOidTag algorithm, 
1013			 SECItem *pwitem,
1014			 PKCS12UnicodeConvertFunction unicodeFn,
1015			 void *wincx)
1016{
1017    SECItem *src = NULL, *dest = NULL, *psalt = NULL;
1018    PRArenaPool *poolp;
1019    SEC_PKCS12AuthenticatedSafe *asafe;
1020    SEC_PKCS7ContentInfo *safe_cinfo = NULL;
1021    SEC_PKCS7ContentInfo *asafe_cinfo = NULL;
1022    void *dummy;
1023    SECStatus rv = SECSuccess;
1024    PRBool swapUnicodeBytes = PR_FALSE;
1025
1026#ifdef IS_LITTLE_ENDIAN
1027    swapUnicodeBytes = PR_TRUE;
1028#endif
1029    
1030    if(((safe != NULL) && (pwitem == NULL)) && (baggage == NULL))
1031	return NULL;
1032
1033    poolp = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
1034    if(poolp == NULL) {
1035	PORT_SetError(SEC_ERROR_NO_MEMORY);
1036	return NULL;
1037    }
1038
1039    /* prepare authenticated safe for encode */
1040    asafe = sec_pkcs12_new_asafe(poolp);
1041    if(asafe != NULL) {
1042
1043	/* set version */
1044	dummy = SEC_ASN1EncodeInteger(asafe->poolp, &asafe->version,
1045				      SEC_PKCS12_PFX_VERSION);
1046	if(dummy == NULL) {
1047	    PORT_SetError(SEC_ERROR_NO_MEMORY);
1048	    rv = SECFailure;
1049	    goto loser;
1050	}
1051
1052	/* generate the privacy salt used to create virtual pwd */
1053	psalt = sec_pkcs12_generate_salt();
1054	if(psalt != NULL) {
1055	    rv = SECITEM_CopyItem(asafe->poolp, &asafe->privacySalt,
1056				  psalt);
1057	    if(rv == SECSuccess) {
1058		asafe->privacySalt.len *= 8;
1059	    } 
1060	    else {
1061		SECITEM_ZfreeItem(psalt, PR_TRUE);
1062		PORT_SetError(SEC_ERROR_NO_MEMORY);
1063		goto loser;
1064	    }
1065	} 
1066
1067	if((psalt == NULL) || (rv == SECFailure)) {
1068	    PORT_SetError(SEC_ERROR_NO_MEMORY);
1069	    rv = SECFailure;
1070	    goto loser;
1071	}
1072
1073	/* package up safe contents */
1074	if(safe != NULL) 
1075	{
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 
1079		 * content info
1080		 */
1081		src = sec_pkcs12_encode_safe_contents(safe);
1082
1083		if(src != NULL) {
1084		    rv = SEC_PKCS7SetContent(safe_cinfo, (char *)src->data, src->len);
1085		    SECITEM_ZfreeItem(src, PR_TRUE);
1086		    if(rv == SECSuccess) {
1087			SECItem *vpwd;
1088			vpwd = sec_pkcs12_create_virtual_password(pwitem, psalt,
1089						unicodeFn, swapUnicodeBytes);
1090			if(vpwd != NULL) {
1091			    rv = SEC_PKCS7EncryptContents(NULL, safe_cinfo,
1092							  vpwd, wincx);
1093			    SECITEM_ZfreeItem(vpwd, PR_TRUE);
1094			} else {
1095			    rv = SECFailure;
1096			    PORT_SetError(SEC_ERROR_NO_MEMORY);
1097			}
1098		    } else {
1099			PORT_SetError(SEC_ERROR_NO_MEMORY);
1100		    }
1101		} else {
1102		    rv = SECFailure;
1103		}
1104	    } else if(safe->safe_size > 0) {
1105		PORT_SetError(SEC_ERROR_NO_MEMORY);
1106		goto loser;
1107	    } else {
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);
1112		}
1113	    }
1114
1115	    if(rv != SECSuccess) {
1116		SEC_PKCS7DestroyContentInfo(safe_cinfo);
1117		safe_cinfo = NULL;
1118		goto loser;
1119	    }
1120
1121	    asafe->safe = safe_cinfo;	
1122	    /*
1123	    PORT_Memcpy(&asafe->safe, safe_cinfo, sizeof(*safe_cinfo));
1124	    */
1125	}
1126
1127	/* copy the baggage to the authenticated safe baggage if present */
1128	if(baggage != NULL) {
1129	    PORT_Memcpy(&asafe->baggage, baggage, sizeof(*baggage));
1130	}
1131
1132	/* encode authenticated safe and store it in a Data content info */
1133	dest = (SECItem *)PORT_ArenaZAlloc(poolp, sizeof(SECItem));
1134	if(dest != NULL) {
1135	    dummy = SEC_ASN1EncodeItem(poolp, dest, asafe, 
1136				SEC_PKCS12AuthenticatedSafeTemplate);
1137	    if(dummy != NULL) {
1138		asafe_cinfo = SEC_PKCS7CreateData();
1139		if(asafe_cinfo != NULL) {
1140		    rv = SEC_PKCS7SetContent(asafe_cinfo, 
1141					 	(char *)dest->data, 
1142						dest->len);
1143		    if(rv != SECSuccess) {
1144			PORT_SetError(SEC_ERROR_NO_MEMORY);
1145			SEC_PKCS7DestroyContentInfo(asafe_cinfo);
1146			asafe_cinfo = NULL;
1147		    }
1148		}
1149	    } else {
1150		PORT_SetError(SEC_ERROR_NO_MEMORY);
1151		rv = SECFailure;
1152	    }
1153	}
1154    }
1155
1156loser:
1157    PORT_FreeArena(poolp, PR_TRUE);
1158    if(safe_cinfo != NULL) {
1159    	SEC_PKCS7DestroyContentInfo(safe_cinfo);
1160    }
1161    if(psalt != NULL) {
1162	SECITEM_ZfreeItem(psalt, PR_TRUE);
1163    }
1164
1165    if(rv == SECFailure) {
1166	return NULL;
1167    }
1168	
1169    return asafe_cinfo;
1170}
1171
1172/* generates the PFX and computes the mac on the authenticated safe 
1173 * NULL implies an error
1174 */
1175static SEC_PKCS12PFXItem *
1176sec_pkcs12_get_pfx(SEC_PKCS7ContentInfo *cinfo, 
1177		   PRBool do_mac, 
1178		   SECItem *pwitem, PKCS12UnicodeConvertFunction unicodeFn)
1179{
1180    SECItem *dest = NULL, *mac = NULL, *salt = NULL, *key = NULL;
1181    SEC_PKCS12PFXItem *pfx;
1182    SECStatus rv = SECFailure;
1183    SGNDigestInfo *di;
1184    SECItem *vpwd;
1185    PRBool swapUnicodeBytes = PR_FALSE;
1186
1187#ifdef IS_LITTLE_ENDIAN
1188    swapUnicodeBytes = PR_TRUE;
1189#endif
1190
1191    if((cinfo == NULL) || ((do_mac == PR_TRUE) && (pwitem == NULL))) {
1192	return NULL;
1193    }
1194
1195    /* allocate new pfx structure */
1196    pfx = sec_pkcs12_new_pfx();
1197    if(pfx == NULL) {
1198	PORT_SetError(SEC_ERROR_NO_MEMORY);
1199	return NULL;
1200    }
1201
1202    PORT_Memcpy(&pfx->authSafe, cinfo, sizeof(*cinfo));
1203    if(do_mac == PR_TRUE) {
1204
1205    	/* salt for computing mac */
1206	salt = sec_pkcs12_generate_salt();
1207	if(salt != NULL) {
1208	    rv = SECITEM_CopyItem(pfx->poolp, &pfx->macData.macSalt, salt);
1209	    pfx->macData.macSalt.len *= 8;
1210
1211	    vpwd = sec_pkcs12_create_virtual_password(pwitem, salt,
1212						unicodeFn, swapUnicodeBytes);
1213	    if(vpwd == NULL) {
1214		rv = SECFailure;
1215		key = NULL;
1216	    } else {
1217		key = sec_pkcs12_generate_key_from_password(SEC_OID_SHA1,
1218							salt, vpwd);
1219		SECITEM_ZfreeItem(vpwd, PR_TRUE);
1220	    }
1221
1222	    if((key != NULL) && (rv == SECSuccess)) {
1223		dest = SEC_PKCS7GetContent(cinfo);
1224		if(dest != NULL) {
1225
1226		    /* compute mac on data -- for password integrity mode */
1227		    mac = sec_pkcs12_generate_mac(key, dest, PR_FALSE);
1228		    if(mac != NULL) {
1229			di = SGN_CreateDigestInfo(SEC_OID_SHA1, 
1230			    			  mac->data, mac->len);
1231			if(di != NULL) {
1232			    rv = SGN_CopyDigestInfo(pfx->poolp, 
1233						    &pfx->macData.safeMac, di);
1234			    SGN_DestroyDigestInfo(di);
1235			} else {
1236			    PORT_SetError(SEC_ERROR_NO_MEMORY);
1237			}
1238			SECITEM_ZfreeItem(mac, PR_TRUE);
1239		    }
1240		} else {
1241		    rv = SECFailure;
1242		}
1243	    } else {
1244		PORT_SetError(SEC_ERROR_NO_MEMORY);
1245		rv = SECFailure;
1246	    }
1247
1248	    if(key != NULL) {
1249		SECITEM_ZfreeItem(key, PR_TRUE);
1250	    }
1251	    SECITEM_ZfreeItem(salt, PR_TRUE);
1252	}
1253    }
1254
1255    if(rv == SECFailure) {
1256	SEC_PKCS12DestroyPFX(pfx);
1257	pfx = NULL;
1258    }
1259
1260    return pfx;
1261}
1262
1263/* der encode the pfx */
1264static SECItem *
1265sec_pkcs12_encode_pfx(SEC_PKCS12PFXItem *pfx)
1266{
1267    SECItem *dest;
1268    void *dummy;
1269
1270    if(pfx == NULL) {
1271	return NULL;
1272    }
1273
1274    dest = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
1275    if(dest == NULL) {
1276	PORT_SetError(SEC_ERROR_NO_MEMORY);
1277	return NULL;
1278    }
1279
1280    dummy = SEC_ASN1EncodeItem(NULL, dest, pfx, SEC_PKCS12PFXItemTemplate);
1281    if(dummy == NULL) {
1282	PORT_SetError(SEC_ERROR_NO_MEMORY);
1283	SECITEM_ZfreeItem(dest, PR_TRUE);
1284	dest = NULL;
1285    }
1286
1287    return dest;
1288}
1289
1290SECItem *
1291SEC_PKCS12GetPFX(char **nicknames,
1292		 CERTCertificate **ref_certs,
1293		 PRBool shroud_keys, 
1294		 SEC_PKCS5GetPBEPassword pbef, 
1295		 void *pbearg,
1296		 PKCS12UnicodeConvertFunction unicodeFn,
1297		 void *wincx)
1298{
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;
1309
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();
1316	}
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.
1322	     */
1323	    safe_alg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC;
1324	}
1325    } else {
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.
1329	 */
1330	safe_alg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC;
1331    }
1332
1333    /* keys are always stored with triple DES */
1334    shroud_alg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC;
1335
1336    /* check for FIPS, if so, do not encrypt certs */
1337    if(PK11_IsFIPS() && !unencryptedCerts) {
1338	unencryptedCerts = PR_TRUE;
1339    }
1340
1341    if((nicknames == NULL) || (pbef == NULL) || (ref_certs == NULL)) {
1342	problem = PR_TRUE;
1343	goto loser;
1344    }
1345
1346
1347    /* get password */
1348    pwitem = (*pbef)(pbearg);
1349    if(pwitem == NULL) {
1350	problem = PR_TRUE;
1351	goto loser;
1352    }
1353    nicks = sec_pkcs12_convert_nickname_list(nicknames);
1354
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) {
1360	problem = PR_TRUE;
1361    }
1362
1363    if((safe != NULL) && (problem == PR_FALSE)) {
1364	/* copy thumbprints */
1365	rv = sec_pkcs12_propagate_thumbprints(nicks, ref_certs, safe, baggage);
1366
1367	/* package everything up into AuthenticatedSafe */
1368	cinfo = sec_pkcs12_get_auth_safe(safe, baggage, 
1369					 safe_alg, pwitem, unicodeFn, wincx);
1370
1371	sec_pkcs12_destroy_cert_content_infos(safe, baggage);
1372
1373	/* get the pfx and mac it */
1374	if(cinfo != NULL) {
1375	    pfx = sec_pkcs12_get_pfx(cinfo, PR_TRUE, pwitem, unicodeFn);
1376	    if(pfx != NULL) {
1377		dest = sec_pkcs12_encode_pfx(pfx);
1378		SEC_PKCS12DestroyPFX(pfx);
1379	    }
1380	    SEC_PKCS7DestroyContentInfo(cinfo);
1381	}
1382
1383	if(safe != NULL) {
1384	    PORT_FreeArena(safe->poolp, PR_TRUE);
1385	}
1386    } else {
1387	if(safe != NULL) {
1388	    PORT_FreeArena(safe->poolp, PR_TRUE);
1389	}
1390    }
1391
1392loser:
1393    if(nicks != NULL) {
1394	sec_pkcs12_destroy_nickname_list(nicks);
1395    }
1396
1397    if(ref_certs != NULL) {
1398	sec_pkcs12_destroy_certificate_list(ref_certs);
1399    }
1400
1401    if(pwitem != NULL) {
1402	SECITEM_ZfreeItem(pwitem, PR_TRUE);
1403    }
1404
1405    if(problem == PR_TRUE) {
1406	dest = NULL;
1407    }
1408
1409    return dest;
1410}