tor-browser

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

nss-policy-check.c (9409B)


      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 /* This program can be used to check the validity of a NSS crypto policy
      6 * configuration file, specified using a config= line.
      7 *
      8 * Exit codes:
      9 *  failure: 2
     10 *  warning: 1
     11 *  success: 0
     12 */
     13 
     14 #include <limits.h>
     15 #include <errno.h>
     16 #include <stdio.h>
     17 #include "utilparst.h"
     18 #include "nss.h"
     19 #include "secport.h"
     20 #include "secutil.h"
     21 #include "secmod.h"
     22 #include "ssl.h"
     23 #include "prenv.h"
     24 #include "plgetopt.h"
     25 
     26 const char *sWarn = "WARN";
     27 const char *sInfo = "INFO";
     28 
     29 void
     30 get_tls_info(SSLProtocolVariant protocolVariant, const char *display)
     31 {
     32    SSLVersionRange vrange_supported, vrange_enabled;
     33    unsigned num_enabled = 0;
     34    PRBool failed = PR_FALSE;
     35 
     36    /* We assume SSL v2 is inactive, and therefore SSL_VersionRangeGetDefault
     37     * gives complete information. */
     38    if ((SSL_VersionRangeGetSupported(protocolVariant, &vrange_supported) != SECSuccess) ||
     39        (SSL_VersionRangeGetDefault(protocolVariant, &vrange_enabled) != SECSuccess) ||
     40        !vrange_enabled.min ||
     41        !vrange_enabled.max ||
     42        vrange_enabled.max < vrange_supported.min ||
     43        vrange_enabled.min > vrange_supported.max) {
     44        failed = PR_TRUE;
     45    } else {
     46        if (vrange_enabled.min < vrange_supported.min) {
     47            vrange_enabled.min = vrange_supported.min;
     48        }
     49        if (vrange_enabled.max > vrange_supported.max) {
     50            vrange_enabled.max = vrange_supported.max;
     51        }
     52        if (vrange_enabled.min > vrange_enabled.max) {
     53            failed = PR_TRUE;
     54        }
     55    }
     56    if (failed) {
     57        num_enabled = 0;
     58    } else {
     59        num_enabled = vrange_enabled.max - vrange_enabled.min + 1;
     60    }
     61    fprintf(stderr, "NSS-POLICY-%s: NUMBER-OF-%s-VERSIONS: %u\n",
     62            num_enabled ? sInfo : sWarn, display, num_enabled);
     63    if (!num_enabled) {
     64        PR_SetEnv("NSS_POLICY_WARN=1");
     65    }
     66 }
     67 
     68 #ifndef PATH_MAX
     69 #define PATH_MAX 1024
     70 #endif
     71 
     72 /* private flags for policy check; should be in sync with pk11wrap/pk11pars.c */
     73 #define SECMOD_FLAG_POLICY_CHECK_IDENTIFIER 0x01
     74 #define SECMOD_FLAG_POLICY_CHECK_VALUE 0x02
     75 
     76 static void
     77 printUsage(const char *progName)
     78 {
     79    fprintf(stderr,
     80            "Usage: %s [options] <path-to-policy-file>\n"
     81            "\tWhere options are:\n"
     82            "\t-f flag\t Set policy check flag (can be specified multiple times)\n"
     83            "\t       \t Possible flags: \"identifier\" or \"value\"\n",
     84            progName);
     85 }
     86 
     87 int
     88 main(int argc, char **argv)
     89 {
     90    const PRUint16 *cipherSuites = SSL_ImplementedCiphers;
     91    int i;
     92    SECStatus rv;
     93    SECMODModule *module = NULL;
     94    char path[PATH_MAX];
     95    const char *filename;
     96    char moduleSpec[1024 + PATH_MAX];
     97    unsigned num_enabled = 0;
     98    int result = 0;
     99    char *flags = NULL;
    100    PLOptState *optstate = NULL;
    101    PLOptStatus status;
    102    char *fullPath = NULL;
    103    int fullPathLen;
    104    char *progName = NULL;
    105    PRUint32 policyCheckFlags = 0;
    106 
    107    progName = PORT_Strdup(argv[0]);
    108    if (!progName) {
    109        result = 2;
    110        goto loser_no_shutdown;
    111    }
    112 
    113    /* Use PL_CreateOptState as SECU_ParseCommandLine ignores
    114     * positional parameters */
    115    optstate = PL_CreateOptState(argc, argv, "f:");
    116    if (!optstate) {
    117        result = 2;
    118        goto loser_no_shutdown;
    119    }
    120    while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
    121        switch (optstate->option) {
    122            case 0: /* positional parameter */
    123                fullPath = PL_strdup(optstate->value);
    124                if (!fullPath) {
    125                    result = 2;
    126                    goto loser_no_shutdown;
    127                }
    128                goto breakout;
    129            case 'f':
    130                if (!PORT_Strcmp(optstate->value, "identifier")) {
    131                    policyCheckFlags |= SECMOD_FLAG_POLICY_CHECK_IDENTIFIER;
    132                } else if (!PORT_Strcmp(optstate->value, "value")) {
    133                    policyCheckFlags |= SECMOD_FLAG_POLICY_CHECK_VALUE;
    134                } else {
    135                    fprintf(stderr, "not a valid flag: %s\n", optstate->value);
    136                    printUsage(progName);
    137                    result = 2;
    138                    goto loser_no_shutdown;
    139                }
    140                break;
    141            default:
    142                printUsage(progName);
    143                result = 2;
    144                goto loser_no_shutdown;
    145        }
    146    }
    147 breakout:
    148    if (status != PL_OPT_OK || !fullPath) {
    149        printUsage(progName);
    150        result = 2;
    151        goto loser_no_shutdown;
    152    }
    153 
    154    fullPathLen = strlen(fullPath);
    155 
    156    if (!fullPathLen || PR_Access(fullPath, PR_ACCESS_READ_OK) != PR_SUCCESS) {
    157        fprintf(stderr, "Error: cannot read file %s\n", fullPath);
    158        result = 2;
    159        goto loser_no_shutdown;
    160    }
    161 
    162    if (fullPathLen >= PATH_MAX) {
    163        fprintf(stderr, "Error: filename parameter is too long\n");
    164        result = 2;
    165        goto loser_no_shutdown;
    166    }
    167 
    168    path[0] = 0;
    169    filename = fullPath + fullPathLen - 1;
    170    while ((filename > fullPath) && (*filename != NSSUTIL_PATH_SEPARATOR[0])) {
    171        filename--;
    172    }
    173 
    174    if (filename == fullPath) {
    175        PORT_Strcpy(path, ".");
    176    } else {
    177        filename++; /* Go past the path separator. */
    178        PORT_Strncat(path, fullPath, (filename - fullPath));
    179    }
    180 
    181    PR_SetEnv("NSS_IGNORE_SYSTEM_POLICY=1");
    182    rv = NSS_NoDB_Init(NULL);
    183    if (rv != SECSuccess) {
    184        fprintf(stderr, "NSS_Init failed: %s\n", PORT_ErrorToString(PR_GetError()));
    185        result = 2;
    186        goto loser_no_shutdown;
    187    }
    188 
    189    PR_SetEnv("NSS_POLICY_LOADED=0");
    190    PR_SetEnv("NSS_POLICY_FAIL=0");
    191    PR_SetEnv("NSS_POLICY_WARN=0");
    192 
    193    flags = PORT_Strdup("internal,moduleDB,skipFirst,moduleDBOnly,critical,printPolicyFeedback");
    194    if (!flags) {
    195        result = 2;
    196        goto loser_no_shutdown;
    197    }
    198 
    199    if (policyCheckFlags & SECMOD_FLAG_POLICY_CHECK_IDENTIFIER) {
    200        char *newflags;
    201 
    202        newflags = PORT_Realloc(flags, strlen(flags) + strlen(",policyCheckIdentifier") + 1);
    203        if (!newflags) {
    204            result = 2;
    205            goto loser_no_shutdown;
    206        }
    207        flags = newflags;
    208        PORT_Strcat(flags, ",policyCheckIdentifier");
    209    }
    210 
    211    if (policyCheckFlags & SECMOD_FLAG_POLICY_CHECK_VALUE) {
    212        char *newflags;
    213 
    214        newflags = PORT_Realloc(flags, strlen(flags) + strlen(",policyCheckValue") + 1);
    215        if (!newflags) {
    216            result = 2;
    217            goto loser_no_shutdown;
    218        }
    219        flags = newflags;
    220        PORT_Strcat(flags, ",policyCheckValue");
    221    }
    222 
    223    snprintf(moduleSpec, sizeof(moduleSpec),
    224             "name=\"Policy File\" "
    225             "parameters=\"configdir='sql:%s' "
    226             "secmod='%s' "
    227             "flags=readOnly,noCertDB,forceSecmodChoice,forceOpen\" "
    228             "NSS=\"flags=%s\"",
    229             path, filename, flags);
    230 
    231    module = SECMOD_LoadModule(moduleSpec, NULL, PR_TRUE);
    232    if (!module || !module->loaded || atoi(PR_GetEnvSecure("NSS_POLICY_LOADED")) != 1) {
    233        fprintf(stderr, "Error: failed to load policy file\n");
    234        result = 2;
    235        goto loser;
    236    }
    237 
    238    rv = SSL_OptionSetDefault(SSL_SECURITY, PR_TRUE);
    239    if (rv != SECSuccess) {
    240        fprintf(stderr, "enable SSL_SECURITY failed: %s\n", PORT_ErrorToString(PR_GetError()));
    241        result = 2;
    242        goto loser;
    243    }
    244 
    245    for (i = 0; i < SSL_NumImplementedCiphers; i++) {
    246        PRUint16 suite = cipherSuites[i];
    247        PRBool enabled;
    248        SSLCipherSuiteInfo info;
    249 
    250        rv = SSL_CipherPrefGetDefault(suite, &enabled);
    251        if (rv != SECSuccess) {
    252            fprintf(stderr,
    253                    "SSL_CipherPrefGetDefault didn't like value 0x%04x (i = %d): %s\n",
    254                    suite, i, PORT_ErrorToString(PR_GetError()));
    255            continue;
    256        }
    257        rv = SSL_GetCipherSuiteInfo(suite, &info, (int)(sizeof info));
    258        if (rv != SECSuccess) {
    259            fprintf(stderr,
    260                    "SSL_GetCipherSuiteInfo didn't like value 0x%04x (i = %d): %s\n",
    261                    suite, i, PORT_ErrorToString(PR_GetError()));
    262            continue;
    263        }
    264        if (enabled) {
    265            ++num_enabled;
    266            fprintf(stderr, "NSS-POLICY-INFO: ciphersuite %s is enabled\n", info.cipherSuiteName);
    267        }
    268    }
    269    fprintf(stderr, "NSS-POLICY-%s: NUMBER-OF-CIPHERSUITES: %u\n", num_enabled ? sInfo : sWarn, num_enabled);
    270    if (!num_enabled) {
    271        PR_SetEnv("NSS_POLICY_WARN=1");
    272    }
    273 
    274    get_tls_info(ssl_variant_stream, "TLS");
    275    get_tls_info(ssl_variant_datagram, "DTLS");
    276 
    277    if (atoi(PR_GetEnvSecure("NSS_POLICY_FAIL")) != 0) {
    278        result = 2;
    279    } else if (atoi(PR_GetEnvSecure("NSS_POLICY_WARN")) != 0) {
    280        result = 1;
    281    }
    282 
    283 loser:
    284    if (module) {
    285        SECMOD_DestroyModule(module);
    286    }
    287    rv = NSS_Shutdown();
    288    if (rv != SECSuccess) {
    289        fprintf(stderr, "NSS_Shutdown failed: %s\n", PORT_ErrorToString(PR_GetError()));
    290        result = 2;
    291    }
    292 loser_no_shutdown:
    293    if (optstate) {
    294        PL_DestroyOptState(optstate);
    295    }
    296    PORT_Free(flags);
    297    PORT_Free(progName);
    298    PORT_Free(fullPath);
    299    if (result == 2) {
    300        fprintf(stderr, "NSS-POLICY-FAIL\n");
    301    } else if (result == 1) {
    302        fprintf(stderr, "NSS-POLICY-WARN\n");
    303    }
    304    return result;
    305 }