tor-browser

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

pk12util.c (38607B)


      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 #ifdef _CRTDBG_MAP_ALLOC
      6 #include <stdlib.h>
      7 #include <crtdbg.h>
      8 #endif
      9 
     10 #include "nspr.h"
     11 #include "secutil.h"
     12 #include "pk11func.h"
     13 #include "pkcs12.h"
     14 #include "p12plcy.h"
     15 #include "pk12util.h"
     16 #include "nss.h"
     17 #include "secport.h"
     18 #include "secpkcs5.h"
     19 #include "sechash.h"
     20 #include "certdb.h"
     21 
     22 #define PKCS12_IN_BUFFER_SIZE 200
     23 
     24 static char *progName;
     25 PRBool pk12_debugging = PR_FALSE;
     26 PRBool dumpRawFile;
     27 static PRBool pk12uForceUnicode;
     28 
     29 PRIntn pk12uErrno = 0;
     30 
     31 static void
     32 Usage()
     33 {
     34 #define FPS PR_fprintf(PR_STDERR,
     35    FPS "Usage:	 %s -i importfile [-I] [-d certdir] [-P dbprefix] [-h tokenname]\n",
     36 			 progName);
     37    FPS "\t\t [-k slotpwfile | -K slotpw] [-w p12filepwfile | -W p12filepw]\n");
     38    FPS "\t\t [-v]\n");
     39 
     40    FPS "Usage:	 %s -l listfile [-I] [-d certdir] [-P dbprefix] [-h tokenname]\n",
     41 			 progName);
     42    FPS "\t\t [-k slotpwfile | -K slotpw] [-w p12filepwfile | -W p12filepw]\n");
     43    FPS "\t\t [-v]\n");
     44 
     45    FPS "Usage:	 %s -o exportfile -n certname [-d certdir] [-P dbprefix]\n",
     46 	progName);
     47    FPS "\t\t [-c key_cipher] [-C cert_cipher] [-M mac_alg]\n"
     48        "\t\t [-m | --key_len keyLen] [--cert_key_len certKeyLen] [-v]\n");
     49    FPS "\t\t [-k slotpwfile | -K slotpw]\n"
     50        "\t\t [-w p12filepwfile | -W p12filepw]\n");
     51 
     52    exit(PK12UERR_USAGE);
     53 }
     54 
     55 static PRBool
     56 p12u_OpenFile(p12uContext *p12cxt, PRBool fileRead)
     57 {
     58    if (!p12cxt || !p12cxt->filename) {
     59        return PR_FALSE;
     60    }
     61 
     62    if (fileRead) {
     63        p12cxt->file = PR_Open(p12cxt->filename,
     64                               PR_RDONLY, 0400);
     65    } else {
     66        p12cxt->file = PR_Open(p12cxt->filename,
     67                               PR_CREATE_FILE | PR_RDWR | PR_TRUNCATE,
     68                               0600);
     69    }
     70 
     71    if (!p12cxt->file) {
     72        p12cxt->error = PR_TRUE;
     73        return PR_FALSE;
     74    }
     75 
     76    return PR_TRUE;
     77 }
     78 
     79 static void
     80 p12u_DestroyContext(p12uContext **ppCtx, PRBool removeFile)
     81 {
     82    if (!ppCtx || !(*ppCtx)) {
     83        return;
     84    }
     85 
     86    if ((*ppCtx)->file != NULL) {
     87        PR_Close((*ppCtx)->file);
     88    }
     89 
     90    if ((*ppCtx)->filename != NULL) {
     91        if (removeFile) {
     92            PR_Delete((*ppCtx)->filename);
     93        }
     94        PL_strfree((*ppCtx)->filename);
     95        (*ppCtx)->filename = NULL;
     96    }
     97 
     98    PR_Free(*ppCtx);
     99    *ppCtx = NULL;
    100 }
    101 
    102 static p12uContext *
    103 p12u_InitContext(PRBool fileImport, char *filename)
    104 {
    105    p12uContext *p12cxt;
    106 
    107    p12cxt = PORT_ZNew(p12uContext);
    108    if (!p12cxt) {
    109        return NULL;
    110    }
    111 
    112    p12cxt->error = PR_FALSE;
    113    p12cxt->errorValue = 0;
    114    p12cxt->filename = PL_strdup(filename);
    115 
    116    if (!p12u_OpenFile(p12cxt, fileImport)) {
    117        p12u_DestroyContext(&p12cxt, PR_FALSE);
    118        return NULL;
    119    }
    120 
    121    return p12cxt;
    122 }
    123 
    124 SECItem *
    125 P12U_NicknameCollisionCallback(SECItem *old_nick, PRBool *cancel, void *wincx)
    126 {
    127    char *nick = NULL;
    128    SECItem *ret_nick = NULL;
    129    CERTCertificate *cert = (CERTCertificate *)wincx;
    130 
    131    if (!cancel || !cert) {
    132        pk12uErrno = PK12UERR_USER_CANCELLED;
    133        return NULL;
    134    }
    135 
    136    if (!old_nick)
    137        fprintf(stdout, "pk12util: no nickname for cert in PKCS12 file.\n");
    138 
    139 #if 0
    140    /* XXX not handled yet  */
    141    *cancel = PR_TRUE;
    142    return NULL;
    143 
    144 #else
    145 
    146    nick = CERT_MakeCANickname(cert);
    147    if (!nick) {
    148        return NULL;
    149    }
    150 
    151    if (old_nick && old_nick->data && old_nick->len &&
    152        PORT_Strlen(nick) == old_nick->len &&
    153        !PORT_Strncmp((char *)old_nick->data, nick, old_nick->len)) {
    154        PORT_Free(nick);
    155        PORT_SetError(SEC_ERROR_IO);
    156        return NULL;
    157    }
    158 
    159    fprintf(stdout, "pk12util: using nickname: %s\n", nick);
    160    ret_nick = PORT_ZNew(SECItem);
    161    if (ret_nick == NULL) {
    162        PORT_Free(nick);
    163        return NULL;
    164    }
    165 
    166    ret_nick->data = (unsigned char *)nick;
    167    ret_nick->len = PORT_Strlen(nick);
    168 
    169    return ret_nick;
    170 #endif
    171 }
    172 
    173 static SECStatus
    174 p12u_SwapUnicodeBytes(SECItem *uniItem)
    175 {
    176    unsigned int i;
    177    unsigned char a;
    178    if ((uniItem == NULL) || (uniItem->len % 2)) {
    179        return SECFailure;
    180    }
    181    for (i = 0; i < uniItem->len; i += 2) {
    182        a = uniItem->data[i];
    183        uniItem->data[i] = uniItem->data[i + 1];
    184        uniItem->data[i + 1] = a;
    185    }
    186    return SECSuccess;
    187 }
    188 
    189 static PRBool
    190 p12u_ucs2_ascii_conversion_function(PRBool toUnicode,
    191                                    unsigned char *inBuf,
    192                                    unsigned int inBufLen,
    193                                    unsigned char *outBuf,
    194                                    unsigned int maxOutBufLen,
    195                                    unsigned int *outBufLen,
    196                                    PRBool swapBytes)
    197 {
    198    SECItem it = { 0 };
    199    SECItem *dup = NULL;
    200    PRBool ret;
    201 
    202 #ifdef DEBUG_CONVERSION
    203    if (pk12_debugging) {
    204        int i;
    205        printf("Converted from:\n");
    206        for (i = 0; i < inBufLen; i++) {
    207            printf("%2x ", inBuf[i]);
    208            /*if (i%60 == 0) printf("\n");*/
    209        }
    210        printf("\n");
    211    }
    212 #endif
    213    it.data = inBuf;
    214    it.len = inBufLen;
    215    dup = SECITEM_DupItem(&it);
    216    if (!dup) {
    217        return PR_FALSE;
    218    }
    219    /* If converting Unicode to ASCII, swap bytes before conversion
    220     * as neccessary.
    221     */
    222    if (!toUnicode && swapBytes) {
    223        if (p12u_SwapUnicodeBytes(dup) != SECSuccess) {
    224            SECITEM_ZfreeItem(dup, PR_TRUE);
    225            return PR_FALSE;
    226        }
    227    }
    228    /* Perform the conversion. */
    229    ret = PORT_UCS2_UTF8Conversion(toUnicode, dup->data, dup->len,
    230                                   outBuf, maxOutBufLen, outBufLen);
    231    SECITEM_ZfreeItem(dup, PR_TRUE);
    232 
    233 #ifdef DEBUG_CONVERSION
    234    if (pk12_debugging) {
    235        int i;
    236        printf("Converted to:\n");
    237        for (i = 0; i < *outBufLen; i++) {
    238            printf("%2x ", outBuf[i]);
    239            /*if (i%60 == 0) printf("\n");*/
    240        }
    241        printf("\n");
    242    }
    243 #endif
    244    return ret;
    245 }
    246 
    247 SECStatus
    248 P12U_UnicodeConversion(PLArenaPool *arena, SECItem *dest, SECItem *src,
    249                       PRBool toUnicode, PRBool swapBytes)
    250 {
    251    unsigned int allocLen;
    252    if (!dest || !src) {
    253        return SECFailure;
    254    }
    255    allocLen = ((toUnicode) ? (src->len << 2) : src->len);
    256    if (arena) {
    257        dest->data = PORT_ArenaZAlloc(arena, allocLen);
    258    } else {
    259        dest->data = PORT_ZAlloc(allocLen);
    260    }
    261    if (PORT_UCS2_ASCIIConversion(toUnicode, src->data, src->len,
    262                                  dest->data, allocLen, &dest->len,
    263                                  swapBytes) == PR_FALSE) {
    264        if (!arena) {
    265            PORT_Free(dest->data);
    266        }
    267        dest->data = NULL;
    268        return SECFailure;
    269    }
    270    return SECSuccess;
    271 }
    272 
    273 /*
    274 *
    275 */
    276 SECItem *
    277 P12U_GetP12FilePassword(PRBool confirmPw, secuPWData *p12FilePw)
    278 {
    279    char *p0 = NULL;
    280    SECItem *pwItem = NULL;
    281 
    282    if (p12FilePw == NULL || p12FilePw->source == PW_NONE) {
    283        char *p1 = NULL;
    284        int rc;
    285        for (;;) {
    286            p0 = SECU_GetPasswordString(NULL,
    287                                        "Enter password for PKCS12 file: ");
    288            if (!confirmPw || p0 == NULL)
    289                break;
    290            p1 = SECU_GetPasswordString(NULL, "Re-enter password: ");
    291            if (p1 == NULL) {
    292                PORT_ZFree(p0, PL_strlen(p0));
    293                p0 = NULL;
    294                break;
    295            }
    296            rc = PL_strcmp(p0, p1);
    297            PORT_ZFree(p1, PL_strlen(p1));
    298            if (rc == 0)
    299                break;
    300            PORT_ZFree(p0, PL_strlen(p0));
    301        }
    302    } else if (p12FilePw->source == PW_FROMFILE) {
    303        p0 = SECU_FilePasswd(NULL, PR_FALSE, p12FilePw->data);
    304    } else { /* Plaintext */
    305        p0 = PORT_Strdup(p12FilePw->data);
    306    }
    307 
    308    if (p0 == NULL) {
    309        return NULL;
    310    }
    311    pwItem = SECITEM_AllocItem(NULL, NULL, PL_strlen(p0) + 1);
    312    memcpy(pwItem->data, p0, pwItem->len);
    313 
    314    PORT_ZFree(p0, PL_strlen(p0));
    315 
    316    return pwItem;
    317 }
    318 
    319 SECStatus
    320 P12U_InitSlot(PK11SlotInfo *slot, secuPWData *slotPw)
    321 {
    322    SECStatus rv;
    323 
    324    /*	New databases, initialize keydb password. */
    325    if (PK11_NeedUserInit(slot)) {
    326        rv = SECU_ChangePW(slot,
    327                           (slotPw->source == PW_PLAINTEXT) ? slotPw->data : 0,
    328                           (slotPw->source == PW_FROMFILE) ? slotPw->data : 0);
    329        if (rv != SECSuccess) {
    330            SECU_PrintError(progName, "Failed to initialize slot \"%s\"",
    331                            PK11_GetSlotName(slot));
    332            return SECFailure;
    333        }
    334    }
    335 
    336    if (PK11_Authenticate(slot, PR_TRUE, slotPw) != SECSuccess) {
    337        SECU_PrintError(progName,
    338                        "Failed to authenticate to PKCS11 slot");
    339        PORT_SetError(SEC_ERROR_USER_CANCELLED);
    340        pk12uErrno = PK12UERR_USER_CANCELLED;
    341        return SECFailure;
    342    }
    343 
    344    return SECSuccess;
    345 }
    346 
    347 /* This routine takes care of getting the PKCS12 file password, then reading and
    348 * verifying the file. It returns the decoder context and a filled in password.
    349 * (The password is needed by P12U_ImportPKCS12Object() to import the private
    350 * key.)
    351 */
    352 SEC_PKCS12DecoderContext *
    353 p12U_ReadPKCS12File(SECItem *uniPwp, char *in_file, PK11SlotInfo *slot,
    354                    secuPWData *slotPw, secuPWData *p12FilePw,
    355                    PRBool ignoreIntegrity)
    356 {
    357    SEC_PKCS12DecoderContext *p12dcx = NULL;
    358    p12uContext *p12cxt = NULL;
    359    SECItem *pwitem = NULL;
    360    SECItem p12file = { 0 };
    361    SECStatus rv = SECFailure;
    362    PRBool swapUnicode = PR_FALSE;
    363    PRBool forceUnicode = pk12uForceUnicode;
    364    PRBool trypw;
    365    int error;
    366 
    367 #ifdef IS_LITTLE_ENDIAN
    368    swapUnicode = PR_TRUE;
    369 #endif
    370 
    371    p12cxt = p12u_InitContext(PR_TRUE, in_file);
    372    if (!p12cxt) {
    373        SECU_PrintError(progName, "File Open failed: %s", in_file);
    374        pk12uErrno = PK12UERR_INIT_FILE;
    375        return NULL;
    376    }
    377 
    378    /* get the password */
    379    pwitem = P12U_GetP12FilePassword(PR_FALSE, p12FilePw);
    380    if (!pwitem) {
    381        pk12uErrno = PK12UERR_USER_CANCELLED;
    382        goto done;
    383    }
    384 
    385    if (P12U_UnicodeConversion(NULL, uniPwp, pwitem, PR_TRUE,
    386                               swapUnicode) != SECSuccess) {
    387        SECU_PrintError(progName, "Unicode conversion failed");
    388        pk12uErrno = PK12UERR_UNICODECONV;
    389        goto done;
    390    }
    391    rv = SECU_FileToItem(&p12file, p12cxt->file);
    392    if (rv != SECSuccess) {
    393        SECU_PrintError(progName, "Failed to read from import file");
    394        goto done;
    395    }
    396 
    397    do {
    398        trypw = PR_FALSE; /* normally we do this once */
    399        rv = SECFailure;
    400        /* init the decoder context */
    401        p12dcx = SEC_PKCS12DecoderStart(uniPwp, slot, slotPw,
    402                                        NULL, NULL, NULL, NULL, NULL);
    403        if (!p12dcx) {
    404            SECU_PrintError(progName, "PKCS12 decoder start failed");
    405            pk12uErrno = PK12UERR_PK12DECODESTART;
    406            break;
    407        }
    408 
    409        /* decode the item */
    410        rv = SEC_PKCS12DecoderUpdate(p12dcx, p12file.data, p12file.len);
    411 
    412        if (rv != SECSuccess) {
    413            error = PR_GetError();
    414            if (error == SEC_ERROR_DECRYPTION_DISALLOWED) {
    415                PR_SetError(error, 0);
    416                break;
    417            }
    418            SECU_PrintError(progName, "PKCS12 decoding failed");
    419            pk12uErrno = PK12UERR_DECODE;
    420        }
    421 
    422        /* does the blob authenticate properly? */
    423        rv = SEC_PKCS12DecoderVerify(p12dcx);
    424        if (rv != SECSuccess) {
    425            if (uniPwp->len == 2) {
    426                /* this is a null PW, try once more with a zero-length PW
    427                   instead of a null string */
    428                SEC_PKCS12DecoderFinish(p12dcx);
    429                uniPwp->len = 0;
    430                trypw = PR_TRUE;
    431            } else if (forceUnicode == pk12uForceUnicode) {
    432                /* try again with a different password encoding */
    433                forceUnicode = !pk12uForceUnicode;
    434                rv = NSS_OptionSet(__NSS_PKCS12_DECODE_FORCE_UNICODE,
    435                                   forceUnicode);
    436                if (rv != SECSuccess) {
    437                    SECU_PrintError(progName, "PKCS12 decoding failed to set option");
    438                    pk12uErrno = PK12UERR_DECODEVERIFY;
    439                    break;
    440                }
    441                SEC_PKCS12DecoderFinish(p12dcx);
    442                trypw = PR_TRUE;
    443            } else {
    444                SECU_PrintError(progName, "PKCS12 decode not verified");
    445                pk12uErrno = PK12UERR_DECODEVERIFY;
    446                break;
    447            }
    448        }
    449    } while (trypw == PR_TRUE);
    450 
    451    /* revert the option setting */
    452    if (forceUnicode != pk12uForceUnicode) {
    453        if (SECSuccess != NSS_OptionSet(__NSS_PKCS12_DECODE_FORCE_UNICODE, pk12uForceUnicode)) {
    454            SECU_PrintError(progName, "PKCS12 decoding failed to set option");
    455            pk12uErrno = PK12UERR_DECODEVERIFY;
    456            rv = SECFailure;
    457        }
    458    }
    459    /* rv has been set at this point */
    460 
    461 done:
    462    /* if we are ignoring Integrity and we failed because we couldn't
    463     * verify the integrity code, go ahead and succeed */
    464    if (rv != SECSuccess && !(ignoreIntegrity &&
    465                              (pk12uErrno == PK12UERR_DECODEVERIFY))) {
    466        if (p12dcx != NULL) {
    467            SEC_PKCS12DecoderFinish(p12dcx);
    468            p12dcx = NULL;
    469        }
    470        if (uniPwp->data) {
    471            SECITEM_ZfreeItem(uniPwp, PR_FALSE);
    472            uniPwp->data = NULL;
    473        }
    474    }
    475    PR_Close(p12cxt->file);
    476    p12cxt->file = NULL;
    477    /* PK11_FreeSlot(slot); */
    478    p12u_DestroyContext(&p12cxt, PR_FALSE);
    479 
    480    if (pwitem) {
    481        SECITEM_ZfreeItem(pwitem, PR_TRUE);
    482    }
    483    SECITEM_ZfreeItem(&p12file, PR_FALSE);
    484    return p12dcx;
    485 }
    486 
    487 /*
    488 * given a filename for pkcs12 file, imports certs and keys
    489 *
    490 * Change: altitude
    491 *  I've changed this function so that it takes the keydb and pkcs12 file
    492 *  passwords from files.  The "pwdKeyDB" and "pwdP12File"
    493 *  variables have been added for this purpose.
    494 */
    495 PRIntn
    496 P12U_ImportPKCS12Object(char *in_file, PK11SlotInfo *slot,
    497                        secuPWData *slotPw, secuPWData *p12FilePw,
    498                        PRBool ignoreIntegrity)
    499 {
    500    SEC_PKCS12DecoderContext *p12dcx = NULL;
    501    SECItem uniPwitem = { 0 };
    502    PRBool forceUnicode = pk12uForceUnicode;
    503    PRBool trypw;
    504    SECStatus rv = SECFailure;
    505 
    506    rv = P12U_InitSlot(slot, slotPw);
    507    if (rv != SECSuccess) {
    508        SECU_PrintError(progName, "Failed to authenticate to \"%s\"",
    509                        PK11_GetSlotName(slot));
    510        pk12uErrno = PK12UERR_PK11GETSLOT;
    511        return rv;
    512    }
    513 
    514    do {
    515        trypw = PR_FALSE; /* normally we do this once */
    516        rv = SECFailure;
    517        p12dcx = p12U_ReadPKCS12File(&uniPwitem, in_file, slot, slotPw,
    518                                     p12FilePw, ignoreIntegrity);
    519 
    520        if (p12dcx == NULL) {
    521            goto loser;
    522        }
    523 
    524        /* make sure the bags are okey dokey -- nicknames correct, etc. */
    525        rv = SEC_PKCS12DecoderValidateBags(p12dcx, P12U_NicknameCollisionCallback);
    526        if (rv != SECSuccess) {
    527            if (PORT_GetError() == SEC_ERROR_PKCS12_DUPLICATE_DATA) {
    528                pk12uErrno = PK12UERR_CERTALREADYEXISTS;
    529            } else {
    530                pk12uErrno = PK12UERR_DECODEVALIBAGS;
    531            }
    532            SECU_PrintError(progName, "PKCS12 decode validate bags failed");
    533            goto loser;
    534        }
    535 
    536        /* stuff 'em in */
    537        if (forceUnicode != pk12uForceUnicode) {
    538            rv = NSS_OptionSet(__NSS_PKCS12_DECODE_FORCE_UNICODE,
    539                               forceUnicode);
    540            if (rv != SECSuccess) {
    541                SECU_PrintError(progName, "PKCS12 decode set option failed");
    542                pk12uErrno = PK12UERR_DECODEIMPTBAGS;
    543                goto loser;
    544            }
    545        }
    546        rv = SEC_PKCS12DecoderImportBags(p12dcx);
    547        if (rv != SECSuccess) {
    548            if (PR_GetError() == SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY &&
    549                forceUnicode == pk12uForceUnicode) {
    550                /* try again with a different password encoding */
    551                forceUnicode = !pk12uForceUnicode;
    552                SEC_PKCS12DecoderFinish(p12dcx);
    553                SECITEM_ZfreeItem(&uniPwitem, PR_FALSE);
    554                trypw = PR_TRUE;
    555            } else {
    556                SECU_PrintError(progName, "PKCS12 decode import bags failed");
    557                pk12uErrno = PK12UERR_DECODEIMPTBAGS;
    558                goto loser;
    559            }
    560        }
    561    } while (trypw);
    562 
    563    /* revert the option setting */
    564    if (forceUnicode != pk12uForceUnicode) {
    565        rv = NSS_OptionSet(__NSS_PKCS12_DECODE_FORCE_UNICODE, pk12uForceUnicode);
    566        if (rv != SECSuccess) {
    567            SECU_PrintError(progName, "PKCS12 decode set option failed");
    568            pk12uErrno = PK12UERR_DECODEIMPTBAGS;
    569            goto loser;
    570        }
    571    }
    572 
    573    fprintf(stdout, "%s: PKCS12 IMPORT SUCCESSFUL\n", progName);
    574    rv = SECSuccess;
    575 
    576 loser:
    577    if (p12dcx) {
    578        SEC_PKCS12DecoderFinish(p12dcx);
    579    }
    580 
    581    if (uniPwitem.data) {
    582        SECITEM_ZfreeItem(&uniPwitem, PR_FALSE);
    583    }
    584 
    585    return rv;
    586 }
    587 
    588 static void
    589 p12u_DoPKCS12ExportErrors()
    590 {
    591    PRErrorCode error_value;
    592 
    593    error_value = PORT_GetError();
    594    if ((error_value == SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY) ||
    595        (error_value == SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME) ||
    596        (error_value == SEC_ERROR_PKCS12_UNABLE_TO_WRITE)) {
    597        fputs(SECU_Strerror(error_value), stderr);
    598    } else if (error_value == SEC_ERROR_USER_CANCELLED) {
    599        ;
    600    } else {
    601        fputs(SECU_Strerror(SEC_ERROR_EXPORTING_CERTIFICATES), stderr);
    602    }
    603 }
    604 
    605 static void
    606 p12u_WriteToExportFile(void *arg, const char *buf, unsigned long len)
    607 {
    608    p12uContext *p12cxt = arg;
    609    int writeLen;
    610 
    611    if (!p12cxt || (p12cxt->error == PR_TRUE)) {
    612        return;
    613    }
    614 
    615    if (p12cxt->file == NULL) {
    616        p12cxt->errorValue = SEC_ERROR_PKCS12_UNABLE_TO_WRITE;
    617        p12cxt->error = PR_TRUE;
    618        return;
    619    }
    620 
    621    writeLen = PR_Write(p12cxt->file, (unsigned char *)buf, (PRInt32)len);
    622 
    623    if (writeLen != (int)len) {
    624        PR_Close(p12cxt->file);
    625        PL_strfree(p12cxt->filename);
    626        p12cxt->filename = NULL;
    627        p12cxt->file = NULL;
    628        p12cxt->errorValue = SEC_ERROR_PKCS12_UNABLE_TO_WRITE;
    629        p12cxt->error = PR_TRUE;
    630    }
    631 }
    632 
    633 void
    634 P12U_ExportPKCS12Object(char *nn, char *outfile, PK11SlotInfo *inSlot,
    635                        SECOidTag cipher, SECOidTag certCipher, SECOidTag hash,
    636                        secuPWData *slotPw, secuPWData *p12FilePw)
    637 {
    638    SEC_PKCS12ExportContext *p12ecx = NULL;
    639    SEC_PKCS12SafeInfo *keySafe = NULL, *certSafe = NULL;
    640    SECItem *pwitem = NULL;
    641    p12uContext *p12cxt = NULL;
    642    CERTCertList *certlist = NULL;
    643    CERTCertListNode *node = NULL;
    644    PK11SlotInfo *slot = NULL;
    645 
    646    if (P12U_InitSlot(inSlot, slotPw) != SECSuccess) {
    647        SECU_PrintError(progName, "Failed to authenticate to \"%s\"",
    648                        PK11_GetSlotName(inSlot));
    649        pk12uErrno = PK12UERR_PK11GETSLOT;
    650        goto loser;
    651    }
    652    certlist = PK11_FindCertsFromNickname(nn, slotPw);
    653    if (!certlist) {
    654        PORT_SetError(SEC_ERROR_UNKNOWN_CERT);
    655        SECU_PrintError(progName, "find user certs from nickname failed");
    656        pk12uErrno = PK12UERR_FINDCERTBYNN;
    657        return;
    658    }
    659 
    660    if ((SECSuccess != CERT_FilterCertListForUserCerts(certlist)) ||
    661        CERT_LIST_EMPTY(certlist)) {
    662        PR_fprintf(PR_STDERR, "%s: no user certs from given nickname\n",
    663                   progName);
    664        pk12uErrno = PK12UERR_FINDCERTBYNN;
    665        goto loser;
    666    }
    667 
    668    /*	Password to use for PKCS12 file.  */
    669    pwitem = P12U_GetP12FilePassword(PR_TRUE, p12FilePw);
    670    if (!pwitem) {
    671        goto loser;
    672    }
    673 
    674    /* we are passing UTF8, drop the NULL in the normal password value.
    675     * UCS2 conversion will add it back if necessary. This only affects
    676     * password > Blocksize of the Hash function and pkcs5v2 pbe (if password
    677     * <=Blocksize then the password is zero padded anyway, so an extra NULL
    678     * at the end has not effect). This is allows us to work with openssl and
    679     * gnutls. Older versions of NSS already fail to decrypt long passwords
    680     * in this case, so we aren't breaking anyone with this code */
    681    if ((pwitem->len > 0) && (!pwitem->data[pwitem->len - 1])) {
    682        pwitem->len--;
    683    }
    684 
    685    p12cxt = p12u_InitContext(PR_FALSE, outfile);
    686    if (!p12cxt) {
    687        SECU_PrintError(progName, "Initialization failed: %s", outfile);
    688        pk12uErrno = PK12UERR_INIT_FILE;
    689        goto loser;
    690    }
    691 
    692    if (certlist) {
    693        CERTCertificate *cert = CERT_LIST_HEAD(certlist)->cert;
    694        if (cert) {
    695            slot = cert->slot; /* use the slot from the first matching
    696                certificate to create the context . This is for keygen */
    697        }
    698    }
    699    if (!slot) {
    700        SECU_PrintError(progName, "cert does not have a slot");
    701        pk12uErrno = PK12UERR_FINDCERTBYNN;
    702        goto loser;
    703    }
    704    p12ecx = SEC_PKCS12CreateExportContext(NULL, NULL, slot, slotPw);
    705    if (!p12ecx) {
    706        SECU_PrintError(progName, "export context creation failed");
    707        pk12uErrno = PK12UERR_EXPORTCXCREATE;
    708        goto loser;
    709    }
    710 
    711    if (SEC_PKCS12AddPasswordIntegrity(p12ecx, pwitem, hash) !=
    712        SECSuccess) {
    713        SECU_PrintError(progName, "PKCS12 add password integrity failed");
    714        pk12uErrno = PK12UERR_PK12ADDPWDINTEG;
    715        goto loser;
    716    }
    717 
    718    for (node = CERT_LIST_HEAD(certlist);
    719         !CERT_LIST_END(node, certlist);
    720         node = CERT_LIST_NEXT(node)) {
    721        CERTCertificate *cert = node->cert;
    722        if (!cert->slot) {
    723            SECU_PrintError(progName, "cert does not have a slot");
    724            pk12uErrno = PK12UERR_FINDCERTBYNN;
    725            goto loser;
    726        }
    727 
    728        keySafe = SEC_PKCS12CreateUnencryptedSafe(p12ecx);
    729        if (certCipher == SEC_OID_UNKNOWN) {
    730            certSafe = keySafe;
    731        } else {
    732            certSafe =
    733                SEC_PKCS12CreatePasswordPrivSafe(p12ecx, pwitem, certCipher);
    734        }
    735 
    736        if (!certSafe || !keySafe) {
    737            SECU_PrintError(progName, "key or cert safe creation failed");
    738            pk12uErrno = PK12UERR_CERTKEYSAFE;
    739            goto loser;
    740        }
    741 
    742        if (SEC_PKCS12AddCertAndKey(p12ecx, certSafe, NULL, cert,
    743                                    CERT_GetDefaultCertDB(), keySafe, NULL,
    744                                    PR_TRUE, pwitem, cipher) != SECSuccess) {
    745            SECU_PrintError(progName, "add cert and key failed");
    746            pk12uErrno = PK12UERR_ADDCERTKEY;
    747            goto loser;
    748        }
    749    }
    750 
    751    CERT_DestroyCertList(certlist);
    752    certlist = NULL;
    753 
    754    if (SEC_PKCS12Encode(p12ecx, p12u_WriteToExportFile, p12cxt) !=
    755        SECSuccess) {
    756        SECU_PrintError(progName, "PKCS12 encode failed");
    757        pk12uErrno = PK12UERR_ENCODE;
    758        goto loser;
    759    }
    760 
    761    p12u_DestroyContext(&p12cxt, PR_FALSE);
    762    SECITEM_ZfreeItem(pwitem, PR_TRUE);
    763    fprintf(stdout, "%s: PKCS12 EXPORT SUCCESSFUL\n", progName);
    764    SEC_PKCS12DestroyExportContext(p12ecx);
    765 
    766    return;
    767 
    768 loser:
    769    SEC_PKCS12DestroyExportContext(p12ecx);
    770 
    771    if (certlist) {
    772        CERT_DestroyCertList(certlist);
    773        certlist = NULL;
    774    }
    775 
    776    p12u_DestroyContext(&p12cxt, PR_TRUE);
    777    if (pwitem) {
    778        SECITEM_ZfreeItem(pwitem, PR_TRUE);
    779    }
    780    p12u_DoPKCS12ExportErrors();
    781    return;
    782 }
    783 
    784 PRIntn
    785 P12U_ListPKCS12File(char *in_file, PK11SlotInfo *slot,
    786                    secuPWData *slotPw, secuPWData *p12FilePw,
    787                    PRBool ignoreIntegrity)
    788 {
    789    SEC_PKCS12DecoderContext *p12dcx = NULL;
    790    SECItem uniPwitem = { 0 };
    791    SECStatus rv = SECFailure;
    792    const SEC_PKCS12DecoderItem *dip;
    793 
    794    p12dcx = p12U_ReadPKCS12File(&uniPwitem, in_file, slot, slotPw, p12FilePw,
    795                                 ignoreIntegrity);
    796    /* did the blob authenticate properly? */
    797    if (p12dcx == NULL) {
    798        SECU_PrintError(progName, "PKCS12 decode not verified");
    799        pk12uErrno = PK12UERR_DECODEVERIFY;
    800        goto loser;
    801    }
    802    rv = SEC_PKCS12DecoderIterateInit(p12dcx);
    803    if (rv != SECSuccess) {
    804        SECU_PrintError(progName, "PKCS12 decode iterate bags failed");
    805        pk12uErrno = PK12UERR_DECODEIMPTBAGS;
    806        rv = SECFailure;
    807    } else {
    808        int fileCounter = 0;
    809        while (SEC_PKCS12DecoderIterateNext(p12dcx, &dip) == SECSuccess) {
    810            switch (dip->type) {
    811                case SEC_OID_PKCS12_V1_CERT_BAG_ID:
    812                    printf("Certificate");
    813                    if (dumpRawFile) {
    814                        PRFileDesc *fd;
    815                        char fileName[20];
    816                        snprintf(fileName, sizeof(fileName), "file%04d.der", ++fileCounter);
    817                        fd = PR_Open(fileName,
    818                                     PR_CREATE_FILE | PR_RDWR | PR_TRUNCATE,
    819                                     0600);
    820                        if (!fd) {
    821                            SECU_PrintError(progName,
    822                                            "Cannot create output file");
    823                        } else {
    824                            PR_Write(fd, dip->der->data, dip->der->len);
    825                            PR_Close(fd);
    826                        }
    827                    } else if (SECU_PrintSignedData(stdout, dip->der,
    828                                                    (dip->hasKey) ? "(has private key)"
    829                                                                  : "",
    830                                                    0, SECU_PrintCertificate) !=
    831                               0) {
    832                        SECU_PrintError(progName, "PKCS12 print cert bag failed");
    833                    }
    834                    if (dip->friendlyName != NULL) {
    835                        printf("    Friendly Name: %s\n\n",
    836                               dip->friendlyName->data);
    837                    }
    838                    if (dip->shroudAlg) {
    839                        SECU_PrintAlgorithmID(stdout, dip->shroudAlg,
    840                                              "Encryption algorithm", 1);
    841                    }
    842                    break;
    843                case SEC_OID_PKCS12_V1_KEY_BAG_ID:
    844                case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
    845                    printf("Key");
    846                    if (dip->type == SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID)
    847                        printf("(shrouded)");
    848                    printf(":\n");
    849                    if (dip->friendlyName != NULL) {
    850                        printf("    Friendly Name: %s\n\n",
    851                               dip->friendlyName->data);
    852                    }
    853                    if (dip->shroudAlg) {
    854                        SECU_PrintAlgorithmID(stdout, dip->shroudAlg,
    855                                              "Encryption algorithm", 1);
    856                    }
    857                    break;
    858                default:
    859                    printf("unknown bag type(%d): %s\n\n", dip->type,
    860                           SECOID_FindOIDTagDescription(dip->type));
    861                    break;
    862            }
    863        }
    864        rv = SECSuccess;
    865    }
    866 
    867 loser:
    868 
    869    if (p12dcx) {
    870        SEC_PKCS12DecoderFinish(p12dcx);
    871    }
    872 
    873    if (uniPwitem.data) {
    874        SECITEM_ZfreeItem(&uniPwitem, PR_FALSE);
    875    }
    876 
    877    return rv;
    878 }
    879 
    880 SECOidTag
    881 PKCS12U_FindTagFromString(char *cipherString)
    882 {
    883    return SECOID_FindOIDTagFromDescripton(cipherString, (size_t)-1, PR_TRUE);
    884 }
    885 
    886 /*
    887 * use the oid table description to map a user input string to a particular
    888 * oid.
    889 */
    890 SECOidTag
    891 PKCS12U_MapCipherFromString(char *cipherString, int keyLen)
    892 {
    893    SECOidTag tag;
    894    SECOidTag cipher;
    895 
    896    /* future enhancement: provide 'friendlier' typed in names for
    897     * pbe mechanisms.
    898     */
    899 
    900    /* look for the oid tag by Description */
    901    tag = PKCS12U_FindTagFromString(cipherString);
    902    if (tag == SEC_OID_UNKNOWN) {
    903        return tag;
    904    }
    905 
    906    cipher = SEC_OID_UNKNOWN;
    907    /* we found a match... get the PBE version of this
    908     * cipher... */
    909    if (!SEC_PKCS5IsAlgorithmPBEAlgTag(tag)) {
    910        cipher = SEC_PKCS5GetPBEAlgorithm(tag, keyLen);
    911        /* no eqivalent PKCS5/PKCS12 cipher, use the raw
    912         * encryption tag we got and pass it directly in,
    913         * pkcs12 will use the pkcsv5 mechanism */
    914        if (cipher == SEC_OID_PKCS5_PBES2) {
    915            cipher = tag;
    916        } else if (cipher == SEC_OID_PKCS5_PBMAC1) {
    917            /* make sure we have not macing ciphers here */
    918            cipher = SEC_OID_UNKNOWN;
    919        }
    920    } else {
    921        cipher = tag;
    922    }
    923    return cipher;
    924 }
    925 
    926 SECOidTag
    927 PKCS12U_MapHashFromString(char *hashString)
    928 {
    929    SECOidTag hashAlg;
    930 
    931    /* look for the oid tag by Description */
    932    hashAlg = PKCS12U_FindTagFromString(hashString);
    933    if (hashAlg == SEC_OID_UNKNOWN) {
    934        return hashAlg;
    935    }
    936    /* make sure it's a hashing oid */
    937    if (HASH_GetHashTypeByOidTag(hashAlg) == HASH_AlgNULL) {
    938        /* allow HMAC here. HMAC implies PKCS 5 v2 pba */
    939        SECOidTag baseHashAlg = HASH_GetHashOidTagByHMACOidTag(hashAlg);
    940        if (baseHashAlg == SEC_OID_UNKNOWN) {
    941            /* not an hmac either, reject the entry */
    942            return SEC_OID_UNKNOWN;
    943        }
    944    }
    945    return hashAlg;
    946 }
    947 
    948 static PRUintn
    949 P12U_Init(char *dir, char *dbprefix, PRBool listonly)
    950 {
    951    SECStatus rv;
    952    PK11_SetPasswordFunc(SECU_GetModulePassword);
    953 
    954    PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
    955    if (listonly && NSS_NoDB_Init("") == SECSuccess) {
    956        rv = SECSuccess;
    957    } else {
    958        rv = NSS_Initialize(dir, dbprefix, dbprefix, "secmod.db", 0);
    959    }
    960    if (rv != SECSuccess) {
    961        SECU_PrintPRandOSError(progName);
    962        exit(-1);
    963    }
    964 
    965    /* setup unicode callback functions */
    966    PORT_SetUCS2_ASCIIConversionFunction(p12u_ucs2_ascii_conversion_function);
    967    /* use the defaults for UCS4-UTF8 and UCS2-UTF8 */
    968 
    969    /* ciphers are already enabled by default, allow policy to work */
    970    /* p12u_EnableAllCiphers(); */
    971 
    972    return 0;
    973 }
    974 
    975 enum {
    976    opt_CertDir = 0,
    977    opt_TokenName,
    978    opt_Import,
    979    opt_SlotPWFile,
    980    opt_SlotPW,
    981    opt_List,
    982    opt_Nickname,
    983    opt_Export,
    984    opt_Raw,
    985    opt_P12FilePWFile,
    986    opt_P12FilePW,
    987    opt_DBPrefix,
    988    opt_Debug,
    989    opt_Cipher,
    990    opt_CertCipher,
    991    opt_KeyLength,
    992    opt_CertKeyLength,
    993    opt_Mac,
    994    opt_IgnoreIntegrity
    995 };
    996 
    997 static secuCommandFlag pk12util_options[] = {
    998    { /* opt_CertDir	       */ 'd', PR_TRUE, 0, PR_FALSE },
    999    { /* opt_TokenName	       */ 'h', PR_TRUE, 0, PR_FALSE },
   1000    { /* opt_Import	       */ 'i', PR_TRUE, 0, PR_FALSE },
   1001    { /* opt_SlotPWFile	       */ 'k', PR_TRUE, 0, PR_FALSE },
   1002    { /* opt_SlotPW	       */ 'K', PR_TRUE, 0, PR_FALSE },
   1003    { /* opt_List              */ 'l', PR_TRUE, 0, PR_FALSE },
   1004    { /* opt_Nickname	       */ 'n', PR_TRUE, 0, PR_FALSE },
   1005    { /* opt_Export	       */ 'o', PR_TRUE, 0, PR_FALSE },
   1006    { /* opt_Raw   	       */ 'r', PR_FALSE, 0, PR_FALSE },
   1007    { /* opt_P12FilePWFile     */ 'w', PR_TRUE, 0, PR_FALSE },
   1008    { /* opt_P12FilePW	       */ 'W', PR_TRUE, 0, PR_FALSE },
   1009    { /* opt_DBPrefix	       */ 'P', PR_TRUE, 0, PR_FALSE },
   1010    { /* opt_Debug	       */ 'v', PR_FALSE, 0, PR_FALSE },
   1011    { /* opt_Cipher	       */ 'c', PR_TRUE, 0, PR_FALSE },
   1012    { /* opt_CertCipher	       */ 'C', PR_TRUE, 0, PR_FALSE },
   1013    { /* opt_KeyLength         */ 'm', PR_TRUE, 0, PR_FALSE, "key_len" },
   1014    { /* opt_CertKeyLength     */ 0, PR_TRUE, 0, PR_FALSE, "cert_key_len" },
   1015    { /* opt_Mac               */ 'M', PR_TRUE, 0, PR_FALSE },
   1016    { /* opt_IgnoreIntegrity   */ 'I', PR_FALSE, 0, PR_FALSE }
   1017 };
   1018 
   1019 int
   1020 main(int argc, char **argv)
   1021 {
   1022    secuPWData slotPw = { PW_NONE, NULL };
   1023    secuPWData p12FilePw = { PW_NONE, NULL };
   1024    PK11SlotInfo *slot;
   1025    char *slotname = NULL;
   1026    char *import_file = NULL;
   1027    char *export_file = NULL;
   1028    char *dbprefix = "";
   1029    SECStatus rv;
   1030    SECOidTag cipher = SEC_OID_AES_256_CBC;
   1031    SECOidTag hash = SEC_OID_SHA256;
   1032    SECOidTag certCipher = SEC_OID_AES_128_CBC;
   1033    int keyLen = 0;
   1034    int certKeyLen = 0;
   1035    secuCommand pk12util;
   1036    PRInt32 forceUnicode;
   1037    PRBool ignoreIntegrity = PR_FALSE;
   1038 
   1039 #ifdef _CRTDBG_MAP_ALLOC
   1040    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
   1041 #endif
   1042 
   1043    pk12util.numCommands = 0;
   1044    pk12util.commands = 0;
   1045    pk12util.numOptions = sizeof(pk12util_options) / sizeof(secuCommandFlag);
   1046    pk12util.options = pk12util_options;
   1047 
   1048    progName = strrchr(argv[0], '/');
   1049    progName = progName ? progName + 1 : argv[0];
   1050 
   1051    rv = SECU_ParseCommandLine(argc, argv, progName, &pk12util);
   1052 
   1053    if (rv != SECSuccess)
   1054        Usage();
   1055 
   1056    pk12_debugging = pk12util.options[opt_Debug].activated;
   1057 
   1058    if ((pk12util.options[opt_Import].activated +
   1059         pk12util.options[opt_Export].activated +
   1060         pk12util.options[opt_List].activated) != 1) {
   1061        Usage();
   1062    }
   1063 
   1064    if (pk12util.options[opt_Export].activated &&
   1065        !pk12util.options[opt_Nickname].activated) {
   1066        Usage();
   1067    }
   1068 
   1069    rv = NSS_OptionGet(__NSS_PKCS12_DECODE_FORCE_UNICODE, &forceUnicode);
   1070    if (rv != SECSuccess) {
   1071        SECU_PrintError(progName,
   1072                        "Failed to get NSS_PKCS12_DECODE_FORCE_UNICODE option");
   1073        Usage();
   1074    }
   1075    pk12uForceUnicode = forceUnicode;
   1076 
   1077    slotname = SECU_GetOptionArg(&pk12util, opt_TokenName);
   1078 
   1079    import_file = (pk12util.options[opt_List].activated) ? SECU_GetOptionArg(&pk12util, opt_List)
   1080                                                         : SECU_GetOptionArg(&pk12util, opt_Import);
   1081    export_file = SECU_GetOptionArg(&pk12util, opt_Export);
   1082 
   1083    if (pk12util.options[opt_P12FilePWFile].activated) {
   1084        p12FilePw.source = PW_FROMFILE;
   1085        p12FilePw.data = PORT_Strdup(pk12util.options[opt_P12FilePWFile].arg);
   1086    }
   1087 
   1088    if (pk12util.options[opt_P12FilePW].activated) {
   1089        p12FilePw.source = PW_PLAINTEXT;
   1090        p12FilePw.data = PORT_Strdup(pk12util.options[opt_P12FilePW].arg);
   1091    }
   1092 
   1093    if (pk12util.options[opt_SlotPWFile].activated) {
   1094        slotPw.source = PW_FROMFILE;
   1095        slotPw.data = PORT_Strdup(pk12util.options[opt_SlotPWFile].arg);
   1096    }
   1097 
   1098    if (pk12util.options[opt_SlotPW].activated) {
   1099        slotPw.source = PW_PLAINTEXT;
   1100        slotPw.data = PORT_Strdup(pk12util.options[opt_SlotPW].arg);
   1101    }
   1102 
   1103    if (pk12util.options[opt_CertDir].activated) {
   1104        SECU_ConfigDirectory(pk12util.options[opt_CertDir].arg);
   1105    }
   1106    if (pk12util.options[opt_DBPrefix].activated) {
   1107        dbprefix = pk12util.options[opt_DBPrefix].arg;
   1108    }
   1109    if (pk12util.options[opt_Raw].activated) {
   1110        dumpRawFile = PR_TRUE;
   1111    }
   1112    if (pk12util.options[opt_IgnoreIntegrity].activated) {
   1113        ignoreIntegrity = PR_TRUE;
   1114    }
   1115    if (pk12util.options[opt_KeyLength].activated) {
   1116        keyLen = atoi(pk12util.options[opt_KeyLength].arg);
   1117    }
   1118    if (pk12util.options[opt_CertKeyLength].activated) {
   1119        certKeyLen = atoi(pk12util.options[opt_CertKeyLength].arg);
   1120    }
   1121 
   1122    P12U_Init(SECU_ConfigDirectory(NULL), dbprefix,
   1123              pk12util.options[opt_List].activated);
   1124 
   1125    if (!slotname || PL_strcmp(slotname, "internal") == 0)
   1126        slot = PK11_GetInternalKeySlot();
   1127    else
   1128        slot = PK11_FindSlotByName(slotname);
   1129 
   1130    if (!slot) {
   1131        SECU_PrintError(progName, "Invalid slot \"%s\"", slotname);
   1132        pk12uErrno = PK12UERR_PK11GETSLOT;
   1133        goto done;
   1134    }
   1135 
   1136    if (pk12util.options[opt_Cipher].activated) {
   1137        char *cipherString = pk12util.options[opt_Cipher].arg;
   1138 
   1139        cipher = PKCS12U_MapCipherFromString(cipherString, keyLen);
   1140        /* We only want encryption PBE's. make sure we don't have
   1141         * any MAC pbes */
   1142        if (cipher == SEC_OID_UNKNOWN) {
   1143            PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
   1144            SECU_PrintError(progName, "Algorithm: \"%s\"", cipherString);
   1145            pk12uErrno = PK12UERR_INVALIDALGORITHM;
   1146            goto done;
   1147        }
   1148    }
   1149 
   1150    if (pk12util.options[opt_CertCipher].activated) {
   1151        char *cipherString = pk12util.options[opt_CertCipher].arg;
   1152 
   1153        if (PORT_Strcasecmp(cipherString, "none") == 0) {
   1154            certCipher = SEC_OID_UNKNOWN;
   1155        } else {
   1156            certCipher = PKCS12U_MapCipherFromString(cipherString, certKeyLen);
   1157            /* If the user requested a cipher and we didn't find it, then
   1158             * don't just silently not encrypt. */
   1159            if (certCipher == SEC_OID_UNKNOWN) {
   1160                PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
   1161                SECU_PrintError(progName, "Algorithm: \"%s\"", cipherString);
   1162                pk12uErrno = PK12UERR_INVALIDALGORITHM;
   1163                goto done;
   1164            }
   1165        }
   1166    }
   1167    /* in FIPS mode default to encoding with pkcs5v2 for the MAC */
   1168    if (PK11_IsFIPS()) {
   1169        hash = SEC_OID_HMAC_SHA256;
   1170    }
   1171    if (pk12util.options[opt_Mac].activated) {
   1172        char *hashString = pk12util.options[opt_Mac].arg;
   1173 
   1174        hash = PKCS12U_MapHashFromString(hashString);
   1175        /* We don't support creating Mac-less pkcs 12 files */
   1176        if (hash == SEC_OID_UNKNOWN) {
   1177            PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
   1178            SECU_PrintError(progName, "Algorithm: \"%s\"", hashString);
   1179            pk12uErrno = PK12UERR_INVALIDALGORITHM;
   1180            goto done;
   1181        }
   1182    }
   1183 
   1184    if (pk12util.options[opt_Import].activated) {
   1185        P12U_ImportPKCS12Object(import_file, slot, &slotPw, &p12FilePw,
   1186                                ignoreIntegrity);
   1187 
   1188    } else if (pk12util.options[opt_Export].activated) {
   1189        P12U_ExportPKCS12Object(pk12util.options[opt_Nickname].arg,
   1190                                export_file, slot, cipher, certCipher,
   1191                                hash, &slotPw, &p12FilePw);
   1192 
   1193    } else if (pk12util.options[opt_List].activated) {
   1194        P12U_ListPKCS12File(import_file, slot, &slotPw, &p12FilePw,
   1195                            ignoreIntegrity);
   1196 
   1197    } else {
   1198        Usage();
   1199        pk12uErrno = PK12UERR_USAGE;
   1200    }
   1201 
   1202 done:
   1203    if (import_file != NULL)
   1204        PORT_ZFree(import_file, PL_strlen(import_file));
   1205    if (export_file != NULL)
   1206        PORT_ZFree(export_file, PL_strlen(export_file));
   1207    if (slotPw.data != NULL)
   1208        PORT_ZFree(slotPw.data, PL_strlen(slotPw.data));
   1209    if (p12FilePw.data != NULL)
   1210        PORT_ZFree(p12FilePw.data, PL_strlen(p12FilePw.data));
   1211    if (slot)
   1212        PK11_FreeSlot(slot);
   1213    if (NSS_Shutdown() != SECSuccess) {
   1214        pk12uErrno = 1;
   1215    }
   1216    PL_ArenaFinish();
   1217    PR_Cleanup();
   1218    return pk12uErrno;
   1219 }