Back to index

lightning-sunbird  0.9+nobinonly
p12exp.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 #include "plarena.h"
00038 #include "secitem.h"
00039 #include "secoid.h"
00040 #include "seccomon.h"
00041 #include "secport.h"
00042 #include "cert.h"
00043 #include "pkcs12.h"
00044 #include "p12local.h"
00045 #include "secpkcs7.h"
00046 #include "secasn1.h"
00047 #include "secerr.h"
00048 #include "p12plcy.h"
00049 
00050 /* release the memory taken up by the list of nicknames */
00051 static void
00052 sec_pkcs12_destroy_nickname_list(SECItem **nicknames)
00053 {
00054     int i = 0;
00055 
00056     if(nicknames == NULL) {
00057        return;
00058     }
00059 
00060     while(nicknames[i] != NULL) {
00061        SECITEM_FreeItem(nicknames[i], PR_FALSE);
00062        i++;
00063     }
00064 
00065     PORT_Free(nicknames);
00066 }
00067    
00068 /* release the memory taken up by the list of certificates */ 
00069 static void
00070 sec_pkcs12_destroy_certificate_list(CERTCertificate **ref_certs)
00071 {
00072     int i = 0;
00073 
00074     if(ref_certs == NULL) {
00075        return;
00076     }
00077 
00078     while(ref_certs[i] != NULL) {
00079        CERT_DestroyCertificate(ref_certs[i]);
00080        i++;
00081     }
00082 }
00083 
00084 static void
00085 sec_pkcs12_destroy_cinfos_for_cert_bags(SEC_PKCS12CertAndCRLBag *certBag)
00086 {
00087     int j = 0;
00088     j = 0;
00089     while(certBag->certAndCRLs[j] != NULL) {
00090        SECOidTag certType = SECOID_FindOIDTag(&certBag->certAndCRLs[j]->BagID);
00091        if(certType == SEC_OID_PKCS12_X509_CERT_CRL_BAG) {
00092            SEC_PKCS12X509CertCRL *x509;
00093            x509 = certBag->certAndCRLs[j]->value.x509;
00094            SEC_PKCS7DestroyContentInfo(&x509->certOrCRL);
00095        }
00096        j++;
00097     }
00098 }
00099 
00100 /* destroy all content infos since they were not allocated in common
00101  * pool
00102  */
00103 static void
00104 sec_pkcs12_destroy_cert_content_infos(SEC_PKCS12SafeContents *safe,
00105                                   SEC_PKCS12Baggage *baggage)
00106 {
00107     int i, j;
00108 
00109     if((safe != NULL) && (safe->contents != NULL)) {
00110        i = 0;
00111        while(safe->contents[i] != NULL) {
00112            SECOidTag bagType = SECOID_FindOIDTag(&safe->contents[i]->safeBagType);
00113            if(bagType == SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID) {
00114               SEC_PKCS12CertAndCRLBag *certBag;
00115               certBag = safe->contents[i]->safeContent.certAndCRLBag;
00116               sec_pkcs12_destroy_cinfos_for_cert_bags(certBag);
00117            }
00118            i++;
00119        }
00120     }
00121 
00122     if((baggage != NULL) && (baggage->bags != NULL)) {
00123        i = 0;
00124        while(baggage->bags[i] != NULL) { 
00125            if(baggage->bags[i]->unencSecrets != NULL) {
00126               j = 0;
00127               while(baggage->bags[i]->unencSecrets[j] != NULL) {
00128                   SECOidTag bagType;
00129                   bagType = SECOID_FindOIDTag(&baggage->bags[i]->unencSecrets[j]->safeBagType);
00130                   if(bagType == SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID) {
00131                      SEC_PKCS12CertAndCRLBag *certBag;
00132                      certBag = baggage->bags[i]->unencSecrets[j]->safeContent.certAndCRLBag;
00133                      sec_pkcs12_destroy_cinfos_for_cert_bags(certBag);
00134                   }
00135                   j++;
00136               }
00137            }
00138            i++;
00139        }
00140     }
00141 }
00142 
00143 /* convert the nickname list from a NULL termincated Char list
00144  * to a NULL terminated SECItem list
00145  */
00146 static SECItem **
00147 sec_pkcs12_convert_nickname_list(char **nicknames)
00148 {
00149     SECItem **nicks;
00150     int i, j;
00151     PRBool error = PR_FALSE;
00152 
00153     if(nicknames == NULL) {
00154        return NULL;
00155     }
00156 
00157     i = j = 0;
00158     while(nicknames[i] != NULL) {
00159        i++;
00160     }
00161 
00162     /* allocate the space and copy the data */   
00163     nicks = (SECItem **)PORT_ZAlloc(sizeof(SECItem *) * (i + 1));
00164     if(nicks != NULL) {
00165        for(j = 0; ((j < i) && (error == PR_FALSE)); j++) {
00166            nicks[j] = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
00167            if(nicks[j] != NULL) {
00168               nicks[j]->data = 
00169                   (unsigned char *)PORT_ZAlloc(PORT_Strlen(nicknames[j])+1);
00170               if(nicks[j]->data != NULL) {
00171                   nicks[j]->len = PORT_Strlen(nicknames[j]);
00172                   PORT_Memcpy(nicks[j]->data, nicknames[j], nicks[j]->len);
00173                   nicks[j]->data[nicks[j]->len] = 0;
00174               } else {
00175                   error = PR_TRUE;
00176               }
00177            } else {
00178               error = PR_TRUE;
00179            }
00180        }
00181     }
00182 
00183     if(error == PR_TRUE) {
00184         for(i = 0; i < j; i++) { 
00185            SECITEM_FreeItem(nicks[i], PR_TRUE);
00186        }
00187        PORT_Free(nicks);
00188        nicks = NULL;
00189     }
00190 
00191     return nicks;
00192 }
00193 
00194 /* package the certificate add_cert into PKCS12 structures,
00195  * retrieve the certificate chain for the cert and return
00196  * the packaged contents.
00197  * poolp -- common memory pool;
00198  * add_cert -- certificate to package up
00199  * nickname for the certificate 
00200  * a return of NULL indicates an error
00201  */
00202 static SEC_PKCS12CertAndCRL *
00203 sec_pkcs12_get_cert(PRArenaPool *poolp,
00204                      CERTCertificate *add_cert, 
00205                      SECItem *nickname)
00206 {
00207     SEC_PKCS12CertAndCRL *cert;
00208     SEC_PKCS7ContentInfo *cinfo;
00209     SGNDigestInfo *t_di;
00210     void *mark;
00211     SECStatus rv;
00212 
00213     if((poolp == NULL) || (add_cert == NULL) || (nickname == NULL)) {
00214        return NULL;
00215     }
00216     mark = PORT_ArenaMark(poolp);
00217 
00218     cert = sec_pkcs12_new_cert_crl(poolp, SEC_OID_PKCS12_X509_CERT_CRL_BAG);
00219     if(cert != NULL) {
00220 
00221        /* copy the nickname */
00222        rv = SECITEM_CopyItem(poolp, &cert->nickname, nickname);
00223        if(rv != SECSuccess) {
00224            PORT_SetError(SEC_ERROR_NO_MEMORY);
00225            cert = NULL;
00226        } else {
00227 
00228            /* package the certificate and cert chain into a NULL signer
00229             * PKCS 7 SignedData content Info and prepare it for encoding 
00230             * since we cannot use DER_ANY_TEMPLATE
00231             */
00232            cinfo = SEC_PKCS7CreateCertsOnly(add_cert, PR_TRUE, NULL);
00233            rv = SEC_PKCS7PrepareForEncode(cinfo, NULL, NULL, NULL);
00234 
00235            /* thumbprint the certificate */
00236            if((cinfo != NULL) && (rv == SECSuccess))
00237            {
00238               PORT_Memcpy(&cert->value.x509->certOrCRL, cinfo, sizeof(*cinfo));
00239               t_di = sec_pkcs12_compute_thumbprint(&add_cert->derCert);
00240               if(t_di != NULL)
00241               {
00242                   /* test */
00243                   rv = SGN_CopyDigestInfo(poolp, &cert->value.x509->thumbprint,
00244                                        t_di);
00245                   if(rv != SECSuccess) {
00246                      cert = NULL;
00247                      PORT_SetError(SEC_ERROR_NO_MEMORY);
00248                   }
00249                   SGN_DestroyDigestInfo(t_di);
00250               }
00251               else
00252                   cert = NULL;
00253            }
00254        }
00255     }
00256 
00257     if (cert == NULL) {
00258        PORT_ArenaRelease(poolp, mark);
00259     } else {
00260        PORT_ArenaUnmark(poolp, mark);
00261     }
00262 
00263     return cert;
00264 }
00265 
00266 /* package the private key associated with the certificate and 
00267  * return the appropriate PKCS 12 structure 
00268  * poolp common memory pool
00269  * nickname key nickname
00270  * cert -- cert to look up
00271  * wincx -- window handle 
00272  * an error is indicated by a return of NULL
00273  */
00274 static SEC_PKCS12PrivateKey *
00275 sec_pkcs12_get_private_key(PRArenaPool *poolp,
00276                         SECItem *nickname,
00277                         CERTCertificate *cert,
00278                         void *wincx)
00279 {
00280     SECKEYPrivateKeyInfo *pki;
00281     SEC_PKCS12PrivateKey *pk;
00282     SECStatus rv;
00283     void *mark;
00284 
00285     if((poolp == NULL) || (nickname == NULL)) {
00286        return NULL;
00287     }
00288 
00289     mark = PORT_ArenaMark(poolp);
00290 
00291     /* retrieve key from the data base */
00292     pki = PK11_ExportPrivateKeyInfo(nickname, cert, wincx);
00293     if(pki == NULL) {
00294        PORT_ArenaRelease(poolp, mark);
00295        PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY);
00296        return NULL;
00297     }
00298 
00299     pk = (SEC_PKCS12PrivateKey *)PORT_ArenaZAlloc(poolp,
00300                                             sizeof(SEC_PKCS12PrivateKey));
00301     if(pk != NULL) {
00302        rv = sec_pkcs12_init_pvk_data(poolp, &pk->pvkData);
00303 
00304        if(rv == SECSuccess) {
00305            /* copy the key into poolp memory space */
00306            rv = SECKEY_CopyPrivateKeyInfo(poolp, &pk->pkcs8data, pki);
00307            if(rv == SECSuccess) {
00308               rv = SECITEM_CopyItem(poolp, &pk->pvkData.nickname, nickname);
00309            }
00310        }
00311 
00312        if(rv != SECSuccess) {
00313            PORT_SetError(SEC_ERROR_NO_MEMORY);
00314            pk = NULL;
00315        }
00316     } else {
00317        PORT_SetError(SEC_ERROR_NO_MEMORY); 
00318     }
00319 
00320     /* destroy private key, zeroing out data */
00321     SECKEY_DestroyPrivateKeyInfo(pki, PR_TRUE);
00322     if (pk == NULL) {
00323        PORT_ArenaRelease(poolp, mark);
00324     } else {
00325        PORT_ArenaUnmark(poolp, mark);
00326     }
00327 
00328     return pk;
00329 }
00330 
00331 /* get a shrouded key item associated with a certificate
00332  * return the appropriate PKCS 12 structure 
00333  * poolp common memory pool
00334  * nickname key nickname
00335  * cert -- cert to look up
00336  * wincx -- window handle 
00337  * an error is indicated by a return of NULL
00338  */
00339 static SEC_PKCS12ESPVKItem *
00340 sec_pkcs12_get_shrouded_key(PRArenaPool *poolp,
00341                          SECItem *nickname,
00342                          CERTCertificate *cert,
00343                          SECOidTag algorithm, 
00344                          SECItem *pwitem,
00345                          PKCS12UnicodeConvertFunction unicodeFn,
00346                          void *wincx)
00347 {
00348     SECKEYEncryptedPrivateKeyInfo *epki;
00349     SEC_PKCS12ESPVKItem *pk;
00350     void *mark;
00351     SECStatus rv;
00352     PK11SlotInfo *slot = NULL;
00353     PRBool swapUnicodeBytes = PR_FALSE;
00354 
00355 #ifdef IS_LITTLE_ENDIAN
00356     swapUnicodeBytes = PR_TRUE;
00357 #endif
00358 
00359     if((poolp == NULL) || (nickname == NULL))
00360        return NULL;
00361 
00362     mark = PORT_ArenaMark(poolp);
00363 
00364     /* use internal key slot */
00365     slot = PK11_GetInternalKeySlot();
00366 
00367     /* retrieve encrypted prviate key */
00368     epki = PK11_ExportEncryptedPrivateKeyInfo(slot, algorithm, pwitem, 
00369                                          nickname, cert, 1, 0, NULL);
00370     PK11_FreeSlot(slot);
00371     if(epki == NULL) {
00372        PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY);
00373        PORT_ArenaRelease(poolp, mark);
00374        return NULL;
00375     }
00376 
00377     /* create a private key and store the data into the poolp memory space */
00378     pk = sec_pkcs12_create_espvk(poolp, SEC_OID_PKCS12_PKCS8_KEY_SHROUDING);
00379     if(pk != NULL) {
00380        rv = sec_pkcs12_init_pvk_data(poolp, &pk->espvkData);
00381        rv = SECITEM_CopyItem(poolp, &pk->espvkData.nickname, nickname);
00382        pk->espvkCipherText.pkcs8KeyShroud = 
00383            (SECKEYEncryptedPrivateKeyInfo *)PORT_ArenaZAlloc(poolp,
00384                                    sizeof(SECKEYEncryptedPrivateKeyInfo));
00385        if((pk->espvkCipherText.pkcs8KeyShroud != NULL)  && (rv == SECSuccess)) {
00386            rv = SECKEY_CopyEncryptedPrivateKeyInfo(poolp, 
00387                                    pk->espvkCipherText.pkcs8KeyShroud, epki);
00388            if(rv == SECSuccess) {
00389               rv = (*unicodeFn)(poolp, &pk->espvkData.uniNickName, nickname, 
00390                               PR_TRUE, swapUnicodeBytes);
00391            }
00392        }
00393 
00394        if(rv != SECSuccess) {
00395            PORT_SetError(SEC_ERROR_NO_MEMORY);
00396            pk = NULL;
00397        }
00398     }
00399 
00400     SECKEY_DestroyEncryptedPrivateKeyInfo(epki, PR_TRUE);
00401     if(pk == NULL) {
00402        PORT_ArenaRelease(poolp, mark);
00403     } else {
00404        PORT_ArenaUnmark(poolp, mark);
00405     }
00406        
00407     return pk;
00408 }
00409 
00410 /* add a thumbprint to a private key associated certs list 
00411  * pvk is the area where the list is stored
00412  * thumb is the thumbprint to copy
00413  * a return of SECFailure indicates an error 
00414  */
00415 static SECStatus 
00416 sec_pkcs12_add_thumbprint(SEC_PKCS12PVKSupportingData *pvk,
00417                        SGNDigestInfo *thumb)
00418 {
00419     SGNDigestInfo **thumb_list = NULL;
00420     int nthumbs, size;
00421     void *mark, *dummy;
00422     SECStatus rv = SECFailure;
00423 
00424     if((pvk == NULL) || (thumb == NULL)) {
00425        return SECFailure;
00426     }
00427 
00428     mark = PORT_ArenaMark(pvk->poolp);
00429 
00430     thumb_list = pvk->assocCerts;
00431     nthumbs = pvk->nThumbs;
00432 
00433     /* allocate list space needed -- either growing or allocating 
00434      * list must be NULL terminated 
00435      */
00436     size = sizeof(SGNDigestInfo *);
00437     dummy = PORT_ArenaGrow(pvk->poolp, thumb_list, (size * (nthumbs + 1)),
00438                         (size * (nthumbs + 2)));
00439     thumb_list = dummy;
00440     if(dummy != NULL) {
00441        thumb_list[nthumbs] = (SGNDigestInfo *)PORT_ArenaZAlloc(pvk->poolp, 
00442                                           sizeof(SGNDigestInfo));
00443        if(thumb_list[nthumbs] != NULL) {
00444            SGN_CopyDigestInfo(pvk->poolp, thumb_list[nthumbs], thumb);
00445            nthumbs += 1;
00446            thumb_list[nthumbs] = 0;
00447        } else {
00448            dummy = NULL;
00449        }
00450     }
00451 
00452     if(dummy == NULL) {
00453        PORT_ArenaRelease(pvk->poolp, mark);
00454        return SECFailure;
00455     } 
00456 
00457     pvk->assocCerts = thumb_list;
00458     pvk->nThumbs = nthumbs;
00459 
00460     PORT_ArenaUnmark(pvk->poolp, mark);
00461     return SECSuccess;
00462 }
00463 
00464 /* search the list of shrouded keys in the baggage for the desired
00465  * name.  return a pointer to the item.  a return of NULL indicates
00466  * that no match was present or that an error occurred.
00467  */
00468 static SEC_PKCS12ESPVKItem *
00469 sec_pkcs12_get_espvk_by_name(SEC_PKCS12Baggage *luggage, 
00470                           SECItem *name)
00471 {
00472     PRBool found = PR_FALSE;
00473     SEC_PKCS12ESPVKItem *espvk = NULL;
00474     int i, j;
00475     SECComparison rv = SECEqual;
00476     SECItem *t_name;
00477     SEC_PKCS12BaggageItem *bag;
00478 
00479     if((luggage == NULL) || (name == NULL)) {
00480        return NULL;
00481     }
00482 
00483     i = 0;
00484     while((found == PR_FALSE) && (i < luggage->luggage_size)) {
00485        j = 0;
00486        bag = luggage->bags[i];
00487        while((found == PR_FALSE) && (j < bag->nEspvks)) {
00488            espvk = bag->espvks[j];
00489            if(espvk->poolp == NULL) {
00490               espvk->poolp = luggage->poolp;
00491            }
00492            t_name = SECITEM_DupItem(&espvk->espvkData.nickname);
00493            if(t_name != NULL) {
00494               rv = SECITEM_CompareItem(name, t_name);
00495               if(rv == SECEqual) {
00496                   found = PR_TRUE;
00497               }
00498               SECITEM_FreeItem(t_name, PR_TRUE);
00499            } else {
00500               PORT_SetError(SEC_ERROR_NO_MEMORY);
00501               return NULL;
00502            }
00503            j++;
00504        }
00505        i++;
00506     }
00507 
00508     if(found != PR_TRUE) {
00509        PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME);
00510        return NULL;
00511     }
00512 
00513     return espvk;
00514 }
00515 
00516 /* locates a certificate and copies the thumbprint to the
00517  * appropriate private key
00518  */
00519 static SECStatus 
00520 sec_pkcs12_propagate_thumbprints(SECItem **nicknames,
00521                              CERTCertificate **ref_certs,
00522                              SEC_PKCS12SafeContents *safe,
00523                              SEC_PKCS12Baggage *baggage)
00524 {
00525     SEC_PKCS12CertAndCRL *cert;
00526     SEC_PKCS12PrivateKey *key;
00527     SEC_PKCS12ESPVKItem *espvk;
00528     int i;
00529     PRBool error = PR_FALSE;
00530     SECStatus rv = SECFailure;
00531 
00532     if((nicknames == NULL) || (safe == NULL)) {
00533        return SECFailure;
00534     }
00535 
00536     i = 0;
00537     while((nicknames[i] != NULL) && (error == PR_FALSE)) {
00538        /* process all certs */
00539        cert = (SEC_PKCS12CertAndCRL *)sec_pkcs12_find_object(safe, baggage,
00540                                    SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID,
00541                                    nicknames[i], NULL);
00542        if(cert != NULL) {
00543            /* locate key and copy thumbprint */
00544            key = (SEC_PKCS12PrivateKey *)sec_pkcs12_find_object(safe, baggage,
00545                                    SEC_OID_PKCS12_KEY_BAG_ID,
00546                                    nicknames[i], NULL);
00547            if(key != NULL) {
00548               key->pvkData.poolp = key->poolp;
00549               rv = sec_pkcs12_add_thumbprint(&key->pvkData, 
00550                      &cert->value.x509->thumbprint);
00551               if(rv == SECFailure)
00552                   error = PR_TRUE;  /* XXX Set error? */
00553            }
00554 
00555            /* look in the baggage as well...*/
00556            if((baggage != NULL) && (error == PR_FALSE)) {
00557               espvk = sec_pkcs12_get_espvk_by_name(baggage, nicknames[i]);
00558               if(espvk != NULL) {
00559                   espvk->espvkData.poolp = espvk->poolp;
00560                   rv = sec_pkcs12_add_thumbprint(&espvk->espvkData,
00561                      &cert->value.x509->thumbprint);
00562                   if(rv == SECFailure)
00563                      error = PR_TRUE;  /* XXX Set error? */
00564               }
00565            }
00566        }
00567        i++;
00568     }
00569 
00570     if(error == PR_TRUE) {
00571        return SECFailure;
00572     }
00573 
00574     return SECSuccess;
00575 }
00576 
00577 /* append a safe bag to the end of the safe contents list */
00578 SECStatus 
00579 sec_pkcs12_append_safe_bag(SEC_PKCS12SafeContents *safe,
00580                         SEC_PKCS12SafeBag *bag)
00581 {
00582     int size;
00583     void *mark = NULL, *dummy = NULL;
00584 
00585     if((bag == NULL) || (safe == NULL))
00586        return SECFailure;
00587 
00588     mark = PORT_ArenaMark(safe->poolp);
00589 
00590     size = (safe->safe_size * sizeof(SEC_PKCS12SafeBag *));
00591     
00592     if(safe->safe_size > 0) {
00593        dummy = (SEC_PKCS12SafeBag **)PORT_ArenaGrow(safe->poolp, 
00594                                    safe->contents, 
00595                                    size, 
00596                                    (size + sizeof(SEC_PKCS12SafeBag *)));
00597        safe->contents = dummy;
00598     } else {
00599        safe->contents = (SEC_PKCS12SafeBag **)PORT_ArenaZAlloc(safe->poolp, 
00600            (2 * sizeof(SEC_PKCS12SafeBag *)));
00601        dummy = safe->contents;
00602     }
00603 
00604     if(dummy == NULL) {
00605        PORT_SetError(SEC_ERROR_NO_MEMORY);
00606        goto loser;
00607     }
00608 
00609     safe->contents[safe->safe_size] = bag;
00610     safe->safe_size++;
00611     safe->contents[safe->safe_size] = NULL;
00612 
00613     PORT_ArenaUnmark(safe->poolp, mark);
00614     return SECSuccess;
00615 
00616 loser:
00617     PORT_ArenaRelease(safe->poolp, mark);
00618     return SECFailure;
00619 }
00620 
00621 /* append a certificate onto the end of a cert bag */
00622 static SECStatus 
00623 sec_pkcs12_append_cert_to_bag(PRArenaPool *arena,
00624                            SEC_PKCS12SafeBag *safebag,
00625                            CERTCertificate *cert,
00626                            SECItem *nickname)
00627 {
00628     int size;
00629     void *dummy = NULL, *mark = NULL;
00630     SEC_PKCS12CertAndCRL *p12cert;
00631     SEC_PKCS12CertAndCRLBag *bag;
00632 
00633     if((arena == NULL) || (safebag == NULL) || 
00634        (cert == NULL) || (nickname == NULL)) {
00635        return SECFailure;
00636     }
00637 
00638     bag = safebag->safeContent.certAndCRLBag;
00639     if(bag == NULL) {
00640        return SECFailure;
00641     }
00642 
00643     mark = PORT_ArenaMark(arena);
00644 
00645     p12cert = sec_pkcs12_get_cert(arena, cert, nickname);
00646     if(p12cert == NULL) {
00647        PORT_ArenaRelease(bag->poolp, mark);
00648        return SECFailure;
00649     }
00650 
00651     size = bag->bag_size * sizeof(SEC_PKCS12CertAndCRL *);
00652     if(bag->bag_size > 0) {
00653        dummy = (SEC_PKCS12CertAndCRL **)PORT_ArenaGrow(bag->poolp,
00654            bag->certAndCRLs, size, size + sizeof(SEC_PKCS12CertAndCRL *));
00655        bag->certAndCRLs = dummy;
00656     } else {
00657        bag->certAndCRLs = (SEC_PKCS12CertAndCRL **)PORT_ArenaZAlloc(bag->poolp,
00658            (2 * sizeof(SEC_PKCS12CertAndCRL *)));
00659        dummy = bag->certAndCRLs;
00660     }
00661 
00662     if(dummy == NULL) {
00663        PORT_SetError(SEC_ERROR_NO_MEMORY);
00664        goto loser;
00665     }
00666 
00667     bag->certAndCRLs[bag->bag_size] = p12cert;
00668     bag->bag_size++;
00669     bag->certAndCRLs[bag->bag_size] = NULL;
00670 
00671     PORT_ArenaUnmark(bag->poolp, mark);
00672     return SECSuccess;
00673 
00674 loser:
00675     PORT_ArenaRelease(bag->poolp, mark);
00676     return SECFailure;
00677 }
00678 
00679 /* append a key onto the end of a list of keys in a key bag */
00680 SECStatus 
00681 sec_pkcs12_append_key_to_bag(SEC_PKCS12SafeBag *safebag,
00682                           SEC_PKCS12PrivateKey *pk)
00683 {
00684     void *mark, *dummy;
00685     SEC_PKCS12PrivateKeyBag *bag;
00686     int size;
00687 
00688     if((safebag == NULL) || (pk == NULL))
00689        return SECFailure;
00690 
00691     bag = safebag->safeContent.keyBag;
00692     if(bag == NULL) {
00693        return SECFailure;
00694     }
00695 
00696     mark = PORT_ArenaMark(bag->poolp);
00697 
00698     size = (bag->bag_size * sizeof(SEC_PKCS12PrivateKey *));
00699 
00700     if(bag->bag_size > 0) {
00701        dummy = (SEC_PKCS12PrivateKey **)PORT_ArenaGrow(bag->poolp,
00702                                    bag->privateKeys, 
00703                                    size, 
00704                                    size + sizeof(SEC_PKCS12PrivateKey *));
00705        bag->privateKeys = dummy;
00706     } else {
00707        bag->privateKeys = (SEC_PKCS12PrivateKey **)PORT_ArenaZAlloc(bag->poolp,
00708            (2 * sizeof(SEC_PKCS12PrivateKey *)));
00709        dummy = bag->privateKeys;
00710     }
00711 
00712     if(dummy == NULL) {
00713        PORT_SetError(SEC_ERROR_NO_MEMORY);
00714        goto loser;
00715     }
00716 
00717     bag->privateKeys[bag->bag_size] = pk;
00718     bag->bag_size++;
00719     bag->privateKeys[bag->bag_size] = NULL;
00720 
00721     PORT_ArenaUnmark(bag->poolp, mark);
00722     return SECSuccess;
00723 
00724 loser:
00725     /* XXX Free memory? */
00726     PORT_ArenaRelease(bag->poolp, mark);
00727     return SECFailure;
00728 }
00729 
00730 /* append a safe bag to the baggage area */
00731 static SECStatus 
00732 sec_pkcs12_append_unshrouded_bag(SEC_PKCS12BaggageItem *bag,
00733                              SEC_PKCS12SafeBag *u_bag)
00734 {
00735     int size;
00736     void *mark = NULL, *dummy = NULL;
00737 
00738     if((bag == NULL) || (u_bag == NULL))
00739        return SECFailure;
00740 
00741     mark = PORT_ArenaMark(bag->poolp);
00742 
00743     /* dump things into the first bag */
00744     size = (bag->nSecrets + 1) * sizeof(SEC_PKCS12SafeBag *);
00745     dummy = PORT_ArenaGrow(bag->poolp,
00746                      bag->unencSecrets, size, 
00747                      size + sizeof(SEC_PKCS12SafeBag *));
00748     bag->unencSecrets = dummy;
00749     if(dummy == NULL) {
00750        PORT_SetError(SEC_ERROR_NO_MEMORY);
00751        goto loser;
00752     }
00753 
00754     bag->unencSecrets[bag->nSecrets] = u_bag;
00755     bag->nSecrets++;
00756     bag->unencSecrets[bag->nSecrets] = NULL;
00757 
00758     PORT_ArenaUnmark(bag->poolp, mark);
00759     return SECSuccess;
00760 
00761 loser:
00762     PORT_ArenaRelease(bag->poolp, mark);
00763     return SECFailure;
00764 }
00765 
00766 /* gather up all certificates and keys and package them up
00767  * in the safe, baggage, or both.
00768  * nicknames is the list of nicknames and corresponding certs in ref_certs
00769  * ref_certs a null terminated list of certificates
00770  * rSafe, rBaggage -- return areas for safe and baggage
00771  * shroud_keys -- store keys externally
00772  * pwitem -- password for computing integrity mac and encrypting contents
00773  * wincx -- window handle
00774  *
00775  * if a failure occurs, an error is set and SECFailure returned.
00776  */
00777 static SECStatus
00778 sec_pkcs12_package_certs_and_keys(SECItem **nicknames,
00779                               CERTCertificate **ref_certs,
00780                               PRBool unencryptedCerts,
00781                               SEC_PKCS12SafeContents **rSafe,
00782                               SEC_PKCS12Baggage **rBaggage,
00783                               PRBool shroud_keys, 
00784                               SECOidTag shroud_alg,
00785                               SECItem *pwitem,
00786                               PKCS12UnicodeConvertFunction unicodeFn,
00787                               void *wincx)
00788 {
00789     PRArenaPool *permArena;
00790     SEC_PKCS12SafeContents *safe = NULL;
00791     SEC_PKCS12Baggage *baggage = NULL;
00792 
00793     SECStatus rv = SECFailure;
00794     PRBool problem = PR_FALSE;
00795 
00796     SEC_PKCS12ESPVKItem *espvk = NULL;
00797     SEC_PKCS12PrivateKey *pk = NULL;
00798     CERTCertificate *add_cert = NULL;
00799     SEC_PKCS12SafeBag *certbag = NULL, *keybag = NULL;
00800     SEC_PKCS12BaggageItem *external_bag = NULL;
00801     int ncerts = 0, nkeys = 0;
00802     int i;
00803 
00804     if((nicknames == NULL) || (rSafe == NULL) || (rBaggage == NULL)) {
00805        return SECFailure;
00806     }
00807        
00808     *rBaggage = baggage;
00809     *rSafe = safe;
00810 
00811     permArena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
00812     if(permArena == NULL) {
00813        PORT_SetError(SEC_ERROR_NO_MEMORY);
00814        return SECFailure;
00815      }
00816 
00817     /* allocate structures */
00818     safe = sec_pkcs12_create_safe_contents(permArena);
00819     if(safe == NULL) {
00820        PORT_SetError(SEC_ERROR_NO_MEMORY);
00821        rv = SECFailure;
00822        goto loser;
00823     }
00824 
00825     certbag = sec_pkcs12_create_safe_bag(permArena, 
00826                                     SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID);
00827     if(certbag == NULL) {
00828        rv = SECFailure;
00829        goto loser;
00830     }
00831 
00832     if(shroud_keys != PR_TRUE) {
00833        keybag = sec_pkcs12_create_safe_bag(permArena, 
00834                                        SEC_OID_PKCS12_KEY_BAG_ID);
00835        if(keybag == NULL) {
00836            rv = SECFailure;
00837            goto loser;
00838        }
00839     }
00840 
00841     if((shroud_keys == PR_TRUE) || (unencryptedCerts == PR_TRUE)) {
00842        baggage = sec_pkcs12_create_baggage(permArena);
00843        if(baggage == NULL) {
00844            rv = SECFailure;
00845            goto loser;
00846        }
00847        external_bag = sec_pkcs12_create_external_bag(baggage);
00848     }
00849 
00850     /* package keys and certs */
00851     i = 0;
00852     while((nicknames[i] != NULL) && (problem == PR_FALSE)) {
00853        if(ref_certs[i] != NULL) {
00854            /* append cert to bag o certs */
00855            rv = sec_pkcs12_append_cert_to_bag(permArena, certbag, 
00856                                           ref_certs[i],
00857                                           nicknames[i]);
00858            if(rv == SECFailure) {
00859               problem = PR_FALSE;
00860            } else {
00861               ncerts++;
00862            }
00863 
00864            if(rv == SECSuccess) {
00865               /* package up them keys */
00866               if(shroud_keys == PR_TRUE) {
00867                   espvk = sec_pkcs12_get_shrouded_key(permArena, 
00868                                                  nicknames[i],
00869                                                  ref_certs[i],
00870                                                  shroud_alg, 
00871                                                  pwitem, unicodeFn,
00872                                                  wincx);
00873                   if(espvk != NULL) {
00874                      rv = sec_pkcs12_append_shrouded_key(external_bag, espvk);
00875                      SECITEM_CopyItem(permArena, &espvk->derCert,
00876                                     &ref_certs[i]->derCert);
00877                   } else {
00878                      rv = SECFailure;
00879                   }
00880               } else {
00881                   pk = sec_pkcs12_get_private_key(permArena, nicknames[i], 
00882                                               ref_certs[i], wincx);
00883                   if(pk != NULL) {
00884                      rv = sec_pkcs12_append_key_to_bag(keybag, pk);
00885                      SECITEM_CopyItem(permArena, &espvk->derCert,
00886                                     &ref_certs[i]->derCert);
00887                   } else {
00888                      rv = SECFailure;
00889                   }
00890               }
00891        
00892               if(rv == SECFailure) {
00893                   problem = PR_TRUE;
00894               } else {
00895                   nkeys++;
00896               }
00897            }
00898        } else {
00899            /* handle only keys here ? */
00900            problem = PR_TRUE;
00901        }
00902        i++;
00903     }
00904 
00905     /* let success fall through */
00906 loser:
00907     if(problem == PR_FALSE) {
00908        /* if we have certs, we want to append the cert bag to the 
00909         * appropriate area 
00910         */
00911        if(ncerts > 0) {
00912            if(unencryptedCerts != PR_TRUE) {
00913               rv = sec_pkcs12_append_safe_bag(safe, certbag);
00914            } else {
00915               rv = sec_pkcs12_append_unshrouded_bag(external_bag, certbag);
00916            }
00917        } else {
00918            rv = SECSuccess;
00919        }
00920 
00921        /* append key bag, if they are stored in safe contents */
00922        if((rv == SECSuccess) && (shroud_keys == PR_FALSE) && (nkeys > 0)) {
00923            rv = sec_pkcs12_append_safe_bag(safe, keybag);
00924        }
00925     } else {
00926        rv = SECFailure;
00927     }
00928 
00929     /* if baggage not used, NULLify it */
00930     if((shroud_keys == PR_TRUE) || (unencryptedCerts == PR_TRUE)) {
00931        if(((unencryptedCerts == PR_TRUE) && (ncerts == 0)) &&
00932           ((shroud_keys == PR_TRUE) && (nkeys == 0)))
00933               baggage = NULL;
00934     } else {
00935        baggage = NULL;
00936     }
00937 
00938     if((problem == PR_TRUE) || (rv == SECFailure)) {
00939        PORT_FreeArena(permArena, PR_TRUE);
00940        rv = SECFailure;
00941        baggage = NULL;
00942        safe = NULL;
00943     }
00944 
00945     *rBaggage = baggage;
00946     *rSafe = safe;
00947 
00948     return rv;
00949 }
00950 
00951 /* DER encode the safe contents and return a SECItem.  if an error
00952  * occurs, NULL is returned.
00953  */
00954 static SECItem *
00955 sec_pkcs12_encode_safe_contents(SEC_PKCS12SafeContents *safe)
00956 {
00957     SECItem *dsafe = NULL, *tsafe;
00958     void *dummy = NULL;
00959     PRArenaPool *arena;
00960 
00961     if(safe == NULL) {
00962        return NULL;
00963     }
00964 
00965 /*    rv = sec_pkcs12_prepare_for_der_code_safe(safe, PR_TRUE);
00966     if(rv != SECSuccess) {
00967        PORT_SetError(SEC_ERROR_NO_MEMORY);
00968        return NULL;
00969     }*/
00970 
00971     arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
00972     if(arena == NULL) {
00973        PORT_SetError(SEC_ERROR_NO_MEMORY);
00974        return NULL;
00975     }
00976 
00977     tsafe = (SECItem *)PORT_ArenaZAlloc(arena, sizeof(SECItem));
00978     if(tsafe != NULL) {
00979        dummy = SEC_ASN1EncodeItem(arena, tsafe, safe, 
00980            SEC_PKCS12SafeContentsTemplate);
00981        if(dummy != NULL) {
00982            dsafe = SECITEM_DupItem(tsafe);
00983        } else {
00984            PORT_SetError(SEC_ERROR_NO_MEMORY);
00985        }
00986     } else {
00987        PORT_SetError(SEC_ERROR_NO_MEMORY);
00988     }
00989 
00990     PORT_FreeArena(arena, PR_TRUE);
00991 
00992     return dsafe;
00993 }
00994 
00995 /* prepare the authenicated safe for encoding and encode it.  
00996  *   baggage is copied to the appropriate area, safe is encoded and
00997  *   encrypted.  the version and transport mode are set on the asafe.
00998  *   the whole ball of wax is then der encoded and packaged up into
00999  *   data content info 
01000  * safe -- container of certs and keys, is encrypted.
01001  * baggage -- container of certs and keys, keys assumed to be encrypted by 
01002  *    another method, certs are in the clear
01003  * algorithm -- algorithm by which to encrypt safe
01004  * pwitem -- password for encryption
01005  * wincx - window handle
01006  *
01007  * return of NULL is an error condition.
01008  */
01009 static SEC_PKCS7ContentInfo *
01010 sec_pkcs12_get_auth_safe(SEC_PKCS12SafeContents *safe, 
01011                       SEC_PKCS12Baggage *baggage,  
01012                       SECOidTag algorithm, 
01013                       SECItem *pwitem,
01014                       PKCS12UnicodeConvertFunction unicodeFn,
01015                       void *wincx)
01016 {
01017     SECItem *src = NULL, *dest = NULL, *psalt = NULL;
01018     PRArenaPool *poolp;
01019     SEC_PKCS12AuthenticatedSafe *asafe;
01020     SEC_PKCS7ContentInfo *safe_cinfo = NULL;
01021     SEC_PKCS7ContentInfo *asafe_cinfo = NULL;
01022     void *dummy;
01023     SECStatus rv = SECSuccess;
01024     PRBool swapUnicodeBytes = PR_FALSE;
01025 
01026 #ifdef IS_LITTLE_ENDIAN
01027     swapUnicodeBytes = PR_TRUE;
01028 #endif
01029     
01030     if(((safe != NULL) && (pwitem == NULL)) && (baggage == NULL))
01031        return NULL;
01032 
01033     poolp = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
01034     if(poolp == NULL) {
01035        PORT_SetError(SEC_ERROR_NO_MEMORY);
01036        return NULL;
01037     }
01038 
01039     /* prepare authenticated safe for encode */
01040     asafe = sec_pkcs12_new_asafe(poolp);
01041     if(asafe != NULL) {
01042 
01043        /* set version */
01044        dummy = SEC_ASN1EncodeInteger(asafe->poolp, &asafe->version,
01045                                   SEC_PKCS12_PFX_VERSION);
01046        if(dummy == NULL) {
01047            PORT_SetError(SEC_ERROR_NO_MEMORY);
01048            rv = SECFailure;
01049            goto loser;
01050        }
01051 
01052        /* generate the privacy salt used to create virtual pwd */
01053        psalt = sec_pkcs12_generate_salt();
01054        if(psalt != NULL) {
01055            rv = SECITEM_CopyItem(asafe->poolp, &asafe->privacySalt,
01056                               psalt);
01057            if(rv == SECSuccess) {
01058               asafe->privacySalt.len *= 8;
01059            } 
01060            else {
01061               SECITEM_ZfreeItem(psalt, PR_TRUE);
01062               PORT_SetError(SEC_ERROR_NO_MEMORY);
01063               goto loser;
01064            }
01065        } 
01066 
01067        if((psalt == NULL) || (rv == SECFailure)) {
01068            PORT_SetError(SEC_ERROR_NO_MEMORY);
01069            rv = SECFailure;
01070            goto loser;
01071        }
01072 
01073        /* package up safe contents */
01074        if(safe != NULL) 
01075        {
01076            safe_cinfo = SEC_PKCS7CreateEncryptedData(algorithm, NULL, wincx);
01077            if((safe_cinfo != NULL) && (safe->safe_size > 0)) {
01078               /* encode the safe and encrypt the contents of the 
01079                * content info
01080                */
01081               src = sec_pkcs12_encode_safe_contents(safe);
01082 
01083               if(src != NULL) {
01084                   rv = SEC_PKCS7SetContent(safe_cinfo, (char *)src->data, src->len);
01085                   SECITEM_ZfreeItem(src, PR_TRUE);
01086                   if(rv == SECSuccess) {
01087                      SECItem *vpwd;
01088                      vpwd = sec_pkcs12_create_virtual_password(pwitem, psalt,
01089                                           unicodeFn, swapUnicodeBytes);
01090                      if(vpwd != NULL) {
01091                          rv = SEC_PKCS7EncryptContents(NULL, safe_cinfo,
01092                                                    vpwd, wincx);
01093                          SECITEM_ZfreeItem(vpwd, PR_TRUE);
01094                      } else {
01095                          rv = SECFailure;
01096                          PORT_SetError(SEC_ERROR_NO_MEMORY);
01097                      }
01098                   } else {
01099                      PORT_SetError(SEC_ERROR_NO_MEMORY);
01100                   }
01101               } else {
01102                   rv = SECFailure;
01103               }
01104            } else if(safe->safe_size > 0) {
01105               PORT_SetError(SEC_ERROR_NO_MEMORY);
01106               goto loser;
01107            } else {
01108               /* case where there is NULL content in the safe contents */
01109               rv = SEC_PKCS7SetContent(safe_cinfo, NULL, 0);
01110               if(rv != SECFailure) {
01111                   PORT_SetError(SEC_ERROR_NO_MEMORY);
01112               }
01113            }
01114 
01115            if(rv != SECSuccess) {
01116               SEC_PKCS7DestroyContentInfo(safe_cinfo);
01117               safe_cinfo = NULL;
01118               goto loser;
01119            }
01120 
01121            asafe->safe = safe_cinfo;      
01122            /*
01123            PORT_Memcpy(&asafe->safe, safe_cinfo, sizeof(*safe_cinfo));
01124            */
01125        }
01126 
01127        /* copy the baggage to the authenticated safe baggage if present */
01128        if(baggage != NULL) {
01129            PORT_Memcpy(&asafe->baggage, baggage, sizeof(*baggage));
01130        }
01131 
01132        /* encode authenticated safe and store it in a Data content info */
01133        dest = (SECItem *)PORT_ArenaZAlloc(poolp, sizeof(SECItem));
01134        if(dest != NULL) {
01135            dummy = SEC_ASN1EncodeItem(poolp, dest, asafe, 
01136                             SEC_PKCS12AuthenticatedSafeTemplate);
01137            if(dummy != NULL) {
01138               asafe_cinfo = SEC_PKCS7CreateData();
01139               if(asafe_cinfo != NULL) {
01140                   rv = SEC_PKCS7SetContent(asafe_cinfo, 
01141                                           (char *)dest->data, 
01142                                           dest->len);
01143                   if(rv != SECSuccess) {
01144                      PORT_SetError(SEC_ERROR_NO_MEMORY);
01145                      SEC_PKCS7DestroyContentInfo(asafe_cinfo);
01146                      asafe_cinfo = NULL;
01147                   }
01148               }
01149            } else {
01150               PORT_SetError(SEC_ERROR_NO_MEMORY);
01151               rv = SECFailure;
01152            }
01153        }
01154     }
01155 
01156 loser:
01157     PORT_FreeArena(poolp, PR_TRUE);
01158     if(safe_cinfo != NULL) {
01159        SEC_PKCS7DestroyContentInfo(safe_cinfo);
01160     }
01161     if(psalt != NULL) {
01162        SECITEM_ZfreeItem(psalt, PR_TRUE);
01163     }
01164 
01165     if(rv == SECFailure) {
01166        return NULL;
01167     }
01168        
01169     return asafe_cinfo;
01170 }
01171 
01172 /* generates the PFX and computes the mac on the authenticated safe 
01173  * NULL implies an error
01174  */
01175 static SEC_PKCS12PFXItem *
01176 sec_pkcs12_get_pfx(SEC_PKCS7ContentInfo *cinfo, 
01177                  PRBool do_mac, 
01178                  SECItem *pwitem, PKCS12UnicodeConvertFunction unicodeFn)
01179 {
01180     SECItem *dest = NULL, *mac = NULL, *salt = NULL, *key = NULL;
01181     SEC_PKCS12PFXItem *pfx;
01182     SECStatus rv = SECFailure;
01183     SGNDigestInfo *di;
01184     SECItem *vpwd;
01185     PRBool swapUnicodeBytes = PR_FALSE;
01186 
01187 #ifdef IS_LITTLE_ENDIAN
01188     swapUnicodeBytes = PR_TRUE;
01189 #endif
01190 
01191     if((cinfo == NULL) || ((do_mac == PR_TRUE) && (pwitem == NULL))) {
01192        return NULL;
01193     }
01194 
01195     /* allocate new pfx structure */
01196     pfx = sec_pkcs12_new_pfx();
01197     if(pfx == NULL) {
01198        PORT_SetError(SEC_ERROR_NO_MEMORY);
01199        return NULL;
01200     }
01201 
01202     PORT_Memcpy(&pfx->authSafe, cinfo, sizeof(*cinfo));
01203     if(do_mac == PR_TRUE) {
01204 
01205        /* salt for computing mac */
01206        salt = sec_pkcs12_generate_salt();
01207        if(salt != NULL) {
01208            rv = SECITEM_CopyItem(pfx->poolp, &pfx->macData.macSalt, salt);
01209            pfx->macData.macSalt.len *= 8;
01210 
01211            vpwd = sec_pkcs12_create_virtual_password(pwitem, salt,
01212                                           unicodeFn, swapUnicodeBytes);
01213            if(vpwd == NULL) {
01214               rv = SECFailure;
01215               key = NULL;
01216            } else {
01217               key = sec_pkcs12_generate_key_from_password(SEC_OID_SHA1,
01218                                                  salt, vpwd);
01219               SECITEM_ZfreeItem(vpwd, PR_TRUE);
01220            }
01221 
01222            if((key != NULL) && (rv == SECSuccess)) {
01223               dest = SEC_PKCS7GetContent(cinfo);
01224               if(dest != NULL) {
01225 
01226                   /* compute mac on data -- for password integrity mode */
01227                   mac = sec_pkcs12_generate_mac(key, dest, PR_FALSE);
01228                   if(mac != NULL) {
01229                      di = SGN_CreateDigestInfo(SEC_OID_SHA1, 
01230                                             mac->data, mac->len);
01231                      if(di != NULL) {
01232                          rv = SGN_CopyDigestInfo(pfx->poolp, 
01233                                               &pfx->macData.safeMac, di);
01234                          SGN_DestroyDigestInfo(di);
01235                      } else {
01236                          PORT_SetError(SEC_ERROR_NO_MEMORY);
01237                      }
01238                      SECITEM_ZfreeItem(mac, PR_TRUE);
01239                   }
01240               } else {
01241                   rv = SECFailure;
01242               }
01243            } else {
01244               PORT_SetError(SEC_ERROR_NO_MEMORY);
01245               rv = SECFailure;
01246            }
01247 
01248            if(key != NULL) {
01249               SECITEM_ZfreeItem(key, PR_TRUE);
01250            }
01251            SECITEM_ZfreeItem(salt, PR_TRUE);
01252        }
01253     }
01254 
01255     if(rv == SECFailure) {
01256        SEC_PKCS12DestroyPFX(pfx);
01257        pfx = NULL;
01258     }
01259 
01260     return pfx;
01261 }
01262 
01263 /* der encode the pfx */
01264 static SECItem *
01265 sec_pkcs12_encode_pfx(SEC_PKCS12PFXItem *pfx)
01266 {
01267     SECItem *dest;
01268     void *dummy;
01269 
01270     if(pfx == NULL) {
01271        return NULL;
01272     }
01273 
01274     dest = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
01275     if(dest == NULL) {
01276        PORT_SetError(SEC_ERROR_NO_MEMORY);
01277        return NULL;
01278     }
01279 
01280     dummy = SEC_ASN1EncodeItem(NULL, dest, pfx, SEC_PKCS12PFXItemTemplate);
01281     if(dummy == NULL) {
01282        PORT_SetError(SEC_ERROR_NO_MEMORY);
01283        SECITEM_ZfreeItem(dest, PR_TRUE);
01284        dest = NULL;
01285     }
01286 
01287     return dest;
01288 }
01289 
01290 SECItem *
01291 SEC_PKCS12GetPFX(char **nicknames,
01292                CERTCertificate **ref_certs,
01293                PRBool shroud_keys, 
01294                SEC_PKCS5GetPBEPassword pbef, 
01295                void *pbearg,
01296                PKCS12UnicodeConvertFunction unicodeFn,
01297                void *wincx)
01298 {
01299     SECItem **nicks = NULL;
01300     SEC_PKCS12PFXItem *pfx = NULL;
01301     SEC_PKCS12Baggage *baggage = NULL;
01302     SEC_PKCS12SafeContents *safe = NULL;
01303     SEC_PKCS7ContentInfo *cinfo = NULL;
01304     SECStatus rv = SECFailure;
01305     SECItem *dest = NULL, *pwitem = NULL;
01306     PRBool problem = PR_FALSE;
01307     PRBool unencryptedCerts;
01308     SECOidTag shroud_alg, safe_alg;
01309 
01310     /* how should we encrypt certs ? */
01311     unencryptedCerts = !SEC_PKCS12IsEncryptionAllowed();
01312     if(!unencryptedCerts) {
01313        safe_alg = SEC_PKCS12GetPreferredEncryptionAlgorithm();
01314        if(safe_alg == SEC_OID_UNKNOWN) {
01315            safe_alg = SEC_PKCS12GetStrongestAllowedAlgorithm();
01316        }
01317        if(safe_alg == SEC_OID_UNKNOWN) {
01318            unencryptedCerts = PR_TRUE;
01319            /* for export where no encryption is allowed, we still need
01320             * to encrypt the NULL contents per the spec.  encrypted info
01321             * is known plaintext, so it shouldn't be a problem.
01322             */
01323            safe_alg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC;
01324        }
01325     } else {
01326        /* for export where no encryption is allowed, we still need
01327         * to encrypt the NULL contents per the spec.  encrypted info
01328         * is known plaintext, so it shouldn't be a problem.
01329         */
01330        safe_alg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC;
01331     }
01332 
01333     /* keys are always stored with triple DES */
01334     shroud_alg = SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC;
01335 
01336     /* check for FIPS, if so, do not encrypt certs */
01337     if(PK11_IsFIPS() && !unencryptedCerts) {
01338        unencryptedCerts = PR_TRUE;
01339     }
01340 
01341     if((nicknames == NULL) || (pbef == NULL) || (ref_certs == NULL)) {
01342        problem = PR_TRUE;
01343        goto loser;
01344     }
01345 
01346 
01347     /* get password */
01348     pwitem = (*pbef)(pbearg);
01349     if(pwitem == NULL) {
01350        problem = PR_TRUE;
01351        goto loser;
01352     }
01353     nicks = sec_pkcs12_convert_nickname_list(nicknames);
01354 
01355     /* get safe and baggage */
01356     rv = sec_pkcs12_package_certs_and_keys(nicks, ref_certs, unencryptedCerts,
01357                                       &safe, &baggage, shroud_keys,
01358                                       shroud_alg, pwitem, unicodeFn, wincx);
01359     if(rv == SECFailure) {
01360        problem = PR_TRUE;
01361     }
01362 
01363     if((safe != NULL) && (problem == PR_FALSE)) {
01364        /* copy thumbprints */
01365        rv = sec_pkcs12_propagate_thumbprints(nicks, ref_certs, safe, baggage);
01366 
01367        /* package everything up into AuthenticatedSafe */
01368        cinfo = sec_pkcs12_get_auth_safe(safe, baggage, 
01369                                     safe_alg, pwitem, unicodeFn, wincx);
01370 
01371        sec_pkcs12_destroy_cert_content_infos(safe, baggage);
01372 
01373        /* get the pfx and mac it */
01374        if(cinfo != NULL) {
01375            pfx = sec_pkcs12_get_pfx(cinfo, PR_TRUE, pwitem, unicodeFn);
01376            if(pfx != NULL) {
01377               dest = sec_pkcs12_encode_pfx(pfx);
01378               SEC_PKCS12DestroyPFX(pfx);
01379            }
01380            SEC_PKCS7DestroyContentInfo(cinfo);
01381        }
01382 
01383        if(safe != NULL) {
01384            PORT_FreeArena(safe->poolp, PR_TRUE);
01385        }
01386     } else {
01387        if(safe != NULL) {
01388            PORT_FreeArena(safe->poolp, PR_TRUE);
01389        }
01390     }
01391 
01392 loser:
01393     if(nicks != NULL) {
01394        sec_pkcs12_destroy_nickname_list(nicks);
01395     }
01396 
01397     if(ref_certs != NULL) {
01398        sec_pkcs12_destroy_certificate_list(ref_certs);
01399     }
01400 
01401     if(pwitem != NULL) {
01402        SECITEM_ZfreeItem(pwitem, PR_TRUE);
01403     }
01404 
01405     if(problem == PR_TRUE) {
01406        dest = NULL;
01407     }
01408 
01409     return dest;
01410 }