Bug 1345368 - land NSS 0c3800b6eaba UPGRADE_NSS_RELEASE, r=me
☠☠ backed out by 4f874bc1e424 ☠ ☠
authorFranziskus Kiefer <franziskuskiefer@gmail.com>
Tue, 23 May 2017 12:36:33 +0200
changeset 360084 bf6ee973f04e83f419c12f93e4f194e26b0bbf47
parent 360083 9cc0b3e19072d6bd87e9823e9c98c64950333b25
child 360085 4f874bc1e42463e30bc5595e84e5aaa450d81167
push id31867
push userryanvm@gmail.com
push dateTue, 23 May 2017 14:09:01 +0000
treeherdermozilla-central@4f874bc1e424 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersme
bugs1345368
milestone55.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 1345368 - land NSS 0c3800b6eaba UPGRADE_NSS_RELEASE, r=me
security/nss/TAG-INFO
security/nss/automation/abi-check/expected-report-libfreebl3.so.txt
security/nss/automation/abi-check/expected-report-libfreeblpriv3.so.txt
security/nss/automation/abi-check/expected-report-libnspr4.so.txt
security/nss/automation/abi-check/expected-report-libnss3.so.txt
security/nss/automation/abi-check/expected-report-libnssckbi.so.txt
security/nss/automation/abi-check/expected-report-libnssdbm3.so.txt
security/nss/automation/abi-check/expected-report-libnsssysinit.so.txt
security/nss/automation/abi-check/expected-report-libnssutil3.so.txt
security/nss/automation/abi-check/expected-report-libplc4.so.txt
security/nss/automation/abi-check/expected-report-libplds4.so.txt
security/nss/automation/abi-check/expected-report-libsmime3.so.txt
security/nss/automation/abi-check/expected-report-libsoftokn3.so.txt
security/nss/automation/abi-check/expected-report-libssl3.so.txt
security/nss/automation/abi-check/previous-nspr-release
security/nss/automation/abi-check/previous-nss-release
security/nss/automation/buildbot-slave/build.sh
security/nss/automation/release/nspr-version.txt
security/nss/automation/release/nss-release-helper.py
security/nss/automation/taskcluster/docker-fuzz/setup.sh
security/nss/automation/taskcluster/graph/src/extend.js
security/nss/automation/taskcluster/graph/src/try_syntax.js
security/nss/cmd/crmftest/testcrmf.c
security/nss/cmd/mpitests/mpitests.gyp
security/nss/coreconf/coreconf.dep
security/nss/coreconf/fuzz.sh
security/nss/fuzz/fuzz.gyp
security/nss/gtests/freebl_gtest/freebl_gtest.gyp
security/nss/gtests/freebl_gtest/mpi_unittest.cc
security/nss/gtests/util_gtest/util_pkcs11uri_unittest.cc
security/nss/lib/freebl/mpi/mpi.c
security/nss/lib/pk11wrap/pk11cert.c
security/nss/lib/ssl/ssl3con.c
security/nss/lib/ssl/ssl3ecc.c
security/nss/lib/ssl/ssl3exthandle.c
security/nss/lib/ssl/ssl3prot.h
security/nss/lib/ssl/sslimpl.h
security/nss/lib/ssl/sslsnce.c
security/nss/lib/util/pkcs11uri.c
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-57e38a8407b3
+0c3800b6eaba
new file mode 100644
new file mode 100644
new file mode 100644
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/abi-check/expected-report-libnss3.so.txt
@@ -0,0 +1,12 @@
+Functions changes summary: 0 Removed, 0 Changed, 6 Added functions
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+6 Added functions:
+
+  'function SECStatus CERT_GetCertIsPerm(const CERTCertificate*, PRBool*)'    {CERT_GetCertIsPerm@@NSS_3.31}
+  'function SECStatus CERT_GetCertIsTemp(const CERTCertificate*, PRBool*)'    {CERT_GetCertIsTemp@@NSS_3.31}
+  'function CERTCertificate* PK11_FindCertFromURI(const char*, void*)'    {PK11_FindCertFromURI@@NSS_3.31}
+  'function CERTCertList* PK11_FindCertsFromURI(const char*, void*)'    {PK11_FindCertsFromURI@@NSS_3.31}
+  'function char* PK11_GetModuleURI(SECMODModule*)'    {PK11_GetModuleURI@@NSS_3.31}
+  'function char* PK11_GetTokenURI()'    {PK11_GetTokenURI@@NSS_3.31}
+
new file mode 100644
new file mode 100644
new file mode 100644
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/abi-check/expected-report-libnssutil3.so.txt
@@ -0,0 +1,12 @@
+Functions changes summary: 0 Removed, 0 Changed, 6 Added functions
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+6 Added functions:
+
+  'function void PK11URI_CreateURI(size_t, size_t)'    {PK11URI_CreateURI@@NSSUTIL_3.31}
+  'function void PK11URI_DestroyURI()'    {PK11URI_DestroyURI@@NSSUTIL_3.31}
+  'function char* PK11URI_FormatURI()'    {PK11URI_FormatURI@@NSSUTIL_3.31}
+  'function const char* PK11URI_GetPathAttribute(const char*)'    {PK11URI_GetPathAttribute@@NSSUTIL_3.31}
+  'function const char* PK11URI_GetQueryAttribute(const char*)'    {PK11URI_GetQueryAttribute@@NSSUTIL_3.31}
+  'function void PK11URI_ParseURI(const char*)'    {PK11URI_ParseURI@@NSSUTIL_3.31}
+
new file mode 100644
new file mode 100644
new file mode 100644
new file mode 100644
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/abi-check/expected-report-libssl3.so.txt
@@ -0,0 +1,14 @@
+Functions changes summary: 0 Removed, 1 Changed, 0 Added function
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+1 function with some indirect sub-type change:
+
+  [C]'function SECStatus SSL_GetPreliminaryChannelInfo(SSLPreliminaryChannelInfo*, PRUintn)' at sslinfo.c:115:1 has some indirect sub-type changes:
+    parameter 1 of type 'SSLPreliminaryChannelInfo*' has sub-type changes:
+      in pointed to type 'typedef SSLPreliminaryChannelInfo' at sslt.h:318:1:
+        underlying type 'struct SSLPreliminaryChannelInfoStr' at sslt.h:287:1 changed:
+          type size changed from 128 to 160 bits
+          1 data member insertion:
+            'PRUint32 SSLPreliminaryChannelInfoStr::maxEarlyDataSize', at offset 128 (in bits) at sslt.h:314:1
+
+
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/abi-check/previous-nspr-release
@@ -0,0 +1,1 @@
+NSPR_4_14_BRANCH
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/abi-check/previous-nss-release
@@ -0,0 +1,1 @@
+NSS_3_30_BRANCH
--- a/security/nss/automation/buildbot-slave/build.sh
+++ b/security/nss/automation/buildbot-slave/build.sh
@@ -14,16 +14,19 @@ proc_args()
 
         case $OPT in
             "--build-nss")
                 BUILD_NSS=1
                 ;;
             "--test-nss")
                 TEST_NSS=1
                 ;;
+            "--check-abi")
+                CHECK_ABI=1
+                ;;
             "--build-jss")
                 BUILD_JSS=1
                 ;;
             "--test-jss")
                 TEST_JSS=1
                 ;;
             "--memtest")
                 NSS_TESTS="memleak"
@@ -35,16 +38,17 @@ proc_args()
             *)
                 echo "Usage: $0 ..."
                 echo "    --memtest   - run the memory leak tests"
                 echo "    --nojsssign - try to sign jss"
                 echo "    --build-nss"
                 echo "    --build-jss"
                 echo "    --test-nss"
                 echo "    --test-jss"
+                echo "    --check-abi"
                 exit 1
                 ;;
         esac 
 
         shift
     done
 }
 
@@ -210,16 +214,81 @@ test_nss()
     print_log "######## details of detected failures (if any) ########"
     grep -B50 FAILED ${OUTPUTFILE}
     [ $? -eq 1 ] || RET=1
 
     print_result "NSS - tests - ${BITS} bits - ${OPT}" ${RET} 0
     return ${RET}
 }
 
+check_abi()
+{
+    print_log "######## NSS ABI CHECK - ${BITS} bits - ${OPT} ########"
+    rm -rf ${HGDIR}/baseline
+    mkdir ${HGDIR}/baseline
+    BASE_NSPR=`cat ${HGDIR}/nss/automation/abi-check/previous-nspr-release`
+    BASE_NSS=`cat ${HGDIR}/nss/automation/abi-check/previous-nss-release`
+
+    print_log "######## creating temporary HG clones ########"
+
+    hg clone -u "${BASE_NSPR}" "${HGDIR}/nspr" "${HGDIR}/baseline/nspr"
+    if [ $? -ne 0 ]; then
+        echo "invalid tag in automation/abi-check/previous-nspr-release"
+        return 1
+    fi
+    hg clone -u "${BASE_NSS}" "${HGDIR}/nss" "${HGDIR}/baseline/nss"
+    if [ $? -ne 0 ]; then
+        echo "invalid tag in automation/abi-check/previous-nss-release"
+        return 1
+    fi
+
+    print_log "######## building older NSPR/NSS ########"
+
+    print_log "$ pushd ${HGDIR}/baseline/nss"
+    pushd ${HGDIR}/baseline/nss
+
+    print_log "$ ${MAKE} ${NSS_BUILD_TARGET}"
+    #${MAKE} ${NSS_BUILD_TARGET} 2>&1 | tee -a ${LOG_ALL} | grep ${GREP_BUFFER} "^${MAKE}"
+    ${MAKE} ${NSS_BUILD_TARGET} 2>&1 | tee -a ${LOG_ALL}
+    RET=$?
+    print_result "NSS - build - ${BITS} bits - ${OPT}" ${RET} 0
+
+    if [ ${RET} -ne 0 ]; then
+        tail -100 ${LOG_ALL}
+        return ${RET}
+    fi
+
+    print_log "$ popd"
+    popd
+
+    ABI_REPORT=${OUTPUTDIR}/abi-diff.txt
+    rm -f ${ABI_REPORT}
+    PREVDIST=${HGDIR}/baseline/dist
+    NEWDIST=${HGDIR}/dist
+    ALL_SOs="libfreebl3.so libfreeblpriv3.so libnspr4.so libnss3.so libnssckbi.so libnssdbm3.so libnsssysinit.so libnssutil3.so libplc4.so libplds4.so libsmime3.so libsoftokn3.so libssl3.so"
+    for SO in ${ALL_SOs}; do
+        if [ ! -f nss/automation/abi-check/expected-report-$SO.txt ]; then
+            touch nss/automation/abi-check/expected-report-$SO.txt
+        fi
+        abidiff --hd1 $PREVDIST/public/ --hd2 $NEWDIST/public \
+            $PREVDIST/*/lib/$SO $NEWDIST/*/lib/$SO \
+            > nss/automation/abi-check/new-report-$SO.txt
+        diff -u nss/automation/abi-check/expected-report-$SO.txt \
+                nss/automation/abi-check/new-report-$SO.txt >> ${ABI_REPORT}
+    done
+
+    if [ -s ${ABI_REPORT} ]; then
+        print_log "FAILED: there are new unexpected ABI changes"
+        cat ${ABI_REPORT}
+        return 1
+    fi
+
+    return 0
+}
+
 test_jss()
 {
     print_log "######## JSS - tests - ${BITS} bits - ${OPT} ########"
 
     print_log "$ cd ${HGDIR}/jss"
     cd ${HGDIR}/jss
 
     print_log "$ ${MAKE} platform"
@@ -283,16 +352,21 @@ build_and_test()
         [ $? -eq 0 ] || return 1
     fi
 
     if [ -n "${TEST_NSS}" ]; then
         test_nss
         [ $? -eq 0 ] || return 1
     fi
 
+    if [ -n "${CHECK_ABI}" ]; then
+        check_abi
+        [ $? -eq 0 ] || return 1
+    fi
+
     if [ -n "${BUILD_JSS}" ]; then
         create_objdir_dist_link
         build_jss
         [ $? -eq 0 ] || return 1
     fi
 
     if [ -n "${TEST_JSS}" ]; then
         test_jss
@@ -355,38 +429,42 @@ run_all()
     move_results
     return ${RESULT}
 }
 
 main()
 {
     VALID=0
     RET=1
+    FAIL=0
 
     for BITS in 32 64; do
         echo ${RUN_BITS} | grep ${BITS} > /dev/null
         [ $? -eq 0 ] || continue
         for OPT in DBG OPT; do
             echo ${RUN_OPT} | grep ${OPT} > /dev/null
             [ $? -eq 0 ] || continue
 
             VALID=1
             set_env
             run_all
             RET=$?
-	    print_log "### result of run_all is ${RET}"
+            print_log "### result of run_all is ${RET}"
+            if [ ${RET} -ne 0 ]; then
+                FAIL=${RET}
+            fi
         done
     done
 
     if [ ${VALID} -ne 1 ]; then
         echo "Need to set valid bits/opt values."
         return 1
     fi
 
-    return ${RET}
+    return ${FAIL}
 }
 
 #function killallsub()
 #{
 #    FINAL_RET=$?
 #    for proc in `jobs -p`
 #    do
 #        kill -9 $proc
