Bug 1283376 - Land NSS_3_26_BETA1 r=franziskus
authorTim Taubert <ttaubert@mozilla.com>
Thu, 30 Jun 2016 08:42:30 +0200
changeset 303181 09592e523356e034cfbe03792bf811a7d4efaef5
parent 303180 7a133276156418748a88108224886d00e471ae58
child 303182 06f5fb5ff50017a848bd1993e2725eab24fc772a
push id79009
push userttaubert@mozilla.com
push dateThu, 30 Jun 2016 06:48:12 +0000
treeherdermozilla-inbound@06f5fb5ff500 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfranziskus
bugs1283376
milestone50.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 1283376 - Land NSS_3_26_BETA1 r=franziskus
old-configure.in
security/nss/.taskcluster.yml
security/nss/TAG-INFO
security/nss/automation/taskcluster/docker/Dockerfile
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-lsan.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/memleak.yml
security/nss/automation/taskcluster/graph/tests/ssl.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/build64-debug.yml
security/nss/automation/taskcluster/graph/windows/build64-opt.yml
security/nss/automation/taskcluster/scripts/build.sh
security/nss/automation/taskcluster/scripts/run_clang_format.sh
security/nss/automation/taskcluster/scripts/run_tests.sh
security/nss/automation/taskcluster/scripts/tools.sh
security/nss/cmd/bltest/blapitest.c
security/nss/cmd/certcgi/certcgi.c
security/nss/cmd/certutil/certext.c
security/nss/cmd/certutil/certutil.c
security/nss/cmd/crlutil/crlgen.c
security/nss/cmd/crlutil/crlutil.c
security/nss/cmd/ecperf/ecperf.c
security/nss/cmd/lib/secutil.c
security/nss/cmd/manifest.mn
security/nss/cmd/pk11mode/pk11mode.c
security/nss/cmd/pk12util/pk12util.c
security/nss/cmd/platlibs.mk
security/nss/cmd/smimetools/cmsutil.c
security/nss/coreconf/config.mk
security/nss/coreconf/coreconf.dep
security/nss/coreconf/mkdepend/parse.c
security/nss/coreconf/nsinstall/pathsub.c
security/nss/coreconf/sanitizers.mk
security/nss/external_tests/ssl_gtest/libssl_internals.c
security/nss/external_tests/ssl_gtest/libssl_internals.h
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_loopback_unittest.cc
security/nss/external_tests/ssl_gtest/test_io.cc
security/nss/external_tests/ssl_gtest/test_io.h
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_hkdf_unittest.cc
security/nss/lib/Makefile
security/nss/lib/certdb/certxutl.c
security/nss/lib/certhigh/certvfy.c
security/nss/lib/certhigh/certvfypkix.c
security/nss/lib/crmf/servget.c
security/nss/lib/freebl/ecl/Makefile
security/nss/lib/freebl/ecl/README
security/nss/lib/freebl/fipsfreebl.c
security/nss/lib/freebl/intel-gcm-wrap.c
security/nss/lib/freebl/pqg.c
security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_aiamgr.c
security/nss/lib/manifest.mn
security/nss/lib/nss/config.mk
security/nss/lib/nss/nss.h
security/nss/lib/nss/nssinit.c
security/nss/lib/pk11wrap/pk11akey.c
security/nss/lib/pk11wrap/pk11cert.c
security/nss/lib/pk11wrap/pk11obj.c
security/nss/lib/pk11wrap/pk11skey.c
security/nss/lib/pk11wrap/pk11slot.c
security/nss/lib/pkcs12/p12d.c
security/nss/lib/pki/pki3hack.c
security/nss/lib/smime/cmsdecode.c
security/nss/lib/softoken/legacydb/dbmshim.c
security/nss/lib/softoken/legacydb/lgattr.c
security/nss/lib/softoken/legacydb/pcertdb.c
security/nss/lib/softoken/pkcs11u.c
security/nss/lib/softoken/softkver.h
security/nss/lib/ssl/Makefile
security/nss/lib/ssl/SSLerrs.h
security/nss/lib/ssl/ssl.h
security/nss/lib/ssl/ssl3con.c
security/nss/lib/ssl/ssl3ecc.c
security/nss/lib/ssl/ssl3ext.c
security/nss/lib/ssl/ssl3prot.h
security/nss/lib/ssl/sslcert.c
security/nss/lib/ssl/sslerr.h
security/nss/lib/ssl/sslimpl.h
security/nss/lib/ssl/sslinfo.c
security/nss/lib/ssl/sslmutex.c
security/nss/lib/ssl/sslnonce.c
security/nss/lib/ssl/sslsecur.c
security/nss/lib/ssl/sslsock.c
security/nss/lib/ssl/sslt.h
security/nss/lib/ssl/tls13con.c
security/nss/lib/ssl/tls13con.h
security/nss/lib/ssl/tls13hkdf.c
security/nss/lib/util/nssutil.h
security/nss/tests/all.sh
security/nss/tests/chains/chains.sh
security/nss/tests/common/cleanup.sh
security/nss/tests/common/init.sh
security/nss/tests/memleak/memleak.sh
security/nss/tests/ssl/ssl.sh
security/nss/tests/ssl/sslauth.txt
security/nss/tests/ssl/sslstress.txt
--- a/old-configure.in
+++ b/old-configure.in
@@ -2452,17 +2452,17 @@ dnl = If NSS was not detected in the sys
 dnl = use the one in the source tree (mozilla/security/nss)
 dnl ========================================================
 
 MOZ_ARG_WITH_BOOL(system-nss,
 [  --with-system-nss       Use system installed NSS],
     _USE_SYSTEM_NSS=1 )
 
 if test -n "$_USE_SYSTEM_NSS"; then
-    AM_PATH_NSS(3.25, [MOZ_SYSTEM_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
+    AM_PATH_NSS(3.26, [MOZ_SYSTEM_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
 fi
 
 if test -n "$MOZ_SYSTEM_NSS"; then
    NSS_LIBS="$NSS_LIBS -lcrmf"
 else
    NSS_CFLAGS="-I${DIST}/include/nss"
 fi
 
--- a/security/nss/.taskcluster.yml
+++ b/security/nss/.taskcluster.yml
@@ -47,35 +47,27 @@ tasks:
             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}}"
+        - "tc-treeherder-stage.v2.{{project}}.{{revision}}.{{pushlog_id}}"
+        - "tc-treeherder.v2.{{project}}.{{revision}}.{{pushlog_id}}"
 
       payload:
-        image: "ttaubert/nss-ci:0.0.16"
+        image: "ttaubert/nss-ci:0.0.17"
 
         env:
           TC_OWNER: {{owner}}
           TC_SOURCE: {{{source}}}
-          TC_REVISION: '{{revision}}'
-          TC_REVISION_HASH: '{{revision_hash}}'
+          NSS_PUSHLOG_ID: '{{pushlog_id}}'
           NSS_HEAD_REPOSITORY: '{{{url}}}'
           NSS_HEAD_REVISION: '{{revision}}'
 
         maxRunTime: 1800
 
         command:
           - bash
           - -cx
@@ -90,14 +82,12 @@ tasks:
             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
           machine:
             platform: nss-decision
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-NSS_3_25_RC1
+NSS_3.26_BETA1
--- a/security/nss/automation/taskcluster/docker/Dockerfile
+++ b/security/nss/automation/taskcluster/docker/Dockerfile
@@ -1,27 +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.
+# Install dependencies.
+ADD setup.sh /tmp/setup.sh
+RUN bash /tmp/setup.sh
+
+# Env variables.
 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
+ENV HOST localhost
+ENV DOMSUF localdomain
 
 # Set a default command for debugging.
 CMD ["/bin/bash", "--login"]
--- a/security/nss/automation/taskcluster/docker/setup.sh
+++ b/security/nss/automation/taskcluster/docker/setup.sh
@@ -17,22 +17,16 @@ 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')
@@ -43,19 +37,22 @@ echo "deb http://ppa.launchpad.net/ubunt
 
 # 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
 
+# Install clang-3.8 into /usr/local/.
+curl http://llvm.org/releases/3.8.0/clang+llvm-3.8.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz | tar xJv -C /usr/local --strip-components=1
+
 # 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/local/bin/clang 5
+update-alternatives --install /usr/bin/g++ g++ /usr/local/bin/clang++ 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
--- a/security/nss/automation/taskcluster/graph/build.js
+++ b/security/nss/automation/taskcluster/graph/build.js
@@ -5,20 +5,19 @@
 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_PUSHLOG_ID = process.env.NSS_PUSHLOG_ID || "{{nss_pushlog_id}}";
 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",
@@ -60,27 +59,20 @@ function parseYamlFile(file, fallback) {
   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
+    "tc-treeherder-stage.v2.nss." + NSS_HEAD_REVISION + "." + NSS_PUSHLOG_ID,
+    "tc-treeherder.v2.nss." + NSS_HEAD_REVISION + "." + NSS_PUSHLOG_ID
   ];
 }
 
 // Generate all tasks for a given build.
 function generateBuildTasks(platform, file) {
   var dir = path.join(__dirname, "./" + platform);
 
   // Parse base definitions.
--- a/security/nss/automation/taskcluster/graph/linux/_build_base.yml
+++ b/security/nss/automation/taskcluster/graph/linux/_build_base.yml
@@ -9,17 +9,17 @@ task:
   schedulerId: task-graph-scheduler
 
   metadata:
     owner: !env TC_OWNER
     source: !env TC_SOURCE
 
   payload:
     maxRunTime: 3600
-    image: ttaubert/nss-ci:0.0.16
+    image: ttaubert/nss-ci:0.0.17
 
     artifacts:
       public:
         type: directory
         path: /home/worker/artifacts
         expires: !from_now 24
 
     command:
@@ -30,11 +30,9 @@ task:
     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
--- a/security/nss/automation/taskcluster/graph/linux/_test_base.yml
+++ b/security/nss/automation/taskcluster/graph/linux/_test_base.yml
@@ -9,14 +9,14 @@ task:
   schedulerId: task-graph-scheduler
 
   metadata:
     owner: !env TC_OWNER
     source: !env TC_SOURCE
 
   payload:
     maxRunTime: 3600
-    image: ttaubert/nss-ci:0.0.16
+    image: ttaubert/nss-ci:0.0.17
 
     command:
       - "/bin/bash"
       - "-c"
       - "bin/checkout.sh && nss/automation/taskcluster/scripts/run_tests.sh"
--- a/security/nss/automation/taskcluster/graph/linux/build32-debug.yml
+++ b/security/nss/automation/taskcluster/graph/linux/build32-debug.yml
@@ -27,52 +27,46 @@
     - gtests
     - lowhash
     - merge
     - ocsp
     - pkits
     - pkix
     - sdr
     - smime
+    - ssl
     - 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
         machine:
           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
+        GCC_VERSION: clang
+        GXX_VERSION: clang++
 
     extra:
       treeherder:
         build:
           platform: linux32
         machine:
           platform: linux32
         collection:
--- a/security/nss/automation/taskcluster/graph/linux/build32-opt.yml
+++ b/security/nss/automation/taskcluster/graph/linux/build32-opt.yml
@@ -28,53 +28,50 @@
     - gtests
     - lowhash
     - merge
     - ocsp
     - pkits
     - pkix
     - sdr
     - smime
+    - ssl
     - 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
         machine:
           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
+        GCC_VERSION: clang
+        GXX_VERSION: clang++
         BUILD_OPT: 1
 
     extra:
       treeherder:
         build:
           platform: linux32
         machine:
           platform: linux32
--- a/security/nss/automation/taskcluster/graph/linux/build64-asan.yml
+++ b/security/nss/automation/taskcluster/graph/linux/build64-asan.yml
@@ -1,19 +1,19 @@
 ---
 - task:
     metadata:
       name: "Linux 64 (ASan, debug)"
       description: "Linux 64 (ASan, debug)"
 
     payload:
       env:
+        GCC_VERSION: clang
+        GXX_VERSION: clang++
         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
         machine:
@@ -31,36 +31,10 @@
     - gtests
     - lowhash
     - merge
     - ocsp
     - pkits
     - pkix
     - sdr
     - smime
+    - ssl
     - 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
-        machine:
-          platform: linux64
-        collection:
-          asan: true
-        groupSymbol: SSL
-        groupName: SSL tests
-
-  tests:
-    - ssl
--- a/security/nss/automation/taskcluster/graph/linux/build64-debug.yml
+++ b/security/nss/automation/taskcluster/graph/linux/build64-debug.yml
@@ -22,59 +22,57 @@
     - chains
     - cipher
     - crmf
     - db
     - ec
     - fips
     - gtests
     - lowhash
+    - memleak
     - merge
     - ocsp
     - pkits
     - pkix
     - sdr
     - smime
+    - ssl
     - 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
         machine:
           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
+        GCC_VERSION: clang
+        GXX_VERSION: clang++
         USE_64: 1
 
     extra:
       treeherder:
         build:
           platform: linux64
         machine:
           platform: linux64
@@ -149,8 +147,31 @@
           platform: linux64
         machine:
           platform: linux64
         collection:
           debug: true
         groupSymbol: Builds
         groupName: Various builds
         symbol: noPkcs11Bypass
+
+- task:
+    metadata:
+      name: "Linux 64 (debug, NSS_DISABLE_LIBPKIX=1)"
+      description: "Linux 64 (debug, NSS_DISABLE_LIBPKIX=1)"
+
+    payload:
+      env:
+        NSS_ENABLE_TLS_1_3: 1
+        NSS_DISABLE_LIBPKIX: 1
+        USE_64: 1
+
+    extra:
+      treeherder:
+        build:
+          platform: linux64
+        machine:
+          platform: linux64
+        collection:
+          debug: true
+        groupSymbol: Builds
+        groupName: Various builds
+        symbol: noLibpkix
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/linux/build64-lsan.yml
@@ -0,0 +1,35 @@
+---
+- task:
+    metadata:
+      name: "Linux 64 (LSan, debug)"
+      description: "Linux 64 (LSan, debug)"
+
+    payload:
+      env:
+        GCC_VERSION: clang
+        GXX_VERSION: clang++
+        NSS_DISABLE_ARENA_FREE_LIST: 1
+        NSS_DISABLE_UNLOAD: 1
+        NSS_ENABLE_TLS_1_3: 1
+        NSS_ENABLE_LSAN: 1
+        USE_ASAN: 1
+        USE_64: 1
+
+    extra:
+      treeherder:
+        build:
+          platform: linux64
+        machine:
+          platform: linux64
+        collection:
+          lsan: true
+
+  tests:
+    - cipher
+    - ec
+    - gtests
+    - lowhash
+    - merge
+    - ocsp
+    - pkits
+    - sdr
deleted file mode 100644
--- a/security/nss/automation/taskcluster/graph/linux/build64-memleak.yml
+++ /dev/null
@@ -1,22 +0,0 @@
----
-- 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
-        machine:
-          platform: linux64
-        collection:
-          memleak: true
-
-  tests:
-    - memleak
--- a/security/nss/automation/taskcluster/graph/linux/build64-opt.yml
+++ b/security/nss/automation/taskcluster/graph/linux/build64-opt.yml
@@ -29,54 +29,51 @@
     - gtests
     - lowhash
     - merge
     - ocsp
     - pkits
     - pkix
     - sdr
     - smime
+    - ssl
     - 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
         machine:
           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
+        GCC_VERSION: clang
+        GXX_VERSION: clang++
         BUILD_OPT: 1
         USE_64: 1
 
     extra:
       treeherder:
         build:
           platform: linux64
         machine:
--- a/security/nss/automation/taskcluster/graph/tests/memleak.yml
+++ b/security/nss/automation/taskcluster/graph/tests/memleak.yml
@@ -2,204 +2,243 @@
 - task:
     metadata:
       name: "MemLeak tests (ocsp)"
       description: "MemLeak tests (ocsp)"
 
     payload:
       env:
         NSS_MEMLEAK_TESTS: ocsp
+        NSS_TESTS: memleak
 
     extra:
       treeherder:
         symbol: ocsp
+        collection:
+          memleak: true
 
 - task:
     metadata:
       name: "MemLeak tests (ssl_server, standard)"
       description: "MemLeak tests (ssl_server, standard)"
 
     payload:
       env:
-        NSS_MEMLEAK_TESTS: "ssl_server"
-        NSS_CYCLES: "standard"
+        NSS_MEMLEAK_TESTS: ssl_server
+        NSS_CYCLES: standard
+        NSS_TESTS: memleak
 
     extra:
       treeherder:
         groupSymbol: Server
         groupName: MemLeak tests (ssl_server)
         symbol: standard
+        collection:
+          memleak: true
 
 - task:
     metadata:
       name: "MemLeak tests (ssl_server, pkix)"
       description: "MemLeak tests (ssl_server, pkix)"
 
     payload:
       env:
-        NSS_MEMLEAK_TESTS: "ssl_server"
-        NSS_CYCLES: "pkix"
+        NSS_MEMLEAK_TESTS: ssl_server
+        NSS_CYCLES: pkix
+        NSS_TESTS: memleak
 
     extra:
       treeherder:
         groupSymbol: Server
         groupName: MemLeak tests (ssl_server)
         symbol: pkix
+        collection:
+          memleak: true
 
 - task:
     metadata:
       name: "MemLeak tests (ssl_server, sharedb)"
       description: "MemLeak tests (ssl_server, sharedb)"
 
     payload:
       env:
-        NSS_MEMLEAK_TESTS: "ssl_server"
-        NSS_CYCLES: "sharedb"
+        NSS_MEMLEAK_TESTS: ssl_server
+        NSS_CYCLES: sharedb
+        NSS_TESTS: memleak
 
     extra:
       treeherder:
         groupSymbol: Server
         groupName: MemLeak tests (ssl_server)
         symbol: sharedb
+        collection:
+          memleak: true
 
 - task:
     metadata:
       name: "MemLeak tests (ssl_server, upgradedb)"
       description: "MemLeak tests (ssl_server, upgradedb)"
 
     payload:
       env:
-        NSS_MEMLEAK_TESTS: "ssl_server"
-        NSS_CYCLES: "upgradedb"
+        NSS_MEMLEAK_TESTS: ssl_server
+        NSS_CYCLES: upgradedb
+        NSS_TESTS: memleak
 
     extra:
       treeherder:
         groupSymbol: Server
         groupName: MemLeak tests (ssl_server)
         symbol: upgradedb
+        collection:
+          memleak: true
 
 - task:
     metadata:
       name: "MemLeak tests (ssl_client, standard)"
       description: "MemLeak tests (ssl_client, standard)"
 
     payload:
       env:
-        NSS_MEMLEAK_TESTS: "ssl_client"
-        NSS_CYCLES: "standard"
+        NSS_MEMLEAK_TESTS: ssl_client
+        NSS_CYCLES: standard
+        NSS_TESTS: memleak
 
     extra:
       treeherder:
         groupSymbol: Client
         groupName: MemLeak tests (ssl_client)
         symbol: standard
+        collection:
+          memleak: true
 
 - task:
     metadata:
       name: "MemLeak tests (ssl_client, pkix)"
       description: "MemLeak tests (ssl_client, pkix)"
 
     payload:
       env:
-        NSS_MEMLEAK_TESTS: "ssl_client"
-        NSS_CYCLES: "pkix"
+        NSS_MEMLEAK_TESTS: ssl_client
+        NSS_TESTS: memleak
+        NSS_CYCLES: pkix
 
     extra:
       treeherder:
         groupSymbol: Client
         groupName: MemLeak tests (ssl_client)
         symbol: pkix
+        collection:
+          memleak: true
 
 - task:
     metadata:
       name: "MemLeak tests (ssl_client, sharedb)"
       description: "MemLeak tests (ssl_client, sharedb)"
 
     payload:
       env:
-        NSS_MEMLEAK_TESTS: "ssl_client"
-        NSS_CYCLES: "sharedb"
+        NSS_MEMLEAK_TESTS: ssl_client
+        NSS_CYCLES: sharedb
+        NSS_TESTS: memleak
 
     extra:
       treeherder:
         groupSymbol: Client
         groupName: MemLeak tests (ssl_client)
         symbol: sharedb
+        collection:
+          memleak: true
 
 - task:
     metadata:
       name: "MemLeak tests (ssl_client, upgradedb)"
       description: "MemLeak tests (ssl_client, upgradedb)"
 
     payload:
       env:
-        NSS_MEMLEAK_TESTS: "ssl_client"
-        NSS_CYCLES: "upgradedb"
+        NSS_MEMLEAK_TESTS: ssl_client
+        NSS_CYCLES: upgradedb
+        NSS_TESTS: memleak
 
     extra:
       treeherder:
         groupSymbol: Client
         groupName: MemLeak tests (ssl_client)
         symbol: upgradedb
+        collection:
+          memleak: true
 
 - task:
     metadata:
       name: "MemLeak tests (chains, standard)"
       description: "MemLeak tests (chains, standard)"
 
     payload:
       env:
-        NSS_MEMLEAK_TESTS: "chains"
-        NSS_CYCLES: "standard"
+        NSS_MEMLEAK_TESTS: chains
+        NSS_CYCLES: standard
+        NSS_TESTS: memleak
 
     extra:
       treeherder:
         groupSymbol: Chains
         groupName: MemLeak tests (chains)
         symbol: standard
+        collection:
+          memleak: true
 
 - task:
     metadata:
       name: "MemLeak tests (chains, pkix)"
       description: "MemLeak tests (chains, pkix)"
 
     payload:
       env:
-        NSS_MEMLEAK_TESTS: "chains"
-        NSS_CYCLES: "pkix"
+        NSS_MEMLEAK_TESTS: chains
+        NSS_TESTS: memleak
+        NSS_CYCLES: pkix
 
     extra:
       treeherder:
         groupSymbol: Chains
         groupName: MemLeak tests (chains)
         symbol: pkix
+        collection:
+          memleak: true
 
 - task:
     metadata:
       name: "MemLeak tests (chains, sharedb)"
       description: "MemLeak tests (chains, sharedb)"
 
     payload:
       env:
-        NSS_MEMLEAK_TESTS: "chains"
-        NSS_CYCLES: "sharedb"
+        NSS_MEMLEAK_TESTS: chains
+        NSS_CYCLES: sharedb
+        NSS_TESTS: memleak
 
     extra:
       treeherder:
         groupSymbol: Chains
         groupName: MemLeak tests (chains)
         symbol: sharedb
+        collection:
+          memleak: true
 
 - task:
     metadata:
       name: "MemLeak tests (chains, upgradedb)"
       description: "MemLeak tests (chains, upgradedb)"
 
     payload:
       env:
-        NSS_MEMLEAK_TESTS: "chains"
-        NSS_CYCLES: "upgradedb"
+        NSS_MEMLEAK_TESTS: chains
+        NSS_CYCLES: upgradedb
+        NSS_TESTS: memleak
 
     extra:
       treeherder:
         groupSymbol: Chains
         groupName: MemLeak tests (chains)
         symbol: upgradedb
+        collection:
+          memleak: true
--- a/security/nss/automation/taskcluster/graph/tests/ssl.yml
+++ b/security/nss/automation/taskcluster/graph/tests/ssl.yml
@@ -2,60 +2,64 @@
 - task:
     metadata:
       name: "SSL tests (standard)"
       description: "SSL tests (standard)"
 
     payload:
       maxRunTime: 7200
       env:
-        NSS_CYCLES: "standard"
+        NSS_CYCLES: standard
+        NSS_TESTS: ssl
 
     extra:
       treeherder:
         symbol: standard
         groupSymbol: SSL
         groupName: SSL tests
 
 - task:
     metadata:
       name: "SSL tests (pkix)"
       description: "SSL tests (pkix)"
 
     payload:
       env:
-        NSS_CYCLES: "pkix"
+        NSS_CYCLES: pkix
+        NSS_TESTS: ssl
 
     extra:
       treeherder:
         symbol: pkix
         groupSymbol: SSL
         groupName: SSL tests
 
 - task:
     metadata:
       name: "SSL tests (sharedb)"
       description: "SSL tests (sharedb)"
 
     payload:
       env:
-        NSS_CYCLES: "sharedb"
+        NSS_CYCLES: sharedb
+        NSS_TESTS: ssl
 
     extra:
       treeherder:
         symbol: sharedb
         groupSymbol: SSL
         groupName: SSL tests
 
 - task:
     metadata:
       name: "SSL tests (upgradedb)"
       description: "SSL tests (upgradedb)"
 
     payload:
       env:
-        NSS_CYCLES: "upgradedb"
+        NSS_CYCLES: upgradedb
+        NSS_TESTS: ssl
 
     extra:
       treeherder:
         symbol: upgradedb
         groupSymbol: SSL
         groupName: SSL tests
--- a/security/nss/automation/taskcluster/graph/tools/clang-format.yml
+++ b/security/nss/automation/taskcluster/graph/tools/clang-format.yml
@@ -10,17 +10,17 @@
     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
+      image: ttaubert/nss-ci:0.0.17
 
       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
@@ -28,10 +28,8 @@
 
     extra:
       treeherder:
         build:
           platform: nss-tools
         machine:
           platform: nss-tools
         symbol: clang-format-3.8
-        revision: !env TC_REVISION
-        revision_hash: !env TC_REVISION_HASH
--- a/security/nss/automation/taskcluster/graph/windows/_build_base.yml
+++ b/security/nss/automation/taskcluster/graph/windows/_build_base.yml
@@ -28,11 +28,9 @@ task:
       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
--- a/security/nss/automation/taskcluster/graph/windows/build64-debug.yml
+++ b/security/nss/automation/taskcluster/graph/windows/build64-debug.yml
@@ -28,8 +28,52 @@
     - lowhash
     - merge
     - ocsp
     - pkits
     - pkix
     - sdr
     - smime
     - tools
+
+- task:
+    metadata:
+      name: "Windows 2012 64 (debug, no TLS 1.3)"
+      description: "Windows 2012 64 (debug, no TLS 1.3)"
+
+    payload:
+      env:
+        USE_64: 1
+
+    extra:
+      treeherder:
+        build:
+          platform: windows2012-64
+        machine:
+          platform: windows2012-64
+        collection:
+          debug: true
+        groupSymbol: Builds
+        groupName: Various builds
+        symbol: noTLSv1.3
+
+- task:
+    metadata:
+      name: "Windows 2012 64 (debug, NO_PKCS11_BYPASS=1)"
+      description: "Windows 2012 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: windows2012-64
+        machine:
+          platform: windows2012-64
+        collection:
+          debug: true
+        groupSymbol: Builds
+        groupName: Various builds
+        symbol: noPkcs11Bypass
--- a/security/nss/automation/taskcluster/graph/windows/build64-opt.yml
+++ b/security/nss/automation/taskcluster/graph/windows/build64-opt.yml
@@ -29,8 +29,54 @@
     - lowhash
     - merge
     - ocsp
     - pkits
     - pkix
     - sdr
     - smime
     - tools
+
+- task:
+    metadata:
+      name: "Windows 2012 64 (opt, no TLS 1.3)"
+      description: "Windows 2012 64 (opt, no TLS 1.3)"
+
+    payload:
+      env:
+        BUILD_OPT: 1
+        USE_64: 1
+
+    extra:
+      treeherder:
+        build:
+          platform: windows2012-64
+        machine:
+          platform: windows2012-64
+        collection:
+          opt: true
+        groupSymbol: Builds
+        groupName: Various builds
+        symbol: noTLSv1.3
+
+- task:
+    metadata:
+      name: "Windows 2012 64 (opt, NO_PKCS11_BYPASS=1)"
+      description: "Windows 2012 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: windows2012-64
+        machine:
+          platform: windows2012-64
+        collection:
+          opt: true
+        groupSymbol: Builds
+        groupName: Various builds
+        symbol: noPkcs11Bypass
--- a/security/nss/automation/taskcluster/scripts/build.sh
+++ b/security/nss/automation/taskcluster/scripts/build.sh
@@ -1,33 +1,31 @@
 #!/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}
+    source $(dirname $0)/tools.sh
 
-    update-alternatives --set gcc "/usr/bin/$GCC"
-    update-alternatives --set g++ "/usr/bin/$GXX"
+    # Set compiler.
+    switch_compilers
 
     # 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
+cd nss && make nss_build_all && cd ..
 
 # Generate certificates.
-cd tests && NSS_TESTS=cert NSS_CYCLES="standard pkix sharedb" ./all.sh
+NSS_TESTS=cert NSS_CYCLES="standard pkix sharedb" $(dirname $0)/run_tests.sh
 
 # Reset test counter so that test runs pick up our certificates.
-cd && echo 1 > tests_results/security/localhost
+echo 1 > tests_results/security/localhost
 
 # Package.
 mkdir artifacts
 tar cvfjh artifacts/dist.tar.bz2 dist tests_results
--- a/security/nss/automation/taskcluster/scripts/run_clang_format.sh
+++ b/security/nss/automation/taskcluster/scripts/run_clang_format.sh
@@ -8,14 +8,14 @@ if [ $(id -u) = 0 ]; then
 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
+    if ! clang-format $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
--- a/security/nss/automation/taskcluster/scripts/run_tests.sh
+++ b/security/nss/automation/taskcluster/scripts/run_tests.sh
@@ -1,19 +1,17 @@
 #!/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}
+    source $(dirname $0)/tools.sh
 
-    update-alternatives --set gcc "/usr/bin/$GCC"
-    update-alternatives --set g++ "/usr/bin/$GXX"
+    # Set compiler.
+    switch_compilers
 
     # Stupid Docker.
     echo "127.0.0.1 localhost.localdomain" >> /etc/hosts
 
     # Drop privileges by re-running this script.
     exec su worker $0
 fi
 
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/scripts/tools.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+
+set -v -e -x
+
+switch_compilers() {
+    GCC=`which ${GCC_VERSION:-gcc-5}`
+    GXX=`which ${GXX_VERSION:-g++-5}`
+
+    if [ -e "$GCC" ] && [ -e "$GXX" ]; then
+        update-alternatives --set gcc $GCC
+        update-alternatives --set g++ $GXX
+    else
+        echo "Unknown compiler $GCC_VERSION/$GXX_VERSION."
+        exit 1
+    fi
+}
--- a/security/nss/cmd/bltest/blapitest.c
+++ b/security/nss/cmd/bltest/blapitest.c
@@ -349,60 +349,52 @@ key_from_filedata(PLArenaPool *arena, SE
             }
             it++;
         }
         fpos += len;
     }
 }
 
 static RSAPrivateKey *
-rsakey_from_filedata(SECItem *filedata)
+rsakey_from_filedata(PLArenaPool *arena, SECItem *filedata)
 {
     RSAPrivateKey *key;
-    PLArenaPool *arena;
-    arena = PORT_NewArena(BLTEST_DEFAULT_CHUNKSIZE);
     key = (RSAPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(RSAPrivateKey));
     key->arena = arena;
     key_from_filedata(arena, &key->version, 0, 9, filedata);
     return key;
 }
 
 static PQGParams *
-pqg_from_filedata(SECItem *filedata)
+pqg_from_filedata(PLArenaPool *arena, SECItem *filedata)
 {
     PQGParams *pqg;
-    PLArenaPool *arena;
-    arena = PORT_NewArena(BLTEST_DEFAULT_CHUNKSIZE);
     pqg = (PQGParams *)PORT_ArenaZAlloc(arena, sizeof(PQGParams));
     pqg->arena = arena;
     key_from_filedata(arena, &pqg->prime, 0, 3, filedata);
     return pqg;
 }
 
 static DSAPrivateKey *
-dsakey_from_filedata(SECItem *filedata)
+dsakey_from_filedata(PLArenaPool *arena, SECItem *filedata)
 {
     DSAPrivateKey *key;
-    PLArenaPool *arena;
-    arena = PORT_NewArena(BLTEST_DEFAULT_CHUNKSIZE);
     key = (DSAPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(DSAPrivateKey));
     key->params.arena = arena;
     key_from_filedata(arena, &key->params.prime, 0, 5, filedata);
     return key;
 }
 
 #ifndef NSS_DISABLE_ECC
 static ECPrivateKey *
-eckey_from_filedata(SECItem *filedata)
+eckey_from_filedata(PLArenaPool *arena, SECItem *filedata)
 {
     ECPrivateKey *key;
-    PLArenaPool *arena;
     SECStatus rv;
     ECParams *tmpECParams = NULL;
-    arena = PORT_NewArena(BLTEST_DEFAULT_CHUNKSIZE);
     key = (ECPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(ECPrivateKey));
     /* read and convert params */
     key->ecParams.arena = arena;
     key_from_filedata(arena, &key->ecParams.DEREncoding, 0, 1, filedata);
     rv = SECOID_Init();
     CHECKERROR(rv, __LINE__);
     rv = EC_DecodeParams(&key->ecParams.DEREncoding, &tmpECParams);
     CHECKERROR(rv, __LINE__);
@@ -1805,20 +1797,20 @@ bltest_dsa_init(bltestCipherInfo *cipher
         }
         TIMEFINISH(cipherInfo->cxtime, cipherInfo->cxreps);
         /* Free the n key objects */
         for (i = 0; i < cipherInfo->cxreps; i++)
             PORT_FreeArena(dummyKey[i]->params.arena, PR_TRUE);
         PORT_Free(dummyKey);
     }
     if (!dsap->pqg && dsap->pqgdata.buf.len > 0) {
-        dsap->pqg = pqg_from_filedata(&dsap->pqgdata.buf);
+        dsap->pqg = pqg_from_filedata(cipherInfo->arena, &dsap->pqgdata.buf);
     }
     if (!asymk->privKey && asymk->key.buf.len > 0) {
-        asymk->privKey = dsakey_from_filedata(&asymk->key.buf);
+        asymk->privKey = dsakey_from_filedata(cipherInfo->arena, &asymk->key.buf);
     }
     if (encrypt) {
         cipherInfo->cipher.pubkeyCipher = dsa_signDigest;
     } else {
         /* Have to convert private key to public key.  Memory
          * is freed with private key's arena  */
         DSAPublicKey *pubkey;
         DSAPrivateKey *key = (DSAPrivateKey *)asymk->privKey;
@@ -1859,17 +1851,17 @@ bltest_ecdsa_init(bltestCipherInfo *ciph
         }
         TIMEFINISH(cipherInfo->cxtime, cipherInfo->cxreps);
         /* Free the n key objects */
         for (i = 0; i < cipherInfo->cxreps; i++)
             PORT_FreeArena(dummyKey[i]->ecParams.arena, PR_TRUE);
         PORT_Free(dummyKey);
     }
     if (!asymk->privKey && asymk->key.buf.len > 0) {
-        asymk->privKey = eckey_from_filedata(&asymk->key.buf);
+        asymk->privKey = eckey_from_filedata(cipherInfo->arena, &asymk->key.buf);
     }
     if (encrypt) {
         cipherInfo->cipher.pubkeyCipher = ecdsa_signDigest;
     } else {
         /* Have to convert private key to public key.  Memory
      * is freed with private key's arena  */
         ECPublicKey *pubkey;
         ECPrivateKey *key = (ECPrivateKey *)asymk->privKey;
@@ -2226,33 +2218,33 @@ pubkeyInitKey(bltestCipherInfo *cipherIn
                 SECITEM_AllocItem(cipherInfo->arena, &expitem, sizeof(int));
                 for (i = 1; i <= sizeof(int); i++)
                     expitem.data[i - 1] = exponent >> (8 * (sizeof(int) - i));
                 *rsaKey = RSA_NewKey(keysize * 8, &expitem);
                 serialize_key(&(*rsaKey)->version, 9, file);
                 rsap->keysizeInBits = keysize * 8;
             } else {
                 setupIO(cipherInfo->arena, &asymk->key, file, NULL, 0);
-                *rsaKey = rsakey_from_filedata(&asymk->key.buf);
+                *rsaKey = rsakey_from_filedata(cipherInfo->arena, &asymk->key.buf);
                 rsap->keysizeInBits = (*rsaKey)->modulus.len * 8;
             }
             break;
         case bltestDSA:
             dsap = &asymk->cipherParams.dsa;
             dsaKey = (DSAPrivateKey **)&asymk->privKey;
             if (keysize > 0) {
                 dsap->keysize = keysize * 8;
                 if (!dsap->pqg)
                     bltest_pqg_init(dsap);
                 rv = DSA_NewKey(dsap->pqg, dsaKey);
                 CHECKERROR(rv, __LINE__);
                 serialize_key(&(*dsaKey)->params.prime, 5, file);
             } else {
                 setupIO(cipherInfo->arena, &asymk->key, file, NULL, 0);
-                *dsaKey = dsakey_from_filedata(&asymk->key.buf);
+                *dsaKey = dsakey_from_filedata(cipherInfo->arena, &asymk->key.buf);
                 dsap->keysize = (*dsaKey)->params.prime.len * 8;
             }
             break;
 #ifndef NSS_DISABLE_ECC
         case bltestECDSA:
             ecKey = (ECPrivateKey **)&asymk->privKey;
             if (curveName != NULL) {
                 tmpECParamsDER = getECParams(curveName);
@@ -2273,17 +2265,17 @@ pubkeyInitKey(bltestCipherInfo *cipherIn
                 ecSerialize[2].len = (*ecKey)->privateValue.len;
                 serialize_key(&(ecSerialize[0]), 3, file);
                 SECITEM_FreeItem(tmpECParamsDER, PR_TRUE);
                 PORT_FreeArena(tmpECParams->arena, PR_TRUE);
                 rv = SECOID_Shutdown();
                 CHECKERROR(rv, __LINE__);
             } else {
                 setupIO(cipherInfo->arena, &asymk->key, file, NULL, 0);
-                *ecKey = eckey_from_filedata(&asymk->key.buf);
+                *ecKey = eckey_from_filedata(cipherInfo->arena, &asymk->key.buf);
             }
             break;
 #endif
         default:
             return SECFailure;
     }
     return SECSuccess;
 }
@@ -3065,43 +3057,43 @@ get_params(PLArenaPool *arena, bltestPar
             params->asymk.cipherParams.rsa.maskHashAlg =
                 mode_str_to_hash_alg(&tempIO.buf);
         /* fall through */
         case bltestRSA:
             sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "key", j);
             load_file_data(arena, &params->asymk.key, filename,
                            bltestBase64Encoded);
             params->asymk.privKey =
-                (void *)rsakey_from_filedata(&params->asymk.key.buf);
+                (void *)rsakey_from_filedata(arena, &params->asymk.key.buf);
             break;
         case bltestDSA:
             sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "key", j);
             load_file_data(arena, &params->asymk.key, filename, bltestBase64Encoded);
             params->asymk.privKey =
-                (void *)dsakey_from_filedata(&params->asymk.key.buf);
+                (void *)dsakey_from_filedata(arena, &params->asymk.key.buf);
             sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "pqg", j);
             load_file_data(arena, &params->asymk.cipherParams.dsa.pqgdata, filename,
                            bltestBase64Encoded);
             params->asymk.cipherParams.dsa.pqg =
-                pqg_from_filedata(&params->asymk.cipherParams.dsa.pqgdata.buf);
+                pqg_from_filedata(arena, &params->asymk.cipherParams.dsa.pqgdata.buf);
             sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "keyseed", j);
             load_file_data(arena, &params->asymk.cipherParams.dsa.keyseed, filename,
                            bltestBase64Encoded);
             sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "sigseed", j);
             load_file_data(arena, &params->asymk.cipherParams.dsa.sigseed, filename,
                            bltestBase64Encoded);
             sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "ciphertext", j);
             load_file_data(arena, &params->asymk.sig, filename, bltestBase64Encoded);
             break;
 #ifndef NSS_DISABLE_ECC
         case bltestECDSA:
             sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "key", j);
             load_file_data(arena, &params->asymk.key, filename, bltestBase64Encoded);
             params->asymk.privKey =
-                (void *)eckey_from_filedata(&params->asymk.key.buf);
+                (void *)eckey_from_filedata(arena, &params->asymk.key.buf);
             sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "sigseed", j);
             load_file_data(arena, &params->asymk.cipherParams.ecdsa.sigseed,
                            filename, bltestBase64Encoded);
             sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "ciphertext", j);
             load_file_data(arena, &params->asymk.sig, filename, bltestBase64Encoded);
             break;
 #endif
         case bltestMD2:
@@ -3162,26 +3154,29 @@ verify_self_test(bltestIO *result, bltes
                 printf("Decryption self-test for %s failed!\n", modestr);
             }
         }
     }
     return equal ? SECSuccess : SECFailure;
 }
 
 static SECStatus
-ReadFileToItem(SECItem *dst, const char *filename)
+ReadFileToItem(PLArenaPool *arena, SECItem *dst, const char *filename)
 {
+    SECItem tmp = {siBuffer, NULL, 0};
     PRFileDesc *file;
     SECStatus rv;
 
     file = PR_Open(filename, PR_RDONLY, 00660);
     if (!file) {
         return SECFailure;
     }
-    rv = SECU_FileToItem(dst, file);
+    rv = SECU_FileToItem(&tmp, file);
+    rv |= SECITEM_CopyItem(arena, dst, &tmp);
+    SECITEM_FreeItem(&tmp, PR_FALSE);
     PR_Close(file);
     return rv;
 }
 
 static SECStatus
 blapi_selftest(bltestCipherMode *modes, int numModes, int inoff, int outoff,
                PRBool encrypt, PRBool decrypt)
 {
@@ -3210,17 +3205,17 @@ blapi_selftest(bltestCipherMode *modes, 
             fprintf(stderr, "%s: Skipping invalid mode.\n", progName);
             continue;
         }
         modestr = mode_strings[mode];
         cipherInfo.mode = mode;
         params = &cipherInfo.params;
         /* get the number of tests in the directory */
         sprintf(filename, "%s/tests/%s/%s", testdir, modestr, "numtests");
-        if (ReadFileToItem(&item, filename) != SECSuccess) {
+        if (ReadFileToItem(arena, &item, filename) != SECSuccess) {
             fprintf(stderr, "%s: Cannot read file %s.\n", progName, filename);
             rv = SECFailure;
             continue;
         }
         /* loop over the tests in the directory */
         numtests = 0;
         for (j = 0; j < item.len; j++) {
             if (!isdigit(item.data[j])) {
@@ -3288,46 +3283,47 @@ blapi_selftest(bltestCipherMode *modes, 
             misalignBuffer(arena, &cipherInfo.output, outoff);
             srv = SECSuccess;
             srv |= cipherDoOp(&cipherInfo);
             rv |= cipherFinish(&cipherInfo);
             rv |= verify_self_test(&cipherInfo.output,
                                    &pt, mode, PR_FALSE, srv);
         }
     }
+    PORT_FreeArena(arena, PR_FALSE);
     return rv;
 }
 
 SECStatus
 dump_file(bltestCipherMode mode, char *filename)
 {
     bltestIO keydata;
     PLArenaPool *arena = NULL;
     arena = PORT_NewArena(BLTEST_DEFAULT_CHUNKSIZE);
     if (mode == bltestRSA || mode == bltestRSA_PSS || mode == bltestRSA_OAEP) {
         RSAPrivateKey *key;
         load_file_data(arena, &keydata, filename, bltestBase64Encoded);
-        key = rsakey_from_filedata(&keydata.buf);
+        key = rsakey_from_filedata(arena, &keydata.buf);
         dump_rsakey(key);
     } else if (mode == bltestDSA) {
 #if 0
     PQGParams *pqg;
     get_file_data(filename, &item, PR_TRUE);
     pqg = pqg_from_filedata(&item);
     dump_pqg(pqg);
 #endif
         DSAPrivateKey *key;
         load_file_data(arena, &keydata, filename, bltestBase64Encoded);
-        key = dsakey_from_filedata(&keydata.buf);
+        key = dsakey_from_filedata(arena, &keydata.buf);
         dump_dsakey(key);
 #ifndef NSS_DISABLE_ECC
     } else if (mode == bltestECDSA) {
         ECPrivateKey *key;
         load_file_data(arena, &keydata, filename, bltestBase64Encoded);
-        key = eckey_from_filedata(&keydata.buf);
+        key = eckey_from_filedata(arena, &keydata.buf);
         dump_eckey(key);
 #endif
     }
     PORT_FreeArena(arena, PR_FALSE);
     return SECFailure;
 }
 
 void
--- a/security/nss/cmd/certcgi/certcgi.c
+++ b/security/nss/cmd/certcgi/certcgi.c
@@ -914,17 +914,23 @@ AddPrivKeyUsagePeriod(void *extHandle,
     if (!arena) {
         error_allocate();
     }
     pkup = PORT_ArenaZNew(arena, CERTPrivKeyUsagePeriod);
     if (pkup == NULL) {
         error_allocate();
     }
     notBeforeStr = (char *)PORT_Alloc(16);
+    if (notBeforeStr == NULL) {
+        error_allocate();
+    }
     notAfterStr = (char *)PORT_Alloc(16);
+    if (notAfterStr == NULL) {
+        error_allocate();
+    }
     *notBeforeStr = '\0';
     *notAfterStr = '\0';
     pkup->arena = arena;
     pkup->notBefore.len = 0;
     pkup->notBefore.data = NULL;
     pkup->notAfter.len = 0;
     pkup->notAfter.data = NULL;
     if (find_field_bool(data, "privKeyUsagePeriod-radio-notBefore", PR_TRUE) ||
@@ -1028,25 +1034,19 @@ AddPrivKeyUsagePeriod(void *extHandle,
 
     rv = EncodeAndAddExtensionValue(arena, extHandle, pkup,
                                     find_field_bool(data,
                                                     "privKeyUsagePeriod-crit",
                                                     PR_TRUE),
                                     SEC_OID_X509_PRIVATE_KEY_USAGE_PERIOD,
                                     (EXTEN_VALUE_ENCODER)
                                         CERT_EncodePrivateKeyUsagePeriod);
-    if (arena) {
-        PORT_FreeArena(arena, PR_FALSE);
-    }
-    if (notBeforeStr != NULL) {
-        PORT_Free(notBeforeStr);
-    }
-    if (notAfterStr != NULL) {
-        PORT_Free(notAfterStr);
-    }
+    PORT_FreeArena(arena, PR_FALSE);
+    PORT_Free(notBeforeStr);
+    PORT_Free(notAfterStr);
     return (rv);
 }
 
 static SECStatus
 AddBasicConstraint(void *extHandle,
                    Pair *data)
 {
     CERTBasicConstraints basicConstraint;
--- a/security/nss/cmd/certutil/certext.c
+++ b/security/nss/cmd/certutil/certext.c
@@ -267,24 +267,25 @@ GetYesNo(char *prompt)
  * nextPos is set to the token after found comma separator or to NULL.
  * NULL in nextPos should be used as indication of the last parsed token.
  * A special value "critical" can be parsed out from the supplied sting.*/
 
 static SECStatus
 parseNextCmdInput(const char *const *valueArray, int *value, char **nextPos,
                   PRBool *critical)
 {
-    char *thisPos = *nextPos;
+    char *thisPos;
     int keyLen = 0;
     int arrIndex = 0;
 
     if (!valueArray || !value || !nextPos || !critical) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return SECFailure;
     }
+    thisPos = *nextPos;
     while (1) {
         if ((*nextPos = strchr(thisPos, ',')) == NULL) {
             keyLen = strlen(thisPos);
         } else {
             keyLen = *nextPos - thisPos;
             *nextPos += 1;
         }
         /* if critical keyword is found, go for another loop,
@@ -911,17 +912,17 @@ AddDNSSubjectAlt(PLArenaPool *arena, CER
 static SECStatus
 AddGeneralSubjectAlt(PLArenaPool *arena, CERTGeneralName **existingListp,
                      const char *altNames)
 {
     return AddSubjectAltNames(arena, existingListp, altNames, 0);
 }
 
 static SECStatus
-AddBasicConstraint(void *extHandle)
+AddBasicConstraint(PLArenaPool *arena, void *extHandle)
 {
     CERTBasicConstraints basicConstraint;
     SECStatus rv;
     char buffer[10];
     PRBool yesNoAns;
 
     do {
         basicConstraint.pathLenConstraint = CERT_UNLIMITED_PATH_CONSTRAINT;
@@ -933,17 +934,17 @@ AddBasicConstraint(void *extHandle)
                                      buffer, sizeof(buffer)) == SECFailure) {
             GEN_BREAK(SECFailure);
         }
         if (PORT_Strlen(buffer) > 0)
             basicConstraint.pathLenConstraint = PORT_Atoi(buffer);
 
         yesNoAns = GetYesNo("Is this a critical extension [y/N]?");
 
-        rv = SECU_EncodeAndAddExtensionValue(NULL, extHandle,
+        rv = SECU_EncodeAndAddExtensionValue(arena, extHandle,
                                              &basicConstraint, yesNoAns, SEC_OID_X509_BASIC_CONSTRAINTS,
                                              (EXTEN_EXT_VALUE_ENCODER)CERT_EncodeBasicConstraintValue);
     } while (0);
 
     return (rv);
 }
 
 static SECStatus
@@ -1977,20 +1978,26 @@ parseNextGenericExt(const char *nextExte
 
     return SECSuccess;
 }
 
 SECStatus
 AddExtensions(void *extHandle, const char *emailAddrs, const char *dnsNames,
               certutilExtnList extList, const char *extGeneric)
 {
+    PLArenaPool *arena;
     SECStatus rv = SECSuccess;
     char *errstring = NULL;
     const char *nextExtension = NULL;
 
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if (arena == NULL) {
+        return SECFailure;
+    }
+
     do {
         /* Add key usage extension */
         if (extList[ext_keyUsage].activated) {
             rv = AddKeyUsage(extHandle, extList[ext_keyUsage].arg);
             if (rv) {
                 errstring = "KeyUsage";
                 break;
             }
@@ -2002,17 +2009,17 @@ AddExtensions(void *extHandle, const cha
             if (rv) {
                 errstring = "ExtendedKeyUsage";
                 break;
             }
         }
 
         /* Add basic constraint extension */
         if (extList[ext_basicConstraint].activated) {
-            rv = AddBasicConstraint(extHandle);
+            rv = AddBasicConstraint(arena, extHandle);
             if (rv) {
                 errstring = "BasicConstraint";
                 break;
             }
         }
 
         /* Add name constraints extension */
         if (extList[ext_nameConstraints].activated) {
@@ -2093,26 +2100,19 @@ AddExtensions(void *extHandle, const cha
             rv = AddInhibitAnyPolicy(extHandle);
             if (rv) {
                 errstring = "InhibitAnyPolicy";
                 break;
             }
         }
 
         if (emailAddrs || dnsNames || extList[ext_subjectAltName].activated) {
-            PLArenaPool *arena;
             CERTGeneralName *namelist = NULL;
             SECItem item = { 0, NULL, 0 };
 
-            arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
-            if (arena == NULL) {
-                rv = SECFailure;
-                break;
-            }
-
             rv = SECSuccess;
 
             if (emailAddrs) {
                 rv |= AddEmailSubjectAlt(arena, &namelist, emailAddrs);
             }
 
             if (dnsNames) {
                 rv |= AddDNSSubjectAlt(arena, &namelist, dnsNames);
@@ -2126,24 +2126,25 @@ AddExtensions(void *extHandle, const cha
             if (rv == SECSuccess) {
                 rv = CERT_EncodeAltNameExtension(arena, namelist, &item);
                 if (rv == SECSuccess) {
                     rv = CERT_AddExtension(extHandle,
                                            SEC_OID_X509_SUBJECT_ALT_NAME,
                                            &item, PR_FALSE, PR_TRUE);
                 }
             }
-            PORT_FreeArena(arena, PR_FALSE);
             if (rv) {
                 errstring = "SubjectAltName";
                 break;
             }
         }
     } while (0);
 
+    PORT_FreeArena(arena, PR_FALSE);
+
     if (rv != SECSuccess) {
         SECU_PrintError(progName, "Problem creating %s extension", errstring);
     }
 
     nextExtension = extGeneric;
     while (nextExtension && *nextExtension) {
         SECItem oid_item, value;
         PRBool isCritical;
@@ -2193,20 +2194,20 @@ AddExtensions(void *extHandle, const cha
             SECU_PrintError(progName, "unable to read file %s",
                             zeroTerminatedFilename);
         }
         PL_strfree(zeroTerminatedFilename);
         if (rv != SECSuccess) {
             break;
         }
         rv = CERT_AddExtensionByOID(extHandle, &oid_item, &value, isCritical,
-                                    PR_FALSE /*copyData*/);
+                                    PR_TRUE /*copyData*/);
+        SECITEM_FreeItem(&value, PR_FALSE);
+        SECITEM_FreeItem(&oid_item, PR_FALSE);
         if (rv != SECSuccess) {
-            SECITEM_FreeItem(&oid_item, PR_FALSE);
-            SECITEM_FreeItem(&value, PR_FALSE);
             SECU_PrintError(progName, "failed to add extension %s", nextExtension);
             break;
         }
         nextExtension = next;
     }
 
     return rv;
 }
--- a/security/nss/cmd/certutil/certutil.c
+++ b/security/nss/cmd/certutil/certutil.c
@@ -214,21 +214,24 @@ CertReq(SECKEYPrivateKey *privk, SECKEYP
     if (!arena) {
         SECU_PrintError(progName, "out of memory");
         return SECFailure;
     }
 
     extHandle = CERT_StartCertificateRequestAttributes(cr);
     if (extHandle == NULL) {
         PORT_FreeArena(arena, PR_FALSE);
+        CERT_DestroyCertificateRequest(cr);
         return SECFailure;
     }
     if (AddExtensions(extHandle, emailAddrs, dnsNames, extnList, extGeneric) !=
         SECSuccess) {
         PORT_FreeArena(arena, PR_FALSE);
+        CERT_FinishExtensions(extHandle);
+        CERT_DestroyCertificateRequest(cr);
         return SECFailure;
     }
     CERT_FinishExtensions(extHandle);
     CERT_FinishCertificateRequestAttributes(cr);
 
     /* Der encode the request */
     encoding = SEC_ASN1EncodeItem(arena, NULL, cr,
                                   SEC_ASN1_GET(CERT_CertificateRequestTemplate));
@@ -384,16 +387,17 @@ ChangeTrustAttributes(CERTCertDBHandle *
             rv = CERT_ChangeCertTrust(handle, cert, trust);
         }
         if (rv != SECSuccess) {
             SECU_PrintError(progName, "unable to modify trust attributes");
             return SECFailure;
         }
     }
     CERT_DestroyCertificate(cert);
+    PORT_Free(trust);
 
     return SECSuccess;
 }
 
 static SECStatus
 DumpChain(CERTCertDBHandle *handle, char *name, PRBool ascii)
 {
     CERTCertificate *the_cert;
@@ -1965,17 +1969,17 @@ CreateCert(
     const char *dnsNames,
     PRBool ascii,
     PRBool selfsign,
     certutilExtnList extnList,
     const char *extGeneric,
     int certVersion,
     SECItem *certDER)
 {
-    void *extHandle;
+    void *extHandle = NULL;
     CERTCertificate *subjectCert = NULL;
     CERTCertificateRequest *certReq = NULL;
     SECStatus rv = SECSuccess;
     CERTCertExtension **CRexts;
 
     do {
         /* Create a certrequest object from the input cert request der */
         certReq = GetCertRequest(certReqDER);
@@ -2009,16 +2013,17 @@ CreateCert(
             if (rv != SECSuccess)
                 break;
             rv = CERT_MergeExtensions(extHandle, CRexts);
             if (rv != SECSuccess)
                 break;
         }
 
         CERT_FinishExtensions(extHandle);
+        extHandle = NULL;
 
         /* self-signing a cert request, find the private key */
         if (selfsign && *selfsignprivkey == NULL) {
             *selfsignprivkey = PK11_FindKeyByDERCert(slot, subjectCert, pwarg);
             if (!*selfsignprivkey) {
                 fprintf(stderr, "Failed to locate private key.\n");
                 rv = SECFailure;
                 break;
@@ -2049,16 +2054,19 @@ CreateCert(
                     PR_smprintf_free(wrapped);
                 }
                 PORT_Free(asciiDER);
             }
         } else {
             rv = SECITEM_CopyItem(NULL, certDER, &subjectCert->derCert);
         }
     } while (0);
+    if (extHandle) {
+        CERT_FinishExtensions(extHandle);
+    }
     CERT_DestroyCertificateRequest(certReq);
     CERT_DestroyCertificate(subjectCert);
     if (rv != SECSuccess) {
         PRErrorCode perr = PR_GetError();
         fprintf(stderr, "%s: unable to create cert (%s)\n", progName,
                 SECU_Strerror(perr));
     }
     return (rv);
@@ -3149,16 +3157,17 @@ certutil_main(int argc, char **argv, PRB
                 SECU_PrintError(progName, "malformed extension OID %s",
                                 oid_str);
                 goto shutdown;
             }
             rv = ListCerts(certHandle, name, email, slot,
                            PR_TRUE /*binary*/, PR_FALSE /*ascii*/,
                            &oid_item,
                            outFile, &pwdata);
+            SECITEM_FreeItem(&oid_item, PR_FALSE);
         } else {
             rv = ListCerts(certHandle, name, email, slot,
                            certutil.options[opt_BinaryDER].activated,
                            certutil.options[opt_ASCIIForIO].activated,
                            NULL, outFile, &pwdata);
         }
         goto shutdown;
     }
--- a/security/nss/cmd/crlutil/crlgen.c
+++ b/security/nss/cmd/crlutil/crlgen.c
@@ -62,26 +62,33 @@ crlgen_FindEntry(CRLGENGeneratorData *cr
 }
 
 /* Removes CRLGENEntryData from hashtable according to certId
  * - certId : cert serial number*/
 static SECStatus
 crlgen_RmEntry(CRLGENGeneratorData *crlGenData, SECItem *certId)
 {
     CRLGENEntryData *data = NULL;
+    SECStatus rv = SECSuccess;
 
-    if (!crlGenData->entryDataHashTable)
+    if (!crlGenData->entryDataHashTable) {
         return SECSuccess;
+    }
+
     data = crlgen_FindEntry(crlGenData, certId);
-    if (!data)
+    if (!data) {
         return SECSuccess;
-    if (PL_HashTableRemove(crlGenData->entryDataHashTable, certId))
-        return SECSuccess;
+    }
+
+    if (!PL_HashTableRemove(crlGenData->entryDataHashTable, certId)) {
+        rv = SECFailure;
+    }
+
     destroyEntryData(data);
-    return SECFailure;
+    return rv;
 }
 
 /* Stores CRLGENEntryData in hashtable according to certId
  * - certId : cert serial number*/
 static CRLGENEntryData *
 crlgen_PlaceAnEntry(CRLGENGeneratorData *crlGenData,
                     CERTCrlEntry *entry, SECItem *certId)
 {
@@ -478,17 +485,16 @@ loser:
 /* Creates and adds CRLNumber extension to extension handle.
  * Since, this is CRL extension, extension handle is the one
  * related to CRL extensions */
 static SECStatus
 crlgen_AddCrlNumber(CRLGENGeneratorData *crlGenData, const char **dataArr)
 {
     PLArenaPool *arena = NULL;
     SECItem encodedItem;
-    void *extHandle = crlGenData->crlExtHandle;
     void *dummy;
     SECStatus rv = SECFailure;
     int code = 0;
 
     PORT_Assert(dataArr && crlGenData);
     if (!crlGenData || !dataArr) {
         goto loser;
     }
@@ -512,17 +518,18 @@ crlgen_AddCrlNumber(CRLGENGeneratorData 
     }
 
     dummy = SEC_ASN1EncodeInteger(arena, &encodedItem, code);
     if (!dummy) {
         rv = SECFailure;
         goto loser;
     }
 
-    rv = CERT_AddExtension(extHandle, SEC_OID_X509_CRL_NUMBER, &encodedItem,
+    rv = CERT_AddExtension(crlGenData->crlExtHandle, SEC_OID_X509_CRL_NUMBER,
+                           &encodedItem,
                            (*dataArr[1] == '1') ? PR_TRUE : PR_FALSE,
                            PR_TRUE);
 
 loser:
     if (arena)
         PORT_FreeArena(arena, PR_FALSE);
     return rv;
 }
--- a/security/nss/cmd/crlutil/crlutil.c
+++ b/security/nss/cmd/crlutil/crlutil.c
@@ -278,16 +278,17 @@ ImportCRL(CERTCertDBHandle *certHandle, 
             SECU_PrintError(progName, "unable to import CRL");
     } else {
         SEC_DestroyCrl(crl);
     }
 loser:
     if (slot) {
         PK11_FreeSlot(slot);
     }
+    SECITEM_FreeItem(&crlDER, PR_FALSE);
     return (rv);
 }
 
 SECStatus
 DumpCRL(PRFileDesc *inFile)
 {
     int rv;
     PLArenaPool *arena = NULL;
@@ -526,16 +527,18 @@ CreateNewCrl(PLArenaPool *arena, CERTCer
         goto loser;
     }
 
     /* set fields */
     signCrl->arena = arena;
     signCrl->dbhandle = certHandle;
     signCrl->crl.arena = arena;
 
+    PORT_ArenaUnmark(arena, mark);
+
     return signCrl;
 
 loser:
     PORT_ArenaRelease(arena, mark);
     return NULL;
 }
 
 static SECStatus
@@ -856,17 +859,17 @@ main(int argc, char **argv)
     int modifyCRL;
     int listCRL;
     int importCRL;
     int showFileCRL;
     int deleteCRL;
     int rv;
     char *nickName;
     char *url;
-    char *dbPrefix = "";
+    char *dbPrefix = PORT_Strdup("");
     char *alg = NULL;
     char *outFile = NULL;
     char *slotName = NULL;
     int ascii = 0;
     int crlType;
     PLOptState *optstate;
     PLOptStatus status;
     SECStatus secstatus;
@@ -933,103 +936,103 @@ main(int argc, char **argv)
                 break;
 
             case 'C':
             case 'L':
                 listCRL = 1;
                 break;
 
             case 'P':
-                dbPrefix = strdup(optstate->value);
+                PORT_Free(dbPrefix);
+                dbPrefix = PORT_Strdup(optstate->value);
                 break;
 
             case 'Z':
-                alg = strdup(optstate->value);
+                alg = PORT_Strdup(optstate->value);
                 break;
 
             case 'a':
                 ascii = 1;
                 break;
 
             case 'c':
                 inCrlInitFile = PR_Open(optstate->value, PR_RDONLY, 0);
                 if (!inCrlInitFile) {
                     PR_fprintf(PR_STDERR, "%s: unable to open \"%s\" for reading\n",
                                progName, optstate->value);
-                    PL_DestroyOptState(optstate);
-                    return -1;
+                    rv = SECFailure;
+                    goto loser;
                 }
                 break;
 
             case 'd':
                 SECU_ConfigDirectory(optstate->value);
                 break;
 
             case 'f':
                 pwdata.source = PW_FROMFILE;
-                pwdata.data = strdup(optstate->value);
+                pwdata.data = PORT_Strdup(optstate->value);
                 break;
 
             case 'h':
-                slotName = strdup(optstate->value);
+                slotName = PORT_Strdup(optstate->value);
                 break;
 
             case 'i':
                 inFile = PR_Open(optstate->value, PR_RDONLY, 0);
                 if (!inFile) {
                     PR_fprintf(PR_STDERR, "%s: unable to open \"%s\" for reading\n",
                                progName, optstate->value);
-                    PL_DestroyOptState(optstate);
-                    return -1;
+                    rv = SECFailure;
+                    goto loser;
                 }
                 break;
 
             case 'n':
-                nickName = strdup(optstate->value);
+                nickName = PORT_Strdup(optstate->value);
                 break;
 
             case 'o':
-                outFile = strdup(optstate->value);
+                outFile = PORT_Strdup(optstate->value);
                 break;
 
             case 'p':
                 decodeOptions |= CRL_DECODE_SKIP_ENTRIES;
                 break;
 
             case 'r': {
                 const char *str = optstate->value;
                 if (str && atoi(str) > 0)
                     iterations = atoi(str);
             } break;
 
             case 't': {
                 crlType = atoi(optstate->value);
                 if (crlType != SEC_CRL_TYPE && crlType != SEC_KRL_TYPE) {
                     PR_fprintf(PR_STDERR, "%s: invalid crl type\n", progName);
-                    PL_DestroyOptState(optstate);
-                    return -1;
+                    rv = SECFailure;
+                    goto loser;
                 }
                 break;
 
                 case 'q':
                     quiet = PR_TRUE;
                     break;
 
                 case 'w':
                     pwdata.source = PW_PLAINTEXT;
-                    pwdata.data = strdup(optstate->value);
+                    pwdata.data = PORT_Strdup(optstate->value);
                     break;
 
                 case 'u':
-                    url = strdup(optstate->value);
+                    url = PORT_Strdup(optstate->value);
                     break;
             }
         }
     }
-    PL_DestroyOptState(optstate);
 
     if (deleteCRL && !nickName)
         Usage(progName);
     if (importCRL && !inFile)
         Usage(progName);
     if (showFileCRL && !inFile)
         Usage(progName);
     if ((generateCRL && !nickName) ||
@@ -1049,28 +1052,28 @@ main(int argc, char **argv)
 
     if (showFileCRL) {
         NSS_NoDB_Init(NULL);
     } else {
         secstatus = NSS_Initialize(SECU_ConfigDirectory(NULL), dbPrefix, dbPrefix,
                                    "secmod.db", readonly ? NSS_INIT_READONLY : 0);
         if (secstatus != SECSuccess) {
             SECU_PrintPRandOSError(progName);
-            return -1;
+            rv = SECFailure;
+            goto loser;
         }
     }
 
     SECU_RegisterDynamicOids();
 
     certHandle = CERT_GetDefaultCertDB();
     if (certHandle == NULL) {
         SECU_PrintError(progName, "unable to open the cert db");
-        /*ignoring return value of NSS_Shutdown() as code returns -1*/
-        (void)NSS_Shutdown();
-        return (-1);
+        rv = SECFailure;
+        goto loser;
     }
 
     CRLGEN_InitCrlGenParserLock();
 
     for (i = 0; i < iterations; i++) {
         /* Read in the private key info */
         if (deleteCRL)
             DeleteCRL(certHandle, nickName, crlType);
@@ -1105,14 +1108,41 @@ main(int argc, char **argv)
             /* list CRLs */
             ListCRLNames(certHandle, crlType, PR_FALSE);
         }
 #endif
     }
 
     CRLGEN_DestroyCrlGenParserLock();
 
+loser:
+    PL_DestroyOptState(optstate);
+
+    if (inFile) {
+        PR_Close(inFile);
+    }
+    if (alg) {
+        PORT_Free(alg);
+    }
+    if (slotName) {
+        PORT_Free(slotName);
+    }
+    if (nickName) {
+        PORT_Free(nickName);
+    }
+    if (outFile) {
+        PORT_Free(outFile);
+    }
+    if (url) {
+        PORT_Free(url);
+    }
+    if (pwdata.data) {
+        PORT_Free(pwdata.data);
+    }
+
+    PORT_Free(dbPrefix);
+
     if (NSS_Shutdown() != SECSuccess) {
         rv = SECFailure;
     }
 
     return (rv != SECSuccess);
 }
--- a/security/nss/cmd/ecperf/ecperf.c
+++ b/security/nss/cmd/ecperf/ecperf.c
@@ -250,48 +250,16 @@ M_TimeOperation(void (*threadFunc)(void 
         }
     }
     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;                                        \
-    params.type = ec_params_named;                           \
-    params.curveOID.data = NULL;                             \
-    params.curveOID.len = 0;                                 \
-    params.curve.seed.data = NULL;                           \
-    params.curve.seed.len = 0;                               \
-    params.DEREncoding.data = NULL;                          \
-    params.DEREncoding.len = 0;                              \
-    params.arena = NULL;                                     \
-    params.fieldID.size = ecCurve_map[name_v]->size;         \
-    params.fieldID.type = ec_field_GFp;                      \
-    hexString2SECItem(params.arena, &params.fieldID.u.prime, \
-                      ecCurve_map[name_v]->irr);             \
-    hexString2SECItem(params.arena, &params.curve.a,         \
-                      ecCurve_map[name_v]->curvea);          \
-    hexString2SECItem(params.arena, &params.curve.b,         \
-                      ecCurve_map[name_v]->curveb);          \
-    genenc[0] = '0';                                         \
-    genenc[1] = '4';                                         \
-    genenc[2] = '\0';                                        \
-    strcat(genenc, ecCurve_map[name_v]->genx);               \
-    strcat(genenc, ecCurve_map[name_v]->geny);               \
-    hexString2SECItem(params.arena, &params.base,            \
-                      genenc);                               \
-    hexString2SECItem(params.arena, &params.order,           \
-                      ecCurve_map[name_v]->order);           \
-    params.cofactor = ecCurve_map[name_v]->cofactor;
-
 /* Test curve using specific field arithmetic. */
 #define ECTEST_NAMED_GFP(name_c, name_v)                               \
     if (usefreebl) {                                                   \
         printf("Testing %s using freebl implementation...\n", name_c); \
         rv = ectest_curve_freebl(name_v, iterations, numThreads);      \
         if (rv != SECSuccess)                                          \
             goto cleanup;                                              \
         printf("... okay.\n");                                         \
@@ -322,20 +290,19 @@ hexString2SECItem(PLArenaPool *arena, SE
     }
 
     /* 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);
-    if (item->data == NULL)
+    if (SECITEM_AllocItem(arena, item, tmp / 2) == NULL) {
         return NULL;
-    item->len = tmp / 2;
+    }
 
     while (str[i]) {
         if ((str[i] >= '0') && (str[i] <= '9'))
             tmp = str[i] - '0';
         else if ((str[i] >= 'a') && (str[i] <= 'f'))
             tmp = str[i] - 'a' + 10;
         else if ((str[i] >= 'A') && (str[i] <= 'F'))
             tmp = str[i] - 'A' + 10;
@@ -574,42 +541,69 @@ ECDH_DeriveWrap(ECPrivateKey *priv, ECPu
     unsigned char secretData[256];
     SECStatus rv;
 
     secret.data = secretData;
     secret.len = sizeof(secretData);
 
     rv = ECDH_Derive(&pub->publicValue, &pub->ecParams,
                      &priv->privateValue, 0, &secret);
-#ifdef notdef
-    if (rv == SECSuccess) {
-        PORT_Free(secret.data);
-    }
-#endif
+    SECITEM_FreeItem(&secret, PR_FALSE);
     return rv;
 }
 
 /* Performs basic 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. */
 SECStatus
 ectest_curve_freebl(ECCurveName curve, int iterations, int numThreads)
 {
-    ECParams ecParams;
+    ECParams ecParams = { 0 };
     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 = SECFailure;
+    PLArenaPool *arena;
 
-    GFP_POPULATE(ecParams, curve);
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if (!arena) {
+        return SECFailure;
+    }
+
+    if ((curve < ECCurve_noName) || (curve > ECCurve_pastLastCurve)) {
+        return SECFailure;
+    }
+
+    ecParams.name = curve;
+    ecParams.type = ec_params_named;
+    ecParams.curveOID.data = NULL;
+    ecParams.curveOID.len = 0;
+    ecParams.curve.seed.data = NULL;
+    ecParams.curve.seed.len = 0;
+    ecParams.DEREncoding.data = NULL;
+    ecParams.DEREncoding.len = 0;
+
+    ecParams.fieldID.size = ecCurve_map[curve]->size;
+    ecParams.fieldID.type = ec_field_GFp;
+    hexString2SECItem(arena, &ecParams.fieldID.u.prime, ecCurve_map[curve]->irr);
+    hexString2SECItem(arena, &ecParams.curve.a, ecCurve_map[curve]->curvea);
+    hexString2SECItem(arena, &ecParams.curve.b, ecCurve_map[curve]->curveb);
+    genenc[0] = '0';
+    genenc[1] = '4';
+    genenc[2] = '\0';
+    strcat(genenc, ecCurve_map[curve]->genx);
+    strcat(genenc, ecCurve_map[curve]->geny);
+    hexString2SECItem(arena, &ecParams.base, genenc);
+    hexString2SECItem(arena, &ecParams.order, ecCurve_map[curve]->order);
+    ecParams.cofactor = ecCurve_map[curve]->cofactor;
 
     PORT_Memset(digestData, 0xa5, sizeof(digestData));
     digest.data = digestData;
     digest.len = sizeof(digestData);
     sig.data = sigData;
     sig.len = sizeof(sigData);
 
     rv = EC_NewKey(&ecParams, &ecPriv);
@@ -635,16 +629,18 @@ ectest_curve_freebl(ECCurveName curve, i
     }
     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:
+    PORT_FreeArena(arena, PR_FALSE);
+    PORT_FreeArena(ecPriv->ecParams.arena, PR_FALSE);
     return rv;
 }
 
 /* Prints help information. */
 void
 printUsage(char *prog)
 {
     printf("Usage: %s [-i iterations] [-t threads ] [-ans] [-fp] [-Al]\n"
@@ -757,13 +753,15 @@ main(int argv, char **argc)
         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:
+    rv |= NSS_Shutdown();
+
     if (rv != SECSuccess) {
         printf("Error: exiting with error value\n");
     }
     return rv;
 }
--- a/security/nss/cmd/lib/secutil.c
+++ b/security/nss/cmd/lib/secutil.c
@@ -208,17 +208,16 @@ SECU_FilePasswd(PK11SlotInfo *slot, PRBo
 
 char *
 SECU_GetModulePassword(PK11SlotInfo *slot, PRBool retry, void *arg)
 {
     char prompt[255];
     secuPWData *pwdata = (secuPWData *)arg;
     secuPWData pwnull = { PW_NONE, 0 };
     secuPWData pwxtrn = { PW_EXTERNAL, "external" };
-    char *pw;
 
     if (pwdata == NULL)
         pwdata = &pwnull;
 
     if (PK11_ProtectedAuthenticationPath(slot)) {
         pwdata = &pwxtrn;
     }
     if (retry && pwdata->source != PW_NONE) {
@@ -227,24 +226,17 @@ SECU_GetModulePassword(PK11SlotInfo *slo
     }
 
     switch (pwdata->source) {
         case PW_NONE:
             sprintf(prompt, "Enter Password or Pin for \"%s\":",
                     PK11_GetTokenName(slot));
             return SECU_GetPasswordString(NULL, prompt);
         case PW_FROMFILE:
-            /* Instead of opening and closing the file every time, get the pw
-             * once, then keep it in memory (duh).
-             */
-            pw = SECU_FilePasswd(slot, retry, pwdata->data);
-            pwdata->source = PW_PLAINTEXT;
-            pwdata->data = PL_strdup(pw);
-            /* it's already been dup'ed */
-            return pw;
+            return SECU_FilePasswd(slot, retry, pwdata->data);
         case PW_EXTERNAL:
             sprintf(prompt,
                     "Press Enter, then enter PIN for \"%s\" on external device.\n",
                     PK11_GetTokenName(slot));
             (void)SECU_GetPasswordString(NULL, prompt);
         /* Fall Through */
         case PW_PLAINTEXT:
             return PL_strdup(pwdata->data);
@@ -3508,19 +3500,17 @@ SECU_SignAndEncodeCRL(CERTCertificate *i
                                SEC_ASN1_GET(CERT_SignedCrlTemplate));
     if (!dummy) {
         *resCode = failToEncode;
         rv = SECFailure;
         goto done;
     }
 
 done:
-    if (caPrivateKey) {
-        SECKEY_DestroyPrivateKey(caPrivateKey);
-    }
+    SECKEY_DestroyPrivateKey(caPrivateKey);
     return rv;
 }
 
 SECStatus
 SECU_CopyCRL(PLArenaPool *destArena, CERTCrl *destCrl, CERTCrl *srcCrl)
 {
     void *dummy;
     SECStatus rv = SECSuccess;
@@ -3562,30 +3552,34 @@ SECU_DerSignDataCRL(PLArenaPool *arena, 
     it.data = 0;
 
     /* XXX We should probably have some asserts here to make sure the key type
      * and algID match
      */
 
     /* Sign input buffer */
     rv = SEC_SignData(&it, buf, len, pk, algID);
-    if (rv)
+    if (rv != SECSuccess) {
         goto loser;
+    }
 
     /* Fill out SignedData object */
     PORT_Memset(sd, 0, sizeof(*sd));
     sd->data.data = buf;
     sd->data.len = len;
-    sd->signature.data = it.data;
-    sd->signature.len = it.len << 3; /* convert to bit string */
+    rv = SECITEM_CopyItem(arena, &sd->signature, &it);
+    if (rv != SECSuccess) {
+        goto loser;
+    }
+
+    sd->signature.len <<= 3; /* convert to bit string */
     rv = SECOID_SetAlgorithmID(arena, &sd->signatureAlgorithm, algID, 0);
-    if (rv)
+    if (rv != SECSuccess) {
         goto loser;
-
-    return rv;
+    }
 
 loser:
     PORT_Free(it.data);
     return rv;
 }
 
 #if 0
 
--- a/security/nss/cmd/manifest.mn
+++ b/security/nss/cmd/manifest.mn
@@ -53,17 +53,16 @@ NSS_SRCDIRS = \
  p7content  \
  p7env  \
  p7sign  \
  p7verify  \
  pk12util \
  pk11gcmtest \
  pk11mode \
  pk1sign  \
- pkix-errcodes \
  pp  \
  pwdecrypt \
  rsaperf \
  sdrtest \
  selfserv  \
  signtool \
  signver \
  smimetools  \
@@ -71,16 +70,23 @@ NSS_SRCDIRS = \
  strsclnt \
  symkeyutil \
  tests \
  tstclnt  \
  vfychain \
  vfyserv \
  modutil \
  $(NULL)
+
+ifndef NSS_DISABLE_LIBPKIX
+NSS_SRCDIRS += \
+ pkix-errcodes \
+ $(NULL)
+endif
+
 endif
 endif
 
 DIRS = \
  $(LIB_SRCDIRS) \
  $(SOFTOKEN_SRCDIRS) \
  $(NSS_SRCDIRS)
 
--- a/security/nss/cmd/pk11mode/pk11mode.c
+++ b/security/nss/cmd/pk11mode/pk11mode.c
@@ -686,18 +686,17 @@ main(int argc, char **argv)
     if (doForkTests) {
         /* try to fork with softoken still loaded, but de-initialized */
         crv = PKM_ForkCheck(CKR_CRYPTOKI_NOT_INITIALIZED, pFunctionList,
                             PR_TRUE, NULL);
         if (crv != CKR_OK)
             goto cleanup;
     }
 
-    if (pSlotList)
-        free(pSlotList);
+    free(pSlotList);
 
     /* demonstrate how an application can be in Hybrid mode */
     /* PKM_HybridMode shows how to switch between NONFIPS */
     /* mode to FIPS mode */
 
     PKM_LogIt("Testing Hybrid mode \n");
     crv = PKM_HybridMode(pwd, pwdLen, &initArgs);
     if (crv == CKR_OK) {
@@ -1892,18 +1891,17 @@ PKM_ShowInfo(CK_FUNCTION_LIST_PTR pFunct
               (int)tokenInfo.hardwareVersion.minor);
     PKM_LogIt("    firmware version number: %d.%d\n",
               (int)tokenInfo.firmwareVersion.major,
               (int)tokenInfo.firmwareVersion.minor);
     if (tokenInfo.flags & CKF_CLOCK_ON_TOKEN) {
         PKM_LogIt("    current time: %.16s\n", tokenInfo.utcTime);
     }
     PKM_LogIt("PKM_ShowInfo done \n\n");
-    if (pSlotList)
-        free(pSlotList);
+    free(pSlotList);
     return crv;
 }
 
 /* PKM_HybridMode                                                         */
 /* The NSS cryptographic module has two modes of operation: FIPS Approved */
 /* mode and NONFIPS Approved mode. The two modes of operation are         */
 /* independent of each other -- they have their own copies of data        */
 /* structures and they are even allowed to be active at the same time.    */
--- a/security/nss/cmd/pk12util/pk12util.c
+++ b/security/nss/cmd/pk12util/pk12util.c
@@ -206,30 +206,32 @@ p12u_ucs2_ascii_conversion_function(PRBo
             /*if (i%60 == 0) printf("\n");*/
         }
         printf("\n");
     }
 #endif
     it.data = inBuf;
     it.len = inBufLen;
     dup = SECITEM_DupItem(&it);
+    if (!dup) {
+        return PR_FALSE;
+    }
     /* If converting Unicode to ASCII, swap bytes before conversion
      * as neccessary.
      */
     if (!toUnicode && swapBytes) {
         if (p12u_SwapUnicodeBytes(dup) != SECSuccess) {
             SECITEM_ZfreeItem(dup, PR_TRUE);
             return PR_FALSE;
         }
     }
     /* Perform the conversion. */
     ret = PORT_UCS2_UTF8Conversion(toUnicode, dup->data, dup->len,
                                    outBuf, maxOutBufLen, outBufLen);
-    if (dup)
-        SECITEM_ZfreeItem(dup, PR_TRUE);
+    SECITEM_ZfreeItem(dup, PR_TRUE);
 
 #ifdef DEBUG_CONVERSION
     if (pk12_debugging) {
         int i;
         printf("Converted to:\n");
         for (i = 0; i < *outBufLen; i++) {
             printf("%2x ", outBuf[i]);
             /*if (i%60 == 0) printf("\n");*/
@@ -1082,16 +1084,20 @@ main(int argc, char **argv)
         P12U_ListPKCS12File(import_file, slot, &slotPw, &p12FilePw);
 
     } else {
         Usage(progName);
         pk12uErrno = PK12UERR_USAGE;
     }
 
 done:
+    if (import_file != NULL)
+        PORT_ZFree(import_file, PL_strlen(import_file));
+    if (export_file != NULL)
+        PORT_ZFree(export_file, PL_strlen(export_file));
     if (slotPw.data != NULL)
         PORT_ZFree(slotPw.data, PL_strlen(slotPw.data));
     if (p12FilePw.data != NULL)
         PORT_ZFree(p12FilePw.data, PL_strlen(p12FilePw.data));
     if (slot)
         PK11_FreeSlot(slot);
     if (NSS_Shutdown() != SECSuccess) {
         pk12uErrno = 1;
--- a/security/nss/cmd/platlibs.mk
+++ b/security/nss/cmd/platlibs.mk
@@ -46,31 +46,33 @@ else
 CRYPTOLIB=$(FREEBL_LIB_DIR)/$(LIB_PREFIX)freebl.$(LIB_SUFFIX)
 SOFTOKENLIB=
 EXTRA_SHARED_LIBS += \
 	-L$(SOFTOKEN_LIB_DIR) \
 	-lsoftokn3 \
 	$(NULL)
 endif
 
+ifndef NSS_DISABLE_LIBPKIX
 ifndef NSS_BUILD_SOFTOKEN_ONLY
 PKIXLIB = \
 	$(DIST)/lib/$(LIB_PREFIX)pkixtop.$(LIB_SUFFIX) \
 	$(DIST)/lib/$(LIB_PREFIX)pkixutil.$(LIB_SUFFIX) \
 	$(DIST)/lib/$(LIB_PREFIX)pkixsystem.$(LIB_SUFFIX) \
 	$(DIST)/lib/$(LIB_PREFIX)pkixcrlsel.$(LIB_SUFFIX) \
 	$(DIST)/lib/$(LIB_PREFIX)pkixmodule.$(LIB_SUFFIX) \
 	$(DIST)/lib/$(LIB_PREFIX)pkixstore.$(LIB_SUFFIX) \
 	$(DIST)/lib/$(LIB_PREFIX)pkixparams.$(LIB_SUFFIX) \
 	$(DIST)/lib/$(LIB_PREFIX)pkixchecker.$(LIB_SUFFIX) \
 	$(DIST)/lib/$(LIB_PREFIX)pkixpki.$(LIB_SUFFIX) \
 	$(DIST)/lib/$(LIB_PREFIX)pkixtop.$(LIB_SUFFIX) \
 	$(DIST)/lib/$(LIB_PREFIX)pkixresults.$(LIB_SUFFIX) \
 	$(DIST)/lib/$(LIB_PREFIX)pkixcertsel.$(LIB_SUFFIX)
 endif
+endif
 
 NSS_LIBS_1=
 SECTOOL_LIB=
 NSS_LIBS_2=
 NSS_LIBS_3=
 NSS_LIBS_4=
 
 ifneq ($(NSS_BUILD_UTIL_ONLY),1)
--- a/security/nss/cmd/smimetools/cmsutil.c
+++ b/security/nss/cmd/smimetools/cmsutil.c
@@ -1164,17 +1164,17 @@ main(int argc, char **argv)
             case 'N':
                 if (mode != SIGN) {
                     fprintf(stderr,
                             "%s: option -N only supported with option -S.\n",
                             progName);
                     Usage(progName);
                     exit(1);
                 }
-                signOptions.nickname = strdup(optstate->value);
+                signOptions.nickname = PORT_Strdup(optstate->value);
                 break;
             case 'O':
                 mode = CERTSONLY;
                 break;
             case 'P':
                 if (mode != SIGN) {
                     fprintf(stderr,
                             "%s: option -P only supported with option -S.\n",
@@ -1532,16 +1532,21 @@ main(int argc, char **argv)
                 exitstatus = 1;
             }
             break;
         default:
             fprintf(stderr, "One of options -D, -S or -E must be set.\n");
             Usage(progName);
             exitstatus = 1;
     }
+
+    if (signOptions.nickname) {
+        PORT_Free(signOptions.nickname);
+    }
+
     if ((mode == SIGN || mode == ENVELOPE || mode == CERTSONLY) &&
         (!exitstatus)) {
         PLArenaPool *arena = PORT_NewArena(1024);
         NSSCMSEncoderContext *ecx;
         SECItem output = { 0, 0, 0 };
 
         if (!arena) {
             fprintf(stderr, "%s: out of memory.\n", progName);
--- a/security/nss/coreconf/config.mk
+++ b/security/nss/coreconf/config.mk
@@ -157,16 +157,20 @@ endif
 ifdef NSS_ALLOW_UNSUPPORTED_CRITICAL
 DEFINES += -DNSS_ALLOW_UNSUPPORTED_CRITICAL
 endif
 
 ifdef BUILD_LIBPKIX_TESTS
 DEFINES += -DBUILD_LIBPKIX_TESTS
 endif
 
+ifdef NSS_DISABLE_LIBPKIX
+DEFINES += -DNSS_DISABLE_LIBPKIX
+endif
+
 ifdef NSS_DISABLE_DBM
 DEFINES += -DNSS_DISABLE_DBM
 endif
 
 ifdef NSS_DISABLE_CHACHAPOLY
 DEFINES += -DNSS_DISABLE_CHACHAPOLY
 endif
 
--- a/security/nss/coreconf/coreconf.dep
+++ b/security/nss/coreconf/coreconf.dep
@@ -5,8 +5,9 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSS in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
+
--- a/security/nss/coreconf/mkdepend/parse.c
+++ b/security/nss/coreconf/mkdepend/parse.c
@@ -424,19 +424,26 @@ define(char *def, struct inclist *file)
 	val = "1";
     define2(def, val, file);
 }
 
 struct symtab **
 slookup(char *symbol, struct inclist *file)
 {
 	register int first = 0;
-	register int last = file->i_ndefs - 1;
+	register int last;
 
-	if (file) while (last >= first)
+	if (!file)
+	{
+	    return NULL;
+	}
+
+	last = file->i_ndefs - 1;
+
+	while (last >= first)
 	{
 	    /* Fast inline binary search */
 	    register char *s1;
 	    register char *s2;
 	    register int middle = first + (last - first) / 2;
 
 	    /* Fast inline strchr() */
 	    s1 = symbol;
@@ -456,17 +463,17 @@ slookup(char *symbol, struct inclist *fi
 	        first = middle + 1;
 	    }
 	    /* else ... */
 	    else
 	    {
 	        last = middle - 1;
 	    }
 	}
-	return(NULL);
+	return NULL;
 }
 
 static int 
 merge2defines(struct inclist *file1, struct inclist *file2)
 {
 	int i;
 
 	if ((file1==NULL) || (file2==NULL) ||
--- a/security/nss/coreconf/nsinstall/pathsub.c
+++ b/security/nss/coreconf/nsinstall/pathsub.c
@@ -1,16 +1,15 @@
 /* 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/. */
 
 /*
 ** Pathname subroutines.
 */
-#include <assert.h>
 #if defined(FREEBSD) || defined(BSDI) || defined(DARWIN)
 #include <sys/types.h>
 #endif /* FREEBSD */
 #include <dirent.h>
 #include <errno.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -153,17 +152,16 @@ xchdir(char *dir)
 
 int
 relatepaths(char *from, char *to, char *outpath)
 {
     char *cp, *cp2;
     int len;
     char buf[NAME_MAX];
 
-    assert(*from == '/' && *to == '/');
     if (!from || *from != '/')
 	fail("relatepaths: from path does not start with /");
     if (!to || *to != '/')
 	fail("relatepaths: to   path does not start with /");
 
     for (cp = to, cp2 = from; *cp == *cp2; cp++, cp2++)
 	if (*cp == '\0')
 	    break;
--- a/security/nss/coreconf/sanitizers.mk
+++ b/security/nss/coreconf/sanitizers.mk
@@ -6,14 +6,14 @@ SANITIZER_FLAGS_COMMON = -fsanitize=addr
 SANITIZER_CFLAGS = $(SANITIZER_FLAGS_COMMON)
 SANITIZER_LDFLAGS = $(SANITIZER_FLAGS_COMMON)
 OS_CFLAGS += $(SANITIZER_CFLAGS)
 LDFLAGS += $(SANITIZER_LDFLAGS)
 
 # ASan needs frame pointers to save stack traces for allocation/free sites.
 # (Warning: some platforms, like ARM Linux in Thumb mode, don't have useful
 # frame pointers even with this option.)
-SANITIZER_CFLAGS += -fno-omit-frame-pointer
+SANITIZER_CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls
 
 # You probably want to be able to get debug info for failures, even with an
 # optimized build.
 OPTIMIZER += -g
 endif
--- a/security/nss/external_tests/ssl_gtest/libssl_internals.c
+++ b/security/nss/external_tests/ssl_gtest/libssl_internals.c
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* This file contains functions for frobbing the internals of libssl */
 #include "libssl_internals.h"
 
 #include "nss.h"
+#include "pk11pub.h"
 #include "seccomon.h"
 #include "ssl.h"
 #include "sslimpl.h"
 
 SECStatus
 SSLInt_IncrementClientHandshakeVersion(PRFileDesc *fd)
 {
     sslSocket *ss = ssl_FindSocket(fd);
@@ -136,8 +137,98 @@ void SSLInt_ForceTimerExpiry(PRFileDesc 
   }
 
   if (!ss->ssl3.hs.rtTimerCb)
     return;
 
   ss->ssl3.hs.rtTimerStarted = PR_IntervalNow() -
       PR_MillisecondsToInterval(ss->ssl3.hs.rtTimeoutMs + 1);
 }
+
+#define CHECK_SECRET(secret)                    \
+  if (ss->ssl3.hs.secret) {                     \
+    fprintf(stderr, "%s != NULL\n", #secret);   \
+    return PR_FALSE;                            \
+  }
+
+PRBool SSLInt_CheckSecretsDestroyed(PRFileDesc *fd)
+{
+  sslSocket *ss = ssl_FindSocket(fd);
+  if (!ss) {
+    return PR_FALSE;
+  }
+
+  CHECK_SECRET(currentSecret);
+  CHECK_SECRET(resumptionPsk);
+  CHECK_SECRET(dheSecret);
+  CHECK_SECRET(earlyTrafficSecret);
+  CHECK_SECRET(hsTrafficSecret);
+
+  return PR_TRUE;
+}
+
+PRBool sslint_DamageTrafficSecret(PRFileDesc *fd,
+                                  size_t offset)
+{
+  unsigned char data[32] = {0};
+  PK11SymKey **keyPtr;
+  PK11SlotInfo *slot = PK11_GetInternalSlot();
+  SECItem key_item = {
+      siBuffer,
+      data,
+      sizeof(data)
+  };
+  sslSocket *ss = ssl_FindSocket(fd);
+  if (!ss) {
+    return PR_FALSE;
+  }
+  if (!slot) {
+    return PR_FALSE;
+  }
+  keyPtr = (PK11SymKey **)((char *)&ss->ssl3.hs + offset);
+  if (!keyPtr)
+    return PR_FALSE;
+  PK11_FreeSymKey(*keyPtr);
+  *keyPtr = PK11_ImportSymKey(slot,
+                              CKM_NSS_HKDF_SHA256, PK11_OriginUnwrap,
+                              CKA_DERIVE, &key_item, NULL);
+  PK11_FreeSlot(slot);
+  if (!*keyPtr)
+    return PR_FALSE;
+
+  return PR_TRUE;
+}
+
+
+PRBool SSLInt_DamageHsTrafficSecret(PRFileDesc *fd)
+{
+  return sslint_DamageTrafficSecret(
+      fd,
+      offsetof(SSL3HandshakeState,
+               hsTrafficSecret));
+}
+
+PRBool SSLInt_DamageEarlyTrafficSecret(PRFileDesc *fd)
+{
+  return sslint_DamageTrafficSecret(
+      fd,
+      offsetof(SSL3HandshakeState,
+               earlyTrafficSecret));
+}
+
+SECStatus
+SSLInt_Set0RttAlpn(PRFileDesc *fd, PRUint8 *data, unsigned int len)
+{
+  sslSocket *ss = ssl_FindSocket(fd);
+  if (!ss) {
+    return SECFailure;
+  }
+
+  ss->ssl3.nextProtoState = SSL_NEXT_PROTO_EARLY_VALUE;
+  if (ss->ssl3.nextProto.data) {
+    SECITEM_FreeItem(&ss->ssl3.nextProto, PR_FALSE);
+  }
+  if (!SECITEM_AllocItem(NULL, &ss->ssl3.nextProto, len))
+    return SECFailure;
+  PORT_Memcpy(ss->ssl3.nextProto.data, data, len);
+
+  return SECSuccess;
+}
--- a/security/nss/external_tests/ssl_gtest/libssl_internals.h
+++ b/security/nss/external_tests/ssl_gtest/libssl_internals.h
@@ -22,10 +22,14 @@ SECStatus SSLInt_UpdateSSLv2ClientRandom
                                          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);
+PRBool SSLInt_CheckSecretsDestroyed(PRFileDesc *fd);
+PRBool SSLInt_DamageHsTrafficSecret(PRFileDesc *fd);
+PRBool SSLInt_DamageEarlyTrafficSecret(PRFileDesc *fd);
+SECStatus SSLInt_Set0RttAlpn(PRFileDesc *fd, PRUint8 *data, unsigned int len);
 
 #endif // ndef libssl_internals_h_
--- a/security/nss/external_tests/ssl_gtest/ssl_agent_unittest.cc
+++ b/security/nss/external_tests/ssl_gtest/ssl_agent_unittest.cc
@@ -8,37 +8,108 @@
 #include "sslerr.h"
 #include "sslproto.h"
 
 #include <memory>
 
 #include "databuffer.h"
 #include "tls_agent.h"
 #include "tls_connect.h"
+#include "tls_filter.h"
 #include "tls_parser.h"
 
 namespace nss_test {
 
 #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
+// This is a 1-RTT ClientHello with ECDHE and DHE.
+const static uint8_t kCannedTls13ClientHello[] = {
+  0x01, 0x00, 0x01, 0xfc, 0x03, 0x04, 0x77, 0x5c,
+  0x3a, 0xd8, 0x3f, 0x43, 0x63, 0x98, 0xfa, 0x68,
+  0xfb, 0x01, 0x39, 0xff, 0x7c, 0x1a, 0x51, 0xa7,
+  0x92, 0xda, 0x97, 0xf5, 0x15, 0x78, 0xb3, 0xbb,
+  0x26, 0xa7, 0xed, 0x6f, 0x69, 0x71, 0x00, 0x00,
+  0x2a, 0xc0, 0x2b, 0xc0, 0x2f, 0xcc, 0xa9, 0xcc,
+  0xa8, 0xc0, 0x0a, 0xc0, 0x09, 0xc0, 0x13, 0xc0,
+  0x14, 0x00, 0x9e, 0xcc, 0xaa, 0x00, 0x33, 0x00,
+  0x32, 0x00, 0x39, 0x00, 0x38, 0x00, 0x16, 0x00,
+  0x13, 0x00, 0x2f, 0x00, 0x35, 0x00, 0x0a, 0x00,
+  0x05, 0x00, 0x04, 0x01, 0x00, 0x01, 0xa9, 0x00,
+  0x00, 0x00, 0x0b, 0x00, 0x09, 0x00, 0x00, 0x06,
+  0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0xff, 0x01,
+  0x00, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x0a, 0x00,
+  0x08, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x01,
+  0x00, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0xff,
+  0x02, 0x00, 0x02, 0x00, 0x0d, 0x00, 0x28, 0x01,
+  0x4b, 0x01, 0x49, 0x00, 0x17, 0x00, 0x41, 0x04,
+  0xbf, 0x31, 0xb4, 0x29, 0x96, 0xf4, 0xe6, 0x4a,
+  0xe3, 0xea, 0x87, 0x05, 0x38, 0x0e, 0x68, 0x02,
+  0xbc, 0x4a, 0x5d, 0x90, 0xed, 0xe7, 0xaa, 0x8e,
+  0xb8, 0x42, 0x84, 0xaa, 0x3a, 0x4f, 0x2b, 0xe3,
+  0x52, 0x9a, 0x9a, 0x76, 0xab, 0xf8, 0x2e, 0x59,
+  0xea, 0xcd, 0x2b, 0x2f, 0x03, 0x18, 0xd2, 0x0c,
+  0xc9, 0x07, 0x15, 0xca, 0xe6, 0x61, 0xf7, 0x79,
+  0x9f, 0xfe, 0xc5, 0x10, 0x40, 0x9e, 0x38, 0x33,
+  0x01, 0x00, 0x01, 0x00, 0xd8, 0x80, 0x1f, 0x06,
+  0x9a, 0xbb, 0xf7, 0xbb, 0xd4, 0x5c, 0x75, 0x1d,
+  0x8e, 0x09, 0x27, 0xad, 0x08, 0xb8, 0x16, 0x0f,
+  0x4f, 0x50, 0x79, 0xe1, 0x7e, 0xd4, 0x3b, 0xc0,
+  0x57, 0xcc, 0x00, 0x5e, 0x28, 0xd8, 0xb3, 0x16,
+  0x7f, 0x36, 0x48, 0x75, 0x8d, 0x03, 0xa4, 0x71,
+  0x86, 0x06, 0xf0, 0xe7, 0x57, 0x47, 0x35, 0xf0,
+  0x04, 0xfb, 0xf7, 0x6c, 0x7a, 0xdd, 0x05, 0x93,
+  0x53, 0x16, 0x12, 0x49, 0xbe, 0x35, 0x67, 0x47,
+  0x6e, 0x3a, 0x91, 0xef, 0x50, 0x09, 0x14, 0x98,
+  0x8b, 0x83, 0xc4, 0x62, 0x77, 0xf3, 0x57, 0x53,
+  0x3f, 0xf4, 0x82, 0xc0, 0x70, 0x25, 0x19, 0x9d,
+  0x93, 0xe2, 0xb9, 0x7b, 0xb4, 0x83, 0x31, 0xef,
+  0xd8, 0x3b, 0xd5, 0x25, 0x70, 0x64, 0x29, 0xa2,
+  0xc2, 0xc5, 0x73, 0x9a, 0xfe, 0x27, 0xca, 0xc0,
+  0x55, 0x34, 0x91, 0x95, 0x05, 0xbf, 0x5e, 0x54,
+  0x4d, 0x95, 0x43, 0x3d, 0x54, 0x6a, 0x89, 0x0b,
+  0x5e, 0xab, 0x08, 0x7b, 0xf8, 0x38, 0x0a, 0x56,
+  0x51, 0x9d, 0xbc, 0xdd, 0x46, 0xa9, 0xfc, 0x95,
+  0xe9, 0x75, 0x1c, 0xc8, 0x18, 0x7f, 0xed, 0xa9,
+  0xca, 0xb6, 0x5e, 0x77, 0x63, 0x33, 0xb1, 0xb5,
+  0x68, 0xce, 0xa5, 0x98, 0xec, 0x8c, 0x34, 0x98,
+  0x1c, 0xa9, 0xa5, 0x84, 0xec, 0xe6, 0xba, 0x0b,
+  0x11, 0xbf, 0x40, 0xa5, 0xf0, 0x3c, 0xd5, 0xd3,
+  0xac, 0x2f, 0x46, 0xed, 0xab, 0xc0, 0xc1, 0x78,
+  0x3f, 0x18, 0x64, 0x5b, 0xff, 0x31, 0xeb, 0x74,
+  0x06, 0x92, 0x42, 0x1e, 0x90, 0xf7, 0xea, 0xa5,
+  0x02, 0x33, 0x8e, 0x01, 0xe3, 0xfa, 0x70, 0x82,
+  0xe5, 0xe7, 0x67, 0x8b, 0x96, 0x20, 0x13, 0x2e,
+  0x65, 0x86, 0xab, 0x28, 0xc8, 0x1b, 0xfe, 0xb4,
+  0x98, 0xed, 0xa4, 0xa0, 0xee, 0xf9, 0x53, 0x74,
+  0x30, 0xac, 0x79, 0x2d, 0xf2, 0x92, 0xd0, 0x5e,
+  0x10, 0xd7, 0xb9, 0x41, 0x00, 0x0d, 0x00, 0x18,
+  0x00, 0x16, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01,
+  0x02, 0x01, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03,
+  0x02, 0x03, 0x05, 0x02, 0x04, 0x02, 0x02, 0x02,
+  0x00, 0x15, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
+
+const static uint8_t kCannedTls13ServerHello[] = {
+  0x03, 0x04, 0xe9, 0x01, 0xa0, 0x81, 0x37, 0x97,
+  0xaa, 0x8c, 0x7e, 0x21, 0x1c, 0x66, 0x3f, 0xa4,
+  0x0f, 0x4d, 0x74, 0x7a, 0xcd, 0x4b, 0xe1, 0x7f,
+  0x37, 0x85, 0x14, 0xb5, 0x7e, 0x30, 0x15, 0x91,
+  0xdf, 0x18, 0xc0, 0x2f, 0x00, 0x49, 0x00, 0x28,
+  0x00, 0x45, 0x00, 0x17, 0x00, 0x41, 0x04, 0x1a,
+  0x53, 0x9b, 0x39, 0xe6, 0xda, 0x66, 0xfc, 0x8a,
+  0x75, 0x68, 0xb7, 0x73, 0xc7, 0x21, 0x1f, 0x01,
+  0x04, 0x54, 0xb4, 0x99, 0x1f, 0x0b, 0x7e, 0xea,
+  0x95, 0xec, 0x78, 0x5c, 0x37, 0x7c, 0x31, 0x56,
+  0x04, 0xc8, 0xbf, 0x79, 0x47, 0x56, 0xb9, 0x87,
+  0x06, 0xc1, 0xfc, 0x63, 0x09, 0x5d, 0xfc, 0x1a,
+  0x9e, 0x2b, 0xb9, 0xca, 0xdb, 0x0e, 0x10, 0xec,
+  0xd5, 0x95, 0x0d, 0x0a, 0x5e, 0x3c, 0xf7
+};
+
+static const char *k0RttData = "ABCDEF";
 #endif
 
 TEST_P(TlsAgentTest, EarlyFinished) {
   DataBuffer buffer;
   MakeTrivialHandshakeRecord(kTlsHandshakeFinished, 0, &buffer);
   ProcessMessage(buffer, TlsAgent::STATE_ERROR,
                  SSL_ERROR_RX_UNEXPECTED_FINISHED);
 }
@@ -46,41 +117,41 @@ TEST_P(TlsAgentTest, EarlyFinished) {
 TEST_P(TlsAgentTest, EarlyCertificateVerify) {
   DataBuffer 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) {
+TEST_P(TlsAgentTestClient, CannedHello) {
   DataBuffer buffer;
   EnsureInit();
   agent_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_3,
                           SSL_LIBRARY_VERSION_TLS_1_3);
-  DataBuffer server_hello_inner(kCannedServerTls13ServerHello,
-                                sizeof(kCannedServerTls13ServerHello));
+  DataBuffer server_hello_inner(kCannedTls13ServerHello,
+                                sizeof(kCannedTls13ServerHello));
   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));
+  DataBuffer server_hello_inner(kCannedTls13ServerHello,
+                                sizeof(kCannedTls13ServerHello));
   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,
@@ -100,18 +171,18 @@ TEST_P(TlsAgentTestClient, EncryptedExte
                           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));
+  DataBuffer server_hello_inner(kCannedTls13ServerHello,
+                                sizeof(kCannedTls13ServerHello));
   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,
@@ -134,18 +205,18 @@ TEST_F(TlsAgentStreamTestClient, Encrypt
   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));
+  DataBuffer server_hello_inner(kCannedTls13ServerHello,
+                                sizeof(kCannedTls13ServerHello));
   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);
@@ -170,16 +241,69 @@ TEST_F(TlsAgentDgramTestClient, Encrypte
 
   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(TlsAgentStreamTestClient, Set0RttOptionThenWrite) {
+  EnsureInit();
+  agent_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
+                          SSL_LIBRARY_VERSION_TLS_1_3);
+  agent_->StartConnect();
+  agent_->Set0RttEnabled(true);
+  auto filter =
+      new TlsInspectorRecordHandshakeMessage(kTlsHandshakeClientHello);
+  agent_->SetPacketFilter(filter);
+  PRInt32 rv = PR_Write(agent_->ssl_fd(),
+                        k0RttData, strlen(k0RttData));
+  EXPECT_EQ(-1, rv);
+  int32_t err = PORT_GetError();
+  EXPECT_EQ(PR_WOULD_BLOCK_ERROR, err);
+  EXPECT_LT(0UL, filter->buffer().len());
+}
+
+TEST_F(TlsAgentStreamTestClient, Set0RttOptionThenRead) {
+  EnsureInit();
+  agent_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
+                          SSL_LIBRARY_VERSION_TLS_1_3);
+  agent_->StartConnect();
+  agent_->Set0RttEnabled(true);
+  DataBuffer buffer;
+  MakeRecord(kTlsApplicationDataType, SSL_LIBRARY_VERSION_TLS_1_3,
+             reinterpret_cast<const uint8_t *>(k0RttData),
+             strlen(k0RttData), &buffer);
+  ProcessMessage(buffer, TlsAgent::STATE_ERROR,
+                 SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA);
+}
+
+// The server is allowing 0-RTT but the client doesn't offer it,
+// so trial decryption isn't engaged and 0-RTT messages cause
+// an error.
+TEST_F(TlsAgentStreamTestServer, Set0RttOptionClientHelloThenRead) {
+  EnsureInit();
+  agent_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
+                          SSL_LIBRARY_VERSION_TLS_1_3);
+  agent_->StartConnect();
+  agent_->Set0RttEnabled(true);
+  DataBuffer buffer;
+  MakeRecord(kTlsHandshakeType, SSL_LIBRARY_VERSION_TLS_1_3,
+             kCannedTls13ClientHello, sizeof(kCannedTls13ClientHello),
+             &buffer);
+  ProcessMessage(buffer, TlsAgent::STATE_CONNECTING);
+  MakeRecord(kTlsApplicationDataType, SSL_LIBRARY_VERSION_TLS_1_3,
+             reinterpret_cast<const uint8_t *>(k0RttData),
+             strlen(k0RttData), &buffer);
+  ProcessMessage(buffer, TlsAgent::STATE_ERROR,
+                 SSL_ERROR_BAD_MAC_READ);
+}
+
 #endif
 
 INSTANTIATE_TEST_CASE_P(AgentTests, TlsAgentTest,
                         ::testing::Combine(
                              TlsAgentTestBase::kTlsRolesAll,
                              TlsConnectTestBase::kTlsModesStream));
 #ifdef NSS_ENABLE_TLS_1_3
 INSTANTIATE_TEST_CASE_P(ClientTests, TlsAgentTestClient,
--- a/security/nss/external_tests/ssl_gtest/ssl_ciphersuite_unittest.cc
+++ b/security/nss/external_tests/ssl_gtest/ssl_ciphersuite_unittest.cc
@@ -236,18 +236,17 @@ INSTANTIATE_CIPHER_TEST_P(AEAD, All, V12
 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);
+                          TLS_DHE_DSS_WITH_AES_256_CBC_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,
--- a/security/nss/external_tests/ssl_gtest/ssl_loopback_unittest.cc
+++ b/security/nss/external_tests/ssl_gtest/ssl_loopback_unittest.cc
@@ -39,16 +39,18 @@ uint8_t kBogusClientKeyExchange[] = {
   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 };
 
+typedef std::function<void(void)> VoidFunction;
+
 // When we see the ClientKeyExchange from |client|, increment the
 // ClientHelloVersion on |server|.
 class TlsInspectorClientHelloVersionChanger : public TlsHandshakeFilter {
  public:
   TlsInspectorClientHelloVersionChanger(TlsAgent* server) : server_(server) {}
 
   virtual PacketFilter::Action FilterHandshake(
       const HandshakeHeader& header,
@@ -227,43 +229,43 @@ TEST_P(TlsConnectGeneric, ConnectResumeC
 
   Reset();
   ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
   ExpectResumption(RESUME_TICKET);
   Connect();
   SendReceive();
 }
 
-TEST_P(TlsConnectGenericPre13, ConnectResumeClientServerTicketOnly) {
+TEST_P(TlsConnectGeneric, ConnectResumeClientServerTicketOnly) {
   // This causes no resumption because the client needs the
   // session cache to resume even with tickets.
   ConfigureSessionCache(RESUME_TICKET, RESUME_TICKET);
   Connect();
   SendReceive();
 
   Reset();
   ConfigureSessionCache(RESUME_TICKET, RESUME_TICKET);
   ExpectResumption(RESUME_NONE);
   Connect();
   SendReceive();
 }
 
-TEST_P(TlsConnectGenericPre13, ConnectResumeClientBothServerNone) {
+TEST_P(TlsConnectGeneric, ConnectResumeClientBothServerNone) {
   ConfigureSessionCache(RESUME_BOTH, RESUME_NONE);
   Connect();
   SendReceive();
 
   Reset();
   ConfigureSessionCache(RESUME_BOTH, RESUME_NONE);
   ExpectResumption(RESUME_NONE);
   Connect();
   SendReceive();
 }
 
-TEST_P(TlsConnectGenericPre13, ConnectResumeClientNoneServerBoth) {
+TEST_P(TlsConnectGeneric, ConnectResumeClientNoneServerBoth) {
   ConfigureSessionCache(RESUME_NONE, RESUME_BOTH);
   Connect();
   SendReceive();
 
   Reset();
   ConfigureSessionCache(RESUME_NONE, RESUME_BOTH);
   ExpectResumption(RESUME_NONE);
   Connect();
@@ -474,18 +476,23 @@ TEST_P(TlsConnectTls12, RequestClientAut
                                   PR_ARRAY_SIZE(SignatureRsaSha384));
   server_->RequestClientAuth(false);
   Connect();
 }
 
 TEST_P(TlsConnectGeneric, ConnectAlpn) {
   EnableAlpn();
   Connect();
-  client_->CheckAlpn(SSL_NEXT_PROTO_SELECTED, "a");
-  server_->CheckAlpn(SSL_NEXT_PROTO_NEGOTIATED, "a");
+  CheckAlpn("a");
+}
+
+TEST_P(TlsConnectGeneric, ConnectAlpnClone) {
+  EnsureModelSockets();
+  Connect();
+  CheckAlpn("a");
 }
 
 TEST_P(TlsConnectDatagram, ConnectSrtp) {
   EnableSrtp();
   Connect();
   CheckSrtp();
   SendReceive();
 }
@@ -1094,37 +1101,287 @@ TEST_F(TlsConnectTest, DisableServerPSKA
   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_F(TlsConnectTest, DamageSecretHandleClientFinished) {
+  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);
+  server_->StartConnect();
+  client_->StartConnect();
+  client_->Handshake();
+  server_->Handshake();
+  std::cerr << "Damaging HS secret\n";
+  SSLInt_DamageHsTrafficSecret(server_->ssl_fd());
+  client_->Handshake();
+  server_->Handshake();
+  // The client thinks it has connected.
+  EXPECT_EQ(TlsAgent::STATE_CONNECTED, client_->state());
+  server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
+  client_->Handshake();
+  client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
+}
+
+// Read record N, process it, and then run the indicated function.
+// Records are numbered from 0.
+class AfterRecordN : public TlsRecordFilter {
+ public:
+  AfterRecordN(TlsAgent *src, TlsAgent *dest, unsigned int record,
+               VoidFunction func) :
+      src_(src),
+      dest_(dest),
+      record_(record),
+      func_(func),
+      counter_(0) {}
+
+  virtual PacketFilter::Action FilterRecord(
+      const RecordHeader& header, const DataBuffer& body, DataBuffer* out) {
+    if (counter_++ == record_) {
+      DataBuffer buf;
+      header.Write(&buf, 0, body);
+      src_->SendDirect(buf);
+      dest_->Handshake();
+      func_();
+      return DROP;
+    }
+
+    return KEEP;
+  }
+
+ private:
+  TlsAgent *src_;
+  TlsAgent *dest_;
+  unsigned int record_;
+  VoidFunction func_;
+  unsigned int counter_;
+};
+
+TEST_F(TlsConnectTest, DamageSecretHandleServerFinished) {
+  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);
+  server_->SetPacketFilter(new AfterRecordN(
+      server_,
+      client_,
+      0, // ServerHello.
+      [this]() {
+        SSLInt_DamageHsTrafficSecret(client_->ssl_fd());
+      }));
+  ConnectExpectFail();
+  client_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
+  server_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
+}
+
+TEST_F(TlsConnectTest, DamageSecretHandleZeroRttClientFinished) {
+  SetupForZeroRtt();
+  client_->Set0RttEnabled(true);
+  server_->Set0RttEnabled(true);
+  client_->SetPacketFilter(new AfterRecordN(
+      client_,
+      server_,
+      0, // ClientHello.
+      [this]() {
+        SSLInt_DamageEarlyTrafficSecret(server_->ssl_fd());
+      }));
+  ConnectExpectFail();
+  client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
+  server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
+}
+
+TEST_F(TlsConnectTest, ZeroRttServerRejectByOption) {
+  SetupForZeroRtt();
+  client_->Set0RttEnabled(true);
+  ExpectResumption(RESUME_TICKET);
+  ZeroRttSendReceive(false);
+  Handshake();
+  CheckConnected();
+  SendReceive();
+}
+
+TEST_F(TlsConnectTest, ZeroRttServerForgetTicket) {
+  SetupForZeroRtt();
+  client_->Set0RttEnabled(true);
+  server_->Set0RttEnabled(true);
+  ClearServerCache();
+  ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+  ExpectResumption(RESUME_NONE);
+  ZeroRttSendReceive(false);
+  Handshake();
+  CheckConnected();
+  SendReceive();
+}
+
+TEST_F(TlsConnectTest, ZeroRttServerOnly) {
+  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_NONE);
+  server_->Set0RttEnabled(true);
+  client_->StartConnect();
+  server_->StartConnect();
+
+  // Client sends ordinary ClientHello.
+  client_->Handshake();
+
+  // Verify that the server doesn't get data.
+  uint8_t buf[100];
+  PRInt32 rv = PR_Read(server_->ssl_fd(), buf, sizeof(buf));
+  EXPECT_EQ(SECFailure, rv);
+  EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
+
+  // Now make sure that things complete.
+  Handshake();
+  CheckConnected();
+  SendReceive();
+  CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
+}
+
+TEST_F(TlsConnectTest, ZeroRtt) {
+  SetupForZeroRtt();
+  client_->Set0RttEnabled(true);
+  server_->Set0RttEnabled(true);
+  ExpectResumption(RESUME_TICKET);
+  ZeroRttSendReceive(true);
+  Handshake();
+  ExpectEarlyDataAccepted(true);
+  CheckConnected();
+  SendReceive();
+}
+
+TEST_F(TlsConnectTest, TestTls13ZeroRttAlpn) {
+  EnableAlpn();
+  SetupForZeroRtt();
+  EnableAlpn();
+  client_->Set0RttEnabled(true);
+  server_->Set0RttEnabled(true);
+  ExpectResumption(RESUME_TICKET);
+  ExpectEarlyDataAccepted(true);
+  ZeroRttSendReceive(true, [this]() {
+      client_->CheckAlpn(SSL_NEXT_PROTO_EARLY_VALUE, "a");
+      return true;
+    });
+  Handshake();
+  CheckConnected();
+  SendReceive();
+  CheckAlpn("a");
+}
+
+// Remove the old ALPN value and so the client will not offer ALPN.
+TEST_F(TlsConnectTest, TestTls13ZeroRttAlpnChangeBoth) {
+  EnableAlpn();
+  SetupForZeroRtt();
+  static const uint8_t alpn[] = { 0x01, 0x62 };  // "b"
+  EnableAlpn(alpn, sizeof(alpn));
+  client_->Set0RttEnabled(true);
+  server_->Set0RttEnabled(true);
+  ExpectResumption(RESUME_TICKET);
+  ZeroRttSendReceive(false, [this]() {
+      client_->CheckAlpn(SSL_NEXT_PROTO_NO_SUPPORT);
+      return false;
+    });
+  Handshake();
+  CheckConnected();
+  SendReceive();
+  CheckAlpn("b");
+}
+
+// Have the server negotiate a different ALPN value, and therefore
+// reject 0-RTT.
+TEST_F(TlsConnectTest, TestTls13ZeroRttAlpnChangeServer) {
+  EnableAlpn();
+  SetupForZeroRtt();
+  static const uint8_t client_alpn[] = { 0x01, 0x61, 0x01, 0x62 }; // "a", "b"
+  static const uint8_t server_alpn[] = { 0x01, 0x62 };  // "b"
+  client_->EnableAlpn(client_alpn, sizeof(client_alpn));
+  server_->EnableAlpn(server_alpn, sizeof(server_alpn));
+  client_->Set0RttEnabled(true);
+  server_->Set0RttEnabled(true);
+  ExpectResumption(RESUME_TICKET);
+  ZeroRttSendReceive(false, [this]() {
+      client_->CheckAlpn(SSL_NEXT_PROTO_EARLY_VALUE, "a");
+      return true;
+    });
+  Handshake();
+  CheckConnected();
+  SendReceive();
+  CheckAlpn("b");
+}
+
+// Check that the client validates the ALPN selection of the server.
+// Stomp the ALPN on the client after sending the ClientHello so
+// that the server selection appears to be incorrect. The client
+// should then fail the connection.
+TEST_F(TlsConnectTest, TestTls13ZeroRttNoAlpnServer) {
+  EnableAlpn();
+  SetupForZeroRtt();
+  client_->Set0RttEnabled(true);
+  server_->Set0RttEnabled(true);
+  EnableAlpn();
+  ExpectResumption(RESUME_TICKET);
+  ZeroRttSendReceive(true, [this]() {
+      PRUint8 b[] = {'b'};
+      client_->CheckAlpn(SSL_NEXT_PROTO_EARLY_VALUE, "a");
+      EXPECT_EQ(SECSuccess, SSLInt_Set0RttAlpn(client_->ssl_fd(), b,
+                                               sizeof(b)));
+      client_->CheckAlpn(SSL_NEXT_PROTO_EARLY_VALUE, "b");
+      return true;
+    });
+  Handshake();
+  client_->CheckErrorCode(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
+  server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
+}
+
+// Set up with no ALPN and then set the client so it thinks it has ALPN.
+// The server responds without the extension and the client returns an
+// error.
+TEST_F(TlsConnectTest, TestTls13ZeroRttNoAlpnClient) {
+  SetupForZeroRtt();
+  client_->Set0RttEnabled(true);
+  server_->Set0RttEnabled(true);
+  ExpectResumption(RESUME_TICKET);
+  ZeroRttSendReceive(true, [this]() {
+      PRUint8 b[] = {'b'};
+      EXPECT_EQ(SECSuccess, SSLInt_Set0RttAlpn(client_->ssl_fd(), b, 1));
+      client_->CheckAlpn(SSL_NEXT_PROTO_EARLY_VALUE, "b");
+      return true;
+    });
+  Handshake();
+  client_->CheckErrorCode(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
+  server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
+}
+
 TEST_P(TlsConnectDatagram, TestDtlsHolddownExpiry) {
   Connect();
   std::cerr << "Expiring holddown timer\n";
   SSLInt_ForceTimerExpiry(client_->ssl_fd());
   SSLInt_ForceTimerExpiry(server_->ssl_fd());
   SendReceive();
   if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
-    EXPECT_EQ(1, SSLInt_CountTls13CipherSpecs(client_->ssl_fd()));
+    // One for send, one for receive.
+    EXPECT_EQ(2, SSLInt_CountTls13CipherSpecs(client_->ssl_fd()));
   }
 }
 
 #endif
 
 class BeforeFinished : public TlsRecordFilter {
  private:
   enum HandshakeState {
     BEFORE_CCS,
     AFTER_CCS,
     DONE
   };
-  typedef std::function<void(void)> VoidFunction;
 
  public:
   BeforeFinished(TlsAgent* client, TlsAgent* server,
                  VoidFunction before_ccs, VoidFunction before_finished)
       : client_(client),
         server_(server),
         before_ccs_(before_ccs),
         before_finished_(before_finished),
@@ -1281,17 +1538,16 @@ TEST_P(TlsConnectGenericPre13, ConnectEC
 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) {}
--- a/security/nss/external_tests/ssl_gtest/test_io.cc
+++ b/security/nss/external_tests/ssl_gtest/test_io.cc
@@ -44,16 +44,17 @@ class Packet : public DataBuffer {
  private:
   size_t offset_;
 };
 
 // Implementation of NSPR methods
 static PRStatus DummyClose(PRFileDesc *f) {
   DummyPrSocket *io = reinterpret_cast<DummyPrSocket *>(f->secret);
   f->secret = nullptr;
+  f->dtor(f);
   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);
 }
@@ -393,16 +394,25 @@ Poller *Poller::Instance() {
   return instance;
 }
 
 void Poller::Shutdown() {
   delete instance;
   instance = nullptr;
 }
 
+Poller::~Poller()
+{
+  while (!timers_.empty()) {
+    Timer *timer = timers_.top();
+    timers_.pop();
+    delete timer;
+  }
+}
+
 void Poller::Wait(Event event, DummyPrSocket *adapter, PollTarget *target,
                   PollCallback cb) {
   auto it = waiters_.find(adapter);
   Waiter *waiter;
 
   if (it == waiters_.end()) {
     waiter = new Waiter(adapter);
   } else {
--- a/security/nss/external_tests/ssl_gtest/test_io.h
+++ b/security/nss/external_tests/ssl_gtest/test_io.h
@@ -113,16 +113,17 @@ class Poller {
             PollCallback cb);
   void Cancel(Event event, DummyPrSocket* adapter);
   void SetTimer(uint32_t timer_ms, PollTarget* target, PollCallback cb,
                 Timer** handle);
   bool Poll();
 
  private:
   Poller() : waiters_(), timers_() {}
+  ~Poller();
 
   class Waiter {
    public:
     Waiter(DummyPrSocket* io) : io_(io) {
       memset(&callbacks_[0], 0, sizeof(callbacks_));
     }
 
     void WaitFor(Event event, PollCallback callback);
--- a/security/nss/external_tests/ssl_gtest/tls_agent.cc
+++ b/security/nss/external_tests/ssl_gtest/tls_agent.cc
@@ -109,34 +109,39 @@ bool TlsAgent::ConfigServerCert(const st
   SECStatus rv = SSL_ConfigSecureServer(ssl_fd_, nullptr, nullptr, ssl_kea_null);
   EXPECT_EQ(SECFailure, rv);
   rv = SSL_ConfigServerCert(ssl_fd_, cert.get(), priv.get(), nullptr, 0);
   EXPECT_EQ(SECSuccess, rv);
 
   return rv == SECSuccess;
 }
 
-bool TlsAgent::EnsureTlsSetup() {
+bool TlsAgent::EnsureTlsSetup(PRFileDesc *modelSocket) {
   // Don't set up twice
   if (ssl_fd_) return true;
 
   if (adapter_->mode() == STREAM) {
-    ssl_fd_ = SSL_ImportFD(nullptr, pr_fd_);
+    ssl_fd_ = SSL_ImportFD(modelSocket, pr_fd_);
   } else {
-    ssl_fd_ = DTLS_ImportFD(nullptr, pr_fd_);
+    ssl_fd_ = DTLS_ImportFD(modelSocket, pr_fd_);
   }
 
   EXPECT_NE(nullptr, ssl_fd_);
   if (!ssl_fd_) return false;
   pr_fd_ = nullptr;
 
   SECStatus rv = SSL_VersionRangeSet(ssl_fd_, &vrange_);
   EXPECT_EQ(SECSuccess, rv);
   if (rv != SECSuccess) return false;
 
+  // Needs to be set before configuring server certs.
+  rv = SSL_OptionSet(ssl_fd_, SSL_NO_STEP_DOWN, PR_TRUE);
+  EXPECT_EQ(SECSuccess, rv);
+  if (rv != SECSuccess) return false;
+
   if (role_ == SERVER) {
     EXPECT_TRUE(ConfigServerCert(name_, true));
 
     rv = SSL_SNISocketConfigHook(ssl_fd_, SniHook, this);
     EXPECT_EQ(SECSuccess, rv);
     if (rv != SECSuccess) return false;
   } else {
     rv = SSL_SetURL(ssl_fd_, "server");
@@ -200,18 +205,18 @@ void TlsAgent::RequestClientAuth(bool re
                           requireAuth ? PR_TRUE : PR_FALSE));
 
   EXPECT_EQ(SECSuccess,
             SSL_AuthCertificateHook(ssl_fd_, &TlsAgent::ClientAuthenticated,
                                     this));
   expect_client_auth_ = true;
 }
 
-void TlsAgent::StartConnect() {
-  EXPECT_TRUE(EnsureTlsSetup());
+void TlsAgent::StartConnect(PRFileDesc *model) {
+  EXPECT_TRUE(EnsureTlsSetup(model));
 
   SECStatus rv;
   rv = SSL_ResetHandshake(ssl_fd_, role_ == SERVER ? PR_TRUE : PR_FALSE);
   EXPECT_EQ(SECSuccess, rv);
   SetState(STATE_CONNECTING);
 }
 
 void TlsAgent::DisableAllCiphers() {
@@ -227,34 +232,34 @@ void TlsAgent::EnableCiphersByKeyExchang
   for (size_t i = 0; i < SSL_NumImplementedCiphers; ++i) {
     SSLCipherSuiteInfo csinfo;
 
     SECStatus rv = SSL_GetCipherSuiteInfo(SSL_ImplementedCiphers[i],
                                           &csinfo, sizeof(csinfo));
     ASSERT_EQ(SECSuccess, rv);
     EXPECT_EQ(sizeof(csinfo), csinfo.length);
 
-    if (csinfo.keaType == kea) {
+    if (csinfo.keaType == kea && !csinfo.isExportable) {
       rv = SSL_CipherPrefSet(ssl_fd_, SSL_ImplementedCiphers[i], PR_TRUE);
       EXPECT_EQ(SECSuccess, rv);
     }
   }
 }
 
 void TlsAgent::EnableCiphersByAuthType(SSLAuthType authType) {
   EXPECT_TRUE(EnsureTlsSetup());
 
   for (size_t i = 0; i < SSL_NumImplementedCiphers; ++i) {
     SSLCipherSuiteInfo csinfo;
 
     SECStatus rv = SSL_GetCipherSuiteInfo(SSL_ImplementedCiphers[i],
                                           &csinfo, sizeof(csinfo));
     ASSERT_EQ(SECSuccess, rv);
 
-    if (csinfo.authType == authType) {
+    if (csinfo.authType == authType && !csinfo.isExportable) {
       rv = SSL_CipherPrefSet(ssl_fd_, SSL_ImplementedCiphers[i], PR_TRUE);
       EXPECT_EQ(SECSuccess, rv);
     }
   }
 }
 
 void TlsAgent::EnableSingleCipher(uint16_t cipher) {
   DisableAllCiphers();
@@ -273,16 +278,24 @@ void TlsAgent::SetSessionTicketsEnabled(
 void TlsAgent::SetSessionCacheEnabled(bool en) {
   EXPECT_TRUE(EnsureTlsSetup());
 
   SECStatus rv = SSL_OptionSet(ssl_fd_, SSL_NO_CACHE,
                                en ? PR_FALSE : PR_TRUE);
   EXPECT_EQ(SECSuccess, rv);
 }
 
+void TlsAgent::Set0RttEnabled(bool en) {
+  EXPECT_TRUE(EnsureTlsSetup());
+
+  SECStatus rv = SSL_OptionSet(ssl_fd_, SSL_ENABLE_0RTT_DATA,
+                               en ? PR_TRUE : PR_FALSE);
+  EXPECT_EQ(SECSuccess, rv);
+}
+
 void TlsAgent::SetVersionRange(uint16_t minver, uint16_t maxver) {
    vrange_.min = minver;
    vrange_.max = maxver;
 
    if (ssl_fd_) {
      SECStatus rv = SSL_VersionRangeSet(ssl_fd_, &vrange_);
      EXPECT_EQ(SECSuccess, rv);
    }
@@ -431,17 +444,22 @@ void TlsAgent::CheckAlpn(SSLNextProtoSta
   SSLNextProtoState state;
   char chosen[10];
   unsigned int chosen_len;
   SECStatus rv = SSL_GetNextProto(ssl_fd_, &state,
                                   reinterpret_cast<unsigned char*>(chosen),
                                   &chosen_len, sizeof(chosen));
   EXPECT_EQ(SECSuccess, rv);
   EXPECT_EQ(expected_state, state);
-  EXPECT_EQ(expected, std::string(chosen, chosen_len));
+  if (state == SSL_NEXT_PROTO_NO_SUPPORT) {
+    EXPECT_EQ("", expected);
+  } else {
+    EXPECT_NE("", expected);
+    EXPECT_EQ(expected, std::string(chosen, chosen_len));
+  }
 }
 
 void TlsAgent::EnableSrtp() {
   EXPECT_TRUE(EnsureTlsSetup());
   const uint16_t ciphers[] = {
     SRTP_AES128_CM_HMAC_SHA1_80, SRTP_AES128_CM_HMAC_SHA1_32
   };
   EXPECT_EQ(SECSuccess, SSL_SetSRTPCiphers(ssl_fd_, ciphers,
@@ -521,18 +539,21 @@ void TlsAgent::Connected() {
   EXPECT_EQ(expected_cipher_suite_, info_.cipherSuite);
 
   rv = SSL_GetCipherSuiteInfo(info_.cipherSuite, &csinfo_, sizeof(csinfo_));
   EXPECT_EQ(SECSuccess, rv);
   EXPECT_EQ(sizeof(csinfo_), csinfo_.length);
 
   if (expected_version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
     PRInt32 cipherSuites = SSLInt_CountTls13CipherSpecs(ssl_fd_);
-    EXPECT_EQ(((mode_ == DGRAM) && (role_ == CLIENT)) ? 2 : 1, cipherSuites);
+    // We use one ciphersuite in each direction, plus one that's kept around
+    // by DTLS for retransmission.
+    EXPECT_EQ(((mode_ == DGRAM) && (role_ == CLIENT)) ? 3 : 2, cipherSuites);
   }
+
   SetState(STATE_CONNECTED);
 }
 
 void TlsAgent::EnableExtendedMasterSecret() {
   ASSERT_TRUE(EnsureTlsSetup());
 
   SECStatus rv = SSL_OptionSet(ssl_fd_,
                                SSL_ENABLE_EXTENDED_MASTER_SECRET,
@@ -544,16 +565,28 @@ void TlsAgent::EnableExtendedMasterSecre
 void TlsAgent::CheckExtendedMasterSecret(bool expected) {
   if (version() >= SSL_LIBRARY_VERSION_TLS_1_3) {
     expected = PR_TRUE;
   }
   ASSERT_EQ(expected, info_.extendedMasterSecretUsed != PR_FALSE)
       << "unexpected extended master secret state for " << name_;
 }
 
+void TlsAgent::CheckEarlyDataAccepted(bool expected) {
+  if (version() < SSL_LIBRARY_VERSION_TLS_1_3) {
+    expected = false;
+  }
+  ASSERT_EQ(expected, info_.earlyDataAccepted != PR_FALSE)
+      << "unexpected early data state for " << name_;
+}
+
+void TlsAgent::CheckSecretsDestroyed() {
+  ASSERT_EQ(PR_TRUE, SSLInt_CheckSecretsDestroyed(ssl_fd_));
+}
+
 void TlsAgent::DisableRollbackDetection() {
   ASSERT_TRUE(EnsureTlsSetup());
 
   SECStatus rv = SSL_OptionSet(ssl_fd_,
                                SSL_ROLLBACK_DETECTION,
                                PR_FALSE);
 
   ASSERT_EQ(SECSuccess, rv);
--- a/security/nss/external_tests/ssl_gtest/tls_agent.h
+++ b/security/nss/external_tests/ssl_gtest/tls_agent.h
@@ -73,68 +73,71 @@ class TlsAgent : public PollTarget {
 
   void SetPeer(TlsAgent* peer) { adapter_->SetPeer(peer->adapter_); }
 
   void SetPacketFilter(PacketFilter* filter) {
     adapter_->SetPacketFilter(filter);
   }
 
 
-  void StartConnect();
+  void StartConnect(PRFileDesc *model = nullptr);
   void CheckKEAType(SSLKEAType type) const;
   void CheckAuthType(SSLAuthType type) const;
 
   void DisableAllCiphers();
   void EnableCiphersByAuthType(SSLAuthType authType);
   void EnableCiphersByKeyExchange(SSLKEAType kea);
   void EnableSingleCipher(uint16_t cipher);
 
   void Handshake();
   // Marks the internal state as CONNECTING in anticipation of renegotiation.
   void PrepareForRenegotiate();
   // Prepares for renegotiation, then actually triggers it.
   void StartRenegotiate();
   bool ConfigServerCert(const std::string& name, bool updateKeyBits = false);
-  bool EnsureTlsSetup();
+  bool EnsureTlsSetup(PRFileDesc *modelSocket = nullptr);
 
   void SetupClientAuth();
   void RequestClientAuth(bool requireAuth);
   bool GetClientAuthCredentials(CERTCertificate** cert,
                                 SECKEYPrivateKey** priv) const;
 
   void ConfigureSessionCache(SessionResumptionMode mode);
   void SetSessionTicketsEnabled(bool en);
   void SetSessionCacheEnabled(bool en);
+  void Set0RttEnabled(bool en);
   void SetVersionRange(uint16_t minver, uint16_t maxver);
   void GetVersionRange(uint16_t* minver, uint16_t* maxver);
   void CheckPreliminaryInfo();
   void SetExpectedVersion(uint16_t version);
   void SetServerKeyBits(uint16_t bits);
   void SetExpectedReadError(bool err);
   void EnableFalseStart();
   void ExpectResumption();
   void SetSignatureAlgorithms(const SSLSignatureAndHashAlg* algorithms,
                               size_t count);
   void EnableAlpn(const uint8_t* val, size_t len);
   void CheckAlpn(SSLNextProtoState expected_state,
-                 const std::string& expected) const;
+                 const std::string& expected = "") const;
   void EnableSrtp();
   void CheckSrtp() const;
   void CheckErrorCode(int32_t expected) const;
   // Send data on the socket, encrypting it.
   void SendData(size_t bytes, size_t blocksize = 1024);
   // Send data directly to the underlying socket, skipping the TLS layer.
   void SendDirect(const DataBuffer& buf);
   void ReadBytes();
   void ResetSentBytes(); // Hack to test drops.
   void EnableExtendedMasterSecret();
   void CheckExtendedMasterSecret(bool expected);
+  void CheckEarlyDataAccepted(bool expected);
   void DisableRollbackDetection();
   void EnableCompression();
   void SetDowngradeCheckVersion(uint16_t version);
+  void CheckSecretsDestroyed();
 
   const std::string& name() const { return name_; }
 
   Role role() const { return role_; }
   std::string role_str() const { return role_ == SERVER ? "server" : "client"; }
 
   State state() const { return state_; }
 
@@ -400,16 +403,21 @@ class TlsAgentTestClient : public TlsAge
                                           ToMode(GetParam())) {}
 };
 
 class TlsAgentStreamTestClient : public TlsAgentTestBase {
  public:
   TlsAgentStreamTestClient() : TlsAgentTestBase(TlsAgent::CLIENT, STREAM) {}
 };
 
+class TlsAgentStreamTestServer : public TlsAgentTestBase {
+ public:
+  TlsAgentStreamTestServer() : TlsAgentTestBase(TlsAgent::SERVER, 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
@@ -105,20 +105,23 @@ static std::string VersionString(uint16_
     return "";
   }
 }
 
 TlsConnectTestBase::TlsConnectTestBase(Mode mode, uint16_t version)
       : mode_(mode),
         client_(new TlsAgent(TlsAgent::kClient, TlsAgent::CLIENT, mode_)),
         server_(new TlsAgent(TlsAgent::kServerRsa, TlsAgent::SERVER, mode_)),
+        client_model_(nullptr),
+        server_model_(nullptr),
         version_(version),
         expected_resumption_mode_(RESUME_NONE),
         session_ids_(),
-        expect_extended_master_secret_(false) {
+        expect_extended_master_secret_(false),
+        expect_early_data_accepted_(false) {
   std::string v;
   if (mode_ == DGRAM && version_ == SSL_LIBRARY_VERSION_TLS_1_1) {
     v = "1.0";
   } else {
     v = VersionString(version_);
   }
   std::cerr << "Version: " << mode_ << " " << v << std::endl;
 }
@@ -143,16 +146,21 @@ void TlsConnectTestBase::SetUp() {
   SSLInt_ClearSessionTicketKey();
   ClearStats();
   Init();
 }
 
 void TlsConnectTestBase::TearDown() {
   delete client_;
   delete server_;
+  if (client_model_) {
+    ASSERT_NE(server_model_, nullptr);
+    delete client_model_;
+    delete server_model_;
+  }
 
   SSL_ClearSessionCache();
   SSLInt_ClearSessionTicketKey();
   SSL_ShutdownServerSessionIDCache();
 }
 
 void TlsConnectTestBase::Init() {
   EXPECT_TRUE(client_->Init());
@@ -187,18 +195,18 @@ void TlsConnectTestBase::ExpectResumptio
   expected_resumption_mode_ = expected;
   if (expected != RESUME_NONE) {
     client_->ExpectResumption();
     server_->ExpectResumption();
   }
 }
 
 void TlsConnectTestBase::EnsureTlsSetup() {
-  EXPECT_TRUE(client_->EnsureTlsSetup());
-  EXPECT_TRUE(server_->EnsureTlsSetup());
+  EXPECT_TRUE(server_->EnsureTlsSetup(server_model_ ? server_model_->ssl_fd() : nullptr));
+  EXPECT_TRUE(client_->EnsureTlsSetup(client_model_ ? client_model_->ssl_fd() : nullptr));
 }
 
 void TlsConnectTestBase::Handshake() {
   EnsureTlsSetup();
   client_->SetServerKeyBits(server_->server_key_bits());
   client_->Handshake();
   server_->Handshake();
 
@@ -209,18 +217,18 @@ void TlsConnectTestBase::Handshake() {
 
 void TlsConnectTestBase::EnableExtendedMasterSecret() {
   client_->EnableExtendedMasterSecret();
   server_->EnableExtendedMasterSecret();
   ExpectExtendedMasterSecret(true);
 }
 
 void TlsConnectTestBase::Connect() {
-  server_->StartConnect();
-  client_->StartConnect();
+  server_->StartConnect(server_model_ ? server_model_->ssl_fd() : nullptr);
+  client_->StartConnect(client_model_ ? client_model_->ssl_fd() : nullptr);
   Handshake();
   CheckConnected();
 }
 
 void TlsConnectTestBase::ConnectWithCipherSuite(uint16_t cipher_suite)
 {
   EnsureTlsSetup();
   client_->EnableSingleCipher(cipher_suite);
@@ -264,18 +272,20 @@ void TlsConnectTestBase::CheckConnected(
     EXPECT_EQ(32U, sid_c1.size());
     std::vector<uint8_t> sid_s1 = server_->session_id();
     EXPECT_EQ(32U, sid_s1.size());
     EXPECT_EQ(sid_c1, sid_s1);
     session_ids_.push_back(sid_c1);
   }
 
   CheckExtendedMasterSecret();
-
+  CheckEarlyDataAccepted();
   CheckResumption(expected_resumption_mode_);
+  client_->CheckSecretsDestroyed();
+  server_->CheckSecretsDestroyed();
 }
 
 void TlsConnectTestBase::CheckKeys(SSLKEAType keaType,
                                    SSLAuthType authType) const {
   client_->CheckKEAType(keaType);
   server_->CheckKEAType(keaType);
   client_->CheckAuthType(authType);
   server_->CheckAuthType(authType);
@@ -355,23 +365,46 @@ void TlsConnectTestBase::CheckResumption
     // tickets.
     EXPECT_EQ(2U, session_ids_.size());
     EXPECT_EQ(session_ids_[session_ids_.size()-1],
               session_ids_[session_ids_.size()-2]);
   }
 }
 
 void TlsConnectTestBase::EnableAlpn() {
-  // A simple value of "a", "b".  Note that the preferred value of "a" is placed
-  // at the end, because the NSS API follows the now defunct NPN specification,
-  // which places the preferred (and default) entry at the end of the list.
-  // NSS will move this final entry to the front when used with ALPN.
-  static const uint8_t val[] = { 0x01, 0x62, 0x01, 0x61 };
-  client_->EnableAlpn(val, sizeof(val));
-  server_->EnableAlpn(val, sizeof(val));
+  client_->EnableAlpn(alpn_dummy_val_, sizeof(alpn_dummy_val_));
+  server_->EnableAlpn(alpn_dummy_val_, sizeof(alpn_dummy_val_));
+}
+
+void TlsConnectTestBase::EnableAlpn(const uint8_t *val, size_t len) {
+  client_->EnableAlpn(val, len);
+  server_->EnableAlpn(val, len);
+}
+
+void TlsConnectTestBase::EnsureModelSockets() {
+  // Make sure models agents are available.
+  if (!client_model_) {
+    ASSERT_EQ(server_model_, nullptr);
+    client_model_ = new TlsAgent(TlsAgent::kClient, TlsAgent::CLIENT, mode_);
+    server_model_ = new TlsAgent(TlsAgent::kServerRsa, TlsAgent::SERVER, mode_);
+  }
+
+  // Initialise agents.
+  ASSERT_TRUE(client_model_->Init());
+  ASSERT_TRUE(server_model_->Init());
+
+  // Set desired properties on the models.
+  // For now only ALPN.
+  client_model_->EnableAlpn(alpn_dummy_val_, sizeof(alpn_dummy_val_));
+  server_model_->EnableAlpn(alpn_dummy_val_, sizeof(alpn_dummy_val_));
+}
+
+void TlsConnectTestBase::CheckAlpn(const std::string& val) {
+  client_->CheckAlpn(SSL_NEXT_PROTO_SELECTED, val);
+  server_->CheckAlpn(SSL_NEXT_PROTO_NEGOTIATED, val);
 }
 
 void TlsConnectTestBase::EnableSrtp() {
   client_->EnableSrtp();
   server_->EnableSrtp();
 }
 
 void TlsConnectTestBase::CheckSrtp() const {
@@ -380,33 +413,96 @@ void TlsConnectTestBase::CheckSrtp() con
 }
 
 void TlsConnectTestBase::SendReceive() {
   client_->SendData(50);
   server_->SendData(50);
   Receive(50);
 }
 
+// Do a first connection so we can do 0-RTT on the second one.
+void TlsConnectTestBase::SetupForZeroRtt() {
+  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);
+  server_->Set0RttEnabled(true); // So we signal that we allow 0-RTT.
+  Connect();
+  SendReceive(); // Need to read so that we absorb the session ticket.
+  CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
+
+  Reset();
+  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);
+  server_->StartConnect();
+  client_->StartConnect();
+}
+
+void TlsConnectTestBase::ZeroRttSendReceive(
+    bool expect_readable,
+    std::function<bool()> post_clienthello_check) {
+  const char *k0RttData = "ABCDEF";
+  const PRInt32 k0RttDataLen = static_cast<PRInt32>(strlen(k0RttData));
+
+  client_->Handshake(); // Send ClientHello.
+  if (post_clienthello_check) {
+    if (!post_clienthello_check())
+      return;
+  }
+  PRInt32 rv = PR_Write(client_->ssl_fd(),
+                        k0RttData, k0RttDataLen); // 0-RTT write.
+  EXPECT_EQ(k0RttDataLen, rv);
+  server_->Handshake(); // Consume ClientHello, EE, Finished.
+
+  std::vector<uint8_t> buf(k0RttDataLen);
+  rv = PR_Read(server_->ssl_fd(), buf.data(), k0RttDataLen); // 0-RTT read
+  if (expect_readable) {
+    std::cerr << "0-RTT read " << rv << " bytes\n";
+    EXPECT_EQ(k0RttDataLen, rv);
+  } else {
+    EXPECT_EQ(SECFailure, rv);
+    EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
+  }
+
+  // Do a second read. this should fail.
+  rv = PR_Read(server_->ssl_fd(),
+               buf.data(), k0RttDataLen);
+  EXPECT_EQ(SECFailure, rv);
+  EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
+
+}
+
 void TlsConnectTestBase::Receive(size_t amount) {
   WAIT_(client_->received_bytes() == amount &&
         server_->received_bytes() == amount, 2000);
   ASSERT_EQ(amount, client_->received_bytes());
   ASSERT_EQ(amount, server_->received_bytes());
 }
 
-
 void TlsConnectTestBase::ExpectExtendedMasterSecret(bool expected) {
   expect_extended_master_secret_ = expected;
 }
 
 void TlsConnectTestBase::CheckExtendedMasterSecret() {
   client_->CheckExtendedMasterSecret(expect_extended_master_secret_);
   server_->CheckExtendedMasterSecret(expect_extended_master_secret_);
 }
 
+void TlsConnectTestBase::ExpectEarlyDataAccepted(bool expected) {
+  expect_early_data_accepted_ = expected;
+}
+
+void TlsConnectTestBase::CheckEarlyDataAccepted() {
+  client_->CheckEarlyDataAccepted(expect_early_data_accepted_);
+  server_->CheckEarlyDataAccepted(expect_early_data_accepted_);
+}
+
 TlsConnectGeneric::TlsConnectGeneric()
   : TlsConnectTestBase(TlsConnectTestBase::ToMode(std::get<0>(GetParam())),
                        std::get<1>(GetParam())) {}
 
 TlsConnectPre12::TlsConnectPre12()
   : TlsConnectTestBase(TlsConnectTestBase::ToMode(std::get<0>(GetParam())),
                        std::get<1>(GetParam())) {}
 
--- a/security/nss/external_tests/ssl_gtest/tls_connect.h
+++ b/security/nss/external_tests/ssl_gtest/tls_connect.h
@@ -76,35 +76,53 @@ class TlsConnectTestBase : public ::test
   void DisableAllCiphers();
   void EnableOnlyStaticRsaCiphers();
   void EnableOnlyDheCiphers();
   void EnableSomeEcdhCiphers();
   void EnableExtendedMasterSecret();
   void ConfigureSessionCache(SessionResumptionMode client,
                              SessionResumptionMode server);
   void EnableAlpn();
+  void EnableAlpn(const uint8_t* val, size_t len);
+  void EnsureModelSockets();
+  void CheckAlpn(const std::string& val);
   void EnableSrtp();
   void CheckSrtp() const;
   void SendReceive();
+  void SetupForZeroRtt();
+  void ZeroRttSendReceive(
+      bool expect_readable,
+      std::function<bool()> post_clienthello_check = nullptr);
   void Receive(size_t amount);
   void ExpectExtendedMasterSecret(bool expected);
+  void ExpectEarlyDataAccepted(bool expected);
 
  protected:
   Mode mode_;
   TlsAgent* client_;
   TlsAgent* server_;
+  TlsAgent* client_model_;
+  TlsAgent* server_model_;
   uint16_t version_;
   SessionResumptionMode expected_resumption_mode_;
   std::vector<std::vector<uint8_t>> session_ids_;
 
+  // A simple value of "a", "b".  Note that the preferred value of "a" is placed
+  // at the end, because the NSS API follows the now defunct NPN specification,
+  // which places the preferred (and default) entry at the end of the list.
+  // NSS will move this final entry to the front when used with ALPN.
+  const uint8_t alpn_dummy_val_[4] = { 0x01, 0x62, 0x01, 0x61 };
+
  private:
   void CheckResumption(SessionResumptionMode expected);
   void CheckExtendedMasterSecret();
+  void CheckEarlyDataAccepted();
 
   bool expect_extended_master_secret_;
+  bool expect_early_data_accepted_;
 };
 
 // A non-parametrized TLS test base.
 class TlsConnectTest : public TlsConnectTestBase {
  public:
  TlsConnectTest() : TlsConnectTestBase(STREAM, 0) {}
 };
 
--- a/security/nss/external_tests/ssl_gtest/tls_hkdf_unittest.cc
+++ b/security/nss/external_tests/ssl_gtest/tls_hkdf_unittest.cc
@@ -41,17 +41,46 @@ const DataBuffer kKey2(kKey2Data,
 
 const char kLabelMasterSecret[] = "master secret";
 
 const uint8_t kSessionHash[] = {
   0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,
   0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff,
   0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,
   0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
-  0xd0,0xd1,0xd2,0xd3
+  0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,
+  0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+  0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,
+  0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+  0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,
+  0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff,
+  0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,
+  0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+  0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,
+  0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff,
+};
+
+const size_t kHashLength[] = {
+  0,  /* ssl_hash_none   */
+  16, /* ssl_hash_md5    */
+  20, /* ssl_hash_sha1   */
+  28, /* ssl_hash_sha224 */
+  32, /* ssl_hash_sha256 */
+  48, /* ssl_hash_sha384 */
+  64, /* ssl_hash_sha512 */
+};
+
+const std::string kHashName[] = {
+  "None",
+  "MD5",
+  "SHA-1",
+  "SHA-224",
+  "SHA-256",
+  "SHA-384",
+  "SHA-512"
 };
 
 static void ImportKey(ScopedPK11SymKey* to, const DataBuffer& key,
                       PK11SlotInfo* slot) {
   SECItem key_item = {
     siBuffer,
     const_cast<uint8_t*>(key.data()),
     static_cast<unsigned int>(key.len())
@@ -76,19 +105,25 @@ void DumpKey(const std::string& label, S
   ASSERT_EQ(SECSuccess, rv);
 
   SECItem *key_data = PK11_GetKeyData(key.get());
   ASSERT_NE(nullptr, key_data);
 
   DumpData(label, key_data->data, key_data->len);
 }
 
-class TlsHkdfTest : public ::testing::Test {
+class TlsHkdfTest
+  : public ::testing::Test,
+    public ::testing::WithParamInterface<SSLHashType> {
  public:
-  TlsHkdfTest() : k1_(), k2_(), slot_(PK11_GetInternalSlot()) {
+  TlsHkdfTest()
+    : k1_(),
+      k2_(),
+      hash_type_(GetParam()),
+      slot_(PK11_GetInternalSlot()) {
     EXPECT_NE(nullptr, slot_);
   }
 
   void SetUp() {
     ImportKey(&k1_, kKey1, slot_.get());
     ImportKey(&k2_, kKey2, slot_.get());
   }
 
@@ -102,84 +137,165 @@ class TlsHkdfTest : public ::testing::Te
     EXPECT_EQ(expected.len(), key_data->len);
     EXPECT_EQ(0, memcmp(expected.data(),
                         key_data->data, expected.len()));
   }
 
   void HkdfExtract(const ScopedPK11SymKey& ikmk1, const ScopedPK11SymKey& ikmk2,
                    SSLHashType base_hash,
                    const DataBuffer& expected) {
+    std::cerr << "Hash = " << kHashName[base_hash] << std::endl;
+
     PK11SymKey* prk = nullptr;
     SECStatus rv = tls13_HkdfExtract(
         ikmk1.get(), ikmk2.get(), base_hash, &prk);
     ASSERT_EQ(SECSuccess, rv);
     ScopedPK11SymKey prkk(prk);
 
     DumpKey("Output", prkk);
     VerifyKey(prkk, expected);
   }
 
   void HkdfExpandLabel(ScopedPK11SymKey* prk, SSLHashType base_hash,
                        const uint8_t *session_hash, size_t session_hash_len,
                        const char *label, size_t label_len,
                        const DataBuffer& expected) {
+    std::cerr << "Hash = " << kHashName[base_hash] << std::endl;
+
     std::vector<uint8_t> output(expected.len());
 
     SECStatus rv = tls13_HkdfExpandLabelRaw(prk->get(), base_hash,
                                             session_hash, session_hash_len,
                                             label, label_len,
                                             &output[0], output.size());
     ASSERT_EQ(SECSuccess, rv);
     DumpData("Output", &output[0], output.size());
     EXPECT_EQ(0, memcmp(expected.data(), &output[0],
                         expected.len()));
   }
 
  protected:
   ScopedPK11SymKey k1_;
   ScopedPK11SymKey k2_;
+  SSLHashType hash_type_;
 
  private:
   ScopedPK11SlotInfo slot_;
 };
 
-TEST_F(TlsHkdfTest, HkdfSha256Key2Only) {
-  const uint8_t expected[] = {
-    0x2f, 0x5f, 0x78, 0xd0, 0xa4, 0xc4, 0x36, 0xee,
-    0x6c, 0x8a, 0x4e, 0xf9, 0xd0, 0x43, 0x81, 0x02,
-    0x13, 0xfd, 0x47, 0x83, 0x63, 0x3a, 0xd2, 0xe1,
-    0x40, 0x6d, 0x2d, 0x98, 0x00, 0xfd, 0xc1, 0x87
+TEST_P(TlsHkdfTest, HkdfNullNull) {
+  const uint8_t tv[][48] = {
+    { /* ssl_hash_none   */ },
+    { /* ssl_hash_md5    */ },
+    { /* ssl_hash_sha1   */ },
+    { /* ssl_hash_sha224 */ },
+    { 0x33, 0xad, 0x0a, 0x1c, 0x60, 0x7e, 0xc0, 0x3b,
+      0x09, 0xe6, 0xcd, 0x98, 0x93, 0x68, 0x0c, 0xe2,
+      0x10, 0xad, 0xf3, 0x00, 0xaa, 0x1f, 0x26, 0x60,
+      0xe1, 0xb2, 0x2e, 0x10, 0xf1, 0x70, 0xf9, 0x2a },
+    { 0x7e, 0xe8, 0x20, 0x6f, 0x55, 0x70, 0x02, 0x3e,
+      0x6d, 0xc7, 0x51, 0x9e, 0xb1, 0x07, 0x3b, 0xc4,
+      0xe7, 0x91, 0xad, 0x37, 0xb5, 0xc3, 0x82, 0xaa,
+      0x10, 0xba, 0x18, 0xe2, 0x35, 0x7e, 0x71, 0x69,
+      0x71, 0xf9, 0x36, 0x2f, 0x2c, 0x2f, 0xe2, 0xa7,
+      0x6b, 0xfd, 0x78, 0xdf, 0xec, 0x4e, 0xa9, 0xb5 }
   };
-  const DataBuffer expected_data(expected, sizeof(expected));
+
+  const DataBuffer expected_data(tv[hash_type_], kHashLength[hash_type_]);
+  HkdfExtract(nullptr, nullptr, hash_type_, expected_data);
+}
 
-  HkdfExtract(nullptr, k2_, ssl_hash_sha256,
-              expected_data);
+TEST_P(TlsHkdfTest, HkdfKey1Only) {
+  const uint8_t tv[][48] = {
+    { /* ssl_hash_none   */ },
+    { /* ssl_hash_md5    */ },
+    { /* ssl_hash_sha1   */ },
+    { /* ssl_hash_sha224 */ },
+    { 0x11, 0x87, 0x38, 0x28, 0xa9, 0x19, 0x78, 0x11,
+      0x33, 0x91, 0x24, 0xb5, 0x8a, 0x1b, 0xb0, 0x9f,
+      0x7f, 0x0d, 0x8d, 0xbb, 0x10, 0xf4, 0x9c, 0x54,
+      0xbd, 0x1f, 0xd8, 0x85, 0xcd, 0x15, 0x30, 0x33 },
+    { 0x51, 0xb1, 0xd5, 0xb4, 0x59, 0x79, 0x79, 0x08,
+      0x4a, 0x15, 0xb2, 0xdb, 0x84, 0xd3, 0xd6, 0xbc,
+      0xfc, 0x93, 0x45, 0xd9, 0xdc, 0x74, 0xda, 0x1a,
+      0x57, 0xc2, 0x76, 0x9f, 0x3f, 0x83, 0x45, 0x2f,
+      0xf6, 0xf3, 0x56, 0x1f, 0x58, 0x63, 0xdb, 0x88,
+      0xda, 0x40, 0xce, 0x63, 0x7d, 0x24, 0x37, 0xf3
+    }
+  };
+
+  const DataBuffer expected_data(tv[hash_type_], kHashLength[hash_type_]);
+  HkdfExtract(k1_, nullptr, hash_type_, expected_data);
 }
 
-TEST_F(TlsHkdfTest, HkdfSha256Key1Key2) {
-  const uint8_t expected[] = {
-    0x79, 0x53, 0xb8, 0xdd, 0x6b, 0x98, 0xce, 0x00,
-    0xb7, 0xdc, 0xe8, 0x03, 0x70, 0x8c, 0xe3, 0xac,
-    0x06, 0x8b, 0x22, 0xfd, 0x0e, 0x34, 0x48, 0xe6,
-    0xe5, 0xe0, 0x8a, 0xd6, 0x16, 0x18, 0xe5, 0x48
+TEST_P(TlsHkdfTest, HkdfKey2Only) {
+  const uint8_t tv[][48] = {
+    { /* ssl_hash_none   */ },
+    { /* ssl_hash_md5    */ },
+    { /* ssl_hash_sha1   */ },
+    { /* ssl_hash_sha224 */ },
+    { 0x2f, 0x5f, 0x78, 0xd0, 0xa4, 0xc4, 0x36, 0xee,
+      0x6c, 0x8a, 0x4e, 0xf9, 0xd0, 0x43, 0x81, 0x02,
+      0x13, 0xfd, 0x47, 0x83, 0x63, 0x3a, 0xd2, 0xe1,
+      0x40, 0x6d, 0x2d, 0x98, 0x00, 0xfd, 0xc1, 0x87, },
+    { 0x7b, 0x40, 0xf9, 0xef, 0x91, 0xff, 0xc9, 0xd1,
+      0x29, 0x24, 0x5c, 0xbf, 0xf8, 0x82, 0x76, 0x68,
+      0xae, 0x4b, 0x63, 0xe8, 0x03, 0xdd, 0x39, 0xa8,
+      0xd4, 0x6a, 0xf6, 0xe5, 0xec, 0xea, 0xf8, 0x7d,
+      0x91, 0x71, 0x81, 0xf1, 0xdb, 0x3b, 0xaf, 0xbf,
+      0xde, 0x71, 0x61, 0x15, 0xeb, 0xb5, 0x5f, 0x68  }
   };
-  const DataBuffer expected_data(expected, sizeof(expected));
 
-  HkdfExtract(k1_, k2_, ssl_hash_sha256,
-              expected_data);
+  const DataBuffer expected_data(tv[hash_type_], kHashLength[hash_type_]);
+  HkdfExtract(nullptr, k2_, hash_type_, expected_data);
 }
 
-TEST_F(TlsHkdfTest, HkdfExpandLabelSha256) {
-  const uint8_t expected[] = {
-    0x34, 0x7c, 0x67, 0x80, 0xff, 0x0b, 0xba, 0xd7,
-    0x1c, 0x28, 0x3b, 0x16, 0xeb, 0x2f, 0x9c, 0xf6,
-    0x2d, 0x24, 0xe6, 0xcd, 0xb6, 0x13, 0xd5, 0x17,
-    0x76, 0x54, 0x8c, 0xb0, 0x7d, 0xcd, 0xe7, 0x4c
+TEST_P(TlsHkdfTest, HkdfKey1Key2) {
+  const uint8_t tv[][48] = {
+    { /* ssl_hash_none   */ },
+    { /* ssl_hash_md5    */ },
+    { /* ssl_hash_sha1   */ },
+    { /* ssl_hash_sha224 */ },
+    { 0x79, 0x53, 0xb8, 0xdd, 0x6b, 0x98, 0xce, 0x00,
+      0xb7, 0xdc, 0xe8, 0x03, 0x70, 0x8c, 0xe3, 0xac,
+      0x06, 0x8b, 0x22, 0xfd, 0x0e, 0x34, 0x48, 0xe6,
+      0xe5, 0xe0, 0x8a, 0xd6, 0x16, 0x18, 0xe5, 0x48, },
+    { 0x01, 0x93, 0xc0, 0x07, 0x3f, 0x6a, 0x83, 0x0e,
+      0x2e, 0x4f, 0xb2, 0x58, 0xe4, 0x00, 0x08, 0x5c,
+      0x68, 0x9c, 0x37, 0x32, 0x00, 0x37, 0xff, 0xc3,
+      0x1c, 0x5b, 0x98, 0x0b, 0x02, 0x92, 0x3f, 0xfd,
+      0x73, 0x5a, 0x6f, 0x2a, 0x95, 0xa3, 0xee, 0xf6,
+      0xd6, 0x8e, 0x6f, 0x86, 0xea, 0x63, 0xf8, 0x33  }
   };
-  const DataBuffer expected_data(expected, sizeof(expected));
+
+  const DataBuffer expected_data(tv[hash_type_], kHashLength[hash_type_]);
+  HkdfExtract(k1_, k2_, hash_type_, expected_data);
+}
 
-  HkdfExpandLabel(&k1_, ssl_hash_sha256,
-                  kSessionHash, 32,
+TEST_P(TlsHkdfTest, HkdfExpandLabel) {
+  const uint8_t tv[][48] = {
+    { /* ssl_hash_none   */ },
+    { /* ssl_hash_md5    */ },
+    { /* ssl_hash_sha1   */ },
+    { /* ssl_hash_sha224 */ },
+    { 0x66, 0x8a, 0x55, 0x1a, 0xef, 0x33, 0x7b, 0x45,
+      0x26, 0xa6, 0x36, 0xb1, 0xe0, 0x23, 0x48, 0x24,
+      0x6f, 0x34, 0xa5, 0x57, 0x11, 0x4a, 0xb5, 0x64,
+      0xc4, 0x5c, 0x69, 0xb4, 0x0f, 0xc8, 0x12, 0xa5},
+    { 0x99, 0x98, 0xde, 0xbf, 0x82, 0x8d, 0xf6, 0x55,
+      0xa1, 0xcf, 0xa8, 0xbe, 0x12, 0x06, 0x5c, 0x8e,
+      0x65, 0xec, 0x80, 0xa1, 0x33, 0xed, 0x61, 0x06,
+      0x09, 0xc6, 0x5c, 0x08, 0xcf, 0xc9, 0x91, 0x39,
+      0xbe, 0xce, 0x4e, 0x4a, 0x9b, 0x67, 0x36, 0x50,
+      0x89, 0x98, 0x59, 0x1c, 0x5d, 0x6e, 0x9c, 0x7d }
+  };
+
+  const DataBuffer expected_data(tv[hash_type_], kHashLength[hash_type_]);
+  HkdfExpandLabel(&k1_, hash_type_, kSessionHash, kHashLength[hash_type_] * 2,
                   kLabelMasterSecret, strlen(kLabelMasterSecret),
                   expected_data);
 }
 
+static const SSLHashType kHashTypes[] = {ssl_hash_sha256, ssl_hash_sha384};
+INSTANTIATE_TEST_CASE_P(AllHashFuncs, TlsHkdfTest,
+                        ::testing::ValuesIn(kHashTypes));
+
 } // namespace nss_test
--- a/security/nss/lib/Makefile
+++ b/security/nss/lib/Makefile
@@ -45,16 +45,20 @@ endif
 ifndef NSS_DISABLE_DBM
 DBM_SRCDIR = dbm  # Add the dbm directory to DIRS.
 endif
 
 ifeq ($(NSS_BUILD_UTIL_ONLY),1)
 SYSINIT_SRCDIR=
 endif
 
+ifndef NSS_DISABLE_LIBPKIX
+LIBPKIX_SRCDIR = libpkix  # Add the libpkix directory to DIRS.
+endif
+
 #######################################################################
 # (5) Execute "global" rules. (OPTIONAL)                              #
 #######################################################################
 
 include $(CORE_DEPTH)/coreconf/rules.mk
 
 #######################################################################
 # (6) Execute "component" rules. (OPTIONAL)                           #
--- a/security/nss/lib/certdb/certxutl.c
+++ b/security/nss/lib/certdb/certxutl.c
@@ -182,32 +182,35 @@ CERT_AddExtensionByOID(void *exthandle, 
 
     /* add to list */
     node->next = handle->head;
     handle->head = node;
 
     /* point to ext struct */
     node->ext = ext;
 
-    /* the object ID of the extension */
-    ext->id = *oid;
-
     /* set critical field */
     if (critical) {
         ext->critical.data = (unsigned char *)&hextrue;
         ext->critical.len = 1;
     }
 
-    /* set the value */
+    /* set object ID of the extension and its value */
     if (copyData) {
+        rv = SECITEM_CopyItem(handle->ownerArena, &ext->id, oid);
+        if (rv) {
+            return (SECFailure);
+        }
+
         rv = SECITEM_CopyItem(handle->ownerArena, &ext->value, value);
         if (rv) {
             return (SECFailure);
         }
     } else {
+        ext->id = *oid;
         ext->value = *value;
     }
 
     handle->count++;
 
     return (SECSuccess);
 }
 
--- a/security/nss/lib/certhigh/certvfy.c
+++ b/security/nss/lib/certhigh/certvfy.c
@@ -7,19 +7,23 @@
 #include "seccomon.h"
 #include "secoid.h"
 #include "genname.h"
 #include "keyhi.h"
 #include "cert.h"
 #include "certdb.h"
 #include "certi.h"
 #include "cryptohi.h"
+
+#ifndef NSS_DISABLE_LIBPKIX
 #include "pkix.h"
-/*#include "pkix_sample_modules.h" */
 #include "pkix_pl_cert.h"
+#else
+#include "nss.h"
+#endif /* NSS_DISABLE_LIBPKIX */
 
 #include "nsspki.h"
 #include "pkitm.h"
 #include "pkim.h"
 #include "pki3hack.h"
 #include "base.h"
 #include "keyhi.h"
 
--- a/security/nss/lib/certhigh/certvfypkix.c
+++ b/security/nss/lib/certhigh/certvfypkix.c
@@ -18,32 +18,34 @@
 #include "certdb.h"
 #include "cert.h"
 #include "secerr.h"
 #include "nssb64.h"
 #include "secasn1.h"
 #include "secder.h"
 #include "pkit.h"
 
+#ifndef NSS_DISABLE_LIBPKIX
 #include "pkix_pl_common.h"
 
 extern PRLogModuleInfo *pkixLog;
 
 #ifdef PKIX_OBJECT_LEAK_TEST
 
 extern PKIX_UInt32
 pkix_pl_lifecycle_ObjectLeakCheck(int *);
 
 extern SECStatus
 pkix_pl_lifecycle_ObjectTableUpdate(int *objCountTable);
 
 PRInt32 parallelFnInvocationCount;
 #endif /* PKIX_OBJECT_LEAK_TEST */
 
 static PRBool usePKIXValidationEngine = PR_FALSE;
+#endif /* NSS_DISABLE_LIBPKIX */
 
 /*
  * FUNCTION: CERT_SetUsePKIXForValidation
  * DESCRIPTION:
  *
  * Enables or disables use of libpkix for certificate validation
  *
  * PARAMETERS:
@@ -53,18 +55,23 @@ static PRBool usePKIXValidationEngine = 
  * THREAD SAFETY:
  *  NOT Thread Safe.
  * RETURNS:
  *  Returns SECSuccess if successfully enabled
  */
 SECStatus
 CERT_SetUsePKIXForValidation(PRBool enable)
 {
+#ifdef NSS_DISABLE_LIBPKIX
+    PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+    return SECFailure;
+#else
     usePKIXValidationEngine = (enable > 0) ? PR_TRUE : PR_FALSE;
     return SECSuccess;
+#endif /* NSS_DISABLE_LIBPKIX */
 }
 
 /*
  * FUNCTION: CERT_GetUsePKIXForValidation
  * DESCRIPTION:
  *
  * Checks if libpkix building function should be use for certificate
  * chain building.
@@ -74,19 +81,24 @@ CERT_SetUsePKIXForValidation(PRBool enab
  * THREAD SAFETY:
  *  NOT Thread Safe
  * RETURNS:
  *  Returns PR_TRUE if libpkix should be used. PR_FALSE otherwise.
  */
 PRBool
 CERT_GetUsePKIXForValidation()
 {
+#ifdef NSS_DISABLE_LIBPKIX
+    return PR_FALSE;
+#else
     return usePKIXValidationEngine;
+#endif /* NSS_DISABLE_LIBPKIX */
 }
 
+#ifndef NSS_DISABLE_LIBPKIX
 #ifdef NOTDEF
 /*
  * FUNCTION: cert_NssKeyUsagesToPkix
  * DESCRIPTION:
  *
  * Converts nss key usage bit field(PRUint32) to pkix key usage
  * bit field.
  *
@@ -1057,16 +1069,17 @@ cleanup:
     PKIX_DECREF(pkixCertChain);
     PKIX_DECREF(validResult);
     PKIX_DECREF(error);
     PKIX_DECREF(verifyNode);
     PKIX_DECREF(buildResult);
 
     PKIX_RETURN(CERTVFYPKIX);
 }
+#endif /* NSS_DISABLE_LIBPKIX */
 
 /*
  * FUNCTION: cert_VerifyCertChainPkix
  * DESCRIPTION:
  *
  * The main wrapper function that is called from CERT_VerifyCert and
  * CERT_VerifyCACertForUsage functions to validate cert with libpkix.
  *
@@ -1103,16 +1116,20 @@ cert_VerifyCertChainPkix(
     PRBool checkSig,
     SECCertUsage requiredUsage,
     PRTime time,
     void *wincx,
     CERTVerifyLog *log,
     PRBool *pSigerror,
     PRBool *pRevoked)
 {
+#ifdef NSS_DISABLE_LIBPKIX
+    PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+    return SECFailure;
+#else
     PKIX_ProcessingParams *procParams = NULL;
     PKIX_BuildResult *result = NULL;
     PKIX_VerifyNode *verifyNode = NULL;
     PKIX_Error *error = NULL;
 
     SECStatus rv = SECFailure;
     void *plContext = NULL;
 
@@ -1221,18 +1238,20 @@ cert_VerifyCertChainPkix(
     } while (errorGenerated);
 
     runningLeakTest = PKIX_FALSE;
     PR_ATOMIC_DECREMENT(&parallelFnInvocationCount);
     usePKIXValidationEngine = savedUsePkixEngFlag;
 #endif /* PKIX_OBJECT_LEAK_TEST */
 
     return rv;
+#endif /* NSS_DISABLE_LIBPKIX */
 }
 
+#ifndef NSS_DISABLE_LIBPKIX
 PKIX_CertSelector *
 cert_GetTargetCertConstraints(CERTCertificate *target, void *plContext)
 {
     PKIX_ComCertSelParams *certSelParams = NULL;
     PKIX_CertSelector *certSelector = NULL;
     PKIX_CertSelector *r = NULL;
     PKIX_PL_Cert *eeCert = NULL;
     PKIX_Error *error = NULL;
@@ -1751,23 +1770,30 @@ static const CERTRevocationFlags certRev
       0 },
     { /* chainTests */
       2,
       certRev_NSS_3_11_Ocsp_Enabled_Soft_Policy_ChainFlags,
       0,
       0,
       0 }
 };
+#endif /* NSS_DISABLE_LIBPKIX */
 
 extern const CERTRevocationFlags *
 CERT_GetClassicOCSPEnabledSoftFailurePolicy()
 {
+#ifdef NSS_DISABLE_LIBPKIX
+    PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+    return NULL;
+#else
     return &certRev_NSS_3_11_Ocsp_Enabled_Soft_Policy;
+#endif /* NSS_DISABLE_LIBPKIX */
 }
 
+#ifndef NSS_DISABLE_LIBPKIX
 static PRUint64 certRev_NSS_3_11_Ocsp_Enabled_Hard_Policy_LeafFlags[2] = {
     /* crl */
     CERT_REV_M_TEST_USING_THIS_METHOD |
         CERT_REV_M_FORBID_NETWORK_FETCHING |
         CERT_REV_M_CONTINUE_TESTING_ON_FRESH_INFO,
     /* ocsp */
     CERT_REV_M_TEST_USING_THIS_METHOD |
         CERT_REV_M_FAIL_ON_MISSING_FRESH_INFO
@@ -1796,23 +1822,30 @@ static const CERTRevocationFlags certRev
       0 },
     { /* chainTests */
       2,
       certRev_NSS_3_11_Ocsp_Enabled_Hard_Policy_ChainFlags,
       0,
       0,
       0 }
 };
+#endif /* NSS_DISABLE_LIBPKIX */
 
 extern const CERTRevocationFlags *
 CERT_GetClassicOCSPEnabledHardFailurePolicy()
 {
+#ifdef NSS_DISABLE_LIBPKIX
+    PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+    return NULL;
+#else
     return &certRev_NSS_3_11_Ocsp_Enabled_Hard_Policy;
+#endif /* NSS_DISABLE_LIBPKIX */
 }
 
+#ifndef NSS_DISABLE_LIBPKIX
 static PRUint64 certRev_NSS_3_11_Ocsp_Disabled_Policy_LeafFlags[2] = {
     /* crl */
     CERT_REV_M_TEST_USING_THIS_METHOD |
         CERT_REV_M_FORBID_NETWORK_FETCHING |
         CERT_REV_M_CONTINUE_TESTING_ON_FRESH_INFO,
     /* ocsp */
     0
 };
@@ -1835,23 +1868,30 @@ static const CERTRevocationFlags certRev
       0 },
     { /* chainTests */
       2,
       certRev_NSS_3_11_Ocsp_Disabled_Policy_ChainFlags,
       0,
       0,
       0 }
 };
+#endif /* NSS_DISABLE_LIBPKIX */
 
 extern const CERTRevocationFlags *
 CERT_GetClassicOCSPDisabledPolicy()
 {
+#ifdef NSS_DISABLE_LIBPKIX
+    PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+    return NULL;
+#else
     return &certRev_NSS_3_11_Ocsp_Disabled_Policy;
+#endif /* NSS_DISABLE_LIBPKIX */
 }
 
+#ifndef NSS_DISABLE_LIBPKIX
 static PRUint64 certRev_PKIX_Verify_Nist_Policy_LeafFlags[2] = {
     /* crl */
     CERT_REV_M_TEST_USING_THIS_METHOD |
         CERT_REV_M_FAIL_ON_MISSING_FRESH_INFO |
         CERT_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE,
     /* ocsp */
     0
 };
@@ -1874,28 +1914,38 @@ static const CERTRevocationFlags certRev
       0 },
     { /* chainTests */
       2,
       certRev_PKIX_Verify_Nist_Policy_ChainFlags,
       0,
       0,
       0 }
 };
+#endif /* NSS_DISABLE_LIBPKIX */
 
 extern const CERTRevocationFlags *
 CERT_GetPKIXVerifyNistRevocationPolicy()
 {
+#ifdef NSS_DISABLE_LIBPKIX
+    PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+    return NULL;
+#else
     return &certRev_PKIX_Verify_Nist_Policy;
+#endif /* NSS_DISABLE_LIBPKIX */
 }
 
 CERTRevocationFlags *
 CERT_AllocCERTRevocationFlags(
     PRUint32 number_leaf_methods, PRUint32 number_leaf_pref_methods,
     PRUint32 number_chain_methods, PRUint32 number_chain_pref_methods)
 {
+#ifdef NSS_DISABLE_LIBPKIX
+    PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+    return NULL;
+#else
     CERTRevocationFlags *flags;
 
     flags = PORT_New(CERTRevocationFlags);
     if (!flags)
         return (NULL);
 
     flags->leafTests.number_of_defined_methods = number_leaf_methods;
     flags->leafTests.cert_rev_flags_per_method =
@@ -1917,37 +1967,43 @@ CERT_AllocCERTRevocationFlags(
         !flags->leafTests.preferred_methods ||
         !flags->chainTests.cert_rev_flags_per_method ||
         !flags->chainTests.preferred_methods) {
         CERT_DestroyCERTRevocationFlags(flags);
         return (NULL);
     }
 
     return flags;
+#endif /* NSS_DISABLE_LIBPKIX */
 }
 
 void
 CERT_DestroyCERTRevocationFlags(CERTRevocationFlags *flags)
 {
+#ifdef NSS_DISABLE_LIBPKIX
+    PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+    return;
+#else
     if (!flags)
         return;
 
     if (flags->leafTests.cert_rev_flags_per_method)
         PORT_Free(flags->leafTests.cert_rev_flags_per_method);
 
     if (flags->leafTests.preferred_methods)
         PORT_Free(flags->leafTests.preferred_methods);
 
     if (flags->chainTests.cert_rev_flags_per_method)
         PORT_Free(flags->chainTests.cert_rev_flags_per_method);
 
     if (flags->chainTests.preferred_methods)
         PORT_Free(flags->chainTests.preferred_methods);
 
     PORT_Free(flags);
+#endif /* NSS_DISABLE_LIBPKIX */
 }
 
 /*
  * CERT_PKIXVerifyCert
  *
  * Verify a Certificate using the PKIX library.
  *
  * Parameters:
@@ -1973,16 +2029,20 @@ CERT_DestroyCERTRevocationFlags(CERTRevo
 SECStatus
 CERT_PKIXVerifyCert(
     CERTCertificate *cert,
     SECCertificateUsage usages,
     CERTValInParam *paramsIn,
     CERTValOutParam *paramsOut,
     void *wincx)
 {
+#ifdef NSS_DISABLE_LIBPKIX
+    PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+    return SECFailure;
+#else
     SECStatus r = SECFailure;
     PKIX_Error *error = NULL;
     PKIX_ProcessingParams *procParams = NULL;
     PKIX_BuildResult *buildResult = NULL;
     void *nbioContext = NULL; /* for non-blocking IO */
     void *buildState = NULL;  /* for non-blocking IO */
     PKIX_CertSelector *certSelector = NULL;
     PKIX_List *certStores = NULL;
@@ -2236,9 +2296,10 @@ CERT_PKIXVerifyCert(
     } while (errorGenerated);
 
     runningLeakTest = PKIX_FALSE;
     PR_ATOMIC_DECREMENT(&parallelFnInvocationCount);
     usePKIXValidationEngine = savedUsePkixEngFlag;
 #endif /* PKIX_OBJECT_LEAK_TEST */
 
     return r;
+#endif /* NSS_DISABLE_LIBPKIX */
 }
--- a/security/nss/lib/crmf/servget.c
+++ b/security/nss/lib/crmf/servget.c
@@ -491,19 +491,17 @@ crmf_copy_cert_req_msg(CRMFCertReqMsg *s
         goto loser;
     }
     /* None of my set/get routines operate on the regInfo field, so
      * for now, that won't get copied over.
      */
     return newReqMsg;
 
 loser:
-    if (newReqMsg != NULL) {
-        CRMF_DestroyCertReqMsg(newReqMsg);
-    }
+    CRMF_DestroyCertReqMsg(newReqMsg);
     return NULL;
 }
 
 CRMFCertReqMsg *
 CRMF_CertReqMessagesGetCertReqMsgAtIndex(CRMFCertReqMessages *inReqMsgs,
                                          int index)
 {
     int numMsgs;
@@ -863,19 +861,17 @@ CRMF_CertRequestGetControlAtIndex(CRMFCe
         default:
             rv = SECFailure;
     }
     if (rv != SECSuccess) {
         goto loser;
     }
     return newControl;
 loser:
-    if (newControl != NULL) {
-        CRMF_DestroyControl(newControl);
-    }
+    CRMF_DestroyControl(newControl);
     return NULL;
 }
 
 static SECItem *
 crmf_copy_control_value(CRMFControl *inControl)
 {
     return SECITEM_DupItem(&inControl->derValue);
 }
deleted file mode 100644
--- a/security/nss/lib/freebl/ecl/Makefile
+++ /dev/null
@@ -1,195 +0,0 @@
-#
-# Makefile for elliptic curve library
-
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-## Define CC to be the C compiler you wish to use.  The GNU cc
-## compiler (gcc) should work, at the very least
-#CC=cc
-#CC=gcc
-
-## 
-## Define PERL to point to your local Perl interpreter.  It
-## should be Perl 5.x, although it's conceivable that Perl 4
-## might work ... I haven't tested it.
-##
-#PERL=/usr/bin/perl
-#PERL=perl
-
-include ../mpi/target.mk
-
-##
-## Define platform-dependent variables for use of floating-point code.
-##
-ifeq ($(TARGET),v9SOLARIS)
-ECL_USE_FP=1
-else
-ifeq ($(TARGET),v8plusSOLARIS)
-ECL_USE_FP=1
-else
-ifeq ($(TARGET),v8SOLARIS)
-ECL_USE_FP=1
-else
-ifeq ($(TARGET),x86LINUX)
-ECL_USE_FP=1
-endif
-endif
-endif
-endif
-
-##
-## Add to definition of CFLAGS depending on use of floating-point code.
-##
-ifeq ($(ECL_USE_FP),1)
-CFLAGS+= -DECL_USE_FP
-endif
-
-##
-## Define LIBS to include any libraries you need to link against.
-## If NO_TABLE is define, LIBS should include '-lm' or whatever is
-## necessary to bring in the math library.  Otherwise, it can be
-## left alone, unless your system has other peculiar requirements.
-##
-LIBS=-L../mpi -lmpi -lm#-lmalloc#-lefence
-
-##
-## Define INCLUDES to include any include directories you need to 
-## compile with.  
-##
-INCLUDES=-I../mpi
-CFLAGS+= $(INCLUDES) $(XCFLAGS)
-
-## 
-## Define RANLIB to be the library header randomizer; you might not
-## need this on some systems (just set it to 'echo' on these systems,
-## such as IRIX)
-##
-RANLIB=echo
-
-## 
-## Define LIBOBJS to be the object files that will be created during
-## the build process.
-##
-LIBOBJS = ecl.o ecl_curve.o ecl_mult.o ecl_gf.o \
-	ec2_aff.o ec2_mont.o ec2_proj.o \
-	ec2_163.o ec2_193.o ec2_233.o \
-	ecp_aff.o ecp_jac.o ecp_mont.o \
-	ec_naf.o ecp_jm.o \
-	ecp_192.o ecp_224.o ecp_256.o ecp_384.o ecp_521.o \
-	ecp_256_32.o
-ifeq ($(ECL_USE_FP),1)
-LIBOBJS+= ecp_fp160.o ecp_fp192.o ecp_fp224.o ecp_fp.o
-endif
-
-## The headers contained in this library.
-LIBHDRS = ecl-exp.h ecl.h ec2.h ecp.h ecl-priv.h ecl-curve.h
-APPHDRS = ecl-exp.h ecl.h ec2.h ecp.h ecl-priv.h ecl-curve.h
-ifeq ($(ECL_GFP_ASSEMBLY_FP),1)
-LIBHDRS += ecp_fp.h
-APPHDRS += ecp_fp.h
-endif
-
-
-help:
-	@ echo ""
-	@ echo "The following targets can be built with this Makefile:"
-	@ echo ""
-	@ echo "libecl.a     - elliptic curve library"
-	@ echo "tests        - build command line tests"
-	@ echo "test         - run command line tests"
-	@ echo "clean        - clean up objects and such"
-	@ echo ""
-
-.SUFFIXES: .c .o .i
-
-.c.i:
-	$(CC) $(CFLAGS) -E $< > $@
-
-#---------------------------------------
-
-$(LIBOBJS): $(LIBHDRS)
-
-ecl.o: ecl.c $(LIBHDRS)
-ecl_curve.o: ecl_curve.c $(LIBHDRS)
-ecl_mult.o: ecl_mult.c $(LIBHDRS)
-ecl_gf.o: ecl_gf.c $(LIBHDRS)
-ec2_aff.o: ec2_aff.c $(LIBHDRS)
-ec2_mont.o: ec2_mont.c $(LIBHDRS)
-ec2_proj.o: ec2_proj.c $(LIBHDRS)
-ec2_163.o: ec2_163.c $(LIBHDRS)
-ec2_193.o: ec2_193.c $(LIBHDRS)
-ec2_233.o: ec2_233.c $(LIBHDRS)
-ecp_aff.o: ecp_aff.c $(LIBHDRS)
-ecp_jac.o: ecp_jac.c $(LIBHDRS)
-ecp_jm.o: ecp_jm.c $(LIBHDRS)
-ecp_mont.o: ecp_mont.c $(LIBHDRS)
-ecp_192.o: ecp_192.c $(LIBHDRS)
-ecp_224.o: ecp_224.c $(LIBHDRS)
-ecp_256.o: ecp_256.c $(LIBHDRS)
-ecp_384.o: ecp_384.c $(LIBHDRS)
-ecp_521.o: ecp_521.c $(LIBHDRS)
-ecp_fp.o: ecp_fp.c $(LIBHDRS)
-ifeq ($(ECL_USE_FP),1)
-ecp_fp160.o: ecp_fp160.c ecp_fpinc.c $(LIBHDRS)
-ecp_fp192.o: ecp_fp192.c ecp_fpinc.c $(LIBHDRS)
-ecp_fp224.o: ecp_fp224.c ecp_fpinc.c $(LIBHDRS)
-endif
-
-libecl.a: $(LIBOBJS)
-	ar -cvr libecl.a $(LIBOBJS)
-	$(RANLIB) libecl.a
-
-lib libs: libecl.a
-
-ecl.i: ecl.h
-
-#---------------------------------------
-
-ECLTESTOBJS = ec2_test.o ecp_test.o ec_naft.o
-ifeq ($(ECL_USE_FP),1)
-ECLTESTOBJS+= ecp_fpt.o
-endif
-ECLTESTS = $(ECLTESTOBJS:.o=)
-
-$(ECLTESTOBJS): %.o: tests/%.c $(LIBHDRS)
-	$(CC) $(CFLAGS) -o $@ -c $<  $(INCLUDES)
-
-$(ECLTESTS): %: %.o libecl.a
-	$(CC) $(CFLAGS) -o $@ $^  $(LIBS)
-
-ifeq ($(ECL_USE_FP),1)
-tests: ec2_test ecp_test ec_naft ecp_fpt 
-else
-tests: ec2_test ecp_test ec_naft
-endif
-
-#---------------------------------------
-
-ifeq ($(ECL_USE_FP),1)
-test: tests
-	./ecp_test
-	./ec2_test
-	./ec_naft
-	./ecp_fpt
-else
-test: tests
-	./ecp_test
-	./ec_naft
-	./ec2_test
-endif
-
-#---------------------------------------
-
-alltests: tests
-
-clean:
-	rm -f *.o *.a *.i
-	rm -f core
-	rm -f *~ .*~
-	rm -f $(ECLTESTS)
-
-clobber: clean
-
-# END
--- a/security/nss/lib/freebl/ecl/README
+++ b/security/nss/lib/freebl/ecl/README
@@ -263,35 +263,8 @@ function in ec2_k163.c:
 		group->meth->field_sqr = &ec_GF2m_nistk163_sqr;
 		group->meth->field_div = &ec_GF2m_nistk163_div;
 		group->point_mul = &ec_GF2m_nistk163_pt_mul;
 		return MP_OKAY;
 	}
 
 For an example of functions that use special field encodings, take a
 look at ecp_mont.c.
-
-TESTING
-=======
-
-The ecl/tests directory contains a collection of standalone tests that
-verify the correctness of the elliptic curve library.
-
-Both ecp_test and ec2_test take the following arguments:
-
-	--print     Print out results of each point arithmetic test.
-	--time      Benchmark point operations and print results.
-
-The set of curves over which ecp_test and ec2_test run is coded into the
-program, but can be changed by editing the source files.
-
-BUILDING
-========
-
-The ecl can be built as a standalone library, separate from NSS,
-dependent only on the mpi library. To build the library:
-
-	> cd ../mpi
-	> make libs
-	> cd ../ecl
-	> make libs
-	> make tests # to build test files
-	> make test  # to run automated tests
--- a/security/nss/lib/freebl/fipsfreebl.c
+++ b/security/nss/lib/freebl/fipsfreebl.c
@@ -1162,19 +1162,17 @@ freebl_fips_ECDSA_Test(ECParams *ecparam
     /* ECDSA Single-Round Known Answer Verification Test. */
     /******************************************************/
 
     /* Perform ECDSA verification process. */
     ecdsaStatus = ECDSA_VerifyDigest(&ecdsa_public_key, &signature, &digest);
 
 loser:
     /* free the memory for the private key arena*/
-    if (ecdsa_private_key != NULL) {
-        PORT_FreeArena(ecdsa_private_key->ecParams.arena, PR_FALSE);
-    }
+    PORT_FreeArena(ecdsa_private_key->ecParams.arena, PR_FALSE);
 
     if (ecdsaStatus != SECSuccess) {
         PORT_SetError( SEC_ERROR_LIBRARY_FAILURE );
         return( SECFailure );
     }
     return( SECSuccess );
 }
 
--- a/security/nss/lib/freebl/intel-gcm-wrap.c
+++ b/security/nss/lib/freebl/intel-gcm-wrap.c
@@ -133,19 +133,17 @@ intel_AES_GCMContext *intel_AES_GCM_Crea
         PORT_Memset(buff, 0, AES_BLOCK_SIZE);
         PORT_Memcpy(buff, gcmParams->pAAD + AAD_whole_len, AAD_remainder_len);
         intel_aes_gcmAAD(gcm->Htbl, buff, AES_BLOCK_SIZE, gcm->T);
     }
     gcm->Alen += gcmParams->ulAADLen;
     return gcm;
 
 loser:
-    if (gcm) {
-        PORT_Free(gcm);
-    }
+    PORT_Free(gcm);
     return NULL;
 }
 
 void intel_AES_GCM_DestroyContext(intel_AES_GCMContext *gcm, PRBool freeit)
 {
     if (freeit) {
         PORT_Free(gcm);
     }
--- a/security/nss/lib/freebl/pqg.c
+++ b/security/nss/lib/freebl/pqg.c
@@ -1321,29 +1321,16 @@ pqg_ParamGen(unsigned int L, unsigned in
 	PORT_SetError(SEC_ERROR_NO_MEMORY);
 	PORT_FreeArena(arena, PR_TRUE);
 	PORT_FreeArena(params->arena, PR_TRUE);
 	return SECFailure;
     }
     verify->arena = arena;
     seed = &verify->seed;
     arena = NULL;
-    /* Initialize bignums */
-    MP_DIGITS(&P) = 0;
-    MP_DIGITS(&Q) = 0;
-    MP_DIGITS(&G) = 0;
-    MP_DIGITS(&H) = 0;
-    MP_DIGITS(&l) = 0;
-    MP_DIGITS(&p0) = 0;
-    CHECK_MPI_OK( mp_init(&P) );
-    CHECK_MPI_OK( mp_init(&Q) );
-    CHECK_MPI_OK( mp_init(&G) );
-    CHECK_MPI_OK( mp_init(&H) );
-    CHECK_MPI_OK( mp_init(&l) );
-    CHECK_MPI_OK( mp_init(&p0) );
 
     /* Select Hash and Compute lengths. */
     /* getFirstHash gives us the smallest acceptable hash for this key
      * strength */
     hashtype = getFirstHash(L,N);
     outlen = HASH_ResultLen(hashtype)*PR_BITS_PER_BYTE;
 
     /* Step 3: n = Ceil(L/outlen)-1; (same as n = Floor((L-1)/outlen)) */
--- a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_aiamgr.c
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_aiamgr.c
@@ -361,17 +361,17 @@ pkix_pl_AIAMgr_GetHTTPCerts(
 
         } else  {
 		PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT);
 	}
 
 cleanup:
         /* Session and request cleanup in case of error. Passing through without cleanup
          * if interrupted by blocked IO. */
-        if (PKIX_ERROR_RECEIVED && aiaMgr) {
+        if (PKIX_ERROR_RECEIVED) {
             if (aiaMgr->client.hdata.requestSession != NULL) {
                 (*hcv1->freeFcn)(aiaMgr->client.hdata.requestSession);
                 aiaMgr->client.hdata.requestSession = NULL;
             }
             if (aiaMgr->client.hdata.serverSession != NULL) {
                 (*hcv1->freeSessionFcn)(aiaMgr->client.hdata.serverSession);
                 aiaMgr->client.hdata.serverSession = NULL;
             }
--- a/security/nss/lib/manifest.mn
+++ b/security/nss/lib/manifest.mn
@@ -22,17 +22,17 @@ SOFTOKEN_SRCDIRS = \
 	$(SQLITE_SRCDIR) \
 	$(DBM_SRCDIR) \
 	$(SOFTOKEN_SRCDIR) \
 	$(NULL)
 ifndef NSS_BUILD_SOFTOKEN_ONLY
 # the rest of nss
 NSS_SRCDIRS = \
 	base dev pki \
-	libpkix \
+	$(LIBPKIX_SRCDIR) \
 	certdb certhigh pk11wrap cryptohi nss \
 	$(ZLIB_SRCDIR) ssl \
 	pkcs7 pkcs12 smime \
 	crmf jar \
 	ckfw $(SYSINIT_SRCDIR) \
 	$(NULL)
 endif
 endif
--- a/security/nss/lib/nss/config.mk
+++ b/security/nss/lib/nss/config.mk
@@ -74,28 +74,33 @@ SHARED_LIBRARY_LIBS = \
 SHARED_LIBRARY_DIRS = \
 	../certhigh \
 	../cryptohi \
 	../pk11wrap \
 	../certdb \
 	../pki \
 	../dev \
 	../base \
+	$(NULL)
+
+ifndef NSS_DISABLE_LIBPKIX
+SHARED_LIBRARY_DIRS += \
 	../libpkix/pkix/certsel \
 	../libpkix/pkix/checker \
 	../libpkix/pkix/params \
 	../libpkix/pkix/results \
 	../libpkix/pkix/top \
 	../libpkix/pkix/util \
 	../libpkix/pkix/crlsel \
 	../libpkix/pkix/store \
 	../libpkix/pkix_pl_nss/pki \
 	../libpkix/pkix_pl_nss/system \
 	../libpkix/pkix_pl_nss/module \
 	$(NULL)
+endif
 
 ifeq (,$(filter-out WINNT WIN95,$(OS_TARGET)))
 ifndef NS_USE_GCC
 # Export 'mktemp' to be backward compatible with NSS 3.2.x and 3.3.x
 # but do not put it in the import library.  See bug 142575.
 DEFINES += -DWIN32_NSS3_DLL_COMPAT
 DLLFLAGS += -EXPORT:mktemp=nss_mktemp,PRIVATE
 endif
--- a/security/nss/lib/nss/nss.h
+++ b/security/nss/lib/nss/nss.h
@@ -17,22 +17,22 @@
 
 /*
  * 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.25" _NSS_CUSTOMIZED
+#define NSS_VERSION  "3.26" _NSS_CUSTOMIZED " Beta"
 #define NSS_VMAJOR   3
 #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/nss/nssinit.c
+++ b/security/nss/lib/nss/nssinit.c
@@ -15,19 +15,22 @@
 #include "key.h"
 #include "secmod.h"
 #include "secoid.h"
 #include "nss.h"
 #include "pk11func.h"
 #include "secerr.h"
 #include "nssbase.h"
 #include "nssutil.h"
+
+#ifndef NSS_DISABLE_LIBPKIX
 #include "pkixt.h"
 #include "pkix.h"
 #include "pkix_tools.h"
+#endif /* NSS_DISABLE_LIBPKIX */
 
 #include "pki3hack.h"
 #include "certi.h"
 #include "secmodi.h"
 #include "ocspti.h"
 #include "ocspi.h"
 #include "utilpars.h"
 
@@ -476,17 +479,20 @@ loser:
  *           smart card tokens will not work).
  * allowAlreadyInitializedModules - if a module has already been loaded and
  *           initialize try to use it.
  * don'tFinalizeModules -  dont shutdown modules we may have loaded.
  */
 
 static PRBool          nssIsInitted = PR_FALSE;
 static NSSInitContext *nssInitContextList = NULL;
+
+#ifndef NSS_DISABLE_LIBPKIX
 static void*           plContext = NULL;
+#endif /* NSS_DISABLE_LIBPKIX */
 
 struct NSSInitContextStr {
     NSSInitContext *next;
     PRUint32 magic;
 };
 
 #define NSS_INIT_MAGIC 0x1413A91C
 static SECStatus nss_InitShutdownList(void);
@@ -521,18 +527,20 @@ nss_Init(const char *configdir, const ch
 		 NSSInitParameters *initParams,
 		 PRBool readOnly, PRBool noCertDB, 
 		 PRBool noModDB, PRBool forceOpen, PRBool noRootInit,
 		 PRBool optimizeSpace, PRBool noSingleThreadedModules,
 		 PRBool allowAlreadyInitializedModules,
 		 PRBool dontFinalizeModules)
 {
     SECStatus rv = SECFailure;
+#ifndef NSS_DISABLE_LIBPKIX
     PKIX_UInt32 actualMinorVersion = 0;
     PKIX_Error *pkixError = NULL;
+#endif /* NSS_DISABLE_LIBPKIX */
     PRBool isReallyInitted;
     char *configStrings = NULL;
     char *configName = NULL;
     PRBool passwordRequired = PR_FALSE;
 
     /* if we are trying to init with a traditional NSS_Init call, maintain
      * the traditional idempotent behavior. */
     if (!initContextPtr && nssIsInitted) {
@@ -679,30 +687,30 @@ nss_Init(const char *configdir, const ch
 		    nss_FindExternalRoot(dbpath, secmodName);
 		}
 	    }
 	}
 
 	pk11sdr_Init();
 	cert_CreateSubjectKeyIDHashTable();
 
+#ifndef NSS_DISABLE_LIBPKIX
 	pkixError = PKIX_Initialize
 	    (PKIX_FALSE, PKIX_MAJOR_VERSION, PKIX_MINOR_VERSION,
 	    PKIX_MINOR_VERSION, &actualMinorVersion, &plContext);
 
 	if (pkixError != NULL) {
 	    goto loser;
 	} else {
             char *ev = PR_GetEnvSecure("NSS_ENABLE_PKIX_VERIFY");
             if (ev && ev[0]) {
                 CERT_SetUsePKIXForValidation(PR_TRUE);
             }
         }
-
-
+#endif /* NSS_DISABLE_LIBPKIX */
     }
 
     /*
      * Now mark the appropriate init state. If initContextPtr was passed
      * in, then return the new context pointer and add it to the
      * nssInitContextList. Otherwise set the global nss_isInitted flag
      */
     PZ_Lock(nssInitLock);
@@ -1075,17 +1083,19 @@ nss_Shutdown(void)
 
     rv = nss_ShutdownShutdownList();
     if (rv != SECSuccess) {
 	shutdownRV = SECFailure;
     }
     cert_DestroyLocks();
     ShutdownCRLCache();
     OCSP_ShutdownGlobal();
+#ifndef NSS_DISABLE_LIBPKIX
     PKIX_Shutdown(plContext);
+#endif /* NSS_DISABLE_LIBPKIX */
     SECOID_Shutdown();
     status = STAN_Shutdown();
     cert_DestroySubjectKeyIDHashTable();
     pk11_SetInternalKeySlot(NULL);
     rv = SECMOD_Shutdown();
     if (rv != SECSuccess) {
 	shutdownRV = SECFailure;
     }
--- a/security/nss/lib/pk11wrap/pk11akey.c
+++ b/security/nss/lib/pk11wrap/pk11akey.c
@@ -808,20 +808,19 @@ PK11_GetPrivateModulusLen(SECKEYPrivateK
 	if (crv != CKR_OK) {
 	    PORT_SetError( PK11_MapError(crv) );
 	    return -1;
 	}
 	length = theTemplate.ulValueLen;
 	if ( *(unsigned char *)theTemplate.pValue == 0) {
 	    length--;
 	}
-	if (theTemplate.pValue != NULL)
-	    PORT_Free(theTemplate.pValue);
+	PORT_Free(theTemplate.pValue);
 	return (int) length;
-	
+
     case fortezzaKey:
     case dsaKey:
     case dhKey:
     default:
 	break;
     }
     if (theTemplate.pValue != NULL)
 	PORT_Free(theTemplate.pValue);
--- a/security/nss/lib/pk11wrap/pk11cert.c
+++ b/security/nss/lib/pk11wrap/pk11cert.c
@@ -2146,31 +2146,36 @@ CERTCertificate *
 PK11_FindCertFromDERCertItem(PK11SlotInfo *slot, const SECItem *inDerCert,
 								 void *wincx)
 
 {
     NSSDER derCert;
     NSSToken *tok;
     nssCryptokiObject *co = NULL;
     SECStatus rv;
+    CERTCertificate *cert = NULL;
 
     tok = PK11Slot_GetNSSToken(slot);
     NSSITEM_FROM_SECITEM(&derCert, inDerCert);
     rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
     if (rv != SECSuccess) {
 	PK11_FreeSlot(slot);
 	return NULL;
     }
 
     co = nssToken_FindCertificateByEncodedCertificate(tok, NULL, &derCert,
                                           nssTokenSearchType_TokenOnly, NULL);
 
-    return co ? PK11_MakeCertFromHandle(slot, co->handle, NULL) : NULL;
+    if (co) {
+	cert = PK11_MakeCertFromHandle(slot, co->handle, NULL);
+	nssCryptokiObject_Destroy(co);
+    }
 
-} 
+    return cert;
+}
 
 /*
  * import a cert for a private key we have already generated. Set the label
  * on both to be the nickname.
  */
 static CK_OBJECT_HANDLE 
 pk11_findKeyObjectByDERCert(PK11SlotInfo *slot, CERTCertificate *cert, 
 								void *wincx)
--- a/security/nss/lib/pk11wrap/pk11obj.c
+++ b/security/nss/lib/pk11wrap/pk11obj.c
@@ -1239,20 +1239,18 @@ PK11_UnwrapPrivKey(PK11SlotInfo *slot, P
 	    PK11_ExitSlotMonitor(slot);
 	}
 	PK11_FreeSymKey(newKey);
 	newKey = NULL;
     } else {
 	crv = CKR_FUNCTION_NOT_SUPPORTED;
     }
 
-    if (ck_id) {
-	SECITEM_FreeItem(ck_id, PR_TRUE);
-	ck_id = NULL;
-    }
+    SECITEM_FreeItem(ck_id, PR_TRUE);
+    ck_id = NULL;
 
     if (crv != CKR_OK) {
 	/* we couldn't unwrap the key, use the internal module to do the
 	 * unwrap, then load the new key into the token */
 	 PK11SlotInfo *int_slot = PK11_GetInternalSlot();
 
 	if (int_slot && (slot != int_slot)) {
 	    SECKEYPrivateKey *privKey = PK11_UnwrapPrivKey(int_slot,
--- a/security/nss/lib/pk11wrap/pk11skey.c
+++ b/security/nss/lib/pk11wrap/pk11skey.c
@@ -1770,18 +1770,17 @@ static PK11SymKey *pk11_ANSIX963Derive(P
     }
 
     PORT_ZFree(buffer, bufferLen);
     if (newSharedSecret != NULL)
 	PK11_FreeSymKey(newSharedSecret);
     return intermediateResult;
 
 loser:
-    if (buffer != NULL)
-	PORT_ZFree(buffer, bufferLen);
+    PORT_ZFree(buffer, bufferLen);
     if (newSharedSecret != NULL)
 	PK11_FreeSymKey(newSharedSecret);
     if (intermediateResult != NULL)
 	PK11_FreeSymKey(intermediateResult);
     return NULL;
 }
 
 /*
--- a/security/nss/lib/pk11wrap/pk11slot.c
+++ b/security/nss/lib/pk11wrap/pk11slot.c
@@ -555,20 +555,18 @@ PK11_FindSlotsByNames(const char *dllNam
                     rv = SECFailure;
                     break;
                 }
                 if ((PR_FALSE == presentOnly || PK11_IsPresent(tmpSlot)) &&
                     ( (!tokenName) ||
                       (0==PORT_Strcmp(tmpSlot->token_name, tokenName)) ) &&
                     ( (!slotName) ||
                       (0==PORT_Strcmp(tmpSlot->slot_name, slotName)) ) ) {
-                    if (tmpSlot) {
-                        PK11_AddSlotToList(slotList, tmpSlot, PR_TRUE);
-                        slotcount++;
-                    }
+                    PK11_AddSlotToList(slotList, tmpSlot, PR_TRUE);
+                    slotcount++;
                 }
             }
         }
     }
     SECMOD_ReleaseReadLock(moduleLock);
 
     if ( (0 == slotcount) || (SECFailure == rv) ) {
         PORT_SetError(SEC_ERROR_NO_TOKEN);
--- a/security/nss/lib/pkcs12/p12d.c
+++ b/security/nss/lib/pkcs12/p12d.c
@@ -1611,17 +1611,17 @@ sec_pkcs12_decoder_set_attribute_value(s
 				           sec_PKCS12Attribute *, i + 1, i + 2);
     }
 
     if(!bag->attribs) {
 	return SECFailure;
     }
 
     bag->attribs[i] = PORT_ArenaZNew(bag->arena, sec_PKCS12Attribute);
-    if(!bag->attribs) {
+    if(!bag->attribs[i]) {
 	return SECFailure;
     }
 
     bag->attribs[i]->attrValue = PORT_ArenaZNewArray(bag->arena, SECItem *, 2);
     if(!bag->attribs[i]->attrValue) {
 	return SECFailure;
     }
 
--- a/security/nss/lib/pki/pki3hack.c
+++ b/security/nss/lib/pki/pki3hack.c
@@ -1322,17 +1322,20 @@ DeleteCertTrustMatchingSlot(PK11SlotInfo
 */
 NSS_EXTERN PRStatus
 STAN_DeleteCertTrustMatchingSlot(NSSCertificate *c)
 {
     PRStatus nssrv = PR_SUCCESS;
 
     NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
     NSSTrust *nssTrust = nssTrustDomain_FindTrustForCertificate(td, c);
-    /* caller made sure nssTrust isn't NULL */
+    if (!nssTrust) {
+        return PR_FAILURE;
+    }
+
     nssPKIObject *tobject = &nssTrust->object;
     nssPKIObject *cobject = &c->object;
     unsigned int i;
 
     /* Iterate through the cert and trust object instances looking for
      * those with matching pk11 slots to delete. Even if some device
      * can't delete we keep going. Keeping a status variable for the
      * loop so that once it's failed the other gets set.
@@ -1347,16 +1350,17 @@ STAN_DeleteCertTrustMatchingSlot(NSSCert
 	    if (!tobject->numInstances || !tobject->instances) continue;
 	    status = DeleteCertTrustMatchingSlot(cInstance->token->pk11slot, tobject);
 	    if (status == PR_FAILURE) {
 	    	/* set the outer one but keep going */
 	    	nssrv = PR_FAILURE;
 	    }
 	}
     }
+    nssTrust_Destroy(nssTrust);
     nssPKIObject_Unlock(cobject);
     nssPKIObject_Destroy(cobject);
     NSSRWLock_UnlockRead(td->tokensLock);
     return nssrv;
 }
 
 /* CERT_TraversePermCertsForSubject */
 NSS_IMPLEMENT PRStatus
--- a/security/nss/lib/smime/cmsdecode.c
+++ b/security/nss/lib/smime/cmsdecode.c
@@ -296,18 +296,17 @@ nss_cms_before_data(NSSCMSDecoderContext
 
     PORT_ArenaUnmark(poolp, mark);
 
     return SECSuccess;
 
 loser:
     if (mark)
 	PORT_ArenaRelease(poolp, mark);
-    if (childp7dcx)
-	PORT_Free(childp7dcx);
+    PORT_Free(childp7dcx);
     p7dcx->childp7dcx = NULL;
     return SECFailure;
 }
 
 static SECStatus
 nss_cms_after_data(NSSCMSDecoderContext *p7dcx)
 {
     NSSCMSDecoderContext *childp7dcx;
--- a/security/nss/lib/softoken/legacydb/dbmshim.c
+++ b/security/nss/lib/softoken/legacydb/dbmshim.c
@@ -598,16 +598,14 @@ dbsopen(const char *dbname, int flags, i
     dbs->sync = dbs_sync;
     dbs->fd = dbs_fd;
 
     return dbs;
 loser:
     if (db) {
 	(*db->close)(db);
     }
-    if (dbsp) {
-	if (dbsp->blobdir) {
-	    PORT_Free(dbsp->blobdir);
-	}
-	PORT_Free(dbsp);
+    if (dbsp->blobdir) {
+        PORT_Free(dbsp->blobdir);
     }
+    PORT_Free(dbsp);
     return NULL;
 }
--- a/security/nss/lib/softoken/legacydb/lgattr.c
+++ b/security/nss/lib/softoken/legacydb/lgattr.c
@@ -66,21 +66,18 @@ lg_NewObjectCache(SDB *sdb, const SECIte
     rv = SECITEM_CopyItem(NULL,&obj->dbKey,dbKey);
     lg_DBUnlock(sdb);
     if (rv != SECSuccess) {
 	goto loser;
     }
 
     return obj;
 loser:
-    if (obj) {
-	(void) lg_DestroyObjectCache(obj);
-    }
+    (void) lg_DestroyObjectCache(obj);
     return NULL;
-
 }
 
 /*
  * free all the data associated with an object. Object reference count must
  * be 'zero'.
  */
 static void
 lg_DestroyObjectCache(LGObjectCache *obj)
@@ -1624,17 +1621,17 @@ lg_SetPublicKeyAttribute(LGObjectCache *
     return  CKR_ATTRIBUTE_READ_ONLY;
 }
 
 static CK_RV
 lg_SetTrustAttribute(LGObjectCache *obj, const CK_ATTRIBUTE *attr)
 {
     unsigned int flags;
     CK_TRUST  trust;
-    NSSLOWCERTCertificate  *cert;
+    NSSLOWCERTCertificate  *cert = NULL;
     NSSLOWCERTCertDBHandle *certHandle;
     NSSLOWCERTCertTrust    dbTrust;
     SECStatus rv;
     CK_RV crv;
 
     if (attr->type == CKA_LABEL) {
 	return CKR_OK;
     }
@@ -1679,16 +1676,19 @@ lg_SetTrustAttribute(LGObjectCache *obj,
     default:
 	crv = CKR_ATTRIBUTE_READ_ONLY;
 	goto done;
     }
 
     rv = nsslowcert_ChangeCertTrust(certHandle, cert, &dbTrust);
     crv = (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR;
 done:
+    if (cert) {
+        nsslowcert_DestroyCertificate(cert);
+    }
     return crv;
 }
 
 static CK_RV
 lg_SetSingleAttribute(LGObjectCache *obj, const CK_ATTRIBUTE *attr, 
 		      PRBool *writePrivate)
 {
     CK_ATTRIBUTE attribLocal;
--- a/security/nss/lib/softoken/legacydb/pcertdb.c
+++ b/security/nss/lib/softoken/legacydb/pcertdb.c
@@ -2768,19 +2768,21 @@ AddNicknameToSubject(NSSLOWCERTCertDBHan
     DeleteDBSubjectEntry(dbhandle, &cert->derSubject);
 
     /* write the new one */
     rv = WriteDBSubjectEntry(dbhandle, entry);
     if ( rv != SECSuccess ) {
 	goto loser;
     }
 
+    DestroyDBEntry((certDBEntry *)entry);
     return(SECSuccess);
 
 loser:
+    DestroyDBEntry((certDBEntry *)entry);
     return(SECFailure);
 }
 
 /*
  * create a new version entry
  */
 static certDBEntryVersion *
 NewDBVersionEntry(unsigned int flags)
@@ -3822,30 +3824,24 @@ isV4DB(DB *db) {
 }
 
 static SECStatus
 UpdateV4DB(NSSLOWCERTCertDBHandle *handle, DB *updatedb)
 {
     DBT key, data;
     certDBEntryCert *entry, *entry2;
     int ret;
-    PLArenaPool *arena = NULL;
     NSSLOWCERTCertificate *cert;
 
     ret = (* updatedb->seq)(updatedb, &key, &data, R_FIRST);
 
     if ( ret ) {
 	return(SECFailure);
     }
 
-    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
-    if (arena == NULL) {
-	return(SECFailure);
-    }
-    
     do {
 	if ( data.size != 1 ) { /* skip version number */
 
 	    /* decode the old DB entry */
 	    entry = (certDBEntryCert *)
 		DecodeV4DBCertEntry((unsigned char*)data.data, data.size);
 	    
 	    if ( entry ) {
@@ -3862,17 +3858,16 @@ UpdateV4DB(NSSLOWCERTCertDBHandle *handl
 			DestroyDBEntry((certDBEntry *)entry2);
 		    }
 		}
 		DestroyDBEntry((certDBEntry *)entry);
 	    }
 	}
     } while ( (* updatedb->seq)(updatedb, &key, &data, R_NEXT) == 0 );
 
-    PORT_FreeArena(arena, PR_FALSE);
     (* updatedb->close)(updatedb);
     return(SECSuccess);
 }
 
 
 /*
  * return true if a database key conflict exists
  */
--- a/security/nss/lib/softoken/pkcs11u.c
+++ b/security/nss/lib/softoken/pkcs11u.c
@@ -912,17 +912,19 @@ sftk_freeObjectData(SFTKObject *object) 
 
    PORT_Free(object);
    return next;
 }
 
 static void
 sftk_InitFreeList(SFTKObjectFreeList *list)
 {
-    list->lock = PZ_NewLock(nssILockObject);
+    if (!list->lock) {
+        list->lock = PZ_NewLock(nssILockObject);
+    }
 }
 
 void sftk_InitFreeLists(void)
 {
     sftk_InitFreeList(&sessionObjectList);
     sftk_InitFreeList(&tokenObjectList);
 }
    
@@ -1924,21 +1926,18 @@ sftk_NewTokenObject(SFTKSlot *slot, SECI
     }
     if (object->refLock == NULL) {
 	goto loser;
     }
     object->refCount = 1;
 
     return object;
 loser:
-    if (object) {
-	(void) sftk_DestroyObject(object);
-    }
+    (void) sftk_DestroyObject(object);
     return NULL;
-
 }
 
 SFTKTokenObject *
 sftk_convertSessionToToken(SFTKObject *obj)
 {
     SECItem *key;
     SFTKSessionObject *so = (SFTKSessionObject *)obj;
     SFTKTokenObject *to = sftk_narrowToTokenObject(obj);
--- 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.25" SOFTOKEN_ECC_STRING
+#define SOFTOKEN_VERSION  "3.26" SOFTOKEN_ECC_STRING " Beta"
 #define SOFTOKEN_VMAJOR   3
 #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/Makefile
+++ b/security/nss/lib/ssl/Makefile
@@ -13,18 +13,18 @@ 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 config.mk
 
--- a/security/nss/lib/ssl/SSLerrs.h
+++ b/security/nss/lib/ssl/SSLerrs.h
@@ -464,8 +464,17 @@ 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.")
+
+ER3(SSL_ERROR_RX_MALFORMED_EARLY_DATA, (SSL_ERROR_BASE + 148),
+    "SSL received an invalid EarlyData extension.")
+
+ER3(SSL_ERROR_END_OF_EARLY_DATA_ALERT, (SSL_ERROR_BASE + 149),
+    "SSL received an unexpected end of early data alert.")
+
+ER3(SSL_ERROR_MISSING_ALPN_EXTENSION, (SSL_ERROR_BASE + 150),
+    "SSL didn't receive an expected ALPN extension.")
--- a/security/nss/lib/ssl/ssl.h
+++ b/security/nss/lib/ssl/ssl.h
@@ -217,16 +217,36 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRF
  * client includes the extension.
  *
  * See SSL_DHEGroupPrefSet() for how to control which groups are enabled.
  *
  * This option cannot be enabled if NSS is not compiled with ECC support.
  */
 #define SSL_REQUIRE_DH_NAMED_GROUPS 32
 
+/* Allow 0-RTT data (for TLS 1.3).
+ *
+ * When this option is set, the server's session tickets will contain
+ * a flag indicating that it accepts 0-RTT. When resuming such a
+ * session, PR_Write() on the client will be allowed immediately after
+ * starting the handshake and PR_Read() on the server will be allowed
+ * on the server to read that data. Calls to
+ * SSL_GetPreliminaryChannelInfo() and SSL_GetNextProto()
+ * can be made used during this period to learn about the channel
+ * parameters [TODO(ekr@rtfm.com): This hasn't landed yet].
+ *
+ * The transition between the 0-RTT and 1-RTT modes is marked by the
+ * handshake callback.
+ *
+ * WARNING: 0-RTT data has different anti-replay and PFS properties than
+ * the rest of the TLS data. See [draft-ietf-tls-tls13; Section 6.2.3]
+ * for more details.
+ */
+#define SSL_ENABLE_0RTT_DATA 33
+
 #ifdef SSL_DEPRECATED_FUNCTION
 /* Old deprecated function names */
 SSL_IMPORT SECStatus SSL_Enable(PRFileDesc *fd, int option, PRBool on);
 SSL_IMPORT SECStatus SSL_EnableDefault(int option, PRBool on);
 #endif
 
 /* New function names */
 SSL_IMPORT SECStatus SSL_OptionSet(PRFileDesc *fd, PRInt32 option, PRBool on);
@@ -278,20 +298,21 @@ SSL_IMPORT SECStatus SSL_SetNextProtoCal
  *
  * The supported protocols are specified in |data| in wire-format (8-bit
  * length-prefixed). For example: "\010http/1.1\006spdy/2". */
 SSL_IMPORT SECStatus SSL_SetNextProtoNego(PRFileDesc *fd,
                                           const unsigned char *data,
                                           unsigned int length);
 
 typedef enum SSLNextProtoState {
-    SSL_NEXT_PROTO_NO_SUPPORT = 0, /* No peer support                */
-    SSL_NEXT_PROTO_NEGOTIATED = 1, /* Mutual agreement               */
-    SSL_NEXT_PROTO_NO_OVERLAP = 2, /* No protocol overlap found      */
-    SSL_NEXT_PROTO_SELECTED = 3    /* Server selected proto (ALPN)   */
+    SSL_NEXT_PROTO_NO_SUPPORT = 0, /* No peer support                   */
+    SSL_NEXT_PROTO_NEGOTIATED = 1, /* Mutual agreement                  */
+    SSL_NEXT_PROTO_NO_OVERLAP = 2, /* No protocol overlap found         */
+    SSL_NEXT_PROTO_SELECTED = 3,   /* Server selected proto (ALPN)      */
+    SSL_NEXT_PROTO_EARLY_VALUE = 4 /* We are in 0-RTT using this value. */
 } SSLNextProtoState;
 
 /* SSL_GetNextProto can be used in the HandshakeCallback or any time after
  * a handshake to retrieve the result of the Next Protocol negotiation.
  *
  * The length of the negotiated protocol, if any, is written into *bufLen.
  * If the negotiated protocol is longer than bufLenMax, then SECFailure is
  * returned. Otherwise, the negotiated protocol, if any, is written into buf,
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -1600,19 +1600,16 @@ ssl3_DestroyCipherSpec(ssl3CipherSpec *s
     if (spec->destroyCompressContext && spec->compressContext) {
         spec->destroyCompressContext(spec->compressContext, 1);
         spec->compressContext = NULL;
     }
     if (spec->destroyDecompressContext && spec->decompressContext) {
         spec->destroyDecompressContext(spec->decompressContext, 1);
         spec->decompressContext = NULL;
     }
-    if (freeSrvName && spec->srvVirtName.data) {
-        SECITEM_FreeItem(&spec->srvVirtName, PR_FALSE);
-    }
     if (spec->master_secret != NULL) {
         PK11_FreeSymKey(spec->master_secret);
         spec->master_secret = NULL;
     }
     spec->msItem.data = NULL;
     spec->msItem.len = 0;
     ssl3_CleanupKeyMaterial(&spec->client);
     ssl3_CleanupKeyMaterial(&spec->server);
@@ -3840,16 +3837,19 @@ ssl3_HandleAlert(sslSocket *ss, sslBuffe
             error = SSL_ERROR_UNRECOGNIZED_NAME_ALERT;
             break;
         case bad_certificate_status_response:
             error = SSL_ERROR_BAD_CERT_STATUS_RESPONSE_ALERT;
             break;
         case bad_certificate_hash_value:
             error = SSL_ERROR_BAD_CERT_HASH_VALUE_ALERT;
             break;
+        case end_of_early_data:
+            error = SSL_ERROR_END_OF_EARLY_DATA_ALERT;
+            break;
         default:
             error = SSL_ERROR_RX_UNKNOWN_ALERT;
             break;
     }
     if (level == alert_fatal) {
         if (!ss->opt.noCache) {
             if (ss->sec.uncache)
                 ss->sec.uncache(ss->sec.ci.sid);
@@ -3859,16 +3859,23 @@ ssl3_HandleAlert(sslSocket *ss, sslBuffe
             /* XXX This is a hack.  We're assuming that any handshake failure
              * XXX on the client hello is a failure to match ciphers.
              */
             error = SSL_ERROR_NO_CYPHER_OVERLAP;
         }
         PORT_SetError(error);
         return SECFailure;
     }
+    if (desc == end_of_early_data) {
+        if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+            PORT_SetError(error);
+            return SECFailure;
+        }
+        return tls13_HandleEndOfEarlyData(ss);
+    }
     if ((desc == no_certificate) && (ss->ssl3.hs.ws == wait_client_cert)) {
         /* I'm a server. I've requested a client cert. He hasn't got one. */
         SECStatus rv;
 
         PORT_Assert(ss->sec.isServer);
         ss->ssl3.hs.ws = wait_client_key;
         rv = ssl3_HandleNoCertificate(ss);
         return rv;
@@ -4993,17 +5000,17 @@ ssl3_TLSHashAlgorithmToOID(SSLHashType h
             return tlsHashOIDMap[i].oid;
         }
     }
     return SEC_OID_UNKNOWN;
 }
 
 /* ssl3_TLSSignatureAlgorithmForKeyType returns the TLS 1.2 signature algorithm
  * identifier for a given KeyType. */
-static SECStatus
+SECStatus
 ssl3_TLSSignatureAlgorithmForKeyType(KeyType keyType, SSLSignType *out)
 {
     switch (keyType) {
         case rsaKey:
             *out = ssl_sign_rsa;
             return SECSuccess;
         case dsaKey:
             *out = ssl_sign_dsa;
@@ -5832,17 +5839,17 @@ 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)
+             1 + (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;
     }
 
@@ -5903,17 +5910,17 @@ ssl3_SendClientHello(sslSocket *ss, PRBo
                               SSL3_RANDOM_LENGTH);
     if (rv != SECSuccess) {
         if (sid->u.ssl3.lock) {
             PR_RWLock_Unlock(sid->u.ssl3.lock);
         }
         return rv; /* err set by ssl3_AppendHandshake* */
     }
 
-    if (sid && sid->version < SSL_LIBRARY_VERSION_TLS_1_3)
+    if (sid->version < SSL_LIBRARY_VERSION_TLS_1_3)
         rv = ssl3_AppendHandshakeVariable(
             ss, sid->u.ssl3.sessionID, sid->u.ssl3.sessionIDLength, 1);
     else
         rv = ssl3_AppendHandshakeNumber(ss, 0, 1);
     if (rv != SECSuccess) {
         if (sid->u.ssl3.lock) {
             PR_RWLock_Unlock(sid->u.ssl3.lock);
         }
@@ -6067,19 +6074,25 @@ ssl3_SendClientHello(sslSocket *ss, PRBo
     flags = 0;
     if (!ss->firstHsDone && !IS_DTLS(ss)) {
         flags |= ssl_SEND_FLAG_CAP_RECORD_VERSION;
     }
     rv = ssl3_FlushHandshake(ss, flags);
     if (rv != SECSuccess) {
         return rv; /* error code set by ssl3_FlushHandshake */
     }
+    if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
+        rv = tls13_MaybeDo0RTTHandshake(ss);
+        if (rv != SECSuccess) {
+            return SECFailure; /* error code set already. */
+        }
+    }
 
     ss->ssl3.hs.ws = wait_server_hello;
-    return rv;
+    return SECSuccess;
 }
 
 /* Called from ssl3_HandlePostHelloHandshakeMessage() when it has deciphered a
  * complete ssl3 Hello Request.
  * Caller must hold Handshake and RecvBuf locks.
  */
 static SECStatus
 ssl3_HandleHelloRequest(sslSocket *ss)
@@ -6690,24 +6703,27 @@ loser:
         PK11_FreeSymKey(pms);
     }
     return rv;
 }
 
 /* DH shares need to be padded to the size of their prime.  Some implementations
  * require this.  TLS 1.3 also requires this. */
 SECStatus
-ssl_AppendPaddedDHKeyShare(sslSocket *ss, SECKEYPublicKey *pubKey)
+ssl_AppendPaddedDHKeyShare(sslSocket *ss, SECKEYPublicKey *pubKey,
+                           PRBool appendLength)
 {
     SECStatus rv;
     unsigned int pad = pubKey->u.dh.prime.len - pubKey->u.dh.publicValue.len;
 
-    rv = ssl3_AppendHandshakeNumber(ss, pubKey->u.dh.prime.len, 2);
-    if (rv != SECSuccess) {
-        return rv;
+    if (appendLength) {
+        rv = ssl3_AppendHandshakeNumber(ss, pubKey->u.dh.prime.len, 2);
+        if (rv != SECSuccess) {
+            return rv;
+        }
     }
     while (pad) {
         rv = ssl3_AppendHandshakeNumber(ss, 0, 1);
         if (rv != SECSuccess) {
             return rv;
         }
         --pad;
     }
@@ -6769,17 +6785,17 @@ ssl3_SendDHClientKeyExchange(sslSocket *
         params = &customParams;
         customGroupDef.bits = SECKEY_PublicKeyStrengthInBits(svrPubKey);
         groupDef = &customGroupDef;
     }
 
     rv = ssl_CreateDHEKeyPair(groupDef, params, &keyPair);
     if (rv != SECSuccess) {
         ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL);
-        return SECFailure;
+        goto loser;
     }
     pubKey = keyPair->keys->pubKey;
     PRINT_BUF(50, (ss, "DH public value:",
                    pubKey->u.dh.publicValue.data,
                    pubKey->u.dh.publicValue.len));
 
     if (isTLS)
         target = CKM_TLS_MASTER_KEY_DERIVE_DH;
@@ -6797,17 +6813,17 @@ ssl3_SendDHClientKeyExchange(sslSocket *
     }
 
     /* Note: send the DH share padded to avoid triggering bugs. */
     rv = ssl3_AppendHandshakeHeader(ss, client_key_exchange,
                                     params->prime.len + 2);
     if (rv != SECSuccess) {
         goto loser; /* err set by ssl3_AppendHandshake* */
     }
-    rv = ssl_AppendPaddedDHKeyShare(ss, pubKey);
+    rv = ssl_AppendPaddedDHKeyShare(ss, pubKey, PR_TRUE);
     if (rv != SECSuccess) {
         goto loser; /* err set by ssl_AppendPaddedDHKeyShare */
     }
 
     rv = ssl3_InitPendingCipherSpec(ss, pms);
     if (rv != SECSuccess) {
         ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
         goto loser;
@@ -6899,43 +6915,30 @@ loser:
 
 /* Called from ssl3_HandleServerHelloDone(). */
 SECStatus
 ssl3_SendCertificateVerify(sslSocket *ss, SECKEYPrivateKey *privKey)
 {
     SECStatus rv = SECFailure;
     PRBool isTLS;
     PRBool isTLS12;
-    PRBool isTLS13;
     SECItem buf = { siBuffer, NULL, 0 };
     SSL3Hashes hashes;
     KeyType keyType;
     unsigned int len;
     SSLSignatureAndHashAlg sigAndHash;
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(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);
 
-    /* TODO(ekr@rtfm.com):
-     * 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.
-     */
-
     if (ss->ssl3.hs.hashType == handshake_hash_record &&
         ss->ssl3.hs.tls12CertVerifyHash != ssl3_GetSuitePrfHash(ss)) {
 #ifndef NO_PKCS11_BYPASS
         if (ss->opt.bypassPKCS11) {
             rv = ssl3_ComputeBypassHandshakeHash(ss->ssl3.hs.messages.buf,
                                                  ss->ssl3.hs.messages.len,
                                                  ss->ssl3.hs.tls12CertVerifyHash,
                                                  &hashes);
@@ -6947,53 +6950,26 @@ ssl3_SendCertificateVerify(sslSocket *ss
                                                  ss->ssl3.hs.tls12CertVerifyHash,
                                                  &hashes);
         }
         if (rv != SECSuccess) {
             ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
             goto done;
         }
     } else {
-        ssl3CipherSpec *spec;
-
-        if (isTLS13) {
-            /* In TLS 1.3, we are already encrypted. */
-            spec = ss->ssl3.cwSpec;
-        } else {
-            spec = ss->ssl3.pwSpec;
-        }
-
-        rv = ssl3_ComputeHandshakeHashes(ss, spec, &hashes, 0);
+        rv = ssl3_ComputeHandshakeHashes(ss, ss->ssl3.pwSpec, &hashes, 0);
     }
     ssl_ReleaseSpecReadLock(ss);
     if (rv != SECSuccess) {
         goto done; /* err code was set by ssl3_ComputeHandshakeHashes */
     }
 
-    if (isTLS13) {
-        rv = tls13_AddContextToHashes(ss, &hashes, tls13_GetHash(ss), PR_TRUE);
-        if (rv != SECSuccess) {
-            goto done; /* err code was set by tls13_AddContextToHashes */
-        }
-    }
-
     isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0);
     isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
 
-    /* Check requested by EKR, he'll fix after merging. */
-    if (ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
-        if (ss->sec.isServer != 0) {
-            ss->ssl3.hs.tls12CertVerifyHash = ssl3_GetSuitePrfHash(ss);
-        }
-        if (hashes.hashAlg != ss->ssl3.hs.tls12CertVerifyHash) {
-            PORT_Assert(0);
-            return SECFailure;
-        }
-    }
-
     keyType = privKey->keyType;
     rv = ssl3_SignHashes(&hashes, privKey, &buf, isTLS);
     if (rv == SECSuccess && !ss->sec.isServer) {
         /* Remember the info about the slot that did the signing.
         ** Later, when doing an SSL restart handshake, verify this.
         ** These calls are mere accessors, and can't fail.
         */
         PK11SlotInfo *slot;
@@ -7037,30 +7013,34 @@ 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)
+SECStatus
+ssl3_SetCipherSuite(sslSocket *ss, ssl3CipherSuite chosenSuite,
+                    PRBool initHashes)
 {
     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;
 
+    if (!initHashes) {
+        return SECSuccess;
+    }
     /* 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.
  */
@@ -7209,17 +7189,17 @@ ssl3_HandleServerHello(sslSocket *ss, SS
         }
     }
     if (!suite_found) {
         desc = handshake_failure;
         errCode = SSL_ERROR_NO_CYPHER_OVERLAP;
         goto alert_loser;
     }
 
-    rv = ssl3_SetCipherSuite(ss, (ssl3CipherSuite)temp);
+    rv = ssl3_SetCipherSuite(ss, (ssl3CipherSuite)temp, PR_TRUE);
     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. */
@@ -8468,17 +8448,17 @@ ssl3_NewSessionID(sslSocket *ss, PRBool 
     if (sid == NULL)
         return sid;
 
     if (is_server) {
         const SECItem *srvName;
         SECStatus rv = SECSuccess;
 
         ssl_GetSpecReadLock(ss); /********************************/
-        srvName = &ss->ssl3.prSpec->srvVirtName;
+        srvName = &ss->ssl3.hs.srvVirtName;
         if (srvName->len && srvName->data) {
             rv = SECITEM_CopyItem(NULL, &sid->u.ssl3.srvName, srvName);
         }
         ssl_ReleaseSpecReadLock(ss); /************************************/
         if (rv != SECSuccess) {
             PORT_Free(sid);
             return NULL;
         }
@@ -8641,17 +8621,17 @@ ssl3_NegotiateCipherSuite(sslSocket *ss,
         ssl3CipherSuiteCfg *suite = &ss->cipherSuites[j];
         SSLVersionRange vrange = { ss->version, ss->version };
         if (!config_match(suite, ss->ssl3.policy, &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) {
-                return ssl3_SetCipherSuite(ss, suite_i);
+                return ssl3_SetCipherSuite(ss, suite_i, PR_TRUE);
             }
         }
     }
     return SECFailure;
 }
 
 /*
  * Call the SNI config hook.
@@ -8662,34 +8642,35 @@ ssl3_NegotiateCipherSuite(sslSocket *ss,
  */
 SECStatus
 ssl3_ServerCallSNICallback(sslSocket *ss)
 {
     int errCode = SSL_ERROR_RX_MALFORMED_CLIENT_HELLO;
     SSL3AlertDescription desc = illegal_parameter;
     int ret = 0;
 
+#ifdef SSL_SNI_ALLOW_NAME_CHANGE_2HS
+#error("No longer allowed to set SSL_SNI_ALLOW_NAME_CHANGE_2HS")
+#endif
     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); /*******************************/
-            if (ss->ssl3.cwSpec->srvVirtName.data) {
+            if (ss->ssl3.hs.srvVirtName.data) {
                 passed = PR_FALSE;
             }
             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 */
             PORT_Assert((ss->ssl3.hs.preliminaryInfo & ssl_preinfo_all) ==
                         ssl_preinfo_all);
 
@@ -8705,33 +8686,32 @@ 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;
+                SECItem pwsNameBuf = { 0, NULL, 0 };
+                SECItem *pwsName = &pwsNameBuf;
+                SECItem *cwsName;
 
                 ssl_GetSpecWriteLock(ss); /*******************************/
-                pwsName = &ss->ssl3.pwSpec->srvVirtName;
-                cwsName = &ss->ssl3.cwSpec->srvVirtName;
-#ifndef SSL_SNI_ALLOW_NAME_CHANGE_2HS
+                cwsName = &ss->ssl3.hs.srvVirtName;
                 /* not allow name change on the 2d HS */
                 if (ss->firstHsDone) {
                     if (ssl3_ServerNameCompare(pwsName, cwsName)) {
                         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); /**************************/
                 if (rv != SECSuccess) {
@@ -8746,30 +8726,28 @@ ssl3_ServerCallSNICallback(sslSocket *ss
                 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); /*******************************/
-#ifndef SSL_SNI_ALLOW_NAME_CHANGE_2HS
                 /* not allow name change on the 2d HS */
                 if (ss->firstHsDone) {
-                    SECItem *cwsName = &ss->ssl3.cwSpec->srvVirtName;
+                    SECItem *cwsName = &ss->ssl3.hs.srvVirtName;
                     if (ssl3_ServerNameCompare(name, cwsName)) {
                         ssl_ReleaseSpecWriteLock(ss); /******************/
                         errCode = SSL_ERROR_UNRECOGNIZED_NAME_ALERT;
                         desc = handshake_failure;
                         ret = SSL_SNI_SEND_ALERT;
                         break;
                     }
                 }
-#endif
-                pwsName = &ss->ssl3.pwSpec->srvVirtName;
+                pwsName = &ss->ssl3.hs.srvVirtName;
                 if (pwsName->data) {
                     SECITEM_FreeItem(pwsName, PR_FALSE);
                 }
                 rv = SECITEM_CopyItem(NULL, pwsName, name);
                 ssl_ReleaseSpecWriteLock(ss); /***************************/
                 if (rv != SECSuccess) {
                     errCode = SSL_ERROR_INTERNAL_ERROR_ALERT;
                     desc = internal_error;
@@ -9287,17 +9265,17 @@ ssl3_HandleClientHelloPart2(sslSocket *s
             if (!suite->enabled)
                 break;
 #endif
             /* 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) {
-                    rv = ssl3_SetCipherSuite(ss, suite_i);
+                    rv = ssl3_SetCipherSuite(ss, suite_i, PR_TRUE);
                     if (rv != SECSuccess) {
                         desc = internal_error;
                         errCode = PORT_GetError();
                         goto alert_loser;
                     }
 
                     /* Use the cached compression method. */
                     ss->ssl3.hs.compression =
@@ -9507,17 +9485,17 @@ compression_found:
             ss->sec.localCert = CERT_DupCertificate(serverCert->serverCert);
 
             /* Copy cached name in to pending spec */
             if (sid != NULL &&
                 sid->version > SSL_LIBRARY_VERSION_3_0 &&
                 sid->u.ssl3.srvName.len && sid->u.ssl3.srvName.data) {
                 /* Set server name from sid */
                 SECItem *sidName = &sid->u.ssl3.srvName;
-                SECItem *pwsName = &ss->ssl3.pwSpec->srvVirtName;
+                SECItem *pwsName = &ss->ssl3.hs.srvVirtName;
                 if (pwsName->data) {
                     SECITEM_FreeItem(pwsName, PR_FALSE);
                 }
                 rv = SECITEM_CopyItem(NULL, pwsName, sidName);
                 if (rv != SECSuccess) {
                     errCode = PORT_GetError();
                     desc = internal_error;
                     goto alert_loser;
@@ -9624,16 +9602,23 @@ compression_found:
 alert_loser:
     if (haveSpecWriteLock) {
         ssl_ReleaseSpecWriteLock(ss);
         haveSpecWriteLock = PR_FALSE;
     }
     (void)SSL3_SendAlert(ss, alert_fatal, desc);
 /* FALLTHRU */
 loser:
+    if (sid && sid != ss->sec.ci.sid) {
+        if (ss->sec.uncache) {
+            ss->sec.uncache(sid);
+        }
+        ssl_FreeSID(sid);
+    }
+
     if (haveSpecWriteLock) {
         ssl_ReleaseSpecWriteLock(ss);
     }
 
     if (haveXmitBufLock) {
         ssl_ReleaseXmitBufLock(ss);
     }
 
@@ -9762,17 +9747,17 @@ ssl3_HandleV2ClientHello(sslSocket *ss, 
         ssl3CipherSuiteCfg *suite = &ss->cipherSuites[j];
         SSLVersionRange vrange = { ss->version, ss->version };
         if (!config_match(suite, ss->ssl3.policy, &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) {
-                rv = ssl3_SetCipherSuite(ss, suite_i);
+                rv = ssl3_SetCipherSuite(ss, suite_i, PR_TRUE);
                 if (rv != SECSuccess) {
                     desc = internal_error;
                     errCode = PORT_GetError();
                     goto alert_loser;
                 }
                 goto suite_found;
             }
         }
@@ -10115,17 +10100,17 @@ ssl3_SendDHServerKeyExchange(sslSocket *
     }
 
     rv = ssl3_AppendHandshakeVariable(ss, pubKey->u.dh.base.data,
                                       pubKey->u.dh.base.len, 2);
     if (rv != SECSuccess) {
         goto loser; /* err set by AppendHandshake. */
     }
 
-    rv = ssl_AppendPaddedDHKeyShare(ss, pubKey);
+    rv = ssl_AppendPaddedDHKeyShare(ss, pubKey, PR_TRUE);
     if (rv != SECSuccess) {
         goto loser; /* err set by AppendHandshake. */
     }
 
     if (ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
         rv = ssl3_AppendSignatureAndHashAlgorithm(ss, &sigAndHash);
         if (rv != SECSuccess) {
             goto loser; /* err set by AppendHandshake. */
@@ -11081,17 +11066,57 @@ ssl3_SendEmptyCertificate(sslSocket *ss)
         if (rv != SECSuccess) {
             return rv;
         }
     }
 
     return ssl3_AppendHandshakeNumber(ss, 0, 3);
 }
 
-SECStatus
+/*
+ * NewSessionTicket
+ * Called from ssl3_HandleFinished
+ */
+static SECStatus
+ssl3_SendNewSessionTicket(sslSocket *ss)
+{
+    SECItem ticket = { 0, NULL, 0 };
+    SECStatus rv;
+
+    rv = ssl3_EncodeSessionTicket(ss, &ticket);
+    if (rv != SECSuccess)
+        goto loser;
+
+    /* Serialize the handshake message. Length =
+     * lifetime (4) + ticket length (2) + ticket. */
+    rv = ssl3_AppendHandshakeHeader(ss, new_session_ticket,
+                                    4 + 2 + ticket.len);
+    if (rv != SECSuccess)
+        goto loser;
+
+    /* This is a fixed value. */
+    rv = ssl3_AppendHandshakeNumber(ss, TLS_EX_SESS_TICKET_LIFETIME_HINT, 4);
+    if (rv != SECSuccess)
+        goto loser;
+
+    /* Encode the ticket. */
+    rv = ssl3_AppendHandshakeVariable(ss, ticket.data, ticket.len, 2);
+    if (rv != SECSuccess)
+        goto loser;
+
+    rv = SECSuccess;
+
+loser:
+    if (ticket.data) {
+        SECITEM_FreeItem(&ticket, PR_FALSE);
+    }
+    return rv;
+}
+
+static SECStatus
 ssl3_HandleNewSessionTicket(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
 {
     SECStatus rv;
     SECItem ticketData;
 
     SSL_TRC(3, ("%d: SSL3[%d]: handle session_ticket handshake",
                 SSL_GETPID(), ss->fd));
 
@@ -12414,16 +12439,24 @@ ssl3_FillInCachedSID(sslSocket *ss, sslS
     sid->expirationTime = sid->creationTime + ssl3_sid_timeout;
     sid->localCert = CERT_DupCertificate(ss->sec.localCert);
     if (ss->sec.isServer) {
         memcpy(&sid->certType, &ss->sec.serverCert->certType, sizeof(sid->certType));
     } else {
         sid->certType.authType = ssl_auth_null;
     }
 
+    if (ss->ssl3.nextProtoState != SSL_NEXT_PROTO_NO_SUPPORT &&
+        ss->ssl3.nextProto.data) {
+        if (SECITEM_CopyItem(
+                NULL, &sid->u.ssl3.alpnSelection, &ss->ssl3.nextProto) != SECSuccess) {
+            return SECFailure; /* error already set. */
+        }
+    }
+
     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;
         memcpy(sid->u.ssl3.keys.wrapped_master_secret,
                ss->ssl3.crSpec->msItem.data, ss->ssl3.crSpec->msItem.len);
@@ -12538,20 +12571,23 @@ ssl3_HandleHandshakeMessage(sslSocket *s
                 hashesPtr = &hashes;
             } else {
                 computeHashes = PR_TRUE;
             }
         }
     } else {
         if (type == certificate_verify) {
             computeHashes =
-                TLS13_IN_HS_STATE(ss, wait_cert_verify);
+                TLS13_IN_HS_STATE(ss, wait_cert_verify,
+                                  wait_0rtt_trial_decrypt);
         } else if (type == finished) {
             computeHashes =
-                TLS13_IN_HS_STATE(ss, wait_cert_request, wait_finished);
+                TLS13_IN_HS_STATE(ss, wait_cert_request, wait_finished,
+                                  wait_0rtt_finished,
+                                  wait_0rtt_trial_decrypt);
         }
     }
 
     ssl_GetSpecReadLock(ss); /************************************/
     if (computeHashes) {
         SSL3Sender sender = (SSL3Sender)0;
         ssl3CipherSpec *rSpec = ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 ? ss->ssl3.crSpec
                                                                            : ss->ssl3.prSpec;
@@ -13395,27 +13431,27 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Cip
         rv = tls13_UnprotectRecord(ss, cText, plaintext, &alert);
     }
 
     if (rv != SECSuccess) {
         ssl_ReleaseSpecReadLock(ss); /***************************/
 
         SSL_DBG(("%d: SSL3[%d]: decryption failed", SSL_GETPID(), ss->fd));
 
-        if (!IS_DTLS(ss)) {
+        if (IS_DTLS(ss) || TLS13_IN_HS_STATE(ss, wait_0rtt_trial_decrypt)) {
+            /* Silently drop the packet */
+            databuf->len = 0; /* Needed to ensure data not left around */
+            return SECSuccess;
+        } else {
             int errCode = PORT_GetError();
             SSL3_SendAlert(ss, alert_fatal, alert);
             /* Reset the error code in case SSL3_SendAlert called
              * PORT_SetError(). */
             PORT_SetError(errCode);
             return SECFailure;
-        } else {
-            /* Silently drop the packet */
-            databuf->len = 0; /* Needed to ensure data not left around */
-            return SECSuccess;
         }
     }
 
     /* SECSuccess */
     if (!IS_DTLS(ss)) {
         ssl3_BumpSequenceNumber(&crSpec->read_seq_num);
     } else {
         dtls_RecordSetRecvd(&crSpec->recvdRecords, dtls_seq_num);
@@ -13499,16 +13535,21 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Cip
     }
 
     /* Application data records are processed by the caller of this
     ** function, not by this function.
     */
     if (rType == content_application_data) {
         if (ss->firstHsDone)
             return SECSuccess;
+        if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 &&
+            ss->sec.isServer &&
+            TLS13_IN_HS_STATE(ss, wait_0rtt_end_of_early_data)) {
+            return tls13_HandleEarlyApplicationData(ss, databuf);
+        }
         (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
         PORT_SetError(SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA);
         return SECFailure;
     }
 
 /* It's a record that must be handled by ssl itself, not the application.
     */
 process_it:
@@ -13606,16 +13647,17 @@ ssl3_InitCipherSpec(ssl3CipherSpec *spec
 **
 ** This function should perhaps acquire and release the SpecWriteLock.
 **
 **
 */
 SECStatus
 ssl3_InitState(sslSocket *ss)
 {
+    SECItem nullItem = { siBuffer, NULL, 0 };
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
     if (ss->ssl3.initialized)
         return SECSuccess; /* Function should be idempotent */
 
     ss->ssl3.policy = SSL_ALLOWED;
 
     ssl_GetSpecWriteLock(ss);
@@ -13638,22 +13680,24 @@ ssl3_InitState(sslSocket *ss)
         ss->ssl3.hs.recvMessageSeq = 0;
         ss->ssl3.hs.rtTimeoutMs = DTLS_RETRANSMIT_INITIAL_MS;
         ss->ssl3.hs.rtRetries = 0;
         ss->ssl3.hs.recvdHighWater = -1;
         PR_INIT_CLIST(&ss->ssl3.hs.lastMessageFlight);
         dtls_SetMTU(ss, 0); /* Set the MTU to the highest plateau */
     }
 
+    ss->ssl3.hs.clientHelloHash = NULL;
     PR_INIT_CLIST(&ss->ssl3.hs.remoteKeyShares);
-    ss->ssl3.hs.xSS = NULL;
-    ss->ssl3.hs.xES = NULL;
+    ss->ssl3.hs.currentSecret = NULL;
+    ss->ssl3.hs.resumptionPsk = NULL;
+    ss->ssl3.hs.resumptionContext = nullItem;
+    ss->ssl3.hs.dheSecret = NULL;
     ss->ssl3.hs.trafficSecret = NULL;
-    ss->ssl3.hs.clientFinishedSecret = NULL;
-    ss->ssl3.hs.serverFinishedSecret = NULL;
+    ss->ssl3.hs.hsTrafficSecret = NULL;
     ss->ssl3.hs.certReqContextLen = 0;
     PR_INIT_CLIST(&ss->ssl3.hs.cipherSpecs);
 
     PORT_Assert(!ss->ssl3.hs.messages.buf && !ss->ssl3.hs.messages.space);
     ss->ssl3.hs.messages.buf = NULL;
     ss->ssl3.hs.messages.space = 0;
 
     ss->ssl3.hs.receivedNewSessionTicket = PR_FALSE;
@@ -13974,46 +14018,60 @@ ssl3_DestroySSL3Info(sslSocket *ss)
     if (ss->ssl3.hs.messages.buf) {
         sslBuffer_Clear(&ss->ssl3.hs.messages);
     }
 
     /* free the SSL3Buffer (msg_body) */
     PORT_Free(ss->ssl3.hs.msg_body.buf);
 
     SECITEM_FreeItem(&ss->ssl3.hs.newSessionTicket.ticket, PR_FALSE);
+    SECITEM_FreeItem(&ss->ssl3.hs.srvVirtName, PR_FALSE);
 
     /* free up the CipherSpecs */
     ssl3_DestroyCipherSpec(&ss->ssl3.specs[0], PR_TRUE /*freeSrvName*/);
     ssl3_DestroyCipherSpec(&ss->ssl3.specs[1], PR_TRUE /*freeSrvName*/);
 
     /* Destroy the DTLS data */
     if (IS_DTLS(ss)) {
         dtls_FreeHandshakeMessages(&ss->ssl3.hs.lastMessageFlight);
         if (ss->ssl3.hs.recvdFragments.buf) {
             PORT_Free(ss->ssl3.hs.recvdFragments.buf);
         }
     }
 
     /* Destroy TLS 1.3 handshake shares */
     tls13_DestroyKeyShares(&ss->ssl3.hs.remoteKeyShares);
 
+    /* Destroy the stored hash. */
+    if (ss->ssl3.hs.clientHelloHash) {
+        PK11_DestroyContext(ss->ssl3.hs.clientHelloHash, PR_TRUE);
+    }
+
     /* Destroy TLS 1.3 cipher specs */
     tls13_DestroyCipherSpecs(&ss->ssl3.hs.cipherSpecs);
 
     /* Destroy TLS 1.3 keys */
-    if (ss->ssl3.hs.xSS)
-        PK11_FreeSymKey(ss->ssl3.hs.xSS);
-    if (ss->ssl3.hs.xES)
-        PK11_FreeSymKey(ss->ssl3.hs.xES);
+    if (ss->ssl3.hs.currentSecret)
+        PK11_FreeSymKey(ss->ssl3.hs.currentSecret);
+    if (ss->ssl3.hs.resumptionPsk)
+        PK11_FreeSymKey(ss->ssl3.hs.resumptionPsk);
+    if (ss->ssl3.hs.dheSecret)
+        PK11_FreeSymKey(ss->ssl3.hs.dheSecret);
+    if (ss->ssl3.hs.resumptionContext.data)
+        SECITEM_FreeItem(&ss->ssl3.hs.resumptionContext, PR_FALSE);
+    if (ss->ssl3.hs.earlyTrafficSecret)
+        PK11_FreeSymKey(ss->ssl3.hs.earlyTrafficSecret);
+    if (ss->ssl3.hs.hsTrafficSecret)
+        PK11_FreeSymKey(ss->ssl3.hs.hsTrafficSecret);
     if (ss->ssl3.hs.trafficSecret)
         PK11_FreeSymKey(ss->ssl3.hs.trafficSecret);
-    if (ss->ssl3.hs.clientFinishedSecret)
-        PK11_FreeSymKey(ss->ssl3.hs.clientFinishedSecret);
-    if (ss->ssl3.hs.serverFinishedSecret)
-        PK11_FreeSymKey(ss->ssl3.hs.serverFinishedSecret);
+
+    ss->ssl3.hs.doing0Rtt = PR_FALSE;
+    /* Destroy TLS 1.3 buffered early data. */
+    tls13_DestroyEarlyData(&ss->ssl3.hs.bufferedEarlyData);
 
     ss->ssl3.initialized = PR_FALSE;
 
     SECITEM_FreeItem(&ss->ssl3.nextProto, PR_FALSE);
 }
 
 #define MAP_NULL(x) (((x) != 0) ? (x) : SEC_OID_NULL_CIPHER)
 
--- a/security/nss/lib/ssl/ssl3ecc.c
+++ b/security/nss/lib/ssl/ssl3ecc.c
@@ -57,29 +57,39 @@ static ECDHEKeyPair gECDHEKeyPairs[29];
 SECStatus
 ssl_NamedGroup2ECParams(PLArenaPool *arena, const namedGroupDef *ecGroup,
                         SECKEYECParams *params)
 {
     SECOidData *oidData = NULL;
     PRUint32 policyFlags = 0;
     SECStatus rv;
 
+    if (!params) {
+        PORT_Assert(0);
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
     if (!ecGroup || ecGroup->type != group_type_ec ||
         (oidData = SECOID_FindOIDByTag(ecGroup->oidTag)) == NULL) {
         PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
         return SECFailure;
     }
 
     rv = NSS_GetAlgorithmPolicy(ecGroup->oidTag, &policyFlags);
     if (rv == SECSuccess && !(policyFlags & NSS_USE_ALG_IN_SSL_KX)) {
         PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
         return SECFailure;
     }
 
-    SECITEM_AllocItem(arena, params, (2 + oidData->oid.len));
+    if (SECITEM_AllocItem(arena, params, (2 + oidData->oid.len)) == NULL) {
+        PORT_SetError(SEC_ERROR_NO_MEMORY);
+        return SECFailure;
+    }
+
     /*
      * params->data needs to contain the ASN encoding of an object ID (OID)
      * representing the named curve. The actual OID is in
      * oidData->oid.data so we simply prepend 0x06 and OID length
      */
     params->data[0] = SEC_ASN1_OBJECT_ID;
     params->data[1] = oidData->oid.len;
     memcpy(params->data + 2, oidData->oid.data, oidData->oid.len);
@@ -274,30 +284,30 @@ loser:
 
 /* This function returns the size of the key_exchange field in
  * the KeyShareEntry structure, i.e.:
  *     opaque point <1..2^8-1>; */
 unsigned int
 tls13_SizeOfECDHEKeyShareKEX(const SECKEYPublicKey *pubKey)
 {
     PORT_Assert(pubKey->keyType == ecKey);
-    return 1 + pubKey->u.ec.publicValue.len;
+    return pubKey->u.ec.publicValue.len;
 }
 
 /* This function encodes the key_exchange field in
  * the KeyShareEntry structure. */
 SECStatus
 tls13_EncodeECDHEKeyShareKEX(sslSocket *ss, const SECKEYPublicKey *pubKey)
 {
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
     PORT_Assert(pubKey->keyType == ecKey);
 
-    return ssl3_AppendHandshakeVariable(ss, pubKey->u.ec.publicValue.data,
-                                        pubKey->u.ec.publicValue.len, 1);
+    return ssl3_AppendHandshake(ss, pubKey->u.ec.publicValue.data,
+                                pubKey->u.ec.publicValue.len);
 }
 
 /*
 ** Called from ssl3_HandleClientKeyExchange()
 */
 SECStatus
 ssl3_HandleECDHClientKeyExchange(sslSocket *ss, SSL3Opaque *b,
                                  PRUint32 length,
@@ -376,42 +386,40 @@ tls13_ImportECDHKeyShare(sslSocket *ss, 
                          const namedGroupDef *ecGroup)
 {
     SECStatus rv;
     SECItem ecPoint = { siBuffer, NULL, 0 };
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
-    rv = ssl3_ConsumeHandshakeVariable(ss, &ecPoint, 1, &b, &length);
-    if (rv != SECSuccess) {
-        PORT_SetError(SSL_ERROR_RX_MALFORMED_ECDHE_KEY_SHARE);
-        return SECFailure;
-    }
-    if (length || !ecPoint.len) {
+    if (!length) {
         PORT_SetError(SSL_ERROR_RX_MALFORMED_ECDHE_KEY_SHARE);
         return SECFailure;
     }
 
     /* Fail if the ec point uses compressed representation */
-    if (ecPoint.data[0] != EC_POINT_FORM_UNCOMPRESSED) {
+    if (b[0] != EC_POINT_FORM_UNCOMPRESSED) {
         PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM);
         return SECFailure;
     }
 
     peerKey->keyType = ecKey;
     /* Set up the encoded params */
     rv = ssl_NamedGroup2ECParams(peerKey->arena, ecGroup,
                                  &peerKey->u.ec.DEREncodedParams);
     if (rv != SECSuccess) {
         ssl_MapLowLevelError(SSL_ERROR_RX_MALFORMED_ECDHE_KEY_SHARE);
         return SECFailure;
     }
 
     /* copy publicValue in peerKey */
+    ecPoint.data = b;
+    ecPoint.len = length;
+
     rv = SECITEM_CopyItem(peerKey->arena, &peerKey->u.ec.publicValue, &ecPoint);
     if (rv != SECSuccess) {
         return SECFailure;
     }
 
     return SECSuccess;
 }
 
@@ -791,19 +799,16 @@ ssl3_SendECDHServerKeyExchange(
         keyPair = (sslEphemeralKeyPair *)PR_NEXT_LINK(&ss->ephemeralKeyPairs);
     } else {
         rv = ssl_CreateECDHEphemeralKeyPair(ecGroup, &keyPair);
         if (rv != SECSuccess) {
             goto loser;
         }
         PR_APPEND_LINK(&keyPair->link, &ss->ephemeralKeyPairs);
     }
-    if (rv != SECSuccess) {
-        goto loser;
-    }
 
     PORT_Assert(keyPair);
     if (!keyPair) {
         PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
         return SECFailure;
     }
 
     ec_params.len = sizeof(paramBuf);
--- a/security/nss/lib/ssl/ssl3ext.c
+++ b/security/nss/lib/ssl/ssl3ext.c
@@ -119,16 +119,23 @@ static SECStatus tls13_ServerHandleKeySh
 static PRInt32 tls13_ClientSendPreSharedKeyXtn(sslSocket *ss, PRBool append,
                                                PRUint32 maxBytes);
 static SECStatus tls13_ServerHandlePreSharedKeyXtn(sslSocket *ss,
                                                    PRUint16 ex_type,
                                                    SECItem *data);
 static SECStatus tls13_ClientHandlePreSharedKeyXtn(sslSocket *ss,
                                                    PRUint16 ex_type,
                                                    SECItem *data);
+static PRInt32 tls13_ClientSendEarlyDataXtn(sslSocket *ss,
+                                            PRBool append,
+                                            PRUint32 maxBytes);
+static SECStatus tls13_ServerHandleEarlyDataXtn(sslSocket *ss, PRUint16 ex_type,
+                                                SECItem *data);
+static SECStatus tls13_ClientHandleEarlyDataXtn(sslSocket *ss, PRUint16 ex_type,
+                                                SECItem *data);
 
 /*
  * Write bytes.  Using this function means the SECItem structure
  * cannot be freed.  The caller is expected to call this function
  * on a shallow copy of the structure.
  */
 static SECStatus
 ssl3_AppendToItem(SECItem *item, const unsigned char *buf, PRUint32 bytes)
@@ -184,22 +191,21 @@ ssl3_SessionTicketShutdown(void *appData
     return SECSuccess;
 }
 
 static PRStatus
 ssl3_GenerateSessionTicketKeysPKCS11(void *data)
 {
     SECStatus rv;
     sslSocket *ss = (sslSocket *)data;
-    sslServerCertType certType;
+    sslServerCertType certType = { ssl_auth_rsa_decrypt, NULL };
     const sslServerCert *sc;
     SECKEYPrivateKey *svrPrivKey;
     SECKEYPublicKey *svrPubKey;
 
-    certType.authType = ssl_auth_rsa_decrypt;
     sc = ssl_FindServerCert(ss, &certType);
     if (!sc || !sc->serverKeyPair) {
         SSL_DBG(("%d: SSL[%d]: No ssl_auth_rsa_decrypt cert and key pair",
                  SSL_GETPID(), ss->fd));
         goto loser;
     }
     svrPrivKey = sc->serverKeyPair->privKey;
     svrPubKey = sc->serverKeyPair->pubKey;
@@ -298,16 +304,17 @@ static const ssl3HelloExtensionHandler c
     { ssl_use_srtp_xtn, &ssl3_ServerHandleUseSRTPXtn },
     { ssl_cert_status_xtn, &ssl3_ServerHandleStatusRequestXtn },
     { ssl_signature_algorithms_xtn, &ssl3_ServerHandleSigAlgsXtn },
     { ssl_tls13_draft_version_xtn, &ssl3_ServerHandleDraftVersionXtn },
     { ssl_extended_master_secret_xtn, &ssl3_HandleExtendedMasterSecretXtn },
     { ssl_signed_cert_timestamp_xtn, &ssl3_ServerHandleSignedCertTimestampXtn },
     { ssl_tls13_key_share_xtn, &tls13_ServerHandleKeyShareXtn },
     { ssl_tls13_pre_shared_key_xtn, &tls13_ServerHandlePreSharedKeyXtn },
+    { ssl_tls13_early_data_xtn, &tls13_ServerHandleEarlyDataXtn },
     { -1, NULL }
 };
 
 /* These two tables are used by the client, to handle server hello
  * extensions. */
 static const ssl3HelloExtensionHandler serverHelloHandlersTLS[] = {
     { ssl_server_name_xtn, &ssl3_HandleServerNameXtn },
     /* TODO: add a handler for ssl_ec_point_formats_xtn */
@@ -316,16 +323,17 @@ static const ssl3HelloExtensionHandler s
     { ssl_next_proto_nego_xtn, &ssl3_ClientHandleNextProtoNegoXtn },
     { ssl_app_layer_protocol_xtn, &ssl3_ClientHandleAppProtoXtn },
     { ssl_use_srtp_xtn, &ssl3_ClientHandleUseSRTPXtn },
     { ssl_cert_status_xtn, &ssl3_ClientHandleStatusRequestXtn },
     { ssl_extended_master_secret_xtn, &ssl3_HandleExtendedMasterSecretXtn },
     { ssl_signed_cert_timestamp_xtn, &ssl3_ClientHandleSignedCertTimestampXtn },
     { ssl_tls13_key_share_xtn, &tls13_ClientHandleKeyShareXtn },
     { ssl_tls13_pre_shared_key_xtn, &tls13_ClientHandlePreSharedKeyXtn },
+    { ssl_tls13_early_data_xtn, &tls13_ClientHandleEarlyDataXtn },
     { -1, NULL }
 };
 
 static const ssl3HelloExtensionHandler serverHelloHandlersSSL3[] = {
     { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn },
     { -1, NULL }
 };
 
@@ -350,16 +358,17 @@ static const ssl3HelloExtensionSender cl
       { ssl_next_proto_nego_xtn, &ssl3_ClientSendNextProtoNegoXtn },
       { ssl_app_layer_protocol_xtn, &ssl3_ClientSendAppProtoXtn },
       { ssl_use_srtp_xtn, &ssl3_ClientSendUseSRTPXtn },
       { ssl_cert_status_xtn, &ssl3_ClientSendStatusRequestXtn },
       { ssl_tls13_draft_version_xtn, &ssl3_ClientSendDraftVersionXtn },
       { ssl_signed_cert_timestamp_xtn, &ssl3_ClientSendSignedCertTimestampXtn },
       { ssl_tls13_key_share_xtn, &tls13_ClientSendKeyShareXtn },
       { ssl_tls13_pre_shared_key_xtn, &tls13_ClientSendPreSharedKeyXtn },
+      { ssl_tls13_early_data_xtn, &tls13_ClientSendEarlyDataXtn },
       /* Some servers (e.g. WebSphere Application Server 7.0 and Tomcat) will
        * time out or terminate the connection if the last extension in the
        * client hello is empty. They are not intolerant of TLS 1.2, so list
        * signature_algorithms at the end. See bug 1243641. */
       { ssl_signature_algorithms_xtn, &ssl3_ClientSendSigAlgsXtn }
       /* any extra entries will appear as { 0, NULL }    */
     };
 
@@ -1125,34 +1134,35 @@ ssl3_ClientSendStatusRequestXtn(sslSocke
 
         xtnData = &ss->xtnData;
         xtnData->advertised[xtnData->numAdvertised++] = ssl_cert_status_xtn;
     }
     return extension_length;
 }
 
 /*
- * NewSessionTicket
- * Called from ssl3_HandleFinished
+ * Called from ssl3_SendNewSessionTicket, tls13_SendNewSessionTicket
  */
 SECStatus
-ssl3_SendNewSessionTicket(sslSocket *ss)
+ssl3_EncodeSessionTicket(sslSocket *ss, SECItem *ticket_data)
 {
     PRUint32 i;
     SECStatus rv;
     NewSessionTicket ticket;
     SECItem plaintext;
     SECItem plaintext_item = { 0, NULL, 0 };
     SECItem ciphertext = { 0, NULL, 0 };
     PRUint32 ciphertext_length;
+    SECItem ticket_buf = { 0, NULL, 0 };
+    SECItem ticket_tmp = { 0, NULL, 0 };
     PRBool ms_is_wrapped;
     unsigned char wrapped_ms[SSL3_MASTER_SECRET_LENGTH];
     SECItem ms_item = { 0, NULL, 0 };
     PRUint32 padding_length;
-    PRUint32 message_length;
+    PRUint32 ticket_length;
     PRUint32 cert_length = 0;
     PRUint8 length_buf[4];
     PRUint32 now;
     PK11SymKey *aes_key_pkcs11 = NULL;
     PK11SymKey *mac_key_pkcs11 = NULL;
 #ifndef NO_PKCS11_BYPASS
     const unsigned char *aes_key = NULL;
     const unsigned char *mac_key = NULL;
@@ -1173,23 +1183,28 @@ ssl3_SendNewSessionTicket(sslSocket *ss)
     unsigned char iv[AES_BLOCK_SIZE];
     SECItem ivItem;
     SECItem *srvName = NULL;
     PRUint32 srvNameLen = 0;
     CK_MECHANISM_TYPE msWrapMech = 0; /* dummy default value,
                                           * must be >= 0 */
     ssl3CipherSpec *spec = ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 ? ss->ssl3.cwSpec : ss->ssl3.pwSpec;
     const sslServerCertType *certType;
+    SECItem alpnSelection = { siBuffer, NULL, 0 };
 
     SSL_TRC(3, ("%d: SSL3[%d]: send session_ticket handshake",
                 SSL_GETPID(), ss->fd));
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
+    ticket.flags = 0;
+    if ((ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) && ss->opt.enable0RttData) {
+        ticket.flags |= ticket_allow_early_data;
+    }
     ticket.ticket_lifetime_hint = TLS_EX_SESS_TICKET_LIFETIME_HINT;
     if (ss->opt.requestCertificate && ss->sec.ci.sid->peerCert) {
         cert_length = 3 + ss->sec.ci.sid->peerCert->derCert.len;
     }
 
     /* Get IV and encryption keys */
     ivItem.data = iv;
     ivItem.len = sizeof(iv);
@@ -1237,47 +1252,43 @@ ssl3_SendNewSessionTicket(sslSocket *ss)
         ms_is_wrapped = PR_TRUE;
     }
     /* Prep to send negotiated name */
     srvName = &ss->sec.ci.sid->u.ssl3.srvName;
     if (srvName->data && srvName->len) {
         srvNameLen = 2 + srvName->len; /* len bytes + name len */
     }
 
+    if (ss->ssl3.nextProtoState != SSL_NEXT_PROTO_NO_SUPPORT &&
+        ss->ssl3.nextProto.data) {
+        alpnSelection = ss->ssl3.nextProto;
+    }
+
     ciphertext_length =
-        sizeof(PRUint16)              /* ticket_version */
-        + sizeof(SSL3ProtocolVersion) /* ssl_version */
-        + sizeof(ssl3CipherSuite)     /* ciphersuite */
-        + 1                           /* compression */
-        + 10                          /* cipher spec parameters */
-        + 1                           /* certType arguments */
-        + 1                           /* SessionTicket.ms_is_wrapped */
-        + 4                           /* msWrapMech */
-        + 2                           /* master_secret.length */
-        + ms_item.len                 /* master_secret */
-        + 1                           /* client_auth_type */
-        + cert_length                 /* cert */
-        + 1                           /* server name type */
-        + srvNameLen                  /* name len + length field */
-        + 1                           /* extendedMasterSecretUsed */
-        + sizeof(ticket.ticket_lifetime_hint);
+        sizeof(PRUint16)                                                                      /* ticket_version */
+        + sizeof(SSL3ProtocolVersion)                                                         /* ssl_version */
+        + sizeof(ssl3CipherSuite)                                                             /* ciphersuite */
+        + 1                                                                                   /* compression */
+        + 10                                                                                  /* cipher spec parameters */
+        + 1                                                                                   /* certType arguments */
+        + 1                                                                                   /* SessionTicket.ms_is_wrapped */
+        + 4                                                                                   /* msWrapMech */
+        + 2                                                                                   /* master_secret.length */
+        + ms_item.len                                                                         /* master_secret */
+        + 1                                                                                   /* client_auth_type */
+        + cert_length                                                                         /* cert */
+        + 1                                                                                   /* server name type */
+        + srvNameLen                                                                          /* name len + length field */
+        + 1                                                                                   /* extendedMasterSecretUsed */
+        + sizeof(ticket.ticket_lifetime_hint) + sizeof(ticket.flags) + 1 + alpnSelection.len; /* npn value + length field. */
     padding_length = AES_BLOCK_SIZE -
                      (ciphertext_length %
                       AES_BLOCK_SIZE);
     ciphertext_length += padding_length;
 
-    message_length =
-        sizeof(ticket.ticket_lifetime_hint) /* ticket_lifetime_hint */
-        + 2                                 /* length field for NewSessionTicket.ticket */
-        + SESS_TICKET_KEY_NAME_LEN          /* key_name */
-        + AES_BLOCK_SIZE                    /* iv */
-        + 2                                 /* length field for NewSessionTicket.ticket.encrypted_state */
-        + ciphertext_length                 /* encrypted_state */
-        + TLS_EX_SESS_TICKET_MAC_LENGTH;    /* mac */
-
     if (SECITEM_AllocItem(NULL, &plaintext_item, ciphertext_length) == NULL)
         goto loser;
 
     plaintext = plaintext_item;
 
     /* ticket_version */
     rv = ssl3_AppendNumberToItem(&plaintext, TLS_EX_SESS_TICKET_VERSION,
                                  sizeof(PRUint16));
@@ -1397,16 +1408,33 @@ ssl3_SendNewSessionTicket(sslSocket *ss)
     }
 
     /* extendedMasterSecretUsed */
     rv = ssl3_AppendNumberToItem(
         &plaintext, ss->sec.ci.sid->u.ssl3.keys.extendedMasterSecretUsed, 1);
     if (rv != SECSuccess)
         goto loser;
 
+    /* Flags */
+    rv = ssl3_AppendNumberToItem(&plaintext, ticket.flags,
+                                 sizeof(ticket.flags));
+    if (rv != SECSuccess)
+        goto loser;
+
+    /* NPN value. */
+    PORT_Assert(alpnSelection.len < 256);
+    rv = ssl3_AppendNumberToItem(&plaintext, alpnSelection.len, 1);
+    if (rv != SECSuccess)
+        goto loser;
+    if (alpnSelection.len) {
+        rv = ssl3_AppendToItem(&plaintext, alpnSelection.data, alpnSelection.len);
+        if (rv != SECSuccess)
+            goto loser;
+    }
+
     PORT_Assert(plaintext.len == padding_length);
     for (i = 0; i < padding_length; i++)
         plaintext.data[i] = (unsigned char)padding_length;
 
     if (SECITEM_AllocItem(NULL, &ciphertext, ciphertext_length) == NULL) {
         rv = SECFailure;
         goto loser;
     }
@@ -1496,55 +1524,64 @@ ssl3_SendNewSessionTicket(sslSocket *ss)
         if (rv != SECSuccess)
             goto loser;
         rv = PK11_DigestFinal(hmac_ctx_pkcs11, computed_mac,
                               &computed_mac_length, sizeof(computed_mac));
         if (rv != SECSuccess)
             goto loser;
     }
 
-    /* Serialize the handshake message. */
-    rv = ssl3_AppendHandshakeHeader(ss, new_session_ticket, message_length);
-    if (rv != SECSuccess)
+    ticket_length =
+        +SESS_TICKET_KEY_NAME_LEN        /* key_name */
+        + AES_BLOCK_SIZE                 /* iv */
+        + 2                              /* length field for NewSessionTicket.ticket.encrypted_state */
+        + ciphertext_length              /* encrypted_state */
+        + TLS_EX_SESS_TICKET_MAC_LENGTH; /* mac */
+
+    if (SECITEM_AllocItem(NULL, &ticket_buf, ticket_length) == NULL) {
+        rv = SECFailure;
         goto loser;
-
-    rv = ssl3_AppendHandshakeNumber(ss, ticket.ticket_lifetime_hint,
-                                    sizeof(ticket.ticket_lifetime_hint));
-    if (rv != SECSuccess)
-        goto loser;
-
-    rv = ssl3_AppendHandshakeNumber(ss,
-                                    message_length - sizeof(ticket.ticket_lifetime_hint) - 2,
-                                    2);
+    }
+    ticket_tmp = ticket_buf; /* Shallow copy because AppendToItem is
+                              * destructive. */
+
+    rv = ssl3_AppendToItem(&ticket_tmp, key_name, SESS_TICKET_KEY_NAME_LEN);
     if (rv != SECSuccess)
         goto loser;
 
-    rv = ssl3_AppendHandshake(ss, key_name, SESS_TICKET_KEY_NAME_LEN);
+    rv = ssl3_AppendToItem(&ticket_tmp, iv, sizeof(iv));
     if (rv != SECSuccess)
         goto loser;
 
-    rv = ssl3_AppendHandshake(ss, iv, sizeof(iv));
+    rv = ssl3_AppendNumberToItem(&ticket_tmp, ciphertext.len, 2);
     if (rv != SECSuccess)
         goto loser;
 
-    rv = ssl3_AppendHandshakeVariable(ss, ciphertext.data, ciphertext.len, 2);
+    rv = ssl3_AppendToItem(&ticket_tmp, ciphertext.data, ciphertext.len);
     if (rv != SECSuccess)
         goto loser;
 
-    rv = ssl3_AppendHandshake(ss, computed_mac, computed_mac_length);
+    rv = ssl3_AppendToItem(&ticket_tmp, computed_mac, computed_mac_length);
     if (rv != SECSuccess)
         goto loser;
 
+    /* Give ownership of memory to caller. */
+    *ticket_data = ticket_buf;
+    ticket_buf.data = NULL;
+
 loser:
     if (hmac_ctx_pkcs11)
         PK11_DestroyContext(hmac_ctx_pkcs11, PR_TRUE);
     if (plaintext_item.data)
         SECITEM_FreeItem(&plaintext_item, PR_FALSE);
     if (ciphertext.data)
         SECITEM_FreeItem(&ciphertext, PR_FALSE);
+    if (ticket_buf.data) {
+        SECITEM_FreeItem(&ticket_buf, PR_FALSE);
+    }
 
     return rv;
 }
 
 /* When a client receives a SessionTicket extension a NewSessionTicket
  * message is expected during the handshake.
  */
 SECStatus
@@ -1594,16 +1631,17 @@ ssl3_ProcessSessionTicketCommon(sslSocke
     CK_MECHANISM_TYPE cipherMech = CKM_AES_CBC;
     unsigned char *padding;
     PRUint32 padding_length;
     unsigned char *buffer;
     unsigned int buffer_len;
     PRInt32 temp;
     SECItem cert_item;
     PRInt8 nameType = TLS_STE_NO_SERVER_NAME;
+    SECItem alpn_item;
 
     /* Turn off stateless session resumption if the client sends a
      * SessionTicket extension, even if the extension turns out to be
      * malformed (ss->sec.ci.sid is non-NULL when doing session
      * renegotiation.)
      */
     if (ss->sec.ci.sid != NULL) {
         if (ss->sec.uncache)
@@ -1920,16 +1958,34 @@ ssl3_ProcessSessionTicketCommon(sslSocke
 
     /* Read extendedMasterSecretUsed */
     temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
     if (temp < 0)
         goto no_ticket;
     PORT_Assert(temp == PR_TRUE || temp == PR_FALSE);
     parsed_session_ticket->extendedMasterSecretUsed = (PRBool)temp;
 
+    rv = ssl3_ConsumeHandshake(ss, &parsed_session_ticket->flags, 4,
+                               &buffer, &buffer_len);
+    if (rv != SECSuccess)
+        goto no_ticket;
+    parsed_session_ticket->flags = PR_ntohl(parsed_session_ticket->flags);
+
+    rv = ssl3_ConsumeHandshakeVariable(ss, &alpn_item, 1, &buffer, &buffer_len);
+    if (rv != SECSuccess)
+        goto no_ticket;
+    if (alpn_item.len != 0) {
+        rv = SECITEM_CopyItem(NULL, &parsed_session_ticket->alpnSelection,
+                              &alpn_item);
+        if (rv != SECSuccess)
+            goto no_ticket;
+        if (alpn_item.len >= 256)
+            goto no_ticket;
+    }
+
     /* Done parsing.  Check that all bytes have been consumed. */
     if (buffer_len != padding_length)
         goto no_ticket;
 
     /* Use the ticket if it has not expired, otherwise free the allocated
      * memory since the ticket is of no use.
      */
     if (parsed_session_ticket->timestamp != 0 &&
@@ -1952,16 +2008,17 @@ ssl3_ProcessSessionTicketCommon(sslSocke
         sid->keaType = parsed_session_ticket->keaType;
         sid->keaKeyBits = parsed_session_ticket->keaKeyBits;
         memcpy(&sid->certType, &parsed_session_ticket->certType,
                sizeof(sslServerCertType));
 
         if (SECITEM_CopyItem(NULL, &sid->u.ssl3.locked.sessionTicket.ticket,
                              &extension_data) != SECSuccess)
             goto no_ticket;
+        sid->u.ssl3.locked.sessionTicket.flags = parsed_session_ticket->flags;
 
 /* Copy master secret. */
 #ifndef NO_PKCS11_BYPASS
         if (ss->opt.bypassPKCS11 &&
             parsed_session_ticket->ms_is_wrapped)
             goto no_ticket;
 #endif
         if (parsed_session_ticket->ms_length >
@@ -1988,16 +2045,21 @@ ssl3_ProcessSessionTicketCommon(sslSocke
             if (sid->peerCert == NULL) {
                 rv = SECFailure;
                 goto loser;
             }
         }
         if (parsed_session_ticket->srvName.data != NULL) {
             sid->u.ssl3.srvName = parsed_session_ticket->srvName;
         }
+        if (parsed_session_ticket->alpnSelection.data != NULL) {
+            sid->u.ssl3.alpnSelection = parsed_session_ticket->alpnSelection;
+            /* So we don't free below. */
+            parsed_session_ticket->alpnSelection.data = NULL;
+        }
         ss->statelessResume = PR_TRUE;
         ss->sec.ci.sid = sid;
     }
 
     if (0) {
     no_ticket:
         SSL_DBG(("%d: SSL[%d]: Session ticket parsing failed.",
                  SSL_GETPID(), ss->fd));
@@ -2018,16 +2080,19 @@ loser:
         SECITEM_FreeItem(decrypted_state, PR_TRUE);
         decrypted_state = NULL;
     }
 
     if (parsed_session_ticket != NULL) {
         if (parsed_session_ticket->peer_cert.data) {
             SECITEM_FreeItem(&parsed_session_ticket->peer_cert, PR_FALSE);
         }
+        if (parsed_session_ticket->alpnSelection.data) {
+            SECITEM_FreeItem(&parsed_session_ticket->alpnSelection, PR_FALSE);
+        }
         PORT_ZFree(parsed_session_ticket, sizeof(SessionTicket));
     }
 
     return rv;
 }
 
 SECStatus
 ssl3_ServerHandleSessionTicketXtn(sslSocket *ss, PRUint16 ex_type,
@@ -3073,19 +3138,19 @@ ssl3_ServerHandleSignedCertTimestampXtn(
  *     opaque point <1..2^8-1>;
  */
 static PRUint32
 tls13_SizeOfKeyShareEntry(const SECKEYPublicKey *pubKey)
 {
     /* Size = NamedGroup(2) + length(2) + opaque<?> share */
     switch (pubKey->keyType) {
         case ecKey:
-            return 2 + 2 + tls13_SizeOfECDHEKeyShareKEX(pubKey);
+            return 2 + 2 + pubKey->u.ec.publicValue.len;
         case dhKey:
-            return 2 + 2 + 2 + pubKey->u.dh.prime.len;
+            return 2 + 2 + pubKey->u.dh.prime.len;
         default:
             PORT_Assert(0);
     }
     return 0;
 }
 
 static PRUint32
 tls13_SizeOfClientKeyShareExtension(sslSocket *ss)
@@ -3116,17 +3181,17 @@ tls13_EncodeKeyShareEntry(sslSocket *ss,
     if (rv != SECSuccess)
         return rv;
 
     switch (pubKey->keyType) {
         case ecKey:
             rv = tls13_EncodeECDHEKeyShareKEX(ss, pubKey);
             break;
         case dhKey:
-            rv = ssl_AppendPaddedDHKeyShare(ss, pubKey);
+            rv = ssl_AppendPaddedDHKeyShare(ss, pubKey, PR_FALSE);
             break;
         default:
             PORT_Assert(0);
             PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
             break;
     }
 
     return rv;
@@ -3355,17 +3420,17 @@ loser:
  *   opaque psk_identity<0..2^16-1>;
  *
  *   struct {
  *        select (Role) {
  *            case client:
  *                psk_identity identities<2..2^16-1>;
  *
  *            case server:
- *                psk_identity identity;
+ *                 uint16 selected_identity;
  *        }
  *   } PreSharedKeyExtension;
  *
  * Presently the only way to get a PSK is by resumption, so this is
  * really a ticket label and there wll be at most one.
  */
 static PRInt32
 tls13_ClientSendPreSharedKeyXtn(sslSocket *ss,
@@ -3456,16 +3521,19 @@ static SECStatus
 tls13_ServerHandlePreSharedKeyXtn(sslSocket *ss, PRUint16 ex_type,
                                   SECItem *data)
 {
     SECItem label;
     PRInt32 len;
     PRBool first = PR_TRUE;
     SECStatus rv;
 
+    SSL_TRC(3, ("%d: SSL3[%d]: handle pre_shared_key extension",
+                SSL_GETPID(), ss->fd));
+
     /* If we are doing < TLS 1.3, then ignore this. */
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
         return SECSuccess;
     }
 
     len = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
     if (len < 0)
         return SECFailure;
@@ -3504,70 +3572,215 @@ tls13_ServerHandlePreSharedKeyXtn(sslSoc
     return SECSuccess;
 }
 
 PRInt32
 tls13_ServerSendPreSharedKeyXtn(sslSocket *ss,
                                 PRBool append,
                                 PRUint32 maxBytes)
 {
-    SECItem *session_ticket =
-        &ss->sec.ci.sid->u.ssl3.locked.sessionTicket.ticket;
     PRInt32 extension_length =
-        2 + 2 + 2 + session_ticket->len; /* type + len +
-                                                inner_len + data */
+        2 + 2 + 2; /* type + len + index */
     SECStatus rv;
 
-    PORT_Assert(session_ticket->len);
+    if (maxBytes < (PRUint32)extension_length) {
+        PORT_Assert(0);
+        return 0;
+    }
 
     if (append) {
         rv = ssl3_AppendHandshakeNumber(ss, ssl_tls13_pre_shared_key_xtn, 2);
         if (rv != SECSuccess)
             return -1;
 
-        rv = ssl3_AppendHandshakeNumber(ss, session_ticket->len + 2, 2);
+        rv = ssl3_AppendHandshakeNumber(ss, 2, 2);
         if (rv != SECSuccess)
             return -1;
 
-        rv = ssl3_AppendHandshakeVariable(ss, session_ticket->data,
-                                          session_ticket->len, 2);
+        /* We only process the first session ticket the client sends,
+         * so the index is always 0. */
+        rv = ssl3_AppendHandshakeNumber(ss, 0, 2);
         if (rv != SECSuccess)
             return -1;
     }
 
     return extension_length;
 }
 
 /* Handle a TLS 1.3 PreSharedKey Extension. We only accept PSKs
  * that contain session tickets. */
 static SECStatus
 tls13_ClientHandlePreSharedKeyXtn(sslSocket *ss, PRUint16 ex_type,
                                   SECItem *data)
 {
-    PRInt32 len;
+    PRInt32 index;
+
+    SSL_TRC(3, ("%d: SSL3[%d]: handle pre_shared_key extension",
+                SSL_GETPID(), ss->fd));
 
     /* If we are doing < TLS 1.3, then ignore this. */
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
         return SECSuccess;
     }
 
-    len = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
-    if (len < 0)
+    index = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
+    if (index < 0)
         return SECFailure;
 
-    if (len != data->len) {
+    /* This should be the end of the extension. */
+    if (data->len) {
         PORT_SetError(SSL_ERROR_MALFORMED_PRE_SHARED_KEY);
         return SECFailure;
     }
 
-    /* Just check for equality since we only sent one PSK label. */
-    if (SECITEM_CompareItem(
-            &ss->sec.ci.sid->u.ssl3.locked.sessionTicket.ticket,
-            data) != SECEqual) {
+    /* We only sent one PSK label so index must be equal to 0 */
+    if (index) {
         PORT_SetError(SSL_ERROR_MALFORMED_PRE_SHARED_KEY);
         return SECFailure;
     }
 
     /* Keep track of negotiated extensions. */
     ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
 
     return SECSuccess;
 }
+
+/*
+ *  struct {
+ *       select (Role) {
+ *           case client:
+ *               opaque context<0..255>;
+ *
+ *           case server:
+ *              struct {};
+ *       }
+ *   } EarlyDataIndication;
+ */
+static PRInt32
+tls13_ClientSendEarlyDataXtn(sslSocket *ss,
+                             PRBool append,
+                             PRUint32 maxBytes)
+{
+    PRInt32 extension_length;
+    SECStatus rv;
+    sslSessionID *sid = ss->sec.ci.sid;
+
+    if (!tls13_ClientAllow0Rtt(ss, sid))
+        return 0;
+
+    /* type + length + empty context. */
+    extension_length = 2 + 2 + 1;
+
+    if (maxBytes < (PRUint32)extension_length) {
+        PORT_Assert(0);
+        return 0;
+    }
+
+    if (append) {
+        rv = ssl3_AppendHandshakeNumber(ss, ssl_tls13_early_data_xtn, 2);
+        if (rv != SECSuccess)
+            return -1;
+
+        rv = ssl3_AppendHandshakeNumber(ss, extension_length - 4, 2);
+        if (rv != SECSuccess)
+            return -1;
+
+        /* Context */
+        rv = ssl3_AppendHandshakeNumber(ss, 0, 1);
+        if (rv != SECSuccess)
+            return -1;
+    }
+
+    ss->ssl3.hs.doing0Rtt = PR_TRUE;
+    ss->xtnData.advertised[ss->xtnData.numAdvertised++] =
+        ssl_tls13_early_data_xtn;
+
+    return extension_length;
+}
+
+static SECStatus
+tls13_ServerHandleEarlyDataXtn(sslSocket *ss, PRUint16 ex_type,
+                               SECItem *data)
+{
+    SECItem tmp;
+    SECStatus rv;
+
+    SSL_TRC(3, ("%d: TLS13[%d]: handle early_data extension",
+                SSL_GETPID(), ss->fd));
+
+    /* If we are doing < TLS 1.3, then ignore this. */
+    if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+        return SECSuccess;
+    }
+
+    /* Context: ignore. */
+    rv = ssl3_ConsumeHandshakeVariable(ss, &tmp, 1, &data->data, &data->len);
+    if (rv != SECSuccess)
+        return SECFailure;
+
+    if (data->len) {
+        PORT_SetError(SSL_ERROR_MALFORMED_EARLY_DATA);
+        return SECFailure;
+    }
+
+    /* Keep track of negotiated extensions.
+     * IMPORTANT: Record the presence of the extension only. This is
+     * only one of several things that the 0-RTT processing code uses
+     * in determining whether to accept 0-RTT.
+     */
+    ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
+
+    return SECSuccess;
+}
+
+/* This is only registered if we are sending it. */
+SECStatus
+tls13_ServerSendEarlyDataXtn(sslSocket *ss,
+                             PRBool append,
+                             PRUint32 maxBytes)
+{
+    SSL_TRC(3, ("%d: TLS13[%d]: send early_data extension",
+                SSL_GETPID(), ss->fd));
+
+    if (maxBytes < 4) {
+        PORT_Assert(0);
+        return 0;
+    }
+
+    if (append) {
+        SECStatus rv;
+
+        rv = ssl3_AppendHandshakeNumber(ss, ssl_tls13_early_data_xtn, 2);
+        if (rv != SECSuccess)
+            return -1;
+
+        rv = ssl3_AppendHandshakeNumber(ss, 0, 2);
+        if (rv != SECSuccess)
+            return -1;
+    }
+
+    return 4;
+}
+
+/* This will only be called if we also offered the extension. */
+static SECStatus
+tls13_ClientHandleEarlyDataXtn(sslSocket *ss, PRUint16 ex_type,
+                               SECItem *data)
+{
+    SSL_TRC(3, ("%d: TLS13[%d]: handle early_data extension",
+                SSL_GETPID(), ss->fd));
+
+    /* If we are doing < TLS 1.3, then ignore this. */
+    if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+        PORT_SetError(SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION);
+        return SECFailure;
+    }
+
+    if (data->len != 0) {
+        PORT_SetError(SSL_ERROR_MALFORMED_EARLY_DATA);
+        return SECFailure;
+    }
+
+    /* Keep track of negotiated extensions. */
+    ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
+
+    return SECSuccess;
+}
--- a/security/nss/lib/ssl/ssl3prot.h
+++ b/security/nss/lib/ssl/ssl3prot.h
@@ -12,17 +12,17 @@
 typedef PRUint8 SSL3Opaque;
 
 typedef PRUint16 SSL3ProtocolVersion;
 /* version numbers are defined in sslproto.h */
 
 /* The TLS 1.3 draft version. Used to avoid negotiating
  * between incompatible pre-standard TLS 1.3 drafts.
  * TODO(ekr@rtfm.com): Remove when TLS 1.3 is published. */
-#define TLS_1_3_DRAFT_VERSION 11
+#define TLS_1_3_DRAFT_VERSION 13
 
 typedef PRUint16 ssl3CipherSuite;
 /* The cipher suites are defined in sslproto.h */
 
 #define MAX_CERT_TYPES 10
 #define MAX_COMPRESSION_METHODS 10
 #define MAX_MAC_LENGTH 64
 #define MAX_PADDING_LENGTH 64
@@ -76,16 +76,17 @@ typedef struct {
     SSL3ChangeCipherSpecChoice choice;
 } SSL3ChangeCipherSpec;
 
 typedef enum { alert_warning = 1,
                alert_fatal = 2 } SSL3AlertLevel;
 
 typedef enum {
     close_notify = 0,
+    end_of_early_data = 1, /* TLS 1.3 */
     unexpected_message = 10,
     bad_record_mac = 20,
     decryption_failed_RESERVED = 21, /* do not send; see RFC 5246 */
     record_overflow = 22,            /* TLS only */
     decompression_failure = 30,
     handshake_failure = 40,
     no_certificate = 41, /* SSL3 only, NOT TLS */
     bad_certificate = 42,
@@ -286,20 +287,27 @@ typedef struct {
  */
 
 /* SessionTicket extension related data structures. */
 
 /* NewSessionTicket handshake message. */
 typedef struct {
     PRUint32 received_timestamp;
     PRUint32 ticket_lifetime_hint;
+    PRUint32 flags;
     SECItem ticket;
 } NewSessionTicket;
 
 typedef enum {
+    ticket_allow_early_data = 1,
+    ticket_allow_dhe_resumption = 2,
+    ticket_allow_psk_resumption = 4
+} TLS13SessionTicketFlags;
+
+typedef enum {
     CLIENT_AUTH_ANONYMOUS = 0,
     CLIENT_AUTH_CERTIFICATE = 1
 } ClientAuthenticationType;
 
 typedef struct {
     ClientAuthenticationType client_auth_type;
     union {
         SSL3Opaque *certificate_list;
--- a/security/nss/lib/ssl/sslcert.c
+++ b/security/nss/lib/ssl/sslcert.c
@@ -161,27 +161,19 @@ ssl_FindServerCert(const sslSocket *ss,
     return NULL;
 }
 
 sslServerCert *
 ssl_FindServerCertByAuthType(const sslSocket *ss, SSLAuthType authType)
 {
     sslServerCertType certType;
     certType.authType = authType;
-    switch (authType) {
-        /* Setting the named curve to NULL ensures that all EC certificates
-         * are matched when searching for this slot. */
-        case ssl_auth_ecdsa:
-        case ssl_auth_ecdh_rsa:
-        case ssl_auth_ecdh_ecdsa:
-            certType.namedCurve = NULL;
-            break;
-        default:
-            break;
-    }
+    /* Setting the named curve to NULL ensures that all EC certificates
+     * are matched when searching for this slot. */
+    certType.namedCurve = NULL;
     return ssl_FindServerCert(ss, &certType);
 }
 
 SECStatus
 ssl_OneTimeCertSetup(sslSocket *ss, const sslServerCert *sc)
 {
     /* Generate a step-down RSA key. */
     if (sc->certType.authType == ssl_auth_rsa_decrypt &&
@@ -637,27 +629,19 @@ ssl_CertSuitableForAuthType(CERTCertific
  * server cert slot of the right type. */
 static sslServerCert *
 ssl_FindOrMakeCertType(sslSocket *ss, SSLAuthType authType)
 {
     sslServerCert *sc;
     sslServerCertType certType;
 
     certType.authType = authType;
-    switch (authType) {
-        case ssl_auth_ecdsa:
-        case ssl_auth_ecdh_rsa:
-        case ssl_auth_ecdh_ecdsa:
-            /* Setting the named curve to NULL ensures that all EC certificates
-             * are matched when searching for this slot. */
-            certType.namedCurve = NULL;
-            break;
-        default:
-            break;
-    }
+    /* Setting the named curve to NULL ensures that all EC certificates
+     * are matched when searching for this slot. */
+    certType.namedCurve = NULL;
     sc = ssl_FindServerCert(ss, &certType);
     if (sc) {
         PR_REMOVE_LINK(&sc->link);
         return sc;
     }
 
     return ssl_NewServerCert(&certType);
 }
--- a/security/nss/lib/ssl/sslerr.h
+++ b/security/nss/lib/ssl/sslerr.h
@@ -226,15 +226,18 @@ typedef enum {
 
     SSL_ERROR_RX_UNEXPECTED_ENCRYPTED_EXTENSIONS = (SSL_ERROR_BASE + 142),
     SSL_ERROR_MISSING_EXTENSION_ALERT       = (SSL_ERROR_BASE + 143),
 
     SSL_ERROR_KEY_EXCHANGE_FAILURE          = (SSL_ERROR_BASE + 144),
     SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION = (SSL_ERROR_BASE + 145),
     SSL_ERROR_RX_MALFORMED_ENCRYPTED_EXTENSIONS = (SSL_ERROR_BASE + 146),
     SSL_ERROR_MALFORMED_PRE_SHARED_KEY = (SSL_ERROR_BASE + 147),
+    SSL_ERROR_MALFORMED_EARLY_DATA = (SSL_ERROR_BASE + 148),
+    SSL_ERROR_END_OF_EARLY_DATA_ALERT = (SSL_ERROR_BASE + 149),
+    SSL_ERROR_MISSING_ALPN_EXTENSION = (SSL_ERROR_BASE + 150),
     SSL_ERROR_END_OF_LIST   /* let the c compiler determine the value of this. */
 } SSLErrorCodes;
 #endif /* NO_SECURITY_ERROR_ENUM */
 
 /* clang-format on */
 
 #endif /* __SSL_ERR_H_ */
--- a/security/nss/lib/ssl/sslimpl.h
+++ b/security/nss/lib/ssl/sslimpl.h
@@ -371,16 +371,17 @@ typedef struct sslOptionsStr {
     unsigned int enableNPN : 1;
     unsigned int enableALPN : 1;
     unsigned int reuseServerECDHEKey : 1;
     unsigned int enableFallbackSCSV : 1;
     unsigned int enableServerDhe : 1;
     unsigned int enableExtendedMS : 1;
     unsigned int enableSignedCertTimestamps : 1;
     unsigned int requireDHENamedGroups : 1;
+    unsigned int enable0RttData : 1;
 } sslOptions;
 
 typedef enum { sslHandshakingUndetermined = 0,
                sslHandshakingAsClient,
                sslHandshakingAsServer
 } sslHandshakingType;
 
 #define SSL_LOCK_RANK_SPEC 255
@@ -599,23 +600,21 @@ typedef struct {
     SSL3SequenceNumber write_seq_num;
     SSL3SequenceNumber read_seq_num;
     SSL3ProtocolVersion version;
     ssl3KeyMaterial client;
     ssl3KeyMaterial server;
     SECItem msItem;
     unsigned char key_block[NUM_MIXERS * HASH_LENGTH_MAX];
     unsigned char raw_master_secret[56];
-    SECItem srvVirtName; /* for server: name that was negotiated
-                          * with a client. For client - is
-                          * always set to NULL.*/
     DTLSEpoch epoch;
     DTLSRecvdRecords recvdRecords;
 
     PRUint8 refCt;
+    const char *phase;
 } ssl3CipherSpec;
 
 typedef enum { never_cached,
                in_client_cache,
                in_server_cache,
                invalid_cache /* no longer in any cache. */
 } Cached;
 
@@ -699,16 +698,20 @@ struct sslSessionIDStr {
 
             SECItem srvName;
 
             /* Signed certificate timestamps received in a TLS extension.
             ** (used only in client).
             */
             SECItem signedCertTimestamps;
 
+            /* The NPN/ALPN value negotiated in the original connection.
+             * Used for TLS 1.3. */
+            SECItem alpnSelection;
+
             /* This lock is lazily initialized by CacheSID when a sid is first
              * cached. Before then, there is no need to lock anything because
              * the sid isn't being shared by anything.
              */
             PRRWLock *lock;
 
             /* The lock must be held while reading or writing these members
              * because they change while the sid is cached.
@@ -797,17 +800,20 @@ typedef enum {
     wait_certificate_status,
     wait_server_cert,
     wait_server_key,
     wait_cert_request,
     wait_hello_done,
     wait_new_session_ticket,
     wait_encrypted_extensions,
     idle_handshake,
-    wait_invalid /* Invalid value. There is no handshake message "invalid". */
+    wait_0rtt_finished,
+    wait_0rtt_end_of_early_data, /* Not processed by handshake code. */
+    wait_0rtt_trial_decrypt,     /* Wait for trial decryption to succeed. */
+    wait_invalid                 /* Invalid value. There is no handshake message "invalid". */
 } SSL3WaitState;
 
 /*
  * TLS extension related constants and data structures.
  */
 typedef struct TLSExtensionDataStr TLSExtensionData;
 typedef struct SessionTicketDataStr SessionTicketData;
 
@@ -865,16 +871,26 @@ typedef struct DTLSQueuedMessageStr {
 } DTLSQueuedMessage;
 
 typedef struct TLS13KeyShareEntryStr {
     PRCList link;               /* The linked list link */
     const namedGroupDef *group; /* The group for the entry */
     SECItem key_exchange;       /* The share itself */
 } TLS13KeyShareEntry;
 
+typedef struct TLS13EarlyDataStr {
+    PRCList link; /* The linked list link */
+    SECItem data; /* The data */
+} TLS13EarlyData;
+
+typedef struct {
+    PRUint8 hash[HASH_LENGTH_MAX * 2];
+    unsigned int len;
+} TLS13CombinedHash;
+
 typedef enum {
     handshake_hash_unknown = 0,
     handshake_hash_combo = 1,  /* The MD5/SHA-1 combination */
     handshake_hash_single = 2, /* A single hash */
     handshake_hash_record
 } SSL3HandshakeHashType;
 
 /*
@@ -905,17 +921,16 @@ typedef struct SSL3HandshakeStateStr {
 #endif
     /* PKCS #11 mode:
      * SSL 3.0 - TLS 1.1 use both |md5| and |sha|. |md5| is used for MD5 and
      * |sha| for SHA-1.
      * TLS 1.2 and later use only |sha|, for SHA-256. */
     PK11Context *md5;
     PK11Context *sha;
     SSLHashType tls12CertVerifyHash;
-
     const ssl3KEADef *kea_def;
     ssl3CipherSuite cipher_suite;
     const ssl3CipherSuiteDef *suite_def;
     SSLCompressionMethod compression;
     sslBuffer msg_body; /* protected by recvBufLock */
                         /* partial handshake message from record layer */
     unsigned int header_bytes;
     /* number of bytes consumed from handshake */
@@ -977,33 +992,44 @@ typedef struct SSL3HandshakeStateStr {
                                     * in progress. */
     unsigned char cookie[32];      /* The cookie */
     unsigned char cookieLen;       /* The length of the cookie */
     PRIntervalTime rtTimerStarted; /* When the timer was started */
     DTLSTimerCb rtTimerCb;         /* The function to call on expiry */
     PRUint32 rtTimeoutMs;          /* The length of the current timeout
                                     * used for backoff (in ms) */
     PRUint32 rtRetries;            /* The retry counter */
+    SECItem srvVirtName;           /* for server: name that was negotiated
+                          * with a client. For client - is
+                          * always set to NULL.*/
 
     /* This group of values is used for TLS 1.3 and above */
+    PK11Context *clientHelloHash;      /* The client hello hash state, used
+                                        * by the server for 0-RTT. */
     PRCList remoteKeyShares;           /* The other side's public keys */
-    PK11SymKey *xSS;                   /* Extracted static secret */
-    PK11SymKey *xES;                   /* Extracted ephemeral secret */
+    PK11SymKey *currentSecret;         /* The secret down the "left hand side"
+                                        * of the TLS 1.3 key schedule. */
+    PK11SymKey *resumptionPsk;         /* The resumption PSK. */
+    SECItem resumptionContext;         /* The resumption context. */
+    PK11SymKey *dheSecret;             /* The (EC)DHE shared secret. */
+    PK11SymKey *earlyTrafficSecret;    /* The secret we use for 0-RTT. */
+    PK11SymKey *hsTrafficSecret;       /* The handshake traffic secret. */
     PK11SymKey *trafficSecret;         /* The source key to use to generate
                                         * traffic keys */
-    PK11SymKey *clientFinishedSecret;  /* Used for client Finished */
-    PK11SymKey *serverFinishedSecret;  /* Used for server Finished */
     unsigned char certReqContext[255]; /* Ties CertificateRequest
                                         * to Certificate */
     PRUint8 certReqContextLen;         /* Length of the context
                                         * cannot be greater than 255. */
     ssl3CipherSuite origCipherSuite;   /* The cipher suite from the original
                                         * connection if we are resuming. */
     PRCList cipherSpecs;               /* The cipher specs in the sequence they
                                         * will be applied. */
+    PRBool doing0Rtt;                  /* Are we doing a 0-RTT handshake? */
+    PRCList bufferedEarlyData;         /* Buffered TLS 1.3 early data
+                                        * on server.*/
 } SSL3HandshakeState;
 
 /*
 ** This is the "ssl3" struct, as in "ss->ssl3".
 ** note:
 ** usually,   crSpec == cwSpec and prSpec == pwSpec.
 ** Sometimes, crSpec == pwSpec and prSpec == cwSpec.
 ** But there are never more than 2 actual specs.
@@ -1123,17 +1149,19 @@ typedef struct SessionTicketStr {
     PRUint8 ms_is_wrapped;
     CK_MECHANISM_TYPE msWrapMech;
     PRUint16 ms_length;
     SSL3Opaque master_secret[48];
     PRBool extendedMasterSecretUsed;
     ClientIdentity client_identity;
     SECItem peer_cert;
     PRUint32 timestamp;
+    PRUint32 flags;
     SECItem srvName; /* negotiated server name */
+    SECItem alpnSelection;
 } SessionTicket;
 
 /*
  * SSL2 buffers used in SSL3.
  *     writeBuf in the SecurityInfo maintained by sslsecur.c is used
  *              to hold the data just about to be passed to the kernel
  *     sendBuf in the ConnectInfo maintained by sslcon.c is used
  *              to hold handshake messages as they are accumulated
@@ -1688,17 +1716,18 @@ extern sslEphemeralKeyPair *ssl_NewEphem
 extern sslEphemeralKeyPair *ssl_CopyEphemeralKeyPair(
     sslEphemeralKeyPair *keyPair);
 extern void ssl_FreeEphemeralKeyPair(sslEphemeralKeyPair *keyPair);
 extern sslEphemeralKeyPair *ssl_LookupEphemeralKeyPair(
     sslSocket *ss, const namedGroupDef *groupDef);
 extern void ssl_FreeEphemeralKeyPairs(sslSocket *ss);
 
 extern SECStatus ssl_AppendPaddedDHKeyShare(sslSocket *ss,
-                                            SECKEYPublicKey *pubKey);
+                                            SECKEYPublicKey *pubKey,
+                                            PRBool appendLength);
 extern const ssl3DHParams *ssl_GetDHEParams(const namedGroupDef *groupDef);
 extern SECStatus ssl_SelectDHEParams(sslSocket *ss,
                                      const namedGroupDef **groupDef,
                                      const ssl3DHParams **params);
 extern SECStatus ssl_CreateDHEKeyPair(const namedGroupDef *groupDef,
                                       const ssl3DHParams *params,
                                       sslEphemeralKeyPair **keyPair);
 extern PRBool ssl_IsValidDHEShare(const SECItem *dh_p, const SECItem *dh_Ys);
@@ -1738,17 +1767,16 @@ extern SECStatus ssl3_CipherPrefGetDefau
 
 extern SECStatus ssl3_CipherPrefSet(sslSocket *ss, ssl3CipherSuite which, PRBool on);
 extern SECStatus ssl3_CipherPrefGet(sslSocket *ss, ssl3CipherSuite which, PRBool *on);
 
 extern SECStatus ssl3_SetPolicy(ssl3CipherSuite which, PRInt32 policy);
 extern SECStatus ssl3_GetPolicy(ssl3CipherSuite which, PRInt32 *policy);
 
 extern void ssl3_InitSocketPolicy(sslSocket *ss);
-extern void ssl3_InitCipherSpec(ssl3CipherSpec *spec);
 
 extern SECStatus ssl3_RedoHandshake(sslSocket *ss, PRBool flushCache);
 extern SECStatus ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b,
                                              PRUint32 length,
                                              PRBool endOfRecord);
 
 extern void ssl3_DestroySSL3Info(sslSocket *ss);
 
@@ -1849,28 +1877,28 @@ extern PRInt32 ssl3_SendSupportedPointFo
 extern SECStatus ssl3_HandleHelloExtensions(sslSocket *ss,
                                             SSL3Opaque **b, PRUint32 *length,
                                             SSL3HandshakeType handshakeMessage);
 
 /* Hello Extension related routines. */
 extern PRBool ssl3_ExtensionNegotiated(sslSocket *ss, PRUint16 ex_type);
 extern void ssl3_SetSIDSessionTicket(sslSessionID *sid,
                                      /*in/out*/ NewSessionTicket *session_ticket);
-extern SECStatus ssl3_SendNewSessionTicket(sslSocket *ss);
+SECStatus ssl3_EncodeSessionTicket(sslSocket *ss, SECItem *ticket_data);
 extern PRBool ssl_GetSessionTicketKeys(unsigned char *keyName,
                                        unsigned char *encKey, unsigned char *macKey);
 extern PRBool ssl_GetSessionTicketKeysPKCS11(SECKEYPrivateKey *svrPrivKey,
                                              SECKEYPublicKey *svrPubKey, void *pwArg,
                                              unsigned char *keyName, PK11SymKey **aesKey,
                                              PK11SymKey **macKey);
 extern SECStatus ssl3_SessionTicketShutdown(void *appData, void *nssData);
 
 /* Tell clients to consider tickets valid for this long. */
 #define TLS_EX_SESS_TICKET_LIFETIME_HINT (2 * 24 * 60 * 60) /* 2 days */
-#define TLS_EX_SESS_TICKET_VERSION (0x0102)
+#define TLS_EX_SESS_TICKET_VERSION (0x0103)
 
 extern SECStatus ssl3_ValidateNextProtoNego(const unsigned char *data,
                                             unsigned int length);
 
 /* Construct a new NSPR socket for the app to use */
 extern PRFileDesc *ssl_NewPRSocket(sslSocket *ss, PRFileDesc *fd);
 extern void ssl_FreePRSocket(PRFileDesc *fd);
 
@@ -1980,20 +2008,28 @@ SECStatus ssl3_FlushHandshake(sslSocket 
 PK11SymKey *ssl3_GetWrappingKey(sslSocket *ss,
                                 PK11SlotInfo *masterSecretSlot,
                                 const sslServerCert *serverCert,
                                 CK_MECHANISM_TYPE masterWrapMech,
                                 void *pwArg);
 PRInt32 tls13_ServerSendPreSharedKeyXtn(sslSocket *ss,
                                         PRBool append,
                                         PRUint32 maxBytes);
+PRInt32 tls13_ServerSendEarlyDataXtn(sslSocket *ss,
+                                     PRBool append,
+                                     PRUint32 maxBytes);
 PRBool ssl3_ClientExtensionAdvertised(sslSocket *ss, PRUint16 ex_type);
 SECStatus ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid);
 const ssl3CipherSuiteDef *ssl_LookupCipherSuiteDef(ssl3CipherSuite suite);
 SECStatus ssl3_SelectServerCert(sslSocket *ss);
+SECStatus ssl3_TLSSignatureAlgorithmForKeyType(KeyType keyType,
+                                               SSLSignType *out);
+
+SECStatus ssl3_SetCipherSuite(sslSocket *ss, ssl3CipherSuite chosenSuite,
+                              PRBool initHashes);
 
 /* Pull in TLS 1.3 functions */
 #include "tls13con.h"
 
 /********************** misc calls *********************/
 
 #ifdef DEBUG
 extern void ssl3_CheckCipherSuiteOrderConsistency();
--- a/security/nss/lib/ssl/sslinfo.c
+++ b/security/nss/lib/ssl/sslinfo.c
@@ -75,16 +75,23 @@ SSL_GetChannelInfo(PRFileDesc *fd, SSLCh
             inf.lastAccessTime = sid->lastAccessTime;
             inf.expirationTime = sid->expirationTime;
             inf.extendedMasterSecretUsed =
                 (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 ||
                  sid->u.ssl3.keys.extendedMasterSecretUsed)
                     ? PR_TRUE
                     : PR_FALSE;
 
+            if (ss->sec.isServer) {
+                inf.earlyDataAccepted = ss->ssl3.hs.doing0Rtt;
+            } else {
+                inf.earlyDataAccepted =
+                    ssl3_ExtensionNegotiated(
+                        ss, ssl_tls13_early_data_xtn);
+            }
             sidLen = sid->u.ssl3.sessionIDLength;
             sidLen = PR_MIN(sidLen, sizeof inf.sessionID);
             inf.sessionIDLength = sidLen;
             memcpy(inf.sessionID, sid->u.ssl3.sessionID, sidLen);
         }
     }
 
     memcpy(info, &inf, inf.length);
@@ -393,17 +400,17 @@ SSL_GetNegotiatedHostInfo(PRFileDesc *fd
         return NULL;
     }
 
     if (ss->sec.isServer) {
         if (ss->version > SSL_LIBRARY_VERSION_3_0 &&
             ss->ssl3.initialized) { /* TLS */
             SECItem *crsName;
             ssl_GetSpecReadLock(ss); /*********************************/
-            crsName = &ss->ssl3.cwSpec->srvVirtName;
+            crsName = &ss->ssl3.hs.srvVirtName;
             if (crsName->data) {
                 sniName = SECITEM_DupItem(crsName);
             }
             ssl_ReleaseSpecReadLock(ss); /*----------------------------*/
         }
         return sniName;
     }
     name = SSL_RevealURL(fd);
--- a/security/nss/lib/ssl/sslmutex.c
+++ b/security/nss/lib/ssl/sslmutex.c
@@ -389,30 +389,34 @@ sslMutex_Init(sslMutex *pMutex, int shar
 SECStatus
 sslMutex_Destroy(sslMutex *pMutex, PRBool processLocal)
 {
     HANDLE hMutex;
     int rv;
     int retvalue = SECSuccess;
 
     PR_ASSERT(pMutex != 0);
+    if (!pMutex) {
+        PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
+        return SECFailure;
+    }
+
     if (PR_FALSE == pMutex->isMultiProcess) {
         return single_process_sslMutex_Destroy(pMutex);
     }
 
 /*  multi-process mode */
 #ifdef WINNT
     /* on NT, get rid of the PRLock used for fibers within a process */
     retvalue = sslMutex_2LevelDestroy(pMutex);
 #endif
 
     PR_ASSERT(pMutex->u.sslMutx != 0 &&
               pMutex->u.sslMutx != INVALID_HANDLE_VALUE);
-    if (!pMutex || (hMutex = pMutex->u.sslMutx) == 0 ||
-        hMutex == INVALID_HANDLE_VALUE) {
+    if ((hMutex = pMutex->u.sslMutx) == 0 || hMutex == INVALID_HANDLE_VALUE) {
         PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
         return SECFailure;
     }
 
     rv = CloseHandle(hMutex); /* ignore error */
     if (!processLocal && rv) {
         pMutex->u.sslMutx = hMutex = INVALID_HANDLE_VALUE;
     }
@@ -425,24 +429,28 @@ sslMutex_Destroy(sslMutex *pMutex, PRBoo
 
 int
 sslMutex_Unlock(sslMutex *pMutex)
 {
     BOOL success = FALSE;
     HANDLE hMutex;
 
     PR_ASSERT(pMutex != 0);
+    if (!pMutex) {
+        PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
+        return SECFailure;
+    }
+
     if (PR_FALSE == pMutex->isMultiProcess) {
         return single_process_sslMutex_Unlock(pMutex);
     }
 
     PR_ASSERT(pMutex->u.sslMutx != 0 &&
               pMutex->u.sslMutx != INVALID_HANDLE_VALUE);
-    if (!pMutex || (hMutex = pMutex->u.sslMutx) == 0 ||
-        hMutex == INVALID_HANDLE_VALUE) {
+    if ((hMutex = pMutex->u.sslMutx) == 0 || hMutex == INVALID_HANDLE_VALUE) {
         PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
         return SECFailure;
     }
     success = ReleaseMutex(hMutex);
     if (!success) {
         nss_MD_win32_map_default_error(GetLastError());
         return SECFailure;
     }
@@ -457,30 +465,33 @@ sslMutex_Unlock(sslMutex *pMutex)
 int
 sslMutex_Lock(sslMutex *pMutex)
 {
     HANDLE hMutex;
     DWORD event;
     DWORD lastError;
     SECStatus rv;
     SECStatus retvalue = SECSuccess;
+
     PR_ASSERT(pMutex != 0);
+    if (!pMutex) {
+        PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
+        return SECFailure;
+    }
 
     if (PR_FALSE == pMutex->isMultiProcess) {
         return single_process_sslMutex_Lock(pMutex);
     }
 #ifdef WINNT
-    /* lock first to preserve from other threads/fibers
-       in the same process */
+    /* lock first to preserve from other threads/fibers in the same process */
     retvalue = single_process_sslMutex_Lock(pMutex);
 #endif
     PR_ASSERT(pMutex->u.sslMutx != 0 &&
               pMutex->u.sslMutx != INVALID_HANDLE_VALUE);
-    if (!pMutex || (hMutex = pMutex->u.sslMutx) == 0 ||
-        hMutex == INVALID_HANDLE_VALUE) {
+    if ((hMutex = pMutex->u.sslMutx) == 0 || hMutex == INVALID_HANDLE_VALUE) {
         PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
         return SECFailure; /* what else ? */
     }
     /* acquire the mutex to be the only owner accross all other processes */
     event = WaitForSingleObject(hMutex, INFINITE);
     switch (event) {
         case WAIT_OBJECT_0:
         case WAIT_ABANDONED:
--- a/security/nss/lib/ssl/sslnonce.c
+++ b/security/nss/lib/ssl/sslnonce.c
@@ -198,16 +198,18 @@ ssl_DestroySID(sslSessionID *sid)
     if (sid->peerCertStatus.items) {
         SECITEM_FreeArray(&sid->peerCertStatus, PR_FALSE);
     }
 
     if (sid->localCert) {
         CERT_DestroyCertificate(sid->localCert);
     }
 
+    SECITEM_FreeItem(&sid->u.ssl3.alpnSelection, PR_FALSE);
+
     PORT_ZFree(sid, sizeof(sslSessionID));
 }
 
 /* BEWARE: This function gets called for both client and server SIDs !!
  * Decrement reference count, and
  *    free sid if ref count is zero, and sid is not in the cache.
  * Does NOT remove from the cache first.
  * If the sid is still in the cache, it is left there until next time
--- a/security/nss/lib/ssl/sslsecur.c
+++ b/security/nss/lib/ssl/sslsecur.c
@@ -844,16 +844,21 @@ ssl_SecureRecv(sslSocket *ss, unsigned c
                 ssl_ReleaseXmitBufLock(ss);
                 return SECFailure;
             }
         }
         ssl_ReleaseXmitBufLock(ss);
     }
 
     rv = 0;
+    if (!PR_CLIST_IS_EMPTY(&ss->ssl3.hs.bufferedEarlyData)) {
+        PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
+        return tls13_Read0RttData(ss, buf, len);
+    }
+
     /* If any of these is non-zero, the initial handshake is not done. */
     if (!ss->firstHsDone) {
         ssl_Get1stHandshakeLock(ss);
         if (ss->handshake) {
             rv = ssl_Do1stHandshake(ss);
         }
         ssl_Release1stHandshakeLock(ss);
     }
@@ -908,23 +913,29 @@ ssl_SecureSend(sslSocket *ss, const unsi
     }
     ssl_ReleaseXmitBufLock(ss);
     if (rv < 0) {
         goto done;
     }
 
     if (len > 0)
         ss->writerThread = PR_GetCurrentThread();
-    /* If any of these is non-zero, the initial handshake is not done. */
+
+    /* Check to see if we can write even though we're not finished.
+     *
+     * Case 1: False start
+     * Case 2: TLS 1.3 0-RTT
+     */
     if (!ss->firstHsDone) {
         PRBool falseStart = PR_FALSE;
         ssl_Get1stHandshakeLock(ss);
-        if (ss->opt.enableFalseStart) {
+        if (ss->opt.enableFalseStart ||
+            (ss->opt.enable0RttData && !ss->sec.isServer)) {
             ssl_GetSSL3HandshakeLock(ss);
-            falseStart = ss->ssl3.hs.canFalseStart;
+            falseStart = ss->ssl3.hs.canFalseStart || ss->ssl3.hs.doing0Rtt;
             ssl_ReleaseSSL3HandshakeLock(ss);
         }
         if (!falseStart && ss->handshake) {
             rv = ssl_Do1stHandshake(ss);
         }
         ssl_Release1stHandshakeLock(ss);
     }
     if (rv < 0) {
@@ -944,17 +955,18 @@ ssl_SecureSend(sslSocket *ss, const unsi
         PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
         rv = PR_FAILURE;
         goto done;
     }
 
     if (!ss->firstHsDone) {
 #ifdef DEBUG
         ssl_GetSSL3HandshakeLock(ss);
-        PORT_Assert(ss->ssl3.hs.canFalseStart);
+        PORT_Assert(ss->ssl3.hs.canFalseStart ||
+                    (ss->ssl3.hs.doing0Rtt && !ss->sec.isServer));
         ssl_ReleaseSSL3HandshakeLock(ss);
 #endif
         SSL_TRC(3, ("%d: SSL[%d]: SecureSend: sending data due to false start",
                     SSL_GETPID(), ss->fd));
     }
 
     ssl_GetXmitBufLock(ss);
     rv = ssl3_SendApplicationData(ss, buf, len, flags);
--- a/security/nss/lib/ssl/sslsock.c
+++ b/security/nss/lib/ssl/sslsock.c
@@ -255,16 +255,17 @@ ssl_DupSocket(sslSocket *os)
 
     ss = ssl_NewSocket((PRBool)(!os->opt.noLocks), os->protocolVariant);
     if (!ss) {
         return NULL;
     }
 
     ss->opt = os->opt;
     ss->opt.useSocks = PR_FALSE;
+    SECITEM_CopyItem(NULL, &ss->opt.nextProtoNego, &os->opt.nextProtoNego);
     ss->vrange = os->vrange;
 
     ss->peerID = !os->peerID ? NULL : PORT_Strdup(os->peerID);
     ss->url = !os->url ? NULL : PORT_Strdup(os->url);
 
     ss->ops = os->ops;
     ss->rTimeout = os->rTimeout;
     ss->wTimeout = os->wTimeout;
@@ -320,16 +321,18 @@ ssl_DupSocket(sslSocket *os)
         ss->sniSocketConfigArg = os->sniSocketConfigArg;
         ss->handleBadCert = os->handleBadCert;
         ss->badCertArg = os->badCertArg;
         ss->handshakeCallback = os->handshakeCallback;
         ss->handshakeCallbackData = os->handshakeCallbackData;
         ss->canFalseStartCallback = os->canFalseStartCallback;
         ss->canFalseStartCallbackData = os->canFalseStartCallbackData;
         ss->pkcs11PinArg = os->pkcs11PinArg;
+        ss->nextProtoCallback = os->nextProtoCallback;
+        ss->nextProtoArg = os->nextProtoArg;
 
         /* Create security data */
         rv = ssl_CopySecurityInfo(ss, os);
         if (rv != SECSuccess) {
             goto loser;
         }
     }
     return ss;
@@ -808,16 +811,20 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 wh
         case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS:
             ss->opt.enableSignedCertTimestamps = on;
             break;
 
         case SSL_REQUIRE_DH_NAMED_GROUPS:
             ss->opt.requireDHENamedGroups = on;
             break;
 
+        case SSL_ENABLE_0RTT_DATA:
+            ss->opt.enable0RttData = on;
+            break;
+
         default:
             PORT_SetError(SEC_ERROR_INVALID_ARGS);
             rv = SECFailure;
     }
 
     /* We can't use the macros for releasing the locks here,
      * because ss->opt.noLocks might have changed just above.
      * We must release these locks (monitors) here, if we aquired them above,
@@ -938,17 +945,19 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 wh
             on = ss->opt.enableExtendedMS;
             break;
         case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS:
             on = ss->opt.enableSignedCertTimestamps;
             break;
         case SSL_REQUIRE_DH_NAMED_GROUPS:
             on = ss->opt.requireDHENamedGroups;
             break;
-
+        case SSL_ENABLE_0RTT_DATA:
+            on = ss->opt.enable0RttData;
+            break;
         default:
             PORT_SetError(SEC_ERROR_INVALID_ARGS);
             rv = SECFailure;
     }
 
     ssl_ReleaseSSL3HandshakeLock(ss);
     ssl_Release1stHandshakeLock(ss);
 
@@ -1053,17 +1062,19 @@ SSL_OptionGetDefault(PRInt32 which, PRBo
             on = ssl_defaults.enableServerDhe;
             break;
         case SSL_ENABLE_EXTENDED_MASTER_SECRET:
             on = ssl_defaults.enableExtendedMS;
             break;
         case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS:
             on = ssl_defaults.enableSignedCertTimestamps;
             break;
-
+        case SSL_ENABLE_0RTT_DATA:
+            on = ssl_defaults.enable0RttData;
+            break;
         default:
             PORT_SetError(SEC_ERROR_INVALID_ARGS);
             rv = SECFailure;
     }
 
     *pOn = on;
     return rv;
 }
@@ -1246,16 +1257,20 @@ SSL_OptionSetDefault(PRInt32 which, PRBo
         case SSL_ENABLE_EXTENDED_MASTER_SECRET:
             ssl_defaults.enableExtendedMS = on;
             break;
 
         case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS:
             ssl_defaults.enableSignedCertTimestamps = on;
             break;
 
+        case SSL_ENABLE_0RTT_DATA:
+            ssl_defaults.enable0RttData = on;
+            break;
+
         default:
             PORT_SetError(SEC_ERROR_INVALID_ARGS);
             return SECFailure;
     }
     return SECSuccess;
 }
 
 /* function tells us if the cipher suite is one that we no longer support. */
@@ -2320,16 +2335,20 @@ SSL_VersionRangeGetSupported(SSLProtocol
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return SECFailure;
     }
 
     switch (protocolVariant) {
         case ssl_variant_stream:
             vrange->min = SSL_LIBRARY_VERSION_3_0;
             vrange->max = SSL_LIBRARY_VERSION_MAX_SUPPORTED;
+            // We don't allow SSLv3 and TLSv1.3 together.
+            if (vrange->max == SSL_LIBRARY_VERSION_TLS_1_3) {
+                vrange->min = SSL_LIBRARY_VERSION_TLS_1_0;
+            }
             break;
         case ssl_variant_datagram:
             vrange->min = SSL_LIBRARY_VERSION_TLS_1_1;
             vrange->max = SSL_LIBRARY_VERSION_MAX_SUPPORTED;
             break;
         default:
             PORT_SetError(SEC_ERROR_INVALID_ARGS);
             return SECFailure;
@@ -3710,17 +3729,17 @@ ssl_NewSocket(PRBool makeLocks, SSLProto
     ss->pkcs11PinArg = NULL;
 
     ssl_ChooseOps(ss);
     ssl3_InitSocketPolicy(ss);
     ssl_InitNamedGroups(ss);
     PR_INIT_CLIST(&ss->ssl3.hs.lastMessageFlight);
     PR_INIT_CLIST(&ss->ssl3.hs.remoteKeyShares);
     PR_INIT_CLIST(&ss->ssl3.hs.cipherSpecs);
-
+    PR_INIT_CLIST(&ss->ssl3.hs.bufferedEarlyData);
     if (makeLocks) {
         rv = ssl_MakeLocks(ss);
         if (rv != SECSuccess)
             goto loser;
     }
     rv = ssl_CreateSecurityInfo(ss);
     if (rv != SECSuccess)
         goto loser;
--- a/security/nss/lib/ssl/sslt.h
+++ b/security/nss/lib/ssl/sslt.h
@@ -183,16 +183,22 @@ typedef struct SSLChannelInfoStr {
     const char* compressionMethodName;
     SSLCompressionMethod compressionMethod;
 
     /* The following fields are added in NSS 3.21.
      * This field only has meaning in TLS < 1.3 and will be set to
      *  PR_FALSE in TLS 1.3.
      */
     PRBool extendedMasterSecretUsed;
+
+    /* The following fields were added in NSS 3.25.
+     * This field only has meaning in TLS >= 1.3, and indicates on the
+     * client side that the server accepted early (0-RTT) data.
+     */
+    PRBool earlyDataAccepted;
 } SSLChannelInfo;
 
 /* Preliminary channel info */
 #define ssl_preinfo_version (1U << 0)
 #define ssl_preinfo_cipher_suite (1U << 1)
 #define ssl_preinfo_all (ssl_preinfo_version | ssl_preinfo_cipher_suite)
 
 typedef struct SSLPreliminaryChannelInfoStr {
@@ -278,27 +284,28 @@ typedef enum {
     ssl_signature_algorithms_xtn = 13,
     ssl_use_srtp_xtn = 14,
     ssl_app_layer_protocol_xtn = 16,
     /* signed_certificate_timestamp extension, RFC 6962 */
     ssl_signed_cert_timestamp_xtn = 18,
     ssl_padding_xtn = 21,
     ssl_extended_master_secret_xtn = 23,
     ssl_session_ticket_xtn = 35,
-    ssl_tls13_key_share_xtn = 40,      /* unofficial TODO(ekr) */
-    ssl_tls13_pre_shared_key_xtn = 41, /* unofficial TODO(ekr) */
+    ssl_tls13_key_share_xtn = 40,
+    ssl_tls13_pre_shared_key_xtn = 41,
+    ssl_tls13_early_data_xtn = 42,
     ssl_next_proto_nego_xtn = 13172,
     ssl_renegotiation_info_xtn = 0xff01,
     ssl_tls13_draft_version_xtn = 0xff02 /* experimental number */
 } SSLExtensionType;
 
 /* This is the old name for the supported_groups extensions. */
 #define ssl_elliptic_curves_xtn ssl_supported_groups_xtn
 
-#define SSL_MAX_EXTENSIONS 15 /* doesn't include ssl_padding_xtn. */
+#define SSL_MAX_EXTENSIONS 16 /* doesn't include ssl_padding_xtn. */
 
 typedef enum {
     ssl_dhe_group_none = 0,
     ssl_ff_dhe_2048_group = 1,
     ssl_ff_dhe_3072_group = 2,
     ssl_ff_dhe_4096_group = 3,
     ssl_ff_dhe_6144_group = 4,
     ssl_ff_dhe_8192_group = 5,
--- a/security/nss/lib/ssl/tls13con.c
+++ b/security/nss/lib/ssl/tls13con.c
@@ -1,100 +1,113 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /*
  * TLS 1.3 Protocol
  *
  * 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 "stdarg.h"
 #include "cert.h"
 #include "ssl.h"
 #include "keyhi.h"
 #include "pk11func.h"
 #include "secitem.h"
 #include "secmod.h"
 #include "sslimpl.h"
 #include "sslproto.h"
 #include "sslerr.h"
 #include "tls13hkdf.h"
 #include "tls13con.h"
 
 typedef enum {
-    TrafficKeyEarlyData,
+    TrafficKeyEarlyHandshake,
+    TrafficKeyEarlyApplicationData,
     TrafficKeyHandshake,
     TrafficKeyApplicationData
 } TrafficKeyType;
 
 typedef enum {
-    InstallCipherSpecRead,
-    InstallCipherSpecWrite,
-    InstallCipherSpecBoth
-} InstallCipherSpecDirection;
+    CipherSpecRead,
+    CipherSpecWrite,
+} CipherSpecDirection;
 
 #define MAX_FINISHED_SIZE 64
 
-static SECStatus tls13_InitializeHandshakeEncryption(sslSocket *ss);
-static SECStatus tls13_SetupNullCipherSpec(sslSocket *ss);
-static SECStatus tls13_SetupPendingCipherSpec(sslSocket *ss);
-static SECStatus tls13_InstallCipherSpec(
-    sslSocket *ss, InstallCipherSpecDirection direction);
-static SECStatus tls13_InitCipherSpec(
-    sslSocket *ss, TrafficKeyType type, InstallCipherSpecDirection install);
+static SECStatus tls13_SetCipherSpec(sslSocket *ss, TrafficKeyType type,
+                                     CipherSpecDirection install,
+                                     PRBool deleteSecret);
 static SECStatus tls13_AESGCM(
     ssl3KeyMaterial *keys,
     PRBool doDecrypt,
     unsigned char *out, int *outlen, int maxout,
     const unsigned char *in, int inlen,
     const unsigned char *additionalData, int additionalDataLen);
 static SECStatus tls13_ChaCha20Poly1305(
     ssl3KeyMaterial *keys,
     PRBool doDecrypt,
     unsigned char *out, int *outlen, int maxout,
     const unsigned char *in, int inlen,
     const unsigned char *additionalData, int additionalDataLen);
 static SECStatus tls13_SendEncryptedExtensions(sslSocket *ss);
+static PRBool tls13_ServerAllow0Rtt(sslSocket *ss, const sslSessionID *sid);
 static SECStatus tls13_HandleEncryptedExtensions(sslSocket *ss, SSL3Opaque *b,
                                                  PRUint32 length);
 static SECStatus tls13_HandleCertificate(
     sslSocket *ss, SSL3Opaque *b, PRUint32 length);
 static SECStatus tls13_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b,
                                                 PRUint32 length);
 static SECStatus tls13_HandleCertificateStatus(sslSocket *ss, SSL3Opaque *b,
                                                PRUint32 length);
+static SECStatus
+tls13_SendCertificateVerify(sslSocket *ss, SECKEYPrivateKey *privKey);
 static SECStatus tls13_HandleCertificateVerify(
     sslSocket *ss, SSL3Opaque *b, PRUint32 length,
-    SSL3Hashes *hashes);
-static SECStatus tls13_HkdfExtractSharedKey(sslSocket *ss, PK11SymKey *key,
-                                            SharedSecretType keyType);
-static SECStatus tls13_SendFinished(sslSocket *ss);
-static SECStatus tls13_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length,
-                                      const SSL3Hashes *hashes);
+    TLS13CombinedHash *hashes);
+static SECStatus
+tls13_DeriveSecret(sslSocket *ss, PK11SymKey *key, const char *label,
+                   const TLS13CombinedHash *hashes,
+                   PK11SymKey **dest);
+static SECStatus tls13_SendFinished(sslSocket *ss, PK11SymKey *baseKey);
+static SECStatus tls13_VerifyFinished(sslSocket *ss, PK11SymKey *secret,
+                                      SSL3Opaque *b, PRUint32 length,
+                                      const TLS13CombinedHash *hashes);
+static SECStatus tls13_ClientHandleFinished(sslSocket *ss,
+                                            SSL3Opaque *b, PRUint32 length,
+                                            const TLS13CombinedHash *hashes);
+static SECStatus tls13_ServerHandleFinished(sslSocket *ss,
+                                            SSL3Opaque *b, PRUint32 length,
+                                            const TLS13CombinedHash *hashes);
+static SECStatus tls13_SendNewSessionTicket(sslSocket *ss);
 static SECStatus tls13_HandleNewSessionTicket(sslSocket *ss, SSL3Opaque *b,
                                               PRUint32 length);
-static SECStatus
-tls13_ComputeHandshakeHashes(sslSocket *ss, SSL3Hashes *hashes);
-static SECStatus tls13_ComputeSecrets1(sslSocket *ss);
-static SECStatus tls13_ComputeSecrets2(sslSocket *ss);
+static void
+tls13_CombineHashes(sslSocket *ss, const PRUint8 *hhash, unsigned int hlen,
+                    TLS13CombinedHash *hashes);
+static SECStatus tls13_ComputeHandshakeHashes(sslSocket *ss,
+                                              TLS13CombinedHash *hashes);
+static SECStatus tls13_ComputeEarlySecrets(sslSocket *ss, PRBool setup0Rtt);
+static SECStatus tls13_ComputeHandshakeSecrets(sslSocket *ss);
+static SECStatus tls13_ComputeApplicationSecrets(sslSocket *ss);
+static SECStatus tls13_ComputeFinalSecrets(sslSocket *ss);
 static SECStatus tls13_ComputeFinished(
-    sslSocket *ss, const SSL3Hashes *hashes,
-    PRBool sending,
-    PRUint8 *output, unsigned int *outputLen,
+    sslSocket *ss, PK11SymKey *baseKey, const TLS13CombinedHash *hashes,
+    PRBool sending, PRUint8 *output, unsigned int *outputLen,
     unsigned int maxOutputLen);
 static SECStatus tls13_SendClientSecondRound(sslSocket *ss);
 static SECStatus tls13_FinishHandshake(sslSocket *ss);
 
-const char kHkdfLabelExpandedSs[] = "expanded static secret";
-const char kHkdfLabelExpandedEs[] = "expanded ephemeral secret";
-const char kHkdfLabelMasterSecret[] = "master secret";
-const char kHkdfLabelTrafficSecret[] = "traffic secret";
+const char kHkdfLabelEarlyTrafficSecret[] = "early traffic secret";
+const char kHkdfLabelHandshakeTrafficSecret[] = "handshake traffic secret";
+const char kHkdfLabelApplicationTrafficSecret[] = "application traffic secret";
 const char kHkdfLabelClientFinishedSecret[] = "client finished";
 const char kHkdfLabelServerFinishedSecret[] = "server finished";
 const char kHkdfLabelResumptionMasterSecret[] = "resumption master secret";
+const char kHkdfLabelResumptionPsk[] = "resumption psk";
+const char kHkdfLabelResumptionContext[] = "resumption context";
 const char kHkdfLabelExporterMasterSecret[] = "exporter master secret";
 const char kHkdfPhaseEarlyHandshakeDataKeys[] = "early handshake key expansion";
 const char kHkdfPhaseEarlyApplicationDataKeys[] = "early application data key expansion";
 const char kHkdfPhaseHandshakeKeys[] = "handshake key expansion";
 const char kHkdfPhaseApplicationDataKeys[] = "application data key expansion";
 const char kHkdfPurposeClientWriteKey[] = "client write key";
 const char kHkdfPurposeServerWriteKey[] = "server write key";
 const char kHkdfPurposeClientWriteIv[] = "client write iv";
@@ -145,16 +158,19 @@ tls13_HandshakeState(SSL3WaitState st)
         STATE_CASE(wait_client_cert);
         STATE_CASE(wait_cert_verify);
         STATE_CASE(wait_finished);
         STATE_CASE(wait_server_hello);
         STATE_CASE(wait_certificate_status);
         STATE_CASE(wait_server_cert);
         STATE_CASE(wait_cert_request);
         STATE_CASE(wait_encrypted_extensions);
+        STATE_CASE(wait_0rtt_finished);
+        STATE_CASE(wait_0rtt_end_of_early_data);
+        STATE_CASE(wait_0rtt_trial_decrypt);
         STATE_CASE(idle_handshake);
         default:
             break;
     }
     PORT_Assert(0);
     return "unknown";
 }
 #endif
@@ -171,18 +187,19 @@ tls13_HandshakeState(SSL3WaitState st)
 void
 tls13_SetHsState(sslSocket *ss, SSL3WaitState ws,
                  const char *func, const char *file, int line)
 {
 #ifdef TRACE
     const char *new_state_name =
         tls13_HandshakeState(ws);
 
-    SSL_TRC(3, ("%d: TLS13[%d]: state change from %s->%s in %s (%s:%d)",
+    SSL_TRC(3, ("%d: TLS13[%d]: %s state change from %s->%s in %s (%s:%d)",
                 SSL_GETPID(), ss->fd,
+                ss->sec.isServer ? "server" : "client",
                 tls13_HandshakeState(TLS13_BASE_WAIT_STATE(ss->ssl3.hs.ws)),
                 new_state_name,
                 func, file, line));
 #endif
 
     ss->ssl3.hs.ws = TLS13_WAIT_STATE(ws);
 }
 
@@ -237,45 +254,56 @@ tls13_CheckHsState(sslSocket *ss, int er
 SSLHashType
 tls13_GetHash(sslSocket *ss)
 {
     /* All TLS 1.3 cipher suites must have an explict PRF hash. */
     PORT_Assert(ss->ssl3.hs.suite_def->prf_hash != ssl_hash_none);
     return ss->ssl3.hs.suite_def->prf_hash;
 }
 
-unsigned int
-tls13_GetHashSize(sslSocket *ss)
+static unsigned int
+tls13_GetHashSizeForHash(SSLHashType hash)
 {
-    switch (tls13_GetHash(ss)) {
+    switch (hash) {
         case ssl_hash_sha256:
             return 32;
         case ssl_hash_sha384:
             return 48;
         default:
             PORT_Assert(0);
     }
     return 32;
 }
 
-CK_MECHANISM_TYPE
-tls13_GetHkdfMechanism(sslSocket *ss)
+unsigned int
+tls13_GetHashSize(sslSocket *ss)
 {
-    switch (tls13_GetHash(ss)) {
+    return tls13_GetHashSizeForHash(tls13_GetHash(ss));
+}
+
+static CK_MECHANISM_TYPE
+tls13_GetHkdfMechanismForHash(SSLHashType hash)
+{
+    switch (hash) {
         case ssl_hash_sha256:
             return CKM_NSS_HKDF_SHA256;
         case ssl_hash_sha384:
             return CKM_NSS_HKDF_SHA384;
         default:
-            /*PORT_Assert(0);*/
-            return CKM_NSS_HKDF_SHA256;
+            PORT_Assert(0);
     }
     return CKM_NSS_HKDF_SHA256;
 }
 
+CK_MECHANISM_TYPE
+tls13_GetHkdfMechanism(sslSocket *ss)
+{
+    return tls13_GetHkdfMechanismForHash(tls13_GetHash(ss));
+}
+
 static CK_MECHANISM_TYPE
 tls13_GetHmacMechanism(sslSocket *ss)
 {
     switch (tls13_GetHash(ss)) {
         case ssl_hash_sha256:
             return CKM_SHA256_HMAC;
         case ssl_hash_sha384:
             return CKM_SHA384_HMAC;
@@ -333,24 +361,19 @@ tls13_SetupClientHello(sslSocket *ss)
 static SECStatus
 tls13_ImportDHEKeyShare(sslSocket *ss, SECKEYPublicKey *peerKey,
                         SSL3Opaque *b, PRUint32 length,
                         SECKEYPublicKey *pubKey)
 {
     SECStatus rv;
     SECItem publicValue = { siBuffer, NULL, 0 };
 
-    rv = ssl3_ConsumeHandshakeVariable(ss, &publicValue,
-                                       2, &b, &length);
-    if (rv != SECSuccess) {
-        PORT_SetError(SSL_ERROR_RX_MALFORMED_DHE_KEY_SHARE);
-        return SECFailure;
-    }
-
-    if (length || !ssl_IsValidDHEShare(&pubKey->u.dh.prime, &publicValue)) {
+    publicValue.data = b;
+    publicValue.len = length;
+    if (!ssl_IsValidDHEShare(&pubKey->u.dh.prime, &publicValue)) {
         PORT_SetError(SSL_ERROR_RX_MALFORMED_DHE_KEY_SHARE);
         return SECFailure;
     }
 
     peerKey->keyType = dhKey;
     rv = SECITEM_CopyItem(peerKey->arena, &peerKey->u.dh.prime,
                           &pubKey->u.dh.prime);
     if (rv != SECSuccess)
@@ -368,21 +391,20 @@ tls13_ImportDHEKeyShare(sslSocket *ss, S
 }
 
 static SECStatus
 tls13_HandleKeyShare(sslSocket *ss,
                      TLS13KeyShareEntry *entry,
                      sslKeyPair *keyPair)
 {
     PORTCheapArenaPool arena;
-    SECStatus rv;
     SECKEYPublicKey *peerKey;
     CK_MECHANISM_TYPE mechanism;
-    PK11SymKey *shared;
     PRErrorCode errorCode;
+    SECStatus rv;
 
     PORT_InitCheapArena(&arena, DER_DEFAULT_CHUNKSIZE);
     peerKey = PORT_ArenaZNew(&arena.arena, SECKEYPublicKey);
     if (peerKey == NULL) {
         goto loser;
     }
     peerKey->arena = &arena.arena;
     peerKey->pkcs11Slot = NULL;
@@ -406,96 +428,120 @@ tls13_HandleKeyShare(sslSocket *ss,
         default:
             PORT_Assert(0);
             goto loser;
     }
     if (rv != SECSuccess) {
         goto loser;
     }
 
-    shared = PK11_PubDeriveWithKDF(keyPair->privKey, peerKey,
-                                   PR_FALSE, NULL, NULL, mechanism,
-                                   tls13_GetHkdfMechanism(ss),
-                                   CKA_DERIVE, 0, CKD_NULL, NULL, NULL);
-    if (!shared) {
+    ss->ssl3.hs.dheSecret = PK11_PubDeriveWithKDF(
+        keyPair->privKey, peerKey, PR_FALSE, NULL, NULL, mechanism,
+        tls13_GetHkdfMechanism(ss), CKA_DERIVE, 0, CKD_NULL, NULL, NULL);
+    if (!ss->ssl3.hs.dheSecret) {
         ssl_MapLowLevelError(SSL_ERROR_KEY_EXCHANGE_FAILURE);
         goto loser;
     }
-
-    /* Extract key. */
-    rv = tls13_HkdfExtractSharedKey(ss, shared, EphemeralSharedSecret);
-    PK11_FreeSymKey(shared);
     PORT_DestroyCheapArena(&arena);
-    return rv;
+    return SECSuccess;
 
 loser:
     PORT_DestroyCheapArena(&arena);
     errorCode = PORT_GetError(); /* don't overwrite the error code */
     tls13_FatalError(ss, errorCode, illegal_parameter);
     return SECFailure;
 }
 
 SECStatus
 tls13_HandlePostHelloHandshakeMessage(sslSocket *ss, SSL3Opaque *b,
                                       PRUint32 length, SSL3Hashes *hashesPtr)
 {
+    TLS13CombinedHash hashes;
+
+    if (TLS13_IN_HS_STATE(ss, wait_0rtt_trial_decrypt)) {
+        SSL_TRC(3, ("%d: TLS13[%d]: %s successfully decrypted handshake after"
+                    "failed 0-RTT",
+                    SSL_GETPID(), ss->fd));
+        TLS13_SET_HS_STATE(ss, ss->opt.requestCertificate ? wait_client_cert
+                                                          : wait_finished);
+    }
+
     /* TODO(ekr@rtfm.com): Would it be better to check all the states here? */
     switch (ss->ssl3.hs.msg_type) {
         case certificate:
             return tls13_HandleCertificate(ss, b, length);
 
         case certificate_status:
             return tls13_HandleCertificateStatus(ss, b, length);
 
         case certificate_request:
             return tls13_HandleCertificateRequest(ss, b, length);
 
         case certificate_verify:
-            return tls13_HandleCertificateVerify(ss, b, length, hashesPtr);
+            if (!hashesPtr) {
+                FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+                return SECFailure;
+            }
+            tls13_CombineHashes(ss, hashesPtr->u.raw, hashesPtr->len,
+                                &hashes);
+            return tls13_HandleCertificateVerify(ss, b, length, &hashes);
 
         case encrypted_extensions:
             return tls13_HandleEncryptedExtensions(ss, b, length);
 
         case new_session_ticket:
             return tls13_HandleNewSessionTicket(ss, b, length);
 
         case finished:
-            return tls13_HandleFinished(ss, b, length, hashesPtr);
+            if (!hashesPtr) {
+                FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+                return SECFailure;
+            }
+            tls13_CombineHashes(ss, hashesPtr->u.raw, hashesPtr->len,
+                                &hashes);
+            if (ss->sec.isServer) {
+                return tls13_ServerHandleFinished(ss, b, length, &hashes);
+            } else {
+                return tls13_ClientHandleFinished(ss, b, length, &hashes);
+            }
 
         default:
             FATAL_ERROR(ss, SSL_ERROR_RX_UNKNOWN_HANDSHAKE, unexpected_message);
             return SECFailure;
     }
 
     PORT_Assert(0); /* Unreached */
     return SECFailure;
 }
 
 static SECStatus
 tls13_RecoverWrappedSharedSecret(sslSocket *ss, sslSessionID *sid)
 {
     PK11SymKey *wrapKey; /* wrapping key */
-    PK11SymKey *SS = NULL;
+    PK11SymKey *RMS = NULL;
     SECItem wrappedMS = { siBuffer, NULL, 0 };
     SSLHashType hashType;
+    const ssl3CipherSuiteDef *cipherDef;
     SECStatus rv;
 
     SSL_TRC(3, ("%d: TLS13[%d]: recovering static secret (%s)",
                 SSL_GETPID(), ss->fd,
                 ss->sec.isServer ? "server" : "client"));
     if (!sid->u.ssl3.keys.msIsWrapped) {
         PORT_Assert(0); /* I think this can't happen. */
         return SECFailure;
     }
 
-    hashType = tls13_GetHash(ss);
-    if (hashType != ssl_hash_sha256 && hashType != ssl_hash_sha384) {
-        PORT_Assert(0);
+    /* Now find the hash used as the PRF for the previous handshake. */
+    cipherDef = ssl_LookupCipherSuiteDef(sid->u.ssl3.cipherSuite);
+    PORT_Assert(cipherDef);
+    if (!cipherDef) {
         return SECFailure;
     }
+    hashType = cipherDef->prf_hash;
 
     /* If we are the server, we compute the wrapping key, but if we
      * are the client, it's coordinates are stored with the ticket. */
     if (ss->sec.isServer) {
         const sslServerCert *serverCert;
 
         serverCert = ssl_FindServerCert(ss, &sid->certType);
         PORT_Assert(serverCert);
@@ -517,32 +563,281 @@ tls13_RecoverWrappedSharedSecret(sslSock
     }
     if (!wrapKey) {
         return SECFailure;
     }
 
     wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret;
     wrappedMS.len = sid->u.ssl3.keys.wrapped_master_secret_len;
 
-    /* unwrap the "master secret" which becomes SS. */
-    SS = PK11_UnwrapSymKeyWithFlags(wrapKey, sid->u.ssl3.masterWrapMech,
-                                    NULL, &wrappedMS,
-                                    CKM_SSL3_MASTER_KEY_DERIVE,
-                                    CKA_DERIVE, tls13_GetHashSize(ss),
-                                    CKF_SIGN | CKF_VERIFY);
+    /* unwrap the "master secret" which is actually RMS. */
+    RMS = PK11_UnwrapSymKeyWithFlags(wrapKey, sid->u.ssl3.masterWrapMech,
+                                     NULL, &wrappedMS,
+                                     CKM_SSL3_MASTER_KEY_DERIVE,
+                                     CKA_DERIVE,
+                                     tls13_GetHashSizeForHash(hashType),
+                                     CKF_SIGN | CKF_VERIFY);
     PK11_FreeSymKey(wrapKey);
-    if (!SS) {
+    if (!RMS) {
         return SECFailure;
     }
-    PRINT_KEY(50, (ss, "Recovered static secret", SS));
-    rv = tls13_HkdfExtractSharedKey(ss, SS, StaticSharedSecret);
-    PK11_FreeSymKey(SS);
+
+    PRINT_KEY(50, (ss, "Recovered RMS", RMS));
+    /* Now compute resumption_psk and resumption_context.
+     *
+     * resumption_psk = HKDF-Expand-Label(resumption_secret,
+     *                                    "resumption psk", "", L)
+     *
+     * resumption_context = HKDF-Expand-Label(resumption_secret,
+     *                                        "resumption context", "", L)
+     */
+    rv = tls13_HkdfExpandLabel(RMS, hashType, NULL, 0,
+                               kHkdfLabelResumptionPsk,
+                               strlen(kHkdfLabelResumptionPsk),
+                               tls13_GetHkdfMechanismForHash(hashType),
+                               tls13_GetHashSizeForHash(hashType),
+                               &ss->ssl3.hs.resumptionPsk);
+    if (rv != SECSuccess) {
+        goto loser;
+    }
+
+    if (SECITEM_AllocItem(NULL, &ss->ssl3.hs.resumptionContext,
+                          tls13_GetHashSizeForHash(hashType)) == NULL) {
+        goto loser;
+    }
+
+    rv = tls13_HkdfExpandLabelRaw(RMS, hashType, NULL, 0,
+                                  kHkdfLabelResumptionContext,
+                                  strlen(kHkdfLabelResumptionContext),
+                                  ss->ssl3.hs.resumptionContext.data,
+                                  ss->ssl3.hs.resumptionContext.len);
+    if (rv != SECSuccess) {
+        goto loser;
+    }
+
+    PK11_FreeSymKey(RMS);
+    return SECSuccess;
+
+loser:
+    if (RMS) {
+        PK11_FreeSymKey(RMS);
+    }
+    return SECFailure;
+}
+
+/* Key Derivation Functions.
+ *
+ * Below is the key schedule from [draft-ietf-tls-tls13].
+ *
+ * The relevant functions from this file are indicated by tls13_Foo().
+ *
+ *                  0
+ *                  |
+ *                  v
+ *    PSK ->  HKDF-Extract      tls13_ComputeEarlySecrets()
+ *                  |
+ *                  v
+ *            Early Secret  --> Derive-Secret(., "early traffic secret",
+ *                  |                         ClientHello)
+ *                  |                         = early_traffic_secret
+ *                  v
+ * (EC)DHE -> HKDF-Extract      tls13_ComputeHandshakeSecrets()
+ *                  |
+ *                  v
+ *               Handshake
+ *                Secret -----> Derive-Secret(., "handshake traffic secret",
+ *                  |                         ClientHello + ServerHello)
+ *                  |                         = handshake_traffic_secret
+ *                  v
+ *       0 -> HKDF-Extract      tls13_ComputeApplicationSecret
+ *                  |
+ *                  v
+ *             Master Secret
+ *                  |
+ *                  +---------> Derive-Secret(., "application traffic secret",
+ *                  |                         ClientHello...Server Finished)
+ *                  |                         = traffic_secret_0
+ *                  |
+ *                  |
+ *                  |           tls13_ComputeFinalSecrets()
+ *                  |
+ *                  +---------> Derive-Secret(., "exporter master secret",
+ *                  |                         ClientHello...Client Finished)
+ *                  |                         = exporter_secret
+ *                  |
+ *                  +---------> Derive-Secret(., "resumption master secret",
+ *                                            ClientHello...Client Finished)
+ *                                            = resumption_secret
+ */
+
+static SECStatus
+tls13_ComputeEarlySecrets(sslSocket *ss, PRBool setup0Rtt)
+{
+    SECStatus rv = SECSuccess;
+    PK11Context *ctx;
+    PRUint8 hash[HASH_LENGTH_MAX];
+    unsigned int len;
+
+    /* Extract off the resumptionPsk (if present), else pass the NULL
+     * resumptionPsk which will be internally translated to zeroes. */
+    PORT_Assert(!ss->ssl3.hs.currentSecret);
+    rv = tls13_HkdfExtract(NULL, ss->ssl3.hs.resumptionPsk,
+                           tls13_GetHash(ss), &ss->ssl3.hs.currentSecret);
     if (rv != SECSuccess) {
         return SECFailure;
     }
+    if (ss->ssl3.hs.resumptionPsk) {
+        PK11_FreeSymKey(ss->ssl3.hs.resumptionPsk);
+        ss->ssl3.hs.resumptionPsk = NULL;
+    }
+
+    if (!ss->ssl3.hs.resumptionContext.data) {
+        PORT_Assert(!setup0Rtt);
+        /* If no resumption context, fill with zeroes. */
+        if (SECITEM_AllocItem(NULL, &ss->ssl3.hs.resumptionContext,
+                              tls13_GetHashSize(ss)) == NULL) {
+            return SECFailure;
+        }
+        PORT_Memset(ss->ssl3.hs.resumptionContext.data, 0,
+                    ss->ssl3.hs.resumptionContext.len);
+    }
+
+    PRINT_BUF(50, (ss, "Resumption context",
+                   ss->ssl3.hs.resumptionContext.data,
+                   ss->ssl3.hs.resumptionContext.len));
+
+    /* Now compute the Hash of the resumptionContext so we can cache
+     * that. */
+    ctx = PK11_CreateDigestContext(ssl3_TLSHashAlgorithmToOID(
+        tls13_GetHash(ss)));
+    if (!ctx) {
+        PORT_SetError(SEC_ERROR_NO_MEMORY);
+        return SECFailure;
+    }
+    rv |= PK11_DigestBegin(ctx);
+    rv |= PK11_DigestOp(ctx,
+                        ss->ssl3.hs.resumptionContext.data,
+                        ss->ssl3.hs.resumptionContext.len);
+    rv |= PK11_DigestFinal(ctx, hash, &len, sizeof(hash));
+    PK11_DestroyContext(ctx, PR_TRUE);
+    if (rv != SECSuccess)
+        return SECFailure;
+    PORT_Assert(len == tls13_GetHashSize(ss));
+    PRINT_BUF(50, (ss, "Hash of resumption context", hash, len));
+
+    /* Stuff it back into the resumptionContext. */
+    SECITEM_FreeItem(&ss->ssl3.hs.resumptionContext, PR_FALSE);
+    if (SECITEM_AllocItem(NULL, &ss->ssl3.hs.resumptionContext,
+                          tls13_GetHashSize(ss)) == NULL) {
+        return SECFailure;
+    }
+    PORT_Memcpy(ss->ssl3.hs.resumptionContext.data, hash, len);
+
+    if (setup0Rtt) {
+        /* Derive the early secret. */
+        rv = tls13_DeriveSecret(ss, ss->ssl3.hs.currentSecret,
+                                kHkdfLabelEarlyTrafficSecret,
+                                NULL,
+                                &ss->ssl3.hs.earlyTrafficSecret);
+        if (rv != SECSuccess)
+            return SECFailure;
+    }
+
+    return SECSuccess;
+}
+
+static SECStatus
+tls13_ComputeHandshakeSecrets(sslSocket *ss)
+{
+    SECStatus rv;
+    PK11SymKey *newSecret = NULL;
+
+    /* First update |currentSecret| to add |dheSecret|, if any. */
+    PORT_Assert(ss->ssl3.hs.currentSecret);
+    PORT_Assert(ss->ssl3.hs.dheSecret);
+    rv = tls13_HkdfExtract(ss->ssl3.hs.currentSecret, ss->ssl3.hs.dheSecret,
+                           tls13_GetHash(ss), &newSecret);
+    if (rv != SECSuccess) {
+        FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+        return rv;
+    }
+    PK11_FreeSymKey(ss->ssl3.hs.dheSecret);
+    ss->ssl3.hs.dheSecret = NULL;
+    PK11_FreeSymKey(ss->ssl3.hs.currentSecret);
+    ss->ssl3.hs.currentSecret = newSecret;
+
+    /* Now compute |hsTrafficSecret| */
+    rv = tls13_DeriveSecret(ss, ss->ssl3.hs.currentSecret,
+                            kHkdfLabelHandshakeTrafficSecret, NULL,
+                            &ss->ssl3.hs.hsTrafficSecret);
+    if (rv != SECSuccess) {
+        FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+        return rv;
+    }
+
+    /* Crank HKDF forward to make master secret, which we
+     * stuff in current secret. */
+    rv = tls13_HkdfExtract(ss->ssl3.hs.currentSecret,
+                           NULL,
+                           tls13_GetHash(ss),
+                           &newSecret);
+
+    if (rv != SECSuccess) {
+        FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+        return SECFailure;
+    }
+    PK11_FreeSymKey(ss->ssl3.hs.currentSecret);
+    ss->ssl3.hs.currentSecret = newSecret;
+
+    return SECSuccess;
+}
+
+static SECStatus
+tls13_ComputeApplicationSecrets(sslSocket *ss)
+{
+    SECStatus rv;
+
+    rv = tls13_DeriveSecret(ss, ss->ssl3.hs.currentSecret,
+                            kHkdfLabelApplicationTrafficSecret,
+                            NULL,
+                            &ss->ssl3.hs.trafficSecret);
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
+
+    return SECSuccess;
+}
+
+static SECStatus
+tls13_ComputeFinalSecrets(sslSocket *ss)
+{
+    SECStatus rv;
+    PK11SymKey *resumptionMasterSecret = NULL;
+
+    PORT_Assert(!ss->ssl3.crSpec->master_secret);
+    PORT_Assert(!ss->ssl3.cwSpec->master_secret);
+
+    rv = tls13_DeriveSecret(ss, ss->ssl3.hs.currentSecret,
+                            kHkdfLabelResumptionMasterSecret,
+                            NULL, &resumptionMasterSecret);
+    PK11_FreeSymKey(ss->ssl3.hs.currentSecret);
+    ss->ssl3.hs.currentSecret = NULL;
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
+
+    /* This is pretty gross. TLS 1.3 uses a number of master secrets:
+     * The master secret to generate the keys and then the resumption
+     * master secret for future connections. To make this work without
+     * refactoring too much of the SSLv3 code, we store the RMS in
+     * |crSpec->master_secret| and |cwSpec->master_secret|.
+     */
+    ss->ssl3.crSpec->master_secret = resumptionMasterSecret;
+    ss->ssl3.cwSpec->master_secret =
+        PK11_ReferenceSymKey(ss->ssl3.crSpec->master_secret);
 
     return SECSuccess;
 }
 
 static void
 tls13_RestoreCipherInfo(sslSocket *ss, sslSessionID *sid)
 {
     /* Set these to match the cached value.
@@ -610,158 +905,186 @@ tls13_CanResume(sslSocket *ss, const ssl
     sc = ssl_FindServerCert(ss, &sid->certType);
     if (!sc || !sc->serverCert) {
         return PR_FALSE;
     }
 
     return PR_TRUE;
 }
 
+static PRBool
+tls13_AlpnTagAllowed(sslSocket *ss, const SECItem *tag)
+{
+    const unsigned char *data = ss->opt.nextProtoNego.data;
+    unsigned int length = ss->opt.nextProtoNego.len;
+    unsigned int offset = 0;
+
+    if (!tag->len)
+        return PR_TRUE;
+
+    while (offset < length) {
+        unsigned int taglen = (unsigned int)data[offset];
+        if ((taglen == tag->len) &&
+            !PORT_Memcmp(data + offset + 1, tag->data, tag->len))
+            return PR_TRUE;
+        offset += 1 + taglen;
+    }
+
+    return PR_FALSE;
+}
+
 /* Called from ssl3_HandleClientHello after we have parsed the
  * ClientHello and are sure that we are going to do TLS 1.3
  * or fail. */
 SECStatus
 tls13_HandleClientHelloPart2(sslSocket *ss,
                              const SECItem *suites,
                              sslSessionID *sid)
 {
     SECStatus rv;
     SSL3Statistics *ssl3stats = SSL_GetStatistics();
     int j;
 
-    rv = tls13_SetupNullCipherSpec(ss);
-    if (rv != SECSuccess) {
-        FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
-        return SECFailure;
-    }
     if (sid != NULL && !tls13_CanResume(ss, sid)) {
         /* Destroy SID if it is present an unusable. */
         SSL_AtomicIncrementLong(&ssl3stats->hch_sid_cache_not_ok);
         if (ss->sec.uncache)
             ss->sec.uncache(sid);
         ssl_FreeSID(sid);
         sid = NULL;
         ss->statelessResume = PR_FALSE;
     }
 
 #ifndef PARANOID
     /* Look for a matching cipher suite. */
     j = ssl3_config_match_init(ss);
     if (j <= 0) { /* no ciphers are working/supported by PK11 */
         FATAL_ERROR(ss, PORT_GetError(), internal_error);
-        goto loser;
+        return SECFailure;
     }
 #endif
 
     rv = ssl3_NegotiateCipherSuite(ss, suites);
     if (rv != SECSuccess) {
         FATAL_ERROR(ss, SSL_ERROR_NO_CYPHER_OVERLAP, handshake_failure);
-        goto loser;
+        return SECFailure;
     }
 
     if (ss->ssl3.hs.kea_def->authKeyType != ssl_auth_psk) {
         /* TODO(ekr@rtfm.com): Free resumeSID. */
         ss->statelessResume = PR_FALSE;
     }
 
     if (ss->statelessResume) {
         PORT_Assert(sid);
 
         rv = tls13_RecoverWrappedSharedSecret(ss, sid);
         if (rv != SECSuccess) {
             FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
-            goto loser;
+            return SECFailure;
         }
 
         SSL_AtomicIncrementLong(&ssl3stats->hch_sid_cache_hits);
         SSL_AtomicIncrementLong(&ssl3stats->hch_sid_stateless_resumes);
 
         tls13_RestoreCipherInfo(ss, sid);
 
         ss->sec.serverCert = ssl_FindServerCert(ss, &sid->certType);
         PORT_Assert(ss->sec.serverCert);
         ss->sec.localCert = CERT_DupCertificate(ss->sec.serverCert->serverCert);
         if (sid->peerCert != NULL) {
             ss->sec.peerCert = CERT_DupCertificate(sid->peerCert);
         }
         ssl3_RegisterServerHelloExtensionSender(
             ss, ssl_tls13_pre_shared_key_xtn, tls13_ServerSendPreSharedKeyXtn);
         ss->sec.ci.sid = sid;
+        ss->ssl3.hs.doing0Rtt = tls13_ServerAllow0Rtt(ss, sid);
     } else {
         if (sid) { /* we had a sid, but it's no longer valid, free it */
             SSL_AtomicIncrementLong(&ssl3stats->hch_sid_cache_not_ok);
             if (ss->sec.uncache)
                 ss->sec.uncache(sid);
             ssl_FreeSID(sid);
             sid = NULL;
         }
         ss->ssl3.hs.origCipherSuite = ss->ssl3.hs.cipher_suite;
         SSL_AtomicIncrementLong(&ssl3stats->hch_sid_cache_misses);
     }
 
-    /* This call needs to happen before the SNI callback because
-     * it sets up |pwSpec| to point to the right place. */
-    rv = tls13_SetupPendingCipherSpec(ss);
+    rv = tls13_ComputeEarlySecrets(ss, ss->ssl3.hs.doing0Rtt);
     if (rv != SECSuccess) {
-        FATAL_ERROR(ss, PORT_GetError(), internal_error);
-        goto loser;
+        FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+        return SECFailure;
     }
 
     rv = ssl3_ServerCallSNICallback(ss);
     if (rv != SECSuccess) {
-        goto loser; /* An alert has already been sent. */
+        return SECFailure; /* An alert has already been sent. */
     }
 
     if (sid) {
         /* Check that the negotiated SID and the cached SID match. */
         if (SECITEM_CompareItem(&sid->u.ssl3.srvName,
-                                &ss->ssl3.pwSpec->srvVirtName) !=
-            SECEqual) {
+                                &ss->ssl3.hs.srvVirtName) != SECEqual) {
             FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO,
                         handshake_failure);
-            goto loser;
+            return SECFailure;
         }
     }
 
     if (!ss->statelessResume) {
         rv = ssl3_SelectServerCert(ss);
         if (rv != SECSuccess) {
-            goto loser;
+            return SECFailure;
         }
     }
 
     /* If this is TLS 1.3 we are expecting a ClientKeyShare
      * extension. Missing/absent extension cause failure
      * below. */
     rv = tls13_HandleClientKeyShare(ss);
     if (rv != SECSuccess) {
-        goto loser; /* An alert was sent already. */
+        return SECFailure; /* An alert was sent already. */
     }
 
     if (!sid) {
         sid = ssl3_NewSessionID(ss, PR_TRUE);
         if (sid == NULL) {
             FATAL_ERROR(ss, PORT_GetError(), internal_error);
-            goto loser;
+            return SECFailure;
         }
         ss->sec.ci.sid = sid;
     }
 
-    ssl_GetXmitBufLock(ss);
-    rv = tls13_SendServerHelloSequence(ss);
-    ssl_ReleaseXmitBufLock(ss);
-    if (rv != SECSuccess) {
-        FATAL_ERROR(ss, PORT_GetError(), handshake_failure);
-        goto loser;
+    if (ss->ssl3.hs.doing0Rtt) {
+        /* Store the handshake hash. We'll want it later. */
+        ss->ssl3.hs.clientHelloHash = PK11_CloneContext(ss->ssl3.hs.sha);
+        if (!ss->ssl3.hs.clientHelloHash) {
+            FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+            return SECFailure;
+        }
+
+        rv = tls13_SetCipherSpec(ss, TrafficKeyEarlyHandshake,
+                                 CipherSpecRead, PR_FALSE);
+        if (rv != SECSuccess) {
+            FATAL_ERROR(ss, PORT_GetError(), handshake_failure);
+            return SECFailure;
+        }
+        TLS13_SET_HS_STATE(ss, wait_encrypted_extensions);
+    } else {
+        ssl_GetXmitBufLock(ss);
+        rv = tls13_SendServerHelloSequence(ss);
+        ssl_ReleaseXmitBufLock(ss);
+        if (rv != SECSuccess) {
+            FATAL_ERROR(ss, PORT_GetError(), handshake_failure);
+            return SECFailure;
+        }
     }
 
     return SECSuccess;
-
-loser:
-    return SECFailure;
 }
 
 /* Called from tls13_HandleClientHello.
  *
  * Caller must hold Handshake and RecvBuf locks.
  */
 SECStatus
 tls13_HandleClientKeyShare(sslSocket *ss)
@@ -1006,74 +1329,64 @@ tls13_HandleCertificateRequest(sslSocket
     TLS13_SET_HS_STATE(ss, wait_server_cert);
 
     rv = ssl3_CompleteHandleCertificateRequest(ss, &algorithms, &ca_list);
     if (rv != SECSuccess) {
         FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
         goto loser;
     }
 
+    PORT_FreeArena(arena, PR_FALSE);
     return SECSuccess;
 
 loser:
     PORT_FreeArena(arena, PR_FALSE);
     return SECFailure;
 }
 
-static SECStatus
-tls13_InitializeHandshakeEncryption(sslSocket *ss)
-{
-    SECStatus rv;
-
-    PORT_Assert(!!ss->ssl3.hs.xSS ==
-                (ss->ssl3.hs.kea_def->authKeyType == ssl_auth_psk));
-    if (!ss->ssl3.hs.xSS) {
-        ss->ssl3.hs.xSS = PK11_ReferenceSymKey(ss->ssl3.hs.xES);
-        if (!ss->ssl3.hs.xSS) {
-            FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
-            return SECFailure;
-        }
-    }
-
-    /* Here we destroy the old cipher spec immediately; in DTLS, we have to
-     * avoid running the holddown timer at this point. Retransmission of old
-     * packets will use the static nullCipherSpec spec. */
-    rv = tls13_InitCipherSpec(ss, TrafficKeyHandshake,
-                              InstallCipherSpecBoth);
-    if (rv != SECSuccess) {
-        FATAL_ERROR(ss, SSL_ERROR_INIT_CIPHER_SUITE_FAILURE, internal_error);
-        return SECFailure;
-    }
-
-    return rv;
-}
-
 /* Called from:  ssl3_HandleClientHello */
 SECStatus
 tls13_SendServerHelloSequence(sslSocket *ss)
 {
     SECStatus rv;
     SECKEYPrivateKey *svrPrivKey;
 
     SSL_TRC(3, ("%d: TLS13[%d]: begin send server_hello sequence",
                 SSL_GETPID(), ss->fd));
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
 
+    if (ss->ssl3.hs.doing0Rtt) {
+        /* TODO(ekr@rtfm.com): Send this in EncryptedExtensions. The spec is
+         * wrong in draft-13. Bug 1281249. */
+        rv = ssl3_RegisterServerHelloExtensionSender(ss, ssl_tls13_early_data_xtn,
+                                                     tls13_ServerSendEarlyDataXtn);
+        if (rv != SECSuccess) {
+            return SECFailure; /* Error code set already. */
+        }
+    }
+
     rv = ssl3_SendServerHello(ss);
     if (rv != SECSuccess) {
         return rv; /* err code is set. */
     }
 
-    rv = tls13_InitializeHandshakeEncryption(ss);
+    rv = tls13_ComputeHandshakeSecrets(ss);
     if (rv != SECSuccess) {
         return SECFailure; /* error code is set. */
     }
 
+    rv = tls13_SetCipherSpec(ss, TrafficKeyHandshake,
+                             CipherSpecWrite, PR_FALSE);
+    if (rv != SECSuccess) {
+        FATAL_ERROR(ss, PORT_GetError(), internal_error);
+        return SECFailure;
+    }
+
     rv = tls13_SendEncryptedExtensions(ss);
     if (rv != SECSuccess) {
         return SECFailure; /* error code is set. */
     }
 
     if (ss->opt.requestCertificate) {
         rv = tls13_SendCertificateRequest(ss);
         if (rv != SECSuccess) {
@@ -1086,75 +1399,113 @@ tls13_SendServerHelloSequence(sslSocket 
             return SECFailure; /* error code is set. */
         }
         rv = ssl3_SendCertificateStatus(ss);
         if (rv != SECSuccess) {
             return SECFailure; /* error code is set. */
         }
 
         svrPrivKey = ss->sec.serverCert->serverKeyPair->privKey;
-        rv = ssl3_SendCertificateVerify(ss, svrPrivKey);
+        rv = tls13_SendCertificateVerify(ss, svrPrivKey);
         if (rv != SECSuccess) {
-            return rv; /* err code is set. */
+            return SECFailure; /* err code is set. */
         }
     }
 
+    rv = tls13_SendFinished(ss, ss->ssl3.hs.hsTrafficSecret);
+    if (rv != SECSuccess) {
+        return SECFailure; /* error code is set. */
+    }
+
     /* Compute the rest of the secrets except for the resumption
      * and exporter secret. */
-    rv = tls13_ComputeSecrets1(ss);
+    rv = tls13_ComputeApplicationSecrets(ss);
+    if (rv != SECSuccess) {
+        FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
+        return SECFailure;
+    }
+
+    rv = tls13_SetCipherSpec(ss, TrafficKeyApplicationData,
+                             CipherSpecWrite, PR_FALSE);
     if (rv != SECSuccess) {
         FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
         return SECFailure;
     }
 
-    rv = tls13_SendFinished(ss);
-    if (rv != SECSuccess) {