Bug 1386955 - land NSS fff2c933097d UPGRADE_NSS_RELEASE, r=me
authorFranziskus Kiefer <franziskuskiefer@gmail.com>
Fri, 25 Aug 2017 09:37:32 +0200
changeset 376862 5807c147fcdefcfd7f1ed517245eedac5a38c420
parent 376861 22c304405b0103e6a684ad0b2721f243d51289b9
child 376863 bb7ce98c2f4ad9630c90be4ba96f80a58bbe2718
push id32394
push userkwierso@gmail.com
push dateFri, 25 Aug 2017 23:22:16 +0000
treeherdermozilla-central@86a3c73984a2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersme
bugs1386955
milestone57.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1386955 - land NSS fff2c933097d UPGRADE_NSS_RELEASE, r=me MozReview-Commit-ID: 5eTpylXNFGc
security/nss/TAG-INFO
security/nss/automation/taskcluster/graph/src/extend.js
security/nss/build.sh
security/nss/coreconf/config.gypi
security/nss/coreconf/coreconf.dep
security/nss/coreconf/werror.py
security/nss/fuzz/mpi_expmod_target.cc
security/nss/fuzz/mpi_helper.cc
security/nss/fuzz/mpi_helper.h
security/nss/help.txt
security/nss/lib/freebl/blapii.h
security/nss/lib/freebl/det_rng.c
security/nss/lib/freebl/fipsfreebl.c
security/nss/lib/freebl/ldvector.c
security/nss/lib/freebl/nsslowhash.c
security/nss/lib/freebl/shvfy.c
security/nss/lib/pk11wrap/pk11skey.c
security/nss/lib/softoken/fipstest.c
security/nss/lib/softoken/legacydb/lgfips.c
security/nss/lib/softoken/legacydb/lginit.c
security/nss/mach
security/nss/nss.gyp
security/nss/tests/all.sh
security/nss/tests/cert/cert.sh
security/nss/tests/fips/fips.sh
security/nss/tests/ssl/ssl.sh
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-d50a14c51077
+fff2c933097d
--- a/security/nss/automation/taskcluster/graph/src/extend.js
+++ b/security/nss/automation/taskcluster/graph/src/extend.js
@@ -86,21 +86,29 @@ queue.filter(task => {
   }
 
   return true;
 });
 
 queue.map(task => {
   if (task.collection == "asan") {
     // CRMF and FIPS tests still leak, unfortunately.
-    if (task.tests == "crmf" || task.tests == "fips") {
+    if (task.tests == "crmf") {
       task.env.ASAN_OPTIONS = "detect_leaks=0";
     }
   }
 
+  // We don't run FIPS SSL tests
+  if (task.tests == "ssl") {
+    if (!task.env) {
+      task.env = {};
+    }
+    task.env.NSS_SSL_TESTS = "crl iopr policy";
+  }
+
   // Windows is slow.
   if (task.platform == "windows2012-64" && task.tests == "chains") {
     task.maxRunTime = 7200;
   }
 
   return task;
 });
 
@@ -315,16 +323,56 @@ async function scheduleLinux(name, base,
     },
     kind: "build",
     symbol: "B"
   }, base);
 
   // The task that builds NSPR+NSS.
   let task_build = queue.scheduleTask(merge(build_base, {name}));
 
+  // Make builds run FIPS tests, which need an extra FIPS build.
+  if (base.collection == "make") {
+    let extra_build = queue.scheduleTask(merge(build_base, {
+      env: { NSS_FORCE_FIPS: "1" },
+      group: "FIPS",
+      name: `${name} w/ NSS_FORCE_FIPS`
+    }));
+
+    // The task that generates certificates.
+    let task_cert = queue.scheduleTask(merge(build_base, {
+      name: "Certificates",
+      command: [
+        "/bin/bash",
+        "-c",
+        "bin/checkout.sh && nss/automation/taskcluster/scripts/gen_certs.sh"
+      ],
+      parent: extra_build,
+      symbol: "Certs-F",
+      group: "FIPS",
+      env: { NSS_TEST_ENABLE_FIPS: "1" }
+    }));
+
+    // Schedule FIPS tests.
+    queue.scheduleTask(merge(base, {
+      parent: task_cert,
+      name: "FIPS",
+      command: [
+        "/bin/bash",
+        "-c",
+        "bin/checkout.sh && nss/automation/taskcluster/scripts/run_tests.sh"
+      ],
+      cycle: "standard",
+      kind: "test",
+      name: "FIPS tests",
+      symbol: "Tests-F",
+      tests: "fips",
+      group: "FIPS"
+    }));
+  }
+
   // The task that generates certificates.
   let task_cert = queue.scheduleTask(merge(build_base, {
     name: "Certificates",
     command: [
       "/bin/bash",
       "-c",
       "bin/checkout.sh && nss/automation/taskcluster/scripts/gen_certs.sh"
     ],
@@ -698,16 +746,54 @@ async function scheduleWindows(name, bas
       expires: 24 * 7,
       type: "directory",
       path: "public\\build"
     }],
     kind: "build",
     symbol: "B"
   });
 
