tor-browser

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

crlutil.c (35140B)


      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 /* test only */
     12 
     13 #include "nspr.h"
     14 #include "plgetopt.h"
     15 #include "secutil.h"
     16 #include "cert.h"
     17 #include "certi.h"
     18 #include "certdb.h"
     19 #include "nss.h"
     20 #include "pk11func.h"
     21 #include "crlgen.h"
     22 
     23 #define SEC_CERT_DB_EXISTS 0
     24 #define SEC_CREATE_CERT_DB 1
     25 
     26 static char *progName;
     27 
     28 static CERTSignedCrl *
     29 FindCRL(CERTCertDBHandle *certHandle, char *name, int type)
     30 {
     31    CERTSignedCrl *crl = NULL;
     32    CERTCertificate *cert = NULL;
     33    SECItem derName;
     34 
     35    derName.data = NULL;
     36    derName.len = 0;
     37 
     38    cert = CERT_FindCertByNicknameOrEmailAddr(certHandle, name);
     39    if (!cert) {
     40        CERTName *certName = NULL;
     41        PLArenaPool *arena = NULL;
     42        SECStatus rv = SECSuccess;
     43 
     44        certName = CERT_AsciiToName(name);
     45        if (certName) {
     46            arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
     47            if (arena) {
     48                SECItem *nameItem =
     49                    SEC_ASN1EncodeItem(arena, NULL, (void *)certName,
     50                                       SEC_ASN1_GET(CERT_NameTemplate));
     51                if (nameItem) {
     52                    rv = SECITEM_CopyItem(NULL, &derName, nameItem);
     53                }
     54                PORT_FreeArena(arena, PR_FALSE);
     55            }
     56            CERT_DestroyName(certName);
     57        }
     58 
     59        if (rv != SECSuccess) {
     60            SECU_PrintError(progName, "SECITEM_CopyItem failed, out of memory");
     61            return ((CERTSignedCrl *)NULL);
     62        }
     63 
     64        if (!derName.len || !derName.data) {
     65            SECU_PrintError(progName, "could not find certificate named '%s'", name);
     66            return ((CERTSignedCrl *)NULL);
     67        }
     68    } else {
     69        SECStatus rv = SECITEM_CopyItem(NULL, &derName, &cert->derSubject);
     70        CERT_DestroyCertificate(cert);
     71        if (rv != SECSuccess) {
     72            return ((CERTSignedCrl *)NULL);
     73        }
     74    }
     75 
     76    crl = SEC_FindCrlByName(certHandle, &derName, type);
     77    if (crl == NULL)
     78        SECU_PrintError(progName, "could not find %s's CRL", name);
     79    if (derName.data) {
     80        SECITEM_FreeItem(&derName, PR_FALSE);
     81    }
     82    return (crl);
     83 }
     84 
     85 static SECStatus
     86 DisplayCRL(CERTCertDBHandle *certHandle, char *nickName, int crlType)
     87 {
     88    CERTSignedCrl *crl = NULL;
     89 
     90    crl = FindCRL(certHandle, nickName, crlType);
     91 
     92    if (crl) {
     93        SECU_PrintCRLInfo(stdout, &crl->crl, "CRL Info:\n", 0);
     94        SEC_DestroyCrl(crl);
     95        return SECSuccess;
     96    }
     97    return SECFailure;
     98 }
     99 
    100 static void
    101 ListCRLNames(CERTCertDBHandle *certHandle, int crlType, PRBool deletecrls)
    102 {
    103    CERTCrlHeadNode *crlList = NULL;
    104    CERTCrlNode *crlNode = NULL;
    105    CERTName *name = NULL;
    106    PLArenaPool *arena = NULL;
    107    SECStatus rv;
    108 
    109    do {
    110        arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
    111        if (arena == NULL) {
    112            fprintf(stderr, "%s: fail to allocate memory\n", progName);
    113            break;
    114        }
    115 
    116        name = PORT_ArenaZAlloc(arena, sizeof(*name));
    117        if (name == NULL) {
    118            fprintf(stderr, "%s: fail to allocate memory\n", progName);
    119            break;
    120        }
    121        name->arena = arena;
    122 
    123        rv = SEC_LookupCrls(certHandle, &crlList, crlType);
    124        if (rv != SECSuccess) {
    125            fprintf(stderr, "%s: fail to look up CRLs (%s)\n", progName,
    126                    SECU_Strerror(PORT_GetError()));
    127            break;
    128        }
    129 
    130        /* just in case */
    131        if (!crlList)
    132            break;
    133 
    134        crlNode = crlList->first;
    135 
    136        fprintf(stdout, "\n");
    137        fprintf(stdout, "\n%-40s %-5s\n\n", "CRL names", "CRL Type");
    138        while (crlNode) {
    139            char *asciiname = NULL;
    140            CERTCertificate *cert = NULL;
    141            if (crlNode->crl && crlNode->crl->crl.derName.data != NULL) {
    142                cert = CERT_FindCertByName(certHandle,
    143                                           &crlNode->crl->crl.derName);
    144                if (!cert) {
    145                    SECU_PrintError(progName, "could not find signing "
    146                                              "certificate in database");
    147                }
    148            }
    149            if (cert) {
    150                char *certName = NULL;
    151                if (cert->nickname && PORT_Strlen(cert->nickname) > 0) {
    152                    certName = cert->nickname;
    153                } else if (cert->emailAddr && PORT_Strlen(cert->emailAddr) > 0) {
    154                    certName = cert->emailAddr;
    155                }
    156                if (certName) {
    157                    asciiname = PORT_Strdup(certName);
    158                }
    159                CERT_DestroyCertificate(cert);
    160            }
    161 
    162            if (!asciiname) {
    163                name = &crlNode->crl->crl.name;
    164                if (!name) {
    165                    SECU_PrintError(progName, "fail to get the CRL "
    166                                              "issuer name");
    167                    continue;
    168                }
    169                asciiname = CERT_NameToAscii(name);
    170            }
    171            fprintf(stdout, "%-40s %-5s\n", asciiname, "CRL");
    172            if (asciiname) {
    173                PORT_Free(asciiname);
    174            }
    175            if (PR_TRUE == deletecrls) {
    176                CERTSignedCrl *acrl = NULL;
    177                SECItem *issuer = &crlNode->crl->crl.derName;
    178                acrl = SEC_FindCrlByName(certHandle, issuer, crlType);
    179                if (acrl) {
    180                    SEC_DeletePermCRL(acrl);
    181                    SEC_DestroyCrl(acrl);
    182                }
    183            }
    184            crlNode = crlNode->next;
    185        }
    186 
    187    } while (0);
    188    if (crlList)
    189        PORT_FreeArena(crlList->arena, PR_FALSE);
    190    PORT_FreeArena(arena, PR_FALSE);
    191 }
    192 
    193 static SECStatus
    194 ListCRL(CERTCertDBHandle *certHandle, char *nickName, int crlType)
    195 {
    196    if (nickName == NULL) {
    197        ListCRLNames(certHandle, crlType, PR_FALSE);
    198        return SECSuccess;
    199    }
    200 
    201    return DisplayCRL(certHandle, nickName, crlType);
    202 }
    203 
    204 static SECStatus
    205 DeleteCRL(CERTCertDBHandle *certHandle, char *name, int type)
    206 {
    207    CERTSignedCrl *crl = NULL;
    208    SECStatus rv = SECFailure;
    209 
    210    crl = FindCRL(certHandle, name, type);
    211    if (!crl) {
    212        SECU_PrintError(progName, "could not find the issuer %s's CRL", name);
    213        return SECFailure;
    214    }
    215    rv = SEC_DeletePermCRL(crl);
    216    SEC_DestroyCrl(crl);
    217    if (rv != SECSuccess) {
    218        SECU_PrintError(progName, "fail to delete the issuer %s's CRL "
    219                                  "from the perm database (reason: %s)",
    220                        name, SECU_Strerror(PORT_GetError()));
    221        return SECFailure;
    222    }
    223    return (rv);
    224 }
    225 
    226 SECStatus
    227 ImportCRL(CERTCertDBHandle *certHandle, char *url, int type,
    228          PRFileDesc *inFile, PRInt32 importOptions, PRInt32 decodeOptions,
    229          secuPWData *pwdata)
    230 {
    231    CERTSignedCrl *crl = NULL;
    232    SECItem crlDER;
    233    PK11SlotInfo *slot = NULL;
    234    int rv;
    235 
    236    crlDER.data = NULL;
    237 
    238    /* Read in the entire file specified with the -f argument */
    239    rv = SECU_ReadDERFromFile(&crlDER, inFile, PR_FALSE, PR_FALSE);
    240    if (rv != SECSuccess) {
    241        SECU_PrintError(progName, "unable to read input file");
    242        return (SECFailure);
    243    }
    244 
    245    decodeOptions |= CRL_DECODE_DONT_COPY_DER;
    246 
    247    slot = PK11_GetInternalKeySlot();
    248 
    249    if (PK11_NeedLogin(slot)) {
    250        rv = PK11_Authenticate(slot, PR_TRUE, pwdata);
    251        if (rv != SECSuccess)
    252            goto loser;
    253    }
    254 
    255    crl = PK11_ImportCRL(slot, &crlDER, url, type,
    256                         NULL, importOptions, NULL, decodeOptions);
    257 
    258    if (!crl) {
    259        const char *errString;
    260 
    261        rv = SECFailure;
    262        errString = SECU_Strerror(PORT_GetError());
    263        if (errString && PORT_Strlen(errString) == 0)
    264            SECU_PrintError(progName,
    265                            "CRL is not imported (error: input CRL is not up to date.)");
    266        else
    267            SECU_PrintError(progName, "unable to import CRL");
    268    } else {
    269        SEC_DestroyCrl(crl);
    270    }
    271 loser:
    272    if (slot) {
    273        PK11_FreeSlot(slot);
    274    }
    275    SECITEM_FreeItem(&crlDER, PR_FALSE);
    276    return (rv);
    277 }
    278 
    279 SECStatus
    280 DumpCRL(PRFileDesc *inFile)
    281 {
    282    int rv;
    283    PLArenaPool *arena = NULL;
    284    CERTSignedCrl *newCrl = NULL;
    285 
    286    SECItem crlDER;
    287    crlDER.data = NULL;
    288 
    289    /* Read in the entire file specified with the -f argument */
    290    rv = SECU_ReadDERFromFile(&crlDER, inFile, PR_FALSE, PR_FALSE);
    291    if (rv != SECSuccess) {
    292        SECU_PrintError(progName, "unable to read input file");
    293        return (SECFailure);
    294    }
    295 
    296    rv = SEC_ERROR_NO_MEMORY;
    297    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    298    if (!arena)
    299        return rv;
    300 
    301    newCrl = CERT_DecodeDERCrlWithFlags(arena, &crlDER, SEC_CRL_TYPE,
    302                                        CRL_DECODE_DEFAULT_OPTIONS);
    303    if (!newCrl)
    304        return SECFailure;
    305 
    306    SECU_PrintCRLInfo(stdout, &newCrl->crl, "CRL file contents", 0);
    307 
    308    PORT_FreeArena(arena, PR_FALSE);
    309    return rv;
    310 }
    311 
    312 static CERTCertificate *
    313 FindSigningCert(CERTCertDBHandle *certHandle, CERTSignedCrl *signCrl,
    314                char *certNickName)
    315 {
    316    CERTCertificate *cert = NULL, *certTemp = NULL;
    317    SECStatus rv = SECFailure;
    318    CERTAuthKeyID *authorityKeyID = NULL;
    319    SECItem *subject = NULL;
    320 
    321    PORT_Assert(certHandle != NULL);
    322    if (!certHandle || (!signCrl && !certNickName)) {
    323        SECU_PrintError(progName, "invalid args for function "
    324                                  "FindSigningCert \n");
    325        return NULL;
    326    }
    327 
    328    if (signCrl) {
    329 #if 0
    330        authorityKeyID = SECU_FindCRLAuthKeyIDExten(tmpArena, scrl);
    331 #endif
    332        subject = &signCrl->crl.derName;
    333    } else {
    334        certTemp = CERT_FindCertByNickname(certHandle, certNickName);
    335        if (!certTemp) {
    336            SECU_PrintError(progName, "could not find certificate \"%s\" "
    337                                      "in database",
    338                            certNickName);
    339            goto loser;
    340        }
    341        subject = &certTemp->derSubject;
    342    }
    343 
    344    cert = SECU_FindCrlIssuer(certHandle, subject, authorityKeyID, PR_Now());
    345    if (!cert) {
    346        SECU_PrintError(progName, "could not find signing certificate "
    347                                  "in database");
    348        goto loser;
    349    } else {
    350        rv = SECSuccess;
    351    }
    352 
    353 loser:
    354    if (certTemp)
    355        CERT_DestroyCertificate(certTemp);
    356    if (cert && rv != SECSuccess)
    357        CERT_DestroyCertificate(cert);
    358    return cert;
    359 }
    360 
    361 static CERTSignedCrl *
    362 CreateModifiedCRLCopy(PLArenaPool *arena, CERTCertDBHandle *certHandle,
    363                      CERTCertificate **cert, char *certNickName,
    364                      PRFileDesc *inFile, PRInt32 decodeOptions,
    365                      PRInt32 importOptions, secuPWData *pwdata)
    366 {
    367    SECItem crlDER = { 0, NULL, 0 };
    368    CERTSignedCrl *signCrl = NULL;
    369    CERTSignedCrl *modCrl = NULL;
    370    PLArenaPool *modArena = NULL;
    371    SECStatus rv = SECSuccess;
    372 
    373    if (!arena || !certHandle || !certNickName) {
    374        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    375        SECU_PrintError(progName, "CreateModifiedCRLCopy: invalid args\n");
    376        return NULL;
    377    }
    378 
    379    modArena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
    380    if (!modArena) {
    381        SECU_PrintError(progName, "fail to allocate memory\n");
    382        return NULL;
    383    }
    384 
    385    if (inFile != NULL) {
    386        rv = SECU_ReadDERFromFile(&crlDER, inFile, PR_FALSE, PR_FALSE);
    387        if (rv != SECSuccess) {
    388            SECU_PrintError(progName, "unable to read input file");
    389            goto loser;
    390        }
    391 
    392        decodeOptions |= CRL_DECODE_DONT_COPY_DER;
    393 
    394        modCrl = CERT_DecodeDERCrlWithFlags(modArena, &crlDER, SEC_CRL_TYPE,
    395                                            decodeOptions);
    396        if (!modCrl) {
    397            SECU_PrintError(progName, "fail to decode CRL");
    398            goto loser;
    399        }
    400 
    401        if (0 == (importOptions & CRL_IMPORT_BYPASS_CHECKS)) {
    402            /* If caCert is a v2 certificate, make sure that it
    403             * can be used for crl signing purpose */
    404            *cert = FindSigningCert(certHandle, modCrl, NULL);
    405            if (!*cert) {
    406                goto loser;
    407            }
    408 
    409            rv = CERT_VerifySignedData(&modCrl->signatureWrap, *cert,
    410                                       PR_Now(), pwdata);
    411            if (rv != SECSuccess) {
    412                SECU_PrintError(progName, "fail to verify signed data\n");
    413                goto loser;
    414            }
    415        }
    416    } else {
    417        modCrl = FindCRL(certHandle, certNickName, SEC_CRL_TYPE);
    418        if (!modCrl) {
    419            SECU_PrintError(progName, "fail to find crl %s in database\n",
    420                            certNickName);
    421            goto loser;
    422        }
    423    }
    424 
    425    signCrl = PORT_ArenaZNew(arena, CERTSignedCrl);
    426    if (signCrl == NULL) {
    427        SECU_PrintError(progName, "fail to allocate memory\n");
    428        goto loser;
    429    }
    430 
    431    rv = SECU_CopyCRL(arena, &signCrl->crl, &modCrl->crl);
    432    if (rv != SECSuccess) {
    433        SECU_PrintError(progName, "unable to dublicate crl for "
    434                                  "modification.");
    435        goto loser;
    436    }
    437 
    438    /* Make sure the update time is current. It can be modified later
    439     * by "update <time>" command from crl generation script */
    440    rv = DER_EncodeTimeChoice(arena, &signCrl->crl.lastUpdate, PR_Now());
    441    if (rv != SECSuccess) {
    442        SECU_PrintError(progName, "fail to encode current time\n");
    443        goto loser;
    444    }
    445 
    446    signCrl->arena = arena;
    447    signCrl->referenceCount = 1;
    448 
    449 loser:
    450    if (crlDER.data) {
    451        SECITEM_FreeItem(&crlDER, PR_FALSE);
    452    }
    453    if (modArena && (!modCrl || modCrl->arena != modArena)) {
    454        PORT_FreeArena(modArena, PR_FALSE);
    455    }
    456    if (modCrl)
    457        SEC_DestroyCrl(modCrl);
    458    if (rv != SECSuccess && signCrl) {
    459        SEC_DestroyCrl(signCrl);
    460        signCrl = NULL;
    461    }
    462    return signCrl;
    463 }
    464 
    465 static CERTSignedCrl *
    466 CreateNewCrl(PLArenaPool *arena, CERTCertDBHandle *certHandle,
    467             CERTCertificate *cert)
    468 {
    469    CERTSignedCrl *signCrl = NULL;
    470    void *dummy = NULL;
    471    SECStatus rv;
    472    void *mark = NULL;
    473 
    474    /* if the CERTSignedCrl structure changes, this function will need to be
    475       updated as well */
    476    if (!cert || !arena) {
    477        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    478        SECU_PrintError(progName, "invalid args for function "
    479                                  "CreateNewCrl\n");
    480        return NULL;
    481    }
    482 
    483    mark = PORT_ArenaMark(arena);
    484 
    485    signCrl = PORT_ArenaZNew(arena, CERTSignedCrl);
    486    if (signCrl == NULL) {
    487        SECU_PrintError(progName, "fail to allocate memory\n");
    488        return NULL;
    489    }
    490 
    491    dummy = SEC_ASN1EncodeInteger(arena, &signCrl->crl.version,
    492                                  SEC_CRL_VERSION_2);
    493    /* set crl->version */
    494    if (!dummy) {
    495        SECU_PrintError(progName, "fail to create crl version data "
    496                                  "container\n");
    497        goto loser;
    498    }
    499 
    500    /* copy SECItem name from cert */
    501    rv = SECITEM_CopyItem(arena, &signCrl->crl.derName, &cert->derSubject);
    502    if (rv != SECSuccess) {
    503        SECU_PrintError(progName, "fail to duplicate der name from "
    504                                  "certificate.\n");
    505        goto loser;
    506    }
    507 
    508    /* copy CERTName name structure from cert issuer */
    509    rv = CERT_CopyName(arena, &signCrl->crl.name, &cert->subject);
    510    if (rv != SECSuccess) {
    511        SECU_PrintError(progName, "fail to duplicate RD name from "
    512                                  "certificate.\n");
    513        goto loser;
    514    }
    515 
    516    rv = DER_EncodeTimeChoice(arena, &signCrl->crl.lastUpdate, PR_Now());
    517    if (rv != SECSuccess) {
    518        SECU_PrintError(progName, "fail to encode current time\n");
    519        goto loser;
    520    }
    521 
    522    /* set fields */
    523    signCrl->arena = arena;
    524    signCrl->dbhandle = certHandle;
    525    signCrl->crl.arena = arena;
    526 
    527    PORT_ArenaUnmark(arena, mark);
    528 
    529    return signCrl;
    530 
    531 loser:
    532    PORT_ArenaRelease(arena, mark);
    533    return NULL;
    534 }
    535 
    536 static SECStatus
    537 UpdateCrl(CERTSignedCrl *signCrl, PRFileDesc *inCrlInitFile)
    538 {
    539    CRLGENGeneratorData *crlGenData = NULL;
    540    SECStatus rv;
    541 
    542    if (!signCrl || !inCrlInitFile) {
    543        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    544        SECU_PrintError(progName, "invalid args for function "
    545                                  "CreateNewCrl\n");
    546        return SECFailure;
    547    }
    548 
    549    crlGenData = CRLGEN_InitCrlGeneration(signCrl, inCrlInitFile);
    550    if (!crlGenData) {
    551        SECU_PrintError(progName, "can not initialize parser structure.\n");
    552        return SECFailure;
    553    }
    554 
    555    rv = CRLGEN_ExtHandleInit(crlGenData);
    556    if (rv == SECFailure) {
    557        SECU_PrintError(progName, "can not initialize entries handle.\n");
    558        goto loser;
    559    }
    560 
    561    rv = CRLGEN_StartCrlGen(crlGenData);
    562    if (rv != SECSuccess) {
    563        SECU_PrintError(progName, "crl generation failed");
    564        goto loser;
    565    }
    566 
    567 loser:
    568    /* CommitExtensionsAndEntries is partially responsible for freeing
    569     * up memory that was used for CRL generation. Should be called regardless
    570     * of previouse call status, but only after initialization of
    571     * crlGenData was done. It will commit all changes that was done before
    572     * an error has occurred.
    573     */
    574    if (SECSuccess != CRLGEN_CommitExtensionsAndEntries(crlGenData)) {
    575        SECU_PrintError(progName, "crl generation failed");
    576        rv = SECFailure;
    577    }
    578    CRLGEN_FinalizeCrlGeneration(crlGenData);
    579    return rv;
    580 }
    581 
    582 static SECStatus
    583 SignAndStoreCrl(CERTSignedCrl *signCrl, CERTCertificate *cert,
    584                char *outFileName, SECOidTag hashAlgTag, int ascii,
    585                char *slotName, char *url, secuPWData *pwdata)
    586 {
    587    PK11SlotInfo *slot = NULL;
    588    PRFileDesc *outFile = NULL;
    589    SECStatus rv;
    590    SignAndEncodeFuncExitStat errCode;
    591 
    592    PORT_Assert(signCrl && (!ascii || outFileName));
    593    if (!signCrl || (ascii && !outFileName)) {
    594        SECU_PrintError(progName, "invalid args for function "
    595                                  "SignAndStoreCrl\n");
    596        return SECFailure;
    597    }
    598 
    599    if (!slotName || !PL_strcmp(slotName, "internal"))
    600        slot = PK11_GetInternalKeySlot();
    601    else
    602        slot = PK11_FindSlotByName(slotName);
    603    if (!slot) {
    604        SECU_PrintError(progName, "can not find requested slot");
    605        return SECFailure;
    606    }
    607 
    608    if (PK11_NeedLogin(slot)) {
    609        rv = PK11_Authenticate(slot, PR_TRUE, pwdata);
    610        if (rv != SECSuccess)
    611            goto loser;
    612    }
    613 
    614    rv = SECU_SignAndEncodeCRL(cert, signCrl, hashAlgTag, &errCode);
    615    if (rv != SECSuccess) {
    616        char *errMsg = NULL;
    617        switch (errCode) {
    618            case noKeyFound:
    619                errMsg = "No private key found of signing cert";
    620                break;
    621 
    622            case noSignatureMatch:
    623                errMsg = "Key and Algorithm OId are do not match";
    624                break;
    625 
    626            default:
    627            case failToEncode:
    628                errMsg = "Failed to encode crl structure";
    629                break;
    630 
    631            case failToSign:
    632                errMsg = "Failed to sign crl structure";
    633                break;
    634 
    635            case noMem:
    636                errMsg = "Can not allocate memory";
    637                break;
    638        }
    639        SECU_PrintError(progName, "%s\n", errMsg);
    640        goto loser;
    641    }
    642 
    643    if (outFileName) {
    644        outFile = PR_Open(outFileName, PR_WRONLY | PR_CREATE_FILE, PR_IRUSR | PR_IWUSR);
    645        if (!outFile) {
    646            SECU_PrintError(progName, "unable to open \"%s\" for writing\n",
    647                            outFileName);
    648            goto loser;
    649        }
    650    }
    651 
    652    rv = SECU_StoreCRL(slot, signCrl->derCrl, outFile, ascii, url);
    653    if (rv != SECSuccess) {
    654        SECU_PrintError(progName, "fail to save CRL\n");
    655    }
    656 
    657 loser:
    658    if (outFile)
    659        PR_Close(outFile);
    660    if (slot)
    661        PK11_FreeSlot(slot);
    662    return rv;
    663 }
    664 
    665 static SECStatus
    666 GenerateCRL(CERTCertDBHandle *certHandle, char *certNickName,
    667            PRFileDesc *inCrlInitFile, PRFileDesc *inFile,
    668            char *outFileName, int ascii, char *slotName,
    669            PRInt32 importOptions, char *alg, PRBool quiet,
    670            PRInt32 decodeOptions, char *url, secuPWData *pwdata,
    671            int modifyFlag)
    672 {
    673    CERTCertificate *cert = NULL;
    674    CERTSignedCrl *signCrl = NULL;
    675    PLArenaPool *arena = NULL;
    676    SECStatus rv;
    677    SECOidTag hashAlgTag = SEC_OID_UNKNOWN;
    678 
    679    if (alg) {
    680        hashAlgTag = SECU_StringToSignatureAlgTag(alg);
    681        if (hashAlgTag == SEC_OID_UNKNOWN) {
    682            SECU_PrintError(progName, "%s -Z:  %s is not a recognized type.\n",
    683                            progName, alg);
    684            return SECFailure;
    685        }
    686    } else {
    687        hashAlgTag = SEC_OID_UNKNOWN;
    688    }
    689 
    690    arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
    691    if (!arena) {
    692        SECU_PrintError(progName, "fail to allocate memory\n");
    693        return SECFailure;
    694    }
    695 
    696    if (modifyFlag == PR_TRUE) {
    697        signCrl = CreateModifiedCRLCopy(arena, certHandle, &cert, certNickName,
    698                                        inFile, decodeOptions, importOptions,
    699                                        pwdata);
    700        if (signCrl == NULL) {
    701            rv = SECFailure;
    702            goto loser;
    703        }
    704    }
    705 
    706    if (!cert) {
    707        cert = FindSigningCert(certHandle, signCrl, certNickName);
    708        if (cert == NULL) {
    709            rv = SECFailure;
    710            goto loser;
    711        }
    712    }
    713 
    714    if (!signCrl) {
    715        if (modifyFlag == PR_TRUE) {
    716            if (!outFileName) {
    717                int len = strlen(certNickName) + 5;
    718                outFileName = PORT_ArenaAlloc(arena, len);
    719                PR_snprintf(outFileName, len, "%s.crl", certNickName);
    720            }
    721            SECU_PrintError(progName, "Will try to generate crl. "
    722                                      "It will be saved in file: %s",
    723                            outFileName);
    724        }
    725        signCrl = CreateNewCrl(arena, certHandle, cert);
    726        if (!signCrl) {
    727            rv = SECFailure;
    728            goto loser;
    729        }
    730    }
    731 
    732    rv = UpdateCrl(signCrl, inCrlInitFile);
    733    if (rv != SECSuccess) {
    734        goto loser;
    735    }
    736 
    737    rv = SignAndStoreCrl(signCrl, cert, outFileName, hashAlgTag, ascii,
    738                         slotName, url, pwdata);
    739    if (rv != SECSuccess) {
    740        goto loser;
    741    }
    742 
    743    if (signCrl && !quiet) {
    744        SECU_PrintCRLInfo(stdout, &signCrl->crl, "CRL Info:\n", 0);
    745    }
    746 
    747 loser:
    748    if (arena && (!signCrl || !signCrl->arena))
    749        PORT_FreeArena(arena, PR_FALSE);
    750    if (signCrl)
    751        SEC_DestroyCrl(signCrl);
    752    if (cert)
    753        CERT_DestroyCertificate(cert);
    754    return (rv);
    755 }
    756 
    757 static void
    758 Usage()
    759 {
    760    fprintf(stderr,
    761            "Usage:  %s -L [-n nickname] [-d keydir] [-P dbprefix] [-t crlType]\n"
    762            "        %s -D -n nickname [-d keydir] [-P dbprefix]\n"
    763            "        %s -S -i crl\n"
    764            "        %s -I -i crl -t crlType [-u url] [-d keydir] [-P dbprefix] [-B] "
    765            "[-p pwd-file] -w [pwd-string]\n"
    766            "        %s -E -t crlType [-d keydir] [-P dbprefix]\n"
    767            "        %s -T\n"
    768            "        %s -G|-M -c crl-init-file -n nickname [-i crl] [-u url] "
    769            "[-d keydir] [-P dbprefix] [-Z alg] ] [-p pwd-file] -w [pwd-string] "
    770            "[-a] [-B]\n",
    771            progName, progName, progName, progName, progName, progName, progName);
    772 
    773    fprintf(stderr, "%-15s List CRL\n", "-L");
    774    fprintf(stderr, "%-20s Specify the nickname of the CA certificate\n",
    775            "-n nickname");
    776    fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n",
    777            "-d keydir");
    778    fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n",
    779            "-P dbprefix");
    780 
    781    fprintf(stderr, "%-15s Delete a CRL from the cert database\n", "-D");
    782    fprintf(stderr, "%-20s Specify the nickname for the CA certificate\n",
    783            "-n nickname");
    784    fprintf(stderr, "%-20s Specify the crl type.\n", "-t crlType");
    785    fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n",
    786            "-d keydir");
    787    fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n",
    788            "-P dbprefix");
    789 
    790    fprintf(stderr, "%-15s Erase all CRLs of specified type from hte cert database\n", "-E");
    791    fprintf(stderr, "%-20s Specify the crl type.\n", "-t crlType");
    792    fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n",
    793            "-d keydir");
    794    fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n",
    795            "-P dbprefix");
    796 
    797    fprintf(stderr, "%-15s Show contents of a CRL file (without database)\n", "-S");
    798    fprintf(stderr, "%-20s Specify the file which contains the CRL to show\n",
    799            "-i crl");
    800 
    801    fprintf(stderr, "%-15s Import a CRL to the cert database\n", "-I");
    802    fprintf(stderr, "%-20s Specify the file which contains the CRL to import\n",
    803            "-i crl");
    804    fprintf(stderr, "%-20s Specify the url.\n", "-u url");
    805    fprintf(stderr, "%-20s Specify the crl type.\n", "-t crlType");
    806    fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n",
    807            "-d keydir");
    808    fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n",
    809            "-P dbprefix");
    810 #ifdef DEBUG
    811    fprintf(stderr, "%-15s Test . Only for debugging purposes. See source code\n", "-T");
    812 #endif
    813    fprintf(stderr, "%-20s CRL Types (default is SEC_CRL_TYPE):\n", " ");
    814    fprintf(stderr, "%-20s \t 0 - SEC_KRL_TYPE\n", " ");
    815    fprintf(stderr, "%-20s \t 1 - SEC_CRL_TYPE\n", " ");
    816    fprintf(stderr, "\n%-20s Bypass CA certificate checks.\n", "-B");
    817    fprintf(stderr, "\n%-20s Partial decode for faster operation.\n", "-p");
    818    fprintf(stderr, "%-20s Repeat the operation.\n", "-r <iterations>");
    819    fprintf(stderr, "\n%-15s Create CRL\n", "-G");
    820    fprintf(stderr, "%-15s Modify CRL\n", "-M");
    821    fprintf(stderr, "%-20s Specify crl initialization file\n",
    822            "-c crl-conf-file");
    823    fprintf(stderr, "%-20s Specify the nickname of the CA certificate\n",
    824            "-n nickname");
    825    fprintf(stderr, "%-20s Specify the file which contains the CRL to import\n",
    826            "-i crl");
    827    fprintf(stderr, "%-20s Specify a CRL output file\n",
    828            "-o crl-output-file");
    829    fprintf(stderr, "%-20s Specify to use base64 encoded CRL output format\n",
    830            "-a");
    831    fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n",
    832            "-d keydir");
    833    fprintf(stderr, "%-20s Provide path to a default pwd file\n",
    834            "-f pwd-file");
    835    fprintf(stderr, "%-20s Provide db password in command line\n",
    836            "-w pwd-string");
    837    fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n",
    838            "-P dbprefix");
    839    fprintf(stderr, "%-20s Specify the url.\n", "-u url");
    840    fprintf(stderr, "\n%-20s Bypass CA certificate checks.\n", "-B");
    841 
    842    exit(-1);
    843 }
    844 
    845 int
    846 main(int argc, char **argv)
    847 {
    848    CERTCertDBHandle *certHandle;
    849    PRFileDesc *inFile;
    850    PRFileDesc *inCrlInitFile = NULL;
    851    int generateCRL;
    852    int modifyCRL;
    853    int listCRL;
    854    int importCRL;
    855    int showFileCRL;
    856    int deleteCRL;
    857    int rv;
    858    char *nickName;
    859    char *url;
    860    char *dbPrefix = PORT_Strdup("");
    861    char *alg = NULL;
    862    char *outFile = NULL;
    863    char *slotName = NULL;
    864    int ascii = 0;
    865    int crlType;
    866    PLOptState *optstate;
    867    PLOptStatus status;
    868    SECStatus secstatus;
    869    PRInt32 decodeOptions = CRL_DECODE_DEFAULT_OPTIONS;
    870    PRInt32 importOptions = CRL_IMPORT_DEFAULT_OPTIONS;
    871    PRBool quiet = PR_FALSE;
    872    PRBool test = PR_FALSE;
    873    PRBool erase = PR_FALSE;
    874    PRInt32 i = 0;
    875    PRInt32 iterations = 1;
    876    PRBool readonly = PR_FALSE;
    877 
    878    secuPWData pwdata = { PW_NONE, 0 };
    879 
    880    progName = strrchr(argv[0], '/');
    881    progName = progName ? progName + 1 : argv[0];
    882 
    883    rv = 0;
    884    deleteCRL = importCRL = listCRL = generateCRL = modifyCRL = showFileCRL = 0;
    885    inFile = NULL;
    886    nickName = url = NULL;
    887    certHandle = NULL;
    888    crlType = SEC_CRL_TYPE;
    889    /*
    890     * Parse command line arguments
    891     */
    892    optstate = PL_CreateOptState(argc, argv, "sqBCDGILMSTEP:f:d:i:h:n:p:t:u:r:aZ:o:c:");
    893    while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
    894        switch (optstate->option) {
    895            case '?':
    896                Usage();
    897                break;
    898 
    899            case 'T':
    900                test = PR_TRUE;
    901                break;
    902 
    903            case 'E':
    904                erase = PR_TRUE;
    905                break;
    906 
    907            case 'B':
    908                importOptions |= CRL_IMPORT_BYPASS_CHECKS;
    909                break;
    910 
    911            case 'G':
    912                generateCRL = 1;
    913                break;
    914 
    915            case 'M':
    916                modifyCRL = 1;
    917                break;
    918 
    919            case 'D':
    920                deleteCRL = 1;
    921                break;
    922 
    923            case 'I':
    924                importCRL = 1;
    925                break;
    926 
    927            case 'S':
    928                showFileCRL = 1;
    929                break;
    930 
    931            case 'C':
    932            case 'L':
    933                listCRL = 1;
    934                break;
    935 
    936            case 'P':
    937                PORT_Free(dbPrefix);
    938                dbPrefix = PORT_Strdup(optstate->value);
    939                break;
    940 
    941            case 'Z':
    942                alg = PORT_Strdup(optstate->value);
    943                break;
    944 
    945            case 'a':
    946                ascii = 1;
    947                break;
    948 
    949            case 'c':
    950                inCrlInitFile = PR_Open(optstate->value, PR_RDONLY, 0);
    951                if (!inCrlInitFile) {
    952                    PR_fprintf(PR_STDERR, "%s: unable to open \"%s\" for reading\n",
    953                               progName, optstate->value);
    954                    rv = SECFailure;
    955                    goto loser;
    956                }
    957                break;
    958 
    959            case 'd':
    960                SECU_ConfigDirectory(optstate->value);
    961                break;
    962 
    963            case 'f':
    964                pwdata.source = PW_FROMFILE;
    965                pwdata.data = PORT_Strdup(optstate->value);
    966                break;
    967 
    968            case 'h':
    969                slotName = PORT_Strdup(optstate->value);
    970                break;
    971 
    972            case 'i':
    973                inFile = PR_Open(optstate->value, PR_RDONLY, 0);
    974                if (!inFile) {
    975                    PR_fprintf(PR_STDERR, "%s: unable to open \"%s\" for reading\n",
    976                               progName, optstate->value);
    977                    rv = SECFailure;
    978                    goto loser;
    979                }
    980                break;
    981 
    982            case 'n':
    983                nickName = PORT_Strdup(optstate->value);
    984                break;
    985 
    986            case 'o':
    987                outFile = PORT_Strdup(optstate->value);
    988                break;
    989 
    990            case 'p':
    991                decodeOptions |= CRL_DECODE_SKIP_ENTRIES;
    992                break;
    993 
    994            case 'r': {
    995                const char *str = optstate->value;
    996                if (str && atoi(str) > 0)
    997                    iterations = atoi(str);
    998            } break;
    999 
   1000            case 't': {
   1001                crlType = atoi(optstate->value);
   1002                if (crlType != SEC_CRL_TYPE && crlType != SEC_KRL_TYPE) {
   1003                    PR_fprintf(PR_STDERR, "%s: invalid crl type\n", progName);
   1004                    rv = SECFailure;
   1005                    goto loser;
   1006                }
   1007                break;
   1008 
   1009                case 'q':
   1010                    quiet = PR_TRUE;
   1011                    break;
   1012 
   1013                case 'w':
   1014                    pwdata.source = PW_PLAINTEXT;
   1015                    pwdata.data = PORT_Strdup(optstate->value);
   1016                    break;
   1017 
   1018                case 'u':
   1019                    url = PORT_Strdup(optstate->value);
   1020                    break;
   1021            }
   1022        }
   1023    }
   1024 
   1025    if (deleteCRL && !nickName)
   1026        Usage();
   1027    if (importCRL && !inFile)
   1028        Usage();
   1029    if (showFileCRL && !inFile)
   1030        Usage();
   1031    if ((generateCRL && !nickName) ||
   1032        (modifyCRL && !inFile && !nickName))
   1033        Usage();
   1034    if (!(listCRL || deleteCRL || importCRL || showFileCRL || generateCRL ||
   1035          modifyCRL || test || erase))
   1036        Usage();
   1037 
   1038    if (listCRL || showFileCRL) {
   1039        readonly = PR_TRUE;
   1040    }
   1041 
   1042    PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
   1043 
   1044    PK11_SetPasswordFunc(SECU_GetModulePassword);
   1045 
   1046    if (showFileCRL) {
   1047        rv = NSS_NoDB_Init(NULL);
   1048        if (rv != SECSuccess) {
   1049            goto loser;
   1050        }
   1051    } else {
   1052        secstatus = NSS_Initialize(SECU_ConfigDirectory(NULL), dbPrefix, dbPrefix,
   1053                                   "secmod.db", readonly ? NSS_INIT_READONLY : 0);
   1054        if (secstatus != SECSuccess) {
   1055            SECU_PrintPRandOSError(progName);
   1056            rv = SECFailure;
   1057            goto loser;
   1058        }
   1059    }
   1060 
   1061    SECU_RegisterDynamicOids();
   1062 
   1063    certHandle = CERT_GetDefaultCertDB();
   1064    if (certHandle == NULL) {
   1065        SECU_PrintError(progName, "unable to open the cert db");
   1066        rv = SECFailure;
   1067        goto loser;
   1068    }
   1069 
   1070    CRLGEN_InitCrlGenParserLock();
   1071 
   1072    for (i = 0; i < iterations; i++) {
   1073        /* Read in the private key info */
   1074        if (deleteCRL)
   1075            DeleteCRL(certHandle, nickName, crlType);
   1076        else if (listCRL) {
   1077            rv = ListCRL(certHandle, nickName, crlType);
   1078        } else if (importCRL) {
   1079            rv = ImportCRL(certHandle, url, crlType, inFile, importOptions,
   1080                           decodeOptions, &pwdata);
   1081        } else if (showFileCRL) {
   1082            rv = DumpCRL(inFile);
   1083        } else if (generateCRL || modifyCRL) {
   1084            if (!inCrlInitFile)
   1085                inCrlInitFile = PR_STDIN;
   1086            rv = GenerateCRL(certHandle, nickName, inCrlInitFile,
   1087                             inFile, outFile, ascii, slotName,
   1088                             importOptions, alg, quiet,
   1089                             decodeOptions, url, &pwdata,
   1090                             modifyCRL);
   1091        } else if (erase) {
   1092            /* list and delete all CRLs */
   1093            ListCRLNames(certHandle, crlType, PR_TRUE);
   1094        }
   1095 #ifdef DEBUG
   1096        else if (test) {
   1097            /* list and delete all CRLs */
   1098            ListCRLNames(certHandle, crlType, PR_TRUE);
   1099            /* list CRLs */
   1100            ListCRLNames(certHandle, crlType, PR_FALSE);
   1101            /* import CRL as a blob */
   1102            rv = ImportCRL(certHandle, url, crlType, inFile, importOptions,
   1103                           decodeOptions, &pwdata);
   1104            /* list CRLs */
   1105            ListCRLNames(certHandle, crlType, PR_FALSE);
   1106        }
   1107 #endif
   1108    }
   1109 
   1110    CRLGEN_DestroyCrlGenParserLock();
   1111 
   1112 loser:
   1113    PL_DestroyOptState(optstate);
   1114 
   1115    if (inFile) {
   1116        PR_Close(inFile);
   1117    }
   1118    if (alg) {
   1119        PORT_Free(alg);
   1120    }
   1121    if (slotName) {
   1122        PORT_Free(slotName);
   1123    }
   1124    if (nickName) {
   1125        PORT_Free(nickName);
   1126    }
   1127    if (outFile) {
   1128        PORT_Free(outFile);
   1129    }
   1130    if (url) {
   1131        PORT_Free(url);
   1132    }
   1133    if (pwdata.data) {
   1134        PORT_Free(pwdata.data);
   1135    }
   1136 
   1137    PORT_Free(dbPrefix);
   1138 
   1139    if (NSS_Shutdown() != SECSuccess) {
   1140        rv = SECFailure;
   1141    }
   1142 
   1143    return (rv != SECSuccess);
   1144 }