tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

p12exp.c (43563B)


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