Bug 1305970 - Update to latest NSS 3.28, r=ttaubert, a=jcristau
authorMartin Thomson <martin.thomson@gmail.com>
Mon, 28 Nov 2016 10:54:24 +1100
changeset 352669 071d92d893791d2f0cd39ddcec368f3e03d71e8f
parent 352668 d8e4710b55d980cb3a63f8bae224595d7ef256a0
child 352670 aed03debf4f236c5ccbd746f1a8fdb353a2b572b
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-esr52@76101b503191 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersttaubert, jcristau
bugs1305970
milestone52.0a2
Bug 1305970 - Update to latest NSS 3.28, r=ttaubert, a=jcristau MozReview-Commit-ID: Ah0iKoxgnLe
security/nss/Makefile
security/nss/TAG-INFO
security/nss/automation/taskcluster/docker/setup.sh
security/nss/automation/taskcluster/graph/src/extend.js
security/nss/automation/taskcluster/graph/src/queue.js
security/nss/automation/taskcluster/graph/src/try_syntax.js
security/nss/automation/taskcluster/scripts/fuzz.sh
security/nss/automation/taskcluster/scripts/run_clang_format.sh
security/nss/automation/taskcluster/scripts/run_tests.sh
security/nss/build.sh
security/nss/cmd/certutil/certutil.c
security/nss/cmd/ecperf/ecperf.c
security/nss/cmd/ecperf/ecperf.gyp
security/nss/cmd/fbectest/fbectest.c
security/nss/cmd/fbectest/fbectest.gyp
security/nss/cmd/lib/exports.gyp
security/nss/cmd/lib/secutil.c
security/nss/cmd/lib/secutil.h
security/nss/cmd/modutil/modutil.gyp
security/nss/cmd/mpitests/mpi-test.c
security/nss/cmd/mpitests/mpitests.gyp
security/nss/cmd/mpitests/test-info.c
security/nss/cmd/pk11ectest/testvecs.h
security/nss/cmd/selfserv/selfserv.c
security/nss/cmd/shlibsign/shlibsign.c
security/nss/cmd/tstclnt/tstclnt.c
security/nss/coreconf/WIN32.mk
security/nss/coreconf/check_cc_clang.py
security/nss/coreconf/config.gypi
security/nss/coreconf/coreconf.dep
security/nss/coreconf/detect_host_arch.py
security/nss/coreconf/nspr.sh
security/nss/coreconf/pkg_config.py
security/nss/coreconf/sanitizers.py
security/nss/coreconf/shlibsign.py
security/nss/coreconf/werror.py
security/nss/exports.gyp
security/nss/fuzz/Makefile
security/nss/fuzz/clone_corpus.sh
security/nss/fuzz/clone_libfuzzer.sh
security/nss/fuzz/common.mk
security/nss/fuzz/fuzz.gyp
security/nss/fuzz/libFuzzer/Makefile
security/nss/fuzz/libFuzzer/config.mk
security/nss/fuzz/libFuzzer/libFuzzer.gyp
security/nss/fuzz/libFuzzer/manifest.mn
security/nss/fuzz/manifest.mn
security/nss/fuzz/nssfuzz.cc
security/nss/fuzz/nssfuzz/Makefile
security/nss/fuzz/nssfuzz/cert_target.cc
security/nss/fuzz/nssfuzz/manifest.mn
security/nss/fuzz/nssfuzz/nssfuzz.cc
security/nss/fuzz/nssfuzz/pkcs8_target.cc
security/nss/fuzz/nssfuzz/registry.h
security/nss/fuzz/nssfuzz/shared.h
security/nss/fuzz/nssfuzz/spki_target.cc
security/nss/fuzz/pkcs8_target.cc
security/nss/fuzz/quickder_targets.cc
security/nss/fuzz/registry.h
security/nss/fuzz/shared.h
security/nss/gtests/common/common.gyp
security/nss/gtests/common/scoped_ptrs.h
security/nss/gtests/der_gtest/der_gtest.gyp
security/nss/gtests/freebl_gtest/freebl_gtest.gyp
security/nss/gtests/freebl_gtest/mpi_unittest.cc
security/nss/gtests/nss_bogo_shim/config.json
security/nss/gtests/nss_bogo_shim/nss_bogo_shim.cc
security/nss/gtests/ssl_gtest/databuffer.h
security/nss/gtests/ssl_gtest/libssl_internals.c
security/nss/gtests/ssl_gtest/libssl_internals.h
security/nss/gtests/ssl_gtest/manifest.mn
security/nss/gtests/ssl_gtest/ssl_0rtt_unittest.cc
security/nss/gtests/ssl_gtest/ssl_agent_unittest.cc
security/nss/gtests/ssl_gtest/ssl_auth_unittest.cc
security/nss/gtests/ssl_gtest/ssl_cert_ext_unittest.cc
security/nss/gtests/ssl_gtest/ssl_dhe_unittest.cc
security/nss/gtests/ssl_gtest/ssl_ecdh_unittest.cc
security/nss/gtests/ssl_gtest/ssl_exporter_unittest.cc
security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc
security/nss/gtests/ssl_gtest/ssl_fuzz_unittest.cc
security/nss/gtests/ssl_gtest/ssl_gtest.gyp
security/nss/gtests/ssl_gtest/ssl_hrr_unittest.cc
security/nss/gtests/ssl_gtest/ssl_resumption_unittest.cc
security/nss/gtests/ssl_gtest/tls_agent.cc
security/nss/gtests/ssl_gtest/tls_agent.h
security/nss/gtests/ssl_gtest/tls_connect.cc
security/nss/gtests/ssl_gtest/tls_connect.h
security/nss/gtests/ssl_gtest/tls_filter.cc
security/nss/gtests/ssl_gtest/tls_filter.h
security/nss/gtests/ssl_gtest/tls_hkdf_unittest.cc
security/nss/lib/base/exports.gyp
security/nss/lib/certdb/exports.gyp
security/nss/lib/certhigh/exports.gyp
security/nss/lib/ckfw/builtins/exports.gyp
security/nss/lib/ckfw/exports.gyp
security/nss/lib/crmf/crmf.gyp
security/nss/lib/crmf/exports.gyp
security/nss/lib/cryptohi/exports.gyp
security/nss/lib/dbm/include/exports.gyp
security/nss/lib/dev/exports.gyp
security/nss/lib/freebl/exports.gyp
security/nss/lib/freebl/freebl.gyp
security/nss/lib/freebl/mpi/mpi-test.c
security/nss/lib/freebl/mpi/mpi.c
security/nss/lib/freebl/mpi/mpi.h
security/nss/lib/freebl/mpi/test-arrays.txt
security/nss/lib/freebl/mpi/test-info.c
security/nss/lib/jar/exports.gyp
security/nss/lib/libpkix/include/exports.gyp
security/nss/lib/libpkix/pkix/certsel/exports.gyp
security/nss/lib/libpkix/pkix/checker/exports.gyp
security/nss/lib/libpkix/pkix/crlsel/exports.gyp
security/nss/lib/libpkix/pkix/params/exports.gyp
security/nss/lib/libpkix/pkix/results/exports.gyp
security/nss/lib/libpkix/pkix/store/exports.gyp
security/nss/lib/libpkix/pkix/top/exports.gyp
security/nss/lib/libpkix/pkix/util/exports.gyp
security/nss/lib/libpkix/pkix_pl_nss/module/exports.gyp
security/nss/lib/libpkix/pkix_pl_nss/pki/exports.gyp
security/nss/lib/libpkix/pkix_pl_nss/system/exports.gyp
security/nss/lib/nss/exports.gyp
security/nss/lib/pk11wrap/exports.gyp
security/nss/lib/pkcs12/exports.gyp
security/nss/lib/pkcs7/exports.gyp
security/nss/lib/pki/exports.gyp
security/nss/lib/smime/exports.gyp
security/nss/lib/softoken/exports.gyp
security/nss/lib/sqlite/exports.gyp
security/nss/lib/ssl/SSLerrs.h
security/nss/lib/ssl/dtlscon.c
security/nss/lib/ssl/exports.gyp
security/nss/lib/ssl/ssl.def
security/nss/lib/ssl/ssl.h
security/nss/lib/ssl/ssl3con.c
security/nss/lib/ssl/ssl3ecc.c
security/nss/lib/ssl/ssl3ext.c
security/nss/lib/ssl/ssl3ext.h
security/nss/lib/ssl/ssl3exthandle.c
security/nss/lib/ssl/ssl3prot.h
security/nss/lib/ssl/sslcert.c
security/nss/lib/ssl/sslerr.h
security/nss/lib/ssl/sslimpl.h
security/nss/lib/ssl/sslinfo.c
security/nss/lib/ssl/sslsock.c
security/nss/lib/ssl/sslt.h
security/nss/lib/ssl/tls13con.c
security/nss/lib/ssl/tls13con.h
security/nss/lib/ssl/tls13exthandle.c
security/nss/lib/ssl/tls13exthandle.h
security/nss/lib/ssl/tls13hkdf.c
security/nss/lib/util/exports.gyp
security/nss/lib/zlib/exports.gyp
security/nss/manifest.mn
security/nss/nss.gyp
security/nss/tests/bogo/bogo.sh
security/nss/tests/common/init.sh
security/nss/tests/mpi/mpi.sh
security/nss/tests/run.sh
security/nss/tests/ssl_gtests/ssl_gtests.sh
--- a/security/nss/Makefile
+++ b/security/nss/Makefile
@@ -41,17 +41,17 @@ include $(CORE_DEPTH)/coreconf/rules.mk
 #######################################################################
 
 
 
 #######################################################################
 # (7) Execute "local" rules. (OPTIONAL).                              #
 #######################################################################
 
-nss_build_all: build_nspr all
+nss_build_all: build_nspr all latest
 
 nss_clean_all: clobber_nspr clobber
 
 NSPR_CONFIG_STATUS = $(CORE_DEPTH)/../nspr/$(OBJDIR_NAME)/config.status
 NSPR_CONFIGURE = $(CORE_DEPTH)/../nspr/configure
 
 #
 # Translate coreconf build options to NSPR configure options.
@@ -158,8 +158,11 @@ build_docs:
 clean_docs:
 	$(MAKE) -C $(CORE_DEPTH)/doc clean
 
 nss_RelEng_bld: import all
 
 package:
 	$(MAKE) -C pkg publish
 
+latest:
+	echo $(OBJDIR_NAME) > $(CORE_DEPTH)/../dist/latest
+
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-5d2424d699a0
+6c26f0cd19ba
--- a/security/nss/automation/taskcluster/docker/setup.sh
+++ b/security/nss/automation/taskcluster/docker/setup.sh
@@ -20,16 +20,19 @@ apt_packages+=('ninja-build')
 apt_packages+=('pkg-config')
 apt_packages+=('zlib1g-dev')
 
 # 32-bit builds
 apt_packages+=('lib32z1-dev')
 apt_packages+=('gcc-multilib')
 apt_packages+=('g++-multilib')
 
+# ct-verif and sanitizers
+apt_packages+=('valgrind')
+
 # Latest Mercurial.
 apt_packages+=('mercurial')
 apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 41BD8711B1F0EC2B0D85B91CF59CE3A8323293EE
 echo "deb http://ppa.launchpad.net/mercurial-ppa/releases/ubuntu xenial main" > /etc/apt/sources.list.d/mercurial.list
 
 # gcc 4.8 and 6
 apt_packages+=('g++-6')
 apt_packages+=('g++-4.8')
--- a/security/nss/automation/taskcluster/graph/src/extend.js
+++ b/security/nss/automation/taskcluster/graph/src/extend.js
@@ -12,17 +12,18 @@ const WINDOWS_CHECKOUT_CMD =
     "(sleep 2; hg clone -r $NSS_HEAD_REVISION $NSS_HEAD_REPOSITORY nss) || " +
     "(sleep 5; hg clone -r $NSS_HEAD_REVISION $NSS_HEAD_REPOSITORY nss)\"";
 
 /*****************************************************************************/
 
 queue.filter(task => {
   if (task.group == "Builds") {
     // Remove extra builds on {A,UB}San and ARM.
-    if (task.collection == "asan" || task.collection == "arm-debug") {
+    if (task.collection == "asan" || task.collection == "arm-debug" ||
+        task.collection == "gyp-asan") {
       return false;
     }
 
     // Remove extra builds w/o libpkix for non-linux64-debug.
     if (task.symbol == "noLibpkix" &&
         (task.platform != "linux64" || task.collection != "debug")) {
       return false;
     }
@@ -36,43 +37,44 @@ queue.filter(task => {
 
     // No BoGo tests on ARM.
     if (task.collection == "arm-debug") {
       return false;
     }
   }
 
   // GYP builds with -Ddisable_libpkix=1 by default.
-  if (task.collection == "gyp" && task.tests == "chains") {
+  if ((task.collection == "gyp" || task.collection == "gyp-asan") &&
+      task.tests == "chains") {
     return false;
   }
 
   return true;
 });
 
 queue.map(task => {
-  if (task.collection == "asan") {
+  if (task.collection == "asan" || task.collection == "gyp-asan") {
     // CRMF and FIPS tests still leak, unfortunately.
     if (task.tests == "crmf" || task.tests == "fips") {
       task.env.ASAN_OPTIONS = "detect_leaks=0";
     }
-
-    // SSL(standard) runs on ASan take some time.
-    if (task.tests == "ssl" && task.cycle == "standard") {
-      task.maxRunTime = 7200;
-    }
   }
 
   if (task.collection == "arm-debug") {
     // These tests take quite some time on our poor ARM devices.
     if (task.tests == "chains" || (task.tests == "ssl" && task.cycle == "standard")) {
       task.maxRunTime = 14400;
     }
   }
 
+  // Windows is slow.
+  if (task.platform == "windows2012-64" && task.tests == "chains") {
+    task.maxRunTime = 7200;
+  }
+
   // Enable TLS 1.3 for every task.
   task.env = task.env || {};
   task.env.NSS_ENABLE_TLS_1_3 = "1";
 
   return task;
 });
 
 /*****************************************************************************/
@@ -109,16 +111,35 @@ export default async function main() {
       "-c",
       "bin/checkout.sh && nss/automation/taskcluster/scripts/build_gyp.sh"
     ],
     platform: "linux64",
     collection: "gyp",
     image: LINUX_IMAGE
   });
 
+  await scheduleLinux("Linux 64 (debug, gyp, asan, ubsan)", {
+    command: [
+      "/bin/bash",
+      "-c",
+      "bin/checkout.sh && nss/automation/taskcluster/scripts/build_gyp.sh -g -v --ubsan --asan"
+    ],
+    env: {
+      ASAN_OPTIONS: "detect_odr_violation=0", // bug 1316276
+      UBSAN_OPTIONS: "print_stacktrace=1",
+      NSS_DISABLE_ARENA_FREE_LIST: "1",
+      NSS_DISABLE_UNLOAD: "1",
+      CC: "clang",
+      CCC: "clang++"
+    },
+    platform: "linux64",
+    collection: "gyp-asan",
+    image: LINUX_IMAGE
+  });
+
   await scheduleLinux("Linux 64 (ASan, debug)", {
     env: {
       UBSAN_OPTIONS: "print_stacktrace=1",
       NSS_DISABLE_ARENA_FREE_LIST: "1",
       NSS_DISABLE_UNLOAD: "1",
       CC: "clang",
       CCC: "clang++",
       USE_UBSAN: "1",
@@ -135,16 +156,18 @@ export default async function main() {
   });
 
   await scheduleWindows("Windows 2012 64 (debug)", {
     collection: "debug"
   });
 
   await scheduleFuzzing();
 
+  await scheduleTestBuilds();
+
   await scheduleTools();
 
   await scheduleLinux("Linux 32 (ARM, debug)", {
     image: "franziskus/nss-arm-ci",
     provisioner: "localprovisioner",
     collection: "arm-debug",
     workerType: "nss-rpi",
     platform: "linux32",
@@ -236,18 +259,21 @@ async function scheduleLinux(name, base)
   return queue.submit();
 }
 
 /*****************************************************************************/
 
 async function scheduleFuzzing() {
   let base = {
     env: {
-      ASAN_OPTIONS: "allocator_may_return_null=1",
+       // bug 1316276
+      ASAN_OPTIONS: "allocator_may_return_null=1:detect_odr_violation=0",
       UBSAN_OPTIONS: "print_stacktrace=1",
+      NSS_DISABLE_ARENA_FREE_LIST: "1",
+      NSS_DISABLE_UNLOAD: "1",
       CC: "clang",
       CCC: "clang++"
     },
     platform: "linux64",
     collection: "fuzz",
     image: LINUX_IMAGE
   };
 
@@ -286,21 +312,103 @@ async function scheduleFuzzing() {
     ],
     env: {GTESTFILTER: "*Fuzz*"},
     tests: "ssl_gtests gtests",
     cycle: "standard",
     symbol: "Gtest",
     kind: "test"
   }));
 
+  queue.scheduleTask(merge(base, {
+    parent: task_build,
+    name: "Cert",
+    command: [
+      "/bin/bash",
+      "-c",
+      "bin/checkout.sh && nss/automation/taskcluster/scripts/fuzz.sh " +
+        "cert nss/fuzz/corpus/cert -max_total_time=300"
+    ],
+    // Need a privileged docker container to remove this.
+    env: {ASAN_OPTIONS: "detect_leaks=0"},
+    symbol: "SCert",
+    kind: "test"
+  }));
+
+  queue.scheduleTask(merge(base, {
+    parent: task_build,
+    name: "SPKI",
+    command: [
+      "/bin/bash",
+      "-c",
+      "bin/checkout.sh && nss/automation/taskcluster/scripts/fuzz.sh " +
+        "spki nss/fuzz/corpus/spki -max_total_time=300"
+    ],
+    // Need a privileged docker container to remove this.
+    env: {ASAN_OPTIONS: "detect_leaks=0"},
+    symbol: "SPKI",
+    kind: "test"
+  }));
+
   return queue.submit();
 }
 
 /*****************************************************************************/
 
+async function scheduleTestBuilds() {
+  let base = {
+    platform: "linux64",
+    collection: "gyp",
+    group: "Test",
+    image: LINUX_IMAGE
+  };
+
+  // Build base definition.
+  let build = merge({
+    command: [
+      "/bin/bash",
+      "-c",
+      "bin/checkout.sh && " +
+      "nss/automation/taskcluster/scripts/build_gyp.sh -g -v --test"
+    ],
+    artifacts: {
+      public: {
+        expires: 24 * 7,
+        type: "directory",
+        path: "/home/worker/artifacts"
+      }
+    },
+    kind: "build",
+    symbol: "B",
+    name: "Linux 64 (debug, gyp, test)"
+  }, base);
+
+  // The task that builds NSPR+NSS.
+  let task_build = queue.scheduleTask(build);
+
+  // Schedule tests.
+  queue.scheduleTask(merge(base, {
+    parent: task_build,
+    name: "mpi",
+    command: [
+      "/bin/bash",
+      "-c",
+      "bin/checkout.sh && nss/automation/taskcluster/scripts/run_tests.sh"
+    ],
+    tests: "mpi",
+    cycle: "standard",
+    symbol: "mpi",
+    kind: "test"
+  }));
+
+  return queue.submit();
+}
+
+
+/*****************************************************************************/
+
 async function scheduleWindows(name, base) {
   base = merge(base, {
     workerType: "nss-win2012r2",
     platform: "windows2012-64",
     env: {
       PATH: "c:\\mozilla-build\\python;c:\\mozilla-build\\msys\\local\\bin;" +
             "c:\\mozilla-build\\7zip;c:\\mozilla-build\\info-zip;" +
             "c:\\mozilla-build\\python\\Scripts;c:\\mozilla-build\\yasm;" +
--- a/security/nss/automation/taskcluster/graph/src/queue.js
+++ b/security/nss/automation/taskcluster/graph/src/queue.js
@@ -10,17 +10,17 @@ import * as image_builder from "./image_
 
 let maps = [];
 let filters = [];
 
 let tasks = new Map();
 let image_tasks = new Map();
 
 let queue = new taskcluster.Queue({
-  baseUrl: "http://taskcluster/queue/v1/"
+  baseUrl: "http://taskcluster/queue/v1"
 });
 
 function fromNow(hours) {
   let d = new Date();
   d.setHours(d.getHours() + (hours|0));
   return d.toJSON();
 }
 
--- a/security/nss/automation/taskcluster/graph/src/try_syntax.js
+++ b/security/nss/automation/taskcluster/graph/src/try_syntax.js
@@ -18,29 +18,29 @@ function parseOptions(opts) {
 
   // If the given value is nonsense default to debug and opt builds.
   if (builds.length == 0) {
     builds = ["d", "o"];
   }
 
   // Parse platforms.
   let allPlatforms = ["linux", "linux64", "linux64-asan", "win64", "arm",
-                      "linux64-gyp", "linux64-fuzz"];
+                      "linux64-gyp", "linux64-gyp-asan", "linux64-fuzz"];
   let platforms = intersect(opts.platform.split(/\s*,\s*/), allPlatforms);
 
   // If the given value is nonsense or "none" default to all platforms.
   if (platforms.length == 0 && opts.platform != "none") {
     platforms = allPlatforms;
   }
 
   // Parse unit tests.
   let aliases = {"gtests": "gtest"};
   let allUnitTests = ["bogo", "crmf", "chains", "cipher", "db", "ec", "fips",
                       "gtest", "lowhash", "merge", "sdr", "smime", "tools",
-                      "ssl"];
+                      "ssl", "mpi", "scert", "spki"];
   let unittests = intersect(opts.unittests.split(/\s*,\s*/).map(t => {
     return aliases[t] || t;
   }), allUnitTests);
 
   // If the given value is "all" run all tests.
   // If it's nonsense then don't run any tests.
   if (opts.unittests == "all") {
     unittests = allUnitTests;
@@ -77,16 +77,20 @@ function filter(opts) {
       return opts.tools.some(tool => {
         return task.symbol.toLowerCase().startsWith(tool);
       });
     }
 
     // Filter unit tests.
     if (task.tests) {
       let found = opts.unittests.some(test => {
+        // TODO: think of something more intelligent here.
+        if (task.symbol.toLowerCase().startsWith("mpi") && test == "mpi") {
+          return true;
+        }
         return (task.group || task.symbol).toLowerCase().startsWith(test);
       });
 
       if (!found) {
         return false;
       }
     }
 
@@ -99,30 +103,33 @@ function filter(opts) {
 
     // Filter by platform.
     let found = opts.platforms.some(platform => {
       let aliases = {
         "linux": "linux32",
         "linux64-asan": "linux64",
         "linux64-fuzz": "linux64",
         "linux64-gyp": "linux64",
+        "linux64-gyp-asan": "linux64",
         "win64": "windows2012-64",
         "arm": "linux32"
       };
 
       // Check the platform name.
       let keep = (task.platform == (aliases[platform] || platform));
 
       // Additional checks.
       if (platform == "linux64-asan") {
         keep &= coll("asan");
       } else if (platform == "arm") {
         keep &= coll("arm-opt") || coll("arm-debug");
       } else if (platform == "linux64-gyp") {
         keep &= coll("gyp");
+      } else if (platform == "linux64-gyp-asan") {
+        keep &= coll("gyp-asan");
       } else if (platform == "linux64-fuzz") {
         keep &= coll("fuzz");
       } else {
         keep &= coll("opt") || coll("debug");
       }
 
       return keep;
     });
new file mode 100755
--- /dev/null
+++ b/security/nss/automation/taskcluster/scripts/fuzz.sh
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+
+source $(dirname $0)/tools.sh
+
+if [ $(id -u) = 0 ]; then
+    # Drop privileges by re-running this script.
+    exec su worker -c "$0 $*"
+fi
+
+# Fetch artifact if needed.
+fetch_dist
+
+# Clone corpus.
+./nss/fuzz/clone_corpus.sh
+
+# Fetch objdir name.
+objdir=$(cat dist/latest)
+
+# Run nssfuzz.
+LD_LIBRARY_PATH=$LD_LIBRARY_PATH:dist/$objdir/lib dist/$objdir/bin/nssfuzz $*
--- a/security/nss/automation/taskcluster/scripts/run_clang_format.sh
+++ b/security/nss/automation/taskcluster/scripts/run_clang_format.sh
@@ -37,16 +37,17 @@ else
          "$top/lib/pki" \
          "$top/lib/smime" \
          "$top/lib/softoken" \
          "$top/lib/ssl" \
          "$top/lib/sysinit" \
          "$top/lib/util" \
          "$top/gtests/common" \
          "$top/gtests/der_gtest" \
+         "$top/gtests/freebl_gtest" \
          "$top/gtests/pk11_gtest" \
          "$top/gtests/ssl_gtest" \
          "$top/gtests/util_gtest" \
     )
 fi
 
 for dir in "${dirs[@]}"; do
     find "$dir" -type f \( -name '*.[ch]' -o -name '*.cc' \) -exec clang-format -i {} \+
--- a/security/nss/automation/taskcluster/scripts/run_tests.sh
+++ b/security/nss/automation/taskcluster/scripts/run_tests.sh
@@ -9,9 +9,9 @@ if [ $(id -u) = 0 ]; then
     # Drop privileges by re-running this script.
     exec su worker $0
 fi
 
 # Fetch artifact if needed.
 fetch_dist
 
 # Run tests.
-cd nss/tests && ./run.sh
+cd nss/tests && ./all.sh
--- a/security/nss/build.sh
+++ b/security/nss/build.sh
@@ -1,22 +1,25 @@
 #!/bin/bash
 # 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.
 
 set -e
 
+source $(dirname $0)/coreconf/nspr.sh
+
 # Usage info
 show_help() {
 cat << EOF
 
 Usage: ${0##*/} [-hcgv] [-j <n>] [--test] [--fuzz] [--scan-build[=output]]
-                [-m32] [--opt|-o]
+                [-m32] [--opt|-o] [--asan] [--ubsan] [--sancov[=edge|bb|func]]
+                [--pprof] [--msan]
 
 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:
 
@@ -26,112 +29,172 @@ NSS build tool options:
     -j <n>        run at most <n> concurrent jobs
     -v            verbose build
     -m32          do a 32-bit build on a 64-bit system
     --test        ignore map files and export everything we have
     --fuzz        enable fuzzing mode. this always enables test builds
     --scan-build  run the build with scan-build (scan-build has to be in the path)
                   --scan-build=/out/path sets the output path for scan-build
     --opt|-o      do an opt build
+    --asan        do an asan build
+    --ubsan       do an ubsan build
+    --msan        do an msan build
+    --sancov      do sanitize coverage builds
+                  --sancov=func sets coverage to function level for example
+    --pprof       build with gperftool support
 EOF
 }
 
 if [ -n "$CCC" ] && [ -z "$CXX" ]; then
     export CXX="$CCC"
 fi
 
 opt_build=0
 build_64=0
 clean=0
 rebuild_gyp=0
 target=Debug
+verbose=0
+fuzz=0
+
+# parse parameters to store in config
+params=$(echo "$*" | perl -pe 's/-c|-v|-g|-j [0-9]*|-h//g' | perl -pe 's/^\s*(.*?)\s*$/\1/')
+params=$(echo "$params $CC $CCC" | tr " " "\n" | perl -pe '/^\s*$/d')
+params=$(echo "${params[*]}" | sort)
+
+cwd=$(cd $(dirname $0); pwd -P)
+dist_dir="$cwd/../dist"
 
 # try to guess sensible defaults
-arch=$(uname -m)
-if [ "$arch" = "x86_64" -o "$arch" = "aarch64" ]; then
+arch=$(python "$cwd/coreconf/detect_host_arch.py")
+if [ "$arch" = "x64" -o "$arch" = "aarch64" ]; then
     build_64=1
 fi
 
 gyp_params=()
 ninja_params=()
 scanbuild=()
-nspr_env=()
+
+enable_fuzz()
+{
+    fuzz=1
+    nspr_sanitizer asan
+    nspr_sanitizer ubsan
+    nspr_sanitizer sancov edge
+    gyp_params+=(-Duse_asan=1)
+    gyp_params+=(-Duse_ubsan=1)
+    gyp_params+=(-Duse_sancov=edge)
+
+    # Adding debug symbols even for opt builds.
+    nspr_opt+=(--enable-debug-symbols)
+}
 
 # parse command line arguments
 while [ $# -gt 0 ]; do
     case $1 in
         -c) clean=1 ;;
         -g) rebuild_gyp=1 ;;
         -j) ninja_params+=(-j "$2"); shift ;;
-        -v) ninja_params+=(-v) ;;
+        -v) ninja_params+=(-v); verbose=1 ;;
         --test) gyp_params+=(-Dtest_build=1) ;;
-        --fuzz) gyp_params+=(-Dtest_build=1 -Dfuzz=1) ;;
+        --fuzz) gyp_params+=(-Dtest_build=1 -Dfuzz=1); enable_fuzz ;;
         --scan-build) scanbuild=(scan-build) ;;
         --scan-build=?*) scanbuild=(scan-build -o "${1#*=}") ;;
-        --opt|-o) opt_build=1; nspr_env+=(BUILD_OPT=1) ;;
+        --opt|-o) opt_build=1 ;;
         -m32|--m32) build_64=0 ;;
+        --asan) gyp_params+=(-Duse_asan=1); nspr_sanitizer asan ;;
+        --ubsan) gyp_params+=(-Duse_ubsan=1); nspr_sanitizer ubsan ;;
+        --sancov) gyp_params+=(-Duse_sancov=edge); nspr_sanitizer sancov edge ;;
+        --sancov=?*) gyp_params+=(-Duse_sancov="${1#*=}"); nspr_sanitizer sancov "${1#*=}" ;;
+        --pprof) gyp_params+=(-Duse_pprof=1) ;;
+        --msan) gyp_params+=(-Duse_msan=1); nspr_sanitizer msan ;;
         *) show_help; exit ;;
     esac
     shift
 done
 
 if [ "$opt_build" = "1" ]; then
     target=Release
+    nspr_opt+=(--disable-debug --enable-optimize)
 else
     target=Debug
 fi
 if [ "$build_64" == "1" ]; then
-    target="${target}_x64"
-    nspr_env+=(USE_64=1)
+    nspr_opt+=(--enable-64bit)
 else
     gyp_params+=(-Dtarget_arch=ia32)
+    nspr_opt+=(--enable-x32)
+fi
+
+# clone fuzzing stuff
+if [ "$fuzz" = "1" ]; then
+    [ $verbose = 0 ] && exec 3>/dev/null || exec 3>&1
+
+    echo "[1/2] Cloning libFuzzer files ..."
+    $cwd/fuzz/clone_libfuzzer.sh 1>&3 2>&3
+
+    echo "[2/2] Cloning fuzzing corpus ..."
+    $cwd/fuzz/clone_corpus.sh 1>&3 2>&3
+
+    exec 3>&-
+fi
+
+# check if we have to rebuild gyp
+if [ "$params" != "$(cat $cwd/out/config 2>/dev/null)" -o "$rebuild_gyp" == 1 -o "$clean" == 1 ]; then
+    rebuild_gyp=1
+    rm -rf "$cwd/../nspr/$target" # force NSPR to rebuild
 fi
 
 # set paths
-cwd=$(cd $(dirname $0); pwd -P)
-dist_dir="$cwd/../dist"
 target_dir="$cwd/out/$target"
 
 # get the realpath of $dist_dir
 dist_dir=$(mkdir -p $dist_dir; cd $dist_dir; pwd -P)
 
-# save the chosen target
-echo $target > $dist_dir/latest
-
 # get object directory
 obj_dir="$dist_dir/$target"
 gyp_params+=(-Dnss_dist_dir=$dist_dir)
 gyp_params+=(-Dnss_dist_obj_dir=$obj_dir)
+gyp_params+=(-Dnspr_lib_dir=$obj_dir/lib)
+gyp_params+=(-Dnspr_include_dir=$obj_dir/include/nspr)
 
 # -c = clean first
 if [ "$clean" = 1 ]; then
     rm -rf "$cwd/out"
     rm -rf "$cwd/../nspr/$target"
+    rm -rf "$dist_dir"
 fi
 
-# figure out the scan-build string
+# save the chosen target
+mkdir -p $dist_dir
+echo $target > $dist_dir/latest
+
+# pass on CC and CCC
 if [ "${#scanbuild[@]}" -gt 0 ]; then
     if [ -n "$CC" ]; then
        scanbuild+=(--use-cc="$CC")
     fi
     if [ -n "$CCC" ]; then
        scanbuild+=(--use-c++="$CCC")
     fi
  fi
 
 # These steps can take a while, so don't overdo them.
 # Force a redo with -g.
 if [ "$rebuild_gyp" = 1 -o ! -d "$target_dir" ]; then
-    # Build NSPR.
-    make "${nspr_env[@]}" -C "$cwd" NSS_GYP_PREFIX=$obj_dir install_nspr
+    build_nspr $verbose
 
     # Run gyp.
-    PKG_CONFIG_PATH="$obj_dir/lib/pkgconfig" \
-        "${scanbuild[@]}" gyp -f ninja "${gyp_params[@]}" --depth="$cwd" \
-          --generator-output="." "$cwd/nss.gyp"
+    [ $verbose = 1 ] && set -v -x
+    "${scanbuild[@]}" gyp -f ninja "${gyp_params[@]}" --depth="$cwd" \
+      --generator-output="." "$cwd/nss.gyp"
+    [ $verbose = 1 ] && set +v +x
+
+    # Store used parameters for next run.
+    echo "$params" > "$cwd/out/config"
 fi
 
 # Run ninja.
 if which ninja >/dev/null 2>&1; then
     ninja=(ninja)
 elif which ninja-build >/dev/null 2>&1; then
     ninja=(ninja-build)
 else
--- a/security/nss/cmd/certutil/certutil.c
+++ b/security/nss/cmd/certutil/certutil.c
@@ -199,16 +199,17 @@ CertReq(SECKEYPrivateKey *privk, SECKEYP
     if (!arena) {
         SECU_PrintError(progName, "out of memory");
         return SECFailure;
     }
 
     /* Create info about public key */
     spki = SECKEY_CreateSubjectPublicKeyInfo(pubk);
     if (!spki) {
+        PORT_FreeArena(arena, PR_FALSE);
         SECU_PrintError(progName, "unable to create subject public key");
         return SECFailure;
     }
 
     /* Change cert type to RSA-PSS, if desired. */
     if (pssCertificate) {
         spki->algorithm.parameters.data = NULL;
         rv = SECOID_SetAlgorithmID(arena, &spki->algorithm,
--- a/security/nss/cmd/ecperf/ecperf.c
+++ b/security/nss/cmd/ecperf/ecperf.c
@@ -4,16 +4,17 @@
 
 #include "blapi.h"
 #include "ec.h"
 #include "ecl-curve.h"
 #include "prprf.h"
 #include "basicutil.h"
 #include "pkcs11.h"
 #include "nspr.h"
+#include "secutil.h"
 #include <stdio.h>
 
 #define __PASTE(x, y) x##y
 
 /*
  * Get the NSS specific PKCS #11 function names.
  */
 #undef CK_PKCS11_FUNCTION_INFO
@@ -88,18 +89,16 @@ static SECOidTag ecCurve_oid_map[] = {
     SEC_OID_UNKNOWN, /* ECCurve_WTLS_9 */
     SEC_OID_CURVE25519,
     SEC_OID_UNKNOWN /* ECCurve_pastLastCurve */
 };
 
 typedef SECStatus (*op_func)(void *, void *, void *);
 typedef SECStatus (*pk11_op_func)(CK_SESSION_HANDLE, void *, void *, void *);
 
-typedef SECItem SECKEYECParams;
-
 typedef struct ThreadDataStr {
     op_func op;
     void *p1;
     void *p2;
     void *p3;
     int iters;
     PRLock *lock;
     int count;
@@ -287,70 +286,16 @@ M_TimeOperation(void (*threadFunc)(void 
     if (usepkcs11) {                                                              \
         printf("Testing %s using pkcs11 implementation...\n", name_c);            \
         rv = ectest_curve_pkcs11(name_v, iterations, numThreads);                 \
         if (rv != SECSuccess)                                                     \
             goto cleanup;                                                         \
         printf("... okay.\n");                                                    \
     }
 
-/*
- * Initializes a SECItem from a hexadecimal string
- *
- * Warning: This function ignores leading 00's, so any leading 00's
- * in the hexadecimal string must be optional.
- */
-static SECItem *
-hexString2SECItem(PLArenaPool *arena, SECItem *item, const char *str)
-{
-    int i = 0;
-    int byteval = 0;
-    int tmp = PORT_Strlen(str);
-
-    PORT_Assert(arena);
-    PORT_Assert(item);
-
-    if ((tmp % 2) != 0) {
-        return NULL;
-    }
-
-    /* skip leading 00's unless the hex string is "00" */
-    while ((tmp > 2) && (str[0] == '0') && (str[1] == '0')) {
-        str += 2;
-        tmp -= 2;
-    }
-
-    item = SECITEM_AllocItem(arena, item, tmp / 2);
-    if (item == NULL) {
-        return NULL;
-    }
-
-    while (str[i]) {
-        if ((str[i] >= '0') && (str[i] <= '9')) {
-            tmp = str[i] - '0';
-        } else if ((str[i] >= 'a') && (str[i] <= 'f')) {
-            tmp = str[i] - 'a' + 10;
-        } else if ((str[i] >= 'A') && (str[i] <= 'F')) {
-            tmp = str[i] - 'A' + 10;
-        } else {
-            /* item is in arena and gets freed by the caller */
-            return NULL;
-        }
-
-        byteval = byteval * 16 + tmp;
-        if ((i % 2) != 0) {
-            item->data[i / 2] = byteval;
-            byteval = 0;
-        }
-        i++;
-    }
-
-    return item;
-}
-
 #define PK11_SETATTRS(x, id, v, l) \
     (x)->type = (id);              \
     (x)->pValue = (v);             \
     (x)->ulValueLen = (l);
 
 SECStatus
 PKCS11_Derive(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE *hKey,
               CK_MECHANISM *pMech, int *dummy)
@@ -617,26 +562,26 @@ ectest_curve_freebl(ECCurveName curve, i
     ecParams.curve.seed.data = NULL;
     ecParams.curve.seed.len = 0;
     ecParams.DEREncoding.data = NULL;
     ecParams.DEREncoding.len = 0;
     ecParams.pointSize = ecCurve_map[curve]->pointSize;
 
     ecParams.fieldID.size = ecCurve_map[curve]->size;
     ecParams.fieldID.type = fieldType;
-    hexString2SECItem(arena, &ecParams.fieldID.u.prime, ecCurve_map[curve]->irr);
-    hexString2SECItem(arena, &ecParams.curve.a, ecCurve_map[curve]->curvea);
-    hexString2SECItem(arena, &ecParams.curve.b, ecCurve_map[curve]->curveb);
+    SECU_HexString2SECItem(arena, &ecParams.fieldID.u.prime, ecCurve_map[curve]->irr);
+    SECU_HexString2SECItem(arena, &ecParams.curve.a, ecCurve_map[curve]->curvea);
+    SECU_HexString2SECItem(arena, &ecParams.curve.b, ecCurve_map[curve]->curveb);
     genenc[0] = '0';
     genenc[1] = '4';
     genenc[2] = '\0';
     strcat(genenc, ecCurve_map[curve]->genx);
     strcat(genenc, ecCurve_map[curve]->geny);
-    hexString2SECItem(arena, &ecParams.base, genenc);
-    hexString2SECItem(arena, &ecParams.order, ecCurve_map[curve]->order);
+    SECU_HexString2SECItem(arena, &ecParams.base, genenc);
+    SECU_HexString2SECItem(arena, &ecParams.order, ecCurve_map[curve]->order);
     ecParams.cofactor = ecCurve_map[curve]->cofactor;
 
     PORT_Memset(digestData, 0xa5, sizeof(digestData));
     digest.data = digestData;
     digest.len = sizeof(digestData);
     sig.data = sigData;
     sig.len = sizeof(sigData);
 
--- a/security/nss/cmd/ecperf/ecperf.gyp
+++ b/security/nss/cmd/ecperf/ecperf.gyp
@@ -17,17 +17,17 @@
         '<(DEPTH)/exports.gyp:dbm_exports',
         '<(DEPTH)/exports.gyp:nss_exports',
         '<(DEPTH)/lib/sqlite/sqlite.gyp:sqlite3'
       ]
     }
   ],
   'target_defaults': {
     'include_dirs': [
-      '../../nss/lib/softoken'
+      '<(DEPTH)/lib/softoken',
     ],
     'defines': [
       'NSS_USE_STATIC_LIBS'
     ]
   },
   'variables': {
     'module': 'nss',
     'use_static_libs': 1
--- a/security/nss/cmd/fbectest/fbectest.c
+++ b/security/nss/cmd/fbectest/fbectest.c
@@ -4,16 +4,17 @@
 
 #include "blapi.h"
 #include "ec.h"
 #include "ecl-curve.h"
 #include "prprf.h"
 #include "basicutil.h"
 #include "secder.h"
 #include "secitem.h"
+#include "secutil.h"
 #include "nspr.h"
 #include <stdio.h>
 
 typedef struct {
     ECCurveName curve;
     int iterations;
     char *privhex;
     char *our_pubhex;
@@ -27,62 +28,16 @@ typedef struct {
     ECCurveName curve;
     char *point;
     char *name;
     ECFieldType fieldType;
 } ECDH_BAD;
 
 #include "testvecs.h"
 
-/*
- * Initializes a SECItem from a hexadecimal string
- *
- */
-static SECItem *
-hexString2SECItem(PLArenaPool *arena, SECItem *item, const char *str)
-{
-    int i = 0;
-    int byteval = 0;
-    int tmp = PORT_Strlen(str);
-
-    PORT_Assert(arena);
-    PORT_Assert(item);
-
-    if ((tmp % 2) != 0) {
-        return NULL;
-    }
-
-    item = SECITEM_AllocItem(arena, item, tmp / 2);
-    if (item == NULL) {
-        return NULL;
-    }
-
-    while (str[i]) {
-        if ((str[i] >= '0') && (str[i] <= '9')) {
-            tmp = str[i] - '0';
-        } else if ((str[i] >= 'a') && (str[i] <= 'f')) {
-            tmp = str[i] - 'a' + 10;
-        } else if ((str[i] >= 'A') && (str[i] <= 'F')) {
-            tmp = str[i] - 'A' + 10;
-        } else {
-            /* item is in arena and gets freed by the caller */
-            return NULL;
-        }
-
-        byteval = byteval * 16 + tmp;
-        if ((i % 2) != 0) {
-            item->data[i / 2] = byteval;
-            byteval = 0;
-        }
-        i++;
-    }
-
-    return item;
-}
-
 void
 printBuf(const SECItem *item)
 {
     int i;
     if (!item || !item->len) {
         printf("(null)\n");
         return;
     }
@@ -138,47 +93,47 @@ ectest_ecdh_kat(ECDH_KAT *kat)
     char genenc[3 + 2 * 2 * MAX_ECKEY_LEN];
     int i;
 
     rv = init_params(&ecParams, curve, &arena, kat->fieldType);
     if (rv != SECSuccess) {
         return rv;
     }
 
-    hexString2SECItem(arena, &ecParams.fieldID.u.prime, ecCurve_map[curve]->irr);
-    hexString2SECItem(arena, &ecParams.curve.a, ecCurve_map[curve]->curvea);
-    hexString2SECItem(arena, &ecParams.curve.b, ecCurve_map[curve]->curveb);
+    SECU_HexString2SECItem(arena, &ecParams.fieldID.u.prime, ecCurve_map[curve]->irr);
+    SECU_HexString2SECItem(arena, &ecParams.curve.a, ecCurve_map[curve]->curvea);
+    SECU_HexString2SECItem(arena, &ecParams.curve.b, ecCurve_map[curve]->curveb);
     genenc[0] = '0';
     genenc[1] = '4';
     genenc[2] = '\0';
     PORT_Assert(PR_ARRAY_SIZE(genenc) >= PORT_Strlen(ecCurve_map[curve]->genx));
     PORT_Assert(PR_ARRAY_SIZE(genenc) >= PORT_Strlen(ecCurve_map[curve]->geny));
     strcat(genenc, ecCurve_map[curve]->genx);
     strcat(genenc, ecCurve_map[curve]->geny);
-    hexString2SECItem(arena, &ecParams.base, genenc);
-    hexString2SECItem(arena, &ecParams.order, ecCurve_map[curve]->order);
+    SECU_HexString2SECItem(arena, &ecParams.base, genenc);
+    SECU_HexString2SECItem(arena, &ecParams.order, ecCurve_map[curve]->order);
 
     if (kat->our_pubhex) {
-        hexString2SECItem(arena, &answer, kat->our_pubhex);
+        SECU_HexString2SECItem(arena, &answer, kat->our_pubhex);
     }
-    hexString2SECItem(arena, &seed, kat->privhex);
+    SECU_HexString2SECItem(arena, &seed, kat->privhex);
     rv = EC_NewKeyFromSeed(&ecParams, &ecPriv, seed.data, seed.len);
     if (rv != SECSuccess) {
         rv = SECFailure;
         goto cleanup;
     }
     if (kat->our_pubhex) {
         if (SECITEM_CompareItem(&answer, &ecPriv->publicValue) != SECEqual) {
             rv = SECFailure;
             goto cleanup;
         }
     }
 
-    hexString2SECItem(arena, &theirKey, kat->their_pubhex);
-    hexString2SECItem(arena, &answer2, kat->common_key);
+    SECU_HexString2SECItem(arena, &theirKey, kat->their_pubhex);
+    SECU_HexString2SECItem(arena, &answer2, kat->common_key);
 
     rv = EC_ValidatePublicKey(&ecParams, &theirKey);
     if (rv != SECSuccess) {
         printf("EC_ValidatePublicKey failed\n");
         goto cleanup;
     }
 
     for (i = 0; i < kat->iterations; ++i) {
@@ -226,17 +181,17 @@ ectest_validate_point(ECDH_BAD *bad)
     SECStatus rv = SECFailure;
     PLArenaPool *arena = NULL;
 
     rv = init_params(&ecParams, bad->curve, &arena, bad->fieldType);
     if (rv != SECSuccess) {
         return rv;
     }
 
-    hexString2SECItem(arena, &point, bad->point);
+    SECU_HexString2SECItem(arena, &point, bad->point);
     rv = EC_ValidatePublicKey(&ecParams, &point);
 
     PORT_FreeArena(arena, PR_FALSE);
     return rv;
 }
 
 void
 printUsage(char *prog)
--- a/security/nss/cmd/fbectest/fbectest.gyp
+++ b/security/nss/cmd/fbectest/fbectest.gyp
@@ -16,17 +16,17 @@
       'dependencies': [
         '<(DEPTH)/exports.gyp:nss_exports',
         '<(DEPTH)/lib/sqlite/sqlite.gyp:sqlite3'
       ]
     }
   ],
   'target_defaults': {
     'include_dirs': [
-      '../../nss/lib/softoken'
+      '<(DEPTH)/lib/softoken',
     ],
     'defines': [
       'NSS_USE_STATIC_LIBS'
     ]
   },
   'variables': {
     'module': 'nss',
     'use_static_libs': 1
--- a/security/nss/cmd/lib/exports.gyp
+++ b/security/nss/cmd/lib/exports.gyp
@@ -11,17 +11,17 @@
       'type': 'none',
       'copies': [
         {
           'files': [
             'basicutil.h',
             'pk11table.h',
             'secutil.h'
           ],
-          'destination': '<(nss_dist_dir)/private/<(module)'
+          'destination': '<(nss_private_dist_dir)/<(module)'
         }
       ]
     }
   ],
   'variables': {
     'module': 'nss'
   }
 }
--- a/security/nss/cmd/lib/secutil.c
+++ b/security/nss/cmd/lib/secutil.c
@@ -3827,8 +3827,51 @@ SECU_ParseSSLVersionRangeString(const ch
 
     if (vrange->min > vrange->max) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return SECFailure;
     }
 
     return SECSuccess;
 }
+
+SECItem *
+SECU_HexString2SECItem(PLArenaPool *arena, SECItem *item, const char *str)
+{
+    int i = 0;
+    int byteval = 0;
+    int tmp = PORT_Strlen(str);
+
+    PORT_Assert(arena);
+    PORT_Assert(item);
+
+    if ((tmp % 2) != 0) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return NULL;
+    }
+
+    item = SECITEM_AllocItem(arena, item, tmp / 2);
+    if (item == NULL) {
+        return NULL;
+    }
+
+    while (str[i]) {
+        if ((str[i] >= '0') && (str[i] <= '9')) {
+            tmp = str[i] - '0';
+        } else if ((str[i] >= 'a') && (str[i] <= 'f')) {
+            tmp = str[i] - 'a' + 10;
+        } else if ((str[i] >= 'A') && (str[i] <= 'F')) {
+            tmp = str[i] - 'A' + 10;
+        } else {
+            /* item is in arena and gets freed by the caller */
+            return NULL;
+        }
+
+        byteval = byteval * 16 + tmp;
+        if ((i % 2) != 0) {
+            item->data[i / 2] = byteval;
+            byteval = 0;
+        }
+        i++;
+    }
+
+    return item;
+}
--- a/security/nss/cmd/lib/secutil.h
+++ b/security/nss/cmd/lib/secutil.h
@@ -317,22 +317,22 @@ extern SECOidTag SECU_StringToSignatureA
 extern SECStatus SECU_StoreCRL(PK11SlotInfo *slot, SECItem *derCrl,
                                PRFileDesc *outFile, PRBool ascii, char *url);
 
 /*
 ** DER sign a single block of data using private key encryption and the
 ** MD5 hashing algorithm. This routine first computes a digital signature
 ** using SEC_SignData, then wraps it with an CERTSignedData and then der
 ** encodes the result.
-**	"arena" is the memory arena to use to allocate data from
-**      "sd" returned CERTSignedData
-** 	"result" the final der encoded data (memory is allocated)
-** 	"buf" the input data to sign
-** 	"len" the amount of data to sign
-** 	"pk" the private key to encrypt with
+**     "arena" is the memory arena to use to allocate data from
+**     "sd" returned CERTSignedData
+**     "result" the final der encoded data (memory is allocated)
+**     "buf" the input data to sign
+**     "len" the amount of data to sign
+**     "pk" the private key to encrypt with
 */
 extern SECStatus SECU_DerSignDataCRL(PLArenaPool *arena, CERTSignedData *sd,
                                      unsigned char *buf, int len,
                                      SECKEYPrivateKey *pk, SECOidTag algID);
 
 typedef enum {
     noKeyFound = 1,
     noSignatureMatch = 2,
@@ -397,16 +397,21 @@ SECU_SECItemHexStringToBinary(SECItem *s
  * the caller must provide the desired default values for the min/max values,
  * by providing defaultVersionRange (which can be obtained from libssl by
  * calling SSL_VersionRangeGetSupported).
  */
 SECStatus
 SECU_ParseSSLVersionRangeString(const char *input,
                                 const SSLVersionRange defaultVersionRange,
                                 SSLVersionRange *vrange);
+/*
+** Read a hex string into a SecItem.
+*/
+extern SECItem *SECU_HexString2SECItem(PLArenaPool *arena, SECItem *item,
+                                       const char *str);
 
 /*
  *
  *  Error messaging
  *
  */
 
 void printflags(char *trusts, unsigned int flags);
--- a/security/nss/cmd/modutil/modutil.gyp
+++ b/security/nss/cmd/modutil/modutil.gyp
@@ -24,18 +24,18 @@
         '<(DEPTH)/exports.gyp:dbm_exports',
         '<(DEPTH)/lib/jar/jar.gyp:jar',
         '<(DEPTH)/lib/zlib/zlib.gyp:nss_zlib'
       ]
     }
   ],
   'target_defaults': {
     'include_dirs': [
-      '<(nss_dist_dir)/private/nss',
-      '<(nss_dist_dir)/private/dbm'
+      '<(nss_private_dist_dir)/nss',
+      '<(nss_private_dist_dir)/dbm'
     ],
     'defines': [
       'NSPR20',
       'YY_NO_UNPUT',
       'YY_NO_INPUT'
     ]
   },
   'variables': {
new file mode 100644
--- /dev/null
+++ b/security/nss/cmd/mpitests/mpi-test.c
@@ -0,0 +1,2127 @@
+/*
+ * mpi-test.c
+ *
+ * This is a general test suite for the MPI library, which tests
+ * all the functions in the library with known values.  The program
+ * exits with a zero (successful) status if the tests pass, or a
+ * nonzero status if the tests fail.
+ *
+ * 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/. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <time.h>
+
+#include "mpi.h"
+#include "mpprime.h"
+
+#include "test-info.c"
+
+/* ZS means Zero Suppressed (no leading zeros) */
+#if MP_USE_LONG_DIGIT
+#define ZS_DIGIT_FMT "%lX"
+#elif MP_USE_LONG_LONG_DIGIT
+#define ZS_DIGIT_FMT "%llX"
+#elif MP_USE_UINT_DIGIT
+#define ZS_DIGIT_FMT "%X"
+#else
+#error "unknown type of digit"
+#endif
+
+/*
+  Test vectors
+
+  If you intend to change any of these values, you must also recompute
+  the corresponding solutions below.  Basically, these are just hex
+  strings (for the big integers) or integer values (for the digits).
+
+  The comparison tests think they know what relationships hold between
+  these values.  If you change that, you may have to adjust the code
+  for the comparison tests accordingly.  Most of the other tests
+  should be fine as long as you re-compute the solutions, though.
+ */
+const char *mp1 = "639A868CDA0C569861B";
+const char *mp2 = "AAFC0A3FE45E5E09DBE2C29";
+const char *mp3 = "B55AA8DF8A7E83241F38AC7A9E479CAEF2E4D7C5";
+const char *mp4 = "-63DBC2265B88268DC801C10EA68476B7BDE0090F";
+const char *mp5 = "F595CB42";
+const char *mp5a = "-4B597E";
+const char *mp6 = "0";
+const char *mp7 = "EBFA7121CD838CE6439CC59DDB4CBEF3";
+const char *mp8 = "5";
+const char *mp9 = "F74A2876A1432698923B0767DA19DCF3D71795EE";
+const char *mp10 = "9184E72A000";
+const char *mp11 = "54D79A3557E8";
+const char *mp12 = "10000000000000000";
+const char *mp13 =
+    "34584F700C15A341E40BF7BFDD88A6630C8FF2B2067469372D391342BDAB6163963C"
+    "D5A5C79F708BDE26E0CCF2DB66CD6D6089E29A877C45F2B050D226E6DA88";
+const char *mp14 =
+    "AC3FA0EABAAC45724814D798942A1E28E14C81E0DE8055CED630E7689DA648683645DB6E"
+    "458D9F5338CC3D4E33A5D1C9BF42780133599E60DEE0049AFA8F9489501AE5C9AA2B8C13"
+    "FD21285A538B2CA87A626BB56E0A654C8707535E637FF4E39174157402BDE3AA30C9F134"
+    "0C1307BAA864B075A9CC828B6A5E2B2BF1AE406D920CC5E7657D7C0E697DEE5375773AF9"
+    "E200A1B8FAD7CD141F9EE47ABB55511FEB9A4D99EBA22F3A3FF6792FA7EE9E5DC0EE94F7"
+    "7A631EDF3D7DD7C2DAAAFDF234D60302AB63D5234CEAE941B9AF0ADDD9E6E3A940A94EE5"
+    "5DB45A7C66E61EDD0477419BBEFA44C325129601C4F45671C6A0E64665DF341D17FBC71F"
+    "77418BD9F4375DDB3B9D56126526D8E5E0F35A121FD4F347013DA880020A752324F31DDD"
+    "9BCDB13A3B86E207A2DE086825E6EEB87B3A64232CFD8205B799BC018634AAE193F19531"
+    "D6EBC19A75F27CFFAA03EB5974898F53FD569AA5CE60F431B53B0CDE715A5F382405C9C4"
+    "761A8E24888328F09F7BCE4E8D80C957DF177629C8421ACCD0C268C63C0DD47C3C0D954F"
+    "D79F7D7297C6788DF4B3E51381759864D880ACA246DF09533739B8BB6085EAF7AE8DC2D9"
+    "F224E6874926C8D24D34B457FD2C9A586C6B99582DC24F787A39E3942786CF1D494B6EB4"
+    "A513498CDA0B217C4E80BCE7DA1C704C35E071AC21E0DA9F57C27C3533F46A8D20B04137"
+    "C1B1384BE4B2EB46";
+const char *mp15 =
+    "39849CF7FD65AF2E3C4D87FE5526221103D90BA26A6642FFE3C3ECC0887BBBC57E011BF1"
+    "05D822A841653509C68F79EBE51C0099B8CBB04DEF31F36F5954208A3209AC122F0E11D8"
+    "4AE67A494D78336A2066D394D42E27EF6B03DDAF6D69F5112C93E714D27C94F82FC7EF77"
+    "445768C68EAE1C4A1407BE1B303243391D325090449764AE469CC53EC8012C4C02A72F37"
+    "07ED7275D2CC8D0A14B5BCC6BF264941520EBA97E3E6BAE4EE8BC87EE0DDA1F5611A6ECB"
+    "65F8AEF4F184E10CADBDFA5A2FEF828901D18C20785E5CC63473D638762DA80625003711"
+    "9E984AC43E707915B133543AF9D5522C3E7180DC58E1E5381C1FB7DC6A5F4198F3E88FA6"
+    "CBB6DFA8B2D1C763226B253E18BCCB79A29EE82D2DE735078C8AE3C3C86D476AAA08434C"
+    "09C274BDD40A1D8FDE38D6536C22F44E807EB73DE4FB36C9F51E0BC835DDBE3A8EFCF2FE"
+    "672B525769DC39230EE624D5EEDBD837C82A52E153F37378C3AD68A81A7ADBDF3345DBCE"
+    "8FA18CA1DE618EF94DF72EAD928D4F45B9E51632ACF158CF8332C51891D1D12C2A7E6684"
+    "360C4BF177C952579A9F442CFFEC8DAE4821A8E7A31C4861D8464CA9116C60866C5E72F7"
+    "434ADBED36D54ACDFDFF70A4EFB46E285131FE725F1C637D1C62115EDAD01C4189716327"
+    "BFAA79618B1656CBFA22C2C965687D0381CC2FE0245913C4D8D96108213680BD8E93E821"
+    "822AD9DDBFE4BD04";
+const char *mp16 = "4A724340668DB150339A70";
+const char *mp17 = "8ADB90F58";
+const char *mp18 = "C64C230AB20E5";
+const char *mp19 =
+    "F1C9DACDA287F2E3C88DCE2393B8F53DAAAC1196DC36510962B6B59454CFE64B";
+const char *mp20 =
+    "D445662C8B6FE394107B867797750C326E0F4A967E135FC430F6CD7207913AC7";
+const char *mp21 = "2";
+
+const mp_digit md1 = 0;
+const mp_digit md2 = 0x1;
+const mp_digit md3 = 0x80;
+const mp_digit md4 = 0x9C97;
+const mp_digit md5 = 0xF5BF;
+const mp_digit md6 = 0x14A0;
+const mp_digit md7 = 0x03E8;
+const mp_digit md8 = 0x0101;
+const mp_digit md9 = 0xA;
+
+/*
+   Solutions of the form x_mpABC, where:
+
+   x = (p)roduct, (s)um, (d)ifference, (q)uotient, (r)emainder, (g)cd,
+       (i)nverse, (e)xponent, square roo(t), (g)cd, (l)cm.  A
+       leading 'm' indicates a modular operation, e.g. ms_mp12 is the
+       modular sum of operands 1 and 2
+
+   ABC are the operand numbers involved in the computation.  If a 'd'
+   precedes the number, it is a digit operand; if a 'c' precedes it,
+   it is a constant; otherwise, it is a full integer.
+ */
+
+const char *p_mp12 = "4286AD72E095C9FE009938750743174ADDD7FD1E53";
+const char *p_mp34 = "-46BDBD66CA108C94A8CF46C325F7B6E2F2BA82D35"
+                     "A1BFD6934C441EE369B60CA29BADC26845E918B";
+const char *p_mp57 = "E260C265A0A27C17AD5F4E59D6E0360217A2EBA6";
+const char *p_mp22 = "7233B5C1097FFC77CCF55928FDC3A5D31B712FDE7A1E91";
+const char *p_mp1d4 = "3CECEA2331F4220BEF68DED";
+const char *p_mp8d6 = "6720";
+const char *p_mp1113 =
+    "11590FC3831C8C3C51813142C88E566408DB04F9E27642F6471A1822E0100B12F7F1"
+    "5699A127C0FA9D26DCBFF458522661F30C6ADA4A07C8C90F9116893F6DBFBF24C3A2"
+    "4340";
+const char *p_mp1415 =
+    "26B36540DE8B3586699CCEAE218A2842C7D5A01590E70C4A26E789107FBCDB06AA2C"
+    "6DDC39E6FA18B16FCB2E934C9A5F844DAD60EE3B1EA82199EC5E9608F67F860FB965"
+    "736055DF0E8F2540EB28D07F47E309B5F5D7C94FF190AB9C83A6970160CA700B1081"
+    "F60518132AF28C6CEE6B7C473E461ABAC52C39CED50A08DD4E7EA8BA18DAD545126D"
+    "A388F6983C29B6BE3F9DCBC15766E8E6D626A92C5296A9C4653CAE5788350C0E2107"
+    "F57E5E8B6994C4847D727FF1A63A66A6CEF42B9C9E6BD04C92550B85D5527DE8A132"
+    "E6BE89341A9285C7CE7FB929D871BBCBD0ED2863B6B078B0DBB30FCA66D6C64284D6"
+    "57F394A0271E15B6EC7A9D530EBAC6CA262EF6F97E1A29FCE7749240E4AECA591ECF"
+    "272122BC587370F9371B67BB696B3CDC1BC8C5B64B6280994EBA00CDEB8EB0F5D06E"
+    "18F401D65FDCECF23DD7B9BB5B4C5458AEF2CCC09BA7F70EACB844750ACFD027521E"
+    "2E047DE8388B35F8512D3DA46FF1A12D4260213602BF7BFFDB6059439B1BD0676449"
+    "8D98C74F48FB3F548948D5BA0C8ECFCD054465132DC43466D6BBD59FBAF8D6D4E157"
+    "2D612B40A956C7D3E140F3B8562EF18568B24D335707D5BAC7495014DF2444172426"
+    "FD099DED560D30D1F945386604AFC85C64BD1E5F531F5C7840475FC0CF0F79810012"
+    "4572BAF5A9910CDBD02B27FFCC3C7E5E88EF59F3AE152476E33EDA696A4F751E0AE4"
+    "A3D2792DEA78E25B9110E12A19EFD09EA47FF9D6594DA445478BEB6901EAF8A35B2D"
+    "FD59BEE9BF7AA8535B7D326EFA5AA2121B5EBE04DD85827A3D43BD04F4AA6D7B62A2"
+    "B6D7A3077286A511A431E1EF75FCEBA3FAE9D5843A8ED17AA02BBB1B571F904699C5"
+    "A6073F87DDD012E2322AB3F41F2A61F428636FE86914148E19B8EF8314ED83332F2F"
+    "8C2ADE95071E792C0A68B903E060DD322A75FD0C2B992059FCCBB58AFA06B50D1634"
+    "BBD93F187FCE0566609FCC2BABB269C66CEB097598AA17957BB4FDA3E64A1B30402E"
+    "851CF9208E33D52E459A92C63FBB66435BB018E155E2C7F055E0B7AB82CD58FC4889"
+    "372ED9EEAC2A07E8E654AB445B9298D2830D6D4DFD117B9C8ABE3968927DC24B3633"
+    "BAD6E6466DB45DDAE87A0AB00336AC2CCCE176704F7214FCAB55743AB76C2B6CA231"
+    "7984610B27B5786DE55C184DDF556EDFEA79A3652831940DAD941E243F482DC17E50"
+    "284BC2FB1AD712A92542C573E55678878F02DFD9E3A863C7DF863227AEDE14B47AD3"
+    "957190124820ADC19F5353878EDB6BF7D0C77352A6E3BDB53EEB88F5AEF6226D6E68"
+    "756776A8FB49B77564147A641664C2A54F7E5B680CCC6A4D22D894E464DF20537094"
+    "548F1732452F9E7F810C0B4B430C073C0FBCE03F0D03F82630654BCE166AA772E1EE"
+    "DD0C08D3E3EBDF0AF54203B43AFDFC40D8FC79C97A4B0A4E1BEB14D8FCEFDDED8758"
+    "6ED65B18";
+const char *p_mp2121 = "4";
+const char *mp_mp345 = "B9B6D3A3";
+const char *mp_mp335 = "16609C2D";
+
+const char *s_mp13 = "B55AA8DF8A7E83241F38B2B446B06A4FB84E5DE0";
+const char *s_mp34 = "517EE6B92EF65C965736EB6BF7C325F73504CEB6";
+const char *s_mp46 = "-63DBC2265B88268DC801C10EA68476B7BDE0090F";
+const char *s_mp5d4 = "F59667D9";
+const char *s_mp2d5 = "AAFC0A3FE45E5E09DBF21E8";
+const char *s_mp1415 =
+    "E5C43DE2B811F4A084625F96E9504039E5258D8348E698CEB9F4D4292622042DB446"
+    "F75F4B65C1FB7A317257FA354BB5A45E789AEC254EAECE11F80A53E3B513822491DB"
+    "D9399DEC4807A2A3A10360129AC93F4A42388D3BF20B310DD0E9E9F4BE07FC88D53A"
+    "78A26091E0AB506A70813712CCBFBDD440A69A906E650EE090FDD6A42A95AC1A414D"
+    "317F1A9F781E6A30E9EE142ECDA45A1E3454A1417A7B9A613DA90831CF88EA1F2E82"
+    "41AE88CC4053220903C2E05BCDD42F02B8CF8868F84C64C5858BAD356143C5494607"
+    "EE22E11650148BAF65A985F6FC4CA540A55697F2B5AA95D6B8CF96EF638416DE1DD6"
+    "3BA9E2C09E22D03E75B60BE456C642F86B82A709253E5E087B507DE3A45F8392423F"
+    "4DBC284E8DC88C43CA77BC8DCEFB6129A59025F80F90FF978116DEBB9209E306FBB9"
+    "1B6111F8B8CFACB7C7C9BC12691C22EE88303E1713F1DFCEB622B8EA102F6365678B"
+    "C580ED87225467AA78E875868BD53B17574BA59305BC1AC666E4B7E9ED72FCFC200E"
+    "189D98FC8C5C7533739C53F52DDECDDFA5A8668BFBD40DABC9640F8FCAE58F532940"
+    "8162261320A25589E9FB51B50F80056471F24B7E1AEC35D1356FC2747FFC13A04B34"
+    "24FCECE10880BD9D97CA8CDEB2F5969BF4F30256EB5ED2BCD1DC64BDC2EE65217848"
+    "48A37FB13F84ED4FB7ACA18C4639EE64309BDD3D552AEB4AAF44295943DC1229A497"
+    "A84A";
+
+const char *ms_mp345 = "1E71E292";
+
+const char *d_mp12 = "-AAFBA6A55DD183FD854A60E";
+const char *d_mp34 = "119366B05E606A9B1E73A6D8944CC1366B0C4E0D4";
+const char *d_mp5d4 = "F5952EAB";
+const char *d_mp6d2 = "-1";
+const char *md_mp345 = "26596B86";
+
+const char *q_mp42 = "-95825A1FFA1A155D5";
+const char *r_mp42 = "-6312E99D7700A3DCB32ADF2";
+const char *q_mp45a = "15344CDA3D841F661D2B61B6EDF7828CE36";
+const char *r_mp45a = "-47C47B";
+const char *q_mp7c2 = "75FD3890E6C1C67321CE62CEEDA65F79";
+const char *q_mp3d6 = "8CAFD53C272BD6FE8B0847BDC3B539EFAB5C3";
+const char *r_mp3d6 = "1E5";
+const char *r_mp5d5 = "1257";
+const char *r_mp47 = "B3A9018D970281A90FB729A181D95CB8";
+const char *q_mp1404 =
+    "-1B994D869142D3EF6123A3CBBC3C0114FA071CFCEEF4B7D231D65591D32501AD80F"
+    "FF49AE4EC80514CC071EF6B42521C2508F4CB2FEAD69A2D2EF3934087DCAF88CC4C4"
+    "659F1CA8A7F4D36817D802F778F1392337FE36302D6865BF0D4645625DF8BB044E19"
+    "930635BE2609FAC8D99357D3A9F81F2578DE15A300964188292107DAC980E0A08CD7"
+    "E938A2135FAD45D50CB1D8C2D4C4E60C27AB98B9FBD7E4DBF752C57D2674520E4BB2"
+    "7E42324C0EFE84FB3E38CF6950E699E86FD45FE40D428400F2F94EDF7E94FAE10B45"
+    "89329E1BF61E5A378C7B31C9C6A234F8254D4C24823B84D0BF8D671D8BC9154DFAC9"
+    "49BD8ACABD6BD32DD4DC587F22C86153CB3954BDF7C2A890D623642492C482CF3E2C"
+    "776FC019C3BBC61688B485E6FD35D6376089C1E33F880E84C4E51E8ABEACE1B3FB70"
+    "3EAD0E28D2D44E7F1C0A859C840775E94F8C1369D985A3C5E8114B21D68B3CBB75D2"
+    "791C586153C85B90CAA483E57A40E2D97950AAB84920A4396C950C87C7FFFE748358"
+    "42A0BF65445B26D40F05BE164B822CA96321F41D85A289C5F5CD5F438A78704C9683"
+    "422299D21899A22F853B0C93081CC9925E350132A0717A611DD932A68A0ACC6E4C7F"
+    "7F685EF8C1F4910AEA5DC00BB5A36FCA07FFEAA490C547F6E14A08FE87041AB803E1"
+    "BD9E23E4D367A2C35762F209073DFF48F3";
+const char *r_mp1404 = "12FF98621ABF63144BFFC3207AC8FC10D8D1A09";
+
+const char *q_mp13c =
+    "34584F700C15A341E40BF7BFDD88A6630C8FF2B2067469372D391342"
+    "BDAB6163963CD5A5C79F708BDE26E0CCF2DB66CD6D6089E29A877C45";
+const char *r_mp13c = "F2B050D226E6DA88";
+const char *q_mp9c16 = "F74A2876A1432698923B0767DA19DCF3D71795E";
+const char *r_mp9c16 = "E";
+
+const char *e_mp5d9 = "A8FD7145E727A20E52E73D22990D35D158090307A"
+                      "13A5215AAC4E9AB1E96BD34E531209E03310400";
+const char *e_mp78 = "AA5F72C737DFFD8CCD108008BFE7C79ADC01A819B"
+                     "32B75FB82EC0FB8CA83311DA36D4063F1E57857A2"
+                     "1AB226563D84A15BB63CE975FF1453BD6750C58D9"
+                     "D113175764F5D0B3C89B262D4702F4D9640A3";
+const char *me_mp817 = "E504493ACB02F7F802B327AB13BF25";
+const char *me_mp5d47 = "1D45ED0D78F2778157992C951DD2734C";
+const char *me_mp1512 = "FB5B2A28D902B9D9";
+const char *me_mp161718 = "423C6AC6DBD74";
+const char *me_mp5114 =
+    "64F0F72807993578BBA3C7C36FFB184028F9EB9A810C92079E1498D8A80FC848E1F0"
+    "25F1DE43B7F6AC063F5CC29D8A7C2D7A66269D72BF5CDC327AF88AF8EF9E601DCB0A"
+    "3F35BFF3525FB1B61CE3A25182F17C0A0633B4089EA15BDC47664A43FEF639748AAC"
+    "19CF58E83D8FA32CD10661D2D4210CC84792937E6F36CB601851356622E63ADD4BD5"
+    "542412C2E0C4958E51FD2524AABDC7D60CFB5DB332EEC9DC84210F10FAE0BA2018F2"
+    "14C9D6867C9D6E49CF28C18D06CE009FD4D04BFC8837C3FAAA773F5CCF6DED1C22DE"
+    "181786AFE188540586F2D74BF312E595244E6936AE52E45742109BAA76C36F2692F5"
+    "CEF97AD462B138BE92721194B163254CBAAEE9B9864B21CCDD5375BCAD0D24132724"
+    "113D3374B4BCF9AA49BA5ACBC12288C0BCF46DCE6CB4A241A91BD559B130B6E9CD3D"
+    "D7A2C8B280C2A278BA9BF5D93244D563015C9484B86D9FEB602501DC16EEBC3EFF19"
+    "53D7999682BF1A1E3B2E7B21F4BDCA3C355039FEF55B9C0885F98DC355CA7A6D8ECF"
+    "5F7F1A6E11A764F2343C823B879B44616B56BF6AE3FA2ACF5483660E618882018E3F"
+    "C8459313BACFE1F93CECC37B2576A5C0B2714BD3EEDEEC22F0E7E3E77B11396B9B99"
+    "D683F2447A4004BBD4A57F6A616CDDFEC595C4FC19884CC2FC21CF5BF5B0B81E0F83"
+    "B9DDA0CF4DFF35BB8D31245912BF4497FD0BD95F0C604E26EA5A8EA4F5EAE870A5BD"
+    "FE8C";
+
+const char *e_mpc2d3 = "100000000000000000000000000000000";
+
+const char *t_mp9 = "FB9B6E32FF0452A34746";
+const char *i_mp27 = "B6AD8DCCDAF92B6FE57D062FFEE3A99";
+const char *i_mp2019 =
+    "BDF3D88DC373A63EED92903115B03FC8501910AF68297B4C41870AED3EA9F839";
+/* "15E3FE09E8AE5523AABA197BD2D16318D3CA148EDF4AE1C1C52FC96AFAF5680B"; */
+
+const char *t_mp15 =
+    "795853094E59B0008093BCA8DECF68587C64BDCA2F3F7F8963DABC12F1CFFFA9B8C4"
+    "365232FD4751870A0EF6CA619287C5D8B7F1747D95076AB19645EF309773E9EACEA0"
+    "975FA4AE16251A8DA5865349C3A903E3B8A2C0DEA3C0720B6020C7FED69AFF62BB72"
+    "10FAC443F9FFA2950776F949E819260C2AF8D94E8A1431A40F8C23C1973DE5D49AA2"
+    "0B3FF5DA5C1D5324E712A78FF33A9B1748F83FA529905924A31DF38643B3F693EF9B"
+    "58D846BB1AEAE4523ECC843FF551C1B300A130B65C1677402778F98C51C10813250E"
+    "2496882877B069E877B59740DC1226F18A5C0F66F64A5F59A9FAFC5E9FC45AEC0E7A"
+    "BEE244F7DD3AC268CF512A0E52E4F5BE5B94";
+
+const char *g_mp71 = "1";
+const char *g_mp25 = "7";
+const char *l_mp1011 = "C589E3D7D64A6942A000";
+
+/* mp9 in radices from 5 to 64 inclusive */
+#define LOW_RADIX 5
+#define HIGH_RADIX 64
+const char *v_mp9[] = {
+    "404041130042310320100141302000203430214122130002340212132414134210033",
+    "44515230120451152500101352430105520150025145320010504454125502",
+    "644641136612541136016610100564613624243140151310023515322",
+    "173512120732412062323044435407317550316717172705712756",
+    "265785018434285762514442046172754680368422060744852",
+    "1411774500397290569709059837552310354075408897518",
+    "184064268501499311A17746095910428222A241708032A",
+    "47706011B225950B02BB45602AA039893118A85950892",
+    "1A188C826B982353CB58422563AC602B783101671A86",
+    "105957B358B89B018958908A9114BC3DDC410B77982",
+    "CB7B3387E23452178846C55DD9D70C7CA9AEA78E8",
+    "F74A2876A1432698923B0767DA19DCF3D71795EE",
+    "17BF7C3673B76D7G7A5GA836277296F806E7453A",
+    "2EBG8HH3HFA6185D6H0596AH96G24C966DD3HG2",
+    "6G3HGBFEG8I3F25EAF61B904EIA40CFDH2124F",
+    "10AHC3D29EBHDF3HD97905CG0JA8061855C3FI",
+    "3BA5A55J5K699B2D09C38A4B237CH51IHA132",
+    "EDEA90DJ0B5CB3FGG1C8587FEB99D3C143CA",
+    "31M26JI1BBD56K3I028MML4EEDMAJK60LGLE",
+    "GGG5M3142FKKG82EJ28111D70EMHC241E4E",
+    "4446F4D5H10982023N297BF0DKBBHLLJB0I",
+    "12E9DEEOBMKAKEP0IM284MIP7FO1O521M46",
+    "85NN0HD48NN2FDDB1F5BMMKIB8CK20MDPK",
+    "2D882A7A0O0JPCJ4APDRIB77IABAKDGJP2",
+    "MFMCI0R7S27AAA3O3L2S8K44HKA7O02CN",
+    "7IGQS73FFSHC50NNH44B6PTTNLC3M6H78",
+    "2KLUB3U9850CSN6ANIDNIF1LB29MJ43LH",
+    "UT52GTL18CJ9H4HR0TJTK6ESUFBHF5FE",
+    "BTVL87QQBMUGF8PFWU4W3VU7U922QTMW",
+    "4OG10HW0MSWJBIDEE2PDH24GA7RIHIAA",
+    "1W8W9AX2DRUX48GXOLMK0PE42H0FEUWN",
+    "SVWI84VBH069WR15W1U2VTK06USY8Z2",
+    "CPTPNPDa5TYCPPNLALENT9IMX2GL0W2",
+    "5QU21UJMRaUYYYYYN6GHSMPOYOXEEUY",
+    "2O2Q7C6RPPB1SXJ9bR4035SPaQQ3H2W",
+    "18d994IbT4PHbD7cGIPCRP00bbQO0bc",
+    "NcDUEEWRO7XT76260WGeBHPVa72RdA",
+    "BbX2WCF9VfSB5LPdJAdeXKV1fd6LC2",
+    "60QDKW67P4JSQaTdQg7JE9ISafLaVU",
+    "33ba9XbDbRdNF4BeDB2XYMhAVDaBdA",
+    "1RIPZJA8gT5L5H7fTcaRhQ39geMMTc",
+    "d65j70fBATjcDiidPYXUGcaBVVLME",
+    "LKA9jhPabDG612TXWkhfT2gMXNIP2",
+    "BgNaYhjfT0G8PBcYRP8khJCR3C9QE",
+    "6Wk8RhJTAgDh10fYAiUVB1aM0HacG",
+    "3dOCjaf78kd5EQNViUZWj3AfFL90I",
+    "290VWkL3aiJoW4MBbHk0Z0bDo22Ni",
+    "1DbDZ1hpPZNUDBUp6UigcJllEdC26",
+    "dFSOLBUM7UZX8Vnc6qokGIOiFo1h",
+    "NcoUYJOg0HVmKI9fR2ag0S8R2hrK",
+    "EOpiJ5Te7oDe2pn8ZhAUKkhFHlZh",
+    "8nXK8rp8neV8LWta1WDgd1QnlWsU",
+    "5T3d6bcSBtHgrH9bCbu84tblaa7r",
+    "3PlUDIYUvMqOVCir7AtquK5dWanq",
+    "2A70gDPX2AtiicvIGGk9poiMtgvu",
+    "1MjiRxjk10J6SVAxFguv9kZiUnIc",
+    "rpre2vIDeb4h3sp50r1YBbtEx9L",
+    "ZHcoip0AglDAfibrsUcJ9M1C8fm",
+    "NHP18+eoe6uU54W49Kc6ZK7+bT2",
+    "FTAA7QXGoQOaZi7PzePtFFN5vNk"
+};
+
+const unsigned char b_mp4[] = {
+    0x01,
+#if MP_DIGIT_MAX > MP_32BIT_MAX
+    0x00, 0x00, 0x00, 0x00,
+#endif
+    0x63, 0xDB, 0xC2, 0x26,
+    0x5B, 0x88, 0x26, 0x8D,
+    0xC8, 0x01, 0xC1, 0x0E,
+    0xA6, 0x84, 0x76, 0xB7,
+    0xBD, 0xE0, 0x09, 0x0F
+};
+
+/* Search for a test suite name in the names table  */
+int find_name(char *name);
+void reason(char *fmt, ...);
+
+/*------------------------------------------------------------------------*/
+/*------------------------------------------------------------------------*/
+
+char g_intbuf[4096]; /* buffer for integer comparison   */
+char a_intbuf[4096]; /* buffer for integer comparison   */
+int g_verbose = 1;   /* print out reasons for failure?  */
+int res;
+
+#define IFOK(x)                                            \
+    {                                                      \
+        if (MP_OKAY > (res = (x))) {                       \
+            reason("test %s failed: error %d\n", #x, res); \
+            return 1;                                      \
+        }                                                  \
+    }
+
+int
+main(int argc, char *argv[])
+{
+    int which, res;
+
+    srand((unsigned int)time(NULL));
+
+    if (argc < 2) {
+        fprintf(stderr, "Usage: %s <test-suite> | list\n"
+                        "Type '%s help' for assistance\n",
+                argv[0], argv[0]);
+        return 2;
+    } else if (argc > 2) {
+        if (strcmp(argv[2], "quiet") == 0)
+            g_verbose = 0;
+    }
+
+    if (strcmp(argv[1], "help") == 0) {
+        fprintf(stderr, "Help for mpi-test\n\n"
+                        "This program is a test driver for the MPI library, which\n"
+                        "tests all the various functions in the library to make sure\n"
+                        "they are working correctly.  The syntax is:\n"
+                        "    %s <suite-name>\n"
+                        "...where <suite-name> is the name of the test you wish to\n"
+                        "run.  To get a list of the tests, use '%s list'.\n\n"
+                        "The program exits with a status of zero if the test passes,\n"
+                        "or non-zero if it fails.  Ordinarily, failure is accompanied\n"
+                        "by a diagnostic message to standard error.  To suppress this\n"
+                        "add the keyword 'quiet' after the suite-name on the command\n"
+                        "line.\n\n",
+                argv[0], argv[0]);
+        return 0;
+    }
+
+    if ((which = find_name(argv[1])) < 0) {
+        fprintf(stderr, "%s: test suite '%s' is not known\n", argv[0], argv[1]);
+        return 2;
+    }
+
+    if ((res = (g_tests[which])()) < 0) {
+        fprintf(stderr, "%s: test suite not implemented yet\n", argv[0]);
+        return 2;
+    } else {
+        return res;
+    }
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+find_name(char *name)
+{
+    int ix = 0;
+
+    while (ix < g_count) {
+        if (strcmp(name, g_names[ix]) == 0)
+            return ix;
+
+        ++ix;
+    }
+
+    return -1;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_list(void)
+{
+    int ix;
+
+    fprintf(stderr, "There are currently %d test suites available\n",
+            g_count);
+
+    for (ix = 1; ix < g_count; ix++)
+        fprintf(stdout, "%-20s %s\n", g_names[ix], g_descs[ix]);
+
+    return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_copy(void)
+{
+    mp_int a, b;
+    int ix;
+
+    mp_init(&a);
+    mp_init(&b);
+
+    mp_read_radix(&a, mp3, 16);
+    mp_copy(&a, &b);
+
+    if (SIGN(&a) != SIGN(&b) || USED(&a) != USED(&b)) {
+        if (SIGN(&a) != SIGN(&b)) {
+            reason("error: sign of original is %d, sign of copy is %d\n",
+                   SIGN(&a), SIGN(&b));
+        } else {
+            reason("error: original precision is %d, copy precision is %d\n",
+                   USED(&a), USED(&b));
+        }
+        mp_clear(&a);
+        mp_clear(&b);
+        return 1;
+    }
+
+    for (ix = 0; ix < USED(&b); ix++) {
+        if (DIGIT(&a, ix) != DIGIT(&b, ix)) {
+            reason("error: digit %d " DIGIT_FMT " != " DIGIT_FMT "\n",
+                   ix, DIGIT(&a, ix), DIGIT(&b, ix));
+            mp_clear(&a);
+            mp_clear(&b);
+            return 1;
+        }
+    }
+
+    mp_clear(&a);
+    mp_clear(&b);
+    return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_exch(void)
+{
+    mp_int a, b;
+
+    mp_init(&a);
+    mp_init(&b);
+    mp_read_radix(&a, mp7, 16);
+    mp_read_radix(&b, mp1, 16);
+
+    mp_exch(&a, &b);
+    mp_toradix(&a, g_intbuf, 16);
+
+    mp_clear(&a);
+    if (strcmp(g_intbuf, mp1) != 0) {
+        mp_clear(&b);
+        reason("error: exchange failed\n");
+        return 1;
+    }
+
+    mp_toradix(&b, g_intbuf, 16);
+
+    mp_clear(&b);
+    if (strcmp(g_intbuf, mp7) != 0) {
+        reason("error: exchange failed\n");
+        return 1;
+    }
+
+    return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_zero(void)
+{
+    mp_int a;
+
+    mp_init(&a);
+    mp_read_radix(&a, mp7, 16);
+    mp_zero(&a);
+
+    if (USED(&a) != 1 || DIGIT(&a, 1) != 0) {
+        mp_toradix(&a, g_intbuf, 16);
+        reason("error: result is %s\n", g_intbuf);
+        mp_clear(&a);
+        return 1;
+    }
+
+    mp_clear(&a);
+    return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_set(void)
+{
+    mp_int a;
+
+    /* Test single digit set */
+    mp_init(&a);
+    mp_set(&a, 5);
+    if (DIGIT(&a, 0) != 5) {
+        mp_toradix(&a, g_intbuf, 16);
+        reason("error: result is %s, expected 5\n", g_intbuf);
+        mp_clear(&a);
+        return 1;
+    }
+
+    /* Test integer set */
+    mp_set_int(&a, -4938110);
+    mp_toradix(&a, g_intbuf, 16);
+    mp_clear(&a);
+    if (strcmp(g_intbuf, mp5a) != 0) {
+        reason("error: result is %s, expected %s\n", g_intbuf, mp5a);
+        return 1;
+    }
+
+    return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_abs(void)
+{
+    mp_int a;
+
+    mp_init(&a);
+    mp_read_radix(&a, mp4, 16);
+    mp_abs(&a, &a);
+
+    if (SIGN(&a) != ZPOS) {
+        reason("error: sign of result is negative\n");
+        mp_clear(&a);
+        return 1;
+    }
+
+    mp_clear(&a);
+    return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_neg(void)
+{
+    mp_int a;
+    mp_sign s;
+
+    mp_init(&a);
+    mp_read_radix(&a, mp4, 16);
+
+    s = SIGN(&a);
+    mp_neg(&a, &a);
+    if (SIGN(&a) == s) {
+        reason("error: sign of result is same as sign of nonzero input\n");
+        mp_clear(&a);
+        return 1;
+    }
+
+    mp_clear(&a);
+    return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_add_d(void)
+{
+    mp_int a;
+
+    mp_init(&a);
+
+    mp_read_radix(&a, mp5, 16);
+    mp_add_d(&a, md4, &a);
+    mp_toradix(&a, g_intbuf, 16);
+
+    if (strcmp(g_intbuf, s_mp5d4) != 0) {
+        reason("error: computed %s, expected %s\n", g_intbuf, s_mp5d4);
+        mp_clear(&a);
+        return 1;
+    }
+
+    mp_read_radix(&a, mp2, 16);
+    mp_add_d(&a, md5, &a);
+    mp_toradix(&a, g_intbuf, 16);
+
+    if (strcmp(g_intbuf, s_mp2d5) != 0) {
+        reason("error: computed %s, expected %s\n", g_intbuf, s_mp2d5);
+        mp_clear(&a);
+        return 1;
+    }
+
+    mp_clear(&a);
+    return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_add(void)
+{
+    mp_int a, b;
+    int res = 0;
+
+    mp_init(&a);
+    mp_init(&b);
+
+    mp_read_radix(&a, mp1, 16);
+    mp_read_radix(&b, mp3, 16);
+    mp_add(&a, &b, &a);
+    mp_toradix(&a, g_intbuf, 16);
+
+    if (strcmp(g_intbuf, s_mp13) != 0) {
+        reason("error: computed %s, expected %s\n", g_intbuf, s_mp13);
+        res = 1;
+        goto CLEANUP;
+    }
+
+    mp_read_radix(&a, mp4, 16);
+    mp_add(&a, &b, &a);
+    mp_toradix(&a, g_intbuf, 16);
+
+    if (strcmp(g_intbuf, s_mp34) != 0) {
+        reason("error: computed %s, expected %s\n", g_intbuf, s_mp34);
+        res = 1;
+        goto CLEANUP;
+    }
+
+    mp_read_radix(&a, mp4, 16);
+    mp_read_radix(&b, mp6, 16);
+    mp_add(&a, &b, &a);
+    mp_toradix(&a, g_intbuf, 16);
+
+    if (strcmp(g_intbuf, s_mp46) != 0) {
+        reason("error: computed %s, expected %s\n", g_intbuf, s_mp46);
+        res = 1;
+        goto CLEANUP;
+    }
+
+    mp_read_radix(&a, mp14, 16);
+    mp_read_radix(&b, mp15, 16);
+    mp_add(&a, &b, &a);
+    mp_toradix(&a, g_intbuf, 16);
+
+    if (strcmp(g_intbuf, s_mp1415) != 0) {
+        reason("error: computed %s, expected %s\n", g_intbuf, s_mp1415);
+        res = 1;
+    }
+
+CLEANUP:
+    mp_clear(&a);
+    mp_clear(&b);
+    return res;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_sub_d(void)
+{
+    mp_int a;
+
+    mp_init(&a);
+    mp_read_radix(&a, mp5, 16);
+
+    mp_sub_d(&a, md4, &a);
+    mp_toradix(&a, g_intbuf, 16);
+
+    if (strcmp(g_intbuf, d_mp5d4) != 0) {
+        reason("error: computed %s, expected %s\n", g_intbuf, d_mp5d4);
+        mp_clear(&a);
+        return 1;
+    }
+
+    mp_read_radix(&a, mp6, 16);
+
+    mp_sub_d(&a, md2, &a);
+    mp_toradix(&a, g_intbuf, 16);
+
+    mp_clear(&a);
+    if (strcmp(g_intbuf, d_mp6d2) != 0) {
+        reason("error: computed %s, expected %s\n", g_intbuf, d_mp6d2);
+        return 1;
+    }
+
+    return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_sub(void)
+{
+    mp_int a, b;
+
+    mp_init(&a);
+    mp_init(&b);
+
+    mp_read_radix(&a, mp1, 16);
+    mp_read_radix(&b, mp2, 16);
+    mp_sub(&a, &b, &a);
+    mp_toradix(&a, g_intbuf, 16);
+
+    if (strcmp(g_intbuf, d_mp12) != 0) {
+        reason("error: computed %s, expected %s\n", g_intbuf, d_mp12);
+        mp_clear(&a);
+        mp_clear(&b);
+        return 1;
+    }
+
+    mp_read_radix(&a, mp3, 16);
+    mp_read_radix(&b, mp4, 16);
+    mp_sub(&a, &b, &a);
+    mp_toradix(&a, g_intbuf, 16);
+
+    if (strcmp(g_intbuf, d_mp34) != 0) {
+        reason("error: computed %s, expected %s\n", g_intbuf, d_mp34);
+        mp_clear(&a);
+        mp_clear(&b);
+        return 1;
+    }
+
+    mp_clear(&a);
+    mp_clear(&b);
+    return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_mul_d(void)
+{
+    mp_int a;
+
+    mp_init(&a);
+    mp_read_radix(&a, mp1, 16);
+
+    IFOK(mp_mul_d(&a, md4, &a));
+    mp_toradix(&a, g_intbuf, 16);
+
+    if (strcmp(g_intbuf, p_mp1d4) != 0) {
+        reason("error: computed %s, expected %s\n", g_intbuf, p_mp1d4);
+        mp_clear(&a);
+        return 1;
+    }
+
+    mp_read_radix(&a, mp8, 16);
+    IFOK(mp_mul_d(&a, md6, &a));
+    mp_toradix(&a, g_intbuf, 16);
+
+    mp_clear(&a);
+    if (strcmp(g_intbuf, p_mp8d6) != 0) {
+        reason("error: computed %s, expected %s\n", g_intbuf, p_mp8d6);
+        return 1;
+    }
+
+    return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_mul(void)
+{
+    mp_int a, b;
+    int res = 0;
+
+    mp_init(&a);
+    mp_init(&b);
+    mp_read_radix(&a, mp1, 16);
+    mp_read_radix(&b, mp2, 16);
+
+    IFOK(mp_mul(&a, &b, &a));
+    mp_toradix(&a, g_intbuf, 16);
+
+    if (strcmp(g_intbuf, p_mp12) != 0) {
+        reason("error: computed %s, expected %s\n", g_intbuf, p_mp12);
+        res = 1;
+        goto CLEANUP;
+    }
+
+    mp_read_radix(&a, mp3, 16);
+    mp_read_radix(&b, mp4, 16);
+    IFOK(mp_mul(&a, &b, &a));
+    mp_toradix(&a, g_intbuf, 16);
+
+    if (strcmp(g_intbuf, p_mp34) != 0) {
+        reason("error: computed %s, expected %s\n", g_intbuf, p_mp34);
+        res = 1;
+        goto CLEANUP;
+    }
+
+    mp_read_radix(&a, mp5, 16);
+    mp_read_radix(&b, mp7, 16);
+    IFOK(mp_mul(&a, &b, &a));
+    mp_toradix(&a, g_intbuf, 16);
+
+    if (strcmp(g_intbuf, p_mp57) != 0) {
+        reason("error: computed %s, expected %s\n", g_intbuf, p_mp57);
+        res = 1;
+        goto CLEANUP;
+    }
+
+    mp_read_radix(&a, mp11, 16);
+    mp_read_radix(&b, mp13, 16);
+    IFOK(mp_mul(&a, &b, &a));
+    mp_toradix(&a, g_intbuf, 16);
+
+    if (strcmp(g_intbuf, p_mp1113) != 0) {
+        reason("error: computed %s, expected %s\n", g_intbuf, p_mp1113);
+        res = 1;
+        goto CLEANUP;
+    }
+
+    mp_read_radix(&a, mp14, 16);
+    mp_read_radix(&b, mp15, 16);
+    IFOK(mp_mul(&a, &b, &a));
+    mp_toradix(&a, g_intbuf, 16);
+
+    if (strcmp(g_intbuf, p_mp1415) != 0) {
+        reason("error: computed %s, expected %s\n", g_intbuf, p_mp1415);
+        res = 1;
+    }
+    mp_read_radix(&a, mp21, 10);
+    mp_read_radix(&b, mp21, 10);
+
+    IFOK(mp_mul(&a, &b, &a));
+    mp_toradix(&a, g_intbuf, 10);
+
+    if (strcmp(g_intbuf, p_mp2121) != 0) {
+        reason("error: computed %s, expected %s\n", g_intbuf, p_mp2121);
+        res = 1;
+        goto CLEANUP;
+    }
+
+CLEANUP:
+    mp_clear(&a);
+    mp_clear(&b);
+    return res;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_sqr(void)
+{
+    mp_int a;
+
+    mp_init(&a);
+    mp_read_radix(&a, mp2, 16);
+
+    mp_sqr(&a, &a);
+    mp_toradix(&a, g_intbuf, 16);
+
+    mp_clear(&a);
+    if (strcmp(g_intbuf, p_mp22) != 0) {
+        reason("error: computed %s, expected %s\n", g_intbuf, p_mp22);
+        return 1;
+    }
+
+    return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_div_d(void)
+{
+    mp_int a, q;
+    mp_digit r;
+    int err = 0;
+
+    mp_init(&a);
+    mp_init(&q);
+    mp_read_radix(&a, mp3, 16);
+
+    IFOK(mp_div_d(&a, md6, &q, &r));
+    mp_toradix(&q, g_intbuf, 16);
+
+    if (strcmp(g_intbuf, q_mp3d6) != 0) {
+        reason("error: computed q = %s, expected %s\n", g_intbuf, q_mp3d6);
+        ++err;
+    }
+
+    sprintf(g_intbuf, ZS_DIGIT_FMT, r);
+
+    if (strcmp(g_intbuf, r_mp3d6) != 0) {
+        reason("error: computed r = %s, expected %s\n", g_intbuf, r_mp3d6);
+        ++err;
+    }
+
+    mp_read_radix(&a, mp9, 16);
+    IFOK(mp_div_d(&a, 16, &q, &r));
+    mp_toradix(&q, g_intbuf, 16);
+
+    if (strcmp(g_intbuf, q_mp9c16) != 0) {
+        reason("error: computed q = %s, expected %s\n", g_intbuf, q_mp9c16);
+        ++err;
+    }
+
+    sprintf(g_intbuf, ZS_DIGIT_FMT, r);
+
+    if (strcmp(g_intbuf, r_mp9c16) != 0) {
+        reason("error: computed r = %s, expected %s\n", g_intbuf, r_mp9c16);
+        ++err;
+    }
+
+    mp_clear(&a);
+    mp_clear(&q);
+    return err;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_div_2(void)
+{
+    mp_int a;
+
+    mp_init(&a);
+    mp_read_radix(&a, mp7, 16);
+    IFOK(mp_div_2(&a, &a));
+    mp_toradix(&a, g_intbuf, 16);
+
+    mp_clear(&a);
+    if (strcmp(g_intbuf, q_mp7c2) != 0) {
+        reason("error: computed %s, expected %s\n", g_intbuf, q_mp7c2);
+        return 1;
+    }
+
+    return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_div_2d(void)
+{
+    mp_int a, q, r;
+
+    mp_init(&q);
+    mp_init(&r);
+    mp_init(&a);
+    mp_read_radix(&a, mp13, 16);
+
+    IFOK(mp_div_2d(&a, 64, &q, &r));
+    mp_clear(&a);
+
+    mp_toradix(&q, g_intbuf, 16);
+
+    if (strcmp(g_intbuf, q_mp13c) != 0) {
+        reason("error: computed %s, expected %s\n", g_intbuf, q_mp13c);
+        mp_clear(&q);
+        mp_clear(&r);
+        return 1;
+    }
+
+    mp_clear(&q);
+
+    mp_toradix(&r, g_intbuf, 16);
+    if (strcmp(g_intbuf, r_mp13c) != 0) {
+        reason("error, computed %s, expected %s\n", g_intbuf, r_mp13c);
+        mp_clear(&r);
+        return 1;
+    }
+
+    mp_clear(&r);
+
+    return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_div(void)
+{
+    mp_int a, b, r;
+    int err = 0;
+
+    mp_init(&a);
+    mp_init(&b);
+    mp_init(&r);
+
+    mp_read_radix(&a, mp4, 16);
+    mp_read_radix(&b, mp2, 16);
+    IFOK(mp_div(&a, &b, &a, &r));
+    mp_toradix(&a, g_intbuf, 16);
+
+    if (strcmp(g_intbuf, q_mp42) != 0) {
+        reason("error: test 1 computed quot %s, expected %s\n", g_intbuf, q_mp42);
+        ++err;
+    }
+
+    mp_toradix(&r, g_intbuf, 16);
+
+    if (strcmp(g_intbuf, r_mp42) != 0) {
+        reason("error: test 1 computed rem %s, expected %s\n", g_intbuf, r_mp42);
+        ++err;
+    }
+
+    mp_read_radix(&a, mp4, 16);
+    mp_read_radix(&b, mp5a, 16);
+    IFOK(mp_div(&a, &b, &a, &r));
+    mp_toradix(&a, g_intbuf, 16);
+
+    if (strcmp(g_intbuf, q_mp45a) != 0) {
+        reason("error: test 2 computed quot %s, expected %s\n", g_intbuf, q_mp45a);
+        ++err;
+    }
+
+    mp_toradix(&r, g_intbuf, 16);
+
+    if (strcmp(g_intbuf, r_mp45a) != 0) {
+        reason("error: test 2 computed rem %s, expected %s\n", g_intbuf, r_mp45a);
+        ++err;
+    }
+
+    mp_read_radix(&a, mp14, 16);
+    mp_read_radix(&b, mp4, 16);
+    IFOK(mp_div(&a, &b, &a, &r));
+    mp_toradix(&a, g_intbuf, 16);
+
+    if (strcmp(g_intbuf, q_mp1404) != 0) {
+        reason("error: test 3 computed quot %s, expected %s\n", g_intbuf, q_mp1404);
+        ++err;
+    }
+
+    mp_toradix(&r, g_intbuf, 16);
+
+    if (strcmp(g_intbuf, r_mp1404) != 0) {
+        reason("error: test 3 computed rem %s, expected %s\n", g_intbuf, r_mp1404);
+        ++err;
+    }
+
+    mp_clear(&a);
+    mp_clear(&b);
+    mp_clear(&r);
+
+    return err;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_expt_d(void)
+{
+    mp_int a;
+
+    mp_init(&a);
+    mp_read_radix(&a, mp5, 16);
+    mp_expt_d(&a, md9, &a);
+    mp_toradix(&a, g_intbuf, 16);
+
+    mp_clear(&a);
+    if (strcmp(g_intbuf, e_mp5d9) != 0) {
+        reason("error: computed %s, expected %s\n", g_intbuf, e_mp5d9);
+        return 1;
+    }
+
+    return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_expt(void)
+{
+    mp_int a, b;
+
+    mp_init(&a);
+    mp_init(&b);
+    mp_read_radix(&a, mp7, 16);
+    mp_read_radix(&b, mp8, 16);
+
+    mp_expt(&a, &b, &a);
+    mp_toradix(&a, g_intbuf, 16);
+    mp_clear(&a);
+    mp_clear(&b);
+
+    if (strcmp(g_intbuf, e_mp78) != 0) {
+        reason("error: computed %s, expected %s\n", g_intbuf, e_mp78);
+        return 1;
+    }
+
+    return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_2expt(void)
+{
+    mp_int a;
+
+    mp_init(&a);
+    mp_2expt(&a, md3);
+    mp_toradix(&a, g_intbuf, 16);
+    mp_clear(&a);
+
+    if (strcmp(g_intbuf, e_mpc2d3) != 0) {
+        reason("error: computed %s, expected %s\n", g_intbuf, e_mpc2d3);
+        return 1;
+    }
+
+    return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_mod_d(void)
+{
+    mp_int a;
+    mp_digit r;
+
+    mp_init(&a);
+    mp_read_radix(&a, mp5, 16);
+    IFOK(mp_mod_d(&a, md5, &r));
+    sprintf(g_intbuf, ZS_DIGIT_FMT, r);
+    mp_clear(&a);
+
+    if (strcmp(g_intbuf, r_mp5d5) != 0) {
+        reason("error: computed %s, expected %s\n", g_intbuf, r_mp5d5);
+        return 1;
+    }
+
+    return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_mod(void)
+{
+    mp_int a, m;
+
+    mp_init(&a);
+    mp_init(&m);
+    mp_read_radix(&a, mp4, 16);
+    mp_read_radix(&m, mp7, 16);
+    IFOK(mp_mod(&a, &m, &a));
+    mp_toradix(&a, g_intbuf, 16);
+    mp_clear(&a);
+    mp_clear(&m);
+
+    if (strcmp(g_intbuf, r_mp47) != 0) {
+        reason("error: computed %s, expected %s\n", g_intbuf, r_mp47);
+        return 1;
+    }
+
+    return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_addmod(void)
+{
+    mp_int a, b, m;
+
+    mp_init(&a);
+    mp_init(&b);
+    mp_init(&m);
+    mp_read_radix(&a, mp3, 16);
+    mp_read_radix(&b, mp4, 16);
+    mp_read_radix(&m, mp5, 16);
+
+    IFOK(mp_addmod(&a, &b, &m, &a));
+    mp_toradix(&a, g_intbuf, 16);
+    mp_clear(&a);
+    mp_clear(&b);
+    mp_clear(&m);
+
+    if (strcmp(g_intbuf, ms_mp345) != 0) {
+        reason("error: computed %s, expected %s\n", g_intbuf, ms_mp345);
+        return 1;
+    }
+
+    return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_submod(void)
+{
+    mp_int a, b, m;
+
+    mp_init(&a);
+    mp_init(&b);
+    mp_init(&m);
+    mp_read_radix(&a, mp3, 16);
+    mp_read_radix(&b, mp4, 16);
+    mp_read_radix(&m, mp5, 16);
+
+    IFOK(mp_submod(&a, &b, &m, &a));
+    mp_toradix(&a, g_intbuf, 16);
+    mp_clear(&a);
+    mp_clear(&b);
+    mp_clear(&m);
+
+    if (strcmp(g_intbuf, md_mp345) != 0) {
+        reason("error: computed %s, expected %s\n", g_intbuf, md_mp345);
+        return 1;
+    }
+
+    return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_mulmod(void)
+{
+    mp_int a, b, m;
+
+    mp_init(&a);
+    mp_init(&b);
+    mp_init(&m);
+    mp_read_radix(&a, mp3, 16);
+    mp_read_radix(&b, mp4, 16);
+    mp_read_radix(&m, mp5, 16);
+
+    IFOK(mp_mulmod(&a, &b, &m, &a));
+    mp_toradix(&a, g_intbuf, 16);
+    mp_clear(&a);
+    mp_clear(&b);
+    mp_clear(&m);
+
+    if (strcmp(g_intbuf, mp_mp345) != 0) {
+        reason("error: computed %s, expected %s\n", g_intbuf, mp_mp345);
+        return 1;
+    }
+
+    return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_sqrmod(void)
+{
+    mp_int a, m;
+
+    mp_init(&a);
+    mp_init(&m);
+    mp_read_radix(&a, mp3, 16);
+    mp_read_radix(&m, mp5, 16);
+
+    IFOK(mp_sqrmod(&a, &m, &a));
+    mp_toradix(&a, g_intbuf, 16);
+    mp_clear(&a);
+    mp_clear(&m);
+
+    if (strcmp(g_intbuf, mp_mp335) != 0) {
+        reason("error: computed %s, expected %s\n", g_intbuf, mp_mp335);
+        return 1;
+    }
+
+    return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_exptmod(void)
+{
+    mp_int a, b, m;
+    int res = 0;
+
+    mp_init(&a);
+    mp_init(&b);
+    mp_init(&m);
+    mp_read_radix(&a, mp8, 16);
+    mp_read_radix(&b, mp1, 16);
+    mp_read_radix(&m, mp7, 16);
+
+    IFOK(mp_exptmod(&a, &b, &m, &a));
+    mp_toradix(&a, g_intbuf, 16);
+
+    if (strcmp(g_intbuf, me_mp817) != 0) {
+        reason("case 1: error: computed %s, expected %s\n", g_intbuf, me_mp817);
+        res = 1;
+        goto CLEANUP;
+    }
+
+    mp_read_radix(&a, mp1, 16);
+    mp_read_radix(&b, mp5, 16);
+    mp_read_radix(&m, mp12, 16);
+
+    IFOK(mp_exptmod(&a, &b, &m, &a));
+    mp_toradix(&a, g_intbuf, 16);
+
+    if (strcmp(g_intbuf, me_mp1512) != 0) {
+        reason("case 2: error: computed %s, expected %s\n", g_intbuf, me_mp1512);
+        res = 1;
+        goto CLEANUP;
+    }
+
+    mp_read_radix(&a, mp5, 16);
+    mp_read_radix(&b, mp1, 16);
+    mp_read_radix(&m, mp14, 16);
+
+    IFOK(mp_exptmod(&a, &b, &m, &a));
+    mp_toradix(&a, g_intbuf, 16);
+
+    if (strcmp(g_intbuf, me_mp5114) != 0) {
+        reason("case 3: error: computed %s, expected %s\n", g_intbuf, me_mp5114);
+        res = 1;
+    }
+
+    mp_read_radix(&a, mp16, 16);
+    mp_read_radix(&b, mp17, 16);
+    mp_read_radix(&m, mp18, 16);
+
+    IFOK(mp_exptmod(&a, &b, &m, &a));
+    mp_toradix(&a, g_intbuf, 16);
+
+    if (strcmp(g_intbuf, me_mp161718) != 0) {
+        reason("case 4: error: computed %s, expected %s\n", g_intbuf, me_mp161718);
+        res = 1;
+    }
+
+CLEANUP:
+    mp_clear(&a);
+    mp_clear(&b);
+    mp_clear(&m);
+    return res;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_exptmod_d(void)
+{
+    mp_int a, m;
+
+    mp_init(&a);
+    mp_init(&m);
+    mp_read_radix(&a, mp5, 16);
+    mp_read_radix(&m, mp7, 16);
+
+    IFOK(mp_exptmod_d(&a, md4, &m, &a));
+    mp_toradix(&a, g_intbuf, 16);
+    mp_clear(&a);
+    mp_clear(&m);
+
+    if (strcmp(g_intbuf, me_mp5d47) != 0) {
+        reason("error: computed %s, expected %s\n", g_intbuf, me_mp5d47);
+        return 1;
+    }
+
+    return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_invmod(void)
+{
+    mp_int a, m, c;
+    mp_int p1, p2, p3, p4, p5;
+    mp_int t1, t2, t3, t4;
+    mp_err res;
+
+    /* 5 128-bit primes. */
+    static const char ivp1[] = { "AAD8A5A2A2BEF644BAEE7DB0CA643719" };
+    static const char ivp2[] = { "CB371AD2B79A90BCC88D0430663E40B9" };
+    static const char ivp3[] = { "C6C818D4DF2618406CA09280C0400099" };
+    static const char ivp4[] = { "CE949C04512E68918006B1F0D7E93F27" };
+    static const char ivp5[] = { "F8EE999B6416645040687440E0B89F51" };
+
+    mp_init(&a);
+    mp_init(&m);
+    mp_read_radix(&a, mp2, 16);
+    mp_read_radix(&m, mp7, 16);
+
+    IFOK(mp_invmod(&a, &m, &a));
+
+    mp_toradix(&a, g_intbuf, 16);
+    mp_clear(&a);
+    mp_clear(&m);
+
+    if (strcmp(g_intbuf, i_mp27) != 0) {
+        reason("error: invmod test 1 computed %s, expected %s\n", g_intbuf, i_mp27);
+        return 1;
+    }
+
+    mp_init(&a);
+    mp_init(&m);
+    mp_read_radix(&a, mp20, 16);
+    mp_read_radix(&m, mp19, 16);
+
+    IFOK(mp_invmod(&a, &m, &a));
+
+    mp_toradix(&a, g_intbuf, 16);
+    mp_clear(&a);
+    mp_clear(&m);
+
+    if (strcmp(g_intbuf, i_mp2019) != 0) {
+        reason("error: invmod test 2 computed %s, expected %s\n", g_intbuf, i_mp2019);
+        return 1;
+    }
+
+    /* Need the following test cases:
+      Odd modulus
+        - a is odd,      relatively prime to m
+        - a is odd,  not relatively prime to m
+        - a is even,     relatively prime to m
+        - a is even, not relatively prime to m
+      Even modulus
+        - a is even  (should fail)
+        - a is odd,  not relatively prime to m
+        - a is odd,      relatively prime to m,
+          m is not a power of 2
+        - m has factor 2**k, k < 32
+        - m has factor 2**k, k > 32
+          m is a power of 2, 2**k
+        - k < 32
+        - k > 32
+    */
+
+    mp_init(&a);
+    mp_init(&m);
+    mp_init(&c);
+    mp_init(&p1);
+    mp_init(&p2);
+    mp_init(&p3);
+    mp_init(&p4);
+    mp_init(&p5);
+    mp_init(&t1);
+    mp_init(&t2);
+    mp_init(&t3);
+    mp_init(&t4);
+
+    mp_read_radix(&p1, ivp1, 16);
+    mp_read_radix(&p2, ivp2, 16);
+    mp_read_radix(&p3, ivp3, 16);
+    mp_read_radix(&p4, ivp4, 16);
+    mp_read_radix(&p5, ivp5, 16);
+
+    IFOK(mp_2expt(&t2, 68));  /* t2 = 2**68 */
+    IFOK(mp_2expt(&t3, 128)); /* t3 = 2**128 */
+    IFOK(mp_2expt(&t4, 31));  /* t4 = 2**31 */
+
+    /* test 3: Odd modulus - a is odd, relatively prime to m */
+
+    IFOK(mp_mul(&p1, &p2, &a));
+    IFOK(mp_mul(&p3, &p4, &m));
+    IFOK(mp_invmod(&a, &m, &t1));
+    IFOK(mp_invmod_xgcd(&a, &m, &c));
+
+    if (mp_cmp(&t1, &c) != 0) {
+        mp_toradix(&t1, g_intbuf, 16);
+        mp_toradix(&c, a_intbuf, 16);
+        reason("error: invmod test 3 computed %s, expected %s\n",
+               g_intbuf, a_intbuf);
+        return 1;
+    }
+    mp_clear(&a);
+    mp_clear(&t1);
+    mp_clear(&c);
+    mp_init(&a);
+    mp_init(&t1);
+    mp_init(&c);
+
+    /* test 4: Odd modulus - a is odd, NOT relatively prime to m */
+
+    IFOK(mp_mul(&p1, &p3, &a));
+    /* reuse same m as before */
+
+    res = mp_invmod_xgcd(&a, &m, &c);
+    if (res != MP_UNDEF)
+        goto CLEANUP4;
+
+    res = mp_invmod(&a, &m, &t1); /* we expect this to fail. */
+    if (res != MP_UNDEF) {
+    CLEANUP4:
+        reason("error: invmod test 4 succeeded, should have failed.\n");
+        return 1;
+    }
+    mp_clear(&a);
+    mp_clear(&t1);
+    mp_clear(&c);
+    mp_init(&a);
+    mp_init(&t1);
+    mp_init(&c);
+
+    /* test 5: Odd modulus - a is even, relatively prime to m */
+
+    IFOK(mp_mul(&p1, &t2, &a));
+    /* reuse m */
+    IFOK(mp_invmod(&a, &m, &t1));
+    IFOK(mp_invmod_xgcd(&a, &m, &c));
+
+    if (mp_cmp(&t1, &c) != 0) {
+        mp_toradix(&t1, g_intbuf, 16);
+        mp_toradix(&c, a_intbuf, 16);
+        reason("error: invmod test 5 computed %s, expected %s\n",
+               g_intbuf, a_intbuf);
+        return 1;
+    }
+    mp_clear(&a);
+    mp_clear(&t1);
+    mp_clear(&c);
+    mp_init(&a);
+    mp_init(&t1);
+    mp_init(&c);
+
+    /* test 6: Odd modulus - a is odd, NOT relatively prime to m */
+
+    /* reuse t2 */
+    IFOK(mp_mul(&t2, &p3, &a));
+    /* reuse same m as before */
+
+    res = mp_invmod_xgcd(&a, &m, &c);
+    if (res != MP_UNDEF)
+        goto CLEANUP6;
+
+    res = mp_invmod(&a, &m, &t1); /* we expect this to fail. */
+    if (res != MP_UNDEF) {
+    CLEANUP6:
+        reason("error: invmod test 6 succeeded, should have failed.\n");
+        return 1;
+    }
+    mp_clear(&a);
+    mp_clear(&m);
+    mp_clear(&c);
+    mp_clear(&t1);
+    mp_init(&a);
+    mp_init(&m);
+    mp_init(&c);
+    mp_init(&t1);
+
+    /* test 7: Even modulus, even a, should fail */
+
+    IFOK(mp_mul(&p3, &t3, &m)); /* even m */
+    /* reuse t2 */
+    IFOK(mp_mul(&p1, &t2, &a)); /* even a */
+
+    res = mp_invmod_xgcd(&a, &m, &c);
+    if (res != MP_UNDEF)
+        goto CLEANUP7;
+
+    res = mp_invmod(&a, &m, &t1); /* we expect this to fail. */
+    if (res != MP_UNDEF) {
+    CLEANUP7:
+        reason("error: invmod test 7 succeeded, should have failed.\n");
+        return 1;
+    }
+    mp_clear(&a);
+    mp_clear(&c);
+    mp_clear(&t1);
+    mp_init(&a);
+    mp_init(&c);
+    mp_init(&t1);
+
+    /* test 8: Even modulus    - a is odd,  not relatively prime to m */
+
+    /* reuse m */
+    IFOK(mp_mul(&p3, &p1, &a)); /* even a */
+
+    res = mp_invmod_xgcd(&a, &m, &c);
+    if (res != MP_UNDEF)
+        goto CLEANUP8;
+
+    res = mp_invmod(&a, &m, &t1); /* we expect this to fail. */
+    if (res != MP_UNDEF) {
+    CLEANUP8:
+        reason("error: invmod test 8 succeeded, should have failed.\n");
+        return 1;
+    }
+    mp_clear(&a);
+    mp_clear(&m);
+    mp_clear(&c);
+    mp_clear(&t1);
+    mp_init(&a);
+    mp_init(&m);
+    mp_init(&c);
+    mp_init(&t1);
+
+    /* test 9: Even modulus    - m has factor 2**k, k < 32
+     *                     - a is odd, relatively prime to m,
+     */
+    IFOK(mp_mul(&p3, &t4, &m)); /* even m */
+    IFOK(mp_mul(&p1, &p2, &a));
+    IFOK(mp_invmod(&a, &m, &t1));
+    IFOK(mp_invmod_xgcd(&a, &m, &c));
+
+    if (mp_cmp(&t1, &c) != 0) {
+        mp_toradix(&t1, g_intbuf, 16);
+        mp_toradix(&c, a_intbuf, 16);
+        reason("error: invmod test 9 computed %s, expected %s\n",
+               g_intbuf, a_intbuf);
+        return 1;
+    }
+    mp_clear(&m);
+    mp_clear(&t1);
+    mp_clear(&c);
+    mp_init(&m);
+    mp_init(&t1);
+    mp_init(&c);
+
+    /* test 10: Even modulus    - m has factor 2**k, k > 32
+     *                      - a is odd, relatively prime to m,
+     */
+    IFOK(mp_mul(&p3, &t3, &m)); /* even m */
+    /* reuse a */
+    IFOK(mp_invmod(&a, &m, &t1));
+    IFOK(mp_invmod_xgcd(&a, &m, &c));
+
+    if (mp_cmp(&t1, &c) != 0) {
+        mp_toradix(&t1, g_intbuf, 16);
+        mp_toradix(&c, a_intbuf, 16);
+        reason("error: invmod test 10 computed %s, expected %s\n",
+               g_intbuf, a_intbuf);
+        return 1;
+    }
+    mp_clear(&t1);
+    mp_clear(&c);
+    mp_init(&t1);
+    mp_init(&c);
+
+    /* test 11: Even modulus    - m is a power of 2, 2**k | k < 32
+     *                          - a is odd, relatively prime to m,
+     */
+    IFOK(mp_invmod(&a, &t4, &t1));
+    IFOK(mp_invmod_xgcd(&a, &t4, &c));
+
+    if (mp_cmp(&t1, &c) != 0) {
+        mp_toradix(&t1, g_intbuf, 16);
+        mp_toradix(&c, a_intbuf, 16);
+        reason("error: invmod test 11 computed %s, expected %s\n",
+               g_intbuf, a_intbuf);
+        return 1;
+    }
+    mp_clear(&t1);
+    mp_clear(&c);
+    mp_init(&t1);
+    mp_init(&c);
+
+    /* test 12: Even modulus    - m is a power of 2, 2**k | k > 32
+     *                          - a is odd, relatively prime to m,
+     */
+    IFOK(mp_invmod(&a, &t3, &t1));
+    IFOK(mp_invmod_xgcd(&a, &t3, &c));
+
+    if (mp_cmp(&t1, &c) != 0) {
+        mp_toradix(&t1, g_intbuf, 16);
+        mp_toradix(&c, a_intbuf, 16);
+        reason("error: invmod test 12 computed %s, expected %s\n",
+               g_intbuf, a_intbuf);
+        return 1;
+    }
+
+    mp_clear(&a);
+    mp_clear(&m);
+    mp_clear(&c);
+    mp_clear(&t1);
+    mp_clear(&t2);
+    mp_clear(&t3);
+    mp_clear(&t4);
+    mp_clear(&p1);
+    mp_clear(&p2);
+    mp_clear(&p3);
+    mp_clear(&p4);
+    mp_clear(&p5);
+
+    return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_cmp_d(void)
+{
+    mp_int a;
+
+    mp_init(&a);
+    mp_read_radix(&a, mp8, 16);
+
+    if (mp_cmp_d(&a, md8) >= 0) {
+        reason("error: %s >= " DIGIT_FMT "\n", mp8, md8);
+        mp_clear(&a);
+        return 1;
+    }
+
+    mp_read_radix(&a, mp5, 16);
+
+    if (mp_cmp_d(&a, md8) <= 0) {
+        reason("error: %s <= " DIGIT_FMT "\n", mp5, md8);
+        mp_clear(&a);
+        return 1;
+    }
+
+    mp_read_radix(&a, mp6, 16);
+
+    if (mp_cmp_d(&a, md1) != 0) {
+        reason("error: %s != " DIGIT_FMT "\n", mp6, md1);
+        mp_clear(&a);
+        return 1;
+    }
+
+    mp_clear(&a);
+    return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_cmp_z(void)
+{
+    mp_int a;
+
+    mp_init(&a);
+    mp_read_radix(&a, mp6, 16);
+
+    if (mp_cmp_z(&a) != 0) {
+        reason("error: someone thinks a zero value is non-zero\n");
+        mp_clear(&a);
+        return 1;
+    }
+
+    mp_read_radix(&a, mp1, 16);
+
+    if (mp_cmp_z(&a) <= 0) {
+        reason("error: someone thinks a positive value is non-positive\n");
+        mp_clear(&a);
+        return 1;
+    }
+
+    mp_read_radix(&a, mp4, 16);
+
+    if (mp_cmp_z(&a) >= 0) {
+        reason("error: someone thinks a negative value is non-negative\n");
+        mp_clear(&a);
+        return 1;
+    }
+
+    mp_clear(&a);
+    return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_cmp(void)
+{
+    mp_int a, b;
+
+    mp_init(&a);
+    mp_init(&b);
+    mp_read_radix(&a, mp3, 16);
+    mp_read_radix(&b, mp4, 16);
+
+    if (mp_cmp(&a, &b) <= 0) {
+        reason("error: %s <= %s\n", mp3, mp4);
+        mp_clear(&a);
+        mp_clear(&b);
+        return 1;
+    }
+
+    mp_read_radix(&b, mp3, 16);
+    if (mp_cmp(&a, &b) != 0) {
+        reason("error: %s != %s\n", mp3, mp3);
+        mp_clear(&a);
+        mp_clear(&b);
+        return 1;
+    }
+
+    mp_read_radix(&a, mp5, 16);
+    if (mp_cmp(&a, &b) >= 0) {
+        reason("error: %s >= %s\n", mp5, mp3);
+        mp_clear(&a);
+        mp_clear(&b);
+        return 1;
+    }
+
+    mp_clear(&a);
+    mp_clear(&b);
+    return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_cmp_mag(void)
+{
+    mp_int a, b;
+
+    mp_init(&a);
+    mp_init(&b);
+    mp_read_radix(&a, mp5, 16);
+    mp_read_radix(&b, mp4, 16);
+
+    if (mp_cmp_mag(&a, &b) >= 0) {
+        reason("error: %s >= %s\n", mp5, mp4);
+        mp_clear(&a);
+        mp_clear(&b);
+        return 1;
+    }
+
+    mp_read_radix(&b, mp5, 16);
+    if (mp_cmp_mag(&a, &b) != 0) {
+        reason("error: %s != %s\n", mp5, mp5);
+        mp_clear(&a);
+        mp_clear(&b);
+        return 1;
+    }
+
+    mp_read_radix(&a, mp1, 16);
+    if (mp_cmp_mag(&b, &a) >= 0) {
+        reason("error: %s >= %s\n", mp5, mp1);
+        mp_clear(&a);
+        mp_clear(&b);
+        return 1;
+    }
+
+    mp_clear(&a);
+    mp_clear(&b);
+    return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_parity(void)
+{
+    mp_int a;
+
+    mp_init(&a);
+    mp_read_radix(&a, mp1, 16);
+
+    if (!mp_isodd(&a)) {
+        reason("error: expected operand to be odd, but it isn't\n");
+        mp_clear(&a);
+        return 1;
+    }
+
+    mp_read_radix(&a, mp6, 16);
+
+    if (!mp_iseven(&a)) {
+        reason("error: expected operand to be even, but it isn't\n");
+        mp_clear(&a);
+        return 1;
+    }
+
+    mp_clear(&a);
+    return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_gcd(void)
+{
+    mp_int a, b;
+    int out = 0;
+
+    mp_init(&a);
+    mp_init(&b);
+    mp_read_radix(&a, mp7, 16);
+    mp_read_radix(&b, mp1, 16);
+
+    mp_gcd(&a, &b, &a);
+    mp_toradix(&a, g_intbuf, 16);
+
+    if (strcmp(g_intbuf, g_mp71) != 0) {
+        reason("error: computed %s, expected %s\n", g_intbuf, g_mp71);
+        out = 1;
+    }
+
+    mp_clear(&a);
+    mp_clear(&b);
+    return out;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_lcm(void)
+{
+    mp_int a, b;
+    int out = 0;
+
+    mp_init(&a);
+    mp_init(&b);
+    mp_read_radix(&a, mp10, 16);
+    mp_read_radix(&b, mp11, 16);
+
+    mp_lcm(&a, &b, &a);
+    mp_toradix(&a, g_intbuf, 16);
+
+    if (strcmp(g_intbuf, l_mp1011) != 0) {
+        reason("error: computed %s, expected%s\n", g_intbuf, l_mp1011);
+        out = 1;
+    }
+
+    mp_clear(&a);
+    mp_clear(&b);
+
+    return out;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_convert(void)
+{
+    int ix;
+    mp_int a;
+
+    mp_init(&a);
+    mp_read_radix(&a, mp9, 16);
+
+    for (ix = LOW_RADIX; ix <= HIGH_RADIX; ix++) {
+        mp_toradix(&a, g_intbuf, ix);
+
+        if (strcmp(g_intbuf, v_mp9[ix - LOW_RADIX]) != 0) {
+            reason("error: radix %d, computed %s, expected %s\n",
+                   ix, g_intbuf, v_mp9[ix - LOW_RADIX]);
+            mp_clear(&a);
+            return 1;
+        }
+    }
+
+    mp_clear(&a);
+    return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_raw(void)
+{
+    int len, out = 0;
+    mp_int a;
+    char *buf;
+
+    mp_init(&a);
+    mp_read_radix(&a, mp4, 16);
+
+    len = mp_raw_size(&a);
+    if (len != sizeof(b_mp4)) {
+        reason("error: test_raw: expected length %d, computed %d\n", sizeof(b_mp4),
+               len);
+        mp_clear(&a);
+        return 1;
+    }
+
+    buf = calloc(len, sizeof(char));
+    mp_toraw(&a, buf);
+
+    if (memcmp(buf, b_mp4, sizeof(b_mp4)) != 0) {
+        reason("error: test_raw: binary output does not match test vector\n");
+        out = 1;
+    }
+
+    free(buf);
+    mp_clear(&a);
+
+    return out;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_pprime(void)
+{
+    mp_int p;
+    int err = 0;
+    mp_err res;
+
+    mp_init(&p);
+    mp_read_radix(&p, mp7, 16);
+
+    if (mpp_pprime(&p, 5) != MP_YES) {
+        reason("error: %s failed Rabin-Miller test, but is prime\n", mp7);
+        err = 1;
+    }
+
+    IFOK(mp_set_int(&p, 9));
+    res = mpp_pprime(&p, 50);
+    if (res == MP_YES) {
+        reason("error: 9 is composite but passed Rabin-Miller test\n");
+        err = 1;
+    } else if (res != MP_NO) {
+        reason("test mpp_pprime(9, 50) failed: error %d\n", res);
+        err = 1;
+    }
+
+    IFOK(mp_set_int(&p, 15));
+    res = mpp_pprime(&p, 50);
+    if (res == MP_YES) {
+        reason("error: 15 is composite but passed Rabin-Miller test\n");
+        err = 1;
+    } else if (res != MP_NO) {
+        reason("test mpp_pprime(15, 50) failed: error %d\n", res);
+        err = 1;
+    }
+
+    mp_clear(&p);
+
+    return err;
+}
+
+/*------------------------------------------------------------------------*/
+
+int
+test_fermat(void)
+{
+    mp_int p;
+    mp_err res;
+    int err = 0;
+
+    mp_init(&p);
+    mp_read_radix(&p, mp7, 16);
+
+    if ((res = mpp_fermat(&p, 2)) != MP_YES) {
+        reason("error: %s failed Fermat test on 2: %s\n", mp7,
+               mp_strerror(res));
+        ++err;
+    }
+
+    if ((res = mpp_fermat(&p, 3)) != MP_YES) {
+        reason("error: %s failed Fermat test on 3: %s\n", mp7,
+               mp_strerror(res));
+        ++err;
+    }
+
+    mp_clear(&p);
+
+    return err;
+}
+
+/*------------------------------------------------------------------------*/
+/* Like fprintf(), but only if we are behaving in a verbose manner        */
+
+void
+reason(char *fmt, ...)
+{
+    va_list ap;
+
+    if (!g_verbose)
+        return;
+
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+}
+
+/*------------------------------------------------------------------------*/
+/* HERE THERE BE DRAGONS                                                  */
new file mode 100644
--- /dev/null
+++ b/security/nss/cmd/mpitests/mpitests.gyp
@@ -0,0 +1,30 @@
+# 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': 'mpi_tests',
+      'type': 'executable',
+      'sources': [
+        'mpi-test.c',
+      ],
+      'dependencies': [
+        '<(DEPTH)/lib/freebl/freebl.gyp:<(freebl_name)',
+      ]
+    }
+  ],
+  'target_defaults': {
+    'include_dirs': [
+      '<(DEPTH)/lib/freebl/mpi',
+      '<(DEPTH)/lib/util',
+    ]
+  },
+  'variables': {
+    'module': 'nss'
+  }
+}
new file mode 100644
--- /dev/null
+++ b/security/nss/cmd/mpitests/test-info.c
@@ -0,0 +1,157 @@
+/*
+ *  test-info.c
+ *
+ *  Arbitrary precision integer arithmetic library
+ *
+ * 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/. */
+
+/* Table mapping test suite names to index numbers */
+const int g_count = 41;
+const char *g_names[] = {
+    "list",              /* print out a list of the available test suites */
+    "copy",              /* test assignment of mp-int structures          */
+    "exchange",          /* test exchange of mp-int structures            */
+    "zero",              /* test zeroing of an mp-int                     */
+    "set",               /* test setting an mp-int to a small constant    */
+    "absolute-value",    /* test the absolute value function              */
+    "negate",            /* test the arithmetic negation function         */
+    "add-digit",         /* test digit addition                           */
+    "add",               /* test full addition                            */
+    "subtract-digit",    /* test digit subtraction                        */
+    "subtract",          /* test full subtraction                         */
+    "multiply-digit",    /* test digit multiplication                     */
+    "multiply",          /* test full multiplication                      */
+    "square",            /* test full squaring function                   */
+    "divide-digit",      /* test digit division                           */
+    "divide-2",          /* test division by two                          */
+    "divide-2d",         /* test division & remainder by 2^d              */
+    "divide",            /* test full division                            */
+    "expt-digit",        /* test digit exponentiation                     */
+    "expt",              /* test full exponentiation                      */
+    "expt-2",            /* test power-of-two exponentiation              */
+    "modulo-digit",      /* test digit modular reduction                  */
+    "modulo",            /* test full modular reduction                   */
+    "mod-add",           /* test modular addition                         */
+    "mod-subtract",      /* test modular subtraction                      */
+    "mod-multiply",      /* test modular multiplication                   */
+    "mod-square",        /* test modular squaring function                */
+    "mod-expt",          /* test full modular exponentiation              */
+    "mod-expt-digit",    /* test digit modular exponentiation             */
+    "mod-inverse",       /* test modular inverse function                 */
+    "compare-digit",     /* test digit comparison function                */
+    "compare-zero",      /* test zero comparison function                 */
+    "compare",           /* test general signed comparison                */
+    "compare-magnitude", /* test general magnitude comparison             */
+    "parity",            /* test parity comparison functions              */
+    "gcd",               /* test greatest common divisor functions        */
+    "lcm",               /* test least common multiple function           */
+    "conversion",        /* test general radix conversion facilities      */
+    "binary",            /* test raw output format                        */
+    "pprime",            /* test probabilistic primality tester           */
+    "fermat"             /* test Fermat pseudoprimality tester            */
+};
+
+/* Test function prototypes */
+int test_list(void);
+int test_copy(void);
+int test_exch(void);
+int test_zero(void);
+int test_set(void);
+int test_abs(void);
+int test_neg(void);
+int test_add_d(void);
+int test_add(void);
+int test_sub_d(void);
+int test_sub(void);
+int test_mul_d(void);
+int test_mul(void);
+int test_sqr(void);
+int test_div_d(void);
+int test_div_2(void);
+int test_div_2d(void);
+int test_div(void);
+int test_expt_d(void);
+int test_expt(void);
+int test_2expt(void);
+int test_mod_d(void);
+int test_mod(void);
+int test_addmod(void);
+int test_submod(void);
+int test_mulmod(void);
+int test_sqrmod(void);
+int test_exptmod(void);
+int test_exptmod_d(void);
+int test_invmod(void);
+int test_cmp_d(void);
+int test_cmp_z(void);
+int test_cmp(void);
+int test_cmp_mag(void);
+int test_parity(void);
+int test_gcd(void);
+int test_lcm(void);
+int test_convert(void);
+int test_raw(void);
+int test_pprime(void);
+int test_fermat(void);
+
+/* Table mapping index numbers to functions */
+int (*g_tests[])(void) = {
+    test_list, test_copy, test_exch, test_zero,
+    test_set, test_abs, test_neg, test_add_d,
+    test_add, test_sub_d, test_sub, test_mul_d,
+    test_mul, test_sqr, test_div_d, test_div_2,
+    test_div_2d, test_div, test_expt_d, test_expt,
+    test_2expt, test_mod_d, test_mod,
+    test_addmod, test_submod, test_mulmod, test_sqrmod,
+    test_exptmod, test_exptmod_d, test_invmod, test_cmp_d,
+    test_cmp_z, test_cmp, test_cmp_mag, test_parity,
+    test_gcd, test_lcm, test_convert, test_raw,
+    test_pprime, test_fermat
+};
+
+/* Table mapping index numbers to descriptions */
+const char *g_descs[] = {
+    "print out a list of the available test suites",
+    "test assignment of mp-int structures",
+    "test exchange of mp-int structures",
+    "test zeroing of an mp-int",
+    "test setting an mp-int to a small constant",
+    "test the absolute value function",
+    "test the arithmetic negation function",
+    "test digit addition",
+    "test full addition",
+    "test digit subtraction",
+    "test full subtraction",
+    "test digit multiplication",
+    "test full multiplication",
+    "test full squaring function",
+    "test digit division",
+    "test division by two",
+    "test division & remainder by 2^d",
+    "test full division",
+    "test digit exponentiation",
+    "test full exponentiation",
+    "test power-of-two exponentiation",
+    "test digit modular reduction",
+    "test full modular reduction",
+    "test modular addition",
+    "test modular subtraction",
+    "test modular multiplication",
+    "test modular squaring function",
+    "test full modular exponentiation",
+    "test digit modular exponentiation",
+    "test modular inverse function",
+    "test digit comparison function",
+    "test zero comparison function",
+    "test general signed comparison",
+    "test general magnitude comparison",
+    "test parity comparison functions",
+    "test greatest common divisor functions",
+    "test least common multiple function",
+    "test general radix conversion facilities",
+    "test raw output format",
+    "test probabilistic primality tester",
+    "test Fermat pseudoprimality tester"
+};
deleted file mode 100644
--- a/security/nss/cmd/pk11ectest/testvecs.h
+++ /dev/null
@@ -1,818 +0,0 @@
-static ECDH_KAT ecdh_testvecs[] = {
-    { ECCurve_NIST_P256, 1,
-      "7d7dc5f71eb29ddaf80d6214632eeae03d9058af1fb6d22ed80badb62bc1a534",
-      "04ead218590119e8876b29146ff89ca61770c4edbbf97d38ce385ed281d8a6b23028af61281fd35e2fa7002523acc85a429cb06ee6648325389f59edfce1405141",
-      "04700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac",
-      "46fc62106420ff012e54a434fbdd2d25ccc5852060561e68040dd7778997bd7b",
-      "curve: P256 vector: 0", ec_field_GFp },
-
-    { ECCurve_NIST_P256, 1,
-      "38f65d6dce47676044d58ce5139582d568f64bb16098d179dbab07741dd5caf5",
-      "04119f2f047902782ab0c9e27a54aff5eb9b964829ca99c06b02ddba95b0a3f6d08f52b726664cac366fc98ac7a012b2682cbd962e5acb544671d41b9445704d1d",
-      "04809f04289c64348c01515eb03d5ce7ac1a8cb9498f5caa50197e58d43a86a7aeb29d84e811197f25eba8f5194092cb6ff440e26d4421011372461f579271cda3",
-      "057d636096cb80b67a8c038c890e887d1adfa4195e9b3ce241c8a778c59cda67",
-      "curve: P256 vector: 1", ec_field_GFp },
-
-    { ECCurve_NIST_P256, 1,
-      "1accfaf1b97712b85a6f54b148985a1bdc4c9bec0bd258cad4b3d603f49f32c8",
-      "04d9f2b79c172845bfdb560bbb01447ca5ecc0470a09513b6126902c6b4f8d1051f815ef5ec32128d3487834764678702e64e164ff7315185e23aff5facd96d7bc",
-      "04a2339c12d4a03c33546de533268b4ad667debf458b464d77443636440ee7fec3ef48a3ab26e20220bcda2c1851076839dae88eae962869a497bf73cb66faf536",
-      "2d457b78b4614132477618a5b077965ec90730a8c81a1c75d6d4ec68005d67ec",
-      "curve: P256 vector: 2", ec_field_GFp },
-
-    { ECCurve_NIST_P256, 1,
-      "207c43a79bfee03db6f4b944f53d2fb76cc49ef1c9c4d34d51b6c65c4db6932d",
-      "0424277c33f450462dcb3d4801d57b9ced05188f16c28eda873258048cd1607e0dc4789753e2b1f63b32ff014ec42cd6a69fac81dfe6d0d6fd4af372ae27c46f88",
-      "04df3989b9fa55495719b3cf46dccd28b5153f7808191dd518eff0c3cff2b705ed422294ff46003429d739a33206c8752552c8ba54a270defc06e221e0feaf6ac4",
-      "96441259534b80f6aee3d287a6bb17b5094dd4277d9e294f8fe73e48bf2a0024",
-      "curve: P256 vector: 3", ec_field_GFp },
-
-    { ECCurve_NIST_P256, 1,
-      "59137e38152350b195c9718d39673d519838055ad908dd4757152fd8255c09bf",
-      "04a8c5fdce8b62c5ada598f141adb3b26cf254c280b2857a63d2ad783a73115f6b806e1aafec4af80a0d786b3de45375b517a7e5b51ffb2c356537c9e6ef227d4a",
-      "0441192d2813e79561e6a1d6f53c8bc1a433a199c835e141b05a74a97b0faeb9221af98cc45e98a7e041b01cf35f462b7562281351c8ebf3ffa02e33a0722a1328",
-      "19d44c8d63e8e8dd12c22a87b8cd4ece27acdde04dbf47f7f27537a6999a8e62",
-      "curve: P256 vector: 4", ec_field_GFp },
-
-    { ECCurve_NIST_P256, 1,
-      "f5f8e0174610a661277979b58ce5c90fee6c9b3bb346a90a7196255e40b132ef",
-      "047b861dcd2844a5a8363f6b8ef8d493640f55879217189d80326aad9480dfc149c4675b45eeb306405f6c33c38bc69eb2bdec9b75ad5af4706aab84543b9cc63a",
-      "0433e82092a0f1fb38f5649d5867fba28b503172b7035574bf8e5b7100a3052792f2cf6b601e0a05945e335550bf648d782f46186c772c0f20d3cd0d6b8ca14b2f",
-      "664e45d5bba4ac931cd65d52017e4be9b19a515f669bea4703542a2c525cd3d3",
-      "curve: P256 vector: 5", ec_field_GFp },
-
-    { ECCurve_NIST_P256, 1,
-      "3b589af7db03459c23068b64f63f28d3c3c6bc25b5bf76ac05f35482888b5190",
-      "049fb38e2d58ea1baf7622e96720101cae3cde4ba6c1e9fa26d9b1de0899102863d5561b900406edf50802dd7d73e89395f8aed72fba0e1d1b61fe1d22302260f0",
-      "046a9e0c3f916e4e315c91147be571686d90464e8bf981d34a90b6353bca6eeba740f9bead39c2f2bcc2602f75b8a73ec7bdffcbcead159d0174c6c4d3c5357f05",
-      "ca342daa50dc09d61be7c196c85e60a80c5cb04931746820be548cdde055679d",
-      "curve: P256 vector: 6", ec_field_GFp },
-
-    { ECCurve_NIST_P256, 1,
-      "d8bf929a20ea7436b2461b541a11c80e61d826c0a4c9d322b31dd54e7f58b9c8",
-      "0420f07631e4a6512a89ad487c4e9d63039e579cb0d7a556cb9e661cd59c1e7fa46de91846b3eee8a5ec09c2ab1f41e21bd83620ccdd1bdce3ab7ea6e02dd274f5",
-      "04a9c0acade55c2a73ead1a86fb0a9713223c82475791cd0e210b046412ce224bbf6de0afa20e93e078467c053d241903edad734c6b403ba758c2b5ff04c9d4229",
-      "35aa9b52536a461bfde4e85fc756be928c7de97923f0416c7a3ac8f88b3d4489",
-      "curve: P256 vector: 7", ec_field_GFp },
-
-    { ECCurve_NIST_P256, 1,
-      "0f9883ba0ef32ee75ded0d8bda39a5146a29f1f2507b3bd458dbea0b2bb05b4d",
-      "04abb61b423be5d6c26e21c605832c9142dc1dfe5a5fff28726737936e6fbf516d733d2513ef58beab202090586fac91bf0fee31e80ab33473ab23a2d89e58fad6",
-      "0494e94f16a98255fff2b9ac0c9598aac35487b3232d3231bd93b7db7df36f9eb9d8049a43579cfa90b8093a94416cbefbf93386f15b3f6e190b6e3455fedfe69a",
-      "605c16178a9bc875dcbff54d63fe00df699c03e8a888e9e94dfbab90b25f39b4",
-      "curve: P256 vector: 8", ec_field_GFp },
-
-    { ECCurve_NIST_P256, 1,
-      "2beedb04b05c6988f6a67500bb813faf2cae0d580c9253b6339e4a3337bb6c08",
-      "043d63e429cb5fa895a9247129bf4e48e89f35d7b11de8158efeb3e106a2a873950cae9e477ef41e7c8c1064379bb7b554ddcbcae79f9814281f1e50f0403c61f3",
-      "04e099bf2a4d557460b5544430bbf6da11004d127cb5d67f64ab07c94fcdf5274fd9c50dbe70d714edb5e221f4e020610eeb6270517e688ca64fb0e98c7ef8c1c5",
-      "f96e40a1b72840854bb62bc13c40cc2795e373d4e715980b261476835a092e0b",
-      "curve: P256 vector: 9", ec_field_GFp },
-
-    { ECCurve_NIST_P256, 1,
-      "77c15dcf44610e41696bab758943eff1409333e4d5a11bbe72c8f6c395e9f848",
-      "04ad5d13c3db508ddcd38457e5991434a251bed49cf5ddcb59cdee73865f138c9f62cec1e70588aa4fdfc7b9a09daa678081c04e1208b9d662b8a2214bf8e81a21",
-      "04f75a5fe56bda34f3c1396296626ef012dc07e4825838778a645c8248cff0165833bbdf1b1772d8059df568b061f3f1122f28a8d819167c97be448e3dc3fb0c3c",
-      "8388fa79c4babdca02a8e8a34f9e43554976e420a4ad273c81b26e4228e9d3a3",
-      "curve: P256 vector: 10", ec_field_GFp },
-
-    { ECCurve_NIST_P256, 1,
-      "42a83b985011d12303db1a800f2610f74aa71cdf19c67d54ce6c9ed951e9093e",
-      "04ab48caa61ea35f13f8ed07ffa6a13e8db224dfecfae1a7df8b1bb6ebaf0cb97d1274530ca2c385a3218bddfbcbf0b4024c9badd5243bff834ebff24a8618dccb",
-      "042db4540d50230756158abf61d9835712b6486c74312183ccefcaef2797b7674d62f57f314e3f3495dc4e099012f5e0ba71770f9660a1eada54104cdfde77243e",
-      "72877cea33ccc4715038d4bcbdfe0e43f42a9e2c0c3b017fc2370f4b9acbda4a",
-      "curve: P256 vector: 11", ec_field_GFp },
-
-    { ECCurve_NIST_P256, 1,
-      "ceed35507b5c93ead5989119b9ba342cfe38e6e638ba6eea343a55475de2800b",
-      "049a8cd9bd72e71752df91440f77c547509a84df98114e7de4f26cdb39234a625dd07cfc84c8e144fab2839f5189bb1d7c88631d579bbc58012ed9a2327da52f62",
-      "04cd94fc9497e8990750309e9a8534fd114b0a6e54da89c4796101897041d14ecbc3def4b5fe04faee0a11932229fff563637bfdee0e79c6deeaf449f85401c5c4",
-      "e4e7408d85ff0e0e9c838003f28cdbd5247cdce31f32f62494b70e5f1bc36307",
-      "curve: P256 vector: 12", ec_field_GFp },
-
-    { ECCurve_NIST_P256, 1,
-      "43e0e9d95af4dc36483cdd1968d2b7eeb8611fcce77f3a4e7d059ae43e509604",
-      "04f989cf8ee956a82e7ebd9881cdbfb2fd946189b08db53559bc8cfdd48071eb145eff28f1a18a616b04b7d337868679f6dd84f9a7b3d7b6f8af276c19611a541d",
-      "0415b9e467af4d290c417402e040426fe4cf236bae72baa392ed89780dfccdb471cdf4e9170fb904302b8fd93a820ba8cc7ed4efd3a6f2d6b05b80b2ff2aee4e77",
-      "ed56bcf695b734142c24ecb1fc1bb64d08f175eb243a31f37b3d9bb4407f3b96",
-      "curve: P256 vector: 13", ec_field_GFp },
-
-    { ECCurve_NIST_P256, 1,
-      "b2f3600df3368ef8a0bb85ab22f41fc0e5f4fdd54be8167a5c3cd4b08db04903",
-      "0469c627625b36a429c398b45c38677cb35d8beb1cf78a571e40e99fe4eac1cd4e81690112b0a88f20f7136b28d7d47e5fbc2ada3c8edd87589bc19ec9590637bd",
-      "0449c503ba6c4fa605182e186b5e81113f075bc11dcfd51c932fb21e951eee2fa18af706ff0922d87b3f0c5e4e31d8b259aeb260a9269643ed520a13bb25da5924",
-      "bc5c7055089fc9d6c89f83c1ea1ada879d9934b2ea28fcf4e4a7e984b28ad2cf",
-      "curve: P256 vector: 14", ec_field_GFp },
-
-    { ECCurve_NIST_P256, 1,
-      "4002534307f8b62a9bf67ff641ddc60fef593b17c3341239e95bdb3e579bfdc8",
-      "045fe964671315a18aa68a2a6e3dd1fde7e23b8ce7181471cfac43c99e1ae80262d5827be282e62c84de531b963884ba832db5d6b2c3a256f0e604fe7e6b8a7f72",
-      "0419b38de39fdd2f70f7091631a4f75d1993740ba9429162c2a45312401636b29c09aed7232b28e060941741b6828bcdfa2bc49cc844f3773611504f82a390a5ae",
-      "9a4e8e657f6b0e097f47954a63c75d74fcba71a30d83651e3e5a91aa7ccd8343",
-      "curve: P256 vector: 15", ec_field_GFp },
-
-    { ECCurve_NIST_P256, 1,
-      "4dfa12defc60319021b681b3ff84a10a511958c850939ed45635934ba4979147",
-      "04c9b2b8496f1440bd4a2d1e52752fd372835b364885e154a7dac49295f281ec7cfbe6b926a8a4de26ccc83b802b1212400754be25d9f3eeaf008b09870ae76321",
-      "042c91c61f33adfe9311c942fdbff6ba47020feff416b7bb63cec13faf9b0999546cab31b06419e5221fca014fb84ec870622a1b12bab5ae43682aa7ea73ea08d0",
-      "3ca1fc7ad858fb1a6aba232542f3e2a749ffc7203a2374a3f3d3267f1fc97b78",
-      "curve: P256 vector: 16", ec_field_GFp },
-
-    { ECCurve_NIST_P256, 1,
-      "1331f6d874a4ed3bc4a2c6e9c74331d3039796314beee3b7152fcdba5556304e",
-      "0459e1e101521046ad9cf1d082e9d2ec7dd22530cce064991f1e55c5bcf5fcb591482f4f673176c8fdaa0bb6e59b15a3e47454e3a04297d3863c9338d98add1f37",
-      "04a28a2edf58025668f724aaf83a50956b7ac1cfbbff79b08c3bf87dfd2828d767dfa7bfffd4c766b86abeaf5c99b6e50cb9ccc9d9d00b7ffc7804b0491b67bc03",
-      "1aaabe7ee6e4a6fa732291202433a237df1b49bc53866bfbe00db96a0f58224f",
-      "curve: P256 vector: 17", ec_field_GFp },
-
-    { ECCurve_NIST_P256, 1,
-      "dd5e9f70ae740073ca0204df60763fb6036c45709bf4a7bb4e671412fad65da3",
-      "0430b9db2e2e977bcdc98cb87dd736cbd8e78552121925cf16e1933657c2fb23146a45028800b81291bce5c2e1fed7ded650620ebbe6050c6f3a7f0dfb4673ab5c",
-      "04a2ef857a081f9d6eb206a81c4cf78a802bdf598ae380c8886ecd85fdc1ed7644563c4c20419f07bc17d0539fade1855e34839515b892c0f5d26561f97fa04d1a",
-      "430e6a4fba4449d700d2733e557f66a3bf3d50517c1271b1ddae1161b7ac798c",
-      "curve: P256 vector: 18", ec_field_GFp },
-
-    { ECCurve_NIST_P256, 1,
-      "5ae026cfc060d55600717e55b8a12e116d1d0df34af831979057607c2d9c2f76",
-      "0446c9ebd1a4a3c8c0b6d572b5dcfba12467603208a9cb5d2acfbb733c40cf639146c913a27d044185d38b467ace011e04d4d9bbbb8cb9ae25fa92aaf15a595e86",
-      "04ccd8a2d86bc92f2e01bce4d6922cf7fe1626aed044685e95e2eebd464505f01fe9ddd583a9635a667777d5b8a8f31b0f79eba12c75023410b54b8567dddc0f38",
-      "1ce9e6740529499f98d1f1d71329147a33df1d05e4765b539b11cf615d6974d3",
-      "curve: P256 vector: 19", ec_field_GFp },
-
-    { ECCurve_NIST_P256, 1,
-      "b601ac425d5dbf9e1735c5e2d5bdb79ca98b3d5be4a2cfd6f2273f150e064d9d",
-      "047c9e950841d26c8dde8994398b8f5d475a022bc63de7773fcf8d552e01f1ba0acc42b9885c9b3bee0f8d8c57d3a8f6355016c019c4062fa22cff2f209b5cc2e1",
-      "04c188ffc8947f7301fb7b53e36746097c2134bf9cc981ba74b4e9c4361f595e4ebf7d2f2056e72421ef393f0c0f2b0e00130e3cac4abbcc00286168e85ec55051",
-      "4690e3743c07d643f1bc183636ab2a9cb936a60a802113c49bb1b3f2d0661660",
-      "curve: P256 vector: 20", ec_field_GFp },
-
-    { ECCurve_NIST_P256, 1,
-      "fefb1dda1845312b5fce6b81b2be205af2f3a274f5a212f66c0d9fc33d7ae535",
-      "0438b54db85500cb20c61056edd3d88b6a9dc26780a047f213a6e1b900f76596eb6387e4e5781571e4eb8ae62991a33b5dc33301c5bc7e125d53794a39160d8fd0",
-      "04317e1020ff53fccef18bf47bb7f2dd7707fb7b7a7578e04f35b3beed222a0eb609420ce5a19d77c6fe1ee587e6a49fbaf8f280e8df033d75403302e5a27db2ae",
-      "30c2261bd0004e61feda2c16aa5e21ffa8d7e7f7dbf6ec379a43b48e4b36aeb0",
-      "curve: P256 vector: 21", ec_field_GFp },
-
-    { ECCurve_NIST_P256, 1,
-      "334ae0c4693d23935a7e8e043ebbde21e168a7cba3fa507c9be41d7681e049ce",
-      "043f2bf1589abf3047bf3e54ac9a95379bff95f8f55405f64eca36a7eebe8ffca75212a94e66c5ae9a8991872f66a72723d80ec5b2e925745c456f5371943b3a06",
-      "0445fb02b2ceb9d7c79d9c2fa93e9c7967c2fa4df5789f9640b24264b1e524fcb15c6e8ecf1f7d3023893b7b1ca1e4d178972ee2a230757ddc564ffe37f5c5a321",
-      "2adae4a138a239dcd93c243a3803c3e4cf96e37fe14e6a9b717be9599959b11c",
-      "curve: P256 vector: 22", ec_field_GFp },
-
-    { ECCurve_NIST_P256, 1,
-      "2c4bde40214fcc3bfc47d4cf434b629acbe9157f8fd0282540331de7942cf09d",
-      "0429c0807f10cbc42fb45c9989da50681eead716daa7b9e91fd32e062f5eb92ca0ff1d6d1955d7376b2da24fe1163a271659136341bc2eb1195fc706dc62e7f34d",
-      "04a19ef7bff98ada781842fbfc51a47aff39b5935a1c7d9625c8d323d511c92de6e9c184df75c955e02e02e400ffe45f78f339e1afe6d056fb3245f4700ce606ef",
-      "2e277ec30f5ea07d6ce513149b9479b96e07f4b6913b1b5c11305c1444a1bc0b",
-      "curve: P256 vector: 23", ec_field_GFp },
-
-    { ECCurve_NIST_P256, 1,
-      "85a268f9d7772f990c36b42b0a331adc92b5941de0b862d5d89a347cbf8faab0",
-      "049cf4b98581ca1779453cc816ff28b4100af56cf1bf2e5bc312d83b6b1b21d3337a5504fcac5231a0d12d658218284868229c844a04a3450d6c7381abe080bf3b",
-      "04356c5a444c049a52fee0adeb7e5d82ae5aa83030bfff31bbf8ce2096cf161c4b57d128de8b2a57a094d1a001e572173f96e8866ae352bf29cddaf92fc85b2f92",
-      "1e51373bd2c6044c129c436e742a55be2a668a85ae08441b6756445df5493857",
-      "curve: P256 vector: 24", ec_field_GFp },
-
-    { ECCurve_NIST_P384, 1,
-      "3cc3122a68f0d95027ad38c067916ba0eb8c38894d22e1b15618b6818a661774ad463b205da88cf699ab4d43c9cf98a1",
-      "049803807f2f6d2fd966cdd0290bd410c0190352fbec7ff6247de1302df86f25d34fe4a97bef60cff548355c015dbb3e5"
-      "fba26ca69ec2f5b5d9dad20cc9da711383a9dbe34ea3fa5a2af75b46502629ad54dd8b7d73a8abb06a3a3be47d650cc99",
-      "04a7c76b970c3b5fe8b05d2838ae04ab47697b9eaf52e764592efda27fe7513272734466b400091adbf2d68c58e0c5006"
-      "6ac68f19f2e1cb879aed43a9969b91a0839c4c38a49749b661efedf243451915ed0905a32b060992b468c64766fc8437a",
-      "5f9d29dc5e31a163060356213669c8ce132e22f57c9a04f40ba7fcead493b457e5621e766c40a2e3d4d6a04b25e533f1",
-      "curve: P384 vector: 0", ec_field_GFp },
-
-    { ECCurve_NIST_P384, 1,
-      "92860c21bde06165f8e900c687f8ef0a05d14f290b3f07d8b3a8cc6404366e5d5119cd6d03fb12dc58e89f13df9cd783",
-      "04ea4018f5a307c379180bf6a62fd2ceceebeeb7d4df063a66fb838aa35243419791f7e2c9d4803c9319aa0eb03c416b"
-      "6668835a91484f05ef028284df6436fb88ffebabcdd69ab0133e6735a1bcfb37203d10d340a8328a7b68770ca75878a1a6",
-      "0430f43fcf2b6b00de53f624f1543090681839717d53c7c955d1d69efaf0349b7363acb447240101cbb3af6641ce4b88e0"
-      "25e46c0c54f0162a77efcc27b6ea792002ae2ba82714299c860857a68153ab62e525ec0530d81b5aa15897981e858757",
-      "a23742a2c267d7425fda94b93f93bbcc24791ac51cd8fd501a238d40812f4cbfc59aac9520d758cf789c76300c69d2ff",
-      "curve: P384 vector: 1", ec_field_GFp },
-
-    { ECCurve_NIST_P384, 1,
-      "12cf6a223a72352543830f3f18530d5cb37f26880a0b294482c8a8ef8afad09aa78b7dc2f2789a78c66af5d1cc553853",
-      "04fcfcea085e8cf74d0dced1620ba8423694f903a219bbf901b0b59d6ac81baad316a242ba32bde85cb248119b852fab6"
-      "6972e3c68c7ab402c5836f2a16ed451a33120a7750a6039f3ff15388ee622b7065f7122bf6d51aefbc29b37b03404581b",
-      "041aefbfa2c6c8c855a1a216774550b79a24cda37607bb1f7cc906650ee4b3816d68f6a9c75da6e4242cebfb6652f65180"
-      "419d28b723ebadb7658fcebb9ad9b7adea674f1da3dc6b6397b55da0f61a3eddacb4acdb14441cb214b04a0844c02fa3",
-      "3d2e640f350805eed1ff43b40a72b2abed0a518bcebe8f2d15b111b6773223da3c3489121db173d414b5bd5ad7153435",
-      "curve: P384 vector: 2", ec_field_GFp },
-
-    { ECCurve_NIST_P384, 1,
-      "8dd48063a3a058c334b5cc7a4ce07d02e5ee6d8f1f3c51a1600962cbab462690ae3cd974fb39e40b0e843daa0fd32de1",
-      "04e38c9846248123c3421861ea4d32669a7b5c3c08376ad28104399494c84ff5efa3894adb2c6cbe8c3c913ef2eec5bd3"
-      "c9fa84024a1028796df84021f7b6c9d02f0f4bd1a612a03cbf75a0beea43fef8ae84b48c60172aadf09c1ad016d0bf3ce",
-      "048bc089326ec55b9cf59b34f0eb754d93596ca290fcb3444c83d4de3a5607037ec397683f8cef07eab2fe357eae36c44"
-      "9d9d16ce8ac85b3f1e94568521aae534e67139e310ec72693526aa2e927b5b322c95a1a033c229cb6770c957cd3148dd7",
-      "6a42cfc392aba0bfd3d17b7ccf062b91fc09bbf3417612d02a90bdde62ae40c54bb2e56e167d6b70db670097eb8db854",
-      "curve: P384 vector: 3", ec_field_GFp },
-
-    { ECCurve_NIST_P384, 1,
-      "84ece6cc3429309bd5b23e959793ed2b111ec5cb43b6c18085fcaea9efa0685d98a6262ee0d330ee250bc8a67d0e733f",
-      "043222063a2997b302ee60ee1961108ff4c7acf1c0ef1d5fb0d164b84bce71c431705cb9aea9a45f5d73806655a058bee"
-      "3e61fa9e7fbe7cd43abf99596a3d3a039e99fa9dc93b0bdd9cad81966d17eeaf557068afa7c78466bb5b22032d1100fa6",
-      "04eb952e2d9ac0c20c6cc48fb225c2ad154f53c8750b003fd3b4ed8ed1dc0defac61bcdde02a2bcfee7067d75d342ed2b"
-      "0f1828205baece82d1b267d0d7ff2f9c9e15b69a72df47058a97f3891005d1fb38858f5603de840e591dfa4f6e7d489e1",
-      "ce7ba454d4412729a32bb833a2d1fd2ae612d4667c3a900e069214818613447df8c611de66da200db7c375cf913e4405",
-      "curve: P384 vector: 4", ec_field_GFp },
-
-    { ECCurve_NIST_P384, 1,
-      "68fce2121dc3a1e37b10f1dde309f9e2e18fac47cd1770951451c3484cdb77cb136d00e731260597cc2859601c01a25b",
-      "04868be0e694841830e424d913d8e7d86b84ee1021d82b0ecf523f09fe89a76c0c95c49f2dfbcf829c1e39709d55efbb"
-      "3b9195eb183675b40fd92f51f37713317e4a9b4f715c8ab22e0773b1bc71d3a219f05b8116074658ee86b52e36f3897116",
-      "04441d029e244eb7168d647d4df50db5f4e4974ab3fdaf022aff058b3695d0b8c814cc88da6285dc6df1ac55c55388500"
-      "3e8025ac23a41d4b1ea2aa46c50c6e479946b59b6d76497cd9249977e0bfe4a6262622f13d42a3c43d66bdbb30403c345",
-      "ba69f0acdf3e1ca95caaac4ecaf475bbe51b54777efce01ca381f45370e486fe87f9f419b150c61e329a286d1aa265ec",
-      "curve: P384 vector: 5", ec_field_GFp },
-
-    { ECCurve_NIST_P384, 1,
-      "b1764c54897e7aae6de9e7751f2f37de849291f88f0f91093155b858d1cc32a3a87980f706b86cc83f927bdfdbeae0bd",
-      "04c371222feaa6770c6f3ea3e0dac9740def4fcf821378b7f91ff937c21e0470f70f3a31d5c6b2912195f10926942b48ae"
-      "047d6b4d765123563f81116bc665b7b8cc6207830d805fd84da7cb805a65baa7c12fd592d1b5b5e3e65d9672a9ef7662",
-      "043d4e6bf08a73404accc1629873468e4269e82d90d832e58ad72142639b5a056ad8d35c66c60e8149fac0c797bceb7c2"
-      "f9b0308dc7f0e6d29f8c277acbc65a21e5adb83d11e6873bc0a07fda0997f482504602f59e10bc5cb476b83d0a4f75e71",
-      "1a6688ee1d6e59865d8e3ada37781d36bb0c2717eef92e61964d3927cb765c2965ea80f7f63e58c322ba0397faeaf62b",
-      "curve: P384 vector: 6", ec_field_GFp },
-
-    { ECCurve_NIST_P384, 1,
-      "f0f7a96e70d98fd5a30ad6406cf56eb5b72a510e9f192f50e1f84524dbf3d2439f7287bb36f5aa912a79deaab4adea82",
-      "0499c8c41cb1ab5e0854a346e4b08a537c1706a61553387c8d94943ab15196d40dbaa55b8210a77a5d00915f2c4ea69e"
-      "ab5531065bdcf17bfb3cb55a02e41a57c7f694c383ad289f900fbd656c2233a93c92e933e7a26f54cbb56f0ad875c51bb0",
-      "04f5f6bef1d110da03be0017eac760cc34b24d092f736f237bc7054b3865312a813bcb62d297fb10a4f7abf54708fe2d3d"
-      "06fdf8d7dc032f4e10010bf19cbf6159321252ff415fb91920d438f24e67e60c2eb0463204679fa356af44cea9c9ebf5",
-      "d06a568bf2336b90cbac325161be7695eacb2295f599500d787f072612aca313ee5d874f807ddef6c1f023fe2b6e7cd0",
-      "curve: P384 vector: 7", ec_field_GFp },
-
-    { ECCurve_NIST_P384, 1,
-      "9efb87ddc61d43c482ba66e1b143aef678fbd0d1bebc2000941fabe677fe5b706bf78fce36d100b17cc787ead74bbca2",
-      "044c34efee8f0c95565d2065d1bbac2a2dd25ae964320eb6bccedc5f3a9b42a881a1afca1bb6b880584fa27b01c193cd9"
-      "2d8fb01dbf7cd0a3868c26b951f393c3c56c2858cee901f7793ff5d271925d13a41f8e52409f4eba1990f33acb0bac669",
-      "047cdec77e0737ea37c67b89b7137fe38818010f4464438ee4d1d35a0c488cad3fde2f37d00885d36d3b795b9f93d23a6"
-      "728c42ee8d6027c56cf979ba4c229fdb01d234944f8ac433650112c3cf0f02844e888a3569dfef7828a8a884589aa055e",
-      "bb3b1eda9c6560d82ff5bee403339f1e80342338a991344853b56b24f109a4d94b92f654f0425edd4c205903d7586104",
-      "curve: P384 vector: 8", ec_field_GFp },
-
-    { ECCurve_NIST_P384, 1,
-      "d787a57fde22ec656a0a525cf3c738b30d73af61e743ea90893ecb2d7b622add2f94ee25c2171467afb093f3f84d0018",
-      "04171546923b87b2cbbad664f01ce932bf09d6a6118168678446bfa9f0938608cb4667a98f4ec8ac1462285c2508f7486"
-      "2fa41cb4db68ae71f1f8a3e8939dc52c2dec61a83c983beb2a02baf29ec49278088882ed0cf56c74b5c173b552ccf63cf",
-      "048eeea3a319c8df99fbc29cb55f243a720d95509515ee5cc587a5c5ae22fbbd009e626db3e911def0b99a4f7ae304b1b"
-      "a73877dc94db9adddc0d9a4b24e8976c22d73c844370e1ee857f8d1b129a3bd5f63f40caf3bd0533e38a5f5777074ff9e",
-      "1e97b60add7cb35c7403dd884c0a75795b7683fff8b49f9d8672a8206bfdcf0a106b8768f983258c74167422e44e4d14",
-      "curve: P384 vector: 9", ec_field_GFp },
-
-    { ECCurve_NIST_P384, 1,
-      "83d70f7b164d9f4c227c767046b20eb34dfc778f5387e32e834b1e6daec20edb8ca5bb4192093f543b68e6aeb7ce788b",
-      "0457cd770f3bbcbe0c78c770eab0b169bc45e139f86378ffae1c2b16966727c2f2eb724572b8f3eb228d130db4ff862c"
-      "637ec5c8813b685558d83e924f14bc719f6eb7ae0cbb2c474227c5bda88637a4f26c64817929af999592da6f787490332f",
-      "04a721f6a2d4527411834b13d4d3a33c29beb83ab7682465c6cbaf6624aca6ea58c30eb0f29dd842886695400d7254f20f"
-      "14ba6e26355109ad35129366d5e3a640ae798505a7fa55a96a36b5dad33de00474f6670f522214dd7952140ab0a7eb68",
-      "1023478840e54775bfc69293a3cf97f5bc914726455c66538eb5623e218feef7df4befa23e09d77145ad577db32b41f9",
-      "curve: P384 vector: 10", ec_field_GFp },
-
-    { ECCurve_NIST_P384, 1,
-      "8f558e05818b88ed383d5fca962e53413db1a0e4637eda194f761944cbea114ab9d5da175a7d57882550b0e432f395a9",
-      "049a2f57f4867ce753d72b0d95195df6f96c1fae934f602efd7b6a54582f556cfa539d89005ca2edac08ad9b72dd1f60b"
-      "ad9b94ee82da9cc601f346044998ba387aee56404dc6ecc8ab2b590443319d0b2b6176f9d0eac2d44678ed561607d09a9",
-      "04d882a8505c2d5cb9b8851fc676677bb0087681ad53faceba1738286b45827561e7da37b880276c656cfc38b32ade847"
-      "e34b314bdc134575654573cffaf40445da2e6aaf987f7e913cd4c3091523058984a25d8f21da8326192456c6a0fa5f60c",
-      "6ad6b9dc8a6cf0d3691c501cbb967867f6e4bbb764b60dbff8fcff3ed42dbba39d63cf325b4b4078858495ddee75f954",
-      "curve: P384 vector: 11", ec_field_GFp },
-
-    { ECCurve_NIST_P384, 1,
-      "0f5dee0affa7bbf239d5dff32987ebb7cf84fcceed643e1d3c62d0b3352aec23b6e5ac7fa4105c8cb26126ad2d1892cb",
-      "0423346bdfbc9d7c7c736e02bdf607671ff6082fdd27334a8bc75f3b23681ebe614d0597dd614fae58677c835a9f0b273"
-      "b82ba36290d2f94db41479eb45ab4eaf67928a2315138d59eecc9b5285dfddd6714f77557216ea44cc6fc119d8243efaf",
-      "04815c9d773dbf5fb6a1b86799966247f4006a23c92e68c55e9eaa998b17d8832dd4d84d927d831d4f68dac67c6488219f"
-      "e79269948b2611484560fd490feec887cb55ef99a4b524880fa7499d6a07283aae2afa33feab97deca40bc606c4d8764",
-      "cc9e063566d46b357b3fcae21827377331e5e290a36e60cd7c39102b828ae0b918dc5a02216b07fe6f1958d834e42437",
-      "curve: P384 vector: 12", ec_field_GFp },
-
-    { ECCurve_NIST_P384, 1,
-      "037b633b5b8ba857c0fc85656868232e2febf59578718391b81da8541a00bfe53c30ae04151847f27499f8d7abad8cf4",
-      "048878ac8a947f7d5cb2b47aad24fbb8210d86126585399a2871f84aa9c5fde3074ae540c6bf82275ca822d0feb862bc7"
-      "4632f5cd2f900c2711c32f8930728eb647d31edd8d650f9654e7d33e5ed1b475489d08daa30d8cbcba6bfc3b60d9b5a37",
-      "041c0eeda7a2be000c5bdcda0478aed4db733d2a9e341224379123ad847030f29e3b168fa18e89a3c0fba2a6ce1c28fc3"
-      "bec8c1c83c118c4dbea94271869f2d868eb65e8b44e21e6f14b0f4d9b38c068daefa27114255b9a41d084cc4a1ad85456",
-      "deff7f03bd09865baf945e73edff6d5122c03fb561db87dec8662e09bed4340b28a9efe118337bb7d3d4f7f568635ff9",
-      "curve: P384 vector: 13", ec_field_GFp },
-
-    { ECCurve_NIST_P384, 1,
-      "e3d07106bedcc096e7d91630ffd3094df2c7859db8d7edbb2e37b4ac47f429a637d06a67d2fba33838764ef203464991",
-      "04e74a1a2b85f1cbf8dbbdf050cf1aff8acb02fda2fb6591f9d3cfe4e79d0ae938a9c1483e7b75f8db24505d65065cdb1"
-      "81773ee591822f7abaa856a1a60bc0a5203548dbd1cb5025466eff8481bd07614eaa04a16c3db76905913e972a5b6b59d",
-      "04c95c185e256bf997f30b311548ae7f768a38dee43eeeef43083f3077be70e2bf39ac1d4daf360c514c8c6be623443d1"
-      "a3e63a663eaf75d8a765ab2b9a35513d7933fa5e26420a5244550ec6c3b6f033b96db2aca3d6ac6aab052ce929595aea5",
-      "c8b1038f735ad3bb3e4637c3e47eab487637911a6b7950a4e461948329d3923b969e5db663675623611a457fcda35a71",
-      "curve: P384 vector: 14", ec_field_GFp },
-
-    { ECCurve_NIST_P384, 1,
-      "f3f9b0c65a49a506632c8a45b10f66b5316f9eeb06fae218f2da62333f99905117b141c760e8974efc4af10570635791",
-      "04a4ad77aa7d86e5361118a6b921710c820721210712f4c347985fdee58aa4effa1e28be80a17b120b139f96300f89b4"
-      "9b1ddf22e07e03f1560d8f45a480094560dba9fae7f9531130c1b57ebb95982496524f31d3797793396fa823f22bdb4328",
-      "043497238a7e6ad166df2dac039aa4dac8d17aa925e7c7631eb3b56e3aaa1c545fcd54d2e5985807910fb202b1fc191d2a"
-      "a49e5c487dcc7aa40a8f234c979446040d9174e3ad357d404d7765183195aed3f913641b90c81a306ebf0d8913861316",
-      "d337eaa32b9f716b8747b005b97a553c59dab0c51df41a2d49039cdae705aa75c7b9e7bc0b6a0e8c578c902bc4fff23e",
-      "curve: P384 vector: 15", ec_field_GFp },
-
-    { ECCurve_NIST_P384, 1,
-      "59fce7fad7de28bac0230690c95710c720e528f9a4e54d3a6a8cd5fc5c5f21637031ce1c5b4e3d39647d8dcb9b794664",
-      "049c43bf971edf09402876ee742095381f78b1bd3aa39b5132af75dbfe7e98bd78bde10fe2e903c2b6379e1deee175a1b"
-      "0a6c58ecea5a477bb01bd543b339f1cc49f1371a2cda4d46eb4e53e250597942351a99665a122ffea9bde0636c375daf2",
-      "0490a34737d45b1aa65f74e0bd0659bc118f8e4b774b761944ffa6573c6df4f41dec0d11b697abd934d390871d4b453240"
-      "9b590719bb3307c149a7817be355d684893a307764b512eeffe07cb699edb5a6ffbf8d6032e6c79d5e93e94212c2aa4e",
-      "32d292b695a4488e42a7b7922e1ae537d76a3d21a0b2e36875f60e9f6d3e8779c2afb3a413b9dd79ae18e70b47d337c1",
-      "curve: P384 vector: 16", ec_field_GFp },
-
-    { ECCurve_NIST_P384, 1,
-      "3e49fbf950a424c5d80228dc4bc35e9f6c6c0c1d04440998da0a609a877575dbe437d6a5cedaa2ddd2a1a17fd112aded",
-      "045a949594228b1a3d6f599eb3db0d06070fbc551c657b58234ba164ce3fe415fa5f3eb823c08dc29b8c341219c77b6b3"
-      "d2baad447c8c290cfed25edd9031c41d0b76921457327f42db31122b81f337bbf0b1039ec830ce9061a3761953c75e4a8",
-      "04dda546acfc8f903d11e2e3920669636d44b2068aeb66ff07aa266f0030e1535b0ed0203cb8a460ac990f1394faf22f1"
-      "d15bbb2597913035faadf413476f4c70f7279769a40c986f470c427b4ee4962abdf8173bbad81874772925fd32f0b159f",
-      "1220e7e6cad7b25df98e5bbdcc6c0b65ca6c2a50c5ff6c41dca71e475646fd489615979ca92fb4389aeadefde79a24f1",
-      "curve: P384 vector: 17", ec_field_GFp },
-
-    { ECCurve_NIST_P384, 1,
-      "50ccc1f7076e92f4638e85f2db98e0b483e6e2204c92bdd440a6deea04e37a07c6e72791c190ad4e4e86e01efba84269",
-      "04756c07df0ce32c839dac9fb4733c9c28b70113a676a7057c38d223f22a3a9095a8d564653af528e04c7e1824be4a651"
-      "217c2ce6962cbd2a2e066297b39d57dd9bb4680f0191d390f70b4e461419b2972ce68ad46127fdda6c39195774ea86df3",
-      "04788be2336c52f4454d63ee944b1e49bfb619a08371048e6da92e584eae70bde1f171c4df378bd1f3c0ab03048a237802"
-      "4673ebd8db604eaf41711748bab2968a23ca4476ce144e728247f08af752929157b5830f1e26067466bdfa8b65145a33",
-      "793bb9cd22a93cf468faf804a38d12b78cb12189ec679ddd2e9aa21fa9a5a0b049ab16a23574fe04c1c3c02343b91beb",
-      "curve: P384 vector: 18", ec_field_GFp },
-
-    { ECCurve_NIST_P384, 1,
-      "06f132b71f74d87bf99857e1e4350a594e5fe35533b888552ceccbc0d8923c902e36141d7691e28631b8bc9bafe5e064",
-      "042a3cc6b8ff5cde926e7e3a189a1bd029c9b586351af8838f4f201cb8f4b70ef3b0da06d352c80fc26baf8f42b784459"
-      "ebf9985960176da6d23c7452a2954ffcbbcb24249b43019a2a023e0b3dabd461f19ad3e775c364f3f11ad49f3099400d3",
-      "04d09bb822eb99e38060954747c82bb3278cf96bbf36fece3400f4c873838a40c135eb3babb9293bd1001bf3ecdee7bf2"
-      "6d416db6e1b87bbb7427788a3b6c7a7ab2c165b1e366f9608df512037584f213a648d47f16ac326e19aae972f63fd76c9",
-      "012d191cf7404a523678c6fc075de8285b243720a903047708bb33e501e0dbee5bcc40d7c3ef6c6da39ea24d830da1e8",
-      "curve: P384 vector: 19", ec_field_GFp },
-
-    { ECCurve_NIST_P384, 1,
-      "12048ebb4331ec19a1e23f1a2c773b664ccfe90a28bfb846fc12f81dff44b7443c77647164bf1e9e67fd2c07a6766241",
-      "04bc18836bc7a9fdf54b5352f37d7528ab8fa8ec544a8c6180511cbfdd49cce377c39e34c031b5240dc9980503ed2f26"
-      "2c8086cbe338191080f0b7a16c7afc4c7b0326f9ac66f58552ef4bb9d24de3429ed5d3277ed58fcf48f2b5f61326bec6c6",
-      "0413741262ede5861dad71063dfd204b91ea1d3b7c631df68eb949969527d79a1dc59295ef7d2bca6743e8cd77b04d1"
-      "b580baaeadc7e19d74a8a04451a135f1be1b02fe299f9dc00bfdf201e83d995c6950bcc1cb89d6f7b30bf54656b9a4da586",
-      "ad0fd3ddffe8884b9263f3c15fe1f07f2a5a22ffdc7e967085eea45f0cd959f20f18f522763e28bcc925e496a52dda98",
-      "curve: P384 vector: 20", ec_field_GFp },
-
-    { ECCurve_NIST_P384, 1,
-      "34d61a699ca576169fcdc0cc7e44e4e1221db0fe63d16850c8104029f7d48449714b9884328cae189978754ab460b486",
-      "04867f81104ccd6b163a7902b670ef406042cb0cce7dcdc63d1dfc91b2c40e3cdf7595834bf9eceb79849f1636fc8462f"
-      "c9d4bde8e875ec49697d258d1d59465f8431c6f5531e1c59e9f9ebe3cf164a8d9ce10a12f1979283a959bad244dd83863",
-      "049e22cbc18657f516a864b37b783348b66f1aa9626cd631f4fa1bd32ad88cf11db52057c660860d39d11fbf024fabd44"
-      "46b0d53c79681c28116df71e9cee74fd56c8b7f04b39f1198cc72284e98be9562e35926fb4f48a9fbecafe729309e8b6f",
-      "dc4ca392dc15e20185f2c6a8ea5ec31dfc96f56153a47394b3072b13d0015f5d4ae13beb3bed54d65848f9b8383e6c95",
-      "curve: P384 vector: 21", ec_field_GFp },
-
-    { ECCurve_NIST_P384, 1,
-      "dc60fa8736d702135ff16aab992bb88eac397f5972456c72ec447374d0d8ce61153831bfc86ad5a6eb5b60bfb96a862c",
-      "04b69beede85d0f829fec1b893ccb9c3e052ff692e13b974537bc5b0f9feaf7b22e84f03231629b24866bdb4b8cf9089"
-      "1466f85e2bfcaba2843285b0e14ebc07ef7dafff8b424416fee647b59897b619f20eed95a632e6a4206bf7da429c04c560",
-      "042db5da5f940eaa884f4db5ec2139b0469f38e4e6fbbcc52df15c0f7cf7fcb1808c749764b6be85d2fdc5b16f58ad5d"
-      "c022e8b02dcf33e1b5a083849545f84ad5e43f77cb71546dbbac0d11bdb2ee202e9d3872e8d028c08990746c5e1dde9989",
-      "d765b208112d2b9ed5ad10c4046e2e3b0dbf57c469329519e239ac28b25c7d852bf757d5de0ee271cadd021d86cfd347",
-      "curve: P384 vector: 22", ec_field_GFp },
-
-    { ECCurve_NIST_P384, 1,
-      "6fa6a1c704730987aa634b0516a826aba8c6d6411d3a4c89772d7a62610256a2e2f289f5c3440b0ec1e70fa339e251ce",
-      "0453de1fc1328e8de14aecab29ad8a40d6b13768f86f7d298433d20fec791f86f8bc73f358098b256a298bb488de257bf"
-      "4ac28944fd27f17b82946c04c66c41f0053d3692f275da55cd8739a95bd8cd3af2f96e4de959ea8344d8945375905858b",
-      "04329647baa354224eb4414829c5368c82d7893b39804e08cbb2180f459befc4b347a389a70c91a23bd9d30c83be5295d"
-      "3cc8f61923fad2aa8e505d6cfa126b9fabd5af9dce290b75660ef06d1caa73681d06089c33bc4246b3aa30dbcd2435b12",
-      "d3778850aeb58804fbe9dfe6f38b9fa8e20c2ca4e0dec335aafceca0333e3f2490b53c0c1a14a831ba37c4b9d74be0f2",
-      "curve: P384 vector: 23", ec_field_GFp },
-
-    { ECCurve_NIST_P384, 1,
-      "74ad8386c1cb2ca0fcdeb31e0869bb3f48c036afe2ef110ca302bc8b910f621c9fcc54cec32bb89ec7caa84c7b8e54a8",
-      "0427a3e83cfb9d5122e73129d801615857da7cc089cccc9c54ab3032a19e0a0a9f677346e37f08a0b3ed8da6e5dd69106"
-      "38d60e44aa5e0fd30c918456796af37f0e41957901645e5c596c6d989f5859b03a0bd7d1f4e77936fff3c74d204e5388e",
-      "0429d8a36d22200a75b7aea1bb47cdfcb1b7fd66de967041434728ab5d533a060df732130600fe6f75852a871fb2938e3"
-      "9e19b53db528395de897a45108967715eb8cb55c3fcbf23379372c0873a058d57544b102ecce722b2ccabb1a603774fd5",
-      "81e1e71575bb4505498de097350186430a6242fa6c57b85a5f984a23371123d2d1424eefbf804258392bc723e4ef1e35",
-      "curve: P384 vector: 24", ec_field_GFp },
-
-    { ECCurve_NIST_P521, 1,
-      "017eecc07ab4b329068fba65e56a1f8890aa935e57134ae0ffcce802735151f4eac6564f6ee9974c5e6887a1fefee5743"
-      "ae2241bfeb95d5ce31ddcb6f9edb4d6fc47",
-      "0400602f9d0cf9e526b29e22381c203c48a886c2b0673033366314f1ffbcba240ba42f4ef38a76174635f91e6b4ed3427"
-      "5eb01c8467d05ca80315bf1a7bbd945f550a501b7c85f26f5d4b2d7355cf6b02117659943762b6d1db5ab4f1dbc44ce7b2"
-      "946eb6c7de342962893fd387d1b73d7a8672d1f236961170b7eb3579953ee5cdc88cd2d",
-      "0400685a48e86c79f0f0875f7bc18d25eb5fc8c0b07e5da4f4370f3a9490340854334b1e1b87fa395464c60626124a4e70"
-      "d0f785601d37c09870ebf176666877a2046d01ba52c56fc8776d9e8f5db4f0cc27636d0b741bbe05400697942e80b739884"
-      "a83bde99e0f6716939e632bc8986fa18dccd443a348b6c3e522497955a4f3c302f676",
-      "005fc70477c3e63bc3954bd0df3ea0d1f41ee21746ed95fc5e1fdf90930d5e136672d72cc770742d1711c3c3a4c334a0ad9"
-      "759436a4d3c5bf6e74b9578fac148c831",
-      "curve: P521 vector: 0", ec_field_GFp },
-
-    { ECCurve_NIST_P521, 1,
-      "00816f19c1fb10ef94d4a1d81c156ec3d1de08b66761f03f06ee4bb9dcebbbfe1eaa1ed49a6a990838d8ed318c14d74cc"
-      "872f95d05d07ad50f621ceb620cd905cfb8",
-      "0400d45615ed5d37fde699610a62cd43ba76bedd8f85ed31005fe00d6450fbbd101291abd96d4945a8b57bc73b3fe9f46"
-      "71105309ec9b6879d0551d930dac8ba45d25501425332844e592b440c0027972ad1526431c06732df19cd46a242172d4d"
-      "d67c2c8c99dfc22e49949a56cf90c6473635ce82f25b33682fb19bc33bd910ed8ce3a7fa",
-      "0401df277c152108349bc34d539ee0cf06b24f5d3500677b4445453ccc21409453aafb8a72a0be9ebe54d12270aa51b3a"
-      "b7f316aa5e74a951c5e53f74cd95fc29aee7a013d52f33a9f3c14384d1587fa8abe7aed74bc33749ad9c570b471776422c"
-      "7d4505d9b0a96b3bfac041e4c6a6990ae7f700e5b4a6640229112deafa0cd8bb0d089b0",
-      "000b3920ac830ade812c8f96805da2236e002acbbf13596a9ab254d44d0e91b6255ebf1229f366fb5a05c5884ef46032c2"
-      "6d42189273ca4efa4c3db6bd12a6853759",
-      "curve: P521 vector: 1", ec_field_GFp },
-
-    { ECCurve_NIST_P521, 1,
-      "012f2e0c6d9e9d117ceb9723bced02eb3d4eebf5feeaf8ee0113ccd8057b13ddd416e0b74280c2d0ba8ed291c443bc1b14"
-      "1caf8afb3a71f97f57c225c03e1e4d42b0",
-      "0400717fcb3d4a40d103871ede044dc803db508aaa4ae74b70b9fb8d8dfd84bfecfad17871879698c292d2fd5e17b4f9343"
-      "636c531a4fac68a35a93665546b9a87867900f3d96a8637036993ab5d244500fff9d2772112826f6436603d3eb234a44d5c"
-      "4e5c577234679c4f9df725ee5b9118f23d8a58d0cc01096daf70e8dfec0128bdc2e8",
-      "040092db3142564d27a5f0006f819908fba1b85038a5bc2509906a497daac67fd7aee0fc2daba4e4334eeaef0e0019204b4"
-      "71cd88024f82115d8149cc0cf4f7ce1a4d5016bad0623f517b158d9881841d2571efbad63f85cbe2e581960c5d670601a67"
-      "60272675a548996217e4ab2b8ebce31d71fca63fcc3c08e91c1d8edd91cf6fe845f8",
-      "006b380a6e95679277cfee4e8353bf96ef2a1ebdd060749f2f046fe571053740bbcc9a0b55790bc9ab56c3208aa05ddf746"
-      "a10a3ad694daae00d980d944aabc6a08f",
-      "curve: P521 vector: 2", ec_field_GFp },
-
-    { ECCurve_NIST_P521, 1,
-      "00e548a79d8b05f923b9825d11b656f222e8cb98b0f89de1d317184dc5a698f7c71161ee7dc11cd31f4f4f8ae3a981e1a3e7"
-      "8bdebb97d7c204b9261b4ef92e0918e0",
-      "04000ce800217ed243dd10a79ad73df578aa8a3f9194af528cd1094bbfee27a3b5481ad5862c8876c0c3f91294c0ab3aa806"
-      "d9020cbaa2ed72b7fecdc5a09a6dad6f3201543c9ab45b12469232918e21d5a351f9a4b9cbf9efb2afcc402fa9b31650bec2d6"
-      "41a05c440d35331c0893d11fb13151335988b303341301a73dc5f61d574e67d9",
-      "0400fdd40d9e9d974027cb3bae682162eac1328ad61bc4353c45bf5afe76bf607d2894c8cce23695d920f2464fda4773d4693b"
-      "e4b3773584691bdb0329b7f4c86cc2990034ceac6a3fef1c3e1c494bfe8d872b183832219a7e14da414d4e3474573671ec19b03"
-      "3be831b915435905925b44947c592959945b4eb7c951c3b9c8cf52530ba23",
-      "00fbbcd0b8d05331fef6086f22a6cce4d35724ab7a2f49dd8458d0bfd57a0b8b70f246c17c4468c076874b0dff7a0336823b19e"
-      "98bf1cec05e4beffb0591f97713c6",
-      "curve: P521 vector: 3", ec_field_GFp },
-
-    { ECCurve_NIST_P521, 1,
-      "01c8aae94bb10b8ca4f7be577b4fb32bb2381032c4942c24fc2d753e7cc5e47b483389d9f3b956d20ee9001b1eef9f23545f72"
-      "c5602140046839e963313c3decc864",
-      "040106a14e2ee8ff970aa8ab0c79b97a33bba2958e070b75b94736b77bbe3f777324fa52872771aa88a63a9e8490c3378df4dc"
-      "760cd14d62be700779dd1a4377943656002366ce3941e0b284b1aa81215d0d3b9778fce23c8cd1e4ed6fa0abf62156c91d4b3eb"
-      "55999c3471bed275e9e60e5aa9d690d310bfb15c9c5bbd6f5e9eb39682b74",
-      "040098d99dee0816550e84dbfced7e88137fddcf581a725a455021115fe49f8dc3cf233cd9ea0e6f039dc7919da973cdceaca20"
-      "5da39e0bd98c8062536c47f258f44b500cd225c8797371be0c4297d2b457740100c774141d8f214c23b61aa2b6cd4806b9b70722"
-      "aa4965fb622f42b7391e27e5ec21c5679c5b06b59127372997d421adc1e",
-      "0145cfa38f25943516c96a5fd4bfebb2f645d10520117aa51971eff442808a23b4e23c187e639ff928c3725fbd1c0c2ad0d4aeb2"
-      "07bc1a6fb6cb6d467888dc044b3c",
-      "curve: P521 vector: 4", ec_field_GFp },
-
-    { ECCurve_NIST_P521, 1,
-      "009b0af137c9696c75b7e6df7b73156bb2d45f482e5a4217324f478b10ceb76af09724cf86afa316e7f89918d31d54824a5c33"
-      "107a483c15c15b96edc661340b1c0e",
-      "0400748cdbb875d35f4bccb62abe20e82d32e4c14dc2feb5b87da2d0ccb11c9b6d4b7737b6c46f0dfb4d896e2db92fcf53cdbb"
-      "ae2a404c0babd564ad7adeac6273efa301984acab8d8f173323de0bb60274b228871609373bb22a17287e9dec7495873abc09a"
-      "8915b54c8455c8e02f654f602e23a2bbd7a9ebb74f3009bd65ecc650814cc0",
-      "04007ae115adaaf041691ab6b7fb8c921f99d8ed32d283d67084e80b9ad9c40c56cd98389fb0a849d9ecf7268c297b6f934061"
-      "19f40e32b5773ed25a28a9a85c4a758801a28e004e37eeaefe1f4dbb71f1878696141af3a10a9691c4ed93487214643b761fa4b"
-      "0fbeeb247cf6d3fba7a60697536ad03f49b80a9d1cb079673654977c5fa94",
-      "005c5721e96c273319fd60ecc46b5962f698e974b429f28fe6962f4ac656be2eb8674c4aafc037eab48ece612953b1e8d86101"
-      "6b6ad0c79805784c67f73ada96f351",
-      "curve: P521 vector: 5", ec_field_GFp },
-
-    { ECCurve_NIST_P521, 1,
-      "01e48faacee6dec83ffcde944cf6bdf4ce4bae72747888ebafee455b1e91584971efb49127976a52f4142952f7c207ec0265f2b"
-      "718cf3ead96ea4f62c752e4f7acd3",
-      "04010eb1b4d9172bcc23f4f20cc9560fc54928c3f34ea61c00391dc766c76ed9fa608449377d1e4fadd1236025417330b4b91086"
-      "704ace3e4e6484c606e2a943478c860149413864069825ee1d0828da9f4a97713005e9bd1adbc3b38c5b946900721a960fe96ad2c"
-      "1b3a44fe3de9156136d44cb17cbc2415729bb782e16bfe2deb3069e43",
-      "04012588115e6f7f7bdcfdf57f03b169b479758baafdaf569d04135987b2ce6164c02a57685eb5276b5dae6295d3fe90620f38b55"
-      "35c6d2260c173e61eb888ca92020301542c169cf97c2596fe2ddd848a222e367c5f7e6267ebc1bcd9ab5dcf49158f1a48e4af29a89"
-      "7b7e6a82091c2db874d8e7abf0f58064691344154f396dbaed188b6",
-      "01736d9717429b4f412e903febe2f9e0fffd81355d6ce2c06ff3f66a3be15ceec6e65e308347593f00d7f33591da4043c30763d72"
-      "749f72cdceebe825e4b34ecd570",
-      "curve: P521 vector: 6", ec_field_GFp },
-
-    { ECCurve_NIST_P521, 1,
-      "00c29aa223ea8d64b4a1eda27f39d3bc98ea0148dd98c1cbe595f8fd2bfbde119c9e017a50f5d1fc121c08c1cef31b75885955"
-      "6eb3e0e042d8dd6aaac57a05ca61e3",
-      "04001511c848ef60d5419a98d10204db0fe58224124370061bcfa4e9249d50618c56bf3722471b259f38263bb7b280d23caf2a"
-      "1ee8737f9371cdb2732cdc958369930c01d461681ae6d8c49b4c5f4d6016143fb1bd7491573e3ed0e6c48b82e821644f87f82f0"
-      "e5f08fd16f1f98fa17586200ab02ed8c627b35c3f27617ec5fd92f456203f",
-      "040169491d55bd09049fdf4c2a53a660480fee4c03a0538675d1cd09b5bba78dac48543ef118a1173b3fbf8b20e39ce0e6b8"
-      "90a163c50f9645b3d21d1cbb3b60a6fff40083494b2eba76910fed33c761804515011fab50e3b377abd8a8a045d886d2238d2"
-      "c268ac1b6ec88bd71b7ba78e2c33c152e4bf7da5d565e4acbecf5e92c7ad662bb",
-      "018f2ae9476c771726a77780208dedfefa205488996b18fecc50bfd4c132753f5766b2cd744afa9918606de2e016effc63622"
-      "e9029e76dc6e3f0c69f7aeced565c2c",
-      "curve: P521 vector: 7", ec_field_GFp },
-
-    { ECCurve_NIST_P521, 1,
-      "0028692be2bf5c4b48939846fb3d5bce74654bb2646e15f8389e23708a1afadf561511ea0d9957d0b53453819d60fba8f65a1"
-      "8f7b29df021b1bb01cd163293acc3cc",
-      "0401cfdc10c799f5c79cb6930a65fba351748e07567993e5e410ef4cacc4cd8a25784991eb4674e41050f930c7190ac812b92"
-      "45f48a7973b658daf408822fe5b85f6680180d9ddfc9af77b9c4a6f02a834db15e535e0b3845b2cce30388301b51cecbe32763"
-      "07ef439b5c9e6a72dc2d94d879bc395052dbb4a5787d06efb280210fb8be037",
-      "04008415f5bbd0eee387d6c09d0ef8acaf29c66db45d6ba101860ae45d3c60e1e0e3f7247a4626a60fdd404965c3566c79f644"
-      "9e856ce0bf94619f97da8da24bd2cfb600fdd7c59c58c361bc50a7a5d0d36f723b17c4f2ad2b03c24d42dc50f74a8c465a0afc"
-      "4683f10fab84652dfe9e928c2626b5456453e1573ff60be1507467d431fbb2",
-      "0105a346988b92ed8c7a25ce4d79d21bc86cfcc7f99c6cd19dbb4a39f48ab943b79e4f0647348da0b80bd864b85c6b8d92536"
-      "d6aa544dc7537a00c858f8b66319e25",
-      "curve: P521 vector: 8", ec_field_GFp },
-
-    { ECCurve_NIST_P521, 1,
-      "01194d1ee613f5366cbc44b504d21a0cf6715e209cd358f2dd5f3e71cc0d67d0e964168c42a084ebda746f9863a86bacffc81"
-      "9f1edf1b8c727ccfb3047240a57c435",
-      "04016bd15c8a58d366f7f2b2f298cc87b7485e9ee70d11d12448b8377c0a82c7626f67aff7f97be7a3546bf417eeeddf75a93"
-      "c130191c84108042ea2fca17fd3f80d1401560502d04b74fce1743aab477a9d1eac93e5226981fdb97a7478ce4ce566ff72439"
-      "31284fad850b0c2bcae0ddd2d97790160c1a2e77c3ed6c95ecc44b89e2637fc",
-      "0401c721eea805a5cba29f34ba5758775be0cf6160e6c08723f5ab17bf96a1ff2bd9427961a4f34b07fc0b14ca4b2bf6845de"
-      "bd5a869f124ebfa7aa72fe565050b7f1800b6e89eb0e1dcf181236f7c548fd1a8c16b258b52c1a9bfd3fe8f22841b26763265"
-      "f074c4ccf2d634ae97b701956f67a11006c52d97197d92f585f5748bc2672eeb",
-      "004531b3d2c6cd12f21604c8610e6723dbf4daf80b5a459d6ba5814397d1c1f7a21d7c114be964e27376aaebe3a7bc3d6af7"
-      "a7f8c7befb611afe487ff032921f750f",
-      "curve: P521 vector: 9", ec_field_GFp },
-
-    { ECCurve_NIST_P521, 1,
-      "01fd90e3e416e98aa3f2b6afa7f3bf368e451ad9ca5bd54b5b14aee2ed6723dde5181f5085b68169b09fbec721372ccf6b"
-      "284713f9a6356b8d560a8ff78ca3737c88",
-      "0401ebea1b10d3e3b971b7efb69fc878de11c7f472e4e4d384c31b8d6288d8071517acade9b39796c7af5163bcf71aeda7"
-      "77533f382c6cf0a4d9bbb938c85f44b78037016b0e3e19c2996b2cbd1ff64730e7ca90edca1984f9b2951333535e5748baa"
-      "34a99f61ff4d5f812079e0f01e87789f34efdad8098015ee74a4f846dd190d16dc6e1",
-      "0401c35823e440a9363ab98d9fc7a7bc0c0532dc7977a79165599bf1a9cc64c00fb387b42cca365286e8430360bfad3643"
-      "bc31354eda50dc936c329ecdb60905c40fcb00d9e7f433531e44df4f6d514201cbaabb06badd6783e01111726d815531d23"
-      "3c5cdb722893ffbb2027259d594de77438809738120c6f783934f926c3fb69b40c409",
-      "0100c8935969077bae0ba89ef0df8161d975ec5870ac811ae7e65ca5394efba4f0633d41bf79ea5e5b9496bbd7aae000b05"
-      "94baa82ef8f244e6984ae87ae1ed124b7",
-      "curve: P521 vector: 10", ec_field_GFp },
-
-    { ECCurve_NIST_P521, 1,
-      "009012ecfdadc85ced630afea534cdc8e9d1ab8be5f3753dcf5f2b09b40eda66fc6858549bc36e6f8df55998cfa9a0703a"
-      "ecf6c42799c245011064f530c09db98369",
-      "0400234e32be0a907131d2d128a6477e0caceb86f02479745e0fe245cb332de631c078871160482eeef584e274df7fa412c"
-      "ea3e1e91f71ecba8781d9205d48386341ad01cf86455b09b1c005cffba8d76289a3759628c874beea462f51f30bd581e380"
-      "3134307dedbb771b3334ee15be2e242cd79c3407d2f58935456c6941dd9b6d155a46",
-      "0400093057fb862f2ad2e82e581baeb3324e7b32946f2ba845a9beeed87d6995f54918ec6619b9931955d5a89d4d74adf10"
-      "46bb362192f2ef6bd3e3d2d04dd1f87054a00aa3fb2448335f694e3cda4ae0cc71b1b2f2a206fa802d7262f19983c44674f"
-      "e15327acaac1fa40424c395a6556cb8167312527fae5865ecffc14bbdc17da78cdcf",
-      "017f36af19303841d13a389d95ec0b801c7f9a679a823146c75c17bc44256e9ad422a4f8b31f14647b2c7d317b933f7c294"
-      "6c4b8abd1d56d620fab1b5ff1a3adc71f",
-      "curve: P521 vector: 11", ec_field_GFp },
-
-    { ECCurve_NIST_P521, 1,
-      "01b5ff847f8eff20b88cfad42c06e58c3742f2f8f1fdfd64b539ba48c25926926bd5e332b45649c0b184f77255e9d58fe8"
-      "afa1a6d968e2cb1d4637777120c765c128",
-      "0401de3dc9263bc8c4969dc684be0eec54befd9a9f3dba194d8658a789341bf0d78d84da6735227cafaf093519516911975"
-      "73c8c360a11e5285712b8bbdf5ac91b977c00812de58cd095ec2e5a9b247eb3ed41d8bef6aeace194a7a05b65aa5d289fbc9"
-      "b1770ec84bb6be0c2c64cc37c1d54a7f5d71377a9adbe20f26f6f2b544a821ea831",
-      "040083192ed0b1cb31f75817794937f66ad91cf74552cd510cedb9fd641310422af5d09f221cad249ee814d16dd7ac84ded"
-      "9eacdc28340fcfc9c0c06abe30a2fc28cd8002212ed868c9ba0fb2c91e2c39ba93996a3e4ebf45f2852d0928c48930e875c"
-      "c7b428d0e7f3f4d503e5d60c68cb49b13c2480cd486bed9200caddaddfe4ff8e3562",
-      "00062f9fc29ae1a68b2ee0dcf956cbd38c88ae5f645eaa546b00ebe87a7260bf724be20d34b9d02076655c933d056b21e30"
-      "4c24ddb1dedf1dd76de611fc4a2340336",
-      "curve: P521 vector: 12", ec_field_GFp },
-
-    { ECCurve_NIST_P521, 1,
-      "011a6347d4e801c91923488354cc533e7e35fddf81ff0fb7f56bb0726e0c29ee5dcdc5f394ba54cf57269048aab6e055895c"
-      "8da24b8b0639a742314390cc04190ed6",
-      "0400fe30267f33ba5cdefc25cbb3c9320dad9ccb1d7d376644620ca4fadee5626a3cede25ad254624def727a7048f7145f761"
-      "62aa98042f9b123b2076f8e8cf59b3fdf001145dc6631953b6e2945e94301d6cbb098fe4b04f7ee9b09411df104dc82d7d79e"
-      "c46a01ed0f2d3e7db6eb680694bdeb107c1078aec6cabd9ebee3d342fe7e54df",
-      "0401a89b636a93e5d2ba6c2292bf23033a84f06a3ac1220ea71e806afbe097a804cc67e9baa514cfb6c12c9194be30212bf7a"
-      "ae7fdf6d376c212f0554e656463ffab7e0182efcaf70fc412d336602e014da47256a0b606f2addcce8053bf817ac8656bb4e4"
-      "2f14c8cbf2a68f488ab35dcdf64056271dee1f606a440ba4bd4e5a11b8b8e54f",
-      "0128ab09bfec5406799e610f772ba17e892249fa8e0e7b18a04b9197034b250b48294f1867fb9641518f92766066a07a8b917"
-      "b0e76879e1011e51ccbd9f540c54d4f",
-      "curve: P521 vector: 13", ec_field_GFp },
-
-    { ECCurve_NIST_P521, 1,
-      "0022b6d2a22d71dfaa811d2d9f9f31fbed27f2e1f3d239538ddf3e4cc8c39a330266db25b7bc0a9704f17bde7f3592bf5f1f2d"
-      "4b56013aacc3d8d1bc02f00d3146cc",
-      "0400ba38cfbf9fd2518a3f61d43549e7a6a6d28b2be57ffd3e0faceb636b34ed17e044a9f249dae8fc132e937e2d9349cd2ed7"
-      "7bb1049ceb692a2ec5b17ad61502a64c001ec91d3058573fa6c0564a02a1a010160c313bc7c73510dc983e5461682b5be00dbc"
-      "e7e2c682ad73f29ca822cdc111f68fabe33a7b384a648342c3cdb9f050bcdb",
-      "04017200b3f16a68cbaed2bf78ba8cddfb6cffac262bba00fbc25f9dc72a07ce59372904899f364c44cb264c097b647d4412be"
-      "e3e519892d534d9129f8a28f7500fee700baba8d672a4f4a3b63de48b96f56e18df5d68f7d70d5109833f43770d6732e06b39ad"
-      "60d93e5b43db8789f1ec0aba47286a39ea584235acea757dbf13d53b58364",
-      "0101e462e9d9159968f6440e956f11dcf2227ae4aea81667122b6af9239a291eb5d6cf5a4087f358525fcacfa46bb2db01a75a"
-      "f1ba519b2d31da33eda87a9d565748",
-      "curve: P521 vector: 14", ec_field_GFp },
-
-    { ECCurve_NIST_P521, 1,
-      "005bacfff268acf6553c3c583b464ea36a1d35e2b257a5d49eb3419d5a095087c2fb4d15cf5bf5af816d0f3ff7586490ccd3ddc1"
-      "a98b39ce63749c6288ce0dbdac7d",
-      "040036e488da7581472a9d8e628c58d6ad727311b7e6a3f6ae33a8544f34b09280249020be7196916fafd90e2ec54b66b5468d23"
-      "61b99b56fa00d7ac37abb8c6f16653011edb9fb8adb6a43f4f5f5fdc1421c9fe04fc8ba46c9b66334e3af927c8befb4307104f299"
-      "acec4e30f812d9345c9720d19869dbfffd4ca3e7d2713eb5fc3f42615",
-      "04004efd5dbd2f979e3831ce98f82355d6ca14a5757842875882990ab85ab9b7352dd6b9b2f4ea9a1e95c3880d65d1f3602f9ca6"
-      "53dc346fac858658d75626f4d4fb080061cf15dbdaa7f31589c98400373da284506d70c89f074ed262a9e28140796b7236c2eef99"
-      "016085e71552ff488c72b7339fefb7915c38459cb20ab85aec4e45052",
-      "0141d6a4b719ab67eaf04a92c0a41e2dda78f4354fb90bdc35202cc7699b9b04d49616f82255debf7bbec045ae58f982a66905fc"
-      "fae69d689785e38c868eb4a27e7b",
-      "curve: P521 vector: 15", ec_field_GFp },
-
-    { ECCurve_NIST_P521, 1,
-      "008e2c93c5423876223a637cad367c8589da69a2d0fc68612f31923ae50219df2452e7cc92615b67f17b57ffd2f52b19154bb40"
-      "d7715336420fde2e89fee244f59dc",
-      "0400fa3b35118d6c422570f724a26f90b2833b19239174cea081c53133f64db60d6940ea1261299c04c1f4587cdb0c4c39616"
-      "479c1bb0c146799a118032dcf98f899c00069f040229006151fa32b51f679c8816f7c17506b403809dc77cd58a2aec430d94d"
-      "13b6c916de99f355aa45fcfbc6853d686c71be496a067d24bfaea4818fc51f75",
-      "040129891de0cf3cf82e8c2cf1bf90bb296fe00ab08ca45bb7892e0e227a504fdd05d2381a4448b68adff9c4153c87eacb783"
-      "30d8bd52515f9f9a0b58e85f446bb4e10009edd679696d3d1d0ef327f200383253f6413683d9e4fcc87bb35f112c2f110098d"
-      "15e5701d7ceee416291ff5fed85e687f727388b9afe26a4f6feed560b218e6bb",
-      "00345e26e0abb1aac12b75f3a9cf41efe1c336396dffa4a067a4c2cfeb878c68b2b045faa4e5b4e6fa4678f5b603c351903b1"
-      "4bf9a6a70c439257199a640890b61d1",
-      "curve: P521 vector: 16", ec_field_GFp },
-
-    { ECCurve_NIST_P521, 1,
-      "0004d49d39d40d8111bf16d28c5936554326b197353eebbcf47545393bc8d3aaf98f14f5be7074bfb38e6cc97b989754074da"
-      "ddb3045f4e4ce745669fdb3ec0d5fa8",
-      "04012ec226d050ce07c79b3df4d0f0891f9f7adf462e8c98dbc1a2a14f5e53a3f5ad894433587cc429a8be9ea1d84fa33b180"
-      "3690dae04da7218d30026157fc995cf52004837dfbf3426f57b5c793269130abb9a38f618532211931154db4eeb9aede88e57"
-      "290f842ea0f2ea9a5f74c6203a3920fe4e305f6118f676b154e1d75b9cb5eb88",
-      "0401a3c20240e59f5b7a3e17c275d2314ba1741210ad58b71036f8c83cc1f6b0f409dfdd9113e94b67ec39c3291426c23ffc"
-      "c447054670d2908ff8fe67dc2306034c5c01d2825bfd3af8b1e13205780c137fe938f84fde40188e61ea02cead81badfdb425"
-      "c29f7d7fb0324debadc10bbb93de68f62c35069268283f5265865db57a79f7bf7",
-      "006fe9de6fb8e672e7fd150fdc5e617fabb0d43906354ccfd224757c7276f7a1010091b17ed072074f8d10a5ec971eb35a5c"
-      "b7076603b7bc38d432cbc059f80f9488",
-      "curve: P521 vector: 17", ec_field_GFp },
-
-    { ECCurve_NIST_P521, 1,
-      "011a5d1cc79cd2bf73ea106f0e60a5ace220813b53e27b739864334a07c03367efda7a4619fa6eef3a9746492283b3c445610"
-      "a023a9cc49bf4591140384fca5c8bb5",
-      "0400eb07c7332eedb7d3036059d35f7d2288d4377d5f42337ad3964079fb120ccd4c8bd384b585621055217023acd9a94fcb3"
-      "b965bfb394675e788ade41a1de73e620c00491a835de2e6e7deb7e090f4a11f2c460c0b1f3d5e94ee8d751014dc720784fd3b"
-      "54500c86ebaef18429f09e8e876d5d1538968a030d7715dde99f0d8f06e29d59",
-      "04007e2d138f2832e345ae8ff65957e40e5ec7163f016bdf6d24a2243daa631d878a4a16783990c722382130f9e51f0c1bd6"
-      "ff5ac96780e48b68f5dec95f42e6144bb500b0de5c896791f52886b0f09913e26e78dd0b69798fc4df6d95e3ca708ecbcbcce1c1895f"
-      "5561bbabaae372e9e67e6e1a3be60e19b470cdf673ec1fc393d3426e20",
-      "01e4e759ecedce1013baf73e6fcc0b92451d03bdd50489b78871c333114990c9ba6a9b2fc7b1a2d9a1794c1b60d9279af6f"
-      "146f0bbfb0683140403bfa4ccdb524a29",
-      "curve: P521 vector: 18", ec_field_GFp },
-
-    { ECCurve_NIST_P521, 1,
-      "010c908caf1be74c616b625fc8c1f514446a6aec83b5937141d6afbb0a8c7666a7746fa1f7a6664a2123e8cdf6cd8bf836c5"
-      "6d3c0ebdcc980e43a186f938f3a78ae7",
-      "040031890f4c7abec3f723362285d77d2636f876817db3bbc88b01e773597b969ff6f013ea470c854ab4a7739004eb8cbea6"
-      "9b82ddf36acadd406871798ecb2ac3aa7f00d8b429ae3250266b9643c0c765a60dc10155bc2531cf8627296f4978b6640a9e"
-      "600e19d0037d58503fa80799546a814d7478a550aa90e5ebeb052527faaeae5d08",
-      "0400118c36022209b1af8ebad1a12b566fc48744576e1199fe80de1cdf851cdf03e5b9091a8f7e079e83b7f827259b691d0"
-      "c22ee29d6bdf73ec7bbfd746f2cd97a357d00da5ff4904548a342e2e7ba6a1f4ee5f840411a96cf63e6fe622f22c13e614e"
-      "0a847c11a1ab3f1d12cc850c32e095614ca8f7e2721477b486e9ff40372977c3f65c",
-      "0163c9191d651039a5fe985a0eea1eba018a40ab1937fcd2b61220820ee8f2302e9799f6edfc3f5174f369d672d377ea895"
-      "4a8d0c8b851e81a56fda95212a6578f0e",
-      "curve: P521 vector: 19", ec_field_GFp },
-
-    { ECCurve_NIST_P521, 1,
-      "01b37d6b7288de671360425d3e5ac1ccb21815079d8d73431e9b74a6f0e7ae004a357575b11ad66642ce8b775593eba9d98"
-      "bf25c75ef0b4d3a2098bbc641f59a2b77",
-      "0400189a5ee34de7e35aefeaeef9220c18071b4c29a4c3bd9d954458bd3e82a7a34da34cff5579b8101c065b1f2f527cf45"
-      "81501e28ef5671873e65267733d003520af01eb4bc50a7b4d4599d7e3fa773ddb9eb252c9b3422872e544bdf75c7bf60f51"
-      "66ddc11eb08fa7c30822dabaee373ab468eb2d922e484e2a527fff2ebb804b7d9a37",
-      "0401780edff1ca1c03cfbe593edc6c049bcb2860294a92c355489d9afb2e702075ade1c953895a456230a0cde905de4a3f"
-      "38573dbfcccd67ad6e7e93f0b5581e926a5d00a5481962c9162962e7f0ebdec936935d0eaa813e8226d40d7f6119bfd940"
-      "602380c86721e61db1830f51e139f210000bcec0d8edd39e54d73a9a129f95cd5fa979",
-      "015d613e267a36342e0d125cdad643d80d97ed0600afb9e6b9545c9e64a98cc6da7c5aaa3a8da0bdd9dd3b97e9788218a8"
-      "0abafc106ef065c8f1c4e1119ef58d298b",
-      "curve: P521 vector: 20", ec_field_GFp },
-
-    { ECCurve_NIST_P521, 1,
-      "00f2661ac762f60c5fff23be5d969ccd4ec6f98e4e72618d12bdcdb9b4102162333788c0bae59f91cdfc172c7a1681ee44d9"
-      "6ab2135a6e5f3415ebbcd55165b1afb0",
-      "0400a8e25a6902d687b4787cdc94c364ac7cecc5c495483ed363dc0aa95ee2bd739c4c4d46b17006c728b076350d7d7e54c"
-      "6822f52f47162a25109aaaba690cab696ec0168d2f08fe19e4dc9ee7a195b03c9f7fe6676f9f520b6270557504e72ca4394"
-      "a2c6918625e15ac0c51b8f95cd560123653fb8e8ee6db961e2c4c62cc54e92e2a2a9",
-      "04016dacffa183e5303083a334f765de724ec5ec9402026d4797884a9828a0d321a8cfac74ab737fe20a7d6befcfc73b6a3"
-      "5c1c7b01d373e31abc192d48a4241a35803011e5327cac22d305e7156e559176e19bee7e4f2f59e86f1a9d0b6603b6a7df"
-      "1069bde6387feb71587b8ffce5b266e1bae86de29378a34e5c74b6724c4d40a719923",
-      "014d6082a3b5ced1ab8ca265a8106f302146c4acb8c30bb14a4c991e3c82a9731288bdb91e0e85bda313912d06384fc44"
-      "f2153fb13506fa9cf43c9aab5750988c943",
-      "curve: P521 vector: 21", ec_field_GFp },
-
-    { ECCurve_NIST_P521, 1,
-      "00f430ca1261f09681a9282e9e970a9234227b1d5e58d558c3cc6eff44d1bdf53de16ad5ee2b18b92d62fc79586116b0e"
-      "fc15f79340fb7eaf5ce6c44341dcf8dde27",
-      "04006c1d9b5eca87de1fb871a0a32f807c725adccde9b3967453a71347d608f0c030cd09e338cdecbf4a02015bc8a6e8"
-      "d3e2595fe773ffc2fc4e4a55d0b1a2cc00323b01141b2109e7f4981c952aa818a2b9f6f5c41feccdb7a7a45b9b4b6729"
-      "37771b008cae5f934dfe3fed10d383ab1f38769c92ce88d9be5414817ecb073a31ab368ccb",
-      "0400a091421d3703e3b341e9f1e7d58f8cf7bdbd1798d001967b801d1cec27e605c580b2387c1cb464f55ce7ac803341"
-      "02ab03cfb86d88af76c9f4129c01bedd3bbfc4008c9c577a8e6fc446815e9d40baa66025f15dae285f19eb668ee60ae9"
-      "c98e7ecdbf2b2a68e22928059f67db188007161d3ecf397e0883f0c4eb7eaf7827a62205cc",
-      "0020c00747cb8d492fd497e0fec54644bf027d418ab686381f109712a99cabe328b9743d2225836f9ad66e5d7fed1de2"
-      "47e0da92f60d5b31f9e47672e57f710598f4",
-      "curve: P521 vector: 22", ec_field_GFp },
-
-    { ECCurve_NIST_P521, 1,
-      "005dc33aeda03c2eb233014ee468dff753b72f73b00991043ea353828ae69d4cd0fadeda7bb278b535d7c57406ff2e6e"
-      "473a5a4ff98e90f90d6dadd25100e8d85666",
-      "0400c825ba307373cec8dd2498eef82e21fd9862168dbfeb83593980ca9f82875333899fe94f137daf1c4189eb502937"
-      "c3a367ea7951ed8b0f3377fcdf2922021d46a5016b8a2540d5e65493888bc337249e67c0a68774f3e8d81e3b4574a012"
-      "5165f0bd58b8af9de74b35832539f95c3cd9f1b759408560aa6851ae3ac7555347b0d3b13b",
-      "04004f38816681771289ce0cb83a5e29a1ab06fc91f786994b23708ff08a08a0f675b809ae99e9f9967eb1a49f196057"
-      "d69e50d6dedb4dd2d9a81c02bdcc8f7f518460009efb244c8b91087de1eed766500f0e81530752d469256ef79f6b965d"
-      "8a2232a0c2dbc4e8e1d09214bab38485be6e357c4200d073b52f04e4a16fc6f5247187aecb",
-      "00c2bfafcd7fbd3e2fd1c750fdea61e70bd4787a7e68468c574ee99ebc47eedef064e8944a73bcb7913dbab5d93dca6"
-      "60d216c553622362794f7a2acc71022bdb16f",
-      "curve: P521 vector: 23", ec_field_GFp },
-
-    { ECCurve_NIST_P521, 1,
-      "00df14b1f1432a7b0fb053965fd8643afee26b2451ecb6a8a53a655d5fbe16e4c64ce8647225eb11e7fdcb23627471"
-      "dffc5c2523bd2ae89957cba3a57a23933e5a78",
-      "04004e8583bbbb2ecd93f0714c332dff5ab3bc6396e62f3c560229664329baa5138c3bb1c36428abd4e23d17fcb7"
-      "a2cfcc224b2e734c8941f6f121722d7b6b9415457601cf0874f204b0363f020864672fadbf87c8811eb147758b254b"
-      "74b14fae742159f0f671a018212bbf25b8519e126d4cad778cfff50d288fd39ceb0cac635b175ec0",
-      "0401a32099b02c0bd85371f60b0dd20890e6c7af048c8179890fda308b359dbbc2b7a832bb8c6526c4af99a7ea3f0"
-      "b3cb96ae1eb7684132795c478ad6f962e4a6f446d017627357b39e9d7632a1370b3e93c1afb5c851b910eb4ead0c9"
-      "d387df67cde85003e0e427552f1cd09059aad0262e235cce5fba8cedc4fdc1463da76dcd4b6d1a46",
-      "01aaf24e5d47e4080c18c55ea35581cd8da30f1a079565045d2008d51b12d0abb4411cda7a0785b15d149ed301a36"
-      "97062f42da237aa7f07e0af3fd00eb1800d9c41",
-      "curve: P521 vector: 24", ec_field_GFp },
-
-    { ECCurve_pastLastCurve, 0, NULL, NULL, NULL, NULL, NULL, 0 }
-};
-
-static ECDH_KAT nonnist_testvecs[] = {
-    { ECCurve25519, 1,
-      "a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4",
-      NULL,
-      "e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c",
-      "c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552",
-      "curve: 25519 vector: 0", ec_field_plain },
-    { ECCurve25519, 1,
-      "4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba0d",
-      NULL,
-      "e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493",
-      "95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957",
-      "curve: 25519 vector: 1", ec_field_plain },
-    { ECCurve25519, 1,
-      "0900000000000000000000000000000000000000000000000000000000000000",
-      NULL,
-      "0900000000000000000000000000000000000000000000000000000000000000",
-      "422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079",
-      "curve: 25519 vector: 2", ec_field_plain },
-    { ECCurve25519, 1000,
-      "0900000000000000000000000000000000000000000000000000000000000000",
-      NULL,
-      "0900000000000000000000000000000000000000000000000000000000000000",
-      "684cf59ba83309552800ef566f2f4d3c1c3887c49360e3875f2eb94d99532c51",
-      "curve: 25519 vector: 1000 iterations", ec_field_plain },
-#ifdef NSS_ENABLE_EXPENSIVE_TESTS
-    /* This test is disabled by default because it takes a very long time
-       * to run. */
-    { ECCurve25519, 1000000,
-      "0900000000000000000000000000000000000000000000000000000000000000",
-      NULL,
-      "0900000000000000000000000000000000000000000000000000000000000000",
-      "7c3911e0ab2586fd864497297e575e6f3bc601c0883c30df5f4dd2d24f665424",
-      "curve: 25519 vector: 1000000 iterations", ec_field_plain },
-#endif
-    { ECCurve25519, 1,
-      "174a56a75017c029e0861044d3c57c291823cf477ae6e21065cc121578bfa893",
-      NULL,
-      "7bd8396462a5788951caf3d3a28cb0904e4d081e62e6ac2d9da7152eb1310f30",
-      "28c09f6be3666a6ab3bf8f5b03eec14e95505e32726ae887053ce6a2061a9656",
-      "curve: 25519 custom vector 1", ec_field_plain },
-    { ECCurve25519, 1,
-      "577a2a7fcdacd4ccf7d7f81ba93ec83ae4bda32bec00ff7d59c294b69404f688",
-      NULL,
-      "a43b5491cbd9273abf694115f383fabe3bdc5f2baa30d2e00e43b6937a75cc5d",
-      "4aed703c32552576ca0b30a3fab53242e1eea29ddec993219d3c2b3c3e59b735",
-      "curve: 25519 custom vector 1", ec_field_plain },
-
-    { ECCurve_pastLastCurve, 0, NULL, NULL, NULL, NULL, NULL, 0 }
-};
-
-static ECDH_BAD nonnist_testvecs_bad_values[] = {
-    { ECCurve25519, "00", "curve: 25519 vector: 0 bad point", ec_field_plain },
-    { ECCurve25519,
-      "0100000000000000000000000000000000000000000000000000000000000000",
-      "curve: 25519 vector: 1 bad point", ec_field_plain },
-    { ECCurve25519,
-      "e0eb7a7c3b41b8ae1656e3faf19fc46ada098deb9c32b1fd866205165f49b8",
-      "curve: 25519 vector: 2 bad point", ec_field_plain },
-    { ECCurve25519,
-      "5f9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f1157",
-      "curve: 25519 vector: 3 bad point", ec_field_plain },
-    { ECCurve25519,
-      "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
-      "curve: 25519 vector: 4 bad point", ec_field_plain },
-    { ECCurve25519,
-      "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
-      "curve: 25519 vector: 5 bad point", ec_field_plain },
-    { ECCurve25519,
-      "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
-      "curve: 25519 vector: 6 bad point", ec_field_plain },
-    { ECCurve25519,
-      "cdeb7a7c3b41b8ae1656e3faf19fc46ada098deb9c32b1fd866205165f49b880",
-      "curve: 25519 vector: 7 bad point", ec_field_plain },
-    { ECCurve25519,
-      "4c9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f11d7",
-      "curve: 25519 vector: 8 bad point", ec_field_plain },
-    { ECCurve25519,
-      "d9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
-      "curve: 25519 vector: 9 bad point", ec_field_plain },
-    { ECCurve25519,
-      "daffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
-      "curve: 25519 vector: 10 bad point", ec_field_plain },
-    { ECCurve25519,
-      "dbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
-      "curve: 25519 vector: 11 bad point", ec_field_plain },
-
-    { ECCurve_pastLastCurve, 0, NULL, 0 }
-};
--- a/security/nss/cmd/selfserv/selfserv.c
+++ b/security/nss/cmd/selfserv/selfserv.c
@@ -1251,17 +1251,17 @@ handle_connection(
     int newln = 0; /* # of consecutive newlns */
     int firstTime = 1;
     int reqLen;
     int rv;
     int numIOVs;
     PRSocketOptionData opt;
     PRIOVec iovs[16];
     char msgBuf[160];
-    char buf[10240];
+    char buf[10240] = { 0 };
     char fileName[513];
     char proto[128];
     PRDescIdentity aboveLayer = PR_INVALID_IO_LAYER;
 
     pBuf = buf;
     bufRem = sizeof buf;
 
     VLOG(("selfserv: handle_connection: starting"));
--- a/security/nss/cmd/shlibsign/shlibsign.c
+++ b/security/nss/cmd/shlibsign/shlibsign.c
@@ -702,17 +702,17 @@ getSlotList(CK_FUNCTION_LIST_PTR pFuncti
 }
 
 int
 main(int argc, char **argv)
 {
     PLOptState *optstate;
     char *program_name;
     char *libname = NULL;
-    PRLibrary *lib;
+    PRLibrary *lib = NULL;
     PRFileDesc *fd;
     PRStatus rv = PR_SUCCESS;
     const char *input_file = NULL; /* read/create encrypted data from here */
     char *output_file = NULL;      /* write new encrypted data here */
     int bytesRead;
     int bytesWritten;
     unsigned char file_buf[512];
     int count = 0;
@@ -865,34 +865,50 @@ main(int argc, char **argv)
         return 1;
     }
 
     /* Get the platform-dependent library name of the
      * NSS cryptographic module.
      */
     libname = PR_GetLibraryName(NULL, "softokn3");
     assert(libname != NULL);
+    if (!libname) {
+        PR_fprintf(PR_STDERR, "getting softokn3 failed");
+        goto cleanup;
+    }
     lib = PR_LoadLibrary(libname);
     assert(lib != NULL);
+    if (!lib) {
+        PR_fprintf(PR_STDERR, "loading softokn3 failed");
+        goto cleanup;
+    }
     PR_FreeLibraryName(libname);
 
     if (FIPSMODE) {
         /* FIPSMODE == FC_GetFunctionList */
         /* library path must be set to an already signed softokn3/freebl */
         pC_GetFunctionList = (CK_C_GetFunctionList)
             PR_FindFunctionSymbol(lib, "FC_GetFunctionList");
     } else {
         /* NON FIPS mode  == C_GetFunctionList */
         pC_GetFunctionList = (CK_C_GetFunctionList)
             PR_FindFunctionSymbol(lib, "C_GetFunctionList");
     }
     assert(pC_GetFunctionList != NULL);
+    if (!pC_GetFunctionList) {
+        PR_fprintf(PR_STDERR, "getting function list failed");
+        goto cleanup;
+    }
 
     crv = (*pC_GetFunctionList)(&pFunctionList);
     assert(crv == CKR_OK);
+    if (crv != CKR_OK) {
+        PR_fprintf(PR_STDERR, "loading function list failed");
+        goto cleanup;
+    }
 
     if (configDir) {
         if (!dbPrefix) {
             dbPrefix = PL_strdup("");
         }
         crv = softokn_Init(pFunctionList, configDir, dbPrefix);
         if (crv != CKR_OK) {
             logIt("Failed to use provided database directory "
@@ -1299,17 +1315,17 @@ cleanup:
     }
 #ifdef USES_LINKS
     if (link_file) { /* allocated by mkoutput function */
         PL_strfree(link_file);
     }
 #endif
 
     disableUnload = PR_GetEnvSecure("NSS_DISABLE_UNLOAD");
-    if (!disableUnload) {
+    if (!disableUnload && lib) {
         PR_UnloadLibrary(lib);
     }
     PR_Cleanup();
 
     if (crv != CKR_OK)
         return crv;
 
     return (successful) ? 0 : 1;
--- a/security/nss/cmd/tstclnt/tstclnt.c
+++ b/security/nss/cmd/tstclnt/tstclnt.c
@@ -184,19 +184,20 @@ handshakeCallback(PRFileDesc *fd, void *
 }
 
 static void
 PrintUsageHeader(const char *progName)
 {
     fprintf(stderr,
             "Usage:  %s -h host [-a 1st_hs_name ] [-a 2nd_hs_name ] [-p port]\n"
             "[-D | -d certdir] [-C] [-b | -R root-module] \n"
-            "[-n nickname] [-Bafosvx] [-c ciphers] [-Y]\n"
+            "[-n nickname] [-Bafosvx] [-c ciphers] [-Y] [-Z]\n"
             "[-V [min-version]:[max-version]] [-K] [-T] [-U]\n"
-            "[-r N] [-w passwd] [-W pwfile] [-q [-t seconds]] [-I groups]\n",
+            "[-r N] [-w passwd] [-W pwfile] [-q [-t seconds]] [-I groups]\n"
+            "[-A requestfile] [-L totalconnections]",
             progName);
 }
 
 static void
 PrintParameterUsage(void)
 {
     fprintf(stderr, "%-20s Send different SNI name. 1st_hs_name - at first\n"
                     "%-20s handshake, 2nd_hs_name - at second handshake.\n"
@@ -253,20 +254,23 @@ PrintParameterUsage(void)
     fprintf(stderr, "%-20s Print cipher values allowed for parameter -c and exit\n", "-Y");
     fprintf(stderr, "%-20s Enforce using an IPv4 destination address\n", "-4");
     fprintf(stderr, "%-20s Enforce using an IPv6 destination address\n", "-6");
     fprintf(stderr, "%-20s (Options -4 and -6 cannot be combined.)\n", "");
     fprintf(stderr, "%-20s Enable the extended master secret extension [RFC7627]\n", "-G");
     fprintf(stderr, "%-20s Require the use of FFDHE supported groups "
                     "[I-D.ietf-tls-negotiated-ff-dhe]\n",
             "-H");
+    fprintf(stderr, "%-20s Read from a file instead of stdin\n", "-A");
+    fprintf(stderr, "%-20s Allow 0-RTT data (TLS 1.3 only)\n", "-Z");
+    fprintf(stderr, "%-20s Disconnect and reconnect up to N times total\n", "-L");
     fprintf(stderr, "%-20s Comma separated list of enabled groups for TLS key exchange.\n"
                     "%-20s The following values are valid:\n"
                     "%-20s P256, P384, P521, x25519, FF2048, FF3072, FF4096, FF6144, FF8192\n",
-            "-G", "", "");
+            "-I", "", "");
 }
 
 static void
 Usage(const char *progName)
 {
     PrintUsageHeader(progName);
     PrintParameterUsage();
     exit(1);
@@ -885,64 +889,581 @@ restartHandshakeAfterServerCertIfNeeded(
 
     if (SSL_AuthCertificateComplete(fd, error) != SECSuccess) {
         rv = SECFailure;
     }
 
     return rv;
 }
 
-int
-main(int argc, char **argv)
+char *host = NULL;
+char *nickname = NULL;
+char *cipherString = NULL;
+int multiplier = 0;
+SSLVersionRange enabledVersions;
+int disableLocking = 0;
+int enableSessionTickets = 0;
+int enableCompression = 0;
+int enableFalseStart = 0;
+int enableCertStatus = 0;
+int enableSignedCertTimestamps = 0;
+int forceFallbackSCSV = 0;
+int enableExtendedMasterSecret = 0;
+PRBool requireDHNamedGroups = 0;
+PRSocketOptionData opt;
+PRNetAddr addr;
+PRBool allowIPv4 = PR_TRUE;
+PRBool allowIPv6 = PR_TRUE;
+PRBool pingServerFirst = PR_FALSE;
+int pingTimeoutSeconds = -1;
+PRBool clientSpeaksFirst = PR_FALSE;
+PRBool skipProtoHeader = PR_FALSE;
+ServerCertAuth serverCertAuth;
+char *hs1SniHostName = NULL;
+char *hs2SniHostName = NULL;
+PRUint16 portno = 443;
+int override = 0;
+char *requestString = NULL;
+PRInt32 requestStringLen = 0;
+PRBool enableZeroRtt = PR_FALSE;
+
+static int
+writeBytesToServer(PRFileDesc *s, PRPollDesc *pollset, const char *buf, int nb)
 {
-    PRFileDesc *s = NULL;
-    PRFileDesc *std_out;
-    char *host = NULL;
-    char *certDir = NULL;
-    char *nickname = NULL;
-    char *cipherString = NULL;
-    char *tmp;
-    int multiplier = 0;
+    SECStatus rv;
+    const char *bufp = buf;
+
+    FPRINTF(stderr, "%s: Writing %d bytes to server\n",
+            progName, nb);
+    do {
+        PRInt32 cc = PR_Send(s, bufp, nb, 0, maxInterval);
+        if (cc < 0) {
+            PRErrorCode err = PR_GetError();
+            if (err != PR_WOULD_BLOCK_ERROR) {
+                SECU_PrintError(progName,
+                                "write to SSL socket failed");
+                return 254;
+            }
+            cc = 0;
+        }
+        bufp += cc;
+        nb -= cc;
+        if (nb <= 0)
+            break;
+
+        rv = restartHandshakeAfterServerCertIfNeeded(s,
+                                                     &serverCertAuth, override);
+        if (rv != SECSuccess) {
+            SECU_PrintError(progName, "authentication of server cert failed");
+            return EXIT_CODE_HANDSHAKE_FAILED;
+        }
+
+        pollset[SSOCK_FD].in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT;
+        pollset[SSOCK_FD].out_flags = 0;
+        FPRINTF(stderr,
+                "%s: about to call PR_Poll on writable socket !\n",
+                progName);
+        cc = PR_Poll(pollset, 1, PR_INTERVAL_NO_TIMEOUT);
+        if (cc < 0) {
+            SECU_PrintError(progName,
+                            "PR_Poll failed");
+            return -1;
+        }
+        FPRINTF(stderr,
+                "%s: PR_Poll returned with writable socket !\n",
+                progName);
+    } while (1);
+
+    return 0;
+}
+
+static int
+run_client(void)
+{
+    int headerSeparatorPtrnId = 0;
+    int error = 0;
     SECStatus rv;
     PRStatus status;
     PRInt32 filesReady;
     int npds;
-    int override = 0;
-    SSLVersionRange enabledVersions;
-    int disableLocking = 0;
-    int enableSessionTickets = 0;
-    int enableCompression = 0;
-    int enableFalseStart = 0;
-    int enableCertStatus = 0;
-    int enableSignedCertTimestamps = 0;
-    int forceFallbackSCSV = 0;
-    int enableExtendedMasterSecret = 0;
-    PRBool requireDHNamedGroups = 0;
-    PRSocketOptionData opt;
-    PRNetAddr addr;
+    PRFileDesc *s = NULL;
+    PRFileDesc *std_out;
     PRPollDesc pollset[2];
-    PRBool allowIPv4 = PR_TRUE;
-    PRBool allowIPv6 = PR_TRUE;
-    PRBool pingServerFirst = PR_FALSE;
-    int pingTimeoutSeconds = -1;
-    PRBool clientSpeaksFirst = PR_FALSE;
     PRBool wrStarted = PR_FALSE;
-    PRBool skipProtoHeader = PR_FALSE;
-    ServerCertAuth serverCertAuth;
-    int headerSeparatorPtrnId = 0;
-    int error = 0;
-    PRUint16 portno = 443;
-    char *hs1SniHostName = NULL;
-    char *hs2SniHostName = NULL;
+    char *requestStringInt = requestString;
+
+    /* Create socket */
+    s = PR_OpenTCPSocket(addr.raw.family);
+    if (s == NULL) {
+        SECU_PrintError(progName, "error creating socket");
+        error = 1;
+        goto done;
+    }
+
+    opt.option = PR_SockOpt_Nonblocking;
+    opt.value.non_blocking = PR_TRUE; /* default */
+    if (serverCertAuth.testFreshStatusFromSideChannel) {
+        opt.value.non_blocking = PR_FALSE;
+    }
+    status = PR_SetSocketOption(s, &opt);
+    if (status != PR_SUCCESS) {
+        SECU_PrintError(progName, "error setting socket options");
+        error = 1;
+        goto done;
+    }
+
+    s = SSL_ImportFD(NULL, s);
+    if (s == NULL) {
+        SECU_PrintError(progName, "error importing socket");
+        error = 1;
+        goto done;
+    }
+
+    SSL_SetPKCS11PinArg(s, &pwdata);
+
+    rv = SSL_OptionSet(s, SSL_SECURITY, 1);
+    if (rv != SECSuccess) {
+        SECU_PrintError(progName, "error enabling socket");
+        error = 1;
+        goto done;
+    }
+
+    rv = SSL_OptionSet(s, SSL_HANDSHAKE_AS_CLIENT, 1);
+    if (rv != SECSuccess) {
+        SECU_PrintError(progName, "error enabling client handshake");
+        error = 1;
+        goto done;
+    }
+
+    /* all SSL3 cipher suites are enabled by default. */
+    if (cipherString) {
+        char *cstringSaved = cipherString;
+        int ndx;
+
+        while (0 != (ndx = *cipherString++)) {
+            int cipher = 0;
+
+            if (ndx == ':') {
+                int ctmp = 0;
+
+                HEXCHAR_TO_INT(*cipherString, ctmp)
+                cipher |= (ctmp << 12);
+                cipherString++;
+                HEXCHAR_TO_INT(*cipherString, ctmp)
+                cipher |= (ctmp << 8);
+                cipherString++;
+                HEXCHAR_TO_INT(*cipherString, ctmp)
+                cipher |= (ctmp << 4);
+                cipherString++;
+                HEXCHAR_TO_INT(*cipherString, ctmp)
+                cipher |= ctmp;
+                cipherString++;
+            } else {
+                if (!isalpha(ndx))
+                    Usage(progName);
+                ndx = tolower(ndx) - 'a';
+                if (ndx < PR_ARRAY_SIZE(ssl3CipherSuites)) {
+                    cipher = ssl3CipherSuites[ndx];
+                }
+            }
+            if (cipher > 0) {
+                SECStatus status;
+                status = SSL_CipherPrefSet(s, cipher, SSL_ALLOWED);
+                if (status != SECSuccess)
+                    SECU_PrintError(progName, "SSL_CipherPrefSet()");
+            } else {
+                Usage(progName);
+            }
+        }
+        PORT_Free(cstringSaved);
+    }
+
+    rv = SSL_VersionRangeSet(s, &enabledVersions);
+    if (rv != SECSuccess) {
+        SECU_PrintError(progName, "error setting SSL/TLS version range ");
+        error = 1;
+        goto done;
+    }
+
+    /* disable SSL socket locking */
+    rv = SSL_OptionSet(s, SSL_NO_LOCKS, disableLocking);
+    if (rv != SECSuccess) {
+        SECU_PrintError(progName, "error disabling SSL socket locking");
+        error = 1;
+        goto done;
+    }
+
+    /* enable Session Ticket extension. */
+    rv = SSL_OptionSet(s, SSL_ENABLE_SESSION_TICKETS, enableSessionTickets);
+    if (rv != SECSuccess) {
+        SECU_PrintError(progName, "error enabling Session Ticket extension");
+        error = 1;
+        goto done;
+    }
+
+    /* enable compression. */
+    rv = SSL_OptionSet(s, SSL_ENABLE_DEFLATE, enableCompression);
+    if (rv != SECSuccess) {
+        SECU_PrintError(progName, "error enabling compression");
+        error = 1;
+        goto done;
+    }
+
+    /* enable false start. */
+    rv = SSL_OptionSet(s, SSL_ENABLE_FALSE_START, enableFalseStart);
+    if (rv != SECSuccess) {
+        SECU_PrintError(progName, "error enabling false start");
+        error = 1;
+        goto done;
+    }
+
+    if (forceFallbackSCSV) {
+        rv = SSL_OptionSet(s, SSL_ENABLE_FALLBACK_SCSV, PR_TRUE);
+        if (rv != SECSuccess) {
+            SECU_PrintError(progName, "error forcing fallback scsv");
+            error = 1;
+            goto done;
+        }
+    }
+
+    /* enable cert status (OCSP stapling). */
+    rv = SSL_OptionSet(s, SSL_ENABLE_OCSP_STAPLING, enableCertStatus);
+    if (rv != SECSuccess) {
+        SECU_PrintError(progName, "error enabling cert status (OCSP stapling)");
+        error = 1;
+        goto done;
+    }
+
+    /* enable extended master secret mode */
+    if (enableExtendedMasterSecret) {
+        rv = SSL_OptionSet(s, SSL_ENABLE_EXTENDED_MASTER_SECRET, PR_TRUE);
+        if (rv != SECSuccess) {
+            SECU_PrintError(progName, "error enabling extended master secret");
+            error = 1;
+            goto done;
+        }
+    }
+
+    /* enable 0-RTT (TLS 1.3 only) */
+    if (enableZeroRtt) {
+        rv = SSL_OptionSet(s, SSL_ENABLE_0RTT_DATA, PR_TRUE);
+        if (rv != SECSuccess) {
+            SECU_PrintError(progName, "error enabling 0-RTT");
+            error = 1;
+            goto done;
+        }
+    }
+
+    /* require the use of fixed finite-field DH groups */
+    if (requireDHNamedGroups) {
+        rv = SSL_OptionSet(s, SSL_REQUIRE_DH_NAMED_GROUPS, PR_TRUE);
+        if (rv != SECSuccess) {
+            SECU_PrintError(progName, "error in requiring the use of fixed finite-field DH groups");
+            error = 1;
+            goto done;
+        }
+    }
+
+    /* enable Signed Certificate Timestamps. */
+    rv = SSL_OptionSet(s, SSL_ENABLE_SIGNED_CERT_TIMESTAMPS,
+                       enableSignedCertTimestamps);
+    if (rv != SECSuccess) {
+        SECU_PrintError(progName, "error enabling signed cert timestamps");
+        error = 1;
+        goto done;
+    }
+
+    if (enabledGroups) {
+        rv = SSL_NamedGroupConfig(s, enabledGroups, enabledGroupsCount);
+        if (rv < 0) {
+            SECU_PrintError(progName, "SSL_NamedGroupConfig failed");
+            error = 1;
+            goto done;
+        }
+    }
+
+    serverCertAuth.dbHandle = CERT_GetDefaultCertDB();
+
+    SSL_AuthCertificateHook(s, ownAuthCertificate, &serverCertAuth);
+    if (override) {
+        SSL_BadCertHook(s, ownBadCertHandler, NULL);
+    }
+    SSL_GetClientAuthDataHook(s, own_GetClientAuthData, (void *)nickname);
+    SSL_HandshakeCallback(s, handshakeCallback, hs2SniHostName);
+    if (hs1SniHostName) {
+        SSL_SetURL(s, hs1SniHostName);
+    } else {
+        SSL_SetURL(s, host);
+    }
+
+    /* Try to connect to the server */
+    status = PR_Connect(s, &addr, PR_INTERVAL_NO_TIMEOUT);
+    if (status != PR_SUCCESS) {
+        if (PR_GetError() == PR_IN_PROGRESS_ERROR) {
+            if (verbose)
+                SECU_PrintError(progName, "connect");
+            milliPause(50 * multiplier);
+            pollset[SSOCK_FD].in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT;
+            pollset[SSOCK_FD].out_flags = 0;
+            pollset[SSOCK_FD].fd = s;
+            while (1) {
+                FPRINTF(stderr,
+                        "%s: about to call PR_Poll for connect completion!\n",
+                        progName);
+                filesReady = PR_Poll(pollset, 1, PR_INTERVAL_NO_TIMEOUT);
+                if (filesReady < 0) {
+                    SECU_PrintError(progName, "unable to connect (poll)");
+                    error = 1;
+                    goto done;
+                }
+                FPRINTF(stderr,
+                        "%s: PR_Poll returned 0x%02x for socket out_flags.\n",
+                        progName, pollset[SSOCK_FD].out_flags);
+                if (filesReady == 0) { /* shouldn't happen! */
+                    FPRINTF(stderr, "%s: PR_Poll returned zero!\n", progName);
+                    error = 1;
+                    goto done;
+                }
+                status = PR_GetConnectStatus(pollset);
+                if (status == PR_SUCCESS) {
+                    break;
+                }
+                if (PR_GetError() != PR_IN_PROGRESS_ERROR) {
+                    SECU_PrintError(progName, "unable to connect (poll)");
+                    error = 1;
+                    goto done;
+                }
+                SECU_PrintError(progName, "poll");
+                milliPause(50 * multiplier);
+            }
+        } else {
+            SECU_PrintError(progName, "unable to connect");
+            error = 1;
+            goto done;
+        }
+    }
+
+    pollset[SSOCK_FD].fd = s;
+    pollset[SSOCK_FD].in_flags = PR_POLL_EXCEPT |
+                                 (clientSpeaksFirst ? 0 : PR_POLL_READ);
+    pollset[STDIN_FD].fd = PR_GetSpecialFD(PR_StandardInput);
+    if (!requestStringInt) {
+        pollset[STDIN_FD].in_flags = PR_POLL_READ;
+        npds = 2;
+    } else {
+        npds = 1;
+    }
+    std_out = PR_GetSpecialFD(PR_StandardOutput);
+
+#if defined(WIN32) || defined(OS2)
+    /* PR_Poll cannot be used with stdin on Windows or OS/2.  (sigh).
+    ** But use of PR_Poll and non-blocking sockets is a major feature
+    ** of this program.  So, we simulate a pollable stdin with a
+    ** TCP socket pair and a  thread that reads stdin and writes to
+    ** that socket pair.
+    */
+    {
+        PRFileDesc *fds[2];
+        PRThread *thread;
+
+        int nspr_rv = PR_NewTCPSocketPair(fds);
+        if (nspr_rv != PR_SUCCESS) {
+            SECU_PrintError(progName, "PR_NewTCPSocketPair failed");
+            error = 1;
+            goto done;
+        }
+        pollset[STDIN_FD].fd = fds[1];
+
+        thread = PR_CreateThread(PR_USER_THREAD, thread_main, fds[0],
+                                 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+                                 PR_UNJOINABLE_THREAD, 0);
+        if (!thread) {
+            SECU_PrintError(progName, "PR_CreateThread failed");
+            error = 1;
+            goto done;
+        }
+    }
+#endif
+
+    if (serverCertAuth.testFreshStatusFromSideChannel) {
+        SSL_ForceHandshake(s);
+        error = serverCertAuth.sideChannelRevocationTestResultCode;
+        goto done;
+    }
+
+    /*
+    ** Select on stdin and on the socket. Write data from stdin to
+    ** socket, read data from socket and write to stdout.
+    */
+    FPRINTF(stderr, "%s: ready...\n", progName);
+    while ((pollset[SSOCK_FD].in_flags | pollset[STDIN_FD].in_flags) ||
+           requestStringInt) {
+        char buf[4000]; /* buffer for stdin */
+        int nb;         /* num bytes read from stdin. */
+
+        rv = restartHandshakeAfterServerCertIfNeeded(s, &serverCertAuth,
+                                                     override);
+        if (rv != SECSuccess) {
+            error = EXIT_CODE_HANDSHAKE_FAILED;
+            SECU_PrintError(progName, "authentication of server cert failed");
+            goto done;
+        }
+
+        pollset[SSOCK_FD].out_flags = 0;
+        pollset[STDIN_FD].out_flags = 0;
+
+        FPRINTF(stderr, "%s: about to call PR_Poll !\n", progName);
+        filesReady = PR_Poll(pollset, npds, PR_INTERVAL_NO_TIMEOUT);
+        if (filesReady < 0) {
+            SECU_PrintError(progName, "select failed");
+            error = 1;
+            goto done;
+        }
+        if (filesReady == 0) { /* shouldn't happen! */
+            FPRINTF(stderr, "%s: PR_Poll returned zero!\n", progName);
+            error = 1;
+            goto done;
+        }
+        FPRINTF(stderr, "%s: PR_Poll returned!\n", progName);
+        if (pollset[STDIN_FD].in_flags) {
+            FPRINTF(stderr,
+                    "%s: PR_Poll returned 0x%02x for stdin out_flags.\n",
+                    progName, pollset[STDIN_FD].out_flags);
+        }
+        if (pollset[SSOCK_FD].in_flags) {
+            FPRINTF(stderr,
+                    "%s: PR_Poll returned 0x%02x for socket out_flags.\n",
+                    progName, pollset[SSOCK_FD].out_flags);
+        }
+        if (requestStringInt) {
+            error = writeBytesToServer(s, pollset,
+                                       requestStringInt, requestStringLen);
+            if (error) {
+                goto done;
+            }
+            requestStringInt = NULL;
+            pollset[SSOCK_FD].in_flags = PR_POLL_READ;
+        }
+        if (pollset[STDIN_FD].out_flags & PR_POLL_READ) {
+            /* Read from stdin and write to socket */
+            nb = PR_Read(pollset[STDIN_FD].fd, buf, sizeof(buf));
+            FPRINTF(stderr, "%s: stdin read %d bytes\n", progName, nb);
+            if (nb < 0) {
+                if (PR_GetError() != PR_WOULD_BLOCK_ERROR) {
+                    SECU_PrintError(progName, "read from stdin failed");
+                    error = 1;
+                    break;
+                }
+            } else if (nb == 0) {
+                /* EOF on stdin, stop polling stdin for read. */
+                pollset[STDIN_FD].in_flags = 0;
+            } else {
+                error = writeBytesToServer(s, pollset, buf, nb);
+                if (error) {
+                    goto done;
+                }
+                pollset[SSOCK_FD].in_flags = PR_POLL_READ;
+            }
+        }
+
+        if (pollset[SSOCK_FD].in_flags) {
+            FPRINTF(stderr,
+                    "%s: PR_Poll returned 0x%02x for socket out_flags.\n",
+                    progName, pollset[SSOCK_FD].out_flags);
+        }
+        if ((pollset[SSOCK_FD].out_flags & PR_POLL_READ) ||
+            (pollset[SSOCK_FD].out_flags & PR_POLL_ERR)
+#ifdef PR_POLL_HUP
+            || (pollset[SSOCK_FD].out_flags & PR_POLL_HUP)
+#endif
+                ) {
+            /* Read from socket and write to stdout */
+            nb = PR_Recv(pollset[SSOCK_FD].fd, buf, sizeof buf, 0, maxInterval);
+            FPRINTF(stderr, "%s: Read from server %d bytes\n", progName, nb);
+            if (nb < 0) {
+                if (PR_GetError() != PR_WOULD_BLOCK_ERROR) {
+                    SECU_PrintError(progName, "read from socket failed");
+                    error = 1;
+                    goto done;
+                }
+            } else if (nb == 0) {
+                /* EOF from socket... stop polling socket for read */
+                pollset[SSOCK_FD].in_flags = 0;
+            } else {
+                if (skipProtoHeader != PR_TRUE || wrStarted == PR_TRUE) {
+                    PR_Write(std_out, buf, nb);
+                } else {
+                    separateReqHeader(std_out, buf, nb, &wrStarted,
+                                      &headerSeparatorPtrnId);
+                }
+                if (verbose)
+                    fputs("\n\n", stderr);
+            }
+        }
+        milliPause(50 * multiplier);
+    }
+
+done:
+    if (s) {
+        PR_Close(s);
+    }
+
+    return error;
+}
+
+PRInt32
+ReadFile(const char *filename, char **data)
+{
+    char *ret = NULL;
+    char buf[8192];
+    unsigned int len = 0;
+    PRStatus rv;
+
+    PRFileDesc *fd = PR_Open(filename, PR_RDONLY, 0);
+    if (!fd)
+        return -1;
+
+    for (;;) {
+        rv = PR_Read(fd, buf, sizeof(buf));
+        if (rv < 0) {
+            PR_Free(ret);
+            return rv;
+        }
+
+        if (!rv)
+            break;
+
+        ret = PR_Realloc(ret, len + rv);
+        if (!ret) {
+            return -1;
+        }
+        PORT_Memcpy(ret + len, buf, rv);
+        len += rv;
+    }
+
+    *data = ret;
+    return len;
+}
+
+int
+main(int argc, char **argv)
+{
     PLOptState *optstate;
     PLOptStatus optstatus;
+    PRStatus status;
     PRStatus prStatus;
+    int error = 0;
+    char *tmp;
+    SECStatus rv;
+    char *certDir = NULL;
     PRBool openDB = PR_TRUE;
     PRBool loadDefaultRootCAs = PR_FALSE;
     char *rootModule = NULL;
+    int numConnections = 1;
+    PRFileDesc *s = NULL;
 
     serverCertAuth.shouldPause = PR_TRUE;
     serverCertAuth.isPaused = PR_FALSE;
     serverCertAuth.dbHandle = NULL;
     serverCertAuth.testFreshStatusFromSideChannel = PR_FALSE;
     serverCertAuth.sideChannelRevocationTestResultCode = EXIT_CODE_HANDSHAKE_FAILED;
     serverCertAuth.requireDataForIntermediates = PR_FALSE;
     serverCertAuth.allowOCSPSideChannelData = PR_TRUE;
@@ -961,17 +1482,17 @@ main(int argc, char **argv)
         }
     }
 
     SSL_VersionRangeGetSupported(ssl_variant_stream, &enabledVersions);
 
     /* XXX: 'B' was used in the past but removed in 3.28,
      *      please leave some time before resuing it. */
     optstate = PL_CreateOptState(argc, argv,
-                                 "46CDFGHI:KM:OR:STUV:W:Ya:bc:d:fgh:m:n:op:qr:st:uvw:z");
+                                 "46A:CDFGHI:KL:M:OR:STUV:WYZa:bc:d:fgh:m:n:op:qr:st:uvw:z");
     while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
         switch (optstate->option) {
             case '?':
             default:
                 Usage(progName);
                 break;
 
             case '4':
@@ -980,16 +1501,24 @@ main(int argc, char **argv)
                     Usage(progName);
                 break;
             case '6':
                 allowIPv4 = PR_FALSE;
                 if (!allowIPv6)
                     Usage(progName);
                 break;
 
+            case 'A':
+                requestStringLen = ReadFile(optstate->value, &requestString);
+                if (requestStringLen < 0) {
+                    fprintf(stderr, "Couldn't read file %s\n", optstate->value);
+                    exit(1);
+                }
+                break;
+
             case 'C':
                 ++dumpServerChain;
                 break;
 
             case 'D':
                 openDB = PR_FALSE;
                 break;
 
@@ -1012,16 +1541,20 @@ main(int argc, char **argv)
             case 'O':
                 serverCertAuth.shouldPause = PR_FALSE;
                 break;
 
             case 'K':
                 forceFallbackSCSV = PR_TRUE;
                 break;
 
+            case 'L':
+                numConnections = atoi(optstate->value);
+                break;
+
             case 'M':
                 switch (atoi(optstate->value)) {
                     case 1:
                         serverCertAuth.allowOCSPSideChannelData = PR_TRUE;
                         serverCertAuth.allowCRLSideChannelData = PR_FALSE;
                         break;
                     case 2:
                         serverCertAuth.allowOCSPSideChannelData = PR_FALSE;
@@ -1059,16 +1592,20 @@ main(int argc, char **argv)
                 }
                 break;
 
             case 'Y':
                 PrintCipherUsage(progName);
                 exit(0);
                 break;
 
+            case 'Z':
+                enableZeroRtt = PR_TRUE;
+                break;
+
             case 'a':
                 if (!hs1SniHostName) {
                     hs1SniHostName = PORT_Strdup(optstate->value);
                 } else if (!hs2SniHostName) {
                     hs2SniHostName = PORT_Strdup(optstate->value);
                 } else {
                     Usage(progName);
                 }
@@ -1237,16 +1774,17 @@ main(int argc, char **argv)
         char *certDirTmp = certDir;
         certDir = SECU_ConfigDirectory(certDirTmp);
         PORT_Free(certDirTmp);
     }
 
     if (pingServerFirst) {
         int iter = 0;
         PRErrorCode err;
+
         int max_attempts = MAX_WAIT_FOR_SERVER;
         if (pingTimeoutSeconds >= 0) {
             /* If caller requested a timeout, let's try just twice. */
             max_attempts = 2;
         }
         do {
             PRIntervalTime timeoutInterval = PR_INTERVAL_NO_TIMEOUT;
             s = PR_OpenTCPSocket(addr.raw.family);
@@ -1314,462 +1852,46 @@ main(int argc, char **argv)
     }
 
     /* all SSL3 cipher suites are enabled by default. */
     if (cipherString) {
         /* disable all the ciphers, then enable the ones we want. */
         disableAllSSLCiphers();
     }
 
-    /* Create socket */
-    s = PR_OpenTCPSocket(addr.raw.family);
-    if (s == NULL) {
-        SECU_PrintError(progName, "error creating socket");
-        error = 1;
-        goto done;
-    }
-
-    opt.option = PR_SockOpt_Nonblocking;
-    opt.value.non_blocking = PR_TRUE; /* default */
-    if (serverCertAuth.testFreshStatusFromSideChannel) {
-        opt.value.non_blocking = PR_FALSE;
-    }
-    PR_SetSocketOption(s, &opt);
-    /*PR_SetSocketOption(PR_GetSpecialFD(PR_StandardInput), &opt);*/
-
-    s = SSL_ImportFD(NULL, s);
-    if (s == NULL) {
-        SECU_PrintError(progName, "error importing socket");
-        error = 1;
-        goto done;
-    }
-
-    SSL_SetPKCS11PinArg(s, &pwdata);
-
-    rv = SSL_OptionSet(s, SSL_SECURITY, 1);
-    if (rv != SECSuccess) {
-        SECU_PrintError(progName, "error enabling socket");
-        error = 1;
-        goto done;
-    }
-
-    rv = SSL_OptionSet(s, SSL_HANDSHAKE_AS_CLIENT, 1);
-    if (rv != SECSuccess) {
-        SECU_PrintError(progName, "error enabling client handshake");
-        error = 1;
-        goto done;
-    }
-
-    /* all SSL3 cipher suites are enabled by default. */
-    if (cipherString) {
-        char *cstringSaved = cipherString;
-        int ndx;
-
-        while (0 != (ndx = *cipherString++)) {
-            int cipher = 0;
-
-            if (ndx == ':') {
-                int ctmp = 0;
-
-                HEXCHAR_TO_INT(*cipherString, ctmp)
-                cipher |= (ctmp << 12);
-                cipherString++;
-                HEXCHAR_TO_INT(*cipherString, ctmp)
-                cipher |= (ctmp << 8);
-                cipherString++;
-                HEXCHAR_TO_INT(*cipherString, ctmp)
-                cipher |= (ctmp << 4);
-                cipherString++;
-                HEXCHAR_TO_INT(*cipherString, ctmp)
-                cipher |= ctmp;
-                cipherString++;
-            } else {
-                if (!isalpha(ndx))
-                    Usage(progName);
-                ndx = tolower(ndx) - 'a';
-                if (ndx < PR_ARRAY_SIZE(ssl3CipherSuites)) {
-                    cipher = ssl3CipherSuites[ndx];
-                }
-            }
-            if (cipher > 0) {
-                SECStatus status;
-                status = SSL_CipherPrefSet(s, cipher, SSL_ALLOWED);
-                if (status != SECSuccess)
-                    SECU_PrintError(progName, "SSL_CipherPrefSet()");
-            } else {
-                Usage(progName);
-            }
-        }
-        PORT_Free(cstringSaved);
-    }
-
-    rv = SSL_VersionRangeSet(s, &enabledVersions);
-    if (rv != SECSuccess) {
-        SECU_PrintError(progName, "error setting SSL/TLS version range ");
-        error = 1;
-        goto done;
-    }
-
-    /* disable SSL socket locking */
-    rv = SSL_OptionSet(s, SSL_NO_LOCKS, disableLocking);
-    if (rv != SECSuccess) {
-        SECU_PrintError(progName, "error disabling SSL socket locking");
-        error = 1;
-        goto done;
-    }
-
-    /* enable Session Ticket extension. */
-    rv = SSL_OptionSet(s, SSL_ENABLE_SESSION_TICKETS, enableSessionTickets);
-    if (rv != SECSuccess) {
-        SECU_PrintError(progName, "error enabling Session Ticket extension");
-        error = 1;
-        goto done;
-    }
-
-    /* enable compression. */
-    rv = SSL_OptionSet(s, SSL_ENABLE_DEFLATE, enableCompression);
-    if (rv != SECSuccess) {
-        SECU_PrintError(progName, "error enabling compression");
-        error = 1;
-        goto done;
-    }
-
-    /* enable false start. */
-    rv = SSL_OptionSet(s, SSL_ENABLE_FALSE_START, enableFalseStart);
-    if (rv != SECSuccess) {
-        SECU_PrintError(progName, "error enabling false start");
-        error = 1;
-        goto done;
-    }
-
-    if (forceFallbackSCSV) {
-        rv = SSL_OptionSet(s, SSL_ENABLE_FALLBACK_SCSV, PR_TRUE);
-        if (rv != SECSuccess) {
-            SECU_PrintError(progName, "error forcing fallback scsv");
-            error = 1;
-            goto done;
-        }
-    }
-
-    /* enable cert status (OCSP stapling). */
-    rv = SSL_OptionSet(s, SSL_ENABLE_OCSP_STAPLING, enableCertStatus);
-    if (rv != SECSuccess) {
-        SECU_PrintError(progName, "error enabling cert status (OCSP stapling)");
-        error = 1;
-        goto done;
-    }
-
-    /* enable extended master secret mode */
-    if (enableExtendedMasterSecret) {
-        rv = SSL_OptionSet(s, SSL_ENABLE_EXTENDED_MASTER_SECRET, PR_TRUE);
-        if (rv != SECSuccess) {
-            SECU_PrintError(progName, "error enabling extended master secret");
-            error = 1;
-            goto done;
-        }
-    }
-
-    /* require the use of fixed finite-field DH groups */
-    if (requireDHNamedGroups) {
-        rv = SSL_OptionSet(s, SSL_REQUIRE_DH_NAMED_GROUPS, PR_TRUE);
-        if (rv != SECSuccess) {
-            SECU_PrintError(progName, "error in requiring the use of fixed finite-field DH groups");
-            error = 1;
-            goto done;
-        }
-    }
-
-    /* enable Signed Certificate Timestamps. */
-    rv = SSL_OptionSet(s, SSL_ENABLE_SIGNED_CERT_TIMESTAMPS,
-                       enableSignedCertTimestamps);
-    if (rv != SECSuccess) {
-        SECU_PrintError(progName, "error enabling signed cert timestamps");
-        error = 1;
-        goto done;
-    }
-
-    if (enabledGroups) {
-        rv = SSL_NamedGroupConfig(s, enabledGroups, enabledGroupsCount);
-        if (rv < 0) {
-            SECU_PrintError(progName, "SSL_NamedGroupConfig failed");
-            error = 1;
+    while (numConnections--) {
+        error = run_client();
+        if (error) {
             goto done;
         }
     }
 
-    serverCertAuth.dbHandle = CERT_GetDefaultCertDB();
-
-    SSL_AuthCertificateHook(s, ownAuthCertificate, &serverCertAuth);
-    if (override) {
-        SSL_BadCertHook(s, ownBadCertHandler, NULL);
-    }
-    SSL_GetClientAuthDataHook(s, own_GetClientAuthData, (void *)nickname);
-    SSL_HandshakeCallback(s, handshakeCallback, hs2SniHostName);
-    if (hs1SniHostName) {
-        SSL_SetURL(s, hs1SniHostName);
-    } else {
-        SSL_SetURL(s, host);
-    }
-
-    /* Try to connect to the server */
-    status = PR_Connect(s, &addr, PR_INTERVAL_NO_TIMEOUT);
-    if (status != PR_SUCCESS) {
-        if (PR_GetError() == PR_IN_PROGRESS_ERROR) {
-            if (verbose)
-                SECU_PrintError(progName, "connect");
-            milliPause(50 * multiplier);
-            pollset[SSOCK_FD].in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT;
-            pollset[SSOCK_FD].out_flags = 0;
-            pollset[SSOCK_FD].fd = s;
-            while (1) {
-                FPRINTF(stderr,
-                        "%s: about to call PR_Poll for connect completion!\n",
-                        progName);
-                filesReady = PR_Poll(pollset, 1, PR_INTERVAL_NO_TIMEOUT);
-                if (filesReady < 0) {
-                    SECU_PrintError(progName, "unable to connect (poll)");
-                    error = 1;
-                    goto done;
-                }
-                FPRINTF(stderr,
-                        "%s: PR_Poll returned 0x%02x for socket out_flags.\n",
-                        progName, pollset[SSOCK_FD].out_flags);
-                if (filesReady == 0) { /* shouldn't happen! */
-                    FPRINTF(stderr, "%s: PR_Poll returned zero!\n", progName);
-                    error = 1;
-                    goto done;
-                }
-                status = PR_GetConnectStatus(pollset);
-                if (status == PR_SUCCESS) {
-                    break;
-                }
-                if (PR_GetError() != PR_IN_PROGRESS_ERROR) {
-                    SECU_PrintError(progName, "unable to connect (poll)");
-                    error = 1;
-                    goto done;
-                }
-                SECU_PrintError(progName, "poll");
-                milliPause(50 * multiplier);
-            }
-        } else {
-            SECU_PrintError(progName, "unable to connect");
-            error = 1;
-            goto done;
-        }
-    }
-
-    pollset[SSOCK_FD].fd = s;
-    pollset[SSOCK_FD].in_flags = PR_POLL_EXCEPT |
-                                 (clientSpeaksFirst ? 0 : PR_POLL_READ);
-    pollset[STDIN_FD].fd = PR_GetSpecialFD(PR_StandardInput);
-    pollset[STDIN_FD].in_flags = PR_POLL_READ;
-    npds = 2;
-    std_out = PR_GetSpecialFD(PR_StandardOutput);
-
-#if defined(WIN32) || defined(OS2)
-    /* PR_Poll cannot be used with stdin on Windows or OS/2.  (sigh).
-    ** But use of PR_Poll and non-blocking sockets is a major feature
-    ** of this program.  So, we simulate a pollable stdin with a
-    ** TCP socket pair and a  thread that reads stdin and writes to
-    ** that socket pair.
-    */
-    {
-        PRFileDesc *fds[2];
-        PRThread *thread;
-
-        int nspr_rv = PR_NewTCPSocketPair(fds);
-        if (nspr_rv != PR_SUCCESS) {
-            SECU_PrintError(progName, "PR_NewTCPSocketPair failed");
-            error = 1;
-            goto done;
-        }
-        pollset[STDIN_FD].fd = fds[1];
-
-        thread = PR_CreateThread(PR_USER_THREAD, thread_main, fds[0],
-                                 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
-                                 PR_UNJOINABLE_THREAD, 0);
-        if (!thread) {
-            SECU_PrintError(progName, "PR_CreateThread failed");
-            error = 1;
-            goto done;
-        }
-    }
-#endif
-
-    if (serverCertAuth.testFreshStatusFromSideChannel) {
-        SSL_ForceHandshake(s);
-        error = serverCertAuth.sideChannelRevocationTestResultCode;
-        goto done;
+done:
+    if (s) {
+        PR_Close(s);
     }
 
-    /*
-    ** Select on stdin and on the socket. Write data from stdin to
-    ** socket, read data from socket and write to stdout.
-    */
-    FPRINTF(stderr, "%s: ready...\n", progName);
-
-    while (pollset[SSOCK_FD].in_flags | pollset[STDIN_FD].in_flags) {
-        char buf[4000]; /* buffer for stdin */
-        int nb;         /* num bytes read from stdin. */
-
-        rv = restartHandshakeAfterServerCertIfNeeded(s, &serverCertAuth,
-                                                     override);
-        if (rv != SECSuccess) {
-            error = EXIT_CODE_HANDSHAKE_FAILED;
-            SECU_PrintError(progName, "authentication of server cert failed");
-            goto done;
-        }
-
-        pollset[SSOCK_FD].out_flags = 0;
-        pollset[STDIN_FD].out_flags = 0;
-
-        FPRINTF(stderr, "%s: about to call PR_Poll !\n", progName);
-        filesReady = PR_Poll(pollset, npds, PR_INTERVAL_NO_TIMEOUT);
-        if (filesReady < 0) {
-            SECU_PrintError(progName, "select failed");
-            error = 1;
-            goto done;
-        }
-        if (filesReady == 0) { /* shouldn't happen! */
-            FPRINTF(stderr, "%s: PR_Poll returned zero!\n", progName);
-            error = 1;
-            goto done;
-        }
-        FPRINTF(stderr, "%s: PR_Poll returned!\n", progName);
-        if (pollset[STDIN_FD].in_flags) {
-            FPRINTF(stderr,
-                    "%s: PR_Poll returned 0x%02x for stdin out_flags.\n",
-                    progName, pollset[STDIN_FD].out_flags);
-        }
-        if (pollset[SSOCK_FD].in_flags) {
-            FPRINTF(stderr,
-                    "%s: PR_Poll returned 0x%02x for socket out_flags.\n",
-                    progName, pollset[SSOCK_FD].out_flags);
-        }
-        if (pollset[STDIN_FD].out_flags & PR_POLL_READ) {
-            /* Read from stdin and write to socket */
-            nb = PR_Read(pollset[STDIN_FD].fd, buf, sizeof(buf));
-            FPRINTF(stderr, "%s: stdin read %d bytes\n", progName, nb);
-            if (nb < 0) {
-                if (PR_GetError() != PR_WOULD_BLOCK_ERROR) {
-                    SECU_PrintError(progName, "read from stdin failed");
-                    error = 1;
-                    break;
-                }
-            } else if (nb == 0) {
-                /* EOF on stdin, stop polling stdin for read. */
-                pollset[STDIN_FD].in_flags = 0;
-            } else {
-                char *bufp = buf;
-                FPRINTF(stderr, "%s: Writing %d bytes to server\n",
-                        progName, nb);
-                do {
-                    PRInt32 cc = PR_Send(s, bufp, nb, 0, maxInterval);
-                    if (cc < 0) {
-                        PRErrorCode err = PR_GetError();
-                        if (err != PR_WOULD_BLOCK_ERROR) {
-                            SECU_PrintError(progName,
-                                            "write to SSL socket failed");
-                            error = 254;
-                            goto done;
-                        }
-                        cc = 0;
-                    }
-                    bufp += cc;
-                    nb -= cc;
-                    if (nb <= 0)
-                        break;
-
-                    rv = restartHandshakeAfterServerCertIfNeeded(s,
-                                                                 &serverCertAuth, override);
-                    if (rv != SECSuccess) {
-                        error = EXIT_CODE_HANDSHAKE_FAILED;
-                        SECU_PrintError(progName, "authentication of server cert failed");
-                        goto done;
-                    }
-
-                    pollset[SSOCK_FD].in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT;
-                    pollset[SSOCK_FD].out_flags = 0;
-                    FPRINTF(stderr,
-                            "%s: about to call PR_Poll on writable socket !\n",
-                            progName);
-                    cc = PR_Poll(pollset, 1, PR_INTERVAL_NO_TIMEOUT);
-                    if (cc < 0) {
-                        SECU_PrintError(progName,
-                                        "PR_Poll failed");
-                        error = 1;
-                        goto done;
-                    }
-                    FPRINTF(stderr,
-                            "%s: PR_Poll returned with writable socket !\n",
-                            progName);
-                } while (1);
-                pollset[SSOCK_FD].in_flags = PR_POLL_READ;
-            }
-        }
-
-        if (pollset[SSOCK_FD].in_flags) {
-            FPRINTF(stderr,
-                    "%s: PR_Poll returned 0x%02x for socket out_flags.\n",
-                    progName, pollset[SSOCK_FD].out_flags);
-        }
-        if ((pollset[SSOCK_FD].out_flags & PR_POLL_READ) ||
-            (pollset[SSOCK_FD].out_flags & PR_POLL_ERR)
-#ifdef PR_POLL_HUP
-            || (pollset[SSOCK_FD].out_flags & PR_POLL_HUP)
-#endif
-                ) {
-            /* Read from socket and write to stdout */
-            nb = PR_Recv(pollset[SSOCK_FD].fd, buf, sizeof buf, 0, maxInterval);
-            FPRINTF(stderr, "%s: Read from server %d bytes\n", progName, nb);
-            if (nb < 0) {
-                if (PR_GetError() != PR_WOULD_BLOCK_ERROR) {
-                    SECU_PrintError(progName, "read from socket failed");
-                    error = 1;
-                    goto done;
-                }
-            } else if (nb == 0) {
-                /* EOF from socket... stop polling socket for read */
-                pollset[SSOCK_FD].in_flags = 0;
-            } else {
-                if (skipProtoHeader != PR_TRUE || wrStarted == PR_TRUE) {
-                    PR_Write(std_out, buf, nb);
-                } else {
-                    separateReqHeader(std_out, buf, nb, &wrStarted,
-                                      &headerSeparatorPtrnId);
-                }
-                if (verbose)
-                    fputs("\n\n", stderr);
-            }
-        }
-        milliPause(50 * multiplier);
-    }
-
-done:
     if (hs1SniHostName) {
         PORT_Free(hs1SniHostName);
     }
     if (hs2SniHostName) {
         PORT_Free(hs2SniHostName);
     }
     if (nickname) {
         PORT_Free(nickname);
     }
     if (pwdata.data) {
         PORT_Free(pwdata.data);
     }
     PORT_Free(host);
+    PORT_Free(requestString);
 
-    if (s) {
-        PR_Close(s);
-    }
     if (enabledGroups) {
         PORT_Free(enabledGroups);
     }
-
     if (NSS_IsInitialized()) {
         SSL_ClearSessionCache();
         if (NSS_Shutdown() != SECSuccess) {
             error = 1;
         }
     }
 
     FPRINTF(stderr, "tstclnt: exiting with return code %d\n", error);
--- a/security/nss/coreconf/WIN32.mk
+++ b/security/nss/coreconf/WIN32.mk
@@ -259,17 +259,17 @@ ifdef NS_USE_GCC
 	AS	= $(CC)
 	ASFLAGS = $(INCLUDES)
 else
 ifdef USE_64
 	AS	= ml64.exe
 	ASFLAGS = -nologo -Cp -Sn -Zi $(INCLUDES)
 else
 	AS	= ml.exe
-	ASFLAGS = -nologo -Cp -Sn -Zi -coff $(INCLUDES)
+	ASFLAGS = -nologo -Cp -Sn -Zi -coff -safeseh $(INCLUDES)
 endif
 endif
 
 #
 # override the definitions of RELEASE_TREE found in tree.mk
 #
 ifndef RELEASE_TREE
     ifdef BUILD_SHIP
--- a/security/nss/coreconf/check_cc_clang.py
+++ b/security/nss/coreconf/check_cc_clang.py
@@ -1,12 +1,20 @@
 #!/usr/bin/env python
 
 import os
 import subprocess
+import sys
 
 def main():
-    cc = os.environ.get('CC', 'cc')
-    cc_is_clang = 'clang' in subprocess.check_output([cc, '--version'])
-    print int(cc_is_clang)
+    if sys.platform == 'win32':
+        print 0
+    else:
+        cc = os.environ.get('CC', 'cc')
+        try:
+            cc_is_clang = 'clang' in subprocess.check_output([cc, '--version'])
+        except OSError:
+            # We probably just don't have CC/cc.
+            cc_is_clang = False
+        print int(cc_is_clang)
 
 if __name__ == '__main__':
     main()
--- a/security/nss/coreconf/config.gypi
+++ b/security/nss/coreconf/config.gypi
@@ -22,32 +22,27 @@
         }, {
           # Default architecture we're building for is the architecture we're
           # building on.
           'target_arch%': '<(host_arch)',
         }],
         ['OS=="win"', {
           'use_system_zlib%': 0,
           'nspr_libs%': ['nspr4.lib', 'plc4.lib', 'plds4.lib'],
-          #XXX: gyp breaks if these are empty!
-          'nspr_lib_dir%': ' ',
-          'nspr_include_dir%': ' ',
           'zlib_libs%': [],
           #TODO
           'moz_debug_flags%': '',
           'dll_prefix': '',
           'dll_suffix': 'dll',
         }, {
           'nspr_libs%': ['-lplds4', '-lplc4', '-lnspr4'],
-          'nspr_lib_dir%': '<!(<(python) <(DEPTH)/coreconf/pkg_config.py . --libs nspr)',
-          'nspr_include_dir%': '<!(<(python) <(DEPTH)/coreconf/pkg_config.py . --cflags nspr)',
           'use_system_zlib%': 1,
         }],
         ['OS=="linux" or OS=="android"', {
-          'zlib_libs%': ['<!@(<(python) <(DEPTH)/coreconf/pkg_config.py raw --libs zlib)'],
+          'zlib_libs%': ['-lz'],
           'moz_debug_flags%': '-gdwarf-2',
           'optimize_flags%': '-O2',
           'dll_prefix': 'lib',
           'dll_suffix': 'so',
         }],
         ['OS=="linux"', {
           'freebl_name': 'freeblpriv3',
         }, {
@@ -92,18 +87,25 @@
     'disable_dbm%': 0,
     'disable_libpkix%': 1,
     'disable_werror%': 0,
     'mozilla_client%': 0,
     'moz_fold_libs%': 0,
     'moz_folded_library_name%': '',
     'ssl_enable_zlib%': 1,
     'use_asan%': 0,
+    'use_ubsan%': 0,
+    'use_msan%': 0,
+    'use_sancov%': 0,
     'test_build%': 0,
     'fuzz%': 0,
+    'sign_libs%': 1,
+    'use_pprof%': 0,
+    'nss_public_dist_dir%': '<(nss_dist_dir)/public',
+    'nss_private_dist_dir%': '<(nss_dist_dir)/private',
   },
   'target_defaults': {
     # Settings specific to targets should go here.
     # This is mostly for linking to libraries.
     'variables': {
       'mapfile%': '',
       'test_build%': 0,
     },
@@ -213,17 +215,17 @@
             'SubSystem': '2',
           },
         },
       }],
     ],
     'default_configuration': 'Debug',
     'configurations': {
       # Common settings for Debug+Release should go here.
-      'Common_Base': {
+      'Common': {
         'abstract': 1,
         'defines': [
           'NSS_NO_INIT_SUPPORT',
           'USE_UTIL_DIRECTLY',
           'NO_NSPR_10_SUPPORT',
           'SSL_DISABLE_DEPRECATED_CIPHER_SUITE_NAMES',
         ],
         'msvs_configuration_attributes': {
@@ -253,40 +255,113 @@
               'XP_UNIX',
               '_REENTRANT',
             ],
             'cflags': [
               '-fPIC',
               '-pipe',
               '-ffunction-sections',
               '-fdata-sections',
-              '<(moz_debug_flags)',
             ],
             'cflags_cc': [
               '-std=c++0x',
             ],
             'conditions': [
-
               [ 'target_arch=="ia32"', {
                 'cflags': ['-m32'],
                 'ldflags': ['-m32'],
               }],
               [ 'target_arch=="x64"', {
                 'cflags': ['-m64'],
                 'ldflags': ['-m64'],
               }],
+              [ 'use_pprof==1' , {
+                'ldflags': [ '-lprofiler' ],
+              }],
             ],
           }],
           [ 'disable_werror==0 and (OS=="linux" or OS=="mac")', {
             'cflags': [
               '<!@(<(python) <(DEPTH)/coreconf/werror.py)',
             ],
           }],
           [ 'fuzz==1', {
-            'cflags': ['-Wno-unused-function']
+            'cflags': [
+              '-Wno-unused-function',
+            ]
+          }],
+          [ 'use_asan==1 or use_ubsan==1', {
+            'cflags': ['-O1'],
+            'xcode_settings': {
+              'GCC_OPTIMIZATION_LEVEL': '1', # -O1
+            }
+          }],
+          [ 'use_asan==1', {
+            'variables': {
+              'asan_flags': '<!(<(python) <(DEPTH)/coreconf/sanitizers.py asan)',
+              'no_ldflags': '<!(<(python) <(DEPTH)/coreconf/sanitizers.py ld)',
+            },
+            'cflags': ['<@(asan_flags)'],
+            'ldflags': ['<@(asan_flags)'],
+            'ldflags!': ['<@(no_ldflags)'],
+            'xcode_settings': {
+              'OTHER_CFLAGS': ['<@(asan_flags)'],
+              'OTHER_LDFLAGS!': ['<@(no_ldflags)'],
+              # We want to pass -fsanitize=... to our final link call,
+              # but not to libtool. OTHER_LDFLAGS is passed to both.
+              # To trick GYP into doing what we want, we'll piggyback on
+              # LIBRARY_SEARCH_PATHS, producing "-L/usr/lib -fsanitize=...".
+              # The -L/usr/lib is redundant but innocuous: it's a default path.
+              'LIBRARY_SEARCH_PATHS': ['/usr/lib <(asan_flags)'],
+            },
+          }],
+          [ 'use_ubsan==1', {
+            'variables': {
+              'ubsan_flags': '<!(<(python) <(DEPTH)/coreconf/sanitizers.py ubsan)',
+              'no_ldflags': '<!(<(python) <(DEPTH)/coreconf/sanitizers.py ld)',
+            },
+            'cflags': ['<@(ubsan_flags)'],
+            'ldflags': ['<@(ubsan_flags)'],
+            'ldflags!': ['<@(no_ldflags)'],
+            'xcode_settings': {
+              'OTHER_CFLAGS': ['<@(ubsan_flags)'],
+              'OTHER_LDFLAGS!': ['<@(no_ldflags)'],
+              # See comment above.
+              'LIBRARY_SEARCH_PATHS': ['/usr/lib <(ubsan_flags)'],
+            },
+          }],
+          [ 'use_msan==1', {
+            'variables': {
+              'msan_flags': '<!(<(python) <(DEPTH)/coreconf/sanitizers.py msan)',
+              'no_ldflags': '<!(<(python) <(DEPTH)/coreconf/sanitizers.py ld)',
+            },
+            'cflags': ['<@(msan_flags)'],
+            'ldflags': ['<@(msan_flags)'],
+            'ldflags!': ['<@(no_ldflags)'],
+            'xcode_settings': {
+              'OTHER_CFLAGS': ['<@(msan_flags)'],
+              'OTHER_LDFLAGS!': ['<@(no_ldflags)'],
+              # See comment above.
+              'LIBRARY_SEARCH_PATHS': ['/usr/lib <(msan_flags)'],
+            },
+          }],
+          [ 'use_sancov!=0', {
+            'variables': {
+              'sancov_flags': '<!(<(python) <(DEPTH)/coreconf/sanitizers.py sancov <(use_sancov))',
+              'no_ldflags': '<!(<(python) <(DEPTH)/coreconf/sanitizers.py ld)',
+            },
+            'cflags': ['<@(sancov_flags)'],
+            'ldflags': ['<@(sancov_flags)'],
+            'ldflags!': ['<@(no_ldflags)'],
+            'xcode_settings': {
+              'OTHER_CFLAGS': ['<@(sancov_flags)'],
+              'OTHER_LDFLAGS!': ['<@(no_ldflags)'],
+              # See comment above.
+              'LIBRARY_SEARCH_PATHS': ['/usr/lib <(sancov_flags)'],
+            },
           }],
           [ 'OS=="android" and mozilla_client==0', {
             'defines': [
               'NO_SYSINFO',
               'NO_FORK_CHECK',
               'ANDROID',
             ],
           }],
@@ -322,89 +397,96 @@
               '-w44267', # Disable C4267: conversion from 'size_t' to 'type', possible loss of data
               '-w44244', # Disable C4244: conversion from 'type1' to 'type2', possible loss of data
               '-w44018', # Disable C4018: 'expression' : signed/unsigned mismatch
               '-w44312', # Disable C4312: 'type cast': conversion from 'type1' to 'type2' of greater size
             ],
             'conditions': [
               [ 'disable_werror==0', {
                 'cflags': ['-WX']
-              }]
+              }],
+              [ 'target_arch=="ia32"', {
+                'msvs_configuration_platform': 'Win32',
+                'msvs_settings': {
+                  'VCLinkerTool': {
+                    'MinimumRequiredVersion': '5.01',  # XP.
+                    'TargetMachine': '1',
+                    'ImageHasSafeExceptionHandlers': 'false',
+                  },
+                  'VCCLCompilerTool': {
+                    'PreprocessorDefinitions': [
+                      'WIN32',
+                    ],
+                  },
+                },
+
+              }],
+              [ 'target_arch=="x64"', {
+                'msvs_configuration_platform': 'x64',
+                'msvs_settings': {
+                  'VCLinkerTool': {
+                    'TargetMachine': '17', # x86-64
+                  },
+                  'VCCLCompilerTool': {
+                    'PreprocessorDefinitions': [
+                      'WIN64',
+                      '_AMD64_',
+                    ],
+                  },
+                },
+              }],
             ],
           }],
           [ 'disable_dbm==1', {
             'defines': [
               'NSS_DISABLE_DBM',
             ],
           }],
           [ 'disable_libpkix==1', {
             'defines': [
               'NSS_DISABLE_LIBPKIX',
             ],
           }],
         ],
       },
-      # Common settings for x86 should go here.
-      'x86_Base': {
-        'abstract': 1,
-        'msvs_settings': {
-          'VCLinkerTool': {
-            'MinimumRequiredVersion': '5.01',  # XP.
-            'TargetMachine': '1',
-          },
-          'VCCLCompilerTool': {
-            'PreprocessorDefinitions': [
-              'WIN32',
+      # Common settings for debug should go here.
+      'Debug': {
+        'inherit_from': ['Common'],
+        'conditions': [
+          [ 'OS=="linux" or OS=="android"', {
+            'cflags': [
+              '-g',
+              '<(moz_debug_flags)',
             ],
-          },
-        },
-        'msvs_configuration_platform': 'Win32',
-      },
-      # Common settings for x86-64 should go here.
-      'x64_Base': {
-        'abstract': 1,
-        'msvs_configuration_platform': 'x64',
-        'msvs_settings': {
-          'VCLinkerTool': {
-            'TargetMachine': '17', # x86-64
-          },
-          'VCCLCompilerTool': {
-            'PreprocessorDefinitions': [
-              'WIN64',
-              '_AMD64_',
-            ],
-          },
-        },
-      },
-      # Common settings for debug should go here.
-      'Debug_Base': {
-        'abstract': 1,
+          }]
+        ],
         #TODO: DEBUG_$USER
         'defines': ['DEBUG'],
         'xcode_settings': {
           'COPY_PHASE_STRIP': 'NO',
           'GCC_OPTIMIZATION_LEVEL': '0',
+          'GCC_GENERATE_DEBUGGING_SYMBOLS': 'YES',
         },
         'msvs_settings': {
           'VCCLCompilerTool': {
             'Optimization': '0',
             'BasicRuntimeChecks': '3',
             'RuntimeLibrary': '2', # /MD
           },
           'VCLinkerTool': {
             'LinkIncremental': '1',
           },
           'VCResourceCompilerTool': {
             'PreprocessorDefinitions': ['DEBUG'],
           },
         },
       },
-      # Common settings for release should go here.n
-      'Release_Base': {
-        'abstract': 1,
+      # Common settings for release should go here.
+      'Release': {
+        'inherit_from': ['Common'],
         'defines': [
           'NDEBUG',
         ],
         'xcode_settings': {
           'DEAD_CODE_STRIPPING': 'YES',  # -Wl,-dead_strip
           'GCC_OPTIMIZATION_LEVEL': '2', # -O2
         },
         'msvs_settings': {
@@ -412,34 +494,30 @@
             'Optimization': '2', # /Os
             'RuntimeLibrary': '2', # /MD
           },
           'VCLinkerTool': {
             'LinkIncremental': '1',
           },
         },
       },
-      #
-      # Concrete configurations
-      #
-      # These configurations shouldn't have anything in them, it should
-      # all be derived from the _Base configurations above.
-      'Debug': {
-        'inherit_from': ['Common_Base', 'x86_Base', 'Debug_Base'],
-      },
-      'Release': {
-        'inherit_from': ['Common_Base', 'x86_Base', 'Release_Base'],
-      },
-      # The gyp ninja backend requires these.
-      'Debug_x64': {
-        'inherit_from': ['Common_Base', 'x64_Base', 'Debug_Base'],
-      },
-      'Release_x64': {
-        'inherit_from': ['Common_Base', 'x64_Base', 'Release_Base'],
-      },
+      'conditions': [
+        [ 'OS=="win"', {
+          # The gyp ninja backend requires these.
+          # TODO: either we should support building both 32/64-bit as
+          # configurations from the same gyp build, or we should fix
+          # upstream gyp to not require these.
+          'Debug_x64': {
+            'inherit_from': ['Debug'],
+          },
+          'Release_x64': {
+            'inherit_from': ['Release'],
+          },
+        }],
+      ],
     },
   },
   'conditions': [
     [ 'OS=="linux" or OS=="android"', {
       'variables': {
         'process_map_file': ['/bin/sh', '-c', '/bin/grep -v ";-" >(mapfile) | sed -e "s,;+,," -e "s; DATA ;;" -e "s,;;,," -e "s,;.*,;," > >@(_outputs)'],
       },
     }],
--- a/security/nss/coreconf/coreconf.dep
+++ b/security/nss/coreconf/coreconf.dep
@@ -5,8 +5,9 @@
 
 /*
  * 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/detect_host_arch.py
+++ b/security/nss/coreconf/detect_host_arch.py
@@ -1,33 +1,25 @@
 #!/usr/bin/env python
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-"""Outputs host CPU architecture in format recognized by gyp."""
+#
+# 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/.
+
+from __future__ import print_function
+
+import fnmatch
 import platform
-import re
 
-def HostArch():
-  """Returns the host architecture with a predictable string."""
-  host_arch = platform.machine().lower()
-  # Convert machine type to format recognized by gyp.
-  if re.match(r'i.86', host_arch) or host_arch == 'i86pc':
-    host_arch = 'ia32'
-  elif host_arch in ['x86_64', 'amd64']:
-    host_arch = 'x64'
-  elif host_arch.startswith('arm'):
-    host_arch = 'arm'
-  elif host_arch.startswith('mips'):
-    host_arch = 'mips'
-  # platform.machine is based on running kernel. It's possible to use 64-bit
-  # kernel with 32-bit userland, e.g. to give linker slightly more memory.
-  # Distinguish between different userland bitness by querying
-  # the python binary.
-  if host_arch == 'x64' and platform.architecture()[0] == '32bit':
-    host_arch = 'ia32'
-  return host_arch
-def DoMain(_):
-  """Hook to be called from gyp without starting a separate python
-  interpreter."""
-  return HostArch()
+def main():
+    host_arch = platform.machine().lower()
+    if host_arch in ('amd64', 'x86_64'):
+        host_arch = 'x64'
+    elif fnmatch.fnmatch(host_arch, 'i?86') or host_arch == 'i86pc':
+        host_arch = 'x64'
+    elif host_arch.startswith('arm'):
+        host_arch = 'arm'
+    elif host_arch.startswith('mips'):
+        host_arch = 'mips'
+    print(host_arch)
+
 if __name__ == '__main__':
-  print DoMain([])
+    main()
new file mode 100644
--- /dev/null
+++ b/security/nss/coreconf/nspr.sh
@@ -0,0 +1,48 @@
+#!/bin/bash
+# This script builds NSPR for NSS.
+#
+# This build system is still under development.  It does not yet support all
+# the features or platforms that the regular NSPR build supports.
+
+# variables
+nspr_opt=()
+nspr_cflags=
+nspr_cxxflags=
+nspr_ldflags=
+
+nspr_sanitizer()
+{
+    nspr_cflags="$nspr_cflags $(python $cwd/coreconf/sanitizers.py $1 $2)"
+    nspr_cxxflags="$nspr_cxxflags $(python $cwd/coreconf/sanitizers.py $1 $2)"
+    nspr_ldflags="$nspr_ldflags $(python $cwd/coreconf/sanitizers.py $1 $2)"
+}
+
+verbose()
+{
+    CFLAGS=$nspr_cflags CXXFLAGS=$nspr_cxxflags LDFLAGS=$nspr_ldflags \
+      CC=$CC CXX=$CCC ../configure "${nspr_opt[@]}" --prefix="$obj_dir"
+    make -C "$cwd/../nspr/$target"
+    make -C "$cwd/../nspr/$target" install
+}
+
+silent()
+{
+    echo "[1/3] configure NSPR ..."
+    CFLAGS=$nspr_cflags CXXFLAGS=$nspr_cxxflags LDFLAGS=$nspr_ldflags \
+      CC=$CC CXX=$CCC ../configure "${nspr_opt[@]}" --prefix="$obj_dir" 1> /dev/null
+    echo "[2/3] make NSPR ..."
+    make -C "$cwd/../nspr/$target" 1> /dev/null
+    echo "[3/3] install NSPR ..."
+    make -C "$cwd/../nspr/$target" install 1> /dev/null
+}
+
+build_nspr()
+{
+    mkdir -p "$cwd/../nspr/$target"
+    cd "$cwd/../nspr/$target"
+    if [ "$1" == 1 ]; then
+        verbose
+    else
+        silent
+    fi
+}
deleted file mode 100644
--- a/security/nss/coreconf/pkg_config.py
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/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/.
-
-import os
-import subprocess
-import sys
-
-def main():
-    is_raw = sys.argv[1] == 'raw'
-    stdout = None if is_raw else subprocess.PIPE
-
-    if sys.argv[2] == '--libs':
-        part_prefix = '-L'
-    elif sys.argv[2] == '--cflags':
-        part_prefix = '-I'
-    else:
-        raise Exception('Specify either --libs or --cflags as the second argument.')
-
-    try:
-        process = subprocess.Popen(['pkg-config'] + sys.argv[2:], stdout=stdout, stderr=open(os.devnull, 'wb'))
-
-    except OSError:
-        # pkg-config is probably not installed
-        return
-
-    if is_raw:
-        process.wait()
-        return
-
-    for part in process.communicate()[0].strip().split():
-        if part.startswith(part_prefix):
-            print os.path.realpath(os.path.join(part[2:], sys.argv[1]))
-            return
-
-if __name__ == '__main__':
-    main()
new file mode 100644
--- /dev/null
+++ b/security/nss/coreconf/sanitizers.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python2
+
+from __future__ import print_function
+import sys
+
+def main():
+    if len(sys.argv) < 2:
+        raise Exception('Specify either "ld", asan", "msan", "sancov" or "ubsan" as argument.')
+
+    sanitizer = sys.argv[1]
+    if sanitizer == "ubsan":
+        print('-fsanitize=undefined -fno-sanitize-recover=undefined ', end='')
+        return
+    if sanitizer == "asan":
+        print('-fsanitize=address ', end='')
+        print('-fno-omit-frame-pointer -fno-optimize-sibling-calls ', end='')
+        return
+    if sanitizer == "msan":
+        print('-fsanitize=memory -fsanitize-memory-track-origins ', end='')
+        print('-fno-omit-frame-pointer -fno-optimize-sibling-calls ', end='')
+        return
+    if sanitizer == "sancov":
+        if len(sys.argv) < 3:
+            raise Exception('sancov requires another argument (edge|bb|func).')
+        print('-fsanitize-coverage='+sys.argv[2]+' ', end='')
+        return
+
+    # We have to remove this from the ld flags when building asan.
+    if sanitizer == "ld":
+        print('-Wl,-z,defs ', end='')
+        return
+
+    raise Exception('Specify either "ld", asan", "msan", "sancov" or "ubsan" as argument.')
+
+if __name__ == '__main__':
+    main()
--- a/security/nss/coreconf/shlibsign.py
+++ b/security/nss/coreconf/shlibsign.py
@@ -1,9 +1,9 @@
-#!/usr/bin/env python
+#!/usr/bin/env python2
 #
 # 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/.
 
 import os
 import subprocess
 import sys
@@ -13,15 +13,18 @@ def main():
         if os.path.isfile(lib_file):
             sign(lib_file)
 
 def sign(lib_file):
     ld_lib_path = os.path.realpath(os.path.join(lib_file, '..'))
     bin_path = os.path.realpath(os.path.join(ld_lib_path, '../bin'))
 
     env = os.environ.copy()
-    env['LD_LIBRARY_PATH'] = env['DYLD_LIBRARY_PATH'] = ld_lib_path
+    if sys.platform == 'win32':
+        env['PATH'] = os.pathsep.join((env['PATH'], ld_lib_path))
+    else:
+        env['LD_LIBRARY_PATH'] = env['DYLD_LIBRARY_PATH'] = ld_lib_path
 
     dev_null = open(os.devnull, 'wb')
-    subprocess.Popen([os.path.join(bin_path, 'shlibsign'), '-v', '-i', lib_file], env=env, stdout=dev_null, stderr=dev_null).wait()
+    subprocess.check_call([os.path.join(bin_path, 'shlibsign'), '-v', '-i', lib_file], env=env, stdout=dev_null, stderr=dev_null)
 
 if __name__ == '__main__':
     main()
--- a/security/nss/coreconf/werror.py
+++ b/security/nss/coreconf/werror.py
@@ -1,17 +1,21 @@
 #!/usr/bin/env python
 
 import os
 import subprocess
 
 def main():
     cc = os.environ.get('CC', 'cc')
     sink = open(os.devnull, 'wb')
-    cc_is_clang = 'clang' in subprocess.check_output([cc, '--version'], stderr=sink)
+    try:
+        cc_is_clang = 'clang' in subprocess.check_output([cc, '--version'], stderr=sink)
+    except OSError:
+        # We probably just don't have CC/cc.
+        return
 
     def warning_supported(warning):
         return subprocess.call([cc, '-x', 'c', '-E', '-Werror',
                                 '-W%s' % warning, os.devnull], stdout=sink, stderr=sink) == 0
     def can_enable():
         # This would be a problem
         if not warning_supported('all'):
             return False
--- a/security/nss/exports.gyp
+++ b/security/nss/exports.gyp
@@ -6,17 +6,17 @@
     'coreconf/config.gypi'
   ],
   'targets': [
     {
       'target_name': 'nss_exports',
       'type': 'none',
       'direct_dependent_settings': {
         'include_dirs': [
-          '<(nss_dist_dir)/public/nss'
+          '<(nss_public_dist_dir)/nss'
         ]
       },
       'dependencies': [
         'cmd/lib/exports.gyp:cmd_lib_exports',
         'lib/base/exports.gyp:lib_base_exports',
         'lib/certdb/exports.gyp:lib_certdb_exports',
         'lib/certhigh/exports.gyp:lib_certhigh_exports',
         'lib/ckfw/builtins/exports.gyp:lib_ckfw_builtins_exports',
@@ -59,17 +59,17 @@
     },
     {
       'target_name': 'dbm_exports',
       'type': 'none',
       'conditions': [
         ['disable_dbm==0', {
           'direct_dependent_settings': {
             'include_dirs': [
-              '<(nss_dist_dir)/public/dbm'
+              '<(nss_public_dist_dir)/dbm'
             ]
           },
           'dependencies': [
             'lib/dbm/include/exports.gyp:lib_dbm_include_exports'
           ],
         }],
       ],
     }
deleted file mode 100644
--- a/security/nss/fuzz/Makefile
+++ /dev/null
@@ -1,42 +0,0 @@
-#! 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).      #
-#######################################################################
-
-
-#######################################################################
-# (5) Execute "global" rules. (OPTIONAL)                              #
-#######################################################################
-
-include $(CORE_DEPTH)/coreconf/rules.mk
-
-#######################################################################
-# (6) Execute "component" rules. (OPTIONAL)                           #
-#######################################################################
-
-
-#######################################################################
-# (7) Execute "local" rules. (OPTIONAL).                              #
-#######################################################################
--- a/security/nss/fuzz/clone_corpus.sh
+++ b/security/nss/fuzz/clone_corpus.sh
@@ -1,4 +1,11 @@
 #!/bin/sh
 
 cd $(dirname $0)
-git clone https://github.com/mozilla/nss-fuzzing-corpus corpus
+
+mkdir tmp/
+git clone --no-checkout --depth 1 https://github.com/mozilla/nss-fuzzing-corpus tmp/
+(cd tmp && git reset --hard master)
+
+mkdir -p corpus
+cp -r tmp/* corpus
+rm -Rf tmp/
--- a/security/nss/fuzz/clone_libfuzzer.sh
+++ b/security/nss/fuzz/clone_libfuzzer.sh
@@ -1,9 +1,11 @@
 #!/bin/sh
 
 cd $(dirname $0)
+
 mkdir tmp/
-git clone -q https://chromium.googlesource.com/chromium/llvm-project/llvm/lib/Fuzzer tmp/
-mv tmp/.git libFuzzer
-rm -fr tmp
-cd libFuzzer
-git reset --hard 4333f2ca71eb7951fcafcdcb111012fbe25c5e7e
+git clone --no-checkout --depth 1 https://chromium.googlesource.com/chromium/llvm-project/llvm/lib/Fuzzer tmp/
+(cd tmp && git reset --hard 1b543d6e5073b56be214394890c9193979a3d7e1)
+
+mkdir -p libFuzzer
+cp tmp/*.cpp tmp/*.h tmp/*.def libFuzzer
+rm -Rf tmp/
deleted file mode 100644
--- a/security/nss/fuzz/common.mk
+++ /dev/null
@@ -1,10 +0,0 @@
-#! 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/.
-
-MKPROG = $(CCC)
-MKSHLIB = $(CCC) $(DSO_LDOPTS) $(DARWIN_SDK_SHLIBFLAGS)
-
-CXXFLAGS += -std=c++11
new file mode 100644
--- /dev/null
+++ b/security/nss/fuzz/fuzz.gyp
@@ -0,0 +1,32 @@
+# 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': 'nssfuzz',
+      'type': 'executable',
+      'sources': [
+        'nssfuzz.cc',
+        'pkcs8_target.cc',
+        'quickder_targets.cc',
+      ],
+      'dependencies': [
+        '<(DEPTH)/exports.gyp:nss_exports',
+        '<(DEPTH)/fuzz/libFuzzer/libFuzzer.gyp:libFuzzer'
+      ]
+    }
+  ],
+  'target_defaults': {
+    'include_dirs': [
+      'libFuzzer',
+    ],
+  },
+  'variables': {
+    'module': 'nss',
+  }
+}
deleted file mode 100644
--- a/security/nss/fuzz/libFuzzer/Makefile
+++ /dev/null
@@ -1,45 +0,0 @@
-#! 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)       #
-#######################################################################
-
-include config.mk
-
-include ../common.mk
-
-#######################################################################
-# (4) Include "local" platform-dependent assignments (OPTIONAL).      #
-#######################################################################
-
-
-#######################################################################
-# (5) Execute "global" rules. (OPTIONAL)                              #
-#######################################################################
-
-include $(CORE_DEPTH)/coreconf/rules.mk
-
-#######################################################################
-# (6) Execute "component" rules. (OPTIONAL)                           #
-#######################################################################
-
-
-#######################################################################
-# (7) Execute "local" rules. (OPTIONAL).                              #
-#######################################################################
deleted file mode 100644
--- a/security/nss/fuzz/libFuzzer/config.mk
+++ /dev/null
@@ -1,14 +0,0 @@
-#
-# 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/.
-
-# According to the LLVM docs, LibFuzzer isn't supposed to be built with any
-# sanitizer flags and in fact, building it with ASan coverage currently causes
-# Clang 3.9+ to crash, so we filter out all sanitizer-related flags here.
-CXXFLAGS := $(filter-out -fsanitize%,$(CXXFLAGS))
-CFLAGS := $(filter-out -fsanitize%,$(CFLAGS))
-LDFLAGS := $(filter-out -fsanitize%,$(LDFLAGS))
-DARWIN_SDK_SHLIBFLAGS := $(filter-out -fsanitize%,$(DARWIN_SDK_SHLIBFLAGS))
-
-CXXFLAGS += -g -O2
new file mode 100644
--- /dev/null
+++ b/security/nss/fuzz/libFuzzer/libFuzzer.gyp
@@ -0,0 +1,43 @@
+# 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'
+  ],
+  'targets': [
+    {
+      'target_name': 'libFuzzer',
+      'type': 'static_library',
+      'sources': [
+        'FuzzerCrossOver.cpp',
+        'FuzzerDriver.cpp',
+        'FuzzerExtFunctionsDlsym.cpp',
+        'FuzzerExtFunctionsWeak.cpp',
+        'FuzzerIO.cpp',
+        'FuzzerLoop.cpp',
+        'FuzzerMutate.cpp',
+        'FuzzerSHA1.cpp',
+        'FuzzerTracePC.cpp',
+        'FuzzerTraceState.cpp',
+        'FuzzerUtil.cpp',
+        'FuzzerUtilDarwin.cpp',
+        'FuzzerUtilLinux.cpp',
+      ],
+      'cflags': [
+        '-O2',
+      ],
+      'cflags/': [
+        ['exclude', '-fsanitize='],
+        ['exclude', '-fsanitize-'],
+      ],
+      'xcode_settings': {
+        'GCC_OPTIMIZATION_LEVEL': '2', # -O2
+        'OTHER_CFLAGS/': [
+          ['exclude', '-fsanitize='],
+          ['exclude', '-fsanitize-'],
+        ],
+      },
+    }
+  ],
+}
deleted file mode 100644
--- a/security/nss/fuzz/libFuzzer/manifest.mn
+++ /dev/null
@@ -1,26 +0,0 @@
-#
-# 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 = ../..
-DEPTH      = ../..
-MODULE = nss
-
-CPPSRCS = \
-      FuzzerCrossOver.cpp \
-      FuzzerDriver.cpp \
-      FuzzerExtFunctionsDlsym.cpp \
-      FuzzerExtFunctionsWeak.cpp \
-      FuzzerIO.cpp \
-      FuzzerLoop.cpp \
-      FuzzerMutate.cpp \
-      FuzzerSHA1.cpp \
-      FuzzerTracePC.cpp \
-      FuzzerTraceState.cpp \
-      FuzzerUtil.cpp \
-      FuzzerUtilDarwin.cpp \
-      FuzzerUtilLinux.cpp \
-      $(NULL)
-
-LIBRARY_NAME = Fuzzer
-LIBRARY_VERSION = 1
deleted file mode 100644
--- a/security/nss/fuzz/manifest.mn
+++ /dev/null
@@ -1,8 +0,0 @@
-# 
-# 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 = ..
-DEPTH      = ..
-
-DIRS = libFuzzer nssfuzz
new file mode 100644
--- /dev/null
+++ b/security/nss/fuzz/nssfuzz.cc
@@ -0,0 +1,148 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include <iomanip>
+#include <iostream>
+#include <memory>
+
+#include "keyhi.h"
+#include "pk11pub.h"
+
+#include "FuzzerInternal.h"
+#include "registry.h"
+#include "shared.h"
+
+using namespace std;
+
+class Args {
+ public:
+  Args(int argc, char **argv) : args_(argv, argv + argc) {}
+
+  string &operator[](const int idx) { return args_[idx]; }
+
+  bool Has(const string &arg) {
+    return any_of(args_.begin(), args_.end(),
+                  [&arg](string &a) { return a.find(arg) == 0; });
+  }
+
+  void Append(const string &arg) { args_.push_back(arg); }
+
+  void Remove(const int index) {
+    assert(index < count());
+    args_.erase(args_.begin() + index);
+  }
+
+  vector<char *> argv() {
+    vector<char *> out;
+    out.resize(count());
+
+    transform(args_.begin(), args_.end(), out.begin(),
+              [](string &a) { return const_cast<char *>(a.c_str()); });
+
+    return out;
+  }
+
+  size_t count() { return args_.size(); }
+
+ private:
+  vector<string> args_;
+};
+
+void printUsage(Args &args) {
+  size_t sep = args[0].rfind("/") + 1;
+  string progName = args[0].substr(sep);
+
+  cerr << progName << " - Various libFuzzer targets for NSS" << endl << endl;
+  cerr << "Usage: " << progName << " <target> <libFuzzer options>" << endl
+       << endl;
+  cerr << "Valid targets:" << endl;
+
+  vector<string> names = Registry::Names();
+
+  // Find length of the longest name.
+  size_t name_w =
+      max_element(names.begin(), names.end(), [](string &a, string &b) {
+        return a.size() < b.size();
+      })->size();
+
+  // Find length of the longest description.
+  auto max = max_element(names.begin(), names.end(), [](string &a, string &b) {
+    return Registry::Desc(a).size() < Registry::Desc(b).size();
+  });
+  size_t desc_w = Registry::Desc(*max).size();
+
+  // Print list of targets.
+  for (string name : names) {
+    cerr << "  " << left << setw(name_w) << name << " - " << setw(desc_w)
+         << Registry::Desc(name)
+         << " [default max_len=" << Registry::MaxLen(name) << "]" << endl;
+  }
+
+  // Some usage examples.
+  cerr << endl << "Run fuzzer with a given corpus directory:" << endl;
+  cerr << "  " << progName << " <target> /path/to/corpus" << endl;
+
+  cerr << endl << "Run fuzzer with a single test input:" << endl;
+  cerr << "  " << progName
+       << " <target> ./crash-14d4355b971092e39572bc306a135ddf9f923e19" << endl;
+
+  cerr << endl
+       << "Specify the number of cores you wish to dedicate to fuzzing:"
+       << endl;
+  cerr << "  " << progName << " <target> -jobs=8 -workers=8 /path/to/corpus"
+       << endl;
+
+  cerr << endl << "Override the maximum length of a test input:" << endl;
+  cerr << "  " << progName << " <target> -max_len=2048 /path/to/corpus" << endl;
+
+  cerr << endl
+       << "Minimize a given corpus and put the result into 'new_corpus':"
+       << endl;
+  cerr << "  " << progName
+       << " <target> -merge=1 -max_len=50000 ./new_corpus /path/to/corpus"
+       << endl;
+
+  cerr << endl << "Merge new test inputs into a corpus:" << endl;
+  cerr
+      << "  " << progName
+      << " <target> -merge=1 -max_len=50000 /path/to/corpus ./inputs1 ./inputs2"
+      << endl;
+
+  cerr << endl << "Print libFuzzer usage information:" << endl;
+  cerr << "  " << progName << " <target> -help=1" << endl << endl;
+
+  cerr << "Check out the docs at http://llvm.org/docs/LibFuzzer.html" << endl;
+}
+
+int main(int argc, char **argv) {
+  Args args(argc, argv);
+
+  if (args.count() < 2 || !Registry::Has(args[1])) {
+    printUsage(args);
+    return 1;
+  }
+
+  string targetName(args[1]);
+
+  // Remove the target argument when -workers=x or -jobs=y is NOT given.
+  // If both are given, libFuzzer will spawn multiple processes for the target.
+  if (!args.Has("-workers=") || !args.Has("-jobs=")) {
+    args.Remove(1);
+  }
+
+  // Set default max_len arg, if none given and we're not merging.
+  if (!args.Has("-max_len=") && !args.Has("-merge=1")) {
+    uint16_t maxLen = Registry::MaxLen(targetName);
+    args.Append("-max_len=" + to_string(maxLen));
+  }
+
+  // Hand control to the libFuzzer driver.
+  vector<char *> args_new(args.argv());
+  argc = args_new.size();
+  argv = args_new.data();
+
+  return fuzzer::FuzzerDriver(&argc, &argv, Registry::Func(targetName));
+}
deleted file mode 100644
--- a/security/nss/fuzz/nssfuzz/Makefile
+++ /dev/null
@@ -1,45 +0,0 @@
-#! 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)       #
-#######################################################################
-
-include $(CORE_DEPTH)/cmd/platlibs.mk
-
-include ../common.mk
-
-#######################################################################
-# (4) Include "local" platform-dependent assignments (OPTIONAL).      #
-#######################################################################
-
-
-#######################################################################
-# (5) Execute "global" rules. (OPTIONAL)                              #
-#######################################################################
-
-include $(CORE_DEPTH)/coreconf/rules.mk
-
-#######################################################################
-# (6) Execute "component" rules. (OPTIONAL)                           #
-#######################################################################
-
-
-#######################################################################
-# (7) Execute "local" rules. (OPTIONAL).                              #
-#######################################################################
deleted file mode 100644
--- a/security/nss/fuzz/nssfuzz/cert_target.cc
+++ /dev/null
@@ -1,35 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* 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/. */
-
-#include <assert.h>
-#include <stdint.h>
-#include <memory>
-
-#include "cert.h"
-
-#include "registry.h"
-#include "shared.h"
-
-extern "C" int cert_fuzzing_target(const uint8_t *Data, size_t Size) {
-  SECItem data = {siBuffer, (unsigned char *)Data, (unsigned int)Size};
-
-  static std::unique_ptr<NSSDatabase> db(new NSSDatabase());
-  assert(db != nullptr);
-
-  static CERTCertDBHandle *certDB = CERT_GetDefaultCertDB();
-  assert(certDB != NULL);
-
-  CERTCertificate *cert =
-      CERT_NewTempCertificate(certDB, &data, nullptr, false, true);
-
-  if (cert) {
-    CERT_DestroyCertificate(cert);
-  }
-
-  return 0;
-}
-
-REGISTER_FUZZING_TARGET("cert", cert_fuzzing_target, 3072, "Certificate Import")
deleted file mode 100644
--- a/security/nss/fuzz/nssfuzz/manifest.mn
+++ /dev/null
@@ -1,24 +0,0 @@
-#
-# 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 = ../..
-DEPTH      = ../..
-MODULE = nss
-
-CPPSRCS = \
-      cert_target.cc \
-      pkcs8_target.cc \
-      spki_target.cc \
-      nssfuzz.cc \
-      $(NULL)
-
-INCLUDES += -I$(CORE_DEPTH)/fuzz/libFuzzer
-
-REQUIRES = nspr nss
-
-PROGRAM = nssfuzz
-
-EXTRA_LIBS = $(DIST)/lib/$(LIB_PREFIX)Fuzzer.$(LIB_SUFFIX)
-
-USE_STATIC_LIBS = 1
deleted file mode 100644
--- a/security/nss/fuzz/nssfuzz/nssfuzz.cc
+++ /dev/null
@@ -1,114 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* 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/. */
-
-#include <iomanip>
-#include <iostream>
-#include <memory>
-
-#include "keyhi.h"
-#include "pk11pub.h"
-
-#include "FuzzerInternal.h"
-#include "registry.h"
-#include "shared.h"
-
-using namespace std;
-
-void printUsage(const vector<string> &args) {
-  size_t sep = args.at(0).rfind("/") + 1;
-  string progName = args.at(0).substr(sep);
-
-  cerr << progName << " - Various libFuzzer targets for NSS" << endl << endl;
-  cerr << "Usage: " << progName << " <target> <libFuzzer options>" << endl
-       << endl;
-  cerr << "Valid targets:" << endl;
-
-  vector<string> names = Registry::Names();
-
-  // Find length of the longest name.
-  size_t name_w =
-      max_element(names.begin(), names.end(), [](string &a, string &b) {
-        return a.size() < b.size();
-      })->size();
-
-  // Find length of the longest description.
-  auto max = max_element(names.begin(), names.end(), [](string &a, string &b) {
-    return Registry::Desc(a).size() < Registry::Desc(b).size();
-  });
-  size_t desc_w = Registry::Desc(*max).size();
-
-  // Print list of targets.
-  for (string name : names) {
-    cerr << "  " << left << setw(name_w) << name << " - " << setw(desc_w)
-         << Registry::Desc(name)
-         << " [default max_len=" << Registry::MaxLen(name) << "]" << endl;
-  }
-
-  // Some usage examples.
-  cerr << endl << "Run fuzzer with a given corpus directory:" << endl;
-  cerr << "  " << progName << " <target> /path/to/corpus" << endl;
-
-  cerr << endl << "Run fuzzer with a single test input:" << endl;
-  cerr << "  " << progName
-       << " <target> ./crash-14d4355b971092e39572bc306a135ddf9f923e19" << endl;
-
-  cerr << endl
-       << "Specify the number of cores you wish to dedicate to fuzzing:"
-       << endl;
-  cerr << "  " << progName << " <target> -jobs=8 -workers=8 /path/to/corpus"
-       << endl;
-
-  cerr << endl << "Override the maximum length of a test input:" << endl;
-  cerr << "  " << progName << " <target> -max_len=2048 /path/to/corpus" << endl;
-
-  cerr << endl
-       << "Minimize a given corpus and put the result into 'new_corpus':"
-       << endl;
-  cerr << "  " << progName
-       << " <target> -merge=1 -max_len=50000 ./new_corpus /path/to/corpus"
-       << endl;
-
-  cerr << endl << "Merge new test inputs into a corpus:" << endl;
-  cerr
-      << "  " << progName
-      << " <target> -merge=1 -max_len=50000 /path/to/corpus ./inputs1 ./inputs2"
-      << endl;
-
-  cerr << endl << "Print libFuzzer usage information:" << endl;
-  cerr << "  " << progName << " <target> -help=1" << endl << endl;
-
-  cerr << "Check out the docs at http://llvm.org/docs/LibFuzzer.html" << endl;
-}
-
-int main(int argc, char **argv) {
-  vector<string> args(argv, argv + argc);
-
-  if (args.size() < 2 || !Registry::Has(args[1])) {
-    printUsage(args);
-    return 1;
-  }
-
-  string targetName = args.at(1);
-  uint16_t maxLen = Registry::MaxLen(targetName);
-  string maxLenArg = "-max_len=" + to_string(maxLen);
-
-  auto find = [](string &a) {
-    return a.find("-max_len=") == 0 || a.find("-merge=1") == 0;
-  };
-
-  if (any_of(args.begin(), args.end(), find)) {
-    // Remove the 2nd argument.
-    argv[1] = argv[0];
-    argv++;
-    argc--;
-  } else {
-    // Set default max_len arg, if none given and we're not merging.
-    argv[1] = const_cast<char *>(maxLenArg.c_str());
-  }
-
-  // Hand control to the libFuzzer driver.
-  return fuzzer::FuzzerDriver(&argc, &argv, Registry::Func(targetName));
-}
deleted file mode 100644
--- a/security/nss/fuzz/nssfuzz/pkcs8_target.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* 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/. */
-
-#include <assert.h>
-#include <stdint.h>
-#include <memory>
-
-#include "keyhi.h"
-#include "pk11pub.h"
-
-#include "registry.h"
-#include "shared.h"
-
-extern "C" int pkcs8_fuzzing_target(const uint8_t *Data, size_t Size) {
-  SECItem data = {siBuffer, (unsigned char *)Data, (unsigned int)Size};
-
-  static std::unique_ptr<NSSDatabase> db(new NSSDatabase());
-  assert(db != nullptr);
-
-  PK11SlotInfo *slot = PK11_GetInternalSlot();
-  assert(slot != nullptr);
-
-  SECKEYPrivateKey *key = nullptr;
-  if (PK11_ImportDERPrivateKeyInfoAndReturnKey(slot, &data, nullptr, nullptr,
-                                               false, false, KU_ALL, &key,
-                                               nullptr) == SECSuccess) {
-    SECKEY_DestroyPrivateKey(key);
-  }
-
-  PK11_FreeSlot(slot);
-  return 0;
-}
-
-REGISTER_FUZZING_TARGET("pkcs8", pkcs8_fuzzing_target, 2048, "PKCS#8 Import")
deleted file mode 100644
--- a/security/nss/fuzz/nssfuzz/registry.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* 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 registry_h__
-#define registry_h__
-
-#include <map>
-#include "FuzzerInternal.h"
-#include "nss.h"
-
-class Registry {
- public:
-  static void Add(std::string name, fuzzer::UserCallback func, uint16_t max_len,
-                  std::string desc) {
-    assert(!Has(name));
-    GetInstance().targets_[name] = TargetData(func, max_len, desc);
-  }
-
-  static bool Has(std::string name) {
-    return GetInstance().targets_.count(name) > 0;
-  }
-
-  static fuzzer::UserCallback Func(std::string name) {
-    assert(Has(name));
-    return std::get<0>(Get(name));
-  }
-
-  static uint16_t MaxLen(std::string name) {
-    assert(Has(name));
-    return std::get<1>(Get(name));
-  }
-
-  static std::string& Desc(std::string name) {
-    assert(Has(name));
-    return std::get<2>(Get(name));
-  }
-
-  static std::vector<std::string> Names() {
-    std::vector<std::string> names;
-    for (auto& it : GetInstance().targets_) {
-      names.push_back(it.first);
-    }
-    return names;
-  }
-
- private:
-  typedef std::tuple<fuzzer::UserCallback, uint16_t, std::string> TargetData;
-
-  static Registry& GetInstance() {
-    static Registry registry;
-    return registry;
-  }
-
-  static TargetData& Get(std::string name) {
-    return GetInstance().targets_[name];
-  }
-
-  Registry() {}
-
-  std::map<std::string, TargetData> targets_;
-};
-
-#define REGISTER_FUZZING_TARGET(name, func, max_len, desc)           \
-  static void __attribute__((constructor)) RegisterFuzzingTarget() { \
-    Registry::Add(name, func, max_len, desc);                        \
-  }
-
-#endif  // registry_h__
deleted file mode 100644
--- a/security/nss/fuzz/nssfuzz/shared.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* 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 shared_h__
-#define shared_h__
-
-#include "nss.h"
-
-class NSSDatabase {
- public:
-  NSSDatabase() { NSS_NoDB_Init(nullptr); }
-  ~NSSDatabase() { NSS_Shutdown(); }
-};
-
-#endif  // shared_h__
deleted file mode 100644
--- a/security/nss/fuzz/nssfuzz/spki_target.cc
+++ /dev/null
@@ -1,35 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* 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/. */
-
-#include <assert.h>
-#include <stdint.h>
-#include <memory>
-
-#include "keyhi.h"
-#include "pk11pub.h"
-
-#include "registry.h"
-#include "shared.h"
-
-extern "C" int spki_fuzzing_target(const uint8_t *Data, size_t Size) {
-  SECItem data = {siBuffer, (unsigned char *)Data, (unsigned int)Size};
-
-  static std::unique_ptr<NSSDatabase> db(new NSSDatabase());
-  assert(db != nullptr);
-
-  CERTSubjectPublicKeyInfo *spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&data);
-
-  if (spki) {
-    SECKEYPublicKey *key = SECKEY_ExtractPublicKey(spki);
-    SECKEY_DestroyPublicKey(key);
-  }
-
-  SECKEY_DestroySubjectPublicKeyInfo(spki);
-
-  return 0;
-}
-
-REGISTER_FUZZING_TARGET("spki", spki_fuzzing_target, 1024, "SPKI Import")
new file mode 100644
--- /dev/null
+++ b/security/nss/fuzz/pkcs8_target.cc
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include <assert.h>
+#include <stdint.h>
+#include <memory>
+
+#include "keyhi.h"
+#include "pk11pub.h"
+
+#include "registry.h"
+#include "shared.h"
+
+extern "C" int pkcs8_fuzzing_target(const uint8_t *Data, size_t Size) {
+  SECItem data = {siBuffer, (unsigned char *)Data, (unsigned int)Size};
+
+  static std::unique_ptr<NSSDatabase> db(new NSSDatabase());
+  assert(db != nullptr);
+
+  PK11SlotInfo *slot = PK11_GetInternalSlot();
+  assert(slot != nullptr);
+
+  SECKEYPrivateKey *key = nullptr;
+  if (PK11_ImportDERPrivateKeyInfoAndReturnKey(slot, &data, nullptr, nullptr,
+                                               false, false, KU_ALL, &key,
+                                               nullptr) == SECSuccess) {
+    SECKEY_DestroyPrivateKey(key);
+  }
+
+  PK11_FreeSlot(slot);
+  return 0;
+}
+
+REGISTER_FUZZING_TARGET("pkcs8", pkcs8_fuzzing_target, 2048, "PKCS#8 Import")
new file mode 100644
--- /dev/null
+++ b/security/nss/fuzz/quickder_targets.cc
@@ -0,0 +1,36 @@
+/* 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/. */
+
+#include <stdint.h>
+
+#include "cert.h"
+
+#include "registry.h"
+
+void QuickDERDecode(void *dst, const SEC_ASN1Template *tpl, const uint8_t *buf,
+                    size_t len) {
+  PORTCheapArenaPool pool;
+  SECItem data = {siBuffer, const_cast<unsigned char *>(buf),
+                  static_cast<unsigned int>(len)};
+
+  PORT_InitCheapArena(&pool, DER_DEFAULT_CHUNKSIZE);
+  (void)SEC_QuickDERDecodeItem(&pool.arena, dst, tpl, &data);
+  PORT_DestroyCheapArena(&pool);
+}
+
+extern "C" int cert_fuzzing_target(const uint8_t *Data, size_t Size) {
+  CERTCertificate cert;
+  QuickDERDecode(&cert, SEC_SignedCertificateTemplate, Data, Size);
+  return 0;
+}
+
+REGISTER_FUZZING_TARGET("cert", cert_fuzzing_target, 3072, "Certificate Import")
+
+extern "C" int spki_fuzzing_target(const uint8_t *Data, size_t Size) {
+  CERTSubjectPublicKeyInfo spki;
+  QuickDERDecode(&spki, CERT_SubjectPublicKeyInfoTemplate, Data, Size);
+  return 0;
+}
+
+REGISTER_FUZZING_TARGET("spki", spki_fuzzing_target, 1024, "SPKI Import")
new file mode 100644
--- /dev/null
+++ b/security/nss/fuzz/registry.h
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* 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 registry_h__
+#define registry_h__
+
+#include <map>
+#include "FuzzerInternal.h"
+#include "nss.h"
+
+class Registry {
+ public:
+  static void Add(std::string name, fuzzer::UserCallback func, uint16_t max_len,
+                  std::string desc) {
+    assert(!Has(name));
+    GetInstance().targets_[name] = TargetData(func, max_len, desc);
+  }
+
+  static bool Has(std::string name) {
+    return GetInstance().targets_.count(name) > 0;
+  }
+
+  static fuzzer::UserCallback Func(std::string name) {
+    assert(Has(name));
+    return std::get<0>(Get(name));
+  }
+
+  static uint16_t MaxLen(std::string name) {
+    assert(Has(name));
+    return std::get<1>(Get(name));
+  }
+
+  static std::string& Desc(std::string name) {
+    assert(Has(name));
+    return std::get<2>(Get(name));
+  }
+
+  static std::vector<std::string> Names() {
+    std::vector<std::string> names;
+    for (auto& it : GetInstance().targets_) {
+      names.push_back(it.first);
+    }
+    return names;
+  }
+
+ private:
+  typedef std::tuple<fuzzer::UserCallback, uint16_t, std::string> TargetData;
+
+  static Registry& GetInstance() {
+    static Registry registry;
+    return registry;
+  }
+
+  static TargetData& Get(std::string name) {
+    return GetInstance().targets_[name];
+  }
+
+  Registry() {}
+
+  std::map<std::string, TargetData> targets_;
+};
+
+#define REGISTER_FUZZING_TARGET(name, func, max_len, desc)     \
+  static void __attribute__((constructor)) Register_##func() { \
+    Registry::Add(name, func, max_len, desc);                  \
+  }
+
+#endif  // registry_h__
new file mode 100644
--- /dev/null
+++ b/security/nss/fuzz/shared.h
@@ -0,0 +1,18 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* 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 shared_h__
+#define shared_h__
+
+#include "nss.h"
+
+class NSSDatabase {
+ public:
+  NSSDatabase() { NSS_NoDB_Init(nullptr); }
+  ~NSSDatabase() { NSS_Shutdown(); }
+};
+
+#endif  // shared_h__
--- a/security/nss/gtests/common/common.gyp
+++ b/security/nss/gtests/common/common.gyp
@@ -13,17 +13,16 @@
       'sources': [
         'gtests.cc'
       ],
       'dependencies': [
         '<(DEPTH)/exports.gyp:nss_exports',
         '<(DEPTH)/lib/nss/nss.gyp:nss3',
         '<(DEPTH)/lib/util/util.gyp:nssutil3',
         '<(DEPTH)/lib/smime/smime.gyp:smime3',
-        '<(DEPTH)/lib/ssl/ssl.gyp:ssl3',
         '<(DEPTH)/gtests/google_test/google_test.gyp:gtest',
         '<(DEPTH)/cmd/lib/lib.gyp:sectool'
       ]
     }
   ],
   'target_defaults': {
     'include_dirs': [
       '../../gtests/google_test/gtest/include',
--- a/security/nss/gtests/common/scoped_ptrs.h
+++ b/security/nss/gtests/common/scoped_ptrs.h
@@ -11,16 +11,20 @@
 #include "cert.h"
 #include "keyhi.h"
 #include "pk11pub.h"
 
 namespace nss_test {
 
 struct ScopedDelete {
   void operator()(CERTCertificate* cert) { CERT_DestroyCertificate(cert); }
+  void operator()(CERTCertificateList* list) {
+    CERT_DestroyCertificateList(list);
+  }
+  void operator()(CERTCertList* list) { CERT_DestroyCertList(list); }
   void operator()(CERTSubjectPublicKeyInfo* spki) {
     SECKEY_DestroySubjectPublicKeyInfo(spki);
   }
   void operator()(PK11SlotInfo* slot) { PK11_FreeSlot(slot); }
   void operator()(PK11SymKey* key) { PK11_FreeSymKey(key); }
   void operator()(SECAlgorithmID* id) { SECOID_DestroyAlgorithmID(id, true); }
   void operator()(SECItem* item) { SECITEM_FreeItem(item, true); }
   void operator()(SECKEYPublicKey* key) { SECKEY_DestroyPublicKey(key); }
@@ -35,16 +39,18 @@ struct ScopedMaybeDelete {
       del(ptr);
     }
   }
 };
 
 #define SCOPED(x) typedef std::unique_ptr<x, ScopedMaybeDelete<x> > Scoped##x
 
 SCOPED(CERTCertificate);
+SCOPED(CERTCertificateList);
+SCOPED(CERTCertList);
 SCOPED(CERTSubjectPublicKeyInfo);
 SCOPED(PK11SlotInfo);
 SCOPED(PK11SymKey);
 SCOPED(SECAlgorithmID);
 SCOPED(SECItem);
 SCOPED(SECKEYPublicKey);
 SCOPED(SECKEYPrivateKey);
 
--- a/security/nss/gtests/der_gtest/der_gtest.gyp
+++ b/security/nss/gtests/der_gtest/der_gtest.gyp
@@ -7,16 +7,17 @@
     '../common/gtest.gypi',
   ],
   'targets': [
     {
       'target_name': 'der_gtest',
       'type': 'executable',
       'sources': [
         'der_getint_unittest.cc',
+        'der_private_key_import_unittest.cc',
         '<(DEPTH)/gtests/common/gtests.cc'
       ],
       'dependencies': [
         '<(DEPTH)/exports.gyp:nss_exports',
         '<(DEPTH)/gtests/google_test/google_test.gyp:gtest',
       ]
     }
   ],
new file mode 100644
--- /dev/null
+++ b/security/nss/gtests/freebl_gtest/freebl_gtest.gyp
@@ -0,0 +1,37 @@
+# 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',
+    '../common/gtest.gypi',
+  ],
+  'targets': [
+    {
+      'target_name': 'freebl_gtest',
+      'type': 'executable',
+      'sources': [
+        'mpi_unittest.cc',
+        '<(DEPTH)/gtests/common/gtests.cc'
+      ],
+      'dependencies': [
+        '<(DEPTH)/exports.gyp:nss_exports',
+        '<(DEPTH)/lib/freebl/freebl.gyp:<(freebl_name)',
+        '<(DEPTH)/gtests/google_test/google_test.gyp:gtest',
+      ],
+      'defines': [
+        'CT_VERIF',
+      ],
+    }
+  ],
+  'target_defaults': {
+    'include_dirs': [
+      '<(DEPTH)/gtests/google_test/gtest/include',
+      '<(DEPTH)/gtests/common',
+      '<(DEPTH)/lib/freebl/mpi',
+    ]
+  },
+  'variables': {
+    'module': 'nss'
+  }
+}
new file mode 100644
--- /dev/null
+++ b/security/nss/gtests/freebl_gtest/mpi_unittest.cc
@@ -0,0 +1,118 @@
+// 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/.
+
+#include "secdert.h"
+#include "secitem.h"
+#include "secport.h"
+
+#include "gtest/gtest.h"
+
+#include <stdint.h>
+#include <string.h>
+#include <string>
+
+#ifdef __MACH__
+#include <mach/clock.h>
+#include <mach/mach.h>
+#endif
+
+#include "mpi.h"
+namespace nss_test {
+
+void gettime(struct timespec *tp) {
+#ifdef __MACH__
+  clock_serv_t cclock;
+  mach_timespec_t mts;
+
+  host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
+  clock_get_time(cclock, &mts);
+  mach_port_deallocate(mach_task_self(), cclock);
+
+  tp->tv_sec = mts.tv_sec;
+  tp->tv_nsec = mts.tv_nsec;
+#else
+  clock_gettime(CLOCK_MONOTONIC, tp);
+#endif
+}
+
+class MPITest : public ::testing::Test {
+ protected:
+  void TestCmp(const std::string a_string, const std::string b_string,
+               int result) {
+    mp_int a, b, c;
+    MP_DIGITS(&a) = 0;
+    MP_DIGITS(&b) = 0;
+    MP_DIGITS(&c) = 0;
+    ASSERT_EQ(MP_OKAY, mp_init(&a));
+    ASSERT_EQ(MP_OKAY, mp_init(&b));
+
+    mp_read_radix(&a, a_string.c_str(), 16);
+    mp_read_radix(&b, b_string.c_str(), 16);
+    EXPECT_EQ(result, mp_cmp(&a, &b));
+  }
+};
+
+TEST_F(MPITest, MpiCmp01Test) { TestCmp("0", "1", -1); }
+TEST_F(MPITest, MpiCmp10Test) { TestCmp("1", "0", 1); }
+TEST_F(MPITest, MpiCmp00Test) { TestCmp("0", "0", 0); }
+TEST_F(MPITest, MpiCmp11Test) { TestCmp("1", "1", 0); }
+
+TEST_F(MPITest, MpiCmpConstTest) {
+  mp_int a, b, c;
+  MP_DIGITS(&a) = 0;
+  MP_DIGITS(&b) = 0;
+  MP_DIGITS(&c) = 0;
+  ASSERT_EQ(MP_OKAY, mp_init(&a));
+  ASSERT_EQ(MP_OKAY, mp_init(&b));
+  ASSERT_EQ(MP_OKAY, mp_init(&c));
+
+  mp_read_radix(
+      &a,
+      const_cast<char *>(
+          "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551"),
+      16);
+  mp_read_radix(
+      &b,
+      const_cast<char *>(
+          "FF0FFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551"),
+      16);
+  mp_read_radix(
+      &c,
+      const_cast<char *>(
+          "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632550"),
+      16);
+
+  mp_taint(&b);
+  mp_taint(&c);
+
+  uint32_t runs = 5000000;
+  uint32_t time_b = 0, time_c = 0;
+  for (uint32_t i = 0; i < runs; ++i) {
+    struct timespec start, end;
+    gettime(&start);
+    int r = mp_cmp(&a, &b);
+    gettime(&end);
+    unsigned long long used = end.tv_sec * 1000000000L + end.tv_nsec;
+    used -= static_cast<unsigned long long>(start.tv_sec * 1000000000L +
+                                            start.tv_nsec);
+    time_b += used;
+    ASSERT_EQ(1, r);
+  }
+  printf("time b: %u\n", time_b / runs);
+
+  for (uint32_t i = 0; i < runs; ++i) {
+    struct timespec start, end;
+    gettime(&start);
+    int r = mp_cmp(&a, &c);
+    gettime(&end);
+    unsigned long long used = end.tv_sec * 1000000000L + end.tv_nsec;
+    used -= static_cast<unsigned long long>(start.tv_sec * 1000000000L +
+                                            start.tv_nsec);
+    time_c += used;
+    ASSERT_EQ(1, r);
+  }
+  printf("time c: %u\n", time_c / runs);
+}
+
+}  // nss_test
--- a/security/nss/gtests/nss_bogo_shim/config.json
+++ b/security/nss/gtests/nss_bogo_shim/config.json
@@ -1,10 +1,24 @@
 {
     "DisabledTests": {
+        "### These tests break whenever we rev versions, so just leave them here for easy uncommenting":"",
+        "#*TLS13*":"(NSS=18, BoGo=16)",
+        "#*HelloRetryRequest*":"(NSS=18, BoGo=16)",
+        "#*KeyShare*":"(NSS=18, BoGo=16)",
+        "#*EncryptedExtensions*":"(NSS=18, BoGo=16)",
+        "#*ServerHelloSignatureAlgorithms*":"(NSS=18, BoGo=16)",
+        "#*SecondClientHello*":"(NSS=18, BoGo=16)",
+        "#*IgnoreClientVersionOrder*":"(NSS=18, BoGo=16)",
+        "Resume-Server-BinderWrongLength":"Alert disagreement (Bug 1317633)",
+        "Resume-Server-NoPSKBinder":"Alert disagreement (Bug 1317633)",
+        "CheckRecordVersion-TLS*":"Bug 1317634",
+        "GREASE-Server-TLS13":"BoringSSL GREASEs without a flag, but we ignore it",
+        "TLS13-ExpectNoSessionTicketOnBadKEMode-Server":"Bug in NSS. Don't send ticket when not permitted by KE modes (Bug 1317635)",
+        "Resume-Server-InvalidPSKBinder":"(Bogo incorrectly expects 'illegal_parameter')",
         "FallbackSCSV-VersionMatch":"Draft version mismatch (NSS=15, BoGo=14)",
         "*KeyUpdate*":"KeyUpdate Unimplemented",
         "ClientAuth-NoFallback-TLS13":"Disagreement about alerts. Bug 1294975",
         "ClientAuth-SHA1-Fallback":"Disagreement about alerts. Bug 1294975",
         "SendWarningAlerts-TLS13":"NSS needs to trigger on warning alerts",
         "NoSupportedCurves":"This tests a non-spec behavior for TLS 1.2 and expects the wrong alert for TLS 1.3",
         "SendEmptyRecords":"Tests a non-spec behavior in BoGo where it chokes on too many empty records",
         "LargePlaintext":"NSS needs to check for over-long records. Bug 1294978",
--- a/security/nss/gtests/nss_bogo_shim/nss_bogo_shim.cc
+++ b/security/nss/gtests/nss_bogo_shim/nss_bogo_shim.cc
@@ -13,16 +13,24 @@
 #include "prio.h"
 #include "prnetdb.h"
 #include "ssl.h"
 #include "sslerr.h"
 #include "sslproto.h"
 
 #include "nsskeys.h"
 
+static const char* kVersionDisableFlags[] = {
+  "no-ssl3",
+  "no-tls1",
+  "no-tls11",
+  "no-tls12",
+  "no-tls13"
+};
+
 bool exitCodeUnimplemented = false;
 
 std::string FormatError(PRErrorCode code) {
   return std::string(":") + PORT_ErrorToName(code) + ":" + ":" +
          PORT_ErrorToString(code);
 }
 
 class TestAgent {
@@ -139,22 +147,100 @@ class TestAgent {
         rv = SSL_GetClientAuthDataHook(ssl_fd_, GetClientAuthDataHook, this);
         if (rv != SECSuccess) return false;
       }
     }
 
     return true;
   }
 
+  bool GetVersionRange(SSLVersionRange* range_out, SSLProtocolVariant variant) {
+    SSLVersionRange supported;
+    if (SSL_VersionRangeGetSupported(variant, &supported) != SECSuccess) {
+      return false;
+    }
+
+    auto max_allowed = static_cast<uint16_t>(cfg_.get<int>("max-version"));
+    if (variant == ssl_variant_datagram) {
+      // For DTLS this is the wire version; adjust if needed.
+      switch (max_allowed) {
+      case SSL_LIBRARY_VERSION_DTLS_1_0_WIRE:
+        max_allowed = SSL_LIBRARY_VERSION_DTLS_1_0;
+        break;
+      case SSL_LIBRARY_VERSION_DTLS_1_2_WIRE:
+        max_allowed = SSL_LIBRARY_VERSION_DTLS_1_2;
+        break;
+      case SSL_LIBRARY_VERSION_DTLS_1_3_WIRE:
+        max_allowed = SSL_LIBRARY_VERSION_DTLS_1_3;
+        break;
+      case 0xffff: // No maximum specified.
+        break;
+      default:
+        // Unrecognized DTLS version.
+        return false;
+      }
+    }
+
+    max_allowed = std::min(max_allowed, supported.max);
+
+    bool found_min = false;
+    bool found_max = false;
+    // Ignore -no-ssl3, because SSLv3 is never supported.
+    for (size_t i = 1; i < PR_ARRAY_SIZE(kVersionDisableFlags); ++i) {
+      auto version =
+        static_cast<uint16_t>(SSL_LIBRARY_VERSION_TLS_1_0 + (i - 1));
+      if (variant == ssl_variant_datagram) {
+        // In DTLS mode, the -no-tlsN flags refer to DTLS versions,
+        // but NSS wants the corresponding TLS versions.
+        if (version == SSL_LIBRARY_VERSION_TLS_1_1) {
+          // DTLS 1.1 doesn't exist.
+          continue;
+        }
+        if (version == SSL_LIBRARY_VERSION_TLS_1_0) {
+          version = SSL_LIBRARY_VERSION_DTLS_1_0;
+        }
+      }
+
+      if (version < supported.min) {
+        continue;
+      }
+      if (version > max_allowed) {
+        break;
+      }
+
+      const bool allowed = !cfg_.get<bool>(kVersionDisableFlags[i]);
+
+      if (!found_min && allowed) {
+        found_min = true;
+        range_out->min = version;
+      }
+      if (found_min && !found_max) {
+        if (allowed) {
+          range_out->max = version;
+        } else {
+          found_max = true;
+        }
+      }
+      if (found_max && allowed) {
+        // Discontiguous range.
+        return false;
+      }
+    }
+
+    // Iff found_min is still false, no usable version was found.
+    return found_min;
+  }
+
   bool SetupOptions() {
     SECStatus rv = SSL_OptionSet(ssl_fd_, SSL_ENABLE_SESSION_TICKETS, PR_TRUE);
     if (rv != SECSuccess) return false;
 
-    SSLVersionRange vrange = {SSL_LIBRARY_VERSION_TLS_1_0,
-                              SSL_LIBRARY_VERSION_TLS_1_3};
+    SSLVersionRange vrange;
+    if (!GetVersionRange(&vrange, ssl_variant_stream)) return false;
+
     rv = SSL_VersionRangeSet(ssl_fd_, &vrange);
     if (rv != SECSuccess) return false;
 
     rv = SSL_OptionSet(ssl_fd_, SSL_NO_CACHE, false);
     if (rv != SECSuccess) return false;
 
     if (!cfg_.get<bool>("server")) {
       // Needed to make resumption work.
@@ -263,16 +349,20 @@ class TestAgent {
 std::unique_ptr<const Config> ReadConfig(int argc, char** argv) {
   std::unique_ptr<Config> cfg(new Config());
 
   cfg->AddEntry<int>("port", 0);
   cfg->AddEntry<bool>("server", false);
   cfg->AddEntry<int>("resume-count", 0);
   cfg->AddEntry<std::string>("key-file", "");
   cfg->AddEntry<std::string>("cert-file", "");
+  cfg->AddEntry<int>("max-version", 0xffff);
+  for (auto flag : kVersionDisableFlags) {
+    cfg->AddEntry<bool>(flag, false);
+  }
 
   auto rv = cfg->ParseArgs(argc, argv);
   switch (rv) {
     case Config::kOK:
       break;
     case Config::kUnknownFlag:
       exitCodeUnimplemented = true;
     default:
--- a/security/nss/gtests/ssl_gtest/databuffer.h
+++ b/security/nss/gtests/ssl_gtest/databuffer.h
@@ -23,17 +23,17 @@ extern bool g_ssl_gtest_verbose;
 namespace nss_test {
 
 class DataBuffer {
  public:
   DataBuffer() : data_(nullptr), len_(0) {}
   DataBuffer(const uint8_t* data, size_t len) : data_(nullptr), len_(0) {
     Assign(data, len);
   }
-  explicit DataBuffer(const DataBuffer& other) : data_(nullptr), len_(0) {
+  DataBuffer(const DataBuffer& other) : data_(nullptr), len_(0) {
     Assign(other);
   }
   ~DataBuffer() { delete[] data_; }
 
   DataBuffer& operator=(const DataBuffer& other) {
     if (&other != this) {
       Assign(other);
     }
@@ -131,17 +131,17 @@ class DataBuffer {
     len_ = index + ins_len + tail_len;
     data_ = new uint8_t[len_ ? len_ : 1];
 
     // The head of the old.
     if (old_value) {
       Write(0, old_value, std::min(old_len, index));
     }
     // Maybe a gap.
-    if (index > old_len) {
+    if (old_value && index > old_len) {
       memset(old_value + index, 0, index - old_len);
     }
     // The new.
     Write(index, ins, ins_len);
     // The tail of the old.
     if (tail_len > 0) {
       Write(index + ins_len, old_value + index + remove, tail_len);
     }
--- a/security/nss/gtests/ssl_gtest/libssl_internals.c
+++ b/security/nss/gtests/ssl_gtest/libssl_internals.c
@@ -89,16 +89,32 @@ PRInt32 SSLInt_CountTls13CipherSpecs(PRF
 
   for (cur_p = PR_NEXT_LINK(&ss->ssl3.hs.cipherSpecs);
        cur_p != &ss->ssl3.hs.cipherSpecs; cur_p = PR_NEXT_LINK(cur_p)) {
     ++ct;
   }
   return ct;
 }
 
+void SSLInt_PrintTls13CipherSpecs(PRFileDesc *fd) {
+  PRCList *cur_p;
+
+  sslSocket *ss = ssl_FindSocket(fd);
+  if (!ss) {
+    return;
+  }
+
+  fprintf(stderr, "Cipher specs\n");
+  for (cur_p = PR_NEXT_LINK(&ss->ssl3.hs.cipherSpecs);
+       cur_p != &ss->ssl3.hs.cipherSpecs; cur_p = PR_NEXT_LINK(cur_p)) {
+    ssl3CipherSpec *spec = (ssl3CipherSpec *)cur_p;
+    fprintf(stderr, "  %s\n", spec->phase);
+  }
+}
+
 /* Force a timer expiry by backdating when the timer was started.
  * We could set the remaining time to 0 but then backoff would not
  * work properly if we decide to test it. */
 void SSLInt_ForceTimerExpiry(PRFileDesc *fd) {
   sslSocket *ss = ssl_FindSocket(fd);
   if (!ss) {
     return;
   }
@@ -117,17 +133,17 @@ void SSLInt_ForceTimerExpiry(PRFileDesc 
 
 PRBool SSLInt_CheckSecretsDestroyed(PRFileDesc *fd) {
   sslSocket *ss = ssl_FindSocket(fd);
   if (!ss) {
     return PR_FALSE;
   }
 
   CHECK_SECRET(currentSecret);
-  CHECK_SECRET(resumptionPsk);
+  CHECK_SECRET(resumptionMasterSecret);
   CHECK_SECRET(dheSecret);
   CHECK_SECRET(clientEarlyTrafficSecret);
   CHECK_SECRET(clientHsTrafficSecret);
   CHECK_SECRET(serverHsTrafficSecret);
 
   return PR_TRUE;
 }
 
--- a/security/nss/gtests/ssl_gtest/libssl_internals.h
+++ b/security/nss/gtests/ssl_gtest/libssl_internals.h
@@ -17,16 +17,17 @@ SECStatus SSLInt_IncrementClientHandshak
 
 SECStatus SSLInt_UpdateSSLv2ClientRandom(PRFileDesc *fd, uint8_t *rnd,
                                          size_t rnd_len, uint8_t *msg,
                                          size_t msg_len);
 
 PRBool SSLInt_ExtensionNegotiated(PRFileDesc *fd, PRUint16 ext);
 void SSLInt_ClearSessionTicketKey();
 PRInt32 SSLInt_CountTls13CipherSpecs(PRFileDesc *fd);
+void SSLInt_PrintTls13CipherSpecs(PRFileDesc *fd);
 void SSLInt_ForceTimerExpiry(PRFileDesc *fd);
 SECStatus SSLInt_SetMTU(PRFileDesc *fd, PRUint16 mtu);
 PRBool SSLInt_CheckSecretsDestroyed(PRFileDesc *fd);
 PRBool SSLInt_DamageClientHsTrafficSecret(PRFileDesc *fd);
 PRBool SSLInt_DamageServerHsTrafficSecret(PRFileDesc *fd);
 PRBool SSLInt_DamageEarlyTrafficSecret(PRFileDesc *fd);
 SECStatus SSLInt_Set0RttAlpn(PRFileDesc *fd, PRUint8 *data, unsigned int len);
 PRBool SSLInt_HasCertWithAuthType(PRFileDesc *fd, SSLAuthType authType);
--- a/security/nss/gtests/ssl_gtest/manifest.mn
+++ b/security/nss/gtests/ssl_gtest/manifest.mn
@@ -17,16 +17,17 @@ CPPSRCS = \
       ssl_auth_unittest.cc \
       ssl_cert_ext_unittest.cc \
       ssl_ciphersuite_unittest.cc \
       ssl_damage_unittest.cc \
       ssl_dhe_unittest.cc \
       ssl_drop_unittest.cc \
       ssl_ecdh_unittest.cc \
       ssl_ems_unittest.cc \
+      ssl_exporter_unittest.cc \
       ssl_extension_unittest.cc \
       ssl_fuzz_unittest.cc \
       ssl_gtest.cc \
       ssl_hrr_unittest.cc \
       ssl_loopback_unittest.cc \
       ssl_record_unittest.cc \
       ssl_resumption_unittest.cc \
       ssl_skip_unittest.cc \
--- a/security/nss/gtests/ssl_gtest/ssl_0rtt_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_0rtt_unittest.cc
@@ -195,22 +195,9 @@ TEST_P(TlsConnectTls13, TestTls13ZeroRtt
     return false;
   });
   Handshake();
   CheckConnected();
   SendReceive();
   CheckAlpn("b");
 }
 
-TEST_F(TlsConnectTest, DamageSecretHandleZeroRttClientFinished) {
-  SetupForZeroRtt();
-  client_->Set0RttEnabled(true);
-  server_->Set0RttEnabled(true);
-  client_->SetPacketFilter(new AfterRecordN(
-      client_, server_,
-      0,  // ClientHello.
-      [this]() { SSLInt_DamageEarlyTrafficSecret(server_->ssl_fd()); }));
-  ConnectExpectFail();
-  client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
-  server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
-}
-
 }  // namespace nss_test
--- a/security/nss/gtests/ssl_gtest/ssl_agent_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_agent_unittest.cc
@@ -39,26 +39,23 @@ const static uint8_t kCannedTls13ClientH
     0xbf, 0x2a, 0xb5, 0x59, 0x64, 0xcc, 0x0c, 0x49, 0x95, 0x36, 0xe4, 0xd9,
     0x2f, 0xd4, 0x24, 0x66, 0x71, 0x6f, 0x5d, 0x70, 0xe2, 0xa0, 0xea, 0x26,
     0x00, 0x2b, 0x00, 0x03, 0x02, 0x7f, kD13, 0x00, 0x0d, 0x00, 0x20, 0x00,
     0x1e, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x02, 0x03, 0x08, 0x04, 0x08,
     0x05, 0x08, 0x06, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x02, 0x01, 0x04,
     0x02, 0x05, 0x02, 0x06, 0x02, 0x02, 0x02};
 
 const static uint8_t kCannedTls13ServerHello[] = {
-    0x7f, kD13, 0x21, 0x12, 0xa7, 0xa7, 0x0d, 0x85, 0x8b, 0xb8, 0x0c, 0xbb,
-    0xdc, 0xa6, 0xfd, 0x97, 0xfe, 0x31, 0x26, 0x49, 0x2d, 0xa8, 0x6c, 0x7b,
-    0x65, 0x30, 0x71, 0x00, 0x31, 0x03, 0x2b, 0x94, 0xe2, 0x16, 0x13, 0x01,
-    0x00, 0x4d, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x28, 0x00, 0x45, 0x00, 0x17,
-    0x00, 0x41, 0x04, 0x10, 0x97, 0x3d, 0x7a, 0xcf, 0xa2, 0x34, 0xe3, 0x69,
-    0xc4, 0xdd, 0x1e, 0xf2, 0xd6, 0xc0, 0x9a, 0x3e, 0xf5, 0x41, 0xf3, 0x03,
-    0x23, 0x94, 0xd2, 0x31, 0x85, 0xb7, 0xae, 0x5d, 0xfa, 0xc6, 0x9a, 0xd0,
-    0xa5, 0x44, 0xa3, 0x3a, 0xe0, 0xbb, 0x61, 0xaa, 0x0a, 0x6f, 0xe8, 0xaf,
-    0xdf, 0x86, 0xd8, 0x48, 0x36, 0x9c, 0x19, 0x70, 0x55, 0x84, 0xb0, 0x1c,
-    0x8d, 0xfc, 0x6e, 0xd8, 0x86, 0xc3, 0x95};
+    0x7f, kD13, 0x9c, 0xbc, 0x14, 0x9b, 0x0e, 0x2e, 0xfa, 0x0d, 0xf3, 0xf0,
+    0x5c, 0x70, 0x7a, 0xe0, 0xd1, 0x9b, 0x3e, 0x5a, 0x44, 0x6b, 0xdf, 0xe5,
+    0xc2, 0x28, 0x64, 0xf7, 0x00, 0xc1, 0x9c, 0x08, 0x76, 0x08, 0x13, 0x01,
+    0x00, 0x28, 0x00, 0x28, 0x00, 0x24, 0x00, 0x1d, 0x00, 0x20, 0xc2, 0xcf,
+    0x23, 0x17, 0x64, 0x23, 0x03, 0xf0, 0xfb, 0x45, 0x98, 0x26, 0xd1, 0x65,
+    0x24, 0xa1, 0x6c, 0xa9, 0x80, 0x8f, 0x2c, 0xac, 0x0a, 0xea, 0x53, 0x3a,
+    0xcb, 0xe3, 0x08, 0x84, 0xae, 0x19};
 static const char *k0RttData = "ABCDEF";
 
 TEST_P(TlsAgentTest, EarlyFinished) {
   DataBuffer buffer;
   MakeTrivialHandshakeRecord(kTlsHandshakeFinished, 0, &buffer);
   ProcessMessage(buffer, TlsAgent::STATE_ERROR,
                  SSL_ERROR_RX_UNEXPECTED_FINISHED);
 }
--- a/security/nss/gtests/ssl_gtest/ssl_auth_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_auth_unittest.cc
@@ -23,16 +23,25 @@ extern "C" {
 namespace nss_test {
 
 TEST_P(TlsConnectGeneric, ServerAuthBigRsa) {
   Reset(TlsAgent::kRsa2048);
   Connect();
   CheckKeys();
 }
 
+TEST_P(TlsConnectGeneric, ServerAuthRsaChain) {
+  Reset(TlsAgent::kServerRsaChain);
+  Connect();
+  CheckKeys();
+  size_t chain_length;
+  EXPECT_TRUE(client_->GetPeerChainLength(&chain_length));
+  EXPECT_EQ(2UL, chain_length);
+}
+
 TEST_P(TlsConnectGeneric, ClientAuth) {
   client_->SetupClientAuth();
   server_->RequestClientAuth(true);
   Connect();
   CheckKeys();
 }
 
 // In TLS 1.3, the client sends its cert rejection on the
--- a/security/nss/gtests/ssl_gtest/ssl_cert_ext_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_cert_ext_unittest.cc
@@ -18,112 +18,112 @@ namespace nss_test {
 
 // Tests for Certificate Transparency (RFC 6962)
 // These don't work with TLS 1.3: see bug 1252745.
 
 // Helper class - stores signed certificate timestamps as provided
 // by the relevant callbacks on the client.
 class SignedCertificateTimestampsExtractor {
  public:
-  SignedCertificateTimestampsExtractor(TlsAgent* client) {
-    client->SetAuthCertificateCallback(
+  SignedCertificateTimestampsExtractor(TlsAgent* client) : client_(client) {
+    client_->SetAuthCertificateCallback(
         [&](TlsAgent* agent, bool checksig, bool isServer) -> SECStatus {
           const SECItem* scts = SSL_PeerSignedCertTimestamps(agent->ssl_fd());
           EXPECT_TRUE(scts);
           if (!scts) {
             return SECFailure;
           }
           auth_timestamps_.reset(new DataBuffer(scts->data, scts->len));
           return SECSuccess;
         });
-    client->SetHandshakeCallback([&](TlsAgent* agent) {
+    client_->SetHandshakeCallback([&](TlsAgent* agent) {
       const SECItem* scts = SSL_PeerSignedCertTimestamps(agent->ssl_fd());
       ASSERT_TRUE(scts);
       handshake_timestamps_.reset(new DataBuffer(scts->data, scts->len));
     });
   }
 
   void assertTimestamps(const DataBuffer& timestamps) {
     EXPECT_TRUE(auth_timestamps_);
     EXPECT_EQ(timestamps, *auth_timestamps_);
 
     EXPECT_TRUE(handshake_timestamps_);
     EXPECT_EQ(timestamps, *handshake_timestamps_);
+
+    const SECItem* current = SSL_PeerSignedCertTimestamps(client_->ssl_fd());
+    EXPECT_EQ(timestamps, DataBuffer(current->data, current->len));
   }
 
  private:
+  TlsAgent* client_;
   std::unique_ptr<DataBuffer> auth_timestamps_;
   std::unique_ptr<DataBuffer> handshake_timestamps_;
 };
 
 static const uint8_t kSctValue[] = {0x01, 0x23, 0x45, 0x67, 0x89};
 static const SECItem kSctItem = {siBuffer, const_cast<uint8_t*>(kSctValue),
                                  sizeof(kSctValue)};
 static const DataBuffer kSctBuffer(kSctValue, sizeof(kSctValue));
 
 // Test timestamps extraction during a successful handshake.
-TEST_P(TlsConnectGenericPre13, SignedCertificateTimestampsHandshake) {
+TEST_P(TlsConnectGeneric, SignedCertificateTimestampsHandshake) {
   EnsureTlsSetup();
   EXPECT_EQ(SECSuccess, SSL_SetSignedCertTimestamps(server_->ssl_fd(),
                                                     &kSctItem, ssl_kea_rsa));
   EXPECT_EQ(SECSuccess,
             SSL_OptionSet(client_->ssl_fd(), SSL_ENABLE_SIGNED_CERT_TIMESTAMPS,
                           PR_TRUE));
   SignedCertificateTimestampsExtractor timestamps_extractor(client_);
 
   Connect();
 
   timestamps_extractor.assertTimestamps(kSctBuffer);
-  const SECItem* c_timestamps = SSL_PeerSignedCertTimestamps(client_->ssl_fd());
-  EXPECT_EQ(SECEqual, SECITEM_CompareItem(&kSctItem, c_timestamps));
 }
 
-TEST_P(TlsConnectGenericPre13, SignedCertificateTimestampsConfig) {
+TEST_P(TlsConnectGeneric, SignedCertificateTimestampsConfig) {
   static const SSLExtraServerCertData kExtraData = {ssl_auth_rsa_sign, nullptr,
                                                     nullptr, &kSctItem};
 
   EnsureTlsSetup();
   EXPECT_TRUE(
       server_->ConfigServerCert(TlsAgent::kServerRsa, true, &kExtraData));
   EXPECT_EQ(SECSuccess,
             SSL_OptionSet(client_->ssl_fd(), SSL_ENABLE_SIGNED_CERT_TIMESTAMPS,
                           PR_TRUE));
   SignedCertificateTimestampsExtractor timestamps_extractor(client_);
 
   Connect();
 
   timestamps_extractor.assertTimestamps(kSctBuffer);
-  const SECItem* c_timestamps = SSL_PeerSignedCertTimestamps(client_->ssl_fd());
-  EXPECT_EQ(SECEqual, SECITEM_CompareItem(&kSctItem, c_timestamps));
 }
 
 // Test SSL_PeerSignedCertTimestamps returning zero-length SECItem
 // when the client / the server / both have not enabled the feature.
-TEST_P(TlsConnectGenericPre13, SignedCertificateTimestampsInactiveClient) {
+TEST_P(TlsConnectGeneric, SignedCertificateTimestampsInactiveClient) {
   EnsureTlsSetup();
   EXPECT_EQ(SECSuccess, SSL_SetSignedCertTimestamps(server_->ssl_fd(),
                                                     &kSctItem, ssl_kea_rsa));
   SignedCertificateTimestampsExtractor timestamps_extractor(client_);
 
   Connect();
   timestamps_extractor.assertTimestamps(DataBuffer());
 }
 
-TEST_P(TlsConnectGenericPre13, SignedCertificateTimestampsInactiveServer) {
+TEST_P(TlsConnectGeneric, SignedCertificateTimestampsInactiveServer) {
   EnsureTlsSetup();
   EXPECT_EQ(SECSuccess,
             SSL_OptionSet(client_->ssl_fd(), SSL_ENABLE_SIGNED_CERT_TIMESTAMPS,
                           PR_TRUE));
   SignedCertificateTimestampsExtractor timestamps_extractor(client_);
 
   Connect();
   timestamps_extractor.assertTimestamps(DataBuffer());
 }
 
-TEST_P(TlsConnectGenericPre13, SignedCertificateTimestampsInactiveBoth) {
+TEST_P(TlsConnectGeneric, SignedCertificateTimestampsInactiveBoth) {
   EnsureTlsSetup();
   SignedCertificateTimestampsExtractor timestamps_extractor(client_);
 
   Connect();
   timestamps_extractor.assertTimestamps(DataBuffer());
 }
 
 // Check that the given agent doesn't have an OCSP response for its peer.
--- a/security/nss/gtests/ssl_gtest/ssl_dhe_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_dhe_unittest.cc
@@ -541,9 +541,69 @@ TEST_P(TlsConnectTls13, ResumeFfdhe) {
   server_->SetPacketFilter(serverCapture);
   ExpectResumption(RESUME_TICKET);
   Connect();
   CheckKeys(ssl_kea_dh, ssl_grp_ffdhe_2048, ssl_auth_rsa_sign, ssl_sig_none);
   ASSERT_LT(0UL, clientCapture->extension().len());
   ASSERT_LT(0UL, serverCapture->extension().len());
 }
 
+class TlsDheSkeChangeSignature : public TlsHandshakeFilter {
+ public:
+  TlsDheSkeChangeSignature(uint16_t version, const uint8_t* data, size_t len)
+      : version_(version), data_(data), len_(len) {}
+
+ protected:
+  virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
+                                               const DataBuffer& input,
+                                               DataBuffer* output) {
+    if (header.handshake_type() != kTlsHandshakeServerKeyExchange) {
+      return KEEP;
+    }
+
+    TlsParser parser(input);
+    EXPECT_TRUE(parser.SkipVariable(2));  // dh_p
+    EXPECT_TRUE(parser.SkipVariable(2));  // dh_g
+    EXPECT_TRUE(parser.SkipVariable(2));  // dh_Ys
+
+    // Copy DH params to output.
+    size_t offset = output->Write(0, input.data(), parser.consumed());
+
+    if (version_ == SSL_LIBRARY_VERSION_TLS_1_2) {
+      // Write signature algorithm.
+      offset = output->Write(offset, ssl_sig_dsa_sha256, 2);
+    }
+
+    // Write new signature.
+    offset = output->Write(offset, len_, 2);
+    offset = output->Write(offset, data_, len_);
+
+    return CHANGE;
+  }
+
+ private:
+  uint16_t version_;
+  const uint8_t* data_;
+  size_t len_;
+};
+
+TEST_P(TlsConnectGenericPre13, InvalidDERSignatureFfdhe) {
+  const uint8_t kBogusDheSignature[] = {
+      0x30, 0x69, 0x3c, 0x02, 0x1c, 0x7d, 0x0b, 0x2f, 0x64, 0x00, 0x27,
+      0xae, 0xcf, 0x1e, 0x28, 0x08, 0x6a, 0x7f, 0xb1, 0xbd, 0x78, 0xb5,
+      0x3b, 0x8c, 0x8f, 0x59, 0xed, 0x8f, 0xee, 0x78, 0xeb, 0x2c, 0xe9,
+      0x02, 0x1c, 0x6d, 0x7f, 0x3c, 0x0f, 0xf4, 0x44, 0x35, 0x0b, 0xb2,
+      0x6d, 0xdc, 0xb8, 0x21, 0x87, 0xdd, 0x0d, 0xb9, 0x46, 0x09, 0x3e,
+      0xef, 0x81, 0x5b, 0x37, 0x09, 0x39, 0xeb};
+
+  Reset(TlsAgent::kServerDsa);
+
+  const std::vector<SSLNamedGroup> client_groups = {ssl_grp_ffdhe_2048};
+  client_->ConfigNamedGroups(client_groups);
+
+  server_->SetPacketFilter(new TlsDheSkeChangeSignature(
+      version_, kBogusDheSignature, sizeof(kBogusDheSignature)));
+
+  ConnectExpectFail();
+  client_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
+}
+
 }  // namespace nss_test
--- a/security/nss/gtests/ssl_gtest/ssl_ecdh_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_ecdh_unittest.cc
@@ -282,17 +282,17 @@ TEST_P(TlsKeyExchangeTest13, Curve25519P
   client_->ConfigNamedGroups(client_groups);
   server_->ConfigNamedGroups(server_groups);
 
   Connect();
 
   CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp256r1, ssl_auth_rsa_sign,
             ssl_sig_rsa_pss_sha256);
   const std::vector<SSLNamedGroup> shares = {ssl_grp_ec_secp256r1};
-  CheckKEXDetails(client_groups, shares, false);
+  CheckKEXDetails(client_groups, shares);
 }
 
 TEST_P(TlsKeyExchangeTest13, Curve25519P256EqualPriorityServer13) {
   EnsureKeyShareSetup();
 
   // The client sends a 25519 key share while the server prefers P256.
   // We have to accept 25519 without retry.
   const std::vector<SSLNamedGroup> client_groups = {ssl_grp_ec_curve25519,
@@ -302,17 +302,17 @@ TEST_P(TlsKeyExchangeTest13, Curve25519P
   client_->ConfigNamedGroups(client_groups);
   server_->ConfigNamedGroups(server_groups);
 
   Connect();
 
   CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_rsa_sign,
             ssl_sig_rsa_pss_sha256);
   const std::vector<SSLNamedGroup> shares = {ssl_grp_ec_curve25519};
-  CheckKEXDetails(client_groups, shares, false);
+  CheckKEXDetails(client_groups, shares);
 }
 
 TEST_P(TlsKeyExchangeTest13, EqualPriorityTestRetryECServer13) {
   EnsureKeyShareSetup();
 
   // The client sends a 25519 key share while the server prefers P256.
   // The server prefers P-384 over x25519, so it must not consider P-256 and
   // x25519 to be equivalent. It will therefore request a P-256 share
@@ -324,17 +324,17 @@ TEST_P(TlsKeyExchangeTest13, EqualPriori
   client_->ConfigNamedGroups(client_groups);
   server_->ConfigNamedGroups(server_groups);
 
   Connect();
 
   CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp256r1, ssl_auth_rsa_sign,
             ssl_sig_rsa_pss_sha256);
   const std::vector<SSLNamedGroup> shares = {ssl_grp_ec_curve25519};
-  CheckKEXDetails(client_groups, shares, true);
+  CheckKEXDetails(client_groups, shares, ssl_grp_ec_secp256r1);
 }
 
 TEST_P(TlsKeyExchangeTest13, NotEqualPriorityWithIntermediateGroup13) {
   EnsureKeyShareSetup();
 
   // The client sends a 25519 key share while the server prefers P256.
   // The server prefers ffdhe_2048 over x25519, so it must not consider the
   // P-256 and x25519 to be equivalent. It will therefore request a P-256 share
@@ -346,17 +346,17 @@ TEST_P(TlsKeyExchangeTest13, NotEqualPri
   client_->ConfigNamedGroups(client_groups);
   server_->ConfigNamedGroups(server_groups);
 
   Connect();
 
   CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp256r1, ssl_auth_rsa_sign,
             ssl_sig_rsa_pss_sha256);
   const std::vector<SSLNamedGroup> shares = {ssl_grp_ec_curve25519};
-  CheckKEXDetails(client_groups, shares, true);
+  CheckKEXDetails(client_groups, shares, ssl_grp_ec_secp256r1);
 }
 
 TEST_P(TlsKeyExchangeTest13,
        NotEqualPriorityWithUnsupportedFFIntermediateGroup13) {
   EnsureKeyShareSetup();
 
   // As in the previous test, the server prefers ffdhe_2048. Thus, even though
   // the client doesn't support this group, the server must not regard x25519 as
@@ -368,17 +368,17 @@ TEST_P(TlsKeyExchangeTest13,
   client_->ConfigNamedGroups(client_groups);
   server_->ConfigNamedGroups(server_groups);
 
   Connect();
 
   CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp256r1, ssl_auth_rsa_sign,
             ssl_sig_rsa_pss_sha256);
   const std::vector<SSLNamedGroup> shares = {ssl_grp_ec_curve25519};
-  CheckKEXDetails(client_groups, shares, true);
+  CheckKEXDetails(client_groups, shares, ssl_grp_ec_secp256r1);
 }
 
 TEST_P(TlsKeyExchangeTest13,
        NotEqualPriorityWithUnsupportedECIntermediateGroup13) {
   EnsureKeyShareSetup();
 
   // As in the previous test, the server prefers P-384. Thus, even though
   // the client doesn't support this group, the server must not regard x25519 as
@@ -390,17 +390,17 @@ TEST_P(TlsKeyExchangeTest13,
   client_->ConfigNamedGroups(client_groups);
   server_->ConfigNamedGroups(server_groups);
 
   Connect();
 
   CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp256r1, ssl_auth_rsa_sign,
             ssl_sig_rsa_pss_sha256);
   const std::vector<SSLNamedGroup> shares = {ssl_grp_ec_curve25519};
-  CheckKEXDetails(client_groups, shares, true);
+  CheckKEXDetails(client_groups, shares, ssl_grp_ec_secp256r1);
 }
 
 TEST_P(TlsKeyExchangeTest13, EqualPriority13) {
   EnsureKeyShareSetup();
 
   // The client sends a 25519 key share while the server prefers P256.
   // We have to accept 25519 without retry because it's considered equivalent to
   // P256 by the server.
@@ -410,17 +410,17 @@ TEST_P(TlsKeyExchangeTest13, EqualPriori
                                                     ssl_grp_ec_curve25519};
   client_->ConfigNamedGroups(client_groups);
   server_->ConfigNamedGroups(server_groups);
 
   Connect();
 
   CheckKeys();
   const std::vector<SSLNamedGroup> shares = {ssl_grp_ec_curve25519};
-  CheckKEXDetails(client_groups, shares, false);
+  CheckKEXDetails(client_groups, shares);
 }
 #endif
 
 TEST_P(TlsConnectGeneric, P256ClientAndCurve25519Server) {
   EnsureTlsSetup();
   client_->DisableAllCiphers();
   client_->EnableCiphersByKeyExchange(ssl_kea_ecdh);
 
@@ -453,17 +453,17 @@ TEST_P(TlsKeyExchangeTest13, MultipleCli
 
   Connect();
 
   // The server would accept 25519 but its preferred group (P256) has to win.
   CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp256r1, ssl_auth_rsa_sign,
             ssl_sig_rsa_pss_sha256);
   const std::vector<SSLNamedGroup> shares = {ssl_grp_ec_curve25519,
                                              ssl_grp_ec_secp256r1};
-  CheckKEXDetails(client_groups, shares, false);
+  CheckKEXDetails(client_groups, shares);
 }
 
 // Replace the point in the client key exchange message with an empty one
 class ECCClientKEXFilter : public TlsHandshakeFilter {
  public:
   ECCClientKEXFilter() {}
 
  protected:
new file mode 100644
--- /dev/null
+++ b/security/nss/gtests/ssl_gtest/ssl_exporter_unittest.cc
@@ -0,0 +1,122 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "ssl.h"
+
+#include "gtest_utils.h"
+#include "tls_connect.h"
+
+namespace nss_test {
+
+static const char* kExporterLabel = "EXPORTER-duck";
+static const uint8_t kExporterContext[] = {0x12, 0x34, 0x56};
+
+static void ExportAndCompare(TlsAgent* client, TlsAgent* server, bool context) {
+  static const size_t exporter_len = 10;
+  uint8_t client_value[exporter_len] = {0};
+  EXPECT_EQ(SECSuccess,
+            SSL_ExportKeyingMaterial(
+                client->ssl_fd(), kExporterLabel, strlen(kExporterLabel),
+                context ? PR_TRUE : PR_FALSE, kExporterContext,
+                sizeof(kExporterContext), client_value, sizeof(client_value)));
+  uint8_t server_value[exporter_len] = {0xff};
+  EXPECT_EQ(SECSuccess,
+            SSL_ExportKeyingMaterial(
+                server->ssl_fd(), kExporterLabel, strlen(kExporterLabel),
+                context ? PR_TRUE : PR_FALSE, kExporterContext,
+                sizeof(kExporterContext), server_value, sizeof(server_value)));
+  EXPECT_EQ(0, memcmp(client_value, server_value, sizeof(client_value)));
+}
+
+TEST_P(TlsConnectGeneric, ExporterBasic) {
+  EnsureTlsSetup();
+  if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
+    server_->EnableSingleCipher(TLS_AES_128_GCM_SHA256);
+  } else {
+    server_->EnableSingleCipher(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA);
+  }
+  Connect();
+  CheckKeys();
+  ExportAndCompare(client_, server_, false);
+}
+
+TEST_P(TlsConnectGeneric, ExporterContext) {
+  EnsureTlsSetup();
+  if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
+    server_->EnableSingleCipher(TLS_AES_128_GCM_SHA256);
+  } else {
+    server_->EnableSingleCipher(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA);
+  }
+  Connect();
+  CheckKeys();
+  ExportAndCompare(client_, server_, true);
+}
+
+// Bug 1312976 - SHA-384 doesn't work in 1.2 right now.
+TEST_P(TlsConnectTls13, ExporterSha384) {
+  EnsureTlsSetup();
+  client_->EnableSingleCipher(TLS_AES_256_GCM_SHA384);
+  Connect();
+  CheckKeys();
+  ExportAndCompare(client_, server_, false);
+}
+
+TEST_P(TlsConnectTls13, ExporterContextEmptyIsSameAsNone) {
+  EnsureTlsSetup();
+  if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
+    server_->EnableSingleCipher(TLS_AES_128_GCM_SHA256);
+  } else {
+    server_->EnableSingleCipher(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA);
+  }
+  Connect();
+  CheckKeys();
+  ExportAndCompare(client_, server_, false);
+}
+
+// This has a weird signature so that it can be passed to the SNI callback.
+int32_t RegularExporterShouldFail(TlsAgent* agent, const SECItem* srvNameArr,
+                                  PRUint32 srvNameArrSize) {
+  uint8_t val[10];
+  EXPECT_EQ(SECFailure, SSL_ExportKeyingMaterial(
+                            agent->ssl_fd(), kExporterLabel,
+                            strlen(kExporterLabel), PR_TRUE, kExporterContext,
+                            sizeof(kExporterContext), val, sizeof(val)))
+      << "regular exporter should fail";
+  return 0;
+}
+
+TEST_P(TlsConnectTls13, EarlyExporter) {
+  SetupForZeroRtt();
+  client_->Set0RttEnabled(true);
+  server_->Set0RttEnabled(true);
+  ExpectResumption(RESUME_TICKET);
+
+  client_->Handshake();  // Send ClientHello.
+  uint8_t client_value[10] = {0};
+  RegularExporterShouldFail(client_, nullptr, 0);
+  EXPECT_EQ(SECSuccess,
+            SSL_ExportEarlyKeyingMaterial(
+                client_->ssl_fd(), kExporterLabel, strlen(kExporterLabel),
+                kExporterContext, sizeof(kExporterContext), client_value,
+                sizeof(client_value)));
+
+  server_->SetSniCallback(RegularExporterShouldFail);
+  server_->Handshake();  // Handle ClientHello.
+  uint8_t server_value[10] = {0};
+  EXPECT_EQ(SECSuccess,
+            SSL_ExportEarlyKeyingMaterial(
+                server_->ssl_fd(), kExporterLabel, strlen(kExporterLabel),
+                kExporterContext, sizeof(kExporterContext), server_value,
+                sizeof(server_value)));
+  EXPECT_EQ(0, memcmp(client_value, server_value, sizeof(client_value)));
+
+  Handshake();
+  ExpectEarlyDataAccepted(true);
+  CheckConnected();
+  SendReceive();
+}
+
+}  // namespace nss_test
--- a/security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc
@@ -109,16 +109,61 @@ class TlsExtensionInjector : public TlsH
     return CHANGE;
   }
 
  private:
   const uint16_t extension_;
   const DataBuffer data_;
 };
 
+class TlsExtensionAppender : public TlsHandshakeFilter {
+ public:
+  TlsExtensionAppender(uint16_t ext, DataBuffer& data)
+      : extension_(ext), data_(data) {}
+
+  virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
+                                               const DataBuffer& input,
+                                               DataBuffer* output) {
+    size_t offset;
+    TlsParser parser(input);
+    if (header.handshake_type() == kTlsHandshakeClientHello) {
+      if (!TlsExtensionFilter::FindClientHelloExtensions(&parser, header)) {
+        return KEEP;
+      }
+    } else if (header.handshake_type() == kTlsHandshakeServerHello) {
+      if (!TlsExtensionFilter::FindServerHelloExtensions(&parser)) {
+        return KEEP;
+      }
+    } else {
+      return KEEP;
+    }
+    offset = parser.consumed();
+    *output = input;
+
+    uint32_t ext_len;
+    if (!parser.Read(&ext_len, 2)) {
+      ADD_FAILURE();
+      return KEEP;
+    }
+
+    ext_len += 4 + data_.len();
+    output->Write(offset, ext_len, 2);
+
+    offset = output->len();
+    offset = output->Write(offset, extension_, 2);
+    WriteVariable(output, offset, data_, 2);
+
+    return CHANGE;
+  }
+
+ private:
+  const uint16_t extension_;
+  const DataBuffer data_;
+};
+
 class TlsExtensionTestBase : public TlsConnectTestBase {
  protected:
   TlsExtensionTestBase(Mode mode, uint16_t version)
       : TlsConnectTestBase(mode, version) {}
   TlsExtensionTestBase(const std::string& mode, ui