tor-browser

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

vfychain.c (28674B)


      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 *  Read in a cert chain from one or more files, and verify the chain for
      7 *  some usage.
      8 *                                                                          *
      9 *  This code was modified from other code also kept in the NSS directory.
     10 ****************************************************************************/
     11 
     12 #include <stdio.h>
     13 #include <string.h>
     14 
     15 #if defined(XP_UNIX)
     16 #include <unistd.h>
     17 #endif
     18 
     19 #include "prerror.h"
     20 
     21 #include "pk11func.h"
     22 #include "seccomon.h"
     23 #include "secutil.h"
     24 #include "secmod.h"
     25 #include "secitem.h"
     26 #include "cert.h"
     27 #include "ocsp.h"
     28 
     29 /* #include <stdlib.h> */
     30 /* #include <errno.h> */
     31 /* #include <fcntl.h> */
     32 /* #include <stdarg.h> */
     33 
     34 #include "nspr.h"
     35 #include "plgetopt.h"
     36 #include "prio.h"
     37 #include "nss.h"
     38 
     39 /* #include "vfyutil.h" */
     40 
     41 #define RD_BUF_SIZE (60 * 1024)
     42 
     43 int verbose;
     44 
     45 secuPWData pwdata = { PW_NONE, 0 };
     46 
     47 static void
     48 Usage(const char *progName)
     49 {
     50    fprintf(stderr,
     51            "Usage: %s [options] [revocation options] certfile "
     52            "[[options] certfile] ...\n"
     53            "\tWhere options are:\n"
     54            "\t-a\t\t Following certfile is base64 encoded\n"
     55            "\t-b YYMMDDHHMMZ\t Validate date (default: now)\n"
     56            "\t-d directory\t Database directory\n"
     57            "\t-i number of consecutive verifications\n"
     58            "\t-f \t\t Enable cert fetching from AIA URL\n"
     59            "\t-o oid\t\t Set policy OID for cert validation(Format OID.1.2.3)\n"
     60            "\t-p \t\t Use PKIX Library to validate certificate by calling:\n"
     61            "\t\t\t   * CERT_VerifyCertificate if specified once,\n"
     62            "\t\t\t   * CERT_PKIXVerifyCert if specified twice and more.\n"
     63            "\t-r\t\t Following certfile is raw binary DER (default)\n"
     64            "\t-t\t\t Following cert is explicitly trusted (overrides db trust).\n"
     65            "\t-u usage \t 0=SSL client, 1=SSL server, 2=SSL StepUp, 3=SSL CA,\n"
     66            "\t\t\t 4=Email signer, 5=Email recipient, 6=Object signer,\n"
     67            "\t\t\t 9=ProtectedObjectSigner, 10=OCSP responder, 11=Any CA,\n"
     68            "\t\t\t 12=IPsec\n"
     69            "\t-T\t\t Trust both explicit trust anchors (-t) and the database.\n"
     70            "\t\t\t (Default is to only trust certificates marked -t, if there are any,\n"
     71            "\t\t\t or to trust the database if there are certificates marked -t.)\n"
     72            "\t-v\t\t Verbose mode. Prints root cert subject(double the\n"
     73            "\t\t\t argument for whole root cert info)\n"
     74            "\t-w password\t Database password.\n"
     75            "\t-W pwfile\t Password file.\n\n"
     76            "\tRevocation options for PKIX API(invoked with -pp options) is a\n"
     77            "\tcollection of the following flags:\n"
     78            "\t\t[-g type [-h flags] [-m type [-s flags]] ...] ...\n"
     79            "\tWhere:\n"
     80            "\t-g test type\t Sets status checking test type. Possible values\n"
     81            "\t\t\tare \"leaf\" or \"chain\"\n"
     82            "\t-h test flags\t Sets revocation flags for the test type it\n"
     83            "\t\t\tfollows. Possible flags: \"testLocalInfoFirst\" and\n"
     84            "\t\t\t\"requireFreshInfo\".\n"
     85            "\t-m method type\t Sets method type for the test type it follows.\n"
     86            "\t\t\tPossible types are \"crl\" and \"ocsp\".\n"
     87            "\t-s method flags\t Sets revocation flags for the method it follows.\n"
     88            "\t\t\tPossible types are \"doNotUse\", \"forbidFetching\",\n"
     89            "\t\t\t\"ignoreDefaultSrc\", \"requireInfo\" and \"failIfNoInfo\".\n",
     90            progName);
     91    exit(1);
     92 }
     93 
     94 /**************************************************************************
     95 **
     96 ** Error and information routines.
     97 **
     98 **************************************************************************/
     99 
    100 void
    101 errWarn(char *function)
    102 {
    103    fprintf(stderr, "Error in function %s: %s\n",
    104            function, SECU_Strerror(PR_GetError()));
    105 }
    106 
    107 void
    108 exitErr(char *function)
    109 {
    110    errWarn(function);
    111    /* Exit gracefully. */
    112    /* ignoring return value of NSS_Shutdown as code exits with 1 anyway*/
    113    (void)NSS_Shutdown();
    114    PR_Cleanup();
    115    exit(1);
    116 }
    117 
    118 typedef struct certMemStr {
    119    struct certMemStr *next;
    120    CERTCertificate *cert;
    121 } certMem;
    122 
    123 certMem *theCerts;
    124 CERTCertList *trustedCertList;
    125 
    126 void
    127 rememberCert(CERTCertificate *cert, PRBool trusted)
    128 {
    129    if (trusted) {
    130        if (!trustedCertList) {
    131            trustedCertList = CERT_NewCertList();
    132        }
    133        CERT_AddCertToListTail(trustedCertList, cert);
    134    } else {
    135        certMem *newCertMem = PORT_ZNew(certMem);
    136        if (newCertMem) {
    137            newCertMem->next = theCerts;
    138            newCertMem->cert = cert;
    139            theCerts = newCertMem;
    140        }
    141    }
    142 }
    143 
    144 void
    145 forgetCerts(void)
    146 {
    147    certMem *oldCertMem;
    148    while (theCerts) {
    149        oldCertMem = theCerts;
    150        theCerts = theCerts->next;
    151        CERT_DestroyCertificate(oldCertMem->cert);
    152        PORT_Free(oldCertMem);
    153    }
    154    if (trustedCertList) {
    155        CERT_DestroyCertList(trustedCertList);
    156    }
    157 }
    158 
    159 CERTCertificate *
    160 getCert(const char *name, PRBool isAscii, const char *progName)
    161 {
    162    CERTCertificate *cert;
    163    CERTCertDBHandle *defaultDB;
    164    PRFileDesc *fd;
    165    SECStatus rv;
    166    SECItem item = { 0, NULL, 0 };
    167 
    168    defaultDB = CERT_GetDefaultCertDB();
    169 
    170    /* First, let's try to find the cert in existing DB. */
    171    cert = CERT_FindCertByNicknameOrEmailAddr(defaultDB, name);
    172    if (cert) {
    173        return cert;
    174    }
    175 
    176    /* Don't have a cert with name "name" in the DB. Try to
    177     * open a file with such name and get the cert from there.*/
    178    fd = PR_Open(name, PR_RDONLY, 0777);
    179    if (!fd) {
    180        PRErrorCode err = PR_GetError();
    181        fprintf(stderr, "open of %s failed, %d = %s\n",
    182                name, err, SECU_Strerror(err));
    183        return cert;
    184    }
    185 
    186    rv = SECU_ReadDERFromFile(&item, fd, isAscii, PR_FALSE);
    187    PR_Close(fd);
    188    if (rv != SECSuccess) {
    189        fprintf(stderr, "%s: SECU_ReadDERFromFile failed\n", progName);
    190        return cert;
    191    }
    192 
    193    if (!item.len) { /* file was empty */
    194        fprintf(stderr, "cert file %s was empty.\n", name);
    195        return cert;
    196    }
    197 
    198    cert = CERT_NewTempCertificate(defaultDB, &item,
    199                                   NULL /* nickname */,
    200                                   PR_FALSE /* isPerm */,
    201                                   PR_TRUE /* copyDER */);
    202    if (!cert) {
    203        PRErrorCode err = PR_GetError();
    204        fprintf(stderr, "couldn't import %s, %d = %s\n",
    205                name, err, SECU_Strerror(err));
    206    }
    207    PORT_Free(item.data);
    208    return cert;
    209 }
    210 
    211 #define REVCONFIG_TEST_UNDEFINED 0
    212 #define REVCONFIG_TEST_LEAF 1
    213 #define REVCONFIG_TEST_CHAIN 2
    214 #define REVCONFIG_METHOD_CRL 1
    215 #define REVCONFIG_METHOD_OCSP 2
    216 
    217 #define REVCONFIG_TEST_LEAF_STR "leaf"
    218 #define REVCONFIG_TEST_CHAIN_STR "chain"
    219 #define REVCONFIG_METHOD_CRL_STR "crl"
    220 #define REVCONFIG_METHOD_OCSP_STR "ocsp"
    221 
    222 #define REVCONFIG_TEST_TESTLOCALINFOFIRST_STR "testLocalInfoFirst"
    223 #define REVCONFIG_TEST_REQUIREFRESHINFO_STR "requireFreshInfo"
    224 #define REVCONFIG_METHOD_DONOTUSEMETHOD_STR "doNotUse"
    225 #define REVCONFIG_METHOD_FORBIDNETWORKFETCHIN_STR "forbidFetching"
    226 #define REVCONFIG_METHOD_IGNOREDEFAULTSRC_STR "ignoreDefaultSrc"
    227 #define REVCONFIG_METHOD_REQUIREINFO_STR "requireInfo"
    228 #define REVCONFIG_METHOD_FAILIFNOINFO_STR "failIfNoInfo"
    229 
    230 #define REV_METHOD_INDEX_MAX 4
    231 
    232 typedef struct RevMethodsStruct {
    233    unsigned int testType;
    234    char *testTypeStr;
    235    unsigned int testFlags;
    236    char *testFlagsStr;
    237    unsigned int methodType;
    238    char *methodTypeStr;
    239    unsigned int methodFlags;
    240    char *methodFlagsStr;
    241 } RevMethods;
    242 
    243 RevMethods revMethodsData[REV_METHOD_INDEX_MAX];
    244 
    245 SECStatus
    246 parseRevMethodsAndFlags()
    247 {
    248    int i;
    249    unsigned int testType = 0;
    250 
    251    for (i = 0; i < REV_METHOD_INDEX_MAX; i++) {
    252        /* testType */
    253        if (revMethodsData[i].testTypeStr) {
    254            char *typeStr = revMethodsData[i].testTypeStr;
    255 
    256            testType = 0;
    257            if (!PORT_Strcmp(typeStr, REVCONFIG_TEST_LEAF_STR)) {
    258                testType = REVCONFIG_TEST_LEAF;
    259            } else if (!PORT_Strcmp(typeStr, REVCONFIG_TEST_CHAIN_STR)) {
    260                testType = REVCONFIG_TEST_CHAIN;
    261            }
    262        }
    263        if (!testType) {
    264            return SECFailure;
    265        }
    266        revMethodsData[i].testType = testType;
    267        /* testFlags */
    268        if (revMethodsData[i].testFlagsStr) {
    269            char *flagStr = revMethodsData[i].testFlagsStr;
    270            unsigned int testFlags = 0;
    271 
    272            if (PORT_Strstr(flagStr, REVCONFIG_TEST_TESTLOCALINFOFIRST_STR)) {
    273                testFlags |= CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST;
    274            }
    275            if (PORT_Strstr(flagStr, REVCONFIG_TEST_REQUIREFRESHINFO_STR)) {
    276                testFlags |= CERT_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE;
    277            }
    278            revMethodsData[i].testFlags = testFlags;
    279        }
    280        /* method type */
    281        if (revMethodsData[i].methodTypeStr) {
    282            char *methodStr = revMethodsData[i].methodTypeStr;
    283            unsigned int methodType = 0;
    284 
    285            if (!PORT_Strcmp(methodStr, REVCONFIG_METHOD_CRL_STR)) {
    286                methodType = REVCONFIG_METHOD_CRL;
    287            } else if (!PORT_Strcmp(methodStr, REVCONFIG_METHOD_OCSP_STR)) {
    288                methodType = REVCONFIG_METHOD_OCSP;
    289            }
    290            if (!methodType) {
    291                return SECFailure;
    292            }
    293            revMethodsData[i].methodType = methodType;
    294        }
    295        if (!revMethodsData[i].methodType) {
    296            revMethodsData[i].testType = REVCONFIG_TEST_UNDEFINED;
    297            continue;
    298        }
    299        /* method flags */
    300        if (revMethodsData[i].methodFlagsStr) {
    301            char *flagStr = revMethodsData[i].methodFlagsStr;
    302            unsigned int methodFlags = 0;
    303 
    304            if (!PORT_Strstr(flagStr, REVCONFIG_METHOD_DONOTUSEMETHOD_STR)) {
    305                methodFlags |= CERT_REV_M_TEST_USING_THIS_METHOD;
    306            }
    307            if (PORT_Strstr(flagStr,
    308                            REVCONFIG_METHOD_FORBIDNETWORKFETCHIN_STR)) {
    309                methodFlags |= CERT_REV_M_FORBID_NETWORK_FETCHING;
    310            }
    311            if (PORT_Strstr(flagStr, REVCONFIG_METHOD_IGNOREDEFAULTSRC_STR)) {
    312                methodFlags |= CERT_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE;
    313            }
    314            if (PORT_Strstr(flagStr, REVCONFIG_METHOD_REQUIREINFO_STR)) {
    315                methodFlags |= CERT_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE;
    316            }
    317            if (PORT_Strstr(flagStr, REVCONFIG_METHOD_FAILIFNOINFO_STR)) {
    318                methodFlags |= CERT_REV_M_FAIL_ON_MISSING_FRESH_INFO;
    319            }
    320            revMethodsData[i].methodFlags = methodFlags;
    321        } else {
    322            revMethodsData[i].methodFlags |= CERT_REV_M_TEST_USING_THIS_METHOD;
    323        }
    324    }
    325    return SECSuccess;
    326 }
    327 
    328 SECStatus
    329 configureRevocationParams(CERTRevocationFlags *flags)
    330 {
    331    int i;
    332    unsigned int testType = REVCONFIG_TEST_UNDEFINED;
    333    static CERTRevocationTests *revTests = NULL;
    334    PRUint64 *revFlags = NULL;
    335 
    336    for (i = 0; i < REV_METHOD_INDEX_MAX; i++) {
    337        if (revMethodsData[i].testType == REVCONFIG_TEST_UNDEFINED) {
    338            continue;
    339        }
    340        if (revMethodsData[i].testType != testType) {
    341            testType = revMethodsData[i].testType;
    342            if (testType == REVCONFIG_TEST_CHAIN) {
    343                revTests = &flags->chainTests;
    344            } else {
    345                revTests = &flags->leafTests;
    346            }
    347            revTests->number_of_preferred_methods = 0;
    348            revTests->preferred_methods = 0;
    349            revFlags = revTests->cert_rev_flags_per_method;
    350        }
    351        /* Set the number of the methods independently to the max number of
    352         * methods. If method flags are not set it will be ignored due to
    353         * default DO_NOT_USE flag. */
    354        revTests->number_of_defined_methods = cert_revocation_method_count;
    355        revTests->cert_rev_method_independent_flags |=
    356            revMethodsData[i].testFlags;
    357        if (revMethodsData[i].methodType == REVCONFIG_METHOD_CRL) {
    358            revFlags[cert_revocation_method_crl] =
    359                revMethodsData[i].methodFlags;
    360        } else if (revMethodsData[i].methodType == REVCONFIG_METHOD_OCSP) {
    361            revFlags[cert_revocation_method_ocsp] =
    362                revMethodsData[i].methodFlags;
    363        }
    364    }
    365    return SECSuccess;
    366 }
    367 
    368 void
    369 freeRevocationMethodData()
    370 {
    371    int i = 0;
    372    for (; i < REV_METHOD_INDEX_MAX; i++) {
    373        if (revMethodsData[i].testTypeStr) {
    374            PORT_Free(revMethodsData[i].testTypeStr);
    375        }
    376        if (revMethodsData[i].testFlagsStr) {
    377            PORT_Free(revMethodsData[i].testFlagsStr);
    378        }
    379        if (revMethodsData[i].methodTypeStr) {
    380            PORT_Free(revMethodsData[i].methodTypeStr);
    381        }
    382        if (revMethodsData[i].methodFlagsStr) {
    383            PORT_Free(revMethodsData[i].methodFlagsStr);
    384        }
    385    }
    386 }
    387 
    388 PRBool
    389 isOCSPEnabled()
    390 {
    391    int i;
    392 
    393    for (i = 0; i < REV_METHOD_INDEX_MAX; i++) {
    394        if (revMethodsData[i].methodType == REVCONFIG_METHOD_OCSP) {
    395            return PR_TRUE;
    396        }
    397    }
    398    return PR_FALSE;
    399 }
    400 
    401 int
    402 main(int argc, char *argv[], char *envp[])
    403 {
    404    char *certDir = NULL;
    405    char *progName = NULL;
    406    char *oidStr = NULL;
    407    CERTCertificate *cert;
    408    CERTCertificate *firstCert = NULL;
    409    CERTCertificate *issuerCert = NULL;
    410    CERTCertDBHandle *defaultDB = NULL;
    411    PRBool isAscii = PR_FALSE;
    412    PRBool trusted = PR_FALSE;
    413    SECStatus secStatus;
    414    SECCertificateUsage certUsage = certificateUsageSSLServer;
    415    PLOptState *optstate;
    416    PRTime time = 0;
    417    PLOptStatus status;
    418    int usePkix = 0;
    419    int rv = 1;
    420    int usage;
    421    CERTVerifyLog log;
    422    CERTCertList *builtChain = NULL;
    423    PRBool certFetching = PR_FALSE;
    424    int revDataIndex = 0;
    425    PRBool ocsp_fetchingFailureIsAFailure = PR_TRUE;
    426    PRBool useDefaultRevFlags = PR_TRUE;
    427    PRBool onlyTrustAnchors = PR_TRUE;
    428    int vfyCounts = 1;
    429 
    430    PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
    431 
    432    progName = PL_strdup(argv[0]);
    433 
    434    optstate = PL_CreateOptState(argc, argv, "ab:c:d:efg:h:i:m:o:prs:tTu:vw:W:");
    435    while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
    436        switch (optstate->option) {
    437            case 0: /* positional parameter */
    438                goto breakout;
    439            case 'a':
    440                isAscii = PR_TRUE;
    441                break;
    442            case 'b':
    443                secStatus = DER_AsciiToTime(&time, optstate->value);
    444                if (secStatus != SECSuccess)
    445                    Usage(progName);
    446                break;
    447            case 'd':
    448                certDir = PL_strdup(optstate->value);
    449                break;
    450            case 'e':
    451                ocsp_fetchingFailureIsAFailure = PR_FALSE;
    452                break;
    453            case 'f':
    454                certFetching = PR_TRUE;
    455                break;
    456            case 'g':
    457                if (revMethodsData[revDataIndex].testTypeStr ||
    458                    revMethodsData[revDataIndex].methodTypeStr) {
    459                    revDataIndex += 1;
    460                    if (revDataIndex == REV_METHOD_INDEX_MAX) {
    461                        fprintf(stderr, "Invalid revocation configuration"
    462                                        "specified.\n");
    463                        secStatus = SECFailure;
    464                        break;
    465                    }
    466                }
    467                useDefaultRevFlags = PR_FALSE;
    468                revMethodsData[revDataIndex].testTypeStr =
    469                    PL_strdup(optstate->value);
    470                break;
    471            case 'h':
    472                revMethodsData[revDataIndex].testFlagsStr =
    473                    PL_strdup(optstate->value);
    474                break;
    475            case 'i':
    476                vfyCounts = PORT_Atoi(optstate->value);
    477                break;
    478                break;
    479            case 'm':
    480                if (revMethodsData[revDataIndex].methodTypeStr) {
    481                    revDataIndex += 1;
    482                    if (revDataIndex == REV_METHOD_INDEX_MAX) {
    483                        fprintf(stderr, "Invalid revocation configuration"
    484                                        "specified.\n");
    485                        secStatus = SECFailure;
    486                        break;
    487                    }
    488                }
    489                useDefaultRevFlags = PR_FALSE;
    490                revMethodsData[revDataIndex].methodTypeStr =
    491                    PL_strdup(optstate->value);
    492                break;
    493            case 'o':
    494                oidStr = PL_strdup(optstate->value);
    495                break;
    496            case 'p':
    497                usePkix += 1;
    498                break;
    499            case 'r':
    500                isAscii = PR_FALSE;
    501                break;
    502            case 's':
    503                revMethodsData[revDataIndex].methodFlagsStr =
    504                    PL_strdup(optstate->value);
    505                break;
    506            case 't':
    507                trusted = PR_TRUE;
    508                break;
    509            case 'T':
    510                onlyTrustAnchors = PR_FALSE;
    511                break;
    512            case 'u':
    513                usage = PORT_Atoi(optstate->value);
    514                if (usage < 0 || usage > 62)
    515                    Usage(progName);
    516                certUsage = ((SECCertificateUsage)1) << usage;
    517                if (certUsage > certificateUsageHighest)
    518                    Usage(progName);
    519                break;
    520            case 'w':
    521                pwdata.source = PW_PLAINTEXT;
    522                pwdata.data = PORT_Strdup(optstate->value);
    523                break;
    524 
    525            case 'W':
    526                pwdata.source = PW_FROMFILE;
    527                pwdata.data = PORT_Strdup(optstate->value);
    528                break;
    529            case 'v':
    530                verbose++;
    531                break;
    532            default:
    533                Usage(progName);
    534                break;
    535        }
    536    }
    537 breakout:
    538    if (status != PL_OPT_OK)
    539        Usage(progName);
    540 
    541    if (usePkix < 2) {
    542        if (oidStr) {
    543            fprintf(stderr, "Policy oid(-o) can be used only with"
    544                            " CERT_PKIXVerifyCert(-pp) function.\n");
    545            Usage(progName);
    546        }
    547        if (trusted) {
    548            fprintf(stderr, "Cert trust flag can be used only with"
    549                            " CERT_PKIXVerifyCert(-pp) function.\n");
    550            Usage(progName);
    551        }
    552        if (!onlyTrustAnchors) {
    553            fprintf(stderr, "Cert trust anchor exclusiveness can be"
    554                            " used only with CERT_PKIXVerifyCert(-pp)"
    555                            " function.\n");
    556        }
    557    }
    558 
    559    if (!useDefaultRevFlags && parseRevMethodsAndFlags()) {
    560        fprintf(stderr, "Invalid revocation configuration specified.\n");
    561        goto punt;
    562    }
    563 
    564    /* Set our password function callback. */
    565    PK11_SetPasswordFunc(SECU_GetModulePassword);
    566 
    567    /* Initialize the NSS libraries. */
    568    if (certDir) {
    569        secStatus = NSS_Init(certDir);
    570    } else {
    571        secStatus = NSS_NoDB_Init(NULL);
    572 
    573        /* load the builtins */
    574        SECMOD_AddNewModule("Builtins", DLL_PREFIX "nssckbi." DLL_SUFFIX, 0, 0);
    575    }
    576    if (secStatus != SECSuccess) {
    577        exitErr("NSS_Init");
    578    }
    579    SECU_RegisterDynamicOids();
    580    if (isOCSPEnabled()) {
    581        CERT_EnableOCSPChecking(CERT_GetDefaultCertDB());
    582        CERT_DisableOCSPDefaultResponder(CERT_GetDefaultCertDB());
    583        if (!ocsp_fetchingFailureIsAFailure) {
    584            CERT_SetOCSPFailureMode(ocspMode_FailureIsNotAVerificationFailure);
    585        }
    586    }
    587 
    588    while (status == PL_OPT_OK) {
    589        switch (optstate->option) {
    590            default:
    591                Usage(progName);
    592                break;
    593            case 'a':
    594                isAscii = PR_TRUE;
    595                break;
    596            case 'r':
    597                isAscii = PR_FALSE;
    598                break;
    599            case 't':
    600                trusted = PR_TRUE;
    601                break;
    602            case 0: /* positional parameter */
    603                if (usePkix < 2 && trusted) {
    604                    fprintf(stderr, "Cert trust flag can be used only with"
    605                                    " CERT_PKIXVerifyCert(-pp) function.\n");
    606                    Usage(progName);
    607                }
    608                cert = getCert(optstate->value, isAscii, progName);
    609                if (!cert)
    610                    goto punt;
    611                rememberCert(cert, trusted);
    612                if (!firstCert)
    613                    firstCert = cert;
    614                trusted = PR_FALSE;
    615        }
    616        status = PL_GetNextOpt(optstate);
    617    }
    618    PL_DestroyOptState(optstate);
    619    if (status == PL_OPT_BAD || !firstCert)
    620        Usage(progName);
    621 
    622    /* Initialize log structure */
    623    log.arena = PORT_NewArena(512);
    624    log.head = log.tail = NULL;
    625    log.count = 0;
    626 
    627    do {
    628        if (usePkix < 2) {
    629            /* NOW, verify the cert chain. */
    630            if (usePkix) {
    631                /* Use old API with libpkix validation lib */
    632                CERT_SetUsePKIXForValidation(PR_TRUE);
    633            }
    634            if (!time)
    635                time = PR_Now();
    636 
    637            defaultDB = CERT_GetDefaultCertDB();
    638            secStatus = CERT_VerifyCertificate(defaultDB, firstCert,
    639                                               PR_TRUE /* check sig */,
    640                                               certUsage,
    641                                               time,
    642                                               &pwdata, /* wincx  */
    643                                               &log,    /* error log */
    644                                               NULL);   /* returned usages */
    645        } else
    646            do {
    647                static CERTValOutParam cvout[4];
    648                static CERTValInParam cvin[7];
    649                SECOidTag oidTag;
    650                int inParamIndex = 0;
    651                static PRUint64 revFlagsLeaf[2];
    652                static PRUint64 revFlagsChain[2];
    653                static CERTRevocationFlags rev;
    654 
    655                if (oidStr) {
    656                    PLArenaPool *arena;
    657                    SECOidData od;
    658                    memset(&od, 0, sizeof od);
    659                    od.offset = SEC_OID_UNKNOWN;
    660                    od.desc = "User Defined Policy OID";
    661                    od.mechanism = CKM_INVALID_MECHANISM;
    662                    od.supportedExtension = INVALID_CERT_EXTENSION;
    663 
    664                    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    665                    if (!arena) {
    666                        fprintf(stderr, "out of memory");
    667                        goto punt;
    668                    }
    669 
    670                    secStatus = SEC_StringToOID(arena, &od.oid, oidStr, 0);
    671                    if (secStatus != SECSuccess) {
    672                        PORT_FreeArena(arena, PR_FALSE);
    673                        fprintf(stderr, "Can not encode oid: %s(%s)\n", oidStr,
    674                                SECU_Strerror(PORT_GetError()));
    675                        break;
    676                    }
    677 
    678                    oidTag = SECOID_AddEntry(&od);
    679                    PORT_FreeArena(arena, PR_FALSE);
    680                    if (oidTag == SEC_OID_UNKNOWN) {
    681                        fprintf(stderr, "Can not add new oid to the dynamic "
    682                                        "table: %s\n",
    683                                oidStr);
    684                        secStatus = SECFailure;
    685                        break;
    686                    }
    687 
    688                    cvin[inParamIndex].type = cert_pi_policyOID;
    689                    cvin[inParamIndex].value.arraySize = 1;
    690                    cvin[inParamIndex].value.array.oids = &oidTag;
    691 
    692                    inParamIndex++;
    693                }
    694 
    695                if (trustedCertList) {
    696                    cvin[inParamIndex].type = cert_pi_trustAnchors;
    697                    cvin[inParamIndex].value.pointer.chain = trustedCertList;
    698 
    699                    inParamIndex++;
    700                }
    701 
    702                cvin[inParamIndex].type = cert_pi_useAIACertFetch;
    703                cvin[inParamIndex].value.scalar.b = certFetching;
    704                inParamIndex++;
    705 
    706                rev.leafTests.cert_rev_flags_per_method = revFlagsLeaf;
    707                rev.chainTests.cert_rev_flags_per_method = revFlagsChain;
    708                secStatus = configureRevocationParams(&rev);
    709                if (secStatus) {
    710                    fprintf(stderr, "Can not config revocation parameters ");
    711                    break;
    712                }
    713 
    714                cvin[inParamIndex].type = cert_pi_revocationFlags;
    715                cvin[inParamIndex].value.pointer.revocation = &rev;
    716                inParamIndex++;
    717 
    718                if (time) {
    719                    cvin[inParamIndex].type = cert_pi_date;
    720                    cvin[inParamIndex].value.scalar.time = time;
    721                    inParamIndex++;
    722                }
    723 
    724                if (!onlyTrustAnchors) {
    725                    cvin[inParamIndex].type = cert_pi_useOnlyTrustAnchors;
    726                    cvin[inParamIndex].value.scalar.b = onlyTrustAnchors;
    727                    inParamIndex++;
    728                }
    729 
    730                cvin[inParamIndex].type = cert_pi_end;
    731 
    732                cvout[0].type = cert_po_trustAnchor;
    733                cvout[0].value.pointer.cert = NULL;
    734                cvout[1].type = cert_po_certList;
    735                cvout[1].value.pointer.chain = NULL;
    736 
    737                /* setting pointer to CERTVerifyLog. Initialized structure
    738                 * will be used CERT_PKIXVerifyCert */
    739                cvout[2].type = cert_po_errorLog;
    740                cvout[2].value.pointer.log = &log;
    741 
    742                cvout[3].type = cert_po_end;
    743 
    744                secStatus = CERT_PKIXVerifyCert(firstCert, certUsage,
    745                                                cvin, cvout, &pwdata);
    746                if (secStatus != SECSuccess) {
    747                    break;
    748                }
    749                issuerCert = cvout[0].value.pointer.cert;
    750                builtChain = cvout[1].value.pointer.chain;
    751            } while (0);
    752 
    753        /* Display validation results */
    754        if (secStatus != SECSuccess || log.count > 0) {
    755            CERTVerifyLogNode *node = NULL;
    756            fprintf(stderr, "Chain is bad!\n");
    757 
    758            SECU_displayVerifyLog(stderr, &log, verbose);
    759            /* Have cert refs in the log only in case of failure.
    760             * Destroy them. */
    761            for (node = log.head; node; node = node->next) {
    762                if (node->cert)
    763                    CERT_DestroyCertificate(node->cert);
    764            }
    765            log.head = log.tail = NULL;
    766            log.count = 0;
    767            rv = 1;
    768        } else {
    769            fprintf(stderr, "Chain is good!\n");
    770            if (issuerCert) {
    771                if (verbose > 1) {
    772                    rv = SEC_PrintCertificateAndTrust(issuerCert, "Root Certificate",
    773                                                      NULL);
    774                    if (rv != SECSuccess) {
    775                        SECU_PrintError(progName, "problem printing certificate");
    776                    }
    777                } else if (verbose > 0) {
    778                    SECU_PrintName(stdout, &issuerCert->subject, "Root "
    779                                                                 "Certificate Subject:",
    780                                   0);
    781                }
    782                CERT_DestroyCertificate(issuerCert);
    783            }
    784            if (builtChain) {
    785                CERTCertListNode *node;
    786                int count = 0;
    787                char buff[256];
    788 
    789                if (verbose) {
    790                    for (node = CERT_LIST_HEAD(builtChain); !CERT_LIST_END(node, builtChain);
    791                         node = CERT_LIST_NEXT(node), count++) {
    792                        snprintf(buff, sizeof(buff), "Certificate %d Subject", count + 1);
    793                        SECU_PrintName(stdout, &node->cert->subject, buff, 0);
    794                    }
    795                }
    796                CERT_DestroyCertList(builtChain);
    797            }
    798            rv = 0;
    799        }
    800    } while (--vfyCounts > 0);
    801 
    802    /* Need to destroy CERTVerifyLog arena at the end */
    803    PORT_FreeArena(log.arena, PR_FALSE);
    804 
    805 punt:
    806    forgetCerts();
    807    if (NSS_Shutdown() != SECSuccess) {
    808        SECU_PrintError(progName, "NSS_Shutdown");
    809        rv = 1;
    810    }
    811    PORT_Free(progName);
    812    PORT_Free(certDir);
    813    PORT_Free(oidStr);
    814    freeRevocationMethodData();
    815    if (pwdata.data) {
    816        PORT_Free(pwdata.data);
    817    }
    818    PL_ArenaFinish();
    819    PR_Cleanup();
    820    return rv;
    821 }