tor-browser

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

p12d.c (113926B)


      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 "nssrenam.h"
      6 #include "nss.h"
      7 #include "p12t.h"
      8 #include "p12.h"
      9 #include "plarena.h"
     10 #include "secitem.h"
     11 #include "secoid.h"
     12 #include "seccomon.h"
     13 #include "secport.h"
     14 #include "cert.h"
     15 #include "secpkcs7.h"
     16 #include "secasn1.h"
     17 #include "secerr.h"
     18 #include "pk11func.h"
     19 #include "p12plcy.h"
     20 #include "p12local.h"
     21 #include "secder.h"
     22 #include "secport.h"
     23 
     24 #include "certdb.h"
     25 
     26 #include "prcpucfg.h"
     27 
     28 /* This belongs in secport.h */
     29 #define PORT_ArenaGrowArray(poolp, oldptr, type, oldnum, newnum) \
     30    (type *)PORT_ArenaGrow((poolp), (oldptr),                    \
     31                           (oldnum) * sizeof(type), (newnum) * sizeof(type))
     32 
     33 typedef struct sec_PKCS12SafeContentsContextStr sec_PKCS12SafeContentsContext;
     34 
     35 /* Opaque structure for decoding SafeContents.  These are used
     36 * for each authenticated safe as well as any nested safe contents.
     37 */
     38 struct sec_PKCS12SafeContentsContextStr {
     39    /* the parent decoder context */
     40    SEC_PKCS12DecoderContext *p12dcx;
     41 
     42    /* memory arena to allocate space from */
     43    PLArenaPool *arena;
     44 
     45    /* decoder context and destination for decoding safe contents */
     46    SEC_ASN1DecoderContext *safeContentsA1Dcx;
     47    sec_PKCS12SafeContents safeContents;
     48 
     49    /* information for decoding safe bags within the safe contents.
     50     * these variables are updated for each safe bag decoded.
     51     */
     52    SEC_ASN1DecoderContext *currentSafeBagA1Dcx;
     53    sec_PKCS12SafeBag *currentSafeBag;
     54    PRBool skipCurrentSafeBag;
     55 
     56    /* if the safe contents is nested, the parent is pointed to here. */
     57    sec_PKCS12SafeContentsContext *nestedSafeContentsCtx;
     58 };
     59 
     60 /* opaque decoder context structure.  information for decoding a pkcs 12
     61 * PDU are stored here as well as decoding pointers for intermediary
     62 * structures which are part of the PKCS 12 PDU.  Upon a successful
     63 * decode, the safe bags containing certificates and keys encountered.
     64 */
     65 struct SEC_PKCS12DecoderContextStr {
     66    PLArenaPool *arena;
     67    PK11SlotInfo *slot;
     68    void *wincx;
     69    PRBool error;
     70    int errorValue;
     71 
     72    /* password */
     73    SECItem *pwitem;
     74 
     75    /* used for decoding the PFX structure */
     76    SEC_ASN1DecoderContext *pfxA1Dcx;
     77    sec_PKCS12PFXItem pfx;
     78 
     79    /* safe bags found during decoding */
     80    sec_PKCS12SafeBag **safeBags;
     81    unsigned int safeBagCount;
     82 
     83    /* state variables for decoding authenticated safes. */
     84    SEC_PKCS7DecoderContext *currentASafeP7Dcx;
     85    SEC_ASN1DecoderContext *aSafeA1Dcx;
     86    SEC_PKCS7DecoderContext *aSafeP7Dcx;
     87    SEC_PKCS7ContentInfo *aSafeCinfo;
     88    sec_PKCS12AuthenticatedSafe authSafe;
     89    sec_PKCS12SafeContents safeContents;
     90 
     91    /* safe contents info */
     92    unsigned int safeContentsCnt;
     93    sec_PKCS12SafeContentsContext **safeContentsList;
     94 
     95    /* HMAC info */
     96    sec_PKCS12MacData macData;
     97 
     98    /* routines for reading back the data to be hmac'd */
     99    /* They are called as follows.
    100     *
    101     * Stage 1: decode the aSafes cinfo into a buffer in dArg,
    102     * which p12d.c sometimes refers to as the "temp file".
    103     * This occurs during SEC_PKCS12DecoderUpdate calls.
    104     *
    105     * dOpen(dArg, PR_FALSE)
    106     * dWrite(dArg, buf, len)
    107     * ...
    108     * dWrite(dArg, buf, len)
    109     * dClose(dArg, PR_FALSE)
    110     *
    111     * Stage 2: verify MAC
    112     * This occurs SEC_PKCS12DecoderVerify.
    113     *
    114     * dOpen(dArg, PR_TRUE)
    115     * dRead(dArg, buf, IN_BUF_LEN)
    116     * ...
    117     * dRead(dArg, buf, IN_BUF_LEN)
    118     * dClose(dArg, PR_TRUE)
    119     */
    120    digestOpenFn dOpen;
    121    digestCloseFn dClose;
    122    digestIOFn dRead, dWrite;
    123    void *dArg;
    124    PRBool dIsOpen; /* is the temp file created? */
    125 
    126    /* helper functions */
    127    SECKEYGetPasswordKey pwfn;
    128    void *pwfnarg;
    129    PRBool swapUnicodeBytes;
    130    PRBool forceUnicode;
    131 
    132    /* import information */
    133    PRBool bagsVerified;
    134 
    135    /* buffer management for the default callbacks implementation */
    136    void *buffer;       /* storage area */
    137    PRInt32 filesize;   /* actual data size */
    138    PRInt32 allocated;  /* total buffer size allocated */
    139    PRInt32 currentpos; /* position counter */
    140    SECPKCS12TargetTokenCAs tokenCAs;
    141    sec_PKCS12SafeBag **keyList; /* used by ...IterateNext() */
    142    unsigned int iteration;
    143    SEC_PKCS12DecoderItem decitem;
    144 };
    145 
    146 /* forward declarations of functions that are used when decoding
    147 * safeContents bags which are nested and when decoding the
    148 * authenticatedSafes.
    149 */
    150 static SECStatus
    151 sec_pkcs12_decoder_begin_nested_safe_contents(sec_PKCS12SafeContentsContext
    152                                                  *safeContentsCtx);
    153 static SECStatus
    154 sec_pkcs12_decoder_finish_nested_safe_contents(sec_PKCS12SafeContentsContext
    155                                                   *safeContentsCtx);
    156 
    157 /* make sure that the PFX version being decoded is a version
    158 * which we support.
    159 */
    160 static PRBool
    161 sec_pkcs12_proper_version(sec_PKCS12PFXItem *pfx)
    162 {
    163    /* if no version, assume it is not supported */
    164    if (pfx->version.len == 0) {
    165        return PR_FALSE;
    166    }
    167 
    168    if (DER_GetInteger(&pfx->version) > SEC_PKCS12_VERSION) {
    169        return PR_FALSE;
    170    }
    171 
    172    return PR_TRUE;
    173 }
    174 
    175 /* retrieve the key for decrypting the safe contents */
    176 static PK11SymKey *
    177 sec_pkcs12_decoder_get_decrypt_key(void *arg, SECAlgorithmID *algid)
    178 {
    179    SEC_PKCS12DecoderContext *p12dcx = (SEC_PKCS12DecoderContext *)arg;
    180    PK11SlotInfo *slot;
    181    PK11SymKey *bulkKey;
    182    SECItem pwitem = { 0 };
    183    SECOidTag algorithm;
    184 
    185    if (!p12dcx) {
    186        return NULL;
    187    }
    188 
    189    /* if no slot specified, use the internal key slot */
    190    if (p12dcx->slot) {
    191        slot = PK11_ReferenceSlot(p12dcx->slot);
    192    } else {
    193        slot = PK11_GetInternalKeySlot();
    194    }
    195 
    196    algorithm = SECOID_GetAlgorithmTag(algid);
    197 
    198    if (p12dcx->forceUnicode) {
    199        if (SECITEM_CopyItem(NULL, &pwitem, p12dcx->pwitem) != SECSuccess) {
    200            PK11_FreeSlot(slot);
    201            return NULL;
    202        }
    203    } else {
    204        if (!sec_pkcs12_decode_password(NULL, &pwitem, algorithm, p12dcx->pwitem)) {
    205            PK11_FreeSlot(slot);
    206            return NULL;
    207        }
    208    }
    209 
    210    bulkKey = PK11_PBEKeyGen(slot, algid, &pwitem, PR_FALSE, p12dcx->wincx);
    211    /* some tokens can't generate PBE keys on their own, generate the
    212     * key in the internal slot, and let the Import code deal with it,
    213     * (if the slot can't generate PBEs, then we need to use the internal
    214     * slot anyway to unwrap). */
    215    if (!bulkKey && !PK11_IsInternal(slot)) {
    216        PK11_FreeSlot(slot);
    217        slot = PK11_GetInternalKeySlot();
    218        bulkKey = PK11_PBEKeyGen(slot, algid, &pwitem, PR_FALSE, p12dcx->wincx);
    219    }
    220    PK11_FreeSlot(slot);
    221 
    222    /* set the password data on the key */
    223    if (bulkKey) {
    224        PK11_SetSymKeyUserData(bulkKey, p12dcx->pwitem, NULL);
    225    }
    226 
    227    if (pwitem.data) {
    228        SECITEM_ZfreeItem(&pwitem, PR_FALSE);
    229    }
    230 
    231    return bulkKey;
    232 }
    233 
    234 /* XXX this needs to be modified to handle enveloped data.  most
    235 * likely, it should mirror the routines for SMIME in that regard.
    236 */
    237 static PRBool
    238 sec_pkcs12_decoder_decryption_allowed(SECAlgorithmID *algid,
    239                                      PK11SymKey *bulkkey)
    240 {
    241    PRBool decryptionAllowed = SEC_PKCS12DecryptionAllowed(algid);
    242 
    243    if (!decryptionAllowed) {
    244        PORT_SetError(SEC_ERROR_BAD_EXPORT_ALGORITHM);
    245        return PR_FALSE;
    246    }
    247 
    248    return PR_TRUE;
    249 }
    250 
    251 /* when we encounter a new safe bag during the decoding, we need
    252 * to allocate space for the bag to be decoded to and set the
    253 * state variables appropriately.  all of the safe bags are allocated
    254 * in a buffer in the outer SEC_PKCS12DecoderContext, however,
    255 * a pointer to the safeBag is also used in the sec_PKCS12SafeContentsContext
    256 * for the current bag.
    257 */
    258 static SECStatus
    259 sec_pkcs12_decoder_init_new_safe_bag(sec_PKCS12SafeContentsContext
    260                                         *safeContentsCtx)
    261 {
    262    void *mark = NULL;
    263    SEC_PKCS12DecoderContext *p12dcx;
    264 
    265    /* make sure that the structures are defined, and there has
    266     * not been an error in the decoding
    267     */
    268    if (!safeContentsCtx || !safeContentsCtx->p12dcx || safeContentsCtx->p12dcx->error) {
    269        return SECFailure;
    270    }
    271 
    272    p12dcx = safeContentsCtx->p12dcx;
    273    mark = PORT_ArenaMark(p12dcx->arena);
    274 
    275    /* allocate a new safe bag, if bags already exist, grow the
    276     * list of bags, otherwise allocate a new list.  the list is
    277     * NULL terminated.
    278     */
    279    p12dcx->safeBags = (!p12dcx->safeBagCount)
    280                           ? PORT_ArenaZNewArray(p12dcx->arena, sec_PKCS12SafeBag *, 2)
    281                           : PORT_ArenaGrowArray(p12dcx->arena, p12dcx->safeBags,
    282                                                 sec_PKCS12SafeBag *, p12dcx->safeBagCount + 1,
    283                                                 p12dcx->safeBagCount + 2);
    284 
    285    if (!p12dcx->safeBags) {
    286        p12dcx->errorValue = PORT_GetError();
    287        goto loser;
    288    }
    289 
    290    /* append the bag to the end of the list and update the reference
    291     * in the safeContentsCtx.
    292     */
    293    p12dcx->safeBags[p12dcx->safeBagCount] =
    294        safeContentsCtx->currentSafeBag =
    295            PORT_ArenaZNew(p12dcx->arena, sec_PKCS12SafeBag);
    296    if (!safeContentsCtx->currentSafeBag) {
    297        p12dcx->errorValue = PORT_GetError();
    298        goto loser;
    299    }
    300    p12dcx->safeBags[++p12dcx->safeBagCount] = NULL;
    301 
    302    safeContentsCtx->currentSafeBag->slot = safeContentsCtx->p12dcx->slot;
    303    safeContentsCtx->currentSafeBag->pwitem = safeContentsCtx->p12dcx->pwitem;
    304    safeContentsCtx->currentSafeBag->swapUnicodeBytes =
    305        safeContentsCtx->p12dcx->swapUnicodeBytes;
    306    safeContentsCtx->currentSafeBag->arena = safeContentsCtx->p12dcx->arena;
    307    safeContentsCtx->currentSafeBag->tokenCAs =
    308        safeContentsCtx->p12dcx->tokenCAs;
    309 
    310    PORT_ArenaUnmark(p12dcx->arena, mark);
    311    return SECSuccess;
    312 
    313 loser:
    314 
    315    /* if an error occurred, release the memory and set the error flag
    316     * the only possible errors triggered by this function are memory
    317     * related.
    318     */
    319    if (mark) {
    320        PORT_ArenaRelease(p12dcx->arena, mark);
    321    }
    322 
    323    p12dcx->error = PR_TRUE;
    324    return SECFailure;
    325 }
    326 
    327 /* A wrapper for updating the ASN1 context in which a safeBag is
    328 * being decoded.  This function is called as a callback from
    329 * secasn1d when decoding SafeContents structures.
    330 */
    331 static void
    332 sec_pkcs12_decoder_safe_bag_update(void *arg, const char *data,
    333                                   unsigned long len, int depth,
    334                                   SEC_ASN1EncodingPart data_kind)
    335 {
    336    sec_PKCS12SafeContentsContext *safeContentsCtx =
    337        (sec_PKCS12SafeContentsContext *)arg;
    338    SEC_PKCS12DecoderContext *p12dcx;
    339    SECStatus rv;
    340 
    341    if (!safeContentsCtx || !safeContentsCtx->p12dcx || !safeContentsCtx->currentSafeBagA1Dcx) {
    342        return;
    343    }
    344    p12dcx = safeContentsCtx->p12dcx;
    345 
    346    /* make sure that there are no errors and we are not skipping the current safeBag */
    347    if (p12dcx->error || safeContentsCtx->skipCurrentSafeBag) {
    348        goto loser;
    349    }
    350 
    351    rv = SEC_ASN1DecoderUpdate(safeContentsCtx->currentSafeBagA1Dcx, data, len);
    352    if (rv != SECSuccess) {
    353        p12dcx->errorValue = PORT_GetError();
    354        p12dcx->error = PR_TRUE;
    355        goto loser;
    356    }
    357 
    358    /* The update may have set safeContentsCtx->skipCurrentSafeBag, and we
    359     * may not get another opportunity to clean up the decoder context.
    360     */
    361    if (safeContentsCtx->skipCurrentSafeBag) {
    362        goto loser;
    363    }
    364 
    365    return;
    366 
    367 loser:
    368    /* Finish the decoder context. Because there
    369     * is not a way of returning an error message, it may be worth
    370     * while to do a check higher up and finish any decoding contexts
    371     * that are still open.
    372     */
    373    SEC_ASN1DecoderFinish(safeContentsCtx->currentSafeBagA1Dcx);
    374    safeContentsCtx->currentSafeBagA1Dcx = NULL;
    375    return;
    376 }
    377 
    378 /* notify function for decoding safeBags.  This function is
    379 * used to filter safeBag types which are not supported,
    380 * initiate the decoding of nested safe contents, and decode
    381 * safeBags in general.  this function is set when the decoder
    382 * context for the safeBag is first created.
    383 */
    384 static void
    385 sec_pkcs12_decoder_safe_bag_notify(void *arg, PRBool before,
    386                                   void *dest, int real_depth)
    387 {
    388    sec_PKCS12SafeContentsContext *safeContentsCtx =
    389        (sec_PKCS12SafeContentsContext *)arg;
    390    SEC_PKCS12DecoderContext *p12dcx;
    391    sec_PKCS12SafeBag *bag;
    392    PRBool after;
    393 
    394    /* if an error is encountered, return */
    395    if (!safeContentsCtx || !safeContentsCtx->p12dcx ||
    396        safeContentsCtx->p12dcx->error) {
    397        return;
    398    }
    399    p12dcx = safeContentsCtx->p12dcx;
    400 
    401    /* to make things more readable */
    402    if (before)
    403        after = PR_FALSE;
    404    else
    405        after = PR_TRUE;
    406 
    407    /* have we determined the safeBagType yet? */
    408    bag = safeContentsCtx->currentSafeBag;
    409    if (bag->bagTypeTag == NULL) {
    410        if (after && (dest == &(bag->safeBagType))) {
    411            bag->bagTypeTag = SECOID_FindOID(&(bag->safeBagType));
    412            if (bag->bagTypeTag == NULL) {
    413                p12dcx->error = PR_TRUE;
    414                p12dcx->errorValue = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
    415            }
    416        }
    417        return;
    418    }
    419 
    420    /* process the safeBag depending on it's type.  those
    421     * which we do not support, are ignored.  we start a decoding
    422     * context for a nested safeContents.
    423     */
    424    switch (bag->bagTypeTag->offset) {
    425        case SEC_OID_PKCS12_V1_KEY_BAG_ID:
    426        case SEC_OID_PKCS12_V1_CERT_BAG_ID:
    427        case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
    428            break;
    429        case SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID:
    430            /* if we are just starting to decode the safeContents, initialize
    431             * a new safeContentsCtx to process it.
    432             */
    433            if (before && (dest == &(bag->safeBagContent))) {
    434                sec_pkcs12_decoder_begin_nested_safe_contents(safeContentsCtx);
    435            } else if (after && (dest == &(bag->safeBagContent))) {
    436                /* clean up the nested decoding */
    437                sec_pkcs12_decoder_finish_nested_safe_contents(safeContentsCtx);
    438            }
    439            break;
    440        case SEC_OID_PKCS12_V1_CRL_BAG_ID:
    441        case SEC_OID_PKCS12_V1_SECRET_BAG_ID:
    442        default:
    443            /* skip any safe bag types we don't understand or handle */
    444            safeContentsCtx->skipCurrentSafeBag = PR_TRUE;
    445            break;
    446    }
    447 
    448    return;
    449 }
    450 
    451 /* notify function for decoding safe contents.  each entry in the
    452 * safe contents is a safeBag which needs to be allocated and
    453 * the decoding context initialized at the beginning and then
    454 * the context needs to be closed and finished at the end.
    455 *
    456 * this function is set when the safeContents decode context is
    457 * initialized.
    458 */
    459 static void
    460 sec_pkcs12_decoder_safe_contents_notify(void *arg, PRBool before,
    461                                        void *dest, int real_depth)
    462 {
    463    sec_PKCS12SafeContentsContext *safeContentsCtx =
    464        (sec_PKCS12SafeContentsContext *)arg;
    465    SEC_PKCS12DecoderContext *p12dcx;
    466    SECStatus rv;
    467 
    468    /* if there is an error we don't want to continue processing,
    469     * just return and keep going.
    470     */
    471    if (!safeContentsCtx || !safeContentsCtx->p12dcx ||
    472        safeContentsCtx->p12dcx->error) {
    473        return;
    474    }
    475    p12dcx = safeContentsCtx->p12dcx;
    476 
    477    /* if we are done with the current safeBag, then we need to
    478     * finish the context and set the state variables appropriately.
    479     */
    480    if (!before) {
    481        SEC_ASN1DecoderClearFilterProc(safeContentsCtx->safeContentsA1Dcx);
    482        SEC_ASN1DecoderFinish(safeContentsCtx->currentSafeBagA1Dcx);
    483        safeContentsCtx->currentSafeBagA1Dcx = NULL;
    484        safeContentsCtx->skipCurrentSafeBag = PR_FALSE;
    485    } else {
    486        /* we are starting a new safe bag.  we need to allocate space
    487         * for the bag and initialize the decoding context.
    488         */
    489        rv = sec_pkcs12_decoder_init_new_safe_bag(safeContentsCtx);
    490        if (rv != SECSuccess) {
    491            goto loser;
    492        }
    493 
    494        /* set up the decoder context */
    495        safeContentsCtx->currentSafeBagA1Dcx =
    496            SEC_ASN1DecoderStart(p12dcx->arena,
    497                                 safeContentsCtx->currentSafeBag,
    498                                 sec_PKCS12SafeBagTemplate);
    499        if (!safeContentsCtx->currentSafeBagA1Dcx) {
    500            p12dcx->errorValue = PORT_GetError();
    501            goto loser;
    502        }
    503 
    504        /* set the notify and filter procs so that the safe bag
    505         * data gets sent to the proper location when decoding.
    506         */
    507        SEC_ASN1DecoderSetNotifyProc(safeContentsCtx->currentSafeBagA1Dcx,
    508                                     sec_pkcs12_decoder_safe_bag_notify,
    509                                     safeContentsCtx);
    510        SEC_ASN1DecoderSetFilterProc(safeContentsCtx->safeContentsA1Dcx,
    511                                     sec_pkcs12_decoder_safe_bag_update,
    512                                     safeContentsCtx, PR_TRUE);
    513    }
    514 
    515    return;
    516 
    517 loser:
    518    /* in the event of an error, we want to close the decoding
    519     * context and clear the filter and notify procedures.
    520     */
    521    p12dcx->error = PR_TRUE;
    522 
    523    if (safeContentsCtx->currentSafeBagA1Dcx) {
    524        SEC_ASN1DecoderFinish(safeContentsCtx->currentSafeBagA1Dcx);
    525        safeContentsCtx->currentSafeBagA1Dcx = NULL;
    526    }
    527 
    528    SEC_ASN1DecoderClearNotifyProc(safeContentsCtx->safeContentsA1Dcx);
    529    SEC_ASN1DecoderClearFilterProc(safeContentsCtx->safeContentsA1Dcx);
    530 
    531    return;
    532 }
    533 
    534 /* initialize the safeContents for decoding.  this routine
    535 * is used for authenticatedSafes as well as nested safeContents.
    536 */
    537 static sec_PKCS12SafeContentsContext *
    538 sec_pkcs12_decoder_safe_contents_init_decode(SEC_PKCS12DecoderContext *p12dcx,
    539                                             PRBool nestedSafe)
    540 {
    541    sec_PKCS12SafeContentsContext *safeContentsCtx = NULL;
    542    const SEC_ASN1Template *theTemplate;
    543 
    544    if (!p12dcx || p12dcx->error) {
    545        return NULL;
    546    }
    547 
    548    /* allocate a new safeContents list or grow the existing list and
    549     * append the new safeContents onto the end.
    550     */
    551    p12dcx->safeContentsList = (!p12dcx->safeContentsCnt)
    552                                   ? PORT_ArenaZNewArray(p12dcx->arena, sec_PKCS12SafeContentsContext *, 2)
    553                                   : PORT_ArenaGrowArray(p12dcx->arena, p12dcx->safeContentsList,
    554                                                         sec_PKCS12SafeContentsContext *,
    555                                                         1 + p12dcx->safeContentsCnt,
    556                                                         2 + p12dcx->safeContentsCnt);
    557 
    558    if (!p12dcx->safeContentsList) {
    559        p12dcx->errorValue = PORT_GetError();
    560        goto loser;
    561    }
    562 
    563    p12dcx->safeContentsList[p12dcx->safeContentsCnt] = safeContentsCtx =
    564        PORT_ArenaZNew(p12dcx->arena, sec_PKCS12SafeContentsContext);
    565    if (!p12dcx->safeContentsList[p12dcx->safeContentsCnt]) {
    566        p12dcx->errorValue = PORT_GetError();
    567        goto loser;
    568    }
    569    p12dcx->safeContentsList[++p12dcx->safeContentsCnt] = NULL;
    570 
    571    /* set up the state variables */
    572    safeContentsCtx->p12dcx = p12dcx;
    573    safeContentsCtx->arena = p12dcx->arena;
    574 
    575    /* begin the decoding -- the template is based on whether we are
    576     * decoding a nested safeContents or not.
    577     */
    578    if (nestedSafe == PR_TRUE) {
    579        theTemplate = sec_PKCS12NestedSafeContentsDecodeTemplate;
    580    } else {
    581        theTemplate = sec_PKCS12SafeContentsDecodeTemplate;
    582    }
    583 
    584    /* start the decoder context */
    585    safeContentsCtx->safeContentsA1Dcx = SEC_ASN1DecoderStart(p12dcx->arena,
    586                                                              &safeContentsCtx->safeContents,
    587                                                              theTemplate);
    588 
    589    if (!safeContentsCtx->safeContentsA1Dcx) {
    590        p12dcx->errorValue = PORT_GetError();
    591        goto loser;
    592    }
    593 
    594    /* set the safeContents notify procedure to look for
    595     * and start the decode of safeBags.
    596     */
    597    SEC_ASN1DecoderSetNotifyProc(safeContentsCtx->safeContentsA1Dcx,
    598                                 sec_pkcs12_decoder_safe_contents_notify,
    599                                 safeContentsCtx);
    600 
    601    return safeContentsCtx;
    602 
    603 loser:
    604    /* in the case of an error, we want to finish the decoder
    605     * context and set the error flag.
    606     */
    607    if (safeContentsCtx && safeContentsCtx->safeContentsA1Dcx) {
    608        SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsA1Dcx);
    609        safeContentsCtx->safeContentsA1Dcx = NULL;
    610    }
    611 
    612    p12dcx->error = PR_TRUE;
    613 
    614    return NULL;
    615 }
    616 
    617 /* wrapper for updating safeContents.  this is set as the filter of
    618 * safeBag when there is a nested safeContents.
    619 */
    620 static void
    621 sec_pkcs12_decoder_nested_safe_contents_update(void *arg, const char *buf,
    622                                               unsigned long len, int depth,
    623                                               SEC_ASN1EncodingPart data_kind)
    624 {
    625    sec_PKCS12SafeContentsContext *safeContentsCtx =
    626        (sec_PKCS12SafeContentsContext *)arg;
    627    SEC_PKCS12DecoderContext *p12dcx;
    628    SECStatus rv;
    629 
    630    /* check for an error */
    631    if (!safeContentsCtx || !safeContentsCtx->p12dcx ||
    632        safeContentsCtx->p12dcx->error || !safeContentsCtx->safeContentsA1Dcx) {
    633        return;
    634    }
    635 
    636    /* no need to update if no data sent in */
    637    if (!len || !buf) {
    638        return;
    639    }
    640 
    641    /* update the decoding context */
    642    p12dcx = safeContentsCtx->p12dcx;
    643    rv = SEC_ASN1DecoderUpdate(safeContentsCtx->safeContentsA1Dcx, buf, len);
    644    if (rv != SECSuccess) {
    645        p12dcx->errorValue = PORT_GetError();
    646        goto loser;
    647    }
    648 
    649    return;
    650 
    651 loser:
    652    /* handle any errors.  If a decoding context is open, close it. */
    653    p12dcx->error = PR_TRUE;
    654    if (safeContentsCtx->safeContentsA1Dcx) {
    655        SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsA1Dcx);
    656        safeContentsCtx->safeContentsA1Dcx = NULL;
    657    }
    658 }
    659 
    660 /* whenever a new safeContentsSafeBag is encountered, we need
    661 * to init a safeContentsContext.
    662 */
    663 static SECStatus
    664 sec_pkcs12_decoder_begin_nested_safe_contents(sec_PKCS12SafeContentsContext
    665                                                  *safeContentsCtx)
    666 {
    667    /* check for an error */
    668    if (!safeContentsCtx || !safeContentsCtx->p12dcx ||
    669        safeContentsCtx->p12dcx->error) {
    670        return SECFailure;
    671    }
    672 
    673    safeContentsCtx->nestedSafeContentsCtx =
    674        sec_pkcs12_decoder_safe_contents_init_decode(safeContentsCtx->p12dcx,
    675                                                     PR_TRUE);
    676    if (!safeContentsCtx->nestedSafeContentsCtx) {
    677        return SECFailure;
    678    }
    679 
    680    /* set up new filter proc */
    681    SEC_ASN1DecoderSetNotifyProc(
    682        safeContentsCtx->nestedSafeContentsCtx->safeContentsA1Dcx,
    683        sec_pkcs12_decoder_safe_contents_notify,
    684        safeContentsCtx->nestedSafeContentsCtx);
    685 
    686    SEC_ASN1DecoderSetFilterProc(safeContentsCtx->currentSafeBagA1Dcx,
    687                                 sec_pkcs12_decoder_nested_safe_contents_update,
    688                                 safeContentsCtx->nestedSafeContentsCtx,
    689                                 PR_TRUE);
    690 
    691    return SECSuccess;
    692 }
    693 
    694 /* when the safeContents is done decoding, we need to reset the
    695 * proper filter and notify procs and close the decoding context
    696 */
    697 static SECStatus
    698 sec_pkcs12_decoder_finish_nested_safe_contents(sec_PKCS12SafeContentsContext
    699                                                   *safeContentsCtx)
    700 {
    701    /* check for error */
    702    if (!safeContentsCtx || !safeContentsCtx->p12dcx ||
    703        safeContentsCtx->p12dcx->error) {
    704        return SECFailure;
    705    }
    706 
    707    /* clean up */
    708    SEC_ASN1DecoderClearFilterProc(safeContentsCtx->currentSafeBagA1Dcx);
    709    SEC_ASN1DecoderClearNotifyProc(
    710        safeContentsCtx->nestedSafeContentsCtx->safeContentsA1Dcx);
    711    SEC_ASN1DecoderFinish(
    712        safeContentsCtx->nestedSafeContentsCtx->safeContentsA1Dcx);
    713    safeContentsCtx->nestedSafeContentsCtx->safeContentsA1Dcx = NULL;
    714    safeContentsCtx->nestedSafeContentsCtx = NULL;
    715 
    716    return SECSuccess;
    717 }
    718 
    719 /* wrapper for updating safeContents.  This is used when decoding
    720 * the nested safeContents and any authenticatedSafes.
    721 */
    722 static void
    723 sec_pkcs12_decoder_safe_contents_callback(void *arg, const char *buf,
    724                                          unsigned long len)
    725 {
    726    SECStatus rv;
    727    sec_PKCS12SafeContentsContext *safeContentsCtx =
    728        (sec_PKCS12SafeContentsContext *)arg;
    729    SEC_PKCS12DecoderContext *p12dcx;
    730 
    731    /* check for error */
    732    if (!safeContentsCtx || !safeContentsCtx->p12dcx ||
    733        safeContentsCtx->p12dcx->error || !safeContentsCtx->safeContentsA1Dcx) {
    734        return;
    735    }
    736    p12dcx = safeContentsCtx->p12dcx;
    737 
    738    /* update the decoder */
    739    rv = SEC_ASN1DecoderUpdate(safeContentsCtx->safeContentsA1Dcx, buf, len);
    740    if (rv != SECSuccess) {
    741        /* if we fail while trying to decode a 'safe', it's probably because
    742         * we didn't have the correct password. */
    743        PORT_SetError(SEC_ERROR_BAD_PASSWORD);
    744        p12dcx->errorValue = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
    745        SEC_PKCS7DecoderAbort(p12dcx->currentASafeP7Dcx, SEC_ERROR_BAD_PASSWORD);
    746        goto loser;
    747    }
    748 
    749    return;
    750 
    751 loser:
    752    /* set the error and finish the context */
    753    p12dcx->error = PR_TRUE;
    754    if (safeContentsCtx->safeContentsA1Dcx) {
    755        SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsA1Dcx);
    756        safeContentsCtx->safeContentsA1Dcx = NULL;
    757    }
    758 
    759    return;
    760 }
    761 
    762 /* this is a wrapper for the ASN1 decoder to call SEC_PKCS7DecoderUpdate
    763 */
    764 static void
    765 sec_pkcs12_decoder_wrap_p7_update(void *arg, const char *data,
    766                                  unsigned long len, int depth,
    767                                  SEC_ASN1EncodingPart data_kind)
    768 {
    769    SEC_PKCS7DecoderContext *p7dcx = (SEC_PKCS7DecoderContext *)arg;
    770 
    771    SEC_PKCS7DecoderUpdate(p7dcx, data, len);
    772 }
    773 
    774 /* notify function for decoding aSafes.  at the beginning,
    775 * of an authenticatedSafe, we start a decode of a safeContents.
    776 * at the end, we clean up the safeContents decoder context and
    777 * reset state variables
    778 */
    779 static void
    780 sec_pkcs12_decoder_asafes_notify(void *arg, PRBool before, void *dest,
    781                                 int real_depth)
    782 {
    783    SEC_PKCS12DecoderContext *p12dcx;
    784    sec_PKCS12SafeContentsContext *safeContentsCtx;
    785 
    786    /* make sure no error occurred. */
    787    p12dcx = (SEC_PKCS12DecoderContext *)arg;
    788    if (!p12dcx || p12dcx->error) {
    789        return;
    790    }
    791 
    792    if (before) {
    793 
    794        /* init a new safeContentsContext */
    795        safeContentsCtx = sec_pkcs12_decoder_safe_contents_init_decode(p12dcx,
    796                                                                       PR_FALSE);
    797        if (!safeContentsCtx) {
    798            goto loser;
    799        }
    800 
    801        /* initiate the PKCS7ContentInfo decode */
    802        p12dcx->currentASafeP7Dcx = SEC_PKCS7DecoderStart(
    803            sec_pkcs12_decoder_safe_contents_callback,
    804            safeContentsCtx,
    805            p12dcx->pwfn, p12dcx->pwfnarg,
    806            sec_pkcs12_decoder_get_decrypt_key, p12dcx,
    807            sec_pkcs12_decoder_decryption_allowed);
    808        if (!p12dcx->currentASafeP7Dcx) {
    809            p12dcx->errorValue = PORT_GetError();
    810            goto loser;
    811        }
    812        SEC_ASN1DecoderSetFilterProc(p12dcx->aSafeA1Dcx,
    813                                     sec_pkcs12_decoder_wrap_p7_update,
    814                                     p12dcx->currentASafeP7Dcx, PR_TRUE);
    815    }
    816 
    817    if (!before) {
    818        /* if one is being decoded, finish the decode */
    819        if (p12dcx->currentASafeP7Dcx != NULL) {
    820            SEC_PKCS7ContentInfo *cinfo;
    821            unsigned int cnt = p12dcx->safeContentsCnt - 1;
    822            safeContentsCtx = p12dcx->safeContentsList[cnt];
    823            if (safeContentsCtx->safeContentsA1Dcx) {
    824                SEC_ASN1DecoderClearFilterProc(p12dcx->aSafeA1Dcx);
    825                SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsA1Dcx);
    826                safeContentsCtx->safeContentsA1Dcx = NULL;
    827            }
    828            cinfo = SEC_PKCS7DecoderFinish(p12dcx->currentASafeP7Dcx);
    829            SEC_ASN1DecoderClearFilterProc(p12dcx->aSafeA1Dcx);
    830            p12dcx->currentASafeP7Dcx = NULL;
    831            if (!cinfo) {
    832                p12dcx->errorValue = PORT_GetError();
    833                goto loser;
    834            }
    835            SEC_PKCS7DestroyContentInfo(cinfo); /* don't leak it */
    836        }
    837    }
    838 
    839    return;
    840 
    841 loser:
    842    /* set the error flag */
    843    p12dcx->error = PR_TRUE;
    844    return;
    845 }
    846 
    847 /* wrapper for updating asafes decoding context.  this function
    848 * writes data being decoded to disk, so that a mac can be computed
    849 * later.
    850 */
    851 static void
    852 sec_pkcs12_decoder_asafes_callback(void *arg, const char *buf,
    853                                   unsigned long len)
    854 {
    855    SEC_PKCS12DecoderContext *p12dcx = (SEC_PKCS12DecoderContext *)arg;
    856    SECStatus rv;
    857 
    858    if (!p12dcx || p12dcx->error) {
    859        return;
    860    }
    861 
    862    /* update the context */
    863    rv = SEC_ASN1DecoderUpdate(p12dcx->aSafeA1Dcx, buf, len);
    864    if (rv != SECSuccess) {
    865        p12dcx->errorValue = PORT_GetError();
    866        p12dcx->error = PR_TRUE;
    867        goto loser;
    868    }
    869 
    870    /* if we are writing to a file, write out the new information */
    871    if (p12dcx->dWrite) {
    872        unsigned long writeLen = (*p12dcx->dWrite)(p12dcx->dArg,
    873                                                   (unsigned char *)buf, len);
    874        if (writeLen != len) {
    875            p12dcx->errorValue = PORT_GetError();
    876            goto loser;
    877        }
    878    }
    879 
    880    return;
    881 
    882 loser:
    883    /* set the error flag */
    884    p12dcx->error = PR_TRUE;
    885    SEC_ASN1DecoderFinish(p12dcx->aSafeA1Dcx);
    886    p12dcx->aSafeA1Dcx = NULL;
    887 
    888    return;
    889 }
    890 
    891 /* start the decode of an authenticatedSafe contentInfo.
    892 */
    893 static SECStatus
    894 sec_pkcs12_decode_start_asafes_cinfo(SEC_PKCS12DecoderContext *p12dcx)
    895 {
    896    if (!p12dcx || p12dcx->error) {
    897        return SECFailure;
    898    }
    899 
    900    /* start the decode context */
    901    p12dcx->aSafeA1Dcx = SEC_ASN1DecoderStart(p12dcx->arena,
    902                                              &p12dcx->authSafe,
    903                                              sec_PKCS12AuthenticatedSafeTemplate);
    904    if (!p12dcx->aSafeA1Dcx) {
    905        p12dcx->errorValue = PORT_GetError();
    906        goto loser;
    907    }
    908 
    909    /* set the notify function */
    910    SEC_ASN1DecoderSetNotifyProc(p12dcx->aSafeA1Dcx,
    911                                 sec_pkcs12_decoder_asafes_notify, p12dcx);
    912 
    913    /* begin the authSafe decoder context */
    914    p12dcx->aSafeP7Dcx = SEC_PKCS7DecoderStart(
    915        sec_pkcs12_decoder_asafes_callback, p12dcx,
    916        p12dcx->pwfn, p12dcx->pwfnarg, NULL, NULL, NULL);
    917    if (!p12dcx->aSafeP7Dcx) {
    918        p12dcx->errorValue = PORT_GetError();
    919        goto loser;
    920    }
    921 
    922    /* open the temp file for writing, if the digest functions were set */
    923    if (p12dcx->dOpen && (*p12dcx->dOpen)(p12dcx->dArg, PR_FALSE) != SECSuccess) {
    924        p12dcx->errorValue = PORT_GetError();
    925        goto loser;
    926    }
    927    /* dOpen(dArg, PR_FALSE) creates the temp file */
    928    p12dcx->dIsOpen = PR_TRUE;
    929 
    930    return SECSuccess;
    931 
    932 loser:
    933    p12dcx->error = PR_TRUE;
    934 
    935    if (p12dcx->aSafeA1Dcx) {
    936        SEC_ASN1DecoderFinish(p12dcx->aSafeA1Dcx);
    937        p12dcx->aSafeA1Dcx = NULL;
    938    }
    939 
    940    if (p12dcx->aSafeP7Dcx) {
    941        SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx);
    942        p12dcx->aSafeP7Dcx = NULL;
    943    }
    944 
    945    return SECFailure;
    946 }
    947 
    948 /* wrapper for updating the safeContents.  this function is used as
    949 * a filter for the pfx when decoding the authenticated safes
    950 */
    951 static void
    952 sec_pkcs12_decode_asafes_cinfo_update(void *arg, const char *buf,
    953                                      unsigned long len, int depth,
    954                                      SEC_ASN1EncodingPart data_kind)
    955 {
    956    SEC_PKCS12DecoderContext *p12dcx;
    957    SECStatus rv;
    958 
    959    p12dcx = (SEC_PKCS12DecoderContext *)arg;
    960    if (!p12dcx || p12dcx->error) {
    961        return;
    962    }
    963 
    964    /* update the safeContents decoder */
    965    rv = SEC_PKCS7DecoderUpdate(p12dcx->aSafeP7Dcx, buf, len);
    966    if (rv != SECSuccess) {
    967        p12dcx->errorValue = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
    968        goto loser;
    969    }
    970 
    971    return;
    972 
    973 loser:
    974 
    975    /* did we find an error?  if so, close the context and set the
    976     * error flag.
    977     */
    978    SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx);
    979    p12dcx->aSafeP7Dcx = NULL;
    980    p12dcx->error = PR_TRUE;
    981 }
    982 
    983 /* notify procedure used while decoding the pfx.  When we encounter
    984 * the authSafes, we want to trigger the decoding of authSafes as well
    985 * as when we encounter the macData, trigger the decoding of it.  we do
    986 * this because we we are streaming the decoder and not decoding in place.
    987 * the pfx which is the destination, only has the version decoded into it.
    988 */
    989 static void
    990 sec_pkcs12_decoder_pfx_notify_proc(void *arg, PRBool before, void *dest,
    991                                   int real_depth)
    992 {
    993    SECStatus rv;
    994    SEC_PKCS12DecoderContext *p12dcx = (SEC_PKCS12DecoderContext *)arg;
    995 
    996    /* if an error occurs, clear the notifyProc and the filterProc
    997     * and continue.
    998     */
    999    if (p12dcx->error) {
   1000        SEC_ASN1DecoderClearNotifyProc(p12dcx->pfxA1Dcx);
   1001        SEC_ASN1DecoderClearFilterProc(p12dcx->pfxA1Dcx);
   1002        return;
   1003    }
   1004 
   1005    if (before && (dest == &p12dcx->pfx.encodedAuthSafe)) {
   1006 
   1007        /* we want to make sure this is a version we support */
   1008        if (!sec_pkcs12_proper_version(&p12dcx->pfx)) {
   1009            p12dcx->errorValue = SEC_ERROR_PKCS12_UNSUPPORTED_VERSION;
   1010            goto loser;
   1011        }
   1012 
   1013        /* start the decode of the aSafes cinfo... */
   1014        rv = sec_pkcs12_decode_start_asafes_cinfo(p12dcx);
   1015        if (rv != SECSuccess) {
   1016            goto loser;
   1017        }
   1018 
   1019        /* set the filter proc to update the authenticated safes. */
   1020        SEC_ASN1DecoderSetFilterProc(p12dcx->pfxA1Dcx,
   1021                                     sec_pkcs12_decode_asafes_cinfo_update,
   1022                                     p12dcx, PR_TRUE);
   1023    }
   1024 
   1025    if (!before && (dest == &p12dcx->pfx.encodedAuthSafe)) {
   1026 
   1027        /* we are done decoding the authenticatedSafes, so we need to
   1028         * finish the decoderContext and clear the filter proc
   1029         * and close the hmac callback, if present
   1030         */
   1031        p12dcx->aSafeCinfo = SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx);
   1032        p12dcx->aSafeP7Dcx = NULL;
   1033        if (!p12dcx->aSafeCinfo) {
   1034            p12dcx->errorValue = PORT_GetError();
   1035            goto loser;
   1036        }
   1037        SEC_ASN1DecoderClearFilterProc(p12dcx->pfxA1Dcx);
   1038        if (p12dcx->dClose && ((*p12dcx->dClose)(p12dcx->dArg, PR_FALSE) != SECSuccess)) {
   1039            p12dcx->errorValue = PORT_GetError();
   1040            goto loser;
   1041        }
   1042    }
   1043 
   1044    return;
   1045 
   1046 loser:
   1047    p12dcx->error = PR_TRUE;
   1048 }
   1049 
   1050 /*  default implementations of the open/close/read/write functions for
   1051    SEC_PKCS12DecoderStart
   1052 */
   1053 
   1054 #define DEFAULT_TEMP_SIZE 4096
   1055 
   1056 static SECStatus
   1057 p12u_DigestOpen(void *arg, PRBool readData)
   1058 {
   1059    SEC_PKCS12DecoderContext *p12cxt = arg;
   1060 
   1061    p12cxt->currentpos = 0;
   1062 
   1063    if (PR_FALSE == readData) {
   1064        /* allocate an initial buffer */
   1065        p12cxt->filesize = 0;
   1066        p12cxt->allocated = DEFAULT_TEMP_SIZE;
   1067        p12cxt->buffer = PORT_Alloc(DEFAULT_TEMP_SIZE);
   1068        PR_ASSERT(p12cxt->buffer);
   1069    } else {
   1070        PR_ASSERT(p12cxt->buffer);
   1071        if (!p12cxt->buffer) {
   1072            return SECFailure; /* no data to read */
   1073        }
   1074    }
   1075 
   1076    return SECSuccess;
   1077 }
   1078 
   1079 static SECStatus
   1080 p12u_DigestClose(void *arg, PRBool removeFile)
   1081 {
   1082    SEC_PKCS12DecoderContext *p12cxt = arg;
   1083 
   1084    PR_ASSERT(p12cxt);
   1085    if (!p12cxt) {
   1086        return SECFailure;
   1087    }
   1088    p12cxt->currentpos = 0;
   1089 
   1090    if (PR_TRUE == removeFile) {
   1091        PR_ASSERT(p12cxt->buffer);
   1092        if (!p12cxt->buffer) {
   1093            return SECFailure;
   1094        }
   1095        if (p12cxt->buffer) {
   1096            PORT_Free(p12cxt->buffer);
   1097            p12cxt->buffer = NULL;
   1098            p12cxt->allocated = 0;
   1099            p12cxt->filesize = 0;
   1100        }
   1101    }
   1102 
   1103    return SECSuccess;
   1104 }
   1105 
   1106 static int
   1107 p12u_DigestRead(void *arg, unsigned char *buf, unsigned long len)
   1108 {
   1109    int toread = len;
   1110    SEC_PKCS12DecoderContext *p12cxt = arg;
   1111 
   1112    if (!buf || len == 0 || !p12cxt->buffer) {
   1113        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1114        return -1;
   1115    }
   1116 
   1117    if ((p12cxt->filesize - p12cxt->currentpos) < (long)len) {
   1118        /* trying to read past the end of the buffer */
   1119        toread = p12cxt->filesize - p12cxt->currentpos;
   1120    }
   1121    memcpy(buf, (char *)p12cxt->buffer + p12cxt->currentpos, toread);
   1122    p12cxt->currentpos += toread;
   1123    return toread;
   1124 }
   1125 
   1126 static int
   1127 p12u_DigestWrite(void *arg, unsigned char *buf, unsigned long len)
   1128 {
   1129    SEC_PKCS12DecoderContext *p12cxt = arg;
   1130 
   1131    if (!buf || len == 0) {
   1132        return -1;
   1133    }
   1134 
   1135    if (p12cxt->currentpos + (long)len > p12cxt->filesize) {
   1136        p12cxt->filesize = p12cxt->currentpos + len;
   1137    } else {
   1138        p12cxt->filesize += len;
   1139    }
   1140    if (p12cxt->filesize > p12cxt->allocated) {
   1141        void *newbuffer;
   1142        size_t newsize = p12cxt->filesize + DEFAULT_TEMP_SIZE;
   1143        newbuffer = PORT_Realloc(p12cxt->buffer, newsize);
   1144        if (NULL == newbuffer) {
   1145            return -1; /* can't extend the buffer */
   1146        }
   1147        p12cxt->buffer = newbuffer;
   1148        p12cxt->allocated = newsize;
   1149    }
   1150    PR_ASSERT(p12cxt->buffer);
   1151    memcpy((char *)p12cxt->buffer + p12cxt->currentpos, buf, len);
   1152    p12cxt->currentpos += len;
   1153    return len;
   1154 }
   1155 
   1156 /* SEC_PKCS12DecoderStart
   1157 *      Creates a decoder context for decoding a PKCS 12 PDU objct.
   1158 *      This function sets up the initial decoding context for the
   1159 *      PFX and sets the needed state variables.
   1160 *
   1161 *      pwitem - the password for the hMac and any encoded safes.
   1162 *               this should be changed to take a callback which retrieves
   1163 *               the password.  it may be possible for different safes to
   1164 *               have different passwords.  also, the password is already
   1165 *               in unicode.  it should probably be converted down below via
   1166 *               a unicode conversion callback.
   1167 *      slot - the slot to import the dataa into should multiple slots
   1168 *               be supported based on key type and cert type?
   1169 *      dOpen, dClose, dRead, dWrite - digest routines for writing data
   1170 *               to a file so it could be read back and the hmac recomputed
   1171 *               and verified.  doesn't seem to be a way for both encoding
   1172 *               and decoding to be single pass, thus the need for these
   1173 *               routines.
   1174 *      dArg - the argument for dOpen, etc.
   1175 *
   1176 *      if NULL == dOpen == dClose == dRead == dWrite == dArg, then default
   1177 *      implementations using a memory buffer are used
   1178 *
   1179 *      This function returns the decoder context, if it was successful.
   1180 *      Otherwise, null is returned.
   1181 */
   1182 SEC_PKCS12DecoderContext *
   1183 SEC_PKCS12DecoderStart(SECItem *pwitem, PK11SlotInfo *slot, void *wincx,
   1184                       digestOpenFn dOpen, digestCloseFn dClose,
   1185                       digestIOFn dRead, digestIOFn dWrite, void *dArg)
   1186 {
   1187    SEC_PKCS12DecoderContext *p12dcx;
   1188    PLArenaPool *arena;
   1189    PRInt32 forceUnicode = PR_FALSE;
   1190    SECStatus rv;
   1191 
   1192    arena = PORT_NewArena(2048); /* different size? */
   1193    if (!arena) {
   1194        return NULL; /* error is already set */
   1195    }
   1196 
   1197    /* allocate the decoder context and set the state variables */
   1198    p12dcx = PORT_ArenaZNew(arena, SEC_PKCS12DecoderContext);
   1199    if (!p12dcx) {
   1200        goto loser; /* error is already set */
   1201    }
   1202 
   1203    if (!dOpen && !dClose && !dRead && !dWrite && !dArg) {
   1204        /* use default implementations */
   1205        dOpen = p12u_DigestOpen;
   1206        dClose = p12u_DigestClose;
   1207        dRead = p12u_DigestRead;
   1208        dWrite = p12u_DigestWrite;
   1209        dArg = (void *)p12dcx;
   1210    }
   1211 
   1212    p12dcx->arena = arena;
   1213    p12dcx->pwitem = pwitem;
   1214    p12dcx->slot = (slot ? PK11_ReferenceSlot(slot)
   1215                         : PK11_GetInternalKeySlot());
   1216    p12dcx->wincx = wincx;
   1217    p12dcx->tokenCAs = SECPKCS12TargetTokenNoCAs;
   1218 #ifdef IS_LITTLE_ENDIAN
   1219    p12dcx->swapUnicodeBytes = PR_TRUE;
   1220 #else
   1221    p12dcx->swapUnicodeBytes = PR_FALSE;
   1222 #endif
   1223    rv = NSS_OptionGet(__NSS_PKCS12_DECODE_FORCE_UNICODE, &forceUnicode);
   1224    if (rv != SECSuccess) {
   1225        goto loser;
   1226    }
   1227    p12dcx->forceUnicode = forceUnicode;
   1228    p12dcx->errorValue = 0;
   1229    p12dcx->error = PR_FALSE;
   1230 
   1231    /* start the decoding of the PFX and set the notify proc
   1232     * for the PFX item.
   1233     */
   1234    p12dcx->pfxA1Dcx = SEC_ASN1DecoderStart(p12dcx->arena, &p12dcx->pfx,
   1235                                            sec_PKCS12PFXItemTemplate);
   1236    if (!p12dcx->pfxA1Dcx) {
   1237        PK11_FreeSlot(p12dcx->slot);
   1238        goto loser;
   1239    }
   1240 
   1241    SEC_ASN1DecoderSetNotifyProc(p12dcx->pfxA1Dcx,
   1242                                 sec_pkcs12_decoder_pfx_notify_proc,
   1243                                 p12dcx);
   1244 
   1245    /* set up digest functions */
   1246    p12dcx->dOpen = dOpen;
   1247    p12dcx->dWrite = dWrite;
   1248    p12dcx->dClose = dClose;
   1249    p12dcx->dRead = dRead;
   1250    p12dcx->dArg = dArg;
   1251    p12dcx->dIsOpen = PR_FALSE;
   1252 
   1253    p12dcx->keyList = NULL;
   1254    p12dcx->decitem.type = 0;
   1255    p12dcx->decitem.der = NULL;
   1256    p12dcx->decitem.hasKey = PR_FALSE;
   1257    p12dcx->decitem.friendlyName = NULL;
   1258    p12dcx->iteration = 0;
   1259 
   1260    return p12dcx;
   1261 
   1262 loser:
   1263    PORT_FreeArena(arena, PR_TRUE);
   1264    return NULL;
   1265 }
   1266 
   1267 SECStatus
   1268 SEC_PKCS12DecoderSetTargetTokenCAs(SEC_PKCS12DecoderContext *p12dcx,
   1269                                   SECPKCS12TargetTokenCAs tokenCAs)
   1270 {
   1271    if (!p12dcx || p12dcx->error) {
   1272        return SECFailure;
   1273    }
   1274    p12dcx->tokenCAs = tokenCAs;
   1275    return SECSuccess;
   1276 }
   1277 
   1278 /* SEC_PKCS12DecoderUpdate
   1279 *      Streaming update sending more data to the decoder.  If
   1280 *      an error occurs, SECFailure is returned.
   1281 *
   1282 *      p12dcx - the decoder context
   1283 *      data, len - the data buffer and length of data to send to
   1284 *              the update functions.
   1285 */
   1286 SECStatus
   1287 SEC_PKCS12DecoderUpdate(SEC_PKCS12DecoderContext *p12dcx,
   1288                        unsigned char *data, unsigned long len)
   1289 {
   1290    SECStatus rv;
   1291 
   1292    if (!p12dcx || p12dcx->error) {
   1293        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1294        return SECFailure;
   1295    }
   1296 
   1297    /* update the PFX decoder context */
   1298    rv = SEC_ASN1DecoderUpdate(p12dcx->pfxA1Dcx, (const char *)data, len);
   1299    if (rv != SECSuccess) {
   1300        p12dcx->errorValue = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
   1301        goto loser;
   1302    }
   1303 
   1304    return SECSuccess;
   1305 
   1306 loser:
   1307 
   1308    p12dcx->error = PR_TRUE;
   1309    return SECFailure;
   1310 }
   1311 
   1312 /* This should be a nice sized buffer for reading in data (potentially large
   1313 ** amounts) to be MACed.  It should be MUCH larger than HASH_LENGTH_MAX.
   1314 */
   1315 #define IN_BUF_LEN 1024
   1316 #ifdef DEBUG
   1317 static const char bufferEnd[] = { "BufferEnd" };
   1318 #endif
   1319 #define FUDGE 128 /* must be as large as bufferEnd or more. */
   1320 
   1321 #ifdef UNSAFE_FUZZER_MODE
   1322 static PRBool
   1323 fuzzer_parity_check(const unsigned char *buf, size_t len)
   1324 {
   1325    unsigned char p = 0;
   1326    for (size_t i = 0; i < len; i++)
   1327        p ^= buf[i];
   1328    return (p & 1) != 0;
   1329 }
   1330 
   1331 static SECStatus
   1332 sec_pkcs12_decoder_unsafe_parity_outcome(SEC_PKCS12DecoderContext *p12dcx)
   1333 {
   1334    PRBool allow = PR_TRUE;
   1335    if (p12dcx->pfx.encodedMacData.data && p12dcx->pfx.encodedMacData.len) {
   1336        allow = fuzzer_parity_check(p12dcx->pfx.encodedMacData.data, p12dcx->pfx.encodedMacData.len);
   1337    }
   1338 
   1339    if (p12dcx->dClose) {
   1340        (*p12dcx->dClose)(p12dcx->dArg, PR_TRUE);
   1341        p12dcx->dIsOpen = PR_FALSE;
   1342    }
   1343 
   1344    if (!allow) {
   1345        PORT_SetError(SEC_ERROR_PKCS12_INVALID_MAC);
   1346        return SECFailure;
   1347    }
   1348 
   1349    return SECSuccess;
   1350 }
   1351 #endif /* UNSAFE_FUZZER_MODE */
   1352 
   1353 /* verify the hmac by reading the data from the temporary file
   1354 * using the routines specified when the decodingContext was
   1355 * created and return SECSuccess if the hmac matches.
   1356 */
   1357 static SECStatus
   1358 sec_pkcs12_decoder_verify_mac(SEC_PKCS12DecoderContext *p12dcx)
   1359 {
   1360    PK11Context *pk11cx = NULL;
   1361    PK11SymKey *symKey = NULL;
   1362    unsigned char *buf;
   1363    SECStatus rv = SECFailure;
   1364    SECStatus lrv;
   1365    unsigned int bufLen;
   1366    int bytesRead;
   1367    SECItem hmacRes;
   1368    SECItem ignore = { 0 };
   1369    CK_MECHANISM_TYPE hmacMech;
   1370 
   1371    if (!p12dcx || p12dcx->error) {
   1372        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1373        return SECFailure;
   1374    }
   1375 #ifdef UNSAFE_FUZZER_MODE
   1376    return sec_pkcs12_decoder_unsafe_parity_outcome(p12dcx);
   1377 #endif /* UNSAFE_FUZZER_MODE */
   1378    buf = (unsigned char *)PORT_Alloc(IN_BUF_LEN + FUDGE);
   1379    if (!buf)
   1380        return SECFailure; /* error code has been set. */
   1381 
   1382 #ifdef DEBUG
   1383    memcpy(buf + IN_BUF_LEN, bufferEnd, sizeof bufferEnd);
   1384 #endif
   1385 
   1386    /* generate hmac key */
   1387    symKey = sec_pkcs12_integrity_key(p12dcx->slot, &p12dcx->macData,
   1388                                      p12dcx->pwitem, &hmacMech, PR_TRUE,
   1389                                      p12dcx->wincx);
   1390    if (symKey == NULL) {
   1391        goto loser;
   1392    }
   1393 
   1394    /* init hmac */
   1395    pk11cx = PK11_CreateContextBySymKey(hmacMech, CKA_SIGN, symKey, &ignore);
   1396    if (!pk11cx) {
   1397        goto loser;
   1398    }
   1399    lrv = PK11_DigestBegin(pk11cx);
   1400    if (lrv == SECFailure) {
   1401        goto loser;
   1402    }
   1403 
   1404    /* try to open the data for readback */
   1405    if (p12dcx->dOpen && ((*p12dcx->dOpen)(p12dcx->dArg, PR_TRUE) != SECSuccess)) {
   1406        goto loser;
   1407    }
   1408 
   1409    /* read the data back IN_BUF_LEN bytes at a time and recompute
   1410     * the hmac.  if fewer bytes are read than are requested, it is
   1411     * assumed that the end of file has been reached. if bytesRead
   1412     * is returned as -1, then an error occurred reading from the
   1413     * file.
   1414     */
   1415    do {
   1416        bytesRead = (*p12dcx->dRead)(p12dcx->dArg, buf, IN_BUF_LEN);
   1417        if (bytesRead < 0) {
   1418            PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_READ);
   1419            goto loser;
   1420        }
   1421        PORT_Assert(bytesRead <= IN_BUF_LEN);
   1422        PORT_Assert(!memcmp(buf + IN_BUF_LEN, bufferEnd, sizeof bufferEnd));
   1423 
   1424        if (bytesRead > IN_BUF_LEN) {
   1425            /* dRead callback overflowed buffer. */
   1426            PORT_SetError(SEC_ERROR_INPUT_LEN);
   1427            goto loser;
   1428        }
   1429 
   1430        if (bytesRead) {
   1431            lrv = PK11_DigestOp(pk11cx, buf, bytesRead);
   1432            if (lrv == SECFailure) {
   1433                goto loser;
   1434            }
   1435        }
   1436    } while (bytesRead == IN_BUF_LEN);
   1437 
   1438    /* finish the hmac context */
   1439    lrv = PK11_DigestFinal(pk11cx, buf, &bufLen, IN_BUF_LEN);
   1440    if (lrv == SECFailure) {
   1441        goto loser;
   1442    }
   1443 
   1444    hmacRes.data = buf;
   1445    hmacRes.len = bufLen;
   1446 
   1447    /* is the hmac computed the same as the hmac which was decoded? */
   1448    rv = SECSuccess;
   1449    if (SECITEM_CompareItem(&hmacRes, &p12dcx->macData.safeMac.digest) != SECEqual) {
   1450        PORT_SetError(SEC_ERROR_PKCS12_INVALID_MAC);
   1451        rv = SECFailure;
   1452    }
   1453 
   1454 loser:
   1455    /* close the file and remove it */
   1456    if (p12dcx->dClose) {
   1457        (*p12dcx->dClose)(p12dcx->dArg, PR_TRUE);
   1458        p12dcx->dIsOpen = PR_FALSE;
   1459    }
   1460 
   1461    if (pk11cx) {
   1462        PK11_DestroyContext(pk11cx, PR_TRUE);
   1463    }
   1464    if (symKey) {
   1465        PK11_FreeSymKey(symKey);
   1466    }
   1467    PORT_ZFree(buf, IN_BUF_LEN + FUDGE);
   1468 
   1469    return rv;
   1470 }
   1471 
   1472 /* SEC_PKCS12DecoderVerify
   1473 *      Verify the macData or the signature of the decoded PKCS 12 PDU.
   1474 *      If the signature or the macData do not match, SECFailure is
   1475 *      returned.
   1476 *
   1477 *      p12dcx - the decoder context
   1478 */
   1479 SECStatus
   1480 SEC_PKCS12DecoderVerify(SEC_PKCS12DecoderContext *p12dcx)
   1481 {
   1482    SECStatus rv = SECSuccess;
   1483 
   1484    /* make sure that no errors have occurred... */
   1485    if (!p12dcx) {
   1486        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1487        return SECFailure;
   1488    }
   1489    if (p12dcx->error) {
   1490        /* error code is already set! PORT_SetError(p12dcx->errorValue); */
   1491        return SECFailure;
   1492    }
   1493 
   1494    rv = SEC_ASN1DecoderFinish(p12dcx->pfxA1Dcx);
   1495    p12dcx->pfxA1Dcx = NULL;
   1496    if (rv != SECSuccess) {
   1497        return rv;
   1498    }
   1499 #ifdef UNSAFE_FUZZER_MODE
   1500    return sec_pkcs12_decoder_unsafe_parity_outcome(p12dcx);
   1501 #else  /* UNSAFE_FUZZER_MODE */
   1502    /* check the signature or the mac depending on the type of
   1503     * integrity used.
   1504     */
   1505    if (p12dcx->pfx.encodedMacData.len) {
   1506        rv = SEC_ASN1DecodeItem(p12dcx->arena, &p12dcx->macData,
   1507                                sec_PKCS12MacDataTemplate,
   1508                                &p12dcx->pfx.encodedMacData);
   1509        if (rv == SECSuccess) {
   1510            return sec_pkcs12_decoder_verify_mac(p12dcx);
   1511        }
   1512        return rv;
   1513    }
   1514    if (SEC_PKCS7VerifySignature(p12dcx->aSafeCinfo, certUsageEmailSigner,
   1515                                 PR_FALSE)) {
   1516        return SECSuccess;
   1517    }
   1518    PORT_SetError(SEC_ERROR_PKCS12_INVALID_MAC);
   1519    return SECFailure;
   1520 #endif /* UNSAFE_FUZZER_MODE */
   1521 }
   1522 
   1523 /* SEC_PKCS12DecoderFinish
   1524 *      Free any open ASN1 or PKCS7 decoder contexts and then
   1525 *      free the arena pool which everything should be allocated
   1526 *      from.  This function should be called upon completion of
   1527 *      decoding and installing of a pfx pdu.  This should be
   1528 *      called even if an error occurs.
   1529 *
   1530 *      p12dcx - the decoder context
   1531 */
   1532 void
   1533 SEC_PKCS12DecoderFinish(SEC_PKCS12DecoderContext *p12dcx)
   1534 {
   1535    unsigned int i;
   1536 
   1537    if (!p12dcx) {
   1538        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1539        return;
   1540    }
   1541 
   1542    if (p12dcx->pfxA1Dcx) {
   1543        SEC_ASN1DecoderFinish(p12dcx->pfxA1Dcx);
   1544        p12dcx->pfxA1Dcx = NULL;
   1545    }
   1546 
   1547    if (p12dcx->aSafeA1Dcx) {
   1548        SEC_ASN1DecoderFinish(p12dcx->aSafeA1Dcx);
   1549        p12dcx->aSafeA1Dcx = NULL;
   1550    }
   1551 
   1552    /* cleanup any old ASN1 decoder contexts */
   1553    for (i = 0; i < p12dcx->safeContentsCnt; ++i) {
   1554        sec_PKCS12SafeContentsContext *safeContentsCtx, *nested;
   1555        safeContentsCtx = p12dcx->safeContentsList[i];
   1556        if (safeContentsCtx) {
   1557            nested = safeContentsCtx->nestedSafeContentsCtx;
   1558            while (nested) {
   1559                if (nested->currentSafeBagA1Dcx) {
   1560                    SEC_ASN1DecoderFinish(nested->currentSafeBagA1Dcx);
   1561                    nested->currentSafeBagA1Dcx = NULL;
   1562                }
   1563                if (nested->safeContentsA1Dcx) {
   1564                    SEC_ASN1DecoderFinish(nested->safeContentsA1Dcx);
   1565                    nested->safeContentsA1Dcx = NULL;
   1566                }
   1567                nested = nested->nestedSafeContentsCtx;
   1568            }
   1569            if (safeContentsCtx->currentSafeBagA1Dcx) {
   1570                SEC_ASN1DecoderFinish(safeContentsCtx->currentSafeBagA1Dcx);
   1571                safeContentsCtx->currentSafeBagA1Dcx = NULL;
   1572            }
   1573            if (safeContentsCtx->safeContentsA1Dcx) {
   1574                SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsA1Dcx);
   1575                safeContentsCtx->safeContentsA1Dcx = NULL;
   1576            }
   1577        }
   1578    }
   1579 
   1580    if (p12dcx->currentASafeP7Dcx &&
   1581        p12dcx->currentASafeP7Dcx != p12dcx->aSafeP7Dcx) {
   1582        SEC_PKCS7ContentInfo *cinfo;
   1583        cinfo = SEC_PKCS7DecoderFinish(p12dcx->currentASafeP7Dcx);
   1584        if (cinfo) {
   1585            SEC_PKCS7DestroyContentInfo(cinfo); /* don't leak it */
   1586        }
   1587    }
   1588    p12dcx->currentASafeP7Dcx = NULL;
   1589 
   1590    if (p12dcx->aSafeP7Dcx) {
   1591        SEC_PKCS7ContentInfo *cinfo;
   1592        cinfo = SEC_PKCS7DecoderFinish(p12dcx->aSafeP7Dcx);
   1593        if (cinfo) {
   1594            SEC_PKCS7DestroyContentInfo(cinfo);
   1595        }
   1596        p12dcx->aSafeP7Dcx = NULL;
   1597    }
   1598 
   1599    if (p12dcx->aSafeCinfo) {
   1600        SEC_PKCS7DestroyContentInfo(p12dcx->aSafeCinfo);
   1601        p12dcx->aSafeCinfo = NULL;
   1602    }
   1603 
   1604    if (p12dcx->decitem.type != 0 && p12dcx->decitem.der != NULL) {
   1605        SECITEM_FreeItem(p12dcx->decitem.der, PR_TRUE);
   1606    }
   1607    if (p12dcx->decitem.friendlyName != NULL) {
   1608        SECITEM_FreeItem(p12dcx->decitem.friendlyName, PR_TRUE);
   1609    }
   1610 
   1611    if (p12dcx->slot) {
   1612        PK11_FreeSlot(p12dcx->slot);
   1613        p12dcx->slot = NULL;
   1614    }
   1615 
   1616    if (p12dcx->dIsOpen && p12dcx->dClose) {
   1617        (*p12dcx->dClose)(p12dcx->dArg, PR_TRUE);
   1618        p12dcx->dIsOpen = PR_FALSE;
   1619    }
   1620 
   1621    if (p12dcx->arena) {
   1622        PORT_FreeArena(p12dcx->arena, PR_TRUE);
   1623    }
   1624 }
   1625 
   1626 static SECStatus
   1627 sec_pkcs12_decoder_set_attribute_value(sec_PKCS12SafeBag *bag,
   1628                                       SECOidTag attributeType,
   1629                                       SECItem *attrValue)
   1630 {
   1631    int i = 0;
   1632    SECOidData *oid;
   1633 
   1634    if (!bag || !attrValue) {
   1635        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1636        return SECFailure;
   1637    }
   1638 
   1639    oid = SECOID_FindOIDByTag(attributeType);
   1640    if (!oid) {
   1641        return SECFailure;
   1642    }
   1643 
   1644    if (!bag->attribs) {
   1645        bag->attribs =
   1646            PORT_ArenaZNewArray(bag->arena, sec_PKCS12Attribute *, 2);
   1647    } else {
   1648        while (bag->attribs[i])
   1649            i++;
   1650        bag->attribs = PORT_ArenaGrowArray(bag->arena, bag->attribs,
   1651                                           sec_PKCS12Attribute *, i + 1, i + 2);
   1652    }
   1653 
   1654    if (!bag->attribs) {
   1655        return SECFailure;
   1656    }
   1657 
   1658    bag->attribs[i] = PORT_ArenaZNew(bag->arena, sec_PKCS12Attribute);
   1659    if (!bag->attribs[i]) {
   1660        return SECFailure;
   1661    }
   1662 
   1663    bag->attribs[i]->attrValue = PORT_ArenaZNewArray(bag->arena, SECItem *, 2);
   1664    if (!bag->attribs[i]->attrValue) {
   1665        return SECFailure;
   1666    }
   1667 
   1668    bag->attribs[i + 1] = NULL;
   1669    bag->attribs[i]->attrValue[0] = attrValue;
   1670    bag->attribs[i]->attrValue[1] = NULL;
   1671 
   1672    return SECITEM_CopyItem(bag->arena, &bag->attribs[i]->attrType, &oid->oid);
   1673 }
   1674 
   1675 static SECItem *
   1676 sec_pkcs12_get_attribute_value(sec_PKCS12SafeBag *bag,
   1677                               SECOidTag attributeType)
   1678 {
   1679    int i;
   1680 
   1681    if (!bag->attribs) {
   1682        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1683        return NULL;
   1684    }
   1685 
   1686    for (i = 0; bag->attribs[i] != NULL; i++) {
   1687        if (SECOID_FindOIDTag(&bag->attribs[i]->attrType) == attributeType) {
   1688            return bag->attribs[i]->attrValue[0];
   1689        }
   1690    }
   1691    return NULL;
   1692 }
   1693 
   1694 /* For now, this function will merely remove any ":"
   1695 * in the nickname which the PK11 functions may have
   1696 * placed there.  This will keep dual certs from appearing
   1697 * twice under "Your" certificates when imported onto smart
   1698 * cards.  Once with the name "Slot:Cert" and another with
   1699 * the nickname "Slot:Slot:Cert"
   1700 */
   1701 static void
   1702 sec_pkcs12_sanitize_nickname(PK11SlotInfo *slot, SECItem *nick)
   1703 {
   1704    char *nickname;
   1705    char *delimit;
   1706    int delimitlen;
   1707 
   1708    nickname = (char *)nick->data;
   1709    if ((delimit = PORT_Strchr(nickname, ':')) != NULL) {
   1710        char *slotName;
   1711        int slotNameLen;
   1712 
   1713        slotNameLen = delimit - nickname;
   1714        slotName = PORT_NewArray(char, (slotNameLen + 1));
   1715        PORT_Assert(slotName);
   1716        if (slotName == NULL) {
   1717            /* What else can we do?*/
   1718            return;
   1719        }
   1720        PORT_Memcpy(slotName, nickname, slotNameLen);
   1721        slotName[slotNameLen] = '\0';
   1722        if (PORT_Strcmp(PK11_GetTokenName(slot), slotName) == 0) {
   1723            delimitlen = PORT_Strlen(delimit + 1);
   1724            PORT_Memmove(nickname, delimit + 1, delimitlen + 1);
   1725            nick->len = delimitlen;
   1726        }
   1727        PORT_Free(slotName);
   1728    }
   1729 }
   1730 
   1731 static SECItem *
   1732 sec_pkcs12_get_nickname(sec_PKCS12SafeBag *bag)
   1733 {
   1734    SECItem *src, *dest;
   1735 
   1736    if (!bag) {
   1737        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1738        return NULL;
   1739    }
   1740 
   1741    src = sec_pkcs12_get_attribute_value(bag, SEC_OID_PKCS9_FRIENDLY_NAME);
   1742 
   1743    /* The return value src is 16-bit Unicode characters, in big-endian format.
   1744     * Check if it is NULL or empty name.
   1745     */
   1746    if (!src || !src->data || src->len < 2 || (!src->data[0] && !src->data[1])) {
   1747        return NULL;
   1748    }
   1749 
   1750    dest = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
   1751    if (!dest) {
   1752        goto loser;
   1753    }
   1754    if (!sec_pkcs12_convert_item_to_unicode(NULL, dest, src, PR_FALSE,
   1755                                            PR_FALSE, PR_FALSE)) {
   1756        goto loser;
   1757    }
   1758 
   1759    sec_pkcs12_sanitize_nickname(bag->slot, dest);
   1760 
   1761    return dest;
   1762 
   1763 loser:
   1764    if (dest) {
   1765        SECITEM_ZfreeItem(dest, PR_TRUE);
   1766    }
   1767 
   1768    bag->problem = PR_TRUE;
   1769    bag->error = PORT_GetError();
   1770    return NULL;
   1771 }
   1772 
   1773 static SECStatus
   1774 sec_pkcs12_set_nickname(sec_PKCS12SafeBag *bag, SECItem *name)
   1775 {
   1776    sec_PKCS12Attribute *attr = NULL;
   1777    SECOidData *oid = SECOID_FindOIDByTag(SEC_OID_PKCS9_FRIENDLY_NAME);
   1778 
   1779    if (!bag || !bag->arena || !name) {
   1780        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1781        return SECFailure;
   1782    }
   1783 
   1784    if (!bag->attribs) {
   1785        if (!oid) {
   1786            goto loser;
   1787        }
   1788 
   1789        bag->attribs =
   1790            PORT_ArenaZNewArray(bag->arena, sec_PKCS12Attribute *, 2);
   1791        if (!bag->attribs) {
   1792            goto loser;
   1793        }
   1794        bag->attribs[0] = PORT_ArenaZNew(bag->arena, sec_PKCS12Attribute);
   1795        if (!bag->attribs[0]) {
   1796            goto loser;
   1797        }
   1798        bag->attribs[1] = NULL;
   1799 
   1800        attr = bag->attribs[0];
   1801        if (SECITEM_CopyItem(bag->arena, &attr->attrType, &oid->oid) != SECSuccess) {
   1802            goto loser;
   1803        }
   1804    } else {
   1805        int i;
   1806        for (i = 0; bag->attribs[i]; i++) {
   1807            if (SECOID_FindOIDTag(&bag->attribs[i]->attrType) == SEC_OID_PKCS9_FRIENDLY_NAME) {
   1808                attr = bag->attribs[i];
   1809                break;
   1810            }
   1811        }
   1812        if (!attr) {
   1813            if (!oid) {
   1814                goto loser;
   1815            }
   1816            bag->attribs = PORT_ArenaGrowArray(bag->arena, bag->attribs,
   1817                                               sec_PKCS12Attribute *, i + 1, i + 2);
   1818            if (!bag->attribs) {
   1819                goto loser;
   1820            }
   1821            bag->attribs[i] = PORT_ArenaZNew(bag->arena, sec_PKCS12Attribute);
   1822            if (!bag->attribs[i]) {
   1823                goto loser;
   1824            }
   1825            bag->attribs[i + 1] = NULL;
   1826            attr = bag->attribs[i];
   1827            if (SECITEM_CopyItem(bag->arena, &attr->attrType, &oid->oid) != SECSuccess) {
   1828                goto loser;
   1829            }
   1830        }
   1831    }
   1832 
   1833    PORT_Assert(attr);
   1834    if (!attr->attrValue) {
   1835        attr->attrValue = PORT_ArenaZNewArray(bag->arena, SECItem *, 2);
   1836        if (!attr->attrValue) {
   1837            goto loser;
   1838        }
   1839        attr->attrValue[0] = PORT_ArenaZNew(bag->arena, SECItem);
   1840        if (!attr->attrValue[0]) {
   1841            goto loser;
   1842        }
   1843        attr->attrValue[1] = NULL;
   1844    }
   1845 
   1846    name->len = PORT_Strlen((char *)name->data);
   1847    if (!sec_pkcs12_convert_item_to_unicode(bag->arena, attr->attrValue[0],
   1848                                            name, PR_FALSE, PR_FALSE, PR_TRUE)) {
   1849        goto loser;
   1850    }
   1851 
   1852    return SECSuccess;
   1853 
   1854 loser:
   1855    bag->problem = PR_TRUE;
   1856    bag->error = PORT_GetError();
   1857    return SECFailure;
   1858 }
   1859 
   1860 static SECStatus
   1861 sec_pkcs12_get_key_info(sec_PKCS12SafeBag *key)
   1862 {
   1863    int i = 0;
   1864    SECKEYPrivateKeyInfo *pki = NULL;
   1865 
   1866    if (!key) {
   1867        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1868        return SECFailure;
   1869    }
   1870 
   1871    /* if the bag does *not* contain an unencrypted PrivateKeyInfo
   1872     * then we cannot convert the attributes.  We are propagating
   1873     * attributes within the PrivateKeyInfo to the SafeBag level.
   1874     */
   1875    if (SECOID_FindOIDTag(&(key->safeBagType)) !=
   1876        SEC_OID_PKCS12_V1_KEY_BAG_ID) {
   1877        return SECSuccess;
   1878    }
   1879 
   1880    pki = key->safeBagContent.pkcs8KeyBag;
   1881 
   1882    if (!pki || !pki->attributes) {
   1883        return SECSuccess;
   1884    }
   1885 
   1886    while (pki->attributes[i]) {
   1887        SECOidTag tag = SECOID_FindOIDTag(&pki->attributes[i]->attrType);
   1888 
   1889        if (tag == SEC_OID_PKCS9_LOCAL_KEY_ID ||
   1890            tag == SEC_OID_PKCS9_FRIENDLY_NAME) {
   1891            SECItem *attrValue = sec_pkcs12_get_attribute_value(key, tag);
   1892            if (!attrValue) {
   1893                if (sec_pkcs12_decoder_set_attribute_value(key, tag,
   1894                                                           pki->attributes[i]->attrValue[0]) != SECSuccess) {
   1895                    key->problem = PR_TRUE;
   1896                    key->error = PORT_GetError();
   1897                    return SECFailure;
   1898                }
   1899            }
   1900        }
   1901        i++;
   1902    }
   1903 
   1904    return SECSuccess;
   1905 }
   1906 
   1907 /* retrieve the nickname for the certificate bag.  first look
   1908 * in the cert bag, otherwise get it from the key.
   1909 */
   1910 static SECItem *
   1911 sec_pkcs12_get_nickname_for_cert(sec_PKCS12SafeBag *cert,
   1912                                 sec_PKCS12SafeBag *key)
   1913 {
   1914    SECItem *nickname;
   1915 
   1916    if (!cert) {
   1917        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1918        return NULL;
   1919    }
   1920 
   1921    nickname = sec_pkcs12_get_nickname(cert);
   1922    if (nickname) {
   1923        return nickname;
   1924    }
   1925 
   1926    if (key) {
   1927        nickname = sec_pkcs12_get_nickname(key);
   1928 
   1929        if (nickname && sec_pkcs12_set_nickname(cert, nickname) != SECSuccess) {
   1930            SECITEM_ZfreeItem(nickname, PR_TRUE);
   1931            return NULL;
   1932        }
   1933    }
   1934 
   1935    return nickname;
   1936 }
   1937 
   1938 /* set the nickname for the certificate */
   1939 static SECStatus
   1940 sec_pkcs12_set_nickname_for_cert(sec_PKCS12SafeBag *cert,
   1941                                 sec_PKCS12SafeBag *key,
   1942                                 SECItem *nickname)
   1943 {
   1944    if (!nickname || !cert) {
   1945        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1946        return SECFailure;
   1947    }
   1948 
   1949    if (sec_pkcs12_set_nickname(cert, nickname) != SECSuccess) {
   1950        return SECFailure;
   1951    }
   1952 
   1953    if (key) {
   1954        if (sec_pkcs12_set_nickname(key, nickname) != SECSuccess) {
   1955            cert->problem = PR_TRUE;
   1956            cert->error = key->error;
   1957            return SECFailure;
   1958        }
   1959    }
   1960 
   1961    return SECSuccess;
   1962 }
   1963 
   1964 /* retrieve the DER cert from the cert bag */
   1965 static SECItem *
   1966 sec_pkcs12_get_der_cert(sec_PKCS12SafeBag *cert)
   1967 {
   1968    if (!cert || !cert->safeBagContent.certBag) {
   1969        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1970        return NULL;
   1971    }
   1972 
   1973    if (SECOID_FindOIDTag(&cert->safeBagType) != SEC_OID_PKCS12_V1_CERT_BAG_ID) {
   1974        return NULL;
   1975    }
   1976 
   1977    /* only support X509 certs not SDSI */
   1978    if (SECOID_FindOIDTag(&cert->safeBagContent.certBag->bagID) != SEC_OID_PKCS9_X509_CERT) {
   1979        return NULL;
   1980    }
   1981 
   1982    return SECITEM_DupItem(&(cert->safeBagContent.certBag->value.x509Cert));
   1983 }
   1984 
   1985 struct certNickInfo {
   1986    PLArenaPool *arena;
   1987    unsigned int nNicks;
   1988    SECItem **nickList;
   1989    unsigned int error;
   1990 };
   1991 
   1992 /* callback for traversing certificates to gather the nicknames
   1993 * used in a particular traversal.  for instance, when using
   1994 * CERT_TraversePermCertsForSubject, gather the nicknames and
   1995 * store them in the certNickInfo for a particular DN.
   1996 *
   1997 * this handles the case where multiple nicknames are allowed
   1998 * for the same dn, which is not currently allowed, but may be
   1999 * in the future.
   2000 */
   2001 static SECStatus
   2002 gatherNicknames(CERTCertificate *cert, void *arg)
   2003 {
   2004    struct certNickInfo *nickArg = (struct certNickInfo *)arg;
   2005    SECItem tempNick;
   2006    unsigned int i;
   2007 
   2008    if (!cert || !nickArg || nickArg->error) {
   2009        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   2010        return SECFailure;
   2011    }
   2012 
   2013    if (!cert->nickname) {
   2014        return SECSuccess;
   2015    }
   2016 
   2017    tempNick.data = (unsigned char *)cert->nickname;
   2018    tempNick.len = PORT_Strlen(cert->nickname) + 1;
   2019    tempNick.type = siAsciiString;
   2020 
   2021    /* do we already have the nickname in the list? */
   2022    if (nickArg->nNicks > 0) {
   2023 
   2024        /* nicknames have been encountered, but there is no list -- bad */
   2025        if (!nickArg->nickList) {
   2026            nickArg->error = SEC_ERROR_INVALID_ARGS;
   2027            PORT_SetError(SEC_ERROR_INVALID_ARGS);
   2028            return SECFailure;
   2029        }
   2030 
   2031        for (i = 0; i < nickArg->nNicks; i++) {
   2032            if (SECITEM_CompareItem(nickArg->nickList[i], &tempNick) == SECEqual) {
   2033                return SECSuccess;
   2034            }
   2035        }
   2036    }
   2037 
   2038    /* add the nickname to the list */
   2039    nickArg->nickList = (nickArg->nNicks == 0)
   2040                            ? PORT_ArenaZNewArray(nickArg->arena, SECItem *, 2)
   2041                            : PORT_ArenaGrowArray(nickArg->arena, nickArg->nickList, SECItem *,
   2042                                                  nickArg->nNicks + 1, nickArg->nNicks + 2);
   2043 
   2044    if (!nickArg->nickList) {
   2045        nickArg->error = SEC_ERROR_NO_MEMORY;
   2046        return SECFailure;
   2047    }
   2048 
   2049    nickArg->nickList[nickArg->nNicks] =
   2050        PORT_ArenaZNew(nickArg->arena, SECItem);
   2051    if (!nickArg->nickList[nickArg->nNicks]) {
   2052        nickArg->error = PORT_GetError();
   2053        return SECFailure;
   2054    }
   2055 
   2056    if (SECITEM_CopyItem(nickArg->arena, nickArg->nickList[nickArg->nNicks],
   2057                         &tempNick) != SECSuccess) {
   2058        nickArg->error = PORT_GetError();
   2059        return SECFailure;
   2060    }
   2061 
   2062    nickArg->nNicks++;
   2063 
   2064    return SECSuccess;
   2065 }
   2066 
   2067 /* traverses the certs in the data base or in the token for the
   2068 * DN to see if any certs currently have a nickname set.
   2069 * If so, return it.
   2070 */
   2071 static SECItem *
   2072 sec_pkcs12_get_existing_nick_for_dn(sec_PKCS12SafeBag *cert)
   2073 {
   2074    struct certNickInfo *nickArg = NULL;
   2075    SECItem *derCert, *returnDn = NULL;
   2076    PLArenaPool *arena = NULL;
   2077    CERTCertificate *tempCert;
   2078 
   2079    if (!cert) {
   2080        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   2081        return NULL;
   2082    }
   2083 
   2084    derCert = sec_pkcs12_get_der_cert(cert);
   2085    if (!derCert) {
   2086        return NULL;
   2087    }
   2088 
   2089    tempCert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL);
   2090    if (!tempCert) {
   2091        returnDn = NULL;
   2092        goto loser;
   2093    }
   2094 
   2095    arena = PORT_NewArena(1024);
   2096    if (!arena) {
   2097        returnDn = NULL;
   2098        goto loser;
   2099    }
   2100    nickArg = PORT_ArenaZNew(arena, struct certNickInfo);
   2101    if (!nickArg) {
   2102        returnDn = NULL;
   2103        goto loser;
   2104    }
   2105    nickArg->error = 0;
   2106    nickArg->nNicks = 0;
   2107    nickArg->nickList = NULL;
   2108    nickArg->arena = arena;
   2109 
   2110    /* if the token is local, first traverse the cert database
   2111     * then traverse the token.
   2112     */
   2113    if (PK11_TraverseCertsForSubjectInSlot(tempCert, cert->slot, gatherNicknames,
   2114                                           (void *)nickArg) != SECSuccess) {
   2115        returnDn = NULL;
   2116        goto loser;
   2117    }
   2118 
   2119    if (nickArg->error) {
   2120        /* XXX do we want to set the error? */
   2121        returnDn = NULL;
   2122        goto loser;
   2123    }
   2124 
   2125    if (nickArg->nNicks == 0) {
   2126        returnDn = NULL;
   2127        goto loser;
   2128    }
   2129 
   2130    /* set it to the first name, for now.  handle multiple names? */
   2131    returnDn = SECITEM_DupItem(nickArg->nickList[0]);
   2132 
   2133 loser:
   2134    if (arena) {
   2135        PORT_FreeArena(arena, PR_TRUE);
   2136    }
   2137 
   2138    if (tempCert) {
   2139        CERT_DestroyCertificate(tempCert);
   2140    }
   2141 
   2142    if (derCert) {
   2143        SECITEM_FreeItem(derCert, PR_TRUE);
   2144    }
   2145 
   2146    return (returnDn);
   2147 }
   2148 
   2149 /* counts certificates found for a given traversal function */
   2150 static SECStatus
   2151 countCertificate(CERTCertificate *cert, void *arg)
   2152 {
   2153    unsigned int *nCerts = (unsigned int *)arg;
   2154 
   2155    if (!cert || !arg) {
   2156        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   2157        return SECFailure;
   2158    }
   2159 
   2160    (*nCerts)++;
   2161    return SECSuccess;
   2162 }
   2163 
   2164 static PRBool
   2165 sec_pkcs12_certs_for_nickname_exist(SECItem *nickname, PK11SlotInfo *slot)
   2166 {
   2167    unsigned int nCerts = 0;
   2168 
   2169    if (!nickname || !slot) {
   2170        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   2171        return PR_TRUE;
   2172    }
   2173 
   2174    /* we want to check the local database first if we are importing to it */
   2175    PK11_TraverseCertsForNicknameInSlot(nickname, slot, countCertificate,
   2176                                        (void *)&nCerts);
   2177    return (PRBool)(nCerts != 0);
   2178 }
   2179 
   2180 /* validate cert nickname such that there is a one-to-one relation
   2181 * between nicknames and dn's.  we want to enforce the case that the
   2182 * nickname is non-NULL and that there is only one nickname per DN.
   2183 *
   2184 * if there is a problem with a nickname or the nickname is not present,
   2185 * the user will be prompted for it.
   2186 */
   2187 static void
   2188 sec_pkcs12_validate_cert_nickname(sec_PKCS12SafeBag *cert,
   2189                                  sec_PKCS12SafeBag *key,
   2190                                  SEC_PKCS12NicknameCollisionCallback nicknameCb,
   2191                                  CERTCertificate *leafCert)
   2192 {
   2193    SECItem *certNickname, *existingDNNick;
   2194    PRBool setNickname = PR_FALSE, cancel = PR_FALSE;
   2195    SECItem *newNickname = NULL;
   2196 
   2197    if (!cert || !cert->hasKey) {
   2198        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   2199        return;
   2200    }
   2201 
   2202    if (!nicknameCb) {
   2203        cert->problem = PR_TRUE;
   2204        cert->error = SEC_ERROR_INVALID_ARGS;
   2205        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   2206        return;
   2207    }
   2208 
   2209    if (cert->hasKey && !key) {
   2210        cert->problem = PR_TRUE;
   2211        cert->error = SEC_ERROR_INVALID_ARGS;
   2212        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   2213        return;
   2214    }
   2215 
   2216    certNickname = sec_pkcs12_get_nickname_for_cert(cert, key);
   2217    existingDNNick = sec_pkcs12_get_existing_nick_for_dn(cert);
   2218 
   2219    /* nickname is already used w/ this dn, so it is safe to return */
   2220    if (certNickname && existingDNNick &&
   2221        SECITEM_CompareItem(certNickname, existingDNNick) == SECEqual) {
   2222        goto loser;
   2223    }
   2224 
   2225    /* nickname not set in pkcs 12 bags, but a nick is already used for
   2226     * this dn.  set the nicks in the p12 bags and finish.
   2227     */
   2228    if (existingDNNick) {
   2229        sec_pkcs12_set_nickname_for_cert(cert, key, existingDNNick);
   2230        goto loser;
   2231    }
   2232 
   2233    /* at this point, we have a certificate for which the DN is not located
   2234     * on the token.  the nickname specified may or may not be NULL.  if it
   2235     * is not null, we need to make sure that there are no other certificates
   2236     * with this nickname in the token for it to be valid.  this imposes a
   2237     * one to one relationship between DN and nickname.
   2238     *
   2239     * if the nickname is null, we need the user to enter a nickname for
   2240     * the certificate.
   2241     *
   2242     * once we have a nickname, we make sure that the nickname is unique
   2243     * for the DN.  if it is not, the user is reprompted to enter a new
   2244     * nickname.
   2245     *
   2246     * in order to exit this loop, the nickname entered is either unique
   2247     * or the user hits cancel and the certificate is not imported.
   2248     */
   2249    setNickname = PR_FALSE;
   2250    while (1) {
   2251        /* we will use the nickname so long as no other certs have the
   2252         * same nickname.  and the nickname is not NULL.
   2253         */
   2254        if (certNickname && certNickname->data &&
   2255            !sec_pkcs12_certs_for_nickname_exist(certNickname, cert->slot)) {
   2256            if (setNickname) {
   2257                sec_pkcs12_set_nickname_for_cert(cert, key, certNickname);
   2258            }
   2259            break;
   2260        }
   2261 
   2262        setNickname = PR_FALSE;
   2263        newNickname = (*nicknameCb)(certNickname, &cancel, leafCert);
   2264        if (cancel) {
   2265            cert->problem = PR_TRUE;
   2266            cert->error = SEC_ERROR_USER_CANCELLED;
   2267            break;
   2268        }
   2269 
   2270        if (!newNickname) {
   2271            cert->problem = PR_TRUE;
   2272            cert->error = PORT_GetError();
   2273            break;
   2274        }
   2275 
   2276        /* at this point we have a new nickname, if we have an existing
   2277         * certNickname, we need to free it and assign the new nickname
   2278         * to it to avoid a memory leak.  happy?
   2279         */
   2280        if (certNickname) {
   2281            SECITEM_ZfreeItem(certNickname, PR_TRUE);
   2282            certNickname = NULL;
   2283        }
   2284 
   2285        certNickname = newNickname;
   2286        setNickname = PR_TRUE;
   2287        /* go back and recheck the new nickname */
   2288    }
   2289 
   2290 loser:
   2291    if (certNickname) {
   2292        SECITEM_ZfreeItem(certNickname, PR_TRUE);
   2293    }
   2294 
   2295    if (existingDNNick) {
   2296        SECITEM_ZfreeItem(existingDNNick, PR_TRUE);
   2297    }
   2298 }
   2299 
   2300 static void
   2301 sec_pkcs12_validate_cert(sec_PKCS12SafeBag *cert,
   2302                         sec_PKCS12SafeBag *key,
   2303                         SEC_PKCS12NicknameCollisionCallback nicknameCb)
   2304 {
   2305    CERTCertificate *leafCert;
   2306 
   2307    if (!cert) {
   2308        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   2309        return;
   2310    }
   2311 
   2312    cert->validated = PR_TRUE;
   2313 
   2314    if (!nicknameCb) {
   2315        cert->noInstall = PR_TRUE;
   2316        cert->problem = PR_TRUE;
   2317        cert->error = SEC_ERROR_INVALID_ARGS;
   2318        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   2319        return;
   2320    }
   2321 
   2322    if (!cert->safeBagContent.certBag) {
   2323        cert->noInstall = PR_TRUE;
   2324        cert->problem = PR_TRUE;
   2325        cert->error = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;
   2326        return;
   2327    }
   2328 
   2329    cert->noInstall = PR_FALSE;
   2330    cert->unused = PR_FALSE;
   2331    cert->problem = PR_FALSE;
   2332    cert->error = 0;
   2333 
   2334    leafCert = CERT_DecodeDERCertificate(
   2335        &cert->safeBagContent.certBag->value.x509Cert, PR_FALSE, NULL);
   2336    if (!leafCert) {
   2337        cert->noInstall = PR_TRUE;
   2338        cert->problem = PR_TRUE;
   2339        cert->error = PORT_GetError();
   2340        return;
   2341    }
   2342 
   2343    sec_pkcs12_validate_cert_nickname(cert, key, nicknameCb, leafCert);
   2344 
   2345    CERT_DestroyCertificate(leafCert);
   2346 }
   2347 
   2348 static void
   2349 sec_pkcs12_validate_key_by_cert(sec_PKCS12SafeBag *cert, sec_PKCS12SafeBag *key,
   2350                                void *wincx)
   2351 {
   2352    CERTCertificate *leafCert;
   2353    SECKEYPrivateKey *privk;
   2354 
   2355    if (!key) {
   2356        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   2357        return;
   2358    }
   2359 
   2360    key->validated = PR_TRUE;
   2361 
   2362    if (!cert) {
   2363        key->problem = PR_TRUE;
   2364        key->noInstall = PR_TRUE;
   2365        key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
   2366        return;
   2367    }
   2368 
   2369    leafCert = CERT_DecodeDERCertificate(
   2370        &(cert->safeBagContent.certBag->value.x509Cert), PR_FALSE, NULL);
   2371    if (!leafCert) {
   2372        key->problem = PR_TRUE;
   2373        key->noInstall = PR_TRUE;
   2374        key->error = PORT_GetError();
   2375        return;
   2376    }
   2377 
   2378    privk = PK11_FindPrivateKeyFromCert(key->slot, leafCert, wincx);
   2379    if (!privk) {
   2380        privk = PK11_FindKeyByDERCert(key->slot, leafCert, wincx);
   2381    }
   2382 
   2383    if (privk) {
   2384        SECKEY_DestroyPrivateKey(privk);
   2385        key->noInstall = PR_TRUE;
   2386    }
   2387 
   2388    CERT_DestroyCertificate(leafCert);
   2389 }
   2390 
   2391 static SECStatus
   2392 sec_pkcs12_add_cert(sec_PKCS12SafeBag *cert, PRBool keyExists, void *wincx)
   2393 {
   2394    SECItem *derCert, *nickName;
   2395    char *nickData = NULL;
   2396    PRBool isIntermediateCA;
   2397    SECStatus rv;
   2398 
   2399    if (!cert) {
   2400        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   2401        return SECFailure;
   2402    }
   2403 
   2404    if (cert->problem || cert->noInstall || cert->installed) {
   2405        return SECSuccess;
   2406    }
   2407 
   2408    derCert = &cert->safeBagContent.certBag->value.x509Cert;
   2409 
   2410    PORT_Assert(!cert->problem && !cert->noInstall);
   2411 
   2412    nickName = sec_pkcs12_get_nickname(cert);
   2413    if (nickName) {
   2414        nickData = (char *)nickName->data;
   2415    }
   2416 
   2417    isIntermediateCA = CERT_IsCADERCert(derCert, NULL) &&
   2418                       !CERT_IsRootDERCert(derCert);
   2419 
   2420    if (keyExists) {
   2421        CERTCertificate *newCert;
   2422 
   2423        newCert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
   2424                                          derCert, NULL, PR_FALSE, PR_FALSE);
   2425        if (!newCert) {
   2426            if (nickName)
   2427                SECITEM_ZfreeItem(nickName, PR_TRUE);
   2428            cert->error = PORT_GetError();
   2429            cert->problem = PR_TRUE;
   2430            return SECFailure;
   2431        }
   2432 
   2433        rv = PK11_ImportCertForKeyToSlot(cert->slot, newCert, nickData,
   2434                                         PR_TRUE, wincx);
   2435        CERT_DestroyCertificate(newCert);
   2436    } else if ((cert->tokenCAs == SECPKCS12TargetTokenNoCAs) ||
   2437               ((cert->tokenCAs == SECPKCS12TargetTokenIntermediateCAs) &&
   2438                !isIntermediateCA)) {
   2439        SECItem *certList[2];
   2440        certList[0] = derCert;
   2441        certList[1] = NULL;
   2442 
   2443        rv = CERT_ImportCerts(CERT_GetDefaultCertDB(), certUsageUserCertImport,
   2444                              1, certList, NULL, PR_TRUE, PR_FALSE, nickData);
   2445    } else {
   2446        rv = PK11_ImportDERCert(cert->slot, derCert, CK_INVALID_HANDLE,
   2447                                nickData, PR_FALSE);
   2448    }
   2449    if (rv) {
   2450        cert->problem = 1;
   2451        cert->error = PORT_GetError();
   2452    }
   2453    cert->installed = PR_TRUE;
   2454    if (nickName)
   2455        SECITEM_ZfreeItem(nickName, PR_TRUE);
   2456    return rv;
   2457 }
   2458 
   2459 static const SECItem *
   2460 sec_pkcs12_get_public_value_and_type(const SECKEYPublicKey *pubKey,
   2461                                     KeyType *type);
   2462 
   2463 static SECStatus
   2464 sec_pkcs12_add_key(sec_PKCS12SafeBag *key, SECKEYPublicKey *pubKey,
   2465                   unsigned int keyUsage,
   2466                   SECItem *nickName, PRBool forceUnicode, void *wincx)
   2467 {
   2468    SECStatus rv;
   2469    const SECItem *publicValue = NULL;
   2470    KeyType keyType;
   2471 
   2472    /* We should always have values for "key" and "pubKey"
   2473       so they can be dereferenced later. */
   2474    if (!key || !pubKey) {
   2475        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   2476        return SECFailure;
   2477    }
   2478 
   2479    if (key->problem || key->noInstall) {
   2480        return SECSuccess;
   2481    }
   2482 
   2483    /* get the value and type from the public key */
   2484    publicValue = sec_pkcs12_get_public_value_and_type(pubKey, &keyType);
   2485    if (!publicValue) {
   2486        key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
   2487        key->problem = PR_TRUE;
   2488        return SECFailure;
   2489    }
   2490 
   2491    switch (SECOID_FindOIDTag(&key->safeBagType)) {
   2492        case SEC_OID_PKCS12_V1_KEY_BAG_ID:
   2493            rv = PK11_ImportPrivateKeyInfo(key->slot,
   2494                                           key->safeBagContent.pkcs8KeyBag,
   2495                                           nickName, publicValue, PR_TRUE, PR_TRUE,
   2496                                           keyUsage, wincx);
   2497            break;
   2498        case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID: {
   2499            SECItem pwitem = { 0 };
   2500            SECAlgorithmID *algid =
   2501                &key->safeBagContent.pkcs8ShroudedKeyBag->algorithm;
   2502            SECOidTag algorithm = SECOID_GetAlgorithmTag(algid);
   2503 
   2504            if (!SEC_PKCS12DecryptionAllowed(algid)) {
   2505                key->error = SEC_ERROR_BAD_EXPORT_ALGORITHM;
   2506                key->problem = PR_TRUE;
   2507                return SECFailure;
   2508            }
   2509 
   2510            if (forceUnicode) {
   2511                if (SECITEM_CopyItem(NULL, &pwitem, key->pwitem) != SECSuccess) {
   2512                    key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
   2513                    key->problem = PR_TRUE;
   2514                    return SECFailure;
   2515                }
   2516            } else {
   2517                if (!sec_pkcs12_decode_password(NULL, &pwitem, algorithm,
   2518                                                key->pwitem)) {
   2519                    key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
   2520                    key->problem = PR_TRUE;
   2521                    return SECFailure;
   2522                }
   2523            }
   2524 
   2525            rv = PK11_ImportEncryptedPrivateKeyInfo(key->slot,
   2526                                                    key->safeBagContent.pkcs8ShroudedKeyBag,
   2527                                                    &pwitem, nickName, publicValue,
   2528                                                    PR_TRUE, PR_TRUE, keyType, keyUsage,
   2529                                                    wincx);
   2530            if (pwitem.data) {
   2531                SECITEM_ZfreeItem(&pwitem, PR_FALSE);
   2532            }
   2533            break;
   2534        }
   2535        default:
   2536            key->error = SEC_ERROR_PKCS12_UNSUPPORTED_VERSION;
   2537            key->problem = PR_TRUE;
   2538            if (nickName) {
   2539                SECITEM_ZfreeItem(nickName, PR_TRUE);
   2540            }
   2541            return SECFailure;
   2542    }
   2543 
   2544    if (rv != SECSuccess) {
   2545        key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
   2546        key->problem = PR_TRUE;
   2547    } else {
   2548        /* try to import the public key. Failure to do so is not fatal,
   2549         * not all tokens can store the public key */
   2550        if (pubKey) {
   2551            PK11_ImportPublicKey(key->slot, pubKey, PR_TRUE);
   2552        }
   2553        key->installed = PR_TRUE;
   2554    }
   2555 
   2556    return rv;
   2557 }
   2558 
   2559 /*
   2560 * The correctness of the code in this file ABSOLUTELY REQUIRES
   2561 * that ALL BAGs share a single common arena.
   2562 *
   2563 * This function allocates the bag list from the arena of whatever bag
   2564 * happens to be passed to it.  Each time a new bag is handed to it,
   2565 * it grows (resizes) the arena of the bag that was handed to it.
   2566 * If the bags have different arenas, it will grow the wrong arena.
   2567 *
   2568 * Worse, if the bags had separate arenas, then while destroying the bags
   2569 * in a bag list, when the bag whose arena contained the bag list was
   2570 * destroyed, the baglist itself would be destroyed, making it difficult
   2571 * or impossible to continue to destroy the bags in the destroyed list.
   2572 */
   2573 static SECStatus
   2574 sec_pkcs12_add_item_to_bag_list(sec_PKCS12SafeBag ***bagList,
   2575                                sec_PKCS12SafeBag *bag)
   2576 {
   2577    sec_PKCS12SafeBag **newBagList = NULL;
   2578    int i = 0;
   2579 
   2580    if (!bagList || !bag) {
   2581        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   2582        return SECFailure;
   2583    }
   2584 
   2585    if (!(*bagList)) {
   2586        newBagList = PORT_ArenaZNewArray(bag->arena, sec_PKCS12SafeBag *, 2);
   2587    } else {
   2588        while ((*bagList)[i])
   2589            i++;
   2590        newBagList = PORT_ArenaGrowArray(bag->arena, *bagList,
   2591                                         sec_PKCS12SafeBag *, i + 1, i + 2);
   2592    }
   2593 
   2594    if (!newBagList) {
   2595        PORT_SetError(SEC_ERROR_NO_MEMORY);
   2596        return SECFailure;
   2597    }
   2598 
   2599    newBagList[i] = bag;
   2600    newBagList[i + 1] = NULL;
   2601    *bagList = newBagList;
   2602 
   2603    return SECSuccess;
   2604 }
   2605 
   2606 static sec_PKCS12SafeBag **
   2607 sec_pkcs12_find_certs_for_key(sec_PKCS12SafeBag **safeBags,
   2608                              sec_PKCS12SafeBag *key)
   2609 {
   2610    sec_PKCS12SafeBag **certList = NULL;
   2611    SECItem *keyId;
   2612    int i;
   2613 
   2614    if (!safeBags || !safeBags[0]) {
   2615        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   2616        return NULL;
   2617    }
   2618 
   2619    keyId = sec_pkcs12_get_attribute_value(key, SEC_OID_PKCS9_LOCAL_KEY_ID);
   2620    if (!keyId) {
   2621        return NULL;
   2622    }
   2623 
   2624    for (i = 0; safeBags[i]; i++) {
   2625        if (SECOID_FindOIDTag(&(safeBags[i]->safeBagType)) == SEC_OID_PKCS12_V1_CERT_BAG_ID) {
   2626            SECItem *certKeyId = sec_pkcs12_get_attribute_value(safeBags[i],
   2627                                                                SEC_OID_PKCS9_LOCAL_KEY_ID);
   2628 
   2629            if (certKeyId && (SECITEM_CompareItem(certKeyId, keyId) == SECEqual)) {
   2630                if (sec_pkcs12_add_item_to_bag_list(&certList, safeBags[i]) != SECSuccess) {
   2631                    /* This would leak the partial list of safeBags,
   2632                     * but that list is allocated from the arena of
   2633                     * one of the safebags, and will be destroyed when
   2634                     * that arena is destroyed.  So this is not a real leak.
   2635                     */
   2636                    return NULL;
   2637                }
   2638            }
   2639        }
   2640    }
   2641 
   2642    return certList;
   2643 }
   2644 
   2645 CERTCertList *
   2646 SEC_PKCS12DecoderGetCerts(SEC_PKCS12DecoderContext *p12dcx)
   2647 {
   2648    CERTCertList *certList = NULL;
   2649    sec_PKCS12SafeBag **safeBags;
   2650    int i;
   2651 
   2652    if (!p12dcx || !p12dcx->safeBags || !p12dcx->safeBags[0]) {
   2653        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   2654        return NULL;
   2655    }
   2656 
   2657    safeBags = p12dcx->safeBags;
   2658    certList = CERT_NewCertList();
   2659 
   2660    if (certList == NULL) {
   2661        return NULL;
   2662    }
   2663 
   2664    for (i = 0; safeBags[i]; i++) {
   2665        if (SECOID_FindOIDTag(&(safeBags[i]->safeBagType)) == SEC_OID_PKCS12_V1_CERT_BAG_ID) {
   2666            SECItem *derCert = sec_pkcs12_get_der_cert(safeBags[i]);
   2667            CERTCertificate *tempCert = NULL;
   2668 
   2669            if (derCert == NULL)
   2670                continue;
   2671            tempCert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
   2672                                               derCert, NULL,
   2673                                               PR_FALSE, PR_TRUE);
   2674 
   2675            if (tempCert) {
   2676                CERT_AddCertToListTail(certList, tempCert);
   2677            }
   2678            SECITEM_FreeItem(derCert, PR_TRUE);
   2679        }
   2680        /* fixed an infinite loop here, by ensuring that i gets incremented
   2681         * if derCert is NULL above.
   2682         */
   2683    }
   2684 
   2685    return certList;
   2686 }
   2687 static sec_PKCS12SafeBag **
   2688 sec_pkcs12_get_key_bags(sec_PKCS12SafeBag **safeBags)
   2689 {
   2690    int i;
   2691    sec_PKCS12SafeBag **keyList = NULL;
   2692    SECOidTag bagType;
   2693 
   2694    if (!safeBags || !safeBags[0]) {
   2695        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   2696        return NULL;
   2697    }
   2698 
   2699    for (i = 0; safeBags[i]; i++) {
   2700        bagType = SECOID_FindOIDTag(&(safeBags[i]->safeBagType));
   2701        switch (bagType) {
   2702            case SEC_OID_PKCS12_V1_KEY_BAG_ID:
   2703            case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
   2704                if (sec_pkcs12_add_item_to_bag_list(&keyList, safeBags[i]) != SECSuccess) {
   2705                    /* This would leak, except that keyList is allocated
   2706                     * from the arena shared by all the safeBags.
   2707                     */
   2708                    return NULL;
   2709                }
   2710                break;
   2711            default:
   2712                break;
   2713        }
   2714    }
   2715 
   2716    return keyList;
   2717 }
   2718 
   2719 /* This function takes two passes over the bags, validating them
   2720 * The two passes are intended to mirror exactly the two passes in
   2721 * sec_pkcs12_install_bags.  But they don't. :(
   2722 */
   2723 static SECStatus
   2724 sec_pkcs12_validate_bags(sec_PKCS12SafeBag **safeBags,
   2725                         SEC_PKCS12NicknameCollisionCallback nicknameCb,
   2726                         void *wincx)
   2727 {
   2728    sec_PKCS12SafeBag **keyList;
   2729    int i;
   2730 
   2731    if (!safeBags || !nicknameCb) {
   2732        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   2733        return SECFailure;
   2734    }
   2735 
   2736    if (!safeBags[0]) {
   2737        return SECSuccess;
   2738    }
   2739 
   2740    /* First pass.  Find all the key bags.
   2741     * Find the matching cert(s) for each key.
   2742     */
   2743    keyList = sec_pkcs12_get_key_bags(safeBags);
   2744    if (keyList) {
   2745        for (i = 0; keyList[i]; ++i) {
   2746            sec_PKCS12SafeBag *key = keyList[i];
   2747            sec_PKCS12SafeBag **certList =
   2748                sec_pkcs12_find_certs_for_key(safeBags, key);
   2749 
   2750            if (certList) {
   2751                int j;
   2752 
   2753                if (SECOID_FindOIDTag(&(key->safeBagType)) ==
   2754                    SEC_OID_PKCS12_V1_KEY_BAG_ID) {
   2755                    /* if it is an unencrypted private key then make sure
   2756                     * the attributes are propageted to the appropriate
   2757                     * level
   2758                     */
   2759                    if (sec_pkcs12_get_key_info(key) != SECSuccess) {
   2760                        return SECFailure;
   2761                    }
   2762                }
   2763 
   2764                sec_pkcs12_validate_key_by_cert(certList[0], key, wincx);
   2765                for (j = 0; certList[j]; ++j) {
   2766                    sec_PKCS12SafeBag *cert = certList[j];
   2767                    cert->hasKey = PR_TRUE;
   2768                    if (key->problem) {
   2769                        cert->problem = PR_TRUE;
   2770                        cert->error = key->error;
   2771                        continue;
   2772                    }
   2773                    sec_pkcs12_validate_cert(cert, key, nicknameCb);
   2774                    if (cert->problem) {
   2775                        key->problem = cert->problem;
   2776                        key->error = cert->error;
   2777                    }
   2778                }
   2779            }
   2780        }
   2781    }
   2782 
   2783    /* Now take a second pass over the safebags and mark for installation any
   2784     * certs that were neither installed nor disqualified by the first pass.
   2785     */
   2786    for (i = 0; safeBags[i]; ++i) {
   2787        sec_PKCS12SafeBag *bag = safeBags[i];
   2788 
   2789        if (!bag->validated) {
   2790            SECOidTag bagType = SECOID_FindOIDTag(&bag->safeBagType);
   2791 
   2792            switch (bagType) {
   2793                case SEC_OID_PKCS12_V1_CERT_BAG_ID:
   2794                    sec_pkcs12_validate_cert(bag, NULL, nicknameCb);
   2795                    break;
   2796                case SEC_OID_PKCS12_V1_KEY_BAG_ID:
   2797                case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
   2798                    bag->noInstall = PR_TRUE;
   2799                    bag->problem = PR_TRUE;
   2800                    bag->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
   2801                    break;
   2802                default:
   2803                    bag->noInstall = PR_TRUE;
   2804            }
   2805        }
   2806    }
   2807 
   2808    return SECSuccess;
   2809 }
   2810 
   2811 SECStatus
   2812 SEC_PKCS12DecoderValidateBags(SEC_PKCS12DecoderContext *p12dcx,
   2813                              SEC_PKCS12NicknameCollisionCallback nicknameCb)
   2814 {
   2815    SECStatus rv;
   2816    int i, probCnt, errorVal = 0;
   2817    if (!p12dcx || p12dcx->error || !p12dcx->safeBags) {
   2818        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   2819        return SECFailure;
   2820    }
   2821 
   2822    rv = sec_pkcs12_validate_bags(p12dcx->safeBags, nicknameCb, p12dcx->wincx);
   2823    if (rv == SECSuccess) {
   2824        p12dcx->bagsVerified = PR_TRUE;
   2825    }
   2826 
   2827    probCnt = 0;
   2828    i = 0;
   2829    while (p12dcx->safeBags[i]) {
   2830        if (p12dcx->safeBags[i]->problem) {
   2831            probCnt++;
   2832            errorVal = p12dcx->safeBags[i]->error;
   2833        }
   2834        i++;
   2835    }
   2836 
   2837    if (probCnt) {
   2838        PORT_SetError(errorVal);
   2839        return SECFailure;
   2840    }
   2841 
   2842    return rv;
   2843 }
   2844 
   2845 SECStatus
   2846 SEC_PKCS12DecoderRenameCertNicknames(SEC_PKCS12DecoderContext *p12dcx,
   2847                                     SEC_PKCS12NicknameRenameCallback nicknameCb,
   2848                                     void *arg)
   2849 {
   2850    int i;
   2851    sec_PKCS12SafeBag *safeBag;
   2852    CERTCertificate *cert;
   2853    SECStatus srv;
   2854 
   2855    if (!p12dcx || p12dcx->error || !p12dcx->safeBags || !nicknameCb) {
   2856        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   2857        return SECFailure;
   2858    }
   2859 
   2860    for (i = 0; (safeBag = p12dcx->safeBags[i]); i++) {
   2861        SECItem *newNickname = NULL;
   2862        SECItem *defaultNickname = NULL;
   2863        SECStatus rename_rv;
   2864 
   2865        if (SECOID_FindOIDTag(&(safeBag->safeBagType)) !=
   2866            SEC_OID_PKCS12_V1_CERT_BAG_ID) {
   2867            continue;
   2868        }
   2869 
   2870        cert = CERT_DecodeDERCertificate(
   2871            &safeBag->safeBagContent.certBag->value.x509Cert,
   2872            PR_FALSE, NULL);
   2873        if (!cert) {
   2874            return SECFailure;
   2875        }
   2876 
   2877        defaultNickname = sec_pkcs12_get_nickname(safeBag);
   2878        rename_rv = (*nicknameCb)(cert, defaultNickname, &newNickname, arg);
   2879 
   2880        CERT_DestroyCertificate(cert);
   2881 
   2882        if (defaultNickname) {
   2883            SECITEM_ZfreeItem(defaultNickname, PR_TRUE);
   2884            defaultNickname = NULL;
   2885        }
   2886 
   2887        if (rename_rv != SECSuccess) {
   2888            return rename_rv;
   2889        }
   2890 
   2891        if (newNickname) {
   2892            srv = sec_pkcs12_set_nickname(safeBag, newNickname);
   2893            SECITEM_ZfreeItem(newNickname, PR_TRUE);
   2894            newNickname = NULL;
   2895            if (srv != SECSuccess) {
   2896                return SECFailure;
   2897            }
   2898        }
   2899    }
   2900 
   2901    return SECSuccess;
   2902 }
   2903 
   2904 static SECKEYPublicKey *
   2905 sec_pkcs12_get_public_key_and_usage(sec_PKCS12SafeBag *certBag,
   2906                                    unsigned int *usage)
   2907 {
   2908    SECKEYPublicKey *pubKey = NULL;
   2909    CERTCertificate *cert = NULL;
   2910 
   2911    if (!certBag || !usage) {
   2912        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   2913        return NULL;
   2914    }
   2915 
   2916    *usage = 0;
   2917 
   2918    cert = CERT_DecodeDERCertificate(
   2919        &certBag->safeBagContent.certBag->value.x509Cert, PR_FALSE, NULL);
   2920    if (!cert) {
   2921        return NULL;
   2922    }
   2923 
   2924    *usage = cert->keyUsage;
   2925    pubKey = CERT_ExtractPublicKey(cert);
   2926    CERT_DestroyCertificate(cert);
   2927    return pubKey;
   2928 }
   2929 
   2930 static const SECItem *
   2931 sec_pkcs12_get_public_value_and_type(const SECKEYPublicKey *pubKey,
   2932                                     KeyType *type)
   2933 {
   2934 
   2935    if (!type || !pubKey) {
   2936        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   2937        return NULL;
   2938    }
   2939 
   2940    *type = pubKey->keyType;
   2941    return PK11_GetPublicValueFromPublicKey(pubKey);
   2942 }
   2943 
   2944 /* This function takes two passes over the bags, installing them in the
   2945 * desired slot.  The two passes are intended to mirror exactly the
   2946 * two passes in sec_pkcs12_validate_bags.
   2947 */
   2948 static SECStatus
   2949 sec_pkcs12_install_bags(sec_PKCS12SafeBag **safeBags, PRBool forceUnicode,
   2950                        void *wincx)
   2951 {
   2952    sec_PKCS12SafeBag **keyList;
   2953    int i;
   2954    int failedKeys = 0;
   2955 
   2956    if (!safeBags) {
   2957        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   2958        return SECFailure;
   2959    }
   2960 
   2961    if (!safeBags[0]) {
   2962        return SECSuccess;
   2963    }
   2964 
   2965    /* First pass.  Find all the key bags.
   2966     * Try to install them, and any certs associated with them.
   2967     */
   2968    keyList = sec_pkcs12_get_key_bags(safeBags);
   2969    if (keyList) {
   2970        for (i = 0; keyList[i]; i++) {
   2971            SECStatus rv;
   2972            SECKEYPublicKey *pubKey = NULL;
   2973            SECItem *nickName = NULL;
   2974            sec_PKCS12SafeBag *key = keyList[i];
   2975            sec_PKCS12SafeBag **certList;
   2976            unsigned int keyUsage;
   2977 
   2978            if (key->problem) {
   2979                ++failedKeys;
   2980                continue;
   2981            }
   2982 
   2983            certList = sec_pkcs12_find_certs_for_key(safeBags, key);
   2984            if (certList && certList[0]) {
   2985                pubKey = sec_pkcs12_get_public_key_and_usage(certList[0],
   2986                                                             &keyUsage);
   2987                /* use the cert's nickname, if it has one, else use the
   2988                 * key's nickname, else fail.
   2989                 */
   2990                nickName = sec_pkcs12_get_nickname_for_cert(certList[0], key);
   2991            } else {
   2992                nickName = sec_pkcs12_get_nickname(key);
   2993            }
   2994            if (!nickName) {
   2995                key->error = SEC_ERROR_BAD_NICKNAME;
   2996                key->problem = PR_TRUE;
   2997                rv = SECFailure;
   2998            } else if (!pubKey) {
   2999                key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;
   3000                key->problem = PR_TRUE;
   3001                rv = SECFailure;
   3002            } else {
   3003                rv = sec_pkcs12_add_key(key, pubKey, keyUsage, nickName,
   3004                                        forceUnicode, wincx);
   3005            }
   3006            if (pubKey) {
   3007                SECKEY_DestroyPublicKey(pubKey);
   3008                pubKey = NULL;
   3009            }
   3010            if (nickName) {
   3011                SECITEM_FreeItem(nickName, PR_TRUE);
   3012                nickName = NULL;
   3013            }
   3014            if (rv != SECSuccess) {
   3015                PORT_SetError(key->error);
   3016                ++failedKeys;
   3017            }
   3018 
   3019            if (certList) {
   3020                int j;
   3021 
   3022                for (j = 0; certList[j]; j++) {
   3023                    sec_PKCS12SafeBag *cert = certList[j];
   3024                    SECStatus certRv;
   3025 
   3026                    if (!cert)
   3027                        continue;
   3028                    if (rv != SECSuccess) {
   3029                        cert->problem = key->problem;
   3030                        cert->error = key->error;
   3031                        cert->noInstall = PR_TRUE;
   3032                        continue;
   3033                    }
   3034 
   3035                    certRv = sec_pkcs12_add_cert(cert, cert->hasKey, wincx);
   3036                    if (certRv != SECSuccess) {
   3037                        key->problem = cert->problem;
   3038                        key->error = cert->error;
   3039                        PORT_SetError(cert->error);
   3040                        return SECFailure;
   3041                    }
   3042                }
   3043            }
   3044        }
   3045    }
   3046    if (failedKeys)
   3047        return SECFailure;
   3048 
   3049    /* Now take a second pass over the safebags and install any certs
   3050     * that were neither installed nor disqualified by the first pass.
   3051     */
   3052    for (i = 0; safeBags[i]; i++) {
   3053        sec_PKCS12SafeBag *bag = safeBags[i];
   3054 
   3055        if (!bag->installed && !bag->problem && !bag->noInstall) {
   3056            SECStatus rv;
   3057            SECOidTag bagType = SECOID_FindOIDTag(&(bag->safeBagType));
   3058 
   3059            switch (bagType) {
   3060                case SEC_OID_PKCS12_V1_CERT_BAG_ID:
   3061                    rv = sec_pkcs12_add_cert(bag, bag->hasKey, wincx);
   3062                    if (rv != SECSuccess) {
   3063                        PORT_SetError(bag->error);
   3064                        return SECFailure;
   3065                    }
   3066                    break;
   3067                case SEC_OID_PKCS12_V1_KEY_BAG_ID:
   3068                case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
   3069                default:
   3070                    break;
   3071            }
   3072        }
   3073    }
   3074 
   3075    return SECSuccess;
   3076 }
   3077 
   3078 SECStatus
   3079 SEC_PKCS12DecoderImportBags(SEC_PKCS12DecoderContext *p12dcx)
   3080 {
   3081    PRBool forceUnicode = PR_FALSE;
   3082    SECStatus rv;
   3083 
   3084    if (!p12dcx || p12dcx->error) {
   3085        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   3086        return SECFailure;
   3087    }
   3088 
   3089    if (!p12dcx->bagsVerified) {
   3090        return SECFailure;
   3091    }
   3092 
   3093    /* We need to check the option here as well as in
   3094     * SEC_PKCS12DecoderStart, because different PBE's could be used
   3095     * for PKCS #7 and PKCS #8 */
   3096    rv = NSS_OptionGet(__NSS_PKCS12_DECODE_FORCE_UNICODE, &forceUnicode);
   3097    if (rv != SECSuccess) {
   3098        return SECFailure;
   3099    }
   3100 
   3101    return sec_pkcs12_install_bags(p12dcx->safeBags, forceUnicode,
   3102                                   p12dcx->wincx);
   3103 }
   3104 
   3105 PRBool
   3106 sec_pkcs12_bagHasKey(SEC_PKCS12DecoderContext *p12dcx, sec_PKCS12SafeBag *bag)
   3107 {
   3108    int i;
   3109    SECItem *keyId;
   3110    SECItem *certKeyId;
   3111 
   3112    certKeyId = sec_pkcs12_get_attribute_value(bag, SEC_OID_PKCS9_LOCAL_KEY_ID);
   3113    if (certKeyId == NULL) {
   3114        return PR_FALSE;
   3115    }
   3116 
   3117    for (i = 0; p12dcx->keyList && p12dcx->keyList[i]; i++) {
   3118        keyId = sec_pkcs12_get_attribute_value(p12dcx->keyList[i],
   3119                                               SEC_OID_PKCS9_LOCAL_KEY_ID);
   3120        if (!keyId) {
   3121            continue;
   3122        }
   3123        if (SECITEM_CompareItem(certKeyId, keyId) == SECEqual) {
   3124            return PR_TRUE;
   3125        }
   3126    }
   3127    return PR_FALSE;
   3128 }
   3129 
   3130 SECItem *
   3131 sec_pkcs12_get_friendlyName(sec_PKCS12SafeBag *bag)
   3132 {
   3133    SECItem *friendlyName;
   3134    SECItem *tempnm;
   3135 
   3136    tempnm = sec_pkcs12_get_attribute_value(bag, SEC_OID_PKCS9_FRIENDLY_NAME);
   3137    friendlyName = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
   3138    if (friendlyName) {
   3139        if (!sec_pkcs12_convert_item_to_unicode(NULL, friendlyName,
   3140                                                tempnm, PR_TRUE, PR_FALSE, PR_FALSE)) {
   3141            SECITEM_FreeItem(friendlyName, PR_TRUE);
   3142            friendlyName = NULL;
   3143        }
   3144    }
   3145    return friendlyName;
   3146 }
   3147 
   3148 /* Following two functions provide access to selected portions of the safe bags.
   3149 * Iteration is implemented per decoder context and may be accessed after
   3150 * SEC_PKCS12DecoderVerify() returns success.
   3151 * When ...DecoderIterateNext() returns SUCCESS a decoder item has been returned
   3152 * where item.type is always set; item.friendlyName is set if it is non-null;
   3153 * item.der, item.hasKey are set only for SEC_OID_PKCS12_V1_CERT_BAG_ID items.
   3154 * ...DecoderIterateNext() returns FAILURE when the list is exhausted or when
   3155 * arguments are invalid; PORT_GetError() is 0 at end-of-list.
   3156 * Caller has read-only access to decoder items. Any SECItems generated are
   3157 * owned by the decoder context and are freed by ...DecoderFinish().
   3158 */
   3159 SECStatus
   3160 SEC_PKCS12DecoderIterateInit(SEC_PKCS12DecoderContext *p12dcx)
   3161 {
   3162    if (!p12dcx || p12dcx->error) {
   3163        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   3164        return SECFailure;
   3165    }
   3166 
   3167    p12dcx->iteration = 0;
   3168    return SECSuccess;
   3169 }
   3170 
   3171 SECStatus
   3172 SEC_PKCS12DecoderIterateNext(SEC_PKCS12DecoderContext *p12dcx,
   3173                             const SEC_PKCS12DecoderItem **ipp)
   3174 {
   3175    sec_PKCS12SafeBag *bag;
   3176 
   3177    if (!p12dcx || p12dcx->error) {
   3178        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   3179        return SECFailure;
   3180    }
   3181 
   3182    if (p12dcx->decitem.type != 0 && p12dcx->decitem.der != NULL) {
   3183        SECITEM_FreeItem(p12dcx->decitem.der, PR_TRUE);
   3184    }
   3185    if (p12dcx->decitem.shroudAlg != NULL) {
   3186        SECOID_DestroyAlgorithmID(p12dcx->decitem.shroudAlg, PR_TRUE);
   3187    }
   3188    if (p12dcx->decitem.friendlyName != NULL) {
   3189        SECITEM_FreeItem(p12dcx->decitem.friendlyName, PR_TRUE);
   3190    }
   3191    p12dcx->decitem.type = 0;
   3192    p12dcx->decitem.der = NULL;
   3193    p12dcx->decitem.shroudAlg = NULL;
   3194    p12dcx->decitem.friendlyName = NULL;
   3195    p12dcx->decitem.hasKey = PR_FALSE;
   3196    *ipp = NULL;
   3197    if (p12dcx->keyList == NULL) {
   3198        p12dcx->keyList = sec_pkcs12_get_key_bags(p12dcx->safeBags);
   3199    }
   3200 
   3201    for (; p12dcx->iteration < p12dcx->safeBagCount; p12dcx->iteration++) {
   3202        bag = p12dcx->safeBags[p12dcx->iteration];
   3203        if (bag == NULL || bag->problem) {
   3204            continue;
   3205        }
   3206        p12dcx->decitem.type = SECOID_FindOIDTag(&(bag->safeBagType));
   3207        switch (p12dcx->decitem.type) {
   3208            case SEC_OID_PKCS12_V1_CERT_BAG_ID:
   3209                p12dcx->decitem.der = sec_pkcs12_get_der_cert(bag);
   3210                p12dcx->decitem.friendlyName = sec_pkcs12_get_friendlyName(bag);
   3211                p12dcx->decitem.hasKey = sec_pkcs12_bagHasKey(p12dcx, bag);
   3212                /* if we don't understand the cert, or it's not parsable, skip it */
   3213                /* as per the comment above, friendlyName may be null legitimately */
   3214                if (!p12dcx->decitem.der) {
   3215                    p12dcx->decitem.type = 0; /* clear out the type we are ignoring */
   3216                    continue;
   3217                }
   3218                break;
   3219            case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
   3220                p12dcx->decitem.shroudAlg = PORT_ZNew(SECAlgorithmID);
   3221                if (p12dcx->decitem.shroudAlg) {
   3222                    SECOID_CopyAlgorithmID(NULL, p12dcx->decitem.shroudAlg,
   3223                                           &bag->safeBagContent.pkcs8ShroudedKeyBag->algorithm);
   3224                }
   3225            /* fall through */
   3226            case SEC_OID_PKCS12_V1_KEY_BAG_ID:
   3227                p12dcx->decitem.friendlyName = sec_pkcs12_get_friendlyName(bag);
   3228                break;
   3229            default:
   3230                /* return these even though we don't expect them */
   3231                break;
   3232            case SEC_OID_UNKNOWN:
   3233                /* ignore these */
   3234                p12dcx->decitem.type = 0; /* clear out the type we are ignoring */
   3235                continue;
   3236        }
   3237        *ipp = &p12dcx->decitem;
   3238        p12dcx->iteration++;
   3239        break; /* end for() */
   3240    }
   3241 
   3242    PORT_SetError(0); /* end-of-list is SECFailure with no PORT error */
   3243    return ((p12dcx->decitem.type == 0) ? SECFailure : SECSuccess);
   3244 }
   3245 
   3246 static SECStatus
   3247 sec_pkcs12_decoder_append_bag_to_context(SEC_PKCS12DecoderContext *p12dcx,
   3248                                         sec_PKCS12SafeBag *bag)
   3249 {
   3250    if (!p12dcx || p12dcx->error) {
   3251        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   3252        return SECFailure;
   3253    }
   3254 
   3255    p12dcx->safeBags = !p12dcx->safeBagCount
   3256                           ? PORT_ArenaZNewArray(p12dcx->arena, sec_PKCS12SafeBag *, 2)
   3257                           : PORT_ArenaGrowArray(p12dcx->arena, p12dcx->safeBags,
   3258                                                 sec_PKCS12SafeBag *, p12dcx->safeBagCount + 1,
   3259                                                 p12dcx->safeBagCount + 2);
   3260 
   3261    if (!p12dcx->safeBags) {
   3262        PORT_SetError(SEC_ERROR_NO_MEMORY);
   3263        return SECFailure;
   3264    }
   3265 
   3266    p12dcx->safeBags[p12dcx->safeBagCount] = bag;
   3267    p12dcx->safeBags[p12dcx->safeBagCount + 1] = NULL;
   3268    p12dcx->safeBagCount++;
   3269 
   3270    return SECSuccess;
   3271 }
   3272 
   3273 static sec_PKCS12SafeBag *
   3274 sec_pkcs12_decoder_convert_old_key(SEC_PKCS12DecoderContext *p12dcx,
   3275                                   void *key, PRBool isEspvk)
   3276 {
   3277    sec_PKCS12SafeBag *keyBag;
   3278    SECOidData *oid;
   3279    SECOidTag keyTag;
   3280    SECItem *keyID, *nickName, *newNickName;
   3281 
   3282    if (!p12dcx || p12dcx->error || !key) {
   3283        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   3284        return NULL;
   3285    }
   3286 
   3287    newNickName = PORT_ArenaZNew(p12dcx->arena, SECItem);
   3288    keyBag = PORT_ArenaZNew(p12dcx->arena, sec_PKCS12SafeBag);
   3289    if (!keyBag || !newNickName) {
   3290        return NULL;
   3291    }
   3292 
   3293    keyBag->swapUnicodeBytes = p12dcx->swapUnicodeBytes;
   3294    keyBag->slot = p12dcx->slot;
   3295    keyBag->arena = p12dcx->arena;
   3296    keyBag->pwitem = p12dcx->pwitem;
   3297    keyBag->tokenCAs = p12dcx->tokenCAs;
   3298    keyBag->oldBagType = PR_TRUE;
   3299 
   3300    keyTag = (isEspvk) ? SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID : SEC_OID_PKCS12_V1_KEY_BAG_ID;
   3301    oid = SECOID_FindOIDByTag(keyTag);
   3302    if (!oid) {
   3303        return NULL;
   3304    }
   3305 
   3306    if (SECITEM_CopyItem(p12dcx->arena, &keyBag->safeBagType, &oid->oid) != SECSuccess) {
   3307        return NULL;
   3308    }
   3309 
   3310    if (isEspvk) {
   3311        SEC_PKCS12ESPVKItem *espvk = (SEC_PKCS12ESPVKItem *)key;
   3312        keyBag->safeBagContent.pkcs8ShroudedKeyBag =
   3313            espvk->espvkCipherText.pkcs8KeyShroud;
   3314        nickName = &(espvk->espvkData.uniNickName);
   3315        if (!espvk->espvkData.assocCerts || !espvk->espvkData.assocCerts[0]) {
   3316            PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE);
   3317            return NULL;
   3318        }
   3319        keyID = &espvk->espvkData.assocCerts[0]->digest;
   3320    } else {
   3321        SEC_PKCS12PrivateKey *pk = (SEC_PKCS12PrivateKey *)key;
   3322        keyBag->safeBagContent.pkcs8KeyBag = &pk->pkcs8data;
   3323        nickName = &(pk->pvkData.uniNickName);
   3324        if (!pk->pvkData.assocCerts || !pk->pvkData.assocCerts[0]) {
   3325            PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE);
   3326            return NULL;
   3327        }
   3328        keyID = &pk->pvkData.assocCerts[0]->digest;
   3329    }
   3330 
   3331    if (nickName->len) {
   3332        if (nickName->len >= 2) {
   3333            if (nickName->data[0] && nickName->data[1]) {
   3334                if (!sec_pkcs12_convert_item_to_unicode(p12dcx->arena, newNickName,
   3335                                                        nickName, PR_FALSE, PR_FALSE, PR_TRUE)) {
   3336                    return NULL;
   3337                }
   3338                nickName = newNickName;
   3339            } else if (nickName->data[0] && !nickName->data[1]) {
   3340                unsigned int j = 0;
   3341                unsigned char t;
   3342                for (j = 0; j < nickName->len; j += 2) {
   3343                    t = nickName->data[j + 1];
   3344                    nickName->data[j + 1] = nickName->data[j];
   3345                    nickName->data[j] = t;
   3346                }
   3347            }
   3348        } else {
   3349            if (!sec_pkcs12_convert_item_to_unicode(p12dcx->arena, newNickName,
   3350                                                    nickName, PR_FALSE, PR_FALSE, PR_TRUE)) {
   3351                return NULL;
   3352            }
   3353            nickName = newNickName;
   3354        }
   3355    }
   3356 
   3357    if (sec_pkcs12_decoder_set_attribute_value(keyBag,
   3358                                               SEC_OID_PKCS9_FRIENDLY_NAME,
   3359                                               nickName) != SECSuccess) {
   3360        return NULL;
   3361    }
   3362 
   3363    if (sec_pkcs12_decoder_set_attribute_value(keyBag, SEC_OID_PKCS9_LOCAL_KEY_ID,
   3364                                               keyID) != SECSuccess) {
   3365        return NULL;
   3366    }
   3367 
   3368    return keyBag;
   3369 }
   3370 
   3371 static sec_PKCS12SafeBag *
   3372 sec_pkcs12_decoder_create_cert(SEC_PKCS12DecoderContext *p12dcx,
   3373                               SECItem *derCert)
   3374 {
   3375    sec_PKCS12SafeBag *certBag;
   3376    SECOidData *oid;
   3377    SGNDigestInfo *digest;
   3378    SECItem *keyId;
   3379    SECStatus rv;
   3380 
   3381    if (!p12dcx || p12dcx->error || !derCert) {
   3382        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   3383        return NULL;
   3384    }
   3385 
   3386    keyId = PORT_ArenaZNew(p12dcx->arena, SECItem);
   3387    if (!keyId) {
   3388        return NULL;
   3389    }
   3390 
   3391    digest = sec_pkcs12_compute_thumbprint(derCert);
   3392    if (!digest) {
   3393        return NULL;
   3394    }
   3395 
   3396    rv = SECITEM_CopyItem(p12dcx->arena, keyId, &digest->digest);
   3397    SGN_DestroyDigestInfo(digest);
   3398    if (rv != SECSuccess) {
   3399        PORT_SetError(SEC_ERROR_NO_MEMORY);
   3400        return NULL;
   3401    }
   3402 
   3403    oid = SECOID_FindOIDByTag(SEC_OID_PKCS12_V1_CERT_BAG_ID);
   3404    certBag = PORT_ArenaZNew(p12dcx->arena, sec_PKCS12SafeBag);
   3405    if (!certBag || !oid || (SECITEM_CopyItem(p12dcx->arena, &certBag->safeBagType, &oid->oid) != SECSuccess)) {
   3406        return NULL;
   3407    }
   3408 
   3409    certBag->slot = p12dcx->slot;
   3410    certBag->pwitem = p12dcx->pwitem;
   3411    certBag->swapUnicodeBytes = p12dcx->swapUnicodeBytes;
   3412    certBag->arena = p12dcx->arena;
   3413    certBag->tokenCAs = p12dcx->tokenCAs;
   3414 
   3415    oid = SECOID_FindOIDByTag(SEC_OID_PKCS9_X509_CERT);
   3416    certBag->safeBagContent.certBag =
   3417        PORT_ArenaZNew(p12dcx->arena, sec_PKCS12CertBag);
   3418    if (!certBag->safeBagContent.certBag || !oid ||
   3419        (SECITEM_CopyItem(p12dcx->arena,
   3420                          &certBag->safeBagContent.certBag->bagID,
   3421                          &oid->oid) != SECSuccess)) {
   3422        return NULL;
   3423    }
   3424 
   3425    if (SECITEM_CopyItem(p12dcx->arena,
   3426                         &(certBag->safeBagContent.certBag->value.x509Cert),
   3427                         derCert) != SECSuccess) {
   3428        return NULL;
   3429    }
   3430 
   3431    if (sec_pkcs12_decoder_set_attribute_value(certBag, SEC_OID_PKCS9_LOCAL_KEY_ID,
   3432                                               keyId) != SECSuccess) {
   3433        return NULL;
   3434    }
   3435 
   3436    return certBag;
   3437 }
   3438 
   3439 static sec_PKCS12SafeBag **
   3440 sec_pkcs12_decoder_convert_old_cert(SEC_PKCS12DecoderContext *p12dcx,
   3441                                    SEC_PKCS12CertAndCRL *oldCert)
   3442 {
   3443    sec_PKCS12SafeBag **certList;
   3444    SECItem **derCertList;
   3445    int i, j;
   3446 
   3447    if (!p12dcx || p12dcx->error || !oldCert) {
   3448        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   3449        return NULL;
   3450    }
   3451 
   3452    derCertList = SEC_PKCS7GetCertificateList(&oldCert->value.x509->certOrCRL);
   3453    if (!derCertList) {
   3454        return NULL;
   3455    }
   3456 
   3457    i = 0;
   3458    while (derCertList[i])
   3459        i++;
   3460 
   3461    certList = PORT_ArenaZNewArray(p12dcx->arena, sec_PKCS12SafeBag *, (i + 1));
   3462    if (!certList) {
   3463        return NULL;
   3464    }
   3465 
   3466    for (j = 0; j < i; j++) {
   3467        certList[j] = sec_pkcs12_decoder_create_cert(p12dcx, derCertList[j]);
   3468        if (!certList[j]) {
   3469            return NULL;
   3470        }
   3471    }
   3472 
   3473    return certList;
   3474 }
   3475 
   3476 static SECStatus
   3477 sec_pkcs12_decoder_convert_old_key_and_certs(SEC_PKCS12DecoderContext *p12dcx,
   3478                                             void *oldKey, PRBool isEspvk,
   3479                                             SEC_PKCS12SafeContents *safe,
   3480                                             SEC_PKCS12Baggage *baggage)
   3481 {
   3482    sec_PKCS12SafeBag *key, **certList;
   3483    SEC_PKCS12CertAndCRL *oldCert;
   3484    SEC_PKCS12PVKSupportingData *pvkData;
   3485    int i;
   3486    SECItem *keyName;
   3487 
   3488    if (!p12dcx || !oldKey) {
   3489        return SECFailure;
   3490    }
   3491 
   3492    if (isEspvk) {
   3493        pvkData = &((SEC_PKCS12ESPVKItem *)(oldKey))->espvkData;
   3494    } else {
   3495        pvkData = &((SEC_PKCS12PrivateKey *)(oldKey))->pvkData;
   3496    }
   3497 
   3498    if (!pvkData->assocCerts || !pvkData->assocCerts[0]) {
   3499        PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE);
   3500        return SECFailure;
   3501    }
   3502 
   3503    oldCert = (SEC_PKCS12CertAndCRL *)sec_pkcs12_find_object(safe, baggage,
   3504                                                             SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID, NULL,
   3505                                                             pvkData->assocCerts[0]);
   3506    if (!oldCert) {
   3507        PORT_SetError(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE);
   3508        return SECFailure;
   3509    }
   3510 
   3511    key = sec_pkcs12_decoder_convert_old_key(p12dcx, oldKey, isEspvk);
   3512    certList = sec_pkcs12_decoder_convert_old_cert(p12dcx, oldCert);
   3513    if (!key || !certList) {
   3514        return SECFailure;
   3515    }
   3516 
   3517    if (sec_pkcs12_decoder_append_bag_to_context(p12dcx, key) != SECSuccess) {
   3518        return SECFailure;
   3519    }
   3520 
   3521    keyName = sec_pkcs12_get_nickname(key);
   3522    if (!keyName) {
   3523        return SECFailure;
   3524    }
   3525 
   3526    i = 0;
   3527    while (certList[i]) {
   3528        if (sec_pkcs12_decoder_append_bag_to_context(p12dcx, certList[i]) != SECSuccess) {
   3529            return SECFailure;
   3530        }
   3531        i++;
   3532    }
   3533 
   3534    certList = sec_pkcs12_find_certs_for_key(p12dcx->safeBags, key);
   3535    if (!certList) {
   3536        return SECFailure;
   3537    }
   3538 
   3539    i = 0;
   3540    while (certList[i] != 0) {
   3541        if (sec_pkcs12_set_nickname(certList[i], keyName) != SECSuccess) {
   3542            return SECFailure;
   3543        }
   3544        i++;
   3545    }
   3546 
   3547    return SECSuccess;
   3548 }
   3549 
   3550 static SECStatus
   3551 sec_pkcs12_decoder_convert_old_safe_to_bags(SEC_PKCS12DecoderContext *p12dcx,
   3552                                            SEC_PKCS12SafeContents *safe,
   3553                                            SEC_PKCS12Baggage *baggage)
   3554 {
   3555    SECStatus rv;
   3556 
   3557    if (!p12dcx || p12dcx->error) {
   3558        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   3559        return SECFailure;
   3560    }
   3561 
   3562    if (safe && safe->contents) {
   3563        int i = 0;
   3564        while (safe->contents[i] != NULL) {
   3565            if (SECOID_FindOIDTag(&safe->contents[i]->safeBagType) == SEC_OID_PKCS12_KEY_BAG_ID) {
   3566                int j = 0;
   3567                SEC_PKCS12PrivateKeyBag *privBag =
   3568                    safe->contents[i]->safeContent.keyBag;
   3569 
   3570                while (privBag->privateKeys[j] != NULL) {
   3571                    SEC_PKCS12PrivateKey *pk = privBag->privateKeys[j];
   3572                    rv = sec_pkcs12_decoder_convert_old_key_and_certs(p12dcx, pk,
   3573                                                                      PR_FALSE, safe, baggage);
   3574                    if (rv != SECSuccess) {
   3575                        goto loser;
   3576                    }
   3577                    j++;
   3578                }
   3579            }
   3580            i++;
   3581        }
   3582    }
   3583 
   3584    if (baggage && baggage->bags) {
   3585        int i = 0;
   3586        while (baggage->bags[i] != NULL) {
   3587            SEC_PKCS12BaggageItem *bag = baggage->bags[i];
   3588            int j = 0;
   3589 
   3590            if (!bag->espvks) {
   3591                i++;
   3592                continue;
   3593            }
   3594 
   3595            while (bag->espvks[j] != NULL) {
   3596                SEC_PKCS12ESPVKItem *espvk = bag->espvks[j];
   3597                rv = sec_pkcs12_decoder_convert_old_key_and_certs(p12dcx, espvk,
   3598                                                                  PR_TRUE, safe, baggage);
   3599                if (rv != SECSuccess) {
   3600                    goto loser;
   3601                }
   3602                j++;
   3603            }
   3604            i++;
   3605        }
   3606    }
   3607 
   3608    return SECSuccess;
   3609 
   3610 loser:
   3611    return SECFailure;
   3612 }
   3613 
   3614 SEC_PKCS12DecoderContext *
   3615 sec_PKCS12ConvertOldSafeToNew(PLArenaPool *arena, PK11SlotInfo *slot,
   3616                              PRBool swapUnicode, SECItem *pwitem,
   3617                              void *wincx, SEC_PKCS12SafeContents *safe,
   3618                              SEC_PKCS12Baggage *baggage)
   3619 {
   3620    SEC_PKCS12DecoderContext *p12dcx;
   3621 
   3622    if (!arena || !slot || !pwitem) {
   3623        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   3624        return NULL;
   3625    }
   3626 
   3627    if (!safe && !baggage) {
   3628        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   3629        return NULL;
   3630    }
   3631 
   3632    p12dcx = PORT_ArenaZNew(arena, SEC_PKCS12DecoderContext);
   3633    if (!p12dcx) {
   3634        return NULL;
   3635    }
   3636 
   3637    p12dcx->arena = arena;
   3638    p12dcx->slot = PK11_ReferenceSlot(slot);
   3639    p12dcx->wincx = wincx;
   3640    p12dcx->error = PR_FALSE;
   3641    p12dcx->swapUnicodeBytes = swapUnicode;
   3642    p12dcx->pwitem = pwitem;
   3643    p12dcx->tokenCAs = SECPKCS12TargetTokenNoCAs;
   3644 
   3645    if (sec_pkcs12_decoder_convert_old_safe_to_bags(p12dcx, safe, baggage) != SECSuccess) {
   3646        p12dcx->error = PR_TRUE;
   3647        return NULL;
   3648    }
   3649 
   3650    return p12dcx;
   3651 }