+  // Make builds run FIPS tests, which need an extra FIPS build.
+  if (base.collection == "make") {
+    let extra_build = queue.scheduleTask(merge(build_base, {
+      env: { NSS_FORCE_FIPS: "1" },
+      group: "FIPS",
+      name: `${name} w/ NSS_FORCE_FIPS`
+    }));
+
+    // The task that generates certificates.
+    let task_cert = queue.scheduleTask(merge(build_base, {
+      name: "Certificates",
+      command: [
+        WINDOWS_CHECKOUT_CMD,
+        "bash -c nss/automation/taskcluster/windows/gen_certs.sh"
+      ],
+      parent: extra_build,
+      symbol: "Certs-F",
+      group: "FIPS",
+      env: { NSS_TEST_ENABLE_FIPS: "1" }
+    }));
+
+    // Schedule FIPS tests.
+    queue.scheduleTask(merge(base, {
+      parent: task_cert,
+      name: "FIPS",
+      command: [
+        WINDOWS_CHECKOUT_CMD,
+        "bash -c nss/automation/taskcluster/windows/run_tests.sh"
+      ],
+      cycle: "standard",
+      kind: "test",
+      name: "FIPS tests",
+      symbol: "Tests-F",
+      tests: "fips",
+      group: "FIPS"
+    }));
+  }
+
   // The task that builds NSPR+NSS.
   let task_build = queue.scheduleTask(merge(build_base, {name}));
 
   // The task that generates certificates.
   let task_cert = queue.scheduleTask(merge(build_base, {
     name: "Certificates",
     command: [
       WINDOWS_CHECKOUT_CMD,
@@ -776,19 +862,16 @@ function scheduleTests(task_build, task_
   let cert_base = merge(test_base, {parent: task_cert});
   queue.scheduleTask(merge(cert_base, {
     name: "CRMF tests", symbol: "CRMF", tests: "crmf"
   }));
   queue.scheduleTask(merge(cert_base, {
     name: "DB tests", symbol: "DB", tests: "dbtests"
   }));
   queue.scheduleTask(merge(cert_base, {
-    name: "FIPS tests", symbol: "FIPS", tests: "fips"
-  }));
-  queue.scheduleTask(merge(cert_base, {
     name: "Merge tests", symbol: "Merge", tests: "merge"
   }));
   queue.scheduleTask(merge(cert_base, {
     name: "S/MIME tests", symbol: "SMIME", tests: "smime"
   }));
   queue.scheduleTask(merge(cert_base, {
     name: "Tools tests", symbol: "Tools", tests: "tools"
   }));
--- a/security/nss/build.sh
+++ b/security/nss/build.sh
@@ -91,16 +91,17 @@ while [ $# -gt 0 ]; do
         --pprof) gyp_params+=(-Duse_pprof=1) ;;
         --ct-verif) gyp_params+=(-Dct_verif=1) ;;
         --disable-tests) gyp_params+=(-Ddisable_tests=1) ;;
         --no-zdefs) gyp_params+=(-Dno_zdefs=1) ;;
         --system-sqlite) gyp_params+=(-Duse_system_sqlite=1) ;;
         --with-nspr=?*) set_nspr_path "${1#*=}"; no_local_nspr=1 ;;
         --system-nspr) set_nspr_path "/usr/include/nspr/:"; no_local_nspr=1 ;;
         --enable-libpkix) gyp_params+=(-Ddisable_libpkix=0) ;;
+        --enable-fips) gyp_params+=(-Ddisable_fips=0) ;;
         *) show_help; exit 2 ;;
     esac
     shift
 done
 
 if [ "$opt_build" = 1 ]; then
     target=Release
 else
--- a/security/nss/coreconf/config.gypi
+++ b/security/nss/coreconf/config.gypi
@@ -104,32 +104,38 @@
     'fuzz_tls%': 0,
     'fuzz_oss%': 0,
     'sign_libs%': 1,
     'use_pprof%': 0,
     'ct_verif%': 0,
     'nss_public_dist_dir%': '<(nss_dist_dir)/public',
     'nss_private_dist_dir%': '<(nss_dist_dir)/private',
     'only_dev_random%': 1,
