diff options
Diffstat (limited to 'security/nss/cmd/nss-policy-check/nss-policy-check.c')
-rw-r--r-- | security/nss/cmd/nss-policy-check/nss-policy-check.c | 305 |
1 files changed, 305 insertions, 0 deletions
diff --git a/security/nss/cmd/nss-policy-check/nss-policy-check.c b/security/nss/cmd/nss-policy-check/nss-policy-check.c new file mode 100644 index 0000000000..b806dfba64 --- /dev/null +++ b/security/nss/cmd/nss-policy-check/nss-policy-check.c @@ -0,0 +1,305 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* This program can be used to check the validity of a NSS crypto policy + * configuration file, specified using a config= line. + * + * Exit codes: + * failure: 2 + * warning: 1 + * success: 0 + */ + +#include <limits.h> +#include <errno.h> +#include <stdio.h> +#include "utilparst.h" +#include "nss.h" +#include "secport.h" +#include "secutil.h" +#include "secmod.h" +#include "ssl.h" +#include "prenv.h" +#include "plgetopt.h" + +const char *sWarn = "WARN"; +const char *sInfo = "INFO"; + +void +get_tls_info(SSLProtocolVariant protocolVariant, const char *display) +{ + SSLVersionRange vrange_supported, vrange_enabled; + unsigned num_enabled = 0; + PRBool failed = PR_FALSE; + + /* We assume SSL v2 is inactive, and therefore SSL_VersionRangeGetDefault + * gives complete information. */ + if ((SSL_VersionRangeGetSupported(protocolVariant, &vrange_supported) != SECSuccess) || + (SSL_VersionRangeGetDefault(protocolVariant, &vrange_enabled) != SECSuccess) || + !vrange_enabled.min || + !vrange_enabled.max || + vrange_enabled.max < vrange_supported.min || + vrange_enabled.min > vrange_supported.max) { + failed = PR_TRUE; + } else { + if (vrange_enabled.min < vrange_supported.min) { + vrange_enabled.min = vrange_supported.min; + } + if (vrange_enabled.max > vrange_supported.max) { + vrange_enabled.max = vrange_supported.max; + } + if (vrange_enabled.min > vrange_enabled.max) { + failed = PR_TRUE; + } + } + if (failed) { + num_enabled = 0; + } else { + num_enabled = vrange_enabled.max - vrange_enabled.min + 1; + } + fprintf(stderr, "NSS-POLICY-%s: NUMBER-OF-%s-VERSIONS: %u\n", + num_enabled ? sInfo : sWarn, display, num_enabled); + if (!num_enabled) { + PR_SetEnv("NSS_POLICY_WARN=1"); + } +} + +#ifndef PATH_MAX +#define PATH_MAX 1024 +#endif + +/* private flags for policy check; should be in sync with pk11wrap/pk11pars.c */ +#define SECMOD_FLAG_POLICY_CHECK_IDENTIFIER 0x01 +#define SECMOD_FLAG_POLICY_CHECK_VALUE 0x02 + +static void +printUsage(const char *progName) +{ + fprintf(stderr, + "Usage: %s [options] <path-to-policy-file>\n" + "\tWhere options are:\n" + "\t-f flag\t Set policy check flag (can be specified multiple times)\n" + "\t \t Possible flags: \"identifier\" or \"value\"\n", + progName); +} + +int +main(int argc, char **argv) +{ + const PRUint16 *cipherSuites = SSL_ImplementedCiphers; + int i; + SECStatus rv; + SECMODModule *module = NULL; + char path[PATH_MAX]; + const char *filename; + char moduleSpec[1024 + PATH_MAX]; + unsigned num_enabled = 0; + int result = 0; + char *flags = NULL; + PLOptState *optstate = NULL; + PLOptStatus status; + char *fullPath = NULL; + int fullPathLen; + char *progName = NULL; + PRUint32 policyCheckFlags = 0; + + progName = PORT_Strdup(argv[0]); + if (!progName) { + result = 2; + goto loser_no_shutdown; + } + + /* Use PL_CreateOptState as SECU_ParseCommandLine ignores + * positional parameters */ + optstate = PL_CreateOptState(argc, argv, "f:"); + if (!optstate) { + result = 2; + goto loser_no_shutdown; + } + while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { + switch (optstate->option) { + case 0: /* positional parameter */ + fullPath = PL_strdup(optstate->value); + if (!fullPath) { + result = 2; + goto loser_no_shutdown; + } + goto breakout; + case 'f': + if (!PORT_Strcmp(optstate->value, "identifier")) { + policyCheckFlags |= SECMOD_FLAG_POLICY_CHECK_IDENTIFIER; + } else if (!PORT_Strcmp(optstate->value, "value")) { + policyCheckFlags |= SECMOD_FLAG_POLICY_CHECK_VALUE; + } else { + fprintf(stderr, "not a valid flag: %s\n", optstate->value); + printUsage(progName); + result = 2; + goto loser_no_shutdown; + } + break; + default: + printUsage(progName); + result = 2; + goto loser_no_shutdown; + } + } +breakout: + if (status != PL_OPT_OK || !fullPath) { + printUsage(progName); + result = 2; + goto loser_no_shutdown; + } + + fullPathLen = strlen(fullPath); + + if (!fullPathLen || PR_Access(fullPath, PR_ACCESS_READ_OK) != PR_SUCCESS) { + fprintf(stderr, "Error: cannot read file %s\n", fullPath); + result = 2; + goto loser_no_shutdown; + } + + if (fullPathLen >= PATH_MAX) { + fprintf(stderr, "Error: filename parameter is too long\n"); + result = 2; + goto loser_no_shutdown; + } + + path[0] = 0; + filename = fullPath + fullPathLen - 1; + while ((filename > fullPath) && (*filename != NSSUTIL_PATH_SEPARATOR[0])) { + filename--; + } + + if (filename == fullPath) { + PORT_Strcpy(path, "."); + } else { + filename++; /* Go past the path separator. */ + PORT_Strncat(path, fullPath, (filename - fullPath)); + } + + PR_SetEnv("NSS_IGNORE_SYSTEM_POLICY=1"); + rv = NSS_NoDB_Init(NULL); + if (rv != SECSuccess) { + fprintf(stderr, "NSS_Init failed: %s\n", PORT_ErrorToString(PR_GetError())); + result = 2; + goto loser_no_shutdown; + } + + PR_SetEnv("NSS_POLICY_LOADED=0"); + PR_SetEnv("NSS_POLICY_FAIL=0"); + PR_SetEnv("NSS_POLICY_WARN=0"); + + flags = PORT_Strdup("internal,moduleDB,skipFirst,moduleDBOnly,critical,printPolicyFeedback"); + if (!flags) { + result = 2; + goto loser_no_shutdown; + } + + if (policyCheckFlags & SECMOD_FLAG_POLICY_CHECK_IDENTIFIER) { + char *newflags; + + newflags = PORT_Realloc(flags, strlen(flags) + strlen(",policyCheckIdentifier") + 1); + if (!newflags) { + result = 2; + goto loser_no_shutdown; + } + flags = newflags; + PORT_Strcat(flags, ",policyCheckIdentifier"); + } + + if (policyCheckFlags & SECMOD_FLAG_POLICY_CHECK_VALUE) { + char *newflags; + + newflags = PORT_Realloc(flags, strlen(flags) + strlen(",policyCheckValue") + 1); + if (!newflags) { + result = 2; + goto loser_no_shutdown; + } + flags = newflags; + PORT_Strcat(flags, ",policyCheckValue"); + } + + snprintf(moduleSpec, sizeof(moduleSpec), + "name=\"Policy File\" " + "parameters=\"configdir='sql:%s' " + "secmod='%s' " + "flags=readOnly,noCertDB,forceSecmodChoice,forceOpen\" " + "NSS=\"flags=%s\"", + path, filename, flags); + + module = SECMOD_LoadModule(moduleSpec, NULL, PR_TRUE); + if (!module || !module->loaded || atoi(PR_GetEnvSecure("NSS_POLICY_LOADED")) != 1) { + fprintf(stderr, "Error: failed to load policy file\n"); + result = 2; + goto loser; + } + + rv = SSL_OptionSetDefault(SSL_SECURITY, PR_TRUE); + if (rv != SECSuccess) { + fprintf(stderr, "enable SSL_SECURITY failed: %s\n", PORT_ErrorToString(PR_GetError())); + result = 2; + goto loser; + } + + for (i = 0; i < SSL_NumImplementedCiphers; i++) { + PRUint16 suite = cipherSuites[i]; + PRBool enabled; + SSLCipherSuiteInfo info; + + rv = SSL_CipherPrefGetDefault(suite, &enabled); + if (rv != SECSuccess) { + fprintf(stderr, + "SSL_CipherPrefGetDefault didn't like value 0x%04x (i = %d): %s\n", + suite, i, PORT_ErrorToString(PR_GetError())); + continue; + } + rv = SSL_GetCipherSuiteInfo(suite, &info, (int)(sizeof info)); + if (rv != SECSuccess) { + fprintf(stderr, + "SSL_GetCipherSuiteInfo didn't like value 0x%04x (i = %d): %s\n", + suite, i, PORT_ErrorToString(PR_GetError())); + continue; + } + if (enabled) { + ++num_enabled; + fprintf(stderr, "NSS-POLICY-INFO: ciphersuite %s is enabled\n", info.cipherSuiteName); + } + } + fprintf(stderr, "NSS-POLICY-%s: NUMBER-OF-CIPHERSUITES: %u\n", num_enabled ? sInfo : sWarn, num_enabled); + if (!num_enabled) { + PR_SetEnv("NSS_POLICY_WARN=1"); + } + + get_tls_info(ssl_variant_stream, "TLS"); + get_tls_info(ssl_variant_datagram, "DTLS"); + + if (atoi(PR_GetEnvSecure("NSS_POLICY_FAIL")) != 0) { + result = 2; + } else if (atoi(PR_GetEnvSecure("NSS_POLICY_WARN")) != 0) { + result = 1; + } + +loser: + if (module) { + SECMOD_DestroyModule(module); + } + rv = NSS_Shutdown(); + if (rv != SECSuccess) { + fprintf(stderr, "NSS_Shutdown failed: %s\n", PORT_ErrorToString(PR_GetError())); + result = 2; + } +loser_no_shutdown: + if (optstate) { + PL_DestroyOptState(optstate); + } + PORT_Free(flags); + PORT_Free(progName); + PORT_Free(fullPath); + if (result == 2) { + fprintf(stderr, "NSS-POLICY-FAIL\n"); + } else if (result == 1) { + fprintf(stderr, "NSS-POLICY-WARN\n"); + } + return result; +} |