Bug 1277255, land NSS_3_25_BETA1, r=franziskus
authorKai Engert <kaie@kuix.de>
Thu, 02 Jun 2016 22:33:04 +0200
changeset 300274 a2f23b6058a275e8239a5edeeda56830afdb584f
parent 300273 009d5a56af0f86e8e3abfa74dbe96ee429cac4e1
child 300275 ddb08c99af9a3909c97a7f0ba8924477c20434b1
push id30309
push usercbook@mozilla.com
push dateFri, 03 Jun 2016 10:00:40 +0000
treeherdermozilla-central@e27fe24a746f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfranziskus
bugs1277255
milestone49.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1277255, land NSS_3_25_BETA1, r=franziskus
security/nss/.clang-format
security/nss/.taskcluster.yml
security/nss/.travis.yml
security/nss/TAG-INFO
security/nss/automation/taskcluster/docker/Dockerfile
security/nss/automation/taskcluster/docker/bin/checkout.sh
security/nss/automation/taskcluster/docker/setup.sh
security/nss/automation/taskcluster/graph/build.js
security/nss/automation/taskcluster/graph/linux/_build_base.yml
security/nss/automation/taskcluster/graph/linux/_test_base.yml
security/nss/automation/taskcluster/graph/linux/build32-debug.yml
security/nss/automation/taskcluster/graph/linux/build32-opt.yml
security/nss/automation/taskcluster/graph/linux/build64-asan.yml
security/nss/automation/taskcluster/graph/linux/build64-debug.yml
security/nss/automation/taskcluster/graph/linux/build64-memleak.yml
security/nss/automation/taskcluster/graph/linux/build64-opt.yml
security/nss/automation/taskcluster/graph/tests/cert.yml
security/nss/automation/taskcluster/graph/tests/chains.yml
security/nss/automation/taskcluster/graph/tests/cipher.yml
security/nss/automation/taskcluster/graph/tests/crmf.yml
security/nss/automation/taskcluster/graph/tests/db.yml
security/nss/automation/taskcluster/graph/tests/ec.yml
security/nss/automation/taskcluster/graph/tests/fips.yml
security/nss/automation/taskcluster/graph/tests/gtests.yml
security/nss/automation/taskcluster/graph/tests/lowhash.yml
security/nss/automation/taskcluster/graph/tests/memleak.yml
security/nss/automation/taskcluster/graph/tests/merge.yml
security/nss/automation/taskcluster/graph/tests/ocsp.yml
security/nss/automation/taskcluster/graph/tests/pkits.yml
security/nss/automation/taskcluster/graph/tests/pkix.yml
security/nss/automation/taskcluster/graph/tests/sdr.yml
security/nss/automation/taskcluster/graph/tests/smime.yml
security/nss/automation/taskcluster/graph/tests/ssl.yml
security/nss/automation/taskcluster/graph/tests/tools.yml
security/nss/automation/taskcluster/graph/tools/clang-format.yml
security/nss/automation/taskcluster/graph/windows/_build_base.yml
security/nss/automation/taskcluster/graph/windows/_test_base.yml
security/nss/automation/taskcluster/graph/windows/build64-debug.yml
security/nss/automation/taskcluster/graph/windows/build64-opt.yml
security/nss/automation/taskcluster/scripts/build.sh
security/nss/automation/taskcluster/scripts/extend_task_graph.sh
security/nss/automation/taskcluster/scripts/run_clang_format.sh
security/nss/automation/taskcluster/scripts/run_tests.sh
security/nss/automation/taskcluster/windows/build.sh
security/nss/automation/taskcluster/windows/releng.manifest
security/nss/automation/taskcluster/windows/run_tests.sh
security/nss/automation/taskcluster/windows/setup.sh
security/nss/automation/travis/validate-formatting.sh
security/nss/circle.yml
security/nss/cmd/bltest/blapitest.c
security/nss/cmd/crlutil/crlutil.c
security/nss/cmd/ecperf/ecperf.c
security/nss/cmd/ecperf/manifest.mn
security/nss/cmd/manifest.mn
security/nss/cmd/platlibs.mk
security/nss/cmd/tstclnt/tstclnt.c
security/nss/coreconf/coreconf.dep
security/nss/external_tests/common/Makefile
security/nss/external_tests/common/gtest.mk
security/nss/external_tests/common/gtests.cc
security/nss/external_tests/common/manifest.mn
security/nss/external_tests/der_gtest/Makefile
security/nss/external_tests/der_gtest/der_gtest.cc
security/nss/external_tests/der_gtest/manifest.mn
security/nss/external_tests/manifest.mn
security/nss/external_tests/pk11_gtest/Makefile
security/nss/external_tests/pk11_gtest/manifest.mn
security/nss/external_tests/pk11_gtest/pk11_gtest.cc
security/nss/external_tests/ssl_gtest/gtest_utils.h
security/nss/external_tests/ssl_gtest/libssl_internals.c
security/nss/external_tests/ssl_gtest/libssl_internals.h
security/nss/external_tests/ssl_gtest/manifest.mn
security/nss/external_tests/ssl_gtest/ssl_agent_unittest.cc
security/nss/external_tests/ssl_gtest/ssl_ciphersuite_unittest.cc
security/nss/external_tests/ssl_gtest/ssl_extension_unittest.cc
security/nss/external_tests/ssl_gtest/ssl_loopback_unittest.cc
security/nss/external_tests/ssl_gtest/test_io.cc
security/nss/external_tests/ssl_gtest/tls_agent.cc
security/nss/external_tests/ssl_gtest/tls_agent.h
security/nss/external_tests/ssl_gtest/tls_connect.cc
security/nss/external_tests/ssl_gtest/tls_connect.h
security/nss/external_tests/ssl_gtest/tls_filter.cc
security/nss/external_tests/ssl_gtest/tls_filter.h
security/nss/external_tests/ssl_gtest/tls_parser.h
security/nss/external_tests/util_gtest/manifest.mn
security/nss/external_tests/util_gtest/util_gtest.cc
security/nss/lib/base/list.c
security/nss/lib/ckfw/instance.c
security/nss/lib/ckfw/nssckfw.h
security/nss/lib/ckfw/session.c
security/nss/lib/ckfw/slot.c
security/nss/lib/freebl/ec.c
security/nss/lib/freebl/ecdecode.c
security/nss/lib/freebl/mpi/README
security/nss/lib/freebl/mpi/mpcpucache.c
security/nss/lib/freebl/mpi/mpcpucache_x86.s
security/nss/lib/freebl/mpi/mpi-config.h
security/nss/lib/freebl/mpi/mpi-priv.h
security/nss/lib/freebl/mpi/mpi.c
security/nss/lib/nss/nss.h
security/nss/lib/pk11wrap/pk11pk12.c
security/nss/lib/pkcs12/p12dec.c
security/nss/lib/pkcs7/p7decode.c
security/nss/lib/pki/tdcache.c
security/nss/lib/pki/trustdomain.c
security/nss/lib/smime/cmsrecinfo.c
security/nss/lib/smime/cmssiginfo.c
security/nss/lib/softoken/legacydb/lgattr.c
security/nss/lib/softoken/legacydb/lowkey.c
security/nss/lib/softoken/legacydb/lowkeyti.h
security/nss/lib/softoken/legacydb/pcertdb.c
security/nss/lib/softoken/lowkey.c
security/nss/lib/softoken/lowkeyti.h
security/nss/lib/softoken/pkcs11.c
security/nss/lib/softoken/pkcs11c.c
security/nss/lib/softoken/sdb.c
security/nss/lib/softoken/softkver.h
security/nss/lib/ssl/SSLerrs.h
security/nss/lib/ssl/derive.c
security/nss/lib/ssl/dtlscon.c
security/nss/lib/ssl/ssl3con.c
security/nss/lib/ssl/ssl3ecc.c
security/nss/lib/ssl/ssl3ext.c
security/nss/lib/ssl/sslcert.c
security/nss/lib/ssl/sslcert.h
security/nss/lib/ssl/sslenum.c
security/nss/lib/ssl/sslimpl.h
security/nss/lib/ssl/sslinfo.c
security/nss/lib/ssl/sslmutex.c
security/nss/lib/ssl/sslproto.h
security/nss/lib/ssl/sslsnce.c
security/nss/lib/ssl/sslsock.c
security/nss/lib/ssl/sslt.h
security/nss/lib/ssl/ssltrace.c
security/nss/lib/ssl/tls13con.c
security/nss/lib/ssl/tls13con.h
security/nss/lib/ssl/tls13hkdf.c
security/nss/lib/ssl/unix_err.c
security/nss/lib/util/nssutil.h
security/nss/tests/all.sh
security/nss/tests/common/init.sh
security/nss/tests/der_gtests/der_gtests.sh
security/nss/tests/ec/ec.sh
security/nss/tests/ec/ecperf.sh
security/nss/tests/gtests/gtests.sh
security/nss/tests/pk11_gtests/pk11_gtests.sh
security/nss/tests/ssl/ssl.sh
security/nss/tests/ssl/sslcov.txt
security/nss/tests/ssl/sslstress.txt
security/nss/tests/ssl_gtests/ssl_gtests.sh
security/nss/tests/util_gtests/util_gtests.sh
--- a/security/nss/.clang-format
+++ b/security/nss/.clang-format
@@ -10,17 +10,17 @@ AllowAllParametersOfDeclarationOnNextLin
 AllowShortBlocksOnASingleLine: false
 AllowShortCaseLabelsOnASingleLine: false
 AllowShortIfStatementsOnASingleLine: false
 AllowShortLoopsOnASingleLine: false
 AllowShortFunctionsOnASingleLine: All
 AlwaysBreakAfterDefinitionReturnType: true
 AlwaysBreakTemplateDeclarations: false
 AlwaysBreakBeforeMultilineStrings: false
-BreakBeforeBinaryOperators: None
+BreakBeforeBinaryOperators: false
 BreakBeforeTernaryOperators: true
 BreakConstructorInitializersBeforeComma: false
 BinPackParameters: true
 BinPackArguments: true
 ColumnLimit:     0
 ConstructorInitializerAllOnOneLineOrOnePerLine: true
 ConstructorInitializerIndentWidth: 4
 DerivePointerAlignment: true
new file mode 100644
--- /dev/null
+++ b/security/nss/.taskcluster.yml
@@ -0,0 +1,101 @@
+---
+version: 0
+metadata:
+  name: "NSS Continuous Integration"
+  description: "The Taskcluster task graph for the NSS tree"
+  owner: "mozilla-taskcluster-maintenance@mozilla.com"
+  source: {{{source}}}
+
+scopes:
+  # Note the below scopes are insecure however these get overriden on the server
+  # side to whatever scopes are set by mozilla-taskcluster.
+  - queue:*
+  - docker-worker:*
+  - scheduler:*
+
+# Available mustache parameters (see the mozilla-taskcluster source):
+#
+# - owner:          push user (email address)
+# - source:         URL of this YAML file
+# - url:            repository URL
+# - project:        alias for the destination repository (basename of
+#                   the repo url)
+# - level:          SCM level of the destination repository
+#                   (1 = try, 3 = core)
+# - revision:       (short) hg revision of the head of the push
+# - revision_hash:  (long) hg revision of the head of the push
+# - comment:        comment of the push
+# - pushlog_id:     id in the pushlog table of the repository
+#
+# and functions:
+# - as_slugid:      convert a label into a slugId
+# - from_now:       generate a timestamp at a fixed offset from now
+
+tasks:
+  - taskId: '{{#as_slugid}}decision task{{/as_slugid}}'
+    reruns: 3
+    task:
+      created: '{{now}}'
+      deadline: '{{#from_now}}1 day{{/from_now}}'
+      expires: '{{#from_now}}14 days{{/from_now}}'
+
+      metadata:
+        owner: mozilla-taskcluster-maintenance@mozilla.com
+        source: {{{source}}}
+        name: "NSS Decision Task"
+        description: |
+            The task that creates all of the other tasks in the task graph
+
+      workerType: "hg-worker"
+      provisionerId: "aws-provisioner-v1"
+
+      tags:
+        createdForUser: {{owner}}
+
+      scopes:
+        - "queue:route:tc-treeherder-stage.nss.{{revision_hash}}"
+        - "queue:route:tc-treeherder.nss.{{revision_hash}}"
+        - "scheduler:extend-task-graph:*"
+        # mozilla-taskcluster will append the appropriate assume:repo:<repo>
+        # scope here.
+
+      routes:
+        - "tc-treeherder-stage.nss.{{revision_hash}}"
+        - "tc-treeherder.nss.{{revision_hash}}"
+
+      payload:
+        image: "ttaubert/nss-ci:0.0.16"
+
+        env:
+          TC_OWNER: {{owner}}
+          TC_SOURCE: {{{source}}}
+          TC_REVISION: '{{revision}}'
+          TC_REVISION_HASH: '{{revision_hash}}'
+          NSS_HEAD_REPOSITORY: '{{{url}}}'
+          NSS_HEAD_REVISION: '{{revision}}'
+
+        maxRunTime: 1800
+
+        command:
+          - bash
+          - -cx
+          - >
+            bin/checkout.sh &&
+            nss/automation/taskcluster/scripts/extend_task_graph.sh
+
+        artifacts:
+          public:
+            type: "directory"
+            path: "/home/worker/artifacts"
+            expires: "{{#from_now}}7 days{{/from_now}}"
+
+        graphs:
+          - /home/worker/artifacts/graph.json
+
+      extra:
+        treeherder:
+          symbol: D
+          revision: '{{revision}}'
+          revision_hash: '{{revision_hash}}'
+          build:
+            platform: nss-decision
new file mode 100644
--- /dev/null
+++ b/security/nss/.travis.yml
@@ -0,0 +1,75 @@
+sudo: required
+dist: trusty
+
+addons:
+  apt:
+    sources:
+    # add PPAs with more up-to-date toolchains
+    - ubuntu-toolchain-r-test
+    - llvm-toolchain-precise-3.8
+    packages:
+    # install toolchains
+    - gcc-5
+    - g++-5
+    - clang-3.8
+    # install additional tools
+    - clang-format-3.8
+
+matrix:
+  include:
+    - os: osx
+      compiler: clang-3.8
+      env:
+        - CC=clang-3.8
+        - CCC=clang++-3.8
+    - os: osx
+      compiler: clang-3.8
+      env:
+        - CC=clang-3.8
+        - CCC=clang++-3.8
+        - BUILD_OPT=1
+    - os: linux
+      compiler: gcc
+      env:
+        - CC=gcc-5
+        - CCC=g++-5
+    - os: linux
+      compiler: gcc
+      env:
+        - CC=gcc-5
+        - CCC=g++-5
+        - BUILD_OPT=1
+    - os: linux
+      compiler: gcc
+      env:
+        - CC=gcc-5
+        - CCC=g++-5
+        - USE_ASAN=1
+    - os: linux
+      env: CLANG_FORMAT=1
+  allow_failures:
+    - env: CLANG_FORMAT=1
+
+env:
+  global:
+    - USE_64=1
+    - NSS_ENABLE_TLS_1_3=1
+
+install:
+  - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew update; brew install llvm38; fi
+
+before_script:
+  - hg clone https://hg.mozilla.org/projects/nspr ../nspr
+
+script:
+  - if [ -n "$CLANG_FORMAT" ]; then automation/travis/validate-formatting.sh lib/ssl; exit $?; fi
+  - make nss_build_all
+  - cd tests; NSS_TESTS="ssl_gtests gtests" NSS_CYCLES=standard ./all.sh
+
+notifications:
+  irc:
+    channels:
+      - "irc.mozilla.org:6697/#nssbot"
+    nick: travisci
+    on_success: change
+    on_failure: always
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-NSS_3_24_RTM
+NSS_3_25_BETA1
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/docker/Dockerfile
@@ -0,0 +1,27 @@
+FROM ubuntu:16.04
+MAINTAINER Tim Taubert <ttaubert@mozilla.com>
+
+RUN useradd -d /home/worker -s /bin/bash -m worker
+WORKDIR /home/worker
+
+# Install non-build specific dependencies.
+ADD setup.sh /tmp/setup.sh
+RUN bash /tmp/setup.sh
+
+# Add build and test scripts.
+ADD bin /home/worker/bin
+RUN chmod +x /home/worker/bin/*
+
+# Set variables usually configured at login.
+ENV HOME /home/worker
+ENV SHELL /bin/bash
+ENV USER worker
+ENV LOGNAME worker
+ENV HOSTNAME taskcluster-worker
+ENV LANG en_US.UTF-8
+ENV LC_ALL en_US.UTF-8
+env HOST localhost
+env DOMSUF localdomain
+
+# Set a default command for debugging.
+CMD ["/bin/bash", "--login"]
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/docker/bin/checkout.sh
@@ -0,0 +1,15 @@
+#!/usr/bin/env bash
+
+set -v -e -x
+
+if [ $(id -u) = 0 ]; then
+    # Drop privileges by re-running this script.
+    exec su worker $0
+fi
+
+# Default values for testing.
+REVISION=${NSS_HEAD_REVISION:-default}
+REPOSITORY=${NSS_HEAD_REPOSITORY:-https://hg.mozilla.org/projects/nss}
+
+# Clone NSS.
+hg clone -r $REVISION $REPOSITORY nss
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/docker/setup.sh
@@ -0,0 +1,71 @@
+#!/usr/bin/env bash
+
+set -v -e -x
+
+apt_packages=()
+apt_packages+=('build-essential')
+apt_packages+=('ca-certificates')
+apt_packages+=('curl')
+apt_packages+=('mercurial')
+apt_packages+=('npm')
+apt_packages+=('git')
+apt_packages+=('valgrind')
+apt_packages+=('zlib1g-dev')
+
+# 32-bit builds
+apt_packages+=('lib32z1-dev')
+apt_packages+=('gcc-multilib')
+apt_packages+=('g++-multilib')
+
+# Install prerequisites.
+apt-get -y update
+export DEBIAN_FRONTEND=noninteractive
+apt-get install -y --no-install-recommends curl apt-utils
+
+# clang(-format)-3.8
+apt_packages+=('clang-3.8')
+apt_packages+=('clang-format-3.8')
+curl http://llvm.org/apt/llvm-snapshot.gpg.key | apt-key add -
+echo "deb http://llvm.org/apt/xenial/ llvm-toolchain-xenial-3.8 main" > /etc/apt/sources.list.d/docker.list
+
+# Install the first round of packages.
+apt-get -y update
+apt-get install -y --no-install-recommends ${apt_packages[@]}
+
+# gcc 6
+apt_packages=()
+apt_packages+=('g++-6')
+apt_packages+=('g++-4.8')
+apt_packages+=('g++-6-multilib')
+apt_packages+=('g++-4.8-multilib')
+apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 60C317803A41BA51845E371A1E9377A2BA9EF27F
+echo "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu xenial main" > /etc/apt/sources.list.d/toolchain.list
+
+# Install the second round of packages.
+apt-get -y update
+apt-get install -y --no-install-recommends ${apt_packages[@]}
+
+# 32-bit builds
+ln -s /usr/include/x86_64-linux-gnu/zconf.h /usr/include
+
+# Compiler options.
+update-alternatives --install /usr/bin/gcc gcc /usr/bin/clang-3.8 5
+update-alternatives --install /usr/bin/g++ g++ /usr/bin/clang++-3.8 5
+update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 10
+update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 10
+update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-6 20
+update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-6 20
+update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-5 30
+update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-5 30
+
+locale-gen en_US.UTF-8
+dpkg-reconfigure locales
+
+# Install required Node modules.
+su -c "npm install flatmap js-yaml merge slugid" worker
+
+# Cleanup.
+rm -rf ~/.ccache ~/.cache
+apt-get clean
+apt-get autoclean
+rm $0
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/build.js
@@ -0,0 +1,184 @@
+/* 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/. */
+
+var fs = require("fs");
+var path = require("path");
+var merge = require("merge");
+var yaml = require("js-yaml");
+var slugid = require("slugid");
+var flatmap = require("flatmap");
+
+// Default values for debugging.
+var TC_REVISION = process.env.TC_REVISION || "{{tc_rev}}";
+var TC_REVISION_HASH = process.env.TC_REVISION_HASH || "{{tc_rev_hash}}";
+var TC_OWNER = process.env.TC_OWNER || "{{tc_owner}}";
+var TC_SOURCE = process.env.TC_SOURCE || "{{tc_source}}";
+var NSS_HEAD_REPOSITORY = process.env.NSS_HEAD_REPOSITORY || "{{nss_head_repo}}";
+var NSS_HEAD_REVISION = process.env.NSS_HEAD_REVISION || "{{nss_head_rev}}";
+
+// Register custom YAML types.
+var YAML_SCHEMA = yaml.Schema.create([
+  // Point in time at $now + x hours.
+  new yaml.Type('!from_now', {
+    kind: "scalar",
+
+    resolve: function (data) {
+      return true;
+    },
+
+    construct: function (data) {
+      var d = new Date();
+      d.setHours(d.getHours() + (data|0));
+      return d.toJSON();
+    }
+  }),
+
+  // Environment variables.
+  new yaml.Type('!env', {
+    kind: "scalar",
+
+    resolve: function (data) {
+      return true;
+    },
+
+    construct: function (data) {
+      return process.env[data];
+    }
+  })
+]);
+
+// Parse a given YAML file.
+function parseYamlFile(file, fallback) {
+  // Return fallback if the file doesn't exist.
+  if (!fs.existsSync(file) && fallback) {
+    return fallback;
+  }
+
+  // Otherwise, read the file or fail.
+  var source = fs.readFileSync(file, "utf-8");
+  return yaml.load(source, {schema: YAML_SCHEMA});
+}
+
+// Add base information to the given task.
+function decorateTask(task) {
+  // Assign random task id.
+  task.taskId = slugid.v4();
+
+  // Permissions.
+  task.task.scopes = [
+    "queue:route:tc-treeherder-stage.nss." + TC_REVISION_HASH,
+    "queue:route:tc-treeherder.nss." + TC_REVISION_HASH,
+    "scheduler:extend-task-graph:*"
+  ];
+
+  // TreeHerder routes.
+  task.task.routes = [
+    "tc-treeherder-stage.nss." + TC_REVISION_HASH,
+    "tc-treeherder.nss." + TC_REVISION_HASH
+  ];
+}
+
+// Generate all tasks for a given build.
+function generateBuildTasks(platform, file) {
+  var dir = path.join(__dirname, "./" + platform);
+
+  // Parse base definitions.
+  var buildBase = parseYamlFile(path.join(dir, "_build_base.yml"), {});
+  var testBase = parseYamlFile(path.join(dir, "_test_base.yml"), {});
+
+  return flatmap(parseYamlFile(path.join(dir, file)), function (task) {
+    // Merge base build task definition with the current one.
+    var tasks = [task = merge.recursive(true, buildBase, task)];
+
+    // Add base info.
+    decorateTask(task);
+
+    // Generate test tasks.
+    if (task.tests) {
+      // The base definition for all tests of this platform.
+      var base = merge.recursive(true, {
+        requires: [task.taskId],
+
+        task: {
+          payload: {
+            env: {
+              TC_PARENT_TASK_ID: task.taskId
+            }
+          }
+        }
+      }, testBase);
+
+      // Generate and append test task definitions.
+      tasks = tasks.concat(flatmap(task.tests, function (name) {
+        return generateTestTasks(name, base, task);
+      }));
+
+      // |tests| is not part of the schema.
+      delete task.tests;
+    }
+
+    return tasks;
+  });
+}
+
+// Generate all tasks for a given test.
+function generateTestTasks(name, base, task) {
+  // Load test definitions.
+  var dir = path.join(__dirname, "./tests");
+  var tests = parseYamlFile(path.join(dir, name + ".yml"));
+
+  return tests.map(function (test) {
+    // Merge test with base definition.
+    test = merge.recursive(true, base, test);
+
+    // Add base info.
+    decorateTask(test);
+
+    // We only want to carry over environment variables...
+    test.task.payload.env =
+      merge.recursive(true, task.task.payload.env,
+                            test.task.payload.env);
+
+    // ...and TreeHerder configuration data.
+    test.task.extra.treeherder =
+      merge.recursive(true, task.task.extra.treeherder,
+                            test.task.extra.treeherder);
+
+    return test;
+  });
+}
+
+// Generate all tasks for a given platform.
+function generatePlatformTasks(platform) {
+  var dir = path.join(__dirname, "./" + platform);
+  var buildBase = parseYamlFile(path.join(dir, "_build_base.yml"), {});
+  var testBase = parseYamlFile(path.join(dir, "_test_base.yml"), {});
+
+  // Parse all build tasks.
+  return flatmap(fs.readdirSync(dir), function (file) {
+    if (!file.startsWith("_") && file.endsWith(".yml")) {
+      var tasks = generateBuildTasks(platform, file);
+
+      // Convert env variables to strings.
+      tasks.forEach(function (task) {
+        var env = task.task.payload.env || {};
+        Object.keys(env).forEach(function (name) {
+          if (typeof(env[name]) != "undefined") {
+            env[name] = env[name] + "";
+          }
+        });
+      });
+
+      return tasks;
+    }
+  });
+}
+
+// Construct the task graph.
+var graph = {
+  tasks: flatmap(["linux", "windows", "tools"], generatePlatformTasks)
+};
+
+// Output the final graph.
+process.stdout.write(JSON.stringify(graph, null, 2));
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/linux/_build_base.yml
@@ -0,0 +1,40 @@
+---
+reruns: 2
+
+task:
+  created: !from_now 0
+  deadline: !from_now 24
+  provisionerId: aws-provisioner-v1
+  workerType: hg-worker
+  schedulerId: task-graph-scheduler
+
+  metadata:
+    owner: !env TC_OWNER
+    source: !env TC_SOURCE
+
+  payload:
+    maxRunTime: 3600
+    image: ttaubert/nss-ci:0.0.16
+
+    artifacts:
+      public:
+        type: directory
+        path: /home/worker/artifacts
+        expires: !from_now 24
+
+    command:
+      - "/bin/bash"
+      - "-c"
+      - "bin/checkout.sh && nss/automation/taskcluster/scripts/build.sh"
+
+    env:
+      NSS_HEAD_REPOSITORY: !env NSS_HEAD_REPOSITORY
+      NSS_HEAD_REVISION: !env NSS_HEAD_REVISION
+      GCC_VERSION: gcc-5
+      GXX_VERSION: g++-5
+
+  extra:
+    treeherder:
+      revision: !env TC_REVISION
+      revision_hash: !env TC_REVISION_HASH
+      symbol: B
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/linux/_test_base.yml
@@ -0,0 +1,22 @@
+---
+reruns: 2
+
+task:
+  created: !from_now 0
+  deadline: !from_now 24
+  provisionerId: aws-provisioner-v1
+  workerType: hg-worker
+  schedulerId: task-graph-scheduler
+
+  metadata:
+    owner: !env TC_OWNER
+    source: !env TC_SOURCE
+
+  payload:
+    maxRunTime: 3600
+    image: ttaubert/nss-ci:0.0.16
+
+    command:
+      - "/bin/bash"
+      - "-c"
+      - "bin/checkout.sh && nss/automation/taskcluster/scripts/run_tests.sh"
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/linux/build32-debug.yml
@@ -0,0 +1,139 @@
+---
+- task:
+    metadata:
+      name: "Linux 32 (debug)"
+      description: "Linux 32 (debug)"
+
+    payload:
+      env:
+        NSS_ENABLE_TLS_1_3: 1
+
+    extra:
+      treeherder:
+        build:
+          platform: linux32
+        collection:
+          debug: true
+
+  tests:
+    - cert
+    - chains
+    - cipher
+    - crmf
+    - db
+    - ec
+    - fips
+    - gtests
+    - lowhash
+    - merge
+    - ocsp
+    - pkits
+    - pkix
+    - sdr
+    - smime
+    - tools
+
+- task:
+    metadata:
+      name: "Linux 32 (debug, no TLS 1.3)"
+      description: "Linux 32 (debug, no TLS 1.3)"
+
+    payload:
+      env:
+        NSS_TESTS: ssl
+
+    extra:
+      treeherder:
+        build:
+          platform: linux32
+        collection:
+          debug: true
+        groupSymbol: Builds
+        groupName: Various builds
+        symbol: noTLSv1.3
+
+  tests:
+    - ssl
+
+- task:
+    metadata:
+      name: "Linux 32 (debug, clang-3.8)"
+      description: "Linux 32 (debug, clang-3.8)"
+
+    payload:
+      env:
+        NSS_ENABLE_TLS_1_3: 1
+        GCC_VERSION: clang-3.8
+        GXX_VERSION: clang++-3.8
+
+    extra:
+      treeherder:
+        build:
+          platform: linux32
+        collection:
+          debug: true
+        groupSymbol: Builds
+        groupName: Various builds
+        symbol: clang-3.8
+
+- task:
+    metadata:
+      name: "Linux 32 (debug, gcc-4.8)"
+      description: "Linux 32 (debug, gcc-4.8)"
+
+    payload:
+      env:
+        NSS_ENABLE_TLS_1_3: 1
+        GCC_VERSION: gcc-4.8
+        GXX_VERSION: g++-4.8
+
+    extra:
+      treeherder:
+        build:
+          platform: linux32
+        collection:
+          debug: true
+        groupSymbol: Builds
+        groupName: Various builds
+        symbol: gcc-4.8
+
+- task:
+    metadata:
+      name: "Linux 32 (debug, gcc-6.1)"
+      description: "Linux 32 (debug, gcc-6.1)"
+
+    payload:
+      env:
+        NSS_ENABLE_TLS_1_3: 1
+        GCC_VERSION: gcc-6
+        GXX_VERSION: g++-6
+
+    extra:
+      treeherder:
+        build:
+          platform: linux32
+        collection:
+          debug: true
+        groupSymbol: Builds
+        groupName: Various builds
+        symbol: gcc-6.1
+
+- task:
+    metadata:
+      name: "Linux 32 (debug, NO_PKCS11_BYPASS=1)"
+      description: "Linux 32 (debug, NO_PKCS11_BYPASS=1)"
+
+    payload:
+      env:
+        NSS_ENABLE_TLS_1_3: 1
+        NO_PKCS11_BYPASS: 1
+
+    extra:
+      treeherder:
+        build:
+          platform: linux32
+        collection:
+          debug: true
+        groupSymbol: Builds
+        groupName: Various builds
+        symbol: noPkcs11Bypass
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/linux/build32-opt.yml
@@ -0,0 +1,145 @@
+---
+- task:
+    metadata:
+      name: "Linux 32 (opt)"
+      description: "Linux 32 (opt)"
+
+    payload:
+      env:
+        NSS_ENABLE_TLS_1_3: 1
+        BUILD_OPT: 1
+
+    extra:
+      treeherder:
+        build:
+          platform: linux32
+        collection:
+          opt: true
+
+  tests:
+    - cert
+    - chains
+    - cipher
+    - crmf
+    - db
+    - ec
+    - fips
+    - gtests
+    - lowhash
+    - merge
+    - ocsp
+    - pkits
+    - pkix
+    - sdr
+    - smime
+    - tools
+
+- task:
+    metadata:
+      name: "Linux 32 (opt, no TLS 1.3)"
+      description: "Linux 32 (opt, no TLS 1.3)"
+
+    payload:
+      env:
+        NSS_TESTS: ssl
+        BUILD_OPT: 1
+
+    extra:
+      treeherder:
+        build:
+          platform: linux32
+        collection:
+          opt: true
+        groupSymbol: Builds
+        groupName: Various builds
+        symbol: noTLSv1.3
+
+  tests:
+    - ssl
+
+- task:
+    metadata:
+      name: "Linux 32 (opt, clang-3.8)"
+      description: "Linux 32 (opt, clang-3.8)"
+
+    payload:
+      env:
+        NSS_ENABLE_TLS_1_3: 1
+        GCC_VERSION: clang-3.8
+        GXX_VERSION: clang++-3.8
+        BUILD_OPT: 1
+
+    extra:
+      treeherder:
+        build:
+          platform: linux32
+        collection:
+          opt: true
+        groupSymbol: Builds
+        groupName: Various builds
+        symbol: clang-3.8
+
+- task:
+    metadata:
+      name: "Linux 32 (opt, gcc-4.8)"
+      description: "Linux 32 (opt, gcc-4.8)"
+
+    payload:
+      env:
+        NSS_ENABLE_TLS_1_3: 1
+        GCC_VERSION: gcc-4.8
+        GXX_VERSION: g++-4.8
+        BUILD_OPT: 1
+
+    extra:
+      treeherder:
+        build:
+          platform: linux32
+        collection:
+          opt: true
+        groupSymbol: Builds
+        groupName: Various builds
+        symbol: gcc-4.8
+
+- task:
+    metadata:
+      name: "Linux 32 (opt, gcc-6.1)"
+      description: "Linux 32 (opt, gcc-6.1)"
+
+    payload:
+      env:
+        NSS_ENABLE_TLS_1_3: 1
+        GCC_VERSION: gcc-6
+        GXX_VERSION: g++-6
+        BUILD_OPT: 1
+
+    extra:
+      treeherder:
+        build:
+          platform: linux32
+        collection:
+          opt: true
+        groupSymbol: Builds
+        groupName: Various builds
+        symbol: gcc-6.1
+
+- task:
+    metadata:
+      name: "Linux 32 (opt, NO_PKCS11_BYPASS=1)"
+      description: "Linux 32 (opt, NO_PKCS11_BYPASS=1)"
+
+    payload:
+      env:
+        NSS_ENABLE_TLS_1_3: 1
+        NO_PKCS11_BYPASS: 1
+        BUILD_OPT: 1
+
+    extra:
+      treeherder:
+        build:
+          platform: linux32
+        collection:
+          opt: true
+        groupSymbol: Builds
+        groupName: Various builds
+        symbol: noPkcs11Bypass
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/linux/build64-asan.yml
@@ -0,0 +1,63 @@
+---
+- task:
+    metadata:
+      name: "Linux 64 (ASan, debug)"
+      description: "Linux 64 (ASan, debug)"
+
+    payload:
+      env:
+        NSS_ENABLE_TLS_1_3: 1
+        GCC_VERSION: clang-3.8
+        GXX_VERSION: clang++-3.8
+        USE_ASAN: 1
+        USE_64: 1
+
+    extra:
+      treeherder:
+        build:
+          platform: linux64
+        collection:
+          asan: true
+
+  tests:
+    - cert
+    - chains
+    - cipher
+    - crmf
+    - db
+    - ec
+    - fips
+    - gtests
+    - lowhash
+    - merge
+    - ocsp
+    - pkits
+    - pkix
+    - sdr
+    - smime
+    - tools
+
+- task:
+    metadata:
+      name: "Linux 64 (ASan, debug, no TLS 1.3)"
+      description: "Linux 64 (ASan, debug, no TLS 1.3)"
+
+    payload:
+      env:
+        GCC_VERSION: clang-3.8
+        GXX_VERSION: clang++-3.8
+        NSS_TESTS: ssl
+        USE_ASAN: 1
+        USE_64: 1
+
+    extra:
+      treeherder:
+        build:
+          platform: linux64
+        collection:
+          asan: true
+        groupSymbol: SSL
+        groupName: SSL tests
+
+  tests:
+    - ssl
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/linux/build64-debug.yml
@@ -0,0 +1,145 @@
+---
+- task:
+    metadata:
+      name: "Linux 64 (debug)"
+      description: "Linux 64 (debug)"
+
+    payload:
+      env:
+        NSS_ENABLE_TLS_1_3: 1
+        USE_64: 1
+
+    extra:
+      treeherder:
+        build:
+          platform: linux64
+        collection:
+          debug: true
+
+  tests:
+    - cert
+    - chains
+    - cipher
+    - crmf
+    - db
+    - ec
+    - fips
+    - gtests
+    - lowhash
+    - merge
+    - ocsp
+    - pkits
+    - pkix
+    - sdr
+    - smime
+    - tools
+
+- task:
+    metadata:
+      name: "Linux 64 (debug, no TLS 1.3)"
+      description: "Linux 64 (debug, no TLS 1.3)"
+
+    payload:
+      env:
+        NSS_TESTS: ssl
+        USE_64: 1
+
+    extra:
+      treeherder:
+        build:
+          platform: linux64
+        collection:
+          debug: true
+        groupSymbol: Builds
+        groupName: Various builds
+        symbol: noTLSv1.3
+
+  tests:
+    - ssl
+
+- task:
+    metadata:
+      name: "Linux 64 (debug, clang-3.8)"
+      description: "Linux 64 (debug, clang-3.8)"
+
+    payload:
+      env:
+        NSS_ENABLE_TLS_1_3: 1
+        GCC_VERSION: clang-3.8
+        GXX_VERSION: clang++-3.8
+        USE_64: 1
+
+    extra:
+      treeherder:
+        build:
+          platform: linux64
+        collection:
+          debug: true
+        groupSymbol: Builds
+        groupName: Various builds
+        symbol: clang-3.8
+
+- task:
+    metadata:
+      name: "Linux 64 (debug, gcc-4.8)"
+      description: "Linux 64 (debug, gcc-4.8)"
+
+    payload:
+      env:
+        NSS_ENABLE_TLS_1_3: 1
+        GCC_VERSION: gcc-4.8
+        GXX_VERSION: g++-4.8
+        USE_64: 1
+
+    extra:
+      treeherder:
+        build:
+          platform: linux64
+        collection:
+          debug: true
+        groupSymbol: Builds
+        groupName: Various builds
+        symbol: gcc-4.8
+
+- task:
+    metadata:
+      name: "Linux 64 (debug, gcc-6.1)"
+      description: "Linux 64 (debug, gcc-6.1)"
+
+    payload:
+      env:
+        NSS_ENABLE_TLS_1_3: 1
+        GCC_VERSION: gcc-6
+        GXX_VERSION: g++-6
+        USE_64: 1
+
+    extra:
+      treeherder:
+        build:
+          platform: linux64
+        collection:
+          debug: true
+        groupSymbol: Builds
+        groupName: Various builds
+        symbol: gcc-6.1
+
+- task:
+    metadata:
+      name: "Linux 64 (debug, NO_PKCS11_BYPASS=1)"
+      description: "Linux 64 (debug, NO_PKCS11_BYPASS=1)"
+
+    payload:
+      env:
+        NSS_ENABLE_TLS_1_3: 1
+        NO_PKCS11_BYPASS: 1
+        USE_64: 1
+
+    extra:
+      treeherder:
+        build:
+          platform: linux64
+        collection:
+          debug: true
+        groupSymbol: Builds
+        groupName: Various builds
+        symbol: noPkcs11Bypass
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/linux/build64-memleak.yml
@@ -0,0 +1,20 @@
+---
+- task:
+    metadata:
+      name: "Linux 64 (MemLeak, debug)"
+      description: "Linux 64 (MemLeak, debug)"
+
+    payload:
+      env:
+        NSS_TESTS: memleak
+        USE_64: 1
+
+    extra:
+      treeherder:
+        build:
+          platform: linux64
+        collection:
+          memleak: true
+
+  tests:
+    - memleak
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/linux/build64-opt.yml
@@ -0,0 +1,151 @@
+---
+- task:
+    metadata:
+      name: "Linux 64 (opt)"
+      description: "Linux 64 (opt)"
+
+    payload:
+      env:
+        NSS_ENABLE_TLS_1_3: 1
+        BUILD_OPT: 1
+        USE_64: 1
+
+    extra:
+      treeherder:
+        build:
+          platform: linux64
+        collection:
+          opt: true
+
+  tests:
+    - cert
+    - chains
+    - cipher
+    - crmf
+    - db
+    - ec
+    - fips
+    - gtests
+    - lowhash
+    - merge
+    - ocsp
+    - pkits
+    - pkix
+    - sdr
+    - smime
+    - tools
+
+- task:
+    metadata:
+      name: "Linux 64 (opt, no TLS 1.3)"
+      description: "Linux 64 (opt, no TLS 1.3)"
+
+    payload:
+      env:
+        NSS_TESTS: ssl
+        BUILD_OPT: 1
+        USE_64: 1
+
+    extra:
+      treeherder:
+        build:
+          platform: linux64
+        collection:
+          opt: true
+        groupSymbol: Builds
+        groupName: Various builds
+        symbol: noTLSv1.3
+
+  tests:
+    - ssl
+
+- task:
+    metadata:
+      name: "Linux 64 (opt, clang-3.8)"
+      description: "Linux 64 (opt, clang-3.8)"
+
+    payload:
+      env:
+        NSS_ENABLE_TLS_1_3: 1
+        GCC_VERSION: clang-3.8
+        GXX_VERSION: clang++-3.8
+        BUILD_OPT: 1
+        USE_64: 1
+
+    extra:
+      treeherder:
+        build:
+          platform: linux64
+        collection:
+          opt: true
+        groupSymbol: Builds
+        groupName: Various builds
+        symbol: clang-3.8
+
+- task:
+    metadata:
+      name: "Linux 64 (opt, gcc-4.8)"
+      description: "Linux 64 (opt, gcc-4.8)"
+
+    payload:
+      env:
+        NSS_ENABLE_TLS_1_3: 1
+        GCC_VERSION: gcc-4.8
+        GXX_VERSION: g++-4.8
+        BUILD_OPT: 1
+        USE_64: 1
+
+    extra:
+      treeherder:
+        build:
+          platform: linux64
+        collection:
+          opt: true
+        groupSymbol: Builds
+        groupName: Various builds
+        symbol: gcc-4.8
+
+- task:
+    metadata:
+      name: "Linux 64 (opt, gcc-6.1)"
+      description: "Linux 64 (opt, gcc-6.1)"
+
+    payload:
+      env:
+        NSS_ENABLE_TLS_1_3: 1
+        GCC_VERSION: gcc-6
+        GXX_VERSION: g++-6
+        BUILD_OPT: 1
+        USE_64: 1
+
+    extra:
+      treeherder:
+        build:
+          platform: linux64
+        collection:
+          opt: true
+        groupSymbol: Builds
+        groupName: Various builds
+        symbol: gcc-6.1
+
+- task:
+    metadata:
+      name: "Linux 64 (opt, NO_PKCS11_BYPASS=1)"
+      description: "Linux 64 (opt, NO_PKCS11_BYPASS=1)"
+
+    payload:
+      env:
+        NSS_ENABLE_TLS_1_3: 1
+        NO_PKCS11_BYPASS: 1
+        BUILD_OPT: 1
+        USE_64: 1
+
+    extra:
+      treeherder:
+        build:
+          platform: linux64
+        collection:
+          opt: true
+        groupSymbol: Builds
+        groupName: Various builds
+        symbol: noPkcs11Bypass
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/tests/cert.yml
@@ -0,0 +1,13 @@
+---
+- task:
+    metadata:
+      name: Cert tests
+      description: Cert tests
+
+    payload:
+      env:
+        NSS_TESTS: cert
+
+    extra:
+      treeherder:
+        symbol: Cert
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/tests/chains.yml
@@ -0,0 +1,13 @@
+---
+- task:
+    metadata:
+      name: Chains tests
+      description: Chains tests
+
+    payload:
+      env:
+        NSS_TESTS: chains
+
+    extra:
+      treeherder:
+        symbol: Chains
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/tests/cipher.yml
@@ -0,0 +1,13 @@
+---
+- task:
+    metadata:
+      name: Cipher tests
+      description: Cipher tests
+
+    payload:
+      env:
+        NSS_TESTS: cipher
+
+    extra:
+      treeherder:
+        symbol: Cipher
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/tests/crmf.yml
@@ -0,0 +1,13 @@
+---
+- task:
+    metadata:
+      name: CRMF tests
+      description: CRMF tests
+
+    payload:
+      env:
+        NSS_TESTS: crmf
+
+    extra:
+      treeherder:
+        symbol: CRMF
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/tests/db.yml
@@ -0,0 +1,13 @@
+---
+- task:
+    metadata:
+      name: DB tests
+      description: DB tests
+
+    payload:
+      env:
+        NSS_TESTS: dbtests
+
+    extra:
+      treeherder:
+        symbol: DB
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/tests/ec.yml
@@ -0,0 +1,13 @@
+---
+- task:
+    metadata:
+      name: EC tests
+      description: EC tests
+
+    payload:
+      env:
+        NSS_TESTS: ec
+
+    extra:
+      treeherder:
+        symbol: EC
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/tests/fips.yml
@@ -0,0 +1,13 @@
+---
+- task:
+    metadata:
+      name: FIPS tests
+      description: FIPS tests
+
+    payload:
+      env:
+        NSS_TESTS: fips
+
+    extra:
+      treeherder:
+        symbol: FIPS
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/tests/gtests.yml
@@ -0,0 +1,13 @@
+---
+- task:
+    metadata:
+      name: GTests
+      description: GTests
+
+    payload:
+      env:
+        NSS_TESTS: ssl_gtests gtests
+
+    extra:
+      treeherder:
+        symbol: GTest
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/tests/lowhash.yml
@@ -0,0 +1,13 @@
+---
+- task:
+    metadata:
+      name: Lowhash tests
+      description: Lowhash tests
+
+    payload:
+      env:
+        NSS_TESTS: lowhash
+
+    extra:
+      treeherder:
+        symbol: Lowhash
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/tests/memleak.yml
@@ -0,0 +1,205 @@
+---
+- task:
+    metadata:
+      name: "MemLeak tests (ocsp)"
+      description: "MemLeak tests (ocsp)"
+
+    payload:
+      env:
+        NSS_MEMLEAK_TESTS: ocsp
+
+    extra:
+      treeherder:
+        symbol: ocsp
+
+- task:
+    metadata:
+      name: "MemLeak tests (ssl_server, standard)"
+      description: "MemLeak tests (ssl_server, standard)"
+
+    payload:
+      env:
+        NSS_MEMLEAK_TESTS: "ssl_server"
+        NSS_CYCLES: "standard"
+
+    extra:
+      treeherder:
+        groupSymbol: Server
+        groupName: MemLeak tests (ssl_server)
+        symbol: standard
+
+- task:
+    metadata:
+      name: "MemLeak tests (ssl_server, pkix)"
+      description: "MemLeak tests (ssl_server, pkix)"
+
+    payload:
+      env:
+        NSS_MEMLEAK_TESTS: "ssl_server"
+        NSS_CYCLES: "pkix"
+
+    extra:
+      treeherder:
+        groupSymbol: Server
+        groupName: MemLeak tests (ssl_server)
+        symbol: pkix
+
+- task:
+    metadata:
+      name: "MemLeak tests (ssl_server, sharedb)"
+      description: "MemLeak tests (ssl_server, sharedb)"
+
+    payload:
+      env:
+        NSS_MEMLEAK_TESTS: "ssl_server"
+        NSS_CYCLES: "sharedb"
+
+    extra:
+      treeherder:
+        groupSymbol: Server
+        groupName: MemLeak tests (ssl_server)
+        symbol: sharedb
+
+- task:
+    metadata:
+      name: "MemLeak tests (ssl_server, upgradedb)"
+      description: "MemLeak tests (ssl_server, upgradedb)"
+
+    payload:
+      env:
+        NSS_MEMLEAK_TESTS: "ssl_server"
+        NSS_CYCLES: "upgradedb"
+
+    extra:
+      treeherder:
+        groupSymbol: Server
+        groupName: MemLeak tests (ssl_server)
+        symbol: upgradedb
+
+- task:
+    metadata:
+      name: "MemLeak tests (ssl_client, standard)"
+      description: "MemLeak tests (ssl_client, standard)"
+
+    payload:
+      env:
+        NSS_MEMLEAK_TESTS: "ssl_client"
+        NSS_CYCLES: "standard"
+
+    extra:
+      treeherder:
+        groupSymbol: Client
+        groupName: MemLeak tests (ssl_client)
+        symbol: standard
+
+- task:
+    metadata:
+      name: "MemLeak tests (ssl_client, pkix)"
+      description: "MemLeak tests (ssl_client, pkix)"
+
+    payload:
+      env:
+        NSS_MEMLEAK_TESTS: "ssl_client"
+        NSS_CYCLES: "pkix"
+
+    extra:
+      treeherder:
+        groupSymbol: Client
+        groupName: MemLeak tests (ssl_client)
+        symbol: pkix
+
+- task:
+    metadata:
+      name: "MemLeak tests (ssl_client, sharedb)"
+      description: "MemLeak tests (ssl_client, sharedb)"
+
+    payload:
+      env:
+        NSS_MEMLEAK_TESTS: "ssl_client"
+        NSS_CYCLES: "sharedb"
+
+    extra:
+      treeherder:
+        groupSymbol: Client
+        groupName: MemLeak tests (ssl_client)
+        symbol: sharedb
+
+- task:
+    metadata:
+      name: "MemLeak tests (ssl_client, upgradedb)"
+      description: "MemLeak tests (ssl_client, upgradedb)"
+
+    payload:
+      env:
+        NSS_MEMLEAK_TESTS: "ssl_client"
+        NSS_CYCLES: "upgradedb"
+
+    extra:
+      treeherder:
+        groupSymbol: Client
+        groupName: MemLeak tests (ssl_client)
+        symbol: upgradedb
+
+- task:
+    metadata:
+      name: "MemLeak tests (chains, standard)"
+      description: "MemLeak tests (chains, standard)"
+
+    payload:
+      env:
+        NSS_MEMLEAK_TESTS: "chains"
+        NSS_CYCLES: "standard"
+
+    extra:
+      treeherder:
+        groupSymbol: Chains
+        groupName: MemLeak tests (chains)
+        symbol: standard
+
+- task:
+    metadata:
+      name: "MemLeak tests (chains, pkix)"
+      description: "MemLeak tests (chains, pkix)"
+
+    payload:
+      env:
+        NSS_MEMLEAK_TESTS: "chains"
+        NSS_CYCLES: "pkix"
+
+    extra:
+      treeherder:
+        groupSymbol: Chains
+        groupName: MemLeak tests (chains)
+        symbol: pkix
+
+- task:
+    metadata:
+      name: "MemLeak tests (chains, sharedb)"
+      description: "MemLeak tests (chains, sharedb)"
+
+    payload:
+      env:
+        NSS_MEMLEAK_TESTS: "chains"
+        NSS_CYCLES: "sharedb"
+
+    extra:
+      treeherder:
+        groupSymbol: Chains
+        groupName: MemLeak tests (chains)
+        symbol: sharedb
+
+- task:
+    metadata:
+      name: "MemLeak tests (chains, upgradedb)"
+      description: "MemLeak tests (chains, upgradedb)"
+
+    payload:
+      env:
+        NSS_MEMLEAK_TESTS: "chains"
+        NSS_CYCLES: "upgradedb"
+
+    extra:
+      treeherder:
+        groupSymbol: Chains
+        groupName: MemLeak tests (chains)
+        symbol: upgradedb
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/tests/merge.yml
@@ -0,0 +1,13 @@
+---
+- task:
+    metadata:
+      name: Merge tests
+      description: Merge tests
+
+    payload:
+      env:
+        NSS_TESTS: merge
+
+    extra:
+      treeherder:
+        symbol: Merge
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/tests/ocsp.yml
@@ -0,0 +1,13 @@
+---
+- task:
+    metadata:
+      name: OCSP tests
+      description: OCSP tests
+
+    payload:
+      env:
+        NSS_TESTS: ocsp
+
+    extra:
+      treeherder:
+        symbol: OCSP
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/tests/pkits.yml
@@ -0,0 +1,13 @@
+---
+- task:
+    metadata:
+      name: NIST PKITS tests
+      description: NIST PKITS tests
+
+    payload:
+      env:
+        NSS_TESTS: pkits
+
+    extra:
+      treeherder:
+        symbol: PKITS
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/tests/pkix.yml
@@ -0,0 +1,13 @@
+---
+- task:
+    metadata:
+      name: libpkix tests
+      description: libpkix tests
+
+    payload:
+      env:
+        NSS_TESTS: libpkix
+
+    extra:
+      treeherder:
+        symbol: PKIX
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/tests/sdr.yml
@@ -0,0 +1,13 @@
+---
+- task:
+    metadata:
+      name: SDR tests
+      description: SDR tests
+
+    payload:
+      env:
+        NSS_TESTS: sdr
+
+    extra:
+      treeherder:
+        symbol: SDR
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/tests/smime.yml
@@ -0,0 +1,13 @@
+---
+- task:
+    metadata:
+      name: S/MIME tests
+      description: S/MIME tests
+
+    payload:
+      env:
+        NSS_TESTS: smime
+
+    extra:
+      treeherder:
+        symbol: SMIME
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/tests/ssl.yml
@@ -0,0 +1,61 @@
+---
+- task:
+    metadata:
+      name: "SSL tests (standard)"
+      description: "SSL tests (standard)"
+
+    payload:
+      maxRunTime: 7200
+      env:
+        NSS_CYCLES: "standard"
+
+    extra:
+      treeherder:
+        symbol: standard
+        groupSymbol: SSL
+        groupName: SSL tests
+
+- task:
+    metadata:
+      name: "SSL tests (pkix)"
+      description: "SSL tests (pkix)"
+
+    payload:
+      env:
+        NSS_CYCLES: "pkix"
+
+    extra:
+      treeherder:
+        symbol: pkix
+        groupSymbol: SSL
+        groupName: SSL tests
+
+- task:
+    metadata:
+      name: "SSL tests (sharedb)"
+      description: "SSL tests (sharedb)"
+
+    payload:
+      env:
+        NSS_CYCLES: "sharedb"
+
+    extra:
+      treeherder:
+        symbol: sharedb
+        groupSymbol: SSL
+        groupName: SSL tests
+
+- task:
+    metadata:
+      name: "SSL tests (upgradedb)"
+      description: "SSL tests (upgradedb)"
+
+    payload:
+      env:
+        NSS_CYCLES: "upgradedb"
+
+    extra:
+      treeherder:
+        symbol: upgradedb
+        groupSymbol: SSL
+        groupName: SSL tests
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/tests/tools.yml
@@ -0,0 +1,13 @@
+---
+- task:
+    metadata:
+      name: Tools tests
+      description: Tools tests
+
+    payload:
+      env:
+        NSS_TESTS: tools
+
+    extra:
+      treeherder:
+        symbol: Tools
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/tools/clang-format.yml
@@ -0,0 +1,35 @@
+---
+- reruns: 0
+  task:
+    created: !from_now 0
+    deadline: !from_now 24
+    provisionerId: aws-provisioner-v1
+    workerType: hg-worker
+    schedulerId: task-graph-scheduler
+
+    metadata:
+      owner: !env TC_OWNER
+      source: !env TC_SOURCE
+      name: clang-format-3.8
+      description: clang-format-3.8
+
+    payload:
+      maxRunTime: 3600
+      image: ttaubert/nss-ci:0.0.16
+
+      command:
+        - "/bin/bash"
+        - "-c"
+        - "bin/checkout.sh && nss/automation/taskcluster/scripts/run_clang_format.sh nss/lib/ssl"
+
+      env:
+        NSS_HEAD_REPOSITORY: !env NSS_HEAD_REPOSITORY
+        NSS_HEAD_REVISION: !env NSS_HEAD_REVISION
+
+    extra:
+      treeherder:
+        build:
+          platform: nss-tools
+        symbol: clang-format-3.8
+        revision: !env TC_REVISION
+        revision_hash: !env TC_REVISION_HASH
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/windows/_build_base.yml
@@ -0,0 +1,38 @@
+---
+reruns: 2
+
+task:
+  created: !from_now 0
+  deadline: !from_now 24
+  provisionerId: aws-provisioner-v1
+  workerType: ttaubert-win2012r2
+  schedulerId: task-graph-scheduler
+
+  metadata:
+    owner: !env TC_OWNER
+    source: !env TC_SOURCE
+
+  payload:
+    maxRunTime: 3600
+
+    artifacts:
+      - type: directory
+        path: "public\\build"
+        expires: !from_now 24
+
+    command:
+      - "time /t && hg clone -r %NSS_HEAD_REVISION% %NSS_HEAD_REPOSITORY% nss"
+      - "time /t && bash -c nss/automation/taskcluster/windows/build.sh"
+
+    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;c:\\mozilla-build\\msys\\bin;c:\\Windows\\system32;c:\\mozilla-build\\upx391w;c:\\mozilla-build\\moztools-x64\\bin;c:\\mozilla-build\\wget"
+      NSS_HEAD_REPOSITORY: !env NSS_HEAD_REPOSITORY
+      NSS_HEAD_REVISION: !env NSS_HEAD_REVISION
+      DOMSUF: localdomain
+      HOST: localhost
+
+  extra:
+    treeherder:
+      revision: !env TC_REVISION
+      revision_hash: !env TC_REVISION_HASH
+      symbol: B
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/windows/_test_base.yml
@@ -0,0 +1,20 @@
+---
+reruns: 2
+
+task:
+  created: !from_now 0
+  deadline: !from_now 24
+  provisionerId: aws-provisioner-v1
+  workerType: ttaubert-win2012r2
+  schedulerId: task-graph-scheduler
+
+  metadata:
+    owner: !env TC_OWNER
+    source: !env TC_SOURCE
+
+  payload:
+    maxRunTime: 3600
+
+    command:
+      - "time /t && hg clone -r %NSS_HEAD_REVISION% %NSS_HEAD_REPOSITORY% nss"
+      - "time /t && bash -c nss/automation/taskcluster/windows/run_tests.sh"
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/windows/build64-debug.yml
@@ -0,0 +1,34 @@
+---
+- task:
+    metadata:
+      name: "Windows 2012 64 (debug)"
+      description: "Windows 2012 64 (debug)"
+
+    payload:
+      env:
+        NSS_ENABLE_TLS_1_3: 1
+        USE_64: 1
+
+    extra:
+      treeherder:
+        build:
+          platform: windows2012-64
+        collection:
+          debug: true
+
+  tests:
+    - cert
+    - cipher
+    - crmf
+    - db
+    - ec
+    - fips
+    - gtests
+    - lowhash
+    - merge
+    - ocsp
+    - pkits
+    - pkix
+    - sdr
+    - smime
+    - tools
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/windows/build64-opt.yml
@@ -0,0 +1,35 @@
+---
+- task:
+    metadata:
+      name: "Windows 2012 64 (opt)"
+      description: "Windows 2012 64 (opt)"
+
+    payload:
+      env:
+        NSS_ENABLE_TLS_1_3: 1
+        BUILD_OPT: 1
+        USE_64: 1
+
+    extra:
+      treeherder:
+        build:
+          platform: windows2012-64
+        collection:
+          opt: true
+
+  tests:
+    - cert
+    - cipher
+    - crmf
+    - db
+    - ec
+    - fips
+    - gtests
+    - lowhash
+    - merge
+    - ocsp
+    - pkits
+    - pkix
+    - sdr
+    - smime
+    - tools
new file mode 100755
--- /dev/null
+++ b/security/nss/automation/taskcluster/scripts/build.sh
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+
+set -v -e -x
+
+if [ $(id -u) = 0 ]; then
+    # Switch compilers.
+    GCC=${GCC_VERSION:-gcc-5}
+    GXX=${GXX_VERSION:-g++-5}
+
+    update-alternatives --set gcc "/usr/bin/$GCC"
+    update-alternatives --set g++ "/usr/bin/$GXX"
+
+    # Drop privileges by re-running this script.
+    exec su worker $0
+fi
+
+# Clone NSPR if needed.
+if [ ! -d "nspr" ]; then
+    hg clone https://hg.mozilla.org/projects/nspr
+fi
+
+# Build.
+cd nss && make nss_build_all
+
+# Package.
+mkdir -p /home/worker/artifacts
+tar cvfjh /home/worker/artifacts/dist.tar.bz2 ../dist
new file mode 100755
--- /dev/null
+++ b/security/nss/automation/taskcluster/scripts/extend_task_graph.sh
@@ -0,0 +1,13 @@
+#!/usr/bin/env bash
+
+set -v -e -x
+
+if [ $(id -u) = 0 ]; then
+    # Drop privileges by re-running this script.
+    exec su worker $0
+fi
+
+mkdir -p /home/worker/artifacts
+
+# Build the task graph definition.
+nodejs nss/automation/taskcluster/graph/build.js > /home/worker/artifacts/graph.json
new file mode 100755
--- /dev/null
+++ b/security/nss/automation/taskcluster/scripts/run_clang_format.sh
@@ -0,0 +1,21 @@
+#!/usr/bin/env bash
+
+set -v -e -x
+
+if [ $(id -u) = 0 ]; then
+    # Drop privileges by re-running this script.
+    exec su worker $0 $@
+fi
+
+# Apply clang-format 3.8 on the provided folder and verify that this doesn't change any file.
+# If any file differs after formatting, the script eventually exits with 1.
+# Any differences between formatted and unformatted files is printed to stdout to give a hint what's wrong.
+
+STATUS=0
+for i in $(find $1 -type f -name '*.[ch]' -print); do
+    if ! clang-format-3.8 $i | diff -Naur $i -; then
+        echo "Sorry, $i is not formatted properly. Please use clang-format 3.8 on your patch before landing."
+        STATUS=1
+    fi
+done
+exit $STATUS
new file mode 100755
--- /dev/null
+++ b/security/nss/automation/taskcluster/scripts/run_tests.sh
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+
+set -v -e -x
+
+if [ $(id -u) = 0 ]; then
+    # Switch compilers.
+    GCC=${GCC_VERSION:-gcc-5}
+    GXX=${GXX_VERSION:-g++-5}
+
+    update-alternatives --set gcc "/usr/bin/$GCC"
+    update-alternatives --set g++ "/usr/bin/$GXX"
+
+    # Stupid Docker.
+    echo "127.0.0.1 localhost.localdomain" >> /etc/hosts
+
+    # Drop privileges by re-running this script.
+    exec su worker $0
+fi
+
+# Fetch artifact if needed.
+if [ ! -d "dist" ]; then
+    curl --retry 3 -Lo dist.tar.bz2 https://queue.taskcluster.net/v1/task/$TC_PARENT_TASK_ID/artifacts/public/dist.tar.bz2
+    tar xvjf dist.tar.bz2
+fi
+
+# Run tests.
+cd nss/tests && ./all.sh
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/windows/build.sh
@@ -0,0 +1,15 @@
+#!/usr/bin/env bash
+
+set -v -e -x
+
+# Set up the toolchain.
+source $(dirname $0)/setup.sh
+
+# Clone NSPR.
+hg clone https://hg.mozilla.org/projects/nspr
+
+# Build.
+cd nss && make nss_build_all
+
+# Package.
+7z a ../public/build/dist.7z ../dist
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/windows/releng.manifest
@@ -0,0 +1,10 @@
+[
+  {
+    "version": "Visual Studio 2015 Update 2 / SDK 10.0.10586.0/212",
+    "size": 332343834,
+    "digest": "55814aaabcd4aa51fe85918ec02a8c29bc067d41ee79ddcfd628daaba5a06d4241a73a51bf5a8bc69cc762b52551009f44b05e65682c45b4684c17fb2d017c2c",
+    "algorithm": "sha512",
+    "filename": "vs2015u2.zip",
+    "unpack": true
+  }
+]
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/windows/run_tests.sh
@@ -0,0 +1,13 @@
+#!/usr/bin/env bash
+
+set -v -e -x
+
+# Set up the toolchain.
+source $(dirname $0)/setup.sh
+
+# Fetch artifact.
+wget -t 3 --retry-connrefused -w 5 --random-wait https://queue.taskcluster.net/v1/task/$TC_PARENT_TASK_ID/artifacts/public/build/dist.7z -O dist.7z
+7z x dist.7z
+
+# Run tests.
+cd nss/tests && ./all.sh
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/windows/setup.sh
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+
+set -v -e -x
+
+hg clone https://hg.mozilla.org/build/tools
+
+tools/scripts/tooltool/tooltool_wrapper.sh $(dirname $0)/releng.manifest https://api.pub.build.mozilla.org/tooltool/ non-existant-file.sh /c/mozilla-build/python/python.exe /c/builds/tooltool.py --authentication-file /c/builds/relengapi.tok -c /c/builds/tooltool_cache
+VSPATH="$(pwd)/vs2015u2"
+
+export WINDOWSSDKDIR="${VSPATH}/SDK"
+export WIN32_REDIST_DIR="${VSPATH}/VC/redist/x64/Microsoft.VC140.CRT"
+export WIN_UCRT_REDIST_DIR="${VSPATH}/SDK/Redist/ucrt/DLLs/x64"
+
+export PATH="${VSPATH}/VC/bin/amd64:${VSPATH}/VC/bin:${VSPATH}/SDK/bin/x64:${VSPATH}/VC/redist/x64/Microsoft.VC140.CRT:${VSPATH}/SDK/Redist/ucrt/DLLs/x64:${VSPATH}/DIASDK/bin/amd64:${PATH}"
+
+export INCLUDE="${VSPATH}/VC/include:${VSPATH}/VC/atlmfc/include:${VSPATH}/SDK/Include/ucrt:${VSPATH}/SDK/Include/shared:${VSPATH}/SDK/Include/um:${VSPATH}/SDK/Include/winrt:${VSPATH}/DIASDK/include"
+export LIB="${VSPATH}/VC/lib/amd64:${VSPATH}/VC/atlmfc/lib/amd64:${VSPATH}/SDK/lib/ucrt/x64:${VSPATH}/SDK/lib/um/x64:${VSPATH}/DIASDK/lib/amd64"
new file mode 100755
--- /dev/null
+++ b/security/nss/automation/travis/validate-formatting.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Apply clang-format 3.8 on the provided folder and verify that this doesn't change any file.
+# If any file differs after formatting, the script eventually exits with 1.
+# Any differences between formatted and unformatted files is printed to stdout to give a hint what's wrong.
+
+STATUS=0
+for i in $(find $1 -type f -name '*.[ch]' -print); do
+  if ! clang-format-3.8 $i | diff $i -; then
+    echo "Sorry, $i is not formatted properly. Please use clang-format 3.8 on your patch before landing."
+    STATUS=1
+  fi
+done
+exit $STATUS
--- a/security/nss/circle.yml
+++ b/security/nss/circle.yml
@@ -1,18 +1,18 @@
 checkout:
     post:
         - cd ..; hg clone https://hg.mozilla.org/projects/nspr
 
 test:
     override:
         - make nss_build_all
-        - cd tests; NSS_TESTS="ssl_gtests pk11_gtests der_gtests util_gtests" NSS_CYCLES=standard ./all.sh
+        - cd tests; NSS_TESTS="ssl_gtests gtests" NSS_CYCLES=standard ./all.sh
         - BUILD_OPT=1 make nss_build_all
-        - cd tests; BUILD_OPT=1 NSS_TESTS="ssl_gtests pk11_gtests der_gtests util_gtests" NSS_CYCLES=standard ./all.sh
+        - cd tests; BUILD_OPT=1 NSS_TESTS="ssl_gtests gtests" NSS_CYCLES=standard ./all.sh
 
 machine:
     environment:
         { USE_64: 1,
           NSS_ENABLE_TLS_1_3: 1,
         }
     hosts:
 
--- a/security/nss/cmd/bltest/blapitest.c
+++ b/security/nss/cmd/bltest/blapitest.c
@@ -977,16 +977,19 @@ setupIO(PLArenaPool *arena, bltestIO *in
                 input->buf.len = 0;
                 break;
             }
             if (in->data[in->len - 1] == '\n')
                 --in->len;
             if (in->data[in->len - 1] == '\r')
                 --in->len;
             SECITEM_CopyItem(arena, &input->buf, in);
+            if (rv != SECSuccess) {
+                return SECFailure;
+            }
             break;
         case bltestHexSpaceDelim:
             SECITEM_AllocItem(arena, &input->buf, in->len / 5);
             for (i = 0, j = 0; i < in->len; i += 5, j++) {
                 tok = &in->data[i];
                 if (tok[0] != '0' || tok[1] != 'x' || tok[4] != ' ')
                     /* bad hex token */
                     break;
@@ -1056,26 +1059,30 @@ finishIO(bltestIO *output, PRFileDesc *f
                 nb = PR_Write(file, hexstr, 2);
             }
             PR_Write(file, "\n", 1);
             break;
     }
     return rv;
 }
 
-void
+SECStatus
 bltestCopyIO(PLArenaPool *arena, bltestIO *dest, bltestIO *src)
 {
-    SECITEM_CopyItem(arena, &dest->buf, &src->buf);
+    if (SECITEM_CopyItem(arena, &dest->buf, &src->buf) != SECSuccess) {
+        return SECFailure;
+    }
     if (src->pBuf.len > 0) {
         dest->pBuf.len = src->pBuf.len;
         dest->pBuf.data = dest->buf.data + (src->pBuf.data - src->buf.data);
     }
     dest->mode = src->mode;
     dest->file = src->file;
+
+    return SECSuccess;
 }
 
 void
 misalignBuffer(PLArenaPool *arena, bltestIO *io, int off)
 {
     ptrdiff_t offset = (ptrdiff_t)io->buf.data % WORDSIZE;
     int length = io->buf.len;
     if (offset != off) {
@@ -3233,17 +3240,17 @@ blapi_selftest(bltestCipherMode *modes, 
             load_file_data(arena, &ct, filename, bltestBase64Encoded);
 
             get_params(arena, params, mode, j);
             /* Forward Operation (Encrypt/Sign/Hash)
             ** Align the input buffer (plaintext) according to request
             ** then perform operation and compare to ciphertext
             */
             if (encrypt) {
-                bltestCopyIO(arena, &cipherInfo.input, &pt);
+                rv |= bltestCopyIO(arena, &cipherInfo.input, &pt);
                 misalignBuffer(arena, &cipherInfo.input, inoff);
                 memset(&cipherInfo.output.buf, 0, sizeof cipherInfo.output.buf);
                 rv |= cipherInit(&cipherInfo, PR_TRUE);
                 misalignBuffer(arena, &cipherInfo.output, outoff);
                 rv |= cipherDoOp(&cipherInfo);
                 rv |= cipherFinish(&cipherInfo);
                 rv |= verify_self_test(&cipherInfo.output,
                                        &ct, mode, PR_TRUE, SECSuccess);
@@ -3255,30 +3262,30 @@ blapi_selftest(bltestCipherMode *modes, 
                     ** consistency between tests that run Sign/Verify back to
                     ** back (eg: self-tests) and tests that are only running
                     ** verify operations, copy the output into the sig buf,
                     ** and then copy the sig buf back out when verifying. For
                     ** self-tests, this is unnecessary copying, but for
                     ** verify-only operations, this ensures that the output
                     ** buffer is properly configured
                     */
-                    bltestCopyIO(arena, &params->asymk.sig, &cipherInfo.output);
+                    rv |= bltestCopyIO(arena, &params->asymk.sig, &cipherInfo.output);
                 }
             }
             if (!decrypt)
                 continue;
             /* Reverse Operation (Decrypt/Verify)
             ** Align the input buffer (ciphertext) according to request
             ** then perform operation and compare to plaintext
             */
             if (is_sigCipher(mode)) {
-                bltestCopyIO(arena, &cipherInfo.input, &pt);
-                bltestCopyIO(arena, &cipherInfo.output, &params->asymk.sig);
+                rv |= bltestCopyIO(arena, &cipherInfo.input, &pt);
+                rv |= bltestCopyIO(arena, &cipherInfo.output, &params->asymk.sig);
             } else {
-                bltestCopyIO(arena, &cipherInfo.input, &ct);
+                rv |= bltestCopyIO(arena, &cipherInfo.input, &ct);
                 memset(&cipherInfo.output.buf, 0, sizeof cipherInfo.output.buf);
             }
             misalignBuffer(arena, &cipherInfo.input, inoff);
             rv |= cipherInit(&cipherInfo, PR_FALSE);
             misalignBuffer(arena, &cipherInfo.output, outoff);
             srv = SECSuccess;
             srv |= cipherDoOp(&cipherInfo);
             rv |= cipherFinish(&cipherInfo);
--- a/security/nss/cmd/crlutil/crlutil.c
+++ b/security/nss/cmd/crlutil/crlutil.c
@@ -34,32 +34,38 @@ FindCRL(CERTCertDBHandle *certHandle, ch
 
     derName.data = NULL;
     derName.len = 0;
 
     cert = CERT_FindCertByNicknameOrEmailAddr(certHandle, name);
     if (!cert) {
         CERTName *certName = NULL;
         PLArenaPool *arena = NULL;
+        SECStatus rv = SECSuccess;
 
         certName = CERT_AsciiToName(name);
         if (certName) {
             arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
             if (arena) {
                 SECItem *nameItem =
                     SEC_ASN1EncodeItem(arena, NULL, (void *)certName,
                                        SEC_ASN1_GET(CERT_NameTemplate));
                 if (nameItem) {
-                    SECITEM_CopyItem(NULL, &derName, nameItem);
+                    rv = SECITEM_CopyItem(NULL, &derName, nameItem);
                 }
                 PORT_FreeArena(arena, PR_FALSE);
             }
             CERT_DestroyName(certName);
         }
 
+        if (rv != SECSuccess) {
+            SECU_PrintError(progName, "SECITEM_CopyItem failed, out of memory");
+            return ((CERTSignedCrl *)NULL);
+        }
+
         if (!derName.len || !derName.data) {
             SECU_PrintError(progName, "could not find certificate named '%s'", name);
             return ((CERTSignedCrl *)NULL);
         }
     } else {
         SECITEM_CopyItem(NULL, &derName, &cert->derSubject);
         CERT_DestroyCertificate(cert);
     }
--- a/security/nss/cmd/ecperf/ecperf.c
+++ b/security/nss/cmd/ecperf/ecperf.c
@@ -3,24 +3,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "blapi.h"
 #include "ec.h"
 #include "ecl-curve.h"
 #include "nss.h"
 #include "secutil.h"
 #include "pkcs11.h"
-#include <nspr.h>
+#include "nspr.h"
 #include <stdio.h>
-#include <strings.h>
-#include <assert.h>
-
-#include <time.h>
-#include <sys/time.h>
-#include <sys/resource.h>
 
 #define __PASTE(x, y) x##y
 
 /*
  * Get the NSS specific PKCS #11 function names.
  */
 #undef CK_PKCS11_FUNCTION_INFO
 #undef CK_NEED_ARG_LIST
@@ -84,16 +78,19 @@ static SECOidTag ecCurve_oid_map[] = {
     SEC_OID_SECG_EC_SECT113R1,
     SEC_OID_SECG_EC_SECT113R2,
     SEC_OID_SECG_EC_SECT131R1,
     SEC_OID_SECG_EC_SECT131R2,
     SEC_OID_SECG_EC_SECT163R1,
     SEC_OID_SECG_EC_SECT193R1,
     SEC_OID_SECG_EC_SECT193R2,
     SEC_OID_SECG_EC_SECT239K1,
+    SEC_OID_UNKNOWN, /* ECCurve_WTLS_1 */
+    SEC_OID_UNKNOWN, /* ECCurve_WTLS_8 */
+    SEC_OID_UNKNOWN, /* ECCurve_WTLS_9 */
     SEC_OID_UNKNOWN /* ECCurve_pastLastCurve */
 };
 
 typedef SECStatus (*op_func)(void *, void *, void *);
 typedef SECStatus (*pk11_op_func)(CK_SESSION_HANDLE, void *, void *, void *);
 
 typedef struct ThreadDataStr {
     op_func op;
@@ -120,16 +117,19 @@ PKCS11Thread(void *data)
 
     threadData->status = SECSuccess;
     threadData->count = 0;
 
     /* get our thread's session */
     PR_Lock(threadData->lock);
     crv = NSC_OpenSession(1, CKF_SERIAL_SESSION, NULL, 0, &session);
     PR_Unlock(threadData->lock);
+    if (crv != CKR_OK) {
+        return;
+    }
 
     if (threadData->isSign) {
         sig.data = sigData;
         sig.len = sizeof(sigData);
         threadData->p2 = (void *)&sig;
     }
 
     while (iters--) {
@@ -204,16 +204,22 @@ M_TimeOperation(void (*threadFunc)(void 
     startTime = PR_Now();
     if (numThreads == 1) {
         for (i = 0; i < iters; i++) {
             if (session) {
                 rv = (*pk11_op)(session, param1, param2, param3);
             } else {
                 rv = (*opfunc)(param1, param2, param3);
             }
+            if (rv != SECSuccess) {
+                PORT_Free(threadIDs);
+                PORT_Free(threadData);
+                SECU_PrintError("Error:", op);
+                return rv;
+            }
         }
         total = iters;
     } else {
         for (i = 0; i < numThreads; i++) {
             threadData[i].op = opfunc;
             threadData[i].p1 = (void *)param1;
             threadData[i].p2 = (void *)param2;
             threadData[i].p3 = (void *)param3;
@@ -226,31 +232,31 @@ M_TimeOperation(void (*threadFunc)(void 
         }
 
         total = 0;
         for (i = 0; i < numThreads; i++) {
             PR_JoinThread(threadIDs[i]);
             /* check the status */
             total += threadData[i].count;
         }
-
-        PORT_Free(threadIDs);
-        PORT_Free(threadData);
     }
 
     totalTime = PR_Now() - startTime;
     /* SecondsToInterval seems to be broken here ... */
     dUserTime = (double)totalTime / (double)1000000;
     if (dUserTime) {
         printf("    %-15s count:%4d sec: %3.2f op/sec: %6.2f\n",
                op, total, dUserTime, (double)total / dUserTime);
         if (rate) {
             *rate = ((double)total) / dUserTime;
         }
     }
+    PORT_Free(threadIDs);
+    PORT_Free(threadData);
+
     return SECSuccess;
 }
 
 #define GFP_POPULATE(params, name_v)                         \
     params.name = name_v;                                    \
     if ((params.name < ECCurve_noName) ||                    \
         (params.name > ECCurve_pastLastCurve))               \
         goto cleanup;                                        \
@@ -306,18 +312,19 @@ M_TimeOperation(void (*threadFunc)(void 
  */
 static SECItem *
 hexString2SECItem(PLArenaPool *arena, SECItem *item, const char *str)
 {
     int i = 0;
     int byteval = 0;
     int tmp = PORT_Strlen(str);
 
-    if ((tmp % 2) != 0)
+    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->data = (unsigned char *)PORT_Alloc(tmp / 2);
@@ -379,32 +386,33 @@ PKCS11_Derive(CK_SESSION_HANDLE session,
 }
 
 SECStatus
 PKCS11_Sign(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE *hKey,
             SECItem *sig, SECItem *digest)
 {
     CK_RV crv;
     CK_MECHANISM mech;
+    CK_ULONG sigLen = sig->len;
 
     mech.mechanism = CKM_ECDSA;
     mech.pParameter = NULL;
     mech.ulParameterLen = 0;
 
     crv = NSC_SignInit(session, &mech, *hKey);
     if (crv != CKR_OK) {
         printf("Sign Failed CK_RV=0x%x\n", (int)crv);
         return SECFailure;
     }
-    crv = NSC_Sign(session, digest->data, digest->len, sig->data,
-                   (CK_ULONG_PTR)&sig->len);
+    crv = NSC_Sign(session, digest->data, digest->len, sig->data, &sigLen);
     if (crv != CKR_OK) {
         printf("Sign Failed CK_RV=0x%x\n", (int)crv);
         return SECFailure;
     }
+    sig->len = (unsigned int)sigLen;
     return SECSuccess;
 }
 
 SECStatus
 PKCS11_Verify(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE *hKey,
               SECItem *sig, SECItem *digest)
 {
     CK_RV crv;
@@ -525,33 +533,37 @@ ectest_curve_pkcs11(ECCurveName curve, i
     mech.pParameter = (void *)&ecdh_params;
     mech.ulParameterLen = sizeof(ecdh_params);
 
     lock = PR_NewLock();
 
     rv = M_TimeOperation(PKCS11Thread, (op_func)PKCS11_Derive, "ECDH_Derive",
                          &ecPriv, &mech, NULL, iterations, numThreads,
                          lock, session, 0, &deriveRate);
-    if (rv != SECSuccess)
+    if (rv != SECSuccess) {
         goto cleanup;
+    }
     rv = M_TimeOperation(PKCS11Thread, (op_func)PKCS11_Sign, "ECDSA_Sign",
                          (void *)&ecPriv, &sig, &digest, iterations, numThreads,
                          lock, session, 1, &signRate);
-    if (rv != SECSuccess)
+    if (rv != SECSuccess) {
         goto cleanup;
+    }
     printf("        ECDHE max rate = %.2f\n", (deriveRate + signRate) / 4.0);
     /* get a signature */
     rv = PKCS11_Sign(session, &ecPriv, &sig, &digest);
-    if (rv != SECSuccess)
+    if (rv != SECSuccess) {
         goto cleanup;
+    }
     rv = M_TimeOperation(PKCS11Thread, (op_func)PKCS11_Verify, "ECDSA_Verify",
                          (void *)&ecPub, &sig, &digest, iterations, numThreads,
                          lock, session, 0, NULL);
-    if (rv != SECSuccess)
+    if (rv != SECSuccess) {
         goto cleanup;
+    }
 
 cleanup:
     if (lock) {
         PR_DestroyLock(lock);
     }
     return rv;
 }
 
@@ -585,59 +597,64 @@ ectest_curve_freebl(ECCurveName curve, i
     ECPrivateKey *ecPriv = NULL;
     ECPublicKey ecPub;
     SECItem sig;
     SECItem digest;
     unsigned char sigData[256];
     unsigned char digestData[20];
     double signRate, deriveRate;
     char genenc[3 + 2 * 2 * MAX_ECKEY_LEN];
-    SECStatus rv;
+    SECStatus rv = SECFailure;
 
     GFP_POPULATE(ecParams, curve);
 
     PORT_Memset(digestData, 0xa5, sizeof(digestData));
     digest.data = digestData;
     digest.len = sizeof(digestData);
     sig.data = sigData;
     sig.len = sizeof(sigData);
 
     rv = EC_NewKey(&ecParams, &ecPriv);
     if (rv != SECSuccess) {
         return SECFailure;
     }
     ecPub.ecParams = ecParams;
     ecPub.publicValue = ecPriv->publicValue;
 
-    M_TimeOperation(genericThread, (op_func)ECDH_DeriveWrap, "ECDH_Derive",
-                    ecPriv, &ecPub, NULL, iterations, numThreads, 0, 0, 0, &deriveRate);
-    if (rv != SECSuccess)
+    rv = M_TimeOperation(genericThread, (op_func)ECDH_DeriveWrap, "ECDH_Derive",
+                         ecPriv, &ecPub, NULL, iterations, numThreads, 0, 0, 0, &deriveRate);
+    if (rv != SECSuccess) {
         goto cleanup;
-    M_TimeOperation(genericThread, (op_func)ECDSA_SignDigest, "ECDSA_Sign",
-                    ecPriv, &sig, &digest, iterations, numThreads, 0, 0, 1, &signRate);
+    }
+    rv = M_TimeOperation(genericThread, (op_func)ECDSA_SignDigest, "ECDSA_Sign",
+                         ecPriv, &sig, &digest, iterations, numThreads, 0, 0, 1, &signRate);
     if (rv != SECSuccess)
         goto cleanup;
     printf("        ECDHE max rate = %.2f\n", (deriveRate + signRate) / 4.0);
     rv = ECDSA_SignDigest(ecPriv, &sig, &digest);
-    if (rv != SECSuccess)
+    if (rv != SECSuccess) {
         goto cleanup;
-    M_TimeOperation(genericThread, (op_func)ECDSA_VerifyDigest, "ECDSA_Verify",
-                    &ecPub, &sig, &digest, iterations, numThreads, 0, 0, 0, NULL);
-    if (rv != SECSuccess)
+    }
+    rv = M_TimeOperation(genericThread, (op_func)ECDSA_VerifyDigest, "ECDSA_Verify",
+                         &ecPub, &sig, &digest, iterations, numThreads, 0, 0, 0, NULL);
+    if (rv != SECSuccess) {
         goto cleanup;
+    }
 
 cleanup:
     return rv;
 }
 
 /* Prints help information. */
 void
 printUsage(char *prog)
 {
-    printf("Usage: %s [-i iterations] [-t threads ] [-ans] [-fp] [-A]\n", prog);
+    printf("Usage: %s [-i iterations] [-t threads ] [-ans] [-fp] [-Al]\n"
+           "-a: ansi\n-n: nist\n-s: secp\n-f: usefreebl\n-p: usepkcs11\n-A: all\n",
+           prog);
 }
 
 /* Performs tests of elliptic curve cryptography over prime fields If
  * tests fail, then it prints an error message, aborts, and returns an
  * error code. Otherwise, returns 0. */
 int
 main(int argv, char **argc)
 {
@@ -646,36 +663,41 @@ main(int argv, char **argc)
     int secp = 0;
     int usefreebl = 0;
     int usepkcs11 = 0;
     int i;
     SECStatus rv = SECSuccess;
     int iterations = 100;
     int numThreads = 1;
 
+    const CK_C_INITIALIZE_ARGS pk11args = {
+        NULL, NULL, NULL, NULL, CKF_LIBRARY_CANT_CREATE_OS_THREADS,
+        (void *)"flags=readOnly,noCertDB,noModDB", NULL
+    };
+
     /* read command-line arguments */
     for (i = 1; i < argv; i++) {
-        if (strcasecmp(argc[i], "-i") == 0) {
+        if (PL_strcasecmp(argc[i], "-i") == 0) {
             i++;
             iterations = atoi(argc[i]);
-        } else if (strcasecmp(argc[i], "-t") == 0) {
+        } else if (PL_strcasecmp(argc[i], "-t") == 0) {
             i++;
             numThreads = atoi(argc[i]);
-        } else if (strcasecmp(argc[i], "-A") == 0) {
+        } else if (PL_strcasecmp(argc[i], "-A") == 0) {
             ansi = nist = secp = 1;
             usepkcs11 = usefreebl = 1;
-        } else if (strcasecmp(argc[i], "-a") == 0) {
+        } else if (PL_strcasecmp(argc[i], "-a") == 0) {
             ansi = 1;
-        } else if (strcasecmp(argc[i], "-n") == 0) {
+        } else if (PL_strcasecmp(argc[i], "-n") == 0) {
             nist = 1;
-        } else if (strcasecmp(argc[i], "-s") == 0) {
+        } else if (PL_strcasecmp(argc[i], "-s") == 0) {
             secp = 1;
-        } else if (strcasecmp(argc[i], "-p") == 0) {
+        } else if (PL_strcasecmp(argc[i], "-p") == 0) {
             usepkcs11 = 1;
-        } else if (strcasecmp(argc[i], "-f") == 0) {
+        } else if (PL_strcasecmp(argc[i], "-f") == 0) {
             usefreebl = 1;
         } else {
             printUsage(argc[0]);
             return 0;
         }
     }
 
     if ((ansi | nist | secp) == 0) {
@@ -686,25 +708,36 @@ main(int argv, char **argc)
     }
 
     rv = NSS_NoDB_Init(NULL);
     if (rv != SECSuccess) {
         SECU_PrintError("Error:", "NSS_NoDB_Init");
         goto cleanup;
     }
 
+    if (usepkcs11) {
+        CK_RV crv = NSC_Initialize((CK_VOID_PTR)&pk11args);
+        if (crv != CKR_OK) {
+            fprintf(stderr, "NSC_Initialize failed crv=0x%x\n", (unsigned int)crv);
+            return SECFailure;
+        }
+    }
+
     /* specific arithmetic tests */
     if (nist) {
+#ifdef NSS_ECC_MORE_THAN_SUITE_B
         ECTEST_NAMED_GFP("SECP-160K1", ECCurve_SECG_PRIME_160K1);
         ECTEST_NAMED_GFP("NIST-P192", ECCurve_NIST_P192);
         ECTEST_NAMED_GFP("NIST-P224", ECCurve_NIST_P224);
+#endif
         ECTEST_NAMED_GFP("NIST-P256", ECCurve_NIST_P256);
         ECTEST_NAMED_GFP("NIST-P384", ECCurve_NIST_P384);
         ECTEST_NAMED_GFP("NIST-P521", ECCurve_NIST_P521);
     }
+#ifdef NSS_ECC_MORE_THAN_SUITE_B
     if (ansi) {
         ECTEST_NAMED_GFP("ANSI X9.62 PRIME192v1", ECCurve_X9_62_PRIME_192V1);
         ECTEST_NAMED_GFP("ANSI X9.62 PRIME192v2", ECCurve_X9_62_PRIME_192V2);
         ECTEST_NAMED_GFP("ANSI X9.62 PRIME192v3", ECCurve_X9_62_PRIME_192V3);
         ECTEST_NAMED_GFP("ANSI X9.62 PRIME239v1", ECCurve_X9_62_PRIME_239V1);
         ECTEST_NAMED_GFP("ANSI X9.62 PRIME239v2", ECCurve_X9_62_PRIME_239V2);
         ECTEST_NAMED_GFP("ANSI X9.62 PRIME239v3", ECCurve_X9_62_PRIME_239V3);
         ECTEST_NAMED_GFP("ANSI X9.62 PRIME256v1", ECCurve_X9_62_PRIME_256V1);
@@ -721,15 +754,16 @@ main(int argv, char **argc)
         ECTEST_NAMED_GFP("SECP-192R1", ECCurve_SECG_PRIME_192R1);
         ECTEST_NAMED_GFP("SECP-224K1", ECCurve_SECG_PRIME_224K1);
         ECTEST_NAMED_GFP("SECP-224R1", ECCurve_SECG_PRIME_224R1);
         ECTEST_NAMED_GFP("SECP-256K1", ECCurve_SECG_PRIME_256K1);
         ECTEST_NAMED_GFP("SECP-256R1", ECCurve_SECG_PRIME_256R1);
         ECTEST_NAMED_GFP("SECP-384R1", ECCurve_SECG_PRIME_384R1);
         ECTEST_NAMED_GFP("SECP-521R1", ECCurve_SECG_PRIME_521R1);
     }
+#endif
 
 cleanup:
     if (rv != SECSuccess) {
         printf("Error: exiting with error value\n");
     }
     return rv;
 }
--- a/security/nss/cmd/ecperf/manifest.mn
+++ b/security/nss/cmd/ecperf/manifest.mn
@@ -1,24 +1,24 @@
-# 
+#
 # 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/.
 
-DEPTH	= ../..
+DEPTH = ../..
 CORE_DEPTH = ../..
 
-# MODULE public and private header  directories are implicitly REQUIRED.
+# MODULE public and private header directories are implicitly REQUIRED.
 MODULE = nss
 
 INCLUDES += -I$(CORE_DEPTH)/nss/lib/softoken
 
 # This next line is used by .mk files
 # and gets translated into $LINCS in manifest.mnw
-REQUIRES = dbm seccmd 
+REQUIRES = dbm seccmd
 
-# DIRS = 
+# DIRS =
 
-CSRCS	= ecperf.c 
+CSRCS = ecperf.c
 
-PROGRAM	= ecperf
+PROGRAM = ecperf
 
 USE_STATIC_LIBS = 1
--- a/security/nss/cmd/manifest.mn
+++ b/security/nss/cmd/manifest.mn
@@ -37,16 +37,17 @@ NSS_SRCDIRS = \
  certcgi \
  certutil  \
  chktest  \
  crlutil  \
  crmftest \
  dbtest \
  derdump  \
  digest  \
+ ecperf \
  httpserv  \
  listsuites \
  makepqg  \
  multinit \
  ocspclnt  \
  ocspresp \
  oidcalc  \
  p7content  \
--- a/security/nss/cmd/platlibs.mk
+++ b/security/nss/cmd/platlibs.mk
@@ -84,17 +84,16 @@ endif
 
 ifneq ($(NSS_BUILD_SOFTOKEN_ONLY),1)
 ifeq ($(OS_ARCH), WINNT)
 # breakdown for windows
 NSS_LIBS_1 = \
 	$(DIST)/lib/$(LIB_PREFIX)smime.$(LIB_SUFFIX) \
 	$(DIST)/lib/$(LIB_PREFIX)ssl.$(LIB_SUFFIX) \
 	$(DIST)/lib/$(LIB_PREFIX)nss.$(LIB_SUFFIX) \
-	$(DIST)/lib/$(LIB_PREFIX)ssl.$(LIB_SUFFIX) \
 	$(NULL)
 NSS_LIBS_2 = \
 	$(DIST)/lib/$(LIB_PREFIX)pkcs12.$(LIB_SUFFIX) \
 	$(DIST)/lib/$(LIB_PREFIX)pkcs7.$(LIB_SUFFIX) \
 	$(DIST)/lib/$(LIB_PREFIX)certhi.$(LIB_SUFFIX) \
 	$(DIST)/lib/$(LIB_PREFIX)cryptohi.$(LIB_SUFFIX) \
 	$(DIST)/lib/$(LIB_PREFIX)pk11wrap.$(LIB_SUFFIX) \
 	$(DIST)/lib/$(LIB_PREFIX)certdb.$(LIB_SUFFIX) \
@@ -114,17 +113,16 @@ NSS_LIBS_4 = \
 	$(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)nspr4.$(LIB_SUFFIX) \
 	$(NULL)
 else
 # breakdown for others
 NSS_LIBS_1 = \
 	$(DIST)/lib/$(LIB_PREFIX)smime.$(LIB_SUFFIX) \
 	$(DIST)/lib/$(LIB_PREFIX)ssl.$(LIB_SUFFIX) \
 	$(DIST)/lib/$(LIB_PREFIX)nss.$(LIB_SUFFIX) \
-	$(DIST)/lib/$(LIB_PREFIX)ssl.$(LIB_SUFFIX) \
 	$(NULL)
 SECTOOL_LIB = \
 	$(DIST)/lib/$(LIB_PREFIX)sectool.$(LIB_SUFFIX) \
 	$(NULL)
 NSS_LIBS_2 = \
 	$(DIST)/lib/$(LIB_PREFIX)pkcs12.$(LIB_SUFFIX) \
 	$(DIST)/lib/$(LIB_PREFIX)pkcs7.$(LIB_SUFFIX) \
 	$(DIST)/lib/$(LIB_PREFIX)certhi.$(LIB_SUFFIX) \
--- a/security/nss/cmd/tstclnt/tstclnt.c
+++ b/security/nss/cmd/tstclnt/tstclnt.c
@@ -57,23 +57,23 @@
 #define EXIT_CODE_SIDECHANNELTEST_BADCERT 1
 #define EXIT_CODE_SIDECHANNELTEST_NODATA 2
 #define EXIT_CODE_SIDECHANNELTEST_REVOKED 3
 
 PRIntervalTime maxInterval = PR_INTERVAL_NO_TIMEOUT;
 
 int ssl3CipherSuites[] = {
     -1,                                  /* SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA* a */
-    -1,                                  /* SSL_FORTEZZA_DMS_WITH_RC4_128_SHA,	 * b */
+    -1,                                  /* SSL_FORTEZZA_DMS_WITH_RC4_128_SHA,   * b */
     TLS_RSA_WITH_RC4_128_MD5,            /* c */
     TLS_RSA_WITH_3DES_EDE_CBC_SHA,       /* d */
     TLS_RSA_WITH_DES_CBC_SHA,            /* e */
     TLS_RSA_EXPORT_WITH_RC4_40_MD5,      /* f */
     TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5,  /* g */
-    -1,                                  /* SSL_FORTEZZA_DMS_WITH_NULL_SHA,	 * h */
+    -1,                                  /* SSL_FORTEZZA_DMS_WITH_NULL_SHA,      * h */
     TLS_RSA_WITH_NULL_MD5,               /* i */
     SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA,  /* j */
     SSL_RSA_FIPS_WITH_DES_CBC_SHA,       /* k */
     TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, /* l */
     TLS_RSA_EXPORT1024_WITH_RC4_56_SHA,  /* m */
     TLS_RSA_WITH_RC4_128_SHA,            /* n */
     TLS_DHE_DSS_WITH_RC4_128_SHA,        /* o */
     TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,   /* p */
@@ -213,38 +213,35 @@ PrintParameterUsage(void)
     fprintf(stderr, "%-20s (use -C three times to include PEM format certificate dumps)\n", "");
     fprintf(stderr, "%-20s Nickname of key and cert for client auth\n",
             "-n nickname");
     fprintf(stderr,
             "%-20s Bypass PKCS11 layer for SSL encryption and MACing.\n", "-B");
     fprintf(stderr,
             "%-20s Restricts the set of enabled SSL/TLS protocols versions.\n"
             "%-20s All versions are enabled by default.\n"
-            "%-20s Possible values for min/max: ssl3 tls1.0 tls1.1 tls1.2\n"
+            "%-20s Possible values for min/max: ssl3 tls1.0 tls1.1 tls1.2 tls1.3\n"
             "%-20s Example: \"-V ssl3:\" enables SSL 3 and newer.\n",
             "-V [min]:[max]", "", "", "");
     fprintf(stderr, "%-20s Send TLS_FALLBACK_SCSV\n", "-K");
     fprintf(stderr, "%-20s Prints only payload data. Skips HTTP header.\n", "-S");
     fprintf(stderr, "%-20s Client speaks first. \n", "-f");
-    fprintf(stderr, "%-20s Use synchronous certificate validation "
-                    "(currently required for TLS 1.3)\n",
-            "-O");
+    fprintf(stderr, "%-20s Use synchronous certificate validation\n", "-O");
     fprintf(stderr, "%-20s Override bad server cert. Make it OK.\n", "-o");
     fprintf(stderr, "%-20s Disable SSL socket locking.\n", "-s");
     fprintf(stderr, "%-20s Verbose progress reporting.\n", "-v");
     fprintf(stderr, "%-20s Use export policy.\n", "-x");
     fprintf(stderr, "%-20s Ping the server and then exit.\n", "-q");
     fprintf(stderr, "%-20s Timeout for server ping (default: no timeout).\n", "-t seconds");
     fprintf(stderr, "%-20s Renegotiate N times (resuming session if N>1).\n", "-r N");
     fprintf(stderr, "%-20s Enable the session ticket extension.\n", "-u");
     fprintf(stderr, "%-20s Enable compression.\n", "-z");
     fprintf(stderr, "%-20s Enable false start.\n", "-g");
     fprintf(stderr, "%-20s Enable the cert_status extension (OCSP stapling).\n", "-T");
     fprintf(stderr, "%-20s Enable the signed_certificate_timestamp extension.\n", "-U");
-    fprintf(stderr, "%-20s Enable the extended master secret extension (session hash).\n", "-G");
     fprintf(stderr, "%-20s Require fresh revocation info from side channel.\n"
                     "%-20s -F once means: require for server cert only\n"
                     "%-20s -F twice means: require for intermediates, too\n"
                     "%-20s (Connect, handshake with server, disable dynamic download\n"
                     "%-20s  of OCSP/CRL, verify cert using CERT_PKIXVerifyCert.)\n"
                     "%-20s Exit code:\n"
                     "%-20s 0: have fresh and valid revocation data, status good\n"
                     "%-20s 1: cert failed to verify, prior to revocation checking\n"
@@ -721,18 +718,18 @@ thread_main(void *arg)
     PRFileDesc *ps = (PRFileDesc *)arg;
     PRFileDesc *std_in = PR_GetSpecialFD(PR_StandardInput);
     int wc, rc;
     char buf[256];
 
 #ifdef WIN32
     {
         /* Put stdin into O_BINARY mode
-	** or else incoming \r\n's will become \n's.
-	*/
+        ** or else incoming \r\n's will become \n's.
+        */
         int smrv = _setmode(_fileno(stdin), _O_BINARY);
         if (smrv == -1) {
             fprintf(stderr,
                     "%s: Cannot change stdin to binary mode. Use -i option instead.\n",
                     progName);
             /* plow ahead anyway */
         }
     }
--- a/security/nss/coreconf/coreconf.dep
+++ b/security/nss/coreconf/coreconf.dep
@@ -5,9 +5,8 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSS in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
-
new file mode 100644
--- /dev/null
+++ b/security/nss/external_tests/common/Makefile
@@ -0,0 +1,41 @@
+#! gmake
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#######################################################################
+# (1) Include initial platform-independent assignments (MANDATORY).   #
+#######################################################################
+
+include manifest.mn
+
+#######################################################################
+# (2) Include "global" configuration information. (OPTIONAL)          #
+#######################################################################
+
+include $(CORE_DEPTH)/coreconf/config.mk
+
+#######################################################################
+# (3) Include "component" configuration information. (OPTIONAL)       #
+#######################################################################
+
+#######################################################################
+# (4) Include "local" platform-dependent assignments (OPTIONAL).      #
+#######################################################################
+
+include gtest.mk
+
+#######################################################################
+# (5) Execute "global" rules. (OPTIONAL)                              #
+#######################################################################
+
+include $(CORE_DEPTH)/coreconf/rules.mk
+
+#######################################################################
+# (6) Execute "component" rules. (OPTIONAL)                           #
+#######################################################################
+
+#######################################################################
+# (7) Execute "local" rules. (OPTIONAL).                              #
+#######################################################################
--- a/security/nss/external_tests/common/gtest.mk
+++ b/security/nss/external_tests/common/gtest.mk
@@ -1,15 +1,15 @@
 #! 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/.
 
-include ../../cmd/platlibs.mk
+include $(CORE_DEPTH)/cmd/platlibs.mk
 
 MKPROG = $(CCC)
 MKSHLIB	= $(CCC) $(DSO_LDOPTS) $(DARWIN_SDK_SHLIBFLAGS)
 
 # gtests pick up errors with signed/unsigned comparisons on some platforms
 # even though we disabled -Wsign-compare.
 # This catches that by enabling the warning.
 # Only add -Wsign-compare if -Werror is enabled, lest we add it on the wrong
new file mode 100644
--- /dev/null
+++ b/security/nss/external_tests/common/gtests.cc
@@ -0,0 +1,22 @@
+#include "nspr.h"
+#include "nss.h"
+#include "ssl.h"
+
+#include <cstdlib>
+
+#define GTEST_HAS_RTTI 0
+#include "gtest/gtest.h"
+
+int main(int argc, char **argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+
+  NSS_NoDB_Init(nullptr);
+  NSS_SetDomesticPolicy();
+  int rv = RUN_ALL_TESTS();
+
+  if (NSS_Shutdown() != SECSuccess) {
+    return 1;
+  }
+
+  return rv;
+}
new file mode 100644
--- /dev/null
+++ b/security/nss/external_tests/common/manifest.mn
@@ -0,0 +1,21 @@
+#
+# 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 = \
+      gtests.cc \
+      $(NULL)
+
+INCLUDES += -I$(CORE_DEPTH)/external_tests/google_test/gtest/include \
+            -I$(CORE_DEPTH)/external_tests/common
+
+REQUIRES = gtest
+
+EXTRA_LIBS = $(DIST)/lib/$(LIB_PREFIX)gtest.$(LIB_SUFFIX)
+
+# NOTE: this is not actually used but required to build gtests.o
+PROGRAM = gtests
\ No newline at end of file
--- a/security/nss/external_tests/der_gtest/Makefile
+++ b/security/nss/external_tests/der_gtest/Makefile
@@ -36,9 +36,8 @@ include $(CORE_DEPTH)/coreconf/rules.mk
 #######################################################################
 # (6) Execute "component" rules. (OPTIONAL)                           #
 #######################################################################
 
 
 #######################################################################
 # (7) Execute "local" rules. (OPTIONAL).                              #
 #######################################################################
-
deleted file mode 100644
--- a/security/nss/external_tests/der_gtest/der_gtest.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-#include "nspr.h"
-#include "nss.h"
-#include "ssl.h"
-
-#include <cstdlib>
-
-#define GTEST_HAS_RTTI 0
-#include "gtest/gtest.h"
-
-int main(int argc, char **argv) {
-  // Start the tests
-  ::testing::InitGoogleTest(&argc, argv);
-
-  NSS_NoDB_Init(nullptr);
-  NSS_SetDomesticPolicy();
-  int rv = RUN_ALL_TESTS();
-
-  NSS_Shutdown();
-
-  return rv;
-}
--- a/security/nss/external_tests/der_gtest/manifest.mn
+++ b/security/nss/external_tests/der_gtest/manifest.mn
@@ -3,18 +3,19 @@
 # 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 = \
       der_getint_unittest.cc \
-      der_gtest.cc \
       $(NULL)
 
 INCLUDES += -I$(CORE_DEPTH)/external_tests/google_test/gtest/include \
             -I$(CORE_DEPTH)/external_tests/common
 
 REQUIRES = nspr nss libdbm gtest
 
 PROGRAM = der_gtest
-EXTRA_LIBS = $(DIST)/lib/$(LIB_PREFIX)gtest.$(LIB_SUFFIX)
+
+EXTRA_LIBS = $(DIST)/lib/$(LIB_PREFIX)gtest.$(LIB_SUFFIX) $(EXTRA_OBJS) \
+             ../common/$(OBJDIR)/gtests$(OBJ_SUFFIX)
--- a/security/nss/external_tests/manifest.mn
+++ b/security/nss/external_tests/manifest.mn
@@ -2,13 +2,14 @@
 # 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 = \
 	google_test \
-        der_gtest \
+	common \
+	der_gtest \
 	util_gtest \
-        pk11_gtest \
-        ssl_gtest \
+	pk11_gtest \
+	ssl_gtest \
 	$(NULL)
--- a/security/nss/external_tests/pk11_gtest/Makefile
+++ b/security/nss/external_tests/pk11_gtest/Makefile
@@ -36,9 +36,8 @@ include $(CORE_DEPTH)/coreconf/rules.mk
 #######################################################################
 # (6) Execute "component" rules. (OPTIONAL)                           #
 #######################################################################
 
 
 #######################################################################
 # (7) Execute "local" rules. (OPTIONAL).                              #
 #######################################################################
-
--- a/security/nss/external_tests/pk11_gtest/manifest.mn
+++ b/security/nss/external_tests/pk11_gtest/manifest.mn
@@ -6,18 +6,20 @@ CORE_DEPTH = ../..
 DEPTH      = ../..
 MODULE = nss
 
 CPPSRCS = \
       pk11_chacha20poly1305_unittest.cc \
       pk11_pbkdf2_unittest.cc \
       pk11_prf_unittest.cc \
       pk11_rsapss_unittest.cc \
-      pk11_gtest.cc \
       $(NULL)
 
 INCLUDES += -I$(CORE_DEPTH)/external_tests/google_test/gtest/include \
             -I$(CORE_DEPTH)/external_tests/common
 
 REQUIRES = nspr nss libdbm gtest
 
 PROGRAM = pk11_gtest
-EXTRA_LIBS = $(DIST)/lib/$(LIB_PREFIX)gtest.$(LIB_SUFFIX)
+
+EXTRA_LIBS = $(DIST)/lib/$(LIB_PREFIX)gtest.$(LIB_SUFFIX) $(EXTRA_OBJS) \
+             ../common/$(OBJDIR)/gtests$(OBJ_SUFFIX)
+
deleted file mode 100644
--- a/security/nss/external_tests/pk11_gtest/pk11_gtest.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-#include "nspr.h"
-#include "nss.h"
-#include "ssl.h"
-
-#include <cstdlib>
-
-#define GTEST_HAS_RTTI 0
-#include "gtest/gtest.h"
-
-int main(int argc, char **argv) {
-  // Start the tests
-  ::testing::InitGoogleTest(&argc, argv);
-
-  NSS_NoDB_Init(nullptr);
-  NSS_SetDomesticPolicy();
-  int rv = RUN_ALL_TESTS();
-
-  NSS_Shutdown();
-
-  return rv;
-}
--- a/security/nss/external_tests/ssl_gtest/gtest_utils.h
+++ b/security/nss/external_tests/ssl_gtest/gtest_utils.h
@@ -11,36 +11,35 @@
 #include "gtest/gtest.h"
 #include "test_io.h"
 
 namespace nss_test {
 
 // Gtest utilities
 class Timeout : public PollTarget {
  public:
-  Timeout(int32_t timer_ms) : handle_(nullptr), timed_out_(false) {
+  Timeout(int32_t timer_ms) : handle_(nullptr) {
     Poller::Instance()->SetTimer(timer_ms, this, &Timeout::ExpiredCallback,
                                  &handle_);
   }
   ~Timeout() {
-    Cancel();
+    if (handle_) {
+      handle_->Cancel();
+    }
   }
 
   static void ExpiredCallback(PollTarget* target, Event event) {
     Timeout* timeout = static_cast<Timeout*>(target);
-    timeout->timed_out_ = true;
+    timeout->handle_ = nullptr;
   }
 
-  void Cancel() { handle_->Cancel(); }
-
-  bool timed_out() const { return timed_out_; }
+  bool timed_out() const { return !handle_; }
 
  private:
   Poller::Timer* handle_;
-  bool timed_out_;
 };
 
 }  // namespace nss_test
 
 #define WAIT_(expression, timeout) \
   do {                             \
     Timeout tm(timeout);           \
     while (!(expression)) {        \
--- a/security/nss/external_tests/ssl_gtest/libssl_internals.c
+++ b/security/nss/external_tests/ssl_gtest/libssl_internals.c
@@ -91,16 +91,27 @@ SSLInt_ExtensionNegotiated(PRFileDesc *f
 
 void
 SSLInt_ClearSessionTicketKey()
 {
   ssl3_SessionTicketShutdown(NULL, NULL);
   NSS_UnregisterShutdown(ssl3_SessionTicketShutdown, NULL);
 }
 
+SECStatus
+SSLInt_SetMTU(PRFileDesc *fd, PRUint16 mtu)
+{
+  sslSocket *ss = ssl_FindSocket(fd);
+  if (ss) {
+    ss->ssl3.mtu = mtu;
+    return SECSuccess;
+  }
+  return SECFailure;
+}
+
 PRInt32 SSLInt_CountTls13CipherSpecs(PRFileDesc *fd)
 {
   PRCList *cur_p;
   PRInt32 ct = 0;
 
   sslSocket *ss = ssl_FindSocket(fd);
   if (!ss) {
     return -1;
--- a/security/nss/external_tests/ssl_gtest/libssl_internals.h
+++ b/security/nss/external_tests/ssl_gtest/libssl_internals.h
@@ -21,12 +21,11 @@ PRUint32 SSLInt_DetermineKEABits(PRUint1
 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_ForceTimerExpiry(PRFileDesc *fd);
+SECStatus SSLInt_SetMTU(PRFileDesc *fd, PRUint16 mtu);
 
-#endif
-
-
+#endif // ndef libssl_internals_h_
--- a/security/nss/external_tests/ssl_gtest/manifest.mn
+++ b/security/nss/external_tests/ssl_gtest/manifest.mn
@@ -12,26 +12,28 @@ CSRCS = \
       $(NULL)
 
 CPPSRCS = \
       ssl_v2_client_hello_unittest.cc \
       ssl_agent_unittest.cc \
       ssl_loopback_unittest.cc \
       ssl_extension_unittest.cc \
       ssl_skip_unittest.cc \
+      ssl_ciphersuite_unittest.cc \
       ssl_gtest.cc \
       test_io.cc \
       tls_agent.cc \
       tls_connect.cc \
       tls_hkdf_unittest.cc \
       tls_filter.cc \
       tls_parser.cc \
       $(NULL)
 
 INCLUDES += -I$(CORE_DEPTH)/external_tests/google_test/gtest/include \
             -I$(CORE_DEPTH)/external_tests/common
 
 REQUIRES = nspr nss libdbm gtest
 
 PROGRAM = ssl_gtest
-EXTRA_LIBS = $(DIST)/lib/$(LIB_PREFIX)gtest.$(LIB_SUFFIX)
+EXTRA_LIBS = $(DIST)/lib/$(LIB_PREFIX)gtest.$(LIB_SUFFIX) \
+             $(DIST)/lib/$(LIB_PREFIX)softokn.$(LIB_SUFFIX)
 
 USE_STATIC_LIBS = 1
--- a/security/nss/external_tests/ssl_gtest/ssl_agent_unittest.cc
+++ b/security/nss/external_tests/ssl_gtest/ssl_agent_unittest.cc
@@ -12,47 +12,177 @@
 
 #include "databuffer.h"
 #include "tls_agent.h"
 #include "tls_connect.h"
 #include "tls_parser.h"
 
 namespace nss_test {
 
-void MakeTrivialHandshakeMessage(uint8_t hs_type, size_t hs_len,
-                                 DataBuffer* out) {
-  size_t total_len = 5 + 4 + hs_len;
-
-  out->Allocate(total_len);
-
-  size_t index = 0;
-  out->Write(index, kTlsHandshakeType, 1); ++index; // Content Type
-  out->Write(index, 3, 1); ++index; // Version high
-  out->Write(index, 1, 1); ++index; // Version low
-  out->Write(index, 4 + hs_len, 2); index += 2; // Length
-
-  out->Write(index, hs_type, 1); ++index; // Handshake record type.
-  out->Write(index, hs_len, 3); index += 3; // Handshake length
-  for (; index < total_len; ++index) {
-    out->Write(index, 1, 1);
-  }
-}
+#ifdef NSS_ENABLE_TLS_1_3
+const static uint8_t kCannedServerTls13ServerHello[] = {
+  0x03, 0x04, 0x54, 0x1a, 0xfc, 0x6c, 0x8e, 0xd7,
+  0x08, 0x96, 0x8f, 0x9c, 0xc8, 0x0a, 0xf6, 0x50,
+  0x20, 0x15, 0xa9, 0x75, 0x52, 0xc5, 0x9c, 0x74,
+  0xf6, 0xc9, 0xea, 0x3b, 0x77, 0x5a, 0x83, 0xaa,
+  0x66, 0xdc, 0xc0, 0x2f, 0x00, 0x4a, 0x00, 0x28,
+  0x00, 0x46, 0x00, 0x17, 0x00, 0x42, 0x41, 0x04,
+  0xbd, 0xbc, 0x15, 0x6f, 0x43, 0xc7, 0x67, 0x7c,
+  0x08, 0x78, 0x08, 0x4d, 0x85, 0x4f, 0xf9, 0x45,
+  0x10, 0x4a, 0x04, 0xf4, 0x07, 0xc0, 0x4c, 0x26,
+  0x51, 0xa0, 0x38, 0x49, 0x98, 0xf7, 0x79, 0x0f,
+  0xb4, 0x26, 0xe6, 0xac, 0x4b, 0x5a, 0x2a, 0x04,
+  0x80, 0x14, 0x03, 0xd0, 0x31, 0xf1, 0x70, 0xe2,
+  0x72, 0x1d, 0x5e, 0xfb, 0x74, 0x80, 0xc8, 0x9e,
+  0x08, 0x39, 0xd6, 0xa5, 0x1b, 0xcf, 0x54, 0x9f
+};
+#endif
 
 TEST_P(TlsAgentTest, EarlyFinished) {
   DataBuffer buffer;
-  MakeTrivialHandshakeMessage(kTlsHandshakeFinished, 0, &buffer);
+  MakeTrivialHandshakeRecord(kTlsHandshakeFinished, 0, &buffer);
   ProcessMessage(buffer, TlsAgent::STATE_ERROR,
                  SSL_ERROR_RX_UNEXPECTED_FINISHED);
 }
 
 TEST_P(TlsAgentTest, EarlyCertificateVerify) {
   DataBuffer buffer;
-  MakeTrivialHandshakeMessage(kTlsHandshakeCertificateVerify, 0, &buffer);
+  MakeTrivialHandshakeRecord(kTlsHandshakeCertificateVerify, 0, &buffer);
   ProcessMessage(buffer, TlsAgent::STATE_ERROR,
                  SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY);
 }
 
+#ifdef NSS_ENABLE_TLS_1_3
+TEST_P(TlsAgentTestClient, CannedServerHello) {
+  DataBuffer buffer;
+  EnsureInit();
+  agent_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_3,
+                          SSL_LIBRARY_VERSION_TLS_1_3);
+  DataBuffer server_hello_inner(kCannedServerTls13ServerHello,
+                                sizeof(kCannedServerTls13ServerHello));
+  uint16_t wire_version = mode_ == STREAM ?
+      SSL_LIBRARY_VERSION_TLS_1_3:
+      TlsVersionToDtlsVersion(SSL_LIBRARY_VERSION_TLS_1_3);
+  server_hello_inner.Write(0, wire_version, 2);
+  DataBuffer server_hello;
+  MakeHandshakeMessage(kTlsHandshakeServerHello,
+                       server_hello_inner.data(),
+                       server_hello_inner.len(),
+                       &server_hello);
+  MakeRecord(kTlsHandshakeType, SSL_LIBRARY_VERSION_TLS_1_3,
+             server_hello.data(), server_hello.len(), &buffer);
+  ProcessMessage(buffer, TlsAgent::STATE_CONNECTING);
+}
+
+TEST_P(TlsAgentTestClient, EncryptedExtensionsInClear) {
+  DataBuffer buffer;
+  DataBuffer server_hello_inner(kCannedServerTls13ServerHello,
+                                sizeof(kCannedServerTls13ServerHello));
+  server_hello_inner.Write(0,
+                           mode_ == STREAM ?
+                           SSL_LIBRARY_VERSION_TLS_1_3:
+                           TlsVersionToDtlsVersion(
+                               SSL_LIBRARY_VERSION_TLS_1_3),
+                           2);
+  DataBuffer server_hello;
+  MakeHandshakeMessage(kTlsHandshakeServerHello,
+                       server_hello_inner.data(),
+                       server_hello_inner.len(),
+                       &server_hello);
+  DataBuffer encrypted_extensions;
+  MakeHandshakeMessage(kTlsHandshakeEncryptedExtensions, nullptr, 0,
+                       &encrypted_extensions, 1);
+  server_hello.Append(encrypted_extensions);
+  MakeRecord(kTlsHandshakeType,
+             SSL_LIBRARY_VERSION_TLS_1_3,
+             server_hello.data(),
+             server_hello.len(), &buffer);
+  EnsureInit();
+  agent_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_3,
+                          SSL_LIBRARY_VERSION_TLS_1_3);
+  ProcessMessage(buffer, TlsAgent::STATE_ERROR,
+                 SSL_ERROR_RX_UNEXPECTED_HANDSHAKE);
+}
+
+TEST_F(TlsAgentStreamTestClient, EncryptedExtensionsInClearTwoPieces) {
+  DataBuffer buffer;
+  DataBuffer buffer2;
+  DataBuffer server_hello_inner(kCannedServerTls13ServerHello,
+                                sizeof(kCannedServerTls13ServerHello));
+  server_hello_inner.Write(0, SSL_LIBRARY_VERSION_TLS_1_3, 2);
+  DataBuffer server_hello;
+  MakeHandshakeMessage(kTlsHandshakeServerHello,
+                       server_hello_inner.data(),
+                       server_hello_inner.len(),
+                       &server_hello);
+  DataBuffer encrypted_extensions;
+  MakeHandshakeMessage(kTlsHandshakeEncryptedExtensions, nullptr, 0,
+                       &encrypted_extensions, 1);
+  server_hello.Append(encrypted_extensions);
+  MakeRecord(kTlsHandshakeType,
+             SSL_LIBRARY_VERSION_TLS_1_3,
+             server_hello.data(), 20,
+             &buffer);
+
+  MakeRecord(kTlsHandshakeType,
+             SSL_LIBRARY_VERSION_TLS_1_3,
+             server_hello.data() + 20,
+             server_hello.len() - 20, &buffer2);
+
+  EnsureInit();
+  agent_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_3,
+                          SSL_LIBRARY_VERSION_TLS_1_3);
+  ProcessMessage(buffer, TlsAgent::STATE_CONNECTING);
+  ProcessMessage(buffer2, TlsAgent::STATE_ERROR,
+                 SSL_ERROR_RX_UNEXPECTED_HANDSHAKE);
+}
+
+
+TEST_F(TlsAgentDgramTestClient, EncryptedExtensionsInClearTwoPieces) {
+  DataBuffer buffer;
+  DataBuffer buffer2;
+  DataBuffer server_hello_inner(kCannedServerTls13ServerHello,
+                                sizeof(kCannedServerTls13ServerHello));
+  server_hello_inner.Write(
+      0, TlsVersionToDtlsVersion(SSL_LIBRARY_VERSION_TLS_1_3), 2);
+  DataBuffer server_hello_frag1;
+  MakeHandshakeMessageFragment(kTlsHandshakeServerHello,
+                       server_hello_inner.data(),
+                       server_hello_inner.len(),
+                       &server_hello_frag1, 0,
+                       0, 20);
+  DataBuffer server_hello_frag2;
+  MakeHandshakeMessageFragment(kTlsHandshakeServerHello,
+                       server_hello_inner.data() + 20,
+                       server_hello_inner.len(), &server_hello_frag2, 0,
+                       20, server_hello_inner.len() - 20);
+  DataBuffer encrypted_extensions;
+  MakeHandshakeMessage(kTlsHandshakeEncryptedExtensions, nullptr, 0,
+                       &encrypted_extensions, 1);
+  server_hello_frag2.Append(encrypted_extensions);
+  MakeRecord(kTlsHandshakeType,
+             SSL_LIBRARY_VERSION_TLS_1_3,
+             server_hello_frag1.data(), server_hello_frag1.len(),
+             &buffer);
+
+  MakeRecord(kTlsHandshakeType,
+             SSL_LIBRARY_VERSION_TLS_1_3,
+             server_hello_frag2.data(), server_hello_frag2.len(),
+             &buffer2, 1);
+
+  EnsureInit();
+  agent_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_3,
+                          SSL_LIBRARY_VERSION_TLS_1_3);
+  ProcessMessage(buffer, TlsAgent::STATE_CONNECTING);
+  ProcessMessage(buffer2, TlsAgent::STATE_ERROR,
+                 SSL_ERROR_RX_UNEXPECTED_HANDSHAKE);
+}
+#endif
+
 INSTANTIATE_TEST_CASE_P(AgentTests, TlsAgentTest,
                         ::testing::Combine(
                              TlsAgentTestBase::kTlsRolesAll,
                              TlsConnectTestBase::kTlsModesStream));
-
-}  // namespace nss_test
+#ifdef NSS_ENABLE_TLS_1_3
+INSTANTIATE_TEST_CASE_P(ClientTests, TlsAgentTestClient,
+                        TlsConnectTestBase::kTlsModesAll);
+#endif
+} // namespace nss_test
new file mode 100644
--- /dev/null
+++ b/security/nss/external_tests/ssl_gtest/ssl_ciphersuite_unittest.cc
@@ -0,0 +1,163 @@
+/* -*- 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 "secerr.h"
+#include "ssl.h"
+#include "sslerr.h"
+#include "sslproto.h"
+#include <memory>
+#include <functional>
+
+#include "tls_connect.h"
+#include "gtest_utils.h"
+
+namespace nss_test {
+
+// mode, version, cipher suite
+typedef std::tuple<std::string, uint16_t, uint16_t> CipherSuiteProfile;
+
+class TlsCipherSuiteTest
+    : public TlsConnectTestBase,
+      public ::testing::WithParamInterface<CipherSuiteProfile> {
+ public:
+
+  TlsCipherSuiteTest()
+      : TlsConnectTestBase(TlsConnectTestBase::ToMode(std::get<0>(GetParam())),
+                           std::get<1>(GetParam())),
+        cipher_suite_(std::get<2>(GetParam()))
+      {}
+
+ protected:
+  uint16_t cipher_suite_;
+
+  void SetupCertificate() {
+    SSLCipherSuiteInfo csinfo;
+    EXPECT_EQ(SECSuccess, SSL_GetCipherSuiteInfo(cipher_suite_,
+                                                 &csinfo, sizeof(csinfo)));
+    std::cerr << "Cipher suite: " << csinfo.cipherSuiteName << std::endl;
+    switch (csinfo.authType) {
+      case ssl_auth_rsa_sign:
+        Reset(TlsAgent::kServerRsaSign);
+        break;
+      case ssl_auth_rsa_decrypt:
+        Reset(TlsAgent::kServerRsaDecrypt);
+        break;
+      case ssl_auth_ecdsa:
+        Reset(TlsAgent::kServerEcdsa);
+        break;
+      case ssl_auth_ecdh_ecdsa:
+        Reset(TlsAgent::kServerEcdhEcdsa);
+        break;
+      case ssl_auth_dsa:
+        Reset(TlsAgent::kServerDsa);
+        break;
+      default:
+        ASSERT_TRUE(false) << "Unsupported cipher suite: " << cipher_suite_;
+        break;
+    }
+  }
+
+  void EnableSingleCipher() {
+    EnsureTlsSetup();
+    // It doesn't matter which does this, but the test is better if both do it.
+    client_->EnableSingleCipher(cipher_suite_);
+    server_->EnableSingleCipher(cipher_suite_);
+  }
+};
+
+
+TEST_P(TlsCipherSuiteTest, ConnectWithCipherSuite) {
+  SetupCertificate();
+  EnableSingleCipher();
+
+  Connect();
+  SendReceive();
+
+  // Check that we used the right cipher suite.
+  uint16_t actual;
+  EXPECT_TRUE(client_->cipher_suite(&actual) && actual == cipher_suite_);
+  EXPECT_TRUE(server_->cipher_suite(&actual) && actual == cipher_suite_);
+}
+
+// This awful macro makes the test instantiations easier to read.
+#define INSTANTIATE_CIPHER_TEST_P(name, modes, versions, ...)           \
+  static const uint16_t k##name##CiphersArr[] = { __VA_ARGS__ };        \
+  static const ::testing::internal::ParamGenerator<uint16_t>            \
+    k##name##Ciphers = ::testing::ValuesIn(k##name##CiphersArr);        \
+  INSTANTIATE_TEST_CASE_P(CipherSuite##name, TlsCipherSuiteTest,        \
+                          ::testing::Combine(                           \
+                               TlsConnectTestBase::kTlsModes##modes,    \
+                               TlsConnectTestBase::kTls##versions,      \
+                               k##name##Ciphers))
+
+// The cipher suites of type ECDH_RSA are disabled because we don't have
+// a compatible certificate in the test fixture.
+INSTANTIATE_CIPHER_TEST_P(RC4, Stream, V10ToV12,
+                          TLS_RSA_WITH_RC4_128_SHA,
+                          TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
+                          TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
+                          // TLS_ECDH_RSA_WITH_RC4_128_SHA,
+                          TLS_ECDHE_RSA_WITH_RC4_128_SHA);
+// TODO - Bug 1251136 move DHE_RSA suites to V12Plus
+INSTANTIATE_CIPHER_TEST_P(AEAD12, All, V12,
+                          TLS_RSA_WITH_AES_128_GCM_SHA256,
+                          TLS_DHE_DSS_WITH_AES_128_GCM_SHA256,
+                          TLS_DHE_DSS_WITH_AES_256_GCM_SHA384,
+                          TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
+                          TLS_RSA_WITH_AES_256_GCM_SHA384,
+                          TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
+                          TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
+                          TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
+                          TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384);
+INSTANTIATE_CIPHER_TEST_P(AEAD, All, V12Plus,
+                          TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+                          TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+                          TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+                          TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+                          TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
+                          TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256);
+INSTANTIATE_CIPHER_TEST_P(CBC12, All, V12,
+                          TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
+                          TLS_RSA_WITH_AES_256_CBC_SHA256,
+                          TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+                          TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+                          TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
+                          TLS_RSA_WITH_AES_128_CBC_SHA256,
+                          TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,
+                          TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
+                          TLS_RSA_WITH_NULL_SHA256);
+INSTANTIATE_CIPHER_TEST_P(CBCStream, Stream, V10ToV12,
+                          TLS_ECDH_ECDSA_WITH_NULL_SHA,
+                          TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
+                          TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
+                          TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
+                          TLS_ECDHE_ECDSA_WITH_NULL_SHA,
+                          TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+                          TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+                          TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+                          // TLS_ECDH_RSA_WITH_NULL_SHA,
+                          // TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
+                          // TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
+                          // TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
+                          TLS_ECDHE_RSA_WITH_NULL_SHA,
+                          TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+                          TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+                          TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA);
+INSTANTIATE_CIPHER_TEST_P(CBCDatagram, Datagram, V11V12,
+                          TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
+                          TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
+                          TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
+                          TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+                          TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+                          TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+                          // TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
+                          // TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
+                          // TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
+                          TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+                          TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+                          TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA);
+
+}  // namespace nspr_test
--- a/security/nss/external_tests/ssl_gtest/ssl_extension_unittest.cc
+++ b/security/nss/external_tests/ssl_gtest/ssl_extension_unittest.cc
@@ -101,17 +101,17 @@ class TlsExtensionInjector : public TlsH
     if (header.handshake_type() == kTlsHandshakeClientHello) {
       TlsParser parser(input);
       if (!TlsExtensionFilter::FindClientHelloExtensions(&parser, header)) {
         return KEEP;
       }
       offset = parser.consumed();
     } else if (header.handshake_type() == kTlsHandshakeServerHello) {
       TlsParser parser(input);
-      if (!TlsExtensionFilter::FindServerHelloExtensions(&parser, header.version())) {
+      if (!TlsExtensionFilter::FindServerHelloExtensions(&parser)) {
         return KEEP;
       }
       offset = parser.consumed();
     } else {
       return KEEP;
     }
 
     *output = input;
@@ -207,16 +207,24 @@ class TlsExtensionTest13
   : public TlsExtensionTestBase,
     public ::testing::WithParamInterface<std::string> {
  public:
   TlsExtensionTest13()
     : TlsExtensionTestBase(TlsConnectTestBase::ToMode(GetParam()),
                            SSL_LIBRARY_VERSION_TLS_1_3) {}
 };
 
+class TlsExtensionTest13Stream
+    : public TlsExtensionTestBase {
+ public:
+  TlsExtensionTest13Stream()
+    : TlsExtensionTestBase(STREAM,
+                           SSL_LIBRARY_VERSION_TLS_1_3) {}
+};
+
 class TlsExtensionTestGeneric
   : public TlsExtensionTestBase,
     public ::testing::WithParamInterface<std::tuple<std::string, uint16_t>> {
  public:
   TlsExtensionTestGeneric()
     : TlsExtensionTestBase(TlsConnectTestBase::ToMode((std::get<0>(GetParam()))),
                            std::get<1>(GetParam())) {}
 };
@@ -650,16 +658,31 @@ TEST_P(TlsExtensionTest13, ModifyDraftVe
   // As above, dropping back to 1.2 fails.
   client_->SetPacketFilter(
       new TlsExtensionDamager(ssl_tls13_draft_version_xtn, 1));
   ConnectExpectFail();
   EXPECT_EQ(SSL_ERROR_PROTOCOL_VERSION_ALERT, client_->error_code());
   EXPECT_EQ(SSL_ERROR_UNSUPPORTED_VERSION, server_->error_code());
 }
 
+#ifdef NSS_ENABLE_TLS_1_3
+// This test only works with TLS because the MAC error causes a
+// timeout on the server.
+TEST_F(TlsExtensionTest13Stream, DropServerKeyShare) {
+  EnsureTlsSetup();
+  server_->SetPacketFilter(
+      new TlsExtensionDropper(ssl_tls13_key_share_xtn));
+  ConnectExpectFail();
+  EXPECT_EQ(SSL_ERROR_MISSING_KEY_SHARE, client_->error_code());
+  // We are trying to decrypt but we can't. Kind of a screwy error
+  // from the TLS 1.3 stack.
+  EXPECT_EQ(SSL_ERROR_BAD_MAC_READ, server_->error_code());
+}
+#endif
+
 INSTANTIATE_TEST_CASE_P(ExtensionStream, TlsExtensionTestGeneric,
                         ::testing::Combine(
                           TlsConnectTestBase::kTlsModesStream,
                           TlsConnectTestBase::kTlsVAll));
 INSTANTIATE_TEST_CASE_P(ExtensionDatagram, TlsExtensionTestGeneric,
                         ::testing::Combine(
                           TlsConnectTestBase::kTlsModesAll,
                           TlsConnectTestBase::kTlsV11Plus));
@@ -669,17 +692,17 @@ INSTANTIATE_TEST_CASE_P(ExtensionDatagra
 INSTANTIATE_TEST_CASE_P(ExtensionTls12Plus, TlsExtensionTest12Plus,
                         ::testing::Combine(
                           TlsConnectTestBase::kTlsModesAll,
                           TlsConnectTestBase::kTlsV12Plus));
 
 INSTANTIATE_TEST_CASE_P(ExtensionPre13Stream, TlsExtensionTestPre13,
                         ::testing::Combine(
                           TlsConnectTestBase::kTlsModesStream,
-                          TlsConnectTestBase::kTlsV10To12));
+                          TlsConnectTestBase::kTlsV10ToV12));
 INSTANTIATE_TEST_CASE_P(ExtensionPre13Datagram, TlsExtensionTestPre13,
                         ::testing::Combine(
                           TlsConnectTestBase::kTlsModesAll,
                           TlsConnectTestBase::kTlsV11V12));
 
 #ifdef NSS_ENABLE_TLS_1_3
 INSTANTIATE_TEST_CASE_P(ExtensionTls13, TlsExtensionTest13,
                         TlsConnectTestBase::kTlsModesAll);
--- a/security/nss/external_tests/ssl_gtest/ssl_loopback_unittest.cc
+++ b/security/nss/external_tests/ssl_gtest/ssl_loopback_unittest.cc
@@ -105,18 +105,16 @@ class TlsServerKeyExchangeEcdhe {
     }
 
     return parser.ReadVariable(&public_key_, 1);
   }
 
   DataBuffer public_key_;
 };
 
-class TlsChaCha20Poly1305Test : public TlsConnectTls12 {};
-
 TEST_P(TlsConnectGeneric, SetupOnly) {}
 
 TEST_P(TlsConnectGeneric, Connect) {
   SetExpectedVersion(std::get<1>(GetParam()));
   Connect();
   CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
 }
 
@@ -141,20 +139,16 @@ TEST_P(TlsConnectGenericPre13, ConnectEc
   SetExpectedVersion(std::get<1>(GetParam()));
   Reset(TlsAgent::kServerEcdhEcdsa);
   EnableSomeEcdhCiphers();
 
   Connect();
   CheckKeys(ssl_kea_ecdh, ssl_auth_ecdh_ecdsa);
 }
 
-TEST_P(TlsConnectStreamPre13, ConnectRC4) {
-  ConnectWithCipherSuite(TLS_RSA_WITH_RC4_128_SHA);
-}
-
 TEST_P(TlsConnectGenericPre13, ConnectFalseStart) {
   client_->EnableFalseStart();
   Connect();
   SendReceive();
 }
 
 TEST_P(TlsConnectGenericPre13, ConnectResumed) {
   ConfigureSessionCache(RESUME_SESSIONID, RESUME_SESSIONID);
@@ -698,29 +692,16 @@ TEST_P(TlsConnectGenericPre13, ConnectEc
                         dhe1.public_key_.len())));
 }
 
 TEST_P(TlsConnectGeneric, ConnectSendReceive) {
   Connect();
   SendReceive();
 }
 
-TEST_P(TlsChaCha20Poly1305Test, SendReceiveChaCha20Poly1305DheRsa) {
-  ConnectWithCipherSuite(TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256);
-}
-
-TEST_P(TlsChaCha20Poly1305Test, SendReceiveChaCha20Poly1305EcdheRsa) {
-  ConnectWithCipherSuite(TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256);
-}
-
-TEST_P(TlsChaCha20Poly1305Test, SendReceiveChaCha20Poly1305EcdheEcdsa) {
-  Reset(TlsAgent::kServerEcdsa);
-  ConnectWithCipherSuite(TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256);
-}
-
 // The next two tests takes advantage of the fact that we
 // automatically read the first 1024 bytes, so if
 // we provide 1200 bytes, they overrun the read buffer
 // provided by the calling test.
 
 // DTLS should return an error.
 TEST_P(TlsConnectDatagram, ShortRead) {
   Connect();
@@ -1006,55 +987,124 @@ TEST_F(TlsConnectTest, TestTls13Resumpti
   CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
   uint16_t original_suite;
   EXPECT_TRUE(client_->cipher_suite(&original_suite));
 
   Reset();
   ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
   TlsExtensionCapture *c1 =
       new TlsExtensionCapture(kTlsExtensionPreSharedKey);
+  client_->SetPacketFilter(c1);
   client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
                            SSL_LIBRARY_VERSION_TLS_1_3);
   server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
                            SSL_LIBRARY_VERSION_TLS_1_3);
   ExpectResumption(RESUME_TICKET);
   Connect();
   SendReceive();
   CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
-  DataBuffer psk1(c1->extension());
-  ASSERT_GE(psk1.len(), 0UL);
-  ASSERT_TRUE(!!client_->peer_cert());
+  // The filter will go away when we reset, so save the captured extension.
+  DataBuffer initialTicket(c1->extension());
+  ASSERT_LT(0U, initialTicket.len());
+
+  ScopedCERTCertificate cert1(SSL_PeerCertificate(client_->ssl_fd()));
+  ASSERT_TRUE(!!cert1.get());
 
   Reset();
   ClearStats();
   ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
   TlsExtensionCapture *c2 =
       new TlsExtensionCapture(kTlsExtensionPreSharedKey);
+  client_->SetPacketFilter(c2);
   client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
                            SSL_LIBRARY_VERSION_TLS_1_3);
   server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
                            SSL_LIBRARY_VERSION_TLS_1_3);
   ExpectResumption(RESUME_TICKET);
   Connect();
   SendReceive();
   CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
-  DataBuffer psk2(c2->extension());
-  ASSERT_GE(psk2.len(), 0UL);
-  ASSERT_TRUE(!!client_->peer_cert());
+  ASSERT_LT(0U, c2->extension().len());
+
+  ScopedCERTCertificate cert2(SSL_PeerCertificate(client_->ssl_fd()));
+  ASSERT_TRUE(!!cert2.get());
 
   // Check that the cipher suite is reported the same on both sides, though in
   // TLS 1.3 resumption actually negotiates a different cipher suite.
   uint16_t resumed_suite;
   EXPECT_TRUE(server_->cipher_suite(&resumed_suite));
   EXPECT_EQ(original_suite, resumed_suite);
   EXPECT_TRUE(client_->cipher_suite(&resumed_suite));
   EXPECT_EQ(original_suite, resumed_suite);
 
   // TODO(ekr@rtfm.com): This will change when we fix bug 1257047.
-  ASSERT_EQ(psk1, psk2);
+  ASSERT_EQ(initialTicket, c2->extension());
+}
+
+TEST_F(TlsConnectTest, DisableClientPSKAndFailToResume) {
+  ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+  client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
+                           SSL_LIBRARY_VERSION_TLS_1_3);
+  server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
+                           SSL_LIBRARY_VERSION_TLS_1_3);
+  Connect();
+  SendReceive(); // Need to read so that we absorb the session ticket.
+  CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
+
+  Reset();
+  ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+  TlsExtensionCapture *capture =
+      new TlsExtensionCapture(kTlsExtensionPreSharedKey);
+  client_->SetPacketFilter(capture);
+  client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
+                           SSL_LIBRARY_VERSION_TLS_1_3);
+  server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
+                           SSL_LIBRARY_VERSION_TLS_1_3);
+  EXPECT_EQ(SECSuccess,
+            SSL_CipherPrefSet(client_->ssl_fd(),
+                              TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256,
+                              PR_FALSE));
+  ExpectResumption(RESUME_NONE);
+  Connect();
+  CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
+  EXPECT_EQ(0U, capture->extension().len());
+}
+
+TEST_F(TlsConnectTest, DisableServerPSKAndFailToResume) {
+  ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+  client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
+                           SSL_LIBRARY_VERSION_TLS_1_3);
+  server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
+                           SSL_LIBRARY_VERSION_TLS_1_3);
+  Connect();
+  SendReceive(); // Need to read so that we absorb the session ticket.
+  CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
+
+  Reset();
+  ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+  TlsExtensionCapture *clientCapture =
+      new TlsExtensionCapture(kTlsExtensionPreSharedKey);
+  client_->SetPacketFilter(clientCapture);
+  TlsExtensionCapture *serverCapture =
+      new TlsExtensionCapture(kTlsExtensionPreSharedKey);
+  server_->SetPacketFilter(serverCapture);
+  client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
+                           SSL_LIBRARY_VERSION_TLS_1_3);
+  server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
+                           SSL_LIBRARY_VERSION_TLS_1_3);
+  EXPECT_EQ(SECSuccess,
+            SSL_CipherPrefSet(server_->ssl_fd(),
+                              TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256,
+                              PR_FALSE));
+  ExpectResumption(RESUME_NONE);
+  Connect();
+  CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
+  // The client should have the extension, but the server should not.
+  EXPECT_LT(0U, clientCapture->extension().len());
+  EXPECT_EQ(0U, serverCapture->extension().len());
 }
 
 TEST_P(TlsConnectDatagram, TestDtlsHolddownExpiry) {
   Connect();
   std::cerr << "Expiring holddown timer\n";
   SSLInt_ForceTimerExpiry(client_->ssl_fd());
   SSLInt_ForceTimerExpiry(server_->ssl_fd());
   SendReceive();
@@ -1093,17 +1143,17 @@ class BeforeFinished : public TlsRecordF
           before_ccs_();
 
           // Write the CCS out as a separate write, so that we can make
           // progress. Ordinarily, libssl sends the CCS and Finished together,
           // but that means that they both get processed together.
           DataBuffer ccs;
           header.Write(&ccs, 0, body);
           server_->SendDirect(ccs);
-          ForceRead();
+          client_->Handshake();
           state_ = AFTER_CCS;
           // Request that the original record be dropped by the filter.
           return DROP;
         }
         break;
 
       case AFTER_CCS:
         EXPECT_EQ(kTlsHandshakeType, header.content_type());
@@ -1116,26 +1166,16 @@ class BeforeFinished : public TlsRecordF
 
       case DONE:
         break;
     }
     return KEEP;
   }
 
  private:
-  void ForceRead() {
-    // Read from the socket to get libssl to process the handshake messages that
-    // were sent from the server up until now.
-    uint8_t block[10];
-    int32_t rv = PR_Read(client_->ssl_fd(), block, sizeof(block));
-    // Expect a blocking error here, since the handshake shouldn't have completed.
-    EXPECT_GT(0, rv);
-    EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PR_GetError());
-  }
-
   TlsAgent* client_;
   TlsAgent* server_;
   VoidFunction before_ccs_;
   VoidFunction before_finished_;
   HandshakeState state_;
 };
 
 TEST_P(TlsConnectGenericPre13, ClientWriteBetweenCCSAndFinishedWithFalseStart) {
@@ -1226,48 +1266,144 @@ TEST_P(TlsConnectGenericPre13, ConnectEC
 
 TEST_P(TlsConnectGenericPre13, ConnectECDHEmptyClientPoint) {
   // add packet filter
   client_->SetPacketFilter(new ECCClientKEXFilter());
   ConnectExpectFail();
   server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_KEY_EXCH);
 }
 
+#ifdef NSS_ENABLE_TLS_1_3
+// Running code after the client has started processing the encrypted part of
+// the server's first flight, but before the Finished is processed is very hard
+// in TLS 1.3.  These encrypted messages are sent in a single encrypted blob.
+// The following test uses DTLS to make it possible to force the client to
+// process the handshake in pieces.
+//
+// The first encrypted message from the server is dropped, and the MTU is
+// reduced to just below the original message size so that the server sends two
+// messages.  The Finished message is then processed separately.
+class BeforeFinished13 : public PacketFilter {
+ private:
+  enum HandshakeState {
+    INIT,
+    BEFORE_FIRST_FRAGMENT,
+    BEFORE_SECOND_FRAGMENT,
+    DONE
+  };
+  typedef std::function<void(void)> VoidFunction;
+
+ public:
+  BeforeFinished13(TlsAgent* client, TlsAgent *server,
+                   VoidFunction before_finished)
+      : client_(client),
+        server_(server),
+        before_finished_(before_finished),
+        records_(0) {}
+
+ protected:
+  virtual PacketFilter::Action Filter(const DataBuffer& input,
+                                      DataBuffer* output) {
+    switch (++records_) {
+      case 1:
+        // Packet 1 is the server's entire first flight.  Drop it.
+        EXPECT_EQ(SECSuccess,
+                  SSLInt_SetMTU(server_->ssl_fd(), input.len() - 1));
+        return DROP;
+
+        // Packet 2 is the first part of the server's retransmitted first
+        // flight.  Keep that.
+
+      case 3:
+        // Packet 3 is the second part of the server's retransmitted first
+        // flight.  Before passing that on, make sure that the client processes
+        // packet 2, then call the before_finished_() callback.
+        client_->Handshake();
+        before_finished_();
+        break;
+
+      default:
+        break;
+    }
+    return KEEP;
+  }
+
+ private:
+  TlsAgent *client_;
+  TlsAgent *server_;
+  VoidFunction before_finished_;
+  size_t records_;
+};
+
+// This test uses an AuthCertificateCallback that blocks.  A filter is used to
+// split the server's first flight into two pieces.  Before the second piece is
+// processed by the client, SSL_AuthCertificateComplete() is called.
+TEST_F(TlsConnectDatagram13, AuthCompleteBeforeFinished) {
+  client_->SetAuthCertificateCallback(
+      [](TlsAgent&, PRBool, PRBool) -> SECStatus {
+        return SECWouldBlock;
+      });
+  server_->SetPacketFilter(new BeforeFinished13(client_, server_, [this]() {
+        EXPECT_EQ(SECSuccess, SSL_AuthCertificateComplete(client_->ssl_fd(), 0));
+      }));
+  Connect();
+}
+
+static void TriggerAuthComplete(PollTarget *target, Event event) {
+  std::cerr << "client: call SSL_AuthCertificateComplete" << std::endl;
+  EXPECT_EQ(TIMER_EVENT, event);
+  TlsAgent* client = static_cast<TlsAgent*>(target);
+  EXPECT_EQ(SECSuccess, SSL_AuthCertificateComplete(client->ssl_fd(), 0));
+}
+
+// This test uses a simple AuthCertificateCallback.  Due to the way that the
+// entire server flight is processed, the call to SSL_AuthCertificateComplete
+// will trigger after the Finished message is processed.
+TEST_F(TlsConnectDatagram13, AuthCompleteAfterFinished) {
+  client_->SetAuthCertificateCallback(
+      [this](TlsAgent&, PRBool, PRBool) -> SECStatus {
+        Poller::Timer *timer_handle;
+        // This is really just to unroll the stack.
+        Poller::Instance()->SetTimer(1U, client_, TriggerAuthComplete,
+                                     &timer_handle);
+        return SECWouldBlock;
+      });
+  Connect();
+}
+#endif // NSS_ENABLE_TLS_1_3
+
 INSTANTIATE_TEST_CASE_P(GenericStream, TlsConnectGeneric,
                         ::testing::Combine(
                           TlsConnectTestBase::kTlsModesStream,
                           TlsConnectTestBase::kTlsVAll));
 INSTANTIATE_TEST_CASE_P(GenericDatagram, TlsConnectGeneric,
                         ::testing::Combine(
                           TlsConnectTestBase::kTlsModesDatagram,
                           TlsConnectTestBase::kTlsV11Plus));
 
 INSTANTIATE_TEST_CASE_P(StreamOnly, TlsConnectStream,
                         TlsConnectTestBase::kTlsVAll);
 INSTANTIATE_TEST_CASE_P(DatagramOnly, TlsConnectDatagram,
                         TlsConnectTestBase::kTlsV11Plus);
 
-INSTANTIATE_TEST_CASE_P(ChaCha20, TlsChaCha20Poly1305Test,
-                        TlsConnectTestBase::kTlsModesAll);
-
 INSTANTIATE_TEST_CASE_P(Pre12Stream, TlsConnectPre12,
                         ::testing::Combine(
                           TlsConnectTestBase::kTlsModesStream,
                           TlsConnectTestBase::kTlsV10V11));
 INSTANTIATE_TEST_CASE_P(Pre12Datagram, TlsConnectPre12,
                         ::testing::Combine(
                           TlsConnectTestBase::kTlsModesDatagram,
                           TlsConnectTestBase::kTlsV11));
 
 INSTANTIATE_TEST_CASE_P(Version12Only, TlsConnectTls12,
                         TlsConnectTestBase::kTlsModesAll);
 
 INSTANTIATE_TEST_CASE_P(Pre13Stream, TlsConnectGenericPre13,
                         ::testing::Combine(
                           TlsConnectTestBase::kTlsModesStream,
-                          TlsConnectTestBase::kTlsV10To12));
+                          TlsConnectTestBase::kTlsV10ToV12));
 INSTANTIATE_TEST_CASE_P(Pre13Datagram, TlsConnectGenericPre13,
                         ::testing::Combine(
                              TlsConnectTestBase::kTlsModesDatagram,
                              TlsConnectTestBase::kTlsV11V12));
 INSTANTIATE_TEST_CASE_P(Pre13StreamOnly, TlsConnectStreamPre13,
-                        TlsConnectTestBase::kTlsV10To12);
+                        TlsConnectTestBase::kTlsV10ToV12);
 }  // namespace nspr_test
--- a/security/nss/external_tests/ssl_gtest/test_io.cc
+++ b/security/nss/external_tests/ssl_gtest/test_io.cc
@@ -22,17 +22,17 @@ namespace nss_test {
 static PRDescIdentity test_fd_identity = PR_INVALID_IO_LAYER;
 
 #define UNIMPLEMENTED()                          \
   std::cerr << "Call to unimplemented function " \
             << __FUNCTION__ << std::endl;        \
   PR_ASSERT(PR_FALSE);                           \
   PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0)
 
-#define LOG(a) std::cerr << name_ << ": " << a << std::endl;
+#define LOG(a) std::cerr << name_ << ": " << a << std::endl
 
 class Packet : public DataBuffer {
  public:
   Packet(const DataBuffer& buf) : DataBuffer(buf), offset_(0) {}
 
   void Advance(size_t delta) {
     PR_ASSERT(offset_ + delta <= len());
     offset_ = std::min(len(), offset_ + delta);
@@ -42,17 +42,19 @@ class Packet : public DataBuffer {
   size_t remaining() const { return len() - offset_; }
 
  private:
   size_t offset_;
 };
 
 // Implementation of NSPR methods
 static PRStatus DummyClose(PRFileDesc *f) {
+  DummyPrSocket *io = reinterpret_cast<DummyPrSocket *>(f->secret);
   f->secret = nullptr;
+  delete io;
   return PR_SUCCESS;
 }
 
 static int32_t DummyRead(PRFileDesc *f, void *buf, int32_t length) {
   DummyPrSocket *io = reinterpret_cast<DummyPrSocket *>(f->secret);
   return io->Read(buf, length);
 }
 
@@ -251,17 +253,20 @@ static int32_t DummyReserved(PRFileDesc 
 }
 
 DummyPrSocket::~DummyPrSocket() {
   Reset();
 }
 
 void DummyPrSocket::Reset() {
   delete filter_;
-  peer_ = nullptr;
+  if (peer_) {
+    peer_->SetPeer(nullptr);
+    peer_ = nullptr;
+  }
   while (!input_.empty())
   {
     Packet* front = input_.front();
     input_.pop();
     delete front;
   }
 }
 
--- a/security/nss/external_tests/ssl_gtest/tls_agent.cc
+++ b/security/nss/external_tests/ssl_gtest/tls_agent.cc
@@ -1,59 +1,62 @@
 /* -*- 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 "tls_agent.h"
-
+#include "tls_parser.h"
 #include "pk11func.h"
 #include "ssl.h"
 #include "sslerr.h"
 #include "sslproto.h"
 #include "keyhi.h"
 #include "databuffer.h"
 
 extern "C" {
 // This is not something that should make you happy.
 #include "libssl_internals.h"
 }
 
 #define GTEST_HAS_RTTI 0
 #include "gtest/gtest.h"
 #include "scoped_ptrs.h"
 
+extern std::string g_working_dir_path;
+
 namespace nss_test {
 
-
 const char* TlsAgent::states[] = {"INIT", "CONNECTING", "CONNECTED", "ERROR"};
 
 const std::string TlsAgent::kClient = "client"; // both sign and encrypt
 const std::string TlsAgent::kServerRsa = "rsa"; // both sign and encrypt
 const std::string TlsAgent::kServerRsaSign = "rsa_sign";
 const std::string TlsAgent::kServerRsaDecrypt = "rsa_decrypt";
 const std::string TlsAgent::kServerEcdsa = "ecdsa";
-const std::string TlsAgent::kServerEcdhRsa = "ecdh_rsa"; // not supported yet
+// TODO: const std::string TlsAgent::kServerEcdhRsa = "ecdh_rsa";
 const std::string TlsAgent::kServerEcdhEcdsa = "ecdh_ecdsa";
+const std::string TlsAgent::kServerDsa = "dsa";
 
 TlsAgent::TlsAgent(const std::string& name, Role role, Mode mode)
   : name_(name),
     mode_(mode),
     server_key_bits_(0),
     pr_fd_(nullptr),
     adapter_(nullptr),
     ssl_fd_(nullptr),
     role_(role),
     state_(STATE_INIT),
     timer_handle_(nullptr),
     falsestart_enabled_(false),
     expected_version_(0),
     expected_cipher_suite_(0),
     expect_resumption_(false),
+    expect_client_auth_(false),
     can_falsestart_hook_called_(false),
     sni_hook_called_(false),
     auth_certificate_hook_called_(false),
     handshake_callback_called_(false),
     error_code_(0),
     send_ctr_(0),
     recv_ctr_(0),
     expected_read_error_(false),
@@ -67,16 +70,17 @@ TlsAgent::TlsAgent(const std::string& na
                                             ssl_variant_stream : ssl_variant_datagram,
                                             &vrange_);
   EXPECT_EQ(SECSuccess, rv);
 }
 
 TlsAgent::~TlsAgent() {
   if (adapter_) {
     Poller::Instance()->Cancel(READABLE_EVENT, adapter_);
+    // The adapter is closed when the FD closes.
   }
   if (timer_handle_) {
     timer_handle_->Cancel();
   }
 
   if (pr_fd_) {
     PR_Close(pr_fd_);
   }
@@ -492,16 +496,17 @@ void TlsAgent::CheckCallbacks() const {
     // (80 bits) is chosen.  Don't test that: plan to remove bad ciphers.
     EXPECT_EQ(falsestart_enabled_ && !expect_resumption_,
               can_falsestart_hook_called_);
   }
 }
 
 void TlsAgent::Connected() {
   LOG("Handshake success");
+  CheckPreliminaryInfo();
   CheckCallbacks();
 
   SECStatus rv = SSL_GetChannelInfo(ssl_fd_, &info_, sizeof(info_));
   EXPECT_EQ(SECSuccess, rv);
   EXPECT_EQ(sizeof(info_), info_.length);
 
   // Preliminary values are exposed through callbacks during the handshake.
   // If either expected values were set or the callbacks were called, check
@@ -575,16 +580,17 @@ void TlsAgent::Handshake() {
 
   int32_t err = PR_GetError();
   switch (err) {
     case PR_WOULD_BLOCK_ERROR:
       LOG("Would have blocked");
       if (mode_ == DGRAM) {
         if (timer_handle_) {
           timer_handle_->Cancel();
+          timer_handle_ = nullptr;
         }
 
         PRIntervalTime timeout;
         rv = DTLS_GetHandshakeTimeout(ssl_fd_, &timeout);
         if (rv == SECSuccess) {
           Poller::Instance()->SetTimer(timeout, this,
                                        &TlsAgent::ReadableCallback,
                                        &timer_handle_);
@@ -648,33 +654,35 @@ void TlsAgent::SendData(size_t bytes, si
   }
 }
 
 void TlsAgent::ReadBytes() {
   uint8_t block[1024];
 
   int32_t rv = PR_Read(ssl_fd_, block, sizeof(block));
   LOG("ReadBytes " << rv);
+  int32_t err;
 
   if (rv >= 0) {
     size_t count = static_cast<size_t>(rv);
     for (size_t i = 0; i < count; ++i) {
       ASSERT_EQ(recv_ctr_ & 0xff, block[i]);
       recv_ctr_++;
     }
   } else {
-    int32_t err = PR_GetError();
+    err = PR_GetError();
     LOG("Read error " << err << ": " << PORT_ErrorToString(err));
     if (err != PR_WOULD_BLOCK_ERROR && expected_read_error_) {
       error_code_ = err;
     }
   }
 
   // If closed, then don't bother waiting around.
-  if (rv) {
+  if (rv > 0 || (rv < 0 && err == PR_WOULD_BLOCK_ERROR)) {
+    LOG("Re-arming");
     Poller::Instance()->Wait(READABLE_EVENT, adapter_, this,
                              &TlsAgent::ReadableCallback);
   }
 }
 
 void TlsAgent::ResetSentBytes() {
   send_ctr_ = 0;
 }
@@ -694,16 +702,26 @@ void TlsAgent::ConfigureSessionCache(Ses
                      PR_TRUE : PR_FALSE);
   EXPECT_EQ(SECSuccess, rv);
 }
 
 static const std::string kTlsRolesAllArr[] = {"CLIENT", "SERVER"};
 ::testing::internal::ParamGenerator<std::string>
   TlsAgentTestBase::kTlsRolesAll = ::testing::ValuesIn(kTlsRolesAllArr);
 
+void TlsAgentTestBase::SetUp() {
+  SSL_ConfigServerSessionIDCache(1024, 0, 0, g_working_dir_path.c_str());
+}
+
+void TlsAgentTestBase::TearDown() {
+  delete agent_;
+  SSL_ClearSessionCache();
+  SSL_ShutdownServerSessionIDCache();
+}
+
 void TlsAgentTestBase::Init() {
   agent_ = new TlsAgent(
       role_ == TlsAgent::CLIENT ? TlsAgent::kClient : TlsAgent::kServerRsa,
       role_, mode_);
   agent_->Init();
   fd_ = DummyPrSocket::CreateFD("dummy", mode_);
   agent_->adapter()->SetPeer(
       DummyPrSocket::GetAdapter(fd_));
@@ -725,9 +743,77 @@ void TlsAgentTestBase::ProcessMessage(co
 
   ASSERT_EQ(expected_state, agent_->state());
 
   if (expected_state == TlsAgent::STATE_ERROR) {
     ASSERT_EQ(error_code, agent_->error_code());
   }
 }
 
+void TlsAgentTestBase::MakeRecord(uint8_t type, uint16_t version,
+                                  const uint8_t *buf, size_t len,
+                                  DataBuffer* out, uint32_t seq_num)
+{
+  size_t index = 0;
+  index = out->Write(index, type, 1);; // Content Type
+  index = out->Write(index,
+             mode_ == STREAM ? version :
+             TlsVersionToDtlsVersion(version),
+             2); // Version
+  if (mode_ == DGRAM) {
+    index = out->Write(index, 0U, 4);
+    index = out->Write(index, seq_num, 4);
+  }
+  index = out->Write(index, len, 2); // Length
+  out->Write(index, buf, len);
+}
+
+void TlsAgentTestBase::MakeHandshakeMessage(uint8_t hs_type,
+                                            const uint8_t *data,
+                                            size_t hs_len,
+                                            DataBuffer* out,
+                                            uint32_t seq_num) {
+  return MakeHandshakeMessageFragment(
+      hs_type, data, hs_len, out, seq_num, 0, 0);
+}
+void TlsAgentTestBase::MakeHandshakeMessageFragment(uint8_t hs_type,
+                                                    const uint8_t *data,
+                                                    size_t hs_len,
+                                                    DataBuffer* out,
+                                                    uint32_t seq_num,
+                                                    uint32_t fragment_offset,
+                                                    uint32_t fragment_length) {
+  size_t index = 0;
+  if (!fragment_length)
+    fragment_length = hs_len;
+  index = out->Write(index, hs_type, 1); // Handshake record type.
+  index = out->Write(index, hs_len, 3); // Handshake length
+  if (mode_ == DGRAM) {
+    index = out->Write(index, seq_num, 2);
+    index = out->Write(index, fragment_offset, 3);
+    index = out->Write(index, fragment_length, 3);
+  }
+  if (data) {
+    index = out->Write(index, data, fragment_length);
+  } else {
+    for (size_t i = 0; i < fragment_length; ++i) {
+      index = out->Write(index, 1, 1);
+    }
+  }
+}
+
+void TlsAgentTestBase::MakeTrivialHandshakeRecord(uint8_t hs_type,
+                                                  size_t hs_len,
+                                                  DataBuffer* out) {
+  size_t index = 0;
+  index = out->Write(index, kTlsHandshakeType, 1); // Content Type
+  index = out->Write(index, 3, 1); // Version high
+  index = out->Write(index, 1, 1); // Version low
+  index =out->Write(index, 4 + hs_len, 2); // Length
+
+  index = out->Write(index, hs_type, 1); // Handshake record type.
+  index = out->Write(index, hs_len, 3); // Handshake length
+  for (size_t i = 0; i < hs_len; ++i) {
+    index = out->Write(index, 1, 1);
+  }
+}
+
 } // namespace nss_test
--- a/security/nss/external_tests/ssl_gtest/tls_agent.h
+++ b/security/nss/external_tests/ssl_gtest/tls_agent.h
@@ -50,17 +50,18 @@ class TlsAgent : public PollTarget {
   enum State { STATE_INIT, STATE_CONNECTING, STATE_CONNECTED, STATE_ERROR };
 
   static const std::string kClient; // the client key is sign only
   static const std::string kServerRsa; // both sign and encrypt
   static const std::string kServerRsaSign;
   static const std::string kServerRsaDecrypt;
   static const std::string kServerEcdsa;
   static const std::string kServerEcdhEcdsa;
-  static const std::string kServerEcdhRsa; // not supported yet
+  // TODO: static const std::string kServerEcdhRsa;
+  static const std::string kServerDsa;
 
   TlsAgent(const std::string& name, Role role, Mode mode);
   virtual ~TlsAgent();
 
   bool Init() {
     pr_fd_ = DummyPrSocket::CreateFD(name_, mode_);
     if (!pr_fd_) return false;
 
@@ -275,18 +276,18 @@ class TlsAgent : public PollTarget {
     EXPECT_FALSE(agent->can_falsestart_hook_called_);
     agent->can_falsestart_hook_called_ = true;
     *canFalseStart = true;
     return SECSuccess;
   }
 
   static void HandshakeCallback(PRFileDesc *fd, void *arg) {
     TlsAgent* agent = reinterpret_cast<TlsAgent*>(arg);
-    agent->CheckPreliminaryInfo();
     agent->handshake_callback_called_ = true;
+    agent->Connected();
     if (agent->handshake_callback_) {
       agent->handshake_callback_(*agent);
     }
   }
 
   void CheckCallbacks() const;
   void Connected();
 
@@ -325,22 +326,42 @@ class TlsAgentTestBase : public ::testin
   static ::testing::internal::ParamGenerator<std::string> kTlsRolesAll;
 
   TlsAgentTestBase(TlsAgent::Role role,
                    Mode mode) : agent_(nullptr),
                                 fd_(nullptr),
                                 role_(role),
                                 mode_(mode) {}
   ~TlsAgentTestBase() {
-    delete agent_;
     if (fd_) {
       PR_Close(fd_);
     }
   }
 
+  void SetUp();
+  void TearDown();
+
+  void MakeRecord(uint8_t type, uint16_t version,
+                  const uint8_t *buf, size_t len,
+                  DataBuffer* out, uint32_t seq_num = 0);
+  void MakeHandshakeMessage(uint8_t hs_type,
+                            const uint8_t *data,
+                            size_t hs_len,
+                            DataBuffer* out,
+                            uint32_t seq_num = 0);
+  void MakeHandshakeMessageFragment(uint8_t hs_type,
+                                    const uint8_t *data,
+                                    size_t hs_len,
+                                    DataBuffer* out,
+                                    uint32_t seq_num,
+                                    uint32_t fragment_offset,
+                                    uint32_t fragment_length);
+  void MakeTrivialHandshakeRecord(uint8_t hs_type,
+                                  size_t hs_len,
+                                  DataBuffer* out);
   static inline TlsAgent::Role ToRole(const std::string& str) {
     return str == "CLIENT" ? TlsAgent::CLIENT : TlsAgent::SERVER;
   }
 
   static inline Mode ToMode(const std::string& str) {
     return str == "TLS" ? STREAM : DGRAM;
   }
 
@@ -352,24 +373,40 @@ class TlsAgentTestBase : public ::testin
                       TlsAgent::State expected_state,
                       int32_t error_code = 0);
 
 
   TlsAgent* agent_;
   PRFileDesc* fd_;
   TlsAgent::Role role_;
   Mode mode_;
-  SSLKEAType kea_;
 };
 
 class TlsAgentTest :
       public TlsAgentTestBase,
       public ::testing::WithParamInterface
       <std::tuple<std::string,std::string>> {
  public:
   TlsAgentTest() :
       TlsAgentTestBase(ToRole(std::get<0>(GetParam())),
                        ToMode(std::get<1>(GetParam()))) {}
 };
 
-}  // namespace nss_test
+class TlsAgentTestClient : public TlsAgentTestBase,
+                           public ::testing::WithParamInterface<std::string> {
+ public:
+  TlsAgentTestClient() : TlsAgentTestBase(TlsAgent::CLIENT,
+                                          ToMode(GetParam())) {}
+};
+
+class TlsAgentStreamTestClient : public TlsAgentTestBase {
+ public:
+  TlsAgentStreamTestClient() : TlsAgentTestBase(TlsAgent::CLIENT, STREAM) {}
+};
+
+class TlsAgentDgramTestClient : public TlsAgentTestBase {
+ public:
+  TlsAgentDgramTestClient() : TlsAgentTestBase(TlsAgent::CLIENT, DGRAM) {}
+};
+
+} // namespace nss_test
 
 #endif
--- a/security/nss/external_tests/ssl_gtest/tls_connect.cc
+++ b/security/nss/external_tests/ssl_gtest/tls_connect.cc
@@ -30,25 +30,28 @@ static const std::string kTlsModesAllArr
   TlsConnectTestBase::kTlsModesAll = ::testing::ValuesIn(kTlsModesAllArr);
 
 static const uint16_t kTlsV10Arr[] = {SSL_LIBRARY_VERSION_TLS_1_0};
 ::testing::internal::ParamGenerator<uint16_t>
   TlsConnectTestBase::kTlsV10 = ::testing::ValuesIn(kTlsV10Arr);
 static const uint16_t kTlsV11Arr[] = {SSL_LIBRARY_VERSION_TLS_1_1};
 ::testing::internal::ParamGenerator<uint16_t>
   TlsConnectTestBase::kTlsV11 = ::testing::ValuesIn(kTlsV11Arr);
+static const uint16_t kTlsV12Arr[] = {SSL_LIBRARY_VERSION_TLS_1_2};
+::testing::internal::ParamGenerator<uint16_t>
+  TlsConnectTestBase::kTlsV12 = ::testing::ValuesIn(kTlsV12Arr);
 static const uint16_t kTlsV10V11Arr[] = {SSL_LIBRARY_VERSION_TLS_1_0,
                                          SSL_LIBRARY_VERSION_TLS_1_1};
 ::testing::internal::ParamGenerator<uint16_t>
   TlsConnectTestBase::kTlsV10V11 = ::testing::ValuesIn(kTlsV10V11Arr);
-static const uint16_t kTlsV10To12Arr[] = {SSL_LIBRARY_VERSION_TLS_1_0,
-                                         SSL_LIBRARY_VERSION_TLS_1_1,
-                                         SSL_LIBRARY_VERSION_TLS_1_2};
+static const uint16_t kTlsV10ToV12Arr[] = {SSL_LIBRARY_VERSION_TLS_1_0,
+                                           SSL_LIBRARY_VERSION_TLS_1_1,
+                                           SSL_LIBRARY_VERSION_TLS_1_2};
 ::testing::internal::ParamGenerator<uint16_t>
-  TlsConnectTestBase::kTlsV10To12 = ::testing::ValuesIn(kTlsV10To12Arr);
+  TlsConnectTestBase::kTlsV10ToV12 = ::testing::ValuesIn(kTlsV10ToV12Arr);
 static const uint16_t kTlsV11V12Arr[] = {SSL_LIBRARY_VERSION_TLS_1_1,
                                          SSL_LIBRARY_VERSION_TLS_1_2};
 ::testing::internal::ParamGenerator<uint16_t>
   TlsConnectTestBase::kTlsV11V12 = ::testing::ValuesIn(kTlsV11V12Arr);
 
 static const uint16_t kTlsV11PlusArr[] = {
 #ifdef NSS_ENABLE_TLS_1_3
   SSL_LIBRARY_VERSION_TLS_1_3,
--- a/security/nss/external_tests/ssl_gtest/tls_connect.h
+++ b/security/nss/external_tests/ssl_gtest/tls_connect.h
@@ -4,16 +4,17 @@
  * 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 tls_connect_h_
 #define tls_connect_h_
 
 #include <tuple>
 
+#include "sslproto.h"
 #include "sslt.h"
 
 #include "tls_agent.h"
 
 #define GTEST_HAS_RTTI 0
 #include "gtest/gtest.h"
 
 namespace nss_test {
@@ -21,19 +22,20 @@ namespace nss_test {
 // A generic TLS connection test base.
 class TlsConnectTestBase : public ::testing::Test {
  public:
   static ::testing::internal::ParamGenerator<std::string> kTlsModesStream;
   static ::testing::internal::ParamGenerator<std::string> kTlsModesDatagram;
   static ::testing::internal::ParamGenerator<std::string> kTlsModesAll;
   static ::testing::internal::ParamGenerator<uint16_t> kTlsV10;
   static ::testing::internal::ParamGenerator<uint16_t> kTlsV11;
+  static ::testing::internal::ParamGenerator<uint16_t> kTlsV12;
   static ::testing::internal::ParamGenerator<uint16_t> kTlsV10V11;
   static ::testing::internal::ParamGenerator<uint16_t> kTlsV11V12;
-  static ::testing::internal::ParamGenerator<uint16_t> kTlsV10To12;
+  static ::testing::internal::ParamGenerator<uint16_t> kTlsV10ToV12;
   static ::testing::internal::ParamGenerator<uint16_t> kTlsV13;
   static ::testing::internal::ParamGenerator<uint16_t> kTlsV11Plus;
   static ::testing::internal::ParamGenerator<uint16_t> kTlsV12Plus;
   static ::testing::internal::ParamGenerator<uint16_t> kTlsVAll;
 
   static inline Mode ToMode(const std::string& str) {
     return str == "TLS" ? STREAM : DGRAM;
   }
@@ -151,15 +153,25 @@ class TlsConnectPre12
 // A TLS 1.2 only generic test.
 class TlsConnectTls12
   : public TlsConnectTestBase,
     public ::testing::WithParamInterface<std::string> {
  public:
   TlsConnectTls12();
 };
 
+#ifdef NSS_ENABLE_TLS_1_3
+// A TLS 1.3 only generic test.
+class TlsConnectDatagram13
+  : public TlsConnectTestBase {
+ public:
+  TlsConnectDatagram13()
+      : TlsConnectTestBase(DGRAM, SSL_LIBRARY_VERSION_TLS_1_3) {}
+};
+#endif
+
 // A variant that is used only with Pre13.
 class TlsConnectGenericPre13 : public TlsConnectGeneric {
 };
 
 } // namespace nss_test
 
 #endif
--- a/security/nss/external_tests/ssl_gtest/tls_filter.cc
+++ b/security/nss/external_tests/ssl_gtest/tls_filter.cc
@@ -279,17 +279,17 @@ PacketFilter::Action TlsExtensionFilter:
     TlsParser parser(input);
     if (!FindClientHelloExtensions(&parser, header)) {
       return KEEP;
     }
     return FilterExtensions(&parser, input, output);
   }
   if (header.handshake_type() == kTlsHandshakeServerHello) {
     TlsParser parser(input);
-    if (!FindServerHelloExtensions(&parser, header.version())) {
+    if (!FindServerHelloExtensions(&parser)) {
       return KEEP;
     }
     return FilterExtensions(&parser, input, output);
   }
   return KEEP;
 }
 
 bool TlsExtensionFilter::FindClientHelloExtensions(TlsParser* parser,
@@ -307,24 +307,30 @@ bool TlsExtensionFilter::FindClientHello
     return false;
   }
   if (!parser->SkipVariable(1)) { // compression methods
     return false;
   }
   return true;
 }
 
-bool TlsExtensionFilter::FindServerHelloExtensions(TlsParser* parser,
-                                                   uint16_t version) {
-  if (!parser->Skip(2 + 32)) { // version + random
+bool TlsExtensionFilter::FindServerHelloExtensions(TlsParser* parser) {
+  uint32_t vtmp;
+  if (!parser->Read(&vtmp, 2)) {
     return false;
   }
-  if (!parser->SkipVariable(1)) { // session ID
+  uint16_t version = static_cast<uint16_t>(vtmp);
+  if (!parser->Skip(32)) { // random
     return false;
   }
+  if (NormalizeTlsVersion(version) <= SSL_LIBRARY_VERSION_TLS_1_2) {
+    if (!parser->SkipVariable(1)) { // session ID
+      return false;
+    }
+  }
   if (!parser->Skip(2)) { // cipher suite
     return false;
   }
   if (NormalizeTlsVersion(version) <= SSL_LIBRARY_VERSION_TLS_1_2) {
     if (!parser->Skip(1)) { // compression method
       return false;
     }
   }
--- a/security/nss/external_tests/ssl_gtest/tls_filter.h
+++ b/security/nss/external_tests/ssl_gtest/tls_filter.h
@@ -189,17 +189,17 @@ class TlsExtensionFilter : public TlsHan
 
   virtual PacketFilter::Action FilterExtension(uint16_t extension_type,
                                                const DataBuffer& input,
                                                DataBuffer* output) = 0;
 
  public:
   static bool FindClientHelloExtensions(TlsParser* parser,
                                         const Versioned& header);
-  static bool FindServerHelloExtensions(TlsParser* parser, uint16_t version);
+  static bool FindServerHelloExtensions(TlsParser* parser);
 
  private:
   PacketFilter::Action FilterExtensions(TlsParser* parser,
                                         const DataBuffer& input,
                                         DataBuffer* output);
 };
 
 class TlsExtensionCapture : public TlsExtensionFilter {
--- a/security/nss/external_tests/ssl_gtest/tls_parser.h
+++ b/security/nss/external_tests/ssl_gtest/tls_parser.h
@@ -17,19 +17,21 @@
 #endif
 #include "databuffer.h"
 
 namespace nss_test {
 
 const uint8_t kTlsChangeCipherSpecType = 20;
 const uint8_t kTlsAlertType = 21;
 const uint8_t kTlsHandshakeType = 22;
+const uint8_t kTlsApplicationDataType = 23;
 
 const uint8_t kTlsHandshakeClientHello = 1;
 const uint8_t kTlsHandshakeServerHello = 2;
+const uint8_t kTlsHandshakeEncryptedExtensions = 8;
 const uint8_t kTlsHandshakeCertificate = 11;
 const uint8_t kTlsHandshakeServerKeyExchange = 12;
 const uint8_t kTlsHandshakeCertificateVerify = 15;
 const uint8_t kTlsHandshakeClientKeyExchange = 16;
 const uint8_t kTlsHandshakeFinished = 20;
 
 const uint8_t kTlsAlertWarning = 1;
 const uint8_t kTlsAlertFatal = 2;
@@ -62,16 +64,23 @@ inline uint16_t NormalizeTlsVersion(uint
     return 0x0302; // special: DTLS 1.0 == TLS 1.1
   }
   if (IsDtls(version)) {
     return (version ^ 0xffff) + 0x0201;
   }
   return version;
 }
 
+inline uint16_t TlsVersionToDtlsVersion(uint16_t version ) {
+  if (version == 0x0302) {
+    return 0xfeff;
+  }
+  return 0xffff - version + 0x0201;
+}
+
 inline void WriteVariable(DataBuffer* target, size_t index,
                           const DataBuffer& buf, size_t len_size) {
   target->Write(index, static_cast<uint32_t>(buf.len()), len_size);
   target->Write(index + len_size, buf.data(), buf.len());
 }
 
 class TlsParser {
  public:
--- a/security/nss/external_tests/util_gtest/manifest.mn
+++ b/security/nss/external_tests/util_gtest/manifest.mn
@@ -2,24 +2,25 @@
 # 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 = \
-	util_gtest.cc \
 	util_utf8_unittest.cc \
 	$(NULL)
 
 INCLUDES += \
 	-I$(CORE_DEPTH)/external_tests/google_test/gtest/include \
 	-I$(CORE_DEPTH)/external_tests/common \
 	$(NULL)
 
 REQUIRES = nspr gtest
 
 PROGRAM = util_gtest
+
 EXTRA_LIBS = \
 	$(DIST)/lib/$(LIB_PREFIX)gtest.$(LIB_SUFFIX) \
 	$(DIST)/lib/$(LIB_PREFIX)nssutil.$(LIB_SUFFIX) \
+	../common/$(OBJDIR)/gtests$(OBJ_SUFFIX) \
 	$(NULL)
deleted file mode 100644
--- a/security/nss/external_tests/util_gtest/util_gtest.cc
+++ /dev/null
@@ -1,9 +0,0 @@
-#define GTEST_HAS_RTTI 0
-#include "gtest/gtest.h"
-
-int main(int argc, char **argv) {
-  // Start the tests
-  ::testing::InitGoogleTest(&argc, argv);
-
-  return RUN_ALL_TESTS();
-}
--- a/security/nss/lib/base/list.c
+++ b/security/nss/lib/base/list.c
@@ -112,16 +112,19 @@ nssList_Create(NSSArena *arenaOpt, PRBoo
     list->i_alloced_arena = i_alloced;
     list->compareFunc = pointer_compare;
     return list;
 }
 
 NSS_IMPLEMENT PRStatus
 nssList_Destroy(nssList *list)
 {
+    if (!list) {
+        return PR_SUCCESS;
+    }
     if (!list->i_alloced_arena) {
         nssList_Clear(list, NULL);
     }
     if (list->lock) {
         (void)PZ_DestroyLock(list->lock);
     }
     if (list->i_alloced_arena) {
         NSSArena_Destroy(list->arena);
@@ -150,16 +153,19 @@ nssList_GetCompareFunction(nssList *list
     return list->compareFunc;
 }
 
 NSS_IMPLEMENT void
 nssList_Clear(nssList *list, nssListElementDestructorFunc destructor)
 {
     PRCList *link;
     nssListElement *node, *tmp;
+    if (!list) {
+        return;
+    }
     NSSLIST_LOCK_IF(list);
     node = list->head;
     list->head = NULL;
     while (node && list->count > 0) {
         if (destructor)
             (*destructor)(node->data);
         link = &node->link;
         tmp = (nssListElement *)PR_NEXT_LINK(link);
@@ -350,17 +356,19 @@ nssList_CreateIterator(nssList *list)
 }
 
 NSS_IMPLEMENT void
 nssListIterator_Destroy(nssListIterator *iter)
 {
     if (iter->lock) {
         (void)PZ_DestroyLock(iter->lock);
     }
-    nssList_Destroy(iter->list);
+    if (iter->list) {
+        nssList_Destroy(iter->list);
+    }
     nss_ZFreeIf(iter);
 }
 
 NSS_IMPLEMENT void *
 nssListIterator_Start(nssListIterator *iter)
 {
     NSSLIST_LOCK_IF(iter);
     if (iter->list->count == 0) {
--- a/security/nss/lib/ckfw/instance.c
+++ b/security/nss/lib/ckfw/instance.c
@@ -21,30 +21,32 @@
  *
  *  -- public accessors --
  *  NSSCKFWInstance_GetMDInstance
  *  NSSCKFWInstance_GetArena
  *  NSSCKFWInstance_MayCreatePthreads
  *  NSSCKFWInstance_CreateMutex
  *  NSSCKFWInstance_GetConfigurationData
  *  NSSCKFWInstance_GetInitArgs
+ *  NSSCKFWInstance_DestroySessionHandle
+ *  NSSCKFWInstance_FindSessionHandle
  *
  *  -- implement public accessors --
  *  nssCKFWInstance_GetMDInstance
  *  nssCKFWInstance_GetArena
  *  nssCKFWInstance_MayCreatePthreads
  *  nssCKFWInstance_CreateMutex
  *  nssCKFWInstance_GetConfigurationData
  *  nssCKFWInstance_GetInitArgs
+ *  nssCKFWInstance_DestroySessionHandle
+ *  nssCKFWInstance_FindSessionHandle
  *
  *  -- private accessors --
  *  nssCKFWInstance_CreateSessionHandle
  *  nssCKFWInstance_ResolveSessionHandle
- *  nssCKFWInstance_DestroySessionHandle
- *  nssCKFWInstance_FindSessionHandle
  *  nssCKFWInstance_CreateObjectHandle
  *  nssCKFWInstance_ResolveObjectHandle
  *  nssCKFWInstance_DestroyObjectHandle
  *
  *  -- module fronts --
  *  nssCKFWInstance_GetNSlots
  *  nssCKFWInstance_GetCryptokiVersion
  *  nssCKFWInstance_GetManufacturerID
@@ -1261,8 +1263,32 @@ NSSCKFWInstance_GetInitArgs(
 #ifdef DEBUG
     if (CKR_OK != nssCKFWInstance_verifyPointer(fwInstance)) {
         return (CK_C_INITIALIZE_ARGS_PTR)NULL;
     }
 #endif /* DEBUG */
 
     return nssCKFWInstance_GetInitArgs(fwInstance);
 }
+
+/*
+ * nssCKFWInstance_DestroySessionHandle
+ *
+ */
+NSS_IMPLEMENT void
+NSSCKFWInstance_DestroySessionHandle(
+    NSSCKFWInstance *fwInstance,
+    CK_SESSION_HANDLE hSession)
+{
+    nssCKFWInstance_DestroySessionHandle(fwInstance, hSession);
+}
+
+/*
+ * nssCKFWInstance_FindSessionHandle
+ *
+ */
+NSS_IMPLEMENT CK_SESSION_HANDLE
+NSSCKFWInstance_FindSessionHandle(
+    NSSCKFWInstance *fwInstance,
+    NSSCKFWSession *fwSession)
+{
+    return nssCKFWInstance_FindSessionHandle(fwInstance, fwSession);
+}
--- a/security/nss/lib/ckfw/nssckfw.h
+++ b/security/nss/lib/ckfw/nssckfw.h
@@ -27,16 +27,19 @@
 /*
  * NSSCKFWInstance
  *
  *  NSSCKFWInstance_GetMDInstance
  *  NSSCKFWInstance_GetArena
  *  NSSCKFWInstance_MayCreatePthreads
  *  NSSCKFWInstance_CreateMutex
  *  NSSCKFWInstance_GetConfigurationData
+ *  NSSCKFWInstance_GetInitArgs
+ *  NSSCKFWInstance_DestroySessionHandle
+ *  NSSCKFWInstance_FindSessionHandle
  */
 
 /*
  * NSSCKFWInstance_GetMDInstance
  *
  */
 
 NSS_EXTERN NSSCKMDInstance *
@@ -87,21 +90,40 @@ NSSCKFWInstance_GetConfigurationData(
  *
  */
 
 NSS_EXTERN CK_C_INITIALIZE_ARGS_PTR
 NSSCKFWInstance_GetInitArgs(
     NSSCKFWInstance *fwInstance);
 
 /*
+ * nssCKFWInstance_DestroySessionHandle
+ *
+ */
+NSS_EXTERN void
+NSSCKFWInstance_DestroySessionHandle(
+    NSSCKFWInstance *fwInstance,
+    CK_SESSION_HANDLE hSession);
+
+/*
+ * nssCKFWInstance_FindSessionHandle
+ *
+ */
+NSS_EXTERN CK_SESSION_HANDLE
+NSSCKFWInstance_FindSessionHandle(
+    NSSCKFWInstance *fwInstance,
+    NSSCKFWSession *fwSession);
+
+/*
  * NSSCKFWSlot
  *
  *  NSSCKFWSlot_GetMDSlot
  *  NSSCKFWSlot_GetFWInstance
  *  NSSCKFWSlot_GetMDInstance
+ *  NSSCKFWSlot_GetSlotID
  *
  */
 
 /*
  * NSSCKFWSlot_GetMDSlot
  *
  */
 
@@ -123,16 +145,25 @@ NSSCKFWSlot_GetFWInstance(
  *
  */
 
 NSS_EXTERN NSSCKMDInstance *
 NSSCKFWSlot_GetMDInstance(
     NSSCKFWSlot *fwSlot);
 
 /*
+ * NSSCKFWSlot_GetSlotID
+ *
+ */
+
+NSS_EXTERN CK_SLOT_ID
+NSSCKFWSlot_GetSlotID(
+    NSSCKFWSlot *fwSlot);
+
+/*
  * NSSCKFWToken
  *
  *  NSSCKFWToken_GetMDToken
  *  NSSCKFWToken_GetFWSlot
  *  NSSCKFWToken_GetMDSlot
  *  NSSCKFWToken_GetSessionState
  *
  */
@@ -213,16 +244,17 @@ NSSCKFWMechanism_GetParameter(
  * NSSCKFWSession
  *
  *  NSSCKFWSession_GetMDSession
  *  NSSCKFWSession_GetArena
  *  NSSCKFWSession_CallNotification
  *  NSSCKFWSession_IsRWSession
  *  NSSCKFWSession_IsSO
  *  NSSCKFWSession_GetCurrentCryptoOperation
+ *  NSSCKFWSession_GetFWSlot
  *
  */
 
 /*
  * NSSCKFWSession_GetMDSession
  *
  */
 
@@ -274,16 +306,25 @@ NSSCKFWSession_IsSO(
  */
 
 NSS_EXTERN NSSCKFWCryptoOperation *
 NSSCKFWSession_GetCurrentCryptoOperation(
     NSSCKFWSession *fwSession,
     NSSCKFWCryptoOperationState state);
 
 /*
+ * NSSCKFWSession_GetFWSlot
+ *
+ */
+
+NSS_EXTERN NSSCKFWSlot *
+NSSCKFWSession_GetFWSlot(
+    NSSCKFWSession *fwSession);
+
+/*
  * NSSCKFWObject
  *
  *  NSSCKFWObject_GetMDObject
  *  NSSCKFWObject_GetArena
  *  NSSCKFWObject_IsTokenObject
  *  NSSCKFWObject_GetAttributeCount
  *  NSSCKFWObject_GetAttributeTypes
  *  NSSCKFWObject_GetAttributeSize
--- a/security/nss/lib/ckfw/session.c
+++ b/security/nss/lib/ckfw/session.c
@@ -20,26 +20,27 @@
  *  nssCKFWSession_Destroy
  *
  *  -- public accessors --
  *  NSSCKFWSession_GetMDSession
  *  NSSCKFWSession_GetArena
  *  NSSCKFWSession_CallNotification
  *  NSSCKFWSession_IsRWSession
  *  NSSCKFWSession_IsSO
+ *  NSSCKFWSession_GetFWSlot
  *
  *  -- implement public accessors --
  *  nssCKFWSession_GetMDSession
  *  nssCKFWSession_GetArena
  *  nssCKFWSession_CallNotification
  *  nssCKFWSession_IsRWSession
  *  nssCKFWSession_IsSO
+ *  nssCKFWSession_GetFWSlot
  *
  *  -- private accessors --
- *  nssCKFWSession_GetSlot
  *  nssCKFWSession_GetSessionState
  *  nssCKFWSession_SetFWFindObjects
  *  nssCKFWSession_GetFWFindObjects
  *  nssCKFWSession_SetMDSession
  *  nssCKFWSession_SetHandle
  *  nssCKFWSession_GetHandle
  *  nssCKFWSession_RegisterSessionObject
  *  nssCKFWSession_DeegisterSessionObject
@@ -2370,8 +2371,20 @@ NSSCKFWSession_GetCurrentCryptoOperation
     }
 
     if (state >= NSSCKFWCryptoOperationState_Max) {
         return (NSSCKFWCryptoOperation *)NULL;
     }
 #endif /* DEBUG */
     return nssCKFWSession_GetCurrentCryptoOperation(fwSession, state);
 }
+
+/*
+ * NSSCKFWSession_GetFWSlot
+ *
+ */
+
+NSS_IMPLEMENT NSSCKFWSlot *
+NSSCKFWSession_GetFWSlot(
+    NSSCKFWSession *fwSession)
+{
+    return nssCKFWSession_GetFWSlot(fwSession);
+}
--- a/security/nss/lib/ckfw/slot.c
+++ b/security/nss/lib/ckfw/slot.c
@@ -18,24 +18,25 @@
  *  -- create/destroy --
  *  nssCKFWSlot_Create
  *  nssCKFWSlot_Destroy
  *
  *  -- public accessors --
  *  NSSCKFWSlot_GetMDSlot
  *  NSSCKFWSlot_GetFWInstance
  *  NSSCKFWSlot_GetMDInstance
+ *  NSSCKFWSlot_GetSlotID
  *
  *  -- implement public accessors --
  *  nssCKFWSlot_GetMDSlot
  *  nssCKFWSlot_GetFWInstance
  *  nssCKFWSlot_GetMDInstance
+ *  nssCKFWSlot_GetSlotID
  *
  *  -- private accessors --
- *  nssCKFWSlot_GetSlotID
  *  nssCKFWSlot_ClearToken
  *
  *  -- module fronts --
  *  nssCKFWSlot_GetSlotDescription
  *  nssCKFWSlot_GetManufacturerID
  *  nssCKFWSlot_GetTokenPresent
  *  nssCKFWSlot_GetRemovableDevice
  *  nssCKFWSlot_GetHardwareSlot
@@ -674,8 +675,20 @@ NSSCKFWSlot_GetMDInstance(
 #ifdef DEBUG
     if (CKR_OK != nssCKFWSlot_verifyPointer(fwSlot)) {
         return (NSSCKMDInstance *)NULL;
     }
 #endif /* DEBUG */
 
     return nssCKFWSlot_GetMDInstance(fwSlot);
 }
+
+/*
+ * NSSCKFWSlot_GetSlotID
+ *
+ */
+
+NSS_IMPLEMENT CK_SLOT_ID
+NSSCKFWSlot_GetSlotID(
+    NSSCKFWSlot *fwSlot)
+{
+    return nssCKFWSlot_GetSlotID(fwSlot);
+}
--- a/security/nss/lib/freebl/ec.c
+++ b/security/nss/lib/freebl/ec.c
@@ -38,19 +38,16 @@ ec_point_at_infinity(SECItem *pointP)
  * the curve whose parameters are encoded in params with base point G.
  */
 SECStatus 
 ec_points_mul(const ECParams *params, const mp_int *k1, const mp_int *k2,
              const SECItem *pointP, SECItem *pointQ)
 {
     mp_int Px, Py, Qx, Qy;
     mp_int Gx, Gy, order, irreducible, a, b;
-#if 0 /* currently don't support non-named curves */
-    unsigned int irr_arr[5];
-#endif
     ECGroup *group = NULL;
     SECStatus rv = SECFailure;
     mp_err err = MP_OKAY;
     int len;
 
 #if EC_DEBUG
     int i;
     char mpstr[256];
@@ -119,40 +116,16 @@ ec_points_mul(const ECParams *params, co
 		CHECK_MPI_OK( mp_read_unsigned_octets(&Py, pointP->data + 1 + len, (mp_size) len) );
 	}
 
 	/* construct from named params, if possible */
 	if (params->name != ECCurve_noName) {
 		group = ECGroup_fromName(params->name);
 	}
 
-#if 0 /* currently don't support non-named curves */
-	if (group == NULL) {
-		/* Set up mp_ints containing the curve coefficients */
-		CHECK_MPI_OK( mp_read_unsigned_octets(&Gx, params->base.data + 1, 
-										  (mp_size) len) );
-		CHECK_MPI_OK( mp_read_unsigned_octets(&Gy, params->base.data + 1 + len, 
-										  (mp_size) len) );
-		SECITEM_TO_MPINT( params->order, &order );
-		SECITEM_TO_MPINT( params->curve.a, &a );
-		SECITEM_TO_MPINT( params->curve.b, &b );
-		if (params->fieldID.type == ec_field_GFp) {
-			SECITEM_TO_MPINT( params->fieldID.u.prime, &irreducible );
-			group = ECGroup_consGFp(&irreducible, &a, &b, &Gx, &Gy, &order, params->cofactor);
-		} else {
-			SECITEM_TO_MPINT( params->fieldID.u.poly, &irreducible );
-			irr_arr[0] = params->fieldID.size;
-			irr_arr[1] = params->fieldID.k1;
-			irr_arr[2] = params->fieldID.k2;
-			irr_arr[3] = params->fieldID.k3;
-			irr_arr[4] = 0;
-			group = ECGroup_consGF2m(&irreducible, irr_arr, &a, &b, &Gx, &Gy, &order, params->cofactor);
-		}
-	}
-#endif
 	if (group == NULL)
 		goto cleanup;
 
 	if ((k2 != NULL) && (pointP != NULL)) {
 		CHECK_MPI_OK( ECPoints_mul(group, k1, k2, &Px, &Py, &Qx, &Qy) );
 	} else {
 		CHECK_MPI_OK( ECPoints_mul(group, k1, NULL, NULL, NULL, &Qx, &Qy) );
     }
--- a/security/nss/lib/freebl/ecdecode.c
+++ b/security/nss/lib/freebl/ecdecode.c
@@ -182,17 +182,17 @@ EC_FillParams(PLArenaPool *arena, const 
 	    return SECFailure;
     }
 
     params->arena = arena;
     params->cofactor = 0;
     params->type = ec_params_named;
     params->name = ECCurve_noName;
 
-    /* For named curves, fill out curveOID */
+    /* Fill out curveOID */
     params->curveOID.len = oid.len;
     params->curveOID.data = (unsigned char *) PORT_ArenaAlloc(arena, oid.len);
     if (params->curveOID.data == NULL) goto cleanup;
     memcpy(params->curveOID.data, oid.data, oid.len);
 
 #if EC_DEBUG
     printf("Curve: %s\n", SECOID_FindOIDTagDescription(tag));
 #endif
--- a/security/nss/lib/freebl/mpi/README
+++ b/security/nss/lib/freebl/mpi/README
@@ -517,23 +517,16 @@ MP_LOGTAB       - If true, the file "log
 MP_MEMSET       - If true, use memset() to zero buffers.  If you run
                   into weird alignment related bugs, set this to zero
                   and an explicit loop will be used.
 
 MP_MEMCPY       - If true, use memcpy() to copy buffers.  If you run
                   into weird alignment bugs, set this to zero and an
                   explicit loop will be used.
 
-MP_CRYPTO       - If true, whenever arrays of digits are free'd, they
-                  are zeroed first.  This is useful if you're using
-                  the library in a cryptographic environment; however,
-                  it does add overhead to each free operation.  For
-                  performance, if you don't care about zeroing your
-                  buffers, set this to false.
-
 MP_ARGCHK       - Set to 0, 1, or 2.  This defines how the argument
                   checking macro, ARGCHK(), gets expanded.  If this 
                   is set to zero, ARGCHK() expands to nothing; no 
                   argument checks are performed.  If this is 1, the
                   ARGCHK() macro expands to code that returns MP_BADARG
                   or similar at runtime.  If it is 2, ARGCHK() expands 
                   to an assert() call that aborts the program on a 
                   bad input.
--- a/security/nss/lib/freebl/mpi/mpcpucache.c
+++ b/security/nss/lib/freebl/mpi/mpcpucache.c
@@ -69,20 +69,24 @@ void freebl_cpuid(unsigned long op, unsi
 
 /* x86 */
 
 #if defined(__GNUC__)
 void freebl_cpuid(unsigned long op, unsigned long *eax, 
 	                 unsigned long *ebx, unsigned long *ecx, 
                          unsigned long *edx)
 {
-/* sigh GCC isn't smart enough to save the ebx PIC register on it's own
+/* Some older processors don't fill the ecx register with cpuid, so clobber it
+ * before calling cpuid, so that there's no risk of picking random bits that
+ * erroneously indicate that absent CPU features are present.
+ * Also, GCC isn't smart enough to save the ebx PIC register on its own
  * in this case, so do it by hand. Use edi to store ebx and pass the
  * value returned in ebx from cpuid through edi. */
-	__asm__("mov %%ebx,%%edi\n\t"
+	__asm__("xor %%ecx, %%ecx\n\t"
+		  "mov %%ebx,%%edi\n\t"
 		  "cpuid\n\t"
 		  "xchgl %%ebx,%%edi\n\t"
 		: "=a" (*eax),
 		  "=D" (*ebx),
 		  "=c" (*ecx),
 		  "=d" (*edx)
 		: "0" (op));
 }
@@ -117,16 +121,17 @@ static unsigned long changeFlag(unsigned
  */
 #define wcpuid __asm __emit 0fh __asm __emit 0a2h
 void freebl_cpuid(unsigned long op,    unsigned long *Reax, 
     unsigned long *Rebx, unsigned long *Recx, unsigned long *Redx)
 {
         unsigned long  Leax, Lebx, Lecx, Ledx;
         __asm {
         pushad
+        xor     ecx,ecx
         mov     eax,op
         wcpuid
         mov     Leax,eax
         mov     Lebx,ebx
         mov     Lecx,ecx
         mov     Ledx,edx
         popad
         }
--- a/security/nss/lib/freebl/mpi/mpcpucache_x86.s
+++ b/security/nss/lib/freebl/mpi/mpcpucache_x86.s
@@ -564,16 +564,17 @@ CacheMap:
 freebl_cpuid:
 	pushl	%ebp
 	pushl	%edi
 	pushl	%esi
 	subl	$8, %esp
 	movl	%edx, %ebp
 /APP
 	pushl %ebx
+	xorl %ecx, %ecx
 	cpuid
 	mov %ebx,%esi
 	popl %ebx
 	
 /NO_APP
 	movl	%eax, (%ebp)
 	movl	24(%esp), %eax
 	movl	%esi, (%eax)
--- a/security/nss/lib/freebl/mpi/mpi-config.h
+++ b/security/nss/lib/freebl/mpi/mpi-config.h
@@ -35,20 +35,16 @@
 #ifndef MP_MEMSET
 #define MP_MEMSET     1  /* use memset() to zero buffers?       */
 #endif
 
 #ifndef MP_MEMCPY
 #define MP_MEMCPY     1  /* use memcpy() to copy buffers?       */
 #endif
 
-#ifndef MP_CRYPTO
-#define MP_CRYPTO     1  /* erase memory on free?               */
-#endif
-
 #ifndef MP_ARGCHK
 /*
   0 = no parameter checks
   1 = runtime checks, continue execution and return an error to caller
   2 = assertions; dump core on parameter errors
  */
 #ifdef DEBUG
 #define MP_ARGCHK     2  /* how to check input arguments        */
@@ -60,19 +56,15 @@
 #ifndef MP_DEBUG
 #define MP_DEBUG      0  /* print diagnostic output?            */
 #endif
 
 #ifndef MP_DEFPREC
 #define MP_DEFPREC    64 /* default precision, in digits        */
 #endif
 
-#ifndef MP_MACRO
-#define MP_MACRO      1  /* use macros for frequent calls?      */
-#endif
-
 #ifndef MP_SQUARE
 #define MP_SQUARE     1  /* use separate squaring code?         */
 #endif
 
 #endif /* ifndef MPI_CONFIG_H_ */
 
 
--- a/security/nss/lib/freebl/mpi/mpi-priv.h
+++ b/security/nss/lib/freebl/mpi/mpi-priv.h
@@ -90,71 +90,29 @@ extern const float s_logv_2[];
 #define  MP_LT       -1
 #define  MP_EQ        0
 #define  MP_GT        1
 
 /* }}} */
 
 /* {{{ private function declarations */
 
-/* 
-   If MP_MACRO is false, these will be defined as actual functions;
-   otherwise, suitable macro definitions will be used.  This works
-   around the fact that ANSI C89 doesn't support an 'inline' keyword
-   (although I hear C9x will ... about bloody time).  At present, the
-   macro definitions are identical to the function bodies, but they'll
-   expand in place, instead of generating a function call.
+void     s_mp_setz(mp_digit *dp, mp_size count); /* zero digits           */
+void     s_mp_copy(const mp_digit *sp, mp_digit *dp, mp_size count); /* copy */
+void    *s_mp_alloc(size_t nb, size_t ni);       /* general allocator     */
+void     s_mp_free(void *ptr);                   /* general free function */
 
-   I chose these particular functions to be made into macros because
-   some profiling showed they are called a lot on a typical workload,
-   and yet they are primarily housekeeping.
- */
-#if MP_MACRO == 0
- void     s_mp_setz(mp_digit *dp, mp_size count); /* zero digits           */
- void     s_mp_copy(const mp_digit *sp, mp_digit *dp, mp_size count); /* copy */
- void    *s_mp_alloc(size_t nb, size_t ni);       /* general allocator     */
- void     s_mp_free(void *ptr);                   /* general free function */
 extern unsigned long mp_allocs;
 extern unsigned long mp_frees;
 extern unsigned long mp_copies;
-#else
-
- /* Even if these are defined as macros, we need to respect the settings
-    of the MP_MEMSET and MP_MEMCPY configuration options...
-  */
- #if MP_MEMSET == 0
-  #define  s_mp_setz(dp, count) \
-       {int ix;for(ix=0;ix<(count);ix++)(dp)[ix]=0;}
- #else
-  #define  s_mp_setz(dp, count) memset(dp, 0, (count) * sizeof(mp_digit))
- #endif /* MP_MEMSET */
-
- #if MP_MEMCPY == 0
-  #define  s_mp_copy(sp, dp, count) \
-       {int ix;for(ix=0;ix<(count);ix++)(dp)[ix]=(sp)[ix];}
- #else
-  #define  s_mp_copy(sp, dp, count) memcpy(dp, sp, (count) * sizeof(mp_digit))
- #endif /* MP_MEMCPY */
-
- #define  s_mp_alloc(nb, ni)  calloc(nb, ni)
- #define  s_mp_free(ptr) {if(ptr) free(ptr);}
-#endif /* MP_MACRO */
 
 mp_err   s_mp_grow(mp_int *mp, mp_size min);   /* increase allocated size */
 mp_err   s_mp_pad(mp_int *mp, mp_size min);    /* left pad with zeroes    */
 
-#if MP_MACRO == 0
- void     s_mp_clamp(mp_int *mp);               /* clip leading zeroes     */
-#else
- #define  s_mp_clamp(mp)\
-  { mp_size used = MP_USED(mp); \
-    while (used > 1 && DIGIT(mp, used - 1) == 0) --used; \
-    MP_USED(mp) = used; \
-  } 
-#endif /* MP_MACRO */
+void     s_mp_clamp(mp_int *mp);               /* clip leading zeroes     */
 
 void     s_mp_exch(mp_int *a, mp_int *b);      /* swap a and b in place   */
 
 mp_err   s_mp_lshd(mp_int *mp, mp_size p);     /* left-shift by p digits  */
 void     s_mp_rshd(mp_int *mp, mp_size p);     /* right-shift by p digits */
 mp_err   s_mp_mul_2d(mp_int *mp, mp_digit d);  /* multiply by 2^d in place */
 void     s_mp_div_2d(mp_int *mp, mp_digit d);  /* divide by 2^d in place  */
 void     s_mp_mod_2d(mp_int *mp, mp_digit d);  /* modulo 2^d in place     */
--- a/security/nss/lib/freebl/mpi/mpi.c
+++ b/security/nss/lib/freebl/mpi/mpi.c
@@ -14,16 +14,20 @@
 
 #if defined(__arm__) && \
     ((defined(__thumb__) && !defined(__thumb2__)) || defined(__ARM_ARCH_3__))
 /* 16-bit thumb or ARM v3 doesn't work inlined assember version */
 #undef MP_ASSEMBLY_MULTIPLY
 #undef MP_ASSEMBLY_SQUARE
 #endif
 
+#if defined(_MSC_VER) && _MSC_VER < 1900
+#define inline __inline
+#endif
+
 #if MP_LOGTAB
 /*
   A table of the logs of 2 for various bases (the 0 and 1 entries of
   this table are meaningless and should not be referenced).  
 
   This table is used to compute output lengths for the mp_toradix()
   function.  Since a number n in radix r takes up about log_r(n)
   digits, we estimate the output size by taking the least integer
@@ -194,19 +198,17 @@ mp_err mp_copy(const mp_int *from, mp_in
       
     } else {
       if((tmp = s_mp_alloc(ALLOC(from), sizeof(mp_digit))) == NULL)
 	return MP_MEM;
 
       s_mp_copy(DIGITS(from), tmp, USED(from));
 
       if(DIGITS(to) != NULL) {
-#if MP_CRYPTO
 	s_mp_setz(DIGITS(to), ALLOC(to));
-#endif
 	s_mp_free(DIGITS(to));
       }
 
       DIGITS(to) = tmp;
       ALLOC(to) = ALLOC(from);
     }
 
     /* Copy the precision and sign from the original */
@@ -256,19 +258,17 @@ void mp_exch(mp_int *mp1, mp_int *mp2)
  */
 
 void   mp_clear(mp_int *mp)
 {
   if(mp == NULL)
     return;
 
   if(DIGITS(mp) != NULL) {
-#if MP_CRYPTO
     s_mp_setz(DIGITS(mp), ALLOC(mp));
-#endif
     s_mp_free(DIGITS(mp));
     DIGITS(mp) = NULL;
   }
 
   USED(mp) = 0;
   ALLOC(mp) = 0;
 
 } /* end mp_clear() */
@@ -2735,19 +2735,17 @@ mp_err   s_mp_grow(mp_int *mp, mp_size m
     /* Set min to next nearest default precision block size */
     min = MP_ROUNDUP(min, s_mp_defprec);
 
     if((tmp = s_mp_alloc(min, sizeof(mp_digit))) == NULL)
       return MP_MEM;
 
     s_mp_copy(DIGITS(mp), tmp, USED(mp));
 
-#if MP_CRYPTO
     s_mp_setz(DIGITS(mp), ALLOC(mp));
-#endif
     s_mp_free(DIGITS(mp));
     DIGITS(mp) = tmp;
     ALLOC(mp) = min;
   }
 
   return MP_OKAY;
 
 } /* end s_mp_grow() */
@@ -2777,96 +2775,86 @@ mp_err   s_mp_pad(mp_int *mp, mp_size mi
   return MP_OKAY;
 
 } /* end s_mp_pad() */
 
 /* }}} */
 
 /* {{{ s_mp_setz(dp, count) */
 
-#if MP_MACRO == 0
 /* Set 'count' digits pointed to by dp to be zeroes                       */
-void s_mp_setz(mp_digit *dp, mp_size count)
+inline void s_mp_setz(mp_digit *dp, mp_size count)
 {
 #if MP_MEMSET == 0
   int  ix;
 
   for(ix = 0; ix < count; ix++)
     dp[ix] = 0;
 #else
   memset(dp, 0, count * sizeof(mp_digit));
 #endif
 
 } /* end s_mp_setz() */
-#endif
 
 /* }}} */
 
 /* {{{ s_mp_copy(sp, dp, count) */
 
-#if MP_MACRO == 0
 /* Copy 'count' digits from sp to dp                                      */
-void s_mp_copy(const mp_digit *sp, mp_digit *dp, mp_size count)
+inline void s_mp_copy(const mp_digit *sp, mp_digit *dp, mp_size count)
 {
 #if MP_MEMCPY == 0
   int  ix;
 
   for(ix = 0; ix < count; ix++)
     dp[ix] = sp[ix];
 #else
   memcpy(dp, sp, count * sizeof(mp_digit));
 #endif
   ++mp_copies;
 
 } /* end s_mp_copy() */
-#endif
 
 /* }}} */
 
 /* {{{ s_mp_alloc(nb, ni) */
 
-#if MP_MACRO == 0
 /* Allocate ni records of nb bytes each, and return a pointer to that     */
-void    *s_mp_alloc(size_t nb, size_t ni)
+inline void *s_mp_alloc(size_t nb, size_t ni)
 {
   ++mp_allocs;
   return calloc(nb, ni);
 
 } /* end s_mp_alloc() */
-#endif
 
 /* }}} */
 
 /* {{{ s_mp_free(ptr) */
 
-#if MP_MACRO == 0
 /* Free the memory pointed to by ptr                                      */
-void     s_mp_free(void *ptr)
+inline void s_mp_free(void *ptr)
 {
   if(ptr) {
     ++mp_frees;
     free(ptr);
   }
 } /* end s_mp_free() */
-#endif
 
 /* }}} */
 
 /* {{{ s_mp_clamp(mp) */
 
-#if MP_MACRO == 0
 /* Remove leading zeroes from the given value                             */
-void     s_mp_clamp(mp_int *mp)
+inline void s_mp_clamp(mp_int *mp)
 {
   mp_size used = MP_USED(mp);
   while (used > 1 && DIGIT(mp, used - 1) == 0)
     --used;
   MP_USED(mp) = used;
 } /* end s_mp_clamp() */
-#endif
 
 /* }}} */
 
 /* {{{ s_mp_exch(a, b) */
 
 /* Exchange the data for a and b; (b, a) = (a, b)                         */
 void     s_mp_exch(mp_int *a, mp_int *b)
 {
@@ -2997,21 +2985,16 @@ void     s_mp_rshd(mp_int *mp, mp_size p
   for (ix = USED(mp) - p; ix > 0; ix--)
     *dst++ = *src++;
 
   MP_USED(mp) -= p;
   /* Fill the top digits with zeroes */
   while (p-- > 0)
     *dst++ = 0;
 
-#if 0
-  /* Strip off any leading zeroes    */
-  s_mp_clamp(mp);
-#endif
-
 } /* end s_mp_rshd() */
 
 /* }}} */
 
 /* {{{ s_mp_div_2(mp) */
 
 /* Divide by two -- take advantage of radix properties to do it fast      */
 void     s_mp_div_2(mp_int *mp)
--- a/security/nss/lib/nss/nss.h
+++ b/security/nss/lib/nss/nss.h
@@ -3,47 +3,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/. */
 
 #ifndef __nss_h_
 #define __nss_h_
 
-/* The private macro _NSS_ECC_STRING is for NSS internal use only. */
-#ifndef NSS_DISABLE_ECC
-#ifdef NSS_ECC_MORE_THAN_SUITE_B
-#define _NSS_ECC_STRING " Extended ECC"
-#else
-#define _NSS_ECC_STRING " Basic ECC"
-#endif
-#else
-#define _NSS_ECC_STRING ""
-#endif
-
 /* The private macro _NSS_CUSTOMIZED is for NSS internal use only. */
 #if defined(NSS_ALLOW_UNSUPPORTED_CRITICAL)
 #define _NSS_CUSTOMIZED " (Customized build)"
 #else
 #define _NSS_CUSTOMIZED 
 #endif
 
 /*
  * NSS's major version, minor version, patch level, build number, and whether
  * this is a beta release.
  *
  * The format of the version string should be
  *     "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
  */
-#define NSS_VERSION  "3.24" _NSS_ECC_STRING _NSS_CUSTOMIZED
+#define NSS_VERSION  "3.25" _NSS_CUSTOMIZED " Beta"
 #define NSS_VMAJOR   3
-#define NSS_VMINOR   24
+#define NSS_VMINOR   25
 #define NSS_VPATCH   0
 #define NSS_VBUILD   0
-#define NSS_BETA     PR_FALSE
+#define NSS_BETA     PR_TRUE
 
 #ifndef RC_INVOKED
 
 #include "seccomon.h"
 
 typedef struct NSSInitParametersStr NSSInitParameters;
 
 /*
--- a/security/nss/lib/pk11wrap/pk11pk12.c
+++ b/security/nss/lib/pk11wrap/pk11pk12.c
@@ -228,20 +228,22 @@ PK11_ImportDERPrivateKeyInfoAndReturnKey
     if (!pki) {
         PORT_FreeArena(temparena, PR_FALSE);
         return rv;
     }
     pki->arena = temparena;
 
     rv = SEC_ASN1DecodeItem(pki->arena, pki, SECKEY_PrivateKeyInfoTemplate,
 		derPKI);
-    if( rv != SECSuccess ) {
+    if (rv != SECSuccess || pki->privateKey.data == NULL) {
         /* If SEC_ASN1DecodeItem fails, we cannot assume anything about the
          * validity of the data in pki. The best we can do is free the arena
-         * and return.
+         * and return. Do the same if SECKEYPrivateKeyInfo.privateKey is a
+         * zero-length octet string (i.e. NULL) to avoid trying to zero the
+         * corresponding SECItem.
          */
         PORT_FreeArena(temparena, PR_TRUE);
         return rv;
     }
 
     rv = PK11_ImportPrivateKeyInfoAndReturnKey(slot, pki, nickname,
 		publicValue, isPerm, isPrivate, keyUsage, privk, wincx);
 
--- a/security/nss/lib/pkcs12/p12dec.c
+++ b/security/nss/lib/pkcs12/p12dec.c
@@ -57,18 +57,28 @@ sec_pkcs12_decode_pfx(SECItem *der_pfx)
 	rv = SEC_ASN1DecodeItem(pfx->poolp, pfx, SEC_PKCS12PFXItemTemplate_OLD, 
 				der_pfx);
 	if(rv != SECSuccess) {
 	    PORT_SetError(SEC_ERROR_PKCS12_DECODING_PFX);
 	    PORT_FreeArena(pfx->poolp, PR_TRUE);
 	    return NULL;
 	}
 	pfx->old = PR_TRUE;
-	SGN_CopyDigestInfo(pfx->poolp, &pfx->macData.safeMac, &pfx->old_safeMac);
-	SECITEM_CopyItem(pfx->poolp, &pfx->macData.macSalt, &pfx->old_macSalt);
+	rv = SGN_CopyDigestInfo(pfx->poolp, &pfx->macData.safeMac, &pfx->old_safeMac);
+	if(rv != SECSuccess) {
+	    PORT_SetError(SEC_ERROR_NO_MEMORY);
+	    PORT_FreeArena(pfx->poolp, PR_TRUE);
+	    return NULL;
+	}
+	rv = SECITEM_CopyItem(pfx->poolp, &pfx->macData.macSalt, &pfx->old_macSalt);
+	if(rv != SECSuccess) {
+	    PORT_SetError(SEC_ERROR_NO_MEMORY);
+	    PORT_FreeArena(pfx->poolp, PR_TRUE);
+	    return NULL;
+	}
     } else {
 	pfx->old = PR_FALSE;
     }
 
     /* convert bit string from bits to bytes */
     pfx->macData.macSalt.len /= 8;
 
     return pfx;
--- a/security/nss/lib/pkcs7/p7decode.c
+++ b/security/nss/lib/pkcs7/p7decode.c
@@ -643,18 +643,26 @@ sec_pkcs7_decoder_notify (void *arg, PRB
      * causes a warning on the mac; to avoid that, we do it the long way.)
      */
     if (before)
 	after = PR_FALSE;
     else
 	after = PR_TRUE;
 
     p7dcx = (SEC_PKCS7DecoderContext*)arg;
+    if (!p7dcx) {
+	return;
+    }
+
     cinfo = p7dcx->cinfo;
 
+    if (!cinfo) {
+	return;
+    }
+
     if (cinfo->contentTypeTag == NULL) {
 	if (after && dest == &(cinfo->contentType))
 	    cinfo->contentTypeTag = SECOID_FindOID(&(cinfo->contentType));
 	return;
     }
 
     switch (cinfo->contentTypeTag->offset) {
       case SEC_OID_PKCS7_SIGNED_DATA:
@@ -862,16 +870,20 @@ sec_pkcs7_decoder_notify (void *arg, PRB
 	if (after && dest == &(digd->contentInfo.content.data)) {
 	    SEC_ASN1DecoderClearFilterProc (p7dcx->dcx);
 	}
 	break;
 
       case SEC_OID_PKCS7_ENCRYPTED_DATA:
 	encd = cinfo->content.encryptedData;
 
+	if (!encd) {
+	    break;
+	}
+
 	/*
 	 * XXX If the decryption key callback is set, we want to start
 	 * the decryption.  If the callback is not set, we will treat the
 	 * content as plain data, since we do not have the key.
 	 *
 	 * Is this the proper thing to do?
 	 */
 	if (before && dest == &(encd->encContentInfo.encContent)) {
--- a/security/nss/lib/pki/tdcache.c
+++ b/security/nss/lib/pki/tdcache.c
@@ -290,35 +290,37 @@ remove_email_entry (
     PRStatus nssrv = PR_FAILURE;
     cache_entry *ce;
     /* Find the subject list in the email hash */
     if (cert->email) {
 	ce = (cache_entry *)nssHash_Lookup(cache->email, cert->email);
 	if (ce) {
 	    nssList *subjects = ce->entry.list;
 	    /* Remove the subject list from the email hash */
-	    nssList_Remove(subjects, subjectList);
+            if (subjects) {
+		nssList_Remove(subjects, subjectList);
 #ifdef DEBUG_CACHE
-	    log_item_dump("removed subject list", &cert->subject);
-	    PR_LOG(s_log, PR_LOG_DEBUG, ("for email %s", cert->email));
+		log_item_dump("removed subject list", &cert->subject);
+		PR_LOG(s_log, PR_LOG_DEBUG, ("for email %s", cert->email));
 #endif
-	    if (nssList_Count(subjects) == 0) {
-		/* No more subject lists for email, delete list and
-		* remove hash entry
-		*/
-		(void)nssList_Destroy(subjects);
-		nssHash_Remove(cache->email, cert->email);
-		/* there are no entries left for this address, free space
-		 * used for email entries
-		 */
-		nssArena_Destroy(ce->arena);
+		if (nssList_Count(subjects) == 0) {
+		    /* No more subject lists for email, delete list and
+		     * remove hash entry
+		     */
+		    (void)nssList_Destroy(subjects);
+		    nssHash_Remove(cache->email, cert->email);
+		    /* there are no entries left for this address, free space
+		     * used for email entries
+		     */
+		     nssArena_Destroy(ce->arena);
 #ifdef DEBUG_CACHE
-		PR_LOG(s_log, PR_LOG_DEBUG, ("removed email %s", cert->email));
+		    PR_LOG(s_log, PR_LOG_DEBUG, ("removed email %s", cert->email));
 #endif
-	    }
+		}
+            }
 	    nssrv = PR_SUCCESS;
 	}
     }
     return nssrv;
 }
 
 NSS_IMPLEMENT void
 nssTrustDomain_RemoveCertFromCacheLOCKED (
--- a/security/nss/lib/pki/trustdomain.c
+++ b/security/nss/lib/pki/trustdomain.c
@@ -107,16 +107,19 @@ nssTrustDomain_GetActiveSlots (
   NSSTrustDomain *td,
   nssUpdateLevel *updateLevel
 )
 {
     PRUint32 count;
     NSSSlot **slots = NULL;
     NSSToken **tp, **tokens;
     *updateLevel = 1;
+    if (!td->tokenList) {
+        return NULL;
+    }
     NSSRWLock_LockRead(td->tokensLock);
     count = nssList_Count(td->tokenList);
     tokens = nss_ZNEWARRAY(NULL, NSSToken *, count + 1);
     if (!tokens) {
 	NSSRWLock_UnlockRead(td->tokensLock);
 	return NULL;
     }
     slots = nss_ZNEWARRAY(NULL, NSSSlot *, count + 1);
--- a/security/nss/lib/smime/cmsrecinfo.c
+++ b/security/nss/lib/smime/cmsrecinfo.c
@@ -133,18 +133,18 @@ nss_cmsrecipientinfo_create(NSSCMSMessag
 	    NSSCMSKeyTransRecipientInfoEx *riExtra;
 
 	    rid->id.subjectKeyID = PORT_ArenaNew(poolp, SECItem);
 	    if (rid->id.subjectKeyID == NULL) {
 		rv = SECFailure;
 		PORT_SetError(SEC_ERROR_NO_MEMORY);
 		break;
 	    } 
-	    SECITEM_CopyItem(poolp, rid->id.subjectKeyID, subjKeyID);
-	    if (rid->id.subjectKeyID->data == NULL) {
+	    rv = SECITEM_CopyItem(poolp, rid->id.subjectKeyID, subjKeyID);
+	    if (rv != SECSuccess || rid->id.subjectKeyID->data == NULL) {
 		rv = SECFailure;
 		PORT_SetError(SEC_ERROR_NO_MEMORY);
 		break;
 	    }
 	    riExtra = &ri->ri.keyTransRecipientInfoEx;
 	    riExtra->version = 0;
 	    riExtra->pubKey = SECKEY_CopyPublicKey(pubKey);
 	    if (riExtra->pubKey == NULL) {
--- a/security/nss/lib/smime/cmssiginfo.c
+++ b/security/nss/lib/smime/cmssiginfo.c
@@ -46,16 +46,17 @@ NSSCMSSignerInfo *
 nss_cmssignerinfo_create(NSSCMSMessage *cmsg, NSSCMSSignerIDSelector type, 
 	CERTCertificate *cert, SECItem *subjKeyID, SECKEYPublicKey *pubKey, 
 	SECKEYPrivateKey *signingKey, SECOidTag digestalgtag)
 {
     void *mark;
     NSSCMSSignerInfo *signerinfo;
     int version;
     PLArenaPool *poolp;
+    SECStatus rv;
 
     poolp = cmsg->poolp;
 
     mark = PORT_ArenaMark(poolp);
 
     signerinfo = (NSSCMSSignerInfo *)PORT_ArenaZAlloc(poolp, sizeof(NSSCMSSignerInfo));
     if (signerinfo == NULL) {
 	PORT_ArenaRelease(poolp, mark);
@@ -75,18 +76,21 @@ nss_cmssignerinfo_create(NSSCMSMessage *
         break;
     case NSSCMSSignerID_SubjectKeyID:
         signerinfo->signerIdentifier.identifierType = NSSCMSSignerID_SubjectKeyID;
         PORT_Assert(subjKeyID);
         if (!subjKeyID)
             goto loser;
 
         signerinfo->signerIdentifier.id.subjectKeyID = PORT_ArenaNew(poolp, SECItem);
-        SECITEM_CopyItem(poolp, signerinfo->signerIdentifier.id.subjectKeyID,
-                         subjKeyID);
+        rv = SECITEM_CopyItem(poolp, signerinfo->signerIdentifier.id.subjectKeyID,
+                              subjKeyID);
+        if (rv != SECSuccess) {
+            goto loser;
+        }
         signerinfo->signingKey = SECKEY_CopyPrivateKey(signingKey);
         if (!signerinfo->signingKey)
             goto loser;
         signerinfo->pubKey = SECKEY_CopyPublicKey(pubKey);
         if (!signerinfo->pubKey)
             goto loser;
         break;
     default:
--- a/security/nss/lib/softoken/legacydb/lgattr.c
+++ b/security/nss/lib/softoken/legacydb/lgattr.c
@@ -131,17 +131,19 @@ lg_CopyAttribute(CK_ATTRIBUTE *attr, CK_
     if (attr->pValue == NULL) {
 	attr->ulValueLen = len;
 	return CKR_OK;
     }
     if (attr->ulValueLen < len) {
 	attr->ulValueLen = (CK_ULONG) -1;
 	return CKR_BUFFER_TOO_SMALL;
     }
-    PORT_Memcpy(attr->pValue,value,len);
+    if (value != NULL) {
+	PORT_Memcpy(attr->pValue,value,len);
+    }
     attr->ulValueLen = len;
     return CKR_OK;
 }
 
 static CK_RV
 lg_CopyAttributeSigned(CK_ATTRIBUTE *attribute, CK_ATTRIBUTE_TYPE type, 
 				void  *value, CK_ULONG len)
 {
--- a/security/nss/lib/softoken/legacydb/lowkey.c
+++ b/security/nss/lib/softoken/legacydb/lowkey.c
@@ -96,55 +96,33 @@ const SEC_ASN1Template lg_nsslowkey_DHPr
     { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.dh.privateValue) },
     { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.dh.base) },
     { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.dh.prime) },
     { 0 }
 };
 
 #ifndef NSS_DISABLE_ECC
 
-/* XXX This is just a placeholder for later when we support
- * generic curves and need full-blown support for parsing EC
- * parameters. For now, we only support named curves in which
- * EC params are simply encoded as an object ID and we don't
- * use lg_nsslowkey_ECParamsTemplate.
- */
-const SEC_ASN1Template lg_nsslowkey_ECParamsTemplate[] = {
-    { SEC_ASN1_CHOICE, offsetof(ECParams,type), NULL, sizeof(ECParams) },
-    { SEC_ASN1_OBJECT_ID, offsetof(ECParams,curveOID), NULL, ec_params_named },
-    { 0 }
-};
-
-
 /* NOTE: The SECG specification allows the private key structure
  * to contain curve parameters but recommends that they be stored
  * in the PrivateKeyAlgorithmIdentifier field of the PrivateKeyInfo
  * instead.
  */
 const SEC_ASN1Template lg_nsslowkey_ECPrivateKeyTemplate[] = {
     { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPrivateKey) },
     { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.ec.version) },
     { SEC_ASN1_OCTET_STRING, 
       offsetof(NSSLOWKEYPrivateKey,u.ec.privateValue) },
-    /* XXX The following template works for now since we only
-     * support named curves for which the parameters are
-     * encoded as an object ID. When we support generic curves,
-     * we'll need to define lg_nsslowkey_ECParamsTemplate
+    /* We only support named curves for which the parameters are
+     * encoded as an object ID.
      */
-#if 1
     { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
       SEC_ASN1_EXPLICIT | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0, 
       offsetof(NSSLOWKEYPrivateKey,u.ec.ecParams.curveOID), 
       SEC_ASN1_SUB(SEC_ObjectIDTemplate) }, 
-#else
-    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
-      SEC_ASN1_EXPLICIT | SEC_ASN1_CONTEXT_SPECIFIC | 0, 
-      offsetof(NSSLOWKEYPrivateKey,u.ec.ecParams), 
-      lg_nsslowkey_ECParamsTemplate }, 
-#endif
     { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
       SEC_ASN1_EXPLICIT | SEC_ASN1_CONTEXT_SPECIFIC |
       SEC_ASN1_XTRN | 1, 
       offsetof(NSSLOWKEYPrivateKey,u.ec.publicValue),
       SEC_ASN1_SUB(SEC_BitStringTemplate) }, 
     { 0 }
 };
 
--- a/security/nss/lib/softoken/legacydb/lowkeyti.h
+++ b/security/nss/lib/softoken/legacydb/lowkeyti.h
@@ -40,17 +40,16 @@ typedef struct NSSLOWKEYDBHandleStr NSSL
 extern const SEC_ASN1Template lg_nsslowkey_PQGParamsTemplate[];
 extern const SEC_ASN1Template lg_nsslowkey_RSAPrivateKeyTemplate[];
 extern const SEC_ASN1Template lg_nsslowkey_RSAPrivateKeyTemplate2[];
 extern const SEC_ASN1Template lg_nsslowkey_DSAPrivateKeyTemplate[];
 extern const SEC_ASN1Template lg_nsslowkey_DHPrivateKeyTemplate[];
 extern const SEC_ASN1Template lg_nsslowkey_DHPrivateKeyExportTemplate[];
 #ifndef NSS_DISABLE_ECC
 #define NSSLOWKEY_EC_PRIVATE_KEY_VERSION   1  /* as per SECG 1 C.4 */
-extern const SEC_ASN1Template lg_nsslowkey_ECParamsTemplate[];
 extern const SEC_ASN1Template lg_nsslowkey_ECPrivateKeyTemplate[];
 #endif /* NSS_DISABLE_ECC */
 
 extern const SEC_ASN1Template lg_nsslowkey_PrivateKeyInfoTemplate[];
 extern const SEC_ASN1Template nsslowkey_EncryptedPrivateKeyInfoTemplate[];
 
 /*
  * PKCS #8 attributes
--- a/security/nss/lib/softoken/legacydb/pcertdb.c
+++ b/security/nss/lib/softoken/legacydb/pcertdb.c
@@ -4347,16 +4347,20 @@ certcallback(SECItem *dbdata, SECItem *d
     PLArenaPool *arena = NULL;
     
     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
     if ( arena == NULL ) {
 	goto loser;
     }
     
     entry = (certDBEntryCert *)PORT_ArenaAlloc(arena, sizeof(certDBEntryCert));
+    if (!entry) {
+	PORT_SetError(SEC_ERROR_NO_MEMORY);
+	goto loser;
+    }
     mystate = (PermCertCallbackState *)data;
     entry->common.version = (unsigned int)dbdata->data[0];
     entry->common.type = (certDBEntryType)dbdata->data[1];
     entry->common.flags = (unsigned int)dbdata->data[2];
     entry->common.arena = arena;
     
     entryitem.len = dbdata->len - SEC_DB_ENTRY_HEADER_LEN;
     entryitem.data = &dbdata->data[SEC_DB_ENTRY_HEADER_LEN];
--- a/security/nss/lib/softoken/lowkey.c
+++ b/security/nss/lib/softoken/lowkey.c
@@ -88,56 +88,34 @@ const SEC_ASN1Template nsslowkey_DHPriva
     { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.dh.privateValue) },
     { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.dh.base) },
     { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.dh.prime) },
     { 0 }
 };
 
 #ifndef NSS_DISABLE_ECC
 
-/* XXX This is just a placeholder for later when we support
- * generic curves and need full-blown support for parsing EC
- * parameters. For now, we only support named curves in which
- * EC params are simply encoded as an object ID and we don't
- * use nsslowkey_ECParamsTemplate.
- */
-const SEC_ASN1Template nsslowkey_ECParamsTemplate[] = {
-    { SEC_ASN1_CHOICE, offsetof(ECParams,type), NULL, sizeof(ECParams) },
-    { SEC_ASN1_OBJECT_ID, offsetof(ECParams,curveOID), NULL, ec_params_named },
-    { 0 }
-};
-
-
 /* NOTE: The SECG specification allows the private key structure
  * to contain curve parameters but recommends that they be stored
  * in the PrivateKeyAlgorithmIdentifier field of the PrivateKeyInfo
  * instead.
  */
 const SEC_ASN1Template nsslowkey_ECPrivateKeyTemplate[] = {
     { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPrivateKey) },
     { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey,u.ec.version) },
     { SEC_ASN1_OCTET_STRING, 
       offsetof(NSSLOWKEYPrivateKey,u.ec.privateValue) },
-    /* XXX The following template works for now since we only
-     * support named curves for which the parameters are
-     * encoded as an object ID. When we support generic curves,
-     * we'll need to define nsslowkey_ECParamsTemplate
+    /* We only support named curves for which the parameters are
+     * encoded as an object ID.
      */
-#if 1
     { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
       SEC_ASN1_EXPLICIT | SEC_ASN1_CONTEXT_SPECIFIC |
       SEC_ASN1_XTRN | 0, 
       offsetof(NSSLOWKEYPrivateKey,u.ec.ecParams.curveOID), 
-      SEC_ASN1_SUB(SEC_ObjectIDTemplate) }, 
-#else
-    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
-      SEC_ASN1_EXPLICIT | SEC_ASN1_CONTEXT_SPECIFIC | 0, 
-      offsetof(NSSLOWKEYPrivateKey,u.ec.ecParams), 
-      nsslowkey_ECParamsTemplate }, 
-#endif
+      SEC_ASN1_SUB(SEC_ObjectIDTemplate) },
     { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED |
       SEC_ASN1_EXPLICIT | SEC_ASN1_CONTEXT_SPECIFIC |
       SEC_ASN1_XTRN | 1, 
       offsetof(NSSLOWKEYPrivateKey,u.ec.publicValue),
       SEC_ASN1_SUB(SEC_BitStringTemplate) }, 
     { 0 }
 };
 #endif /* NSS_DISABLE_ECC */
--- a/security/nss/lib/softoken/lowkeyti.h
+++ b/security/nss/lib/softoken/lowkeyti.h
@@ -17,17 +17,16 @@
 extern const SEC_ASN1Template nsslowkey_PQGParamsTemplate[];
 extern const SEC_ASN1Template nsslowkey_RSAPrivateKeyTemplate[];
 extern const SEC_ASN1Template nsslowkey_DSAPrivateKeyTemplate[];
 extern const SEC_ASN1Template nsslowkey_DSAPrivateKeyExportTemplate[];
 extern const SEC_ASN1Template nsslowkey_DHPrivateKeyTemplate[];
 extern const SEC_ASN1Template nsslowkey_DHPrivateKeyExportTemplate[];
 #ifndef NSS_DISABLE_ECC
 #define NSSLOWKEY_EC_PRIVATE_KEY_VERSION   1  /* as per SECG 1 C.4 */
-extern const SEC_ASN1Template nsslowkey_ECParamsTemplate[];
 extern const SEC_ASN1Template nsslowkey_ECPrivateKeyTemplate[];
 #endif /* NSS_DISABLE_ECC */
 
 extern const SEC_ASN1Template nsslowkey_PrivateKeyInfoTemplate[];
 extern const SEC_ASN1Template nsslowkey_EncryptedPrivateKeyInfoTemplate[];
 
 /*
  * PKCS #8 attributes
--- a/security/nss/lib/softoken/pkcs11.c
+++ b/security/nss/lib/softoken/pkcs11.c
@@ -2208,27 +2208,23 @@ sftk_IsWeakKey(unsigned char *key,CK_KEY
  *     Start of PKCS 11 functions 
  *
  **********************************************************************/
 
 
 /* return the function list */
 CK_RV NSC_GetFunctionList(CK_FUNCTION_LIST_PTR *pFunctionList)
 {
-    CHECK_FORK();
-
     *pFunctionList = (CK_FUNCTION_LIST_PTR) &sftk_funcList;
     return CKR_OK;
 }
 
 /* return the function list */
 CK_RV C_GetFunctionList(CK_FUNCTION_LIST_PTR *pFunctionList)
 {
-    CHECK_FORK();
-
     return NSC_GetFunctionList(pFunctionList);
 }
 
 static PLHashNumber
 sftk_HashNumber(const void *key)
 {
     return (PLHashNumber)((char *)key - (char *)NULL);
 }
--- a/security/nss/lib/softoken/pkcs11c.c
+++ b/security/nss/lib/softoken/pkcs11c.c
@@ -2064,16 +2064,19 @@ sftk_InitCBCMac(CK_SESSION_HANDLE hSessi
 #endif
     unsigned char ivBlock[SFTK_MAX_BLOCK_SIZE];
     SFTKSessionContext *context;
     CK_RV crv;
     unsigned int blockSize;
 
     switch (pMechanism->mechanism) {
     case CKM_RC2_MAC_GENERAL:
+	if (!pMechanism->pParameter) {
+	    return CKR_MECHANISM_PARAM_INVALID;
+	}
 	mac_bytes = 
 	    ((CK_RC2_MAC_GENERAL_PARAMS *)pMechanism->pParameter)->ulMacLength;
 	/* fall through */
     case CKM_RC2_MAC:
 	/* this works because ulEffectiveBits is in the same place in both the
 	 * CK_RC2_MAC_GENERAL_PARAMS and CK_RC2_CBC_PARAMS */
 	rc2_params.ulEffectiveBits = ((CK_RC2_MAC_GENERAL_PARAMS *)
 				pMechanism->pParameter)->ulEffectiveBits;
@@ -6079,17 +6082,17 @@ CK_RV NSC_DeriveKey( CK_SESSION_HANDLE h
     CK_MECHANISM_TYPE mechanism = pMechanism->mechanism;
     PRBool          isTLS = PR_FALSE;
     PRBool          isDH = PR_FALSE;
     HASH_HashType   tlsPrfHash = HASH_AlgNULL;
     SECStatus       rv;
     int             i;
     unsigned int    outLen;
     unsigned char   sha_out[SHA1_LENGTH];
-    unsigned char   key_block[NUM_MIXERS * MD5_LENGTH];
+    unsigned char   key_block[NUM_MIXERS * SFTK_MAX_MAC_LENGTH];
     unsigned char   key_block2[MD5_LENGTH];
     PRBool          isFIPS;		
     HASH_HashType   hashType;
     PRBool          extractValue = PR_TRUE;
 
     CHECK_FORK();
 
     if (!slot) {
--- a/security/nss/lib/softoken/sdb.c
+++ b/security/nss/lib/softoken/sdb.c
@@ -406,17 +406,17 @@ sdb_measureAccess(const char *directory)
 
 	/* We'll use the variable part first in the filename string, just in
 	 * case it's longer than assumed, so if anything gets cut off, it
 	 * will be cut off from the constant part.
 	 * This code assumes the directory name at the beginning of
 	 * temp remains unchanged during our loop. */
         PR_snprintf(tempStartOfFilename, maxFileNameLen,
 		    ".%lu%s", (PRUint32)(time+i), doesntExistName);
-	PR_Access(temp,PR_ACCESS_EXISTS);
+	PR_Access(temp, PR_ACCESS_EXISTS);
 	next = PR_IntervalNow();
 	delta = next - time;
 	if (delta >= duration)
 	    break;
     }
 
     PORT_Free(temp);
 
@@ -1725,21 +1725,26 @@ sdb_init(char *dbname, char *table, sdbD
 	error = sdb_mapSQLError(type, SQLITE_CANTOPEN);
 	goto loser;
     }
     sqlerr = sdb_openDB(dbname, &sqlDB, flags);
     if (sqlerr != SQLITE_OK) {
 	error = sdb_mapSQLError(type, sqlerr); 
 	goto loser;
     }
-    /* sql created the file, but it doesn't set appropriate modes for
-     * a database */
-    if (create) {
-	/* NO NSPR call for this? :( */
-	chmod (dbname, 0600);
+
+    /*
+     * SQL created the file, but it doesn't set appropriate modes for
+     * a database.
+     *
+     * NO NSPR call for chmod? :(
+     */
+    if (create && chmod(dbname, 0600) != 0) {
+        error = sdb_mapSQLError(type, SQLITE_CANTOPEN);
+        goto loser;
     }
 
     if (flags != SDB_RDONLY) {
 	sqlerr = sqlite3_exec(sqlDB, BEGIN_CMD, NULL, 0, NULL);
 	if (sqlerr != SQLITE_OK) {
 	    error = sdb_mapSQLError(type, sqlerr);
 	    goto loser;
 	}
--- a/security/nss/lib/softoken/softkver.h
+++ b/security/nss/lib/softoken/softkver.h
@@ -20,16 +20,16 @@
 
 /*
  * Softoken's major version, minor version, patch level, build number,
  * and whether this is a beta release.
  *
  * The format of the version string should be
  *     "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
  */
-#define SOFTOKEN_VERSION  "3.24" SOFTOKEN_ECC_STRING
+#define SOFTOKEN_VERSION  "3.25" SOFTOKEN_ECC_STRING " Beta"
 #define SOFTOKEN_VMAJOR   3
-#define SOFTOKEN_VMINOR   24
+#define SOFTOKEN_VMINOR   25
 #define SOFTOKEN_VPATCH   0
 #define SOFTOKEN_VBUILD   0
-#define SOFTOKEN_BETA     PR_FALSE
+#define SOFTOKEN_BETA     PR_TRUE
 
 #endif /* _SOFTKVER_H_ */
--- a/security/nss/lib/ssl/SSLerrs.h
+++ b/security/nss/lib/ssl/SSLerrs.h
@@ -464,9 +464,8 @@ ER3(SSL_ERROR_KEY_EXCHANGE_FAILURE, (SSL
 ER3(SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION, (SSL_ERROR_BASE + 145),
     "SSL received an extension that is not permitted for this version.")
 
 ER3(SSL_ERROR_RX_MALFORMED_ENCRYPTED_EXTENSIONS, (SSL_ERROR_BASE + 146),
     "SSL received a malformed Encrypted Extensions handshake message.")
 
 ER3(SSL_ERROR_RX_MALFORMED_PRE_SHARED_KEY, (SSL_ERROR_BASE + 147),
     "SSL received an invalid PreSharedKey extension.")
-
--- a/security/nss/lib/ssl/derive.c
+++ b/security/nss/lib/ssl/derive.c
@@ -63,16 +63,17 @@ static const char *const mixers[NUM_MIXE
 };
 
 SECStatus
 ssl3_KeyAndMacDeriveBypass(
     ssl3CipherSpec *pwSpec,
     const unsigned char *cr,
     const unsigned char *sr,
     PRBool isTLS,
+    HASH_HashType tls12HashType,
     PRBool isExport)
 {
     const ssl3BulkCipherDef *cipher_def = pwSpec->cipher_def;
     unsigned char *key_block = pwSpec->key_block;
     unsigned char *key_block2 = NULL;
     unsigned int block_bytes = 0;
     unsigned int block_needed = 0;
     unsigned int i;
@@ -153,28 +154,28 @@ ssl3_KeyAndMacDeriveBypass(
     if (isTLS) {
         SECItem keyblk;
 
         keyblk.type = siBuffer;
         keyblk.data = key_block;
         keyblk.len = block_needed;
 
         if (isTLS12) {
-            status = TLS_P_hash(HASH_AlgSHA256, &pwSpec->msItem,
+            status = TLS_P_hash(tls12HashType, &pwSpec->msItem,
                                 "key expansion", &srcr, &keyblk, isFIPS);
         } else {
             status = TLS_PRF(&pwSpec->msItem, "key expansion", &srcr, &keyblk,
                              isFIPS);
         }
         if (status != SECSuccess) {
             goto key_and_mac_derive_fail;
         }
         block_bytes = keyblk.len;
     } else {
-       /* key_block =
+        /* key_block =
         *     MD5(master_secret + SHA('A' + master_secret +
         *                      ServerHello.random + ClientHello.random)) +
         *     MD5(master_secret + SHA('BB' + master_secret +
         *                      ServerHello.random + ClientHello.random)) +
         *     MD5(master_secret + SHA('CCC' + master_secret +
         *                      ServerHello.random + ClientHello.random)) +
         *     [...];
         */
@@ -430,16 +431,17 @@ key_and_mac_derive_fail:
  */
 SECStatus
 ssl3_MasterSecretDeriveBypass(
     ssl3CipherSpec *pwSpec,
     const unsigned char *cr,
     const unsigned char *sr,
     const SECItem *pms,
     PRBool isTLS,
+    HASH_HashType tls12HashType,
     PRBool isRSA)
 {
     unsigned char *key_block = pwSpec->key_block;
     SECStatus rv = SECSuccess;
     PRBool isFIPS = PR_FALSE;
     PRBool isTLS12 = pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2;
 
     SECItem crsr;
@@ -472,17 +474,17 @@ ssl3_MasterSecretDeriveBypass(
     /* finally do the key gen */
     if (isTLS) {
         SECItem master = { siBuffer, NULL, 0 };
 
         master.data = key_block;
         master.len = SSL3_MASTER_SECRET_LENGTH;
 
         if (isTLS12) {
-            rv = TLS_P_hash(HASH_AlgSHA256, pms, "master secret", &crsr,
+            rv = TLS_P_hash(tls12HashType, pms, "master secret", &crsr,
                             &master, isFIPS);
         } else {
             rv = TLS_PRF(pms, "master secret", &crsr, &master, isFIPS);
         }
         if (rv != SECSuccess) {
             PORT_SetError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
         }
     } else {
@@ -614,19 +616,17 @@ SSL_CanBypass(CERTCertificate *cert, SEC
     CK_MECHANISM_TYPE mechanism_array[2];
     SECItem enc_pms = { siBuffer, NULL, 0 };
     PRBool isTLS = PR_FALSE;
     SSLCipherSuiteInfo csdef;
     PRBool testrsa = PR_FALSE;
     PRBool testrsa_export = PR_FALSE;
     PRBool testecdh = PR_FALSE;
     PRBool testecdhe = PR_FALSE;
-#ifndef NSS_DISABLE_ECC
     SECKEYECParams ecParams = { siBuffer, NULL, 0 };
-#endif
 
     if (!cert || !srvPrivkey || !ciphersuites || !pcanbypass) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return SECFailure;
     }
 
     srvPubkey = CERT_ExtractPublicKey(cert);
     if (!srvPubkey)
@@ -751,17 +751,16 @@ SSL_CanBypass(CERTCertificate *cert, SEC
         }
 
         /* Check for NULL to avoid double free.
          * SECItem_FreeItem sets data NULL in secitem.c#265
          */
         if (enc_pms.data != NULL) {
             SECITEM_FreeItem(&enc_pms, PR_FALSE);
         }
-#ifndef NSS_DISABLE_ECC
         for (; (privKeytype == ecKey && (testecdh || testecdhe)) ||
                (privKeytype == rsaKey && testecdhe);) {
             CK_MECHANISM_TYPE target;
             SECKEYPublicKey *keapub = NULL;
             SECKEYPrivateKey *keapriv;
             SECKEYPublicKey *cpub = NULL; /* client's ephemeral ECDH keys */
             SECKEYPrivateKey *cpriv = NULL;
             SECKEYECParams *pecParams = NULL;
@@ -855,17 +854,16 @@ SSL_CanBypass(CERTCertificate *cert, SEC
                 goto done;
             break;
         }
         /* Check for NULL to avoid double free. */
         if (ecParams.data != NULL) {
             PORT_Free(ecParams.data);
             ecParams.data = NULL;
         }
-#endif /* NSS_DISABLE_ECC */
         if (pms)
             PK11_FreeSymKey(pms);
     }
 
     /* *pcanbypass has been set */
     rv = SECSuccess;
 
 done:
@@ -873,22 +871,20 @@ done:
         PK11_FreeSymKey(pms);
 
     /* Check for NULL to avoid double free.
      * SECItem_FreeItem sets data NULL in secitem.c#265
      */
     if (enc_pms.data != NULL) {
         SECITEM_FreeItem(&enc_pms, PR_FALSE);
     }
-#ifndef NSS_DISABLE_ECC
     if (ecParams.data != NULL) {
         PORT_Free(ecParams.data);
         ecParams.data = NULL;
     }
-#endif /* NSS_DISABLE_ECC */
 
     if (srvPubkey) {
         SECKEY_DestroyPublicKey(srvPubkey);
         srvPubkey = NULL;
     }
 
     return rv;
 #endif /* NO_PKCS11_BYPASS */
--- a/security/nss/lib/ssl/dtlscon.c
+++ b/security/nss/lib/ssl/dtlscon.c
@@ -27,25 +27,21 @@ static const PRUint16 COMMON_MTU_VALUES[
     576 - 28,  /* Common assumption */
     256 - 28   /* We're in serious trouble now */
 };
 
 #define DTLS_COOKIE_BYTES 32
 
 /* List copied from ssl3con.c:cipherSuites */
 static const ssl3CipherSuite nonDTLSSuites[] = {
-#ifndef NSS_DISABLE_ECC
     TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
     TLS_ECDHE_RSA_WITH_RC4_128_SHA,
-#endif /* NSS_DISABLE_ECC */
     TLS_DHE_DSS_WITH_RC4_128_SHA,
-#ifndef NSS_DISABLE_ECC
     TLS_ECDH_RSA_WITH_RC4_128_SHA,
     TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
-#endif /* NSS_DISABLE_ECC */
     TLS_RSA_WITH_RC4_128_MD5,
     TLS_RSA_WITH_RC4_128_SHA,
     TLS_RSA_EXPORT1024_WITH_RC4_56_SHA,
     TLS_RSA_EXPORT_WITH_RC4_40_MD5,
     0 /* End of list marker */
 };
 
 /* Map back and forth between TLS and DTLS versions in wire format.
@@ -341,29 +337,29 @@ dtls_HandleHandshake(sslSocket *ss, sslB
             dtls_CancelTimer(ss);
 
             /* Reset the timer to the initial value if the retry counter
              * is 0, per Sec. 4.2.4.1 */
             if (ss->ssl3.hs.rtRetries == 0) {
                 ss->ssl3.hs.rtTimeoutMs = DTLS_RETRANSMIT_INITIAL_MS;
             }
 
-            rv = ssl3_HandleHandshakeMessage(ss, buf.buf, ss->ssl3.hs.msg_len);
+            rv = ssl3_HandleHandshakeMessage(ss, buf.buf, ss->ssl3.hs.msg_len,
+                                             buf.len == fragment_length);
             if (rv == SECFailure) {
                 /* Do not attempt to process rest of messages in this record */
                 break;
             }
         } else {
             if (message_seq < ss->ssl3.hs.recvMessageSeq) {
                 /* Case 3: we do an immediate retransmit if we're
                  * in a waiting state. */
                 rv = dtls_RetransmitDetected(ss);
                 break;
-            }
-            else if (message_seq > ss->ssl3.hs.recvMessageSeq) {
+            } else if (message_seq > ss->ssl3.hs.recvMessageSeq) {
                 /* Case 2
                  *
                  * Ignore this message. This means we don't handle out of
                  * order complete messages that well, but we're still
                  * compliant and this probably does not happen often
                  *
                  * XXX OK for now. Maybe do something smarter at some point?
                  */
@@ -448,19 +444,20 @@ dtls_HandleHandshake(sslSocket *ss, sslB
                         break;
                     }
                 }
 
                 /* If we have all the bytes, then we are good to go */
                 if (ss->ssl3.hs.recvdHighWater == ss->ssl3.hs.msg_len) {
                     ss->ssl3.hs.recvdHighWater = -1;
 
-                    rv = ssl3_HandleHandshakeMessage(ss,
-                                                     ss->ssl3.hs.msg_body.buf,
-                                                     ss->ssl3.hs.msg_len);
+                    rv = ssl3_HandleHandshakeMessage(
+                        ss,
+                        ss->ssl3.hs.msg_body.buf, ss->ssl3.hs.msg_len,
+                        buf.len == fragment_length);
                     if (rv == SECFailure)
                         break; /* Skip rest of record */
 
                     /* At this point we are advancing our state machine, so
                      * we can free our last flight of messages */
                     dtls_FreeHandshakeMessages(&ss->ssl3.hs.lastMessageFlight);
                     dtls_CancelTimer(ss);
 
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -24,19 +24,17 @@
 #include "prerror.h"
 #include "pratom.h"
 #include "prthread.h"
 #include "nss.h"
 #include "nssoptions.h"
 
 #include "pk11func.h"
 #include "secmod.h"
-#ifndef NO_PKCS11_BYPASS
 #include "blapi.h"
-#endif
 
 #include <stdio.h>
 #ifdef NSS_SSL_ENABLE_ZLIB
 #include "zlib.h"
 #endif
 
 #ifndef PK11_SETATTRS
 #define PK11_SETATTRS(x, id, v, l) \
@@ -93,72 +91,75 @@ static SECStatus ssl3_AESGCMBypass(ssl3K
  *
  * Important: See bug 946147 before enabling, reordering, or adding any cipher
  * suites to this list.
  */
 /* clang-format off */
 static ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED] = {
    /*      cipher_suite                     policy       enabled   isPresent */
 
-#ifndef NSS_DISABLE_ECC
  /* ECDHE-PSK from [draft-mattsson-tls-ecdhe-psk-aead]. Only enabled if
   * we are doing TLS 1.3 PSK-resumption.
   */
  { TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256,   SSL_ALLOWED, PR_TRUE,  PR_FALSE},
  { TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE},
  { TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,   SSL_ALLOWED, PR_TRUE, PR_FALSE},
  { TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE},
  { TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,   SSL_ALLOWED, PR_TRUE, PR_FALSE},
+ { TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, SSL_ALLOWED, PR_FALSE, PR_FALSE},
+ { TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,   SSL_ALLOWED, PR_FALSE, PR_FALSE},
    /* TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA is out of order to work around
     * bug 946147.
     */
  { TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,    SSL_ALLOWED, PR_TRUE, PR_FALSE},
  { TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,    SSL_ALLOWED, PR_TRUE, PR_FALSE},
  { TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,      SSL_ALLOWED, PR_TRUE, PR_FALSE},
  { TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE},
  { TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,   SSL_ALLOWED, PR_TRUE, PR_FALSE},
  { TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,      SSL_ALLOWED, PR_TRUE, PR_FALSE},
+ { TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, SSL_ALLOWED, PR_FALSE, PR_FALSE},
+ { TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,   SSL_ALLOWED, PR_FALSE, PR_FALSE},
  { TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,   SSL_ALLOWED, PR_FALSE, PR_FALSE},
  { TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,     SSL_ALLOWED, PR_FALSE, PR_FALSE},
  { TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,        SSL_ALLOWED, PR_FALSE, PR_FALSE},
  { TLS_ECDHE_RSA_WITH_RC4_128_SHA,          SSL_ALLOWED, PR_FALSE, PR_FALSE},
-#endif /* NSS_DISABLE_ECC */
 
  { TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,     SSL_ALLOWED, PR_TRUE,  PR_FALSE},
  { TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,SSL_ALLOWED,PR_TRUE,  PR_FALSE},
  { TLS_DHE_DSS_WITH_AES_128_GCM_SHA256,     SSL_ALLOWED, PR_FALSE, PR_FALSE},
+ { TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,     SSL_ALLOWED, PR_FALSE, PR_FALSE},
+ { TLS_DHE_DSS_WITH_AES_256_GCM_SHA384,     SSL_ALLOWED, PR_FALSE, PR_FALSE},
  { TLS_DHE_RSA_WITH_AES_128_CBC_SHA,        SSL_ALLOWED, PR_TRUE,  PR_FALSE},
  { TLS_DHE_DSS_WITH_AES_128_CBC_SHA,        SSL_ALLOWED, PR_TRUE,  PR_FALSE},
  { TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,     SSL_ALLOWED, PR_TRUE,  PR_FALSE},
  { TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,     SSL_ALLOWED, PR_FALSE, PR_FALSE},
  { TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,   SSL_ALLOWED, PR_FALSE, PR_FALSE},
  { TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA,   SSL_ALLOWED, PR_FALSE, PR_FALSE},
  { TLS_DHE_RSA_WITH_AES_256_CBC_SHA,        SSL_ALLOWED, PR_TRUE,  PR_FALSE},
  { TLS_DHE_DSS_WITH_AES_256_CBC_SHA,        SSL_ALLOWED, PR_TRUE,  PR_FALSE},
  { TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,     SSL_ALLOWED, PR_TRUE,  PR_FALSE},
  { TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,     SSL_ALLOWED, PR_FALSE, PR_FALSE},
  { TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA,   SSL_ALLOWED, PR_FALSE, PR_FALSE},
  { TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA,   SSL_ALLOWED, PR_FALSE, PR_FALSE},
  { TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,       SSL_ALLOWED, PR_TRUE,  PR_FALSE},
  { TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,       SSL_ALLOWED, PR_TRUE,  PR_FALSE},
  { TLS_DHE_DSS_WITH_RC4_128_SHA,            SSL_ALLOWED, PR_FALSE, PR_FALSE},
 
-#ifndef NSS_DISABLE_ECC
  { TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,     SSL_ALLOWED, PR_FALSE, PR_FALSE},
  { TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,       SSL_ALLOWED, PR_FALSE, PR_FALSE},
  { TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,     SSL_ALLOWED, PR_FALSE, PR_FALSE},
  { TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,       SSL_ALLOWED, PR_FALSE, PR_FALSE},
  { TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,    SSL_ALLOWED, PR_FALSE, PR_FALSE},
  { TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,      SSL_ALLOWED, PR_FALSE, PR_FALSE},
  { TLS_ECDH_ECDSA_WITH_RC4_128_SHA,         SSL_ALLOWED, PR_FALSE, PR_FALSE},
  { TLS_ECDH_RSA_WITH_RC4_128_SHA,           SSL_ALLOWED, PR_FALSE, PR_FALSE},
-#endif /* NSS_DISABLE_ECC */
 
  /* RSA */
  { TLS_RSA_WITH_AES_128_GCM_SHA256,         SSL_ALLOWED, PR_TRUE,  PR_FALSE},
+ { TLS_RSA_WITH_AES_256_GCM_SHA384,         SSL_ALLOWED, PR_FALSE, PR_FALSE},
  { TLS_RSA_WITH_AES_128_CBC_SHA,            SSL_ALLOWED, PR_TRUE,  PR_FALSE},
  { TLS_RSA_WITH_AES_128_CBC_SHA256,         SSL_ALLOWED, PR_TRUE,  PR_FALSE},
  { TLS_RSA_WITH_CAMELLIA_128_CBC_SHA,       SSL_ALLOWED, PR_FALSE, PR_FALSE},
  { TLS_RSA_WITH_AES_256_CBC_SHA,            SSL_ALLOWED, PR_TRUE,  PR_FALSE},
  { TLS_RSA_WITH_AES_256_CBC_SHA256,         SSL_ALLOWED, PR_TRUE,  PR_FALSE},
  { TLS_RSA_WITH_CAMELLIA_256_CBC_SHA,       SSL_ALLOWED, PR_FALSE, PR_FALSE},
  { TLS_RSA_WITH_SEED_CBC_SHA,               SSL_ALLOWED, PR_FALSE, PR_FALSE},
  { SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA,      SSL_ALLOWED, PR_FALSE, PR_FALSE},
@@ -176,39 +177,36 @@ static ssl3CipherSuiteCfg cipherSuites[s
  { TLS_RSA_EXPORT1024_WITH_RC4_56_SHA,      SSL_ALLOWED, PR_FALSE, PR_FALSE},
  { TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA,     SSL_ALLOWED, PR_FALSE, PR_FALSE},
 
  /* export ciphersuites with 512-bit public key exchange keys */
  { TLS_RSA_EXPORT_WITH_RC4_40_MD5,          SSL_ALLOWED, PR_FALSE, PR_FALSE},
  { TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5,      SSL_ALLOWED, PR_FALSE, PR_FALSE},
 
  /* ciphersuites with no encryption */
-#ifndef NSS_DISABLE_ECC
  { TLS_ECDHE_ECDSA_WITH_NULL_SHA,           SSL_ALLOWED, PR_FALSE, PR_FALSE},
  { TLS_ECDHE_RSA_WITH_NULL_SHA,             SSL_ALLOWED, PR_FALSE, PR_FALSE},
  { TLS_ECDH_RSA_WITH_NULL_SHA,              SSL_ALLOWED, PR_FALSE, PR_FALSE},
  { TLS_ECDH_ECDSA_WITH_NULL_SHA,            SSL_ALLOWED, PR_FALSE, PR_FALSE},
-#endif /* NSS_DISABLE_ECC */
  { TLS_RSA_WITH_NULL_SHA,                   SSL_ALLOWED, PR_FALSE, PR_FALSE},
  { TLS_RSA_WITH_NULL_SHA256,                SSL_ALLOWED, PR_FALSE, PR_FALSE},
  { TLS_RSA_WITH_NULL_MD5,                   SSL_ALLOWED, PR_FALSE, PR_FALSE},
 };
 /* clang-format on */
 
 static const SSLSignatureAndHashAlg defaultSignatureAlgorithms[] = {
     { ssl_hash_sha256, ssl_sign_rsa },
     { ssl_hash_sha384, ssl_sign_rsa },
     { ssl_hash_sha512, ssl_sign_rsa },
     { ssl_hash_sha1, ssl_sign_rsa },
-#ifndef NSS_DISABLE_ECC
     { ssl_hash_sha256, ssl_sign_ecdsa },
     { ssl_hash_sha384, ssl_sign_ecdsa },
     { ssl_hash_sha512, ssl_sign_ecdsa },
     { ssl_hash_sha1, ssl_sign_ecdsa },
-#endif
+    { ssl_hash_sha384, ssl_sign_dsa },
     { ssl_hash_sha256, ssl_sign_dsa },
     { ssl_hash_sha1, ssl_sign_dsa }
 };
 PR_STATIC_ASSERT(PR_ARRAY_SIZE(defaultSignatureAlgorithms) <=
                  MAX_SIGNATURE_ALGORITHMS);
 
 /* Verify that SSL_ImplementedCiphers and cipherSuites are in consistent order.
  */
@@ -257,19 +255,17 @@ compressionEnabled(sslSocket *ss, SSLCom
 #endif
         default:
             return PR_FALSE;
     }
 }
 
 static const /*SSL3ClientCertificateType */ PRUint8 certificate_types[] = {
     ct_RSA_sign,
-#ifndef NSS_DISABLE_ECC
     ct_ECDSA_sign,
-#endif /* NSS_DISABLE_ECC */
     ct_DSS_sign,
 };
 
 #define EXPORT_RSA_KEY_LENGTH 64 /* bytes */
 
 /* This global item is used only in servers.  It is is initialized by
 ** SSL_ConfigSecureServer(), and is used in ssl3_SendCertificateRequest().
 */
@@ -297,16 +293,17 @@ static const ssl3BulkCipherDef bulk_ciph
     {cipher_des40,        calg_des,          8, 5, type_block,  8, 8, 0, 0, SEC_OID_DES_40_CBC},
     {cipher_idea,         calg_idea,        16,16, type_block,  8, 8, 0, 0, SEC_OID_IDEA_CBC},
     {cipher_aes_128,      calg_aes,         16,16, type_block, 16,16, 0, 0, SEC_OID_AES_128_CBC},
     {cipher_aes_256,      calg_aes,         32,32, type_block, 16,16, 0, 0, SEC_OID_AES_256_CBC},
     {cipher_camellia_128, calg_camellia,    16,16, type_block, 16,16, 0, 0, SEC_OID_CAMELLIA_128_CBC},
     {cipher_camellia_256, calg_camellia,    32,32, type_block, 16,16, 0, 0, SEC_OID_CAMELLIA_256_CBC},
     {cipher_seed,         calg_seed,        16,16, type_block, 16,16, 0, 0, SEC_OID_SEED_CBC},
     {cipher_aes_128_gcm,  calg_aes_gcm,     16,16, type_aead,   4, 0,16, 8, SEC_OID_AES_128_GCM},
+    {cipher_aes_256_gcm,  calg_aes_gcm,     32,32, type_aead,   4, 0,16, 8, SEC_OID_AES_256_GCM},
     {cipher_chacha20,     calg_chacha20,    32,32, type_aead,  12, 0,16, 0, SEC_OID_CHACHA20_POLY1305},
     {cipher_missing,      calg_null,         0, 0, type_stream, 0, 0, 0, 0, 0},
 };
 
 static const ssl3KEADef kea_defs[] =
 { /* indexed by SSL3KeyExchangeAlgorithm */
     /* kea            exchKeyType signKeyType authKeyType, is_limited limit tls_keygen ephemeral  oid */
     {kea_null,           ssl_kea_null, ssl_sign_null, ssl_auth_null, PR_FALSE,   0, PR_FALSE, PR_FALSE, 0},
@@ -320,192 +317,189 @@ static const ssl3KEADef kea_defs[] =
     {kea_dh_rsa_export,  ssl_kea_dh,   ssl_sign_rsa, ssl_auth_rsa_sign,   PR_TRUE,  512, PR_FALSE, PR_FALSE, SEC_OID_TLS_DH_RSA_EXPORT},
     {kea_dhe_dss,        ssl_kea_dh,   ssl_sign_dsa, ssl_auth_dsa,   PR_FALSE,   0, PR_FALSE, PR_TRUE,  SEC_OID_TLS_DHE_DSS},
     {kea_dhe_dss_export, ssl_kea_dh,   ssl_sign_dsa, ssl_auth_dsa,   PR_TRUE,  512, PR_FALSE, PR_TRUE,  SEC_OID_TLS_DHE_DSS_EXPORT},
     {kea_dhe_rsa,        ssl_kea_dh,   ssl_sign_rsa, ssl_auth_rsa_sign,   PR_FALSE,   0, PR_FALSE, PR_TRUE,  SEC_OID_TLS_DHE_RSA},
     {kea_dhe_rsa_export, ssl_kea_dh,   ssl_sign_rsa, ssl_auth_rsa_sign,   PR_TRUE,  512, PR_FALSE, PR_TRUE,  SEC_OID_TLS_DHE_RSA_EXPORT},
     {kea_dh_anon,        ssl_kea_dh,   ssl_sign_null, ssl_auth_null, PR_FALSE,   0, PR_FALSE, PR_TRUE,  SEC_OID_TLS_DH_ANON},
     {kea_dh_anon_export, ssl_kea_dh,   ssl_sign_null, ssl_auth_null, PR_TRUE,  512, PR_FALSE, PR_TRUE,  SEC_OID_TLS_DH_ANON_EXPORT},
     {kea_rsa_fips,       ssl_kea_rsa,  ssl_sign_rsa, ssl_auth_rsa_decrypt,   PR_FALSE,   0, PR_TRUE,  PR_FALSE, SEC_OID_TLS_RSA},
-#ifndef NSS_DISABLE_ECC
     {kea_ecdh_ecdsa,     ssl_kea_ecdh, ssl_sign_null, ssl_auth_ecdh_ecdsa, PR_FALSE,   0, PR_FALSE, PR_FALSE, SEC_OID_TLS_ECDH_ECDSA},
     {kea_ecdhe_ecdsa,    ssl_kea_ecdh, ssl_sign_ecdsa, ssl_auth_ecdsa, PR_FALSE,   0, PR_FALSE, PR_TRUE,  SEC_OID_TLS_ECDHE_ECDSA},
     {kea_ecdh_rsa,       ssl_kea_ecdh, ssl_sign_null, ssl_auth_ecdh_rsa, PR_FALSE,   0, PR_FALSE, PR_FALSE, SEC_OID_TLS_ECDH_RSA},
     {kea_ecdhe_rsa,      ssl_kea_ecdh, ssl_sign_rsa, ssl_auth_rsa_sign,   PR_FALSE,   0, PR_FALSE, PR_TRUE,  SEC_OID_TLS_ECDHE_RSA},
     {kea_ecdh_anon,      ssl_kea_ecdh, ssl_sign_null, ssl_auth_null, PR_FALSE,   0, PR_FALSE, PR_TRUE,  SEC_OID_TLS_ECDH_ANON},
     {kea_ecdhe_psk,      ssl_kea_ecdh_psk, ssl_sign_null, ssl_auth_psk, PR_FALSE, 0, PR_FALSE, PR_TRUE, SEC_OID_TLS_ECDHE_PSK}
-#endif /* NSS_DISABLE_ECC */
 };
 
 /* must use ssl_LookupCipherSuiteDef to access */
 static const ssl3CipherSuiteDef cipher_suite_defs[] =
 {
-/*  cipher_suite                    bulk_cipher_alg mac_alg key_exchange_alg */
-
-    {TLS_NULL_WITH_NULL_NULL,       cipher_null,   mac_null, kea_null},
-    {TLS_RSA_WITH_NULL_MD5,         cipher_null,   mac_md5, kea_rsa},
-    {TLS_RSA_WITH_NULL_SHA,         cipher_null,   mac_sha, kea_rsa},
-    {TLS_RSA_WITH_NULL_SHA256,      cipher_null,   hmac_sha256, kea_rsa},
-    {TLS_RSA_EXPORT_WITH_RC4_40_MD5,cipher_rc4_40, mac_md5, kea_rsa_export},
-    {TLS_RSA_WITH_RC4_128_MD5,      cipher_rc4,    mac_md5, kea_rsa},
-    {TLS_RSA_WITH_RC4_128_SHA,      cipher_rc4,    mac_sha, kea_rsa},
+/*  cipher_suite                    bulk_cipher_alg mac_alg key_exchange_alg prf_hash_alg */
+/*  Note that the prf_hash_alg is the hash function used by the PRF, see sslimpl.h.  */
+
+    {TLS_NULL_WITH_NULL_NULL,       cipher_null,   mac_null, kea_null, ssl_hash_none},
+    {TLS_RSA_WITH_NULL_MD5,         cipher_null,   mac_md5, kea_rsa, ssl_hash_none},
+    {TLS_RSA_WITH_NULL_SHA,         cipher_null,   mac_sha, kea_rsa, ssl_hash_none},
+    {TLS_RSA_WITH_NULL_SHA256,      cipher_null,   hmac_sha256, kea_rsa, ssl_hash_sha256},
+    {TLS_RSA_EXPORT_WITH_RC4_40_MD5,cipher_rc4_40, mac_md5, kea_rsa_export, ssl_hash_none},
+    {TLS_RSA_WITH_RC4_128_MD5,      cipher_rc4,    mac_md5, kea_rsa, ssl_hash_none},
+    {TLS_RSA_WITH_RC4_128_SHA,      cipher_rc4,    mac_sha, kea_rsa, ssl_hash_none},
     {TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5,
-                                    cipher_rc2_40, mac_md5, kea_rsa_export},
+                                    cipher_rc2_40, mac_md5, kea_rsa_export, ssl_hash_none},
 #if 0 /* not implemented */
-    {TLS_RSA_WITH_IDEA_CBC_SHA,     cipher_idea,   mac_sha, kea_rsa},
+    {TLS_RSA_WITH_IDEA_CBC_SHA,     cipher_idea,   mac_sha, kea_rsa, ssl_hash_none},
     {TLS_RSA_EXPORT_WITH_DES40_CBC_SHA,
-                                    cipher_des40,  mac_sha, kea_rsa_export},
+                                    cipher_des40,  mac_sha, kea_rsa_export, ssl_hash_none},
 #endif
-    {TLS_RSA_WITH_DES_CBC_SHA,      cipher_des,    mac_sha, kea_rsa},
-    {TLS_RSA_WITH_3DES_EDE_CBC_SHA, cipher_3des,   mac_sha, kea_rsa},
-    {TLS_DHE_DSS_WITH_DES_CBC_SHA,  cipher_des,    mac_sha, kea_dhe_dss},
+    {TLS_RSA_WITH_DES_CBC_SHA,      cipher_des,    mac_sha, kea_rsa, ssl_hash_none},
+    {TLS_RSA_WITH_3DES_EDE_CBC_SHA, cipher_3des,   mac_sha, kea_rsa, ssl_hash_none},
+    {TLS_DHE_DSS_WITH_DES_CBC_SHA,  cipher_des,    mac_sha, kea_dhe_dss, ssl_hash_none},
     {TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
-                                    cipher_3des,   mac_sha, kea_dhe_dss},
-    {TLS_DHE_DSS_WITH_RC4_128_SHA,  cipher_rc4,    mac_sha, kea_dhe_dss},
+                                    cipher_3des,   mac_sha, kea_dhe_dss, ssl_hash_none},
+    {TLS_DHE_DSS_WITH_RC4_128_SHA,  cipher_rc4,    mac_sha, kea_dhe_dss, ssl_hash_none},
 #if 0 /* not implemented */
     {TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA,
-                                    cipher_des40,  mac_sha, kea_dh_dss_export},
-    {TLS_DH_DSS_DES_CBC_SHA,        cipher_des,    mac_sha, kea_dh_dss},
-    {TLS_DH_DSS_3DES_CBC_SHA,       cipher_3des,   mac_sha, kea_dh_dss},
+                                    cipher_des40,  mac_sha, kea_dh_dss_export, ssl_hash_none},
+    {TLS_DH_DSS_DES_CBC_SHA,        cipher_des,    mac_sha, kea_dh_dss, ssl_hash_none},
+    {TLS_DH_DSS_3DES_CBC_SHA,       cipher_3des,   mac_sha, kea_dh_dss, ssl_hash_none},
     {TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA,
-                                    cipher_des40,  mac_sha, kea_dh_rsa_export},
-    {TLS_DH_RSA_DES_CBC_SHA,        cipher_des,    mac_sha, kea_dh_rsa},
-    {TLS_DH_RSA_3DES_CBC_SHA,       cipher_3des,   mac_sha, kea_dh_rsa},
+                                    cipher_des40,  mac_sha, kea_dh_rsa_export, ssl_hash_none},
+    {TLS_DH_RSA_DES_CBC_SHA,        cipher_des,    mac_sha, kea_dh_rsa, ssl_hash_none},
+    {TLS_DH_RSA_3DES_CBC_SHA,       cipher_3des,   mac_sha, kea_dh_rsa, ssl_hash_none},
     {TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA,
-                                    cipher_des40,  mac_sha, kea_dh_dss_export},
+                                    cipher_des40,  mac_sha, kea_dh_dss_export, ssl_hash_none},
     {TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA,
-                                    cipher_des40,  mac_sha, kea_dh_rsa_export},
+                                    cipher_des40,  mac_sha, kea_dh_rsa_export, ssl_hash_none},
 #endif
-    {TLS_DHE_RSA_WITH_DES_CBC_SHA,  cipher_des,    mac_sha, kea_dhe_rsa},
+    {TLS_DHE_RSA_WITH_DES_CBC_SHA,  cipher_des,    mac_sha, kea_dhe_rsa, ssl_hash_none},
     {TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
-                                    cipher_3des,   mac_sha, kea_dhe_rsa},
+                                    cipher_3des,   mac_sha, kea_dhe_rsa, ssl_hash_none},
 #if 0
-    {SSL_DH_ANON_EXPORT_RC4_40_MD5, cipher_rc4_40, mac_md5, kea_dh_anon_export},
+    {SSL_DH_ANON_EXPORT_RC4_40_MD5, cipher_rc4_40, mac_md5, kea_dh_anon_export, ssl_hash_none},
     {TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA,
-                                    cipher_des40,  mac_sha, kea_dh_anon_export},
-    {TLS_DH_anon_WITH_DES_CBC_SHA,  cipher_des,    mac_sha, kea_dh_anon},
-    {TLS_DH_anon_WITH_3DES_CBC_SHA, cipher_3des,   mac_sha, kea_dh_anon},
+                                    cipher_des40,  mac_sha, kea_dh_anon_export, ssl_hash_none},
+    {TLS_DH_anon_WITH_DES_CBC_SHA,  cipher_des,    mac_sha, kea_dh_anon, ssl_hash_none},
+    {TLS_DH_anon_WITH_3DES_CBC_SHA, cipher_3des,   mac_sha, kea_dh_anon, ssl_hash_none},
 #endif
 
 
 /* New TLS cipher suites */
-    {TLS_RSA_WITH_AES_128_CBC_SHA,      cipher_aes_128, mac_sha, kea_rsa},
-    {TLS_RSA_WITH_AES_128_CBC_SHA256,   cipher_aes_128, hmac_sha256, kea_rsa},
-    {TLS_DHE_DSS_WITH_AES_128_CBC_SHA,  cipher_aes_128, mac_sha, kea_dhe_dss},
-    {TLS_DHE_RSA_WITH_AES_128_CBC_SHA,  cipher_aes_128, mac_sha, kea_dhe_rsa},
-    {TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, cipher_aes_128, hmac_sha256, kea_dhe_rsa},
-    {TLS_RSA_WITH_AES_256_CBC_SHA,      cipher_aes_256, mac_sha, kea_rsa},
-    {TLS_RSA_WITH_AES_256_CBC_SHA256,   cipher_aes_256, hmac_sha256, kea_rsa},
-    {TLS_DHE_DSS_WITH_AES_256_CBC_SHA,  cipher_aes_256, mac_sha, kea_dhe_dss},
-    {TLS_DHE_RSA_WITH_AES_256_CBC_SHA,  cipher_aes_256, mac_sha, kea_dhe_rsa},
-    {TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, cipher_aes_256, hmac_sha256, kea_dhe_rsa},
+    {TLS_RSA_WITH_AES_128_CBC_SHA,      cipher_aes_128, mac_sha, kea_rsa, ssl_hash_none},
+    {TLS_RSA_WITH_AES_128_CBC_SHA256,   cipher_aes_128, hmac_sha256, kea_rsa, ssl_hash_sha256},
+    {TLS_DHE_DSS_WITH_AES_128_CBC_SHA,  cipher_aes_128, mac_sha, kea_dhe_dss, ssl_hash_none},
+    {TLS_DHE_RSA_WITH_AES_128_CBC_SHA,  cipher_aes_128, mac_sha, kea_dhe_rsa, ssl_hash_none},
+    {TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, cipher_aes_128, hmac_sha256, kea_dhe_rsa, ssl_hash_sha256},
+    {TLS_RSA_WITH_AES_256_CBC_SHA,      cipher_aes_256, mac_sha, kea_rsa, ssl_hash_none},
+    {TLS_RSA_WITH_AES_256_CBC_SHA256,   cipher_aes_256, hmac_sha256, kea_rsa, ssl_hash_sha256},
+    {TLS_DHE_DSS_WITH_AES_256_CBC_SHA,  cipher_aes_256, mac_sha, kea_dhe_dss, ssl_hash_none},
+    {TLS_DHE_RSA_WITH_AES_256_CBC_SHA,  cipher_aes_256, mac_sha, kea_dhe_rsa, ssl_hash_none},
+    {TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, cipher_aes_256, hmac_sha256, kea_dhe_rsa, ssl_hash_sha256},
+    {TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, cipher_aes_256_gcm, mac_aead, kea_dhe_rsa, ssl_hash_sha384},
 #if 0
-    {TLS_DH_DSS_WITH_AES_128_CBC_SHA,   cipher_aes_128, mac_sha, kea_dh_dss},
-    {TLS_DH_RSA_WITH_AES_128_CBC_SHA,   cipher_aes_128, mac_sha, kea_dh_rsa},
-    {TLS_DH_anon_WITH_AES_128_CBC_SHA,  cipher_aes_128, mac_sha, kea_dh_anon},
-    {TLS_DH_DSS_WITH_AES_256_CBC_SHA,   cipher_aes_256, mac_sha, kea_dh_dss},
-    {TLS_DH_RSA_WITH_AES_256_CBC_SHA,   cipher_aes_256, mac_sha, kea_dh_rsa},
-    {TLS_DH_anon_WITH_AES_256_CBC_SHA,  cipher_aes_256, mac_sha, kea_dh_anon},
+    {TLS_DH_DSS_WITH_AES_128_CBC_SHA,   cipher_aes_128, mac_sha, kea_dh_dss, ssl_hash_none},
+    {TLS_DH_RSA_WITH_AES_128_CBC_SHA,   cipher_aes_128, mac_sha, kea_dh_rsa, ssl_hash_none},
+    {TLS_DH_anon_WITH_AES_128_CBC_SHA,  cipher_aes_128, mac_sha, kea_dh_anon, ssl_hash_none},
+    {TLS_DH_DSS_WITH_AES_256_CBC_SHA,   cipher_aes_256, mac_sha, kea_dh_dss, ssl_hash_none},
+    {TLS_DH_RSA_WITH_AES_256_CBC_SHA,   cipher_aes_256, mac_sha, kea_dh_rsa, ssl_hash_none},
+    {TLS_DH_anon_WITH_AES_256_CBC_SHA,  cipher_aes_256, mac_sha, kea_dh_anon, ssl_hash_none},
 #endif
 
-    {TLS_RSA_WITH_SEED_CBC_SHA,     cipher_seed,   mac_sha, kea_rsa},
-
-    {TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, cipher_camellia_128, mac_sha, kea_rsa},
+    {TLS_RSA_WITH_SEED_CBC_SHA,     cipher_seed,   mac_sha, kea_rsa, ssl_hash_none},
+
+    {TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, cipher_camellia_128, mac_sha, kea_rsa, ssl_hash_none},
     {TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA,
-     cipher_camellia_128, mac_sha, kea_dhe_dss},
+     cipher_camellia_128, mac_sha, kea_dhe_dss, ssl_hash_none},
     {TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,
-     cipher_camellia_128, mac_sha, kea_dhe_rsa},
-    {TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, cipher_camellia_256, mac_sha, kea_rsa},
+     cipher_camellia_128, mac_sha, kea_dhe_rsa, ssl_hash_none},
+    {TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, cipher_camellia_256, mac_sha, kea_rsa, ssl_hash_none},
     {TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA,
-     cipher_camellia_256, mac_sha, kea_dhe_dss},
+     cipher_camellia_256, mac_sha, kea_dhe_dss, ssl_hash_none},
     {TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA,
-     cipher_camellia_256, mac_sha, kea_dhe_rsa},
+     cipher_camellia_256, mac_sha, kea_dhe_rsa, ssl_hash_none},
 
     {TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA,
-                                    cipher_des,    mac_sha,kea_rsa_export_1024},
+                                    cipher_des,    mac_sha,kea_rsa_export_1024, ssl_hash_none},
     {TLS_RSA_EXPORT1024_WITH_RC4_56_SHA,
-                                    cipher_rc4_56, mac_sha,kea_rsa_export_1024},
-
-    {SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_rsa_fips},
-    {SSL_RSA_FIPS_WITH_DES_CBC_SHA, cipher_des,    mac_sha, kea_rsa_fips},
-
-    {TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_dhe_rsa},
-    {TLS_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_rsa},
-    {TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_ecdhe_rsa},
-    {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_ecdhe_ecdsa},
-
-    {TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_dhe_dss},
-    {TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, cipher_aes_128, hmac_sha256, kea_dhe_dss},
-    {TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, cipher_aes_256, hmac_sha256, kea_dhe_dss},
-
-    {TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, cipher_chacha20, mac_aead, kea_dhe_rsa},
-
-#ifndef NSS_DISABLE_ECC
-    {TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, cipher_chacha20, mac_aead, kea_ecdhe_rsa},
-    {TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, cipher_chacha20, mac_aead, kea_ecdhe_ecdsa},
-
-    {TLS_ECDH_ECDSA_WITH_NULL_SHA,        cipher_null, mac_sha, kea_ecdh_ecdsa},
-    {TLS_ECDH_ECDSA_WITH_RC4_128_SHA,      cipher_rc4, mac_sha, kea_ecdh_ecdsa},
-    {TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_ecdh_ecdsa},
-    {TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_ecdh_ecdsa},
-    {TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_ecdh_ecdsa},
-
-    {TLS_ECDHE_ECDSA_WITH_NULL_SHA,        cipher_null, mac_sha, kea_ecdhe_ecdsa},
-    {TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,      cipher_rc4, mac_sha, kea_ecdhe_ecdsa},
-    {TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_ecdhe_ecdsa},
-    {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_ecdhe_ecdsa},
-    {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, cipher_aes_128, hmac_sha256, kea_ecdhe_ecdsa},
-    {TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_ecdhe_ecdsa},
-
-    {TLS_ECDH_RSA_WITH_NULL_SHA,         cipher_null,    mac_sha, kea_ecdh_rsa},
-    {TLS_ECDH_RSA_WITH_RC4_128_SHA,      cipher_rc4,     mac_sha, kea_ecdh_rsa},
-    {TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, cipher_3des,    mac_sha, kea_ecdh_rsa},
-    {TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,  cipher_aes_128, mac_sha, kea_ecdh_rsa},
-    {TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,  cipher_aes_256, mac_sha, kea_ecdh_rsa},
-
-    {TLS_ECDHE_RSA_WITH_NULL_SHA,         cipher_null,    mac_sha, kea_ecdhe_rsa},
-    {TLS_ECDHE_RSA_WITH_RC4_128_SHA,      cipher_rc4,     mac_sha, kea_ecdhe_rsa},
-    {TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, cipher_3des,    mac_sha, kea_ecdhe_rsa},
-    {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,  cipher_aes_128, mac_sha, kea_ecdhe_rsa},
-    {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, cipher_aes_128, hmac_sha256, kea_ecdhe_rsa},
-    {TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,  cipher_aes_256, mac_sha, kea_ecdhe_rsa},
-
-#if 0
-    {TLS_ECDH_anon_WITH_NULL_SHA,         cipher_null,    mac_sha, kea_ecdh_anon},
-    {TLS_ECDH_anon_WITH_RC4_128_SHA,      cipher_rc4,     mac_sha, kea_ecdh_anon},
-    {TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA, cipher_3des,    mac_sha, kea_ecdh_anon},
-    {TLS_ECDH_anon_WITH_AES_128_CBC_SHA,  cipher_aes_128, mac_sha, kea_ecdh_anon},
-    {TLS_ECDH_anon_WITH_AES_256_CBC_SHA,  cipher_aes_256, mac_sha, kea_ecdh_anon},
-#endif
-    {TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_ecdhe_psk},
-#endif /* NSS_DISABLE_ECC */
+                                    cipher_rc4_56, mac_sha,kea_rsa_export_1024, ssl_hash_none},
+
+    {SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_rsa_fips, ssl_hash_none},
+    {SSL_RSA_FIPS_WITH_DES_CBC_SHA, cipher_des,    mac_sha, kea_rsa_fips, ssl_hash_none},
+
+    {TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_dhe_rsa, ssl_hash_sha256},
+    {TLS_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_rsa, ssl_hash_sha256},
+
+    {TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_ecdhe_rsa, ssl_hash_sha256},
+    {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_ecdhe_ecdsa, ssl_hash_sha256},
+    {TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, cipher_aes_256_gcm, mac_aead, kea_ecdhe_ecdsa, ssl_hash_sha384},
+    {TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, cipher_aes_256_gcm, mac_aead, kea_ecdhe_rsa, ssl_hash_sha384},
+    {TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, cipher_aes_256, hmac_sha384, kea_ecdhe_ecdsa, ssl_hash_sha384},
+    {TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, cipher_aes_256, hmac_sha384, kea_ecdhe_rsa, ssl_hash_sha384},
+    {TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_dhe_dss, ssl_hash_sha256},
+    {TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, cipher_aes_128, hmac_sha256, kea_dhe_dss, ssl_hash_sha256},
+    {TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, cipher_aes_256, hmac_sha256, kea_dhe_dss, ssl_hash_sha256},
+    {TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, cipher_aes_256_gcm, mac_aead, kea_dhe_dss, ssl_hash_sha384},
+    {TLS_RSA_WITH_AES_256_GCM_SHA384, cipher_aes_256_gcm, mac_aead, kea_rsa, ssl_hash_sha384},
+
+    {TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, cipher_chacha20, mac_aead, kea_dhe_rsa, ssl_hash_sha256},
+
+    {TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, cipher_chacha20, mac_aead, kea_ecdhe_rsa, ssl_hash_sha256},
+    {TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, cipher_chacha20, mac_aead, kea_ecdhe_ecdsa, ssl_hash_sha256},
+
+    {TLS_ECDH_ECDSA_WITH_NULL_SHA,        cipher_null, mac_sha, kea_ecdh_ecdsa, ssl_hash_none},
+    {TLS_ECDH_ECDSA_WITH_RC4_128_SHA,      cipher_rc4, mac_sha, kea_ecdh_ecdsa, ssl_hash_none},
+    {TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_ecdh_ecdsa, ssl_hash_none},
+    {TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_ecdh_ecdsa, ssl_hash_none},
+    {TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_ecdh_ecdsa, ssl_hash_none},
+
+    {TLS_ECDHE_ECDSA_WITH_NULL_SHA,        cipher_null, mac_sha, kea_ecdhe_ecdsa, ssl_hash_none},
+    {TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,      cipher_rc4, mac_sha, kea_ecdhe_ecdsa, ssl_hash_none},
+    {TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_ecdhe_ecdsa, ssl_hash_none},
+    {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_ecdhe_ecdsa, ssl_hash_none},
+    {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, cipher_aes_128, hmac_sha256, kea_ecdhe_ecdsa, ssl_hash_sha256},
+    {TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_ecdhe_ecdsa, ssl_hash_none},
+
+    {TLS_ECDH_RSA_WITH_NULL_SHA,         cipher_null,    mac_sha, kea_ecdh_rsa, ssl_hash_none},
+    {TLS_ECDH_RSA_WITH_RC4_128_SHA,      cipher_rc4,     mac_sha, kea_ecdh_rsa, ssl_hash_none},
+    {TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, cipher_3des,    mac_sha, kea_ecdh_rsa, ssl_hash_none},
+    {TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,  cipher_aes_128, mac_sha, kea_ecdh_rsa, ssl_hash_none},
+    {TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,  cipher_aes_256, mac_sha, kea_ecdh_rsa, ssl_hash_none},
+
+    {TLS_ECDHE_RSA_WITH_NULL_SHA,         cipher_null,    mac_sha, kea_ecdhe_rsa, ssl_hash_none},
+    {TLS_ECDHE_RSA_WITH_RC4_128_SHA,      cipher_rc4,     mac_sha, kea_ecdhe_rsa, ssl_hash_none},
+    {TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, cipher_3des,    mac_sha, kea_ecdhe_rsa, ssl_hash_none},
+    {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,  cipher_aes_128, mac_sha, kea_ecdhe_rsa, ssl_hash_none},
+    {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, cipher_aes_128, hmac_sha256, kea_ecdhe_rsa, ssl_hash_sha256},
+    {TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,  cipher_aes_256, mac_sha, kea_ecdhe_rsa, ssl_hash_none},
+
+    {TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_ecdhe_psk, ssl_hash_sha256},
 };
 /* clang-format on */
 
 static const CK_MECHANISM_TYPE auth_alg_defs[] = {
     CKM_INVALID_MECHANISM, /* ssl_auth_null */
-    CKM_RSA_PKCS, /* ssl_auth_rsa_decrypt */
+    CKM_RSA_PKCS,          /* ssl_auth_rsa_decrypt */
     CKM_DSA, /* ? _SHA1 */ /* ssl_auth_dsa */
     CKM_INVALID_MECHANISM, /* ssl_auth_kea (unused) */
-    CKM_ECDSA, /* ssl_auth_ecdsa */
-    CKM_ECDH1_DERIVE, /* ssl_auth_ecdh_rsa */
-    CKM_ECDH1_DERIVE, /* ssl_auth_ecdh_ecdsa */
-    CKM_RSA_PKCS, /* ssl_auth_rsa_sign */
-    CKM_RSA_PKCS_PSS, /* ssl_auth_rsa_pss */
-    CKM_NSS_HKDF_SHA256 /* ssl_auth_psk (just check for HKDF) */
+    CKM_ECDSA,             /* ssl_auth_ecdsa */
+    CKM_ECDH1_DERIVE,      /* ssl_auth_ecdh_rsa */
+    CKM_ECDH1_DERIVE,      /* ssl_auth_ecdh_ecdsa */
+    CKM_RSA_PKCS,          /* ssl_auth_rsa_sign */
+    CKM_RSA_PKCS_PSS,      /* ssl_auth_rsa_pss */
+    CKM_NSS_HKDF_SHA256    /* ssl_auth_psk (just check for HKDF) */
 };
 PR_STATIC_ASSERT(PR_ARRAY_SIZE(auth_alg_defs) == ssl_auth_size);
 
 static const CK_MECHANISM_TYPE kea_alg_defs[] = {
     CKM_INVALID_MECHANISM, /* ssl_kea_null */
-    CKM_RSA_PKCS, /* ssl_kea_rsa */
-    CKM_DH_PKCS_DERIVE, /* ssl_kea_dh */
+    CKM_RSA_PKCS,          /* ssl_kea_rsa */
+    CKM_DH_PKCS_DERIVE,    /* ssl_kea_dh */
     CKM_INVALID_MECHANISM, /* ssl_kea_fortezza (unused) */
-    CKM_ECDH1_DERIVE, /* ssl_kea_ecdh */
-    CKM_ECDH1_DERIVE /* ssl_kea_ecdh_psk */
+    CKM_ECDH1_DERIVE,      /* ssl_kea_ecdh */
+    CKM_ECDH1_DERIVE       /* ssl_kea_ecdh_psk */
 };
 PR_STATIC_ASSERT(PR_ARRAY_SIZE(kea_alg_defs) == ssl_kea_size);
 
 typedef struct SSLCipher2MechStr {
     SSLCipherAlgorithm calg;
     CK_MECHANISM_TYPE cmech;
 } SSLCipher2Mech;
 
@@ -528,28 +522,30 @@ static const SSLCipher2Mech alg2Mech[] =
 };
 
 #define mmech_invalid (CK_MECHANISM_TYPE)0x80000000L
 #define mmech_md5 CKM_SSL3_MD5_MAC
 #define mmech_sha CKM_SSL3_SHA1_MAC
 #define mmech_md5_hmac CKM_MD5_HMAC
 #define mmech_sha_hmac CKM_SHA_1_HMAC
 #define mmech_sha256_hmac CKM_SHA256_HMAC
+#define mmech_sha384_hmac CKM_SHA384_HMAC
 
 /* clang-format off */
 static const ssl3MACDef mac_defs[] = { /* indexed by SSL3MACAlgorithm */
     /* pad_size is only used for SSL 3.0 MAC. See RFC 6101 Sec. 5.2.3.1. */
     /* mac      mmech       pad_size  mac_size                       */
     { mac_null, mmech_invalid,    0,  0         ,  0},
     { mac_md5,  mmech_md5,       48,  MD5_LENGTH,  SEC_OID_HMAC_MD5 },
     { mac_sha,  mmech_sha,       40,  SHA1_LENGTH, SEC_OID_HMAC_SHA1},
     {hmac_md5,  mmech_md5_hmac,   0,  MD5_LENGTH,  SEC_OID_HMAC_MD5},
     {hmac_sha,  mmech_sha_hmac,   0,  SHA1_LENGTH, SEC_OID_HMAC_SHA1},
     {hmac_sha256, mmech_sha256_hmac, 0, SHA256_LENGTH, SEC_OID_HMAC_SHA256},
     { mac_aead, mmech_invalid,    0,  0, 0 },
+    {hmac_sha384, mmech_sha384_hmac, 0, SHA384_LENGTH, SEC_OID_HMAC_SHA384}
 };
 /* clang-format on */
 
 /* indexed by SSL3BulkCipher */
 const char *const ssl3_cipherName[] = {
     "NULL",
     "RC4",
     "RC4-40",
@@ -569,17 +565,16 @@ const char *const ssl3_cipherName[] = {
     "missing"
 };
 
 const PRUint8 tls13_downgrade_random[] = { 0x44, 0x4F, 0x57, 0x4E,
                                            0x47, 0x52, 0x44, 0x01 };
 const PRUint8 tls12_downgrade_random[] = { 0x44, 0x4F, 0x57, 0x4E,
                                            0x47, 0x52, 0x44, 0x00 };
 
-#ifndef NSS_DISABLE_ECC
 /* The ECCWrappedKeyInfo structure defines how various pieces of
  * information are laid out within wrappedSymmetricWrappingkey
  * for ECDH key exchange. Since wrappedSymmetricWrappingkey is
  * a 512-byte buffer (see sslimpl.h), the variable length field
  * in ECCWrappedKeyInfo can be at most (512 - 8) = 504 bytes.
  *
  * XXX For now, NSS only supports named elliptic curves of size 571 bits
  * or smaller. The public value will fit within 145 bytes and EC params
@@ -591,17 +586,16 @@ const PRUint8 tls12_downgrade_random[] =
 typedef struct ECCWrappedKeyInfoStr {
     PRUint16 size;                          /* EC public key size in bits */
     PRUint16 encodedParamLen;               /* length (in bytes) of DER encoded EC params */
     PRUint16 pubValueLen;                   /* length (in bytes) of EC public value */
     PRUint16 wrappedKeyLen;                 /* length (in bytes) of the wrapped key */
     PRUint8 var[MAX_EC_WRAPPED_KEY_BUFLEN]; /* this buffer contains the */
     /* EC public-key params, the EC public value and the wrapped key  */
 } ECCWrappedKeyInfo;
-#endif /* NSS_DISABLE_ECC */
 
 CK_MECHANISM_TYPE
 ssl3_Alg2Mech(SSLCipherAlgorithm calg)
 {
     PORT_Assert(alg2Mech[calg].calg == calg);
     return alg2Mech[calg].cmech;
 }
 
@@ -736,32 +730,39 @@ ssl3_CipherSuiteAllowedForVersionRange(
              *   TLS_DH_anon_EXPORT_WITH_RC4_40_MD5:     never implemented
              *   TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA:  never implemented
              */
             return vrange->min <= SSL_LIBRARY_VERSION_TLS_1_0;
 
         case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
         case TLS_RSA_WITH_AES_256_CBC_SHA256:
         case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+        case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
         case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+        case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
         case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
         case TLS_RSA_WITH_AES_128_CBC_SHA256:
         case TLS_RSA_WITH_AES_128_GCM_SHA256:
+        case TLS_RSA_WITH_AES_256_GCM_SHA384:
         case TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
         case TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
         case TLS_RSA_WITH_NULL_SHA256:
+        case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
         case TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:
-        case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
-        case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
         case TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+        case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
+        case TLS_DHE_DSS_WITH_AES_256_GCM_SHA384:
             return vrange->max == SSL_LIBRARY_VERSION_TLS_1_2;
 
         case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+        case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
         case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
-        case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+        case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+        case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+        case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
             return vrange->max >= SSL_LIBRARY_VERSION_TLS_1_2;
 
         /* RFC 4492: ECC cipher suites need TLS extensions to negotiate curves and
          * point formats.*/
         case TLS_ECDH_ECDSA_WITH_NULL_SHA:
         case TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
         case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
         case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
@@ -825,23 +826,23 @@ ssl_LookupCipherSuiteCfg(ssl3CipherSuite
     PORT_SetError(SSL_ERROR_UNKNOWN_CIPHER_SUITE);
     return NULL;
 }
 
 static PRBool
 ssl3_HasCert(sslSocket *ss, SSLAuthType authType)
 {
     PRCList *cursor;
-    if (authType == ssl_auth_null) {
+    if (authType == ssl_auth_null || authType == ssl_auth_psk) {
         return PR_TRUE;
     }
     for (cursor = PR_NEXT_LINK(&ss->serverCerts);
          cursor != &ss->serverCerts;
          cursor = PR_NEXT_LINK(cursor)) {
-        sslServerCert *cert = (sslServerCert*)cursor;
+        sslServerCert *cert = (sslServerCert *)cursor;
         if (cert->certType.authType == authType &&
             cert->serverKeyPair &&
             cert->serverKeyPair->privKey &&
             cert->serverCertChain) {
             return PR_TRUE;
         }
     }
     return PR_FALSE;
@@ -956,19 +957,19 @@ config_match(ssl3CipherSuiteCfg *suite, 
     if (!suite->enabled)
         return PR_FALSE;
 
     if ((suite->policy == SSL_NOT_ALLOWED) ||
         (suite->policy > policy))
         return PR_FALSE;
 
     /* We only allow PSK for TLS 1.3 and only if there is resumption. */
-    if (kea_defs[cipher_def->key_exchange_alg].authKeyType ==
-        ssl_auth_psk) {
-        return tls13_AllowPskCipher(ss, cipher_def);
+    if (kea_defs[cipher_def->key_exchange_alg].authKeyType == ssl_auth_psk &&
+        !tls13_AllowPskCipher(ss, cipher_def)) {
+        return PR_FALSE;
     }
 
     return (PRBool)(suite->isPresent &&
                     ssl3_CipherSuiteAllowedForVersionRange(
                         suite->cipher_suite, vrange));
 }
 
 /* return number of cipher suites that match policy, enabled state and are
@@ -987,16 +988,34 @@ count_cipher_suites(sslSocket *ss, int p
             count++;
     }
     if (count <= 0) {
         PORT_SetError(SSL_ERROR_SSL_DISABLED);
     }
     return count;
 }
 
+PRBool
+tls13_PskSuiteEnabled(sslSocket *ss)
+{
+    int i;
+    const ssl3CipherSuiteDef *cipher_def;
+
+    for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; ++i) {
+        ssl3CipherSuiteCfg *suite = &ss->cipherSuites[i];
+
+        cipher_def = ssl_LookupCipherSuiteDef(suite->cipher_suite);
+        if (ssl_auth_psk == kea_defs[cipher_def->key_exchange_alg].authKeyType &&
+            config_match(suite, ss->ssl3.policy, PR_TRUE, &ss->vrange, ss)) {
+            return PR_TRUE;
+        }
+    }
+    return PR_FALSE;
+}
+
 /*
  * Null compression, mac and encryption functions
  */
 
 static SECStatus
 Null_Cipher(void *ctx, unsigned char *output, int *outputLen, int maxOutputLen,
             const unsigned char *input, int inputLen)
 {
@@ -1079,30 +1098,28 @@ ssl3_SignHashes(SSL3Hashes *hash, SECKEY
             if (hash->hashAlg == ssl_hash_none) {
                 hashItem.data = hash->u.s.sha;
                 hashItem.len = sizeof(hash->u.s.sha);
             } else {
                 hashItem.data = hash->u.raw;
                 hashItem.len = hash->len;
             }
             break;
-#ifndef NSS_DISABLE_ECC
         case ecKey:
             doDerEncode = PR_TRUE;
             /* ssl_hash_none is used to specify the MD5/SHA1 concatenated hash.
              * In that case, we use just the SHA1 part. */
             if (hash->hashAlg == ssl_hash_none) {
                 hashItem.data = hash->u.s.sha;
                 hashItem.len = sizeof(hash->u.s.sha);
             } else {
                 hashItem.data = hash->u.raw;
                 hashItem.len = hash->len;
             }
             break;
-#endif /* NSS_DISABLE_ECC */
         default:
             PORT_SetError(SEC_ERROR_INVALID_KEY);
             goto done;
     }
     PRINT_BUF(60, (NULL, "hash(es) to be signed", hashItem.data, hashItem.len));
 
     if (hash->hashAlg == ssl_hash_none) {
         signatureLen = PK11_SignatureLen(key);
@@ -1190,17 +1207,16 @@ ssl3_VerifySignedHashes(SSL3Hashes *hash
                 if (!signature) {
                     PORT_SetError(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
                     return SECFailure;
                 }
                 buf = signature;
             }
             break;
 
-#ifndef NSS_DISABLE_ECC
         case ecKey:
             encAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
             /* ssl_hash_none is used to specify the MD5/SHA1 concatenated hash.
              * In that case, we use just the SHA1 part.
              * ECDSA signatures always encode the integers r and s using ASN.1
              * (unlike DSA where ASN.1 encoding is used with TLS but not with
              * SSL3). So we can use VFY_VerifyDigestDirect for ECDSA.
              */
@@ -1208,17 +1224,16 @@ ssl3_VerifySignedHashes(SSL3Hashes *hash
                 hashAlg = SEC_OID_SHA1;
                 hashItem.data = hash->u.s.sha;
                 hashItem.len = sizeof(hash->u.s.sha);
             } else {
                 hashItem.data = hash->u.raw;
                 hashItem.len = hash->len;
             }
             break;
-#endif /* NSS_DISABLE_ECC */
 
         default:
             SECKEY_DestroyPublicKey(key);
             PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
             return SECFailure;
     }
 
     PRINT_BUF(60, (NULL, "hash(es) to be verified",
@@ -2356,16 +2371,56 @@ ssl3_CanBypassCipher(SSLCipherAlgorithm 
         case calg_chacha20:
             return PR_FALSE;
         default:
             return PR_TRUE;
     }
 }
 #endif
 
+HASH_HashType
+ssl3_GetTls12HashType(sslSocket *ss)
+{
+    if (ss->ssl3.pwSpec->version < SSL_LIBRARY_VERSION_TLS_1_2) {
+        return HASH_AlgNULL;
+    }
+
+    switch (ss->ssl3.hs.suite_def->prf_hash) {
+        case ssl_hash_sha384:
+            return HASH_AlgSHA384;
+        case ssl_hash_sha256:
+        case ssl_hash_none:
+            /* ssl_hash_none is for pre-1.2 suites, which use SHA-256. */
+            return HASH_AlgSHA256;
+        default:
+            PORT_Assert(0);
+    }
+    return HASH_AlgSHA256;
+}
+
+#ifndef NO_PKCS11_BYPASS
+typedef void (*hash_clone_func)(void *, void *);
+
+static hash_clone_func
+ssl3_GetTls12BypassHashCloneFunc(sslSocket *ss)
+{
+    switch (ss->ssl3.hs.suite_def->prf_hash) {
+        case ssl_hash_sha384:
+            return (hash_clone_func)SHA384_Clone;
+        case ssl_hash_sha256:
+        case ssl_hash_none:
+            /* ssl_hash_none is for pre-1.2 suites, which use SHA-256. */
+            return (hash_clone_func)SHA256_Clone;
+        default:
+            PORT_Assert(0);
+    }
+    return (hash_clone_func)SHA256_Clone;
+}
+#endif
+
 /* Complete the initialization of all keys, ciphers, MACs and their contexts
  * for the pending Cipher Spec.
  * Called from: ssl3_SendClientKeyExchange  (for Full handshake)
  *              ssl3_HandleRSAClientKeyExchange (for Full handshake)
  *              ssl3_HandleServerHello      (for session restart)
  *              ssl3_HandleClientHello      (for session restart)
  * Sets error code, but caller probably should override to disambiguate.
  * NULL pms means re-use old master_secret.
@@ -2401,21 +2456,23 @@ ssl3_InitPendingCipherSpec(sslSocket *ss
     }
 #ifndef NO_PKCS11_BYPASS
     if (ss->opt.bypassPKCS11 && pwSpec->msItem.len && pwSpec->msItem.data &&
         ssl3_CanBypassCipher(ss->ssl3.pwSpec->cipher_def->calg)) {
         /* Double Bypass succeeded in extracting the master_secret */
         const ssl3KEADef *kea_def = ss->ssl3.hs.kea_def;
         PRBool isTLS = (PRBool)(kea_def->tls_keygen ||
                                 (pwSpec->version > SSL_LIBRARY_VERSION_3_0));
+        HASH_HashType hashType = ssl3_GetTls12HashType(ss);
         pwSpec->bypassCiphers = PR_TRUE;
         rv = ssl3_KeyAndMacDeriveBypass(pwSpec,
                                         (const unsigned char *)&ss->ssl3.hs.client_random,
                                         (const unsigned char *)&ss->ssl3.hs.server_random,
                                         isTLS,
+                                        hashType,
                                         (PRBool)(kea_def->is_limited));
         if (rv == SECSuccess) {
             rv = ssl3_InitPendingContextsBypass(ss);
         }
     } else
 #endif
         if (pwSpec->master_secret) {
         rv = ssl3_DeriveConnectionKeysPKCS11(ss);
@@ -2532,16 +2589,19 @@ ssl3_ComputeRecordMAC(
                 hashObj = HASH_GetRawHashObject(HASH_AlgMD5);
                 break;
             case ssl_hmac_sha: /* used with TLS */
                 hashObj = HASH_GetRawHashObject(HASH_AlgSHA1);
                 break;
             case ssl_hmac_sha256: /* used with TLS */
                 hashObj = HASH_GetRawHashObject(HASH_AlgSHA256);
                 break;
+            case ssl_hmac_sha384: /* used with TLS */
+                hashObj = HASH_GetRawHashObject(HASH_AlgSHA384);
+                break;
             default:
                 break;
         }
         if (!hashObj) {
             PORT_Assert(0);
             PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
             return SECFailure;
         }
@@ -3461,18 +3521,17 @@ SSL3_SendAlert(sslSocket *ss, SSL3AlertL
             ss->sec.uncache(ss->sec.ci.sid);
         }
     }
     ssl_GetXmitBufLock(ss);
     rv = ssl3_FlushHandshake(ss, ssl_SEND_FLAG_FORCE_INTO_BUFFER);
     if (rv == SECSuccess) {
         PRInt32 sent;
         sent = ssl3_SendRecord(ss, NULL, content_alert, bytes, 2,
-                               (desc == no_certificate) ?
-                               ssl_SEND_FLAG_FORCE_INTO_BUFFER : 0);
+                               (desc == no_certificate) ? ssl_SEND_FLAG_FORCE_INTO_BUFFER : 0);
         rv = (sent >= 0) ? SECSuccess : (SECStatus)sent;
     }
     if (level == alert_fatal) {
         ss->ssl3.fatalAlertSent = PR_TRUE;
     }
     ssl_ReleaseXmitBufLock(ss);
     ssl_ReleaseSSL3HandshakeLock(ss);
     return rv; /* error set by ssl3_FlushHandshake or ssl3_SendRecord */
@@ -3849,16 +3908,42 @@ ssl3_HandleChangeCipherSpecs(sslSocket *
      */
     if (ss->ssl3.prSpec == ss->ssl3.pwSpec) {
         ssl3_DestroyCipherSpec(ss->ssl3.prSpec, PR_FALSE /*freeSrvName*/);
     }
     ssl_ReleaseSpecWriteLock(ss); /*************************************/
     return SECSuccess;
 }
 
+static CK_MECHANISM_TYPE
+ssl3_GetTls12PrfHashMechanism(sslSocket *ss)
+{
+    switch (ss->ssl3.hs.suite_def->prf_hash) {
+        case ssl_hash_sha384:
+            return CKM_SHA384;
+        case ssl_hash_sha256:
+        case ssl_hash_none:
+            /* ssl_hash_none is for pre-1.2 suites, which use SHA-256. */
+            return CKM_SHA256;
+        default:
+            PORT_Assert(0);
+    }
+    return CKM_SHA256;
+}
+
+static SSLHashType
+ssl3_GetSuitePrfHash(sslSocket *ss)
+{
+    /* ssl_hash_none is for pre-1.2 suites, which use SHA-256. */
+    if (ss->ssl3.hs.suite_def->prf_hash == ssl_hash_none) {
+        return ssl_hash_sha256;
+    }
+    return ss->ssl3.hs.suite_def->prf_hash;
+}
+
 /* This method completes the derivation of the MS from the PMS.
 **
 ** 1. Derive the MS, if possible, else return an error.
 **
 ** 2. Check the version if |pms_version| is non-zero and if wrong,
 **    return an error.
 **
 ** 3. If |msp| is nonzero, return MS in |*msp|.
@@ -3972,17 +4057,17 @@ ssl3_ComputeMasterSecretInt(sslSocket *s
     }
 
     master_params.pVersion = pms_version_ptr;
     master_params.RandomInfo.pClientRandom = cr;
     master_params.RandomInfo.ulClientRandomLen = SSL3_RANDOM_LENGTH;
     master_params.RandomInfo.pServerRandom = sr;
     master_params.RandomInfo.ulServerRandomLen = SSL3_RANDOM_LENGTH;
     if (isTLS12) {
-        master_params.prfHashMechanism = CKM_SHA256;
+        master_params.prfHashMechanism = ssl3_GetTls12PrfHashMechanism(ss);
         master_params_len = sizeof(CK_TLS12_MASTER_KEY_DERIVE_PARAMS);
     } else {
         /* prfHashMechanism is not relevant with this PRF */
         master_params_len = sizeof(CK_SSL3_MASTER_KEY_DERIVE_PARAMS);
     }
 
     params.data = (unsigned char *)&master_params;
     params.len = master_params_len;
@@ -4215,17 +4300,17 @@ ssl3_DeriveConnectionKeysPKCS11(sslSocke
         returnedKeys.pIVServer = NULL;
     }
 
     calg = cipher_def->calg;
     bulk_mechanism = ssl3_Alg2Mech(calg);
 
     if (isTLS12) {
         key_derive = CKM_TLS12_KEY_AND_MAC_DERIVE;
-        key_material_params.prfHashMechanism = CKM_SHA256;
+        key_material_params.prfHashMechanism = ssl3_GetTls12PrfHashMechanism(ss);
         key_material_params_len = sizeof(CK_TLS12_KEY_MAT_PARAMS);
     } else if (isTLS) {
         key_derive = CKM_TLS_KEY_AND_MAC_DERIVE;
         key_material_params_len = sizeof(CK_SSL3_KEY_MAT_PARAMS);
     } else {
         key_derive = CKM_SSL3_KEY_AND_MAC_DERIVE;
         key_material_params_len = sizeof(CK_SSL3_KEY_MAT_PARAMS);
     }
@@ -4280,35 +4365,45 @@ ssl3_DeriveConnectionKeysPKCS11(sslSocke
 loser:
     if (symKey)
         PK11_FreeSymKey(symKey);
     ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
     return SECFailure;
 }
 
 /* ssl3_InitHandshakeHashes creates handshake hash contexts and hashes in
- * buffered messages in ss->ssl3.hs.messages. */
+ * buffered messages in ss->ssl3.hs.messages. Called from
+ * ssl3_NegotiateCipherSuite() and ssl3_HandleServerHello. */
 static SECStatus
 ssl3_InitHandshakeHashes(sslSocket *ss)
 {
     SSL_TRC(30, ("%d: SSL3[%d]: start handshake hashes", SSL_GETPID(), ss->fd));
 
     PORT_Assert(ss->ssl3.hs.hashType == handshake_hash_unknown);
 #ifndef NO_PKCS11_BYPASS
     if (ss->opt.bypassPKCS11) {
         PORT_Assert(!ss->ssl3.hs.sha_obj && !ss->ssl3.hs.sha_clone);
         if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
-            /* If we ever support ciphersuites where the PRF hash isn't SHA-256
-             * then this will need to be updated. */
-            ss->ssl3.hs.sha_obj = HASH_GetRawHashObject(HASH_AlgSHA256);
+            const SECOidData *hashOid =
+                SECOID_FindOIDByMechanism(ssl3_GetTls12PrfHashMechanism(ss));
+
+            if (hashOid == NULL) {
+                PORT_Assert(hashOid == NULL);
+                ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
+                return SECFailure;
+            }
+
+            ss->ssl3.hs.sha_obj = HASH_GetRawHashObject(
+                HASH_GetHashTypeByOidTag(hashOid->offset));
+
             if (!ss->ssl3.hs.sha_obj) {
                 ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
                 return SECFailure;
             }
-            ss->ssl3.hs.sha_clone = (void (*)(void *, void *))SHA256_Clone;
+            ss->ssl3.hs.sha_clone = ssl3_GetTls12BypassHashCloneFunc(ss);
             ss->ssl3.hs.hashType = handshake_hash_single;
             ss->ssl3.hs.sha_obj->begin(ss->ssl3.hs.sha_cx);
         } else {
             ss->ssl3.hs.hashType = handshake_hash_combo;
             MD5_Begin((MD5Context *)ss->ssl3.hs.md5_cx);
             SHA1_Begin((SHA1Context *)ss->ssl3.hs.sha_cx);
         }
     } else
@@ -4316,19 +4411,30 @@ ssl3_InitHandshakeHashes(sslSocket *ss)
     {
         PORT_Assert(!ss->ssl3.hs.md5 && !ss->ssl3.hs.sha);
         /*
          * note: We should probably lookup an SSL3 slot for these
          * handshake hashes in hopes that we wind up with the same slots
          * that the master secret will wind up in ...
          */
         if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
-            /* If we ever support ciphersuites where the PRF hash isn't SHA-256
-             * then this will need to be updated. */
-            ss->ssl3.hs.sha = PK11_CreateDigestContext(SEC_OID_SHA256);
+            /* determine the hash from the prf */
+            const SECOidData *hash_oid =
+                SECOID_FindOIDByMechanism(ssl3_GetTls12PrfHashMechanism(ss));
+
+            /* Get the PKCS #11 mechanism for the Hash from the cipher suite (prf_hash)
+             * Convert that to the OidTag. We can then use that OidTag to create our
+             * PK11Context */
+            PORT_Assert(hash_oid != NULL);
+            if (hash_oid == NULL) {
+                ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
+                return SECFailure;
+            }
+
+            ss->ssl3.hs.sha = PK11_CreateDigestContext(hash_oid->offset);
             if (ss->ssl3.hs.sha == NULL) {
                 ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
                 return SECFailure;
             }
             ss->ssl3.hs.hashType = handshake_hash_single;
 
             if (PK11_DigestBegin(ss->ssl3.hs.sha) != SECSuccess) {
                 ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
@@ -4638,16 +4744,22 @@ ssl3_AppendHandshakeHeader(sslSocket *ss
 
 /* ssl3_AppendSignatureAndHashAlgorithm appends the serialisation of
  * |sigAndHash| to the current handshake message. */
 SECStatus
 ssl3_AppendSignatureAndHashAlgorithm(
     sslSocket *ss, const SSLSignatureAndHashAlg *sigAndHash)
 {
     PRUint8 serialized[2];
+    SECOidTag hashAlg = ssl3_TLSHashAlgorithmToOID(sigAndHash->hashAlg);
+    if (hashAlg == SEC_OID_UNKNOWN) {
+        PORT_Assert(0);
+        PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM);
+        return SECFailure;
+    }
 
     serialized[0] = (PRUint8)sigAndHash->hashAlg;
     serialized[1] = (PRUint8)sigAndHash->sigAlg;
 
     return ssl3_AppendHandshake(ss, serialized, sizeof(serialized));
 }
 
 /**************************************************************************
@@ -4753,17 +4865,20 @@ ssl3_ConsumeHandshakeVariable(sslSocket 
         i->len = count;
         *b += count;
         *length -= count;
     }
     return SECSuccess;
 }
 
 /* tlsHashOIDMap contains the mapping between TLS hash identifiers and the
- * SECOidTag used internally by NSS. */
+ * SECOidTag used internally by NSS.
+ *
+ * See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
+ */
 static const struct {
     SSLHashType tlsHash;
     SECOidTag oid;
 } tlsHashOIDMap[] = {
     { ssl_hash_sha1, SEC_OID_SHA1 },
     { ssl_hash_sha256, SEC_OID_SHA256 },
     { ssl_hash_sha384, SEC_OID_SHA384 },
     { ssl_hash_sha512, SEC_OID_SHA512 }
@@ -4878,19 +4993,17 @@ ssl3_IsSupportedSignatureAlgorithm(const
         ssl_hash_sha1,
         ssl_hash_sha256,
         ssl_hash_sha384,
         ssl_hash_sha512
     };
 
     static const SSLSignType supportedSigAlgs[] = {
         ssl_sign_rsa,
-#ifndef NSS_DISABLE_ECC
         ssl_sign_ecdsa,
-#endif
         ssl_sign_dsa
     };
 
     unsigned int i;
     PRBool hashOK = PR_FALSE;
     PRBool signOK = PR_FALSE;
 
     for (i = 0; i < PR_ARRAY_SIZE(supportedHashes); ++i) {
@@ -4976,21 +5089,21 @@ ssl3_ComputeHandshakeHashes(sslSocket *s
         ss->ssl3.hs.hashType == handshake_hash_single) {
         /* compute them without PKCS11 */
         PRUint64 sha_cx[MAX_MAC_CONTEXT_LLONGS];
 
         ss->ssl3.hs.sha_clone(sha_cx, ss->ssl3.hs.sha_cx);
         ss->ssl3.hs.sha_obj->end(sha_cx, hashes->u.raw, &hashes->len,
                                  sizeof(hashes->u.raw));
 
-        PRINT_BUF(60, (NULL, "SHA-256: result", hashes->u.raw, hashes->len));
+        PRINT_BUF(60, (NULL, "HASH: result", hashes->u.raw, hashes->len));
 
         /* If we ever support ciphersuites where the PRF hash isn't SHA-256
          * then this will need to be updated. */
-        hashes->hashAlg = ssl_hash_sha256;
+        hashes->hashAlg = ssl3_GetSuitePrfHash(ss);
         rv = SECSuccess;
     } else if (ss->opt.bypassPKCS11) {
         /* compute them without PKCS11 */
         PRUint64 md5_cx[MAX_MAC_CONTEXT_LLONGS];
         PRUint64 sha_cx[MAX_MAC_CONTEXT_LLONGS];
 
 #define md5cx ((MD5Context *)md5_cx)
 #define shacx ((SHA1Context *)sha_cx)
@@ -5088,19 +5201,18 @@ ssl3_ComputeHandshakeHashes(sslSocket *s
         }
         rv |= PK11_DigestFinal(h, hashes->u.raw, &hashes->len,
                                sizeof(hashes->u.raw));
         if (rv != SECSuccess) {
             ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
             rv = SECFailure;
             goto tls12_loser;
         }
-        /* If we ever support ciphersuites where the PRF hash isn't SHA-256
-         * then this will need to be updated. */
-        hashes->hashAlg = ssl_hash_sha256;
+
+        hashes->hashAlg = ssl3_GetSuitePrfHash(ss);
         rv = SECSuccess;
 
     tls12_loser:
         if (stateBuf) {
             if (PK11_RestoreContext(h, stateBuf, stateLen) != SECSuccess) {
                 ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
                 rv = SECFailure;
             }
@@ -5556,22 +5668,20 @@ ssl3_SendClientHello(sslSocket *ss, PRBo
             return SECFailure;
         }
         total_exten_len += extLen;
 
         if (total_exten_len > 0)
             total_exten_len += 2;
     }
 
-#ifndef NSS_DISABLE_ECC
     if (!total_exten_len || !isTLS) {
         /* not sending the elliptic_curves and ec_point_formats extensions */
         ssl3_DisableECCSuites(ss, NULL); /* disable all ECC suites */
     }
-#endif /* NSS_DISABLE_ECC */
 
     if (IS_DTLS(ss)) {
         ssl3_DisableNonDTLSSuites(ss);
     }
 
     /* how many suites are permitted by policy and user preference? */
     num_suites = count_cipher_suites(ss, ss->ssl3.policy, PR_TRUE);
     if (!num_suites) {
@@ -5594,31 +5704,33 @@ ssl3_SendClientHello(sslSocket *ss, PRBo
     /* count compression methods */
     numCompressionMethods = 0;
     for (i = 0; i < compressionMethodsCount; i++) {
         if (compressionEnabled(ss, compressions[i]))
             numCompressionMethods++;
     }
 
     length = sizeof(SSL3ProtocolVersion) + SSL3_RANDOM_LENGTH +
-            1 + (((sid == NULL) || sid->version >= SSL_LIBRARY_VERSION_TLS_1_3)
-            ? 0 : sid->u.ssl3.sessionIDLength) +
-            2 + num_suites * sizeof(ssl3CipherSuite) +
-            1 + numCompressionMethods + total_exten_len;
+             1 + (((sid == NULL) || sid->version >= SSL_LIBRARY_VERSION_TLS_1_3)
+                      ? 0
+                      : sid->u.ssl3.sessionIDLength) +
+             2 + num_suites * sizeof(ssl3CipherSuite) +
+             1 + numCompressionMethods + total_exten_len;
     if (IS_DTLS(ss)) {
         length += 1 + ss->ssl3.hs.cookieLen;
     }
 
     /* A padding extension may be included to ensure that the record containing
      * the ClientHello doesn't have a length between 256 and 511 bytes
      * (inclusive). Initial, ClientHello records with such lengths trigger bugs
      * in F5 devices.
      *
-     * This is not done for DTLS nor for renegotiation. */
-    if (!IS_DTLS(ss) && isTLS && !ss->firstHsDone) {
+     * This is not done for DTLS, for renegotiation, or when there are no
+     * extensions. */
+    if (!IS_DTLS(ss) && isTLS && !ss->firstHsDone && total_exten_len) {
         paddingExtensionLen = ssl3_CalculatePaddingExtensionLength(length);
         total_exten_len += paddingExtensionLen;
         length += paddingExtensionLen;
     } else {
         paddingExtensionLen = 0;
     }
 
     rv = ssl3_AppendHandshakeHeader(ss, client_hello, length);
@@ -5923,21 +6035,19 @@ ssl_UnwrapSymWrappingKey(
     SSLWrappedSymWrappingKey *pWswk,
     SECKEYPrivateKey *svrPrivKey,
     SSLAuthType authType,
     CK_MECHANISM_TYPE masterWrapMech,
     void *pwArg)
 {
     PK11SymKey *unwrappedWrappingKey = NULL;
     SECItem wrappedKey;
-#ifndef NSS_DISABLE_ECC
     PK11SymKey *Ks;
     SECKEYPublicKey pubWrapKey;
     ECCWrappedKeyInfo *ecWrapped;
-#endif /* NSS_DISABLE_ECC */
 
     /* found the wrapping key on disk. */
     PORT_Assert(pWswk->symWrapMechanism == masterWrapMech);
     PORT_Assert(pWswk->authType == authType);
     if (pWswk->symWrapMechanism != masterWrapMech ||
         pWswk->authType != authType) {
         goto loser;
     }
@@ -5946,21 +6056,20 @@ ssl_UnwrapSymWrappingKey(
     wrappedKey.len = pWswk->wrappedSymKeyLen;
     PORT_Assert(wrappedKey.len <= sizeof pWswk->wrappedSymmetricWrappingkey);
 
     switch (authType) {
 
         case ssl_auth_rsa_decrypt:
         case ssl_auth_rsa_sign: /* bad: see Bug 1248320 */
             unwrappedWrappingKey =
-                    PK11_PubUnwrapSymKey(svrPrivKey, &wrappedKey,
-                                         masterWrapMech, CKA_UNWRAP, 0);
-            break;
-
-#ifndef NSS_DISABLE_ECC
+                PK11_PubUnwrapSymKey(svrPrivKey, &wrappedKey,
+                                     masterWrapMech, CKA_UNWRAP, 0);
+            break;
+
         case ssl_auth_ecdsa:
         case ssl_auth_ecdh_rsa:
         case ssl_auth_ecdh_ecdsa:
             /*
              * For ssl_auth_ecd*, we first create an EC public key based on
              * data stored with the wrappedSymmetricWrappingkey. Next,
              * we do an ECDH computation involving this public key and
              * the SSL server's (long-term) EC private key. The resulting
@@ -5968,20 +6077,22 @@ ssl_UnwrapSymWrappingKey(
              * it is used to recover the symmetric wrapping key.
              *
              * The data in wrappedSymmetricWrappingkey is laid out as defined
              * in the ECCWrappedKeyInfo structure.
              */
             ecWrapped = (ECCWrappedKeyInfo *)pWswk->wrappedSymmetricWrappingkey;
 
             PORT_Assert(ecWrapped->encodedParamLen + ecWrapped->pubValueLen +
-                            ecWrapped->wrappedKeyLen <= MAX_EC_WRAPPED_KEY_BUFLEN);
+                            ecWrapped->wrappedKeyLen <=
+                        MAX_EC_WRAPPED_KEY_BUFLEN);
 
             if (ecWrapped->encodedParamLen + ecWrapped->pubValueLen +
-                    ecWrapped->wrappedKeyLen > MAX_EC_WRAPPED_KEY_BUFLEN) {
+                    ecWrapped->wrappedKeyLen >
+                MAX_EC_WRAPPED_KEY_BUFLEN) {
                 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
                 goto loser;
             }
 
             pubWrapKey.keyType = ecKey;
             pubWrapKey.u.ec.size = ecWrapped->size;
             pubWrapKey.u.ec.DEREncodedParams.len = ecWrapped->encodedParamLen;
             pubWrapKey.u.ec.DEREncodedParams.data = ecWrapped->var;
@@ -6003,17 +6114,16 @@ ssl_UnwrapSymWrappingKey(
 
             /*  Use Ks to unwrap the wrapping key */
             unwrappedWrappingKey = PK11_UnwrapSymKey(Ks, masterWrapMech, NULL,
                                                      &wrappedKey, masterWrapMech,
                                                      CKA_UNWRAP, 0);
             PK11_FreeSymKey(Ks);
 
             break;
-#endif
 
         default:
             /* Assert? */
             SET_ERROR_CODE
             goto loser;
     }
 loser:
     return unwrappedWrappingKey;
@@ -6082,38 +6192,36 @@ ssl_InitSymWrapKeysLock(void)
  * Put the new key in the in-memory array.
  *
  * Note that this function performs some fairly inadvisable functions with
  * certificate private keys.  ECDSA keys are used with ECDH; similarly, RSA
  * signing keys are used to encrypt.  Bug 1248320.
  */
 PK11SymKey *
 ssl3_GetWrappingKey(sslSocket *ss,
-               PK11SlotInfo *masterSecretSlot,
-               const sslServerCert *serverCert,
-               CK_MECHANISM_TYPE masterWrapMech,
-               void *pwArg)
+                    PK11SlotInfo *masterSecretSlot,
+                    const sslServerCert *serverCert,
+                    CK_MECHANISM_TYPE masterWrapMech,
+                    void *pwArg)
 {
     SSLAuthType authType;
     SECKEYPrivateKey *svrPrivKey;
     SECKEYPublicKey *svrPubKey = NULL;
     PK11SymKey *unwrappedWrappingKey = NULL;
     PK11SymKey **pSymWrapKey;
     CK_MECHANISM_TYPE asymWrapMechanism = CKM_INVALID_MECHANISM;
     int length;
     int symWrapMechIndex;
     SECStatus rv;
     SECItem wrappedKey;
     SSLWrappedSymWrappingKey wswk;
-#ifndef NSS_DISABLE_ECC
     PK11SymKey *Ks = NULL;
     SECKEYPublicKey *pubWrapKey = NULL;
     SECKEYPrivateKey *privWrapKey = NULL;
     ECCWrappedKeyInfo *ecWrapped;
-#endif /* NSS_DISABLE_ECC */
 
     PORT_Assert(serverCert);
     PORT_Assert(serverCert->serverKeyPair);
     PORT_Assert(serverCert->serverKeyPair->privKey);
     PORT_Assert(serverCert->serverKeyPair->pubKey);
     if (!serverCert || !serverCert->serverKeyPair ||
         !serverCert->serverKeyPair->privKey ||
         !serverCert->serverKeyPair->pubKey) {
@@ -6188,17 +6296,16 @@ ssl3_GetWrappingKey(sslSocket *ss,
     switch (authType) {
         case ssl_auth_rsa_decrypt:
         case ssl_auth_rsa_sign: /* bad: see Bug 1248320 */
             asymWrapMechanism = CKM_RSA_PKCS;
             rv = PK11_PubWrapSymKey(asymWrapMechanism, svrPubKey,
                                     unwrappedWrappingKey, &wrappedKey);
             break;
 
-#ifndef NSS_DISABLE_ECC
         case ssl_auth_ecdsa:
         case ssl_auth_ecdh_rsa:
         case ssl_auth_ecdh_ecdsa:
             /*
              * We generate an ephemeral EC key pair. Perform an ECDH
              * computation involving this ephemeral EC public key and
              * the SSL server's (long-term) EC private key. The resulting
              * shared secret is treated in the same way as Fortezza's Ks,
@@ -6224,19 +6331,21 @@ ssl3_GetWrappingKey(sslSocket *ss,
             }
 
             /* Set the key size in bits */
             if (pubWrapKey->u.ec.size == 0) {
                 pubWrapKey->u.ec.size = SECKEY_PublicKeyStrengthInBits(svrPubKey);
             }
 
             PORT_Assert(pubWrapKey->u.ec.DEREncodedParams.len +
-                            pubWrapKey->u.ec.publicValue.len < MAX_EC_WRAPPED_KEY_BUFLEN);
+                            pubWrapKey->u.ec.publicValue.len <
+                        MAX_EC_WRAPPED_KEY_BUFLEN);
             if (pubWrapKey->u.ec.DEREncodedParams.len +
-                    pubWrapKey->u.ec.publicValue.len >= MAX_EC_WRAPPED_KEY_BUFLEN) {
+                    pubWrapKey->u.ec.publicValue.len >=
+                MAX_EC_WRAPPED_KEY_BUFLEN) {
                 PORT_SetError(SEC_ERROR_INVALID_KEY);
                 rv = SECFailure;
                 goto ec_cleanup;
             }
 
             /* Derive Ks using ECDH */
             Ks = PK11_PubDeriveWithKDF(svrPrivKey, pubWrapKey, PR_FALSE, NULL,
                                        NULL, CKM_ECDH1_DERIVE, masterWrapMech,
@@ -6279,17 +6388,16 @@ ssl3_GetWrappingKey(sslSocket *ss,
             if (privWrapKey)
                 SECKEY_DestroyPrivateKey(privWrapKey);
             if (pubWrapKey)
                 SECKEY_DestroyPublicKey(pubWrapKey);
             if (Ks)
                 PK11_FreeSymKey(Ks);
             asymWrapMechanism = masterWrapMech;
             break;
-#endif /* NSS_DISABLE_ECC */
 
         default:
             rv = SECFailure;
             break;
     }
 
     if (rv != SECSuccess) {
         ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
@@ -6599,21 +6707,19 @@ ssl3_SendClientKeyExchange(sslSocket *ss
         case ssl_kea_rsa:
             rv = sendRSAClientKeyExchange(ss, serverKey);
             break;
 
         case ssl_kea_dh:
             rv = sendDHClientKeyExchange(ss, serverKey);
             break;
 
-#ifndef NSS_DISABLE_ECC
         case ssl_kea_ecdh:
             rv = ssl3_SendECDHClientKeyExchange(ss, serverKey);
             break;
-#endif /* NSS_DISABLE_ECC */
 
         default:
             /* got an unknown or unsupported Key Exchange Algorithm.  */
             SEND_ALERT
             PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
             break;
     }
 
@@ -6645,33 +6751,33 @@ ssl3_SendCertificateVerify(sslSocket *ss
 
     SSL_TRC(3, ("%d: SSL3[%d]: send certificate_verify handshake",
                 SSL_GETPID(), ss->fd));
 
     isTLS13 = (PRBool)(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
     ssl_GetSpecReadLock(ss);
     if (ss->ssl3.hs.hashType == handshake_hash_single &&
         ss->ssl3.hs.backupHash) {
-        PORT_Assert(!ss->ssl3.hs.backupHash);
         PORT_Assert(!isTLS13);
         /* TODO(ekr@rtfm.com): The backup hash here contains a SHA-1 hash
          * but in TLS 1.3, we always sign H(Context, Hash(handshake))
          * where:
          *
          * H is the negotiated signature hash and
          * Hash is the cipher-suite specific handshake hash
          * Generally this means that Hash is SHA-256.
          *
          * We need code to negotiate H but the current code is a mess.
          */
         if (isTLS13) {
             /* rv is already set to SECFailure */
             PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
         } else {
             rv = ssl3_ComputeBackupHandshakeHashes(ss, &hashes);
+            PORT_Assert(!ss->ssl3.hs.backupHash);
         }
     } else {
         ssl3CipherSpec *spec;
 
         if (isTLS13) {
             /* In TLS 1.3, we are already encrypted. */
             spec = ss->ssl3.cwSpec;
         } else {
@@ -6741,16 +6847,36 @@ ssl3_SendCertificateVerify(sslSocket *ss
     }
 
 done:
     if (buf.data)
         PORT_Free(buf.data);
     return rv;
 }
 
+/* Once a cipher suite has been selected, make sure that the necessary secondary
+ * information is properly set. */
+static SECStatus
+ssl3_SetCipherSuite(sslSocket *ss, ssl3CipherSuite chosenSuite)
+{
+    ss->ssl3.hs.cipher_suite = chosenSuite;
+    ss->ssl3.hs.suite_def = ssl_LookupCipherSuiteDef(chosenSuite);
+    if (!ss->ssl3.hs.suite_def) {
+        PORT_Assert(0);
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+
+    ss->ssl3.hs.kea_def = &kea_defs[ss->ssl3.hs.suite_def->key_exchange_alg];
+    ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_cipher_suite;
+
+    /* Now we've have a cipher suite, initialize the handshake hashes. */
+    return ssl3_InitHandshakeHashes(ss);
+}
+
 /* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
  * ssl3 ServerHello message.
  * Caller must hold Handshake and RecvBuf locks.
  */
 static SECStatus
 ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
 {
     PRInt32 temp; /* allow for consume number failure */
@@ -6818,23 +6944,16 @@ ssl3_HandleServerHello(sslSocket *ss, SS
         desc = (version > SSL_LIBRARY_VERSION_3_0) ? protocol_version
                                                    : handshake_failure;
         errCode = SSL_ERROR_UNSUPPORTED_VERSION;
         goto alert_loser;
     }
     ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_version;
     isTLS = (ss->version > SSL_LIBRARY_VERSION_3_0);
 
-    rv = ssl3_InitHandshakeHashes(ss);
-    if (rv != SECSuccess) {
-        desc = internal_error;
-        errCode = PORT_GetError();
-        goto alert_loser;
-    }
-
     rv = ssl3_ConsumeHandshake(
         ss, &ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH, &b, &length);
     if (rv != SECSuccess) {
         goto loser; /* alert has been sent */
     }
 
     /* Check the ServerHello.random per
      * [draft-ietf-tls-tls13-11 Section 6.3.1.1].
@@ -6901,27 +7020,23 @@ ssl3_HandleServerHello(sslSocket *ss, SS
             break; /* success */
         }
     }
     if (!suite_found) {
         desc = handshake_failure;
         errCode = SSL_ERROR_NO_CYPHER_OVERLAP;
         goto alert_loser;
     }
-    ss->ssl3.hs.cipher_suite = (ssl3CipherSuite)temp;
-    ss->ssl3.hs.suite_def = ssl_LookupCipherSuiteDef((ssl3CipherSuite)temp);
-    ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_cipher_suite;
-    PORT_Assert(ss->ssl3.hs.suite_def);
-    if (!ss->ssl3.hs.suite_def) {
-        errCode = SEC_ERROR_LIBRARY_FAILURE;
-        PORT_SetError(errCode);
-        goto loser; /* we don't send alerts for our screw-ups. */
-    }
-
-    ss->ssl3.hs.kea_def = &kea_defs[ss->ssl3.hs.suite_def->key_exchange_alg];
+
+    rv = ssl3_SetCipherSuite(ss, (ssl3CipherSuite)temp);
+    if (rv != SECSuccess) {
+        desc = internal_error;
+        errCode = PORT_GetError();
+        goto alert_loser;
+    }
 
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
         /* find selected compression method in our list. */
         temp = ssl3_ConsumeHandshakeNumber(ss, 1, &b, &length);
         if (temp < 0) {
             goto loser; /* alert has been sent */
         }
         suite_found = PR_FALSE;
@@ -7474,21 +7589,19 @@ ssl3_HandleServerKeyExchange(sslSocket *
                 SECITEM_CopyItem(arena, &peerKey->u.dh.publicValue, &dh_Ys)) {
                 goto no_memory;
             }
             ss->sec.peerKey = peerKey;
             ss->ssl3.hs.ws = wait_cert_request;
             return SECSuccess;
         }
 
-#ifndef NSS_DISABLE_ECC
         case ssl_kea_ecdh:
             rv = ssl3_HandleECDHServerKeyExchange(ss, b, length);
             return rv;
-#endif /* NSS_DISABLE_ECC */
 
         default:
             desc = handshake_failure;
             errCode = SEC_ERROR_UNSUPPORTED_KEYALG;
             break; /* goto alert_loser; */
     }
 
 alert_loser:
@@ -7547,26 +7660,26 @@ done:
     if (pubk)
         SECKEY_DestroyPublicKey(pubk);
     return rv;
 }
 
 /* Destroys the backup handshake hash context if we don't need it. Note that
  * this function selects the hash algorithm for client authentication
  * signatures; ssl3_SendCertificateVerify uses the presence of the backup hash
- * to determine whether to use SHA-1 or SHA-256. */
+ * to determine whether to use SHA-1, or the PRF hash of the cipher suite. */
 static void
 ssl3_DestroyBackupHandshakeHashIfNotNeeded(sslSocket *ss,
                                            const SECItem *algorithms)
 {
     SECStatus rv;
     SSLSignType sigAlg;
     PRBool preferSha1 = PR_FALSE;
     PRBool supportsSha1 = PR_FALSE;
-    PRBool supportsSha256 = PR_FALSE;
+    PRBool supportsHandshakeHash = PR_FALSE;
     PRBool needBackupHash = PR_FALSE;
     unsigned int i;
 
 #ifndef NO_PKCS11_BYPASS
     /* Backup handshake hash is not supported in PKCS #11 bypass mode. */
     if (ss->opt.bypassPKCS11) {
         PORT_Assert(!ss->ssl3.hs.backupHash);
         return;
@@ -7580,25 +7693,25 @@ ssl3_DestroyBackupHandshakeHashIfNotNeed
         goto done;
     }
 
     /* Determine the server's hash support for that signature algorithm. */
     for (i = 0; i < algorithms->len; i += 2) {
         if (algorithms->data[i + 1] == sigAlg) {
             if (algorithms->data[i] == ssl_hash_sha1) {
                 supportsSha1 = PR_TRUE;
-            } else if (algorithms->data[i] == ssl_hash_sha256) {
-                supportsSha256 = PR_TRUE;
-            }
-        }
-    }
-
-    /* If either the server does not support SHA-256 or the client key prefers
+            } else if (algorithms->data[i] == ss->ssl3.hs.suite_def->prf_hash) {
+                supportsHandshakeHash = PR_TRUE;
+            }
+        }
+    }
+
+    /* If either the server does not support the handshake hash or the client key prefers
      * SHA-1, leave the backup hash. */
-    if (supportsSha1 && (preferSha1 || !supportsSha256)) {
+    if (supportsSha1 && (preferSha1 || !supportsHandshakeHash)) {
         needBackupHash = PR_TRUE;
     }
 
 done:
     if (!needBackupHash) {
         PK11_DestroyContext(ss->ssl3.hs.backupHash, PR_TRUE);
         ss->ssl3.hs.backupHash = NULL;
     }
@@ -8337,37 +8450,29 @@ ssl3_KEASupportsTickets(const ssl3KEADef
 ** and a TLS 1.1 client should definitely not be offering *only* export
 ** cipher suites. Therefore, we refuse to negotiate export cipher suites
 ** with any client that indicates support for TLS 1.1 or higher when we
 ** (the server) have TLS 1.1 support enabled.
 */
 SECStatus
 ssl3_NegotiateCipherSuite(sslSocket *ss, const SECItem *suites)
 {
-    ssl3CipherSuiteCfg *chosenSuite = NULL;
     int j;
     int i;
 
     for (j = 0; j < ssl_V3_SUITES_IMPLEMENTED; j++) {
         ssl3CipherSuiteCfg *suite = &ss->cipherSuites[j];
-        SSLVersionRange vrange = {ss->version, ss->version};
+        SSLVersionRange vrange = { ss->version, ss->version };
         if (!config_match(suite, ss->ssl3.policy, PR_TRUE, &vrange, ss)) {
             continue;
         }
         for (i = 0; i + 1 < suites->len; i += 2) {
             PRUint16 suite_i = (suites->data[i] << 8) | suites->data[i + 1];
             if (suite_i == suite->cipher_suite) {
-                chosenSuite = suite;
-                ss->ssl3.hs.cipher_suite = chosenSuite->cipher_suite;
-                ss->ssl3.hs.suite_def =
-                        ssl_LookupCipherSuiteDef(ss->ssl3.hs.cipher_suite);
-                ss->ssl3.hs.kea_def =
-                        &kea_defs[ss->ssl3.hs.suite_def->key_exchange_alg];
-                ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_cipher_suite;
-                return SECSuccess;
+                return ssl3_SetCipherSuite(ss, suite_i);
             }
         }
     }
     return SECFailure;
 }
 
 /*
  * Call the SNI config hook.
@@ -8375,41 +8480,42 @@ ssl3_NegotiateCipherSuite(sslSocket *ss,
  * Called from:
  *   ssl3_HandleClientHello
  *   tls13_HandleClientHelloPart2
  */
 SECStatus
 ssl3_ServerCallSNICallback(sslSocket *ss)
 {
     int errCode = SSL_ERROR_RX_MALFORMED_CLIENT_HELLO;
-    SSL3AlertDescription desc  = illegal_parameter;
+    SSL3AlertDescription desc = illegal_parameter;
     int ret = 0;
 
     if (!ssl3_ExtensionNegotiated(ss, ssl_server_name_xtn)) {
 #ifndef SSL_SNI_ALLOW_NAME_CHANGE_2HS
         if (ss->firstHsDone) {
             /* Check that we don't have the name is current spec
              * if this extension was not negotiated on the 2d hs. */
             PRBool passed = PR_TRUE;
-            ssl_GetSpecReadLock(ss);  /*******************************/
+            ssl_GetSpecReadLock(ss); /*******************************/
             if (ss->ssl3.cwSpec->srvVirtName.data) {
                 passed = PR_FALSE;
             }
-            ssl_ReleaseSpecReadLock(ss);  /***************************/
+            ssl_ReleaseSpecReadLock(ss); /***************************/
             if (!passed) {
                 errCode = SSL_ERROR_UNRECOGNIZED_NAME_ALERT;
                 desc = handshake_failure;
                 goto alert_loser;
             }
         }
 #endif
         return SECSuccess;
     }
 
-    if (ss->sniSocketConfig) do { /* not a loop */
+    if (ss->sniSocketConfig)
+        do { /* not a loop */
             PORT_Assert((ss->ssl3.hs.preliminaryInfo & ssl_preinfo_all) ==
                         ssl_preinfo_all);
 
             ret = SSL_SNI_SEND_ALERT;
             /* If extension is negotiated, the len of names should > 0. */
             if (ss->xtnData.sniNameArrSize) {
                 /* Calling client callback to reconfigure the socket. */
                 ret = (SECStatus)(*ss->sniSocketConfig)(ss->fd,
@@ -8419,77 +8525,77 @@ ssl3_ServerCallSNICallback(sslSocket *ss
             }
             if (ret <= SSL_SNI_SEND_ALERT) {
                 /* Application does not know the name or was not able to
                  * properly reconfigure the socket. */
                 errCode = SSL_ERROR_UNRECOGNIZED_NAME_ALERT;
                 desc = unrecognized_name;
                 break;
             } else if (ret == SSL_SNI_CURRENT_CONFIG_IS_USED) {
-                SECStatus       rv = SECSuccess;
-                SECItem *       cwsName, *pwsName;
-
-                ssl_GetSpecWriteLock(ss);  /*******************************/
+                SECStatus rv = SECSuccess;
+                SECItem *cwsName, *pwsName;
+
+                ssl_GetSpecWriteLock(ss); /*******************************/
                 pwsName = &ss->ssl3.pwSpec->srvVirtName;
                 cwsName = &ss->ssl3.cwSpec->srvVirtName;
 #ifndef SSL_SNI_ALLOW_NAME_CHANGE_2HS
                 /* not allow name change on the 2d HS */
                 if (ss->firstHsDone) {
                     if (ssl3_ServerNameCompare(pwsName, cwsName)) {
-                        ssl_ReleaseSpecWriteLock(ss);  /******************/
+                        ssl_ReleaseSpecWriteLock(ss); /******************/
                         errCode = SSL_ERROR_UNRECOGNIZED_NAME_ALERT;
                         desc = handshake_failure;
                         ret = SSL_SNI_SEND_ALERT;
                         break;
                     }
                 }
 #endif
                 if (pwsName->data) {
                     SECITEM_FreeItem(pwsName, PR_FALSE);
                 }
                 if (cwsName->data) {
                     rv = SECITEM_CopyItem(NULL, pwsName, cwsName);
                 }
-                ssl_ReleaseSpecWriteLock(ss);  /**************************/
+                ssl_ReleaseSpecWriteLock(ss); /**************************/
                 if (rv != SECSuccess) {
                     errCode = SSL_ERROR_INTERNAL_ERROR_ALERT;
                     desc = internal_error;
                     ret = SSL_SNI_SEND_ALERT;
                     break;
                 }
             } else if ((unsigned int)ret < ss->xtnData.sniNameArrSize) {
                 /* Application has configured new socket info. Lets check it
                  * and save the name. */
-                SECStatus       rv;
-                SECItem *       name = &ss->xtnData.sniNameArr[ret];
-                int             configedCiphers;
-                SECItem *       pwsName;
+                SECStatus rv;
+                SECItem *name = &ss->xtnData.sniNameArr[ret];
+                int configedCiphers;
+                SECItem *pwsName;
 
                 /* get rid of the old name and save the newly picked. */
                 /* This code is protected by ssl3HandshakeLock. */
-                ssl_GetSpecWriteLock(ss);  /*******************************/
+                ssl_GetSpecWriteLock(ss); /*******************************/
 #ifndef SSL_SNI_ALLOW_NAME_CHANGE_2HS
                 /* not allow name change on the 2d HS */
                 if (ss->firstHsDone) {
                     SECItem *cwsName = &ss->ssl3.cwSpec->srvVirtName;
                     if (ssl3_ServerNameCompare(name, cwsName)) {
-                        ssl_ReleaseSpecWriteLock(ss);  /******************/
+                        ssl_ReleaseSpecWriteLock(ss); /******************/
                         errCode = SSL_ERROR_UNRECOGNIZED_NAME_ALERT;
                         desc = handshake_failure;
                         ret = SSL_SNI_SEND_ALERT;
                         break;
                     }
                 }
 #endif
                 pwsName = &ss->ssl3.pwSpec->srvVirtName;
                 if (pwsName->data) {
                     SECITEM_FreeItem(pwsName, PR_FALSE);
                 }
                 rv = SECITEM_CopyItem(NULL, pwsName, name);
-                ssl_ReleaseSpecWriteLock(ss);  /***************************/
+                ssl_ReleaseSpecWriteLock(ss); /***************************/
                 if (rv != SECSuccess) {
                     errCode = SSL_ERROR_INTERNAL_ERROR_ALERT;
                     desc = internal_error;
                     ret = SSL_SNI_SEND_ALERT;
                     break;
                 }
                 configedCiphers = ssl3_config_match_init(ss);
                 if (configedCiphers <= 0) {
@@ -8508,26 +8614,17 @@ ssl3_ServerCallSNICallback(sslSocket *ss
                 /* Callback returned index outside of the boundary. */
                 PORT_Assert((unsigned int)ret < ss->xtnData.sniNameArrSize);
                 errCode = SSL_ERROR_INTERNAL_ERROR_ALERT;
                 desc = internal_error;
                 ret = SSL_SNI_SEND_ALERT;
                 break;
             }
         } while (0);
-    /* Free sniNameArr. The data that each SECItem in the array
-     * points into is the data from the input buffer "b". It will
-     * not be available outside the scope of this function or
-     * the callers (*HandleClientHelloPart2) and the callers
-     must not use it after this point. */
-    if (ss->xtnData.sniNameArr) {
-        PORT_Free(ss->xtnData.sniNameArr);
-        ss->xtnData.sniNameArr = NULL;
-        ss->xtnData.sniNameArrSize = 0;
-    }
+    ssl3_FreeSniNameArray(&ss->xtnData);
     if (ret <= SSL_SNI_SEND_ALERT) {
         /* desc and errCode should be set. */
         goto alert_loser;
     }
 
     return SECSuccess;
 
 alert_loser:
@@ -8546,29 +8643,27 @@ ssl3_SelectServerCert(sslSocket *ss)
      * a) the right authentication method, and
      * b) the right named curve (EC only)
      *
      * We might want to do some sort of ranking here later.  For now, it's all
      * based on what order they are configured in. */
     for (cursor = PR_NEXT_LINK(&ss->serverCerts);
          cursor != &ss->serverCerts;
          cursor = PR_NEXT_LINK(cursor)) {
-        sslServerCert *cert = (sslServerCert*)cursor;
+        sslServerCert *cert = (sslServerCert *)cursor;
         if (cert->certType.authType != kea_def->authKeyType) {
             continue;
         }
-#ifndef NSS_DISABLE_ECC
         if ((cert->certType.authType == ssl_auth_ecdsa ||
              cert->certType.authType == ssl_auth_ecdh_rsa ||
              cert->certType.authType == ssl_auth_ecdh_ecdsa) &&
             !SSL_IS_CURVE_NEGOTIATED(ss->ssl3.hs.negotiatedECCurves,
                                      cert->certType.u.namedCurve)) {
             continue;
         }
-#endif
 
         /* Found one. */
         ss->sec.serverCert = cert;
         ss->sec.authType = cert->certType.authType;
         ss->sec.authKeyBits = cert->serverKeyBits;
         return SECSuccess;
     }
 
@@ -8660,23 +8755,16 @@ ssl3_HandleClientHello(sslSocket *ss, SS
         desc = (version > SSL_LIBRARY_VERSION_3_0) ? protocol_version
                                                    : handshake_failure;
         errCode = SSL_ERROR_UNSUPPORTED_VERSION;
         goto alert_loser;
     }
     isTLS13 = ss->version >= SSL_LIBRARY_VERSION_TLS_1_3;
     ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_version;
 
-    rv = ssl3_InitHandshakeHashes(ss);
-    if (rv != SECSuccess) {
-        desc = internal_error;
-        errCode = PORT_GetError();
-        goto alert_loser;
-    }
-
     /* Generate the Server Random now so it is available
      * when we process the ClientKeyShare in TLS 1.3 */
     rv = ssl3_GetNewRandom(&ss->ssl3.hs.server_random);
     if (rv != SECSuccess) {
         errCode = SSL_ERROR_GENERATE_RANDOM_FAILURE;
         goto loser;
     }
 
@@ -8883,16 +8971,22 @@ ssl3_HandleClientHello(sslSocket *ss, SS
                         sidBytes.len);
             sid->u.ssl3.sessionIDLength = sidBytes.len;
         } else {
             sid->u.ssl3.sessionIDLength = 0;
         }
         ss->sec.ci.sid = NULL;
     }
 
+    /* Free a potentially leftover session ID from a previous handshake. */
+    if (ss->sec.ci.sid) {
+        ssl_FreeSID(ss->sec.ci.sid);
+        ss->sec.ci.sid = NULL;
+    }
+
     /* We only send a session ticket extension if the client supports
      * the extension and we are unable to do either a stateful or
      * stateless resume.
      *
      * TODO: send a session ticket if performing a stateful
      * resumption.  (As per RFC4507, a server may issue a session
      * ticket while doing a (stateless or stateful) session resume,
      * but OpenSSL-0.9.8g does not accept session tickets while
@@ -8918,20 +9012,18 @@ ssl3_HandleClientHello(sslSocket *ss, SS
             SSL_AtomicIncrementLong(&ssl3stats.hch_sid_cache_not_ok);
             if (ss->sec.uncache)
                 ss->sec.uncache(sid);
             ssl_FreeSID(sid);
             sid = NULL;
         }
     }
 
-#ifndef NSS_DISABLE_ECC
     /* Disable any ECC cipher suites for which we have no cert. */
     ssl3_FilterECCipherSuitesByServerCerts(ss);
-#endif
 
     if (IS_DTLS(ss)) {
         ssl3_DisableNonDTLSSuites(ss);
     }
 
 #ifdef PARANOID
     /* Look for a matching cipher suite. */
     j = ssl3_config_match_init(ss);
@@ -8949,27 +9041,28 @@ ssl3_HandleClientHello(sslSocket *ss, SS
     }
     if (rv != SECSuccess) {
         goto loser;
     }
     return SECSuccess;
 
 alert_loser:
     (void)SSL3_SendAlert(ss, level, desc);
-    /* FALLTHRU */
+/* FALLTHRU */
 loser:
     PORT_SetError(errCode);
     return SECFailure;
 }
 
-static SECStatus ssl3_HandleClientHelloPart2(sslSocket *ss,
-                                             SECItem *suites,
-                                             SECItem *comps,
-                                             sslSessionID *sid,
-                                             PRBool canOfferSessionTicket)
+static SECStatus
+ssl3_HandleClientHelloPart2(sslSocket *ss,
+                            SECItem *suites,
+                            SECItem *comps,
+                            sslSessionID *sid,
+                            PRBool canOfferSessionTicket)
 {
     PRBool haveSpecWriteLock = PR_FALSE;
     PRBool haveXmitBufLock = PR_FALSE;
     int errCode = SSL_ERROR_RX_MALFORMED_CLIENT_HELLO;
     SSL3AlertDescription desc = illegal_parameter;
     SECStatus rv;
     unsigned int i;
     int j;
@@ -9013,57 +9106,57 @@ static SECStatus ssl3_HandleClientHelloP
              * Implemented ("isPresent") shouldn't change for servers.
              */
             if (!config_match(suite, ss->ssl3.policy, PR_TRUE, &vrange, ss))
                 break;
 #else
             if (!suite->enabled)
                 break;
 #endif
-            /* Double check that the cached cipher suite is in the client's list */
+            /* Double check that the cached cipher suite is in the client's
+             * list.  If it isn't, fall through and start a new session. */
             for (i = 0; i + 1 < suites->len; i += 2) {
                 PRUint16 suite_i = (suites->data[i] << 8) | suites->data[i + 1];
                 if (suite_i == suite->cipher_suite) {
-                    ss->ssl3.hs.cipher_suite =
-                        suite->cipher_suite;
-                    ss->ssl3.hs.suite_def =
-                        ssl_LookupCipherSuiteDef(ss->ssl3.hs.cipher_suite);
-                    ss->ssl3.hs.kea_def =
-                        &kea_defs[ss->ssl3.hs.suite_def->key_exchange_alg];
-                    ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_cipher_suite;
+                    rv = ssl3_SetCipherSuite(ss, suite_i);
+                    if (rv != SECSuccess) {
+                        desc = internal_error;
+                        errCode = PORT_GetError();
+                        goto alert_loser;
+                    }
 
                     /* Use the cached compression method. */
                     ss->ssl3.hs.compression =
                         sid->u.ssl3.compression;
                     goto compression_found;
                 }
             }
         } while (0);
 /* START A NEW SESSION */
 
 #ifndef PARANOID
     /* Look for a matching cipher suite. */
     j = ssl3_config_match_init(ss);
-    if (j <= 0) {                  /* no ciphers are working/supported by PK11 */
+    if (j <= 0) { /* no ciphers are working/supported by PK11 */
         desc = internal_error;
         errCode = PORT_GetError(); /* error code is already set. */
         goto alert_loser;
     }
 #endif
 
     rv = ssl3_NegotiateCipherSuite(ss, suites);
     if (rv != SECSuccess) {
         desc = handshake_failure;
         errCode = SSL_ERROR_NO_CYPHER_OVERLAP;
         goto alert_loser;
     }
 
     if (canOfferSessionTicket)
         canOfferSessionTicket =
-                ssl3_KEASupportsTickets(ss->ssl3.hs.kea_def);
+            ssl3_KEASupportsTickets(ss->ssl3.hs.kea_def);
 
     if (canOfferSessionTicket) {
         ssl3_RegisterServerHelloExtensionSender(ss,
                                                 ssl_session_ticket_xtn, ssl3_SendSessionTicketXtn);
     }
 
     /* Select a compression algorithm. */
     for (i = 0; i < comps->len; i++) {
@@ -9251,22 +9344,17 @@ compression_found:
                 if (rv != SECSuccess) {
                     errCode = PORT_GetError();
                     desc = internal_error;
                     goto alert_loser;
                 }
             }
 
             /* Clean up sni name array */
-            if (ssl3_ExtensionNegotiated(ss, ssl_server_name_xtn) &&
-                ss->xtnData.sniNameArr) {
-                PORT_Free(ss->xtnData.sniNameArr);
-                ss->xtnData.sniNameArr = NULL;
-                ss->xtnData.sniNameArrSize = 0;
-            }
+            ssl3_FreeSniNameArray(&ss->xtnData);
 
             ssl_GetXmitBufLock(ss);
             haveXmitBufLock = PR_TRUE;
 
             rv = ssl3_SendServerHello(ss);
             if (rv != SECSuccess) {
                 errCode = PORT_GetError();
                 goto loser;
@@ -9358,17 +9446,17 @@ compression_found:
     return SECSuccess;
 
 alert_loser:
     if (haveSpecWriteLock) {
         ssl_ReleaseSpecWriteLock(ss);
         haveSpecWriteLock = PR_FALSE;
     }
     (void)SSL3_SendAlert(ss, alert_fatal, desc);
-    /* FALLTHRU */
+/* FALLTHRU */
 loser:
     if (haveSpecWriteLock) {
         ssl_ReleaseSpecWriteLock(ss);
     }
 
     if (haveXmitBufLock) {
         ssl_ReleaseXmitBufLock(ss);
     }
@@ -9448,23 +9536,16 @@ ssl3_HandleV2ClientHello(sslSocket *ss, 
         /* send back which ever alert client will understand. */
         desc = (version > SSL_LIBRARY_VERSION_3_0) ? protocol_version
                                                    : handshake_failure;
         errCode = SSL_ERROR_UNSUPPORTED_VERSION;
         goto alert_loser;
     }
     ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_version;
 
-    rv = ssl3_InitHandshakeHashes(ss);
-    if (rv != SECSuccess) {
-        desc = internal_error;
-        errCode = PORT_GetError();
-        goto alert_loser;
-    }
-
     /* if we get a non-zero SID, just ignore it. */
     if (length != total) {
         SSL_DBG(("%d: SSL3[%d]: bad v2 client hello message, len=%d should=%d",
                  SSL_GETPID(), ss->fd, length, total));
         desc = illegal_parameter;
         errCode = SSL_ERROR_RX_MALFORMED_CLIENT_HELLO;
         goto alert_loser;
     }
@@ -9483,20 +9564,18 @@ ssl3_HandleV2ClientHello(sslSocket *ss, 
 
     PORT_Memset(&ss->ssl3.hs.client_random, 0, SSL3_RANDOM_LENGTH);
     PORT_Memcpy(
         &ss->ssl3.hs.client_random.rand[SSL3_RANDOM_LENGTH - rand_length],
         random, rand_length);
 
     PRINT_BUF(60, (ss, "client random:", &ss->ssl3.hs.client_random.rand[0],
                    SSL3_RANDOM_LENGTH));
-#ifndef NSS_DISABLE_ECC
     /* Disable any ECC cipher suites for which we have no cert. */
     ssl3_FilterECCipherSuitesByServerCerts(ss);
-#endif
     i = ssl3_config_match_init(ss);
     if (i <= 0) {
         errCode = PORT_GetError(); /* error code is already set. */
         goto alert_loser;
     }
 
     /* Select a cipher suite.
     **
@@ -9509,36 +9588,36 @@ ssl3_HandleV2ClientHello(sslSocket *ss, 
         ssl3CipherSuiteCfg *suite = &ss->cipherSuites[j];
         SSLVersionRange vrange = { ss->version, ss->version };
         if (!config_match(suite, ss->ssl3.policy, PR_TRUE, &vrange, ss)) {
             continue;
         }
         for (i = 0; i + 2 < suite_length; i += 3) {
             PRUint32 suite_i = (suites[i] << 16) | (suites[i + 1] << 8) | suites[i + 2];
             if (suite_i == suite->cipher_suite) {
-                ss->ssl3.hs.cipher_suite = suite->cipher_suite;
-                ss->ssl3.hs.suite_def =
-                    ssl_LookupCipherSuiteDef(ss->ssl3.hs.cipher_suite);
-                ss->ssl3.hs.kea_def =
-                    &kea_defs[ss->ssl3.hs.suite_def->key_exchange_alg];
-                ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_cipher_suite;
+                rv = ssl3_SetCipherSuite(ss, suite_i);
+                if (rv != SECSuccess) {
+                    desc = internal_error;
+                    errCode = PORT_GetError();
+                    goto alert_loser;
+                }
                 goto suite_found;
             }
         }
     }
     errCode = SSL_ERROR_NO_CYPHER_OVERLAP;
     goto alert_loser;
 
 suite_found:
 
     /* If the ClientHello version is less than our maximum version, check for a
      * TLS_FALLBACK_SCSV and reject the connection if found. */
     if (ss->vrange.max > ss->clientHelloVersion) {
         for (i = 0; i + 2 < suite_length; i += 3) {
-            PRUint16 suite_i = (suites[i + 1] << 8) | suites[i + 2];
+            PRUint16 suite_i = (suites[i] << 16) | (suites[i + 1] << 8) | suites[i + 2];
             if (suite_i == TLS_FALLBACK_SCSV) {
                 desc = inappropriate_fallback;
                 errCode = SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT;
                 goto alert_loser;
             }
         }
     }
 
@@ -9980,18 +10059,18 @@ ssl3_SendServerKeyExchange(sslSocket *ss
                 goto loser; /* ssl3_SignHashes has set err. */
             }
             if (signed_hash.data == NULL) {
                 /* how can this happen and rv == SECSuccess ?? */
                 PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
                 goto loser;
             }
             length = 2 + sdPub->u.rsa.modulus.len +
-                    2 + sdPub->u.rsa.publicExponent.len +
-                    2 + signed_hash.len;
+                     2 + sdPub->u.rsa.publicExponent.len +
+                     2 + signed_hash.len;
 
             if (ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
                 length += 2;
             }
 
             rv = ssl3_AppendHandshakeHeader(ss, server_key_exchange, length);
             if (rv != SECSuccess) {
                 goto loser; /* err set by AppendHandshake. */
@@ -10025,22 +10104,20 @@ ssl3_SendServerKeyExchange(sslSocket *ss
             PORT_Free(signed_hash.data);
             return SECSuccess;
 
         case ssl_kea_dh: {
             rv = ssl3_SendDHServerKeyExchange(ss);
             return rv;
         }
 
-#ifndef NSS_DISABLE_ECC
         case ssl_kea_ecdh: {
             rv = ssl3_SendECDHServerKeyExchange(ss, &sigAndHash);
             return rv;
         }
-#endif /* NSS_DISABLE_ECC */
 
         case ssl_kea_null:
         default:
             PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
             break;
     }
 loser:
     if (signed_hash.data != NULL)
@@ -10048,30 +10125,32 @@ loser:
     return SECFailure;
 }
 
 SECStatus
 ssl3_EncodeCertificateRequestSigAlgs(sslSocket *ss, PRUint8 *buf,
                                      unsigned maxLen, PRUint32 *len)
 {
     unsigned int i;
+    /* We only track a single hash, the one that is the basis for the PRF. */
+    SSLHashType suiteHashAlg = ssl3_GetSuitePrfHash(ss);
 
     PORT_Assert(maxLen >= ss->ssl3.signatureAlgorithmCount * 2);
     if (maxLen < ss->ssl3.signatureAlgorithmCount * 2) {
         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
         return SECFailure;
     }
 
     *len = 0;
     for (i = 0; i < ss->ssl3.signatureAlgorithmCount; ++i) {
         const SSLSignatureAndHashAlg *alg = &ss->ssl3.signatureAlgorithms[i];
         /* Note that we don't support a handshake hash with anything other than
-         * SHA-256, so asking for a signature from clients for something else
-         * would be inviting disaster. */
-        if (alg->hashAlg == ssl_hash_sha256) {
+         * the PRF hash, so asking for a signature from clients for something
+         * else would be inviting disaster. */
+        if (alg->hashAlg == suiteHashAlg) {
             buf[(*len)++] = (PRUint8)alg->hashAlg;
             buf[(*len)++] = (PRUint8)alg->sigAlg;
         }
     }
 
     if (*len == 0) {
         PORT_SetError(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
         return SECFailure;
@@ -10450,17 +10529,17 @@ ssl3_HandleRSAClientKeyExchange(sslSocke
 
             if (client_version != ss->clientHelloVersion) {
                 /* Version roll-back detected. ensure failure.  */
                 rv = PK11_GenerateRandom(rsaPmsBuf, sizeof rsaPmsBuf);
             }
         }
         /* have PMS, build MS without PKCS11 */
         rv = ssl3_MasterSecretDeriveBypass(pwSpec, cr, sr, &pmsItem, isTLS,
-                                           PR_TRUE);
+                                           ssl3_GetTls12HashType(ss), PR_TRUE);
         if (rv != SECSuccess) {
             pwSpec->msItem.data = pwSpec->raw_master_secret;
             pwSpec->msItem.len = SSL3_MASTER_SECRET_LENGTH;
             PK11_GenerateRandom(pwSpec->msItem.data, pwSpec->msItem.len);
         }
         rv = ssl3_InitPendingCipherSpec(ss, NULL);
     } else
 #endif
@@ -10649,18 +10728,17 @@ ssl3_HandleClientKeyExchange(sslSocket *
         PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CLIENT_KEY_EXCH);
         return SECFailure;
     }
 
     kea_def = ss->ssl3.hs.kea_def;
 
     if (ss->ssl3.hs.usedStepDownKey) {
         PORT_Assert(kea_def->is_limited /* XXX OR cert is signing only */
-                    && kea_def->authKeyType == ssl_auth_rsa_sign
-                    && ss->stepDownKeyPair != NULL);
+                    && kea_def->authKeyType == ssl_auth_rsa_sign && ss->stepDownKeyPair != NULL);
         if (!kea_def->is_limited ||
             kea_def->authKeyType != ssl_auth_rsa_sign ||
             ss->stepDownKeyPair == NULL) {
             /* shouldn't happen, don't use step down if it does */
             goto skip;
         }
         serverKeyPair = ss->stepDownKeyPair;
         ss->sec.keaKeyBits = EXPORT_RSA_KEY_LENGTH * BPB;
@@ -10668,27 +10746,24 @@ ssl3_HandleClientKeyExchange(sslSocket *
     skip:
     if (kea_def->ephemeral) {
         if (kea_def->exchKeyType == ssl_kea_dh && ss->dheKeyPair) {
             serverKeyPair = ss->dheKeyPair;
             if (serverKeyPair->pubKey) {
                 ss->sec.keaKeyBits =
                     SECKEY_PublicKeyStrengthInBits(serverKeyPair->pubKey);
             }
-        }
-#ifndef NSS_DISABLE_ECC
-        else if (kea_def->exchKeyType == ssl_kea_ecdh &&
-                 ss->ephemeralECDHKeyPair) {
+        } else if (kea_def->exchKeyType == ssl_kea_ecdh &&
+                   ss->ephemeralECDHKeyPair) {
             serverKeyPair = ss->ephemeralECDHKeyPair;
             if (serverKeyPair->pubKey) {
                 ss->sec.keaKeyBits =
-                        SECKEY_PublicKeyStrengthInBits(serverKeyPair->pubKey);
-            }
-        }
-#endif
+                    SECKEY_PublicKeyStrengthInBits(serverKeyPair->pubKey);
+            }
+        }
     } else {
         serverKeyPair = ss->sec.serverCert->serverKeyPair;
         ss->sec.keaKeyBits = ss->sec.serverCert->serverKeyBits;
     }
 
     if (serverKeyPair) {
         serverKey = serverKeyPair->privKey;
     }
@@ -10721,17 +10796,16 @@ ssl3_HandleClientKeyExchange(sslSocket *
             rv = ssl3_HandleDHClientKeyExchange(ss, b, length,
                                                 serverPubKey, serverKey);
             if (rv != SECSuccess) {
                 SSL3_SendAlert(ss, alert_fatal, handshake_failure);
                 return SECFailure; /* error code set */
             }
             break;
 
-#ifndef NSS_DISABLE_ECC
         case ssl_kea_ecdh:
             if (serverKeyPair) {
                 serverPubKey = serverKeyPair->pubKey;
             }
             if (serverPubKey == NULL) {
                 /* XXX Is this the right error code? */
                 PORT_SetError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE);
                 return SECFailure;
@@ -10741,17 +10815,16 @@ ssl3_HandleClientKeyExchange(sslSocket *
             if (ss->ephemeralECDHKeyPair) {
                 ssl3_FreeKeyPair(ss->ephemeralECDHKeyPair);
                 ss->ephemeralECDHKeyPair = NULL;
             }
             if (rv != SECSuccess) {
                 return SECFailure; /* error code set */
             }
             break;
-#endif /* NSS_DISABLE_ECC */
 
         default:
             (void)ssl3_HandshakeFailure(ss);
             PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
             return SECFailure;
     }
     ss->ssl3.hs.ws = ss->sec.peerCert ? wait_cert_verify : wait_change_cipher;
     return SECSuccess;
@@ -11364,21 +11437,16 @@ ssl3_AuthCertificate(sslSocket *ss)
             }
         }
 
         if (rv == SECWouldBlock) {
             if (ss->sec.isServer) {
                 errCode = SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SERVERS;
                 goto loser;
             }
-            /* TODO(ekr@rtfm.com): Reenable for TLS 1.3 */
-            if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
-                errCode = SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_VERSION;
-                goto loser;
-            }
 
             ss->ssl3.hs.authCertificatePending = PR_TRUE;
             rv = SECSuccess;
         }
 
         if (rv != SECSuccess) {
             ssl3_SendAlertForCertError(ss, errCode);
             goto loser;
@@ -11576,40 +11644,40 @@ ssl3_AuthCertificateComplete(sslSocket *
 done:
     ssl_ReleaseSSL3HandshakeLock(ss);
     ssl_ReleaseRecvBufLock(ss);
 
     return rv;
 }
 
 static SECStatus
-ssl3_ComputeTLSFinished(ssl3CipherSpec *spec,
+ssl3_ComputeTLSFinished(sslSocket *ss, ssl3CipherSpec *spec,
                         PRBool isServer,
                         const SSL3Hashes *hashes,
                         TLSFinished *tlsFinished)
 {
     SECStatus rv;
     CK_TLS_MAC_PARAMS tls_mac_params;
     SECItem param = { siBuffer, NULL, 0 };
     PK11Context *prf_context;
     unsigned int retLen;
 
     if (!spec->master_secret || spec->bypassCiphers) {
         const char *label = isServer ? "server finished" : "client finished";
         unsigned int len = 15;
-
+        HASH_HashType hashType = ssl3_GetTls12HashType(ss);
         return ssl3_TLSPRFWithMasterSecret(spec, label, len, hashes->u.raw,
                                            hashes->len, tlsFinished->verify_data,
-                                           sizeof tlsFinished->verify_data);
+                                           sizeof tlsFinished->verify_data, hashType);
     }
 
     if (spec->version < SSL_LIBRARY_VERSION_TLS_1_2) {
         tls_mac_params.prfMechanism = CKM_TLS_PRF;
     } else {
-        tls_mac_params.prfMechanism = CKM_SHA256;
+        tls_mac_params.prfMechanism = ssl3_GetTls12PrfHashMechanism(ss);
     }
     tls_mac_params.ulMacLength = 12;
     tls_mac_params.ulServerOrClient = isServer ? 1 : 2;
     param.data = (unsigned char *)&tls_mac_params;
     param.len = sizeof(tls_mac_params);
     prf_context = PK11_CreateContextBySymKey(CKM_TLS_MAC, CKA_SIGN,
                                              spec->master_secret, &param);
     if (!prf_context)
@@ -11628,17 +11696,17 @@ ssl3_ComputeTLSFinished(ssl3CipherSpec *
 
 /* The calling function must acquire and release the appropriate
  * lock (e.g., ssl_GetSpecReadLock / ssl_ReleaseSpecReadLock for
  * ss->ssl3.crSpec).
  */
 SECStatus
 ssl3_TLSPRFWithMasterSecret(ssl3CipherSpec *spec, const char *label,
                             unsigned int labelLen, const unsigned char *val, unsigned int valLen,
-                            unsigned char *out, unsigned int outLen)
+                            unsigned char *out, unsigned int outLen, HASH_HashType tls12HashType)
 {
     SECStatus rv = SECSuccess;
 
     if (spec->master_secret && !spec->bypassCiphers) {
         SECItem param = { siBuffer, NULL, 0 };
         CK_MECHANISM_TYPE mech = CKM_TLS_PRF_GENERAL;
         PK11Context *prf_context;
         unsigned int retLen;
@@ -11669,17 +11737,17 @@ ssl3_TLSPRFWithMasterSecret(ssl3CipherSp
         SECItem outData = { siBuffer };
         PRBool isFIPS = PR_FALSE;
 
         inData.data = (unsigned char *)val;
         inData.len = valLen;
         outData.data = out;
         outData.len = outLen;
         if (spec->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
-            rv = TLS_P_hash(HASH_AlgSHA256, &spec->msItem, label, &inData,
+            rv = TLS_P_hash(tls12HashType, &spec->msItem, label, &inData,
                             &outData, isFIPS);
         } else {
             rv = TLS_PRF(&spec->msItem, label, &inData, &outData, isFIPS);
         }
         PORT_Assert(rv != SECSuccess || outData.len == outLen);
 #endif
     }
     return rv;
@@ -11804,17 +11872,17 @@ ssl3_SendFinished(sslSocket *ss, PRInt32
     PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
     ssl_GetSpecReadLock(ss);
     cwSpec = ss->ssl3.cwSpec;
     isTLS = (PRBool)(cwSpec->version > SSL_LIBRARY_VERSION_3_0);
     rv = ssl3_ComputeHandshakeHashes(ss, cwSpec, &hashes, sender);
     if (isTLS && rv == SECSuccess) {
-        rv = ssl3_ComputeTLSFinished(cwSpec, isServer, &hashes, &tlsFinished);
+        rv = ssl3_ComputeTLSFinished(ss, cwSpec, isServer, &hashes, &tlsFinished);
     }
     ssl_ReleaseSpecReadLock(ss);
     if (rv != SECSuccess) {
         goto fail; /* err code was set by ssl3_ComputeHandshakeHashes */
     }
 
     if (isTLS) {
         if (isServer)
@@ -11975,17 +12043,17 @@ ssl3_HandleFinished(sslSocket *ss, SSL3O
     if (isTLS) {
         TLSFinished tlsFinished;
 
         if (length != sizeof tlsFinished) {
             (void)SSL3_SendAlert(ss, alert_fatal, decode_error);
             PORT_SetError(SSL_ERROR_RX_MALFORMED_FINISHED);
             return SECFailure;
         }
-        rv = ssl3_ComputeTLSFinished(ss->ssl3.crSpec, !isServer,
+        rv = ssl3_ComputeTLSFinished(ss, ss->ssl3.crSpec, !isServer,
                                      hashes, &tlsFinished);
         if (!isServer)
             ss->ssl3.hs.finishedMsgs.tFinished[1] = tlsFinished;
         else
             ss->ssl3.hs.finishedMsgs.tFinished[0] = tlsFinished;
         ss->ssl3.hs.finishedBytes = sizeof tlsFinished;
         if (rv != SECSuccess ||
             0 != NSS_SecureMemcmp(&tlsFinished, b, length)) {
@@ -12101,23 +12169,20 @@ xmit_loser:
 
 SECStatus
 ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid)
 {
     SECStatus rv;
 
     /* fill in the sid */
     sid->u.ssl3.cipherSuite =
-            ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 ?
-            ss->ssl3.hs.origCipherSuite : ss->ssl3.hs.cipher_suite;
+        ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 ? ss->ssl3.hs.origCipherSuite : ss->ssl3.hs.cipher_suite;
     sid->u.ssl3.compression = ss->ssl3.hs.compression;
     sid->u.ssl3.policy = ss->ssl3.policy;
-#ifndef NSS_DISABLE_ECC
     sid->u.ssl3.negotiatedECCurves = ss->ssl3.hs.negotiatedECCurves;
-#endif
     sid->version = ss->version;
     sid->authType = ss->sec.authType;
     sid->authKeyBits = ss->sec.authKeyBits;
     sid->keaType = ss->sec.keaType;
     sid->keaKeyBits = ss->sec.keaKeyBits;
     sid->lastAccessTime = sid->creationTime = ssl_Time();
     sid->expirationTime = sid->creationTime + ssl3_sid_timeout;
     sid->localCert = CERT_DupCertificate(ss->sec.localCert);
@@ -12127,17 +12192,17 @@ ssl3_FillInCachedSID(sslSocket *ss, sslS
         sid->certType.authType = ssl_auth_null;
     }
 
     ssl_GetSpecReadLock(ss); /*************************************/
 
     /* Copy the master secret (wrapped or unwrapped) into the sid */
     if (ss->ssl3.crSpec->msItem.len && ss->ssl3.crSpec->msItem.data) {
         sid->u.ssl3.keys.wrapped_master_secret_len =
-                ss->ssl3.crSpec->msItem.len;
+            ss->ssl3.crSpec->msItem.len;
         memcpy(sid->u.ssl3.keys.wrapped_master_secret,
                ss->ssl3.crSpec->msItem.data, ss->ssl3.crSpec->msItem.len);
         sid->u.ssl3.masterValid = PR_TRUE;
         sid->u.ssl3.keys.msIsWrapped = PR_FALSE;
         rv = SECSuccess;
     } else {
         rv = ssl3_CacheWrappedMasterSecret(ss, ss->sec.ci.sid,
                                            ss->ssl3.crSpec,
@@ -12196,25 +12261,27 @@ ssl3_FinishHandshake(sslSocket *ss)
     return SECSuccess;
 }
 
 /* Called from ssl3_HandleHandshake() when it has gathered a complete ssl3
  * hanshake message.
  * Caller must hold Handshake and RecvBuf locks.
  */
 SECStatus
-ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
+ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, PRUint32 length,
+                            PRBool endOfRecord)
 {
     SECStatus rv = SECSuccess;
     SSL3HandshakeType type = ss->ssl3.hs.msg_type;
-    SSL3Hashes hashes; /* computed hashes are put here. */
+    SSL3Hashes hashes;            /* computed hashes are put here. */
     SSL3Hashes *hashesPtr = NULL; /* Set when hashes are computed */
     PRUint8 hdr[4];
     PRUint8 dtlsData[8];
     PRBool computeHashes = PR_FALSE;
+    PRUint16 epoch;
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
     /*
      * We have to compute the hashes before we update them with the
      * current message.
      */
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
@@ -12316,16 +12383,17 @@ ssl3_HandleHandshakeMessage(sslSocket *s
          */
         rv = ssl3_AuthCertificate(ss); /* sets ss->ssl3.hs.ws */
         PORT_Assert(rv != SECWouldBlock);
         if (rv != SECSuccess) {
             return rv;
         }
     }
 
+    epoch = ss->ssl3.crSpec->epoch;
     switch (ss->ssl3.hs.msg_type) {
         case client_hello:
             if (!ss->sec.isServer) {
                 (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
                 PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CLIENT_HELLO);
                 return SECFailure;
             }
             rv = ssl3_HandleClientHello(ss, b, length);
@@ -12342,16 +12410,24 @@ ssl3_HandleHandshakeMessage(sslSocket *s
             if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
                 rv = ssl3_HandlePostHelloHandshakeMessage(ss, b, length, hashesPtr);
             } else {
                 rv = tls13_HandlePostHelloHandshakeMessage(ss, b, length,
                                                            hashesPtr);
             }
             break;
     }
+    if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 &&
+        (epoch != ss->ssl3.crSpec->epoch) && !endOfRecord) {
+        /* If we changed read cipher states, there must not be any
+         * data in the input queue. */
+        (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
+        PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE);
+        return SECFailure;
+    }
 
     if (IS_DTLS(ss) && (rv != SECFailure)) {
         /* Increment the expected sequence number */
         ss->ssl3.hs.recvMessageSeq++;
     }
     return rv;
 }
 
@@ -12508,17 +12584,18 @@ ssl3_HandleHandshake(sslSocket *ss, sslB
 
         /*
          * Header has been gathered and there is at least one byte of new
          * data available for this message. If it can be done right out
          * of the original buffer, then use it from there.
          */
         if (ss->ssl3.hs.msg_body.len == 0 && buf->len >= ss->ssl3.hs.msg_len) {
             /* handle it f