tor-browser

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

certutil.c (142847B)


      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 /*
      6 ** certutil.c
      7 **
      8 ** utility for managing certificates and the cert database
      9 **
     10 */
     11 #include <stdio.h>
     12 #include <string.h>
     13 #include <stdlib.h>
     14 
     15 #if defined(WIN32)
     16 #include "fcntl.h"
     17 #include "io.h"
     18 #endif
     19 
     20 #include "secutil.h"
     21 
     22 #if defined(XP_UNIX)
     23 #include <unistd.h>
     24 #endif
     25 
     26 #include "nspr.h"
     27 #include "prtypes.h"
     28 #include "prtime.h"
     29 #include "prlong.h"
     30 
     31 #include "pk11func.h"
     32 #include "secasn1.h"
     33 #include "cert.h"
     34 #include "cryptohi.h"
     35 #include "secoid.h"
     36 #include "certdb.h"
     37 #include "nss.h"
     38 #include "certutil.h"
     39 #include "basicutil.h"
     40 #include "ssl.h"
     41 
     42 #define MIN_KEY_BITS 512
     43 /* MAX_KEY_BITS should agree with RSA_MAX_MODULUS_BITS in freebl */
     44 #define MAX_KEY_BITS 8192
     45 #define DEFAULT_KEY_BITS 2048
     46 
     47 #define GEN_BREAK(e) \
     48    rv = e;          \
     49    break;
     50 
     51 char *progName;
     52 
     53 static SECStatus
     54 ChangeCertTrust(CERTCertDBHandle *handle, CERTCertificate *cert,
     55                CERTCertTrust *trust, PK11SlotInfo *slot, void *pwdata)
     56 {
     57    SECStatus rv;
     58 
     59    rv = CERT_ChangeCertTrust(handle, cert, trust);
     60    if (rv != SECSuccess) {
     61        if (PORT_GetError() == SEC_ERROR_TOKEN_NOT_LOGGED_IN) {
     62            rv = PK11_Authenticate(slot, PR_TRUE, pwdata);
     63            if (PORT_GetError() == SEC_ERROR_TOKEN_NOT_LOGGED_IN) {
     64                PK11SlotInfo *internalslot;
     65                internalslot = PK11_GetInternalKeySlot();
     66                rv = PK11_Authenticate(internalslot, PR_TRUE, pwdata);
     67                if (rv != SECSuccess) {
     68                    SECU_PrintError(progName,
     69                                    "could not authenticate to token %s.",
     70                                    PK11_GetTokenName(internalslot));
     71                    PK11_FreeSlot(internalslot);
     72                    return SECFailure;
     73                }
     74                PK11_FreeSlot(internalslot);
     75            }
     76            rv = CERT_ChangeCertTrust(handle, cert, trust);
     77        }
     78    }
     79    return rv;
     80 }
     81 
     82 static CERTCertificateRequest *
     83 GetCertRequest(const SECItem *reqDER, void *pwarg)
     84 {
     85    CERTCertificateRequest *certReq = NULL;
     86    CERTSignedData signedData;
     87    PLArenaPool *arena = NULL;
     88    SECStatus rv;
     89 
     90    do {
     91        arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
     92        if (arena == NULL) {
     93            GEN_BREAK(SECFailure);
     94        }
     95 
     96        certReq = (CERTCertificateRequest *)PORT_ArenaZAlloc(arena, sizeof(CERTCertificateRequest));
     97        if (!certReq) {
     98            GEN_BREAK(SECFailure);
     99        }
    100        certReq->arena = arena;
    101 
    102        /* Since cert request is a signed data, must decode to get the inner
    103           data
    104         */
    105        PORT_Memset(&signedData, 0, sizeof(signedData));
    106        rv = SEC_ASN1DecodeItem(arena, &signedData,
    107                                SEC_ASN1_GET(CERT_SignedDataTemplate), reqDER);
    108        if (rv) {
    109            break;
    110        }
    111        rv = SEC_ASN1DecodeItem(arena, certReq,
    112                                SEC_ASN1_GET(CERT_CertificateRequestTemplate), &signedData.data);
    113        if (rv) {
    114            break;
    115        }
    116        rv = CERT_VerifySignedDataWithPublicKeyInfo(&signedData,
    117                                                    &certReq->subjectPublicKeyInfo, pwarg);
    118    } while (0);
    119 
    120    if (rv) {
    121        SECU_PrintError(progName, "bad certificate request\n");
    122        if (arena) {
    123            PORT_FreeArena(arena, PR_FALSE);
    124        }
    125        certReq = NULL;
    126    }
    127 
    128    return certReq;
    129 }
    130 
    131 static SECStatus
    132 AddCert(PK11SlotInfo *slot, CERTCertDBHandle *handle, char *name, char *trusts,
    133        const SECItem *certDER, PRBool emailcert, void *pwdata)
    134 {
    135    CERTCertTrust *trust = NULL;
    136    CERTCertificate *cert = NULL;
    137    SECStatus rv;
    138 
    139    do {
    140        /* Read in an ASCII cert and return a CERTCertificate */
    141        cert = CERT_DecodeCertFromPackage((char *)certDER->data, certDER->len);
    142        if (!cert) {
    143            SECU_PrintError(progName, "could not decode certificate");
    144            GEN_BREAK(SECFailure);
    145        }
    146 
    147        /* Create a cert trust */
    148        trust = (CERTCertTrust *)PORT_ZAlloc(sizeof(CERTCertTrust));
    149        if (!trust) {
    150            SECU_PrintError(progName, "unable to allocate cert trust");
    151            GEN_BREAK(SECFailure);
    152        }
    153 
    154        rv = CERT_DecodeTrustString(trust, trusts);
    155        if (rv) {
    156            SECU_PrintError(progName, "unable to decode trust string");
    157            GEN_BREAK(SECFailure);
    158        }
    159 
    160        rv = PK11_ImportCert(slot, cert, CK_INVALID_HANDLE, name, PR_FALSE);
    161        if (rv != SECSuccess) {
    162            /* sigh, PK11_Import Cert and CERT_ChangeCertTrust should have
    163             * been coded to take a password arg. */
    164            if (PORT_GetError() == SEC_ERROR_TOKEN_NOT_LOGGED_IN) {
    165                rv = PK11_Authenticate(slot, PR_TRUE, pwdata);
    166                if (rv != SECSuccess) {
    167                    SECU_PrintError(progName,
    168                                    "could not authenticate to token %s.",
    169                                    PK11_GetTokenName(slot));
    170                    GEN_BREAK(SECFailure);
    171                }
    172                rv = PK11_ImportCert(slot, cert, CK_INVALID_HANDLE,
    173                                     name, PR_FALSE);
    174            }
    175            if (rv != SECSuccess) {
    176                SECU_PrintError(progName,
    177                                "could not add certificate to token or database");
    178                GEN_BREAK(SECFailure);
    179            }
    180        }
    181        rv = ChangeCertTrust(handle, cert, trust, slot, pwdata);
    182        if (rv != SECSuccess) {
    183            SECU_PrintError(progName,
    184                            "could not change trust on certificate");
    185            GEN_BREAK(SECFailure);
    186        }
    187 
    188        if (emailcert) {
    189            CERT_SaveSMimeProfile(cert, NULL, pwdata);
    190        }
    191 
    192    } while (0);
    193 
    194    CERT_DestroyCertificate(cert);
    195    PORT_Free(trust);
    196 
    197    return rv;
    198 }
    199 
    200 static SECStatus
    201 CertReq(SECKEYPrivateKey *privk, SECKEYPublicKey *pubk, KeyType keyType,
    202        SECOidTag hashAlgTag, CERTName *subject, const char *phone, int ascii,
    203        const char *emailAddrs, const char *dnsNames,
    204        certutilExtnList extnList, const char *extGeneric,
    205        PRBool pssCertificate, /*out*/ SECItem *result)
    206 {
    207    CERTSubjectPublicKeyInfo *spki;
    208    CERTCertificateRequest *cr;
    209    SECItem *encoding;
    210    SECOidTag signAlgTag = SEC_OID_UNKNOWN;
    211    SECStatus rv;
    212    PLArenaPool *arena;
    213    void *extHandle;
    214    SECItem signedReq = { siBuffer, NULL, 0 };
    215    SECAlgorithmID signAlg;
    216 
    217    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    218    if (!arena) {
    219        SECU_PrintError(progName, "out of memory");
    220        return SECFailure;
    221    }
    222 
    223    /* Create info about public key */
    224    spki = SECKEY_CreateSubjectPublicKeyInfo(pubk);
    225    if (!spki) {
    226        PORT_FreeArena(arena, PR_FALSE);
    227        SECU_PrintError(progName, "unable to create subject public key");
    228        return SECFailure;
    229    }
    230 
    231    /* Change cert type to RSA-PSS, if desired. */
    232    if (pssCertificate) {
    233        /* force a PSS signature. We can do a PSS signature with an
    234         * RSA key, this will force us to generate a PSS signature */
    235        signAlgTag = SEC_OID_PKCS1_RSA_PSS_SIGNATURE;
    236        /* override the SPKI algorithm id. */
    237        rv = SEC_CreateSignatureAlgorithmID(arena, &spki->algorithm,
    238                                            signAlgTag, hashAlgTag,
    239                                            NULL, NULL, pubk);
    240        if (rv != SECSuccess) {
    241            PORT_FreeArena(arena, PR_FALSE);
    242            SECKEY_DestroySubjectPublicKeyInfo(spki);
    243            SECU_PrintError(progName, "unable to set algorithm ID");
    244            return SECFailure;
    245        }
    246    }
    247 
    248    /* Generate certificate request */
    249    cr = CERT_CreateCertificateRequest(subject, spki, NULL);
    250    SECKEY_DestroySubjectPublicKeyInfo(spki);
    251    if (!cr) {
    252        PORT_FreeArena(arena, PR_FALSE);
    253        SECU_PrintError(progName, "unable to make certificate request");
    254        return SECFailure;
    255    }
    256 
    257    extHandle = CERT_StartCertificateRequestAttributes(cr);
    258    if (extHandle == NULL) {
    259        PORT_FreeArena(arena, PR_FALSE);
    260        CERT_DestroyCertificateRequest(cr);
    261        return SECFailure;
    262    }
    263    if (AddExtensions(extHandle, emailAddrs, dnsNames, extnList, extGeneric) !=
    264        SECSuccess) {
    265        PORT_FreeArena(arena, PR_FALSE);
    266        CERT_FinishExtensions(extHandle);
    267        CERT_DestroyCertificateRequest(cr);
    268        return SECFailure;
    269    }
    270    CERT_FinishExtensions(extHandle);
    271    CERT_FinishCertificateRequestAttributes(cr);
    272 
    273    /* Der encode the request */
    274    encoding = SEC_ASN1EncodeItem(arena, NULL, cr,
    275                                  SEC_ASN1_GET(CERT_CertificateRequestTemplate));
    276    CERT_DestroyCertificateRequest(cr);
    277    if (encoding == NULL) {
    278        PORT_FreeArena(arena, PR_FALSE);
    279        SECU_PrintError(progName, "der encoding of request failed");
    280        return SECFailure;
    281    }
    282 
    283    PORT_Memset(&signAlg, 0, sizeof(signAlg));
    284    rv = SEC_CreateSignatureAlgorithmID(arena, &signAlg, signAlgTag, hashAlgTag,
    285                                        NULL, privk, NULL);
    286    if (rv != SECSuccess) {
    287        PORT_FreeArena(arena, PR_FALSE);
    288        SECU_PrintError(progName, "can't create a signature algorithm id");
    289        return SECFailure;
    290    }
    291 
    292    /* Sign the request */
    293    rv = SEC_DerSignDataWithAlgorithmID(arena, &signedReq,
    294                                        encoding->data, encoding->len,
    295                                        privk, &signAlg);
    296    if (rv) {
    297        PORT_FreeArena(arena, PR_FALSE);
    298        SECU_PrintError(progName, "signing of data failed");
    299        return SECFailure;
    300    }
    301 
    302    /* Encode request in specified format */
    303    if (ascii) {
    304        char *obuf;
    305        char *header, *name, *email, *org, *state, *country;
    306 
    307        obuf = BTOA_ConvertItemToAscii(&signedReq);
    308        if (!obuf) {
    309            goto oom;
    310        }
    311 
    312        name = CERT_GetCommonName(subject);
    313        if (!name) {
    314            name = PORT_Strdup("(not specified)");
    315        }
    316 
    317        if (!phone)
    318            phone = "(not specified)";
    319 
    320        email = CERT_GetCertEmailAddress(subject);
    321        if (!email)
    322            email = PORT_Strdup("(not specified)");
    323 
    324        org = CERT_GetOrgName(subject);
    325        if (!org)
    326            org = PORT_Strdup("(not specified)");
    327 
    328        state = CERT_GetStateName(subject);
    329        if (!state)
    330            state = PORT_Strdup("(not specified)");
    331 
    332        country = CERT_GetCountryName(subject);
    333        if (!country)
    334            country = PORT_Strdup("(not specified)");
    335 
    336        header = PR_smprintf(
    337            "\nCertificate request generated by Netscape certutil\n"
    338            "Phone: %s\n\n"
    339            "Common Name: %s\n"
    340            "Email: %s\n"
    341            "Organization: %s\n"
    342            "State: %s\n"
    343            "Country: %s\n\n"
    344            "%s\n",
    345            phone, name, email, org, state, country, NS_CERTREQ_HEADER);
    346 
    347        PORT_Free(name);
    348        PORT_Free(email);
    349        PORT_Free(org);
    350        PORT_Free(state);
    351        PORT_Free(country);
    352 
    353        if (header) {
    354            char *trailer = PR_smprintf("\n%s\n", NS_CERTREQ_TRAILER);
    355            if (trailer) {
    356                PRUint32 headerLen = PL_strlen(header);
    357                PRUint32 obufLen = PL_strlen(obuf);
    358                PRUint32 trailerLen = PL_strlen(trailer);
    359                SECITEM_AllocItem(NULL, result,
    360                                  headerLen + obufLen + trailerLen);
    361                if (result->data) {
    362                    PORT_Memcpy(result->data, header, headerLen);
    363                    PORT_Memcpy(result->data + headerLen, obuf, obufLen);
    364                    PORT_Memcpy(result->data + headerLen + obufLen,
    365                                trailer, trailerLen);
    366                }
    367                PR_smprintf_free(trailer);
    368            }
    369            PR_smprintf_free(header);
    370        }
    371        PORT_Free(obuf);
    372    } else {
    373        (void)SECITEM_CopyItem(NULL, result, &signedReq);
    374    }
    375 
    376    if (!result->data) {
    377    oom:
    378        SECU_PrintError(progName, "out of memory");
    379        PORT_SetError(SEC_ERROR_NO_MEMORY);
    380        rv = SECFailure;
    381    }
    382 
    383    PORT_FreeArena(arena, PR_FALSE);
    384    return rv;
    385 }
    386 
    387 static SECStatus
    388 ChangeTrustAttributes(CERTCertDBHandle *handle, PK11SlotInfo *slot,
    389                      char *name, char *trusts, void *pwdata)
    390 {
    391    SECStatus rv;
    392    CERTCertificate *cert;
    393    CERTCertTrust *trust;
    394 
    395    cert = CERT_FindCertByNicknameOrEmailAddrCX(handle, name, pwdata);
    396    if (!cert) {
    397        SECU_PrintError(progName, "could not find certificate named \"%s\"",
    398                        name);
    399        return SECFailure;
    400    }
    401 
    402    trust = (CERTCertTrust *)PORT_ZAlloc(sizeof(CERTCertTrust));
    403    if (!trust) {
    404        SECU_PrintError(progName, "unable to allocate cert trust");
    405        return SECFailure;
    406    }
    407 
    408    /* This function only decodes these characters: pPwcTCu, */
    409    rv = CERT_DecodeTrustString(trust, trusts);
    410    if (rv) {
    411        SECU_PrintError(progName, "unable to decode trust string");
    412        return SECFailure;
    413    }
    414 
    415    /* CERT_ChangeCertTrust API does not have a way to pass in
    416     * a context, so NSS can't prompt for the password if it needs to.
    417     * check to see if the failure was token not logged in and
    418     * log in if need be. */
    419    rv = ChangeCertTrust(handle, cert, trust, slot, pwdata);
    420    if (rv != SECSuccess) {
    421        SECU_PrintError(progName, "unable to modify trust attributes");
    422        return SECFailure;
    423    }
    424    CERT_DestroyCertificate(cert);
    425    PORT_Free(trust);
    426 
    427    return SECSuccess;
    428 }
    429 
    430 static SECStatus
    431 DumpChain(CERTCertDBHandle *handle, char *name, PRBool ascii,
    432          PRBool simpleSelfSigned)
    433 {
    434    CERTCertificate *the_cert;
    435    CERTCertificateList *chain;
    436    int i, j;
    437    the_cert = SECU_FindCertByNicknameOrFilename(handle, name,
    438                                                 ascii, NULL);
    439    if (!the_cert) {
    440        SECU_PrintError(progName, "Could not find: %s\n", name);
    441        return SECFailure;
    442    }
    443    if (simpleSelfSigned &&
    444        SECEqual == SECITEM_CompareItem(&the_cert->derIssuer,
    445                                        &the_cert->derSubject)) {
    446        printf("\"%s\" [%s]\n\n", the_cert->nickname, the_cert->subjectName);
    447        CERT_DestroyCertificate(the_cert);
    448        return SECSuccess;
    449    }
    450 
    451    chain = CERT_CertChainFromCert(the_cert, 0, PR_TRUE);
    452    CERT_DestroyCertificate(the_cert);
    453    if (!chain) {
    454        SECU_PrintError(progName, "Could not obtain chain for: %s\n", name);
    455        return SECFailure;
    456    }
    457    for (i = chain->len - 1; i >= 0; i--) {
    458        CERTCertificate *c;
    459        c = CERT_FindCertByDERCert(handle, &chain->certs[i]);
    460        for (j = i; j < chain->len - 1; j++) {
    461            printf("  ");
    462        }
    463        if (c) {
    464            printf("\"%s\" [%s]\n\n", c->nickname, c->subjectName);
    465            CERT_DestroyCertificate(c);
    466        } else {
    467            printf("(null)\n\n");
    468        }
    469    }
    470    CERT_DestroyCertificateList(chain);
    471    return SECSuccess;
    472 }
    473 
    474 static SECStatus
    475 outputCertOrExtension(CERTCertificate *the_cert, PRBool raw, PRBool ascii,
    476                      SECItem *extensionOID, PRFileDesc *outfile)
    477 {
    478    SECItem data;
    479    PRInt32 numBytes;
    480    SECStatus rv = SECFailure;
    481    if (extensionOID) {
    482        int i;
    483        PRBool found = PR_FALSE;
    484        for (i = 0; the_cert->extensions[i] != NULL; i++) {
    485            CERTCertExtension *extension = the_cert->extensions[i];
    486            if (SECITEM_CompareItem(&extension->id, extensionOID) == SECEqual) {
    487                found = PR_TRUE;
    488                numBytes = PR_Write(outfile, extension->value.data,
    489                                    extension->value.len);
    490                rv = SECSuccess;
    491                if (numBytes != (PRInt32)extension->value.len) {
    492                    SECU_PrintSystemError(progName, "error writing extension");
    493                    rv = SECFailure;
    494                }
    495                break;
    496            }
    497        }
    498        if (!found) {
    499            SECU_PrintSystemError(progName, "extension not found");
    500            rv = SECFailure;
    501        }
    502    } else {
    503        data.data = the_cert->derCert.data;
    504        data.len = the_cert->derCert.len;
    505        if (ascii) {
    506            PR_fprintf(outfile, "%s\n%s\n%s\n", NS_CERT_HEADER,
    507                       BTOA_DataToAscii(data.data, data.len), NS_CERT_TRAILER);
    508            rv = SECSuccess;
    509        } else if (raw) {
    510            numBytes = PR_Write(outfile, data.data, data.len);
    511            rv = SECSuccess;
    512            if (numBytes != (PRInt32)data.len) {
    513                SECU_PrintSystemError(progName, "error writing raw cert");
    514                rv = SECFailure;
    515            }
    516        } else {
    517            rv = SEC_PrintCertificateAndTrust(the_cert, "Certificate", NULL);
    518            if (rv != SECSuccess) {
    519                SECU_PrintError(progName, "problem printing certificate");
    520            }
    521        }
    522    }
    523    return rv;
    524 }
    525 
    526 static SECStatus
    527 listCerts(CERTCertDBHandle *handle, char *name, char *email,
    528          PK11SlotInfo *slot, PRBool raw, PRBool ascii,
    529          SECItem *extensionOID,
    530          PRFileDesc *outfile, void *pwarg)
    531 {
    532    SECStatus rv = SECFailure;
    533    CERTCertList *certs;
    534    CERTCertListNode *node;
    535 
    536    /* List certs on a non-internal slot. */
    537    if (!PK11_IsFriendly(slot) && PK11_NeedLogin(slot)) {
    538        SECStatus newrv = PK11_Authenticate(slot, PR_TRUE, pwarg);
    539        if (newrv != SECSuccess) {
    540            SECU_PrintError(progName, "could not authenticate to token %s.",
    541                            PK11_GetTokenName(slot));
    542            return SECFailure;
    543        }
    544    }
    545    if (name) {
    546        CERTCertificate *the_cert =
    547            SECU_FindCertByNicknameOrFilename(handle, name, ascii, NULL);
    548        if (!the_cert) {
    549            SECU_PrintError(progName, "Could not find cert: %s\n", name);
    550            return SECFailure;
    551        }
    552        /* Here, we have one cert with the desired nickname or email
    553         * address.  Now, we will attempt to get a list of ALL certs
    554         * with the same subject name as the cert we have.  That list
    555         * should contain, at a minimum, the one cert we have already found.
    556         * If the list of certs is empty (NULL), the libraries have failed.
    557         */
    558        certs = CERT_CreateSubjectCertList(NULL, handle, &the_cert->derSubject,
    559                                           PR_Now(), PR_FALSE);
    560        CERT_DestroyCertificate(the_cert);
    561        if (!certs) {
    562            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
    563            SECU_PrintError(progName, "problem printing certificates");
    564            return SECFailure;
    565        }
    566        for (node = CERT_LIST_HEAD(certs); !CERT_LIST_END(node, certs);
    567             node = CERT_LIST_NEXT(node)) {
    568            rv = outputCertOrExtension(node->cert, raw, ascii, extensionOID,
    569                                       outfile);
    570            if (rv != SECSuccess) {
    571                break;
    572            }
    573        }
    574    } else if (email) {
    575        certs = PK11_FindCertsFromEmailAddress(email, NULL);
    576        if (!certs) {
    577            SECU_PrintError(progName,
    578                            "Could not find certificates for email address: %s\n",
    579                            email);
    580            return SECFailure;
    581        }
    582        for (node = CERT_LIST_HEAD(certs); !CERT_LIST_END(node, certs);
    583             node = CERT_LIST_NEXT(node)) {
    584            rv = outputCertOrExtension(node->cert, raw, ascii, extensionOID,
    585                                       outfile);
    586            if (rv != SECSuccess) {
    587                break;
    588            }
    589        }
    590    } else {
    591        certs = PK11_ListCertsInSlot(slot);
    592        if (certs) {
    593            for (node = CERT_LIST_HEAD(certs); !CERT_LIST_END(node, certs);
    594                 node = CERT_LIST_NEXT(node)) {
    595                SECU_PrintCertNickname(node, stdout);
    596            }
    597            rv = SECSuccess;
    598        }
    599    }
    600    if (certs) {
    601        CERT_DestroyCertList(certs);
    602    }
    603    if (rv) {
    604        SECU_PrintError(progName, "problem printing certificate nicknames");
    605        return SECFailure;
    606    }
    607 
    608    return SECSuccess; /* not rv ?? */
    609 }
    610 
    611 static SECStatus
    612 ListCerts(CERTCertDBHandle *handle, char *nickname, char *email,
    613          PK11SlotInfo *slot, PRBool raw, PRBool ascii,
    614          SECItem *extensionOID,
    615          PRFileDesc *outfile, secuPWData *pwdata)
    616 {
    617    SECStatus rv;
    618 
    619    if (slot && PK11_NeedUserInit(slot)) {
    620        printf("\nDatabase needs user init\n");
    621    }
    622 
    623    if (!ascii && !raw && !nickname && !email) {
    624        PR_fprintf(outfile, "\n%-60s %-5s\n%-60s %-5s\n\n",
    625                   "Certificate Nickname", "Trust Attributes", "",
    626                   "SSL,S/MIME,JAR/XPI");
    627    }
    628    if (slot == NULL) {
    629        CERTCertList *list;
    630        CERTCertListNode *node;
    631 
    632        list = PK11_ListCerts(PK11CertListAll, pwdata);
    633        for (node = CERT_LIST_HEAD(list); !CERT_LIST_END(node, list);
    634             node = CERT_LIST_NEXT(node)) {
    635            SECU_PrintCertNickname(node, stdout);
    636        }
    637        CERT_DestroyCertList(list);
    638        return SECSuccess;
    639    }
    640    rv = listCerts(handle, nickname, email, slot, raw, ascii,
    641                   extensionOID, outfile, pwdata);
    642    return rv;
    643 }
    644 
    645 static SECStatus
    646 DeleteCert(CERTCertDBHandle *handle, char *name, void *pwdata)
    647 {
    648    SECStatus rv;
    649    CERTCertificate *cert;
    650 
    651    cert = CERT_FindCertByNicknameOrEmailAddrCX(handle, name, pwdata);
    652    if (!cert) {
    653        SECU_PrintError(progName, "could not find certificate named \"%s\"",
    654                        name);
    655        return SECFailure;
    656    }
    657 
    658    rv = SEC_DeletePermCertificate(cert);
    659    CERT_DestroyCertificate(cert);
    660    if (rv) {
    661        SECU_PrintError(progName, "unable to delete certificate");
    662    }
    663    return rv;
    664 }
    665 
    666 static SECStatus
    667 RenameCert(CERTCertDBHandle *handle, char *name, char *newName, void *pwdata)
    668 {
    669    SECStatus rv;
    670    CERTCertificate *cert;
    671 
    672    cert = CERT_FindCertByNicknameOrEmailAddrCX(handle, name, pwdata);
    673    if (!cert) {
    674        SECU_PrintError(progName, "could not find certificate named \"%s\"",
    675                        name);
    676        return SECFailure;
    677    }
    678 
    679    rv = __PK11_SetCertificateNickname(cert, newName);
    680    CERT_DestroyCertificate(cert);
    681    if (rv) {
    682        SECU_PrintError(progName, "unable to rename certificate");
    683    }
    684    return rv;
    685 }
    686 
    687 static SECStatus
    688 ValidateCert(CERTCertDBHandle *handle, char *name, char *date,
    689             char *certUsage, PRBool checkSig, PRBool logit,
    690             PRBool ascii, secuPWData *pwdata)
    691 {
    692    SECStatus rv;
    693    CERTCertificate *cert = NULL;
    694    PRTime timeBoundary;
    695    SECCertificateUsage usage;
    696    CERTVerifyLog reallog;
    697    CERTVerifyLog *log = NULL;
    698 
    699    if (!certUsage) {
    700        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    701        return (SECFailure);
    702    }
    703 
    704    switch (*certUsage) {
    705        case 'O':
    706            usage = certificateUsageStatusResponder;
    707            break;
    708        case 'L':
    709            usage = certificateUsageSSLCA;
    710            break;
    711        case 'A':
    712            usage = certificateUsageAnyCA;
    713            break;
    714        case 'Y':
    715            usage = certificateUsageVerifyCA;
    716            break;
    717        case 'C':
    718            usage = certificateUsageSSLClient;
    719            break;
    720        case 'V':
    721            usage = certificateUsageSSLServer;
    722            break;
    723        case 'I':
    724            usage = certificateUsageIPsec;
    725            break;
    726        case 'S':
    727            usage = certificateUsageEmailSigner;
    728            break;
    729        case 'R':
    730            usage = certificateUsageEmailRecipient;
    731            break;
    732        case 'J':
    733            usage = certificateUsageObjectSigner;
    734            break;
    735        default:
    736            PORT_SetError(SEC_ERROR_INVALID_ARGS);
    737            return (SECFailure);
    738    }
    739    do {
    740        cert = SECU_FindCertByNicknameOrFilename(handle, name, ascii,
    741                                                 NULL);
    742        if (!cert) {
    743            SECU_PrintError(progName, "could not find certificate named \"%s\"",
    744                            name);
    745            GEN_BREAK(SECFailure)
    746        }
    747 
    748        if (date != NULL) {
    749            rv = DER_AsciiToTime(&timeBoundary, date);
    750            if (rv) {
    751                SECU_PrintError(progName, "invalid input date");
    752                GEN_BREAK(SECFailure)
    753            }
    754        } else {
    755            timeBoundary = PR_Now();
    756        }
    757 
    758        if (logit) {
    759            log = &reallog;
    760 
    761            log->count = 0;
    762            log->head = NULL;
    763            log->tail = NULL;
    764            log->arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    765            if (log->arena == NULL) {
    766                SECU_PrintError(progName, "out of memory");
    767                GEN_BREAK(SECFailure)
    768            }
    769        }
    770 
    771        rv = CERT_VerifyCertificate(handle, cert, checkSig, usage,
    772                                    timeBoundary, pwdata, log, &usage);
    773        if (log) {
    774            if (log->head == NULL) {
    775                fprintf(stdout, "%s: certificate is valid\n", progName);
    776                GEN_BREAK(SECSuccess)
    777            } else {
    778                char *nick;
    779                CERTVerifyLogNode *node;
    780 
    781                node = log->head;
    782                while (node) {
    783                    if (node->cert->nickname != NULL) {
    784                        nick = node->cert->nickname;
    785                    } else {
    786                        nick = node->cert->subjectName;
    787                    }
    788                    fprintf(stderr, "%s : %s\n", nick,
    789                            SECU_Strerror(node->error));
    790                    CERT_DestroyCertificate(node->cert);
    791                    node = node->next;
    792                }
    793            }
    794        } else {
    795            if (rv != SECSuccess) {
    796                PRErrorCode perr = PORT_GetError();
    797                fprintf(stdout, "%s: certificate is invalid: %s\n",
    798                        progName, SECU_Strerror(perr));
    799                GEN_BREAK(SECFailure)
    800            }
    801            fprintf(stdout, "%s: certificate is valid\n", progName);
    802            GEN_BREAK(SECSuccess)
    803        }
    804    } while (0);
    805 
    806    if (cert) {
    807        CERT_DestroyCertificate(cert);
    808    }
    809 
    810    return (rv);
    811 }
    812 
    813 static PRBool
    814 ItemIsPrintableASCII(const SECItem *item)
    815 {
    816    unsigned char *src = item->data;
    817    unsigned int len = item->len;
    818    while (len-- > 0) {
    819        unsigned char uc = *src++;
    820        if (uc < 0x20 || uc > 0x7e)
    821            return PR_FALSE;
    822    }
    823    return PR_TRUE;
    824 }
    825 
    826 /* Caller ensures that dst is at least item->len*2+1 bytes long */
    827 static void
    828 SECItemToHex(const SECItem *item, char *dst)
    829 {
    830    if (dst && item && item->data) {
    831        unsigned char *src = item->data;
    832        unsigned int len = item->len;
    833        for (; len > 0; --len, dst += 2) {
    834            snprintf(dst, 3, "%02x", *src++);
    835        }
    836        *dst = '\0';
    837    }
    838 }
    839 
    840 #define MAX_CKA_ID_BIN_LEN 20
    841 #define MAX_CKA_ID_STR_LEN 40
    842 
    843 /* output human readable key ID in buffer, which should have at least
    844 * MAX_CKA_ID_STR_LEN + 3 octets (quotations and a null terminator) */
    845 static void
    846 formatPrivateKeyID(SECKEYPrivateKey *privkey, char *buffer)
    847 {
    848    SECItem *ckaID;
    849 
    850    ckaID = PK11_GetLowLevelKeyIDForPrivateKey(privkey);
    851    if (!ckaID) {
    852        strcpy(buffer, "(no CKA_ID)");
    853    } else if (ItemIsPrintableASCII(ckaID)) {
    854        int len = PR_MIN(MAX_CKA_ID_STR_LEN, ckaID->len);
    855        buffer[0] = '"';
    856        memcpy(buffer + 1, ckaID->data, len);
    857        buffer[1 + len] = '"';
    858        buffer[2 + len] = '\0';
    859    } else {
    860        /* print ckaid in hex */
    861        SECItem idItem = *ckaID;
    862        if (idItem.len > MAX_CKA_ID_BIN_LEN)
    863            idItem.len = MAX_CKA_ID_BIN_LEN;
    864        SECItemToHex(&idItem, buffer);
    865    }
    866    SECITEM_ZfreeItem(ckaID, PR_TRUE);
    867 }
    868 
    869 /* print key number, key ID (in hex or ASCII), key label (nickname) */
    870 static SECStatus
    871 PrintKey(PRFileDesc *out, const char *nickName, int count,
    872         SECKEYPrivateKey *key, void *pwarg)
    873 {
    874    char ckaIDbuf[MAX_CKA_ID_STR_LEN + 4];
    875    CERTCertificate *cert;
    876    KeyType keyType;
    877 
    878    formatPrivateKeyID(key, ckaIDbuf);
    879    cert = PK11_GetCertFromPrivateKey(key);
    880    if (cert) {
    881        keyType = CERT_GetCertKeyType(&cert->subjectPublicKeyInfo);
    882        CERT_DestroyCertificate(cert);
    883    } else {
    884        keyType = key->keyType;
    885    }
    886    PR_fprintf(out, "<%2d> %-8.8s %-42.42s %s\n", count,
    887               SECKEY_GetKeyTypeString(keyType), ckaIDbuf, nickName);
    888 
    889    return SECSuccess;
    890 }
    891 
    892 /* returns SECSuccess if ANY keys are found, SECFailure otherwise. */
    893 static SECStatus
    894 ListKeysInSlot(PK11SlotInfo *slot, const char *nickName, KeyType keyType,
    895               void *pwarg)
    896 {
    897    SECKEYPrivateKeyList *list;
    898    SECKEYPrivateKeyListNode *node;
    899    int count = 0;
    900 
    901    if (PK11_NeedLogin(slot)) {
    902        SECStatus rv = PK11_Authenticate(slot, PR_TRUE, pwarg);
    903        if (rv != SECSuccess) {
    904            SECU_PrintError(progName, "could not authenticate to token %s.",
    905                            PK11_GetTokenName(slot));
    906            return SECFailure;
    907        }
    908    }
    909 
    910    if (nickName && nickName[0])
    911        list = PK11_ListPrivKeysInSlot(slot, (char *)nickName, pwarg);
    912    else
    913        list = PK11_ListPrivateKeysInSlot(slot);
    914    if (list == NULL) {
    915        SECU_PrintError(progName, "problem listing keys");
    916        return SECFailure;
    917    }
    918    for (node = PRIVKEY_LIST_HEAD(list);
    919         !PRIVKEY_LIST_END(node, list);
    920         node = PRIVKEY_LIST_NEXT(node)) {
    921        char *keyName;
    922        static const char orphan[] = { "(orphan)" };
    923 
    924        if (keyType != nullKey && keyType != node->key->keyType)
    925            continue;
    926        keyName = PK11_GetPrivateKeyNickname(node->key);
    927        if (!keyName || !keyName[0]) {
    928            /* Try extra hard to find nicknames for keys that lack them. */
    929            CERTCertificate *cert;
    930            PORT_Free((void *)keyName);
    931            keyName = NULL;
    932            cert = PK11_GetCertFromPrivateKey(node->key);
    933            if (cert) {
    934                if (cert->nickname && cert->nickname[0]) {
    935                    keyName = PORT_Strdup(cert->nickname);
    936                } else if (cert->emailAddr && cert->emailAddr[0]) {
    937                    keyName = PORT_Strdup(cert->emailAddr);
    938                }
    939                CERT_DestroyCertificate(cert);
    940            }
    941        }
    942        if (nickName) {
    943            if (!keyName || PL_strcmp(keyName, nickName)) {
    944                /* PKCS#11 module returned unwanted keys */
    945                PORT_Free((void *)keyName);
    946                continue;
    947            }
    948        }
    949        if (!keyName)
    950            keyName = (char *)orphan;
    951 
    952        PrintKey(PR_STDOUT, keyName, count, node->key, pwarg);
    953 
    954        if (keyName != (char *)orphan)
    955            PORT_Free((void *)keyName);
    956        count++;
    957    }
    958    SECKEY_DestroyPrivateKeyList(list);
    959 
    960    if (count == 0) {
    961        PR_fprintf(PR_STDOUT, "%s: no keys found\n", progName);
    962        return SECFailure;
    963    }
    964    return SECSuccess;
    965 }
    966 
    967 /* returns SECSuccess if ANY keys are found, SECFailure otherwise. */
    968 static SECStatus
    969 ListKeys(PK11SlotInfo *slot, const char *nickName, int index,
    970         KeyType keyType, PRBool dopriv, secuPWData *pwdata)
    971 {
    972    SECStatus rv = SECFailure;
    973    static const char fmt[] =
    974        "%s: Checking token \"%.33s\" in slot \"%.65s\"\n";
    975 
    976    if (slot == NULL) {
    977        PK11SlotList *list;
    978        PK11SlotListElement *le;
    979 
    980        list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_FALSE, pwdata);
    981        if (list) {
    982            for (le = list->head; le; le = le->next) {
    983                PR_fprintf(PR_STDOUT, fmt, progName,
    984                           PK11_GetTokenName(le->slot),
    985                           PK11_GetSlotName(le->slot));
    986                rv &= ListKeysInSlot(le->slot, nickName, keyType, pwdata);
    987            }
    988            PK11_FreeSlotList(list);
    989        }
    990    } else {
    991        PR_fprintf(PR_STDOUT, fmt, progName, PK11_GetTokenName(slot),
    992                   PK11_GetSlotName(slot));
    993        rv = ListKeysInSlot(slot, nickName, keyType, pwdata);
    994    }
    995    return rv;
    996 }
    997 
    998 static SECStatus
    999 DeleteCertAndKey(char *nickname, secuPWData *pwdata)
   1000 {
   1001    SECStatus rv;
   1002    CERTCertificate *cert;
   1003    PK11SlotInfo *slot;
   1004 
   1005    slot = PK11_GetInternalKeySlot();
   1006    if (PK11_NeedLogin(slot)) {
   1007        rv = PK11_Authenticate(slot, PR_TRUE, pwdata);
   1008        if (rv != SECSuccess) {
   1009            SECU_PrintError(progName, "could not authenticate to token %s.",
   1010                            PK11_GetTokenName(slot));
   1011            PK11_FreeSlot(slot);
   1012            return SECFailure;
   1013        }
   1014    }
   1015    cert = PK11_FindCertFromNickname(nickname, pwdata);
   1016    if (!cert) {
   1017        PK11_FreeSlot(slot);
   1018        return SECFailure;
   1019    }
   1020    rv = PK11_DeleteTokenCertAndKey(cert, pwdata);
   1021    if (rv != SECSuccess) {
   1022        SECU_PrintError("problem deleting private key \"%s\"\n", nickname);
   1023    }
   1024    CERT_DestroyCertificate(cert);
   1025    PK11_FreeSlot(slot);
   1026    return rv;
   1027 }
   1028 
   1029 static SECKEYPrivateKey *
   1030 findPrivateKeyByID(PK11SlotInfo *slot, const char *ckaID, secuPWData *pwarg)
   1031 {
   1032    PORTCheapArenaPool arena;
   1033    SECItem ckaIDItem = { 0 };
   1034    SECKEYPrivateKey *privkey = NULL;
   1035    SECStatus rv;
   1036 
   1037    if (PK11_NeedLogin(slot)) {
   1038        rv = PK11_Authenticate(slot, PR_TRUE, pwarg);
   1039        if (rv != SECSuccess) {
   1040            SECU_PrintError(progName, "could not authenticate to token %s.",
   1041                            PK11_GetTokenName(slot));
   1042            return NULL;
   1043        }
   1044    }
   1045 
   1046    if (0 == PL_strncasecmp("0x", ckaID, 2)) {
   1047        ckaID += 2; /* skip leading "0x" */
   1048    }
   1049    PORT_InitCheapArena(&arena, DER_DEFAULT_CHUNKSIZE);
   1050    if (SECU_HexString2SECItem(&arena.arena, &ckaIDItem, ckaID)) {
   1051        privkey = PK11_FindKeyByKeyID(slot, &ckaIDItem, pwarg);
   1052    }
   1053    PORT_DestroyCheapArena(&arena);
   1054    return privkey;
   1055 }
   1056 
   1057 static SECStatus
   1058 DeleteKey(SECKEYPrivateKey *privkey, secuPWData *pwarg)
   1059 {
   1060    SECStatus rv;
   1061    PK11SlotInfo *slot;
   1062 
   1063    slot = PK11_GetSlotFromPrivateKey(privkey);
   1064    if (PK11_NeedLogin(slot)) {
   1065        rv = PK11_Authenticate(slot, PR_TRUE, pwarg);
   1066        if (rv != SECSuccess) {
   1067            SECU_PrintError(progName, "could not authenticate to token %s.",
   1068                            PK11_GetTokenName(slot));
   1069            return SECFailure;
   1070        }
   1071    }
   1072 
   1073    rv = PK11_DeleteTokenPrivateKey(privkey, PR_TRUE);
   1074    if (rv != SECSuccess) {
   1075        char ckaIDbuf[MAX_CKA_ID_STR_LEN + 4];
   1076        formatPrivateKeyID(privkey, ckaIDbuf);
   1077        SECU_PrintError("problem deleting private key \"%s\"\n", ckaIDbuf);
   1078    }
   1079 
   1080    PK11_FreeSlot(slot);
   1081    return rv;
   1082 }
   1083 
   1084 /*
   1085 *  L i s t M o d u l e s
   1086 *
   1087 *  Print a list of the PKCS11 modules that are
   1088 *  available. This is useful for smartcard people to
   1089 *  make sure they have the drivers loaded.
   1090 *
   1091 */
   1092 static SECStatus
   1093 ListModules(void)
   1094 {
   1095    PK11SlotList *list;
   1096    PK11SlotListElement *le;
   1097 
   1098    /* get them all! */
   1099    list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_FALSE, NULL);
   1100    if (list == NULL)
   1101        return SECFailure;
   1102 
   1103    /* look at each slot*/
   1104    for (le = list->head; le; le = le->next) {
   1105        char *token_uri = PK11_GetTokenURI(le->slot);
   1106        printf("\n");
   1107        printf("    slot: %s\n", PK11_GetSlotName(le->slot));
   1108        printf("   token: %s\n", PK11_GetTokenName(le->slot));
   1109        printf("     uri: %s\n", token_uri);
   1110        PORT_Free(token_uri);
   1111    }
   1112    PK11_FreeSlotList(list);
   1113 
   1114    return SECSuccess;
   1115 }
   1116 
   1117 static void
   1118 PrintBuildFlags()
   1119 {
   1120 #ifdef NSS_FIPS_DISABLED
   1121    PR_fprintf(PR_STDOUT, "NSS_FIPS_DISABLED\n");
   1122 #endif
   1123 #ifdef NSS_NO_INIT_SUPPORT
   1124    PR_fprintf(PR_STDOUT, "NSS_NO_INIT_SUPPORT\n");
   1125 #endif
   1126    exit(0);
   1127 }
   1128 
   1129 static void
   1130 PrintSyntax()
   1131 {
   1132 #define FPS fprintf(stderr,
   1133    FPS "Type %s -H for more detailed descriptions\n", progName);
   1134    FPS "Usage:  %s -N [-d certdir] [-P dbprefix] [-f pwfile] [--empty-password]\n", progName);
   1135    FPS "Usage:  %s -T [-d certdir] [-P dbprefix] [-h token-name]\n"
   1136        "\t\t [-f pwfile] [-0 SSO-password]\n", progName);
   1137    FPS "\t%s -A -n cert-name -t trustargs [-d certdir] [-P dbprefix] [-a] [-i input]\n",
   1138        progName);
   1139    FPS "\t%s -B -i batch-file\n", progName);
   1140    FPS "\t%s -C [-c issuer-name | -x] -i cert-request-file -o cert-file\n"
   1141        "\t\t [-m serial-number] [-w warp-months] [-v months-valid]\n"
   1142        "\t\t [-f pwfile] [-d certdir] [-P dbprefix] [-Z hashAlg]\n"
   1143        "\t\t [-1 | --keyUsage [keyUsageKeyword,..]] [-2] [-3] [-4]\n"
   1144        "\t\t [-5 | --nsCertType [nsCertTypeKeyword,...]]\n"
   1145        "\t\t [-6 | --extKeyUsage [extKeyUsageKeyword,...]] [-7 emailAddrs]\n"
   1146        "\t\t [-8 dns-names] [-a]\n",
   1147        progName);
   1148    FPS "\t%s -D -n cert-name [-d certdir] [-P dbprefix]\n", progName);
   1149    FPS "\t%s --rename -n cert-name --new-n new-cert-name\n"
   1150        "\t\t [-d certdir] [-P dbprefix]\n", progName);
   1151    FPS "\t%s -E -n cert-name -t trustargs [-d certdir] [-P dbprefix] [-a] [-i input]\n",
   1152        progName);
   1153    FPS "\t%s -F -n cert-name [-d certdir] [-P dbprefix]\n",
   1154        progName);
   1155    FPS "\t%s -F -k key-id [-d certdir] [-P dbprefix]\n",
   1156        progName);
   1157    FPS "\t%s -G -n key-name [-h token-name] [-k rsa] [-g key-size] [-y exp]\n"
   1158        "\t\t [-f pwfile] [-z noisefile] [-d certdir] [-P dbprefix]\n", progName);
   1159    FPS "\t%s -G [-h token-name] -k dsa [-q pqgfile -g key-size] [-f pwfile]\n"
   1160        "\t\t [-z noisefile] [-d certdir] [-P dbprefix]\n", progName);
   1161    FPS "\t%s -G [-h token-name] -k ec -q curve [-f pwfile]\n"
   1162        "\t\t [-z noisefile] [-d certdir] [-P dbprefix]\n", progName);
   1163    FPS "\t%s -K [-n key-name] [-h token-name] [-k dsa|ec|rsa|all]\n",
   1164        progName);
   1165    FPS "\t\t [-f pwfile] [-X] [-d certdir] [-P dbprefix]\n");
   1166    FPS "\t%s --upgrade-merge --source-dir upgradeDir --upgrade-id uniqueID\n",
   1167        progName);
   1168    FPS "\t\t [--upgrade-token-name tokenName] [-d targetDBDir]\n");
   1169    FPS "\t\t [-P targetDBPrefix] [--source-prefix upgradeDBPrefix]\n");
   1170    FPS "\t\t [-f targetPWfile] [-@ upgradePWFile]\n");
   1171    FPS "\t%s --merge --source-dir sourceDBDir [-d targetDBdir]\n",
   1172        progName);
   1173    FPS "\t\t [-P targetDBPrefix] [--source-prefix sourceDBPrefix]\n");
   1174    FPS "\t\t [-f targetPWfile] [-@ sourcePWFile]\n");
   1175    FPS "\t%s -L [-n cert-name] [-h token-name] [--email email-address]\n",
   1176        progName);
   1177    FPS "\t\t [-X] [-r] [-a] [--dump-ext-val OID] [-d certdir] [-P dbprefix]\n");
   1178    FPS "\t%s --build-flags\n", progName);
   1179    FPS "\t%s -M -n cert-name -t trustargs [-d certdir] [-P dbprefix]\n",
   1180        progName);
   1181    FPS "\t%s -O -n cert-name [-X] [-d certdir] [-a] [-P dbprefix]\n"
   1182        "\t\t [--simple-self-signed]\n",
   1183        progName);
   1184    FPS "\t%s -R -s subj -o cert-request-file [-d certdir] [-P dbprefix] [-p phone] [-a]\n"
   1185        "\t\t [-7 emailAddrs] [-k key-type-or-id] [-h token-name] [-f pwfile]\n"
   1186        "\t\t [-g key-size] [-Z hashAlg]\n",
   1187        progName);
   1188    FPS "\t%s -V -n cert-name -u usage [-b time] [-e] [-a]\n"
   1189        "\t\t[-X] [-d certdir] [-P dbprefix]\n",
   1190        progName);
   1191    FPS "Usage:  %s -W [-d certdir] [-f pwfile] [-@newpwfile]\n",
   1192        progName);
   1193    FPS "\t%s -S -n cert-name -s subj [-c issuer-name | -x]  -t trustargs\n"
   1194        "\t\t [-k key-type-or-id] [-q key-params] [-h token-name] [-g key-size]\n"
   1195        "\t\t [-m serial-number] [-w warp-months] [-v months-valid]\n"
   1196        "\t\t [-f pwfile] [-d certdir] [-P dbprefix] [-Z hashAlg]\n"
   1197        "\t\t [-p phone] [-1] [-2] [-3] [-4] [-5] [-6] [-7 emailAddrs]\n"
   1198        "\t\t [-8 DNS-names]\n"
   1199        "\t\t [--extAIA] [--extSIA] [--extCP] [--extPM] [--extPC] [--extIA]\n"
   1200        "\t\t [--extSKID] [--extNC] [--extSAN type:name[,type:name]...]\n"
   1201        "\t\t [--extGeneric OID:critical-flag:filename[,OID:critical-flag:filename]...]\n", progName);
   1202    FPS "\t%s -U [-X] [-d certdir] [-P dbprefix]\n", progName);
   1203    exit(1);
   1204 }
   1205 
   1206 enum usage_level {
   1207    usage_all = 0,
   1208    usage_selected = 1
   1209 };
   1210 
   1211 static void luCommonDetailsAE();
   1212 
   1213 static void
   1214 luA(enum usage_level ul, const char *command)
   1215 {
   1216    int is_my_command = (command && 0 == strcmp(command, "A"));
   1217    if (ul == usage_all || !command || is_my_command)
   1218    FPS "%-15s Add a certificate to the database        (create if needed)\n",
   1219        "-A");
   1220    if (ul == usage_selected && !is_my_command)
   1221        return;
   1222    if (ul == usage_all) {
   1223    FPS "%-20s\n", "   All options under -E apply");
   1224    } else {
   1225        luCommonDetailsAE();
   1226    }
   1227 }
   1228 
   1229 static void
   1230 luB(enum usage_level ul, const char *command)
   1231 {
   1232    int is_my_command = (command && 0 == strcmp(command, "B"));
   1233    if (ul == usage_all || !command || is_my_command)
   1234    FPS "%-15s Run a series of certutil commands from a batch file\n", "-B");
   1235    if (ul == usage_selected && !is_my_command)
   1236        return;
   1237    FPS "%-20s Specify the batch file\n", "   -i batch-file");
   1238 }
   1239 
   1240 static void
   1241 luE(enum usage_level ul, const char *command)
   1242 {
   1243    int is_my_command = (command && 0 == strcmp(command, "E"));
   1244    if (ul == usage_all || !command || is_my_command)
   1245    FPS "%-15s Add an Email certificate to the database (create if needed)\n",
   1246        "-E");
   1247    if (ul == usage_selected && !is_my_command)
   1248        return;
   1249    luCommonDetailsAE();
   1250 }
   1251 
   1252 static void
   1253 luCommonDetailsAE()
   1254 {
   1255    FPS "%-20s Specify the nickname of the certificate to add\n",
   1256        "   -n cert-name");
   1257    FPS "%-20s Set the certificate trust attributes:\n",
   1258        "   -t trustargs");
   1259    FPS "%-25s trustargs is of the form x,y,z where x is for SSL, y is for S/MIME,\n", "");
   1260    FPS "%-25s and z is for code signing. Use ,, for no explicit trust.\n", "");
   1261    FPS "%-25s p \t prohibited (explicitly distrusted)\n", "");
   1262    FPS "%-25s P \t trusted peer\n", "");
   1263    FPS "%-25s c \t valid CA\n", "");
   1264    FPS "%-25s T \t trusted CA to issue client certs (implies c)\n", "");
   1265    FPS "%-25s C \t trusted CA to issue server certs (implies c)\n", "");
   1266    FPS "%-25s u \t user cert\n", "");
   1267    FPS "%-25s w \t send warning\n", "");
   1268    FPS "%-25s g \t make step-up cert\n", "");
   1269    FPS "%-20s Specify the password file\n",
   1270        "   -f pwfile");
   1271    FPS "%-20s Cert database directory (default is ~/.netscape)\n",
   1272        "   -d certdir");
   1273    FPS "%-20s Cert & Key database prefix\n",
   1274        "   -P dbprefix");
   1275    FPS "%-20s The input certificate is encoded in ASCII (RFC1113)\n",
   1276        "   -a");
   1277    FPS "%-20s Specify the certificate file (default is stdin)\n",
   1278        "   -i input");
   1279    FPS "\n");
   1280 }
   1281 
   1282 static void
   1283 luC(enum usage_level ul, const char *command)
   1284 {
   1285    int is_my_command = (command && 0 == strcmp(command, "C"));
   1286    if (ul == usage_all || !command || is_my_command)
   1287    FPS "%-15s Create a new binary certificate from a BINARY cert request\n",
   1288        "-C");
   1289    if (ul == usage_selected && !is_my_command)
   1290        return;
   1291    FPS "%-20s The nickname of the issuer cert\n",
   1292        "   -c issuer-name");
   1293    FPS "%-20s The BINARY certificate request file\n",
   1294        "   -i cert-request ");
   1295    FPS "%-20s Output binary cert to this file (default is stdout)\n",
   1296        "   -o output-cert");
   1297    FPS "%-20s Self sign\n",
   1298        "   -x");
   1299    FPS "%-20s Sign the certificate with RSA-PSS (the issuer key must be rsa)\n",
   1300        "   --pss-sign");
   1301    FPS "%-20s Cert serial number\n",
   1302        "   -m serial-number");
   1303    FPS "%-20s Time Warp\n",
   1304        "   -w warp-months");
   1305    FPS "%-20s Months valid (default is 3)\n",
   1306        "   -v months-valid");
   1307    FPS "%-20s Specify the password file\n",
   1308        "   -f pwfile");
   1309    FPS "%-20s Cert database directory (default is ~/.netscape)\n",
   1310        "   -d certdir");
   1311    FPS "%-20s Cert & Key database prefix\n",
   1312        "   -P dbprefix");
   1313    FPS "%-20s \n"
   1314              "%-20s Specify the hash algorithm to use. Possible keywords:\n"
   1315              "%-20s \"MD2\", \"MD4\", \"MD5\", \"SHA1\", \"SHA224\",\n"
   1316              "%-20s \"SHA256\", \"SHA384\", \"SHA512\"\n",
   1317        "   -Z hashAlg", "", "", "");
   1318    FPS "%-20s \n"
   1319              "%-20s Create key usage extension. Possible keywords:\n"
   1320              "%-20s \"digitalSignature\", \"nonRepudiation\", \"keyEncipherment\",\n"
   1321              "%-20s \"dataEncipherment\", \"keyAgreement\", \"certSigning\",\n"
   1322              "%-20s \"crlSigning\", \"critical\"\n",
   1323        "   -1 | --keyUsage keyword,keyword,...", "", "", "", "");
   1324    FPS "%-20s Create basic constraint extension\n",
   1325        "   -2 ");
   1326    FPS "%-20s Create authority key ID extension\n",
   1327        "   -3 ");
   1328    FPS "%-20s Create crl distribution point extension\n",
   1329        "   -4 ");
   1330    FPS "%-20s \n"
   1331              "%-20s Create netscape cert type extension. Possible keywords:\n"
   1332              "%-20s \"sslClient\", \"sslServer\", \"smime\", \"objectSigning\",\n"
   1333              "%-20s \"sslCA\", \"smimeCA\", \"objectSigningCA\", \"critical\".\n",
   1334        "   -5 | --nsCertType keyword,keyword,... ", "", "", "");
   1335    FPS "%-20s \n"
   1336              "%-20s Create extended key usage extension. Possible keywords:\n"
   1337              "%-20s \"serverAuth\", \"clientAuth\",\"codeSigning\",\n"
   1338              "%-20s \"emailProtection\", \"timeStamp\",\"ocspResponder\",\n"
   1339              "%-20s \"stepUp\", \"msTrustListSign\", \"x509Any\",\n"
   1340              "%-20s \"ipsecIKE\", \"ipsecIKEEnd\", \"ipsecIKEIntermediate\",\n"
   1341              "%-20s \"ipsecEnd\", \"ipsecTunnel\", \"ipsecUser\",\n"
   1342              "%-20s \"critical\"\n",
   1343        "   -6 | --extKeyUsage keyword,keyword,...", "", "", "", "", "", "", "");
   1344    FPS "%-20s Create an email subject alt name extension\n",
   1345        "   -7 emailAddrs");
   1346    FPS "%-20s Create an dns subject alt name extension\n",
   1347        "   -8 dnsNames");
   1348    FPS "%-20s The input certificate request is encoded in ASCII (RFC1113)\n",
   1349        "   -a");
   1350    FPS "\n");
   1351 }
   1352 
   1353 static void
   1354 luG(enum usage_level ul, const char *command)
   1355 {
   1356    int is_my_command = (command && 0 == strcmp(command, "G"));
   1357    if (ul == usage_all || !command || is_my_command)
   1358    FPS "%-15s Generate a new key pair\n",
   1359        "-G");
   1360    if (ul == usage_selected && !is_my_command)
   1361        return;
   1362    FPS "%-20s Name of token in which to generate key (default is internal)\n",
   1363        "   -h token-name");
   1364    FPS "%-20s Type of key pair to generate (\"dsa\", \"ec\", \"rsa\" (default))\n",
   1365        "   -k key-type");
   1366    FPS "%-20s Key size in bits, (min %d, max %d, default %d) (not for ec)\n",
   1367        "   -g key-size", MIN_KEY_BITS, MAX_KEY_BITS, DEFAULT_KEY_BITS);
   1368    FPS "%-20s Set the public exponent value (3, 17, 65537) (rsa only)\n",
   1369        "   -y exp");
   1370    FPS "%-20s Specify the password file\n",
   1371        "   -f password-file");
   1372    FPS "%-20s Specify the noise file to be used\n",
   1373        "   -z noisefile");
   1374    FPS "%-20s read PQG value from pqgfile (dsa only)\n",
   1375        "   -q pqgfile");
   1376    FPS "%-20s Elliptic curve name (ec only)\n",
   1377        "   -q curve-name");
   1378    FPS "%-20s One of nistp256, nistp384, nistp521, curve25519.\n", "");
   1379    FPS "%-20s If a custom token is present, the following curves are also supported:\n", "");
   1380    FPS "%-20s sect163k1, nistk163, sect163r1, sect163r2,\n", "");
   1381    FPS "%-20s nistb163, sect193r1, sect193r2, sect233k1, nistk233,\n", "");
   1382    FPS "%-20s sect233r1, nistb233, sect239k1, sect283k1, nistk283,\n", "");
   1383    FPS "%-20s sect283r1, nistb283, sect409k1, nistk409, sect409r1,\n", "");
   1384    FPS "%-20s nistb409, sect571k1, nistk571, sect571r1, nistb571,\n", "");
   1385    FPS "%-20s secp160k1, secp160r1, secp160r2, secp192k1, secp192r1,\n", "");
   1386    FPS "%-20s nistp192, secp224k1, secp224r1, nistp224, secp256k1,\n", "");
   1387    FPS "%-20s secp256r1, secp384r1, secp521r1,\n", "");
   1388    FPS "%-20s prime192v1, prime192v2, prime192v3, \n", "");
   1389    FPS "%-20s prime239v1, prime239v2, prime239v3, c2pnb163v1, \n", "");
   1390    FPS "%-20s c2pnb163v2, c2pnb163v3, c2pnb176v1, c2tnb191v1, \n", "");
   1391    FPS "%-20s c2tnb191v2, c2tnb191v3,  \n", "");
   1392    FPS "%-20s c2pnb208w1, c2tnb239v1, c2tnb239v2, c2tnb239v3, \n", "");
   1393    FPS "%-20s c2pnb272w1, c2pnb304w1, \n", "");
   1394    FPS "%-20s c2tnb359w1, c2pnb368w1, c2tnb431r1, secp112r1, \n", "");
   1395    FPS "%-20s secp112r2, secp128r1, secp128r2, sect113r1, sect113r2\n", "");
   1396    FPS "%-20s sect131r1, sect131r2\n", "");
   1397    FPS "%-20s Key database directory (default is ~/.netscape)\n",
   1398        "   -d keydir");
   1399    FPS "%-20s Cert & Key database prefix\n",
   1400        "   -P dbprefix");
   1401    FPS "%-20s\n"
   1402        "%-20s PKCS #11 key Attributes.\n",
   1403        "   --keyAttrFlags attrflags", "");
   1404    FPS "%-20s Comma separated list of key attribute attribute flags,\n", "");
   1405    FPS "%-20s selected from the following list of choices:\n", "");
   1406    FPS "%-20s {token | session} {public | private} {sensitive | insensitive}\n", "");
   1407    FPS "%-20s {modifiable | unmodifiable} {extractable | unextractable}\n", "");
   1408    FPS "%-20s\n",
   1409        "   --keyOpFlagsOn opflags");
   1410    FPS "%-20s\n"
   1411        "%-20s PKCS #11 key Operation Flags.\n",
   1412        "   --keyOpFlagsOff opflags", "");
   1413    FPS "%-20s Comma separated list of one or more of the following:\n", "");
   1414    FPS "%-20s encrypt, decrypt, sign, sign_recover, verify,\n", "");
   1415    FPS "%-20s verify_recover, wrap, unwrap, derive\n", "");
   1416    FPS "\n");
   1417 }
   1418 
   1419 static void
   1420 luD(enum usage_level ul, const char *command)
   1421 {
   1422    int is_my_command = (command && 0 == strcmp(command, "D"));
   1423    if (ul == usage_all || !command || is_my_command)
   1424    FPS "%-15s Delete a certificate from the database\n",
   1425        "-D");
   1426    if (ul == usage_selected && !is_my_command)
   1427        return;
   1428    FPS "%-20s The nickname of the cert to delete\n",
   1429        "   -n cert-name");
   1430    FPS "%-20s Cert database directory (default is ~/.netscape)\n",
   1431        "   -d certdir");
   1432    FPS "%-20s Cert & Key database prefix\n",
   1433        "   -P dbprefix");
   1434    FPS "\n");
   1435 }
   1436 
   1437 static void
   1438 luF(enum usage_level ul, const char *command)
   1439 {
   1440    int is_my_command = (command && 0 == strcmp(command, "F"));
   1441    if (ul == usage_all || !command || is_my_command)
   1442    FPS "%-15s Delete a key and associated certificate from the database\n",
   1443        "-F");
   1444    if (ul == usage_selected && !is_my_command)
   1445        return;
   1446    FPS "%-20s The nickname of the key to delete\n",
   1447        "   -n cert-name");
   1448    FPS "%-20s The key id of the key to delete, obtained using -K\n",
   1449        "   -k key-id");
   1450    FPS "%-20s Cert database directory (default is ~/.netscape)\n",
   1451        "   -d certdir");
   1452    FPS "%-20s Cert & Key database prefix\n",
   1453        "   -P dbprefix");
   1454    FPS "\n");
   1455 }
   1456 
   1457 static void
   1458 luU(enum usage_level ul, const char *command)
   1459 {
   1460    int is_my_command = (command && 0 == strcmp(command, "U"));
   1461    if (ul == usage_all || !command || is_my_command)
   1462    FPS "%-15s List all modules\n", /*, or print out a single named module\n",*/
   1463        "-U");
   1464    if (ul == usage_selected && !is_my_command)
   1465        return;
   1466    FPS "%-20s Module database directory (default is '~/.netscape')\n",
   1467        "   -d moddir");
   1468    FPS "%-20s Cert & Key database prefix\n",
   1469        "   -P dbprefix");
   1470    FPS "%-20s force the database to open R/W\n",
   1471        "   -X");
   1472    FPS "\n");
   1473 }
   1474 
   1475 static void
   1476 luK(enum usage_level ul, const char *command)
   1477 {
   1478    int is_my_command = (command && 0 == strcmp(command, "K"));
   1479    if (ul == usage_all || !command || is_my_command)
   1480    FPS "%-15s List all private keys\n",
   1481        "-K");
   1482    if (ul == usage_selected && !is_my_command)
   1483        return;
   1484    FPS "%-20s Name of token to search (\"all\" for all tokens)\n",
   1485        "   -h token-name ");
   1486 
   1487    FPS "%-20s Key type (\"all\" (default), \"dsa\","
   1488                                                    " \"ec\","
   1489                                                    " \"rsa\")\n",
   1490        "   -k key-type");
   1491    FPS "%-20s The nickname of the key or associated certificate\n",
   1492        "   -n name");
   1493    FPS "%-20s Specify the password file\n",
   1494        "   -f password-file");
   1495    FPS "%-20s Key database directory (default is ~/.netscape)\n",
   1496        "   -d keydir");
   1497    FPS "%-20s Cert & Key database prefix\n",
   1498        "   -P dbprefix");
   1499    FPS "%-20s force the database to open R/W\n",
   1500        "   -X");
   1501    FPS "\n");
   1502 }
   1503 
   1504 static void
   1505 luL(enum usage_level ul, const char *command)
   1506 {
   1507    int is_my_command = (command && 0 == strcmp(command, "L"));
   1508    if (ul == usage_all || !command || is_my_command)
   1509    FPS "%-15s List all certs, or print out a single named cert (or a subset)\n",
   1510        "-L");
   1511    if (ul == usage_selected && !is_my_command)
   1512        return;
   1513    FPS "%-20s Name of token to search (\"all\" for all tokens)\n",
   1514        "   -h token-name ");
   1515    FPS "%-20s Pretty print named cert (list all if unspecified)\n",
   1516        "   -n cert-name");
   1517    FPS "%-20s \n"
   1518              "%-20s Pretty print cert with email address (list all if unspecified)\n",
   1519        "   --email email-address", "");
   1520    FPS "%-20s Cert database directory (default is ~/.netscape)\n",
   1521        "   -d certdir");
   1522    FPS "%-20s Cert & Key database prefix\n",
   1523        "   -P dbprefix");
   1524    FPS "%-20s force the database to open R/W\n",
   1525        "   -X");
   1526    FPS "%-20s For single cert, print binary DER encoding\n",
   1527        "   -r");
   1528    FPS "%-20s For single cert, print ASCII encoding (RFC1113)\n",
   1529        "   -a");
   1530    FPS "%-20s \n"
   1531              "%-20s For single cert, print binary DER encoding of extension OID\n",
   1532        "   --dump-ext-val OID", "");
   1533    FPS "\n");
   1534 }
   1535 
   1536 static void
   1537 luM(enum usage_level ul, const char *command)
   1538 {
   1539    int is_my_command = (command && 0 == strcmp(command, "M"));
   1540    if (ul == usage_all || !command || is_my_command)
   1541    FPS "%-15s Modify trust attributes of certificate\n",
   1542        "-M");
   1543    if (ul == usage_selected && !is_my_command)
   1544        return;
   1545    FPS "%-20s The nickname of the cert to modify\n",
   1546        "   -n cert-name");
   1547    FPS "%-20s Set the certificate trust attributes (see -A above)\n",
   1548        "   -t trustargs");
   1549    FPS "%-20s Cert database directory (default is ~/.netscape)\n",
   1550        "   -d certdir");
   1551    FPS "%-20s Cert & Key database prefix\n",
   1552        "   -P dbprefix");
   1553    FPS "\n");
   1554 }
   1555 
   1556 static void
   1557 luN(enum usage_level ul, const char *command)
   1558 {
   1559    int is_my_command = (command && 0 == strcmp(command, "N"));
   1560    if (ul == usage_all || !command || is_my_command)
   1561    FPS "%-15s Create a new certificate database\n",
   1562        "-N");
   1563    if (ul == usage_selected && !is_my_command)
   1564        return;
   1565    FPS "%-20s Cert database directory (default is ~/.netscape)\n",
   1566        "   -d certdir");
   1567    FPS "%-20s Cert & Key database prefix\n",
   1568        "   -P dbprefix");
   1569    FPS "%-20s Specify the password file\n",
   1570        "   -f password-file");
   1571    FPS "%-20s use empty password when creating a new database\n",
   1572        "   --empty-password");
   1573    FPS "\n");
   1574 }
   1575 
   1576 static void
   1577 luT(enum usage_level ul, const char *command)
   1578 {
   1579    int is_my_command = (command && 0 == strcmp(command, "T"));
   1580    if (ul == usage_all || !command || is_my_command)
   1581    FPS "%-15s Reset the Key database or token\n",
   1582        "-T");
   1583    if (ul == usage_selected && !is_my_command)
   1584        return;
   1585    FPS "%-20s Cert database directory (default is ~/.netscape)\n",
   1586        "   -d certdir");
   1587    FPS "%-20s Cert & Key database prefix\n",
   1588        "   -P dbprefix");
   1589    FPS "%-20s Token to reset (default is internal)\n",
   1590        "   -h token-name");
   1591    FPS "%-20s Set token's Site Security Officer password\n",
   1592        "   -0 SSO-password");
   1593    FPS "\n");
   1594 }
   1595 
   1596 static void
   1597 luO(enum usage_level ul, const char *command)
   1598 {
   1599    int is_my_command = (command && 0 == strcmp(command, "O"));
   1600    if (ul == usage_all || !command || is_my_command)
   1601    FPS "%-15s Print the chain of a certificate\n",
   1602        "-O");
   1603    if (ul == usage_selected && !is_my_command)
   1604        return;
   1605    FPS "%-20s The nickname of the cert to modify\n",
   1606        "   -n cert-name");
   1607    FPS "%-20s Cert database directory (default is ~/.netscape)\n",
   1608        "   -d certdir");
   1609    FPS "%-20s Input the certificate in ASCII (RFC1113); default is binary\n",
   1610        "   -a");
   1611    FPS "%-20s Cert & Key database prefix\n",
   1612        "   -P dbprefix");
   1613    FPS "%-20s force the database to open R/W\n",
   1614        "   -X");
   1615    FPS "%-20s don't search for a chain if issuer name equals subject name\n",
   1616        "   --simple-self-signed");
   1617    FPS "\n");
   1618 }
   1619 
   1620 static void
   1621 luR(enum usage_level ul, const char *command)
   1622 {
   1623    int is_my_command = (command && 0 == strcmp(command, "R"));
   1624    if (ul == usage_all || !command || is_my_command)
   1625    FPS "%-15s Generate a certificate request (stdout)\n",
   1626        "-R");
   1627    if (ul == usage_selected && !is_my_command)
   1628        return;
   1629    FPS "%-20s Specify the subject name (using RFC1485)\n",
   1630        "   -s subject");
   1631    FPS "%-20s Output the cert request to this file\n",
   1632        "   -o output-req");
   1633    FPS "%-20s Type of key pair to generate (\"dsa\", \"ec\", \"rsa\" (default))\n",
   1634        "   -k key-type-or-id");
   1635    FPS "%-20s or nickname of the cert key to use, or key id obtained using -K\n",
   1636        "");
   1637    FPS "%-20s Name of token in which to generate key (default is internal)\n",
   1638        "   -h token-name");
   1639    FPS "%-20s Key size in bits, RSA keys only (min %d, max %d, default %d)\n",
   1640        "   -g key-size", MIN_KEY_BITS, MAX_KEY_BITS, DEFAULT_KEY_BITS);
   1641    FPS "%-20s Create a certificate request restricted to RSA-PSS (rsa only)\n",
   1642        "   --pss");
   1643    FPS "%-20s Name of file containing PQG parameters (dsa only)\n",
   1644        "   -q pqgfile");
   1645    FPS "%-20s Elliptic curve name (ec only)\n",
   1646        "   -q curve-name");
   1647    FPS "%-20s See the \"-G\" option for a full list of supported names.\n",
   1648        "");
   1649    FPS "%-20s Specify the password file\n",
   1650        "   -f pwfile");
   1651    FPS "%-20s Key database directory (default is ~/.netscape)\n",
   1652        "   -d keydir");
   1653    FPS "%-20s Cert & Key database prefix\n",
   1654        "   -P dbprefix");
   1655    FPS "%-20s Specify the contact phone number (\"123-456-7890\")\n",
   1656        "   -p phone");
   1657    FPS "%-20s \n"
   1658              "%-20s Specify the hash algorithm to use. Possible keywords:\n"
   1659              "%-20s \"MD2\", \"MD4\", \"MD5\", \"SHA1\", \"SHA224\",\n"
   1660              "%-20s \"SHA256\", \"SHA384\", \"SHA512\"\n",
   1661        "   -Z hashAlg", "", "", "");
   1662    FPS "%-20s Output the cert request in ASCII (RFC1113); default is binary\n",
   1663        "   -a");
   1664    FPS "%-20s \n",
   1665        "   See -S for available extension options");
   1666    FPS "%-20s \n",
   1667        "   See -G for available key flag options");
   1668    FPS "\n");
   1669 }
   1670 
   1671 static void
   1672 luV(enum usage_level ul, const char *command)
   1673 {
   1674    int is_my_command = (command && 0 == strcmp(command, "V"));
   1675    if (ul == usage_all || !command || is_my_command)
   1676    FPS "%-15s Validate a certificate\n",
   1677        "-V");
   1678    if (ul == usage_selected && !is_my_command)
   1679        return;
   1680    FPS "%-20s The nickname of the cert to Validate\n",
   1681        "   -n cert-name");
   1682    FPS "%-20s validity time (\"YYMMDDHHMMSS[+HHMM|-HHMM|Z]\")\n",
   1683        "   -b time");
   1684    FPS "%-20s Check certificate signature \n",
   1685        "   -e ");
   1686    FPS "%-20s Specify certificate usage:\n", "   -u certusage");
   1687    FPS "%-25s C \t SSL Client\n", "");
   1688    FPS "%-25s V \t SSL Server\n", "");
   1689    FPS "%-25s I \t IPsec\n", "");
   1690    FPS "%-25s L \t SSL CA\n", "");
   1691    FPS "%-25s A \t Any CA\n", "");
   1692    FPS "%-25s Y \t Verify CA\n", "");
   1693    FPS "%-25s S \t Email signer\n", "");
   1694    FPS "%-25s R \t Email Recipient\n", "");
   1695    FPS "%-25s O \t OCSP status responder\n", "");
   1696    FPS "%-25s J \t Object signer\n", "");
   1697    FPS "%-20s Cert database directory (default is ~/.netscape)\n",
   1698        "   -d certdir");
   1699    FPS "%-20s Input the certificate in ASCII (RFC1113); default is binary\n",
   1700        "   -a");
   1701    FPS "%-20s Cert & Key database prefix\n",
   1702        "   -P dbprefix");
   1703    FPS "%-20s force the database to open R/W\n",
   1704        "   -X");
   1705    FPS "\n");
   1706 }
   1707 
   1708 static void
   1709 luW(enum usage_level ul, const char *command)
   1710 {
   1711    int is_my_command = (command && 0 == strcmp(command, "W"));
   1712    if (ul == usage_all || !command || is_my_command)
   1713    FPS "%-15s Change the key database password\n",
   1714        "-W");
   1715    if (ul == usage_selected && !is_my_command)
   1716        return;
   1717    FPS "%-20s cert and key database directory\n",
   1718        "   -d certdir");
   1719    FPS "%-20s Specify a file with the current password\n",
   1720        "   -f pwfile");
   1721    FPS "%-20s Specify a file with the new password in two lines\n",
   1722        "   -@ newpwfile");
   1723    FPS "\n");
   1724 }
   1725 
   1726 static void
   1727 luRename(enum usage_level ul, const char *command)
   1728 {
   1729    int is_my_command = (command && 0 == strcmp(command, "rename"));
   1730    if (ul == usage_all || !command || is_my_command)
   1731    FPS "%-15s Change the database nickname of a certificate\n",
   1732        "--rename");
   1733    if (ul == usage_selected && !is_my_command)
   1734        return;
   1735    FPS "%-20s The old nickname of the cert to rename\n",
   1736        "   -n cert-name");
   1737    FPS "%-20s The new nickname of the cert to rename\n",
   1738        "   --new-n new-name");
   1739    FPS "%-20s Cert database directory (default is ~/.netscape)\n",
   1740        "   -d certdir");
   1741    FPS "%-20s Cert & Key database prefix\n",
   1742        "   -P dbprefix");
   1743    FPS "\n");
   1744 }
   1745 
   1746 static void
   1747 luUpgradeMerge(enum usage_level ul, const char *command)
   1748 {
   1749    int is_my_command = (command && 0 == strcmp(command, "upgrade-merge"));
   1750    if (ul == usage_all || !command || is_my_command)
   1751    FPS "%-15s Upgrade an old database and merge it into a new one\n",
   1752        "--upgrade-merge");
   1753    if (ul == usage_selected && !is_my_command)
   1754        return;
   1755    FPS "%-20s Cert database directory to merge into (default is ~/.netscape)\n",
   1756        "   -d certdir");
   1757    FPS "%-20s Cert & Key database prefix of the target database\n",
   1758        "   -P dbprefix");
   1759    FPS "%-20s Specify the password file for the target database\n",
   1760        "   -f pwfile");
   1761    FPS "%-20s \n%-20s Cert database directory to upgrade from\n",
   1762        "   --source-dir certdir", "");
   1763    FPS "%-20s \n%-20s Cert & Key database prefix of the upgrade database\n",
   1764        "   --source-prefix dbprefix", "");
   1765    FPS "%-20s \n%-20s Unique identifier for the upgrade database\n",
   1766        "   --upgrade-id uniqueID", "");
   1767    FPS "%-20s \n%-20s Name of the token while it is in upgrade state\n",
   1768        "   --upgrade-token-name name", "");
   1769    FPS "%-20s Specify the password file for the upgrade database\n",
   1770        "   -@ pwfile");
   1771    FPS "\n");
   1772 }
   1773 
   1774 static void
   1775 luMerge(enum usage_level ul, const char *command)
   1776 {
   1777    int is_my_command = (command && 0 == strcmp(command, "merge"));
   1778    if (ul == usage_all || !command || is_my_command)
   1779    FPS "%-15s Merge source database into the target database\n",
   1780        "--merge");
   1781    if (ul == usage_selected && !is_my_command)
   1782        return;
   1783    FPS "%-20s Cert database directory of target (default is ~/.netscape)\n",
   1784        "   -d certdir");
   1785    FPS "%-20s Cert & Key database prefix of the target database\n",
   1786        "   -P dbprefix");
   1787    FPS "%-20s Specify the password file for the target database\n",
   1788        "   -f pwfile");
   1789    FPS "%-20s \n%-20s Cert database directory of the source database\n",
   1790        "   --source-dir certdir", "");
   1791    FPS "%-20s \n%-20s Cert & Key database prefix of the source database\n",
   1792        "   --source-prefix dbprefix", "");
   1793    FPS "%-20s Specify the password file for the source database\n",
   1794        "   -@ pwfile");
   1795    FPS "\n");
   1796 }
   1797 
   1798 static void
   1799 luS(enum usage_level ul, const char *command)
   1800 {
   1801    int is_my_command = (command && 0 == strcmp(command, "S"));
   1802    if (ul == usage_all || !command || is_my_command)
   1803    FPS "%-15s Make a certificate and add to database\n",
   1804        "-S");
   1805    if (ul == usage_selected && !is_my_command)
   1806        return;
   1807    FPS "%-20s Specify the nickname of the cert\n",
   1808        "   -n key-name");
   1809    FPS "%-20s Specify the subject name (using RFC1485)\n",
   1810        "   -s subject");
   1811    FPS "%-20s The nickname of the issuer cert\n",
   1812        "   -c issuer-name");
   1813    FPS "%-20s Set the certificate trust attributes (see -A above)\n",
   1814        "   -t trustargs");
   1815    FPS "%-20s Type of key pair to generate (\"dsa\", \"ec\", \"rsa\" (default))\n",
   1816        "   -k key-type-or-id");
   1817    FPS "%-20s Name of token in which to generate key (default is internal)\n",
   1818        "   -h token-name");
   1819    FPS "%-20s Key size in bits, RSA keys only (min %d, max %d, default %d)\n",
   1820        "   -g key-size", MIN_KEY_BITS, MAX_KEY_BITS, DEFAULT_KEY_BITS);
   1821    FPS "%-20s Create a certificate restricted to RSA-PSS (rsa only)\n",
   1822        "   --pss");
   1823    FPS "%-20s Name of file containing PQG parameters (dsa only)\n",
   1824        "   -q pqgfile");
   1825    FPS "%-20s Elliptic curve name (ec only)\n",
   1826        "   -q curve-name");
   1827    FPS "%-20s See the \"-G\" option for a full list of supported names.\n",
   1828        "");
   1829    FPS "%-20s Self sign\n",
   1830        "   -x");
   1831    FPS "%-20s Sign the certificate with RSA-PSS (the issuer key must be rsa)\n",
   1832        "   --pss-sign");
   1833    FPS "%-20s Cert serial number\n",
   1834        "   -m serial-number");
   1835    FPS "%-20s Time Warp\n",
   1836        "   -w warp-months");
   1837    FPS "%-20s Months valid (default is 3)\n",
   1838        "   -v months-valid");
   1839    FPS "%-20s Specify the password file\n",
   1840        "   -f pwfile");
   1841    FPS "%-20s Cert database directory (default is ~/.netscape)\n",
   1842        "   -d certdir");
   1843    FPS "%-20s Cert & Key database prefix\n",
   1844        "   -P dbprefix");
   1845    FPS "%-20s Specify the contact phone number (\"123-456-7890\")\n",
   1846        "   -p phone");
   1847    FPS "%-20s \n"
   1848              "%-20s Specify the hash algorithm to use. Possible keywords:\n"
   1849              "%-20s \"MD2\", \"MD4\", \"MD5\", \"SHA1\", \"SHA224\",\n"
   1850              "%-20s \"SHA256\", \"SHA384\", \"SHA512\"\n",
   1851        "   -Z hashAlg", "", "", "");
   1852    FPS "%-20s Create key usage extension\n",
   1853        "   -1 ");
   1854    FPS "%-20s Create basic constraint extension\n",
   1855        "   -2 ");
   1856    FPS "%-20s Create authority key ID extension\n",
   1857        "   -3 ");
   1858    FPS "%-20s Create crl distribution point extension\n",
   1859        "   -4 ");
   1860    FPS "%-20s Create netscape cert type extension\n",
   1861        "   -5 ");
   1862    FPS "%-20s Create extended key usage extension\n",
   1863        "   -6 ");
   1864    FPS "%-20s Create an email subject alt name extension\n",
   1865        "   -7 emailAddrs ");
   1866    FPS "%-20s Create a DNS subject alt name extension\n",
   1867        "   -8 DNS-names");
   1868    FPS "%-20s Create an Authority Information Access extension\n",
   1869        "   --extAIA ");
   1870    FPS "%-20s Create a Subject Information Access extension\n",
   1871        "   --extSIA ");
   1872    FPS "%-20s Create a Certificate Policies extension\n",
   1873        "   --extCP ");
   1874    FPS "%-20s Create a Policy Mappings extension\n",
   1875        "   --extPM ");
   1876    FPS "%-20s Create a Policy Constraints extension\n",
   1877        "   --extPC ");
   1878    FPS "%-20s Create an Inhibit Any Policy extension\n",
   1879        "   --extIA ");
   1880    FPS "%-20s Create a subject key ID extension\n",
   1881        "   --extSKID ");
   1882    FPS "%-20s \n",
   1883        "   See -G for available key flag options");
   1884    FPS "%-20s Create a name constraints extension\n",
   1885        "   --extNC ");
   1886    FPS "%-20s \n"
   1887        "%-20s Create a Subject Alt Name extension with one or multiple names\n",
   1888        "   --extSAN type:name[,type:name]...", "");
   1889    FPS "%-20s - type: directory, dn, dns, edi, ediparty, email, ip, ipaddr,\n", "");
   1890    FPS "%-20s         other, registerid, rfc822, uri, x400, x400addr\n", "");
   1891    FPS "%-20s \n"
   1892        "%-20s Add one or multiple extensions that certutil cannot encode yet,\n"
   1893        "%-20s by loading their encodings from external files.\n",
   1894        "   --extGeneric OID:critical-flag:filename[,OID:critical-flag:filename]...", "", "");
   1895    FPS "%-20s - OID (example): 1.2.3.4\n", "");
   1896    FPS "%-20s - critical-flag: critical or not-critical\n", "");
   1897    FPS "%-20s - filename: full path to a file containing an encoded extension\n", "");
   1898    FPS "\n");
   1899 }
   1900 
   1901 static void
   1902 luBuildFlags(enum usage_level ul, const char *command)
   1903 {
   1904    int is_my_command = (command && 0 == strcmp(command, "build-flags"));
   1905    if (ul == usage_all || !command || is_my_command)
   1906    FPS "%-15s Print enabled build flags relevant for NSS test execution\n",
   1907        "--build-flags");
   1908    if (ul == usage_selected && !is_my_command)
   1909        return;
   1910    FPS "\n");
   1911 }
   1912 
   1913 static void
   1914 LongUsage(enum usage_level ul, const char *command)
   1915 {
   1916    luA(ul, command);
   1917    luB(ul, command);
   1918    luE(ul, command);
   1919    luC(ul, command);
   1920    luG(ul, command);
   1921    luD(ul, command);
   1922    luRename(ul, command);
   1923    luF(ul, command);
   1924    luU(ul, command);
   1925    luK(ul, command);
   1926    luL(ul, command);
   1927    luBuildFlags(ul, command);
   1928    luM(ul, command);
   1929    luN(ul, command);
   1930    luT(ul, command);
   1931    luO(ul, command);
   1932    luR(ul, command);
   1933    luV(ul, command);
   1934    luW(ul, command);
   1935    luUpgradeMerge(ul, command);
   1936    luMerge(ul, command);
   1937    luS(ul, command);
   1938 #undef FPS
   1939 }
   1940 
   1941 static void
   1942 Usage()
   1943 {
   1944    PR_fprintf(PR_STDERR,
   1945               "%s - Utility to manipulate NSS certificate databases\n\n"
   1946               "Usage:  %s <command> -d <database-directory> <options>\n\n"
   1947               "Valid commands:\n",
   1948               progName, progName);
   1949    LongUsage(usage_selected, NULL);
   1950    PR_fprintf(PR_STDERR, "\n"
   1951                          "%s -H <command> : Print available options for the given command\n"
   1952                          "%s -H : Print complete help output of all commands and options\n"
   1953                          "%s --syntax : Print a short summary of all commands and options\n",
   1954               progName, progName, progName);
   1955    exit(1);
   1956 }
   1957 
   1958 static CERTCertificate *
   1959 MakeV1Cert(CERTCertDBHandle *handle,
   1960           CERTCertificateRequest *req,
   1961           char *issuerNickName,
   1962           PRBool selfsign,
   1963           unsigned int serialNumber,
   1964           int warpmonths,
   1965           int validityMonths)
   1966 {
   1967    CERTCertificate *issuerCert = NULL;
   1968    CERTValidity *validity;
   1969    CERTCertificate *cert = NULL;
   1970    PRExplodedTime printableTime;
   1971    PRTime now, after;
   1972 
   1973    if (!selfsign) {
   1974        issuerCert = CERT_FindCertByNicknameOrEmailAddr(handle, issuerNickName);
   1975        if (!issuerCert) {
   1976            SECU_PrintError(progName, "could not find certificate named \"%s\"",
   1977                            issuerNickName);
   1978            return NULL;
   1979        }
   1980    }
   1981 
   1982    now = PR_Now();
   1983    PR_ExplodeTime(now, PR_GMTParameters, &printableTime);
   1984    if (warpmonths) {
   1985        printableTime.tm_month += warpmonths;
   1986        now = PR_ImplodeTime(&printableTime);
   1987        PR_ExplodeTime(now, PR_GMTParameters, &printableTime);
   1988    }
   1989    printableTime.tm_month += validityMonths;
   1990    after = PR_ImplodeTime(&printableTime);
   1991 
   1992    /* note that the time is now in micro-second unit */
   1993    validity = CERT_CreateValidity(now, after);
   1994    if (validity) {
   1995        cert = CERT_CreateCertificate(serialNumber,
   1996                                      (selfsign ? &req->subject
   1997                                                : &issuerCert->subject),
   1998                                      validity, req);
   1999 
   2000        CERT_DestroyValidity(validity);
   2001    }
   2002    if (issuerCert) {
   2003        CERT_DestroyCertificate(issuerCert);
   2004    }
   2005 
   2006    return (cert);
   2007 }
   2008 
   2009 static SECStatus
   2010 SetSignatureAlgorithm(PLArenaPool *arena,
   2011                      SECAlgorithmID *signAlg,
   2012                      SECAlgorithmID *spkiAlg,
   2013                      SECOidTag hashAlgTag,
   2014                      SECKEYPrivateKey *privKey,
   2015                      PRBool pssSign)
   2016 {
   2017    SECOidTag signAlgTag = SEC_OID_UNKNOWN;
   2018    SECItem *params = NULL;
   2019 
   2020    if (pssSign) {
   2021        signAlgTag = SEC_OID_PKCS1_RSA_PSS_SIGNATURE;
   2022    }
   2023    if (SECOID_GetAlgorithmTag(spkiAlg) == SEC_OID_PKCS1_RSA_PSS_SIGNATURE) {
   2024        signAlgTag = SEC_OID_PKCS1_RSA_PSS_SIGNATURE;
   2025        params = &spkiAlg->parameters;
   2026    }
   2027    return SEC_CreateSignatureAlgorithmID(arena, signAlg, signAlgTag,
   2028                                          hashAlgTag, params, privKey, NULL);
   2029 }
   2030 
   2031 static SECStatus
   2032 SignCert(CERTCertDBHandle *handle, CERTCertificate *cert, PRBool selfsign,
   2033         SECOidTag hashAlgTag,
   2034         SECKEYPrivateKey *privKey, char *issuerNickName,
   2035         int certVersion, PRBool pssSign, void *pwarg)
   2036 {
   2037    SECItem der;
   2038    SECKEYPrivateKey *caPrivateKey = NULL;
   2039    SECStatus rv;
   2040    PLArenaPool *arena;
   2041    CERTCertificate *issuer;
   2042    void *dummy;
   2043 
   2044    arena = cert->arena;
   2045 
   2046    if (selfsign) {
   2047        issuer = cert;
   2048    } else {
   2049        issuer = PK11_FindCertFromNickname(issuerNickName, pwarg);
   2050        if ((CERTCertificate *)NULL == issuer) {
   2051            SECU_PrintError(progName, "unable to find issuer with nickname %s",
   2052                            issuerNickName);
   2053            rv = SECFailure;
   2054            goto done;
   2055        }
   2056        privKey = caPrivateKey = PK11_FindKeyByAnyCert(issuer, pwarg);
   2057        if (caPrivateKey == NULL) {
   2058            SECU_PrintError(progName, "unable to retrieve key %s", issuerNickName);
   2059            rv = SECFailure;
   2060            CERT_DestroyCertificate(issuer);
   2061            goto done;
   2062        }
   2063    }
   2064 
   2065    if (pssSign &&
   2066        (SECKEY_GetPrivateKeyType(privKey) != rsaKey &&
   2067         SECKEY_GetPrivateKeyType(privKey) != rsaPssKey)) {
   2068        SECU_PrintError(progName, "unable to create RSA-PSS signature with key %s",
   2069                        issuerNickName);
   2070        rv = SECFailure;
   2071        if (!selfsign) {
   2072            CERT_DestroyCertificate(issuer);
   2073        }
   2074        goto done;
   2075    }
   2076 
   2077    rv = SetSignatureAlgorithm(arena,
   2078                               &cert->signature,
   2079                               &issuer->subjectPublicKeyInfo.algorithm,
   2080                               hashAlgTag,
   2081                               privKey,
   2082                               pssSign);
   2083    if (!selfsign) {
   2084        CERT_DestroyCertificate(issuer);
   2085    }
   2086    if (rv != SECSuccess) {
   2087        goto done;
   2088    }
   2089 
   2090    switch (certVersion) {
   2091        case (SEC_CERTIFICATE_VERSION_1):
   2092            /* The initial version for x509 certificates is version one
   2093             * and this default value must be an implicit DER encoding. */
   2094            cert->version.data = NULL;
   2095            cert->version.len = 0;
   2096            break;
   2097        case (SEC_CERTIFICATE_VERSION_2):
   2098        case (SEC_CERTIFICATE_VERSION_3):
   2099        case 3: /* unspecified format (would be version 4 certificate). */
   2100            *(cert->version.data) = certVersion;
   2101            cert->version.len = 1;
   2102            break;
   2103        default:
   2104            PORT_SetError(SEC_ERROR_INVALID_ARGS);
   2105            rv = SECFailure;
   2106            goto done;
   2107    }
   2108 
   2109    der.len = 0;
   2110    der.data = NULL;
   2111    dummy = SEC_ASN1EncodeItem(arena, &der, cert,
   2112                               SEC_ASN1_GET(CERT_CertificateTemplate));
   2113    if (!dummy) {
   2114        fprintf(stderr, "Could not encode certificate.\n");
   2115        rv = SECFailure;
   2116        goto done;
   2117    }
   2118 
   2119    rv = SEC_DerSignDataWithAlgorithmID(arena, &cert->derCert, der.data, der.len,
   2120                                        privKey, &cert->signature);
   2121    if (rv != SECSuccess) {
   2122        fprintf(stderr, "Could not sign encoded certificate data.\n");
   2123        /* result allocated out of the arena, it will be freed
   2124         * when the arena is freed */
   2125        goto done;
   2126    }
   2127 done:
   2128    if (caPrivateKey) {
   2129        SECKEY_DestroyPrivateKey(caPrivateKey);
   2130    }
   2131    return rv;
   2132 }
   2133 
   2134 static SECStatus
   2135 CreateCert(
   2136    CERTCertDBHandle *handle,
   2137    PK11SlotInfo *slot,
   2138    char *issuerNickName,
   2139    const SECItem *certReqDER,
   2140    SECKEYPrivateKey **selfsignprivkey,
   2141    void *pwarg,
   2142    SECOidTag hashAlgTag,
   2143    unsigned int serialNumber,
   2144    int warpmonths,
   2145    int validityMonths,
   2146    const char *emailAddrs,
   2147    const char *dnsNames,
   2148    PRBool ascii,
   2149    PRBool selfsign,
   2150    certutilExtnList extnList,
   2151    const char *extGeneric,
   2152    int certVersion,
   2153    PRBool pssSign,
   2154    SECItem *certDER)
   2155 {
   2156    void *extHandle = NULL;
   2157    CERTCertificate *subjectCert = NULL;
   2158    CERTCertificateRequest *certReq = NULL;
   2159    SECStatus rv = SECSuccess;
   2160    CERTCertExtension **CRexts;
   2161 
   2162    do {
   2163        /* Create a certrequest object from the input cert request der */
   2164        certReq = GetCertRequest(certReqDER, pwarg);
   2165        if (certReq == NULL) {
   2166            GEN_BREAK(SECFailure)
   2167        }
   2168 
   2169        subjectCert = MakeV1Cert(handle, certReq, issuerNickName, selfsign,
   2170                                 serialNumber, warpmonths, validityMonths);
   2171        if (subjectCert == NULL) {
   2172            GEN_BREAK(SECFailure)
   2173        }
   2174 
   2175        extHandle = CERT_StartCertExtensions(subjectCert);
   2176        if (extHandle == NULL) {
   2177            GEN_BREAK(SECFailure)
   2178        }
   2179 
   2180        rv = AddExtensions(extHandle, emailAddrs, dnsNames, extnList, extGeneric);
   2181        if (rv != SECSuccess) {
   2182            GEN_BREAK(SECFailure)
   2183        }
   2184 
   2185        if (certReq->attributes != NULL &&
   2186            certReq->attributes[0] != NULL &&
   2187            certReq->attributes[0]->attrType.data != NULL &&
   2188            certReq->attributes[0]->attrType.len > 0 &&
   2189            SECOID_FindOIDTag(&certReq->attributes[0]->attrType) ==
   2190                SEC_OID_PKCS9_EXTENSION_REQUEST) {
   2191            rv = CERT_GetCertificateRequestExtensions(certReq, &CRexts);
   2192            if (rv != SECSuccess)
   2193                break;
   2194            rv = CERT_MergeExtensions(extHandle, CRexts);
   2195            if (rv != SECSuccess)
   2196                break;
   2197        }
   2198 
   2199        CERT_FinishExtensions(extHandle);
   2200        extHandle = NULL;
   2201 
   2202        /* self-signing a cert request, find the private key */
   2203        if (selfsign && *selfsignprivkey == NULL) {
   2204            *selfsignprivkey = PK11_FindKeyByDERCert(slot, subjectCert, pwarg);
   2205            if (!*selfsignprivkey) {
   2206                fprintf(stderr, "Failed to locate private key.\n");
   2207                rv = SECFailure;
   2208                break;
   2209            }
   2210        }
   2211 
   2212        rv = SignCert(handle, subjectCert, selfsign, hashAlgTag,
   2213                      *selfsignprivkey, issuerNickName,
   2214                      certVersion, pssSign, pwarg);
   2215        if (rv != SECSuccess)
   2216            break;
   2217 
   2218        rv = SECFailure;
   2219        if (ascii) {
   2220            char *asciiDER = BTOA_DataToAscii(subjectCert->derCert.data,
   2221                                              subjectCert->derCert.len);
   2222            if (asciiDER) {
   2223                char *wrapped = PR_smprintf("%s\n%s\n%s\n",
   2224                                            NS_CERT_HEADER,
   2225                                            asciiDER,
   2226                                            NS_CERT_TRAILER);
   2227                if (wrapped) {
   2228                    PRUint32 wrappedLen = PL_strlen(wrapped);
   2229                    if (SECITEM_AllocItem(NULL, certDER, wrappedLen)) {
   2230                        PORT_Memcpy(certDER->data, wrapped, wrappedLen);
   2231                        rv = SECSuccess;
   2232                    }
   2233                    PR_smprintf_free(wrapped);
   2234                }
   2235                PORT_Free(asciiDER);
   2236            }
   2237        } else {
   2238            rv = SECITEM_CopyItem(NULL, certDER, &subjectCert->derCert);
   2239        }
   2240    } while (0);
   2241    if (extHandle) {
   2242        CERT_FinishExtensions(extHandle);
   2243    }
   2244    CERT_DestroyCertificateRequest(certReq);
   2245    CERT_DestroyCertificate(subjectCert);
   2246    if (rv != SECSuccess) {
   2247        PRErrorCode perr = PR_GetError();
   2248        fprintf(stderr, "%s: unable to create cert (%s)\n", progName,
   2249                SECU_Strerror(perr));
   2250    }
   2251    return (rv);
   2252 }
   2253 
   2254 /*
   2255 * map a class to a user presentable string
   2256 */
   2257 static const char *objClassArray[] = {
   2258    "Data",
   2259    "Certificate",
   2260    "Public Key",
   2261    "Private Key",
   2262    "Secret Key",
   2263    "Hardware Feature",
   2264    "Domain Parameters",
   2265    "Mechanism"
   2266 };
   2267 
   2268 static const char *objNSSClassArray[] = {
   2269    "CKO_NSS",
   2270    "Crl",
   2271    "SMIME Record",
   2272    "Trust",
   2273    "Builtin Root List"
   2274 };
   2275 
   2276 const char *
   2277 getObjectClass(CK_ULONG classType)
   2278 {
   2279    static char buf[sizeof(CK_ULONG) * 2 + 3];
   2280 
   2281    if (classType <= CKO_MECHANISM) {
   2282        return objClassArray[classType];
   2283    }
   2284    if (classType >= CKO_NSS && classType <= CKO_NSS_BUILTIN_ROOT_LIST) {
   2285        return objNSSClassArray[classType - CKO_NSS];
   2286    }
   2287    snprintf(buf, sizeof(buf), "0x%lx", classType);
   2288    return buf;
   2289 }
   2290 
   2291 typedef struct {
   2292    char *name;
   2293    int nameSize;
   2294    CK_ULONG value;
   2295 } flagArray;
   2296 
   2297 #define NAME_SIZE(x) #x, sizeof(#x) - 1
   2298 
   2299 flagArray opFlagsArray[] = {
   2300    { NAME_SIZE(encrypt), CKF_ENCRYPT },
   2301    { NAME_SIZE(decrypt), CKF_DECRYPT },
   2302    { NAME_SIZE(sign), CKF_SIGN },
   2303    { NAME_SIZE(sign_recover), CKF_SIGN_RECOVER },
   2304    { NAME_SIZE(verify), CKF_VERIFY },
   2305    { NAME_SIZE(verify_recover), CKF_VERIFY_RECOVER },
   2306    { NAME_SIZE(wrap), CKF_WRAP },
   2307    { NAME_SIZE(unwrap), CKF_UNWRAP },
   2308    { NAME_SIZE(derive), CKF_DERIVE }
   2309 };
   2310 
   2311 int opFlagsCount = PR_ARRAY_SIZE(opFlagsArray);
   2312 
   2313 flagArray attrFlagsArray[] = {
   2314    { NAME_SIZE(token), PK11_ATTR_TOKEN },
   2315    { NAME_SIZE(session), PK11_ATTR_SESSION },
   2316    { NAME_SIZE(private), PK11_ATTR_PRIVATE },
   2317    { NAME_SIZE(public), PK11_ATTR_PUBLIC },
   2318    { NAME_SIZE(modifiable), PK11_ATTR_MODIFIABLE },
   2319    { NAME_SIZE(unmodifiable), PK11_ATTR_UNMODIFIABLE },
   2320    { NAME_SIZE(sensitive), PK11_ATTR_SENSITIVE },
   2321    { NAME_SIZE(insensitive), PK11_ATTR_INSENSITIVE },
   2322    { NAME_SIZE(extractable), PK11_ATTR_EXTRACTABLE },
   2323    { NAME_SIZE(unextractable), PK11_ATTR_UNEXTRACTABLE }
   2324 };
   2325 
   2326 int attrFlagsCount = PR_ARRAY_SIZE(attrFlagsArray);
   2327 
   2328 #define MAX_STRING 30
   2329 CK_ULONG
   2330 GetFlags(char *flagsString, flagArray *flags, int count)
   2331 {
   2332    CK_ULONG flagsValue = strtol(flagsString, NULL, 0);
   2333    int i;
   2334 
   2335    if ((flagsValue != 0) || (*flagsString == 0)) {
   2336        return flagsValue;
   2337    }
   2338    while (*flagsString) {
   2339        for (i = 0; i < count; i++) {
   2340            if (strncmp(flagsString, flags[i].name, flags[i].nameSize) ==
   2341                0) {
   2342                flagsValue |= flags[i].value;
   2343                flagsString += flags[i].nameSize;
   2344                if (*flagsString != 0) {
   2345                    flagsString++;
   2346                }
   2347                break;
   2348            }
   2349        }
   2350        if (i == count) {
   2351            char name[MAX_STRING];
   2352            char *tok;
   2353 
   2354            strncpy(name, flagsString, MAX_STRING);
   2355            name[MAX_STRING - 1] = 0;
   2356            tok = strchr(name, ',');
   2357            if (tok) {
   2358                *tok = 0;
   2359            }
   2360            fprintf(stderr, "Unknown flag (%s)\n", name);
   2361            tok = strchr(flagsString, ',');
   2362            if (tok == NULL) {
   2363                break;
   2364            }
   2365            flagsString = tok + 1;
   2366        }
   2367    }
   2368    return flagsValue;
   2369 }
   2370 
   2371 CK_FLAGS
   2372 GetOpFlags(char *flags)
   2373 {
   2374    return GetFlags(flags, opFlagsArray, opFlagsCount);
   2375 }
   2376 
   2377 PK11AttrFlags
   2378 GetAttrFlags(char *flags)
   2379 {
   2380    return GetFlags(flags, attrFlagsArray, attrFlagsCount);
   2381 }
   2382 
   2383 char *
   2384 mkNickname(unsigned char *data, int len)
   2385 {
   2386    char *nick = PORT_Alloc(len + 1);
   2387    if (!nick) {
   2388        return nick;
   2389    }
   2390    PORT_Memcpy(nick, data, len);
   2391    nick[len] = 0;
   2392    return nick;
   2393 }
   2394 
   2395 /*
   2396 * dump a PK11_MergeTokens error log to the console
   2397 */
   2398 void
   2399 DumpMergeLog(const char *progname, PK11MergeLog *log)
   2400 {
   2401    PK11MergeLogNode *node;
   2402 
   2403    for (node = log->head; node; node = node->next) {
   2404        SECItem attrItem;
   2405        char *nickname = NULL;
   2406        const char *objectClass = NULL;
   2407        SECStatus rv;
   2408 
   2409        attrItem.data = NULL;
   2410        rv = PK11_ReadRawAttribute(PK11_TypeGeneric, node->object,
   2411                                   CKA_LABEL, &attrItem);
   2412        if (rv == SECSuccess) {
   2413            nickname = mkNickname(attrItem.data, attrItem.len);
   2414            PORT_Free(attrItem.data);
   2415        }
   2416        attrItem.data = NULL;
   2417        rv = PK11_ReadRawAttribute(PK11_TypeGeneric, node->object,
   2418                                   CKA_CLASS, &attrItem);
   2419        if (rv == SECSuccess) {
   2420            if (attrItem.len == sizeof(CK_ULONG)) {
   2421                objectClass = getObjectClass(*(CK_ULONG *)attrItem.data);
   2422            }
   2423            PORT_Free(attrItem.data);
   2424        }
   2425 
   2426        fprintf(stderr, "%s: Could not merge object %s (type %s): %s\n",
   2427                progName,
   2428                nickname ? nickname : "unnamed",
   2429                objectClass ? objectClass : "unknown",
   2430                SECU_Strerror(node->error));
   2431 
   2432        if (nickname) {
   2433            PORT_Free(nickname);
   2434        }
   2435    }
   2436 }
   2437 
   2438 /*  Certutil commands  */
   2439 enum {
   2440    cmd_AddCert = 0,
   2441    cmd_CreateNewCert,
   2442    cmd_DeleteCert,
   2443    cmd_AddEmailCert,
   2444    cmd_DeleteKey,
   2445    cmd_GenKeyPair,
   2446    cmd_PrintHelp,
   2447    cmd_PrintSyntax,
   2448    cmd_ListKeys,
   2449    cmd_ListCerts,
   2450    cmd_ModifyCertTrust,
   2451    cmd_NewDBs,
   2452    cmd_DumpChain,
   2453    cmd_CertReq,
   2454    cmd_CreateAndAddCert,
   2455    cmd_TokenReset,
   2456    cmd_ListModules,
   2457    cmd_CheckCertValidity,
   2458    cmd_ChangePassword,
   2459    cmd_Version,
   2460    cmd_Batch,
   2461    cmd_Merge,
   2462    cmd_UpgradeMerge, /* test only */
   2463    cmd_Rename,
   2464    cmd_BuildFlags,
   2465    max_cmd
   2466 };
   2467 
   2468 /*  Certutil options */
   2469 enum certutilOpts {
   2470    opt_SSOPass = 0,
   2471    opt_AddKeyUsageExt,
   2472    opt_AddBasicConstraintExt,
   2473    opt_AddAuthorityKeyIDExt,
   2474    opt_AddCRLDistPtsExt,
   2475    opt_AddNSCertTypeExt,
   2476    opt_AddExtKeyUsageExt,
   2477    opt_ExtendedEmailAddrs,
   2478    opt_ExtendedDNSNames,
   2479    opt_ASCIIForIO,
   2480    opt_ValidityTime,
   2481    opt_IssuerName,
   2482    opt_CertDir,
   2483    opt_VerifySig,
   2484    opt_PasswordFile,
   2485    opt_KeySize,
   2486    opt_TokenName,
   2487    opt_InputFile,
   2488    opt_Emailaddress,
   2489    opt_KeyIndex,
   2490    opt_KeyType,
   2491    opt_DetailedInfo,
   2492    opt_SerialNumber,
   2493    opt_Nickname,
   2494    opt_OutputFile,
   2495    opt_PhoneNumber,
   2496    opt_DBPrefix,
   2497    opt_PQGFile,
   2498    opt_BinaryDER,
   2499    opt_Subject,
   2500    opt_Trust,
   2501    opt_Usage,
   2502    opt_Validity,
   2503    opt_OffsetMonths,
   2504    opt_SelfSign,
   2505    opt_RW,
   2506    opt_Exponent,
   2507    opt_NoiseFile,
   2508    opt_Hash,
   2509    opt_NewPasswordFile,
   2510    opt_AddAuthInfoAccExt,
   2511    opt_AddSubjInfoAccExt,
   2512    opt_AddCertPoliciesExt,
   2513    opt_AddPolicyMapExt,
   2514    opt_AddPolicyConstrExt,
   2515    opt_AddInhibAnyExt,
   2516    opt_AddNameConstraintsExt,
   2517    opt_AddSubjectKeyIDExt,
   2518    opt_AddCmdKeyUsageExt,
   2519    opt_AddCmdNSCertTypeExt,
   2520    opt_AddCmdExtKeyUsageExt,
   2521    opt_SourceDir,
   2522    opt_SourcePrefix,
   2523    opt_UpgradeID,
   2524    opt_UpgradeTokenName,
   2525    opt_KeyOpFlagsOn,
   2526    opt_KeyOpFlagsOff,
   2527    opt_KeyAttrFlags,
   2528    opt_EmptyPassword,
   2529    opt_CertVersion,
   2530    opt_AddSubjectAltNameExt,
   2531    opt_DumpExtensionValue,
   2532    opt_GenericExtensions,
   2533    opt_NewNickname,
   2534    opt_Pss,
   2535    opt_PssSign,
   2536    opt_SimpleSelfSigned,
   2537    opt_Help
   2538 };
   2539 
   2540 static const secuCommandFlag commands_init[] = {
   2541    { /* cmd_AddCert             */ 'A', PR_FALSE, 0, PR_FALSE },
   2542    { /* cmd_CreateNewCert       */ 'C', PR_FALSE, 0, PR_FALSE },
   2543    { /* cmd_DeleteCert          */ 'D', PR_FALSE, 0, PR_FALSE },
   2544    { /* cmd_AddEmailCert        */ 'E', PR_FALSE, 0, PR_FALSE },
   2545    { /* cmd_DeleteKey           */ 'F', PR_FALSE, 0, PR_FALSE },
   2546    { /* cmd_GenKeyPair          */ 'G', PR_FALSE, 0, PR_FALSE },
   2547    { /* cmd_PrintHelp           */ 'H', PR_FALSE, 0, PR_FALSE, "help" },
   2548    { /* cmd_PrintSyntax         */ 0, PR_FALSE, 0, PR_FALSE,
   2549      "syntax" },
   2550    { /* cmd_ListKeys            */ 'K', PR_FALSE, 0, PR_FALSE },
   2551    { /* cmd_ListCerts           */ 'L', PR_FALSE, 0, PR_FALSE },
   2552    { /* cmd_ModifyCertTrust     */ 'M', PR_FALSE, 0, PR_FALSE },
   2553    { /* cmd_NewDBs              */ 'N', PR_FALSE, 0, PR_FALSE },
   2554    { /* cmd_DumpChain           */ 'O', PR_FALSE, 0, PR_FALSE },
   2555    { /* cmd_CertReq             */ 'R', PR_FALSE, 0, PR_FALSE },
   2556    { /* cmd_CreateAndAddCert    */ 'S', PR_FALSE, 0, PR_FALSE },
   2557    { /* cmd_TokenReset          */ 'T', PR_FALSE, 0, PR_FALSE },
   2558    { /* cmd_ListModules         */ 'U', PR_FALSE, 0, PR_FALSE },
   2559    { /* cmd_CheckCertValidity   */ 'V', PR_FALSE, 0, PR_FALSE },
   2560    { /* cmd_ChangePassword      */ 'W', PR_FALSE, 0, PR_FALSE },
   2561    { /* cmd_Version             */ 'Y', PR_FALSE, 0, PR_FALSE },
   2562    { /* cmd_Batch               */ 'B', PR_FALSE, 0, PR_FALSE },
   2563    { /* cmd_Merge               */ 0, PR_FALSE, 0, PR_FALSE, "merge" },
   2564    { /* cmd_UpgradeMerge        */ 0, PR_FALSE, 0, PR_FALSE,
   2565      "upgrade-merge" },
   2566    { /* cmd_Rename              */ 0, PR_FALSE, 0, PR_FALSE,
   2567      "rename" },
   2568    { /* cmd_BuildFlags          */ 0, PR_FALSE, 0, PR_FALSE,
   2569      "build-flags" }
   2570 };
   2571 #define NUM_COMMANDS ((sizeof commands_init) / (sizeof commands_init[0]))
   2572 
   2573 static const secuCommandFlag options_init[] = {
   2574    { /* opt_SSOPass             */ '0', PR_TRUE, 0, PR_FALSE },
   2575    { /* opt_AddKeyUsageExt      */ '1', PR_FALSE, 0, PR_FALSE },
   2576    { /* opt_AddBasicConstraintExt*/ '2', PR_FALSE, 0, PR_FALSE },
   2577    { /* opt_AddAuthorityKeyIDExt*/ '3', PR_FALSE, 0, PR_FALSE },
   2578    { /* opt_AddCRLDistPtsExt    */ '4', PR_FALSE, 0, PR_FALSE },
   2579    { /* opt_AddNSCertTypeExt    */ '5', PR_FALSE, 0, PR_FALSE },
   2580    { /* opt_AddExtKeyUsageExt   */ '6', PR_FALSE, 0, PR_FALSE },
   2581    { /* opt_ExtendedEmailAddrs  */ '7', PR_TRUE, 0, PR_FALSE },
   2582    { /* opt_ExtendedDNSNames    */ '8', PR_TRUE, 0, PR_FALSE },
   2583    { /* opt_ASCIIForIO          */ 'a', PR_FALSE, 0, PR_FALSE },
   2584    { /* opt_ValidityTime        */ 'b', PR_TRUE, 0, PR_FALSE },
   2585    { /* opt_IssuerName          */ 'c', PR_TRUE, 0, PR_FALSE },
   2586    { /* opt_CertDir             */ 'd', PR_TRUE, 0, PR_FALSE },
   2587    { /* opt_VerifySig           */ 'e', PR_FALSE, 0, PR_FALSE },
   2588    { /* opt_PasswordFile        */ 'f', PR_TRUE, 0, PR_FALSE },
   2589    { /* opt_KeySize             */ 'g', PR_TRUE, 0, PR_FALSE },
   2590    { /* opt_TokenName           */ 'h', PR_TRUE, 0, PR_FALSE },
   2591    { /* opt_InputFile           */ 'i', PR_TRUE, 0, PR_FALSE },
   2592    { /* opt_Emailaddress        */ 0, PR_TRUE, 0, PR_FALSE, "email" },
   2593    { /* opt_KeyIndex            */ 'j', PR_TRUE, 0, PR_FALSE },
   2594    { /* opt_KeyType             */ 'k', PR_TRUE, 0, PR_FALSE },
   2595    { /* opt_DetailedInfo        */ 'l', PR_FALSE, 0, PR_FALSE },
   2596    { /* opt_SerialNumber        */ 'm', PR_TRUE, 0, PR_FALSE },
   2597    { /* opt_Nickname            */ 'n', PR_TRUE, 0, PR_FALSE },
   2598    { /* opt_OutputFile          */ 'o', PR_TRUE, 0, PR_FALSE },
   2599    { /* opt_PhoneNumber         */ 'p', PR_TRUE, 0, PR_FALSE },
   2600    { /* opt_DBPrefix            */ 'P', PR_TRUE, 0, PR_FALSE },
   2601    { /* opt_PQGFile             */ 'q', PR_TRUE, 0, PR_FALSE },
   2602    { /* opt_BinaryDER           */ 'r', PR_FALSE, 0, PR_FALSE },
   2603    { /* opt_Subject             */ 's', PR_TRUE, 0, PR_FALSE },
   2604    { /* opt_Trust               */ 't', PR_TRUE, 0, PR_FALSE },
   2605    { /* opt_Usage               */ 'u', PR_TRUE, 0, PR_FALSE },
   2606    { /* opt_Validity            */ 'v', PR_TRUE, 0, PR_FALSE },
   2607    { /* opt_OffsetMonths        */ 'w', PR_TRUE, 0, PR_FALSE },
   2608    { /* opt_SelfSign            */ 'x', PR_FALSE, 0, PR_FALSE },
   2609    { /* opt_RW                  */ 'X', PR_FALSE, 0, PR_FALSE },
   2610    { /* opt_Exponent            */ 'y', PR_TRUE, 0, PR_FALSE },
   2611    { /* opt_NoiseFile           */ 'z', PR_TRUE, 0, PR_FALSE },
   2612    { /* opt_Hash                */ 'Z', PR_TRUE, 0, PR_FALSE },
   2613    { /* opt_NewPasswordFile     */ '@', PR_TRUE, 0, PR_FALSE },
   2614    { /* opt_AddAuthInfoAccExt   */ 0, PR_FALSE, 0, PR_FALSE, "extAIA" },
   2615    { /* opt_AddSubjInfoAccExt   */ 0, PR_FALSE, 0, PR_FALSE, "extSIA" },
   2616    { /* opt_AddCertPoliciesExt  */ 0, PR_FALSE, 0, PR_FALSE, "extCP" },
   2617    { /* opt_AddPolicyMapExt     */ 0, PR_FALSE, 0, PR_FALSE, "extPM" },
   2618    { /* opt_AddPolicyConstrExt  */ 0, PR_FALSE, 0, PR_FALSE, "extPC" },
   2619    { /* opt_AddInhibAnyExt      */ 0, PR_FALSE, 0, PR_FALSE, "extIA" },
   2620    { /* opt_AddNameConstraintsExt*/ 0, PR_FALSE, 0, PR_FALSE, "extNC" },
   2621    { /* opt_AddSubjectKeyIDExt  */ 0, PR_FALSE, 0, PR_FALSE,
   2622      "extSKID" },
   2623    { /* opt_AddCmdKeyUsageExt   */ 0, PR_TRUE, 0, PR_FALSE,
   2624      "keyUsage" },
   2625    { /* opt_AddCmdNSCertTypeExt */ 0, PR_TRUE, 0, PR_FALSE,
   2626      "nsCertType" },
   2627    { /* opt_AddCmdExtKeyUsageExt*/ 0, PR_TRUE, 0, PR_FALSE,
   2628      "extKeyUsage" },
   2629 
   2630    { /* opt_SourceDir           */ 0, PR_TRUE, 0, PR_FALSE,
   2631      "source-dir" },
   2632    { /* opt_SourcePrefix        */ 0, PR_TRUE, 0, PR_FALSE,
   2633      "source-prefix" },
   2634    { /* opt_UpgradeID           */ 0, PR_TRUE, 0, PR_FALSE,
   2635      "upgrade-id" },
   2636    { /* opt_UpgradeTokenName    */ 0, PR_TRUE, 0, PR_FALSE,
   2637      "upgrade-token-name" },
   2638    { /* opt_KeyOpFlagsOn        */ 0, PR_TRUE, 0, PR_FALSE,
   2639      "keyOpFlagsOn" },
   2640    { /* opt_KeyOpFlagsOff       */ 0, PR_TRUE, 0, PR_FALSE,
   2641      "keyOpFlagsOff" },
   2642    { /* opt_KeyAttrFlags        */ 0, PR_TRUE, 0, PR_FALSE,
   2643      "keyAttrFlags" },
   2644    { /* opt_EmptyPassword       */ 0, PR_FALSE, 0, PR_FALSE,
   2645      "empty-password" },
   2646    { /* opt_CertVersion         */ 0, PR_TRUE, 0, PR_FALSE,
   2647      "certVersion" },
   2648    { /* opt_AddSubjectAltExt    */ 0, PR_TRUE, 0, PR_FALSE, "extSAN" },
   2649    { /* opt_DumpExtensionValue  */ 0, PR_TRUE, 0, PR_FALSE,
   2650      "dump-ext-val" },
   2651    { /* opt_GenericExtensions   */ 0, PR_TRUE, 0, PR_FALSE,
   2652      "extGeneric" },
   2653    { /* opt_NewNickname         */ 0, PR_TRUE, 0, PR_FALSE,
   2654      "new-n" },
   2655    { /* opt_Pss                 */ 0, PR_FALSE, 0, PR_FALSE,
   2656      "pss" },
   2657    { /* opt_PssSign             */ 0, PR_FALSE, 0, PR_FALSE,
   2658      "pss-sign" },
   2659    { /* opt_SimpleSelfSigned    */ 0, PR_FALSE, 0, PR_FALSE,
   2660      "simple-self-signed" },
   2661 };
   2662 #define NUM_OPTIONS ((sizeof options_init) / (sizeof options_init[0]))
   2663 
   2664 static secuCommandFlag certutil_commands[NUM_COMMANDS];
   2665 static secuCommandFlag certutil_options[NUM_OPTIONS];
   2666 
   2667 static const secuCommand certutil = {
   2668    NUM_COMMANDS,
   2669    NUM_OPTIONS,
   2670    certutil_commands,
   2671    certutil_options
   2672 };
   2673 
   2674 static certutilExtnList certutil_extns;
   2675 
   2676 static int
   2677 certutil_main(int argc, char **argv, PRBool initialize)
   2678 {
   2679    CERTCertDBHandle *certHandle;
   2680    PK11SlotInfo *slot = NULL;
   2681    CERTName *subject = 0;
   2682    PRFileDesc *inFile = PR_STDIN;
   2683    PRFileDesc *outFile = PR_STDOUT;
   2684    SECItem certReqDER = { siBuffer, NULL, 0 };
   2685    SECItem certDER = { siBuffer, NULL, 0 };
   2686    const char *slotname = "internal";
   2687    const char *certPrefix = "";
   2688    char *sourceDir = "";
   2689    const char *srcCertPrefix = "";
   2690    char *upgradeID = "";
   2691    char *upgradeTokenName = "";
   2692    KeyType keytype = rsaKey;
   2693    char *name = NULL;
   2694    char *newName = NULL;
   2695    char *email = NULL;
   2696    char *keysource = NULL;
   2697    SECOidTag hashAlgTag = SEC_OID_UNKNOWN;
   2698    int keysize = DEFAULT_KEY_BITS;
   2699    int publicExponent = 0x010001;
   2700    int certVersion = SEC_CERTIFICATE_VERSION_3;
   2701    unsigned int serialNumber = 0;
   2702    int warpmonths = 0;
   2703    int validityMonths = 3;
   2704    int commandsEntered = 0;
   2705    char commandToRun = '\0';
   2706    secuPWData pwdata = { PW_NONE, 0 };
   2707    secuPWData pwdata2 = { PW_NONE, 0 };
   2708    PRBool readOnly = PR_FALSE;
   2709    PRBool initialized = PR_FALSE;
   2710    CK_FLAGS keyOpFlagsOn = 0;
   2711    CK_FLAGS keyOpFlagsOff = 0;
   2712    PK11AttrFlags keyAttrFlags =
   2713        PK11_ATTR_TOKEN | PK11_ATTR_SENSITIVE | PK11_ATTR_PRIVATE;
   2714 
   2715    SECKEYPrivateKey *privkey = NULL;
   2716    SECKEYPublicKey *pubkey = NULL;
   2717 
   2718    int i;
   2719    SECStatus rv;
   2720 
   2721    progName = PORT_Strrchr(argv[0], '/');
   2722    progName = progName ? progName + 1 : argv[0];
   2723    memcpy(certutil_commands, commands_init, sizeof commands_init);
   2724    memcpy(certutil_options, options_init, sizeof options_init);
   2725 
   2726    rv = SECU_ParseCommandLine(argc, argv, progName, &certutil);
   2727 
   2728    if (rv != SECSuccess)
   2729        Usage();
   2730 
   2731    if (certutil.commands[cmd_PrintSyntax].activated) {
   2732        PrintSyntax();
   2733    }
   2734 
   2735    if (certutil.commands[cmd_PrintHelp].activated) {
   2736        char buf[2];
   2737        const char *command = NULL;
   2738        for (i = 0; i < max_cmd; i++) {
   2739            if (i == cmd_PrintHelp)
   2740                continue;
   2741            if (certutil.commands[i].activated) {
   2742                if (certutil.commands[i].flag) {
   2743                    buf[0] = certutil.commands[i].flag;
   2744                    buf[1] = 0;
   2745                    command = buf;
   2746                } else {
   2747                    command = certutil.commands[i].longform;
   2748                }
   2749                break;
   2750            }
   2751        }
   2752        LongUsage((command ? usage_selected : usage_all), command);
   2753        exit(1);
   2754    }
   2755 
   2756    if (certutil.commands[cmd_BuildFlags].activated) {
   2757        PrintBuildFlags();
   2758    }
   2759 
   2760    if (certutil.options[opt_PasswordFile].arg) {
   2761        pwdata.source = PW_FROMFILE;
   2762        pwdata.data = certutil.options[opt_PasswordFile].arg;
   2763    }
   2764    if (certutil.options[opt_NewPasswordFile].arg) {
   2765        pwdata2.source = PW_FROMFILE;
   2766        pwdata2.data = certutil.options[opt_NewPasswordFile].arg;
   2767    }
   2768 
   2769    if (certutil.options[opt_CertDir].activated)
   2770        SECU_ConfigDirectory(certutil.options[opt_CertDir].arg);
   2771 
   2772    if (certutil.options[opt_SourceDir].activated)
   2773        sourceDir = certutil.options[opt_SourceDir].arg;
   2774 
   2775    if (certutil.options[opt_UpgradeID].activated)
   2776        upgradeID = certutil.options[opt_UpgradeID].arg;
   2777 
   2778    if (certutil.options[opt_UpgradeTokenName].activated)
   2779        upgradeTokenName = certutil.options[opt_UpgradeTokenName].arg;
   2780 
   2781    if (certutil.options[opt_KeySize].activated) {
   2782        keysize = PORT_Atoi(certutil.options[opt_KeySize].arg);
   2783        if ((keysize < MIN_KEY_BITS) || (keysize > MAX_KEY_BITS)) {
   2784            PR_fprintf(PR_STDERR,
   2785                       "%s -g:  Keysize must be between %d and %d.\n",
   2786                       progName, MIN_KEY_BITS, MAX_KEY_BITS);
   2787            return 255;
   2788        }
   2789        if (keytype == ecKey) {
   2790            PR_fprintf(PR_STDERR, "%s -g:  Not for ec keys.\n", progName);
   2791            return 255;
   2792        }
   2793    }
   2794 
   2795    /*  -h specify token name  */
   2796    if (certutil.options[opt_TokenName].activated) {
   2797        if (PL_strcmp(certutil.options[opt_TokenName].arg, "all") == 0)
   2798            slotname = NULL;
   2799        else
   2800            slotname = certutil.options[opt_TokenName].arg;
   2801    }
   2802 
   2803    /*  -Z hash type  */
   2804    if (certutil.options[opt_Hash].activated) {
   2805        char *arg = certutil.options[opt_Hash].arg;
   2806        hashAlgTag = SECU_StringToSignatureAlgTag(arg);
   2807        if (hashAlgTag == SEC_OID_UNKNOWN) {
   2808            PR_fprintf(PR_STDERR, "%s -Z:  %s is not a recognized type.\n",
   2809                       progName, arg);
   2810            return 255;
   2811        }
   2812    }
   2813 
   2814    /*  -k key type  */
   2815    if (certutil.options[opt_KeyType].activated) {
   2816        char *arg = certutil.options[opt_KeyType].arg;
   2817        if (PL_strcmp(arg, "rsa") == 0) {
   2818            keytype = rsaKey;
   2819        } else if (PL_strcmp(arg, "dsa") == 0) {
   2820            keytype = dsaKey;
   2821        } else if (PL_strcmp(arg, "ec") == 0) {
   2822            keytype = ecKey;
   2823        } else if (PL_strcmp(arg, "all") == 0) {
   2824            keytype = nullKey;
   2825        } else {
   2826            /* use an existing private/public key pair */
   2827            keysource = arg;
   2828        }
   2829    } else if (certutil.commands[cmd_ListKeys].activated) {
   2830        keytype = nullKey;
   2831    }
   2832 
   2833    if (certutil.options[opt_KeyOpFlagsOn].activated) {
   2834        keyOpFlagsOn = GetOpFlags(certutil.options[opt_KeyOpFlagsOn].arg);
   2835    }
   2836    if (certutil.options[opt_KeyOpFlagsOff].activated) {
   2837        keyOpFlagsOff = GetOpFlags(certutil.options[opt_KeyOpFlagsOff].arg);
   2838        keyOpFlagsOn &= ~keyOpFlagsOff; /* make off override on */
   2839    }
   2840    if (certutil.options[opt_KeyAttrFlags].activated) {
   2841        keyAttrFlags = GetAttrFlags(certutil.options[opt_KeyAttrFlags].arg);
   2842    }
   2843 
   2844    /*  -m serial number */
   2845    if (certutil.options[opt_SerialNumber].activated) {
   2846        int sn = PORT_Atoi(certutil.options[opt_SerialNumber].arg);
   2847        if (sn < 0) {
   2848            PR_fprintf(PR_STDERR, "%s -m:  %s is not a valid serial number.\n",
   2849                       progName, certutil.options[opt_SerialNumber].arg);
   2850            return 255;
   2851        }
   2852        serialNumber = sn;
   2853    }
   2854 
   2855    /*  -P certdb name prefix */
   2856    if (certutil.options[opt_DBPrefix].activated) {
   2857        if (certutil.options[opt_DBPrefix].arg) {
   2858            certPrefix = certutil.options[opt_DBPrefix].arg;
   2859        } else {
   2860            Usage();
   2861        }
   2862    }
   2863 
   2864    /*  --source-prefix certdb name prefix */
   2865    if (certutil.options[opt_SourcePrefix].activated) {
   2866        if (certutil.options[opt_SourcePrefix].arg) {
   2867            srcCertPrefix = certutil.options[opt_SourcePrefix].arg;
   2868        } else {
   2869            Usage();
   2870        }
   2871    }
   2872 
   2873    /*  -q PQG file or curve name */
   2874    if (certutil.options[opt_PQGFile].activated) {
   2875        if ((keytype != dsaKey) && (keytype != ecKey)) {
   2876            PR_fprintf(PR_STDERR, "%s -q: specifies a PQG file for DSA keys"
   2877                                  " (-k dsa) or a named curve for EC keys (-k ec)\n)",
   2878                       progName);
   2879            return 255;
   2880        }
   2881    }
   2882 
   2883    /*  -s subject name  */
   2884    if (certutil.options[opt_Subject].activated) {
   2885        subject = CERT_AsciiToName(certutil.options[opt_Subject].arg);
   2886        if (!subject) {
   2887            PR_fprintf(PR_STDERR, "%s -s: improperly formatted name: \"%s\"\n",
   2888                       progName, certutil.options[opt_Subject].arg);
   2889            return 255;
   2890        }
   2891    }
   2892 
   2893    /*  -v validity period  */
   2894    if (certutil.options[opt_Validity].activated) {
   2895        validityMonths = PORT_Atoi(certutil.options[opt_Validity].arg);
   2896        if (validityMonths < 0) {
   2897            PR_fprintf(PR_STDERR, "%s -v: incorrect validity period: \"%s\"\n",
   2898                       progName, certutil.options[opt_Validity].arg);
   2899            return 255;
   2900        }
   2901    }
   2902 
   2903    /*  -w warp months  */
   2904    if (certutil.options[opt_OffsetMonths].activated)
   2905        warpmonths = PORT_Atoi(certutil.options[opt_OffsetMonths].arg);
   2906 
   2907    /*  -y public exponent (for RSA)  */
   2908    if (certutil.options[opt_Exponent].activated) {
   2909        publicExponent = PORT_Atoi(certutil.options[opt_Exponent].arg);
   2910        if ((publicExponent != 3) &&
   2911            (publicExponent != 17) &&
   2912            (publicExponent != 65537)) {
   2913            PR_fprintf(PR_STDERR, "%s -y: incorrect public exponent %d.",
   2914                       progName, publicExponent);
   2915            PR_fprintf(PR_STDERR, "Must be 3, 17, or 65537.\n");
   2916            return 255;
   2917        }
   2918    }
   2919 
   2920    /*  --certVersion */
   2921    if (certutil.options[opt_CertVersion].activated) {
   2922        certVersion = PORT_Atoi(certutil.options[opt_CertVersion].arg);
   2923        if (certVersion < 1 || certVersion > 4) {
   2924            PR_fprintf(PR_STDERR, "%s -certVersion: incorrect certificate version %d.",
   2925                       progName, certVersion);
   2926            PR_fprintf(PR_STDERR, "Must be 1, 2, 3 or 4.\n");
   2927            return 255;
   2928        }
   2929        certVersion = certVersion - 1;
   2930    }
   2931 
   2932    /*  Check number of commands entered.  */
   2933    commandsEntered = 0;
   2934    for (i = 0; i < certutil.numCommands; i++) {
   2935        if (certutil.commands[i].activated) {
   2936            commandToRun = certutil.commands[i].flag;
   2937            commandsEntered++;
   2938        }
   2939        if (commandsEntered > 1)
   2940            break;
   2941    }
   2942    if (commandsEntered > 1) {
   2943        PR_fprintf(PR_STDERR, "%s: only one command at a time!\n", progName);
   2944        PR_fprintf(PR_STDERR, "You entered: ");
   2945        for (i = 0; i < certutil.numCommands; i++) {
   2946            if (certutil.commands[i].activated)
   2947                PR_fprintf(PR_STDERR, " -%c", certutil.commands[i].flag);
   2948        }
   2949        PR_fprintf(PR_STDERR, "\n");
   2950        return 255;
   2951    }
   2952    if (commandsEntered == 0) {
   2953        Usage();
   2954    }
   2955 
   2956    if (certutil.commands[cmd_ListCerts].activated ||
   2957        certutil.commands[cmd_PrintHelp].activated ||
   2958        certutil.commands[cmd_ListKeys].activated ||
   2959        certutil.commands[cmd_ListModules].activated ||
   2960        certutil.commands[cmd_CheckCertValidity].activated ||
   2961        certutil.commands[cmd_Version].activated) {
   2962        readOnly = !certutil.options[opt_RW].activated;
   2963    }
   2964 
   2965    /*  -A, -D, -M, -S, -V, and all require -n  */
   2966    if ((certutil.commands[cmd_AddCert].activated ||
   2967         certutil.commands[cmd_DeleteCert].activated ||
   2968         certutil.commands[cmd_DumpChain].activated ||
   2969         certutil.commands[cmd_ModifyCertTrust].activated ||
   2970         certutil.commands[cmd_CreateAndAddCert].activated ||
   2971         certutil.commands[cmd_CheckCertValidity].activated) &&
   2972        !certutil.options[opt_Nickname].activated) {
   2973        PR_fprintf(PR_STDERR,
   2974                   "%s -%c: nickname is required for this command (-n).\n",
   2975                   progName, commandToRun);
   2976        return 255;
   2977    }
   2978 
   2979    /*  -A, -E, -M, -S require trust  */
   2980    if ((certutil.commands[cmd_AddCert].activated ||
   2981         certutil.commands[cmd_AddEmailCert].activated ||
   2982         certutil.commands[cmd_ModifyCertTrust].activated ||
   2983         certutil.commands[cmd_CreateAndAddCert].activated) &&
   2984        !certutil.options[opt_Trust].activated) {
   2985        PR_fprintf(PR_STDERR,
   2986                   "%s -%c: trust is required for this command (-t).\n",
   2987                   progName, commandToRun);
   2988        return 255;
   2989    }
   2990 
   2991    /*  if -L is given raw, ascii or dump mode, it must be for only one cert. */
   2992    if (certutil.commands[cmd_ListCerts].activated &&
   2993        (certutil.options[opt_ASCIIForIO].activated ||
   2994         certutil.options[opt_DumpExtensionValue].activated ||
   2995         certutil.options[opt_BinaryDER].activated) &&
   2996        !certutil.options[opt_Nickname].activated) {
   2997        PR_fprintf(PR_STDERR,
   2998                   "%s: nickname is required to dump cert in raw or ascii mode.\n",
   2999                   progName);
   3000        return 255;
   3001    }
   3002 
   3003    /*  -L can only be in (raw || ascii).  */
   3004    if (certutil.commands[cmd_ListCerts].activated &&
   3005        certutil.options[opt_ASCIIForIO].activated &&
   3006        certutil.options[opt_BinaryDER].activated) {
   3007        PR_fprintf(PR_STDERR,
   3008                   "%s: cannot specify both -r and -a when dumping cert.\n",
   3009                   progName);
   3010        return 255;
   3011    }
   3012 
   3013    /*  If making a cert request, need a subject.  */
   3014    if ((certutil.commands[cmd_CertReq].activated ||
   3015         certutil.commands[cmd_CreateAndAddCert].activated) &&
   3016        !(certutil.options[opt_Subject].activated || keysource)) {
   3017        PR_fprintf(PR_STDERR,
   3018                   "%s -%c: subject is required to create a cert request.\n",
   3019                   progName, commandToRun);
   3020        return 255;
   3021    }
   3022 
   3023    /*  If making a cert, need a serial number.  */
   3024    if ((certutil.commands[cmd_CreateNewCert].activated ||
   3025         certutil.commands[cmd_CreateAndAddCert].activated) &&
   3026        !certutil.options[opt_SerialNumber].activated) {
   3027        /*  Make a default serial number from the current time.  */
   3028        PRTime now = PR_Now();
   3029        LL_USHR(now, now, 19);
   3030        LL_L2UI(serialNumber, now);
   3031    }
   3032 
   3033    /*  Validation needs the usage to validate for.  */
   3034    if (certutil.commands[cmd_CheckCertValidity].activated &&
   3035        !certutil.options[opt_Usage].activated) {
   3036        PR_fprintf(PR_STDERR,
   3037                   "%s -V: specify a usage to validate the cert for (-u).\n",
   3038                   progName);
   3039        return 255;
   3040    }
   3041 
   3042    /* Rename needs an old and a new nickname */
   3043    if (certutil.commands[cmd_Rename].activated &&
   3044        !(certutil.options[opt_Nickname].activated &&
   3045          certutil.options[opt_NewNickname].activated)) {
   3046 
   3047        PR_fprintf(PR_STDERR,
   3048                   "%s --rename: specify an old nickname (-n) and\n"
   3049                   "   a new nickname (--new-n).\n",
   3050                   progName);
   3051        return 255;
   3052    }
   3053 
   3054    /* Delete needs a nickname or a key ID */
   3055    if (certutil.commands[cmd_DeleteKey].activated &&
   3056        !(certutil.options[opt_Nickname].activated || keysource)) {
   3057        PR_fprintf(PR_STDERR,
   3058                   "%s -%c: specify a nickname (-n) or\n"
   3059                   "   a key ID (-k).\n",
   3060                   progName, commandToRun);
   3061        return 255;
   3062    }
   3063 
   3064    /* Upgrade/Merge needs a source database and a upgrade id. */
   3065    if (certutil.commands[cmd_UpgradeMerge].activated &&
   3066        !(certutil.options[opt_SourceDir].activated &&
   3067          certutil.options[opt_UpgradeID].activated)) {
   3068 
   3069        PR_fprintf(PR_STDERR,
   3070                   "%s --upgrade-merge: specify an upgrade database directory "
   3071                   "(--source-dir) and\n"
   3072                   "   an upgrade ID (--upgrade-id).\n",
   3073                   progName);
   3074        return 255;
   3075    }
   3076 
   3077    /* Merge needs a source database */
   3078    if (certutil.commands[cmd_Merge].activated &&
   3079        !certutil.options[opt_SourceDir].activated) {
   3080 
   3081        PR_fprintf(PR_STDERR,
   3082                   "%s --merge: specify an source database directory "
   3083                   "(--source-dir)\n",
   3084                   progName);
   3085        return 255;
   3086    }
   3087 
   3088    /*  To make a cert, need either a issuer or to self-sign it.  */
   3089    if (certutil.commands[cmd_CreateAndAddCert].activated &&
   3090        !(certutil.options[opt_IssuerName].activated ||
   3091          certutil.options[opt_SelfSign].activated)) {
   3092        PR_fprintf(PR_STDERR,
   3093                   "%s -S: must specify issuer (-c) or self-sign (-x).\n",
   3094                   progName);
   3095        return 255;
   3096    }
   3097 
   3098    /*  Using slotname == NULL for listing keys and certs on all slots,
   3099     *  but only that. */
   3100    if (!(certutil.commands[cmd_ListKeys].activated ||
   3101          certutil.commands[cmd_DumpChain].activated ||
   3102          certutil.commands[cmd_ListCerts].activated) &&
   3103        slotname == NULL) {
   3104        PR_fprintf(PR_STDERR,
   3105                   "%s -%c: cannot use \"-h all\" for this command.\n",
   3106                   progName, commandToRun);
   3107        return 255;
   3108    }
   3109 
   3110    /*  Using keytype == nullKey for list all key types, but only that.  */
   3111    if (!certutil.commands[cmd_ListKeys].activated && keytype == nullKey) {
   3112        PR_fprintf(PR_STDERR,
   3113                   "%s -%c: cannot use \"-k all\" for this command.\n",
   3114                   progName, commandToRun);
   3115        return 255;
   3116    }
   3117 
   3118    /*  Open the input file.  */
   3119    if (certutil.options[opt_InputFile].activated) {
   3120        inFile = PR_Open(certutil.options[opt_InputFile].arg, PR_RDONLY, 0);
   3121        if (!inFile) {
   3122            PR_fprintf(PR_STDERR,
   3123                       "%s:  unable to open \"%s\" for reading (%ld, %ld).\n",
   3124                       progName, certutil.options[opt_InputFile].arg,
   3125                       PR_GetError(), PR_GetOSError());
   3126            return 255;
   3127        }
   3128    }
   3129 
   3130    /*  Open the output file.  */
   3131    if (certutil.options[opt_OutputFile].activated) {
   3132        outFile = PR_Open(certutil.options[opt_OutputFile].arg,
   3133                          PR_CREATE_FILE | PR_RDWR | PR_TRUNCATE, 00660);
   3134        if (!outFile) {
   3135            PR_fprintf(PR_STDERR,
   3136                       "%s:  unable to open \"%s\" for writing (%ld, %ld).\n",
   3137                       progName, certutil.options[opt_OutputFile].arg,
   3138                       PR_GetError(), PR_GetOSError());
   3139            return 255;
   3140        }
   3141    }
   3142 
   3143    name = SECU_GetOptionArg(&certutil, opt_Nickname);
   3144    newName = SECU_GetOptionArg(&certutil, opt_NewNickname);
   3145    email = SECU_GetOptionArg(&certutil, opt_Emailaddress);
   3146 
   3147    PK11_SetPasswordFunc(SECU_GetModulePassword);
   3148 
   3149    if (PR_TRUE == initialize) {
   3150        /*  Initialize NSPR and NSS.  */
   3151        PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
   3152        if (!certutil.commands[cmd_UpgradeMerge].activated) {
   3153            rv = NSS_Initialize(SECU_ConfigDirectory(NULL),
   3154                                certPrefix, certPrefix,
   3155                                "secmod.db", readOnly ? NSS_INIT_READONLY : 0);
   3156        } else {
   3157            rv = NSS_InitWithMerge(SECU_ConfigDirectory(NULL),
   3158                                   certPrefix, certPrefix, "secmod.db",
   3159                                   sourceDir, srcCertPrefix, srcCertPrefix,
   3160                                   upgradeID, upgradeTokenName,
   3161                                   readOnly ? NSS_INIT_READONLY : 0);
   3162        }
   3163        if (rv != SECSuccess) {
   3164            SECU_PrintPRandOSError(progName);
   3165            rv = SECFailure;
   3166            goto shutdown;
   3167        }
   3168        initialized = PR_TRUE;
   3169        SECU_RegisterDynamicOids();
   3170        /* Ensure the SSL error code table has been registered. Bug 1460284. */
   3171        SSL_OptionSetDefault(-1, 0);
   3172    }
   3173    certHandle = CERT_GetDefaultCertDB();
   3174 
   3175    if (certutil.commands[cmd_Version].activated) {
   3176        printf("Certificate database content version: command not implemented.\n");
   3177    }
   3178 
   3179    if (PL_strcmp(slotname, "internal") == 0)
   3180        slot = PK11_GetInternalKeySlot();
   3181    else if (slotname != NULL)
   3182        slot = PK11_FindSlotByName(slotname);
   3183 
   3184    if (!slot && (certutil.commands[cmd_NewDBs].activated ||
   3185                  certutil.commands[cmd_ModifyCertTrust].activated ||
   3186                  certutil.commands[cmd_ChangePassword].activated ||
   3187                  certutil.commands[cmd_TokenReset].activated ||
   3188                  certutil.commands[cmd_CreateAndAddCert].activated ||
   3189                  certutil.commands[cmd_AddCert].activated ||
   3190                  certutil.commands[cmd_Merge].activated ||
   3191                  certutil.commands[cmd_UpgradeMerge].activated ||
   3192                  certutil.commands[cmd_AddEmailCert].activated)) {
   3193 
   3194        SECU_PrintError(progName, "could not find the slot %s", slotname);
   3195        rv = SECFailure;
   3196        goto shutdown;
   3197    }
   3198 
   3199    /*  If creating new database, initialize the password.  */
   3200    if (certutil.commands[cmd_NewDBs].activated) {
   3201        if (certutil.options[opt_EmptyPassword].activated && (PK11_NeedUserInit(slot))) {
   3202            rv = PK11_InitPin(slot, (char *)NULL, "");
   3203        } else {
   3204            rv = SECU_ChangePW2(slot, 0, 0, certutil.options[opt_PasswordFile].arg,
   3205                                certutil.options[opt_NewPasswordFile].arg);
   3206        }
   3207        if (rv != SECSuccess) {
   3208            SECU_PrintError(progName, "Could not set password for the slot");
   3209            goto shutdown;
   3210        }
   3211    }
   3212 
   3213    /* if we are going to modify the cert database,
   3214     * make sure it's initialized */
   3215    if (certutil.commands[cmd_ModifyCertTrust].activated ||
   3216        certutil.commands[cmd_CreateAndAddCert].activated ||
   3217        certutil.commands[cmd_AddCert].activated ||
   3218        certutil.commands[cmd_AddEmailCert].activated) {
   3219        if (PK11_NeedLogin(slot) && PK11_NeedUserInit(slot)) {
   3220            char *password = NULL;
   3221            /* fetch the password from the command line or the file
   3222             * if no password is supplied, initialize the password to NULL */
   3223            if (pwdata.source == PW_FROMFILE) {
   3224                password = SECU_FilePasswd(slot, PR_FALSE, pwdata.data);
   3225            } else if (pwdata.source == PW_PLAINTEXT) {
   3226                password = PL_strdup(pwdata.data);
   3227            }
   3228            rv = PK11_InitPin(slot, (char *)NULL, password ? password : "");
   3229            if (password) {
   3230                PORT_Memset(password, 0, PL_strlen(password));
   3231                PORT_Free(password);
   3232            }
   3233            if (rv != SECSuccess) {
   3234                SECU_PrintError(progName, "Could not set password for the slot");
   3235                goto shutdown;
   3236            }
   3237        }
   3238    }
   3239 
   3240    /* walk through the upgrade merge if necessary.
   3241     * This option is more to test what some applications will want to do
   3242     * to do an automatic upgrade. The --merge command is more useful for
   3243     * the general case where 2 database need to be merged together.
   3244     */
   3245    if (certutil.commands[cmd_UpgradeMerge].activated) {
   3246        if (*upgradeTokenName == 0) {
   3247            upgradeTokenName = upgradeID;
   3248        }
   3249        if (!PK11_IsInternal(slot)) {
   3250            fprintf(stderr, "Only internal DB's can be upgraded\n");
   3251            rv = SECSuccess;
   3252            goto shutdown;
   3253        }
   3254        if (!PK11_IsRemovable(slot)) {
   3255            printf("database already upgraded.\n");
   3256            rv = SECSuccess;
   3257            goto shutdown;
   3258        }
   3259        if (!PK11_NeedLogin(slot)) {
   3260            printf("upgrade complete!\n");
   3261            rv = SECSuccess;
   3262            goto shutdown;
   3263        }
   3264        /* authenticate to the old DB if necessary */
   3265        if (PORT_Strcmp(PK11_GetTokenName(slot), upgradeTokenName) == 0) {
   3266            /* if we need a password, supply it. This will be the password
   3267             * for the old database */
   3268            rv = PK11_Authenticate(slot, PR_FALSE, &pwdata2);
   3269            if (rv != SECSuccess) {
   3270                SECU_PrintError(progName, "Could not get password for %s",
   3271                                upgradeTokenName);
   3272                goto shutdown;
   3273            }
   3274            /*
   3275             * if we succeeded above, but still aren't logged in, that means
   3276             * we just supplied the password for the old database. We may
   3277             * need the password for the new database. NSS will automatically
   3278             * change the token names at this point
   3279             */
   3280            if (PK11_IsLoggedIn(slot, &pwdata)) {
   3281                printf("upgrade complete!\n");
   3282                rv = SECSuccess;
   3283                goto shutdown;
   3284            }
   3285        }
   3286 
   3287        /* call PK11_IsPresent to update our cached token information */
   3288        if (!PK11_IsPresent(slot)) {
   3289            /* this shouldn't happen. We call isPresent to force a token
   3290             * info update */
   3291            fprintf(stderr, "upgrade/merge internal error\n");
   3292            rv = SECFailure;
   3293            goto shutdown;
   3294        }
   3295 
   3296        /* the token is now set to the state of the source database,
   3297         * if we need a password for it, PK11_Authenticate will
   3298         * automatically prompt us */
   3299        rv = PK11_Authenticate(slot, PR_FALSE, &pwdata);
   3300        if (rv == SECSuccess) {
   3301            printf("upgrade complete!\n");
   3302        } else {
   3303            SECU_PrintError(progName, "Could not get password for %s",
   3304                            PK11_GetTokenName(slot));
   3305        }
   3306        goto shutdown;
   3307    }
   3308 
   3309    /*
   3310     * merge 2 databases.
   3311     */
   3312    if (certutil.commands[cmd_Merge].activated) {
   3313        PK11SlotInfo *sourceSlot = NULL;
   3314        PK11MergeLog *log;
   3315        char *modspec = PR_smprintf(
   3316            "configDir='%s' certPrefix='%s' tokenDescription='%s'",
   3317            sourceDir, srcCertPrefix,
   3318            *upgradeTokenName ? upgradeTokenName : "Source Database");
   3319 
   3320        if (!modspec) {
   3321            rv = SECFailure;
   3322            goto shutdown;
   3323        }
   3324 
   3325        sourceSlot = SECMOD_OpenUserDB(modspec);
   3326        PR_smprintf_free(modspec);
   3327        if (!sourceSlot) {
   3328            SECU_PrintError(progName, "couldn't open source database");
   3329            rv = SECFailure;
   3330            goto shutdown;
   3331        }
   3332 
   3333        rv = PK11_Authenticate(slot, PR_FALSE, &pwdata);
   3334        if (rv != SECSuccess) {
   3335            SECU_PrintError(progName, "Couldn't get password for %s",
   3336                            PK11_GetTokenName(slot));
   3337            goto merge_fail;
   3338        }
   3339 
   3340        rv = PK11_Authenticate(sourceSlot, PR_FALSE, &pwdata2);
   3341        if (rv != SECSuccess) {
   3342            SECU_PrintError(progName, "Couldn't get password for %s",
   3343                            PK11_GetTokenName(sourceSlot));
   3344            goto merge_fail;
   3345        }
   3346 
   3347        log = PK11_CreateMergeLog();
   3348        if (!log) {
   3349            rv = SECFailure;
   3350            SECU_PrintError(progName, "couldn't create error log");
   3351            goto merge_fail;
   3352        }
   3353 
   3354        rv = PK11_MergeTokens(slot, sourceSlot, log, &pwdata, &pwdata2);
   3355        if (rv != SECSuccess) {
   3356            DumpMergeLog(progName, log);
   3357        }
   3358        PK11_DestroyMergeLog(log);
   3359 
   3360    merge_fail:
   3361        SECMOD_CloseUserDB(sourceSlot);
   3362        PK11_FreeSlot(sourceSlot);
   3363        goto shutdown;
   3364    }
   3365 
   3366    /* The following 8 options are mutually exclusive with all others. */
   3367 
   3368    /*  List certs (-L)  */
   3369    if (certutil.commands[cmd_ListCerts].activated) {
   3370        if (certutil.options[opt_DumpExtensionValue].activated) {
   3371            const char *oid_str;
   3372            SECItem oid_item;
   3373            SECStatus srv;
   3374            oid_item.data = NULL;
   3375            oid_item.len = 0;
   3376            oid_str = certutil.options[opt_DumpExtensionValue].arg;
   3377            srv = GetOidFromString(NULL, &oid_item, oid_str, strlen(oid_str));
   3378            if (srv != SECSuccess) {
   3379                SECU_PrintError(progName, "malformed extension OID %s",
   3380                                oid_str);
   3381                goto shutdown;
   3382            }
   3383            rv = ListCerts(certHandle, name, email, slot,
   3384                           PR_TRUE /*binary*/, PR_FALSE /*ascii*/,
   3385                           &oid_item,
   3386                           outFile, &pwdata);
   3387            SECITEM_FreeItem(&oid_item, PR_FALSE);
   3388        } else {
   3389            rv = ListCerts(certHandle, name, email, slot,
   3390                           certutil.options[opt_BinaryDER].activated,
   3391                           certutil.options[opt_ASCIIForIO].activated,
   3392                           NULL, outFile, &pwdata);
   3393        }
   3394        goto shutdown;
   3395    }
   3396    if (certutil.commands[cmd_DumpChain].activated) {
   3397        rv = DumpChain(certHandle, name,
   3398                       certutil.options[opt_ASCIIForIO].activated,
   3399                       certutil.options[opt_SimpleSelfSigned].activated);
   3400        goto shutdown;
   3401    }
   3402    /*  XXX needs work  */
   3403    /*  List keys (-K)  */
   3404    if (certutil.commands[cmd_ListKeys].activated) {
   3405        rv = ListKeys(slot, name, 0 /*keyindex*/, keytype, PR_FALSE /*dopriv*/,
   3406                      &pwdata);
   3407        goto shutdown;
   3408    }
   3409    /*  List modules (-U)  */
   3410    if (certutil.commands[cmd_ListModules].activated) {
   3411        rv = ListModules();
   3412        goto shutdown;
   3413    }
   3414    /*  Delete cert (-D)  */
   3415    if (certutil.commands[cmd_DeleteCert].activated) {
   3416        rv = DeleteCert(certHandle, name, &pwdata);
   3417        goto shutdown;
   3418    }
   3419    /*  Rename cert (--rename)  */
   3420    if (certutil.commands[cmd_Rename].activated) {
   3421        rv = RenameCert(certHandle, name, newName, &pwdata);
   3422        goto shutdown;
   3423    }
   3424    /*  Delete key (-F)  */
   3425    if (certutil.commands[cmd_DeleteKey].activated) {
   3426        if (certutil.options[opt_Nickname].activated) {
   3427            rv = DeleteCertAndKey(name, &pwdata);
   3428        } else {
   3429            privkey = findPrivateKeyByID(slot, keysource, &pwdata);
   3430            if (!privkey) {
   3431                SECU_PrintError(progName, "%s is not a key-id", keysource);
   3432                rv = SECFailure;
   3433            } else {
   3434                rv = DeleteKey(privkey, &pwdata);
   3435                /* already destroyed by PK11_DeleteTokenPrivateKey */
   3436                privkey = NULL;
   3437            }
   3438        }
   3439        goto shutdown;
   3440    }
   3441    /*  Modify trust attribute for cert (-M)  */
   3442    if (certutil.commands[cmd_ModifyCertTrust].activated) {
   3443        rv = ChangeTrustAttributes(certHandle, slot, name,
   3444                                   certutil.options[opt_Trust].arg, &pwdata);
   3445        goto shutdown;
   3446    }
   3447    /*  Change key db password (-W) (future - change pw to slot?)  */
   3448    if (certutil.commands[cmd_ChangePassword].activated) {
   3449        rv = SECU_ChangePW2(slot, 0, 0, certutil.options[opt_PasswordFile].arg,
   3450                            certutil.options[opt_NewPasswordFile].arg);
   3451        if (rv != SECSuccess) {
   3452            SECU_PrintError(progName, "Could not set password for the slot");
   3453            goto shutdown;
   3454        }
   3455    }
   3456    /*  Reset the a token */
   3457    if (certutil.commands[cmd_TokenReset].activated) {
   3458        char *sso_pass = "";
   3459 
   3460        if (certutil.options[opt_SSOPass].activated) {
   3461            sso_pass = certutil.options[opt_SSOPass].arg;
   3462        }
   3463        rv = PK11_ResetToken(slot, sso_pass);
   3464 
   3465        goto shutdown;
   3466    }
   3467    /*  Check cert validity against current time (-V)  */
   3468    if (certutil.commands[cmd_CheckCertValidity].activated) {
   3469        /* XXX temporary hack for fips - must log in to get priv key */
   3470        if (certutil.options[opt_VerifySig].activated) {
   3471            if (slot && PK11_NeedLogin(slot)) {
   3472                SECStatus newrv = PK11_Authenticate(slot, PR_TRUE, &pwdata);
   3473                if (newrv != SECSuccess) {
   3474                    SECU_PrintError(progName, "could not authenticate to token %s.",
   3475                                    PK11_GetTokenName(slot));
   3476                    goto shutdown;
   3477                }
   3478            }
   3479        }
   3480        rv = ValidateCert(certHandle, name,
   3481                          certutil.options[opt_ValidityTime].arg,
   3482                          certutil.options[opt_Usage].arg,
   3483                          certutil.options[opt_VerifySig].activated,
   3484                          certutil.options[opt_DetailedInfo].activated,
   3485                          certutil.options[opt_ASCIIForIO].activated,
   3486                          &pwdata);
   3487        if (rv != SECSuccess && PR_GetError() == SEC_ERROR_INVALID_ARGS)
   3488            SECU_PrintError(progName, "validation failed");
   3489        goto shutdown;
   3490    }
   3491 
   3492    /*
   3493     *  Key generation
   3494     */
   3495 
   3496    /*  These commands may require keygen.  */
   3497    if (certutil.commands[cmd_CertReq].activated ||
   3498        certutil.commands[cmd_CreateAndAddCert].activated ||
   3499        certutil.commands[cmd_GenKeyPair].activated) {
   3500        if (keysource) {
   3501            CERTCertificate *keycert;
   3502            keycert = CERT_FindCertByNicknameOrEmailAddr(certHandle, keysource);
   3503            if (!keycert) {
   3504                keycert = PK11_FindCertFromNickname(keysource, NULL);
   3505            }
   3506 
   3507            if (keycert) {
   3508                privkey = PK11_FindKeyByDERCert(slot, keycert, &pwdata);
   3509            } else {
   3510                /* Interpret keysource as CKA_ID */
   3511                privkey = findPrivateKeyByID(slot, keysource, &pwdata);
   3512            }
   3513 
   3514            if (!privkey) {
   3515                SECU_PrintError(
   3516                    progName,
   3517                    "%s is neither a key-type nor a nickname nor a key-id", keysource);
   3518                return SECFailure;
   3519            }
   3520 
   3521            pubkey = SECKEY_ConvertToPublicKey(privkey);
   3522            if (!pubkey) {
   3523                SECU_PrintError(progName,
   3524                                "Could not get keys from cert %s", keysource);
   3525                if (keycert) {
   3526                    CERT_DestroyCertificate(keycert);
   3527                }
   3528                rv = SECFailure;
   3529                goto shutdown;
   3530            }
   3531            keytype = privkey->keyType;
   3532 
   3533            /* On CertReq for renewal if no subject has been
   3534             * specified obtain it from the certificate.
   3535             */
   3536            if (certutil.commands[cmd_CertReq].activated && !subject) {
   3537                if (keycert) {
   3538                    subject = CERT_AsciiToName(keycert->subjectName);
   3539                    if (!subject) {
   3540                        SECU_PrintError(
   3541                            progName,
   3542                            "Could not get subject from certificate %s",
   3543                            keysource);
   3544                        CERT_DestroyCertificate(keycert);
   3545                        rv = SECFailure;
   3546                        goto shutdown;
   3547                    }
   3548                } else {
   3549                    SECU_PrintError(progName, "Subject name not provided");
   3550                    rv = SECFailure;
   3551                    goto shutdown;
   3552                }
   3553            }
   3554            if (keycert) {
   3555                CERT_DestroyCertificate(keycert);
   3556            }
   3557        } else {
   3558            privkey =
   3559                CERTUTIL_GeneratePrivateKey(keytype, slot, keysize,
   3560                                            publicExponent,
   3561                                            certutil.options[opt_NoiseFile].arg,
   3562                                            &pubkey,
   3563                                            certutil.options[opt_PQGFile].arg,
   3564                                            keyAttrFlags,
   3565                                            keyOpFlagsOn,
   3566                                            keyOpFlagsOff,
   3567                                            &pwdata);
   3568            if (privkey == NULL) {
   3569                SECU_PrintError(progName, "unable to generate key(s)\n");
   3570                rv = SECFailure;
   3571                goto shutdown;
   3572            }
   3573        }
   3574        privkey->wincx = &pwdata;
   3575        PORT_Assert(pubkey != NULL);
   3576 
   3577        /*  If all that was needed was keygen, exit.  */
   3578        if (certutil.commands[cmd_GenKeyPair].activated) {
   3579            rv = SECSuccess;
   3580            goto shutdown;
   3581        }
   3582    }
   3583 
   3584    if (certutil.options[opt_Pss].activated) {
   3585        if (!certutil.commands[cmd_CertReq].activated &&
   3586            !certutil.commands[cmd_CreateAndAddCert].activated) {
   3587            PR_fprintf(PR_STDERR,
   3588                       "%s -%c: --pss only works with -R or -S.\n",
   3589                       progName, commandToRun);
   3590            return 255;
   3591        }
   3592        if (keytype != rsaKey) {
   3593            PR_fprintf(PR_STDERR,
   3594                       "%s -%c: --pss only works with RSA keys.\n",
   3595                       progName, commandToRun);
   3596            return 255;
   3597        }
   3598    }
   3599 
   3600    /* --pss-sign is to sign a certificate with RSA-PSS, even if the
   3601     * issuer's key is an RSA key.  If the key is an RSA-PSS key, the
   3602     * generated signature is always RSA-PSS. */
   3603    if (certutil.options[opt_PssSign].activated) {
   3604        if (!certutil.commands[cmd_CreateNewCert].activated &&
   3605            !certutil.commands[cmd_CreateAndAddCert].activated) {
   3606            PR_fprintf(PR_STDERR,
   3607                       "%s -%c: --pss-sign only works with -C or -S.\n",
   3608                       progName, commandToRun);
   3609            return 255;
   3610        }
   3611        if (keytype != rsaKey) {
   3612            PR_fprintf(PR_STDERR,
   3613                       "%s -%c: --pss-sign only works with RSA keys.\n",
   3614                       progName, commandToRun);
   3615            return 255;
   3616        }
   3617    }
   3618 
   3619    if (certutil.options[opt_SimpleSelfSigned].activated &&
   3620        !certutil.commands[cmd_DumpChain].activated) {
   3621        PR_fprintf(PR_STDERR,
   3622                   "%s -%c: --simple-self-signed only works with -O.\n",
   3623                   progName, commandToRun);
   3624        return 255;
   3625    }
   3626 
   3627    /* If we need a list of extensions convert the flags into list format */
   3628    if (certutil.commands[cmd_CertReq].activated ||
   3629        certutil.commands[cmd_CreateAndAddCert].activated ||
   3630        certutil.commands[cmd_CreateNewCert].activated) {
   3631        certutil_extns[ext_keyUsage].activated =
   3632            certutil.options[opt_AddCmdKeyUsageExt].activated;
   3633        if (!certutil_extns[ext_keyUsage].activated) {
   3634            certutil_extns[ext_keyUsage].activated =
   3635                certutil.options[opt_AddKeyUsageExt].activated;
   3636        } else {
   3637            certutil_extns[ext_keyUsage].arg =
   3638                certutil.options[opt_AddCmdKeyUsageExt].arg;
   3639        }
   3640        certutil_extns[ext_basicConstraint].activated =
   3641            certutil.options[opt_AddBasicConstraintExt].activated;
   3642        certutil_extns[ext_nameConstraints].activated =
   3643            certutil.options[opt_AddNameConstraintsExt].activated;
   3644        certutil_extns[ext_authorityKeyID].activated =
   3645            certutil.options[opt_AddAuthorityKeyIDExt].activated;
   3646        certutil_extns[ext_subjectKeyID].activated =
   3647            certutil.options[opt_AddSubjectKeyIDExt].activated;
   3648        certutil_extns[ext_CRLDistPts].activated =
   3649            certutil.options[opt_AddCRLDistPtsExt].activated;
   3650        certutil_extns[ext_NSCertType].activated =
   3651            certutil.options[opt_AddCmdNSCertTypeExt].activated;
   3652        if (!certutil_extns[ext_NSCertType].activated) {
   3653            certutil_extns[ext_NSCertType].activated =
   3654                certutil.options[opt_AddNSCertTypeExt].activated;
   3655        } else {
   3656            certutil_extns[ext_NSCertType].arg =
   3657                certutil.options[opt_AddCmdNSCertTypeExt].arg;
   3658        }
   3659 
   3660        certutil_extns[ext_extKeyUsage].activated =
   3661            certutil.options[opt_AddCmdExtKeyUsageExt].activated;
   3662        if (!certutil_extns[ext_extKeyUsage].activated) {
   3663            certutil_extns[ext_extKeyUsage].activated =
   3664                certutil.options[opt_AddExtKeyUsageExt].activated;
   3665        } else {
   3666            certutil_extns[ext_extKeyUsage].arg =
   3667                certutil.options[opt_AddCmdExtKeyUsageExt].arg;
   3668        }
   3669        certutil_extns[ext_subjectAltName].activated =
   3670            certutil.options[opt_AddSubjectAltNameExt].activated;
   3671        if (certutil_extns[ext_subjectAltName].activated) {
   3672            certutil_extns[ext_subjectAltName].arg =
   3673                certutil.options[opt_AddSubjectAltNameExt].arg;
   3674        }
   3675 
   3676        certutil_extns[ext_authInfoAcc].activated =
   3677            certutil.options[opt_AddAuthInfoAccExt].activated;
   3678        certutil_extns[ext_subjInfoAcc].activated =
   3679            certutil.options[opt_AddSubjInfoAccExt].activated;
   3680        certutil_extns[ext_certPolicies].activated =
   3681            certutil.options[opt_AddCertPoliciesExt].activated;
   3682        certutil_extns[ext_policyMappings].activated =
   3683            certutil.options[opt_AddPolicyMapExt].activated;
   3684        certutil_extns[ext_policyConstr].activated =
   3685            certutil.options[opt_AddPolicyConstrExt].activated;
   3686        certutil_extns[ext_inhibitAnyPolicy].activated =
   3687            certutil.options[opt_AddInhibAnyExt].activated;
   3688    }
   3689 
   3690    /* -A -C or -E    Read inFile */
   3691    if (certutil.commands[cmd_CreateNewCert].activated ||
   3692        certutil.commands[cmd_AddCert].activated ||
   3693        certutil.commands[cmd_AddEmailCert].activated) {
   3694        PRBool isCreate = certutil.commands[cmd_CreateNewCert].activated;
   3695        rv = SECU_ReadDERFromFile(isCreate ? &certReqDER : &certDER, inFile,
   3696                                  certutil.options[opt_ASCIIForIO].activated,
   3697                                  PR_TRUE);
   3698        if (rv)
   3699            goto shutdown;
   3700    }
   3701 
   3702    /*
   3703     *  Certificate request
   3704     */
   3705 
   3706    /*  Make a cert request (-R).  */
   3707    if (certutil.commands[cmd_CertReq].activated) {
   3708        rv = CertReq(privkey, pubkey, keytype, hashAlgTag, subject,
   3709                     certutil.options[opt_PhoneNumber].arg,
   3710                     certutil.options[opt_ASCIIForIO].activated,
   3711                     certutil.options[opt_ExtendedEmailAddrs].arg,
   3712                     certutil.options[opt_ExtendedDNSNames].arg,
   3713                     certutil_extns,
   3714                     (certutil.options[opt_GenericExtensions].activated ? certutil.options[opt_GenericExtensions].arg
   3715                                                                        : NULL),
   3716                     certutil.options[opt_Pss].activated,
   3717                     &certReqDER);
   3718        if (rv)
   3719            goto shutdown;
   3720        privkey->wincx = &pwdata;
   3721    }
   3722 
   3723    /*
   3724     *  Certificate creation
   3725     */
   3726 
   3727    /*  If making and adding a cert, create a cert request file first without
   3728     *  any extensions, then load it with the command line extensions
   3729     *  and output the cert to another file.
   3730     */
   3731    if (certutil.commands[cmd_CreateAndAddCert].activated) {
   3732        static certutilExtnList nullextnlist = { { PR_FALSE, NULL } };
   3733        rv = CertReq(privkey, pubkey, keytype, hashAlgTag, subject,
   3734                     certutil.options[opt_PhoneNumber].arg,
   3735                     PR_FALSE, /* do not BASE64-encode regardless of -a option */
   3736                     NULL,
   3737                     NULL,
   3738                     nullextnlist,
   3739                     (certutil.options[opt_GenericExtensions].activated ? certutil.options[opt_GenericExtensions].arg
   3740                                                                        : NULL),
   3741                     certutil.options[opt_Pss].activated,
   3742                     &certReqDER);
   3743        if (rv)
   3744            goto shutdown;
   3745        privkey->wincx = &pwdata;
   3746    }
   3747 
   3748    /*  Create a certificate (-C or -S).  */
   3749    if (certutil.commands[cmd_CreateAndAddCert].activated ||
   3750        certutil.commands[cmd_CreateNewCert].activated) {
   3751        rv = CreateCert(certHandle, slot,
   3752                        certutil.options[opt_IssuerName].arg,
   3753                        &certReqDER, &privkey, &pwdata, hashAlgTag,
   3754                        serialNumber, warpmonths, validityMonths,
   3755                        certutil.options[opt_ExtendedEmailAddrs].arg,
   3756                        certutil.options[opt_ExtendedDNSNames].arg,
   3757                        certutil.options[opt_ASCIIForIO].activated &&
   3758                            certutil.commands[cmd_CreateNewCert].activated,
   3759                        certutil.options[opt_SelfSign].activated,
   3760                        certutil_extns,
   3761                        (certutil.options[opt_GenericExtensions].activated ? certutil.options[opt_GenericExtensions].arg
   3762                                                                           : NULL),
   3763                        certVersion,
   3764                        certutil.options[opt_PssSign].activated,
   3765                        &certDER);
   3766        if (rv)
   3767            goto shutdown;
   3768    }
   3769 
   3770    /*
   3771     * Adding a cert to the database (or slot)
   3772     */
   3773 
   3774    /* -A -E or -S    Add the cert to the DB */
   3775    if (certutil.commands[cmd_CreateAndAddCert].activated ||
   3776        certutil.commands[cmd_AddCert].activated ||
   3777        certutil.commands[cmd_AddEmailCert].activated) {
   3778        if (strstr(certutil.options[opt_Trust].arg, "u")) {
   3779            fprintf(stderr, "Notice: Trust flag u is set automatically if the "
   3780                            "private key is present.\n");
   3781        }
   3782        rv = AddCert(slot, certHandle, name,
   3783                     certutil.options[opt_Trust].arg,
   3784                     &certDER,
   3785                     certutil.commands[cmd_AddEmailCert].activated, &pwdata);
   3786        if (rv)
   3787            goto shutdown;
   3788    }
   3789 
   3790    if (certutil.commands[cmd_CertReq].activated ||
   3791        certutil.commands[cmd_CreateNewCert].activated) {
   3792        SECItem *item = certutil.commands[cmd_CertReq].activated ? &certReqDER
   3793                                                                 : &certDER;
   3794        PRInt32 written = PR_Write(outFile, item->data, item->len);
   3795        if (written < 0 || (PRUint32)written != item->len) {
   3796            rv = SECFailure;
   3797        }
   3798    }
   3799 
   3800 shutdown:
   3801    if (slot) {
   3802        PK11_FreeSlot(slot);
   3803    }
   3804    if (privkey) {
   3805        SECKEY_DestroyPrivateKey(privkey);
   3806    }
   3807    if (pubkey) {
   3808        SECKEY_DestroyPublicKey(pubkey);
   3809    }
   3810    if (subject) {
   3811        CERT_DestroyName(subject);
   3812    }
   3813    if (name) {
   3814        PL_strfree(name);
   3815    }
   3816    if (newName) {
   3817        PL_strfree(newName);
   3818    }
   3819    if (inFile && inFile != PR_STDIN) {
   3820        PR_Close(inFile);
   3821    }
   3822    if (outFile && outFile != PR_STDOUT) {
   3823        PR_Close(outFile);
   3824    }
   3825    SECITEM_FreeItem(&certReqDER, PR_FALSE);
   3826    SECITEM_FreeItem(&certDER, PR_FALSE);
   3827    if (pwdata.data && pwdata.source == PW_PLAINTEXT) {
   3828        /* Allocated by a PL_strdup call in SECU_GetModulePassword. */
   3829        PL_strfree(pwdata.data);
   3830    }
   3831    if (email) {
   3832        PL_strfree(email);
   3833    }
   3834 
   3835    /* Open the batch command file.
   3836     *
   3837     * - If -B <command line> option is specified, the contents in the
   3838     * command file will be interpreted as subsequent certutil
   3839     * commands to be executed in the current certutil process
   3840     * context after the current certutil command has been executed.
   3841     * - Each line in the command file consists of the command
   3842     * line arguments for certutil.
   3843     * - The -d <configdir> option will be ignored if specified in the
   3844     * command file.
   3845     * - Quoting with double quote characters ("...") is supported
   3846     * to allow white space in a command line argument.  The
   3847     * double quote character cannot be escaped and quoting cannot
   3848     * be nested in this version.
   3849     * - each line in the batch file is limited to 512 characters
   3850     */
   3851 
   3852    if ((SECSuccess == rv) && certutil.commands[cmd_Batch].activated) {
   3853        FILE *batchFile = NULL;
   3854        char *nextcommand = NULL;
   3855        PRInt32 cmd_len = 0, buf_size = 0;
   3856        static const int increment = 512;
   3857 
   3858        if (!certutil.options[opt_InputFile].activated ||
   3859            !certutil.options[opt_InputFile].arg) {
   3860            PR_fprintf(PR_STDERR,
   3861                       "%s:  no batch input file specified.\n",
   3862                       progName);
   3863            return 255;
   3864        }
   3865        batchFile = fopen(certutil.options[opt_InputFile].arg, "r");
   3866        if (!batchFile) {
   3867            PR_fprintf(PR_STDERR,
   3868                       "%s:  unable to open \"%s\" for reading (%ld, %ld).\n",
   3869                       progName, certutil.options[opt_InputFile].arg,
   3870                       PR_GetError(), PR_GetOSError());
   3871            return 255;
   3872        }
   3873        /* read and execute command-lines in a loop */
   3874        while (SECSuccess == rv) {
   3875            PRBool invalid = PR_FALSE;
   3876            int newargc = 2;
   3877            char *space = NULL;
   3878            char *nextarg = NULL;
   3879            char **newargv = NULL;
   3880            char *crlf;
   3881 
   3882            if (cmd_len + increment > buf_size) {
   3883                char *new_buf;
   3884                buf_size += increment;
   3885                new_buf = PORT_Realloc(nextcommand, buf_size);
   3886                if (!new_buf) {
   3887                    PR_fprintf(PR_STDERR, "%s: PORT_Realloc(%ld) failed\n",
   3888                               progName, buf_size);
   3889                    break;
   3890                }
   3891                nextcommand = new_buf;
   3892                nextcommand[cmd_len] = '\0';
   3893            }
   3894            if (!fgets(nextcommand + cmd_len, buf_size - cmd_len, batchFile)) {
   3895                break;
   3896            }
   3897            crlf = PORT_Strrchr(nextcommand, '\n');
   3898            if (crlf) {
   3899                *crlf = '\0';
   3900            }
   3901            cmd_len = strlen(nextcommand);
   3902            if (cmd_len && nextcommand[cmd_len - 1] == '\\') {
   3903                nextcommand[--cmd_len] = '\0';
   3904                continue;
   3905            }
   3906 
   3907            /* we now need to split the command into argc / argv format */
   3908 
   3909            newargv = PORT_Alloc(sizeof(char *) * (newargc + 1));
   3910            newargv[0] = progName;
   3911            newargv[1] = nextcommand;
   3912            nextarg = nextcommand;
   3913            while ((space = PORT_Strpbrk(nextarg, " \f\n\r\t\v"))) {
   3914                while (isspace((unsigned char)*space)) {
   3915                    *space = '\0';
   3916                    space++;
   3917                }
   3918                if (*space == '\0') {
   3919                    break;
   3920                } else if (*space != '\"') {
   3921                    nextarg = space;
   3922                } else {
   3923                    char *closingquote = strchr(space + 1, '\"');
   3924                    if (closingquote) {
   3925                        *closingquote = '\0';
   3926                        space++;
   3927                        nextarg = closingquote + 1;
   3928                    } else {
   3929                        invalid = PR_TRUE;
   3930                        nextarg = space;
   3931                    }
   3932                }
   3933                newargc++;
   3934                newargv = PORT_Realloc(newargv, sizeof(char *) * (newargc + 1));
   3935                newargv[newargc - 1] = space;
   3936            }
   3937            newargv[newargc] = NULL;
   3938 
   3939            /* invoke next command */
   3940            if (PR_TRUE == invalid) {
   3941                PR_fprintf(PR_STDERR, "Missing closing quote in batch command :\n%s\nNot executed.\n",
   3942                           nextcommand);
   3943                rv = SECFailure;
   3944            } else {
   3945                if (0 != certutil_main(newargc, newargv, PR_FALSE))
   3946                    rv = SECFailure;
   3947            }
   3948            PORT_Free(newargv);
   3949            cmd_len = 0;
   3950            nextcommand[0] = '\0';
   3951        }
   3952        PORT_Free(nextcommand);
   3953        fclose(batchFile);
   3954    }
   3955 
   3956    if ((initialized == PR_TRUE) && NSS_Shutdown() != SECSuccess) {
   3957        exit(1);
   3958    }
   3959    if (rv == SECSuccess) {
   3960        return 0;
   3961    } else {
   3962        return 255;
   3963    }
   3964 }
   3965 
   3966 int
   3967 main(int argc, char **argv)
   3968 {
   3969    int rv = certutil_main(argc, argv, PR_TRUE);
   3970    PL_ArenaFinish();
   3971    PR_Cleanup();
   3972    return rv;
   3973 }