+    'disable_fips%': 1,
   },
   'target_defaults': {
     # Settings specific to targets should go here.
     # This is mostly for linking to libraries.
     'variables': {
       'mapfile%': '',
       'test_build%': 0,
       'debug_optimization_level%': '0',
       'release_optimization_level%': '2',
     },
     'standalone_static_library': 0,
     'include_dirs': [
       '<(nspr_include_dir)',
       '<(nss_dist_dir)/private/<(module)',
     ],
     'conditions': [
+      [ 'disable_fips==1', {
+        'defines': [
+          'NSS_FIPS_DISABLED',
+        ],
+      }],
       [ 'OS!="android" and OS!="mac" and OS!="win"', {
         'libraries': [
           '-lpthread',
         ],
       }],
       [ 'OS=="linux"', {
         'libraries': [
           '-ldl',
--- a/security/nss/coreconf/coreconf.dep
+++ b/security/nss/coreconf/coreconf.dep
@@ -5,9 +5,8 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSS in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
-
--- a/security/nss/coreconf/werror.py
+++ b/security/nss/coreconf/werror.py
@@ -19,17 +19,17 @@ def main():
     def can_enable():
         # This would be a problem
         if not warning_supported('all'):
             return False
 
         # If we aren't clang, make sure we have gcc 4.8 at least
         if not cc_is_clang:
             try:
-                v = subprocess.check_output([cc, '-dumpversion'], stderr=sink)
+                v = subprocess.check_output([cc, '-dumpversion'], stderr=sink).decode("utf-8")
                 v = v.strip(' \r\n').split('.')
                 v = list(map(int, v))
                 if v[0] < 4 or (v[0] == 4 and v[1] < 8):
                     # gcc 4.8 minimum
                     return False
             except OSError:
                 return False
         return True
--- a/security/nss/fuzz/mpi_expmod_target.cc
+++ b/security/nss/fuzz/mpi_expmod_target.cc
@@ -14,14 +14,20 @@ extern "C" int LLVMFuzzerTestOneInput(co
   if (size < 3) {
     return 0;
   }
   INIT_FOUR_NUMBERS
 
   auto modulus = get_modulus(data, size, ctx);
   // Compare with OpenSSL exp mod
   m1 = &std::get<1>(modulus);
+  print_bn("A", A);
+  print_bn("B", B);
+  print_bn("m", std::get<0>(modulus));
+  check_equal(A, &a, max_size);
+  check_equal(B, &b, max_size);
+  check_equal(std::get<0>(modulus), m1, 3 * max_size);
   assert(mp_exptmod(&a, &b, m1, &c) == MP_OKAY);
   (void)BN_mod_exp(C, A, B, std::get<0>(modulus), ctx);
   check_equal(C, &c, 2 * max_size);
 
   CLEANUP_AND_RETURN
 }
--- a/security/nss/fuzz/mpi_helper.cc
+++ b/security/nss/fuzz/mpi_helper.cc
@@ -7,16 +7,22 @@
 #include "mpi_helper.h"
 #include <cstdlib>
 #include <random>
 
 char *to_char(const uint8_t *x) {
   return reinterpret_cast<char *>(const_cast<unsigned char *>(x));
 }
 
+void print_bn(std::string label, BIGNUM *x) {
+  char *xc = BN_bn2hex(x);
+  std::cout << label << ": " << std::hex << xc << std::endl;
+  OPENSSL_free(xc);
+}
+
 // Check that the two numbers are equal.
 void check_equal(BIGNUM *b, mp_int *m, size_t max_size) {
   char *bnBc = BN_bn2hex(b);
   char mpiMc[max_size];
   mp_tohex(m, mpiMc);
   std::string bnA(bnBc);
   std::string mpiA(mpiMc);
   OPENSSL_free(bnBc);
--- a/security/nss/fuzz/mpi_helper.h
+++ b/security/nss/fuzz/mpi_helper.h
@@ -18,16 +18,17 @@
 #include <openssl/bn.h>
 
 void check_equal(BIGNUM *b, mp_int *m, size_t max_size);
 void parse_input(const uint8_t *data, size_t size, BIGNUM *A, BIGNUM *B,
                  mp_int *a, mp_int *b);
 void parse_input(const uint8_t *data, size_t size, BIGNUM *A, mp_int *a);
 std::tuple<BIGNUM *, mp_int> get_modulus(const uint8_t *data, size_t size,
                                          BN_CTX *ctx);
+void print_bn(std::string label, BIGNUM *x);
 
 // Initialise MPI and BN variables
 // XXX: Also silence unused variable warnings for R.
 #define INIT_FOUR_NUMBERS                \
   mp_int a, b, c, r;                     \
   mp_int *m1 = nullptr;                  \
   BN_CTX *ctx = BN_CTX_new();            \
   BN_CTX_start(ctx);                     \
--- a/security/nss/help.txt
+++ b/security/nss/help.txt
@@ -1,13 +1,14 @@
 Usage: build.sh [-hcv] [-j <n>] [--nspr] [--gyp|-g] [--opt|-o] [-m32]
                 [--test] [--pprof] [--scan-build[=output]] [--ct-verif]
                 [--asan] [--ubsan] [--msan] [--sancov[=edge|bb|func|...]]
                 [--disable-tests] [--fuzz[=tls|oss]] [--system-sqlite]
                 [--no-zdefs] [--with-nspr] [--system-nspr] [--enable-libpkix]
+                [--enable-fips]
 
 This script builds NSS with gyp and ninja.
 
 This build system is still under development.  It does not yet support all
 the features or platforms that NSS supports.
 
 NSS build tool options:
 
@@ -38,8 +39,9 @@ NSS build tool options:
     --disable-tests  don't build tests and corresponding cmdline utils
     --system-sqlite  use system sqlite
     --no-zdefs       don't set -Wl,-z,defs
     --with-nspr      don't build NSPR but use the one at the given location, e.g.
                      --with-nspr=/path/to/nspr/include:/path/to/nspr/lib
     --system-nspr    use system nspr. This requires an installation of NSPR and
                      might not work on all systems.
     --enable-libpkix make libpkix part of the build.
+    --enable-fips    don't disable FIPS checks.
--- a/security/nss/lib/freebl/blapii.h
+++ b/security/nss/lib/freebl/blapii.h
@@ -17,18 +17,20 @@
 typedef SECStatus (*freeblCipherFunc)(void *cx, unsigned char *output,
                                       unsigned int *outputLen, unsigned int maxOutputLen,
                                       const unsigned char *input, unsigned int inputLen,
                                       unsigned int blocksize);
 typedef void (*freeblDestroyFunc)(void *cx, PRBool freeit);
 
 SEC_BEGIN_PROTOS
 
+#ifndef NSS_FIPS_DISABLED
 SECStatus BL_FIPSEntryOK(PRBool freeblOnly);
 PRBool BL_POSTRan(PRBool freeblOnly);
+#endif
 
 #if defined(XP_UNIX) && !defined(NO_FORK_CHECK)
 
 extern PRBool bl_parentForkedAfterC_Initialize;
 
 #define SKIP_AFTER_FORK(x)                 \
     if (!bl_parentForkedAfterC_Initialize) \
     x
--- a/security/nss/lib/freebl/det_rng.c
+++ b/security/nss/lib/freebl/det_rng.c
@@ -3,36 +3,50 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "blapi.h"
 #include "blapit.h"
 #include "chacha20.h"
 #include "nssilock.h"
 #include "seccomon.h"
 #include "secerr.h"
+#include "prinit.h"
 
 #define GLOBAL_BYTES_SIZE 100
 static PRUint8 globalBytes[GLOBAL_BYTES_SIZE];
 static unsigned long globalNumCalls = 0;
 static PZLock *rng_lock = NULL;
+static PRCallOnceType coRNGInit;
+static const PRCallOnceType pristineCallOnce;
 
-SECStatus
-RNG_RNGInit(void)
+static PRStatus
+rng_init(void)
 {
     rng_lock = PZ_NewLock(nssILockOther);
     if (!rng_lock) {
         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-        return SECFailure;
+        return PR_FAILURE;
     }
     /* --- LOCKED --- */
     PZ_Lock(rng_lock);
     memset(globalBytes, 0, GLOBAL_BYTES_SIZE);
     PZ_Unlock(rng_lock);
     /* --- UNLOCKED --- */
 
+    return PR_SUCCESS;
+}
+
+SECStatus
+RNG_RNGInit(void)
+{
+    /* Allow only one call to initialize the context */
+    if (PR_CallOnce(&coRNGInit, rng_init) != PR_SUCCESS) {
+        return SECFailure;
+    }
+
     return SECSuccess;
 }
 
 /* Take min(size, GLOBAL_BYTES_SIZE) bytes from data and use as seed and reset
  * the rng state. */
 SECStatus
 RNG_RandomUpdate(const void *data, size_t bytes)
 {
@@ -92,18 +106,21 @@ RNG_GenerateGlobalRandomBytes(void *dest
     /* --- UNLOCKED --- */
 
     return SECSuccess;
 }
 
 void
 RNG_RNGShutdown(void)
 {
-    PZ_DestroyLock(rng_lock);
-    rng_lock = NULL;
+    if (rng_lock) {
+        PZ_DestroyLock(rng_lock);
+        rng_lock = NULL;
+    }
+    coRNGInit = pristineCallOnce;
 }
 
 /* Test functions are not implemented! */
 SECStatus
 PRNGTEST_Instantiate(const PRUint8 *entropy, unsigned int entropy_len,
                      const PRUint8 *nonce, unsigned int nonce_len,
                      const PRUint8 *personal_string, unsigned int ps_len)
 {
--- a/security/nss/lib/freebl/fipsfreebl.c
+++ b/security/nss/lib/freebl/fipsfreebl.c
@@ -1,16 +1,17 @@
 /*
  * PKCS #11 FIPS Power-Up Self Test.
  *
  * 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/. */
 /* $Id: fipstest.c,v 1.31 2012/06/28 17:55:06 rrelyea%redhat.com Exp $ */
 
+#ifndef NSS_FIPS_DISABLED
 #ifdef FREEBL_NO_DEPEND
 #include "stubs.h"
 #endif
 
 #include "blapi.h"
 #include "seccomon.h" /* Required for RSA and DSA. */
 #include "secerr.h"
 #include "prtypes.h"
@@ -1584,19 +1585,16 @@ freebl_fipsPowerUpSelfTest(unsigned int 
  * nss-util are not loaded, then we can't run all the selftests, and we need
  * to prevent the softoken function pointer table from operating until the
  * libraries are loaded and we try to use them.
  */
 static PRBool self_tests_freebl_ran = PR_FALSE;
 static PRBool self_tests_ran = PR_FALSE;
 static PRBool self_tests_freebl_success = PR_FALSE;
 static PRBool self_tests_success = PR_FALSE;
-#if defined(DEBUG)
-static PRBool fips_mode_available = PR_FALSE;
-#endif
 
 /*
  * accessors for freebl
  */
 PRBool
 BL_POSTRan(PRBool freebl_only)
 {
     SECStatus rv;
@@ -1639,17 +1637,16 @@ static void
 bl_startup_tests(void)
 {
     const char *libraryName;
     PRBool freebl_only = PR_FALSE;
     SECStatus rv;
 
     PORT_Assert(self_tests_freebl_ran == PR_FALSE);
     PORT_Assert(self_tests_success == PR_FALSE);
-    PORT_Assert(fips_mode_available == PR_FALSE);
     self_tests_freebl_ran = PR_TRUE;      /* we are running the tests */
     self_tests_success = PR_FALSE;        /* force it just in case */
     self_tests_freebl_success = PR_FALSE; /* force it just in case */
 
 #ifdef FREEBL_NO_DEPEND
     rv = FREEBL_InitStubs();
     if (rv != SECSuccess) {
         freebl_only = PR_TRUE;
@@ -1708,8 +1705,9 @@ BL_FIPSEntryOK(PRBool freebl_only)
     }
     /* standalone freebl can initialize */
     if (freebl_only && self_tests_freebl_success) {
         return SECSuccess;
     }
     PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
     return SECFailure;
 }
+#endif
--- a/security/nss/lib/freebl/ldvector.c
+++ b/security/nss/lib/freebl/ldvector.c
@@ -315,18 +315,22 @@ FREEBL_GetVector(void)
 
 #ifdef FREEBL_NO_DEPEND
     /* this entry point is only valid if nspr and nss-util has been loaded */
     rv = FREEBL_InitStubs();
     if (rv != SECSuccess) {
         return NULL;
     }
 #endif
-    /* make sure the Full self tests have been run before continuing */
+
+#ifndef NSS_FIPS_DISABLED
+    /* In FIPS mode make sure the Full self tests have been run before
+     * continuing. */
     BL_POSTRan(PR_FALSE);
+#endif
 
     return &vector;
 }
 
 #ifdef FREEBL_LOWHASH
 static const struct NSSLOWVectorStr nssvector =
     {
       sizeof nssvector,
--- a/security/nss/lib/freebl/nsslowhash.c
+++ b/security/nss/lib/freebl/nsslowhash.c
@@ -17,16 +17,17 @@ struct NSSLOWInitContextStr {
     int count;
 };
 
 struct NSSLOWHASHContextStr {
     const SECHashObject *hashObj;
     void *hashCtxt;
 };
 
+#ifndef NSS_FIPS_DISABLED
 static int
 nsslow_GetFIPSEnabled(void)
 {
 #ifdef LINUX
     FILE *f;
     char d;
     size_t size;
 
@@ -35,39 +36,42 @@ nsslow_GetFIPSEnabled(void)
         return 0;
 
     size = fread(&d, 1, 1, f);
     fclose(f);
     if (size != 1)
         return 0;
     if (d != '1')
         return 0;
-#endif
+#endif /* LINUX */
     return 1;
 }
+#endif /* NSS_FIPS_DISABLED */
 
 static NSSLOWInitContext dummyContext = { 0 };
 static PRBool post_failed = PR_TRUE;
 
 NSSLOWInitContext *
 NSSLOW_Init(void)
 {
 #ifdef FREEBL_NO_DEPEND
     (void)FREEBL_InitStubs();
 #endif
 
+#ifndef NSS_FIPS_DISABLED
     /* make sure the FIPS product is installed if we are trying to
      * go into FIPS mode */
     if (nsslow_GetFIPSEnabled()) {
         if (BL_FIPSEntryOK(PR_TRUE) != SECSuccess) {
             PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
             post_failed = PR_TRUE;
             return NULL;
         }
     }
+#endif
     post_failed = PR_FALSE;
 
     return &dummyContext;
 }
 
 void
 NSSLOW_Shutdown(NSSLOWInitContext *context)
 {
--- a/security/nss/lib/freebl/shvfy.c
+++ b/security/nss/lib/freebl/shvfy.c
@@ -14,16 +14,18 @@
 #include "seccomon.h"
 #include "secerr.h"
 #include "stdio.h"
 #include "prmem.h"
 #include "hasht.h"
 #include "pqg.h"
 #include "blapii.h"
 
+#ifndef NSS_FIPS_DISABLED
+
 /*
  * Most modern version of Linux support a speed optimization scheme where an
  * application called prelink modifies programs and shared libraries to quickly
  * load if they fit into an already designed address space. In short, prelink
  * scans the list of programs and libraries on your system, assigns them a
  * predefined space in the the address space, then provides the fixups to the
  * library.
 
@@ -532,8 +534,28 @@ BLAPI_VerifySelf(const char *name)
         /*
          * If name is NULL, freebl is statically linked into softoken.
          * softoken will call BLAPI_SHVerify next to verify itself.
          */
         return PR_TRUE;
     }
     return blapi_SHVerify(name, (PRFuncPtr)decodeInt, PR_TRUE);
 }
+
+#else /* NSS_FIPS_DISABLED */
+
+PRBool
+BLAPI_SHVerifyFile(const char *shName)
+{
+    return PR_FALSE;
+}
+PRBool
+BLAPI_SHVerify(const char *name, PRFuncPtr addr)
+{
+    return PR_FALSE;
+}
+PRBool
+BLAPI_VerifySelf(const char *name)
+{
+    return PR_FALSE;
+}
+
+#endif /* NSS_FIPS_DISABLED */
--- a/security/nss/lib/pk11wrap/pk11skey.c
+++ b/security/nss/lib/pk11wrap/pk11skey.c
@@ -177,16 +177,20 @@ pk11_CreateSymKey(PK11SlotInfo *slot, CK
  * destroy a symetric key
  */
 void
 PK11_FreeSymKey(PK11SymKey *symKey)
 {
     PK11SlotInfo *slot;
     PRBool freeit = PR_TRUE;
 
+    if (!symKey) {
+        return;
+    }
+
     if (PR_ATOMIC_DECREMENT(&symKey->refCount) == 0) {
         PK11SymKey *parent = symKey->parent;
 
         symKey->parent = NULL;
         if ((symKey->owner) && symKey->objectID != CK_INVALID_HANDLE) {
             pk11_EnterKeyMonitor(symKey);
             (void)PK11_GETTAB(symKey->slot)->C_DestroyObject(symKey->session, symKey->objectID);
             pk11_ExitKeyMonitor(symKey);
--- a/security/nss/lib/softoken/fipstest.c
+++ b/security/nss/lib/softoken/fipstest.c
@@ -1,15 +1,16 @@
 /*
  * PKCS #11 FIPS Power-Up Self Test.
  *
  * 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/. */
 
+#ifndef NSS_FIPS_DISABLED
 #include "seccomon.h"
 #include "blapi.h"
 #include "softoken.h"
 #include "lowkeyi.h"
 #include "secoid.h"
 #include "secerr.h"
 
 /*
@@ -647,8 +648,16 @@ sftk_FIPSEntryOK()
         sftk_startup_tests();
     }
 #endif
     if (!sftk_self_tests_success) {
         return CKR_DEVICE_ERROR;
     }
     return CKR_OK;
 }
+#else
+#include "pkcs11t.h"
+CK_RV
+sftk_FIPSEntryOK()
+{
+    return CKR_DEVICE_ERROR;
+}
+#endif /* NSS_FIPS_DISABLED */
--- a/security/nss/lib/softoken/legacydb/lgfips.c
+++ b/security/nss/lib/softoken/legacydb/lgfips.c
@@ -1,16 +1,18 @@
 /*
  * PKCS #11 FIPS Power-Up Self Test.
  *
  * 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/. */
 /* $Id: fipstest.c,v 1.31 2012/06/28 17:55:06 rrelyea%redhat.com Exp $ */
 
+#ifndef NSS_FIPS_DISABLED
+
 #include "seccomon.h"
 #include "lgdb.h"
 #include "blapi.h"
 
 /*
  * different platforms have different ways of calling and initial entry point
  * when the dll/.so is loaded. Most platforms support either a posix pragma
  * or the GCC attribute. Some platforms suppor a pre-defined name, and some
@@ -108,8 +110,10 @@ lg_FIPSEntryOK()
      * is not set, and init support has not been properly enabled, softken
      * will always fail because of the test below */
     if (!lg_self_tests_ran) {
         lg_startup_tests();
     }
 #endif
     return lg_self_tests_success;
 }
+
+#endif /* NSS_FIPS_DISABLED */
--- a/security/nss/lib/softoken/legacydb/lginit.c
+++ b/security/nss/lib/softoken/legacydb/lginit.c
@@ -581,21 +581,25 @@ legacy_Open(const char *configdir, const
 {
     CK_RV crv = CKR_OK;
     SECStatus rv;
     PRBool readOnly = ((flags & 0x7) == SDB_RDONLY) ? PR_TRUE : PR_FALSE;
 
 #define NSS_VERSION_VARIABLE __nss_dbm_version
 #include "verref.h"
 
+#ifndef NSS_FIPS_DISABLED
     if (flags & SDB_FIPS) {
+        /* We shouldn't get here when FIPS is not enabled on the database. But
+         * we also don't care when this NSS build doesn't support FIPS. */
         if (!lg_FIPSEntryOK()) {
             return CKR_DEVICE_ERROR;
         }
     }
+#endif
 
     rv = SECOID_Init();
     if (SECSuccess != rv) {
         return CKR_DEVICE_ERROR;
     }
     nsslowcert_InitLocks();
 
     if (keyDB)
--- a/security/nss/mach
+++ b/security/nss/mach
@@ -1,14 +1,14 @@
 #!/usr/bin/env python
 #
 # 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 is a collection of helper tools to get stuff done in NSS.
 #
 
 import sys
 import argparse
 import subprocess
 import os
@@ -18,23 +18,25 @@ from hashlib import sha256
 cwd = os.path.dirname(os.path.abspath(__file__))
 
 
 class cfAction(argparse.Action):
     docker_command = ["docker"]
     restorecon = None
 
     def __call__(self, parser, args, values, option_string=None):
-        if "noroot" not in values:
+        if not args.noroot:
             self.setDockerCommand()
+
+        if values:
+            files = [os.path.abspath(x) for x in values]
         else:
-            values.remove("noroot")
-        files = [os.path.join('/home/worker/nss',
-                              os.path.relpath(os.path.abspath(x), start=cwd))
-                     for x in values]
+            files = self.modifiedFiles()
+        files = [os.path.join('/home/worker/nss', os.path.relpath(x, start=cwd))
+                 for x in files]
 
         # First check if we can run docker.
         try:
             with open(os.devnull, "w") as f:
                 subprocess.check_call(
                     self.docker_command + ["images"], stdout=f)
         except:
             print("Please install docker and start the docker daemon.")
@@ -54,19 +56,20 @@ class cfAction(argparse.Action):
             ]
             with open(os.devnull, "w") as f:
                 subprocess.check_call(command, stdout=f)
         except:
             print("I have to build the docker image first.")
             self.buildImage(docker_image, cf_docker_folder)
 
         command = self.docker_command + [
-                'run', '-v', cwd + ':/home/worker/nss:Z', '--rm', '-ti', docker_image
+            'run', '-v', cwd + ':/home/worker/nss:Z', '--rm', '-ti', docker_image
         ]
-        # The clang format script returns 1 if something's to do. We don't care.
+        # The clang format script returns 1 if something's to do. We don't
+        # care.
         subprocess.call(command + files)
         if self.restorecon is not None:
             subprocess.call([self.restorecon, '-R', cwd])
 
     def filesChanged(self, path):
         hash = sha256()
         for dirname, dirnames, files in os.walk(path):
             for file in files:
@@ -92,43 +95,72 @@ class cfAction(argparse.Action):
         return
 
     def setDockerCommand(self):
         if platform.system() == "Linux":
             from distutils.spawn import find_executable
             self.restorecon = find_executable('restorecon')
             self.docker_command = ["sudo"] + self.docker_command
 
+    def modifiedFiles(self):
+        files = []
+        if os.path.exists(os.path.join(cwd, '.hg')):
+            st = subprocess.Popen(['hg', 'status', '-m', '-a'],
+                                  cwd=cwd, stdout=subprocess.PIPE)
+            for line in iter(st.stdout.readline, ''):
+                files += [line[2:].rstrip()]
+        elif os.path.exists(os.path.join(cwd, '.git')):
+            st = subprocess.Popen(['git', 'status', '--porcelain'],
+                                  cwd=cwd, stdout=subprocess.PIPE)
+            for line in iter(st.stdout.readline, ''):
+                if line[1] == 'M' or line[1] != 'D' and \
+                        (line[0] == 'M' or line[0] == 'A' or
+                         line[0] == 'C' or line[0] == 'U'):
+                    files += [line[3:].rstrip()]
+                elif line[0] == 'R':
+                    files += [line[line.index(' -> ', beg=4) + 4:]]
+        else:
+            print('Warning: neither mercurial nor git detected!')
+
+        def isFormatted(x):
+            return x[-2:] == '.c' or x[-3:] == '.cc' or x[-2:] == '.h'
+        return [x for x in files if isFormatted(x)]
+
 
 class buildAction(argparse.Action):
+
     def __call__(self, parser, args, values, option_string=None):
         cwd = os.path.dirname(os.path.abspath(__file__))
         subprocess.check_call([cwd + "/build.sh"] + values)
 
 
 class testAction(argparse.Action):
+
     def runTest(self, test, cycles="standard"):
         cwd = os.path.dirname(os.path.abspath(__file__))
         domsuf = os.getenv('DOMSUF', "localdomain")
         host = os.getenv('HOST', "localhost")
         env = {
             "NSS_TESTS": test,
             "NSS_CYCLES": cycles,
             "DOMSUF": domsuf,
             "HOST": host
         }
+        os_env = os.environ
+        os_env.update(env)
         command = cwd + "/tests/all.sh"
-        subprocess.check_call(command, env=env)
+        subprocess.check_call(command, env=os_env)
 
     def __call__(self, parser, args, values, option_string=None):
         self.runTest(values)
 
 
 class commandsAction(argparse.Action):
     commands = []
+
     def __call__(self, parser, args, values, option_string=None):
         for c in commandsAction.commands:
             print(c)
 
 
 def parse_arguments():
     parser = argparse.ArgumentParser(
         description='NSS helper script. ' +
@@ -137,21 +169,30 @@ def parse_arguments():
 
     parser_build = subparsers.add_parser(
         'build', help='All arguments are passed to build.sh')
     parser_build.add_argument(
         'build_args', nargs='*', help="build arguments", action=buildAction)
 
     parser_cf = subparsers.add_parser(
         'clang-format',
-        help='Run clang-format on all folders or provide a folder to format.')
+        help="""
+        Run clang-format.
+
+        By default this runs against any files that you have modified.  If
+        there are no modified files, it checks everything.
+        """)
     parser_cf.add_argument(
-        'cf_args',
+        '--noroot',
+        help='On linux, suppress the use of \'sudo\' for running docker.',
+        action='store_true')
+    parser_cf.add_argument(
+        '<file/dir>',
         nargs='*',
-        help="clang-format folders and noroot if you don't want to use sudo",
+        help="Specify files or directories to run clang-format on",
         action=cfAction)
 
     parser_test = subparsers.add_parser(
         'tests', help='Run tests through tests/all.sh.')
     tests = [
         "cipher", "lowhash", "chains", "cert", "dbtests", "tools", "fips",
         "sdr", "crmf", "smime", "ssl", "ocsp", "merge", "pkits", "ec",
         "gtests", "ssl_gtests"
--- a/security/nss/nss.gyp
+++ b/security/nss/nss.gyp
@@ -126,17 +126,16 @@
             'cmd/certcgi/certcgi.gyp:certcgi',
             'cmd/chktest/chktest.gyp:chktest',
             'cmd/crmftest/crmftest.gyp:crmftest',
             'cmd/dbtest/dbtest.gyp:dbtest',
             'cmd/derdump/derdump.gyp:derdump',
             'cmd/digest/digest.gyp:digest',
             'cmd/ecperf/ecperf.gyp:ecperf',
             'cmd/fbectest/fbectest.gyp:fbectest',
-            'cmd/fipstest/fipstest.gyp:fipstest',
             'cmd/httpserv/httpserv.gyp:httpserv',
             'cmd/listsuites/listsuites.gyp:listsuites',
             'cmd/makepqg/makepqg.gyp:makepqg',
             'cmd/multinit/multinit.gyp:multinit',
             'cmd/ocspclnt/ocspclnt.gyp:ocspclnt',
             'cmd/ocspresp/ocspresp.gyp:ocspresp',
             'cmd/oidcalc/oidcalc.gyp:oidcalc',
             'cmd/p7content/p7content.gyp:p7content',
@@ -185,16 +184,21 @@
               ],
             }],
             [ 'test_build==1', {
               'dependencies': [
                 'cmd/mpitests/mpitests.gyp:mpi_tests',
                 'gtests/freebl_gtest/freebl_gtest.gyp:freebl_gtest',
               ],
             }],
+            [ 'disable_fips==0', {
+              'dependencies': [
+                'cmd/fipstest/fipstest.gyp:fipstest',
+              ],
+            }],
           ],
         },
       ],
     }],
     [ 'sign_libs==1', {
       'targets': [
         {
         'target_name': 'nss_sign_shared_libs',
--- a/security/nss/tests/all.sh
+++ b/security/nss/tests/all.sh
@@ -102,16 +102,18 @@
 #   Unlike the old QA this is based on files sourcing each other
 #   This is done to save time, since a great portion of time is lost
 #   in calling and sourcing the same things multiple times over the
 #   network. Also, this way all scripts have all shell function
 #   available and a completely common environment
 #
 ########################################################################
 
+RUN_FIPS=""
+
 ############################## run_tests ###############################
 # run test suites defined in TESTS variable, skip scripts defined in
 # TESTS_SKIP variable
 ########################################################################
 run_tests()
 {
     for TEST in ${TESTS}
     do
@@ -182,17 +184,17 @@ run_cycle_upgrade_db()
     html "</TABLE><BR>"
 
     OLDHOSTDIR="${HOSTDIR}"
     HOSTDIR="${HOSTDIR}/upgradedb"
     mkdir -p "${HOSTDIR}"
     init_directories
 
     if [ -r "${OLDHOSTDIR}/cert.log" ]; then
-        DIRS="alicedir bobdir CA cert_extensions client clientCA dave eccurves eve ext_client ext_server fips SDR server serverCA stapling tools/copydir cert.log cert.done tests.*"
+        DIRS="alicedir bobdir CA cert_extensions client clientCA dave eccurves eve ext_client ext_server $RUN_FIPS SDR server serverCA stapling tools/copydir cert.log cert.done tests.*"
         for i in $DIRS
         do
             cp -r ${OLDHOSTDIR}/${i} ${HOSTDIR} #2> /dev/null
         done
     fi
 
     # upgrade certs dbs to shared db
     TESTS="dbupgrade"
@@ -268,17 +270,22 @@ run_cycles()
     done
 }
 
 ############################## main code ###############################
 
 cycles="standard pkix upgradedb sharedb"
 CYCLES=${NSS_CYCLES:-$cycles}
 
-tests="cipher lowhash libpkix cert dbtests tools fips sdr crmf smime ssl ocsp merge pkits ec gtests ssl_gtests"
+if [ -n "$NSS_FORCE_FIPS" ]; then
+    RUN_FIPS="fips"
+    export NSS_TEST_ENABLE_FIPS=1
+fi
+
+tests="cipher lowhash libpkix cert dbtests tools $RUN_FIPS sdr crmf smime ssl ocsp merge pkits ec gtests ssl_gtests"
 # Don't run chains tests when we have a gyp build.
 if [ "$OBJDIR" != "Debug" -a "$OBJDIR" != "Release" ]; then
   tests="$tests chains"
 fi
 TESTS=${NSS_TESTS:-$tests}
 
 ALL_TESTS=${TESTS}
 
--- a/security/nss/tests/cert/cert.sh
+++ b/security/nss/tests/cert/cert.sh
@@ -1970,43 +1970,43 @@ cert_test_ocspresp()
 
 ############################## cert_cleanup ############################
 # local shell function to finish this script (no exit since it might be
 # sourced)
 ########################################################################
 cert_cleanup()
 {
   cert_log "$SCRIPTNAME: finished $SCRIPTNAME"
-  html "</TABLE><BR>" 
+  html "</TABLE><BR>"
   cd ${QADIR}
   . common/cleanup.sh
 }
 
 ################## main #################################################
 
-cert_init 
+cert_init
 cert_all_CA
-cert_extended_ssl 
-cert_ssl 
-cert_smime_client        
-if [ -z "$NSS_TEST_DISABLE_FIPS" ]; then
+cert_extended_ssl
+cert_ssl
+cert_smime_client
+if [[ -n "$NSS_TEST_ENABLE_FIPS" ]]; then
     cert_fips
 fi
 cert_eccurves
 cert_extensions
 cert_san_and_generic_extensions
 cert_test_password
 cert_test_distrust
 cert_test_ocspresp
 
 if [ -z "$NSS_TEST_DISABLE_CRL" ] ; then
     cert_crl_ssl
 else
     echo "$SCRIPTNAME: Skipping CRL Tests"
 fi
 
 if [ -n "$DO_DIST_ST" -a "$DO_DIST_ST" = "TRUE" ] ; then
-    cert_stresscerts 
+    cert_stresscerts
 fi
 
 cert_iopr_setup
 
 cert_cleanup
--- a/security/nss/tests/fips/fips.sh
+++ b/security/nss/tests/fips/fips.sh
@@ -18,16 +18,17 @@
 #
 ########################################################################
 
 ############################## fips_init ##############################
 # local shell function to initialize this script 
 ########################################################################
 fips_init()
 {
+  export NSS_TEST_ENABLE_FIPS=1
   SCRIPTNAME=fips.sh      # sourced - $0 would point to all.sh
 
   if [ -z "${CLEANUP}" ] ; then     # if nobody else is responsible for
       CLEANUP="${SCRIPTNAME}"       # cleaning this script will do it
   fi
 
   if [ -z "${INIT_SOURCED}" -o "${INIT_SOURCED}" != "TRUE" ]; then
       cd ../common
--- a/security/nss/tests/ssl/ssl.sh
+++ b/security/nss/tests/ssl/ssl.sh
@@ -1167,32 +1167,32 @@ ssl_run_tests()
             "normal")
                 SERVER_OPTIONS=
                 ;;
             "fips")
                 SERVER_OPTIONS=
                 ssl_set_fips server on
                 ;;
             *)
-                echo "${SCRIPTNAME}: Error: Unknown server mode ${SERVER_MODE}"
-                continue
+                html_failed "${SCRIPTNAME}: Error: Unknown server mode ${SERVER_MODE}"
+                return 1
                 ;;
             esac
 
             case "${CLIENT_MODE}" in
             "normal")
                 CLIENT_OPTIONS=
                 ;;
             "fips")
                 SERVER_OPTIONS=
                 ssl_set_fips client on
                 ;;
             *)
-                echo "${SCRIPTNAME}: Error: Unknown client mode ${CLIENT_MODE}"
-                continue
+                html_failed "${SCRIPTNAME}: Error: Unknown client mode ${CLIENT_MODE}"
+                return 1
                 ;;
             esac
 
             ssl_run_all
 
             if [ "${SERVER_MODE}" = "fips" ]; then
                 ssl_set_fips server off
             fi