@@ -404,11 +482,13 @@ main()
 
 #touch $IS_RUNNING_FILE
 
 echo "tinderbox args: $0 $@"
 . ${ENVVARS}
 proc_args "$@"
 main
 
-#RET=$?
+RET=$?
+print_log "### result of main is ${RET}"
+
 #rm $IS_RUNNING_FILE
-#exit ${RET}
+exit ${RET}
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/release/nspr-version.txt
@@ -0,0 +1,10 @@
+4.15
+
+# The first line of this file must contain the human readable NSPR
+# version number, which is the minimum required version of NSPR
+# that is supported by this version of NSS.
+#
+# This information is used by release automation,
+# when creating an NSS source archive.
+#
+# All other lines in this file are ignored.
--- a/security/nss/automation/release/nss-release-helper.py
+++ b/security/nss/automation/release/nss-release-helper.py
@@ -166,21 +166,23 @@ def set_4_digit_release_number():
     major = args[1].strip()
     minor = args[2].strip()
     patch = args[3].strip()
     build = args[4].strip()
     version = major + '.' + minor + '.' + patch + '.' + build
     set_all_lib_versions(version, major, minor, patch, build)
 
 def create_nss_release_archive():
-    ensure_arguments_after_action(4, "nss_release_version  nss_hg_release_tag  nspr_release_version  path_to_stage_directory")
+    ensure_arguments_after_action(3, "nss_release_version  nss_hg_release_tag  path_to_stage_directory")
     nssrel = args[1].strip() #e.g. 3.19.3
     nssreltag = args[2].strip() #e.g. NSS_3_19_3_RTM
-    nsprrel = args[3].strip() #e.g. 4.10.8
-    stagedir = args[4].strip() #e.g. ../stage
+    stagedir = args[3].strip() #e.g. ../stage
+
+    with open('automation/release/nspr-version.txt') as nspr_version_file:
+        nsprrel = next(nspr_version_file).strip()
 
     nspr_tar = "nspr-" + nsprrel + ".tar.gz"
     nsprtar_with_path= stagedir + "/v" + nsprrel + "/src/" + nspr_tar
     if (not os.path.exists(nsprtar_with_path)):
         exit_with_failure("cannot find nspr archive at expected location " + nsprtar_with_path)
 
     nss_stagedir= stagedir + "/" + nssreltag + "/src"
     if (os.path.exists(nss_stagedir)):
--- a/security/nss/automation/taskcluster/docker-fuzz/setup.sh
+++ b/security/nss/automation/taskcluster/docker-fuzz/setup.sh
@@ -17,25 +17,34 @@ apt_packages+=('git')
 apt_packages+=('gyp')
 apt_packages+=('libssl-dev')
 apt_packages+=('libxml2-utils')
 apt_packages+=('locales')
 apt_packages+=('ninja-build')
 apt_packages+=('pkg-config')
 apt_packages+=('zlib1g-dev')
 
+# 32-bit builds
+apt_packages+=('gcc-multilib')
+apt_packages+=('g++-multilib')
+
 # Latest Mercurial.
 apt_packages+=('mercurial')
 apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 41BD8711B1F0EC2B0D85B91CF59CE3A8323293EE
 echo "deb http://ppa.launchpad.net/mercurial-ppa/releases/ubuntu xenial main" > /etc/apt/sources.list.d/mercurial.list
 
 # Install packages.
 apt-get -y update
 apt-get install -y --no-install-recommends ${apt_packages[@]}
 
+# 32-bit builds
+dpkg --add-architecture i386
+apt-get -y update
+apt-get install -y --no-install-recommends libssl-dev:i386
+
 # Install LLVM/clang-4.0.
 mkdir clang-tmp
 git clone -n --depth 1 https://chromium.googlesource.com/chromium/src/tools/clang clang-tmp/clang
 git -C clang-tmp/clang checkout HEAD scripts/update.py
 clang-tmp/clang/scripts/update.py
 rm -fr clang-tmp
 
 locale-gen en_US.UTF-8
--- a/security/nss/automation/taskcluster/graph/src/extend.js
+++ b/security/nss/automation/taskcluster/graph/src/extend.js
@@ -58,21 +58,16 @@ queue.filter(task => {
     return false;
   }
 
   if (task.group == "Test") {
     // Don't run test builds on old make platforms
     if (task.collection == "make") {
       return false;
     }
-
-    // Disable mpi tests for now on 32-bit builds (bug 1362392)
-    if (task.platform == "linux32") {
-      return false;
-    }
   }
 
 
   // Don't run additional hardware tests on ARM (we don't have anything there).
   if (task.group == "Cipher" && task.platform == "aarch64" && task.env &&
       (task.env.NSS_DISABLE_PCLMUL == "1" || task.env.NSS_DISABLE_HW_AES == "1"
        || task.env.NSS_DISABLE_AVX == "1")) {
     return false;
@@ -163,16 +158,17 @@ export default async function main() {
     env: {BUILD_OPT: "1"}
   });
 
   await scheduleWindows("Windows 2012 64 (debug)", {
     collection: "debug"
   });
 
   await scheduleFuzzing();
+  await scheduleFuzzing32();
 
   await scheduleTools();
 
   let aarch64_base = {
     image: "franziskus/nss-aarch64-ci",
     provisioner: "localprovisioner",
     workerType: "nss-aarch64",
     platform: "aarch64",
@@ -410,16 +406,120 @@ async function scheduleFuzzing() {
   scheduleFuzzingRun(tls_fm_base, "TLS Client", "tls-client", 20000, "client");
   scheduleFuzzingRun(tls_fm_base, "TLS Server", "tls-server", 20000, "server");
   scheduleFuzzingRun(tls_fm_base, "DTLS Client", "dtls-client", 20000, "dtls-client");
   scheduleFuzzingRun(tls_fm_base, "DTLS Server", "dtls-server", 20000, "dtls-server");
 
   return queue.submit();
 }
 
+async function scheduleFuzzing32() {
+  let base = {
+    env: {
+      ASAN_OPTIONS: "allocator_may_return_null=1:detect_stack_use_after_return=1",
+      UBSAN_OPTIONS: "print_stacktrace=1",
+      NSS_DISABLE_ARENA_FREE_LIST: "1",
+      NSS_DISABLE_UNLOAD: "1",
+      CC: "clang",
+      CCC: "clang++"
+    },
+    features: ["allowPtrace"],
+    platform: "linux32",
+    collection: "fuzz",
+    image: FUZZ_IMAGE
+  };
+
+  // Build base definition.
+  let build_base = merge({
+    command: [
+      "/bin/bash",
+      "-c",
+      "bin/checkout.sh && " +
+      "nss/automation/taskcluster/scripts/build_gyp.sh -g -v --fuzz -m32"
+    ],
+    artifacts: {
+      public: {
+        expires: 24 * 7,
+        type: "directory",
+        path: "/home/worker/artifacts"
+      }
+    },
+    kind: "build",
+    symbol: "B"
+  }, base);
+
+  // The task that builds NSPR+NSS.
+  let task_build = queue.scheduleTask(merge(build_base, {
+    name: "Linux 32 (debug, fuzz)"
+  }));
+
+  // The task that builds NSPR+NSS (TLS fuzzing mode).
+  let task_build_tls = queue.scheduleTask(merge(build_base, {
+    name: "Linux 32 (debug, TLS fuzz)",
+    symbol: "B",
+    group: "TLS",
+    command: [
+      "/bin/bash",
+      "-c",
+      "bin/checkout.sh && " +
+      "nss/automation/taskcluster/scripts/build_gyp.sh -g -v --fuzz=tls -m32"
+    ],
+  }));
+
+  // Schedule tests.
+  queue.scheduleTask(merge(base, {
+    parent: task_build_tls,
+    name: "Gtests",
+    command: [
+      "/bin/bash",
+      "-c",
+      "bin/checkout.sh && nss/automation/taskcluster/scripts/run_tests.sh"
+    ],
+    env: {GTESTFILTER: "*Fuzz*"},
+    tests: "ssl_gtests gtests",
+    cycle: "standard",
+    symbol: "Gtest",
+    kind: "test"
+  }));
+
+  // Schedule fuzzing runs.
+  let run_base = merge(base, {parent: task_build, kind: "test"});
+  scheduleFuzzingRun(run_base, "CertDN", "certDN", 4096);
+  scheduleFuzzingRun(run_base, "QuickDER", "quickder", 10000);
+
+  // Schedule MPI fuzzing runs.
+  let mpi_base = merge(run_base, {group: "MPI"});
+  let mpi_names = ["add", "addmod", "div", "expmod", "mod", "mulmod", "sqr",
+                   "sqrmod", "sub", "submod"];
+  for (let name of mpi_names) {
+    scheduleFuzzingRun(mpi_base, `MPI (${name})`, `mpi-${name}`, 4096, name);
+  }
+  scheduleFuzzingRun(mpi_base, `MPI (invmod)`, `mpi-invmod`, 256, "invmod");
+
+  // Schedule TLS fuzzing runs (non-fuzzing mode).
+  let tls_base = merge(run_base, {group: "TLS"});
+  scheduleFuzzingRun(tls_base, "TLS Client", "tls-client", 20000, "client-nfm",
+                     "tls-client-no_fuzzer_mode");
+  scheduleFuzzingRun(tls_base, "TLS Server", "tls-server", 20000, "server-nfm",
+                     "tls-server-no_fuzzer_mode");
+  scheduleFuzzingRun(tls_base, "DTLS Client", "dtls-client", 20000,
+                     "dtls-client-nfm", "dtls-client-no_fuzzer_mode");
+  scheduleFuzzingRun(tls_base, "DTLS Server", "dtls-server", 20000,
+                     "dtls-server-nfm", "dtls-server-no_fuzzer_mode");
+
+  // Schedule TLS fuzzing runs (fuzzing mode).
+  let tls_fm_base = merge(tls_base, {parent: task_build_tls});
+  scheduleFuzzingRun(tls_fm_base, "TLS Client", "tls-client", 20000, "client");
+  scheduleFuzzingRun(tls_fm_base, "TLS Server", "tls-server", 20000, "server");
+  scheduleFuzzingRun(tls_fm_base, "DTLS Client", "dtls-client", 20000, "dtls-client");
+  scheduleFuzzingRun(tls_fm_base, "DTLS Server", "dtls-server", 20000, "dtls-server");
+
+  return queue.submit();
+}
+
 /*****************************************************************************/
 
 async function scheduleTestBuilds(base, args = "") {
   // Build base definition.
   let build = merge({
     command: [
       "/bin/bash",
       "-c",
--- a/security/nss/automation/taskcluster/graph/src/try_syntax.js
+++ b/security/nss/automation/taskcluster/graph/src/try_syntax.js
@@ -18,17 +18,17 @@ function parseOptions(opts) {
 
   // If the given value is nonsense default to debug and opt builds.
   if (builds.length == 0) {
     builds = ["d", "o"];
   }
 
   // Parse platforms.
   let allPlatforms = ["linux", "linux64", "linux64-asan", "win64",
-                      "linux64-make", "linux-make", "linux64-fuzz", "aarch64"];
+                      "linux64-make", "linux-make", "linux-fuzz", "linux64-fuzz", "aarch64"];
   let platforms = intersect(opts.platform.split(/\s*,\s*/), allPlatforms);
 
   // If the given value is nonsense or "none" default to all platforms.
   if (platforms.length == 0 && opts.platform != "none") {
     platforms = allPlatforms;
   }
 
   // Parse unit tests.
@@ -99,32 +99,33 @@ function filter(opts) {
     }
 
     let coll = name => name == (task.collection || "opt");
 
     // Filter by platform.
     let found = opts.platforms.some(platform => {
       let aliases = {
         "linux": "linux32",
+        "linux-fuzz": "linux32",
         "linux64-asan": "linux64",
         "linux64-fuzz": "linux64",
         "linux64-make": "linux64",
         "linux-make": "linux32",
         "win64": "windows2012-64"
       };
 
       // Check the platform name.
       let keep = (task.platform == (aliases[platform] || platform));
 
       // Additional checks.
       if (platform == "linux64-asan") {
         keep &= coll("asan");
       } else if (platform == "linux64-make" || platform == "linux-make") {
         keep &= coll("make");
-      } else if (platform == "linux64-fuzz") {
+      } else if (platform == "linux64-fuzz" || platform == "linux-fuzz") {
         keep &= coll("fuzz");
       } else {
         keep &= coll("opt") || coll("debug");
       }
 
       return keep;
     });
 
--- a/security/nss/cmd/crmftest/testcrmf.c
+++ b/security/nss/cmd/crmftest/testcrmf.c
@@ -1256,21 +1256,23 @@ DoChallengeResponse(SECKEYPrivateKey *pr
     for (i = 0; i < numChallengesSet; i++) {
         publicValue = CMMF_POPODecKeyChallContentGetPublicValue(chalContent, i);
         if (publicValue == NULL) {
             printf("Could not get the public value for challenge at index %d\n",
                    i);
             return 908;
         }
         keyID = PK11_MakeIDFromPubKey(publicValue);
+        SECITEM_FreeItem(publicValue, PR_TRUE);
         if (keyID == NULL) {
             printf("Could not make the keyID from the public value\n");
             return 909;
         }
         foundPrivKey = PK11_FindKeyByKeyID(privKey->pkcs11Slot, keyID, &pwdata);
+        SECITEM_FreeItem(keyID, PR_TRUE);
         if (foundPrivKey == NULL) {
             printf("Could not find the private key corresponding to the public"
                    " value.\n");
             return 910;
         }
         rv = CMMF_POPODecKeyChallContDecryptChallenge(chalContent, i,
                                                       foundPrivKey);
         if (rv != SECSuccess) {
--- a/security/nss/cmd/mpitests/mpitests.gyp
+++ b/security/nss/cmd/mpitests/mpitests.gyp
@@ -26,14 +26,25 @@
         '<(DEPTH)/lib/pki/pki.gyp:nsspki',
       ]
     }
   ],
   'target_defaults': {
     'include_dirs': [
       '<(DEPTH)/lib/freebl/mpi',
       '<(DEPTH)/lib/util',
-    ]
+    ],
+    # This uses test builds and has to set defines for MPI.
+    'conditions': [
+      [ 'target_arch=="ia32"', {
+        'defines': [
+          'MP_USE_UINT_DIGIT',
+          'MP_ASSEMBLY_MULTIPLY',
+          'MP_ASSEMBLY_SQUARE',
+          'MP_ASSEMBLY_DIV_2DX1D',
+        ],
+      }],
+    ],
   },
   'variables': {
     'module': 'nss'
   }
 }
--- a/security/nss/coreconf/coreconf.dep
+++ b/security/nss/coreconf/coreconf.dep
@@ -5,9 +5,8 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSS in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
-
--- a/security/nss/coreconf/fuzz.sh
+++ b/security/nss/coreconf/fuzz.sh
@@ -19,17 +19,20 @@ gyp_params+=(-Dtest_build=1 -Dfuzz=1 -Ds
 
 # Add debug symbols even for opt builds.
 nspr_params+=(--enable-debug-symbols)
 
 if [ "$fuzz_oss" = 1 ]; then
   gyp_params+=(-Dno_zdefs=1 -Dfuzz_oss=1)
 else
   enable_sanitizer asan
-  enable_ubsan
+  # Ubsan doesn't build on 32-bit at the moment. Disable it.
+  if [ "$build_64" = 1 ]; then
+    enable_ubsan
+  fi
   enable_sancov
 fi
 
 if [ "$fuzz_tls" = 1 ]; then
   gyp_params+=(-Dfuzz_tls=1)
 fi
 
 if [ ! -f "/usr/lib/libFuzzingEngine.a" ]; then
--- a/security/nss/fuzz/fuzz.gyp
+++ b/security/nss/fuzz/fuzz.gyp
@@ -83,16 +83,25 @@
             'libraries': [
               '/usr/lib/x86_64-linux-gnu/libcrypto.a',
             ],
           }, {
             'libraries': [
               '-lcrypto',
             ],
           }],
+          # For test builds we have to set MPI defines.
+          [ 'target_arch=="ia32"', {
+            'defines': [
+              'MP_USE_UINT_DIGIT',
+              'MP_ASSEMBLY_MULTIPLY',
+              'MP_ASSEMBLY_SQUARE',
+              'MP_ASSEMBLY_DIV_2DX1D',
+            ],
+          }],
         ],
       },
     },
     {
       'target_name': 'nssfuzz-pkcs8',
       'type': 'executable',
       'sources': [
         'asn1_mutators.cc',
--- a/security/nss/gtests/freebl_gtest/freebl_gtest.gyp
+++ b/security/nss/gtests/freebl_gtest/freebl_gtest.gyp
@@ -24,23 +24,16 @@
         '<(DEPTH)/lib/cryptohi/cryptohi.gyp:cryptohi',
         '<(DEPTH)/lib/certhigh/certhigh.gyp:certhi',
         '<(DEPTH)/lib/certdb/certdb.gyp:certdb',
         '<(DEPTH)/lib/base/base.gyp:nssb',
         '<(DEPTH)/lib/dev/dev.gyp:nssdev',
         '<(DEPTH)/lib/pki/pki.gyp:nsspki',
         '<(DEPTH)/lib/ssl/ssl.gyp:ssl',
       ],
-      'conditions': [
-        [ 'ct_verif==1', {
-          'defines': [
-            'CT_VERIF',
-          ],
-        }],
-      ],
     },
     {
       'target_name': 'prng_gtest',
       'type': 'executable',
       'sources': [
         'prng_kat_unittest.cc',
       ],
       'dependencies': [
@@ -57,14 +50,30 @@
         '<(DEPTH)/lib/pki/pki.gyp:nsspki',
         '<(DEPTH)/lib/ssl/ssl.gyp:ssl',
       ],
     },
   ],
   'target_defaults': {
     'include_dirs': [
       '<(DEPTH)/lib/freebl/mpi',
-    ]
+    ],
+    # For test builds we have to set MPI defines.
+    'conditions': [
+      [ 'ct_verif==1', {
+        'defines': [
+          'CT_VERIF',
+        ],
+      }],
+      [ 'target_arch=="ia32"', {
+        'defines': [
+          'MP_USE_UINT_DIGIT',
+          'MP_ASSEMBLY_MULTIPLY',
+          'MP_ASSEMBLY_SQUARE',
+          'MP_ASSEMBLY_DIV_2DX1D',
+        ],
+      }],
+    ],
   },
   'variables': {
     'module': 'nss'
   }
 }
--- a/security/nss/gtests/freebl_gtest/mpi_unittest.cc
+++ b/security/nss/gtests/freebl_gtest/mpi_unittest.cc
@@ -48,23 +48,49 @@ class MPITest : public ::testing::Test {
 
     mp_read_radix(&a, a_string.c_str(), 16);
     mp_read_radix(&b, b_string.c_str(), 16);
     EXPECT_EQ(result, mp_cmp(&a, &b));
 
     mp_clear(&a);
     mp_clear(&b);
   }
+
+  void TestDiv(const std::string a_string, const std::string b_string,
+               const std::string result) {
+    mp_int a, b, c;
+    MP_DIGITS(&a) = 0;
+    MP_DIGITS(&b) = 0;
+    MP_DIGITS(&c) = 0;
+    ASSERT_EQ(MP_OKAY, mp_init(&a));
+    ASSERT_EQ(MP_OKAY, mp_init(&b));
+    ASSERT_EQ(MP_OKAY, mp_init(&c));
+
+    mp_read_radix(&a, a_string.c_str(), 16);
+    mp_read_radix(&b, b_string.c_str(), 16);
+    mp_read_radix(&c, result.c_str(), 16);
+    EXPECT_EQ(MP_OKAY, mp_div(&a, &b, &a, &b));
+    EXPECT_EQ(0, mp_cmp(&a, &c));
+
+    mp_clear(&a);
+    mp_clear(&b);
+    mp_clear(&c);
+  }
 };
 
 TEST_F(MPITest, MpiCmp01Test) { TestCmp("0", "1", -1); }
 TEST_F(MPITest, MpiCmp10Test) { TestCmp("1", "0", 1); }
 TEST_F(MPITest, MpiCmp00Test) { TestCmp("0", "0", 0); }
 TEST_F(MPITest, MpiCmp11Test) { TestCmp("1", "1", 0); }
+TEST_F(MPITest, MpiDiv32ErrorTest) {
+  TestDiv("FFFF00FFFFFFFF000000000000", "FFFF00FFFFFFFFFF", "FFFFFFFFFF");
+}
 
+#ifdef NSS_X64
+// This tests assumes 64-bit mp_digits.
 TEST_F(MPITest, MpiCmpUnalignedTest) {
   mp_int a, b, c;
   MP_DIGITS(&a) = 0;
   MP_DIGITS(&b) = 0;
   MP_DIGITS(&c) = 0;
   ASSERT_EQ(MP_OKAY, mp_init(&a));
   ASSERT_EQ(MP_OKAY, mp_init(&b));
   ASSERT_EQ(MP_OKAY, mp_init(&c));
@@ -85,16 +111,17 @@ TEST_F(MPITest, MpiCmpUnalignedTest) {
   char c_tmp[40];
   ASSERT_EQ(MP_OKAY, mp_toradix(&c, c_tmp, 16));
   ASSERT_TRUE(strncmp(c_tmp, "feffffffffffffff100000000000000", 31));
 
   mp_clear(&a);
   mp_clear(&b);
   mp_clear(&c);
 }
+#endif
 
 // This test is slow. Disable it by default so we can run these tests on CI.
 class DISABLED_MPITest : public ::testing::Test {};
 
 TEST_F(DISABLED_MPITest, MpiCmpConstTest) {
   mp_int a, b, c;
   MP_DIGITS(&a) = 0;
   MP_DIGITS(&b) = 0;
--- a/security/nss/gtests/util_gtest/util_pkcs11uri_unittest.cc
+++ b/security/nss/gtests/util_gtest/util_pkcs11uri_unittest.cc
@@ -26,35 +26,41 @@ class PK11URITest : public ::testing::Te
                           const PK11URIAttribute *qattrs, size_t num_qattrs) {
     ScopedPK11URI tmp(
         PK11URI_CreateURI(pattrs, num_pattrs, qattrs, num_qattrs));
     ASSERT_TRUE(tmp);
 
     size_t i;
     for (i = 0; i < num_pattrs; i++) {
       const char *value = PK11URI_GetPathAttribute(tmp.get(), pattrs[i].name);
-      ASSERT_TRUE(value);
-      ASSERT_EQ(std::string(value), std::string(pattrs[i].value));
+      EXPECT_TRUE(value);
+      if (value) {
+        EXPECT_EQ(std::string(value), std::string(pattrs[i].value));
+      }
     }
     for (i = 0; i < num_qattrs; i++) {
       const char *value = PK11URI_GetQueryAttribute(tmp.get(), qattrs[i].name);
-      ASSERT_TRUE(value);
-      ASSERT_EQ(std::string(value), std::string(qattrs[i].value));
+      EXPECT_TRUE(value);
+      if (value) {
+        EXPECT_EQ(std::string(value), std::string(qattrs[i].value));
+      }
     }
   }
 
   void TestCreateFormat(const PK11URIAttribute *pattrs, size_t num_pattrs,
                         const PK11URIAttribute *qattrs, size_t num_qattrs,
                         const std::string &formatted) {
     ScopedPK11URI tmp(
         PK11URI_CreateURI(pattrs, num_pattrs, qattrs, num_qattrs));
     ASSERT_TRUE(tmp);
     char *out = PK11URI_FormatURI(nullptr, tmp.get());
-    ASSERT_TRUE(out);
-    ASSERT_EQ(std::string(out), formatted);
+    EXPECT_TRUE(out);
+    if (out) {
+      EXPECT_EQ(std::string(out), formatted);
+    }
     PORT_Free(out);
   }
 
   bool TestParse(const std::string &str) {
     ScopedPK11URI tmp(PK11URI_ParseURI(str.c_str()));
     return tmp != nullptr;
   }
 
@@ -62,33 +68,39 @@ class PK11URITest : public ::testing::Te
                          size_t num_pattrs, const PK11URIAttribute *qattrs,
                          size_t num_qattrs) {
     ScopedPK11URI tmp(PK11URI_ParseURI(str.c_str()));
     ASSERT_TRUE(tmp);
 
     size_t i;
     for (i = 0; i < num_pattrs; i++) {
       const char *value = PK11URI_GetPathAttribute(tmp.get(), pattrs[i].name);
-      ASSERT_TRUE(value);
-      ASSERT_EQ(std::string(value), std::string(pattrs[i].value));
+      EXPECT_TRUE(value);
+      if (value) {
+        EXPECT_EQ(std::string(value), std::string(pattrs[i].value));
+      }
     }
     for (i = 0; i < num_qattrs; i++) {
       const char *value = PK11URI_GetQueryAttribute(tmp.get(), qattrs[i].name);
-      ASSERT_TRUE(value);
-      ASSERT_EQ(std::string(value), std::string(qattrs[i].value));
+      EXPECT_TRUE(value);
+      if (value) {
+        EXPECT_EQ(std::string(value), std::string(qattrs[i].value));
+      }
     }
   }
 
   void TestParseFormat(const std::string &str, const std::string &formatted) {
     ScopedPK11URI tmp(PK11URI_ParseURI(str.c_str()));
     ASSERT_TRUE(tmp);
     char *out = PK11URI_FormatURI(nullptr, tmp.get());
-    ASSERT_TRUE(out);
-    ASSERT_EQ(std::string(out), formatted);
-    PORT_Free(out);
+    EXPECT_TRUE(out);
+    if (out) {
+      EXPECT_EQ(std::string(out), formatted);
+      PORT_Free(out);
+    }
   }
 
  protected:
 };
 
 const PK11URIAttribute pattrs[] = {
     {"token", "aaa"}, {"manufacturer", "bbb"}, {"vendor", "ccc"}};
 
--- a/security/nss/lib/freebl/mpi/mpi.c
+++ b/security/nss/lib/freebl/mpi/mpi.c
@@ -2854,16 +2854,19 @@ s_mp_clamp(mp_int *mp)
 
 /* {{{ s_mp_exch(a, b) */
 
 /* Exchange the data for a and b; (b, a) = (a, b)                         */
 void
 s_mp_exch(mp_int *a, mp_int *b)
 {
     mp_int tmp;
+    if (!a || !b) {
+        return;
+    }
 
     tmp = *a;
     *a = *b;
     *b = tmp;
 
 } /* end s_mp_exch() */
 
 /* }}} */
@@ -4159,21 +4162,17 @@ s_mp_sqr(mp_int *a)
   Compute a = a / b and b = a mod b.  Assumes b > a.
  */
 
 mp_err s_mp_div(mp_int *rem,  /* i: dividend, o: remainder */
                 mp_int *div,  /* i: divisor                */
                 mp_int *quot) /* i: 0;        o: quotient  */
 {
     mp_int part, t;
-#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_DIV_WORD)
-    mp_word q_msd;
-#else
     mp_digit q_msd;
-#endif
     mp_err res;
     mp_digit d;
     mp_digit div_msd;
     int ix;
 
     if (mp_cmp_z(div) == 0)
         return MP_RANGE;
 
@@ -4208,90 +4207,83 @@ mp_err s_mp_div(mp_int *rem,  /* i: divi
         int partExtended = 0; /* set to true if we need to extend part */
 
         unusedRem = MP_USED(rem) - MP_USED(div);
         MP_DIGITS(&part) = MP_DIGITS(rem) + unusedRem;
         MP_ALLOC(&part) = MP_ALLOC(rem) - unusedRem;
         MP_USED(&part) = MP_USED(div);
 
         /* We have now truncated the part of the remainder to the same length as
-     * the divisor. If part is smaller than div, extend part by one digit. */
+         * the divisor. If part is smaller than div, extend part by one digit. */
         if (s_mp_cmp(&part, div) < 0) {
             --unusedRem;
 #if MP_ARGCHK == 2
             assert(unusedRem >= 0);
 #endif
             --MP_DIGITS(&part);
             ++MP_USED(&part);
             ++MP_ALLOC(&part);
             partExtended = 1;
         }
 
         /* Compute a guess for the next quotient digit       */
         q_msd = MP_DIGIT(&part, MP_USED(&part) - 1);
         div_msd = MP_DIGIT(div, MP_USED(div) - 1);
         if (!partExtended) {
             /* In this case, q_msd /= div_msd is always 1. First, since div_msd is
-       * normalized to have the high bit set, 2*div_msd > MP_DIGIT_MAX. Since
-       * we didn't extend part, q_msd >= div_msd. Therefore we know that
-       * div_msd <= q_msd <= MP_DIGIT_MAX < 2*div_msd. Dividing by div_msd we
-       * get 1 <= q_msd/div_msd < 2. So q_msd /= div_msd must be 1. */
+             * normalized to have the high bit set, 2*div_msd > MP_DIGIT_MAX. Since
+             * we didn't extend part, q_msd >= div_msd. Therefore we know that
+             * div_msd <= q_msd <= MP_DIGIT_MAX < 2*div_msd. Dividing by div_msd we
+             * get 1 <= q_msd/div_msd < 2. So q_msd /= div_msd must be 1. */
             q_msd = 1;
         } else {
-#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_DIV_WORD)
-            q_msd = (q_msd << MP_DIGIT_BIT) | MP_DIGIT(&part, MP_USED(&part) - 2);
-            q_msd /= div_msd;
-            if (q_msd == RADIX)
-                --q_msd;
-#else
             if (q_msd == div_msd) {
                 q_msd = MP_DIGIT_MAX;
             } else {
                 mp_digit r;
                 MP_CHECKOK(s_mpv_div_2dx1d(q_msd, MP_DIGIT(&part, MP_USED(&part) - 2),
                                            div_msd, &q_msd, &r));
             }
-#endif
         }
 #if MP_ARGCHK == 2
         assert(q_msd > 0); /* This case should never occur any more. */
 #endif
         if (q_msd <= 0)
             break;
 
         /* See what that multiplies out to                   */
         mp_copy(div, &t);
-        MP_CHECKOK(s_mp_mul_d(&t, (mp_digit)q_msd));
+        MP_CHECKOK(s_mp_mul_d(&t, q_msd));
 
         /*
-       If it's too big, back it off.  We should not have to do this
-       more than once, or, in rare cases, twice.  Knuth describes a
-       method by which this could be reduced to a maximum of once, but
-       I didn't implement that here.
-     * When using s_mpv_div_2dx1d, we may have to do this 3 times.
-     */
+           If it's too big, back it off.  We should not have to do this
+           more than once, or, in rare cases, twice.  Knuth describes a
+           method by which this could be reduced to a maximum of once, but
+           I didn't implement that here.
+           When using s_mpv_div_2dx1d, we may have to do this 3 times.
+         */
         for (i = 4; s_mp_cmp(&t, &part) > 0 && i > 0; --i) {
             --q_msd;
             MP_CHECKOK(s_mp_sub(&t, div)); /* t -= div */
         }
         if (i < 0) {
             res = MP_RANGE;
             goto CLEANUP;
         }
 
         /* At this point, q_msd should be the right next digit   */
         MP_CHECKOK(s_mp_sub(&part, &t)); /* part -= t */
         s_mp_clamp(rem);
 
         /*
-      Include the digit in the quotient.  We allocated enough memory
-      for any quotient we could ever possibly get, so we should not
-      have to check for failures here
-     */
-        MP_DIGIT(quot, unusedRem) = (mp_digit)q_msd;
+          Include the digit in the quotient.  We allocated enough memory
+          for any quotient we could ever possibly get, so we should not
+          have to check for failures here
+         */
+        MP_DIGIT(quot, unusedRem) = q_msd;
     }
 
     /* Denormalize remainder                */
     if (d) {
         s_mp_div_2d(rem, d);
     }
 
     s_mp_clamp(quot);
--- a/security/nss/lib/pk11wrap/pk11cert.c
+++ b/security/nss/lib/pk11wrap/pk11cert.c
@@ -760,17 +760,22 @@ find_certs_from_nickname(const char *nic
         if (token) {
             slot = PK11_ReferenceSlot(token->pk11slot);
         } else {
             PORT_SetError(SEC_ERROR_NO_TOKEN);
         }
         *delimit = ':';
     } else {
         slot = PK11_GetInternalKeySlot();
-        token = nssToken_AddRef(PK11Slot_GetNSSToken(slot));
+        token = PK11Slot_GetNSSToken(slot);
+        if (token) {
+            nssToken_AddRef(token);
+        } else {
+            PORT_SetError(SEC_ERROR_NO_TOKEN);
+        }
     }
     if (token) {
         nssList *certList;
         nssCryptokiObject **instances;
         nssPKIObjectCollection *collection;
         nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
         if (!PK11_IsPresent(slot)) {
             goto loser;
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -33,23 +33,16 @@
 #include "secmod.h"
 #include "blapi.h"
 
 #include <stdio.h>
 #ifdef NSS_SSL_ENABLE_ZLIB
 #include "zlib.h"
 #endif
 
-#ifndef PK11_SETATTRS
-#define PK11_SETATTRS(x, id, v, l) \
-    (x)->type = (id);              \
-    (x)->pValue = (v);             \
-    (x)->ulValueLen = (l);
-#endif
-
 static PK11SymKey *ssl3_GenerateRSAPMS(sslSocket *ss, ssl3CipherSpec *spec,
                                        PK11SlotInfo *serverKeySlot);
 static SECStatus ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms);
 static SECStatus ssl3_DeriveConnectionKeys(sslSocket *ss);
 static SECStatus ssl3_HandshakeFailure(sslSocket *ss);
 static SECStatus ssl3_SendCertificate(sslSocket *ss);
 static SECStatus ssl3_SendCertificateRequest(sslSocket *ss);
 static SECStatus ssl3_SendNextProto(sslSocket *ss);
--- a/security/nss/lib/ssl/ssl3ecc.c
+++ b/security/nss/lib/ssl/ssl3ecc.c
@@ -26,23 +26,16 @@
 #include "prthread.h"
 #include "prinit.h"
 
 #include "pk11func.h"
 #include "secmod.h"
 
 #include <stdio.h>
 
-#ifndef PK11_SETATTRS
-#define PK11_SETATTRS(x, id, v, l) \
-    (x)->type = (id);              \
-    (x)->pValue = (v);             \
-    (x)->ulValueLen = (l);
-#endif
-
 SECStatus
 ssl_NamedGroup2ECParams(PLArenaPool *arena, const sslNamedGroupDef *ecGroup,
                         SECKEYECParams *params)
 {
     SECOidData *oidData = NULL;
 
     if (!params) {
         PORT_Assert(0);
--- a/security/nss/lib/ssl/ssl3exthandle.c
+++ b/security/nss/lib/ssl/ssl3exthandle.c
@@ -11,24 +11,26 @@
 #include "sslimpl.h"
 #include "pk11pub.h"
 #include "blapit.h"
 #include "prinit.h"
 #include "ssl3ext.h"
 #include "ssl3exthandle.h"
 #include "tls13exthandle.h" /* For tls13_ServerSendStatusRequestXtn. */
 
-static SECStatus ssl3_ParseEncryptedSessionTicket(sslSocket *ss,
-                                                  SECItem *data, EncryptedSessionTicket *enc_session_ticket);
 static SECStatus ssl3_AppendToItem(SECItem *item, const unsigned char *buf,
                                    PRUint32 bytes);
-static SECStatus ssl3_ConsumeFromItem(SECItem *item, unsigned char **buf, PRUint32 bytes);
+static SECStatus ssl3_ConsumeFromItem(SECItem *item, unsigned char **buf,
+                                      PRUint32 bytes);
 static SECStatus ssl3_AppendNumberToItem(SECItem *item, PRUint32 num,
                                          PRInt32 lenSize);
-static SECStatus ssl3_ConsumeFromItem(SECItem *item, unsigned char **buf, PRUint32 bytes);
+
+PRUint32 ssl_ticket_lifetime = 2 * 24 * 60 * 60; /* 2 days in seconds */
+#define TLS_EX_SESS_TICKET_VERSION (0x0105)
+#define TLS_EX_SESS_TICKET_MAC_LENGTH 32
 
 /*
  * 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)
@@ -324,36 +326,38 @@ ssl3_SendSessionTicketXtn(
     return extension_length;
 
 loser:
     xtnData->ticketTimestampVerified = PR_FALSE;
     return -1;
 }
 
 static SECStatus
-ssl3_ParseEncryptedSessionTicket(sslSocket *ss, SECItem *data,
-                                 EncryptedSessionTicket *enc_session_ticket)
+ssl3_ParseEncryptedSessionTicket(sslSocket *ss, const SECItem *data,
+                                 EncryptedSessionTicket *encryptedTicket)
 {
-    if (ssl3_ConsumeFromItem(data, &enc_session_ticket->key_name,
+    SECItem copy = *data;
+
+    if (ssl3_ConsumeFromItem(&copy, &encryptedTicket->key_name,
                              SESS_TICKET_KEY_NAME_LEN) !=
         SECSuccess)
         return SECFailure;
-    if (ssl3_ConsumeFromItem(data, &enc_session_ticket->iv,
+    if (ssl3_ConsumeFromItem(&copy, &encryptedTicket->iv,
                              AES_BLOCK_SIZE) !=
         SECSuccess)
         return SECFailure;
-    if (ssl3_ConsumeHandshakeVariable(ss, &enc_session_ticket->encrypted_state,
-                                      2, &data->data, &data->len) !=
+    if (ssl3_ConsumeHandshakeVariable(ss, &encryptedTicket->encrypted_state,
+                                      2, &copy.data, &copy.len) !=
         SECSuccess)
         return SECFailure;
-    if (ssl3_ConsumeFromItem(data, &enc_session_ticket->mac,
+    if (ssl3_ConsumeFromItem(&copy, &encryptedTicket->mac,
                              TLS_EX_SESS_TICKET_MAC_LENGTH) !=
         SECSuccess)
         return SECFailure;
-    if (data->len != 0) /* Make sure that we have consumed all bytes. */
+    if (copy.len != 0) /* Make sure that we have consumed all bytes. */
         return SECFailure;
 
     return SECSuccess;
 }
 
 PRBool
 ssl_AlpnTagAllowed(const sslSocket *ss, const SECItem *tag)
 {
@@ -872,19 +876,16 @@ ssl3_ClientHandleStatusRequestXtn(const 
         return SECFailure;
     }
 
     /* Keep track of negotiated extensions. */
     xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
     return SECSuccess;
 }
 
-PRUint32 ssl_ticket_lifetime = 2 * 24 * 60 * 60; /* 2 days in seconds */
-#define TLS_EX_SESS_TICKET_VERSION (0x0104)
-
 /*
  * Called from ssl3_SendNewSessionTicket, tls13_SendNewSessionTicket
  */
 SECStatus
 ssl3_EncodeSessionTicket(sslSocket *ss,
                          const NewSessionTicket *ticket,
                          SECItem *ticket_data)
 {
@@ -903,39 +904,36 @@ ssl3_EncodeSessionTicket(sslSocket *ss,
     PRUint32 padding_length;
     PRUint32 ticket_length;
     PRUint32 cert_length = 0;
     PRUint8 length_buf[4];
     PRUint32 now;
     unsigned char key_name[SESS_TICKET_KEY_NAME_LEN];
     PK11SymKey *aes_key = NULL;
     PK11SymKey *mac_key = NULL;
-    CK_MECHANISM_TYPE cipherMech = CKM_AES_CBC;
     PK11Context *aes_ctx;
-    CK_MECHANISM_TYPE macMech = CKM_SHA256_HMAC;
     PK11Context *hmac_ctx = NULL;
     unsigned char computed_mac[TLS_EX_SESS_TICKET_MAC_LENGTH];
     unsigned int computed_mac_length;
     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;
-    SECItem alpnSelection = { siBuffer, NULL, 0 };
+    SECItem *alpnSelection = NULL;
 
     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));
 
     if (ss->opt.requestCertificate && ss->sec.ci.sid->peerCert) {
-        cert_length = 3 + ss->sec.ci.sid->peerCert->derCert.len;
+        cert_length = 2 + ss->sec.ci.sid->peerCert->derCert.len;
     }
 
     /* Get IV and encryption keys */
     ivItem.data = iv;
     ivItem.len = sizeof(iv);
     rv = PK11_GenerateRandom(iv, sizeof(iv));
     if (rv != SECSuccess)
         goto loser;
@@ -971,60 +969,56 @@ ssl3_EncodeSessionTicket(sslSocket *ss,
         } else {
             /* TODO: else send an empty ticket. */
             goto loser;
         }
         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->xtnData.nextProtoState != SSL_NEXT_PROTO_NO_SUPPORT &&
-        ss->xtnData.nextProto.data) {
-        alpnSelection = ss->xtnData.nextProto;
-    }
+    PORT_Assert(ss->xtnData.nextProtoState == SSL_NEXT_PROTO_SELECTED ||
+                ss->xtnData.nextProtoState == SSL_NEXT_PROTO_NEGOTIATED ||
+                ss->xtnData.nextProto.len == 0);
+    alpnSelection = &ss->xtnData.nextProto;
 
     ciphertext_length =
-        sizeof(PRUint16)                       /* ticket_version */
+        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 */
+        + 2 + srvName->len                     /* name len + length field */
         + 1                                    /* extendedMasterSecretUsed */
         + sizeof(ticket->ticket_lifetime_hint) /* ticket lifetime hint */
         + sizeof(ticket->flags)                /* ticket flags */
-        + 1 + alpnSelection.len                /* npn value + length field. */
+        + 1 + alpnSelection->len               /* alpn value + length field */
         + 4;                                   /* maxEarlyData */
 #ifdef UNSAFE_FUZZER_MODE
     padding_length = 0;
 #else
     padding_length = AES_BLOCK_SIZE -
                      (ciphertext_length %
                       AES_BLOCK_SIZE);
 #endif
     ciphertext_length += padding_length;
 
     if (SECITEM_AllocItem(NULL, &plaintext_item, ciphertext_length) == NULL)
         goto loser;
 
     plaintext = plaintext_item;
 
-    /* ticket_version */
+    /* ticket version */
     rv = ssl3_AppendNumberToItem(&plaintext, TLS_EX_SESS_TICKET_VERSION,
                                  sizeof(PRUint16));
     if (rv != SECSuccess)
         goto loser;
 
     /* ssl_version */
     rv = ssl3_AppendNumberToItem(&plaintext, ss->version,
                                  sizeof(SSL3ProtocolVersion));
@@ -1079,23 +1073,23 @@ ssl3_EncodeSessionTicket(sslSocket *ss,
         goto loser;
     rv = ssl3_AppendNumberToItem(&plaintext, ms_item.len, 2);
     if (rv != SECSuccess)
         goto loser;
     rv = ssl3_AppendToItem(&plaintext, ms_item.data, ms_item.len);
     if (rv != SECSuccess)
         goto loser;
 
-    /* client_identity */
+    /* client identity */
     if (ss->opt.requestCertificate && ss->sec.ci.sid->peerCert) {
         rv = ssl3_AppendNumberToItem(&plaintext, CLIENT_AUTH_CERTIFICATE, 1);
         if (rv != SECSuccess)
             goto loser;
         rv = ssl3_AppendNumberToItem(&plaintext,
-                                     ss->sec.ci.sid->peerCert->derCert.len, 3);
+                                     ss->sec.ci.sid->peerCert->derCert.len, 2);
         if (rv != SECSuccess)
             goto loser;
         rv = ssl3_AppendToItem(&plaintext,
                                ss->sec.ci.sid->peerCert->derCert.data,
                                ss->sec.ci.sid->peerCert->derCert.len);
         if (rv != SECSuccess)
             goto loser;
     } else {
@@ -1106,54 +1100,46 @@ ssl3_EncodeSessionTicket(sslSocket *ss,
 
     /* timestamp */
     now = ssl_Time();
     rv = ssl3_AppendNumberToItem(&plaintext, now,
                                  sizeof(ticket->ticket_lifetime_hint));
     if (rv != SECSuccess)
         goto loser;
 
-    if (srvNameLen) {
-        /* Name Type (sni_host_name) */
-        rv = ssl3_AppendNumberToItem(&plaintext, srvName->type, 1);
-        if (rv != SECSuccess)
-            goto loser;
-        /* HostName (length and value) */
-        rv = ssl3_AppendNumberToItem(&plaintext, srvName->len, 2);
-        if (rv != SECSuccess)
-            goto loser;
+    /* HostName (length and value) */
+    rv = ssl3_AppendNumberToItem(&plaintext, srvName->len, 2);
+    if (rv != SECSuccess)
+        goto loser;
+    if (srvName->len) {
         rv = ssl3_AppendToItem(&plaintext, srvName->data, srvName->len);
         if (rv != SECSuccess)
             goto loser;
-    } else {
-        /* No Name */
-        rv = ssl3_AppendNumberToItem(&plaintext, (char)TLS_STE_NO_SERVER_NAME, 1);
-        if (rv != SECSuccess)
-            goto loser;
     }
 
     /* 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);
+    /* ALPN 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 (alpnSelection->len) {
+        rv = ssl3_AppendToItem(&plaintext, alpnSelection->data,
+                               alpnSelection->len);
         if (rv != SECSuccess)
             goto loser;
     }
 
     rv = ssl3_AppendNumberToItem(&plaintext, ssl_max_early_data_size, 4);
     if (rv != SECSuccess)
         goto loser;
 
@@ -1167,17 +1153,17 @@ ssl3_EncodeSessionTicket(sslSocket *ss,
     }
 
     /* Generate encrypted portion of ticket. */
     PORT_Assert(aes_key);
 #ifdef UNSAFE_FUZZER_MODE
     ciphertext.len = plaintext_item.len;
     PORT_Memcpy(ciphertext.data, plaintext_item.data, plaintext_item.len);
 #else
-    aes_ctx = PK11_CreateContextBySymKey(cipherMech, CKA_ENCRYPT, aes_key, &ivItem);
+    aes_ctx = PK11_CreateContextBySymKey(CKM_AES_CBC, CKA_ENCRYPT, aes_key, &ivItem);
     if (!aes_ctx)
         goto loser;
 
     rv = PK11_CipherOp(aes_ctx, ciphertext.data,
                        (int *)&ciphertext.len, ciphertext.len,
                        plaintext_item.data, plaintext_item.len);
     PK11_Finalize(aes_ctx);
     PK11_DestroyContext(aes_ctx, PR_TRUE);
@@ -1185,17 +1171,18 @@ ssl3_EncodeSessionTicket(sslSocket *ss,
         goto loser;
 #endif
 
     /* Convert ciphertext length to network order. */
     (void)ssl_EncodeUintX(ciphertext.len, 2, length_buf);
 
     /* Compute MAC. */
     PORT_Assert(mac_key);
-    hmac_ctx = PK11_CreateContextBySymKey(macMech, CKA_SIGN, mac_key, &macParam);
+    hmac_ctx = PK11_CreateContextBySymKey(CKM_SHA256_HMAC, CKA_SIGN, mac_key,
+                                          &macParam);
     if (!hmac_ctx)
         goto loser;
 
     rv = PK11_DigestBegin(hmac_ctx);
     if (rv != SECSuccess)
         goto loser;
     rv = PK11_DigestOp(hmac_ctx, key_name, SESS_TICKET_KEY_NAME_LEN);
     if (rv != SECSuccess)
@@ -1280,465 +1267,535 @@ ssl3_ClientHandleSessionTicketXtn(const 
         return SECSuccess; /* Ignore the extension. */
     }
 
     /* Keep track of negotiated extensions. */
     xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
     return SECSuccess;
 }
 
-/* Generic ticket processing code, common to TLS 1.0-1.2 and
- * TLS 1.3. */
+static SECStatus
+ssl_DecryptSessionTicket(sslSocket *ss, const SECItem *rawTicket,
+                         const EncryptedSessionTicket *encryptedTicket,
+                         SECItem *decryptedTicket)
+{
+    SECStatus rv;
+    unsigned char keyName[SESS_TICKET_KEY_NAME_LEN];
+
+    PK11SymKey *macKey = NULL;
+    PK11Context *hmacCtx;
+    unsigned char computedMac[TLS_EX_SESS_TICKET_MAC_LENGTH];
+    unsigned int computedMacLength;
+    SECItem macParam = { siBuffer, NULL, 0 };
+
+    PK11SymKey *aesKey = NULL;
+#ifndef UNSAFE_FUZZER_MODE
+    PK11Context *aesCtx;
+    SECItem ivItem;
+
+    unsigned int i;
+    SSL3Opaque *padding;
+    SSL3Opaque paddingLength;
+#endif
+
+    PORT_Assert(!decryptedTicket->data);
+    PORT_Assert(!decryptedTicket->len);
+    if (rawTicket->len < TLS_EX_SESS_TICKET_MAC_LENGTH) {
+        PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
+        return SECFailure;
+    }
+
+    /* Get session ticket keys. */
+    rv = ssl_GetSessionTicketKeys(ss, keyName, &aesKey, &macKey);
+    if (rv != SECSuccess) {
+        SSL_DBG(("%d: SSL[%d]: Unable to get/generate session ticket keys.",
+                 SSL_GETPID(), ss->fd));
+        return SECFailure; /* code already set */
+    }
+
+    /* If the ticket sent by the client was generated under a key different from
+     * the one we have, bypass ticket processing.  This reports success, meaning
+     * that the handshake completes, but doesn't resume.
+     */
+    if (PORT_Memcmp(encryptedTicket->key_name, keyName,
+                    SESS_TICKET_KEY_NAME_LEN) != 0) {
+#ifndef UNSAFE_FUZZER_MODE
+        SSL_DBG(("%d: SSL[%d]: Session ticket key_name sent mismatch.",
+                 SSL_GETPID(), ss->fd));
+        return SECSuccess;
+#endif
+    }
+
+    /* Verify the MAC on the ticket. */
+    PORT_Assert(macKey);
+    hmacCtx = PK11_CreateContextBySymKey(CKM_SHA256_HMAC, CKA_SIGN, macKey,
+                                         &macParam);
+    if (!hmacCtx) {
+        SSL_DBG(("%d: SSL[%d]: Unable to create HMAC context: %d.",
+                 SSL_GETPID(), ss->fd, PORT_GetError()));
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+
+    SSL_DBG(("%d: SSL[%d]: Successfully created HMAC context.",
+             SSL_GETPID(), ss->fd));
+    do {
+        rv = PK11_DigestBegin(hmacCtx);
+        if (rv != SECSuccess) {
+            break;
+        }
+        rv = PK11_DigestOp(hmacCtx, rawTicket->data,
+                           rawTicket->len - TLS_EX_SESS_TICKET_MAC_LENGTH);
+        if (rv != SECSuccess) {
+            break;
+        }
+        rv = PK11_DigestFinal(hmacCtx, computedMac, &computedMacLength,
+                              sizeof(computedMac));
+    } while (0);
+    PK11_DestroyContext(hmacCtx, PR_TRUE);
+    if (rv != SECSuccess) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+
+    if (NSS_SecureMemcmp(computedMac, encryptedTicket->mac,
+                         computedMacLength) != 0) {
+#ifndef UNSAFE_FUZZER_MODE
+        SSL_DBG(("%d: SSL[%d]: Session ticket MAC mismatch.",
+                 SSL_GETPID(), ss->fd));
+        PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
+        return SECFailure;
+#endif
+    }
+
+    /* Decrypt the ticket. */
+
+    /* Plaintext is shorter than the ciphertext due to padding. */
+    if (!SECITEM_AllocItem(NULL, decryptedTicket,
+                           encryptedTicket->encrypted_state.len)) {
+        return SECFailure; /* code already set */
+    }
+
+    PORT_Assert(aesKey);
+#ifdef UNSAFE_FUZZER_MODE
+    decryptedTicket->len = encryptedTicket->encrypted_state.len;
+    PORT_Memcpy(decryptedTicket->data,
+                encryptedTicket->encrypted_state.data,
+                encryptedTicket->encrypted_state.len);
+#else
+    ivItem.data = encryptedTicket->iv;
+    ivItem.len = AES_BLOCK_SIZE;
+    aesCtx = PK11_CreateContextBySymKey(CKM_AES_CBC, CKA_DECRYPT, aesKey,
+                                        &ivItem);
+    if (!aesCtx) {
+        SSL_DBG(("%d: SSL[%d]: Unable to create AES context.",
+                 SSL_GETPID(), ss->fd));
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+
+    do {
+        rv = PK11_CipherOp(aesCtx, decryptedTicket->data,
+                           (int *)&decryptedTicket->len, decryptedTicket->len,
+                           encryptedTicket->encrypted_state.data,
+                           encryptedTicket->encrypted_state.len);
+        if (rv != SECSuccess) {
+            break;
+        }
+        rv = PK11_Finalize(aesCtx);
+        if (rv != SECSuccess) {
+            break;
+        }
+    } while (0);
+    PK11_DestroyContext(aesCtx, PR_TRUE);
+    if (rv != SECSuccess) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+
+    /* Check padding. */
+    paddingLength = decryptedTicket->data[decryptedTicket->len - 1];
+    if (paddingLength == 0 || paddingLength > AES_BLOCK_SIZE) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+
+    padding = &decryptedTicket->data[decryptedTicket->len - paddingLength];
+    for (i = 0; i < paddingLength; i++, padding++) {
+        if (paddingLength != *padding) {
+            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+            return SECFailure;
+        }
+    }
+    decryptedTicket->len -= paddingLength;
+#endif /* UNSAFE_FUZZER_MODE */
+
+    return SECSuccess;
+}
+
+static SECStatus
+ssl_ParseSessionTicket(sslSocket *ss, const SECItem *decryptedTicket,
+                       SessionTicket *parsedTicket)
+{
+    PRUint32 temp;
+    SECStatus rv;
+
+    SSL3Opaque *buffer = decryptedTicket->data;
+    unsigned int len = decryptedTicket->len;
+
+    PORT_Memset(parsedTicket, 0, sizeof(*parsedTicket));
+    parsedTicket->valid = PR_FALSE;
+
+    /* If the decrypted ticket is empty, then report success, but leave the
+     * ticket marked as invalid. */
+    if (decryptedTicket->len == 0) {
+        return SECSuccess;
+    }
+
+    /* Read ticket version. */
+    rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 2, &buffer, &len);
+    if (rv != SECSuccess) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+
+    /* Skip the ticket if the version is wrong.  This won't result in a
+     * handshake failure, just a failure to resume. */
+    if (temp != TLS_EX_SESS_TICKET_VERSION) {
+        return SECSuccess;
+    }
+
+    /* Read SSLVersion. */
+    rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 2, &buffer, &len);
+    if (rv != SECSuccess) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    parsedTicket->ssl_version = (SSL3ProtocolVersion)temp;
+    if (!ssl3_VersionIsSupported(ss->protocolVariant,
+                                 parsedTicket->ssl_version)) {
+        /* This socket doesn't support the version from the ticket. */
+        return SECSuccess;
+    }
+
+    /* Read cipher_suite. */
+    rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 2, &buffer, &len);
+    if (rv != SECSuccess) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    parsedTicket->cipher_suite = (ssl3CipherSuite)temp;
+
+    /* Read compression_method. */
+    rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &len);
+    if (rv != SECSuccess) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    parsedTicket->compression_method = (SSLCompressionMethod)temp;
+
+    /* Read cipher spec parameters. */
+    rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &len);
+    if (rv != SECSuccess) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    parsedTicket->authType = (SSLAuthType)temp;
+    rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &len);
+    if (rv != SECSuccess) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    parsedTicket->authKeyBits = temp;
+    rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &len);
+    if (rv != SECSuccess) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    parsedTicket->keaType = (SSLKEAType)temp;
+    rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &len);
+    if (rv != SECSuccess) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    parsedTicket->keaKeyBits = temp;
+
+    /* Read the optional named curve. */
+    rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &len);
+    if (rv != SECSuccess) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    if (parsedTicket->authType == ssl_auth_ecdsa ||
+        parsedTicket->authType == ssl_auth_ecdh_rsa ||
+        parsedTicket->authType == ssl_auth_ecdh_ecdsa) {
+        const sslNamedGroupDef *group =
+            ssl_LookupNamedGroup((SSLNamedGroup)temp);
+        if (!group || group->keaType != ssl_kea_ecdh) {
+            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+            return SECFailure;
+        }
+        parsedTicket->namedCurve = group;
+    }
+
+    /* Read the master secret (and how it is wrapped). */
+    rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &len);
+    if (rv != SECSuccess) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    PORT_Assert(temp == PR_TRUE || temp == PR_FALSE);
+    parsedTicket->ms_is_wrapped = (PRBool)temp;
+
+    rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &len);
+    if (rv != SECSuccess) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    parsedTicket->msWrapMech = (CK_MECHANISM_TYPE)temp;
+
+    rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 2, &buffer, &len);
+    if (rv != SECSuccess) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    if (temp == 0 || temp > sizeof(parsedTicket->master_secret)) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    parsedTicket->ms_length = (PRUint16)temp;
+
+    /* Read the master secret. */
+    rv = ssl3_ExtConsumeHandshake(ss, parsedTicket->master_secret,
+                                  parsedTicket->ms_length, &buffer, &len);
+    if (rv != SECSuccess) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    /* Read client identity */
+    rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &len);
+    if (rv != SECSuccess) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    parsedTicket->client_auth_type = (ClientAuthenticationType)temp;
+    switch (parsedTicket->client_auth_type) {
+        case CLIENT_AUTH_ANONYMOUS:
+            break;
+        case CLIENT_AUTH_CERTIFICATE:
+            rv = ssl3_ExtConsumeHandshakeVariable(ss, &parsedTicket->peer_cert, 2,
+                                                  &buffer, &len);
+            if (rv != SECSuccess) {
+                PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+                return SECFailure;
+            }
+            break;
+        default:
+            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+            return SECFailure;
+    }
+    /* Read timestamp. */
+    rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &len);
+    if (rv != SECSuccess) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    parsedTicket->timestamp = temp;
+
+    /* Read server name */
+    rv = ssl3_ExtConsumeHandshakeVariable(ss, &parsedTicket->srvName, 2,
+                                          &buffer, &len);
+    if (rv != SECSuccess) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+
+    /* Read extendedMasterSecretUsed */
+    rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &len);
+    if (rv != SECSuccess) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    PORT_Assert(temp == PR_TRUE || temp == PR_FALSE);
+    parsedTicket->extendedMasterSecretUsed = (PRBool)temp;
+
+    rv = ssl3_ExtConsumeHandshake(ss, &temp, 4, &buffer, &len);
+    if (rv != SECSuccess) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    parsedTicket->flags = PR_ntohl(temp);
+
+    rv = ssl3_ExtConsumeHandshakeVariable(ss, &parsedTicket->alpnSelection, 1,
+                                          &buffer, &len);
+    PORT_Assert(parsedTicket->alpnSelection.len < 256);
+    if (rv != SECSuccess) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+
+    rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &len);
+    if (rv != SECSuccess) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    parsedTicket->maxEarlyData = temp;
+
+#ifndef UNSAFE_FUZZER_MODE
+    /* Done parsing.  Check that all bytes have been consumed. */
+    if (len != 0) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+#endif
+
+    parsedTicket->valid = PR_TRUE;
+    return SECSuccess;
+}
+
+static SECStatus
+ssl_CreateSIDFromTicket(sslSocket *ss, const SECItem *rawTicket,
+                        SessionTicket *parsedTicket, sslSessionID **out)
+{
+    sslSessionID *sid;
+    SECStatus rv;
+
+    sid = ssl3_NewSessionID(ss, PR_TRUE);
+    if (sid == NULL) {
+        return SECFailure;
+    }
+
+    /* Copy over parameters. */
+    sid->version = parsedTicket->ssl_version;
+    sid->u.ssl3.cipherSuite = parsedTicket->cipher_suite;
+    sid->u.ssl3.compression = parsedTicket->compression_method;
+    sid->authType = parsedTicket->authType;
+    sid->authKeyBits = parsedTicket->authKeyBits;
+    sid->keaType = parsedTicket->keaType;
+    sid->keaKeyBits = parsedTicket->keaKeyBits;
+    sid->namedCurve = parsedTicket->namedCurve;
+
+    rv = SECITEM_CopyItem(NULL, &sid->u.ssl3.locked.sessionTicket.ticket,
+                          rawTicket);
+    if (rv != SECSuccess) {
+        goto loser;
+    }
+    sid->u.ssl3.locked.sessionTicket.flags = parsedTicket->flags;
+    sid->u.ssl3.locked.sessionTicket.max_early_data_size =
+        parsedTicket->maxEarlyData;
+
+    if (parsedTicket->ms_length >
+        sizeof(sid->u.ssl3.keys.wrapped_master_secret)) {
+        goto loser;
+    }
+    PORT_Memcpy(sid->u.ssl3.keys.wrapped_master_secret,
+                parsedTicket->master_secret, parsedTicket->ms_length);
+    sid->u.ssl3.keys.wrapped_master_secret_len = parsedTicket->ms_length;
+    sid->u.ssl3.masterWrapMech = parsedTicket->msWrapMech;
+    sid->u.ssl3.keys.msIsWrapped = parsedTicket->ms_is_wrapped;
+    sid->u.ssl3.masterValid = PR_TRUE;
+    sid->u.ssl3.keys.resumable = PR_TRUE;
+    sid->u.ssl3.keys.extendedMasterSecretUsed = parsedTicket->extendedMasterSecretUsed;
+
+    /* Copy over client cert from session ticket if there is one. */
+    if (parsedTicket->peer_cert.data != NULL) {
+        PORT_Assert(!sid->peerCert);
+        sid->peerCert = CERT_NewTempCertificate(ss->dbHandle,
+                                                &parsedTicket->peer_cert,
+                                                NULL, PR_FALSE, PR_TRUE);
+        if (!sid->peerCert) {
+            goto loser;
+        }
+    }
+
+    /* Transfer ownership of the remaining items. */
+    if (parsedTicket->srvName.data != NULL) {
+        SECITEM_FreeItem(&sid->u.ssl3.srvName, PR_FALSE);
+        rv = SECITEM_CopyItem(NULL, &sid->u.ssl3.srvName,
+                              &parsedTicket->srvName);
+        if (rv != SECSuccess) {
+            goto loser;
+        }
+    }
+    if (parsedTicket->alpnSelection.data != NULL) {
+        rv = SECITEM_CopyItem(NULL, &sid->u.ssl3.alpnSelection,
+                              &parsedTicket->alpnSelection);
+        if (rv != SECSuccess) {
+            goto loser;
+        }
+    }
+
+    *out = sid;
+    return SECSuccess;
+
+loser:
+    ssl_FreeSID(sid);
+    return SECFailure;
+}
+
+/* Generic ticket processing code, common to all TLS versions. */
 SECStatus
 ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data)
 {
+    EncryptedSessionTicket encryptedTicket;
+    SECItem decryptedTicket = { siBuffer, NULL, 0 };
+    SessionTicket parsedTicket;
     SECStatus rv;
-    SECItem *decrypted_state = NULL;
-    SessionTicket *parsed_session_ticket = NULL;
-    sslSessionID *sid = NULL;
-    SSL3Statistics *ssl3stats;
-    PRUint32 i;
-    SECItem extension_data;
-    EncryptedSessionTicket enc_session_ticket;
-    unsigned char computed_mac[TLS_EX_SESS_TICKET_MAC_LENGTH];
-    unsigned int computed_mac_length;
-    unsigned char key_name[SESS_TICKET_KEY_NAME_LEN];
-    PK11SymKey *aes_key = NULL;
-    PK11SymKey *mac_key = NULL;
-    PK11Context *hmac_ctx;
-    CK_MECHANISM_TYPE macMech = CKM_SHA256_HMAC;
-    PK11Context *aes_ctx;
-    CK_MECHANISM_TYPE cipherMech = CKM_AES_CBC;
-    unsigned char *padding;
-    PRUint32 padding_length;
-    unsigned char *buffer;
-    unsigned int buffer_len;
-    PRUint32 temp;
-    SECItem cert_item;
-    PRUint32 nameType;
-    SECItem macParam = { siBuffer, NULL, 0 };
-    SECItem alpn_item;
-    SECItem ivItem;
 
-    /* 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) {
         ss->sec.uncache(ss->sec.ci.sid);
         ssl_FreeSID(ss->sec.ci.sid);
         ss->sec.ci.sid = NULL;
     }
 
-    extension_data.data = data->data; /* Keep a copy for future use. */
-    extension_data.len = data->len;
-
-    if (ssl3_ParseEncryptedSessionTicket(ss, data, &enc_session_ticket) !=
-        SECSuccess) {
-        return SECSuccess; /* Pretend it isn't there */
-    }
-
-    /* Get session ticket keys. */
-    rv = ssl_GetSessionTicketKeys(ss, key_name, &aes_key, &mac_key);
+    rv = ssl3_ParseEncryptedSessionTicket(ss, data, &encryptedTicket);
     if (rv != SECSuccess) {
-        SSL_DBG(("%d: SSL[%d]: Unable to get/generate session ticket keys.",
-                 SSL_GETPID(), ss->fd));
-        goto loser;
-    }
-
-    /* If the ticket sent by the client was generated under a key different
-     * from the one we have, bypass ticket processing.
-     */
-    if (PORT_Memcmp(enc_session_ticket.key_name, key_name,
-                    SESS_TICKET_KEY_NAME_LEN) != 0) {
-#ifndef UNSAFE_FUZZER_MODE
-        SSL_DBG(("%d: SSL[%d]: Session ticket key_name sent mismatch.",
-                 SSL_GETPID(), ss->fd));
-        goto no_ticket;
-#endif
+        PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
+        return SECFailure;
     }
 
-    /* Verify the MAC on the ticket.  MAC verification may also
-     * fail if the MAC key has been recently refreshed.
-     */
-    PORT_Assert(mac_key);
-    hmac_ctx = PK11_CreateContextBySymKey(macMech, CKA_SIGN, mac_key, &macParam);
-    if (!hmac_ctx) {
-        SSL_DBG(("%d: SSL[%d]: Unable to create HMAC context: %d.",
-                 SSL_GETPID(), ss->fd, PORT_GetError()));
-        goto no_ticket;
-    } else {
-        SSL_DBG(("%d: SSL[%d]: Successfully created HMAC context.",
-                 SSL_GETPID(), ss->fd));
-    }
-    rv = PK11_DigestBegin(hmac_ctx);
-    if (rv != SECSuccess) {
-        PK11_DestroyContext(hmac_ctx, PR_TRUE);
-        goto no_ticket;
-    }
-    rv = PK11_DigestOp(hmac_ctx, extension_data.data,
-                       extension_data.len -
-                           TLS_EX_SESS_TICKET_MAC_LENGTH);
+    rv = ssl_DecryptSessionTicket(ss, data, &encryptedTicket,
+                                  &decryptedTicket);
     if (rv != SECSuccess) {
-        PK11_DestroyContext(hmac_ctx, PR_TRUE);
-        goto no_ticket;
-    }
-    rv = PK11_DigestFinal(hmac_ctx, computed_mac,
-                          &computed_mac_length, sizeof(computed_mac));
-    PK11_DestroyContext(hmac_ctx, PR_TRUE);
-    if (rv != SECSuccess)
-        goto no_ticket;
-
-    if (NSS_SecureMemcmp(computed_mac, enc_session_ticket.mac,
-                         computed_mac_length) !=
-        0) {
-#ifndef UNSAFE_FUZZER_MODE
-        SSL_DBG(("%d: SSL[%d]: Session ticket MAC mismatch.",
-                 SSL_GETPID(), ss->fd));
-        goto no_ticket;
-#endif
-    }
-
-    /* We ignore key_name for now.
-     * This is ok as MAC verification succeeded.
-     */
-
-    /* Decrypt the ticket. */
-
-    /* Plaintext is shorter than the ciphertext due to padding. */
-    decrypted_state = SECITEM_AllocItem(NULL, NULL,
-                                        enc_session_ticket.encrypted_state.len);
-
-    PORT_Assert(aes_key);
-#ifdef UNSAFE_FUZZER_MODE
-    decrypted_state->len = enc_session_ticket.encrypted_state.len;
-    PORT_Memcpy(decrypted_state->data,
-                enc_session_ticket.encrypted_state.data,
-                enc_session_ticket.encrypted_state.len);
-#else
-    ivItem.data = enc_session_ticket.iv;
-    ivItem.len = AES_BLOCK_SIZE;
-    aes_ctx = PK11_CreateContextBySymKey(cipherMech, CKA_DECRYPT,
-                                         aes_key, &ivItem);
-    if (!aes_ctx) {
-        SSL_DBG(("%d: SSL[%d]: Unable to create AES context.",
-                 SSL_GETPID(), ss->fd));
-        goto no_ticket;
-    }
-
-    rv = PK11_CipherOp(aes_ctx, decrypted_state->data,
-                       (int *)&decrypted_state->len, decrypted_state->len,
-                       enc_session_ticket.encrypted_state.data,
-                       enc_session_ticket.encrypted_state.len);
-    PK11_Finalize(aes_ctx);
-    PK11_DestroyContext(aes_ctx, PR_TRUE);
-    if (rv != SECSuccess)
-        goto no_ticket;
-
-    /* Check padding. */
-    padding_length =
-        (PRUint32)decrypted_state->data[decrypted_state->len - 1];
-    if (padding_length == 0 || padding_length > AES_BLOCK_SIZE)
-        goto no_ticket;
-
-    padding = &decrypted_state->data[decrypted_state->len - padding_length];
-    for (i = 0; i < padding_length; i++, padding++) {
-        if (padding_length != (PRUint32)*padding)
-            goto no_ticket;
-    }
-#endif
-
-    /* Deserialize session state. */
-    buffer = decrypted_state->data;
-    buffer_len = decrypted_state->len;
-
-    parsed_session_ticket = PORT_ZAlloc(sizeof(SessionTicket));
-    if (parsed_session_ticket == NULL) {
-        rv = SECFailure;
-        goto loser;
+        PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
+        return SECFailure;
     }
 
-    /* Read ticket_version and reject if the version is wrong */
-    rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 2, &buffer, &buffer_len);
-    if (rv != SECSuccess || temp != TLS_EX_SESS_TICKET_VERSION)
-        goto no_ticket;
-
-    parsed_session_ticket->ticket_version = (SSL3ProtocolVersion)temp;
-
-    /* Read SSLVersion. */
-    rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 2, &buffer, &buffer_len);
-    if (rv != SECSuccess)
-        goto no_ticket;
-    parsed_session_ticket->ssl_version = (SSL3ProtocolVersion)temp;
-
-    /* Read cipher_suite. */
-    rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 2, &buffer, &buffer_len);
-    if (rv != SECSuccess)
-        goto no_ticket;
-    parsed_session_ticket->cipher_suite = (ssl3CipherSuite)temp;
-
-    /* Read compression_method. */
-    rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &buffer_len);
-    if (rv != SECSuccess)
-        goto no_ticket;
-    parsed_session_ticket->compression_method = (SSLCompressionMethod)temp;
+    rv = ssl_ParseSessionTicket(ss, &decryptedTicket, &parsedTicket);
+    if (rv != SECSuccess) {
+        SSL3Statistics *ssl3stats;
 
-    /* Read cipher spec parameters. */
-    rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &buffer_len);
-    if (rv != SECSuccess)
-        goto no_ticket;
-    parsed_session_ticket->authType = (SSLAuthType)temp;
-    rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &buffer_len);
-    if (rv != SECSuccess)
-        goto no_ticket;
-    parsed_session_ticket->authKeyBits = temp;
-    rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &buffer_len);
-    if (rv != SECSuccess)
-        goto no_ticket;
-    parsed_session_ticket->keaType = (SSLKEAType)temp;
-    rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &buffer_len);
-    if (rv != SECSuccess)
-        goto no_ticket;
-    parsed_session_ticket->keaKeyBits = temp;
-
-    /* Read the optional named curve. */
-    rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &buffer_len);
-    if (rv != SECSuccess)
-        goto no_ticket;
-    if (parsed_session_ticket->authType == ssl_auth_ecdsa ||
-        parsed_session_ticket->authType == ssl_auth_ecdh_rsa ||
-        parsed_session_ticket->authType == ssl_auth_ecdh_ecdsa) {
-        const sslNamedGroupDef *group =
-            ssl_LookupNamedGroup((SSLNamedGroup)temp);
-        if (!group || group->keaType != ssl_kea_ecdh) {
-            goto no_ticket;
-        }
-        parsed_session_ticket->namedCurve = group;
+        SSL_DBG(("%d: SSL[%d]: Session ticket parsing failed.",
+                 SSL_GETPID(), ss->fd));
+        ssl3stats = SSL_GetStatistics();
+        SSL_AtomicIncrementLong(&ssl3stats->hch_sid_ticket_parse_failures);
+        goto loser; /* code already set */
     }
 
-    /* Read wrapped master_secret. */
-    rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &buffer_len);
-    if (rv != SECSuccess)
-        goto no_ticket;
-    parsed_session_ticket->ms_is_wrapped = (PRBool)temp;
-
-    rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &buffer_len);
-    if (rv != SECSuccess)
-        goto no_ticket;
-    parsed_session_ticket->msWrapMech = (CK_MECHANISM_TYPE)temp;
-
-    rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 2, &buffer, &buffer_len);
-    if (rv != SECSuccess)
-        goto no_ticket;
-    parsed_session_ticket->ms_length = (PRUint16)temp;
-    if (parsed_session_ticket->ms_length == 0 || /* sanity check MS. */
-        parsed_session_ticket->ms_length >
-            sizeof(parsed_session_ticket->master_secret))
-        goto no_ticket;
-
-    /* Allow for the wrapped master secret to be longer. */
-    if (buffer_len < parsed_session_ticket->ms_length)
-        goto no_ticket;
-    PORT_Memcpy(parsed_session_ticket->master_secret, buffer,
-                parsed_session_ticket->ms_length);
-    buffer += parsed_session_ticket->ms_length;
-    buffer_len -= parsed_session_ticket->ms_length;
-
-    /* Read client_identity */
-    rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &buffer_len);
-    if (rv != SECSuccess)
-        goto no_ticket;
-    parsed_session_ticket->client_identity.client_auth_type =
-        (ClientAuthenticationType)temp;
-    switch (parsed_session_ticket->client_identity.client_auth_type) {
-        case CLIENT_AUTH_ANONYMOUS:
-            break;
-        case CLIENT_AUTH_CERTIFICATE:
-            rv = ssl3_ExtConsumeHandshakeVariable(ss, &cert_item, 3,
-                                                  &buffer, &buffer_len);
-            if (rv != SECSuccess)
-                goto no_ticket;
-            rv = SECITEM_CopyItem(NULL, &parsed_session_ticket->peer_cert,
-                                  &cert_item);
-            if (rv != SECSuccess)
-                goto no_ticket;
-            break;
-        default:
-            goto no_ticket;
-    }
-    /* Read timestamp. */
-    rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &buffer_len);
-    if (rv != SECSuccess)
-        goto no_ticket;
-    parsed_session_ticket->timestamp = temp;
-
-    /* Read server name */
-    rv = ssl3_ExtConsumeHandshakeNumber(ss, &nameType, 1, &buffer, &buffer_len);
-    if (rv != SECSuccess)
-        goto no_ticket;
-    if ((PRInt8)nameType != TLS_STE_NO_SERVER_NAME) {
-        SECItem name_item;
-        rv = ssl3_ExtConsumeHandshakeVariable(ss, &name_item, 2, &buffer,
-                                              &buffer_len);
-        if (rv != SECSuccess)
-            goto no_ticket;
-        rv = SECITEM_CopyItem(NULL, &parsed_session_ticket->srvName,
-                              &name_item);
-        if (rv != SECSuccess)
-            goto no_ticket;
-        parsed_session_ticket->srvName.type = (PRUint8)nameType;
-    }
-
-    /* Read extendedMasterSecretUsed */
-    rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &buffer_len);
-    if (rv != SECSuccess)
-        goto no_ticket;
-    PORT_Assert(temp == PR_TRUE || temp == PR_FALSE);
-    parsed_session_ticket->extendedMasterSecretUsed = (PRBool)temp;
-
-    rv = ssl3_ExtConsumeHandshake(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);
+    /* Use the ticket if it is valid and unexpired. */
+    if (parsedTicket.valid &&
+        parsedTicket.timestamp + ssl_ticket_lifetime > ssl_Time()) {
+        sslSessionID *sid;
 
-    rv = ssl3_ExtConsumeHandshakeVariable(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;
-    }
-
-    rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &buffer_len);
-    if (rv != SECSuccess) {
-        goto no_ticket;
-    }
-    parsed_session_ticket->maxEarlyData = temp;
-
-#ifndef UNSAFE_FUZZER_MODE
-    /* Done parsing.  Check that all bytes have been consumed. */
-    if (buffer_len != padding_length) {
-        goto no_ticket;
-    }
-#endif
-
-    /* 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 &&
-        parsed_session_ticket->timestamp + ssl_ticket_lifetime >
-            ssl_Time()) {
-
-        sid = ssl3_NewSessionID(ss, PR_TRUE);
-        if (sid == NULL) {
-            rv = SECFailure;
-            goto loser;
-        }
-
-        /* Copy over parameters. */
-        sid->version = parsed_session_ticket->ssl_version;
-        sid->u.ssl3.cipherSuite = parsed_session_ticket->cipher_suite;
-        sid->u.ssl3.compression = parsed_session_ticket->compression_method;
-        sid->authType = parsed_session_ticket->authType;
-        sid->authKeyBits = parsed_session_ticket->authKeyBits;
-        sid->keaType = parsed_session_ticket->keaType;
-        sid->keaKeyBits = parsed_session_ticket->keaKeyBits;
-        sid->namedCurve = parsed_session_ticket->namedCurve;
-
-        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;
-        sid->u.ssl3.locked.sessionTicket.max_early_data_size =
-            parsed_session_ticket->maxEarlyData;
-
-        if (parsed_session_ticket->ms_length >
-            sizeof(sid->u.ssl3.keys.wrapped_master_secret))
-            goto no_ticket;
-        PORT_Memcpy(sid->u.ssl3.keys.wrapped_master_secret,
-                    parsed_session_ticket->master_secret,
-                    parsed_session_ticket->ms_length);
-        sid->u.ssl3.keys.wrapped_master_secret_len =
-            parsed_session_ticket->ms_length;
-        sid->u.ssl3.masterWrapMech = parsed_session_ticket->msWrapMech;
-        sid->u.ssl3.keys.msIsWrapped =
-            parsed_session_ticket->ms_is_wrapped;
-        sid->u.ssl3.masterValid = PR_TRUE;
-        sid->u.ssl3.keys.resumable = PR_TRUE;
-        sid->u.ssl3.keys.extendedMasterSecretUsed = parsed_session_ticket->extendedMasterSecretUsed;
-
-        /* Copy over client cert from session ticket if there is one. */
-        if (parsed_session_ticket->peer_cert.data != NULL) {
-            if (sid->peerCert != NULL)
-                CERT_DestroyCertificate(sid->peerCert);
-            sid->peerCert = CERT_NewTempCertificate(ss->dbHandle,
-                                                    &parsed_session_ticket->peer_cert, NULL, PR_FALSE, PR_TRUE);
-            if (sid->peerCert == NULL) {
-                rv = SECFailure;
-                goto loser;
-            }
-        }
-        if (parsed_session_ticket->srvName.data != NULL) {
-            if (sid->u.ssl3.srvName.data) {
-                SECITEM_FreeItem(&sid->u.ssl3.srvName, PR_FALSE);
-            }
-            sid->u.ssl3.srvName = parsed_session_ticket->srvName;
-            parsed_session_ticket->srvName.data = NULL;
-        }
-        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;
+        rv = ssl_CreateSIDFromTicket(ss, data, &parsedTicket, &sid);
+        if (rv != SECSuccess) {
+            goto loser; /* code already set */
         }
         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));
-        ssl3stats = SSL_GetStatistics();
-        SSL_AtomicIncrementLong(&ssl3stats->hch_sid_ticket_parse_failures);
-    }
-    rv = SECSuccess;
+    SECITEM_ZfreeItem(&decryptedTicket, PR_FALSE);
+    PORT_Memset(&parsedTicket, 0, sizeof(parsedTicket));
+    return SECSuccess;
 
 loser:
-    /* ss->sec.ci.sid == sid if it did NOT come here via goto statement
-     * in that case do not free sid
-     */
-    if (sid && (ss->sec.ci.sid != sid)) {
-        ssl_FreeSID(sid);
-        sid = NULL;
-    }
-    if (decrypted_state != NULL) {
-        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);
-        }
-        if (parsed_session_ticket->srvName.data) {
-            SECITEM_FreeItem(&parsed_session_ticket->srvName, PR_FALSE);
-        }
-        PORT_ZFree(parsed_session_ticket, sizeof(SessionTicket));
-    }
-
-    return rv;
+    SECITEM_ZfreeItem(&decryptedTicket, PR_FALSE);
+    PORT_Memset(&parsedTicket, 0, sizeof(parsedTicket));
+    return SECFailure;
 }
 
 SECStatus
 ssl3_ServerHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
                                   SECItem *data)
 {
 
     /* Ignore the SessionTicket extension if processing is disabled. */
--- a/security/nss/lib/ssl/ssl3prot.h
+++ b/security/nss/lib/ssl/ssl3prot.h
@@ -300,32 +300,21 @@ typedef enum {
     tls13_psk_dh_ke = 1
 } TLS13PskKEModes;
 
 typedef enum {
     CLIENT_AUTH_ANONYMOUS = 0,
     CLIENT_AUTH_CERTIFICATE = 1
 } ClientAuthenticationType;
 
-typedef struct {
-    ClientAuthenticationType client_auth_type;
-    union {
-        SSL3Opaque *certificate_list;
-    } identity;
-} ClientIdentity;
-
 #define SESS_TICKET_KEY_NAME_LEN 16
 #define SESS_TICKET_KEY_NAME_PREFIX "NSS!"
 #define SESS_TICKET_KEY_NAME_PREFIX_LEN 4
 #define SESS_TICKET_KEY_VAR_NAME_LEN 12
 
 typedef struct {
     unsigned char *key_name;
     unsigned char *iv;
     SECItem encrypted_state;
     unsigned char *mac;
 } EncryptedSessionTicket;
 
-#define TLS_EX_SESS_TICKET_MAC_LENGTH 32
-
-#define TLS_STE_NO_SERVER_NAME -1
-
 #endif /* __ssl3proto_h_ */
--- a/security/nss/lib/ssl/sslimpl.h
+++ b/security/nss/lib/ssl/sslimpl.h
@@ -987,17 +987,17 @@ typedef struct SSLWrappedSymWrappingKeyS
     /* mechanism used to wrap the SymmetricWrappingKey using
      * server's public and/or private keys. */
     PRInt16 wrapMechIndex;
     PRUint16 wrapKeyIndex;
     PRUint16 wrappedSymKeyLen;
 } SSLWrappedSymWrappingKey;
 
 typedef struct SessionTicketStr {
-    PRUint16 ticket_version;
+    PRBool valid;
     SSL3ProtocolVersion ssl_version;
     ssl3CipherSuite cipher_suite;
     SSLCompressionMethod compression_method;
     SSLAuthType authType;
     PRUint32 authKeyBits;
     SSLKEAType keaType;
     PRUint32 keaKeyBits;
     const sslNamedGroupDef *namedCurve; /* For certificate lookup. */
@@ -1005,17 +1005,17 @@ typedef struct SessionTicketStr {
     /*
      * msWrapMech contains a meaningful value only if ms_is_wrapped is true.
      */
     PRUint8 ms_is_wrapped;
     CK_MECHANISM_TYPE msWrapMech;
     PRUint16 ms_length;
     SSL3Opaque master_secret[48];
     PRBool extendedMasterSecretUsed;
-    ClientIdentity client_identity;
+    ClientAuthenticationType client_auth_type;
     SECItem peer_cert;
     PRUint32 timestamp;
     PRUint32 flags;
     SECItem srvName; /* negotiated server name */
     SECItem alpnSelection;
     PRUint32 maxEarlyData;
 } SessionTicket;
 
--- a/security/nss/lib/ssl/sslsnce.c
+++ b/security/nss/lib/ssl/sslsnce.c
@@ -1803,16 +1803,17 @@ ssl_GetSessionTicketKeys(sslSocket *ss, 
     if (PR_SUCCESS != PR_CallOnceWithArg(&ssl_session_ticket_keys.setup,
                                          &ssl_GenerateSessionTicketKeysOnce,
                                          ss->pkcs11PinArg)) {
         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
         return SECFailure;
     }
 
     if (!ssl_session_ticket_keys.encKey || !ssl_session_ticket_keys.macKey) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
         return SECFailure;
     }
 
     PORT_Memcpy(keyName, ssl_session_ticket_keys.keyName,
                 sizeof(ssl_session_ticket_keys.keyName));
     *encKey = ssl_session_ticket_keys.encKey;
     *macKey = ssl_session_ticket_keys.macKey;
     return SECSuccess;
--- a/security/nss/lib/util/pkcs11uri.c
+++ b/security/nss/lib/util/pkcs11uri.c
@@ -676,17 +676,17 @@ PK11URI_ParseURI(const char *string)
 
     if (strncmp("pkcs11:", p, 7) != 0) {
         return NULL;
     }
     p += 7;
 
     result = pk11uri_AllocURI();
     if (result == NULL) {
-        goto fail;
+        return NULL;
     }
 
     /* Parse the path component and its attributes. */
     ret = pk11uri_ParseAttributes(&p, "?", ';', PK11URI_PCHAR,
                                   pattr_names, PR_ARRAY_SIZE(pattr_names),
                                   &result->pattrs, &result->vpattrs,
                                   pk11uri_ComparePathAttributeName,
                                   PR_FALSE, PR_FALSE);