Commit d2f0b46f authored by Kai Engert's avatar Kai Engert

Bug 1474887, nss-policy-check: a tool to check a NSS policy configuration for errors, r=rrelyea

parent ff9d194a
1 Added function:
'function char* NSSUTIL_AddNSSFlagToModuleSpec(char*, char*)' {NSSUTIL_AddNSSFlagToModuleSpec@@NSSUTIL_3.39}
......@@ -928,6 +928,9 @@ function scheduleTests(task_build, task_cert, test_base) {
queue.scheduleTask(merge(no_cert_base, {
name: "SDR tests", symbol: "SDR", tests: "sdr"
}));
queue.scheduleTask(merge(no_cert_base, {
name: "Policy tests", symbol: "Policy", tests: "policy"
}));
// Schedule tests that need certificates.
let cert_base = merge(test_base, {parent: task_cert});
......
......@@ -37,7 +37,7 @@ function parseOptions(opts) {
let aliases = {"gtests": "gtest"};
let allUnitTests = ["bogo", "crmf", "chains", "cipher", "db", "ec", "fips",
"gtest", "interop", "lowhash", "merge", "sdr", "smime", "tools",
"ssl", "mpi", "scert", "spki"];
"ssl", "mpi", "scert", "spki", "policy"];
let unittests = intersect(opts.unittests.split(/\s*,\s*/).map(t => {
return aliases[t] || t;
}), allUnitTests);
......
......@@ -47,6 +47,7 @@ NSS_SRCDIRS = \
listsuites \
makepqg \
multinit \
nss-policy-check \
ocspclnt \
ocspresp \
oidcalc \
......
#! gmake
#
# 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/.
#######################################################################
# (1) Include initial platform-independent assignments (MANDATORY). #
#######################################################################
include manifest.mn
#######################################################################
# (2) Include "global" configuration information. (OPTIONAL) #
#######################################################################
include $(CORE_DEPTH)/coreconf/config.mk
#######################################################################
# (3) Include "component" configuration information. (OPTIONAL) #
#######################################################################
#######################################################################
# (4) Include "local" platform-dependent assignments (OPTIONAL). #
#######################################################################
include ../platlibs.mk
#######################################################################
# (5) Execute "global" rules. (OPTIONAL) #
#######################################################################
include $(CORE_DEPTH)/coreconf/rules.mk
#######################################################################
# (6) Execute "component" rules. (OPTIONAL) #
#######################################################################
#######################################################################
# (7) Execute "local" rules. (OPTIONAL). #
#######################################################################
include ../platrules.mk
#
# 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/.
CORE_DEPTH = ../..
MODULE = nss
CSRCS = nss-policy-check.c
REQUIRES = seccmd
PROGRAM = nss-policy-check
/* 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"
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
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;
int fullPathLen;
if (argc != 2) {
fprintf(stderr, "Syntax: nss-policy-check <path-to-policy-file>\n");
result = 2;
goto loser;
}
fullPathLen = strlen(argv[1]);
if (!fullPathLen || PR_Access(argv[1], PR_ACCESS_READ_OK) != PR_SUCCESS) {
fprintf(stderr, "Error: cannot read file %s\n", argv[1]);
result = 2;
goto loser;
}
if (fullPathLen >= PATH_MAX) {
fprintf(stderr, "Error: filename parameter is too long\n");
result = 2;
goto loser;
}
path[0] = 0;
filename = argv[1] + fullPathLen - 1;
while ((filename > argv[1]) && (*filename != NSSUTIL_PATH_SEPARATOR[0])) {
filename--;
}
if (filename == argv[1]) {
PORT_Strcpy(path, ".");
} else {
filename++; /* Go past the path separator. */
PORT_Strncat(path, argv[1], (filename - argv[1]));
}
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;
}
PR_SetEnv("NSS_POLICY_LOADED=0");
PR_SetEnv("NSS_POLICY_FAIL=0");
PR_SetEnv("NSS_POLICY_WARN=0");
sprintf(moduleSpec,
"name=\"Policy File\" "
"parameters=\"configdir='sql:%s' "
"secmod='%s' "
"flags=readOnly,noCertDB,forceSecmodChoice,forceOpen\" "
"NSS=\"flags=internal,moduleDB,skipFirst,moduleDBOnly,critical,printPolicyFeedback\"",
path, filename);
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;
}
if (result == 2) {
fprintf(stderr, "NSS-POLICY-FAIL\n");
} else if (result == 1) {
fprintf(stderr, "NSS-POLICY-WARN\n");
}
return result;
}
# 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/.
{
'includes': [
'../../coreconf/config.gypi',
'../../cmd/platlibs.gypi'
],
'targets': [
{
'target_name': 'nss-policy-check',
'type': 'executable',
'sources': [
'nss-policy-check.c'
],
'dependencies': [
'<(DEPTH)/exports.gyp:nss_exports'
]
}
],
'variables': {
'module': 'nss'
}
}
\ No newline at end of file
......@@ -54,7 +54,7 @@ nss_mktemp(char *path)
#define NSS_MAX_FLAG_SIZE sizeof("readOnly") + sizeof("noCertDB") + \
sizeof("noModDB") + sizeof("forceOpen") + sizeof("passwordRequired") + \
sizeof("optimizeSpace")
sizeof("optimizeSpace") + sizeof("printPolicyFeedback")
#define NSS_DEFAULT_MOD_NAME "NSS Internal Module"
static char *
......
This diff is collapsed.
......@@ -328,3 +328,9 @@ SECITEM_MakeItem;
;+ local:
;+ *;
;+};
;+NSSUTIL_3.39 { # NSS Utilities 3.39 release
;+ global:
NSSUTIL_AddNSSFlagToModuleSpec;
;+ local:
;+ *;
;+};
......@@ -913,6 +913,92 @@ NSSUTIL_MkModuleSpec(char *dllName, char *commonName, char *parameters,
return NSSUTIL_MkModuleSpecEx(dllName, commonName, parameters, NSS, NULL);
}
/************************************************************************
* add a single flag to the Flags= section inside the spec's NSS= section */
char *
NSSUTIL_AddNSSFlagToModuleSpec(char *spec, char *addFlag)
{
const char *prefix = "flags=";
const size_t prefixLen = strlen(prefix);
char *lib = NULL, *name = NULL, *param = NULL, *nss = NULL, *conf = NULL;
char *nss2 = NULL, *result = NULL;
SECStatus rv;
rv = NSSUTIL_ArgParseModuleSpecEx(spec, &lib, &name, &param, &nss, &conf);
if (rv != SECSuccess) {
return NULL;
}
if (nss && NSSUTIL_ArgHasFlag("flags", addFlag, nss)) {
/* It's already there, nothing to do! */
PORT_Free(lib);
PORT_Free(name);
PORT_Free(param);
PORT_Free(nss);
PORT_Free(conf);
return PORT_Strdup(spec);
}
if (!nss || !strlen(nss)) {
nss2 = PORT_Alloc(prefixLen + strlen(addFlag) + 1);
PORT_Strcpy(nss2, prefix);
PORT_Strcat(nss2, addFlag);
} else {
const char *iNss = nss;
PRBool alreadyAdded = PR_FALSE;
size_t maxSize = strlen(nss) + strlen(addFlag) + prefixLen + 2; /* space and null terminator */
nss2 = PORT_Alloc(maxSize);
*nss2 = 0;
while (*iNss) {
iNss = NSSUTIL_ArgStrip(iNss);
if (PORT_Strncasecmp(iNss, prefix, prefixLen) == 0) {
/* We found an existing Flags= section. */
char *oldFlags;
const char *valPtr;
int valSize;
valPtr = iNss + prefixLen;
oldFlags = NSSUTIL_ArgFetchValue(valPtr, &valSize);
iNss = valPtr + valSize;
PORT_Strcat(nss2, prefix);
PORT_Strcat(nss2, oldFlags);
PORT_Strcat(nss2, ",");
PORT_Strcat(nss2, addFlag);
PORT_Strcat(nss2, " ");
PORT_Free(oldFlags);
alreadyAdded = PR_TRUE;
iNss = NSSUTIL_ArgStrip(iNss);
PORT_Strcat(nss2, iNss); /* remainder of input */
break;
} else {
/* Append this other name=value pair and continue. */
const char *startOfNext = NSSUTIL_ArgSkipParameter(iNss);
PORT_Strncat(nss2, iNss, (startOfNext - iNss));
if (nss2[strlen(nss2) - 1] != ' ') {
PORT_Strcat(nss2, " ");
}
iNss = startOfNext;
}
iNss = NSSUTIL_ArgStrip(iNss);
}
if (!alreadyAdded) {
/* nss wasn't empty, and it didn't contain a Flags section. We can
* assume that other content from nss has already been added to
* nss2, which means we already have a trailing space separator. */
PORT_Strcat(nss2, prefix);
PORT_Strcat(nss2, addFlag);
}
}
result = NSSUTIL_MkModuleSpecEx(lib, name, param, nss2, conf);
PORT_Free(lib);
PORT_Free(name);
PORT_Free(param);
PORT_Free(nss);
PORT_Free(nss2);
PORT_Free(conf);
return result;
}
#define NSSUTIL_ARG_FORTEZZA_FLAG "FORTEZZA"
/******************************************************************************
* Parse the cipher flags from the NSS parameter
......
......@@ -46,6 +46,7 @@ char *NSSUTIL_MkModuleSpec(char *dllName, char *commonName,
char *parameters, char *NSS);
char *NSSUTIL_MkModuleSpecEx(char *dllName, char *commonName,
char *parameters, char *NSS, char *config);
char *NSSUTIL_AddNSSFlagToModuleSpec(char *spec, char *addFlag);
void NSSUTIL_ArgParseCipherFlags(unsigned long *newCiphers,
const char *cipherList);
char *NSSUTIL_MkNSSString(char **slotStrings, int slotCount, PRBool internal,
......
......@@ -247,7 +247,7 @@ def parse_arguments():
tests = [
"cipher", "lowhash", "chains", "cert", "dbtests", "tools", "fips",
"sdr", "crmf", "smime", "ssl", "ocsp", "merge", "pkits", "ec",
"gtests", "ssl_gtests", "bogo", "interop"
"gtests", "ssl_gtests", "bogo", "interop", "policy"
]
parser_test.add_argument(
'test', choices=tests, help="Available tests", action=testAction)
......
......@@ -135,6 +135,7 @@
'cmd/listsuites/listsuites.gyp:listsuites',
'cmd/makepqg/makepqg.gyp:makepqg',
'cmd/multinit/multinit.gyp:multinit',
'cmd/nss-policy-check/nss-policy-check.gyp:nss-policy-check',
'cmd/ocspclnt/ocspclnt.gyp:ocspclnt',
'cmd/ocspresp/ocspresp.gyp:ocspresp',
'cmd/oidcalc/oidcalc.gyp:oidcalc',
......
......@@ -97,7 +97,7 @@ e.g. `NSS_TESTS=ssl_gtests ./all.sh` or by changing into the according directory
and running the bash script there `cd ssl_gtests && ./ssl_gtests.sh`. The
following tests are available:
cipher lowhash libpkix cert dbtests tools fips sdr crmf smime ssl ocsp merge pkits chains ec gtests ssl_gtests bogo
cipher lowhash libpkix cert dbtests tools fips sdr crmf smime ssl ocsp merge pkits chains ec gtests ssl_gtests bogo policy
To make tests run faster it's recommended to set `NSS_CYCLES=standard` to run
only the standard cycle.
......
......@@ -37,6 +37,7 @@
# memleak.sh - memory leak testing (optional)
# ssl_gtests.sh- Gtest based unit tests for ssl
# gtests.sh - Gtest based unit tests for everything else
# policy.sh - Crypto Policy tests
# bogo.sh - Bogo interop tests (disabled by default)
# https://boringssl.googlesource.com/boringssl/+/master/ssl/test/PORTING.md
# interop.sh - Interoperability tests (disabled by default)
......@@ -300,7 +301,7 @@ if [ $NO_INIT_SUPPORT -eq 0 ]; then
RUN_FIPS="fips"
fi
tests="cipher lowhash libpkix cert dbtests tools $RUN_FIPS sdr crmf smime ssl ocsp merge pkits ec gtests ssl_gtests"
tests="cipher lowhash libpkix cert dbtests tools $RUN_FIPS sdr crmf smime ssl ocsp merge pkits ec gtests ssl_gtests policy"
# Don't run chains tests when we have a gyp build.
if [ "$OBJDIR" != "Debug" -a "$OBJDIR" != "Release" ]; then
tests="$tests chains"
......
# col 1: expected return value of nss-policy-check
# col 2: policy config statement, using _ instead of space
# col 3: an extended regular expression, expected to match the output
# col 4: description of the test
#
0 disallow=ALL_allow=HMAC-SHA256:HMAC-SHA1:HMAC-SHA384:HMAC-SHA512:SECP256R1:SECP384R1:SECP521R1:aes256-gcm:chacha20-poly1305:aes256-cbc:camellia256-cbc:aes128-gcm:aes128-cbc:camellia128-cbc:SHA256:SHA384:SHA512:SHA1:ECDHE-RSA:ECDHE-ECDSA:RSA:DHE-RSA:tls-version-min=tls1.0:dtls-version-min=dtls1.0:DH-MIN=1023:DSA-MIN=2048:RSA-MIN=2048 NSS-POLICY-INFO.*LOADED-SUCCESSFULLY Standard policy
0 disallow=ALL_allow=HMAC-SHA1:HMAC-SHA256:HMAC-SHA384:HMAC-SHA512:SECP256R1:SECP384R1:SECP521R1:aes256-gcm:chacha20-poly1305:aes256-cbc:camellia256-cbc:aes128-gcm:aes128-cbc:camellia128-cbc:des-ede3-cbc:rc4:SHA256:SHA384:SHA512:SHA1:ECDHE-RSA:ECDHE-ECDSA:RSA:DHE-RSA:DHE-DSS:tls-version-min=tls1.0:dtls-version-min=tls1.0:DH-MIN=1023:DSA-MIN=1023:RSA-MIN=1023 NSS-POLICY-INFO.*LOADED-SUCCESSFULLY Legacy policy
0 disallow=ALL_allow=HMAC-SHA256:HMAC-SHA384:HMAC-SHA512:SECP384R1:SECP521R1:aes256-gcm:chacha20-poly1305:SHA384:SHA512:ECDHE-RSA:ECDHE-ECDSA:RSA:DHE-RSA:tls-version-min=tls1.2:dtls-version-min=dtls1.2:DH-MIN=3072:DSA-MIN=3072:RSA-MIN=3072 NSS-POLICY-INFO.*LOADED-SUCCESSFULLY Reduced policy
2 disallow=ALL_allow=dtls-version-min=:dtls-version-max= NSS-POLICY-FAIL Missing value
2 disallow=ALL_allow=RSA-MIN=whatever NSS-POLICY-FAIL Invalid value
2 disallow=ALL_allow=flower NSS-POLICY-FAIL Invalid identifier
1 disallow=all NSS-POLICY-WARN.*NUMBER-OF-CERT-SIG disallow all
1 disallow=ALL_allow=HMAC-SHA256:HMAC-SHA384:HMAC-SHA512:SECP384R1:SECP521R1:aes256-gcm:chacha20-poly1305:ECDHE-RSA:ECDHE-ECDSA:RSA:DHE-RSA:tls-version-min=tls1.2:dtls-version-min=dtls1.2:DH-MIN=3072:DSA-MIN=3072:RSA-MIN=3072 NSS-POLICY-WARN.*NUMBER-OF-HASH No Hashes
1 disallow=ALL_allow=tls-version-min=0:tls-version-max=0 NSS-POLICY-WARN.*NUMBER-OF-TLS-VERSIONS All TLS versions disabled
1 disallow=ALL_allow=dtls-version-min=0:dtls-version-max=0 NSS-POLICY-WARN.*NUMBER-OF-DTLS-VERSIONS All DTLS versions disabled
1 disallow=ALL_allow=tls-version-min=tls1.2:tls-version-max=tls1.1 NSS-POLICY-WARN.*NUMBER-OF-TLS-VERSIONS Invalid range of TLS versions
1 disallow=ALL_allow=dtls-version-min=tls1.2:dtls-version-max=tls1.1 NSS-POLICY-WARN.*NUMBER-OF-DTLS-VERSIONS Invalid range of DTLS versions
1 disallow=ALL_allow=tls-version-min=tls1.1:tls-version-max=tls1.2 NSS-POLICY-INFO.*NUMBER-OF-TLS-VERSIONS Valid range of TLS versions
1 disallow=ALL_allow=dtls-version-min=tls1.1:dtls-version-max=tls1.2 NSS-POLICY-INFO.*NUMBER-OF-DTLS-VERSIONS Valid range of DTLS versions
#! /bin/bash
#
# 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/.
########################################################################
#
# mozilla/security/nss/tests/policy/policy.sh
#
# Script to test NSS crypto policy code
#
########################################################################
ignore_blank_lines()
{
LC_ALL=C grep -v '^[[:space:]]*\(#\|$\)' "$1"
}
policy_run_tests()
{
html_head "CRYPTO-POLICY"
POLICY_INPUT=${QADIR}/policy/crypto-policy.txt
ignore_blank_lines ${POLICY_INPUT} | \
while read value policy match testname
do
echo "$SCRIPTNAME: running \"$testname\" ----------------------------"
policy=`echo ${policy} | sed -e 's;_; ;g'`
match=`echo ${match} | sed -e 's;_; ;g'`
POLICY_FILE="${TMP}/nss-policy"
echo "$SCRIPTNAME: policy: \"$policy\""
cat > "$POLICY_FILE" << ++EOF++
library=
name=Policy
NSS=flags=policyOnly,moduleDB
++EOF++
echo "config=\"${policy}\"" >> "$POLICY_FILE"
echo "" >> "$POLICY_FILE"
nss-policy-check "$POLICY_FILE" >${TMP}/$HOST.tmp.$$ 2>&1
ret=$?
cat ${TMP}/$HOST.tmp.$$
html_msg $ret $value "\"${testname}\"" \
"produced a returncode of $ret, expected is $value"
egrep "${match}" ${TMP}/$HOST.tmp.$$
ret=$?
html_msg $ret 0 "\"${testname}\" output is expected to match \"${match}\""
done
}
policy_run_tests
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment