Bug 1277255, land NSS_3_25_RC0, r=kaie
authorFranziskus Kiefer <franziskuskiefer@gmail.com>
Mon, 13 Jun 2016 17:31:45 +0200
changeset 301702 bb5316a4c7c2645a555e190432d000eae6bf003c
parent 301701 3f6483d4dfb3af6995627c30dc8b9ea885d986e5
child 301703 3a53ff76208b2cfe4b8d77f17aec627387773fa8
push id30339
push usercbook@mozilla.com
push dateMon, 13 Jun 2016 23:16:11 +0000
treeherdermozilla-central@ddb6b3014922 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskaie
bugs1277255
milestone50.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1277255, land NSS_3_25_RC0, r=kaie
security/nss/.taskcluster.yml
security/nss/TAG-INFO
security/nss/automation/taskcluster/graph/linux/build32-debug.yml
security/nss/automation/taskcluster/graph/linux/build32-opt.yml
security/nss/automation/taskcluster/graph/linux/build64-asan.yml
security/nss/automation/taskcluster/graph/linux/build64-debug.yml
security/nss/automation/taskcluster/graph/linux/build64-memleak.yml
security/nss/automation/taskcluster/graph/linux/build64-opt.yml
security/nss/automation/taskcluster/graph/tests/cert.yml
security/nss/automation/taskcluster/graph/tools/clang-format.yml
security/nss/automation/taskcluster/graph/windows/build64-debug.yml
security/nss/automation/taskcluster/graph/windows/build64-opt.yml
security/nss/automation/taskcluster/scripts/build.sh
security/nss/automation/taskcluster/windows/build.sh
security/nss/cmd/selfserv/selfserv.c
security/nss/cmd/tstclnt/tstclnt.c
security/nss/coreconf/config.mk
security/nss/coreconf/coreconf.dep
security/nss/external_tests/ssl_gtest/manifest.mn
security/nss/external_tests/ssl_gtest/ssl_ciphersuite_unittest.cc
security/nss/external_tests/ssl_gtest/ssl_dhe_unittest.cc
security/nss/external_tests/ssl_gtest/ssl_extension_unittest.cc
security/nss/external_tests/ssl_gtest/ssl_loopback_unittest.cc
security/nss/external_tests/ssl_gtest/ssl_skip_unittest.cc
security/nss/external_tests/ssl_gtest/tls_agent.cc
security/nss/external_tests/ssl_gtest/tls_agent.h
security/nss/external_tests/ssl_gtest/tls_connect.cc
security/nss/external_tests/ssl_gtest/tls_connect.h
security/nss/lib/ckfw/builtins/certdata.txt
security/nss/lib/ckfw/builtins/nssckbi.h
security/nss/lib/freebl/mpi/mdxptest.c
security/nss/lib/freebl/mpi/mpi-priv.h
security/nss/lib/freebl/mpi/mpi.c
security/nss/lib/nss/nss.h
security/nss/lib/softoken/softkver.h
security/nss/lib/ssl/derive.c
security/nss/lib/ssl/dhe-param.c
security/nss/lib/ssl/ssl.h
security/nss/lib/ssl/ssl3con.c
security/nss/lib/ssl/ssl3ecc.c
security/nss/lib/ssl/ssl3ext.c
security/nss/lib/ssl/ssl3prot.h
security/nss/lib/ssl/sslcert.c
security/nss/lib/ssl/sslcert.h
security/nss/lib/ssl/sslenum.c
security/nss/lib/ssl/sslimpl.h
security/nss/lib/ssl/sslinfo.c
security/nss/lib/ssl/sslproto.h
security/nss/lib/ssl/sslsecur.c
security/nss/lib/ssl/sslsnce.c
security/nss/lib/ssl/sslsock.c
security/nss/lib/ssl/sslt.h
security/nss/lib/ssl/tls13con.c
security/nss/lib/util/nssutil.h
security/nss/lib/util/secoid.c
security/nss/lib/util/secoidt.h
--- a/security/nss/.taskcluster.yml
+++ b/security/nss/.taskcluster.yml
@@ -94,8 +94,10 @@ tasks:
 
       extra:
         treeherder:
           symbol: D
           revision: '{{revision}}'
           revision_hash: '{{revision_hash}}'
           build:
             platform: nss-decision
+          machine:
+            platform: nss-decision
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-NSS_3_25_BETA1
+NSS_3_25_RC0
--- a/security/nss/automation/taskcluster/graph/linux/build32-debug.yml
+++ b/security/nss/automation/taskcluster/graph/linux/build32-debug.yml
@@ -7,21 +7,22 @@
     payload:
       env:
         NSS_ENABLE_TLS_1_3: 1
 
     extra:
       treeherder:
         build:
           platform: linux32
+        machine:
+          platform: linux32
         collection:
           debug: true
 
   tests:
-    - cert
     - chains
     - cipher
     - crmf
     - db
     - ec
     - fips
     - gtests
     - lowhash
@@ -41,16 +42,18 @@
     payload:
       env:
         NSS_TESTS: ssl
 
     extra:
       treeherder:
         build:
           platform: linux32
+        machine:
+          platform: linux32
         collection:
           debug: true
         groupSymbol: Builds
         groupName: Various builds
         symbol: noTLSv1.3
 
   tests:
     - ssl
@@ -65,16 +68,18 @@
         NSS_ENABLE_TLS_1_3: 1
         GCC_VERSION: clang-3.8
         GXX_VERSION: clang++-3.8
 
     extra:
       treeherder:
         build:
           platform: linux32
+        machine:
+          platform: linux32
         collection:
           debug: true
         groupSymbol: Builds
         groupName: Various builds
         symbol: clang-3.8
 
 - task:
     metadata:
@@ -86,16 +91,18 @@
         NSS_ENABLE_TLS_1_3: 1
         GCC_VERSION: gcc-4.8
         GXX_VERSION: g++-4.8
 
     extra:
       treeherder:
         build:
           platform: linux32
+        machine:
+          platform: linux32
         collection:
           debug: true
         groupSymbol: Builds
         groupName: Various builds
         symbol: gcc-4.8
 
 - task:
     metadata:
@@ -107,16 +114,18 @@
         NSS_ENABLE_TLS_1_3: 1
         GCC_VERSION: gcc-6
         GXX_VERSION: g++-6
 
     extra:
       treeherder:
         build:
           platform: linux32
+        machine:
+          platform: linux32
         collection:
           debug: true
         groupSymbol: Builds
         groupName: Various builds
         symbol: gcc-6.1
 
 - task:
     metadata:
@@ -127,13 +136,15 @@
       env:
         NSS_ENABLE_TLS_1_3: 1
         NO_PKCS11_BYPASS: 1
 
     extra:
       treeherder:
         build:
           platform: linux32
+        machine:
+          platform: linux32
         collection:
           debug: true
         groupSymbol: Builds
         groupName: Various builds
         symbol: noPkcs11Bypass
--- a/security/nss/automation/taskcluster/graph/linux/build32-opt.yml
+++ b/security/nss/automation/taskcluster/graph/linux/build32-opt.yml
@@ -8,21 +8,22 @@
       env:
         NSS_ENABLE_TLS_1_3: 1
         BUILD_OPT: 1
 
     extra:
       treeherder:
         build:
           platform: linux32
+        machine:
+          platform: linux32
         collection:
           opt: true
 
   tests:
-    - cert
     - chains
     - cipher
     - crmf
     - db
     - ec
     - fips
     - gtests
     - lowhash
@@ -43,16 +44,18 @@
       env:
         NSS_TESTS: ssl
         BUILD_OPT: 1
 
     extra:
       treeherder:
         build:
           platform: linux32
+        machine:
+          platform: linux32
         collection:
           opt: true
         groupSymbol: Builds
         groupName: Various builds
         symbol: noTLSv1.3
 
   tests:
     - ssl
@@ -68,16 +71,18 @@
         GCC_VERSION: clang-3.8
         GXX_VERSION: clang++-3.8
         BUILD_OPT: 1
 
     extra:
       treeherder:
         build:
           platform: linux32
+        machine:
+          platform: linux32
         collection:
           opt: true
         groupSymbol: Builds
         groupName: Various builds
         symbol: clang-3.8
 
 - task:
     metadata:
@@ -90,16 +95,18 @@
         GCC_VERSION: gcc-4.8
         GXX_VERSION: g++-4.8
         BUILD_OPT: 1
 
     extra:
       treeherder:
         build:
           platform: linux32
+        machine:
+          platform: linux32
         collection:
           opt: true
         groupSymbol: Builds
         groupName: Various builds
         symbol: gcc-4.8
 
 - task:
     metadata:
@@ -112,16 +119,18 @@
         GCC_VERSION: gcc-6
         GXX_VERSION: g++-6
         BUILD_OPT: 1
 
     extra:
       treeherder:
         build:
           platform: linux32
+        machine:
+          platform: linux32
         collection:
           opt: true
         groupSymbol: Builds
         groupName: Various builds
         symbol: gcc-6.1
 
 - task:
     metadata:
@@ -133,13 +142,15 @@
         NSS_ENABLE_TLS_1_3: 1
         NO_PKCS11_BYPASS: 1
         BUILD_OPT: 1
 
     extra:
       treeherder:
         build:
           platform: linux32
+        machine:
+          platform: linux32
         collection:
           opt: true
         groupSymbol: Builds
         groupName: Various builds
         symbol: noPkcs11Bypass
--- a/security/nss/automation/taskcluster/graph/linux/build64-asan.yml
+++ b/security/nss/automation/taskcluster/graph/linux/build64-asan.yml
@@ -11,21 +11,22 @@
         GXX_VERSION: clang++-3.8
         USE_ASAN: 1
         USE_64: 1
 
     extra:
       treeherder:
         build:
           platform: linux64
+        machine:
+          platform: linux64
         collection:
           asan: true
 
   tests:
-    - cert
     - chains
     - cipher
     - crmf
     - db
     - ec
     - fips
     - gtests
     - lowhash
@@ -49,15 +50,17 @@
         NSS_TESTS: ssl
         USE_ASAN: 1
         USE_64: 1
 
     extra:
       treeherder:
         build:
           platform: linux64
+        machine:
+          platform: linux64
         collection:
           asan: true
         groupSymbol: SSL
         groupName: SSL tests
 
   tests:
     - ssl
--- a/security/nss/automation/taskcluster/graph/linux/build64-debug.yml
+++ b/security/nss/automation/taskcluster/graph/linux/build64-debug.yml
@@ -8,21 +8,22 @@
       env:
         NSS_ENABLE_TLS_1_3: 1
         USE_64: 1
 
     extra:
       treeherder:
         build:
           platform: linux64
+        machine:
+          platform: linux64
         collection:
           debug: true
 
   tests:
-    - cert
     - chains
     - cipher
     - crmf
     - db
     - ec
     - fips
     - gtests
     - lowhash
@@ -43,16 +44,18 @@
       env:
         NSS_TESTS: ssl
         USE_64: 1
 
     extra:
       treeherder:
         build:
           platform: linux64
+        machine:
+          platform: linux64
         collection:
           debug: true
         groupSymbol: Builds
         groupName: Various builds
         symbol: noTLSv1.3
 
   tests:
     - ssl
@@ -68,16 +71,18 @@
         GCC_VERSION: clang-3.8
         GXX_VERSION: clang++-3.8
         USE_64: 1
 
     extra:
       treeherder:
         build:
           platform: linux64
+        machine:
+          platform: linux64
         collection:
           debug: true
         groupSymbol: Builds
         groupName: Various builds
         symbol: clang-3.8
 
 - task:
     metadata:
@@ -90,16 +95,18 @@
         GCC_VERSION: gcc-4.8
         GXX_VERSION: g++-4.8
         USE_64: 1
 
     extra:
       treeherder:
         build:
           platform: linux64
+        machine:
+          platform: linux64
         collection:
           debug: true
         groupSymbol: Builds
         groupName: Various builds
         symbol: gcc-4.8
 
 - task:
     metadata:
@@ -112,16 +119,18 @@
         GCC_VERSION: gcc-6
         GXX_VERSION: g++-6
         USE_64: 1
 
     extra:
       treeherder:
         build:
           platform: linux64
+        machine:
+          platform: linux64
         collection:
           debug: true
         groupSymbol: Builds
         groupName: Various builds
         symbol: gcc-6.1
 
 - task:
     metadata:
@@ -133,13 +142,15 @@
         NSS_ENABLE_TLS_1_3: 1
         NO_PKCS11_BYPASS: 1
         USE_64: 1
 
     extra:
       treeherder:
         build:
           platform: linux64
+        machine:
+          platform: linux64
         collection:
           debug: true
         groupSymbol: Builds
         groupName: Various builds
         symbol: noPkcs11Bypass
--- a/security/nss/automation/taskcluster/graph/linux/build64-memleak.yml
+++ b/security/nss/automation/taskcluster/graph/linux/build64-memleak.yml
@@ -8,13 +8,15 @@
       env:
         NSS_TESTS: memleak
         USE_64: 1
 
     extra:
       treeherder:
         build:
           platform: linux64
+        machine:
+          platform: linux64
         collection:
           memleak: true
 
   tests:
     - memleak
--- a/security/nss/automation/taskcluster/graph/linux/build64-opt.yml
+++ b/security/nss/automation/taskcluster/graph/linux/build64-opt.yml
@@ -9,21 +9,22 @@
         NSS_ENABLE_TLS_1_3: 1
         BUILD_OPT: 1
         USE_64: 1
 
     extra:
       treeherder:
         build:
           platform: linux64
+        machine:
+          platform: linux64
         collection:
           opt: true
 
   tests:
-    - cert
     - chains
     - cipher
     - crmf
     - db
     - ec
     - fips
     - gtests
     - lowhash
@@ -45,16 +46,18 @@
         NSS_TESTS: ssl
         BUILD_OPT: 1
         USE_64: 1
 
     extra:
       treeherder:
         build:
           platform: linux64
+        machine:
+          platform: linux64
         collection:
           opt: true
         groupSymbol: Builds
         groupName: Various builds
         symbol: noTLSv1.3
 
   tests:
     - ssl
@@ -71,16 +74,18 @@
         GXX_VERSION: clang++-3.8
         BUILD_OPT: 1
         USE_64: 1
 
     extra:
       treeherder:
         build:
           platform: linux64
+        machine:
+          platform: linux64
         collection:
           opt: true
         groupSymbol: Builds
         groupName: Various builds
         symbol: clang-3.8
 
 - task:
     metadata:
@@ -94,16 +99,18 @@
         GXX_VERSION: g++-4.8
         BUILD_OPT: 1
         USE_64: 1
 
     extra:
       treeherder:
         build:
           platform: linux64
+        machine:
+          platform: linux64
         collection:
           opt: true
         groupSymbol: Builds
         groupName: Various builds
         symbol: gcc-4.8
 
 - task:
     metadata:
@@ -117,16 +124,18 @@
         GXX_VERSION: g++-6
         BUILD_OPT: 1
         USE_64: 1
 
     extra:
       treeherder:
         build:
           platform: linux64
+        machine:
+          platform: linux64
         collection:
           opt: true
         groupSymbol: Builds
         groupName: Various builds
         symbol: gcc-6.1
 
 - task:
     metadata:
@@ -139,13 +148,15 @@
         NO_PKCS11_BYPASS: 1
         BUILD_OPT: 1
         USE_64: 1
 
     extra:
       treeherder:
         build:
           platform: linux64
+        machine:
+          platform: linux64
         collection:
           opt: true
         groupSymbol: Builds
         groupName: Various builds
         symbol: noPkcs11Bypass
deleted file mode 100644
--- a/security/nss/automation/taskcluster/graph/tests/cert.yml
+++ /dev/null
@@ -1,13 +0,0 @@
----
-- task:
-    metadata:
-      name: Cert tests
-      description: Cert tests
-
-    payload:
-      env:
-        NSS_TESTS: cert
-
-    extra:
-      treeherder:
-        symbol: Cert
--- a/security/nss/automation/taskcluster/graph/tools/clang-format.yml
+++ b/security/nss/automation/taskcluster/graph/tools/clang-format.yml
@@ -25,11 +25,13 @@
       env:
         NSS_HEAD_REPOSITORY: !env NSS_HEAD_REPOSITORY
         NSS_HEAD_REVISION: !env NSS_HEAD_REVISION
 
     extra:
       treeherder:
         build:
           platform: nss-tools
+        machine:
+          platform: nss-tools
         symbol: clang-format-3.8
         revision: !env TC_REVISION
         revision_hash: !env TC_REVISION_HASH
--- a/security/nss/automation/taskcluster/graph/windows/build64-debug.yml
+++ b/security/nss/automation/taskcluster/graph/windows/build64-debug.yml
@@ -8,21 +8,22 @@
       env:
         NSS_ENABLE_TLS_1_3: 1
         USE_64: 1
 
     extra:
       treeherder:
         build:
           platform: windows2012-64
+        machine:
+          platform: windows2012-64
         collection:
           debug: true
 
   tests:
-    - cert
     - cipher
     - crmf
     - db
     - ec
     - fips
     - gtests
     - lowhash
     - merge
--- a/security/nss/automation/taskcluster/graph/windows/build64-opt.yml
+++ b/security/nss/automation/taskcluster/graph/windows/build64-opt.yml
@@ -9,21 +9,22 @@
         NSS_ENABLE_TLS_1_3: 1
         BUILD_OPT: 1
         USE_64: 1
 
     extra:
       treeherder:
         build:
           platform: windows2012-64
+        machine:
+          platform: windows2012-64
         collection:
           opt: true
 
   tests:
-    - cert
     - cipher
     - crmf
     - db
     - ec
     - fips
     - gtests
     - lowhash
     - merge
--- a/security/nss/automation/taskcluster/scripts/build.sh
+++ b/security/nss/automation/taskcluster/scripts/build.sh
@@ -17,11 +17,17 @@ fi
 # Clone NSPR if needed.
 if [ ! -d "nspr" ]; then
     hg clone https://hg.mozilla.org/projects/nspr
 fi
 
 # Build.
 cd nss && make nss_build_all
 
+# Generate certificates.
+cd tests && NSS_TESTS=cert NSS_CYCLES="standard pkix sharedb" ./all.sh
+
+# Reset test counter so that test runs pick up our certificates.
+cd && echo 1 > tests_results/security/localhost
+
 # Package.
-mkdir -p /home/worker/artifacts
-tar cvfjh /home/worker/artifacts/dist.tar.bz2 ../dist
+mkdir artifacts
+tar cvfjh artifacts/dist.tar.bz2 dist tests_results
--- a/security/nss/automation/taskcluster/windows/build.sh
+++ b/security/nss/automation/taskcluster/windows/build.sh
@@ -6,10 +6,16 @@ set -v -e -x
 source $(dirname $0)/setup.sh
 
 # Clone NSPR.
 hg clone https://hg.mozilla.org/projects/nspr
 
 # Build.
 cd nss && make nss_build_all
 
+# Generate certificates.
+cd tests && NSS_TESTS=cert NSS_CYCLES="standard pkix sharedb" ./all.sh
+
+# Reset test counter so that test runs pick up our certificates.
+cd ../../ && echo 1 > tests_results/security/localhost
+
 # Package.
-7z a ../public/build/dist.7z ../dist
+7z a public/build/dist.7z dist tests_results
--- a/security/nss/cmd/selfserv/selfserv.c
+++ b/security/nss/cmd/selfserv/selfserv.c
@@ -161,17 +161,17 @@ PrintUsageHeader(const char *progName)
             "         [-f password_file] [-L [seconds]] [-M maxProcs] [-P dbprefix]\n"
             "         [-V [min-version]:[max-version]] [-a sni_name]\n"
             "         [ T <good|revoked|unknown|badsig|corrupted|none|ocsp>] [-A ca]\n"
             "         [-C SSLCacheEntries] [-S dsa_nickname]"
 #ifndef NSS_DISABLE_ECC
             " [-e ec_nickname]"
 #endif /* NSS_DISABLE_ECC */
             "\n"
-            "         -U [0|1] -H [0|1] -W [0|1]\n",
+            "         -U [0|1] -H [0|1|2] -W [0|1]\n",
             progName);
 }
 
 static void
 PrintParameterUsage()
 {
     fputs(
         "-V [min]:[max] restricts the set of enabled SSL/TLS protocol versions.\n"
@@ -214,17 +214,18 @@ PrintParameterUsage()
         "   failure: return a failure response (try later, unsigned)\n"
         "   badsig: use a good status but with an invalid signature\n"
         "   corrupted: stapled cert status is an invalid block of data\n"
         "   random: each connection uses a random status from this list:\n"
         "           good, revoked, unknown, failure, badsig, corrupted\n"
         "   ocsp: fetch from external OCSP server using AIA, or none\n"
         "-A <ca> Nickname of a CA used to sign a stapled cert status\n"
         "-U override default ECDHE ephemeral key reuse, 0: refresh, 1: reuse\n"
-        "-H override default DHE server support, 0: disable, 1: enable\n"
+        "-H override default DHE server support, 0: disable, 1: enable, "
+            " 2: require DH named groups\n"
         "-W override default DHE server weak parameters support, 0: disable, 1: enable\n"
         "-c Restrict ciphers\n"
         "-Y prints cipher values allowed for parameter -c and exits\n"
         "-G enables the extended master secret extension [RFC7627]\n",
         stderr);
 }
 
 static void
@@ -1928,16 +1929,21 @@ server_main(
         }
     }
 
     if (configureDHE > -1) {
         rv = SSL_OptionSet(model_sock, SSL_ENABLE_SERVER_DHE, (configureDHE > 0));
         if (rv != SECSuccess) {
             errExit("error configuring server side DHE support");
         }
+        rv = SSL_OptionSet(model_sock, SSL_REQUIRE_DH_NAMED_GROUPS, (configureDHE > 1));
+        if (rv != SECSuccess) {
+            errExit("error configuring server side FFDHE support");
+        }
+        PORT_Assert(configureDHE <= 2);
     }
 
     if (configureReuseECDHE > -1) {
         rv = SSL_OptionSet(model_sock, SSL_REUSE_SERVER_ECDHE_KEY, (configureReuseECDHE > 0));
         if (rv != SECSuccess) {
             errExit("error configuring server side reuse of ECDHE key");
         }
     }
--- a/security/nss/cmd/tstclnt/tstclnt.c
+++ b/security/nss/cmd/tstclnt/tstclnt.c
@@ -250,16 +250,18 @@ PrintParameterUsage(void)
             "-F", "", "", "", "", "", "", "", "", "");
     fprintf(stderr, "%-20s Test -F allows 0=any (default), 1=only OCSP, 2=only CRL\n", "-M");
     fprintf(stderr, "%-20s Restrict ciphers\n", "-c ciphers");
     fprintf(stderr, "%-20s Print cipher values allowed for parameter -c and exit\n", "-Y");
     fprintf(stderr, "%-20s Enforce using an IPv4 destination address\n", "-4");
     fprintf(stderr, "%-20s Enforce using an IPv6 destination address\n", "-6");
     fprintf(stderr, "%-20s (Options -4 and -6 cannot be combined.)\n", "");
     fprintf(stderr, "%-20s Enable the extended master secret extension [RFC7627]\n", "-G");
+    fprintf(stderr, "%-20s Require the use of FFDHE supported groups "
+                    "[I-D.ietf-tls-negotiated-ff-dhe]\n", "-H");
 }
 
 static void
 Usage(const char *progName)
 {
     PrintUsageHeader(progName);
     PrintParameterUsage();
     exit(1);
@@ -911,16 +913,17 @@ main(int argc, char **argv)
     int useExportPolicy = 0;
     int enableSessionTickets = 0;
     int enableCompression = 0;
     int enableFalseStart = 0;
     int enableCertStatus = 0;
     int enableSignedCertTimestamps = 0;
     int forceFallbackSCSV = 0;
     int enableExtendedMasterSecret = 0;
+    PRBool requireDHNamedGroups = 0;
     PRSocketOptionData opt;
     PRNetAddr addr;
     PRPollDesc pollset[2];
     PRBool allowIPv4 = PR_TRUE;
     PRBool allowIPv6 = PR_TRUE;
     PRBool pingServerFirst = PR_FALSE;
     int pingTimeoutSeconds = -1;
     PRBool clientSpeaksFirst = PR_FALSE;
@@ -959,17 +962,17 @@ main(int argc, char **argv)
         if (sec > 0) {
             maxInterval = PR_SecondsToInterval(sec);
         }
     }
 
     SSL_VersionRangeGetSupported(ssl_variant_stream, &enabledVersions);
 
     optstate = PL_CreateOptState(argc, argv,
-                                 "46BCDFGKM:OR:STUV:W:Ya:bc:d:fgh:m:n:op:qr:st:uvw:xz");
+                                 "46BCDFGHKM:OR:STUV:W:Ya:bc:d:fgh:m:n:op:qr:st:uvw:xz");
     while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
         switch (optstate->option) {
             case '?':
             default:
                 Usage(progName);
                 break;
 
             case '4':
@@ -1002,16 +1005,20 @@ main(int argc, char **argv)
                 }
                 serverCertAuth.testFreshStatusFromSideChannel = PR_TRUE;
                 break;
 
             case 'G':
                 enableExtendedMasterSecret = PR_TRUE;
                 break;
 
+            case 'H':
+                requireDHNamedGroups = PR_TRUE;
+                break;
+
             case 'I': /* reserved for OCSP multi-stapling */
                 break;
 
             case 'O':
                 serverCertAuth.shouldPause = PR_FALSE;
                 break;
 
             case 'K':
@@ -1449,16 +1456,25 @@ main(int argc, char **argv)
     if (enableExtendedMasterSecret) {
         rv = SSL_OptionSet(s, SSL_ENABLE_EXTENDED_MASTER_SECRET, PR_TRUE);
         if (rv != SECSuccess) {
             SECU_PrintError(progName, "error enabling extended master secret");
             return 1;
         }
     }
 
+    /* require the use of fixed finite-field DH groups */
+    if (requireDHNamedGroups) {
+        rv = SSL_OptionSet(s, SSL_REQUIRE_DH_NAMED_GROUPS, PR_TRUE);
+        if (rv != SECSuccess) {
+            SECU_PrintError(progName, "error enabling extended master secret");
+            return 1;
+        }
+    }
+
     /* enable Signed Certificate Timestamps. */
     rv = SSL_OptionSet(s, SSL_ENABLE_SIGNED_CERT_TIMESTAMPS,
                        enableSignedCertTimestamps);
     if (rv != SECSuccess) {
         SECU_PrintError(progName, "error enabling signed cert timestamps");
         return 1;
     }
 
--- a/security/nss/coreconf/config.mk
+++ b/security/nss/coreconf/config.mk
@@ -204,15 +204,20 @@ DEFINES += -DNO_NSPR_10_SUPPORT
 # Hide old, deprecated, TLS cipher suite names when building NSS
 DEFINES += -DSSL_DISABLE_DEPRECATED_CIPHER_SUITE_NAMES
 
 # Mozilla's mozilla/modules/zlib/src/zconf.h adds the MOZ_Z_ prefix to zlib
 # exported symbols, which causes problem when NSS is built as part of Mozilla.
 # So we add a NSS_SSL_ENABLE_ZLIB variable to allow Mozilla to turn this off.
 NSS_SSL_ENABLE_ZLIB = 1
 
+# Allow disabling PKCS11 bypass.
+ifdef NSS_NO_PKCS11_BYPASS
+DEFINES += -DNO_PKCS11_BYPASS
+endif
+
 # Allow build-time configuration of TLS 1.3 (Experimental)
 ifdef NSS_ENABLE_TLS_1_3
 ifdef NSS_DISABLE_ECC
 $(error Setting NSS_ENABLE_TLS_1_3 and NSS_DISABLE_ECC isn't a good idea.)
 endif
 DEFINES += -DNSS_ENABLE_TLS_1_3
 endif
--- a/security/nss/coreconf/coreconf.dep
+++ b/security/nss/coreconf/coreconf.dep
@@ -5,8 +5,9 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSS in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
+
--- a/security/nss/external_tests/ssl_gtest/manifest.mn
+++ b/security/nss/external_tests/ssl_gtest/manifest.mn
@@ -7,23 +7,24 @@ DEPTH      = ../..
 MODULE = nss
 
 # These sources have access to libssl internals
 CSRCS = \
       libssl_internals.c \
       $(NULL)
 
 CPPSRCS = \
-      ssl_v2_client_hello_unittest.cc \
       ssl_agent_unittest.cc \
-      ssl_loopback_unittest.cc \
+      ssl_ciphersuite_unittest.cc \
+      ssl_dhe_unittest.cc \
       ssl_extension_unittest.cc \
+      ssl_gtest.cc \
+      ssl_loopback_unittest.cc \
       ssl_skip_unittest.cc \
-      ssl_ciphersuite_unittest.cc \
-      ssl_gtest.cc \
+      ssl_v2_client_hello_unittest.cc \
       test_io.cc \
       tls_agent.cc \
       tls_connect.cc \
       tls_hkdf_unittest.cc \
       tls_filter.cc \
       tls_parser.cc \
       $(NULL)
 
--- a/security/nss/external_tests/ssl_gtest/ssl_ciphersuite_unittest.cc
+++ b/security/nss/external_tests/ssl_gtest/ssl_ciphersuite_unittest.cc
@@ -14,26 +14,23 @@
 #include "tls_connect.h"
 #include "gtest_utils.h"
 
 namespace nss_test {
 
 // mode, version, cipher suite
 typedef std::tuple<std::string, uint16_t, uint16_t> CipherSuiteProfile;
 
-class TlsCipherSuiteTest
-    : public TlsConnectTestBase,
-      public ::testing::WithParamInterface<CipherSuiteProfile> {
+class TlsCipherSuiteTestBase : public TlsConnectTestBase {
  public:
-
-  TlsCipherSuiteTest()
-      : TlsConnectTestBase(TlsConnectTestBase::ToMode(std::get<0>(GetParam())),
-                           std::get<1>(GetParam())),
-        cipher_suite_(std::get<2>(GetParam()))
-      {}
+  TlsCipherSuiteTestBase(std::string mode, uint16_t version,
+                         uint16_t cipher_suite)
+    : TlsConnectTestBase(TlsConnectTestBase::ToMode(mode), version),
+      cipher_suite_(cipher_suite)
+    {}
 
  protected:
   uint16_t cipher_suite_;
 
   void SetupCertificate() {
     SSLCipherSuiteInfo csinfo;
     EXPECT_EQ(SECSuccess, SSL_GetCipherSuiteInfo(cipher_suite_,
                                                  &csinfo, sizeof(csinfo)));
@@ -61,69 +58,186 @@ class TlsCipherSuiteTest
   }
 
   void EnableSingleCipher() {
     EnsureTlsSetup();
     // It doesn't matter which does this, but the test is better if both do it.
     client_->EnableSingleCipher(cipher_suite_);
     server_->EnableSingleCipher(cipher_suite_);
   }
+
+  void ConnectAndCheckCipherSuite() {
+    Connect();
+    SendReceive();
+
+    // Check that we used the right cipher suite.
+    uint16_t actual;
+    EXPECT_TRUE(client_->cipher_suite(&actual) && actual == cipher_suite_);
+    EXPECT_TRUE(server_->cipher_suite(&actual) && actual == cipher_suite_);
+  }
+};
+
+class TlsCipherSuiteTest
+    : public TlsCipherSuiteTestBase,
+      public ::testing::WithParamInterface<CipherSuiteProfile> {
+
+ public:
+  TlsCipherSuiteTest()
+      : TlsCipherSuiteTestBase(std::get<0>(GetParam()),
+                               std::get<1>(GetParam()),
+                               std::get<2>(GetParam()))
+      {}
 };
 
+TEST_P(TlsCipherSuiteTest, SingleCipherSuite) {
+  SetupCertificate();
+  EnableSingleCipher();
+  ConnectAndCheckCipherSuite();
+}
 
-TEST_P(TlsCipherSuiteTest, ConnectWithCipherSuite) {
-  SetupCertificate();
+class TlsResumptionTest
+    : public TlsCipherSuiteTestBase,
+      public ::testing::WithParamInterface<CipherSuiteProfile> {
+
+ public:
+  TlsResumptionTest()
+      : TlsCipherSuiteTestBase(std::get<0>(GetParam()),
+                               std::get<1>(GetParam()),
+                               std::get<2>(GetParam()))
+      {}
+
+  bool SkipIfCipherSuiteIsDSA() {
+    SSLCipherSuiteInfo csinfo;
+    SECStatus rv = SSL_GetCipherSuiteInfo(cipher_suite_,
+                                          &csinfo, sizeof(csinfo));
+    if (rv != SECSuccess) {
+      EXPECT_TRUE(false) << "Can't get cipher suite info";
+      return false;
+    }
+    bool isDSA = csinfo.authType == ssl_auth_dsa;
+    if (isDSA) {
+      std::cerr << "Skipping DSA suite: " << csinfo.cipherSuiteName << std::endl;
+    }
+    return isDSA;
+  }
+
+  void EnablePskCipherSuite() {
+    SSLCipherSuiteInfo targetInfo;
+    ASSERT_EQ(SECSuccess, SSL_GetCipherSuiteInfo(cipher_suite_,
+                                                 &targetInfo,
+                                                 sizeof(targetInfo)));
+    SSLKEAType targetKea;
+    switch (targetInfo.keaType) {
+      case ssl_kea_ecdh:
+        targetKea = ssl_kea_ecdh_psk;
+        break;
+      case ssl_kea_dh:
+        targetKea = ssl_kea_dh_psk;
+        break;
+      default:
+        EXPECT_TRUE(false) << "Unsupported KEA type for "
+                           << targetInfo.cipherSuiteName;
+        return;
+    }
+
+    size_t count = SSL_GetNumImplementedCiphers();
+    const uint16_t *ciphers = SSL_GetImplementedCiphers();
+    bool found = false;
+    for (size_t i = 0; i < count; ++i) {
+      SSLCipherSuiteInfo candidateInfo;
+      ASSERT_EQ(SECSuccess, SSL_GetCipherSuiteInfo(ciphers[i],
+                                                   &candidateInfo,
+                                                   sizeof(candidateInfo)));
+      if (candidateInfo.authType == ssl_auth_psk &&
+          candidateInfo.keaType == targetKea &&
+          candidateInfo.symCipher == targetInfo.symCipher &&
+          candidateInfo.macAlgorithm == targetInfo.macAlgorithm) {
+        // We aren't able to check that the PRF hash is the same.  This is OK
+        // because there are (currently) no suites that have different PRF
+        // hashes but also use the same symmetric cipher.
+        EXPECT_EQ(SECSuccess,
+                  SSL_CipherPrefSet(client_->ssl_fd(), ciphers[i], PR_TRUE));
+        EXPECT_EQ(SECSuccess,
+                  SSL_CipherPrefSet(server_->ssl_fd(), ciphers[i], PR_TRUE));
+        found = true;
+      }
+    }
+    EXPECT_TRUE(found) << "Can't find matching PSK cipher for "
+                       << targetInfo.cipherSuiteName;
+  }
+};
+
+TEST_P(TlsResumptionTest, ResumeCipherSuite) {
+  if (SkipIfCipherSuiteIsDSA()) {
+    return; // Tickets don't work with DSA (bug 1174677).
+  }
+
+  SetupCertificate(); // This is only needed once.
+
+  ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
   EnableSingleCipher();
 
-  Connect();
-  SendReceive();
+  ConnectAndCheckCipherSuite();
 
-  // Check that we used the right cipher suite.
-  uint16_t actual;
-  EXPECT_TRUE(client_->cipher_suite(&actual) && actual == cipher_suite_);
-  EXPECT_TRUE(server_->cipher_suite(&actual) && actual == cipher_suite_);
+  Reset();
+  ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+  EnableSingleCipher();
+  // Enable a PSK cipher suite, since EnableSingleCipher() disabled all of them.
+  // On resumption in TLS 1.3, even though a PSK cipher suite is negotiated, the
+  // original cipher suite is reported through the API.  That is what makes this
+  // test work without more tweaks.
+  if (version_ == SSL_LIBRARY_VERSION_TLS_1_3) {
+    EnablePskCipherSuite();
+  }
+
+  ExpectResumption(RESUME_TICKET);
+  ConnectAndCheckCipherSuite();
 }
 
 // This awful macro makes the test instantiations easier to read.
 #define INSTANTIATE_CIPHER_TEST_P(name, modes, versions, ...)           \
   static const uint16_t k##name##CiphersArr[] = { __VA_ARGS__ };        \
   static const ::testing::internal::ParamGenerator<uint16_t>            \
     k##name##Ciphers = ::testing::ValuesIn(k##name##CiphersArr);        \
   INSTANTIATE_TEST_CASE_P(CipherSuite##name, TlsCipherSuiteTest,        \
                           ::testing::Combine(                           \
                                TlsConnectTestBase::kTlsModes##modes,    \
                                TlsConnectTestBase::kTls##versions,      \
+                               k##name##Ciphers));                      \
+  INSTANTIATE_TEST_CASE_P(Resume##name, TlsResumptionTest,              \
+                          ::testing::Combine(                           \
+                               TlsConnectTestBase::kTlsModes##modes,    \
+                               TlsConnectTestBase::kTls##versions,      \
                                k##name##Ciphers))
 
 // The cipher suites of type ECDH_RSA are disabled because we don't have
 // a compatible certificate in the test fixture.
 INSTANTIATE_CIPHER_TEST_P(RC4, Stream, V10ToV12,
                           TLS_RSA_WITH_RC4_128_SHA,
                           TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
                           TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
                           // TLS_ECDH_RSA_WITH_RC4_128_SHA,
                           TLS_ECDHE_RSA_WITH_RC4_128_SHA);
-// TODO - Bug 1251136 move DHE_RSA suites to V12Plus
 INSTANTIATE_CIPHER_TEST_P(AEAD12, All, V12,
                           TLS_RSA_WITH_AES_128_GCM_SHA256,
+                          TLS_RSA_WITH_AES_256_GCM_SHA384,
                           TLS_DHE_DSS_WITH_AES_128_GCM_SHA256,
                           TLS_DHE_DSS_WITH_AES_256_GCM_SHA384,
-                          TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
-                          TLS_RSA_WITH_AES_256_GCM_SHA384,
-                          TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
-                          TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
                           TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
                           TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384);
 INSTANTIATE_CIPHER_TEST_P(AEAD, All, V12Plus,
                           TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
                           TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
                           TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
                           TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+                          TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
+                          TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
                           TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
-                          TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256);
+                          TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
+                          TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256);
 INSTANTIATE_CIPHER_TEST_P(CBC12, All, V12,
                           TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
                           TLS_RSA_WITH_AES_256_CBC_SHA256,
                           TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
                           TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
                           TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
                           TLS_RSA_WITH_AES_128_CBC_SHA256,
                           TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,
new file mode 100644
--- /dev/null
+++ b/security/nss/external_tests/ssl_gtest/ssl_dhe_unittest.cc
@@ -0,0 +1,464 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "secerr.h"
+#include "ssl.h"
+#include "sslerr.h"
+#include "sslproto.h"
+#include <memory>
+#include <functional>
+
+#include "scoped_ptrs.h"
+#include "tls_parser.h"
+#include "tls_filter.h"
+#include "tls_connect.h"
+#include "gtest_utils.h"
+
+namespace nss_test {
+
+TEST_P(TlsConnectGeneric, ConnectDhe) {
+  EnableOnlyDheCiphers();
+  Connect();
+  CheckKeys(ssl_kea_dh, ssl_auth_rsa_sign);
+}
+
+TEST_P(TlsConnectGeneric, ConnectFfdheClient) {
+  EnableOnlyDheCiphers();
+  EXPECT_EQ(SECSuccess,
+            SSL_OptionSet(client_->ssl_fd(),
+                          SSL_REQUIRE_DH_NAMED_GROUPS, PR_TRUE));
+  auto clientCapture = new TlsExtensionCapture(ssl_supported_groups_xtn);
+  client_->SetPacketFilter(clientCapture);
+
+  Connect();
+
+  CheckKeys(ssl_kea_dh, ssl_auth_rsa_sign);
+
+  // Extension value: length + FFDHE 2048 group identifier.
+  const uint8_t val[] = { 0x00, 0x02, 0x01, 0x00 };
+  DataBuffer expected_groups(val, sizeof(val));
+  EXPECT_EQ(expected_groups, clientCapture->extension());
+}
+
+// Requiring the FFDHE extension on the server alone means that clients won't be
+// able to connect using a DHE suite.  They should still connect in TLS 1.3,
+// because the client automatically sends the supported groups extension.
+TEST_P(TlsConnectGenericPre13, ConnectFfdheServer) {
+  EnableOnlyDheCiphers();
+  EXPECT_EQ(SECSuccess,
+            SSL_OptionSet(server_->ssl_fd(),
+                          SSL_REQUIRE_DH_NAMED_GROUPS, PR_TRUE));
+
+  if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
+    Connect();
+    CheckKeys(ssl_kea_dh, ssl_auth_rsa_sign);
+  } else {
+    ConnectExpectFail();
+    client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
+    server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
+  }
+}
+
+class TlsDheServerKeyExchangeDamager : public TlsHandshakeFilter {
+ public:
+  TlsDheServerKeyExchangeDamager() {}
+  virtual PacketFilter::Action FilterHandshake(
+      const TlsHandshakeFilter::HandshakeHeader& header,
+      const DataBuffer& input, DataBuffer* output) {
+    if (header.handshake_type() != kTlsHandshakeServerKeyExchange) {
+      return KEEP;
+    }
+
+    // Damage the first octet of dh_p.  Anything other than the known prime will
+    // be rejected as "weak" when we have SSL_REQUIRE_DH_NAMED_GROUPS enabled.
+    *output = input;
+    output->data()[3] ^= 73;
+    return CHANGE;
+  }
+};
+
+// Changing the prime in the server's key share results in an error.  This will
+// invalidate the signature over the ServerKeyShare. That's ok, NSS won't check
+// the signature until everything else has been checked.
+TEST_P(TlsConnectGenericPre13, DamageServerKeyShare) {
+  EnableOnlyDheCiphers();
+  EXPECT_EQ(SECSuccess,
+            SSL_OptionSet(client_->ssl_fd(),
+                          SSL_REQUIRE_DH_NAMED_GROUPS, PR_TRUE));
+  server_->SetPacketFilter(new TlsDheServerKeyExchangeDamager());
+
+  ConnectExpectFail();
+
+  client_->CheckErrorCode(SSL_ERROR_WEAK_SERVER_EPHEMERAL_DH_KEY);
+  server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
+}
+
+class TlsDheSkeChangeY : public TlsHandshakeFilter {
+ public:
+  enum ChangeYTo {
+    kYZero,
+    kYOne,
+    kYPMinusOne,
+    kYGreaterThanP,
+    kYTooLarge,
+    kYZeroPad
+  };
+
+  TlsDheSkeChangeY(ChangeYTo change) : change_Y_(change) {}
+
+ protected:
+  void ChangeY(const DataBuffer& input, DataBuffer* output,
+               size_t offset, const DataBuffer& prime) {
+    static const uint8_t kExtraZero = 0;
+    static const uint8_t kTooLargeExtra = 1;
+
+    uint32_t dh_Ys_len;
+    EXPECT_TRUE(input.Read(offset, 2, &dh_Ys_len));
+    EXPECT_LT(offset + dh_Ys_len, input.len());
+    offset += 2;
+
+    // This isn't generally true, but our code pads.
+    EXPECT_EQ(prime.len(), dh_Ys_len)
+        << "Length of dh_Ys must equal length of dh_p";
+
+    *output = input;
+    switch (change_Y_) {
+      case kYZero:
+        memset(output->data() + offset, 0, prime.len());
+        break;
+
+      case kYOne:
+        memset(output->data() + offset, 0, prime.len() - 1);
+        output->Write(offset + prime.len() - 1, 1U, 1);
+        break;
+
+      case kYPMinusOne:
+        output->Write(offset, prime);
+        EXPECT_TRUE(output->data()[offset + prime.len() - 1] & 0x01)
+            << "P must at least be odd";
+        --output->data()[offset + prime.len() - 1];
+        break;
+
+      case kYGreaterThanP:
+        // Set the first 32 octets of Y to 0xff, except the first which we set
+        // to p[0].  This will make Y > p.  That is, unless p is Mersenne, or
+        // improbably large (but still the same bit length).  We currently only
+        // use a fixed prime that isn't a problem for this code.
+        EXPECT_LT(0, prime.data()[0]) << "dh_p should not be zero-padded";
+        offset = output->Write(offset, prime.data()[0], 1);
+        memset(output->data() + offset, 0xff, 31);
+        break;
+
+      case kYTooLarge:
+        // Increase the dh_Ys length.
+        output->Write(offset - 2, prime.len() + sizeof(kTooLargeExtra), 2);
+        // Then insert the octet.
+        output->Splice(&kTooLargeExtra, sizeof(kTooLargeExtra), offset);
+        break;
+
+      case kYZeroPad:
+        output->Write(offset - 2, prime.len() + sizeof(kExtraZero), 2);
+        output->Splice(&kExtraZero, sizeof(kExtraZero), offset);
+        break;
+    }
+  }
+
+ private:
+  ChangeYTo change_Y_;
+};
+
+class TlsDheSkeChangeYServer : public TlsDheSkeChangeY {
+ public:
+  TlsDheSkeChangeYServer(ChangeYTo change, bool modify)
+      : TlsDheSkeChangeY(change), modify_(modify), p_() {}
+
+  const DataBuffer& prime() const {
+    return p_;
+  }
+
+ protected:
+  virtual PacketFilter::Action FilterHandshake(
+      const TlsHandshakeFilter::HandshakeHeader& header,
+      const DataBuffer& input, DataBuffer* output) override {
+    if (header.handshake_type() != kTlsHandshakeServerKeyExchange) {
+      return KEEP;
+    }
+
+    size_t offset = 2;
+    // Read dh_p
+    uint32_t dh_len = 0;
+    EXPECT_TRUE(input.Read(0, 2, &dh_len));
+    EXPECT_GT(input.len(), offset + dh_len);
+    p_.Assign(input.data() + offset, dh_len);
+    offset += dh_len;
+
+    // Skip dh_g to find dh_Ys
+    EXPECT_TRUE(input.Read(offset, 2, &dh_len));
+    offset += 2 + dh_len;
+
+    if (modify_) {
+      ChangeY(input, output, offset, p_);
+      return CHANGE;
+    }
+    return KEEP;
+  }
+
+ private:
+  bool modify_;
+  DataBuffer p_;
+};
+
+class TlsDheSkeChangeYClient : public TlsDheSkeChangeY {
+ public:
+  TlsDheSkeChangeYClient(ChangeYTo change,
+                         const TlsDheSkeChangeYServer *server_filter)
+      : TlsDheSkeChangeY(change), server_filter_(server_filter) {}
+
+ protected:
+  virtual PacketFilter::Action FilterHandshake(
+      const TlsHandshakeFilter::HandshakeHeader& header,
+      const DataBuffer& input, DataBuffer* output) override {
+    if (header.handshake_type() != kTlsHandshakeClientKeyExchange) {
+      return KEEP;
+    }
+
+    ChangeY(input, output, 0, server_filter_->prime());
+    return CHANGE;
+  }
+
+ private:
+  const TlsDheSkeChangeYServer *server_filter_;
+};
+
+/* This matrix includes: mode (stream/datagram), TLS version, what change to
+ * make to dh_Ys, whether the client will be configured to require DH named
+ * groups.  Test all combinations. */
+typedef std::tuple<std::string, uint16_t,
+                   TlsDheSkeChangeY::ChangeYTo, bool> DamageDHYProfile;
+class TlsDamageDHYTest
+    : public TlsConnectTestBase,
+      public ::testing::WithParamInterface<DamageDHYProfile> {
+ public:
+  TlsDamageDHYTest()
+      : TlsConnectTestBase(TlsConnectTestBase::ToMode(std::get<0>(GetParam())),
+                           std::get<1>(GetParam())) {}
+};
+
+TEST_P(TlsDamageDHYTest, DamageServerY) {
+  EnableOnlyDheCiphers();
+  if (std::get<3>(GetParam())) {
+    EXPECT_EQ(SECSuccess,
+              SSL_OptionSet(client_->ssl_fd(),
+                            SSL_REQUIRE_DH_NAMED_GROUPS, PR_TRUE));
+  }
+  TlsDheSkeChangeY::ChangeYTo change = std::get<2>(GetParam());
+  server_->SetPacketFilter(new TlsDheSkeChangeYServer(change, true));
+
+  ConnectExpectFail();
+  if (change == TlsDheSkeChangeY::kYZeroPad) {
+    // Zero padding Y only manifests in a signature failure.
+    // In TLS 1.0 and 1.1, the client reports a device error.
+    if (version_ < SSL_LIBRARY_VERSION_TLS_1_2) {
+      client_->CheckErrorCode(SEC_ERROR_PKCS11_DEVICE_ERROR);
+    } else {
+      client_->CheckErrorCode(SEC_ERROR_BAD_SIGNATURE);
+    }
+    server_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
+  } else {
+    client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_DHE_KEY_SHARE);
+    server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
+  }
+}
+
+TEST_P(TlsDamageDHYTest, DamageClientY) {
+  EnableOnlyDheCiphers();
+  if (std::get<3>(GetParam())) {
+    EXPECT_EQ(SECSuccess,
+              SSL_OptionSet(client_->ssl_fd(),
+                            SSL_REQUIRE_DH_NAMED_GROUPS, PR_TRUE));
+  }
+  // The filter on the server is required to capture the prime.
+  TlsDheSkeChangeYServer* server_filter
+      = new TlsDheSkeChangeYServer(TlsDheSkeChangeY::kYZero, false);
+  server_->SetPacketFilter(server_filter);
+
+  // The client filter does the damage.
+  TlsDheSkeChangeY::ChangeYTo change = std::get<2>(GetParam());
+  client_->SetPacketFilter(
+      new TlsDheSkeChangeYClient(change, server_filter));
+
+  ConnectExpectFail();
+  if (change == TlsDheSkeChangeY::kYZeroPad) {
+    // Zero padding Y only manifests in a finished error.
+    client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
+    server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
+  } else {
+    client_->CheckErrorCode(SSL_ERROR_HANDSHAKE_FAILURE_ALERT);
+    server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_DHE_KEY_SHARE);
+  }
+}
+
+static const TlsDheSkeChangeY::ChangeYTo kAllYArr[] = {
+  TlsDheSkeChangeY::kYZero,
+  TlsDheSkeChangeY::kYOne,
+  TlsDheSkeChangeY::kYPMinusOne,
+  TlsDheSkeChangeY::kYGreaterThanP,
+  TlsDheSkeChangeY::kYTooLarge,
+  TlsDheSkeChangeY::kYZeroPad
+};
+static ::testing::internal::ParamGenerator<TlsDheSkeChangeY::ChangeYTo>
+  kAllY = ::testing::ValuesIn(kAllYArr);
+static const bool kTrueFalseArr[] = { true, false };
+static ::testing::internal::ParamGenerator<bool>
+  kTrueFalse = ::testing::ValuesIn(kTrueFalseArr);
+
+INSTANTIATE_TEST_CASE_P(DamageYStream, TlsDamageDHYTest,
+                        ::testing::Combine(
+                          TlsConnectTestBase::kTlsModesStream,
+                          TlsConnectTestBase::kTlsV10ToV12,
+                          kAllY, kTrueFalse));
+INSTANTIATE_TEST_CASE_P(DamageYDatagram, TlsDamageDHYTest,
+                        ::testing::Combine(
+                             TlsConnectTestBase::kTlsModesDatagram,
+                             TlsConnectTestBase::kTlsV11V12,
+                             kAllY, kTrueFalse));
+
+class TlsDheSkeMakePEven : public TlsHandshakeFilter {
+ public:
+  virtual PacketFilter::Action FilterHandshake(
+      const TlsHandshakeFilter::HandshakeHeader& header,
+      const DataBuffer& input, DataBuffer* output) {
+    if (header.handshake_type() != kTlsHandshakeServerKeyExchange) {
+      return KEEP;
+    }
+
+    // Find the end of dh_p
+    uint32_t dh_len = 0;
+    EXPECT_TRUE(input.Read(0, 2, &dh_len));
+    EXPECT_GT(input.len(), 2 + dh_len) << "enough space for dh_p";
+    size_t offset = 2 + dh_len - 1;
+    EXPECT_TRUE((input.data()[offset] & 0x01) == 0x01) << "p should be odd";
+
+    *output = input;
+    output->data()[offset] &= 0xfe;
+
+    return CHANGE;
+  }
+};
+
+// Even without requiring named groups, an even value for p is bad news.
+TEST_P(TlsConnectGenericPre13, MakeDhePEven) {
+  EnableOnlyDheCiphers();
+  server_->SetPacketFilter(new TlsDheSkeMakePEven());
+
+  ConnectExpectFail();
+
+  client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_DHE_KEY_SHARE);
+  server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
+}
+
+class TlsDheSkeZeroPadP : public TlsHandshakeFilter {
+ public:
+  virtual PacketFilter::Action FilterHandshake(
+      const TlsHandshakeFilter::HandshakeHeader& header,
+      const DataBuffer& input, DataBuffer* output) {
+    if (header.handshake_type() != kTlsHandshakeServerKeyExchange) {
+      return KEEP;
+    }
+
+    *output = input;
+    uint32_t dh_len = 0;
+    EXPECT_TRUE(input.Read(0, 2, &dh_len));
+    static const uint8_t kZeroPad = 0;
+    output->Write(0, dh_len + sizeof(kZeroPad), 2); // increment the length
+    output->Splice(&kZeroPad, sizeof(kZeroPad), 2); // insert a zero
+
+    return CHANGE;
+  }
+};
+
+// Zero padding only causes signature failure.
+TEST_P(TlsConnectGenericPre13, PadDheP) {
+  EnableOnlyDheCiphers();
+  server_->SetPacketFilter(new TlsDheSkeZeroPadP());
+
+  ConnectExpectFail();
+
+  // In TLS 1.0 and 1.1, the client reports a device error.
+  if (version_ < SSL_LIBRARY_VERSION_TLS_1_2) {
+    client_->CheckErrorCode(SEC_ERROR_PKCS11_DEVICE_ERROR);
+  } else {
+    client_->CheckErrorCode(SEC_ERROR_BAD_SIGNATURE);
+  }
+  server_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
+}
+
+// The server should not pick the weak DH group if the client includes FFDHE
+// named groups in the supported_groups extension. The server then picks a
+// commonly-supported named DH group and this connects.
+//
+// Note: This test case can take ages to generate the weak DH key.
+TEST_P(TlsConnectGenericPre13, WeakDHGroup) {
+  EnableOnlyDheCiphers();
+  EXPECT_EQ(SECSuccess,
+            SSL_OptionSet(client_->ssl_fd(),
+                          SSL_REQUIRE_DH_NAMED_GROUPS, PR_TRUE));
+  EXPECT_EQ(SECSuccess,
+            SSL_EnableWeakDHEPrimeGroup(server_->ssl_fd(), PR_TRUE));
+
+  Connect();
+}
+
+#ifdef NSS_ENABLE_TLS_1_3
+
+// In the absence of HelloRetryRequest, enabling only the 3072-bit group causes
+// the TLS 1.3 handshake to fail because the client will only add the 2048-bit
+// group to its ClientHello.
+TEST_P(TlsConnectTls13, DisableFfdhe2048) {
+  EnableOnlyDheCiphers();
+  static const SSLDHEGroupType groups[] = { ssl_ff_dhe_3072_group };
+  EXPECT_EQ(SECSuccess,
+            SSL_DHEGroupPrefSet(client_->ssl_fd(), groups,
+                                PR_ARRAY_SIZE(groups)));
+  EXPECT_EQ(SECSuccess,
+            SSL_DHEGroupPrefSet(server_->ssl_fd(), groups,
+                                PR_ARRAY_SIZE(groups)));
+  EXPECT_EQ(SECSuccess,
+            SSL_OptionSet(server_->ssl_fd(),
+                          SSL_REQUIRE_DH_NAMED_GROUPS, PR_TRUE));
+
+  ConnectExpectFail();
+
+  server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
+  client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
+}
+
+TEST_P(TlsConnectTls13, ResumeFfdhe) {
+  EnableOnlyDheCiphers();
+  ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+  Connect();
+  SendReceive(); // Need to read so that we absorb the session ticket.
+  CheckKeys(ssl_kea_dh, ssl_auth_rsa_sign);
+
+  Reset();
+  ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
+  EnableOnlyDheCiphers();
+  TlsExtensionCapture *clientCapture =
+      new TlsExtensionCapture(kTlsExtensionPreSharedKey);
+  client_->SetPacketFilter(clientCapture);
+  TlsExtensionCapture *serverCapture =
+      new TlsExtensionCapture(kTlsExtensionPreSharedKey);
+  server_->SetPacketFilter(serverCapture);
+  ExpectResumption(RESUME_TICKET);
+  Connect();
+  CheckKeys(ssl_kea_dh, ssl_auth_rsa_sign);
+  ASSERT_LT(0UL, clientCapture->extension().len());
+  ASSERT_LT(0UL, serverCapture->extension().len());
+}
+
+#endif // NSS_ENABLE_TLS_1_3
+
+} // namespace nss_test
--- a/security/nss/external_tests/ssl_gtest/ssl_extension_unittest.cc
+++ b/security/nss/external_tests/ssl_gtest/ssl_extension_unittest.cc
@@ -490,17 +490,17 @@ TEST_P(TlsExtensionTest12, SignatureAlgo
     {ssl_hash_sha512, ssl_sign_rsa},
     {ssl_hash_sha384, ssl_sign_ecdsa}
   };
 
   TlsExtensionCapture *capture =
     new TlsExtensionCapture(ssl_signature_algorithms_xtn);
   client_->SetSignatureAlgorithms(algorithms, PR_ARRAY_SIZE(algorithms));
   client_->SetPacketFilter(capture);
-  DisableDheAndEcdheCiphers();
+  EnableOnlyStaticRsaCiphers();
   Connect();
 
   const DataBuffer& ext = capture->extension();
   EXPECT_EQ(2 + PR_ARRAY_SIZE(algorithms) * 2, ext.len());
   for (size_t i = 0, cursor = 2;
        i < PR_ARRAY_SIZE(algorithms) && cursor < ext.len();
        ++i) {
     uint32_t v;
--- a/security/nss/external_tests/ssl_gtest/ssl_loopback_unittest.cc
+++ b/security/nss/external_tests/ssl_gtest/ssl_loopback_unittest.cc
@@ -123,17 +123,17 @@ TEST_P(TlsConnectGeneric, ConnectEcdsa) 
   Reset(TlsAgent::kServerEcdsa);
   Connect();
   CheckKeys(ssl_kea_ecdh, ssl_auth_ecdsa);
 }
 
 TEST_P(TlsConnectGenericPre13, ConnectEcdh) {
   SetExpectedVersion(std::get<1>(GetParam()));
   Reset(TlsAgent::kServerEcdhEcdsa);
-  DisableDheAndEcdheCiphers();
+  DisableAllCiphers();
   EnableSomeEcdhCiphers();
 
   Connect();
   CheckKeys(ssl_kea_ecdh, ssl_auth_ecdh_ecdsa);
 }
 
 TEST_P(TlsConnectGenericPre13, ConnectEcdhWithoutDisablingSuites) {
   SetExpectedVersion(std::get<1>(GetParam()));
@@ -432,23 +432,23 @@ TEST_P(TlsConnectGeneric, SignatureAlgor
 // There is no need for overlap on signatures; since we don't actually use the
 // signatures for static RSA, this should still connect successfully.
 // This should also work in TLS 1.0 and 1.1 where the algorithms aren't used.
 TEST_P(TlsConnectGenericPre13, SignatureAlgorithmNoOverlapStaticRsa) {
   client_->SetSignatureAlgorithms(SignatureRsaSha384,
                                   PR_ARRAY_SIZE(SignatureRsaSha384));
   server_->SetSignatureAlgorithms(SignatureRsaSha256,
                                   PR_ARRAY_SIZE(SignatureRsaSha256));
-  DisableDheAndEcdheCiphers();
+  EnableOnlyStaticRsaCiphers();
   Connect();
   CheckKeys(ssl_kea_rsa, ssl_auth_rsa_decrypt);
 }
 
 TEST_P(TlsConnectGenericPre13, ConnectStaticRSA) {
-  DisableDheAndEcdheCiphers();
+  EnableOnlyStaticRsaCiphers();
   Connect();
   CheckKeys(ssl_kea_rsa, ssl_auth_rsa_decrypt);
 }
 
 // Signature algorithms governs both verification and generation of signatures.
 // With ECDSA, we need to at least have a common signature algorithm configured.
 TEST_P(TlsConnectTls12, SignatureAlgorithmNoOverlapEcdsa) {
   Reset(TlsAgent::kServerEcdsa);
@@ -464,23 +464,21 @@ TEST_P(TlsConnectPre12, SignatureAlgorit
   Reset(TlsAgent::kServerEcdsa);
   client_->SetSignatureAlgorithms(SignatureEcdsaSha384,
                                   PR_ARRAY_SIZE(SignatureEcdsaSha384));
   server_->SetSignatureAlgorithms(SignatureEcdsaSha256,
                                   PR_ARRAY_SIZE(SignatureEcdsaSha256));
   Connect();
 }
 
-// The server requests client auth but doesn't offer a SHA-256 option.
-// This fails because NSS only uses SHA-256 for handshake transcript hashes.
-TEST_P(TlsConnectTls12, RequestClientAuthWithoutSha256) {
+TEST_P(TlsConnectTls12, RequestClientAuthWithSha384) {
   server_->SetSignatureAlgorithms(SignatureRsaSha384,
                                   PR_ARRAY_SIZE(SignatureRsaSha384));
   server_->RequestClientAuth(false);
-  ConnectExpectFail();
+  Connect();
 }
 
 TEST_P(TlsConnectGeneric, ConnectAlpn) {
   EnableAlpn();
   Connect();
   client_->CheckAlpn(SSL_NEXT_PROTO_SELECTED, "a");
   server_->CheckAlpn(SSL_NEXT_PROTO_NEGOTIATED, "a");
 }
@@ -571,58 +569,51 @@ TEST_P(TlsConnectStreamPre13, ConnectAnd
 TEST_P(TlsConnectStreamPre13, ConnectAndServerRenegotiate) {
   Connect();
   client_->PrepareForRenegotiate();
   server_->StartRenegotiate();
   Handshake();
   CheckConnected();
 }
 
-// TODO implement DHE for 1.3
-TEST_P(TlsConnectGenericPre13, ConnectDhe) {
-  DisableEcdheCiphers();
-  Connect();
-  CheckKeys(ssl_kea_dh, ssl_auth_rsa_sign);
-}
-
 // Test that a totally bogus EPMS is handled correctly.
 // This test is stream so we can catch the bad_record_mac alert.
 TEST_P(TlsConnectStreamPre13, ConnectStaticRSABogusCKE) {
-  DisableDheAndEcdheCiphers();
+  EnableOnlyStaticRsaCiphers();
   TlsInspectorReplaceHandshakeMessage* i1 =
       new TlsInspectorReplaceHandshakeMessage(kTlsHandshakeClientKeyExchange,
                                               DataBuffer(
                                                   kBogusClientKeyExchange,
                                                   sizeof(kBogusClientKeyExchange)));
   client_->SetPacketFilter(i1);
   auto alert_recorder = new TlsAlertRecorder();
   server_->SetPacketFilter(alert_recorder);
   ConnectExpectFail();
   EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
   EXPECT_EQ(kTlsAlertBadRecordMac, alert_recorder->description());
 }
 
 // Test that a PMS with a bogus version number is handled correctly.
 // This test is stream so we can catch the bad_record_mac alert.
 TEST_P(TlsConnectStreamPre13, ConnectStaticRSABogusPMSVersionDetect) {
-  DisableDheAndEcdheCiphers();
+  EnableOnlyStaticRsaCiphers();
   client_->SetPacketFilter(new TlsInspectorClientHelloVersionChanger(
       server_));
   auto alert_recorder = new TlsAlertRecorder();
   server_->SetPacketFilter(alert_recorder);
   ConnectExpectFail();
   EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
   EXPECT_EQ(kTlsAlertBadRecordMac, alert_recorder->description());
 }
 
 // Test that a PMS with a bogus version number is ignored when
 // rollback detection is disabled. This is a positive control for
 // ConnectStaticRSABogusPMSVersionDetect.
 TEST_P(TlsConnectGenericPre13, ConnectStaticRSABogusPMSVersionIgnore) {
-  DisableDheAndEcdheCiphers();
+  EnableOnlyStaticRsaCiphers();
   client_->SetPacketFilter(new TlsInspectorClientHelloVersionChanger(
       server_));
   server_->DisableRollbackDetection();
   Connect();
 }
 
 TEST_P(TlsConnectGeneric, ConnectEcdhe) {
   Connect();
@@ -739,54 +730,60 @@ TEST_P(TlsConnectGenericPre13, ConnectEx
   EnableExtendedMasterSecret();
   Connect();
   Reset();
   ExpectResumption(RESUME_SESSIONID);
   EnableExtendedMasterSecret();
   Connect();
 }
 
+TEST_P(TlsConnectTls12Plus, ConnectExtendedMasterSecretSha384) {
+  EnableExtendedMasterSecret();
+  server_->EnableSingleCipher(TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384);
+  ConnectWithCipherSuite(TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384);
+}
+
 TEST_P(TlsConnectGenericPre13, ConnectExtendedMasterSecretStaticRSA) {
-  DisableDheAndEcdheCiphers();
+  EnableOnlyStaticRsaCiphers();
   EnableExtendedMasterSecret();
   Connect();
 }
 
 // This test is stream so we can catch the bad_record_mac alert.
 TEST_P(TlsConnectStreamPre13, ConnectExtendedMasterSecretStaticRSABogusCKE) {
-  DisableDheAndEcdheCiphers();
+  EnableOnlyStaticRsaCiphers();
   EnableExtendedMasterSecret();
   TlsInspectorReplaceHandshakeMessage* inspect =
       new TlsInspectorReplaceHandshakeMessage(kTlsHandshakeClientKeyExchange,
                                               DataBuffer(
                                                   kBogusClientKeyExchange,
                                                   sizeof(kBogusClientKeyExchange)));
   client_->SetPacketFilter(inspect);
   auto alert_recorder = new TlsAlertRecorder();
   server_->SetPacketFilter(alert_recorder);
   ConnectExpectFail();
   EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
   EXPECT_EQ(kTlsAlertBadRecordMac, alert_recorder->description());
 }
 
 // This test is stream so we can catch the bad_record_mac alert.
 TEST_P(TlsConnectStreamPre13, ConnectExtendedMasterSecretStaticRSABogusPMSVersionDetect) {
-  DisableDheAndEcdheCiphers();
+  EnableOnlyStaticRsaCiphers();
   EnableExtendedMasterSecret();
   client_->SetPacketFilter(new TlsInspectorClientHelloVersionChanger(
       server_));
   auto alert_recorder = new TlsAlertRecorder();
   server_->SetPacketFilter(alert_recorder);
   ConnectExpectFail();
   EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
   EXPECT_EQ(kTlsAlertBadRecordMac, alert_recorder->description());
 }
 
 TEST_P(TlsConnectStreamPre13, ConnectExtendedMasterSecretStaticRSABogusPMSVersionIgnore) {
-  DisableDheAndEcdheCiphers();
+  EnableOnlyStaticRsaCiphers();
   EnableExtendedMasterSecret();
   client_->SetPacketFilter(new TlsInspectorClientHelloVersionChanger(
       server_));
   server_->DisableRollbackDetection();
   Connect();
 }
 
 TEST_P(TlsConnectGenericPre13, ConnectExtendedMasterSecretECDHE) {
@@ -1053,20 +1050,20 @@ TEST_F(TlsConnectTest, DisableClientPSKA
   ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
   TlsExtensionCapture *capture =
       new TlsExtensionCapture(kTlsExtensionPreSharedKey);
   client_->SetPacketFilter(capture);
   client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
                            SSL_LIBRARY_VERSION_TLS_1_3);
   server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
                            SSL_LIBRARY_VERSION_TLS_1_3);
-  EXPECT_EQ(SECSuccess,
-            SSL_CipherPrefSet(client_->ssl_fd(),
-                              TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256,
-                              PR_FALSE));
+  // We need to disable ALL PSK cipher suites with the same symmetric cipher and
+  // PRF hash.  Otherwise the server will just use a different key exchange.
+  client_->DisableAllCiphers();
+  client_->EnableCiphersByAuthType(ssl_auth_rsa_sign);
   ExpectResumption(RESUME_NONE);
   Connect();
   CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
   EXPECT_EQ(0U, capture->extension().len());
 }
 
 TEST_F(TlsConnectTest, DisableServerPSKAndFailToResume) {
   ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
@@ -1085,20 +1082,20 @@ TEST_F(TlsConnectTest, DisableServerPSKA
   client_->SetPacketFilter(clientCapture);
   TlsExtensionCapture *serverCapture =
       new TlsExtensionCapture(kTlsExtensionPreSharedKey);
   server_->SetPacketFilter(serverCapture);
   client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
                            SSL_LIBRARY_VERSION_TLS_1_3);
   server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
                            SSL_LIBRARY_VERSION_TLS_1_3);
-  EXPECT_EQ(SECSuccess,
-            SSL_CipherPrefSet(server_->ssl_fd(),
-                              TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256,
-                              PR_FALSE));
+  // We need to disable ALL PSK cipher suites with the same symmetric cipher and
+  // PRF hash.  Otherwise the server will just use a different key exchange.
+  server_->DisableAllCiphers();
+  server_->EnableCiphersByAuthType(ssl_auth_rsa_sign);
   ExpectResumption(RESUME_NONE);
   Connect();
   CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
   // The client should have the extension, but the server should not.
   EXPECT_LT(0U, clientCapture->extension().len());
   EXPECT_EQ(0U, serverCapture->extension().len());
 }
 
@@ -1363,16 +1360,32 @@ TEST_F(TlsConnectDatagram13, AuthComplet
         Poller::Timer *timer_handle;
         // This is really just to unroll the stack.
         Poller::Instance()->SetTimer(1U, client_, TriggerAuthComplete,
                                      &timer_handle);
         return SECWouldBlock;
       });
   Connect();
 }
+
+// The TLS v1.3 spec section C.4 states that 'Implementations MUST NOT send or
+// accept any records with a version less than { 3, 0 }'. Thus we will not
+// allow version ranges including both SSL v3 and TLS v1.3.
+TEST_F(TlsConnectTest, DisallowSSLv3HelloWithTLSv13Enabled) {
+  SECStatus rv;
+  SSLVersionRange vrange = { SSL_LIBRARY_VERSION_3_0,
+                             SSL_LIBRARY_VERSION_TLS_1_3 };
+
+  EnsureTlsSetup();
+  rv = SSL_VersionRangeSet(client_->ssl_fd(), &vrange);
+  EXPECT_EQ(SECFailure, rv);
+
+  rv = SSL_VersionRangeSet(server_->ssl_fd(), &vrange);
+  EXPECT_EQ(SECFailure, rv);
+}
 #endif // NSS_ENABLE_TLS_1_3
 
 INSTANTIATE_TEST_CASE_P(GenericStream, TlsConnectGeneric,
                         ::testing::Combine(
                           TlsConnectTestBase::kTlsModesStream,
                           TlsConnectTestBase::kTlsVAll));
 INSTANTIATE_TEST_CASE_P(GenericDatagram, TlsConnectGeneric,
                         ::testing::Combine(
@@ -1390,20 +1403,30 @@ INSTANTIATE_TEST_CASE_P(Pre12Stream, Tls
                           TlsConnectTestBase::kTlsV10V11));
 INSTANTIATE_TEST_CASE_P(Pre12Datagram, TlsConnectPre12,
                         ::testing::Combine(
                           TlsConnectTestBase::kTlsModesDatagram,
                           TlsConnectTestBase::kTlsV11));
 
 INSTANTIATE_TEST_CASE_P(Version12Only, TlsConnectTls12,
                         TlsConnectTestBase::kTlsModesAll);
+#ifdef NSS_ENABLE_TLS_1_3
+INSTANTIATE_TEST_CASE_P(Version13Only, TlsConnectTls13,
+                        TlsConnectTestBase::kTlsModesAll);
+#endif
 
 INSTANTIATE_TEST_CASE_P(Pre13Stream, TlsConnectGenericPre13,
                         ::testing::Combine(
                           TlsConnectTestBase::kTlsModesStream,
                           TlsConnectTestBase::kTlsV10ToV12));
 INSTANTIATE_TEST_CASE_P(Pre13Datagram, TlsConnectGenericPre13,
                         ::testing::Combine(
                              TlsConnectTestBase::kTlsModesDatagram,
                              TlsConnectTestBase::kTlsV11V12));
 INSTANTIATE_TEST_CASE_P(Pre13StreamOnly, TlsConnectStreamPre13,
                         TlsConnectTestBase::kTlsV10ToV12);
+
+INSTANTIATE_TEST_CASE_P(Version12Plus, TlsConnectTls12Plus,
+                        ::testing::Combine(
+                          TlsConnectTestBase::kTlsModesAll,
+                          TlsConnectTestBase::kTlsV12Plus));
+
 }  // namespace nspr_test
--- a/security/nss/external_tests/ssl_gtest/ssl_skip_unittest.cc
+++ b/security/nss/external_tests/ssl_gtest/ssl_skip_unittest.cc
@@ -99,17 +99,17 @@ class TlsSkipTest
     }
     ConnectExpectFail();
     EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
     EXPECT_EQ(alert, alert_recorder->description());
   }
 };
 
 TEST_P(TlsSkipTest, SkipCertificateRsa) {
-  DisableDheAndEcdheCiphers();
+  EnableOnlyStaticRsaCiphers();
   ServerSkipTest(new TlsHandshakeSkipFilter(kTlsHandshakeCertificate));
   client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_HELLO_DONE);
 }
 
 TEST_P(TlsSkipTest, SkipCertificateDhe) {
   ServerSkipTest(new TlsHandshakeSkipFilter(kTlsHandshakeCertificate));
   client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH);
 }
--- a/security/nss/external_tests/ssl_gtest/tls_agent.cc
+++ b/security/nss/external_tests/ssl_gtest/tls_agent.cc
@@ -209,56 +209,62 @@ void TlsAgent::StartConnect() {
   EXPECT_TRUE(EnsureTlsSetup());
 
   SECStatus rv;
   rv = SSL_ResetHandshake(ssl_fd_, role_ == SERVER ? PR_TRUE : PR_FALSE);
   EXPECT_EQ(SECSuccess, rv);
   SetState(STATE_CONNECTING);
 }
 
-void TlsAgent::DisableCiphersByKeyExchange(SSLKEAType kea) {
+void TlsAgent::DisableAllCiphers() {
+  for (size_t i = 0; i < SSL_NumImplementedCiphers; ++i) {
+    SECStatus rv = SSL_CipherPrefSet(ssl_fd_, SSL_ImplementedCiphers[i], PR_FALSE);
+    EXPECT_EQ(SECSuccess, rv);
+  }
+}
+
+void TlsAgent::EnableCiphersByKeyExchange(SSLKEAType kea) {
   EXPECT_TRUE(EnsureTlsSetup());
 
   for (size_t i = 0; i < SSL_NumImplementedCiphers; ++i) {
     SSLCipherSuiteInfo csinfo;
 
     SECStatus rv = SSL_GetCipherSuiteInfo(SSL_ImplementedCiphers[i],
                                           &csinfo, sizeof(csinfo));
     ASSERT_EQ(SECSuccess, rv);
     EXPECT_EQ(sizeof(csinfo), csinfo.length);
 
     if (csinfo.keaType == kea) {
-      rv = SSL_CipherPrefSet(ssl_fd_, SSL_ImplementedCiphers[i], PR_FALSE);
+      rv = SSL_CipherPrefSet(ssl_fd_, SSL_ImplementedCiphers[i], PR_TRUE);
       EXPECT_EQ(SECSuccess, rv);
     }
   }
 }
 
 void TlsAgent::EnableCiphersByAuthType(SSLAuthType authType) {
   EXPECT_TRUE(EnsureTlsSetup());
 
   for (size_t i = 0; i < SSL_NumImplementedCiphers; ++i) {
     SSLCipherSuiteInfo csinfo;
 
     SECStatus rv = SSL_GetCipherSuiteInfo(SSL_ImplementedCiphers[i],
                                           &csinfo, sizeof(csinfo));
     ASSERT_EQ(SECSuccess, rv);
 
-    bool enable = csinfo.authType == authType;
-    rv = SSL_CipherPrefSet(ssl_fd_, SSL_ImplementedCiphers[i], enable);
-    EXPECT_EQ(SECSuccess, rv);
+    if (csinfo.authType == authType) {
+      rv = SSL_CipherPrefSet(ssl_fd_, SSL_ImplementedCiphers[i], PR_TRUE);
+      EXPECT_EQ(SECSuccess, rv);
+    }
   }
 }
 
 void TlsAgent::EnableSingleCipher(uint16_t cipher) {
-  for (size_t i = 0; i < SSL_NumImplementedCiphers; ++i) {
-    bool enable = SSL_ImplementedCiphers[i] == cipher;
-    SECStatus rv = SSL_CipherPrefSet(ssl_fd_, SSL_ImplementedCiphers[i], enable);
-    EXPECT_EQ(SECSuccess, rv);
-  }
+  DisableAllCiphers();
+  SECStatus rv = SSL_CipherPrefSet(ssl_fd_, cipher, PR_TRUE);
+  EXPECT_EQ(SECSuccess, rv);
 }
 
 void TlsAgent::SetSessionTicketsEnabled(bool en) {
   EXPECT_TRUE(EnsureTlsSetup());
 
   SECStatus rv = SSL_OptionSet(ssl_fd_, SSL_ENABLE_SESSION_TICKETS,
                                en ? PR_TRUE : PR_FALSE);
   EXPECT_EQ(SECSuccess, rv);
@@ -649,16 +655,21 @@ void TlsAgent::SendData(size_t bytes, si
     LOG("Writing " << tosend << " bytes");
     int32_t rv = PR_Write(ssl_fd_, block, tosend);
     ASSERT_EQ(tosend, static_cast<size_t>(rv));
 
     bytes -= tosend;
   }
 }
 
+static bool ErrorIsNonFatal(PRErrorCode code) {
+  return code == PR_WOULD_BLOCK_ERROR ||
+      code == SSL_ERROR_RX_SHORT_DTLS_READ;
+}
+
 void TlsAgent::ReadBytes() {
   uint8_t block[1024];
 
   int32_t rv = PR_Read(ssl_fd_, block, sizeof(block));
   LOG("ReadBytes " << rv);
   int32_t err;
 
   if (rv >= 0) {
@@ -671,17 +682,17 @@ void TlsAgent::ReadBytes() {
     err = PR_GetError();
     LOG("Read error " << err << ": " << PORT_ErrorToString(err));
     if (err != PR_WOULD_BLOCK_ERROR && expected_read_error_) {
       error_code_ = err;
     }
   }
 
   // If closed, then don't bother waiting around.
-  if (rv > 0 || (rv < 0 && err == PR_WOULD_BLOCK_ERROR)) {
+  if (rv > 0 || (rv < 0 && ErrorIsNonFatal(err))) {
     LOG("Re-arming");
     Poller::Instance()->Wait(READABLE_EVENT, adapter_, this,
                              &TlsAgent::ReadableCallback);
   }
 }
 
 void TlsAgent::ResetSentBytes() {
   send_ctr_ = 0;
@@ -717,19 +728,18 @@ void TlsAgentTestBase::TearDown() {
   SSL_ShutdownServerSessionIDCache();
 }
 
 void TlsAgentTestBase::Init() {
   agent_ = new TlsAgent(
       role_ == TlsAgent::CLIENT ? TlsAgent::kClient : TlsAgent::kServerRsa,
       role_, mode_);
   agent_->Init();
-  fd_ = DummyPrSocket::CreateFD("dummy", mode_);
-  agent_->adapter()->SetPeer(
-      DummyPrSocket::GetAdapter(fd_));
+  fd_ = DummyPrSocket::CreateFD(agent_->role_str(), mode_);
+  agent_->adapter()->SetPeer(DummyPrSocket::GetAdapter(fd_));
   agent_->StartConnect();
 }
 
 void TlsAgentTestBase::EnsureInit() {
   if (!agent_) {
     Init();
   }
 }
--- a/security/nss/external_tests/ssl_gtest/tls_agent.h
+++ b/security/nss/external_tests/ssl_gtest/tls_agent.h
@@ -15,17 +15,17 @@
 
 #include "test_io.h"
 
 #define GTEST_HAS_RTTI 0
 #include "gtest/gtest.h"
 
 namespace nss_test {
 
-#define LOG(msg) std::cerr << name_ << ": " << msg << std::endl
+#define LOG(msg) std::cerr << role_str() << ": " << msg << std::endl
 
 enum SessionResumptionMode {
   RESUME_NONE = 0,
   RESUME_SESSIONID = 1,
   RESUME_TICKET = 2,
   RESUME_BOTH = RESUME_SESSIONID | RESUME_TICKET
 };
 
@@ -57,17 +57,17 @@ class TlsAgent : public PollTarget {
   static const std::string kServerEcdhEcdsa;
   // TODO: static const std::string kServerEcdhRsa;
   static const std::string kServerDsa;
 
   TlsAgent(const std::string& name, Role role, Mode mode);
   virtual ~TlsAgent();
 
   bool Init() {
-    pr_fd_ = DummyPrSocket::CreateFD(name_, mode_);
+    pr_fd_ = DummyPrSocket::CreateFD(role_str(), mode_);
     if (!pr_fd_) return false;
 
     adapter_ = DummyPrSocket::GetAdapter(pr_fd_);
     if (!adapter_) return false;
 
     return true;
   }
 
@@ -77,24 +77,26 @@ class TlsAgent : public PollTarget {
     adapter_->SetPacketFilter(filter);
   }
 
 
   void StartConnect();
   void CheckKEAType(SSLKEAType type) const;
   void CheckAuthType(SSLAuthType type) const;
 
+  void DisableAllCiphers();
+  void EnableCiphersByAuthType(SSLAuthType authType);
+  void EnableCiphersByKeyExchange(SSLKEAType kea);
+  void EnableSingleCipher(uint16_t cipher);
+
   void Handshake();
   // Marks the internal state as CONNECTING in anticipation of renegotiation.
   void PrepareForRenegotiate();
   // Prepares for renegotiation, then actually triggers it.
   void StartRenegotiate();
-  void DisableCiphersByKeyExchange(SSLKEAType kea);
-  void EnableCiphersByAuthType(SSLAuthType authType);
-  void EnableSingleCipher(uint16_t cipher);
   bool ConfigServerCert(const std::string& name, bool updateKeyBits = false);
   bool EnsureTlsSetup();
 
   void SetupClientAuth();
   void RequestClientAuth(bool requireAuth);
   bool GetClientAuthCredentials(CERTCertificate** cert,
                                 SECKEYPrivateKey** priv) const;
 
@@ -127,16 +129,17 @@ class TlsAgent : public PollTarget {
   void CheckExtendedMasterSecret(bool expected);
   void DisableRollbackDetection();
   void EnableCompression();
   void SetDowngradeCheckVersion(uint16_t version);
 
   const std::string& name() const { return name_; }
 
   Role role() const { return role_; }
+  std::string role_str() const { return role_ == SERVER ? "server" : "client"; }
 
   State state() const { return state_; }
 
   const CERTCertificate* peer_cert() const {
     return SSL_PeerCertificate(ssl_fd_);
   }
 
   const char* state_str() const { return state_str(state()); }
--- a/security/nss/external_tests/ssl_gtest/tls_connect.cc
+++ b/security/nss/external_tests/ssl_gtest/tls_connect.cc
@@ -289,42 +289,55 @@ void TlsConnectTestBase::ConnectExpectFa
   ASSERT_EQ(TlsAgent::STATE_ERROR, server_->state());
 }
 
 void TlsConnectTestBase::SetExpectedVersion(uint16_t version) {
   client_->SetExpectedVersion(version);
   server_->SetExpectedVersion(version);
 }
 
-void TlsConnectTestBase::DisableDheCiphers() {
-  client_->DisableCiphersByKeyExchange(ssl_kea_dh);
-  server_->DisableCiphersByKeyExchange(ssl_kea_dh);
+void TlsConnectTestBase::DisableAllCiphers() {
+  EnsureTlsSetup();
+  client_->DisableAllCiphers();
+  server_->DisableAllCiphers();
 }
 
-void TlsConnectTestBase::DisableEcdheCiphers() {
-  client_->DisableCiphersByKeyExchange(ssl_kea_ecdh);
-  server_->DisableCiphersByKeyExchange(ssl_kea_ecdh);
+void TlsConnectTestBase::EnableOnlyStaticRsaCiphers() {
+  DisableAllCiphers();
+
+  client_->EnableCiphersByKeyExchange(ssl_kea_rsa);
+  server_->EnableCiphersByKeyExchange(ssl_kea_rsa);
 }
 
-void TlsConnectTestBase::DisableDheAndEcdheCiphers() {
-  DisableDheCiphers();
-  DisableEcdheCiphers();
+void TlsConnectTestBase::EnableOnlyDheCiphers() {
+  DisableAllCiphers();
+
+  client_->EnableCiphersByKeyExchange(ssl_kea_dh);
+  client_->EnableCiphersByKeyExchange(ssl_kea_dh_psk);
+  server_->EnableCiphersByKeyExchange(ssl_kea_dh);
+  server_->EnableCiphersByKeyExchange(ssl_kea_dh_psk);
 }
 
 void TlsConnectTestBase::EnableSomeEcdhCiphers() {
   client_->EnableCiphersByAuthType(ssl_auth_ecdh_rsa);
   client_->EnableCiphersByAuthType(ssl_auth_ecdh_ecdsa);
   server_->EnableCiphersByAuthType(ssl_auth_ecdh_rsa);
   server_->EnableCiphersByAuthType(ssl_auth_ecdh_ecdsa);
 }
 
 void TlsConnectTestBase::ConfigureSessionCache(SessionResumptionMode client,
                                                SessionResumptionMode server) {
   client_->ConfigureSessionCache(client);
   server_->ConfigureSessionCache(server);
+  if ((server & RESUME_TICKET) != 0) {
+    // This is an abomination.  NSS encrypts session tickets with the server's
+    // RSA public key.  That means we need the server to have an RSA certificate
+    // even if it won't be used for the connection.
+    server_->ConfigServerCert(TlsAgent::kServerRsaDecrypt);
+  }
 }
 
 void TlsConnectTestBase::CheckResumption(SessionResumptionMode expected) {
   EXPECT_NE(RESUME_BOTH, expected);
 
   int resume_ct = expected ? 1 : 0;
   int stateless_ct = (expected & RESUME_TICKET) ? 1 : 0;
 
@@ -396,9 +409,19 @@ TlsConnectGeneric::TlsConnectGeneric()
 TlsConnectPre12::TlsConnectPre12()
   : TlsConnectTestBase(TlsConnectTestBase::ToMode(std::get<0>(GetParam())),
                        std::get<1>(GetParam())) {}
 
 TlsConnectTls12::TlsConnectTls12()
   : TlsConnectTestBase(TlsConnectTestBase::ToMode(GetParam()),
                        SSL_LIBRARY_VERSION_TLS_1_2) {}
 
+TlsConnectTls12Plus::TlsConnectTls12Plus()
+  : TlsConnectTestBase(TlsConnectTestBase::ToMode(std::get<0>(GetParam())),
+                       std::get<1>(GetParam())) {}
+
+#ifdef NSS_ENABLE_TLS_1_3
+TlsConnectTls13::TlsConnectTls13()
+  : TlsConnectTestBase(TlsConnectTestBase::ToMode(GetParam()),
+                       SSL_LIBRARY_VERSION_TLS_1_3) {}
+#endif
+
 } // namespace nss_test
--- a/security/nss/external_tests/ssl_gtest/tls_connect.h
+++ b/security/nss/external_tests/ssl_gtest/tls_connect.h
@@ -68,19 +68,19 @@ class TlsConnectTestBase : public ::test
   // Connect and expect it to fail.
   void ConnectExpectFail();
   void ConnectWithCipherSuite(uint16_t cipher_suite);
   void CheckKeys(SSLKEAType akeyType, SSLAuthType authType) const;
 
   void SetExpectedVersion(uint16_t version);
   // Expect resumption of a particular type.
   void ExpectResumption(SessionResumptionMode expected);
-  void DisableDheAndEcdheCiphers();
-  void DisableDheCiphers();
-  void DisableEcdheCiphers();
+  void DisableAllCiphers();
+  void EnableOnlyStaticRsaCiphers();
+  void EnableOnlyDheCiphers();
   void EnableSomeEcdhCiphers();
   void EnableExtendedMasterSecret();
   void ConfigureSessionCache(SessionResumptionMode client,
                              SessionResumptionMode server);
   void EnableAlpn();
   void EnableSrtp();
   void CheckSrtp() const;
   void SendReceive();
@@ -153,18 +153,33 @@ class TlsConnectPre12
 // A TLS 1.2 only generic test.
 class TlsConnectTls12
   : public TlsConnectTestBase,
     public ::testing::WithParamInterface<std::string> {
  public:
   TlsConnectTls12();
 };
 
+// A TLS 1.2+ generic test.
+class TlsConnectTls12Plus
+  : public TlsConnectTestBase,
+    public ::testing::WithParamInterface<std::tuple<std::string, uint16_t>> {
+ public:
+  TlsConnectTls12Plus();
+};
+
 #ifdef NSS_ENABLE_TLS_1_3
 // A TLS 1.3 only generic test.
+class TlsConnectTls13
+  : public TlsConnectTestBase,
+    public ::testing::WithParamInterface<std::string> {
+ public:
+  TlsConnectTls13();
+};
+
 class TlsConnectDatagram13
   : public TlsConnectTestBase {
  public:
   TlsConnectDatagram13()
       : TlsConnectTestBase(DGRAM, SSL_LIBRARY_VERSION_TLS_1_3) {}
 };
 #endif
 
--- a/security/nss/lib/ckfw/builtins/certdata.txt
+++ b/security/nss/lib/ckfw/builtins/certdata.txt
@@ -4675,136 +4675,16 @@ CKA_SERIAL_NUMBER MULTILINE_OCTAL
 \002\001\000
 END
 CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
 CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
 CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
 CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE
 
 #
-# Certificate "Sonera Class 1 Root CA"
-#
-# Issuer: CN=Sonera Class1 CA,O=Sonera,C=FI
-# Serial Number: 36 (0x24)
-# Subject: CN=Sonera Class1 CA,O=Sonera,C=FI
-# Not Valid Before: Fri Apr 06 10:49:13 2001
-# Not Valid After : Tue Apr 06 10:49:13 2021
-# Fingerprint (MD5): 33:B7:84:F5:5F:27:D7:68:27:DE:14:DE:12:2A:ED:6F
-# Fingerprint (SHA1): 07:47:22:01:99:CE:74:B9:7C:B0:3D:79:B2:64:A2:C8:55:E9:33:FF
-CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE
-CKA_TOKEN CK_BBOOL CK_TRUE
-CKA_PRIVATE CK_BBOOL CK_FALSE
-CKA_MODIFIABLE CK_BBOOL CK_FALSE
-CKA_LABEL UTF8 "Sonera Class 1 Root CA"
-CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509
-CKA_SUBJECT MULTILINE_OCTAL
-\060\071\061\013\060\011\006\003\125\004\006\023\002\106\111\061
-\017\060\015\006\003\125\004\012\023\006\123\157\156\145\162\141
-\061\031\060\027\006\003\125\004\003\023\020\123\157\156\145\162
-\141\040\103\154\141\163\163\061\040\103\101
-END
-CKA_ID UTF8 "0"
-CKA_ISSUER MULTILINE_OCTAL
-\060\071\061\013\060\011\006\003\125\004\006\023\002\106\111\061
-\017\060\015\006\003\125\004\012\023\006\123\157\156\145\162\141
-\061\031\060\027\006\003\125\004\003\023\020\123\157\156\145\162
-\141\040\103\154\141\163\163\061\040\103\101
-END
-CKA_SERIAL_NUMBER MULTILINE_OCTAL
-\002\001\044
-END
-CKA_VALUE MULTILINE_OCTAL
-\060\202\003\040\060\202\002\010\240\003\002\001\002\002\001\044
-\060\015\006\011\052\206\110\206\367\015\001\001\005\005\000\060
-\071\061\013\060\011\006\003\125\004\006\023\002\106\111\061\017
-\060\015\006\003\125\004\012\023\006\123\157\156\145\162\141\061
-\031\060\027\006\003\125\004\003\023\020\123\157\156\145\162\141
-\040\103\154\141\163\163\061\040\103\101\060\036\027\015\060\061
-\060\064\060\066\061\060\064\071\061\063\132\027\015\062\061\060
-\064\060\066\061\060\064\071\061\063\132\060\071\061\013\060\011
-\006\003\125\004\006\023\002\106\111\061\017\060\015\006\003\125
-\004\012\023\006\123\157\156\145\162\141\061\031\060\027\006\003
-\125\004\003\023\020\123\157\156\145\162\141\040\103\154\141\163
-\163\061\040\103\101\060\202\001\042\060\015\006\011\052\206\110
-\206\367\015\001\001\001\005\000\003\202\001\017\000\060\202\001
-\012\002\202\001\001\000\265\211\037\053\117\147\012\171\377\305
-\036\370\177\074\355\321\176\332\260\315\155\057\066\254\064\306
-\333\331\144\027\010\143\060\063\042\212\114\356\216\273\017\015
-\102\125\311\235\056\245\357\367\247\214\303\253\271\227\313\216
-\357\077\025\147\250\202\162\143\123\017\101\214\175\020\225\044
-\241\132\245\006\372\222\127\235\372\245\001\362\165\351\037\274
-\126\046\122\116\170\031\145\130\125\003\130\300\024\256\214\174
-\125\137\160\133\167\043\006\066\227\363\044\265\232\106\225\344
-\337\015\013\005\105\345\321\362\035\202\273\306\023\340\376\252
-\172\375\151\060\224\363\322\105\205\374\362\062\133\062\336\350
-\154\135\037\313\244\042\164\260\200\216\135\224\367\006\000\113
-\251\324\136\056\065\120\011\363\200\227\364\014\027\256\071\330
-\137\315\063\301\034\312\211\302\042\367\105\022\355\136\022\223
-\235\143\253\202\056\271\353\102\101\104\313\112\032\000\202\015
-\236\371\213\127\076\114\307\027\355\054\213\162\063\137\162\172
-\070\126\325\346\331\256\005\032\035\165\105\261\313\245\045\034
-\022\127\066\375\042\067\002\003\001\000\001\243\063\060\061\060
-\017\006\003\125\035\023\001\001\377\004\005\060\003\001\001\377
-\060\021\006\003\125\035\016\004\012\004\010\107\342\014\213\366
-\123\210\122\060\013\006\003\125\035\017\004\004\003\002\001\006
-\060\015\006\011\052\206\110\206\367\015\001\001\005\005\000\003
-\202\001\001\000\213\032\262\311\135\141\264\341\271\053\271\123
-\321\262\205\235\167\216\026\356\021\075\333\302\143\331\133\227
-\145\373\022\147\330\052\134\266\253\345\136\303\267\026\057\310
-\350\253\035\212\375\253\032\174\325\137\143\317\334\260\335\167
-\271\250\346\322\042\070\207\007\024\331\377\276\126\265\375\007
-\016\074\125\312\026\314\247\246\167\067\373\333\134\037\116\131
-\006\207\243\003\103\365\026\253\267\204\275\116\357\237\061\067
-\360\106\361\100\266\321\014\245\144\370\143\136\041\333\125\116
-\117\061\166\234\020\141\216\266\123\072\243\021\276\257\155\174
-\036\275\256\055\342\014\151\307\205\123\150\242\141\272\305\076
-\264\171\124\170\236\012\307\002\276\142\321\021\202\113\145\057
-\221\132\302\250\207\261\126\150\224\171\371\045\367\301\325\256
-\032\270\273\075\217\251\212\070\025\367\163\320\132\140\321\200
-\260\360\334\325\120\315\116\356\222\110\151\355\262\043\036\060
-\314\310\224\310\266\365\073\206\177\077\246\056\237\366\076\054
-\265\222\226\076\337\054\223\212\377\201\214\017\017\131\041\031
-\127\275\125\232
-END
-
-# Trust for Certificate "Sonera Class 1 Root CA"
-# Issuer: CN=Sonera Class1 CA,O=Sonera,C=FI
-# Serial Number: 36 (0x24)
-# Subject: CN=Sonera Class1 CA,O=Sonera,C=FI
-# Not Valid Before: Fri Apr 06 10:49:13 2001
-# Not Valid After : Tue Apr 06 10:49:13 2021
-# Fingerprint (MD5): 33:B7:84:F5:5F:27:D7:68:27:DE:14:DE:12:2A:ED:6F
-# Fingerprint (SHA1): 07:47:22:01:99:CE:74:B9:7C:B0:3D:79:B2:64:A2:C8:55:E9:33:FF
-CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST
-CKA_TOKEN CK_BBOOL CK_TRUE
-CKA_PRIVATE CK_BBOOL CK_FALSE
-CKA_MODIFIABLE CK_BBOOL CK_FALSE
-CKA_LABEL UTF8 "Sonera Class 1 Root CA"
-CKA_CERT_SHA1_HASH MULTILINE_OCTAL
-\007\107\042\001\231\316\164\271\174\260\075\171\262\144\242\310
-\125\351\063\377
-END
-CKA_CERT_MD5_HASH MULTILINE_OCTAL
-\063\267\204\365\137\047\327\150\047\336\024\336\022\052\355\157
-END
-CKA_ISSUER MULTILINE_OCTAL
-\060\071\061\013\060\011\006\003\125\004\006\023\002\106\111\061
-\017\060\015\006\003\125\004\012\023\006\123\157\156\145\162\141
-\061\031\060\027\006\003\125\004\003\023\020\123\157\156\145\162
-\141\040\103\154\141\163\163\061\040\103\101
-END
-CKA_SERIAL_NUMBER MULTILINE_OCTAL
-\002\001\044
-END
-CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
-CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
-CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
-CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE
-
-#
 # Certificate "Sonera Class 2 Root CA"
 #
 # Issuer: CN=Sonera Class2 CA,O=Sonera,C=FI
 # Serial Number: 29 (0x1d)
 # Subject: CN=Sonera Class2 CA,O=Sonera,C=FI
 # Not Valid Before: Fri Apr 06 07:29:40 2001
 # Not Valid After : Tue Apr 06 07:29:40 2021
 # Fingerprint (MD5): A3:EC:75:0F:2E:88:DF:FA:48:01:4E:0B:5C:48:6F:FB
@@ -29227,8 +29107,1026 @@ END
 CKA_SERIAL_NUMBER MULTILINE_OCTAL
 \002\020\041\326\320\112\117\045\017\311\062\067\374\252\136\022
 \215\351
 END
 CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
 CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
 CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
 CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE
+
+#
+# Certificate "Hellenic Academic and Research Institutions RootCA 2015"
+#
+# Issuer: CN=Hellenic Academic and Research Institutions RootCA 2015,O=Hellenic Academic and Research Institutions Cert. Authority,L=Athens,C=GR
+# Serial Number: 0 (0x0)
+# Subject: CN=Hellenic Academic and Research Institutions RootCA 2015,O=Hellenic Academic and Research Institutions Cert. Authority,L=Athens,C=GR
+# Not Valid Before: Tue Jul 07 10:11:21 2015
+# Not Valid After : Sat Jun 30 10:11:21 2040
+# Fingerprint (SHA-256): A0:40:92:9A:02:CE:53:B4:AC:F4:F2:FF:C6:98:1C:E4:49:6F:75:5E:6D:45:FE:0B:2A:69:2B:CD:52:52:3F:36
+# Fingerprint (SHA1): 01:0C:06:95:A6:98:19:14:FF:BF:5F:C6:B0:B6:95:EA:29:E9:12:A6
+CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE
+CKA_TOKEN CK_BBOOL CK_TRUE
+CKA_PRIVATE CK_BBOOL CK_FALSE
+CKA_MODIFIABLE CK_BBOOL CK_FALSE
+CKA_LABEL UTF8 "Hellenic Academic and Research Institutions RootCA 2015"
+CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509
+CKA_SUBJECT MULTILINE_OCTAL
+\060\201\246\061\013\060\011\006\003\125\004\006\023\002\107\122
+\061\017\060\015\006\003\125\004\007\023\006\101\164\150\145\156
+\163\061\104\060\102\006\003\125\004\012\023\073\110\145\154\154
+\145\156\151\143\040\101\143\141\144\145\155\151\143\040\141\156
+\144\040\122\145\163\145\141\162\143\150\040\111\156\163\164\151
+\164\165\164\151\157\156\163\040\103\145\162\164\056\040\101\165
+\164\150\157\162\151\164\171\061\100\060\076\006\003\125\004\003
+\023\067\110\145\154\154\145\156\151\143\040\101\143\141\144\145
+\155\151\143\040\141\156\144\040\122\145\163\145\141\162\143\150
+\040\111\156\163\164\151\164\165\164\151\157\156\163\040\122\157
+\157\164\103\101\040\062\060\061\065
+END
+CKA_ID UTF8 "0"
+CKA_ISSUER MULTILINE_OCTAL
+\060\201\246\061\013\060\011\006\003\125\004\006\023\002\107\122
+\061\017\060\015\006\003\125\004\007\023\006\101\164\150\145\156
+\163\061\104\060\102\006\003\125\004\012\023\073\110\145\154\154
+\145\156\151\143\040\101\143\141\144\145\155\151\143\040\141\156
+\144\040\122\145\163\145\141\162\143\150\040\111\156\163\164\151
+\164\165\164\151\157\156\163\040\103\145\162\164\056\040\101\165
+\164\150\157\162\151\164\171\061\100\060\076\006\003\125\004\003
+\023\067\110\145\154\154\145\156\151\143\040\101\143\141\144\145
+\155\151\143\040\141\156\144\040\122\145\163\145\141\162\143\150
+\040\111\156\163\164\151\164\165\164\151\157\156\163\040\122\157
+\157\164\103\101\040\062\060\061\065
+END
+CKA_SERIAL_NUMBER MULTILINE_OCTAL
+\002\001\000
+END
+CKA_VALUE MULTILINE_OCTAL
+\060\202\006\013\060\202\003\363\240\003\002\001\002\002\001\000
+\060\015\006\011\052\206\110\206\367\015\001\001\013\005\000\060
+\201\246\061\013\060\011\006\003\125\004\006\023\002\107\122\061
+\017\060\015\006\003\125\004\007\023\006\101\164\150\145\156\163
+\061\104\060\102\006\003\125\004\012\023\073\110\145\154\154\145
+\156\151\143\040\101\143\141\144\145\155\151\143\040\141\156\144
+\040\122\145\163\145\141\162\143\150\040\111\156\163\164\151\164
+\165\164\151\157\156\163\040\103\145\162\164\056\040\101\165\164
+\150\157\162\151\164\171\061\100\060\076\006\003\125\004\003\023
+\067\110\145\154\154\145\156\151\143\040\101\143\141\144\145\155
+\151\143\040\141\156\144\040\122\145\163\145\141\162\143\150\040
+\111\156\163\164\151\164\165\164\151\157\156\163\040\122\157\157
+\164\103\101\040\062\060\061\065\060\036\027\015\061\065\060\067
+\060\067\061\060\061\061\062\061\132\027\015\064\060\060\066\063
+\060\061\060\061\061\062\061\132\060\201\246\061\013\060\011\006
+\003\125\004\006\023\002\107\122\061\017\060\015\006\003\125\004
+\007\023\006\101\164\150\145\156\163\061\104\060\102\006\003\125
+\004\012\023\073\110\145\154\154\145\156\151\143\040\101\143\141
+\144\145\155\151\143\040\141\156\144\040\122\145\163\145\141\162
+\143\150\040\111\156\163\164\151\164\165\164\151\157\156\163\040
+\103\145\162\164\056\040\101\165\164\150\157\162\151\164\171\061
+\100\060\076\006\003\125\004\003\023\067\110\145\154\154\145\156
+\151\143\040\101\143\141\144\145\155\151\143\040\141\156\144\040
+\122\145\163\145\141\162\143\150\040\111\156\163\164\151\164\165
+\164\151\157\156\163\040\122\157\157\164\103\101\040\062\060\061
+\065\060\202\002\042\060\015\006\011\052\206\110\206\367\015\001
+\001\001\005\000\003\202\002\017\000\060\202\002\012\002\202\002
+\001\000\302\370\251\077\033\211\374\074\074\004\135\075\220\066
+\260\221\072\171\074\146\132\357\155\071\001\111\032\264\267\317
+\177\115\043\123\267\220\000\343\023\052\050\246\061\361\221\000
+\343\050\354\256\041\101\316\037\332\375\175\022\133\001\203\017
+\271\260\137\231\341\362\022\203\200\115\006\076\337\254\257\347
+\241\210\153\061\257\360\213\320\030\063\270\333\105\152\064\364
+\002\200\044\050\012\002\025\225\136\166\052\015\231\072\024\133
+\366\313\313\123\274\023\115\001\210\067\224\045\033\102\274\042
+\330\216\243\226\136\072\331\062\333\076\350\360\020\145\355\164
+\341\057\247\174\257\047\064\273\051\175\233\266\317\011\310\345
+\323\012\374\210\145\145\164\012\334\163\034\134\315\100\261\034
+\324\266\204\214\114\120\317\150\216\250\131\256\302\047\116\202
+\242\065\335\024\364\037\377\262\167\325\207\057\252\156\175\044
+\047\347\306\313\046\346\345\376\147\007\143\330\105\015\335\072
+\131\145\071\130\172\222\231\162\075\234\204\136\210\041\270\325
+\364\054\374\331\160\122\117\170\270\275\074\053\213\225\230\365
+\263\321\150\317\040\024\176\114\134\137\347\213\345\365\065\201
+\031\067\327\021\010\267\146\276\323\112\316\203\127\000\072\303
+\201\370\027\313\222\066\135\321\243\330\165\033\341\213\047\352
+\172\110\101\375\105\031\006\255\047\231\116\301\160\107\335\265
+\237\201\123\022\345\261\214\110\135\061\103\027\343\214\306\172
+\143\226\113\051\060\116\204\116\142\031\136\074\316\227\220\245
+\177\001\353\235\340\370\213\211\335\045\230\075\222\266\176\357
+\331\361\121\121\175\055\046\310\151\131\141\340\254\152\270\052
+\066\021\004\172\120\275\062\204\276\057\334\162\325\327\035\026
+\107\344\107\146\040\077\364\226\305\257\216\001\172\245\017\172
+\144\365\015\030\207\331\256\210\325\372\204\301\072\300\151\050
+\055\362\015\150\121\252\343\245\167\306\244\220\016\241\067\213
+\061\043\107\301\011\010\353\156\367\170\233\327\202\374\204\040
+\231\111\031\266\022\106\261\373\105\125\026\251\243\145\254\234
+\007\017\352\153\334\037\056\006\162\354\206\210\022\344\055\333
+\137\005\057\344\360\003\323\046\063\347\200\302\315\102\241\027
+\064\013\002\003\001\000\001\243\102\060\100\060\017\006\003\125
+\035\023\001\001\377\004\005\060\003\001\001\377\060\016\006\003
+\125\035\017\001\001\377\004\004\003\002\001\006\060\035\006\003
+\125\035\016\004\026\004\024\161\025\147\310\310\311\275\165\135
+\162\320\070\030\152\235\363\161\044\124\013\060\015\006\011\052
+\206\110\206\367\015\001\001\013\005\000\003\202\002\001\000\165
+\273\155\124\113\252\020\130\106\064\362\142\327\026\066\135\010
+\136\325\154\310\207\275\264\056\106\362\061\370\174\352\102\265
+\223\026\125\334\241\014\022\240\332\141\176\017\130\130\163\144
+\162\307\350\105\216\334\251\362\046\077\306\171\214\261\123\010
+\063\201\260\126\023\276\346\121\134\330\233\012\117\113\234\126
+\123\002\351\117\366\015\140\352\115\102\125\350\174\033\041\041
+\323\033\072\314\167\362\270\220\361\150\307\371\132\376\372\055
+\364\277\311\365\105\033\316\070\020\052\067\212\171\243\264\343
+\011\154\205\206\223\377\211\226\047\170\201\217\147\343\106\164
+\124\216\331\015\151\342\112\364\115\164\003\377\262\167\355\225
+\147\227\344\261\305\253\277\152\043\350\324\224\342\104\050\142
+\304\113\342\360\330\342\051\153\032\160\176\044\141\223\173\117
+\003\062\045\015\105\044\053\226\264\106\152\277\112\013\367\232
+\217\301\254\032\305\147\363\157\064\322\372\163\143\214\357\026
+\260\250\244\106\052\370\353\022\354\162\264\357\370\053\176\214
+\122\300\213\204\124\371\057\076\343\125\250\334\146\261\331\341
+\137\330\263\214\131\064\131\244\253\117\154\273\037\030\333\165
+\253\330\313\222\315\224\070\141\016\007\006\037\113\106\020\361
+\025\276\215\205\134\073\112\053\201\171\017\264\151\237\111\120
+\227\115\367\016\126\135\300\225\152\302\066\303\033\150\311\365
+\052\334\107\232\276\262\316\305\045\350\372\003\271\332\371\026
+\156\221\204\365\034\050\310\374\046\314\327\034\220\126\247\137
+\157\072\004\274\315\170\211\013\216\017\057\243\252\117\242\033
+\022\075\026\010\100\017\361\106\114\327\252\173\010\301\012\365
+\155\047\336\002\217\312\303\265\053\312\351\353\310\041\123\070
+\245\314\073\330\167\067\060\242\117\331\157\321\362\100\255\101
+\172\027\305\326\112\065\211\267\101\325\174\206\177\125\115\203
+\112\245\163\040\300\072\257\220\361\232\044\216\331\216\161\312
+\173\270\206\332\262\217\231\076\035\023\015\022\021\356\324\253
+\360\351\025\166\002\344\340\337\252\040\036\133\141\205\144\100
+\251\220\227\015\255\123\322\132\035\207\152\000\227\145\142\264
+\276\157\152\247\365\054\102\355\062\255\266\041\236\276\274
+END
+
+# Trust for "Hellenic Academic and Research Institutions RootCA 2015"
+# Issuer: CN=Hellenic Academic and Research Institutions RootCA 2015,O=Hellenic Academic and Research Institutions Cert. Authority,L=Athens,C=GR
+# Serial Number: 0 (0x0)
+# Subject: CN=Hellenic Academic and Research Institutions RootCA 2015,O=Hellenic Academic and Research Institutions Cert. Authority,L=Athens,C=GR
+# Not Valid Before: Tue Jul 07 10:11:21 2015
+# Not Valid After : Sat Jun 30 10:11:21 2040
+# Fingerprint (SHA-256): A0:40:92:9A:02:CE:53:B4:AC:F4:F2:FF:C6:98:1C:E4:49:6F:75:5E:6D:45:FE:0B:2A:69:2B:CD:52:52:3F:36
+# Fingerprint (SHA1): 01:0C:06:95:A6:98:19:14:FF:BF:5F:C6:B0:B6:95:EA:29:E9:12:A6
+CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST
+CKA_TOKEN CK_BBOOL CK_TRUE
+CKA_PRIVATE CK_BBOOL CK_FALSE
+CKA_MODIFIABLE CK_BBOOL CK_FALSE
+CKA_LABEL UTF8 "Hellenic Academic and Research Institutions RootCA 2015"
+CKA_CERT_SHA1_HASH MULTILINE_OCTAL
+\001\014\006\225\246\230\031\024\377\277\137\306\260\266\225\352
+\051\351\022\246
+END
+CKA_CERT_MD5_HASH MULTILINE_OCTAL
+\312\377\342\333\003\331\313\113\351\017\255\204\375\173\030\316
+END
+CKA_ISSUER MULTILINE_OCTAL
+\060\201\246\061\013\060\011\006\003\125\004\006\023\002\107\122
+\061\017\060\015\006\003\125\004\007\023\006\101\164\150\145\156
+\163\061\104\060\102\006\003\125\004\012\023\073\110\145\154\154
+\145\156\151\143\040\101\143\141\144\145\155\151\143\040\141\156
+\144\040\122\145\163\145\141\162\143\150\040\111\156\163\164\151
+\164\165\164\151\157\156\163\040\103\145\162\164\056\040\101\165
+\164\150\157\162\151\164\171\061\100\060\076\006\003\125\004\003
+\023\067\110\145\154\154\145\156\151\143\040\101\143\141\144\145
+\155\151\143\040\141\156\144\040\122\145\163\145\141\162\143\150
+\040\111\156\163\164\151\164\165\164\151\157\156\163\040\122\157
+\157\164\103\101\040\062\060\061\065
+END
+CKA_SERIAL_NUMBER MULTILINE_OCTAL
+\002\001\000
+END
+CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
+CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
+CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
+CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE
+
+#
+# Certificate "Hellenic Academic and Research Institutions ECC RootCA 2015"
+#
+# Issuer: CN=Hellenic Academic and Research Institutions ECC RootCA 2015,O=Hellenic Academic and Research Institutions Cert. Authority,L=Athens,C=GR
+# Serial Number: 0 (0x0)
+# Subject: CN=Hellenic Academic and Research Institutions ECC RootCA 2015,O=Hellenic Academic and Research Institutions Cert. Authority,L=Athens,C=GR
+# Not Valid Before: Tue Jul 07 10:37:12 2015
+# Not Valid After : Sat Jun 30 10:37:12 2040
+# Fingerprint (SHA-256): 44:B5:45:AA:8A:25:E6:5A:73:CA:15:DC:27:FC:36:D2:4C:1C:B9:95:3A:06:65:39:B1:15:82:DC:48:7B:48:33
+# Fingerprint (SHA1): 9F:F1:71:8D:92:D5:9A:F3:7D:74:97:B4:BC:6F:84:68:0B:BA:B6:66
+CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE
+CKA_TOKEN CK_BBOOL CK_TRUE
+CKA_PRIVATE CK_BBOOL CK_FALSE
+CKA_MODIFIABLE CK_BBOOL CK_FALSE
+CKA_LABEL UTF8 "Hellenic Academic and Research Institutions ECC RootCA 2015"
+CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509
+CKA_SUBJECT MULTILINE_OCTAL
+\060\201\252\061\013\060\011\006\003\125\004\006\023\002\107\122
+\061\017\060\015\006\003\125\004\007\023\006\101\164\150\145\156
+\163\061\104\060\102\006\003\125\004\012\023\073\110\145\154\154
+\145\156\151\143\040\101\143\141\144\145\155\151\143\040\141\156
+\144\040\122\145\163\145\141\162\143\150\040\111\156\163\164\151
+\164\165\164\151\157\156\163\040\103\145\162\164\056\040\101\165
+\164\150\157\162\151\164\171\061\104\060\102\006\003\125\004\003
+\023\073\110\145\154\154\145\156\151\143\040\101\143\141\144\145
+\155\151\143\040\141\156\144\040\122\145\163\145\141\162\143\150
+\040\111\156\163\164\151\164\165\164\151\157\156\163\040\105\103
+\103\040\122\157\157\164\103\101\040\062\060\061\065
+END
+CKA_ID UTF8 "0"
+CKA_ISSUER MULTILINE_OCTAL
+\060\201\252\061\013\060\011\006\003\125\004\006\023\002\107\122
+\061\017\060\015\006\003\125\004\007\023\006\101\164\150\145\156
+\163\061\104\060\102\006\003\125\004\012\023\073\110\145\154\154
+\145\156\151\143\040\101\143\141\144\145\155\151\143\040\141\156
+\144\040\122\145\163\145\141\162\143\150\040\111\156\163\164\151
+\164\165\164\151\157\156\163\040\103\145\162\164\056\040\101\165
+\164\150\157\162\151\164\171\061\104\060\102\006\003\125\004\003
+\023\073\110\145\154\154\145\156\151\143\040\101\143\141\144\145
+\155\151\143\040\141\156\144\040\122\145\163\145\141\162\143\150
+\040\111\156\163\164\151\164\165\164\151\157\156\163\040\105\103
+\103\040\122\157\157\164\103\101\040\062\060\061\065
+END
+CKA_SERIAL_NUMBER MULTILINE_OCTAL
+\002\001\000
+END
+CKA_VALUE MULTILINE_OCTAL
+\060\202\002\303\060\202\002\112\240\003\002\001\002\002\001\000
+\060\012\006\010\052\206\110\316\075\004\003\002\060\201\252\061
+\013\060\011\006\003\125\004\006\023\002\107\122\061\017\060\015
+\006\003\125\004\007\023\006\101\164\150\145\156\163\061\104\060
+\102\006\003\125\004\012\023\073\110\145\154\154\145\156\151\143
+\040\101\143\141\144\145\155\151\143\040\141\156\144\040\122\145
+\163\145\141\162\143\150\040\111\156\163\164\151\164\165\164\151
+\157\156\163\040\103\145\162\164\056\040\101\165\164\150\157\162
+\151\164\171\061\104\060\102\006\003\125\004\003\023\073\110\145
+\154\154\145\156\151\143\040\101\143\141\144\145\155\151\143\040
+\141\156\144\040\122\145\163\145\141\162\143\150\040\111\156\163
+\164\151\164\165\164\151\157\156\163\040\105\103\103\040\122\157
+\157\164\103\101\040\062\060\061\065\060\036\027\015\061\065\060
+\067\060\067\061\060\063\067\061\062\132\027\015\064\060\060\066
+\063\060\061\060\063\067\061\062\132\060\201\252\061\013\060\011
+\006\003\125\004\006\023\002\107\122\061\017\060\015\006\003\125
+\004\007\023\006\101\164\150\145\156\163\061\104\060\102\006\003
+\125\004\012\023\073\110\145\154\154\145\156\151\143\040\101\143
+\141\144\145\155\151\143\040\141\156\144\040\122\145\163\145\141
+\162\143\150\040\111\156\163\164\151\164\165\164\151\157\156\163
+\040\103\145\162\164\056\040\101\165\164\150\157\162\151\164\171
+\061\104\060\102\006\003\125\004\003\023\073\110\145\154\154\145
+\156\151\143\040\101\143\141\144\145\155\151\143\040\141\156\144
+\040\122\145\163\145\141\162\143\150\040\111\156\163\164\151\164
+\165\164\151\157\156\163\040\105\103\103\040\122\157\157\164\103
+\101\040\062\060\061\065\060\166\060\020\006\007\052\206\110\316
+\075\002\001\006\005\053\201\004\000\042\003\142\000\004\222\240
+\101\350\113\202\204\134\342\370\061\021\231\206\144\116\011\045
+\057\235\101\057\012\256\065\117\164\225\262\121\144\153\215\153
+\346\077\160\225\360\005\104\107\246\162\070\120\166\225\002\132
+\216\256\050\236\371\055\116\231\357\054\110\157\114\045\051\350
+\321\161\133\337\035\301\165\067\264\327\372\173\172\102\234\152
+\012\126\132\174\151\013\252\200\011\044\154\176\301\106\243\102
+\060\100\060\017\006\003\125\035\023\001\001\377\004\005\060\003
+\001\001\377\060\016\006\003\125\035\017\001\001\377\004\004\003
+\002\001\006\060\035\006\003\125\035\016\004\026\004\024\264\042
+\013\202\231\044\001\016\234\273\344\016\375\277\373\227\040\223
+\231\052\060\012\006\010\052\206\110\316\075\004\003\002\003\147
+\000\060\144\002\060\147\316\026\142\070\242\254\142\105\247\251
+\225\044\300\032\047\234\062\073\300\300\325\272\251\347\370\004
+\103\123\205\356\122\041\336\235\365\045\203\076\236\130\113\057
+\327\147\023\016\041\002\060\005\341\165\001\336\150\355\052\037
+\115\114\011\010\015\354\113\255\144\027\050\347\165\316\105\145
+\162\041\027\313\042\101\016\214\023\230\070\232\124\155\233\312
+\342\174\352\002\130\042\221
+END
+
+# Trust for "Hellenic Academic and Research Institutions ECC RootCA 2015"
+# Issuer: CN=Hellenic Academic and Research Institutions ECC RootCA 2015,O=Hellenic Academic and Research Institutions Cert. Authority,L=Athens,C=GR
+# Serial Number: 0 (0x0)
+# Subject: CN=Hellenic Academic and Research Institutions ECC RootCA 2015,O=Hellenic Academic and Research Institutions Cert. Authority,L=Athens,C=GR
+# Not Valid Before: Tue Jul 07 10:37:12 2015
+# Not Valid After : Sat Jun 30 10:37:12 2040
+# Fingerprint (SHA-256): 44:B5:45:AA:8A:25:E6:5A:73:CA:15:DC:27:FC:36:D2:4C:1C:B9:95:3A:06:65:39:B1:15:82:DC:48:7B:48:33
+# Fingerprint (SHA1): 9F:F1:71:8D:92:D5:9A:F3:7D:74:97:B4:BC:6F:84:68:0B:BA:B6:66
+CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST
+CKA_TOKEN CK_BBOOL CK_TRUE
+CKA_PRIVATE CK_BBOOL CK_FALSE
+CKA_MODIFIABLE CK_BBOOL CK_FALSE
+CKA_LABEL UTF8 "Hellenic Academic and Research Institutions ECC RootCA 2015"
+CKA_CERT_SHA1_HASH MULTILINE_OCTAL
+\237\361\161\215\222\325\232\363\175\164\227\264\274\157\204\150
+\013\272\266\146
+END
+CKA_CERT_MD5_HASH MULTILINE_OCTAL
+\201\345\264\027\353\302\365\341\113\015\101\173\111\222\376\357
+END
+CKA_ISSUER MULTILINE_OCTAL
+\060\201\252\061\013\060\011\006\003\125\004\006\023\002\107\122
+\061\017\060\015\006\003\125\004\007\023\006\101\164\150\145\156
+\163\061\104\060\102\006\003\125\004\012\023\073\110\145\154\154
+\145\156\151\143\040\101\143\141\144\145\155\151\143\040\141\156
+\144\040\122\145\163\145\141\162\143\150\040\111\156\163\164\151
+\164\165\164\151\157\156\163\040\103\145\162\164\056\040\101\165
+\164\150\157\162\151\164\171\061\104\060\102\006\003\125\004\003
+\023\073\110\145\154\154\145\156\151\143\040\101\143\141\144\145
+\155\151\143\040\141\156\144\040\122\145\163\145\141\162\143\150
+\040\111\156\163\164\151\164\165\164\151\157\156\163\040\105\103
+\103\040\122\157\157\164\103\101\040\062\060\061\065
+END
+CKA_SERIAL_NUMBER MULTILINE_OCTAL
+\002\001\000
+END
+CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
+CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
+CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
+CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE
+
+#
+# Certificate "Certplus Root CA G1"
+#
+# Issuer: CN=Certplus Root CA G1,O=Certplus,C=FR
+# Serial Number:11:20:55:83:e4:2d:3e:54:56:85:2d:83:37:b7:2c:dc:46:11
+# Subject: CN=Certplus Root CA G1,O=Certplus,C=FR
+# Not Valid Before: Mon May 26 00:00:00 2014
+# Not Valid After : Fri Jan 15 00:00:00 2038
+# Fingerprint (SHA-256): 15:2A:40:2B:FC:DF:2C:D5:48:05:4D:22:75:B3:9C:7F:CA:3E:C0:97:80:78:B0:F0:EA:76:E5:61:A6:C7:43:3E
+# Fingerprint (SHA1): 22:FD:D0:B7:FD:A2:4E:0D:AC:49:2C:A0:AC:A6:7B:6A:1F:E3:F7:66
+CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE
+CKA_TOKEN CK_BBOOL CK_TRUE
+CKA_PRIVATE CK_BBOOL CK_FALSE
+CKA_MODIFIABLE CK_BBOOL CK_FALSE
+CKA_LABEL UTF8 "Certplus Root CA G1"
+CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509
+CKA_SUBJECT MULTILINE_OCTAL
+\060\076\061\013\060\011\006\003\125\004\006\023\002\106\122\061
+\021\060\017\006\003\125\004\012\014\010\103\145\162\164\160\154
+\165\163\061\034\060\032\006\003\125\004\003\014\023\103\145\162
+\164\160\154\165\163\040\122\157\157\164\040\103\101\040\107\061
+END
+CKA_ID UTF8 "0"
+CKA_ISSUER MULTILINE_OCTAL
+\060\076\061\013\060\011\006\003\125\004\006\023\002\106\122\061
+\021\060\017\006\003\125\004\012\014\010\103\145\162\164\160\154
+\165\163\061\034\060\032\006\003\125\004\003\014\023\103\145\162
+\164\160\154\165\163\040\122\157\157\164\040\103\101\040\107\061
+END
+CKA_SERIAL_NUMBER MULTILINE_OCTAL
+\002\022\021\040\125\203\344\055\076\124\126\205\055\203\067\267
+\054\334\106\021
+END
+CKA_VALUE MULTILINE_OCTAL
+\060\202\005\153\060\202\003\123\240\003\002\001\002\002\022\021
+\040\125\203\344\055\076\124\126\205\055\203\067\267\054\334\106
+\021\060\015\006\011\052\206\110\206\367\015\001\001\015\005\000
+\060\076\061\013\060\011\006\003\125\004\006\023\002\106\122\061
+\021\060\017\006\003\125\004\012\014\010\103\145\162\164\160\154
+\165\163\061\034\060\032\006\003\125\004\003\014\023\103\145\162
+\164\160\154\165\163\040\122\157\157\164\040\103\101\040\107\061
+\060\036\027\015\061\064\060\065\062\066\060\060\060\060\060\060
+\132\027\015\063\070\060\061\061\065\060\060\060\060\060\060\132
+\060\076\061\013\060\011\006\003\125\004\006\023\002\106\122\061
+\021\060\017\006\003\125\004\012\014\010\103\145\162\164\160\154
+\165\163\061\034\060\032\006\003\125\004\003\014\023\103\145\162
+\164\160\154\165\163\040\122\157\157\164\040\103\101\040\107\061
+\060\202\002\042\060\015\006\011\052\206\110\206\367\015\001\001
+\001\005\000\003\202\002\017\000\060\202\002\012\002\202\002\001
+\000\332\120\207\266\332\270\251\076\235\144\372\126\063\232\126
+\075\026\345\003\225\262\064\034\232\155\142\005\324\330\217\347
+\211\144\237\272\333\144\213\144\346\171\052\141\315\257\217\132
+\211\221\145\271\130\374\264\003\137\221\077\055\020\025\340\176
+\317\274\374\177\103\147\250\255\136\066\043\330\230\263\115\363
+\103\236\071\174\052\374\354\210\325\210\356\160\275\205\026\055
+\352\113\211\074\243\161\102\376\034\375\323\034\055\020\270\206
+\124\352\103\270\333\306\207\332\250\256\200\045\317\172\046\035
+\252\221\260\110\157\256\265\336\236\330\327\372\000\375\306\217
+\320\121\273\142\175\244\261\214\262\377\040\021\272\065\143\005
+\206\107\140\103\063\220\366\107\242\003\117\226\115\235\117\301
+\352\352\234\242\376\064\056\336\267\312\033\166\244\267\255\237
+\351\250\324\170\077\170\376\362\070\011\066\035\322\026\002\310
+\354\052\150\257\365\216\224\357\055\023\172\036\102\112\035\025
+\061\256\014\004\127\374\141\163\363\061\126\206\061\200\240\304
+\021\156\060\166\343\224\360\137\004\304\254\207\162\211\230\305
+\235\314\127\010\232\364\014\374\175\172\005\072\372\107\200\071
+\266\317\204\023\167\157\047\352\377\226\147\027\010\155\351\015
+\326\043\120\060\260\025\164\023\076\345\057\377\016\315\304\013
+\112\135\360\330\000\063\111\146\353\241\030\174\131\056\075\050
+\271\141\161\313\265\245\272\270\352\334\342\160\157\010\152\334
+\207\147\064\357\337\060\162\335\363\311\077\043\377\065\341\276
+\041\051\040\060\201\344\031\245\040\351\045\312\163\061\164\051
+\276\342\102\325\363\262\046\146\307\150\375\031\263\347\040\223
+\231\350\135\340\136\207\347\106\350\045\234\012\051\044\324\315
+\130\206\122\100\044\262\173\017\230\022\040\044\366\220\154\107
+\310\015\273\030\040\056\331\375\374\213\362\051\352\207\164\225
+\340\102\120\170\204\004\101\141\260\364\041\043\217\055\313\050
+\041\362\152\154\364\032\246\305\024\264\067\145\117\225\375\200
+\310\370\162\345\045\153\304\140\261\173\155\216\112\212\163\316
+\131\373\160\172\163\006\023\331\323\164\067\044\101\012\021\157
+\227\334\347\344\176\241\275\025\362\272\207\017\075\150\212\026
+\007\002\003\001\000\001\243\143\060\141\060\016\006\003\125\035
+\017\001\001\377\004\004\003\002\001\006\060\017\006\003\125\035
+\023\001\001\377\004\005\060\003\001\001\377\060\035\006\003\125
+\035\016\004\026\004\024\250\301\300\233\221\250\103\025\174\135
+\006\047\264\052\121\330\227\013\201\261\060\037\006\003\125\035
+\043\004\030\060\026\200\024\250\301\300\233\221\250\103\025\174
+\135\006\047\264\052\121\330\227\013\201\261\060\015\006\011\052
+\206\110\206\367\015\001\001\015\005\000\003\202\002\001\000\234
+\126\157\001\176\321\275\114\365\212\306\360\046\037\344\340\070
+\030\314\062\303\051\073\235\101\051\064\141\306\327\360\000\241
+\353\244\162\217\224\027\274\023\054\165\264\127\356\012\174\011
+\172\334\325\312\241\320\064\023\370\167\253\237\345\376\330\036
+\164\212\205\007\217\177\314\171\172\312\226\315\315\375\117\373
+\375\043\015\220\365\364\136\323\306\141\175\236\021\340\002\356
+\011\004\331\007\335\246\212\267\014\203\044\273\203\120\222\376
+\140\165\021\076\330\235\260\212\172\265\340\235\233\313\220\122
+\113\260\223\052\324\076\026\063\345\236\306\145\025\076\144\073
+\004\077\333\014\217\137\134\035\151\037\257\363\351\041\214\363
+\357\227\366\232\267\031\266\204\164\234\243\124\265\160\116\143
+\330\127\135\123\041\233\100\222\103\372\326\167\125\063\117\144
+\325\373\320\054\152\216\155\045\246\357\205\350\002\304\123\076
+\271\236\207\274\314\065\032\336\241\351\212\143\207\145\036\021
+\052\333\143\167\227\024\276\232\024\231\021\262\300\356\260\117
+\370\024\041\062\103\117\237\253\242\313\250\017\252\073\006\125
+\306\022\051\127\010\324\067\327\207\047\255\111\131\247\221\253
+\104\172\136\215\160\333\227\316\110\120\261\163\223\366\360\203
+\140\371\315\361\341\061\375\133\174\161\041\143\024\024\252\257
+\305\336\223\176\150\261\354\042\242\252\220\165\236\265\103\162
+\352\144\243\204\113\375\014\250\046\153\161\227\356\126\143\146
+\350\102\124\371\307\035\337\320\217\133\337\310\060\157\210\376
+\015\304\063\034\123\250\243\375\110\020\362\344\012\116\341\025
+\127\374\156\144\060\302\125\021\334\352\251\315\112\124\254\051
+\143\104\317\112\100\240\326\150\131\033\063\371\357\072\213\333
+\040\222\334\102\204\277\001\253\207\300\325\040\202\333\306\271
+\203\205\102\134\017\103\073\152\111\065\325\230\364\025\277\372
+\141\201\014\011\040\030\322\320\027\014\313\110\000\120\351\166
+\202\214\144\327\072\240\007\125\314\036\061\300\357\072\264\145
+\373\343\277\102\153\236\017\250\275\153\230\334\330\333\313\213
+\244\335\327\131\364\156\335\376\252\303\221\320\056\102\007\300
+\014\115\123\315\044\261\114\133\036\121\364\337\351\222\372
+END
+
+# Trust for "Certplus Root CA G1"
+# Issuer: CN=Certplus Root CA G1,O=Certplus,C=FR
+# Serial Number:11:20:55:83:e4:2d:3e:54:56:85:2d:83:37:b7:2c:dc:46:11
+# Subject: CN=Certplus Root CA G1,O=Certplus,C=FR
+# Not Valid Before: Mon May 26 00:00:00 2014
+# Not Valid After : Fri Jan 15 00:00:00 2038
+# Fingerprint (SHA-256): 15:2A:40:2B:FC:DF:2C:D5:48:05:4D:22:75:B3:9C:7F:CA:3E:C0:97:80:78:B0:F0:EA:76:E5:61:A6:C7:43:3E
+# Fingerprint (SHA1): 22:FD:D0:B7:FD:A2:4E:0D:AC:49:2C:A0:AC:A6:7B:6A:1F:E3:F7:66
+CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST
+CKA_TOKEN CK_BBOOL CK_TRUE
+CKA_PRIVATE CK_BBOOL CK_FALSE
+CKA_MODIFIABLE CK_BBOOL CK_FALSE
+CKA_LABEL UTF8 "Certplus Root CA G1"
+CKA_CERT_SHA1_HASH MULTILINE_OCTAL
+\042\375\320\267\375\242\116\015\254\111\054\240\254\246\173\152
+\037\343\367\146
+END
+CKA_CERT_MD5_HASH MULTILINE_OCTAL
+\177\011\234\367\331\271\134\151\151\126\325\067\076\024\015\102
+END
+CKA_ISSUER MULTILINE_OCTAL
+\060\076\061\013\060\011\006\003\125\004\006\023\002\106\122\061
+\021\060\017\006\003\125\004\012\014\010\103\145\162\164\160\154
+\165\163\061\034\060\032\006\003\125\004\003\014\023\103\145\162
+\164\160\154\165\163\040\122\157\157\164\040\103\101\040\107\061
+END
+CKA_SERIAL_NUMBER MULTILINE_OCTAL
+\002\022\021\040\125\203\344\055\076\124\126\205\055\203\067\267
+\054\334\106\021
+END
+CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
+CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
+CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
+CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE
+
+#
+# Certificate "Certplus Root CA G2"
+#
+# Issuer: CN=Certplus Root CA G2,O=Certplus,C=FR
+# Serial Number:11:20:d9:91:ce:ae:a3:e8:c5:e7:ff:e9:02:af:cf:73:bc:55
+# Subject: CN=Certplus Root CA G2,O=Certplus,C=FR
+# Not Valid Before: Mon May 26 00:00:00 2014
+# Not Valid After : Fri Jan 15 00:00:00 2038
+# Fingerprint (SHA-256): 6C:C0:50:41:E6:44:5E:74:69:6C:4C:FB:C9:F8:0F:54:3B:7E:AB:BB:44:B4:CE:6F:78:7C:6A:99:71:C4:2F:17
+# Fingerprint (SHA1): 4F:65:8E:1F:E9:06:D8:28:02:E9:54:47:41:C9:54:25:5D:69:CC:1A
+CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE
+CKA_TOKEN CK_BBOOL CK_TRUE
+CKA_PRIVATE CK_BBOOL CK_FALSE
+CKA_MODIFIABLE CK_BBOOL CK_FALSE
+CKA_LABEL UTF8 "Certplus Root CA G2"
+CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509
+CKA_SUBJECT MULTILINE_OCTAL
+\060\076\061\013\060\011\006\003\125\004\006\023\002\106\122\061
+\021\060\017\006\003\125\004\012\014\010\103\145\162\164\160\154
+\165\163\061\034\060\032\006\003\125\004\003\014\023\103\145\162
+\164\160\154\165\163\040\122\157\157\164\040\103\101\040\107\062
+END
+CKA_ID UTF8 "0"
+CKA_ISSUER MULTILINE_OCTAL
+\060\076\061\013\060\011\006\003\125\004\006\023\002\106\122\061
+\021\060\017\006\003\125\004\012\014\010\103\145\162\164\160\154
+\165\163\061\034\060\032\006\003\125\004\003\014\023\103\145\162
+\164\160\154\165\163\040\122\157\157\164\040\103\101\040\107\062
+END
+CKA_SERIAL_NUMBER MULTILINE_OCTAL
+\002\022\021\040\331\221\316\256\243\350\305\347\377\351\002\257
+\317\163\274\125
+END
+CKA_VALUE MULTILINE_OCTAL
+\060\202\002\034\060\202\001\242\240\003\002\001\002\002\022\021
+\040\331\221\316\256\243\350\305\347\377\351\002\257\317\163\274
+\125\060\012\006\010\052\206\110\316\075\004\003\003\060\076\061
+\013\060\011\006\003\125\004\006\023\002\106\122\061\021\060\017
+\006\003\125\004\012\014\010\103\145\162\164\160\154\165\163\061
+\034\060\032\006\003\125\004\003\014\023\103\145\162\164\160\154
+\165\163\040\122\157\157\164\040\103\101\040\107\062\060\036\027
+\015\061\064\060\065\062\066\060\060\060\060\060\060\132\027\015
+\063\070\060\061\061\065\060\060\060\060\060\060\132\060\076\061
+\013\060\011\006\003\125\004\006\023\002\106\122\061\021\060\017
+\006\003\125\004\012\014\010\103\145\162\164\160\154\165\163\061
+\034\060\032\006\003\125\004\003\014\023\103\145\162\164\160\154
+\165\163\040\122\157\157\164\040\103\101\040\107\062\060\166\060
+\020\006\007\052\206\110\316\075\002\001\006\005\053\201\004\000
+\042\003\142\000\004\315\017\133\126\202\337\360\105\032\326\255
+\367\171\360\035\311\254\226\326\236\116\234\037\264\102\021\312
+\206\277\155\373\205\243\305\345\031\134\327\356\246\077\151\147
+\330\170\342\246\311\304\333\055\171\056\347\213\215\002\157\061
+\042\115\006\343\140\162\105\235\016\102\167\236\316\317\345\177
+\205\233\030\344\374\314\056\162\323\026\223\116\312\231\143\134
+\241\005\052\154\006\243\143\060\141\060\016\006\003\125\035\017
+\001\001\377\004\004\003\002\001\006\060\017\006\003\125\035\023
+\001\001\377\004\005\060\003\001\001\377\060\035\006\003\125\035
+\016\004\026\004\024\332\203\143\002\171\216\332\114\306\074\043
+\024\330\217\303\040\253\050\140\131\060\037\006\003\125\035\043
+\004\030\060\026\200\024\332\203\143\002\171\216\332\114\306\074
+\043\024\330\217\303\040\253\050\140\131\060\012\006\010\052\206
+\110\316\075\004\003\003\003\150\000\060\145\002\060\160\376\260
+\013\331\367\203\227\354\363\125\035\324\334\263\006\016\376\063
+\230\235\213\071\220\153\224\041\355\266\327\135\326\114\327\041
+\247\347\277\041\017\053\315\367\052\334\205\007\235\002\061\000
+\206\024\026\345\334\260\145\302\300\216\024\237\277\044\026\150
+\345\274\371\171\151\334\255\105\053\367\266\061\163\314\006\245
+\123\223\221\032\223\256\160\152\147\272\327\236\345\141\032\137
+END
+
+# Trust for "Certplus Root CA G2"
+# Issuer: CN=Certplus Root CA G2,O=Certplus,C=FR
+# Serial Number:11:20:d9:91:ce:ae:a3:e8:c5:e7:ff:e9:02:af:cf:73:bc:55
+# Subject: CN=Certplus Root CA G2,O=Certplus,C=FR
+# Not Valid Before: Mon May 26 00:00:00 2014
+# Not Valid After : Fri Jan 15 00:00:00 2038
+# Fingerprint (SHA-256): 6C:C0:50:41:E6:44:5E:74:69:6C:4C:FB:C9:F8:0F:54:3B:7E:AB:BB:44:B4:CE:6F:78:7C:6A:99:71:C4:2F:17
+# Fingerprint (SHA1): 4F:65:8E:1F:E9:06:D8:28:02:E9:54:47:41:C9:54:25:5D:69:CC:1A
+CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST
+CKA_TOKEN CK_BBOOL CK_TRUE
+CKA_PRIVATE CK_BBOOL CK_FALSE
+CKA_MODIFIABLE CK_BBOOL CK_FALSE
+CKA_LABEL UTF8 "Certplus Root CA G2"
+CKA_CERT_SHA1_HASH MULTILINE_OCTAL
+\117\145\216\037\351\006\330\050\002\351\124\107\101\311\124\045
+\135\151\314\032
+END
+CKA_CERT_MD5_HASH MULTILINE_OCTAL
+\247\356\304\170\055\033\356\055\271\051\316\326\247\226\062\061
+END
+CKA_ISSUER MULTILINE_OCTAL
+\060\076\061\013\060\011\006\003\125\004\006\023\002\106\122\061
+\021\060\017\006\003\125\004\012\014\010\103\145\162\164\160\154
+\165\163\061\034\060\032\006\003\125\004\003\014\023\103\145\162
+\164\160\154\165\163\040\122\157\157\164\040\103\101\040\107\062
+END
+CKA_SERIAL_NUMBER MULTILINE_OCTAL
+\002\022\021\040\331\221\316\256\243\350\305\347\377\351\002\257
+\317\163\274\125
+END
+CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
+CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
+CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
+CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE
+
+#
+# Certificate "OpenTrust Root CA G1"
+#
+# Issuer: CN=OpenTrust Root CA G1,O=OpenTrust,C=FR
+# Serial Number:11:20:b3:90:55:39:7d:7f:36:6d:64:c2:a7:9f:6b:63:8e:67
+# Subject: CN=OpenTrust Root CA G1,O=OpenTrust,C=FR
+# Not Valid Before: Mon May 26 08:45:50 2014
+# Not Valid After : Fri Jan 15 00:00:00 2038
+# Fingerprint (SHA-256): 56:C7:71:28:D9:8C:18:D9:1B:4C:FD:FF:BC:25:EE:91:03:D4:75:8E:A2:AB:AD:82:6A:90:F3:45:7D:46:0E:B4
+# Fingerprint (SHA1): 79:91:E8:34:F7:E2:EE:DD:08:95:01:52:E9:55:2D:14:E9:58:D5:7E
+CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE
+CKA_TOKEN CK_BBOOL CK_TRUE
+CKA_PRIVATE CK_BBOOL CK_FALSE
+CKA_MODIFIABLE CK_BBOOL CK_FALSE
+CKA_LABEL UTF8 "OpenTrust Root CA G1"
+CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509
+CKA_SUBJECT MULTILINE_OCTAL
+\060\100\061\013\060\011\006\003\125\004\006\023\002\106\122\061
+\022\060\020\006\003\125\004\012\014\011\117\160\145\156\124\162
+\165\163\164\061\035\060\033\006\003\125\004\003\014\024\117\160
+\145\156\124\162\165\163\164\040\122\157\157\164\040\103\101\040
+\107\061
+END
+CKA_ID UTF8 "0"
+CKA_ISSUER MULTILINE_OCTAL
+\060\100\061\013\060\011\006\003\125\004\006\023\002\106\122\061
+\022\060\020\006\003\125\004\012\014\011\117\160\145\156\124\162
+\165\163\164\061\035\060\033\006\003\125\004\003\014\024\117\160
+\145\156\124\162\165\163\164\040\122\157\157\164\040\103\101\040
+\107\061
+END
+CKA_SERIAL_NUMBER MULTILINE_OCTAL
+\002\022\021\040\263\220\125\071\175\177\066\155\144\302\247\237
+\153\143\216\147
+END
+CKA_VALUE MULTILINE_OCTAL
+\060\202\005\157\060\202\003\127\240\003\002\001\002\002\022\021
+\040\263\220\125\071\175\177\066\155\144\302\247\237\153\143\216
+\147\060\015\006\011\052\206\110\206\367\015\001\001\013\005\000
+\060\100\061\013\060\011\006\003\125\004\006\023\002\106\122\061
+\022\060\020\006\003\125\004\012\014\011\117\160\145\156\124\162
+\165\163\164\061\035\060\033\006\003\125\004\003\014\024\117\160
+\145\156\124\162\165\163\164\040\122\157\157\164\040\103\101\040
+\107\061\060\036\027\015\061\064\060\065\062\066\060\070\064\065
+\065\060\132\027\015\063\070\060\061\061\065\060\060\060\060\060
+\060\132\060\100\061\013\060\011\006\003\125\004\006\023\002\106
+\122\061\022\060\020\006\003\125\004\012\014\011\117\160\145\156
+\124\162\165\163\164\061\035\060\033\006\003\125\004\003\014\024
+\117\160\145\156\124\162\165\163\164\040\122\157\157\164\040\103
+\101\040\107\061\060\202\002\042\060\015\006\011\052\206\110\206
+\367\015\001\001\001\005\000\003\202\002\017\000\060\202\002\012
+\002\202\002\001\000\370\171\106\332\226\305\060\136\212\161\003
+\055\160\244\273\260\305\010\334\315\346\065\300\200\244\021\055
+\335\346\207\256\135\075\221\322\207\154\067\267\332\142\236\233
+\302\044\327\217\361\333\246\246\337\106\157\121\246\161\313\076
+\033\061\147\142\367\021\133\064\047\325\171\116\214\233\130\275
+\042\020\015\134\047\014\335\060\345\250\323\135\041\070\164\027
+\376\343\037\266\117\073\153\055\333\175\140\037\214\175\114\005
+\302\353\001\026\025\230\024\216\321\220\167\042\077\354\302\071
+\270\171\072\360\111\044\342\225\221\334\141\064\222\214\124\164
+\357\261\175\214\001\342\070\175\301\137\152\137\044\262\216\142
+\027\255\171\040\255\253\035\267\340\264\226\110\117\146\103\020
+\006\026\044\003\341\340\234\216\306\106\117\216\032\231\341\217
+\271\216\063\154\151\336\130\255\240\016\247\144\124\021\151\104
+\146\117\114\022\247\216\054\175\304\324\133\305\000\064\060\301
+\331\231\376\062\316\007\204\264\116\315\012\377\066\115\142\361
+\247\143\127\344\333\152\247\256\277\053\271\311\346\262\047\211
+\345\176\232\034\115\150\306\301\030\336\063\053\121\106\113\034
+\216\367\075\014\371\212\064\024\304\373\063\065\043\361\314\361
+\052\307\245\273\260\242\316\376\123\153\115\101\033\146\050\262
+\226\372\247\256\012\116\271\071\063\104\234\164\301\223\034\370
+\340\236\044\045\103\361\233\043\202\252\337\054\040\260\334\066
+\116\003\263\174\002\324\346\173\032\252\207\023\277\076\241\164
+\273\233\016\341\300\223\237\327\244\146\312\273\033\073\343\060
+\364\063\131\212\007\162\003\125\347\163\152\003\061\156\157\226
+\033\343\242\237\257\222\307\355\365\102\267\045\114\073\023\004
+\317\034\226\257\034\042\243\320\253\005\262\114\022\043\122\334
+\375\031\133\047\234\036\073\172\375\102\043\333\043\200\023\360
+\274\121\025\124\224\246\167\076\320\164\121\275\121\024\010\071
+\067\313\037\064\251\060\235\122\204\056\125\220\261\272\337\125
+\000\013\330\126\055\261\111\111\162\200\251\142\327\300\366\030
+\021\004\125\315\164\173\317\141\160\171\364\173\054\134\134\222
+\374\345\270\132\253\114\223\225\241\047\356\245\276\317\161\043
+\102\272\233\166\055\002\003\001\000\001\243\143\060\141\060\016
+\006\003\125\035\017\001\001\377\004\004\003\002\001\006\060\017
+\006\003\125\035\023\001\001\377\004\005\060\003\001\001\377\060
+\035\006\003\125\035\016\004\026\004\024\227\106\041\127\041\065
+\332\066\125\307\363\361\067\160\345\010\366\223\051\266\060\037
+\006\003\125\035\043\004\030\060\026\200\024\227\106\041\127\041
+\065\332\066\125\307\363\361\067\160\345\010\366\223\051\266\060
+\015\006\011\052\206\110\206\367\015\001\001\013\005\000\003\202
+\002\001\000\035\335\002\140\174\340\065\247\346\230\173\352\104
+\316\147\100\117\362\223\156\146\324\071\211\046\254\323\115\004
+\074\273\207\041\077\067\364\161\045\332\113\272\253\226\202\201
+\221\266\355\331\261\244\145\227\342\157\144\131\244\226\356\140
+\312\037\043\373\105\272\377\217\044\360\312\251\061\177\171\037
+\200\263\055\062\272\144\147\140\257\271\131\315\337\232\111\323
+\250\202\261\371\230\224\212\314\340\273\340\004\033\231\140\261
+\106\145\334\010\242\262\106\236\104\210\352\223\176\127\026\322
+\025\162\137\056\113\253\324\235\143\270\343\110\345\376\204\056
+\130\012\237\103\035\376\267\030\222\206\103\113\016\234\062\206
+\054\140\365\351\110\352\225\355\160\051\361\325\057\375\065\264
+\127\317\333\205\110\231\271\302\157\154\217\315\170\225\254\144
+\050\375\126\260\303\157\303\276\131\122\341\137\204\217\200\362
+\364\015\066\255\166\263\243\265\341\144\166\072\130\334\175\117
+\136\126\154\345\125\131\127\245\337\361\212\146\060\214\324\122
+\142\070\167\264\276\050\327\312\066\304\233\005\360\370\025\333
+\333\361\357\064\235\035\170\112\210\126\147\156\140\377\217\310
+\213\341\216\275\102\251\063\012\131\102\022\022\052\372\261\235
+\103\216\005\233\231\332\142\255\127\066\263\035\266\015\171\055
+\226\270\353\362\014\113\014\245\224\306\060\247\046\031\055\355
+\114\006\120\060\361\375\130\075\271\113\027\137\031\264\152\204
+\124\264\070\117\071\242\015\226\150\303\050\224\375\355\055\037
+\112\153\103\226\056\220\001\020\373\070\246\201\013\320\277\165
+\323\324\271\316\361\077\157\016\034\036\067\161\345\030\207\165
+\031\077\120\271\136\244\105\064\255\260\312\346\345\023\166\017
+\061\024\251\216\055\224\326\325\205\115\163\025\117\113\362\262
+\076\355\154\275\375\016\235\146\163\260\075\264\367\277\250\340
+\021\244\304\256\165\011\112\143\000\110\040\246\306\235\013\011
+\212\264\340\346\316\076\307\076\046\070\351\053\336\246\010\111
+\003\004\220\212\351\217\277\350\266\264\052\243\043\215\034\034
+\262\071\222\250\217\002\134\100\071\165\324\163\101\002\167\336
+\315\340\103\207\326\344\272\112\303\154\022\177\376\052\346\043
+\326\214\161
+END
+
+# Trust for "OpenTrust Root CA G1"
+# Issuer: CN=OpenTrust Root CA G1,O=OpenTrust,C=FR
+# Serial Number:11:20:b3:90:55:39:7d:7f:36:6d:64:c2:a7:9f:6b:63:8e:67
+# Subject: CN=OpenTrust Root CA G1,O=OpenTrust,C=FR
+# Not Valid Before: Mon May 26 08:45:50 2014
+# Not Valid After : Fri Jan 15 00:00:00 2038
+# Fingerprint (SHA-256): 56:C7:71:28:D9:8C:18:D9:1B:4C:FD:FF:BC:25:EE:91:03:D4:75:8E:A2:AB:AD:82:6A:90:F3:45:7D:46:0E:B4
+# Fingerprint (SHA1): 79:91:E8:34:F7:E2:EE:DD:08:95:01:52:E9:55:2D:14:E9:58:D5:7E
+CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST
+CKA_TOKEN CK_BBOOL CK_TRUE
+CKA_PRIVATE CK_BBOOL CK_FALSE
+CKA_MODIFIABLE CK_BBOOL CK_FALSE
+CKA_LABEL UTF8 "OpenTrust Root CA G1"
+CKA_CERT_SHA1_HASH MULTILINE_OCTAL
+\171\221\350\064\367\342\356\335\010\225\001\122\351\125\055\024
+\351\130\325\176
+END
+CKA_CERT_MD5_HASH MULTILINE_OCTAL
+\166\000\314\201\051\315\125\136\210\152\172\056\367\115\071\332
+END
+CKA_ISSUER MULTILINE_OCTAL
+\060\100\061\013\060\011\006\003\125\004\006\023\002\106\122\061
+\022\060\020\006\003\125\004\012\014\011\117\160\145\156\124\162
+\165\163\164\061\035\060\033\006\003\125\004\003\014\024\117\160
+\145\156\124\162\165\163\164\040\122\157\157\164\040\103\101\040
+\107\061
+END
+CKA_SERIAL_NUMBER MULTILINE_OCTAL
+\002\022\021\040\263\220\125\071\175\177\066\155\144\302\247\237
+\153\143\216\147
+END
+CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
+CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
+CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
+CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE
+
+#
+# Certificate "OpenTrust Root CA G2"
+#
+# Issuer: CN=OpenTrust Root CA G2,O=OpenTrust,C=FR
+# Serial Number:11:20:a1:69:1b:bf:bd:b9:bd:52:96:8f:23:e8:48:bf:26:11
+# Subject: CN=OpenTrust Root CA G2,O=OpenTrust,C=FR
+# Not Valid Before: Mon May 26 00:00:00 2014
+# Not Valid After : Fri Jan 15 00:00:00 2038
+# Fingerprint (SHA-256): 27:99:58:29:FE:6A:75:15:C1:BF:E8:48:F9:C4:76:1D:B1:6C:22:59:29:25:7B:F4:0D:08:94:F2:9E:A8:BA:F2
+# Fingerprint (SHA1): 79:5F:88:60:C5:AB:7C:3D:92:E6:CB:F4:8D:E1:45:CD:11:EF:60:0B
+CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE
+CKA_TOKEN CK_BBOOL CK_TRUE
+CKA_PRIVATE CK_BBOOL CK_FALSE
+CKA_MODIFIABLE CK_BBOOL CK_FALSE
+CKA_LABEL UTF8 "OpenTrust Root CA G2"
+CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509
+CKA_SUBJECT MULTILINE_OCTAL
+\060\100\061\013\060\011\006\003\125\004\006\023\002\106\122\061
+\022\060\020\006\003\125\004\012\014\011\117\160\145\156\124\162
+\165\163\164\061\035\060\033\006\003\125\004\003\014\024\117\160
+\145\156\124\162\165\163\164\040\122\157\157\164\040\103\101\040
+\107\062
+END
+CKA_ID UTF8 "0"
+CKA_ISSUER MULTILINE_OCTAL
+\060\100\061\013\060\011\006\003\125\004\006\023\002\106\122\061
+\022\060\020\006\003\125\004\012\014\011\117\160\145\156\124\162
+\165\163\164\061\035\060\033\006\003\125\004\003\014\024\117\160
+\145\156\124\162\165\163\164\040\122\157\157\164\040\103\101\040
+\107\062
+END
+CKA_SERIAL_NUMBER MULTILINE_OCTAL
+\002\022\021\040\241\151\033\277\275\271\275\122\226\217\043\350
+\110\277\046\021
+END
+CKA_VALUE MULTILINE_OCTAL
+\060\202\005\157\060\202\003\127\240\003\002\001\002\002\022\021
+\040\241\151\033\277\275\271\275\122\226\217\043\350\110\277\046
+\021\060\015\006\011\052\206\110\206\367\015\001\001\015\005\000
+\060\100\061\013\060\011\006\003\125\004\006\023\002\106\122\061
+\022\060\020\006\003\125\004\012\014\011\117\160\145\156\124\162
+\165\163\164\061\035\060\033\006\003\125\004\003\014\024\117\160
+\145\156\124\162\165\163\164\040\122\157\157\164\040\103\101\040
+\107\062\060\036\027\015\061\064\060\065\062\066\060\060\060\060
+\060\060\132\027\015\063\070\060\061\061\065\060\060\060\060\060
+\060\132\060\100\061\013\060\011\006\003\125\004\006\023\002\106
+\122\061\022\060\020\006\003\125\004\012\014\011\117\160\145\156
+\124\162\165\163\164\061\035\060\033\006\003\125\004\003\014\024
+\117\160\145\156\124\162\165\163\164\040\122\157\157\164\040\103
+\101\040\107\062\060\202\002\042\060\015\006\011\052\206\110\206
+\367\015\001\001\001\005\000\003\202\002\017\000\060\202\002\012
+\002\202\002\001\000\314\266\127\245\063\224\020\201\062\123\337
+\141\176\017\166\071\317\134\302\123\165\035\111\172\226\070\335
+\242\163\152\361\157\336\136\242\132\271\161\041\276\066\331\241
+\374\274\356\154\250\174\064\032\161\032\350\032\330\137\016\104
+\006\355\247\340\363\322\141\013\340\062\242\226\321\070\360\302
+\332\001\027\374\344\254\117\350\356\211\036\164\253\117\277\036
+\011\266\066\152\126\363\341\356\226\211\146\044\006\344\315\102
+\072\112\335\340\232\260\304\202\105\263\376\311\253\134\174\076
+\311\353\027\057\014\175\156\256\245\217\310\254\045\012\157\372
+\325\105\230\322\065\011\366\003\103\224\376\331\277\040\225\171
+\200\230\212\331\211\065\273\121\033\244\067\175\374\231\073\253
+\377\277\254\015\217\103\261\231\173\026\020\176\035\157\107\304
+\025\217\004\226\010\006\102\004\370\204\326\035\274\221\246\102
+\276\111\325\152\210\077\274\055\121\321\236\215\340\122\314\127
+\335\065\065\130\333\264\217\044\210\344\213\337\334\153\124\322
+\201\053\262\316\222\113\034\037\106\372\035\330\222\313\166\147
+\265\011\231\011\345\254\027\024\125\160\306\074\240\126\012\003
+\263\334\142\031\337\310\265\060\177\365\074\046\165\021\275\327
+\033\263\207\236\007\257\145\161\345\240\317\032\247\011\020\035
+\223\211\146\133\350\074\142\062\265\265\072\156\351\205\001\213
+\236\103\214\147\163\050\131\133\353\343\334\054\314\245\046\162
+\142\022\264\346\234\203\104\366\121\244\342\300\172\044\127\312
+\016\245\077\072\265\073\213\345\166\356\160\346\222\336\026\134
+\050\133\227\031\047\222\376\172\222\124\316\223\071\012\026\207
+\274\143\263\365\261\223\134\340\156\267\320\352\371\142\062\210
+\104\373\277\047\050\266\060\225\135\022\050\271\225\276\217\123
+\030\345\242\030\026\342\126\244\262\054\020\365\035\067\246\370
+\267\366\320\131\134\211\367\302\325\265\224\164\321\325\376\033
+\266\360\346\326\036\173\322\074\313\250\343\365\030\363\041\037
+\156\357\115\150\006\173\055\135\156\103\211\246\300\371\240\277
+\202\036\317\123\177\264\353\054\333\135\366\152\175\100\044\005
+\162\211\070\001\223\313\161\302\071\135\006\021\366\157\170\370
+\067\015\071\204\047\002\003\001\000\001\243\143\060\141\060\016
+\006\003\125\035\017\001\001\377\004\004\003\002\001\006\060\017
+\006\003\125\035\023\001\001\377\004\005\060\003\001\001\377\060
+\035\006\003\125\035\016\004\026\004\024\152\071\372\102\042\367
+\346\211\000\115\136\175\063\203\313\270\156\167\206\257\060\037
+\006\003\125\035\043\004\030\060\026\200\024\152\071\372\102\042
+\367\346\211\000\115\136\175\063\203\313\270\156\167\206\257\060
+\015\006\011\052\206\110\206\367\015\001\001\015\005\000\003\202
+\002\001\000\230\313\253\100\074\345\063\002\227\177\055\207\246
+\217\324\136\112\257\270\036\347\273\161\373\200\144\045\251\263
+\032\076\150\135\047\046\247\272\052\341\360\127\203\012\144\117
+\036\042\164\033\351\220\137\360\254\317\377\117\150\172\070\244
+\020\154\015\261\307\244\167\200\030\266\242\050\104\166\247\064
+\235\161\204\057\312\131\322\107\210\231\101\042\311\060\230\141
+\156\075\250\250\005\155\321\037\300\121\104\126\177\047\065\002
+\335\136\230\012\102\353\060\277\215\241\233\121\252\073\352\223
+\106\144\305\000\171\336\041\153\366\127\240\206\327\006\162\354
+\160\106\113\213\163\335\240\041\165\076\334\035\300\217\323\117
+\163\034\205\331\376\177\142\310\225\157\266\323\173\214\272\123
+\302\157\233\104\114\171\320\035\160\263\327\237\002\364\262\007
+\260\307\345\370\255\043\016\246\126\311\051\022\167\110\331\057
+\106\375\073\360\374\164\160\222\245\216\070\010\037\144\060\266
+\267\113\373\066\254\020\216\240\122\063\143\235\003\065\126\305
+\151\275\306\043\132\047\224\366\244\022\370\055\063\074\241\126
+\245\137\326\031\351\355\174\010\275\167\315\047\144\314\224\332
+\116\106\120\207\340\371\301\123\200\036\273\255\373\107\122\213
+\033\375\242\371\336\016\042\267\075\063\131\154\324\336\365\225
+\006\062\015\121\031\101\134\076\117\006\367\271\053\200\047\366
+\243\252\172\174\006\341\103\303\023\071\142\032\066\275\340\050
+\056\224\002\344\051\056\140\125\256\100\075\260\164\222\136\360
+\040\144\226\077\137\105\135\210\265\212\332\002\240\133\105\124
+\336\070\075\011\300\250\112\145\106\026\374\252\277\124\116\115
+\133\276\070\103\267\050\312\213\063\252\032\045\272\045\134\051
+\057\133\112\156\214\352\055\234\052\366\005\166\340\167\227\200
+\210\335\147\023\157\035\150\044\213\117\267\164\201\345\364\140
+\237\172\125\327\076\067\332\026\153\076\167\254\256\030\160\225
+\010\171\051\003\212\376\301\073\263\077\032\017\244\073\136\037
+\130\241\225\311\253\057\163\112\320\055\156\232\131\017\125\030
+\170\055\074\121\246\227\213\346\273\262\160\252\114\021\336\377
+\174\053\067\324\172\321\167\064\217\347\371\102\367\074\201\014
+\113\122\012
+END
+
+# Trust for "OpenTrust Root CA G2"
+# Issuer: CN=OpenTrust Root CA G2,O=OpenTrust,C=FR
+# Serial Number:11:20:a1:69:1b:bf:bd:b9:bd:52:96:8f:23:e8:48:bf:26:11
+# Subject: CN=OpenTrust Root CA G2,O=OpenTrust,C=FR
+# Not Valid Before: Mon May 26 00:00:00 2014
+# Not Valid After : Fri Jan 15 00:00:00 2038
+# Fingerprint (SHA-256): 27:99:58:29:FE:6A:75:15:C1:BF:E8:48:F9:C4:76:1D:B1:6C:22:59:29:25:7B:F4:0D:08:94:F2:9E:A8:BA:F2
+# Fingerprint (SHA1): 79:5F:88:60:C5:AB:7C:3D:92:E6:CB:F4:8D:E1:45:CD:11:EF:60:0B
+CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST
+CKA_TOKEN CK_BBOOL CK_TRUE
+CKA_PRIVATE CK_BBOOL CK_FALSE
+CKA_MODIFIABLE CK_BBOOL CK_FALSE
+CKA_LABEL UTF8 "OpenTrust Root CA G2"
+CKA_CERT_SHA1_HASH MULTILINE_OCTAL
+\171\137\210\140\305\253\174\075\222\346\313\364\215\341\105\315
+\021\357\140\013
+END
+CKA_CERT_MD5_HASH MULTILINE_OCTAL
+\127\044\266\131\044\153\256\310\376\034\014\040\362\300\116\353
+END
+CKA_ISSUER MULTILINE_OCTAL
+\060\100\061\013\060\011\006\003\125\004\006\023\002\106\122\061
+\022\060\020\006\003\125\004\012\014\011\117\160\145\156\124\162
+\165\163\164\061\035\060\033\006\003\125\004\003\014\024\117\160
+\145\156\124\162\165\163\164\040\122\157\157\164\040\103\101\040
+\107\062
+END
+CKA_SERIAL_NUMBER MULTILINE_OCTAL
+\002\022\021\040\241\151\033\277\275\271\275\122\226\217\043\350
+\110\277\046\021
+END
+CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
+CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
+CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
+CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE
+
+#
+# Certificate "OpenTrust Root CA G3"
+#
+# Issuer: CN=OpenTrust Root CA G3,O=OpenTrust,C=FR
+# Serial Number:11:20:e6:f8:4c:fc:24:b0:be:05:40:ac:da:83:1b:34:60:3f
+# Subject: CN=OpenTrust Root CA G3,O=OpenTrust,C=FR
+# Not Valid Before: Mon May 26 00:00:00 2014
+# Not Valid After : Fri Jan 15 00:00:00 2038
+# Fingerprint (SHA-256): B7:C3:62:31:70:6E:81:07:8C:36:7C:B8:96:19:8F:1E:32:08:DD:92:69:49:DD:8F:57:09:A4:10:F7:5B:62:92
+# Fingerprint (SHA1): 6E:26:64:F3:56:BF:34:55:BF:D1:93:3F:7C:01:DE:D8:13:DA:8A:A6
+CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE
+CKA_TOKEN CK_BBOOL CK_TRUE
+CKA_PRIVATE CK_BBOOL CK_FALSE
+CKA_MODIFIABLE CK_BBOOL CK_FALSE
+CKA_LABEL UTF8 "OpenTrust Root CA G3"
+CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509
+CKA_SUBJECT MULTILINE_OCTAL
+\060\100\061\013\060\011\006\003\125\004\006\023\002\106\122\061
+\022\060\020\006\003\125\004\012\014\011\117\160\145\156\124\162
+\165\163\164\061\035\060\033\006\003\125\004\003\014\024\117\160
+\145\156\124\162\165\163\164\040\122\157\157\164\040\103\101\040
+\107\063
+END
+CKA_ID UTF8 "0"
+CKA_ISSUER MULTILINE_OCTAL
+\060\100\061\013\060\011\006\003\125\004\006\023\002\106\122\061
+\022\060\020\006\003\125\004\012\014\011\117\160\145\156\124\162
+\165\163\164\061\035\060\033\006\003\125\004\003\014\024\117\160
+\145\156\124\162\165\163\164\040\122\157\157\164\040\103\101\040
+\107\063
+END
+CKA_SERIAL_NUMBER MULTILINE_OCTAL
+\002\022\021\040\346\370\114\374\044\260\276\005\100\254\332\203
+\033\064\140\077
+END
+CKA_VALUE MULTILINE_OCTAL
+\060\202\002\041\060\202\001\246\240\003\002\001\002\002\022\021
+\040\346\370\114\374\044\260\276\005\100\254\332\203\033\064\140
+\077\060\012\006\010\052\206\110\316\075\004\003\003\060\100\061
+\013\060\011\006\003\125\004\006\023\002\106\122\061\022\060\020
+\006\003\125\004\012\014\011\117\160\145\156\124\162\165\163\164
+\061\035\060\033\006\003\125\004\003\014\024\117\160\145\156\124
+\162\165\163\164\040\122\157\157\164\040\103\101\040\107\063\060
+\036\027\015\061\064\060\065\062\066\060\060\060\060\060\060\132
+\027\015\063\070\060\061\061\065\060\060\060\060\060\060\132\060
+\100\061\013\060\011\006\003\125\004\006\023\002\106\122\061\022
+\060\020\006\003\125\004\012\014\011\117\160\145\156\124\162\165
+\163\164\061\035\060\033\006\003\125\004\003\014\024\117\160\145
+\156\124\162\165\163\164\040\122\157\157\164\040\103\101\040\107
+\063\060\166\060\020\006\007\052\206\110\316\075\002\001\006\005
+\053\201\004\000\042\003\142\000\004\112\356\130\256\115\312\146
+\336\006\072\243\021\374\340\030\360\156\034\272\055\060\014\211
+\331\326\356\233\163\203\251\043\025\214\057\131\212\132\335\024
+\352\235\131\053\103\267\006\354\062\266\272\356\101\265\255\135
+\241\205\314\352\035\024\146\243\147\176\106\342\224\363\347\266
+\126\241\025\131\241\117\067\227\271\042\036\275\021\353\364\262
+\037\136\303\024\232\345\331\227\231\243\143\060\141\060\016\006
+\003\125\035\017\001\001\377\004\004\003\002\001\006\060\017\006
+\003\125\035\023\001\001\377\004\005\060\003\001\001\377\060\035
+\006\003\125\035\016\004\026\004\024\107\167\303\024\213\142\071
+\014\311\157\341\120\115\320\020\130\334\225\210\155\060\037\006
+\003\125\035\043\004\030\060\026\200\024\107\167\303\024\213\142
+\071\014\311\157\341\120\115\320\020\130\334\225\210\155\060\012
+\006\010\052\206\110\316\075\004\003\003\003\151\000\060\146\002
+\061\000\217\250\334\235\272\014\004\027\372\025\351\075\057\051
+\001\227\277\201\026\063\100\223\154\374\371\355\200\160\157\252
+\217\333\204\302\213\365\065\312\006\334\144\157\150\026\341\217
+\221\271\002\061\000\330\113\245\313\302\320\010\154\351\030\373
+\132\335\115\137\044\013\260\000\041\045\357\217\247\004\046\161
+\342\174\151\345\135\232\370\101\037\073\071\223\223\235\125\352
+\315\215\361\373\301
+END
+
+# Trust for "OpenTrust Root CA G3"
+# Issuer: CN=OpenTrust Root CA G3,O=OpenTrust,C=FR
+# Serial Number:11:20:e6:f8:4c:fc:24:b0:be:05:40:ac:da:83:1b:34:60:3f
+# Subject: CN=OpenTrust Root CA G3,O=OpenTrust,C=FR
+# Not Valid Before: Mon May 26 00:00:00 2014
+# Not Valid After : Fri Jan 15 00:00:00 2038
+# Fingerprint (SHA-256): B7:C3:62:31:70:6E:81:07:8C:36:7C:B8:96:19:8F:1E:32:08:DD:92:69:49:DD:8F:57:09:A4:10:F7:5B:62:92
+# Fingerprint (SHA1): 6E:26:64:F3:56:BF:34:55:BF:D1:93:3F:7C:01:DE:D8:13:DA:8A:A6
+CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST
+CKA_TOKEN CK_BBOOL CK_TRUE
+CKA_PRIVATE CK_BBOOL CK_FALSE
+CKA_MODIFIABLE CK_BBOOL CK_FALSE
+CKA_LABEL UTF8 "OpenTrust Root CA G3"
+CKA_CERT_SHA1_HASH MULTILINE_OCTAL
+\156\046\144\363\126\277\064\125\277\321\223\077\174\001\336\330
+\023\332\212\246
+END
+CKA_CERT_MD5_HASH MULTILINE_OCTAL
+\041\067\264\027\026\222\173\147\106\160\251\226\327\250\023\044
+END
+CKA_ISSUER MULTILINE_OCTAL
+\060\100\061\013\060\011\006\003\125\004\006\023\002\106\122\061
+\022\060\020\006\003\125\004\012\014\011\117\160\145\156\124\162
+\165\163\164\061\035\060\033\006\003\125\004\003\014\024\117\160
+\145\156\124\162\165\163\164\040\122\157\157\164\040\103\101\040
+\107\063
+END
+CKA_SERIAL_NUMBER MULTILINE_OCTAL
+\002\022\021\040\346\370\114\374\044\260\276\005\100\254\332\203
+\033\064\140\077
+END
+CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
+CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
+CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST
+CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE
--- a/security/nss/lib/ckfw/builtins/nssckbi.h
+++ b/security/nss/lib/ckfw/builtins/nssckbi.h
@@ -40,18 +40,18 @@
  *     ...
  *   - NSS 3.29 branch: 250-255
  *
  * NSS_BUILTINS_LIBRARY_VERSION_MINOR is a CK_BYTE.  It's not clear
  * whether we may use its full range (0-255) or only 0-99 because
  * of the comment in the CK_VERSION type definition.
  */
 #define NSS_BUILTINS_LIBRARY_VERSION_MAJOR 2
-#define NSS_BUILTINS_LIBRARY_VERSION_MINOR 7
-#define NSS_BUILTINS_LIBRARY_VERSION "2.7"
+#define NSS_BUILTINS_LIBRARY_VERSION_MINOR 8
+#define NSS_BUILTINS_LIBRARY_VERSION "2.8"
 
 /* These version numbers detail the semantic changes to the ckfw engine. */
 #define NSS_BUILTINS_HARDWARE_VERSION_MAJOR 1
 #define NSS_BUILTINS_HARDWARE_VERSION_MINOR 0
 
 /* These version numbers detail the semantic changes to ckbi itself
  * (new PKCS #11 objects), etc. */
 #define NSS_BUILTINS_FIRMWARE_VERSION_MAJOR 1
--- a/security/nss/lib/freebl/mpi/mdxptest.c
+++ b/security/nss/lib/freebl/mpi/mdxptest.c
@@ -1,16 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <malloc.h>
 #include <time.h>
 #include "mpi.h"
 #include "mpi-priv.h"
 
 /* #define OLD_WAY 1  */
 
 /* This key is the 1024-bit test key used for speed testing of RSA private 
 ** key ops.
@@ -262,49 +261,42 @@ main(int argc, char **argv)
     memset(buf, 0x41, sizeof buf);
 
   if (iters < 2) {
     testNewFuncs( default_n, modulus_len);
     testNewFuncs( default_n+1, modulus_len - 1);
     testNewFuncs( default_n+2, modulus_len - 2);
     testNewFuncs( default_n+3, modulus_len - 3);
 
-    printf("%lu allocations, %lu frees, %lu copies\n", mp_allocs, mp_frees, mp_copies);
     rv = testModExp(default_n, 0, buf, buf2, modulus_len);
     dumpBytes((unsigned char *)buf2, modulus_len);
 
-    printf("%lu allocations, %lu frees, %lu copies\n", mp_allocs, mp_frees, mp_copies);
     rv = testModExp(default_n, 1, buf, buf2, modulus_len);
     dumpBytes((unsigned char *)buf2, modulus_len);
 
-    printf("%lu allocations, %lu frees, %lu copies\n", mp_allocs, mp_frees, mp_copies);
     rv = testModExp(default_n, 2, buf, buf2, modulus_len);
     dumpBytes((unsigned char *)buf2, modulus_len);
 
-    printf("%lu allocations, %lu frees, %lu copies\n", mp_allocs, mp_frees, mp_copies);
     rv = testModExp(default_n, 3, buf, buf2, modulus_len);
     dumpBytes((unsigned char *)buf2, modulus_len);
   }
-    printf("%lu allocations, %lu frees, %lu copies\n", mp_allocs, mp_frees, mp_copies);
     rv = doModExp(default_n, default_d, buf, buf2, modulus_len);
     if (rv != 0) {
 	fprintf(stderr, "Error in modexp operation:\n");
 	exit(1);
     }
     dumpBytes((unsigned char *)buf2, modulus_len);
-    printf("%lu allocations, %lu frees, %lu copies\n", mp_allocs, mp_frees, mp_copies);
 
     timeCtx = CreateTimingContext();
     TimingBegin(timeCtx);
     i = iters;
     while (i--) {
 	rv = doModExp(default_n, default_d, buf, buf2, modulus_len);
 	if (rv != 0) {
 	    fprintf(stderr, "Error in modexp operation\n");
 	    exit(1);
 	}
     }
     TimingEnd(timeCtx);
     printf("%ld iterations in %s\n", iters, TimingGenerateString(timeCtx));
-    printf("%lu allocations, %lu frees, %lu copies\n", mp_allocs, mp_frees, mp_copies);
 
     return 0;
 }
--- a/security/nss/lib/freebl/mpi/mpi-priv.h
+++ b/security/nss/lib/freebl/mpi/mpi-priv.h
@@ -95,20 +95,16 @@ extern const float s_logv_2[];
 
 /* {{{ private function declarations */
 
 void     s_mp_setz(mp_digit *dp, mp_size count); /* zero digits           */
 void     s_mp_copy(const mp_digit *sp, mp_digit *dp, mp_size count); /* copy */
 void    *s_mp_alloc(size_t nb, size_t ni);       /* general allocator     */
 void     s_mp_free(void *ptr);                   /* general free function */
 
-extern unsigned long mp_allocs;
-extern unsigned long mp_frees;
-extern unsigned long mp_copies;
-
 mp_err   s_mp_grow(mp_int *mp, mp_size min);   /* increase allocated size */
 mp_err   s_mp_pad(mp_int *mp, mp_size min);    /* left pad with zeroes    */
 
 void     s_mp_clamp(mp_int *mp);               /* clip leading zeroes     */
 
 void     s_mp_exch(mp_int *a, mp_int *b);      /* swap a and b in place   */
 
 mp_err   s_mp_lshd(mp_int *mp, mp_size p);     /* left-shift by p digits  */
--- a/security/nss/lib/freebl/mpi/mpi.c
+++ b/security/nss/lib/freebl/mpi/mpi.c
@@ -57,20 +57,16 @@ static const char *mp_err_string[] = {
 /* Value to digit maps for radix conversion   */
 
 /* s_dmap_1 - standard digits and letters */
 static const char *s_dmap_1 = 
   "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";
 
 /* }}} */
 
-unsigned long mp_allocs;
-unsigned long mp_frees;
-unsigned long mp_copies;
-
 /* {{{ Default precision manipulation */
 
 /* Default precision for newly created mp_int's      */
 static mp_size s_mp_defprec = MP_DEFPREC;
 
 mp_size mp_get_prec(void)
 {
   return s_mp_defprec;
@@ -2804,41 +2800,37 @@ inline void s_mp_copy(const mp_digit *sp
 #if MP_MEMCPY == 0
   int  ix;
 
   for(ix = 0; ix < count; ix++)
     dp[ix] = sp[ix];
 #else
   memcpy(dp, sp, count * sizeof(mp_digit));
 #endif
-  ++mp_copies;
-
 } /* end s_mp_copy() */
 
 /* }}} */
 
 /* {{{ s_mp_alloc(nb, ni) */
 
 /* Allocate ni records of nb bytes each, and return a pointer to that     */
 inline void *s_mp_alloc(size_t nb, size_t ni)
 {
-  ++mp_allocs;
   return calloc(nb, ni);
 
 } /* end s_mp_alloc() */
 
 /* }}} */
 
 /* {{{ s_mp_free(ptr) */
 
 /* Free the memory pointed to by ptr                                      */
 inline void s_mp_free(void *ptr)
 {
   if(ptr) {
-    ++mp_frees;
     free(ptr);
   }
 } /* end s_mp_free() */
 
 /* }}} */
 
 /* {{{ s_mp_clamp(mp) */
 
--- a/security/nss/lib/nss/nss.h
+++ b/security/nss/lib/nss/nss.h
@@ -17,22 +17,22 @@
 
 /*
  * NSS's major version, minor version, patch level, build number, and whether
  * this is a beta release.
  *
  * The format of the version string should be
  *     "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
  */
-#define NSS_VERSION  "3.25" _NSS_CUSTOMIZED " Beta"
+#define NSS_VERSION  "3.25" _NSS_CUSTOMIZED
 #define NSS_VMAJOR   3
 #define NSS_VMINOR   25
 #define NSS_VPATCH   0
 #define NSS_VBUILD   0
-#define NSS_BETA     PR_TRUE
+#define NSS_BETA     PR_FALSE
 
 #ifndef RC_INVOKED
 
 #include "seccomon.h"
 
 typedef struct NSSInitParametersStr NSSInitParameters;
 
 /*
--- a/security/nss/lib/softoken/softkver.h
+++ b/security/nss/lib/softoken/softkver.h
@@ -20,16 +20,16 @@
 
 /*
  * Softoken's major version, minor version, patch level, build number,
  * and whether this is a beta release.
  *
  * The format of the version string should be
  *     "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
  */
-#define SOFTOKEN_VERSION  "3.25" SOFTOKEN_ECC_STRING " Beta"
+#define SOFTOKEN_VERSION  "3.25" SOFTOKEN_ECC_STRING
 #define SOFTOKEN_VMAJOR   3
 #define SOFTOKEN_VMINOR   25
 #define SOFTOKEN_VPATCH   0
 #define SOFTOKEN_VBUILD   0
-#define SOFTOKEN_BETA     PR_TRUE
+#define SOFTOKEN_BETA     PR_FALSE
 
 #endif /* _SOFTKVER_H_ */
--- a/security/nss/lib/ssl/derive.c
+++ b/security/nss/lib/ssl/derive.c
@@ -765,17 +765,17 @@ SSL_CanBypass(CERTCertificate *cert, SEC
             SECKEYPrivateKey *cpriv = NULL;
             SECKEYECParams *pecParams = NULL;
 
             if (privKeytype == ecKey && testecdhe) {
                 /* TLS_ECDHE_ECDSA */
                 pecParams = &srvPubkey->u.ec.DEREncodedParams;
             } else if (privKeytype == rsaKey && testecdhe) {
                 /* TLS_ECDHE_RSA */
-                ECName ec_curve;
+                const namedGroupDef *ecGroup;
                 int serverKeyStrengthInBits;
                 int signatureKeyStrength;
                 int requiredECCbits;
 
                 /* find a curve of equivalent strength to the RSA key's */
                 requiredECCbits = PK11_GetPrivateModulusLen(srvPrivkey);
                 if (requiredECCbits < 0)
                     break;
@@ -788,21 +788,20 @@ SSL_CanBypass(CERTCertificate *cert, SEC
                 serverKeyStrengthInBits *= BPB;
 
                 signatureKeyStrength =
                     SSL_RSASTRENGTH_TO_ECSTRENGTH(serverKeyStrengthInBits);
 
                 if (requiredECCbits > signatureKeyStrength)
                     requiredECCbits = signatureKeyStrength;
 
-                ec_curve =
-                    ssl3_GetCurveWithECKeyStrength(
-                        ssl3_GetSupportedECCurveMask(NULL),
-                        requiredECCbits);
-                rv = ssl3_ECName2Params(NULL, ec_curve, &ecParams);
+                ecGroup =
+                    ssl_GetECGroupWithStrength(PR_UINT32_MAX,
+                                               requiredECCbits);
+                rv = ssl_NamedGroup2ECParams(NULL, ecGroup, &ecParams);
                 if (rv == SECFailure) {
                     break;
                 }
                 pecParams = &ecParams;
             }
 
             if (testecdhe) {
                 /* generate server's ephemeral keys */
--- a/security/nss/lib/ssl/dhe-param.c
+++ b/security/nss/lib/ssl/dhe-param.c
@@ -34,17 +34,18 @@ static const unsigned char ff_dhe_2048_p
     0xC3, 0xFE, 0x3B, 0x1B, 0x4C, 0x6F, 0xAD, 0x73,
     0x3B, 0xB5, 0xFC, 0xBC, 0x2E, 0xC2, 0x20, 0x05,
     0xC5, 0x8E, 0xF1, 0x83, 0x7D, 0x16, 0x83, 0xB2,
     0xC6, 0xF3, 0x4A, 0x26, 0xC1, 0xB2, 0xEF, 0xFA,
     0x88, 0x6B, 0x42, 0x38, 0x61, 0x28, 0x5C, 0x97,
     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
 };
 
-static const ssl3DHParams ff_dhe_2048 = {
+static const ssl3DHParams ff_dhe_2048_params = {
+    ffdhe_2048,
     { siBuffer, (unsigned char *)ff_dhe_2048_p, sizeof(ff_dhe_2048_p) },
     { siBuffer, (unsigned char *)ff_dhe_g2, sizeof(ff_dhe_g2) },
 };
 
 static const unsigned char ff_dhe_3072_p[] = {
     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
     0xAD, 0xF8, 0x54, 0x58, 0xA2, 0xBB, 0x4A, 0x9A,
     0xAF, 0xDC, 0x56, 0x20, 0x27, 0x3D, 0x3C, 0xF1,
@@ -90,17 +91,18 @@ static const unsigned char ff_dhe_3072_p
     0xAB, 0xC5, 0x21, 0x97, 0x9B, 0x0D, 0xEA, 0xDA,
     0x1D, 0xBF, 0x9A, 0x42, 0xD5, 0xC4, 0x48, 0x4E,
     0x0A, 0xBC, 0xD0, 0x6B, 0xFA, 0x53, 0xDD, 0xEF,
     0x3C, 0x1B, 0x20, 0xEE, 0x3F, 0xD5, 0x9D, 0x7C,
     0x25, 0xE4, 0x1D, 0x2B, 0x66, 0xC6, 0x2E, 0x37,
     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
 };
 
-static const ssl3DHParams ff_dhe_3072 = {
+static const ssl3DHParams ff_dhe_3072_params = {
+    ffdhe_3072,
     { siBuffer, (unsigned char *)ff_dhe_3072_p, sizeof(ff_dhe_3072_p) },
     { siBuffer, (unsigned char *)ff_dhe_g2, sizeof(ff_dhe_g2) },
 };
 
 static const unsigned char ff_dhe_4096_p[] = {
     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
     0xAD, 0xF8, 0x54, 0x58, 0xA2, 0xBB, 0x4A, 0x9A,
     0xAF, 0xDC, 0x56, 0x20, 0x27, 0x3D, 0x3C, 0xF1,
@@ -162,17 +164,18 @@ static const unsigned char ff_dhe_4096_p
     0x2A, 0x4E, 0xCE, 0xA9, 0xF9, 0x8D, 0x0A, 0xCC,
     0x0A, 0x82, 0x91, 0xCD, 0xCE, 0xC9, 0x7D, 0xCF,
     0x8E, 0xC9, 0xB5, 0x5A, 0x7F, 0x88, 0xA4, 0x6B,
     0x4D, 0xB5, 0xA8, 0x51, 0xF4, 0x41, 0x82, 0xE1,
     0xC6, 0x8A, 0x00, 0x7E, 0x5E, 0x65, 0x5F, 0x6A,
     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
 };
 
-static const ssl3DHParams ff_dhe_4096 = {
+static const ssl3DHParams ff_dhe_4096_params = {
+    ffdhe_4096,
     { siBuffer, (unsigned char *)ff_dhe_4096_p, sizeof(ff_dhe_4096_p) },
     { siBuffer, (unsigned char *)ff_dhe_g2, sizeof(ff_dhe_g2) },
 };
 
 static const unsigned char ff_dhe_6144_p[] = {
     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
     0xAD, 0xF8, 0x54, 0x58, 0xA2, 0xBB, 0x4A, 0x9A,
     0xAF, 0xDC, 0x56, 0x20, 0x27, 0x3D, 0x3C, 0xF1,
@@ -266,17 +269,18 @@ static const unsigned char ff_dhe_6144_p
     0x5B, 0x3B, 0x71, 0xF9, 0xDC, 0x6B, 0x80, 0xD6,
     0x3F, 0xDD, 0x4A, 0x8E, 0x9A, 0xDB, 0x1E, 0x69,
     0x62, 0xA6, 0x95, 0x26, 0xD4, 0x31, 0x61, 0xC1,
     0xA4, 0x1D, 0x57, 0x0D, 0x79, 0x38, 0xDA, 0xD4,
     0xA4, 0x0E, 0x32, 0x9C, 0xD0, 0xE4, 0x0E, 0x65,
     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
 };
 
-static const ssl3DHParams ff_dhe_6144 = {
+static const ssl3DHParams ff_dhe_6144_params = {
+    ffdhe_6144,
     { siBuffer, (unsigned char *)ff_dhe_6144_p, sizeof(ff_dhe_6144_p) },
     { siBuffer, (unsigned char *)ff_dhe_g2, sizeof(ff_dhe_g2) },
 };
 
 static const unsigned char ff_dhe_8192_p[] = {
     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
     0xAD, 0xF8, 0x54, 0x58, 0xA2, 0xBB, 0x4A, 0x9A,
     0xAF, 0xDC, 0x56, 0x20, 0x27, 0x3D, 0x3C, 0xF1,
@@ -402,12 +406,13 @@ static const unsigned char ff_dhe_8192_p
     0xA6, 0xBB, 0xFD, 0xE5, 0x30, 0x67, 0x7F, 0x0D,
     0x97, 0xD1, 0x1D, 0x49, 0xF7, 0xA8, 0x44, 0x3D,
     0x08, 0x22, 0xE5, 0x06, 0xA9, 0xF4, 0x61, 0x4E,
     0x01, 0x1E, 0x2A, 0x94, 0x83, 0x8F, 0xF8, 0x8C,
     0xD6, 0x8C, 0x8B, 0xB7, 0xC5, 0xC6, 0x42, 0x4C,
     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
 };
 
-static const ssl3DHParams ff_dhe_8192 = {
+static const ssl3DHParams ff_dhe_8192_params = {
+    ffdhe_8192,
     { siBuffer, (unsigned char *)ff_dhe_8192_p, sizeof(ff_dhe_8192_p) },
     { siBuffer, (unsigned char *)ff_dhe_g2, sizeof(ff_dhe_g2) },
 };
--- a/security/nss/lib/ssl/ssl.h
+++ b/security/nss/lib/ssl/ssl.h
@@ -201,16 +201,32 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRF
  * the handshake transcript into the master secret. This option is
  * disabled by default.
  */
 #define SSL_ENABLE_EXTENDED_MASTER_SECRET 30
 
 /* Request Signed Certificate Timestamps via TLS extension (client) */
 #define SSL_ENABLE_SIGNED_CERT_TIMESTAMPS 31
 
+/* Ordinarily, when negotiating a TLS_DHE_* cipher suite the server picks the
+ * group.  draft-ietf-tls-negotiated-ff-dhe changes this to use supported_groups
+ * (formerly supported_curves) to signal which pre-defined groups are OK.
+ *
+ * This option causes an NSS client to use this extension and demand that those
+ * groups be used.  A client will signal any enabled DHE groups in the
+ * supported_groups extension and reject groups that don't match what it has
+ * enabled.  A server will only negotiate TLS_DHE_* cipher suites if the
+ * client includes the extension.
+ *
+ * See SSL_DHEGroupPrefSet() for how to control which groups are enabled.
+ *
+ * This option cannot be enabled if NSS is not compiled with ECC support.
+ */
+#define SSL_REQUIRE_DH_NAMED_GROUPS 32
+
 #ifdef SSL_DEPRECATED_FUNCTION
 /* Old deprecated function names */
 SSL_IMPORT SECStatus SSL_Enable(PRFileDesc *fd, int option, PRBool on);
 SSL_IMPORT SECStatus SSL_EnableDefault(int option, PRBool on);
 #endif
 
 /* New function names */
 SSL_IMPORT SECStatus SSL_OptionSet(PRFileDesc *fd, PRInt32 option, PRBool on);
@@ -351,17 +367,17 @@ SSL_IMPORT unsigned int SSL_SignatureMax
 ** parameters that can be used by NSS for the given server socket.
 ** The first item in the array is used as the default group, if no other
 ** selection criteria can be used by NSS.
 ** The set is provided as an array of identifiers as defined by SSLDHEGroupType.
 ** If more than one group identifier is provided, NSS will select the one to use.
 ** For example, a TLS extension sent by the client might indicate a preference.
 */
 SSL_IMPORT SECStatus SSL_DHEGroupPrefSet(PRFileDesc *fd,
-                                         SSLDHEGroupType *groups,
+                                         const SSLDHEGroupType *groups,
                                          PRUint16 num_groups);
 
 /* Enable the use of a DHE group that's smaller than the library default,
 ** for backwards compatibility reasons. The DH parameters will be created
 ** at the time this function is called, which might take a very long time.
 ** The function will block until generation is completed.
 ** The intention is to enforce that fresh and safe parameters are generated
 ** each time a process is started.
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -91,20 +91,26 @@ static SECStatus ssl3_AESGCMBypass(ssl3K
  *
  * Important: See bug 946147 before enabling, reordering, or adding any cipher
  * suites to this list.
  */
 /* clang-format off */
 static ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED] = {
    /*      cipher_suite                     policy       enabled   isPresent */
 
- /* ECDHE-PSK from [draft-mattsson-tls-ecdhe-psk-aead]. Only enabled if
-  * we are doing TLS 1.3 PSK-resumption.
+ /* ECDHE-PSK from [draft-mattsson-tls-ecdhe-psk-aead]. We only enable PSK if we
+  * are doing TLS 1.3 PSK-resumption.
   */
- { TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256,   SSL_ALLOWED, PR_TRUE,  PR_FALSE},
+ { TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE },
+ { TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE },
+ { TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384, SSL_ALLOWED, PR_TRUE, PR_FALSE },
+ { TLS_DHE_PSK_WITH_AES_128_GCM_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE },
+ { TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE },
+ { TLS_DHE_PSK_WITH_AES_256_GCM_SHA384, SSL_ALLOWED, PR_TRUE, PR_FALSE },
+
  { TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE},
  { TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,   SSL_ALLOWED, PR_TRUE, PR_FALSE},
  { TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE},
  { TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,   SSL_ALLOWED, PR_TRUE, PR_FALSE},
  { TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, SSL_ALLOWED, PR_FALSE, PR_FALSE},
  { TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,   SSL_ALLOWED, PR_FALSE, PR_FALSE},
    /* TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA is out of order to work around
     * bug 946147.
@@ -322,17 +328,18 @@ static const ssl3KEADef kea_defs[] =
     {kea_dh_anon,        ssl_kea_dh,   ssl_sign_null, ssl_auth_null, PR_FALSE,   0, PR_FALSE, PR_TRUE,  SEC_OID_TLS_DH_ANON},
     {kea_dh_anon_export, ssl_kea_dh,   ssl_sign_null, ssl_auth_null, PR_TRUE,  512, PR_FALSE, PR_TRUE,  SEC_OID_TLS_DH_ANON_EXPORT},
     {kea_rsa_fips,       ssl_kea_rsa,  ssl_sign_rsa, ssl_auth_rsa_decrypt,   PR_FALSE,   0, PR_TRUE,  PR_FALSE, SEC_OID_TLS_RSA},
     {kea_ecdh_ecdsa,     ssl_kea_ecdh, ssl_sign_null, ssl_auth_ecdh_ecdsa, PR_FALSE,   0, PR_FALSE, PR_FALSE, SEC_OID_TLS_ECDH_ECDSA},
     {kea_ecdhe_ecdsa,    ssl_kea_ecdh, ssl_sign_ecdsa, ssl_auth_ecdsa, PR_FALSE,   0, PR_FALSE, PR_TRUE,  SEC_OID_TLS_ECDHE_ECDSA},
     {kea_ecdh_rsa,       ssl_kea_ecdh, ssl_sign_null, ssl_auth_ecdh_rsa, PR_FALSE,   0, PR_FALSE, PR_FALSE, SEC_OID_TLS_ECDH_RSA},
     {kea_ecdhe_rsa,      ssl_kea_ecdh, ssl_sign_rsa, ssl_auth_rsa_sign,   PR_FALSE,   0, PR_FALSE, PR_TRUE,  SEC_OID_TLS_ECDHE_RSA},
     {kea_ecdh_anon,      ssl_kea_ecdh, ssl_sign_null, ssl_auth_null, PR_FALSE,   0, PR_FALSE, PR_TRUE,  SEC_OID_TLS_ECDH_ANON},
-    {kea_ecdhe_psk,      ssl_kea_ecdh_psk, ssl_sign_null, ssl_auth_psk, PR_FALSE, 0, PR_FALSE, PR_TRUE, SEC_OID_TLS_ECDHE_PSK}
+    {kea_ecdhe_psk,      ssl_kea_ecdh_psk, ssl_sign_null, ssl_auth_psk, PR_FALSE, 0, PR_FALSE, PR_TRUE, SEC_OID_TLS_ECDHE_PSK},
+    {kea_dhe_psk,      ssl_kea_dh_psk, ssl_sign_null, ssl_auth_psk, PR_FALSE, 0, PR_FALSE, PR_TRUE, SEC_OID_TLS_DHE_PSK},
 };
 
 /* must use ssl_LookupCipherSuiteDef to access */
 static const ssl3CipherSuiteDef cipher_suite_defs[] =
 {
 /*  cipher_suite                    bulk_cipher_alg mac_alg key_exchange_alg prf_hash_alg */
 /*  Note that the prf_hash_alg is the hash function used by the PRF, see sslimpl.h.  */
 
@@ -466,16 +473,21 @@ static const ssl3CipherSuiteDef cipher_s
     {TLS_ECDHE_RSA_WITH_NULL_SHA,         cipher_null,    mac_sha, kea_ecdhe_rsa, ssl_hash_none},
     {TLS_ECDHE_RSA_WITH_RC4_128_SHA,      cipher_rc4,     mac_sha, kea_ecdhe_rsa, ssl_hash_none},
     {TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, cipher_3des,    mac_sha, kea_ecdhe_rsa, ssl_hash_none},
     {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,  cipher_aes_128, mac_sha, kea_ecdhe_rsa, ssl_hash_none},
     {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, cipher_aes_128, hmac_sha256, kea_ecdhe_rsa, ssl_hash_sha256},
     {TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,  cipher_aes_256, mac_sha, kea_ecdhe_rsa, ssl_hash_none},
 
     {TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_ecdhe_psk, ssl_hash_sha256},
+    {TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256, cipher_chacha20, mac_aead, kea_ecdhe_psk, ssl_hash_sha256},
+    {TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384, cipher_aes_256_gcm, mac_aead, kea_ecdhe_psk, ssl_hash_sha384},
+    {TLS_DHE_PSK_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_dhe_psk, ssl_hash_sha256},
+    {TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256, cipher_chacha20, mac_aead, kea_dhe_psk, ssl_hash_sha256},
+    {TLS_DHE_PSK_WITH_AES_256_GCM_SHA384, cipher_aes_256_gcm, mac_aead, kea_dhe_psk, ssl_hash_sha384},
 };
 /* clang-format on */
 
 static const CK_MECHANISM_TYPE auth_alg_defs[] = {
     CKM_INVALID_MECHANISM, /* ssl_auth_null */
     CKM_RSA_PKCS,          /* ssl_auth_rsa_decrypt */
     CKM_DSA, /* ? _SHA1 */ /* ssl_auth_dsa */
     CKM_INVALID_MECHANISM, /* ssl_auth_kea (unused) */
@@ -489,17 +501,18 @@ static const CK_MECHANISM_TYPE auth_alg_
 PR_STATIC_ASSERT(PR_ARRAY_SIZE(auth_alg_defs) == ssl_auth_size);
 
 static const CK_MECHANISM_TYPE kea_alg_defs[] = {
     CKM_INVALID_MECHANISM, /* ssl_kea_null */
     CKM_RSA_PKCS,          /* ssl_kea_rsa */
     CKM_DH_PKCS_DERIVE,    /* ssl_kea_dh */
     CKM_INVALID_MECHANISM, /* ssl_kea_fortezza (unused) */
     CKM_ECDH1_DERIVE,      /* ssl_kea_ecdh */
-    CKM_ECDH1_DERIVE       /* ssl_kea_ecdh_psk */
+    CKM_ECDH1_DERIVE,      /* ssl_kea_ecdh_psk */
+    CKM_DH_PKCS_DERIVE     /* ssl_kea_dh_psk */
 };
 PR_STATIC_ASSERT(PR_ARRAY_SIZE(kea_alg_defs) == ssl_kea_size);
 
 typedef struct SSLCipher2MechStr {
     SSLCipherAlgorithm calg;
     CK_MECHANISM_TYPE cmech;
 } SSLCipher2Mech;
 
@@ -740,29 +753,29 @@ ssl3_CipherSuiteAllowedForVersionRange(
         case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
         case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
         case TLS_RSA_WITH_AES_128_CBC_SHA256:
         case TLS_RSA_WITH_AES_128_GCM_SHA256:
         case TLS_RSA_WITH_AES_256_GCM_SHA384:
         case TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
         case TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
         case TLS_RSA_WITH_NULL_SHA256:
-        case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
         case TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:
-        case TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
-        case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
         case TLS_DHE_DSS_WITH_AES_256_GCM_SHA384:
             return vrange->max == SSL_LIBRARY_VERSION_TLS_1_2;
 
         case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
         case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
         case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
         case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+        case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+        case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
         case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
         case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+        case TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
             return vrange->max >= SSL_LIBRARY_VERSION_TLS_1_2;
 
         /* RFC 4492: ECC cipher suites need TLS extensions to negotiate curves and
          * point formats.*/
         case TLS_ECDH_ECDSA_WITH_NULL_SHA:
         case TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
         case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
         case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
@@ -781,16 +794,21 @@ ssl3_CipherSuiteAllowedForVersionRange(
         case TLS_ECDHE_RSA_WITH_RC4_128_SHA:
         case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
         case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
         case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
             return vrange->max >= SSL_LIBRARY_VERSION_TLS_1_0 &&
                    vrange->min < SSL_LIBRARY_VERSION_TLS_1_3;
 
         case TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256:
+        case TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256:
+        case TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384:
+        case TLS_DHE_PSK_WITH_AES_128_GCM_SHA256:
+        case TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256:
+        case TLS_DHE_PSK_WITH_AES_256_GCM_SHA384:
             return vrange->max >= SSL_LIBRARY_VERSION_TLS_1_3;
 
         default:
             return vrange->min < SSL_LIBRARY_VERSION_TLS_1_3;
     }
 }
 
 /* return pointer to ssl3CipherSuiteDef for suite, or NULL */
@@ -823,32 +841,98 @@ ssl_LookupCipherSuiteCfg(ssl3CipherSuite
             return &suites[i];
     }
     /* return NULL and let the caller handle it.  */
     PORT_SetError(SSL_ERROR_UNKNOWN_CIPHER_SUITE);
     return NULL;
 }
 
 static PRBool
-ssl3_HasCert(sslSocket *ss, SSLAuthType authType)
+ssl_NamedGroupTypeEnabled(const sslSocket *ss, NamedGroupType groupType)
+{
+    unsigned int i;
+    for (i = 0; i < ssl_named_group_count; ++i) {
+        if (ssl_named_groups[i].type == groupType &&
+            ssl_NamedGroupEnabled(ss, &ssl_named_groups[i])) {
+            return PR_TRUE;
+        }
+    }
+    return PR_FALSE;
+}
+
+static PRBool
+ssl_KEAEnabled(const sslSocket *ss, SSLKEAType keaType)
+{
+    switch (keaType) {
+        case ssl_kea_rsa:
+            return PR_TRUE;
+
+        case ssl_kea_dh:
+        case ssl_kea_dh_psk: {
+            if (ss->sec.isServer && !ss->opt.enableServerDhe) {
+                return PR_FALSE;
+            }
+
+            /* No need to check for a common FFDHE group if we are in TLS 1.2 or
+             * earlier and named groups aren't required. */
+            if (!ss->opt.requireDHENamedGroups &&
+                ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+                return PR_TRUE;
+            }
+            /* If the server requires the extension, then the client must have
+             * already sent a ffdhe group. peerSupportsFfdheGroups is set to true in
+             * ssl_HandleSupportedGroupsXtn(). */
+            if (ss->sec.isServer && !ss->ssl3.hs.peerSupportsFfdheGroups) {
+                return PR_FALSE;
+            }
+            return ssl_NamedGroupTypeEnabled(ss, group_type_ff);
+        }
+
+        case ssl_kea_ecdh:
+        case ssl_kea_ecdh_psk:
+            return ssl_NamedGroupTypeEnabled(ss, group_type_ec);
+
+        case ssl_kea_fortezza:
+        default:
+            PORT_Assert(0);
+    }
+    return PR_FALSE;
+}
+
+static PRBool
+ssl_HasCert(const sslSocket *ss, SSLAuthType authType)
 {
     PRCList *cursor;
     if (authType == ssl_auth_null || authType == ssl_auth_psk) {
         return PR_TRUE;
     }
     for (cursor = PR_NEXT_LINK(&ss->serverCerts);
          cursor != &ss->serverCerts;
          cursor = PR_NEXT_LINK(cursor)) {
         sslServerCert *cert = (sslServerCert *)cursor;
-        if (cert->certType.authType == authType &&
-            cert->serverKeyPair &&
-            cert->serverKeyPair->privKey &&
-            cert->serverCertChain) {
-            return PR_TRUE;
-        }
+        if (cert->certType.authType != authType) {
+            continue;
+        }
+        if (!cert->serverKeyPair ||
+            !cert->serverKeyPair->privKey ||
+            !cert->serverCertChain) {
+            continue;
+        }
+        /* When called from ssl3_config_match_init(), all the EC curves will be
+         * enabled, so this will essentially do nothing (unless we implement
+         * curve configuration).  However, once we have seen the
+         * supported_groups extension and this is called from config_match(),
+         * this will filter out certificates with an unsupported curve. */
+        if ((authType == ssl_auth_ecdsa ||
+             authType == ssl_auth_ecdh_ecdsa ||
+             authType == ssl_auth_ecdh_rsa) &&
+            !ssl_NamedGroupEnabled(ss, cert->certType.namedCurve)) {
+            continue;
+        }
+        return PR_TRUE;
     }
     return PR_FALSE;
 }
 
 /* Initialize the suite->isPresent value for config_match
  * Returns count of enabled ciphers supported by extant tokens,
  * regardless of policy or user preference.
  * If this returns zero, the user cannot do SSL v3.
@@ -892,17 +976,17 @@ ssl3_config_match_init(sslSocket *ss)
             cipher_alg = bulk_cipher_defs[cipher_def->bulk_cipher_alg].calg;
             cipher_mech = ssl3_Alg2Mech(cipher_alg);
 
             /* Mark the suites that are backed by real tokens, certs and keys */
             suite->isPresent = PR_TRUE;
 
             authType = kea_defs[cipher_def->key_exchange_alg].authKeyType;
             if (authType != ssl_auth_null) {
-                if (isServer && !ssl3_HasCert(ss, authType)) {
+                if (isServer && !ssl_HasCert(ss, authType)) {
                     suite->isPresent = PR_FALSE;
                 }
                 if (!PK11_TokenExists(auth_alg_defs[authType])) {
                     suite->isPresent = PR_FALSE;
                 }
             }
 
             keaType = kea_defs[cipher_def->key_exchange_alg].exchKeyType;
@@ -923,73 +1007,71 @@ ssl3_config_match_init(sslSocket *ss)
     }
     PORT_Assert(numPresent > 0 || numEnabled == 0);
     if (numPresent <= 0) {
         PORT_SetError(SSL_ERROR_NO_CIPHERS_SUPPORTED);
     }
     return numPresent;
 }
 
-/* return PR_TRUE if suite matches policy, enabled state and is applicable to
- * the given version range. */
-/* It would be a REALLY BAD THING (tm) if we ever permitted the use
-** of a cipher that was NOT_ALLOWED.  So, if this is ever called with
-** policy == SSL_NOT_ALLOWED, report no match.
-*/
-/* adjust suite enabled to the availability of a token that can do the
- * cipher suite. */
+/* Return PR_TRUE if suite is usable.  This if the suite is permitted by policy,
+ * enabled, has a certificate (as needed), has a viable key agreement method, is
+ * usable with the negotiated TLS version, and is otherwise usable. */
 static PRBool
-config_match(ssl3CipherSuiteCfg *suite, int policy, PRBool enabled,
+config_match(ssl3CipherSuiteCfg *suite, int policy,
              const SSLVersionRange *vrange, const sslSocket *ss)
 {
     const ssl3CipherSuiteDef *cipher_def;
-
-    PORT_Assert(policy != SSL_NOT_ALLOWED && enabled != PR_FALSE);
-    if (policy == SSL_NOT_ALLOWED || !enabled)
+    const ssl3KEADef *kea_def;
+
+    PORT_Assert(policy != SSL_NOT_ALLOWED);
+    if (policy == SSL_NOT_ALLOWED)
         return PR_FALSE;
 
-    cipher_def = ssl_LookupCipherSuiteDef(suite->cipher_suite);
-    PORT_Assert(cipher_def != NULL);
-
-    PORT_Assert(ss != NULL);
-    if (ss->sec.isServer && !ss->opt.enableServerDhe &&
-        kea_defs[cipher_def->key_exchange_alg].exchKeyType == ssl_kea_dh)
-        return PR_FALSE;
-
-    if (!suite->enabled)
+    if (!suite->enabled || !suite->isPresent)
         return PR_FALSE;
 
     if ((suite->policy == SSL_NOT_ALLOWED) ||
         (suite->policy > policy))
         return PR_FALSE;
 
+    PORT_Assert(ss != NULL);
+    cipher_def = ssl_LookupCipherSuiteDef(suite->cipher_suite);
+    PORT_Assert(cipher_def != NULL);
+    kea_def = &kea_defs[cipher_def->key_exchange_alg];
+    PORT_Assert(kea_def != NULL);
+    if (!ssl_KEAEnabled(ss, kea_def->exchKeyType)) {
+        return PR_FALSE;
+    }
+
+    if (ss->sec.isServer && !ssl_HasCert(ss, kea_def->authKeyType)) {
+        return PR_FALSE;
+    }
+
     /* We only allow PSK for TLS 1.3 and only if there is resumption. */
-    if (kea_defs[cipher_def->key_exchange_alg].authKeyType == ssl_auth_psk &&
+    if (kea_def->authKeyType == ssl_auth_psk &&
         !tls13_AllowPskCipher(ss, cipher_def)) {
         return PR_FALSE;
     }
 
-    return (PRBool)(suite->isPresent &&
-                    ssl3_CipherSuiteAllowedForVersionRange(
-                        suite->cipher_suite, vrange));
-}
-
-/* return number of cipher suites that match policy, enabled state and are
- * applicable for the configured protocol version range. */
+    return ssl3_CipherSuiteAllowedForVersionRange(suite->cipher_suite, vrange);
+}
+
+/* Return the number of cipher suites that are usable. */
 /* called from ssl3_SendClientHello */
 static int
-count_cipher_suites(sslSocket *ss, int policy, PRBool enabled)
+count_cipher_suites(sslSocket *ss, int policy)
 {
     int i, count = 0;
 
     if (SSL_ALL_VERSIONS_DISABLED(&ss->vrange)) {
         return 0;
     }
     for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) {
-        if (config_match(&ss->cipherSuites[i], policy, enabled, &ss->vrange, ss))
+        if (config_match(&ss->cipherSuites[i], policy, &ss->vrange, ss))
             count++;
     }
     if (count <= 0) {
         PORT_SetError(SSL_ERROR_SSL_DISABLED);
     }
     return count;
 }
 
@@ -999,17 +1081,17 @@ tls13_PskSuiteEnabled(sslSocket *ss)
     int i;
     const ssl3CipherSuiteDef *cipher_def;
 
     for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; ++i) {
         ssl3CipherSuiteCfg *suite = &ss->cipherSuites[i];
 
         cipher_def = ssl_LookupCipherSuiteDef(suite->cipher_suite);
         if (ssl_auth_psk == kea_defs[cipher_def->key_exchange_alg].authKeyType &&
-            config_match(suite, ss->ssl3.policy, PR_TRUE, &ss->vrange, ss)) {
+            config_match(suite, ss->ssl3.policy, &ss->vrange, ss)) {
             return PR_TRUE;
         }
     }
     return PR_FALSE;
 }
 
 /*
  * Null compression, mac and encryption functions
@@ -1341,16 +1423,19 @@ ssl3_ComputeExportRSAKeyHash(SSLHashType
                              SSL3Hashes *hashes, PRBool bypassPKCS11)
 {
     PRUint8 *hashBuf;
     PRUint8 *pBuf;
     SECStatus rv = SECSuccess;
     unsigned int bufLen;
     PRUint8 buf[2 * SSL3_RANDOM_LENGTH + 2 + 4096 / 8 + 2 + 4096 / 8];
 
+    PORT_Assert(publicExponent.data);
+    PORT_Assert(modulus.data);
+
     bufLen = 2 * SSL3_RANDOM_LENGTH + 2 + modulus.len + 2 + publicExponent.len;
     if (bufLen <= sizeof buf) {
         hashBuf = buf;
     } else {
         hashBuf = PORT_Alloc(bufLen);
         if (!hashBuf) {
             return SECFailure;
         }
@@ -1371,88 +1456,103 @@ ssl3_ComputeExportRSAKeyHash(SSLHashType
     memcpy(pBuf, publicExponent.data, publicExponent.len);
     pBuf += publicExponent.len;
     PORT_Assert((unsigned int)(pBuf - hashBuf) == bufLen);
 
     rv = ssl3_ComputeCommonKeyHash(hashAlg, hashBuf, bufLen, hashes,
                                    bypassPKCS11);
 
     PRINT_BUF(95, (NULL, "RSAkey hash: ", hashBuf, bufLen));
-    if (hashAlg == ssl_hash_none) {
-        PRINT_BUF(95, (NULL, "RSAkey hash: MD5 result",
-                       hashes->u.s.md5, MD5_LENGTH));
-        PRINT_BUF(95, (NULL, "RSAkey hash: SHA1 result",
-                       hashes->u.s.sha, SHA1_LENGTH));
-    } else {
-        PRINT_BUF(95, (NULL, "RSAkey hash: result",
-                       hashes->u.raw, hashes->len));
-    }
-
-    if (hashBuf != buf && hashBuf != NULL)
+    if (rv == SECSuccess) {
+        if (hashAlg == ssl_hash_none) {
+            PRINT_BUF(95, (NULL, "RSAkey hash: MD5 result",
+                           hashes->u.s.md5, MD5_LENGTH));
+            PRINT_BUF(95, (NULL, "RSAkey hash: SHA1 result",
+                           hashes->u.s.sha, SHA1_LENGTH));
+        } else {
+            PRINT_BUF(95, (NULL, "RSAkey hash: result",
+                           hashes->u.raw, hashes->len));
+        }
+    }
+
+    if (hashBuf != buf && hashBuf != NULL) {
         PORT_Free(hashBuf);
+    }
     return rv;
 }
 
 /* Caller must set hiLevel error code. */
 /* Called from ssl3_HandleServerKeyExchange. */
 static SECStatus
-ssl3_ComputeDHKeyHash(SSLHashType hashAlg,
-                      SECItem dh_p, SECItem dh_g, SECItem dh_Ys,
-                      SSL3Random *client_rand, SSL3Random *server_rand,
-                      SSL3Hashes *hashes, PRBool bypassPKCS11)
+ssl3_ComputeDHKeyHash(sslSocket *ss, SSLHashType hashAlg, SSL3Hashes *hashes,
+                      SECItem dh_p, SECItem dh_g, SECItem dh_Ys, PRBool padY)
 {
     PRUint8 *hashBuf;
     PRUint8 *pBuf;
     SECStatus rv = SECSuccess;
     unsigned int bufLen;
     PRUint8 buf[2 * SSL3_RANDOM_LENGTH + 2 + 4096 / 8 + 2 + 4096 / 8];
 
-    bufLen = 2 * SSL3_RANDOM_LENGTH + 2 + dh_p.len + 2 + dh_g.len + 2 + dh_Ys.len;
+    PORT_Assert(dh_p.data);
+    PORT_Assert(dh_g.data);
+
+    bufLen = 2 * SSL3_RANDOM_LENGTH +
+             2 + dh_p.len +
+             2 + dh_g.len +
+             2 + (padY ? dh_p.len : dh_Ys.len);
     if (bufLen <= sizeof buf) {
         hashBuf = buf;
     } else {
         hashBuf = PORT_Alloc(bufLen);
         if (!hashBuf) {
             return SECFailure;
         }
     }
 
-    memcpy(hashBuf, client_rand, SSL3_RANDOM_LENGTH);
+    memcpy(hashBuf, &ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH);
     pBuf = hashBuf + SSL3_RANDOM_LENGTH;
-    memcpy(pBuf, server_rand, SSL3_RANDOM_LENGTH);
+    memcpy(pBuf, &ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH);
     pBuf += SSL3_RANDOM_LENGTH;
     pBuf[0] = (PRUint8)(dh_p.len >> 8);
     pBuf[1] = (PRUint8)(dh_p.len);
     pBuf += 2;
     memcpy(pBuf, dh_p.data, dh_p.len);
     pBuf += dh_p.len;
     pBuf[0] = (PRUint8)(dh_g.len >> 8);
     pBuf[1] = (PRUint8)(dh_g.len);
     pBuf += 2;
     memcpy(pBuf, dh_g.data, dh_g.len);
     pBuf += dh_g.len;
-    pBuf[0] = (PRUint8)(dh_Ys.len >> 8);
-    pBuf[1] = (PRUint8)(dh_Ys.len);
+    pBuf[0] = (PRUint8)(dh_p.len >> 8);
+    pBuf[1] = (PRUint8)(dh_p.len);
     pBuf += 2;
+    if (padY && dh_p.len > dh_Ys.len) {
+        memset(pBuf, 0, dh_p.len - dh_Ys.len);
+        pBuf += dh_p.len - dh_Ys.len;
+    }
+    /* If we're padding Y, dh_Ys can't be longer than dh_p. */
+    PORT_Assert(!padY || dh_p.len >= dh_Ys.len);
     memcpy(pBuf, dh_Ys.data, dh_Ys.len);
     pBuf += dh_Ys.len;
     PORT_Assert((unsigned int)(pBuf - hashBuf) == bufLen);
 
     rv = ssl3_ComputeCommonKeyHash(hashAlg, hashBuf, bufLen, hashes,
-                                   bypassPKCS11);
+                                   ss->opt.bypassPKCS11);
 
     PRINT_BUF(95, (NULL, "DHkey hash: ", hashBuf, bufLen));
-    if (hashAlg == ssl_hash_none) {
-        PRINT_BUF(95, (NULL, "DHkey hash: MD5 result",
-                       hashes->u.s.md5, MD5_LENGTH));
-        PRINT_BUF(95, (NULL, "DHkey hash: SHA1 result",
-                       hashes->u.s.sha, SHA1_LENGTH));
-    } else {
-        PRINT_BUF(95, (NULL, "DHkey hash: result",
-                       hashes->u.raw, hashes->len));
+    if (rv == SECSuccess) {
+        if (hashAlg == ssl_hash_none) {
+            PRINT_BUF(95, (NULL, "DHkey hash: MD5 result",
+                           hashes->u.s.md5, MD5_LENGTH));
+            PRINT_BUF(95, (NULL, "DHkey hash: SHA1 result",
+                           hashes->u.s.sha, SHA1_LENGTH));
+        } else {
+            PRINT_BUF(95, (NULL, "DHkey hash: result",
+                           hashes->u.raw, hashes->len));
+        }
     }
 
     if (hashBuf != buf && hashBuf != NULL)
         PORT_Free(hashBuf);
     return rv;
 }
 
 void
@@ -3908,32 +4008,40 @@ ssl3_HandleChangeCipherSpecs(sslSocket *
      */
     if (ss->ssl3.prSpec == ss->ssl3.pwSpec) {
         ssl3_DestroyCipherSpec(ss->ssl3.prSpec, PR_FALSE /*freeSrvName*/);
     }
     ssl_ReleaseSpecWriteLock(ss); /*************************************/
     return SECSuccess;
 }
 
+/* Function valid for >= TLS 1.2, only. */
 static CK_MECHANISM_TYPE
-ssl3_GetTls12PrfHashMechanism(sslSocket *ss)
-{
-    switch (ss->ssl3.hs.suite_def->prf_hash) {
+ssl3_GetHashMechanismByHashType(SSLHashType hashType)
+{
+    switch (hashType) {
         case ssl_hash_sha384:
             return CKM_SHA384;
         case ssl_hash_sha256:
         case ssl_hash_none:
             /* ssl_hash_none is for pre-1.2 suites, which use SHA-256. */
             return CKM_SHA256;
         default:
             PORT_Assert(0);
     }
     return CKM_SHA256;
 }
 
+/* Function valid for >= TLS 1.2, only. */
+static CK_MECHANISM_TYPE
+ssl3_GetPrfHashMechanism(sslSocket *ss)
+{
+    return ssl3_GetHashMechanismByHashType(ss->ssl3.hs.suite_def->prf_hash);
+}
+
 static SSLHashType
 ssl3_GetSuitePrfHash(sslSocket *ss)
 {
     /* ssl_hash_none is for pre-1.2 suites, which use SHA-256. */
     if (ss->ssl3.hs.suite_def->prf_hash == ssl_hash_none) {
         return ssl_hash_sha256;
     }
     return ss->ssl3.hs.suite_def->prf_hash;
@@ -4057,17 +4165,17 @@ ssl3_ComputeMasterSecretInt(sslSocket *s
     }
 
     master_params.pVersion = pms_version_ptr;
     master_params.RandomInfo.pClientRandom = cr;
     master_params.RandomInfo.ulClientRandomLen = SSL3_RANDOM_LENGTH;
     master_params.RandomInfo.pServerRandom = sr;
     master_params.RandomInfo.ulServerRandomLen = SSL3_RANDOM_LENGTH;
     if (isTLS12) {
-        master_params.prfHashMechanism = ssl3_GetTls12PrfHashMechanism(ss);
+        master_params.prfHashMechanism = ssl3_GetPrfHashMechanism(ss);
         master_params_len = sizeof(CK_TLS12_MASTER_KEY_DERIVE_PARAMS);
     } else {
         /* prfHashMechanism is not relevant with this PRF */
         master_params_len = sizeof(CK_SSL3_MASTER_KEY_DERIVE_PARAMS);
     }
 
     params.data = (unsigned char *)&master_params;
     params.len = master_params_len;
@@ -4115,18 +4223,18 @@ tls_ComputeExtendedMasterSecretInt(sslSo
     if (isDH) {
         master_derive = CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE_DH;
     } else {
         master_derive = CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE;
         pms_version_ptr = &pms_version;
     }
 
     if (pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
-        /* TLS 1.2 */
-        extended_master_params.prfHashMechanism = CKM_SHA256;
+        /* TLS 1.2+ */
+        extended_master_params.prfHashMechanism = ssl3_GetPrfHashMechanism(ss);
         key_derive = CKM_TLS12_KEY_AND_MAC_DERIVE;
     } else {
         /* TLS < 1.2 */
         extended_master_params.prfHashMechanism = CKM_TLS_PRF;
         key_derive = CKM_TLS_KEY_AND_MAC_DERIVE;
     }
 
     extended_master_params.pVersion = pms_version_ptr;
@@ -4217,18 +4325,18 @@ ssl3_DeriveMasterSecret(sslSocket *ss, P
 }
 
 /*
  * Derive encryption and MAC Keys (and IVs) from master secret
  * Sets a useful error code when returning SECFailure.
  *
  * Called only from ssl3_InitPendingCipherSpec(),
  * which in turn is called from
- *              sendRSAClientKeyExchange        (for Full handshake)
- *              sendDHClientKeyExchange         (for Full handshake)
+ *              ssl3_SendRSAClientKeyExchange    (for Full handshake)
+ *              ssl3_SendDHClientKeyExchange     (for Full handshake)
  *              ssl3_HandleClientKeyExchange    (for Full handshake)
  *              ssl3_HandleServerHello          (for session restart)
  *              ssl3_HandleClientHello          (for session restart)
  * Caller MUST hold the specWriteLock, and SSL3HandshakeLock.
  * ssl3_InitPendingCipherSpec does that.
  *
  */
 static SECStatus
@@ -4300,17 +4408,17 @@ ssl3_DeriveConnectionKeysPKCS11(sslSocke
         returnedKeys.pIVServer = NULL;
     }
 
     calg = cipher_def->calg;
     bulk_mechanism = ssl3_Alg2Mech(calg);
 
     if (isTLS12) {
         key_derive = CKM_TLS12_KEY_AND_MAC_DERIVE;
-        key_material_params.prfHashMechanism = ssl3_GetTls12PrfHashMechanism(ss);
+        key_material_params.prfHashMechanism = ssl3_GetPrfHashMechanism(ss);
         key_material_params_len = sizeof(CK_TLS12_KEY_MAT_PARAMS);
     } else if (isTLS) {
         key_derive = CKM_TLS_KEY_AND_MAC_DERIVE;
         key_material_params_len = sizeof(CK_SSL3_KEY_MAT_PARAMS);
     } else {
         key_derive = CKM_SSL3_KEY_AND_MAC_DERIVE;
         key_material_params_len = sizeof(CK_SSL3_KEY_MAT_PARAMS);
     }
@@ -4373,22 +4481,25 @@ loser:
  * buffered messages in ss->ssl3.hs.messages. Called from
  * ssl3_NegotiateCipherSuite() and ssl3_HandleServerHello. */
 static SECStatus
 ssl3_InitHandshakeHashes(sslSocket *ss)
 {
     SSL_TRC(30, ("%d: SSL3[%d]: start handshake hashes", SSL_GETPID(), ss->fd));
 
     PORT_Assert(ss->ssl3.hs.hashType == handshake_hash_unknown);
+    if (ss->version == SSL_LIBRARY_VERSION_TLS_1_2) {
+        ss->ssl3.hs.hashType = handshake_hash_record;
+    } else
 #ifndef NO_PKCS11_BYPASS
-    if (ss->opt.bypassPKCS11) {
+        if (ss->opt.bypassPKCS11) {
         PORT_Assert(!ss->ssl3.hs.sha_obj && !ss->ssl3.hs.sha_clone);
-        if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
+        if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
             const SECOidData *hashOid =
-                SECOID_FindOIDByMechanism(ssl3_GetTls12PrfHashMechanism(ss));
+                SECOID_FindOIDByMechanism(ssl3_GetPrfHashMechanism(ss));
 
             if (hashOid == NULL) {
                 PORT_Assert(hashOid == NULL);
                 ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
                 return SECFailure;
             }
 
             ss->ssl3.hs.sha_obj = HASH_GetRawHashObject(
@@ -4410,20 +4521,20 @@ ssl3_InitHandshakeHashes(sslSocket *ss)
 #endif
     {
         PORT_Assert(!ss->ssl3.hs.md5 && !ss->ssl3.hs.sha);
         /*
          * note: We should probably lookup an SSL3 slot for these
          * handshake hashes in hopes that we wind up with the same slots
          * that the master secret will wind up in ...
          */
-        if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
+        if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
             /* determine the hash from the prf */
             const SECOidData *hash_oid =
-                SECOID_FindOIDByMechanism(ssl3_GetTls12PrfHashMechanism(ss));
+                SECOID_FindOIDByMechanism(ssl3_GetPrfHashMechanism(ss));
 
             /* Get the PKCS #11 mechanism for the Hash from the cipher suite (prf_hash)
              * Convert that to the OidTag. We can then use that OidTag to create our
              * PK11Context */
             PORT_Assert(hash_oid != NULL);
             if (hash_oid == NULL) {
                 ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
                 return SECFailure;
@@ -4435,38 +4546,16 @@ ssl3_InitHandshakeHashes(sslSocket *ss)
                 return SECFailure;
             }
             ss->ssl3.hs.hashType = handshake_hash_single;
 
             if (PK11_DigestBegin(ss->ssl3.hs.sha) != SECSuccess) {
                 ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
                 return SECFailure;
             }
-
-            /* Create a backup SHA-1 hash for a potential client auth
-             * signature.
-             *
-             * In TLS 1.2, ssl3_ComputeHandshakeHashes always uses the
-             * handshake hash function (SHA-256). If the server or the client
-             * does not support SHA-256 as a signature hash, we can either
-             * maintain a backup SHA-1 handshake hash or buffer all handshake
-             * messages.
-             */
-            if (!ss->sec.isServer) {
-                ss->ssl3.hs.backupHash = PK11_CreateDigestContext(SEC_OID_SHA1);
-                if (ss->ssl3.hs.backupHash == NULL) {
-                    ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
-                    return SECFailure;
-                }
-
-                if (PK11_DigestBegin(ss->ssl3.hs.backupHash) != SECSuccess) {
-                    ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
-                    return SECFailure;
-                }
-            }
         } else {
             /* Both ss->ssl3.hs.md5 and ss->ssl3.hs.sha should be NULL or
              * created successfully. */
             ss->ssl3.hs.md5 = PK11_CreateDigestContext(SEC_OID_MD5);
             if (ss->ssl3.hs.md5 == NULL) {
                 ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
                 return SECFailure;
             }
@@ -4485,26 +4574,23 @@ ssl3_InitHandshakeHashes(sslSocket *ss)
             }
             if (PK11_DigestBegin(ss->ssl3.hs.sha) != SECSuccess) {
                 ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
                 return SECFailure;
             }
         }
     }
 
-    if (ss->ssl3.hs.messages.len > 0) {
+    if (ss->ssl3.hs.hashType != handshake_hash_record &&
+        ss->ssl3.hs.messages.len > 0) {
         if (ssl3_UpdateHandshakeHashes(ss, ss->ssl3.hs.messages.buf,
-                                       ss->ssl3.hs.messages.len) !=
-            SECSuccess) {
+                                       ss->ssl3.hs.messages.len) != SECSuccess) {
             return SECFailure;
         }
-        PORT_Free(ss->ssl3.hs.messages.buf);
-        ss->ssl3.hs.messages.buf = NULL;
-        ss->ssl3.hs.messages.len = 0;
-        ss->ssl3.hs.messages.space = 0;
+        sslBuffer_Clear(&ss->ssl3.hs.messages);
     }
 
     return SECSuccess;
 }
 
 SECStatus
 ssl3_RestartHandshakeHashes(sslSocket *ss)
 {
@@ -4534,56 +4620,61 @@ ssl3_RestartHandshakeHashes(sslSocket *s
  */
 /* Called from  ssl3_InitHandshakeHashes()
 **      ssl3_AppendHandshake()
 **      ssl3_HandleV2ClientHello()
 **      ssl3_HandleHandshakeMessage()
 ** Caller must hold the ssl3Handshake lock.
 */
 SECStatus
-ssl3_UpdateHandshakeHashes(sslSocket *ss, const unsigned char *b,
-                           unsigned int l)
+ssl3_UpdateHandshakeHashes(sslSocket *ss, const unsigned char *b, unsigned int l)
 {
     SECStatus rv = SECSuccess;
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
-    /* We need to buffer the handshake messages until we have established
-     * which handshake hash function to use. */
-    if (ss->ssl3.hs.hashType == handshake_hash_unknown) {
+    /* With TLS 1.3, and versions TLS.1.1 and older, we keep the hash(es)
+     * always up to date. However, we must initially buffer the handshake
+     * messages, until we know what to do.
+     * If ss->ssl3.hs.hashType != handshake_hash_unknown,
+     * it means we know what to do. We calculate (hash our input),
+     * and we stop appending to the buffer.
+     *
+     * With TLS 1.2, we always append all handshake messages,
+     * and never update the hash, because the hash function we must use for
+     * certificate_verify might be different from the hash function we use
+     * when signing other handshake hashes. */
+
+    if (ss->ssl3.hs.hashType == handshake_hash_unknown ||
+        ss->ssl3.hs.hashType == handshake_hash_record) {
         return sslBuffer_Append(&ss->ssl3.hs.messages, b, l);
     }
 
     PRINT_BUF(90, (NULL, "handshake hash input:", b, l));
 
 #ifndef NO_PKCS11_BYPASS
     if (ss->opt.bypassPKCS11) {
         if (ss->ssl3.hs.hashType == handshake_hash_single) {
+            PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
             ss->ssl3.hs.sha_obj->update(ss->ssl3.hs.sha_cx, b, l);
-        } else {
+        } else if (ss->ssl3.hs.hashType == handshake_hash_combo) {
             MD5_Update((MD5Context *)ss->ssl3.hs.md5_cx, b, l);
             SHA1_Update((SHA1Context *)ss->ssl3.hs.sha_cx, b, l);
         }
         return rv;
     }
 #endif
     if (ss->ssl3.hs.hashType == handshake_hash_single) {
+        PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
         rv = PK11_DigestOp(ss->ssl3.hs.sha, b, l);
         if (rv != SECSuccess) {
             ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
             return rv;
         }
-        if (ss->ssl3.hs.backupHash) {
-            rv = PK11_DigestOp(ss->ssl3.hs.backupHash, b, l);
-            if (rv != SECSuccess) {
-                ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
-                return rv;
-            }
-        }
-    } else {
+    } else if (ss->ssl3.hs.hashType == handshake_hash_combo) {
         rv = PK11_DigestOp(ss->ssl3.hs.md5, b, l);
         if (rv != SECSuccess) {
             ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
             return rv;
         }
         rv = PK11_DigestOp(ss->ssl3.hs.sha, b, l);
         if (rv != SECSuccess) {
             ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
@@ -5050,16 +5141,68 @@ ssl3_ConsumeSignatureAndHashAlgorithm(ss
     }
     return SECSuccess;
 }
 
 /**************************************************************************
  * end of Consume Handshake functions.
  **************************************************************************/
 
+#ifndef NO_PKCS11_BYPASS
+static SECStatus
+ssl3_ComputeBypassHandshakeHash(unsigned char *buf, unsigned int len,
+                                SSLHashType hashAlg, SSL3Hashes *hashes)
+{
+    const SECHashObject *h_obj = NULL;
+    PRUint64 h_cx[MAX_MAC_CONTEXT_LLONGS];
+    const SECOidData *hashOid =
+        SECOID_FindOIDByMechanism(ssl3_GetHashMechanismByHashType(hashAlg));
+
+    if (hashOid) {
+        h_obj = HASH_GetRawHashObject(HASH_GetHashTypeByOidTag(hashOid->offset));
+    }
+    if (!h_obj) {
+        ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
+        return SECFailure;
+    }
+    h_obj->begin(h_cx);
+    h_obj->update(h_cx, buf, len);
+    h_obj->end(h_cx, hashes->u.raw, &hashes->len, sizeof(hashes->u.raw));
+    PRINT_BUF(60, (NULL, "HASH: result", hashes->u.raw, hashes->len));
+    hashes->hashAlg = hashAlg;
+    return SECSuccess;
+}
+#endif
+
+static SECStatus
+ssl3_ComputePkcs11HandshakeHash(unsigned char *buf, unsigned int len,
+                                SSLHashType hashAlg, SSL3Hashes *hashes)
+{
+    SECStatus rv = SECFailure;
+    PK11Context *hashContext = PK11_CreateDigestContext(
+        ssl3_TLSHashAlgorithmToOID(hashAlg));
+
+    if (!hashContext) {
+        return rv;
+    }
+    rv = PK11_DigestBegin(hashContext);
+    if (rv == SECSuccess) {
+        rv = PK11_DigestOp(hashContext, buf, len);
+    }
+    if (rv == SECSuccess) {
+        rv = PK11_DigestFinal(hashContext, hashes->u.raw, &hashes->len,
+                              sizeof(hashes->u.raw));
+    }
+    if (rv == SECSuccess) {
+        hashes->hashAlg = hashAlg;
+    }
+    PK11_DestroyContext(hashContext, PR_TRUE);
+    return rv;
+}
+
 /* Extract the hashes of handshake messages to this point.
  * Called from ssl3_SendCertificateVerify
  *             ssl3_SendFinished
  *             ssl3_HandleHandshakeMessage
  *
  * Caller must hold the SSL3HandshakeLock.
  * Caller must hold a read or write lock on the Spec R/W lock.
  *  (There is presently no way to assert on a Read lock.)
@@ -5095,17 +5238,23 @@ ssl3_ComputeHandshakeHashes(sslSocket *s
                                  sizeof(hashes->u.raw));
 
         PRINT_BUF(60, (NULL, "HASH: result", hashes->u.raw, hashes->len));
 
         /* If we ever support ciphersuites where the PRF hash isn't SHA-256
          * then this will need to be updated. */
         hashes->hashAlg = ssl3_GetSuitePrfHash(ss);
         rv = SECSuccess;
-    } else if (ss->opt.bypassPKCS11) {
+    } else if (ss->opt.bypassPKCS11 &&
+               ss->ssl3.hs.hashType == handshake_hash_record) {
+        rv = ssl3_ComputeBypassHandshakeHash(ss->ssl3.hs.messages.buf,
+                                             ss->ssl3.hs.messages.len,
+                                             ssl3_GetSuitePrfHash(ss),
+                                             hashes);
+    } else if (ss->opt.bypassPKCS11) { /* TLS 1.1 or lower */
         /* compute them without PKCS11 */
         PRUint64 md5_cx[MAX_MAC_CONTEXT_LLONGS];
         PRUint64 sha_cx[MAX_MAC_CONTEXT_LLONGS];
 
 #define md5cx ((MD5Context *)md5_cx)
 #define shacx ((SHA1Context *)sha_cx)
 
         MD5_Clone(md5cx, (MD5Context *)ss->ssl3.hs.md5_cx);
@@ -5215,16 +5364,21 @@ ssl3_ComputeHandshakeHashes(sslSocket *s
             if (PK11_RestoreContext(h, stateBuf, stateLen) != SECSuccess) {
                 ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
                 rv = SECFailure;
             }
             if (stateBuf != stackBuf) {
                 PORT_ZFree(stateBuf, stateLen);
             }
         }
+    } else if (ss->ssl3.hs.hashType == handshake_hash_record) {
+        rv = ssl3_ComputePkcs11HandshakeHash(ss->ssl3.hs.messages.buf,
+                                             ss->ssl3.hs.messages.len,
+                                             ssl3_GetSuitePrfHash(ss),
+                                             hashes);
     } else {
         /* compute hashes with PKCS11 */
         PK11Context *md5;
         PK11Context *sha = NULL;
         unsigned char *md5StateBuf = NULL;
         unsigned char *shaStateBuf = NULL;
         unsigned int md5StateLen, shaStateLen;
         unsigned char md5StackBuf[256];
@@ -5363,41 +5517,16 @@ ssl3_ComputeHandshakeHashes(sslSocket *s
             if (shaStateBuf != shaStackBuf) {
                 PORT_ZFree(shaStateBuf, shaStateLen);
             }
         }
     }
     return rv;
 }
 
-static SECStatus
-ssl3_ComputeBackupHandshakeHashes(sslSocket *ss,
-                                  SSL3Hashes *hashes) /* output goes here. */
-{
-    SECStatus rv = SECSuccess;
-
-    PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
-    PORT_Assert(!ss->sec.isServer);
-    PORT_Assert(ss->ssl3.hs.hashType == handshake_hash_single);
-
-    rv = PK11_DigestFinal(ss->ssl3.hs.backupHash, hashes->u.raw, &hashes->len,
-                          sizeof(hashes->u.raw));
-    if (rv != SECSuccess) {
-        ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
-        rv = SECFailure;
-        goto loser;
-    }
-    hashes->hashAlg = ssl_hash_sha1;
-
-loser:
-    PK11_DestroyContext(ss->ssl3.hs.backupHash, PR_TRUE);
-    ss->ssl3.hs.backupHash = NULL;
-    return rv;
-}
-
 /**************************************************************************
  * end of Handshake Hash functions.
  * Begin Send and Handle functions for handshakes.
  **************************************************************************/
 
 /* Called from ssl3_HandleHelloRequest(),
  *             ssl3_RedoHandshake()
  *             ssl_BeginClientHandshake (when resuming ssl3 session)
@@ -5668,27 +5797,22 @@ ssl3_SendClientHello(sslSocket *ss, PRBo
             return SECFailure;
         }
         total_exten_len += extLen;
 
         if (total_exten_len > 0)
             total_exten_len += 2;
     }
 
-    if (!total_exten_len || !isTLS) {
-        /* not sending the elliptic_curves and ec_point_formats extensions */
-        ssl3_DisableECCSuites(ss, NULL); /* disable all ECC suites */
-    }
-
     if (IS_DTLS(ss)) {
         ssl3_DisableNonDTLSSuites(ss);
     }
 
     /* how many suites are permitted by policy and user preference? */
-    num_suites = count_cipher_suites(ss, ss->ssl3.policy, PR_TRUE);
+    num_suites = count_cipher_suites(ss, ss->ssl3.policy);
     if (!num_suites) {
         if (sid->u.ssl3.lock) {
             PR_RWLock_Unlock(sid->u.ssl3.lock);
         }
         return SECFailure; /* count_cipher_suites has set error code. */
     }
 
     fallbackSCSV = ss->opt.enableFallbackSCSV && (!requestingResume ||
@@ -5831,17 +5955,17 @@ ssl3_SendClientHello(sslSocket *ss, PRBo
                 PR_RWLock_Unlock(sid->u.ssl3.lock);
             }
             return rv; /* err set by ssl3_AppendHandshake* */
         }
         actual_count++;
     }
     for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) {
         ssl3CipherSuiteCfg *suite = &ss->cipherSuites[i];
-        if (config_match(suite, ss->ssl3.policy, PR_TRUE, &ss->vrange, ss)) {
+        if (config_match(suite, ss->ssl3.policy, &ss->vrange, ss)) {
             actual_count++;
             if (actual_count > num_suites) {
                 if (sid->u.ssl3.lock) {
                     PR_RWLock_Unlock(sid->u.ssl3.lock);
                 }
                 /* set error card removal/insertion error */
                 PORT_SetError(SSL_ERROR_TOKEN_INSERTION_REMOVAL);
                 return SECFailure;
@@ -6454,17 +6578,17 @@ hexEncode(char *out, const unsigned char
         *(out++) = hextable[in[i] & 15];
     }
 }
 #endif
 
 /* Called from ssl3_SendClientKeyExchange(). */
 /* Presently, this always uses PKCS11.  There is no bypass for this. */
 static SECStatus
-sendRSAClientKeyExchange(sslSocket *ss, SECKEYPublicKey *svrPubKey)
+ssl3_SendRSAClientKeyExchange(sslSocket *ss, SECKEYPublicKey *svrPubKey)
 {
     PK11SymKey *pms = NULL;
     SECStatus rv = SECFailure;
     SECItem enc_pms = { siBuffer, NULL, 0 };
     PRBool isTLS;
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
@@ -6559,110 +6683,147 @@ loser:
         PORT_Free(enc_pms.data);
     }
     if (pms != NULL) {
         PK11_FreeSymKey(pms);
     }
     return rv;
 }
 
+/* DH shares need to be padded to the size of their prime.  Some implementations
+ * require this.  TLS 1.3 also requires this. */
+SECStatus
+ssl_AppendPaddedDHKeyShare(sslSocket *ss, SECKEYPublicKey *pubKey)
+{
+    SECStatus rv;
+    unsigned int pad = pubKey->u.dh.prime.len - pubKey->u.dh.publicValue.len;
+
+    rv = ssl3_AppendHandshakeNumber(ss, pubKey->u.dh.prime.len, 2);
+    if (rv != SECSuccess) {
+        return rv;
+    }
+    while (pad) {
+        rv = ssl3_AppendHandshakeNumber(ss, 0, 1);
+        if (rv != SECSuccess) {
+            return rv;
+        }
+        --pad;
+    }
+    rv = ssl3_AppendHandshake(ss, pubKey->u.dh.publicValue.data,
+                              pubKey->u.dh.publicValue.len);
+    if (rv != SECSuccess) {
+        return rv;
+    }
+    return SECSuccess;
+}
+
 /* Called from ssl3_SendClientKeyExchange(). */
 /* Presently, this always uses PKCS11.  There is no bypass for this. */
 static SECStatus
-sendDHClientKeyExchange(sslSocket *ss, SECKEYPublicKey *svrPubKey)
+ssl3_SendDHClientKeyExchange(sslSocket *ss, SECKEYPublicKey *svrPubKey)
 {
     PK11SymKey *pms = NULL;
-    SECStatus rv = SECFailure;
+    SECStatus rv;
     PRBool isTLS;
     CK_MECHANISM_TYPE target;
 
-    SECKEYDHParams dhParam;           /* DH parameters */
-    SECKEYPublicKey *pubKey = NULL;   /* Ephemeral DH key */
-    SECKEYPrivateKey *privKey = NULL; /* Ephemeral DH key */
+    const ssl3DHParams *params;
+    ssl3DHParams customParams;
+    const namedGroupDef *groupDef;
+    namedGroupDef customGroupDef = {
+        0, ffdhe_custom, 0, group_type_ff,
+        SEC_OID_TLS_DHE_CUSTOM, PR_FALSE
+    };
+    sslEphemeralKeyPair *keyPair = NULL;
+    SECKEYPublicKey *pubKey;
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
 
     isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0);
 
     /* Copy DH parameters from server key */
 
     if (svrPubKey->keyType != dhKey) {
         PORT_SetError(SEC_ERROR_BAD_KEY);
-        goto loser;
-    }
-    dhParam.prime.data = svrPubKey->u.dh.prime.data;
-    dhParam.prime.len = svrPubKey->u.dh.prime.len;
-    dhParam.base.data = svrPubKey->u.dh.base.data;
-    dhParam.base.len = svrPubKey->u.dh.base.len;
-
-    /* Generate ephemeral DH keypair */
-    privKey = SECKEY_CreateDHPrivateKey(&dhParam, &pubKey, NULL);
-    if (!privKey || !pubKey) {
+        return SECFailure;
+    }
+
+    /* Work out the parameters. */
+    if (ss->opt.requireDHENamedGroups || ss->ssl3.hs.peerSupportsFfdheGroups) {
+        /* We already validated the group in ssl_HandleDHServerKeyExchange(),
+         * but this function also allows us to retrieve the group parameters. */
+        rv = ssl_ValidateDHENamedGroup(ss, &svrPubKey->u.dh.prime,
+                                       &svrPubKey->u.dh.base,
+                                       &groupDef, &params);
+        /* We already checked this. */
+        PORT_Assert(rv == SECSuccess);
+    } else {
+        customParams.name = ffdhe_custom;
+        customParams.prime.data = svrPubKey->u.dh.prime.data;
+        customParams.prime.len = svrPubKey->u.dh.prime.len;
+        customParams.base.data = svrPubKey->u.dh.base.data;
+        customParams.base.len = svrPubKey->u.dh.base.len;
+        params = &customParams;
+        customGroupDef.bits = SECKEY_PublicKeyStrengthInBits(svrPubKey);
+        groupDef = &customGroupDef;
+    }
+
+    rv = ssl_CreateDHEKeyPair(groupDef, params, &keyPair);
+    if (rv != SECSuccess) {
         ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL);
-        rv = SECFailure;
-        goto loser;
-    }
+        return SECFailure;
+    }
+    pubKey = keyPair->keys->pubKey;
     PRINT_BUF(50, (ss, "DH public value:",
                    pubKey->u.dh.publicValue.data,
                    pubKey->u.dh.publicValue.len));
 
     if (isTLS)
         target = CKM_TLS_MASTER_KEY_DERIVE_DH;
     else
         target = CKM_SSL3_MASTER_KEY_DERIVE_DH;
 
     /* Determine the PMS */
-
-    pms = PK11_PubDerive(privKey, svrPubKey, PR_FALSE, NULL, NULL,
-                         CKM_DH_PKCS_DERIVE, target, CKA_DERIVE, 0, NULL);
+    pms = PK11_PubDerive(keyPair->keys->privKey, svrPubKey,
+                         PR_FALSE, NULL, NULL, CKM_DH_PKCS_DERIVE,
+                         target, CKA_DERIVE, 0, NULL);
 
     if (pms == NULL) {
         ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
         goto loser;
     }
 
-    SECKEY_DestroyPrivateKey(privKey);
-    privKey = NULL;
-
+    /* Note: send the DH share padded to avoid triggering bugs. */
     rv = ssl3_AppendHandshakeHeader(ss, client_key_exchange,
-                                    pubKey->u.dh.publicValue.len + 2);
+                                    params->prime.len + 2);
     if (rv != SECSuccess) {
         goto loser; /* err set by ssl3_AppendHandshake* */
     }
-    rv = ssl3_AppendHandshakeVariable(ss,
-                                      pubKey->u.dh.publicValue.data,
-                                      pubKey->u.dh.publicValue.len, 2);
-    SECKEY_DestroyPublicKey(pubKey);
-    pubKey = NULL;
-
-    if (rv != SECSuccess) {
-        goto loser; /* err set by ssl3_AppendHandshake* */
+    rv = ssl_AppendPaddedDHKeyShare(ss, pubKey);
+    if (rv != SECSuccess) {
+        goto loser; /* err set by ssl_AppendPaddedDHKeyShare */
     }
 
     rv = ssl3_InitPendingCipherSpec(ss, pms);
-    PK11_FreeSymKey(pms);
-    pms = NULL;
-
     if (rv != SECSuccess) {
         ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
         goto loser;
     }
 
-    rv = SECSuccess;
+    PK11_FreeSymKey(pms);
+    ssl_FreeEphemeralKeyPair(keyPair);
+    return SECSuccess;
 
 loser:
-
     if (pms)
         PK11_FreeSymKey(pms);
-    if (privKey)
-        SECKEY_DestroyPrivateKey(privKey);
-    if (pubKey)
-        SECKEY_DestroyPublicKey(pubKey);
-    return rv;
+    if (keyPair)
+        ssl_FreeEphemeralKeyPair(keyPair);
+    return SECFailure;
 }
 
 /* Called from ssl3_HandleServerHelloDone(). */
 static SECStatus
 ssl3_SendClientKeyExchange(sslSocket *ss)
 {
     SECKEYPublicKey *serverKey = NULL;
     SECStatus rv = SECFailure;
@@ -6700,21 +6861,21 @@ ssl3_SendClientKeyExchange(sslSocket *ss
         }
     }
 
     ss->sec.keaType = ss->ssl3.hs.kea_def->exchKeyType;
     ss->sec.keaKeyBits = SECKEY_PublicKeyStrengthInBits(serverKey);
 
     switch (ss->ssl3.hs.kea_def->exchKeyType) {
         case ssl_kea_rsa:
-            rv = sendRSAClientKeyExchange(ss, serverKey);
+            rv = ssl3_SendRSAClientKeyExchange(ss, serverKey);
             break;
 
         case ssl_kea_dh:
-            rv = sendDHClientKeyExchange(ss, serverKey);
+            rv = ssl3_SendDHClientKeyExchange(ss, serverKey);
             break;
 
         case ssl_kea_ecdh:
             rv = ssl3_SendECDHClientKeyExchange(ss, serverKey);
             break;
 
         default:
             /* got an unknown or unsupported Key Exchange Algorithm.  */
@@ -6749,35 +6910,47 @@ ssl3_SendCertificateVerify(sslSocket *ss
     PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
     SSL_TRC(3, ("%d: SSL3[%d]: send certificate_verify handshake",
                 SSL_GETPID(), ss->fd));
 
     isTLS13 = (PRBool)(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
     ssl_GetSpecReadLock(ss);
-    if (ss->ssl3.hs.hashType == handshake_hash_single &&
-        ss->ssl3.hs.backupHash) {
-        PORT_Assert(!isTLS13);
-        /* TODO(ekr@rtfm.com): The backup hash here contains a SHA-1 hash
-         * but in TLS 1.3, we always sign H(Context, Hash(handshake))
-         * where:
-         *
-         * H is the negotiated signature hash and
-         * Hash is the cipher-suite specific handshake hash
-         * Generally this means that Hash is SHA-256.
-         *
-         * We need code to negotiate H but the current code is a mess.
-         */
-        if (isTLS13) {
-            /* rv is already set to SECFailure */
-            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-        } else {
-            rv = ssl3_ComputeBackupHandshakeHashes(ss, &hashes);
-            PORT_Assert(!ss->ssl3.hs.backupHash);
+
+    /* TODO(ekr@rtfm.com):
+     * In TLS 1.3, we always sign H(Context, Hash(handshake))
+     * where:
+     *
+     * H is the negotiated signature hash and
+     * Hash is the cipher-suite specific handshake hash
+     * Generally this means that Hash is SHA-256.
+     *
+     * We need code to negotiate H.
+     */
+
+    if (ss->ssl3.hs.hashType == handshake_hash_record &&
+        ss->ssl3.hs.tls12CertVerifyHash != ssl3_GetSuitePrfHash(ss)) {
+#ifndef NO_PKCS11_BYPASS
+        if (ss->opt.bypassPKCS11) {
+            rv = ssl3_ComputeBypassHandshakeHash(ss->ssl3.hs.messages.buf,
+                                                 ss->ssl3.hs.messages.len,
+                                                 ss->ssl3.hs.tls12CertVerifyHash,
+                                                 &hashes);
+        } else
+#endif
+        {
+            rv = ssl3_ComputePkcs11HandshakeHash(ss->ssl3.hs.messages.buf,
+                                                 ss->ssl3.hs.messages.len,
+                                                 ss->ssl3.hs.tls12CertVerifyHash,
+                                                 &hashes);
+        }
+        if (rv != SECSuccess) {
+            ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
+            goto done;
         }
     } else {
         ssl3CipherSpec *spec;
 
         if (isTLS13) {
             /* In TLS 1.3, we are already encrypted. */
             spec = ss->ssl3.cwSpec;
         } else {
@@ -6796,16 +6969,27 @@ ssl3_SendCertificateVerify(sslSocket *ss
         if (rv != SECSuccess) {
             goto done; /* err code was set by tls13_AddContextToHashes */
         }
     }
 
     isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0);
     isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
 
+    /* Check requested by EKR, he'll fix after merging. */
+    if (ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
+        if (ss->sec.isServer != 0) {
+            ss->ssl3.hs.tls12CertVerifyHash = ssl3_GetSuitePrfHash(ss);
+        }
+        if (hashes.hashAlg != ss->ssl3.hs.tls12CertVerifyHash) {
+            PORT_Assert(0);
+            return SECFailure;
+        }
+    }
+
     keyType = privKey->keyType;
     rv = ssl3_SignHashes(&hashes, privKey, &buf, isTLS);
     if (rv == SECSuccess && !ss->sec.isServer) {
         /* Remember the info about the slot that did the signing.
         ** Later, when doing an SSL restart handshake, verify this.
         ** These calls are mere accessors, and can't fail.
         */
         PK11SlotInfo *slot;
@@ -6998,17 +7182,17 @@ ssl3_HandleServerHello(sslSocket *ss, SS
     if (temp < 0) {
         goto loser; /* alert has been sent */
     }
     ssl3_config_match_init(ss);
     for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) {
         ssl3CipherSuiteCfg *suite = &ss->cipherSuites[i];
         if (temp == suite->cipher_suite) {
             SSLVersionRange vrange = { ss->version, ss->version };
-            if (!config_match(suite, ss->ssl3.policy, PR_TRUE, &vrange, ss)) {
+            if (!config_match(suite, ss->ssl3.policy, &vrange, ss)) {
                 /* config_match already checks whether the cipher suite is
                  * acceptable for the version, but the check is repeated here
                  * in order to give a more precise error code. */
                 if (!ssl3_CipherSuiteAllowedForVersionRange(temp, &vrange)) {
                     desc = handshake_failure;
                     errCode = SSL_ERROR_CIPHER_DISALLOWED_FOR_VERSION;
                     goto alert_loser;
                 }
@@ -7345,285 +7529,335 @@ ssl3_HandleServerHelloPart2(sslSocket *s
 alert_loser:
     (void)SSL3_SendAlert(ss, alert_fatal, desc);
 
 loser:
     *retErrCode = errCode;
     return SECFailure;
 }
 
+static SECStatus
+ssl_HandleRSAServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
+{
+    SECStatus rv;
+    int errCode = SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH;
+    SSL3AlertDescription desc = illegal_parameter;
+    SSLHashType hashAlg = ssl_hash_none;
+    PRBool isTLS = ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0;
+
+    SECItem modulus = { siBuffer, NULL, 0 };
+    SECItem exponent = { siBuffer, NULL, 0 };
+
+    SSL3Hashes hashes;
+    SECItem signature = { siBuffer, NULL, 0 };
+    PLArenaPool *arena = NULL;
+    SECKEYPublicKey *peerKey = NULL;
+
+    rv = ssl3_ConsumeHandshakeVariable(ss, &modulus, 2, &b, &length);
+    if (rv != SECSuccess) {
+        goto loser; /* malformed. */
+    }
+    /* This exchange method is only used by export cipher suites.
+     * Those are broken and so this code will eventually be removed. */
+    if (SECKEY_BigIntegerBitLength(&modulus) < 512) {
+        desc = isTLS ? insufficient_security : illegal_parameter;
+        goto alert_loser;
+    }
+    rv = ssl3_ConsumeHandshakeVariable(ss, &exponent, 2, &b, &length);
+    if (rv != SECSuccess) {
+        goto loser; /* malformed. */
+    }
+    if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
+        SSLSignatureAndHashAlg sigAndHash;
+
+        rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length,
+                                                   &sigAndHash);
+        if (rv != SECSuccess) {
+            goto loser; /* malformed or unsupported. */
+        }
+        rv = ssl3_CheckSignatureAndHashAlgorithmConsistency(
+            ss, &sigAndHash, ss->sec.peerCert);
+        if (rv != SECSuccess) {
+            goto loser;
+        }
+        hashAlg = sigAndHash.hashAlg;
+    }
+    rv = ssl3_ConsumeHandshakeVariable(ss, &signature, 2, &b, &length);
+    if (rv != SECSuccess) {
+        goto loser; /* malformed. */
+    }
+    if (length != 0) {
+        if (isTLS)
+            desc = decode_error;
+        goto alert_loser; /* malformed. */
+    }
+
+    /* failures after this point are not malformed handshakes. */
+    /* TLS: send decrypt_error if signature failed. */
+    desc = isTLS ? decrypt_error : handshake_failure;
+
+    /*
+     *  check to make sure the hash is signed by right guy
+     */
+    rv = ssl3_ComputeExportRSAKeyHash(hashAlg, modulus, exponent,
+                                      &ss->ssl3.hs.client_random,
+                                      &ss->ssl3.hs.server_random,
+                                      &hashes, ss->opt.bypassPKCS11);
+    if (rv != SECSuccess) {
+        errCode =
+            ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
+        goto alert_loser;
+    }
+    rv = ssl3_VerifySignedHashes(&hashes, ss->sec.peerCert, &signature,
+                                 isTLS, ss->pkcs11PinArg);
+    if (rv != SECSuccess) {
+        errCode =
+            ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
+        goto alert_loser;
+    }
+
+    /*
+     * we really need to build a new key here because we can no longer
+     * ignore calling SECKEY_DestroyPublicKey. Using the key may allocate
+     * pkcs11 slots and ID's.
+     */
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if (arena == NULL) {
+        errCode = SEC_ERROR_NO_MEMORY;
+        goto loser;
+    }
+
+    peerKey = PORT_ArenaZNew(arena, SECKEYPublicKey);
+    if (peerKey == NULL) {
+        errCode = SEC_ERROR_NO_MEMORY;
+        goto loser;
+    }
+
+    peerKey->arena = arena;
+    peerKey->keyType = rsaKey;
+    peerKey->pkcs11Slot = NULL;
+    peerKey->pkcs11ID = CK_INVALID_HANDLE;
+    if (SECITEM_CopyItem(arena, &peerKey->u.rsa.modulus, &modulus) ||
+        SECITEM_CopyItem(arena, &peerKey->u.rsa.publicExponent, &exponent)) {
+        errCode = SEC_ERROR_NO_MEMORY;
+        goto loser;
+    }
+    ss->sec.peerKey = peerKey;
+    return SECSuccess;
+
+alert_loser:
+    (void)SSL3_SendAlert(ss, alert_fatal, desc);
+loser:
+    if (arena) {
+        PORT_FreeArena(arena, PR_FALSE);
+    }
+    PORT_SetError(ssl_MapLowLevelError(errCode));
+    return SECFailure;
+}
+
+static SECStatus
+ssl_HandleDHServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
+{
+    SECStatus rv;
+    int errCode = SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH;
+    SSL3AlertDescription desc = illegal_parameter;
+    SSLHashType hashAlg = ssl_hash_none;
+    PRBool isTLS = ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0;
+
+    SECItem dh_p = { siBuffer, NULL, 0 };
+    SECItem dh_g = { siBuffer, NULL, 0 };
+    SECItem dh_Ys = { siBuffer, NULL, 0 };
+    unsigned dh_p_bits;
+    unsigned dh_g_bits;
+    PRInt32 minDH;
+
+    SSL3Hashes hashes;
+    SECItem signature = { siBuffer, NULL, 0 };
+    PLArenaPool *arena = NULL;
+    SECKEYPublicKey *peerKey = NULL;
+
+    rv = ssl3_ConsumeHandshakeVariable(ss, &dh_p, 2, &b, &length);
+    if (rv != SECSuccess) {
+        goto loser; /* malformed. */
+    }
+
+    rv = NSS_OptionGet(NSS_DH_MIN_KEY_SIZE, &minDH);
+    if (rv != SECSuccess) {
+        minDH = SSL_DH_MIN_P_BITS;
+    }
+    dh_p_bits = SECKEY_BigIntegerBitLength(&dh_p);
+    if (dh_p_bits < minDH) {
+        errCode = SSL_ERROR_WEAK_SERVER_EPHEMERAL_DH_KEY;
+        goto alert_loser;
+    }
+    rv = ssl3_ConsumeHandshakeVariable(ss, &dh_g, 2, &b, &length);
+    if (rv != SECSuccess) {
+        goto loser; /* malformed. */
+    }
+    /* Abort if dh_g is 0, 1, or obviously too big. */
+    dh_g_bits = SECKEY_BigIntegerBitLength(&dh_g);
+    if (dh_g_bits > dh_p_bits || dh_g_bits <= 1) {
+        goto alert_loser;
+    }
+    if (ss->opt.requireDHENamedGroups) {
+        /* If we're doing named groups, make sure it's good. */
+        rv = ssl_ValidateDHENamedGroup(ss, &dh_p, &dh_g, NULL, NULL);
+        if (rv != SECSuccess) {
+            errCode = SSL_ERROR_WEAK_SERVER_EPHEMERAL_DH_KEY;
+            goto alert_loser;
+        }
+    }
+
+    rv = ssl3_ConsumeHandshakeVariable(ss, &dh_Ys, 2, &b, &length);
+    if (rv != SECSuccess) {
+        goto loser; /* malformed. */
+    }
+    if (!ssl_IsValidDHEShare(&dh_p, &dh_Ys)) {
+        errCode = SSL_ERROR_RX_MALFORMED_DHE_KEY_SHARE;
+        goto alert_loser;
+    }
+
+    if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
+        SSLSignatureAndHashAlg sigAndHash;
+
+        rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length,
+                                                   &sigAndHash);
+        if (rv != SECSuccess) {
+            goto loser; /* malformed or unsupported. */
+        }
+        rv = ssl3_CheckSignatureAndHashAlgorithmConsistency(
+            ss, &sigAndHash, ss->sec.peerCert);
+        if (rv != SECSuccess) {
+            goto loser;
+        }
+        hashAlg = sigAndHash.hashAlg;
+    }
+    rv = ssl3_ConsumeHandshakeVariable(ss, &signature, 2, &b, &length);
+    if (rv != SECSuccess) {
+        goto loser; /* malformed. */
+    }
+    if (length != 0) {
+        if (isTLS) {
+            desc = decode_error;
+        }
+        goto alert_loser; /* malformed. */
+    }
+
+    PRINT_BUF(60, (NULL, "Server DH p", dh_p.data, dh_p.len));
+    PRINT_BUF(60, (NULL, "Server DH g", dh_g.data, dh_g.len));
+    PRINT_BUF(60, (NULL, "Server DH Ys", dh_Ys.data, dh_Ys.len));
+
+    /* failures after this point are not malformed handshakes. */
+    /* TLS: send decrypt_error if signature failed. */
+    desc = isTLS ? decrypt_error : handshake_failure;
+
+    /*
+     * Check to make sure the hash is signed by right guy.
+     */
+    rv = ssl3_ComputeDHKeyHash(ss, hashAlg, &hashes,
+                               dh_p, dh_g, dh_Ys, PR_FALSE /* padY */);
+    if (rv != SECSuccess) {
+        errCode =
+            ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
+        goto alert_loser;
+    }
+    rv = ssl3_VerifySignedHashes(&hashes, ss->sec.peerCert, &signature,
+                                 isTLS, ss->pkcs11PinArg);
+    if (rv != SECSuccess) {
+        errCode =
+            ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
+        goto alert_loser;
+    }
+
+    /*
+     * we really need to build a new key here because we can no longer
+     * ignore calling SECKEY_DestroyPublicKey. Using the key may allocate
+     * pkcs11 slots and ID's.
+     */
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if (arena == NULL) {
+        errCode = SEC_ERROR_NO_MEMORY;
+        goto loser;
+    }
+
+    peerKey = PORT_ArenaZNew(arena, SECKEYPublicKey);
+    if (peerKey == NULL) {
+        errCode = SEC_ERROR_NO_MEMORY;
+        goto loser;
+    }
+
+    peerKey->arena = arena;
+    peerKey->keyType = dhKey;
+    peerKey->pkcs11Slot = NULL;
+    peerKey->pkcs11ID = CK_INVALID_HANDLE;
+
+    if (SECITEM_CopyItem(arena, &peerKey->u.dh.prime, &dh_p) ||
+        SECITEM_CopyItem(arena, &peerKey->u.dh.base, &dh_g) ||
+        SECITEM_CopyItem(arena, &peerKey->u.dh.publicValue, &dh_Ys)) {
+        errCode = SEC_ERROR_NO_MEMORY;
+        goto loser;
+    }
+    ss->sec.peerKey = peerKey;
+    return SECSuccess;
+
+alert_loser:
+    (void)SSL3_SendAlert(ss, alert_fatal, desc);
+loser:
+    if (arena) {
+        PORT_FreeArena(arena, PR_FALSE);
+    }
+    PORT_SetError(ssl_MapLowLevelError(errCode));
+    return SECFailure;
+}
+
 /* Called from ssl3_HandlePostHelloHandshakeMessage() when it has deciphered a
  * complete ssl3 ServerKeyExchange message.
  * Caller must hold Handshake and RecvBuf locks.
  */
 static SECStatus
 ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
 {
-    PLArenaPool *arena = NULL;
-    SECKEYPublicKey *peerKey = NULL;
-    PRBool isTLS, isTLS12;
     SECStatus rv;
-    int errCode = SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH;
-    SSL3AlertDescription desc = illegal_parameter;
-    SSL3Hashes hashes;
-    SECItem signature = { siBuffer, NULL, 0 };
-    SSLSignatureAndHashAlg sigAndHash;
-
-    sigAndHash.hashAlg = ssl_hash_none;
 
     SSL_TRC(3, ("%d: SSL3[%d]: handle server_key_exchange handshake",
                 SSL_GETPID(), ss->fd));
     PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
     if (ss->ssl3.hs.ws != wait_server_key) {
-        errCode = SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH;
-        desc = unexpected_message;
-        goto alert_loser;
-    }
-
-    isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0);
-    isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
+        SSL3_SendAlert(ss, alert_fatal, unexpected_message);
+        PORT_SetError(SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH);
+        return SECFailure;
+    }
 
     switch (ss->ssl3.hs.kea_def->exchKeyType) {
-        case ssl_kea_rsa: {
-            SECItem modulus = { siBuffer, NULL, 0 };
-            SECItem exponent = { siBuffer, NULL, 0 };
-
-            rv = ssl3_ConsumeHandshakeVariable(ss, &modulus, 2, &b, &length);
-            if (rv != SECSuccess) {
-                goto loser; /* malformed. */
-            }
-            /* This exchange method is only used by export cipher suites.
-             * Those are broken and so this code will eventually be removed. */
-            if (SECKEY_BigIntegerBitLength(&modulus) < 512) {
-                desc = isTLS ? insufficient_security : illegal_parameter;
-                goto alert_loser;
-            }
-            rv = ssl3_ConsumeHandshakeVariable(ss, &exponent, 2, &b, &length);
-            if (rv != SECSuccess) {
-                goto loser; /* malformed. */
-            }
-            if (isTLS12) {
-                rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length,
-                                                           &sigAndHash);
-                if (rv != SECSuccess) {
-                    goto loser; /* malformed or unsupported. */
-                }
-                rv = ssl3_CheckSignatureAndHashAlgorithmConsistency(ss,
-                                                                    &sigAndHash, ss->sec.peerCert);
-                if (rv != SECSuccess) {
-                    goto loser;
-                }
-            }
-            rv = ssl3_ConsumeHandshakeVariable(ss, &signature, 2, &b, &length);
-            if (rv != SECSuccess) {
-                goto loser; /* malformed. */
-            }
-            if (length != 0) {
-                if (isTLS)
-                    desc = decode_error;
-                goto alert_loser; /* malformed. */
-            }
-
-            /* failures after this point are not malformed handshakes. */
-            /* TLS: send decrypt_error if signature failed. */
-            desc = isTLS ? decrypt_error : handshake_failure;
-
-            /*
-             *  check to make sure the hash is signed by right guy
-             */
-            rv = ssl3_ComputeExportRSAKeyHash(sigAndHash.hashAlg, modulus, exponent,
-                                              &ss->ssl3.hs.client_random,
-                                              &ss->ssl3.hs.server_random,
-                                              &hashes, ss->opt.bypassPKCS11);
-            if (rv != SECSuccess) {
-                errCode =
-                    ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
-                goto alert_loser;
-            }
-            rv = ssl3_VerifySignedHashes(&hashes, ss->sec.peerCert, &signature,
-                                         isTLS, ss->pkcs11PinArg);
-            if (rv != SECSuccess) {
-                errCode =
-                    ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
-                goto alert_loser;
-            }
-
-            /*
-             * we really need to build a new key here because we can no longer
-             * ignore calling SECKEY_DestroyPublicKey. Using the key may allocate
-             * pkcs11 slots and ID's.
-             */
-            arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
-            if (arena == NULL) {
-                goto no_memory;
-            }
-
-            peerKey = PORT_ArenaZNew(arena, SECKEYPublicKey);
-            if (peerKey == NULL) {
-                goto no_memory;
-            }
-
-            peerKey->arena = arena;
-            peerKey->keyType = rsaKey;
-            peerKey->pkcs11Slot = NULL;
-            peerKey->pkcs11ID = CK_INVALID_HANDLE;
-            if (SECITEM_CopyItem(arena, &peerKey->u.rsa.modulus, &modulus) ||
-                SECITEM_CopyItem(arena, &peerKey->u.rsa.publicExponent, &exponent)) {
-                goto no_memory;
-            }
-            ss->sec.peerKey = peerKey;
-            ss->ssl3.hs.ws = wait_cert_request;
-            return SECSuccess;
-        }
-
-        case ssl_kea_dh: {
-            SECItem dh_p = { siBuffer, NULL, 0 };
-            SECItem dh_g = { siBuffer, NULL, 0 };
-            SECItem dh_Ys = { siBuffer, NULL, 0 };
-            unsigned dh_p_bits;
-            unsigned dh_g_bits;
-            unsigned dh_Ys_bits;
-            PRInt32 minDH;
-
-            rv = ssl3_ConsumeHandshakeVariable(ss, &dh_p, 2, &b, &length);
-            if (rv != SECSuccess) {
-                goto loser; /* malformed. */
-            }
-
-            rv = NSS_OptionGet(NSS_DH_MIN_KEY_SIZE, &minDH);
-            if (rv != SECSuccess) {
-                minDH = SSL_DH_MIN_P_BITS;
-            }
-            dh_p_bits = SECKEY_BigIntegerBitLength(&dh_p);
-            if (dh_p_bits < minDH) {
-                errCode = SSL_ERROR_WEAK_SERVER_EPHEMERAL_DH_KEY;
-                goto alert_loser;
-            }
-            rv = ssl3_ConsumeHandshakeVariable(ss, &dh_g, 2, &b, &length);
-            if (rv != SECSuccess) {
-                goto loser; /* malformed. */
-            }
-            /* Abort if dh_g is 0, 1, or obviously too big. */
-            dh_g_bits = SECKEY_BigIntegerBitLength(&dh_g);
-            if (dh_g_bits > dh_p_bits || dh_g_bits <= 1)
-                goto alert_loser;
-            rv = ssl3_ConsumeHandshakeVariable(ss, &dh_Ys, 2, &b, &length);
-            if (rv != SECSuccess) {
-                goto loser; /* malformed. */
-            }
-            dh_Ys_bits = SECKEY_BigIntegerBitLength(&dh_Ys);
-            if (dh_Ys_bits > dh_p_bits || dh_Ys_bits <= 1)
-                goto alert_loser;
-            if (isTLS12) {
-                rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length,
-                                                           &sigAndHash);
-                if (rv != SECSuccess) {
-                    goto loser; /* malformed or unsupported. */
-                }
-                rv = ssl3_CheckSignatureAndHashAlgorithmConsistency(ss,
-                                                                    &sigAndHash, ss->sec.peerCert);
-                if (rv != SECSuccess) {
-                    goto loser;
-                }
-            }
-            rv = ssl3_ConsumeHandshakeVariable(ss, &signature, 2, &b, &length);
-            if (rv != SECSuccess) {
-                goto loser; /* malformed. */
-            }
-            if (length != 0) {
-                if (isTLS)
-                    desc = decode_error;
-                goto alert_loser; /* malformed. */
-            }
-
-            PRINT_BUF(60, (NULL, "Server DH p", dh_p.data, dh_p.len));
-            PRINT_BUF(60, (NULL, "Server DH g", dh_g.data, dh_g.len));
-            PRINT_BUF(60, (NULL, "Server DH Ys", dh_Ys.data, dh_Ys.len));
-
-            /* failures after this point are not malformed handshakes. */
-            /* TLS: send decrypt_error if signature failed. */
-            desc = isTLS ? decrypt_error : handshake_failure;
-
-            /*
-             *  check to make sure the hash is signed by right guy
-             */
-            rv = ssl3_ComputeDHKeyHash(sigAndHash.hashAlg, dh_p, dh_g, dh_Ys,
-                                       &ss->ssl3.hs.client_random,
-                                       &ss->ssl3.hs.server_random,
-                                       &hashes, ss->opt.bypassPKCS11);
-            if (rv != SECSuccess) {
-                errCode =
-                    ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
-                goto alert_loser;
-            }
-            rv = ssl3_VerifySignedHashes(&hashes, ss->sec.peerCert, &signature,
-                                         isTLS, ss->pkcs11PinArg);
-            if (rv != SECSuccess) {
-                errCode =
-                    ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
-                goto alert_loser;
-            }
-
-            /*
-             * we really need to build a new key here because we can no longer
-             * ignore calling SECKEY_DestroyPublicKey. Using the key may allocate
-             * pkcs11 slots and ID's.
-             */
-            arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
-            if (arena == NULL) {
-                goto no_memory;
-            }
-
-            peerKey = PORT_ArenaZNew(arena, SECKEYPublicKey);
-            if (peerKey == NULL) {
-                goto no_memory;
-            }
-
-            peerKey->arena = arena;
-            peerKey->keyType = dhKey;
-            peerKey->pkcs11Slot = NULL;
-            peerKey->pkcs11ID = CK_INVALID_HANDLE;
-
-            if (SECITEM_CopyItem(arena, &peerKey->u.dh.prime, &dh_p) ||
-                SECITEM_CopyItem(arena, &peerKey->u.dh.base, &dh_g) ||
-                SECITEM_CopyItem(arena, &peerKey->u.dh.publicValue, &dh_Ys)) {
-                goto no_memory;
-            }
-            ss->sec.peerKey = peerKey;
-            ss->ssl3.hs.ws = wait_cert_request;
-            return SECSuccess;
-        }
+        case ssl_kea_rsa:
+            rv = ssl_HandleRSAServerKeyExchange(ss, b, length);
+            break;
+
+        case ssl_kea_dh:
+            rv = ssl_HandleDHServerKeyExchange(ss, b, length);
+            break;
 
         case ssl_kea_ecdh:
             rv = ssl3_HandleECDHServerKeyExchange(ss, b, length);
-            return rv;
+            break;
 
         default:
-            desc = handshake_failure;
-            errCode = SEC_ERROR_UNSUPPORTED_KEYALG;
-            break; /* goto alert_loser; */
-    }
-
-alert_loser:
-    (void)SSL3_SendAlert(ss, alert_fatal, desc);
-loser:
-    if (arena) {
-        PORT_FreeArena(arena, PR_FALSE);
-    }
-    PORT_SetError(errCode);
-    return SECFailure;
-
-no_memory: /* no-memory error has already been set. */
-    if (arena) {
-        PORT_FreeArena(arena, PR_FALSE);
-    }
-    ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
-    return SECFailure;
+            SSL3_SendAlert(ss, alert_fatal, handshake_failure);
+            PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
+            rv = SECFailure;
+            break;
+    }
+
+    if (rv == SECSuccess) {
+        ss->ssl3.hs.ws = wait_cert_request;
+    }
+    /* All Handle*ServerKeyExchange functions set the error code. */
+    return rv;
 }
 
 /*
  * Returns the TLS signature algorithm for the client authentication key and
  * whether it is an RSA or DSA key that may be able to sign only SHA-1 hashes.
  */
 static SECStatus
 ssl3_ExtractClientKeyInfo(sslSocket *ss,
@@ -7657,70 +7891,18 @@ ssl3_ExtractClientKeyInfo(sslSocket *ss,
     }
 
 done:
     if (pubk)
         SECKEY_DestroyPublicKey(pubk);
     return rv;
 }
 
-/* Destroys the backup handshake hash context if we don't need it. Note that
- * this function selects the hash algorithm for client authentication
- * signatures; ssl3_SendCertificateVerify uses the presence of the backup hash
- * to determine whether to use SHA-1, or the PRF hash of the cipher suite. */
 static void
-ssl3_DestroyBackupHandshakeHashIfNotNeeded(sslSocket *ss,
-                                           const SECItem *algorithms)
-{
-    SECStatus rv;
-    SSLSignType sigAlg;
-    PRBool preferSha1 = PR_FALSE;
-    PRBool supportsSha1 = PR_FALSE;
-    PRBool supportsHandshakeHash = PR_FALSE;
-    PRBool needBackupHash = PR_FALSE;
-    unsigned int i;
-
-#ifndef NO_PKCS11_BYPASS
-    /* Backup handshake hash is not supported in PKCS #11 bypass mode. */
-    if (ss->opt.bypassPKCS11) {
-        PORT_Assert(!ss->ssl3.hs.backupHash);
-        return;
-    }
-#endif
-    PORT_Assert(ss->ssl3.hs.backupHash);
-
-    /* Determine the key's signature algorithm and whether it prefers SHA-1. */
-    rv = ssl3_ExtractClientKeyInfo(ss, &sigAlg, &preferSha1);
-    if (rv != SECSuccess) {
-        goto done;
-    }
-
-    /* Determine the server's hash support for that signature algorithm. */
-    for (i = 0; i < algorithms->len; i += 2) {
-        if (algorithms->data[i + 1] == sigAlg) {
-            if (algorithms->data[i] == ssl_hash_sha1) {
-                supportsSha1 = PR_TRUE;
-            } else if (algorithms->data[i] == ss->ssl3.hs.suite_def->prf_hash) {
-                supportsHandshakeHash = PR_TRUE;
-            }
-        }
-    }
-
-    /* If either the server does not support the handshake hash or the client key prefers
-     * SHA-1, leave the backup hash. */
-    if (supportsSha1 && (preferSha1 || !supportsHandshakeHash)) {
-        needBackupHash = PR_TRUE;
-    }
-
-done:
-    if (!needBackupHash) {
-        PK11_DestroyContext(ss->ssl3.hs.backupHash, PR_TRUE);
-        ss->ssl3.hs.backupHash = NULL;
-    }
-}
+ssl3_DecideTls12CertVerifyHash(sslSocket *ss, const SECItem *algorithms);
 
 typedef struct dnameNode {
     struct dnameNode *next;
     SECItem name;
 } dnameNode;
 
 /*
  * Parse the ca_list structure in a CertificateRequest.
@@ -7938,18 +8120,19 @@ ssl3_CompleteHandleCertificateRequest(ss
                 certUsageSSLClient, PR_FALSE);
             if (ss->ssl3.clientCertChain == NULL) {
                 CERT_DestroyCertificate(ss->ssl3.clientCertificate);
                 ss->ssl3.clientCertificate = NULL;
                 SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
                 ss->ssl3.clientPrivateKey = NULL;
                 goto send_no_certificate;
             }
-            if (ss->ssl3.hs.hashType == handshake_hash_single) {
-                ssl3_DestroyBackupHandshakeHashIfNotNeeded(ss, algorithms);
+            if (ss->ssl3.hs.hashType == handshake_hash_record ||
+                ss->ssl3.hs.hashType == handshake_hash_single) {
+                ssl3_DecideTls12CertVerifyHash(ss, algorithms);
             }
             break; /* not an error */
 
         case SECFailure:
         default:
         send_no_certificate:
             if (ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0) {
                 ss->ssl3.sendEmptyCert = PR_TRUE;
@@ -8075,24 +8258,16 @@ ssl3_SendClientSecondRound(sslSocket *ss
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
     sendClientCert = !ss->ssl3.sendEmptyCert &&
                      ss->ssl3.clientCertChain != NULL &&
                      ss->ssl3.clientPrivateKey != NULL;
 
-    if (!sendClientCert &&
-        ss->ssl3.hs.hashType == handshake_hash_single &&
-        ss->ssl3.hs.backupHash) {
-        /* Don't need the backup handshake hash. */
-        PK11_DestroyContext(ss->ssl3.hs.backupHash, PR_TRUE);
-        ss->ssl3.hs.backupHash = NULL;
-    }
-
     /* We must wait for the server's certificate to be authenticated before
      * sending the client certificate in order to disclosing the client
      * certificate to an attacker that does not have a valid cert for the
      * domain we are connecting to.
      *
      * XXX: We should do the same for the NPN extension, but for that we
      * need an option to give the application the ability to leak the NPN
      * information to get better performance.
@@ -8456,17 +8631,17 @@ SECStatus
 ssl3_NegotiateCipherSuite(sslSocket *ss, const SECItem *suites)
 {
     int j;
     int i;
 
     for (j = 0; j < ssl_V3_SUITES_IMPLEMENTED; j++) {
         ssl3CipherSuiteCfg *suite = &ss->cipherSuites[j];
         SSLVersionRange vrange = { ss->version, ss->version };
-        if (!config_match(suite, ss->ssl3.policy, PR_TRUE, &vrange, ss)) {
+        if (!config_match(suite, ss->ssl3.policy, &vrange, ss)) {
             continue;
         }
         for (i = 0; i + 1 < suites->len; i += 2) {
             PRUint16 suite_i = (suites->data[i] << 8) | suites->data[i + 1];
             if (suite_i == suite->cipher_suite) {
                 return ssl3_SetCipherSuite(ss, suite_i);
             }
         }
@@ -8650,18 +8825,17 @@ ssl3_SelectServerCert(sslSocket *ss)
          cursor = PR_NEXT_LINK(cursor)) {
         sslServerCert *cert = (sslServerCert *)cursor;
         if (cert->certType.authType != kea_def->authKeyType) {
             continue;
         }
         if ((cert->certType.authType == ssl_auth_ecdsa ||
              cert->certType.authType == ssl_auth_ecdh_rsa ||
              cert->certType.authType == ssl_auth_ecdh_ecdsa) &&
-            !SSL_IS_CURVE_NEGOTIATED(ss->ssl3.hs.negotiatedECCurves,
-                                     cert->certType.u.namedCurve)) {
+            !ssl_NamedGroupEnabled(ss, cert->certType.namedCurve)) {
             continue;
         }
 
         /* Found one. */
         ss->sec.serverCert = cert;
         ss->sec.authType = cert->certType.authType;
         ss->sec.authKeyBits = cert->serverKeyBits;
         return SECSuccess;
@@ -9012,19 +9186,16 @@ ssl3_HandleClientHello(sslSocket *ss, SS
             SSL_AtomicIncrementLong(&ssl3stats.hch_sid_cache_not_ok);
             if (ss->sec.uncache)
                 ss->sec.uncache(sid);
             ssl_FreeSID(sid);
             sid = NULL;
         }
     }
 
-    /* Disable any ECC cipher suites for which we have no cert. */
-    ssl3_FilterECCipherSuitesByServerCerts(ss);
-
     if (IS_DTLS(ss)) {
         ssl3_DisableNonDTLSSuites(ss);
     }
 
 #ifdef PARANOID
     /* Look for a matching cipher suite. */
     j = ssl3_config_match_init(ss);
     if (j <= 0) {                  /* no ciphers are working/supported by PK11 */
@@ -9035,16 +9206,17 @@ ssl3_HandleClientHello(sslSocket *ss, SS
 
     if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
         rv = tls13_HandleClientHelloPart2(ss, &suites, sid);
     } else {
         rv = ssl3_HandleClientHelloPart2(ss, &suites, &comps, sid,
                                          canOfferSessionTicket);
     }
     if (rv != SECSuccess) {
+        errCode = PORT_GetError();
         goto loser;
     }
     return SECSuccess;
 
 alert_loser:
     (void)SSL3_SendAlert(ss, level, desc);
 /* FALLTHRU */
 loser:
@@ -9100,17 +9272,17 @@ ssl3_HandleClientHelloPart2(sslSocket *s
             if (j <= 0)
                 break;
 #ifdef PARANOID
             /* Double check that the cached cipher suite is still enabled,
              * implemented, and allowed by policy.  Might have been disabled.
              * The product policy won't change during the process lifetime.
              * Implemented ("isPresent") shouldn't change for servers.
              */
-            if (!config_match(suite, ss->ssl3.policy, PR_TRUE, &vrange, ss))
+            if (!config_match(suite, ss->ssl3.policy, &vrange, ss))
                 break;
 #else
             if (!suite->enabled)
                 break;
 #endif
             /* Double check that the cached cipher suite is in the client's
              * list.  If it isn't, fall through and start a new session. */
             for (i = 0; i + 1 < suites->len; i += 2) {
@@ -9564,35 +9736,33 @@ ssl3_HandleV2ClientHello(sslSocket *ss, 
 
     PORT_Memset(&ss->ssl3.hs.client_random, 0, SSL3_RANDOM_LENGTH);
     PORT_Memcpy(
         &ss->ssl3.hs.client_random.rand[SSL3_RANDOM_LENGTH - rand_length],
         random, rand_length);
 
     PRINT_BUF(60, (ss, "client random:", &ss->ssl3.hs.client_random.rand[0],
                    SSL3_RANDOM_LENGTH));
-    /* Disable any ECC cipher suites for which we have no cert. */
-    ssl3_FilterECCipherSuitesByServerCerts(ss);
     i = ssl3_config_match_init(ss);
     if (i <= 0) {
         errCode = PORT_GetError(); /* error code is already set. */
         goto alert_loser;
     }
 
     /* Select a cipher suite.
     **
     ** NOTE: This suite selection algorithm should be the same as the one in
     ** ssl3_HandleClientHello().
     **
     ** See the comments about export cipher suites in ssl3_HandleClientHello().
     */
     for (j = 0; j < ssl_V3_SUITES_IMPLEMENTED; j++) {
         ssl3CipherSuiteCfg *suite = &ss->cipherSuites[j];
         SSLVersionRange vrange = { ss->version, ss->version };
-        if (!config_match(suite, ss->ssl3.policy, PR_TRUE, &vrange, ss)) {
+        if (!config_match(suite, ss->ssl3.policy, &vrange, ss)) {
             continue;
         }
         for (i = 0; i + 2 < suite_length; i += 3) {
             PRUint32 suite_i = (suites[i] << 16) | (suites[i + 1] << 8) | suites[i + 2];
             if (suite_i == suite->cipher_suite) {
                 rv = ssl3_SetCipherSuite(ss, suite_i);
                 if (rv != SECSuccess) {
                     desc = internal_error;
@@ -9810,79 +9980,106 @@ ssl3_SendServerHello(sslSocket *ss)
 
     return SECSuccess;
 }
 
 static SECStatus
 ssl3_PickSignatureHashAlgorithm(sslSocket *ss,
                                 SSLSignatureAndHashAlg *out);
 
+SECStatus
+ssl_CreateDHEKeyPair(const namedGroupDef *groupDef,
+                     const ssl3DHParams *params,
+                     sslEphemeralKeyPair **keyPair)
+{
+    SECKEYDHParams dhParam;
+    SECKEYPublicKey *pubKey = NULL;   /* Ephemeral DH key */
+    SECKEYPrivateKey *privKey = NULL; /* Ephemeral DH key */
+    sslEphemeralKeyPair *pair;
+
+    dhParam.prime.data = params->prime.data;
+    dhParam.prime.len = params->prime.len;
+    dhParam.base.data = params->base.data;
+    dhParam.base.len = params->base.len;
+
+    PRINT_BUF(60, (NULL, "Server DH p", dhParam.prime.data,
+                   dhParam.prime.len));
+    PRINT_BUF(60, (NULL, "Server DH g", dhParam.base.data,
+                   dhParam.base.len));
+
+    /* Generate ephemeral DH keypair */
+    privKey = SECKEY_CreateDHPrivateKey(&dhParam, &pubKey, NULL);
+    if (!privKey || !pubKey) {
+        ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL);
+        return SECFailure;
+    }
+
+    pair = ssl_NewEphemeralKeyPair(groupDef, privKey, pubKey);
+    if (!pair) {
+        SECKEY_DestroyPrivateKey(privKey);
+        SECKEY_DestroyPublicKey(pubKey);
+
+        return SECFailure;
+    }
+
+    *keyPair = pair;
+    return SECSuccess;
+}
+
 static SECStatus
 ssl3_SendDHServerKeyExchange(sslSocket *ss)
 {
     const ssl3KEADef *kea_def = ss->ssl3.hs.kea_def;
     SECStatus rv = SECFailure;
     int length;
     PRBool isTLS;
     SECItem signed_hash = { siBuffer, NULL, 0 };
     SSL3Hashes hashes;
     SSLSignatureAndHashAlg sigAndHash;
-    SECKEYDHParams dhParam;
-
-    ssl3KeyPair *keyPair = NULL;
-    SECKEYPublicKey *pubKey = NULL;   /* Ephemeral DH key */
-    SECKEYPrivateKey *privKey = NULL; /* Ephemeral DH key */
+
+    const ssl3DHParams *params;
+    sslEphemeralKeyPair *keyPair;
+    SECKEYPublicKey *pubKey;
     SECKEYPrivateKey *certPrivateKey;
+    const namedGroupDef *groupDef;
 
     if (kea_def->kea != kea_dhe_dss && kea_def->kea != kea_dhe_rsa) {
         /* TODO: Support DH_anon. It might be sufficient to drop the signature.
                  See bug 1170510. */
         PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
         return SECFailure;
     }
 
-    dhParam.prime.data = ss->dheParams->prime.data;
-    dhParam.prime.len = ss->dheParams->prime.len;
-    dhParam.base.data = ss->dheParams->base.data;
-    dhParam.base.len = ss->dheParams->base.len;
-
-    PRINT_BUF(60, (NULL, "Server DH p", dhParam.prime.data,
-                   dhParam.prime.len));
-    PRINT_BUF(60, (NULL, "Server DH g", dhParam.base.data,
-                   dhParam.base.len));
-
-    /* Generate ephemeral DH keypair */
-    privKey = SECKEY_CreateDHPrivateKey(&dhParam, &pubKey, NULL);
-    if (!privKey || !pubKey) {
+    rv = ssl_SelectDHEParams(ss, &groupDef, &params);
+    if (rv == SECFailure) {
+        PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
+        return SECFailure;
+    }
+
+    rv = ssl_CreateDHEKeyPair(groupDef, params, &keyPair);
+    if (rv == SECFailure) {
         ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL);
-        goto loser;
-    }
-
-    keyPair = ssl3_NewKeyPair(privKey, pubKey);
-    if (!keyPair) {
-        ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL);
-        goto loser;
-    }
-
-    PRINT_BUF(50, (ss, "DH public value:",
-                   pubKey->u.dh.publicValue.data,
-                   pubKey->u.dh.publicValue.len));
+        return SECFailure;
+    }
+    PR_APPEND_LINK(&keyPair->link, &ss->ephemeralKeyPairs);
 
     if (ssl3_PickSignatureHashAlgorithm(ss, &sigAndHash) != SECSuccess) {
         ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL);
         goto loser;
     }
 
-    rv = ssl3_ComputeDHKeyHash(sigAndHash.hashAlg,
+    pubKey = keyPair->keys->pubKey;
+    PRINT_BUF(50, (ss, "DH public value:",
+                   pubKey->u.dh.publicValue.data,
+                   pubKey->u.dh.publicValue.len));
+    rv = ssl3_ComputeDHKeyHash(ss, sigAndHash.hashAlg, &hashes,
                                pubKey->u.dh.prime,
                                pubKey->u.dh.base,
                                pubKey->u.dh.publicValue,
-                               &ss->ssl3.hs.client_random,
-                               &ss->ssl3.hs.server_random,
-                               &hashes, ss->opt.bypassPKCS11);
+                               PR_TRUE /* padY */);
     if (rv != SECSuccess) {
         ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
         goto loser;
     }
 
     isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0);
     certPrivateKey = ss->sec.serverCert->serverKeyPair->privKey;
     rv = ssl3_SignHashes(&hashes, certPrivateKey, &signed_hash, isTLS);
@@ -9890,17 +10087,17 @@ ssl3_SendDHServerKeyExchange(sslSocket *
         goto loser; /* ssl3_SignHashes has set err. */
     }
     if (signed_hash.data == NULL) {
         PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
         goto loser;
     }
     length = 2 + pubKey->u.dh.prime.len +
              2 + pubKey->u.dh.base.len +
-             2 + pubKey->u.dh.publicValue.len +
+             2 + pubKey->u.dh.prime.len +
              2 + signed_hash.len;
 
     if (ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
         length += 2;
     }
 
     rv = ssl3_AppendHandshakeHeader(ss, server_key_exchange, length);
     if (rv != SECSuccess) {
@@ -9914,18 +10111,17 @@ ssl3_SendDHServerKeyExchange(sslSocket *
     }
 
     rv = ssl3_AppendHandshakeVariable(ss, pubKey->u.dh.base.data,
                                       pubKey->u.dh.base.len, 2);
     if (rv != SECSuccess) {
         goto loser; /* err set by AppendHandshake. */
     }
 
-    rv = ssl3_AppendHandshakeVariable(ss, pubKey->u.dh.publicValue.data,
-                                      pubKey->u.dh.publicValue.len, 2);
+    rv = ssl_AppendPaddedDHKeyShare(ss, pubKey);
     if (rv != SECSuccess) {
         goto loser; /* err set by AppendHandshake. */
     }
 
     if (ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
         rv = ssl3_AppendSignatureAndHashAlgorithm(ss, &sigAndHash);
         if (rv != SECSuccess) {
             goto loser; /* err set by AppendHandshake. */
@@ -9933,26 +10129,21 @@ ssl3_SendDHServerKeyExchange(sslSocket *
     }
 
     rv = ssl3_AppendHandshakeVariable(ss, signed_hash.data,
                                       signed_hash.len, 2);
     if (rv != SECSuccess) {
         goto loser; /* err set by AppendHandshake. */
     }
     PORT_Free(signed_hash.data);
-    ss->dheKeyPair = keyPair;
     return SECSuccess;
 
 loser:
     if (signed_hash.data)
         PORT_Free(signed_hash.data);
-    if (privKey)
-        SECKEY_DestroyPrivateKey(privKey);
-    if (pubKey)
-        SECKEY_DestroyPublicKey(pubKey);
     return SECFailure;
 }
 
 /* ssl3_PickSignatureHashAlgorithm selects a hash algorithm to use when signing
  * elements of the handshake. (The negotiated cipher suite determines the
  * signature algorithm.) Prior to TLS 1.2, the MD5/SHA1 combination is always
  * used. With TLS 1.2, a client may advertise its support for signature and
  * hash combinations. */
@@ -10005,16 +10196,70 @@ ssl3_PickSignatureHashAlgorithm(sslSocke
             }
         }
     }
 
     PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM);
     return SECFailure;
 }
 
+static void
+ssl3_DecideTls12CertVerifyHash(sslSocket *ss, const SECItem *algorithms)
+{
+    SECStatus rv;
+    SSLSignType sigAlg;
+    PRBool preferSha1 = PR_FALSE;
+    PRBool supportsSha1 = PR_FALSE;
+    PRBool supportsHandshakeHash = PR_FALSE;
+    unsigned int i;
+    SSLHashType otherHashAlg = ssl_hash_none;
+
+    /* Determine the key's signature algorithm and whether it prefers SHA-1. */
+    rv = ssl3_ExtractClientKeyInfo(ss, &sigAlg, &preferSha1);
+    if (rv != SECSuccess) {
+        return;
+    }
+
+    /* Determine the server's hash support for that signature algorithm. */
+    for (i = 0; i < algorithms->len; i += 2) {
+        if (algorithms->data[i + 1] == sigAlg) {
+            SSLHashType hashAlg = algorithms->data[i];
+            SECOidTag hashOID;
+            PRUint32 policy;
+            if (hashAlg == ssl_hash_sha1 &&
+                ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
+                /* TLS 1.3 explicitly forbids using SHA-1 with certificate_verify. */
+                continue;
+            }
+            hashOID = ssl3_TLSHashAlgorithmToOID(hashAlg);
+            if ((NSS_GetAlgorithmPolicy(hashOID, &policy) == SECSuccess) &&
+                !(policy & NSS_USE_ALG_IN_SSL_KX)) {
+                /* we ignore hashes we don't support */
+                continue;
+            }
+            if (hashAlg == ssl_hash_sha1) {
+                supportsSha1 = PR_TRUE;
+            } else if (hashAlg == ssl3_GetSuitePrfHash(ss)) {
+                supportsHandshakeHash = PR_TRUE;
+            }
+            if (otherHashAlg == ssl_hash_none) {
+                otherHashAlg = hashAlg;
+            }
+        }
+    }
+
+    if (supportsSha1 && preferSha1) {
+        ss->ssl3.hs.tls12CertVerifyHash = ssl_hash_sha1;
+    } else if (supportsHandshakeHash) {
+        ss->ssl3.hs.tls12CertVerifyHash = ssl3_GetSuitePrfHash(ss); /* Use suite PRF hash. */
+    } else {
+        ss->ssl3.hs.tls12CertVerifyHash = otherHashAlg;
+    }
+}
+
 static SECStatus
 ssl3_SendServerKeyExchange(sslSocket *ss)
 {
     const ssl3KEADef *kea_def = ss->ssl3.hs.kea_def;
     SECStatus rv = SECFailure;
     int length;
     PRBool isTLS;
     SECItem signed_hash = { siBuffer, NULL, 0 };
@@ -10125,35 +10370,28 @@ loser:
     return SECFailure;
 }
 
 SECStatus
 ssl3_EncodeCertificateRequestSigAlgs(sslSocket *ss, PRUint8 *buf,
                                      unsigned maxLen, PRUint32 *len)
 {
     unsigned int i;
-    /* We only track a single hash, the one that is the basis for the PRF. */
-    SSLHashType suiteHashAlg = ssl3_GetSuitePrfHash(ss);
 
     PORT_Assert(maxLen >= ss->ssl3.signatureAlgorithmCount * 2);
     if (maxLen < ss->ssl3.signatureAlgorithmCount * 2) {
         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
         return SECFailure;
     }
 
     *len = 0;
     for (i = 0; i < ss->ssl3.signatureAlgorithmCount; ++i) {
         const SSLSignatureAndHashAlg *alg = &ss->ssl3.signatureAlgorithms[i];
-        /* Note that we don't support a handshake hash with anything other than
-         * the PRF hash, so asking for a signature from clients for something
-         * else would be inviting disaster. */
-        if (alg->hashAlg == suiteHashAlg) {
-            buf[(*len)++] = (PRUint8)alg->hashAlg;
-            buf[(*len)++] = (PRUint8)alg->sigAlg;
-        }
+        buf[(*len)++] = (PRUint8)alg->hashAlg;
+        buf[(*len)++] = (PRUint8)alg->sigAlg;
     }
 
     if (*len == 0) {
         PORT_SetError(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
         return SECFailure;
     }
     return SECSuccess;
 }
@@ -10281,70 +10519,88 @@ ssl3_SendServerHelloDone(sslSocket *ss)
 static SECStatus
 ssl3_HandleCertificateVerify(sslSocket *ss, SSL3Opaque *b, PRUint32 length,
                              SSL3Hashes *hashes)
 {
     SECItem signed_hash = { siBuffer, NULL, 0 };
     SECStatus rv;
     int errCode = SSL_ERROR_RX_MALFORMED_CERT_VERIFY;
     SSL3AlertDescription desc = handshake_failure;
-    PRBool isTLS, isTLS12;
+    PRBool isTLS;
     SSLSignatureAndHashAlg sigAndHash;
+    SSL3Hashes localHashes;
+    SSL3Hashes *hashesForVerify = NULL;
 
     SSL_TRC(3, ("%d: SSL3[%d]: handle certificate_verify handshake",
                 SSL_GETPID(), ss->fd));
     PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
+    /* TLS 1.3 is handled by tls13_HandleCertificateVerify */
+    PORT_Assert(ss->ssl3.prSpec->version <= SSL_LIBRARY_VERSION_TLS_1_2);
+
     isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0);
-    isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
 
     if (ss->ssl3.hs.ws != wait_cert_verify) {
         desc = unexpected_message;
         errCode = SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY;
         goto alert_loser;
     }
 
-    if (!hashes) {
-        PORT_Assert(0);
-        desc = internal_error;
-        errCode = SEC_ERROR_LIBRARY_FAILURE;
-        goto alert_loser;
-    }
-
-    if (isTLS12) {
+    if (ss->ssl3.hs.hashType != handshake_hash_record) {
+        if (!hashes) {
+            PORT_Assert(0);
+            desc = internal_error;
+            errCode = SEC_ERROR_LIBRARY_FAILURE;
+            goto alert_loser;
+        }
+        hashesForVerify = hashes;
+    } else {
         rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length,
                                                    &sigAndHash);
         if (rv != SECSuccess) {
             goto loser; /* malformed or unsupported. */
         }
         rv = ssl3_CheckSignatureAndHashAlgorithmConsistency(
             ss, &sigAndHash, ss->sec.peerCert);
         if (rv != SECSuccess) {
             errCode = PORT_GetError();
             desc = decrypt_error;
             goto alert_loser;
         }
-
-        /* We only support CertificateVerify messages that use the handshake
-         * hash. */
-        if (sigAndHash.hashAlg != hashes->hashAlg) {
-            errCode = SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM;
+#ifndef NO_PKCS11_BYPASS
+        if (ss->opt.bypassPKCS11) {
+            rv = ssl3_ComputeBypassHandshakeHash(hashes->u.pointer_to_hash_input.data,
+                                                 hashes->u.pointer_to_hash_input.len,
+                                                 sigAndHash.hashAlg,
+                                                 &localHashes);
+        } else
+#endif
+        {
+            rv = ssl3_ComputePkcs11HandshakeHash(hashes->u.pointer_to_hash_input.data,
+                                                 hashes->u.pointer_to_hash_input.len,
+                                                 sigAndHash.hashAlg,
+                                                 &localHashes);
+        }
+        if (rv == SECSuccess) {
+            hashesForVerify = &localHashes;
+        } else {
+            errCode = SSL_ERROR_DIGEST_FAILURE;
             desc = decrypt_error;
             goto alert_loser;
         }
     }
 
     rv = ssl3_ConsumeHandshakeVariable(ss, &signed_hash, 2, &b, &length);
     if (rv != SECSuccess) {
         goto loser; /* malformed. */
     }
 
     /* XXX verify that the key & kea match */
-    rv = ssl3_VerifySignedHashes(hashes, ss->sec.peerCert, &signed_hash,
+    rv = ssl3_VerifySignedHashes(hashesForVerify, ss->sec.peerCert, &signed_hash,
                                  isTLS, ss->pkcs11PinArg);
     if (rv != SECSuccess) {
         errCode = PORT_GetError();
         desc = isTLS ? decrypt_error : handshake_failure;
         goto alert_loser;
     }
 
     signed_hash.data = NULL;
@@ -10364,17 +10620,17 @@ loser:
 }
 
 /* find a slot that is able to generate a PMS and wrap it with RSA.
  * Then generate and return the PMS.
  * If the serverKeySlot parameter is non-null, this function will use
  * that slot to do the job, otherwise it will find a slot.
  *
  * Called from  ssl3_DeriveConnectionKeysPKCS11()  (above)
- *      sendRSAClientKeyExchange()         (above)
+ *      ssl3_SendRSAClientKeyExchange()     (above)
  *      ssl3_HandleRSAClientKeyExchange()  (below)
  * Caller must hold the SpecWriteLock, the SSL3HandshakeLock
  */
 static PK11SymKey *
 ssl3_GenerateRSAPMS(sslSocket *ss, ssl3CipherSpec *spec,
                     PK11SlotInfo *serverKeySlot)
 {
     PK11SymKey *pms = NULL;
@@ -10448,17 +10704,17 @@ ssl3_GenerateRSAPMS(sslSocket *ss, ssl3C
  * the failure must occur.
  *
  * Called from ssl3_HandleClientKeyExchange
  */
 static SECStatus
 ssl3_HandleRSAClientKeyExchange(sslSocket *ss,
                                 SSL3Opaque *b,
                                 PRUint32 length,
-                                SECKEYPrivateKey *serverKey)
+                                sslKeyPair *serverKeyPair)
 {
 #ifndef NO_PKCS11_BYPASS
     unsigned char *cr = (unsigned char *)&ss->ssl3.hs.client_random;
     unsigned char *sr = (unsigned char *)&ss->ssl3.hs.server_random;
     ssl3CipherSpec *pwSpec = ss->ssl3.pwSpec;
     unsigned int outLen = 0;
     PRBool isTLS = PR_FALSE;
     SECItem pmsItem = { siBuffer, NULL, 0 };
@@ -10509,17 +10765,17 @@ ssl3_HandleRSAClientKeyExchange(sslSocke
         /* TRIPLE BYPASS, get PMS directly from RSA decryption.
          * Use PK11_PrivDecryptPKCS1 to decrypt the PMS to a buffer,
          * then, check for version rollback attack, then
          * do the equivalent of ssl3_DeriveMasterSecret, placing the MS in
          * pwSpec->msItem.  Finally call ssl3_InitPendingCipherSpec with
          * ss and NULL, so that it will use the MS we've already derived here.
          */
 
-        rv = PK11_PrivDecryptPKCS1(serverKey, rsaPmsBuf, &outLen,
+        rv = PK11_PrivDecryptPKCS1(serverKeyPair->privKey, rsaPmsBuf, &outLen,
                                    sizeof rsaPmsBuf, enc_pms.data, enc_pms.len);
         if (rv != SECSuccess) {
             /* triple bypass failed.  Let's try for a double bypass. */
             goto double_bypass;
         } else if (ss->opt.detectRollBack) {
             SSL3ProtocolVersion client_version =
                 (rsaPmsBuf[0] << 8) | rsaPmsBuf[1];
 
@@ -10574,17 +10830,17 @@ ssl3_HandleRSAClientKeyExchange(sslSocke
          *
          * We do two derivations here because we can't rely on having
          * a function that only performs the PMS version and length
          * check. The only redundant cost is that this runs the PRF,
          * which isn't necessary here.
          */
 
         /* Generate the bogus PMS (R) */
-        slot = PK11_GetSlotFromPrivateKey(serverKey);
+        slot = PK11_GetSlotFromPrivateKey(serverKeyPair->privKey);
         if (!slot) {
             PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
             return SECFailure;
         }
 
         if (!PK11_DoesMechanism(slot, CKM_SSL3_MASTER_KEY_DERIVE)) {
             PK11_FreeSlot(slot);
             slot = PK11_GetBestSlot(CKM_SSL3_MASTER_KEY_DERIVE, NULL);
@@ -10605,17 +10861,17 @@ ssl3_HandleRSAClientKeyExchange(sslSocke
         }
 
         /*
          * unwrap pms out of the incoming buffer
          * Note: CKM_SSL3_MASTER_KEY_DERIVE is NOT the mechanism used to do
          *  the unwrap.  Rather, it is the mechanism with which the
          *      unwrapped pms will be used.
          */
-        realPms = PK11_PubUnwrapSymKey(serverKey, &enc_pms,
+        realPms = PK11_PubUnwrapSymKey(serverKeyPair->privKey, &enc_pms,
                                        CKM_SSL3_MASTER_KEY_DERIVE, CKA_DERIVE, 0);
         /* Temporarily use the PMS if unwrapping the real PMS fails. */
         useFauxPms |= (realPms == NULL);
 
         /* Attempt to derive the MS from the PMS. This is the only way to
          * check the version field in the RSA PMS. If this fails, we
          * then use the faux PMS in place of the PMS. Note that this
          * operation should never fail if we are using the faux PMS
@@ -10647,80 +10903,77 @@ ssl3_HandleRSAClientKeyExchange(sslSocke
 
     return SECSuccess;
 }
 
 static SECStatus
 ssl3_HandleDHClientKeyExchange(sslSocket *ss,
                                SSL3Opaque *b,
                                PRUint32 length,
-                               SECKEYPublicKey *srvrPubKey,
-                               SECKEYPrivateKey *serverKey)
+                               sslKeyPair *serverKeyPair)
 {
     PK11SymKey *pms;
     SECStatus rv;
     SECKEYPublicKey clntPubKey;
     CK_MECHANISM_TYPE target;
     PRBool isTLS;
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
-    PORT_Assert(srvrPubKey);
 
     clntPubKey.keyType = dhKey;
-    clntPubKey.u.dh.prime.len = srvrPubKey->u.dh.prime.len;
-    clntPubKey.u.dh.prime.data = srvrPubKey->u.dh.prime.data;
-    clntPubKey.u.dh.base.len = srvrPubKey->u.dh.base.len;
-    clntPubKey.u.dh.base.data = srvrPubKey->u.dh.base.data;
+    clntPubKey.u.dh.prime.len = serverKeyPair->pubKey->u.dh.prime.len;
+    clntPubKey.u.dh.prime.data = serverKeyPair->pubKey->u.dh.prime.data;
+    clntPubKey.u.dh.base.len = serverKeyPair->pubKey->u.dh.base.len;
+    clntPubKey.u.dh.base.data = serverKeyPair->pubKey->u.dh.base.data;
 
     rv = ssl3_ConsumeHandshakeVariable(ss, &clntPubKey.u.dh.publicValue,
                                        2, &b, &length);
     if (rv != SECSuccess) {
-        goto loser;
+        return SECFailure;
+    }
+
+    if (!ssl_IsValidDHEShare(&serverKeyPair->pubKey->u.dh.prime,
+                             &clntPubKey.u.dh.publicValue)) {
+        PORT_SetError(SSL_ERROR_RX_MALFORMED_DHE_KEY_SHARE);
+        return SECFailure;
     }
 
     isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0);
 
     if (isTLS)
         target = CKM_TLS_MASTER_KEY_DERIVE_DH;
     else
         target = CKM_SSL3_MASTER_KEY_DERIVE_DH;
 
-    /*  Determine the PMS */
-    pms = PK11_PubDerive(serverKey, &clntPubKey, PR_FALSE, NULL, NULL,
+    /* Determine the PMS */
+    pms = PK11_PubDerive(serverKeyPair->privKey, &clntPubKey, PR_FALSE, NULL, NULL,
                          CKM_DH_PKCS_DERIVE, target, CKA_DERIVE, 0, NULL);
     if (pms == NULL) {
+        ssl_FreeEphemeralKeyPairs(ss);
         ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
-        goto loser;
+        return SECFailure;
     }
 
     rv = ssl3_InitPendingCipherSpec(ss, pms);
     PK11_FreeSymKey(pms);
-    pms = NULL;
-
-loser:
-    if (ss->dheKeyPair) {
-        ssl3_FreeKeyPair(ss->dheKeyPair);
-        ss->dheKeyPair = NULL;
-    }
+    ssl_FreeEphemeralKeyPairs(ss);
     return rv;
 }
 
 /* Called from ssl3_HandlePostHelloHandshakeMessage() when it has deciphered
  * a complete ssl3 ClientKeyExchange message from the remote client
  * Caller must hold Handshake and RecvBuf locks.
  */
 static SECStatus
 ssl3_HandleClientKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
 {
-    SECKEYPrivateKey *serverKey = NULL;
+    sslKeyPair *serverKeyPair = NULL;
     SECStatus rv;
     const ssl3KEADef *kea_def;
-    ssl3KeyPair *serverKeyPair = NULL;
-    SECKEYPublicKey *serverPubKey = NULL;
 
     SSL_TRC(3, ("%d: SSL3[%d]: handle client_key_exchange handshake",
                 SSL_GETPID(), ss->fd));
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
     if (ss->ssl3.hs.ws != wait_client_key) {
@@ -10740,99 +10993,69 @@ ssl3_HandleClientKeyExchange(sslSocket *
             /* shouldn't happen, don't use step down if it does */
             goto skip;
         }
         serverKeyPair = ss->stepDownKeyPair;
         ss->sec.keaKeyBits = EXPORT_RSA_KEY_LENGTH * BPB;
     } else
     skip:
     if (kea_def->ephemeral) {
-        if (kea_def->exchKeyType == ssl_kea_dh && ss->dheKeyPair) {
-            serverKeyPair = ss->dheKeyPair;
-            if (serverKeyPair->pubKey) {
-                ss->sec.keaKeyBits =
-                    SECKEY_PublicKeyStrengthInBits(serverKeyPair->pubKey);
-            }
-        } else if (kea_def->exchKeyType == ssl_kea_ecdh &&
-                   ss->ephemeralECDHKeyPair) {
-            serverKeyPair = ss->ephemeralECDHKeyPair;
-            if (serverKeyPair->pubKey) {
-                ss->sec.keaKeyBits =
-                    SECKEY_PublicKeyStrengthInBits(serverKeyPair->pubKey);
-            }
-        }
+        sslEphemeralKeyPair *keyPair;
+        /* There should be exactly one pair. */
+        PORT_Assert(!PR_CLIST_IS_EMPTY(&ss->ephemeralKeyPairs));
+        PORT_Assert(PR_PREV_LINK(&ss->ephemeralKeyPairs) ==
+                    PR_NEXT_LINK(&ss->ephemeralKeyPairs));
+        keyPair = (sslEphemeralKeyPair *)PR_NEXT_LINK(&ss->ephemeralKeyPairs);
+        serverKeyPair = keyPair->keys;
+        ss->sec.keaKeyBits =
+            SECKEY_PublicKeyStrengthInBits(serverKeyPair->pubKey);
     } else {
         serverKeyPair = ss->sec.serverCert->serverKeyPair;
         ss->sec.keaKeyBits = ss->sec.serverCert->serverKeyBits;
     }
 
-    if (serverKeyPair) {
-        serverKey = serverKeyPair->privKey;
-    }
-
-    if (serverKey == NULL) {
-        SEND_ALERT
+    if (!serverKeyPair) {
+        SSL3_SendAlert(ss, alert_fatal, handshake_failure);
         PORT_SetError(SSL_ERROR_NO_SERVER_KEY_FOR_ALG);
         return SECFailure;
     }
+    PORT_Assert(serverKeyPair->pubKey);
+    PORT_Assert(serverKeyPair->privKey);
 
     ss->sec.keaType = kea_def->exchKeyType;
 
     switch (kea_def->exchKeyType) {
         case ssl_kea_rsa:
-            rv = ssl3_HandleRSAClientKeyExchange(ss, b, length, serverKey);
-            if (rv != SECSuccess) {
-                SEND_ALERT
-                return SECFailure; /* error code set */
-            }
+            rv = ssl3_HandleRSAClientKeyExchange(ss, b, length, serverKeyPair);
             break;
 
         case ssl_kea_dh:
-            if (ss->dheKeyPair && ss->dheKeyPair->pubKey) {
-                serverPubKey = ss->dheKeyPair->pubKey;
-            }
-            if (!serverPubKey) {
-                PORT_SetError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE);
-                return SECFailure;
-            }
-            rv = ssl3_HandleDHClientKeyExchange(ss, b, length,
-                                                serverPubKey, serverKey);
-            if (rv != SECSuccess) {
-                SSL3_SendAlert(ss, alert_fatal, handshake_failure);
-                return SECFailure; /* error code set */
-            }
+            rv = ssl3_HandleDHClientKeyExchange(ss, b, length, serverKeyPair);
             break;
 
         case ssl_kea_ecdh:
-            if (serverKeyPair) {
-                serverPubKey = serverKeyPair->pubKey;
-            }
-            if (serverPubKey == NULL) {
-                /* XXX Is this the right error code? */
-                PORT_SetError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE);
-                return SECFailure;
-            }
-            rv = ssl3_HandleECDHClientKeyExchange(ss, b, length,
-                                                  serverPubKey, serverKey);
-            if (ss->ephemeralECDHKeyPair) {
-                ssl3_FreeKeyPair(ss->ephemeralECDHKeyPair);
-                ss->ephemeralECDHKeyPair = NULL;
-            }
-            if (rv != SECSuccess) {
-                return SECFailure; /* error code set */
-            }
+            rv = ssl3_HandleECDHClientKeyExchange(ss, b, length, serverKeyPair);
             break;
 
         default:
             (void)ssl3_HandshakeFailure(ss);
             PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
             return SECFailure;
     }
-    ss->ssl3.hs.ws = ss->sec.peerCert ? wait_cert_verify : wait_change_cipher;
-    return SECSuccess;
+    ssl_FreeEphemeralKeyPairs(ss);
+    if (rv == SECSuccess) {
+        ss->ssl3.hs.ws = ss->sec.peerCert ? wait_cert_verify : wait_change_cipher;
+    } else {
+        /* PORT_SetError has been called by all the Handle*ClientKeyExchange
+         * functions above.  However, not all error paths result in an alert, so
+         * this ensures that the server knows about the error.  Note that if an
+         * alert was already sent, SSL3_SendAlert() is a noop. */
+        (void)SSL3_SendAlert(ss, alert_fatal, handshake_failure);
+    }
+    return rv;
 }
 
 /* This is TLS's equivalent of sending a no_certificate alert. */
 SECStatus
 ssl3_SendEmptyCertificate(sslSocket *ss)
 {
     SECStatus rv;
     unsigned int len = 0;
@@ -11667,17 +11890,17 @@ ssl3_ComputeTLSFinished(sslSocket *ss, s
         return ssl3_TLSPRFWithMasterSecret(spec, label, len, hashes->u.raw,
                                            hashes->len, tlsFinished->verify_data,
                                            sizeof tlsFinished->verify_data, hashType);
     }
 
     if (spec->version < SSL_LIBRARY_VERSION_TLS_1_2) {
         tls_mac_params.prfMechanism = CKM_TLS_PRF;
     } else {
-        tls_mac_params.prfMechanism = ssl3_GetTls12PrfHashMechanism(ss);
+        tls_mac_params.prfMechanism = ssl3_GetPrfHashMechanism(ss);
     }
     tls_mac_params.ulMacLength = 12;
     tls_mac_params.ulServerOrClient = isServer ? 1 : 2;
     param.data = (unsigned char *)&tls_mac_params;
     param.len = sizeof(tls_mac_params);
     prf_context = PK11_CreateContextBySymKey(CKM_TLS_MAC, CKA_SIGN,
                                              spec->master_secret, &param);
     if (!prf_context)
@@ -12172,22 +12395,22 @@ ssl3_FillInCachedSID(sslSocket *ss, sslS
 {
     SECStatus rv;
 
     /* fill in the sid */
     sid->u.ssl3.cipherSuite =
         ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 ? ss->ssl3.hs.origCipherSuite : ss->ssl3.hs.cipher_suite;
     sid->u.ssl3.compression = ss->ssl3.hs.compression;
     sid->u.ssl3.policy = ss->ssl3.policy;
-    sid->u.ssl3.negotiatedECCurves = ss->ssl3.hs.negotiatedECCurves;
     sid->version = ss->version;
     sid->authType = ss->sec.authType;
     sid->authKeyBits = ss->sec.authKeyBits;
     sid->keaType = ss->sec.keaType;
     sid->keaKeyBits = ss->sec.keaKeyBits;
+    sid->namedGroups = ss->namedGroups;
     sid->lastAccessTime = sid->creationTime = ssl_Time();
     sid->expirationTime = sid->creationTime + ssl3_sid_timeout;
     sid->localCert = CERT_DupCertificate(ss->sec.localCert);
     if (ss->sec.isServer) {
         memcpy(&sid->certType, &ss->sec.serverCert->certType, sizeof(sid->certType));
     } else {
         sid->certType.authType = ssl_auth_null;
     }
@@ -12280,20 +12503,43 @@ ssl3_HandleHandshakeMessage(sslSocket *s
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
     /*
      * We have to compute the hashes before we update them with the
      * current message.
      */
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
-        if (((type == finished) && (ss->ssl3.hs.ws == wait_finished)) ||
-            ((type == certificate_verify) &&
-             (ss->ssl3.hs.ws == wait_cert_verify))) {
+        if ((type == finished) && (ss->ssl3.hs.ws == wait_finished)) {
             computeHashes = PR_TRUE;
+        } else if ((type == certificate_verify) && (ss->ssl3.hs.ws == wait_cert_verify)) {
+            if (ss->ssl3.hs.hashType == handshake_hash_record) {
+                /* We cannot compute the hash yet. We must wait until we have
+                 * decoded the certificate_verify message in
+                 * ssl3_HandleCertificateVerify, which will tell us which
+                 * hash function we must use.
+                 *
+                 * (ssl3_HandleCertificateVerify cannot simply look at the
+                 * buffer length itself, because at the time we reach it,
+                 * additional handshake messages will have been added to the
+                 * buffer, e.g. the certificate_verify message itself.)
+                 *
+                 * Therefore, we use SSL3Hashes.u.pointer_to_hash_input
+                 * to signal the current state of the buffer.
+                 *
+                 * ssl3_HandleCertificateVerify will detect
+                 *     hashType == handshake_hash_record
+                 * and use that information to calculate the hash.
+                 */
+                hashes.u.pointer_to_hash_input.data = ss->ssl3.hs.messages.buf;
+                hashes.u.pointer_to_hash_input.len = ss->ssl3.hs.messages.len;
+                hashesPtr = &hashes;
+            } else {
+                computeHashes = PR_TRUE;
+            }
         }
     } else {
         if (type == certificate_verify) {
             computeHashes =
                 TLS13_IN_HS_STATE(ss, wait_cert_verify);
         } else if (type == finished) {
             computeHashes =
                 TLS13_IN_HS_STATE(ss, wait_cert_request, wait_finished);
@@ -13371,19 +13617,19 @@ ssl3_InitState(sslSocket *ss)
     ssl_GetSpecWriteLock(ss);
     ss->ssl3.crSpec = ss->ssl3.cwSpec = &ss->ssl3.specs[0];
     ss->ssl3.prSpec = ss->ssl3.pwSpec = &ss->ssl3.specs[1];
     ssl3_InitCipherSpec(ss->ssl3.crSpec);
     ssl3_InitCipherSpec(ss->ssl3.prSpec);
     ss->ssl3.crSpec->version = ss->ssl3.prSpec->version = ss->vrange.max;
     ss->ssl3.hs.sendingSCSV = PR_FALSE;
     ss->ssl3.hs.preliminaryInfo = 0;
+    ss->ssl3.hs.peerSupportsFfdheGroups = PR_FALSE;
 
     ss->ssl3.hs.ws = (ss->sec.isServer) ? wait_client_hello : wait_server_hello;
-    ss->ssl3.hs.negotiatedECCurves = ssl3_GetSupportedECCurveMask(ss);
     ssl_ReleaseSpecWriteLock(ss);
 
     PORT_Memset(&ss->xtnData, 0, sizeof(TLSExtensionData));
 
     if (IS_DTLS(ss)) {
         ss->ssl3.hs.sendMessageSeq = 0;
         ss->ssl3.hs.recvMessageSeq = 0;
         ss->ssl3.hs.rtTimeoutMs = DTLS_RETRANSMIT_INITIAL_MS;
@@ -13409,87 +13655,45 @@ ssl3_InitState(sslSocket *ss)
     ss->ssl3.hs.receivedNewSessionTicket = PR_FALSE;
     PORT_Memset(&ss->ssl3.hs.newSessionTicket, 0,
                 sizeof(ss->ssl3.hs.newSessionTicket));
 
     ss->ssl3.initialized = PR_TRUE;
     return SECSuccess;
 }
 
-/* Returns a reference counted object that contains a key pair.
- * Or NULL on failure.  Initial ref count is 1.
- * Uses the keys in the pair as input.
- */
-ssl3KeyPair *
-ssl3_NewKeyPair(SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey)
-{
-    ssl3KeyPair *pair;
-
-    if (!privKey || !pubKey) {
-        PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
-        return NULL;
-    }
-    pair = PORT_ZNew(ssl3KeyPair);
-    if (!pair)
-        return NULL; /* error code is set. */
-    pair->refCount = 1;
-    pair->privKey = privKey;
-    pair->pubKey = pubKey;
-    return pair; /* success */
-}
-
-ssl3KeyPair *
-ssl3_GetKeyPairRef(ssl3KeyPair *keyPair)
-{
-    PR_ATOMIC_INCREMENT(&keyPair->refCount);
-    return keyPair;
-}
-
-void
-ssl3_FreeKeyPair(ssl3KeyPair *keyPair)
-{
-    PRInt32 newCount = PR_ATOMIC_DECREMENT(&keyPair->refCount);
-    if (!newCount) {
-        if (keyPair->privKey)
-            SECKEY_DestroyPrivateKey(keyPair->privKey);
-        if (keyPair->pubKey)
-            SECKEY_DestroyPublicKey(keyPair->pubKey);
-        PORT_Free(keyPair);
-    }
-}
-
 /*
  * Creates the public and private RSA keys for SSL Step down.
  * Called from SSL_ConfigSecureServer in sslsecur.c
  */
 SECStatus
 ssl3_CreateRSAStepDownKeys(sslSocket *ss)
 {
     SECStatus rv = SECSuccess;
     SECKEYPrivateKey *privKey; /* RSA step down key */
     SECKEYPublicKey *pubKey;   /* RSA step down key */
     const sslServerCert *cert;
     unsigned int len;
 
     if (ss->stepDownKeyPair)
-        ssl3_FreeKeyPair(ss->stepDownKeyPair);
+        ssl_FreeKeyPair(ss->stepDownKeyPair);
     ss->stepDownKeyPair = NULL;
 #ifndef HACKED_EXPORT_SERVER
     cert = ssl_FindServerCertByAuthType(ss, ssl_auth_rsa_decrypt);
     if (!cert || !cert->serverKeyPair) {
         return SECFailure;
     }
     len = PK11_GetPrivateModulusLen(cert->serverKeyPair->privKey);
     /* Sigh, should have a get key strength call for private keys */
     if (len > EXPORT_RSA_KEY_LENGTH) {
         /* need to ask for the key size in bits */
         privKey = SECKEY_CreateRSAPrivateKey(EXPORT_RSA_KEY_LENGTH * BPB,
                                              &pubKey, NULL);
         if (!privKey || !pubKey ||
-            !(ss->stepDownKeyPair = ssl3_NewKeyPair(privKey, pubKey))) {
+            !(ss->stepDownKeyPair = ssl_NewKeyPair(privKey, pubKey))) {
             ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL);
             rv = SECFailure;
         }
     }
 #endif
     return rv;
 }
 
@@ -13759,20 +13963,17 @@ ssl3_DestroySSL3Info(sslSocket *ss)
     }
     if (ss->ssl3.hs.sha) {
         PK11_DestroyContext(ss->ssl3.hs.sha, PR_TRUE);
     }
     if (ss->ssl3.hs.clientSigAndHash) {
         PORT_Free(ss->ssl3.hs.clientSigAndHash);
     }
     if (ss->ssl3.hs.messages.buf) {
-        PORT_Free(ss->ssl3.hs.messages.buf);
-        ss->ssl3.hs.messages.buf = NULL;
-        ss->ssl3.hs.messages.len = 0;
-        ss->ssl3.hs.messages.space = 0;
+        sslBuffer_Clear(&ss->ssl3.hs.messages);
     }
 
     /* free the SSL3Buffer (msg_body) */
     PORT_Free(ss->ssl3.hs.msg_body.buf);
 
     SECITEM_FreeItem(&ss->ssl3.hs.newSessionTicket.ticket, PR_FALSE);
 
     /* free up the CipherSpecs */
@@ -13800,20 +14001,16 @@ ssl3_DestroySSL3Info(sslSocket *ss)
         PK11_FreeSymKey(ss->ssl3.hs.xES);
     if (ss->ssl3.hs.trafficSecret)
         PK11_FreeSymKey(ss->ssl3.hs.trafficSecret);
     if (ss->ssl3.hs.clientFinishedSecret)
         PK11_FreeSymKey(ss->ssl3.hs.clientFinishedSecret);
     if (ss->ssl3.hs.serverFinishedSecret)
         PK11_FreeSymKey(ss->ssl3.hs.serverFinishedSecret);
 
-    if (ss->ssl3.dheGroups) {
-        PORT_Free(ss->ssl3.dheGroups);
-    }
-
     ss->ssl3.initialized = PR_FALSE;
 
     SECITEM_FreeItem(&ss->ssl3.nextProto, PR_FALSE);
 }
 
 #define MAP_NULL(x) (((x) != 0) ? (x) : SEC_OID_NULL_CIPHER)
 
 SECStatus
--- a/security/nss/lib/ssl/ssl3ecc.c
+++ b/security/nss/lib/ssl/ssl3ecc.c
@@ -33,140 +33,48 @@
 
 #ifndef PK11_SETATTRS
 #define PK11_SETATTRS(x, id, v, l) \
     (x)->type = (id);              \
     (x)->pValue = (v);             \
     (x)->ulValueLen = (l);
 #endif
 
-static SECStatus ssl3_CreateECDHEphemeralKeys(sslSocket *ss, ECName ec_curve);
-
-#define supportedCurve(x) (((x) > ec_noName) && ((x) < ec_pastLastName))
-
-/* Table containing OID tags for elliptic curves named in the
- * ECC-TLS IETF draft.
- */
-static const SECOidTag ecName2OIDTag[] = {
-    0,
-    SEC_OID_SECG_EC_SECT163K1, /*  1 */
-    SEC_OID_SECG_EC_SECT163R1, /*  2 */
-    SEC_OID_SECG_EC_SECT163R2, /*  3 */
-    SEC_OID_SECG_EC_SECT193R1, /*  4 */
-    SEC_OID_SECG_EC_SECT193R2, /*  5 */
-    SEC_OID_SECG_EC_SECT233K1, /*  6 */
-    SEC_OID_SECG_EC_SECT233R1, /*  7 */
-    SEC_OID_SECG_EC_SECT239K1, /*  8 */
-    SEC_OID_SECG_EC_SECT283K1, /*  9 */
-    SEC_OID_SECG_EC_SECT283R1, /* 10 */
-    SEC_OID_SECG_EC_SECT409K1, /* 11 */
-    SEC_OID_SECG_EC_SECT409R1, /* 12 */
-    SEC_OID_SECG_EC_SECT571K1, /* 13 */
-    SEC_OID_SECG_EC_SECT571R1, /* 14 */
-    SEC_OID_SECG_EC_SECP160K1, /* 15 */
-    SEC_OID_SECG_EC_SECP160R1, /* 16 */
-    SEC_OID_SECG_EC_SECP160R2, /* 17 */
-    SEC_OID_SECG_EC_SECP192K1, /* 18 */
-    SEC_OID_SECG_EC_SECP192R1, /* 19 */
-    SEC_OID_SECG_EC_SECP224K1, /* 20 */
-    SEC_OID_SECG_EC_SECP224R1, /* 21 */
-    SEC_OID_SECG_EC_SECP256K1, /* 22 */
-    SEC_OID_SECG_EC_SECP256R1, /* 23 */
-    SEC_OID_SECG_EC_SECP384R1, /* 24 */
-    SEC_OID_SECG_EC_SECP521R1, /* 25 */
-};
-
-static const PRUint16 curve2bits[] = {
-    0,    /*  ec_noName     = 0,   */
-    163,  /*  ec_sect163k1  = 1,   */
-    163,  /*  ec_sect163r1  = 2,   */
-    163,  /*  ec_sect163r2  = 3,   */
-    193,  /*  ec_sect193r1  = 4,   */
-    193,  /*  ec_sect193r2  = 5,   */
-    233,  /*  ec_sect233k1  = 6,   */
-    233,  /*  ec_sect233r1  = 7,   */
-    239,  /*  ec_sect239k1  = 8,   */
-    283,  /*  ec_sect283k1  = 9,   */
-    283,  /*  ec_sect283r1  = 10,  */
-    409,  /*  ec_sect409k1  = 11,  */
-    409,  /*  ec_sect409r1  = 12,  */
-    571,  /*  ec_sect571k1  = 13,  */
-    571,  /*  ec_sect571r1  = 14,  */
-    160,  /*  ec_secp160k1  = 15,  */
-    160,  /*  ec_secp160r1  = 16,  */
-    160,  /*  ec_secp160r2  = 17,  */
-    192,  /*  ec_secp192k1  = 18,  */
-    192,  /*  ec_secp192r1  = 19,  */
-    224,  /*  ec_secp224k1  = 20,  */
-    224,  /*  ec_secp224r1  = 21,  */
-    256,  /*  ec_secp256k1  = 22,  */
-    256,  /*  ec_secp256r1  = 23,  */
-    384,  /*  ec_secp384r1  = 24,  */
-    521,  /*  ec_secp521r1  = 25,  */
-    65535 /*  ec_pastLastName      */
-};
-
-typedef struct Bits2CurveStr {
-    PRUint16 bits;
-    ECName curve;
-} Bits2Curve;
-
-static const Bits2Curve bits2curve[] = {
-    { 192, ec_secp192r1 /*  = 19,  fast */ },
-    { 160, ec_secp160r2 /*  = 17,  fast */ },
-    { 160, ec_secp160k1 /*  = 15,  */ },
-    { 160, ec_secp160r1 /*  = 16,  */ },
-    { 163, ec_sect163k1 /*  = 1,   */ },
-    { 163, ec_sect163r1 /*  = 2,   */ },
-    { 163, ec_sect163r2 /*  = 3,   */ },
-    { 192, ec_secp192k1 /*  = 18,  */ },
-    { 193, ec_sect193r1 /*  = 4,   */ },
-    { 193, ec_sect193r2 /*  = 5,   */ },
-    { 224, ec_secp224r1 /*  = 21,  fast */ },
-    { 224, ec_secp224k1 /*  = 20,  */ },
-    { 233, ec_sect233k1 /*  = 6,   */ },
-    { 233, ec_sect233r1 /*  = 7,   */ },
-    { 239, ec_sect239k1 /*  = 8,   */ },
-    { 256, ec_secp256r1 /*  = 23,  fast */ },
-    { 256, ec_secp256k1 /*  = 22,  */ },
-    { 283, ec_sect283k1 /*  = 9,   */ },
-    { 283, ec_sect283r1 /*  = 10,  */ },
-    { 384, ec_secp384r1 /*  = 24,  fast */ },
-    { 409, ec_sect409k1 /*  = 11,  */ },
-    { 409, ec_sect409r1 /*  = 12,  */ },
-    { 521, ec_secp521r1 /*  = 25,  fast */ },
-    { 571, ec_sect571k1 /*  = 13,  */ },
-    { 571, ec_sect571r1 /*  = 14,  */ },
-    { 65535, ec_noName }
-};
+static SECStatus ssl_CreateECDHEphemeralKeys(sslSocket *ss,
+                                             const namedGroupDef *ecGroup);
 
 typedef struct ECDHEKeyPairStr {
-    ssl3KeyPair *pair;
+    sslEphemeralKeyPair *pair;
     int error; /* error code of the call-once function */
     PRCallOnceType once;
 } ECDHEKeyPair;
 
 /* arrays of ECDHE KeyPairs */
-static ECDHEKeyPair gECDHEKeyPairs[ec_pastLastName];
+static PRCallOnceType gECDHEInitOnce;
+static int gECDHEInitError;
+/* This must be the same as ssl_named_groups_count.  ssl_ECRegister() asserts
+ * this at runtime; no compile-time error, sorry. */
+static ECDHEKeyPair gECDHEKeyPairs[29];
 
 SECStatus
-ssl3_ECName2Params(PLArenaPool *arena, ECName curve, SECKEYECParams *params)
+ssl_NamedGroup2ECParams(PLArenaPool *arena, const namedGroupDef *ecGroup,
+                        SECKEYECParams *params)
 {
     SECOidData *oidData = NULL;
     PRUint32 policyFlags = 0;
+    SECStatus rv;
 
-    if ((curve <= ec_noName) || (curve >= ec_pastLastName) ||
-        ((oidData = SECOID_FindOIDByTag(ecName2OIDTag[curve])) == NULL)) {
+    if (!ecGroup || ecGroup->type != group_type_ec ||
+        (oidData = SECOID_FindOIDByTag(ecGroup->oidTag)) == NULL) {
         PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
         return SECFailure;
     }
 
-    if ((NSS_GetAlgorithmPolicy(ecName2OIDTag[curve], &policyFlags) ==
-         SECSuccess) &&
-        !(policyFlags & NSS_USE_ALG_IN_SSL_KX)) {
+    rv = NSS_GetAlgorithmPolicy(ecGroup->oidTag, &policyFlags);
+    if (rv == SECSuccess && !(policyFlags & NSS_USE_ALG_IN_SSL_KX)) {
         PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
         return SECFailure;
     }
 
     SECITEM_AllocItem(arena, params, (2 + oidData->oid.len));
     /*
      * params->data needs to contain the ASN encoding of an object ID (OID)
      * representing the named curve. The actual OID is in
@@ -174,54 +82,55 @@ ssl3_ECName2Params(PLArenaPool *arena, E
      */
     params->data[0] = SEC_ASN1_OBJECT_ID;
     params->data[1] = oidData->oid.len;
     memcpy(params->data + 2, oidData->oid.data, oidData->oid.len);
 
     return SECSuccess;
 }
 
-ECName
-ssl3_PubKey2ECName(SECKEYPublicKey *pubKey)
+const namedGroupDef *
+ssl_ECPubKey2NamedGroup(const SECKEYPublicKey *pubKey)
 {
     SECItem oid = { siBuffer, NULL, 0 };
     SECOidData *oidData = NULL;
     PRUint32 policyFlags = 0;
-    ECName i;
-    SECKEYECParams *params;
+    unsigned int i;
+    const SECKEYECParams *params;
 
     if (pubKey->keyType != ecKey) {
         PORT_Assert(0);
-        return ec_noName;
+        return NULL;
     }
 
     params = &pubKey->u.ec.DEREncodedParams;
 
     /*
      * params->data needs to contain the ASN encoding of an object ID (OID)
      * representing a named curve. Here, we strip away everything
      * before the actual OID and use the OID to look up a named curve.
      */
     if (params->data[0] != SEC_ASN1_OBJECT_ID)
-        return ec_noName;
+        return NULL;
     oid.len = params->len - 2;
     oid.data = params->data + 2;
     if ((oidData = SECOID_FindOID(&oid)) == NULL)
-        return ec_noName;
+        return NULL;
     if ((NSS_GetAlgorithmPolicy(oidData->offset, &policyFlags) ==
          SECSuccess) &&
         !(policyFlags & NSS_USE_ALG_IN_SSL_KX)) {
-        return ec_noName;
+        return NULL;
     }
-    for (i = ec_noName + 1; i < ec_pastLastName; i++) {
-        if (ecName2OIDTag[i] == oidData->offset)
-            return i;
+    for (i = 0; i < ssl_named_group_count; ++i) {
+        if (ssl_named_groups[i].oidTag == oidData->offset) {
+            return &ssl_named_groups[i];
+        }
     }
 
-    return ec_noName;
+    return NULL;
 }
 
 /* Caller must set hiLevel error code. */
 static SECStatus
 ssl3_ComputeECDHKeyHash(SSLHashType hashAlg,
                         SECItem ec_params, SECItem server_ecpoint,
                         SSL3Random *client_rand, SSL3Random *server_rand,
                         SSL3Hashes *hashes, PRBool bypassPKCS11)
@@ -277,166 +186,152 @@ ssl3_ComputeECDHKeyHash(SSLHashType hash
 /* Called from ssl3_SendClientKeyExchange(). */
 SECStatus
 ssl3_SendECDHClientKeyExchange(sslSocket *ss, SECKEYPublicKey *svrPubKey)
 {
     PK11SymKey *pms = NULL;
     SECStatus rv = SECFailure;
     PRBool isTLS, isTLS12;
     CK_MECHANISM_TYPE target;
-    SECKEYPublicKey *pubKey = NULL;   /* Ephemeral ECDH key */
-    SECKEYPrivateKey *privKey = NULL; /* Ephemeral ECDH key */
+    const namedGroupDef *groupDef;
+    sslEphemeralKeyPair *keyPair = NULL;
+    SECKEYPublicKey *pubKey;
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
 
     isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0);
     isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
 
     /* Generate ephemeral EC keypair */
     if (svrPubKey->keyType != ecKey) {
         PORT_SetError(SEC_ERROR_BAD_KEY);
         goto loser;
     }
-    /* XXX SHOULD CALL ssl3_CreateECDHEphemeralKeys here, instead! */
-    privKey = SECKEY_CreateECPrivateKey(&svrPubKey->u.ec.DEREncodedParams,
-                                        &pubKey, ss->pkcs11PinArg);
-    if (!privKey || !pubKey) {
-        ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL);
-        rv = SECFailure;
+    groupDef = ssl_ECPubKey2NamedGroup(svrPubKey);
+    if (!groupDef) {
+        PORT_SetError(SEC_ERROR_BAD_KEY);
         goto loser;
     }
+    rv = ssl_CreateECDHEphemeralKeyPair(groupDef, &keyPair);
+    if (rv != SECSuccess) {
+        ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL);
+        goto loser;
+    }
+
+    pubKey = keyPair->keys->pubKey;
     PRINT_BUF(50, (ss, "ECDH public value:",
                    pubKey->u.ec.publicValue.data,
                    pubKey->u.ec.publicValue.len));
 
     if (isTLS12) {
         target = CKM_TLS12_MASTER_KEY_DERIVE_DH;
     } else if (isTLS) {
         target = CKM_TLS_MASTER_KEY_DERIVE_DH;
     } else {
         target = CKM_SSL3_MASTER_KEY_DERIVE_DH;
     }
 
-    /*  Determine the PMS */
-    pms = PK11_PubDeriveWithKDF(privKey, svrPubKey, PR_FALSE, NULL, NULL,
-                                CKM_ECDH1_DERIVE, target, CKA_DERIVE, 0,
-                                CKD_NULL, NULL, NULL);
+    /* Determine the PMS */
+    pms = PK11_PubDeriveWithKDF(keyPair->keys->privKey, svrPubKey,
+                                PR_FALSE, NULL, NULL, CKM_ECDH1_DERIVE, target,
+                                CKA_DERIVE, 0, CKD_NULL, NULL, NULL);
 
     if (pms == NULL) {
-        SSL3AlertDescription desc = illegal_parameter;
-        (void)SSL3_SendAlert(ss, alert_fatal, desc);
+        (void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
         ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
         goto loser;
     }
 
-    SECKEY_DestroyPrivateKey(privKey);
-    privKey = NULL;
-
     rv = ssl3_AppendHandshakeHeader(ss, client_key_exchange,
                                     pubKey->u.ec.publicValue.len + 1);
     if (rv != SECSuccess) {
         goto loser; /* err set by ssl3_AppendHandshake* */
     }
 
-    rv = ssl3_AppendHandshakeVariable(ss,
-                                      pubKey->u.ec.publicValue.data,
+    rv = ssl3_AppendHandshakeVariable(ss, pubKey->u.ec.publicValue.data,
                                       pubKey->u.ec.publicValue.len, 1);
-    SECKEY_DestroyPublicKey(pubKey);
-    pubKey = NULL;
 
     if (rv != SECSuccess) {
         goto loser; /* err set by ssl3_AppendHandshake* */
     }
 
     rv = ssl3_InitPendingCipherSpec(ss, pms);
-    PK11_FreeSymKey(pms);
-    pms = NULL;
-
     if (rv != SECSuccess) {
         ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
         goto loser;
     }
 
-    rv = SECSuccess;
+    PK11_FreeSymKey(pms);
+    ssl_FreeEphemeralKeyPair(keyPair);
+    return SECSuccess;
 
 loser:
     if (pms)
         PK11_FreeSymKey(pms);
-    if (privKey)
-        SECKEY_DestroyPrivateKey(privKey);
-    if (pubKey)
-        SECKEY_DestroyPublicKey(pubKey);
-    return rv;
-}
-
-ECName
-tls13_GroupForECDHEKeyShare(ssl3KeyPair *pair)
-{
-    return ssl3_PubKey2ECName(pair->pubKey);
+    if (keyPair)
+        ssl_FreeEphemeralKeyPair(keyPair);
+    return SECFailure;
 }
 
 /* This function returns the size of the key_exchange field in
- * the KeyShareEntry structure. */
+ * the KeyShareEntry structure, i.e.:
+ *     opaque point <1..2^8-1>; */
 unsigned int
-tls13_SizeOfECDHEKeyShareKEX(ssl3KeyPair *pair)
+tls13_SizeOfECDHEKeyShareKEX(const SECKEYPublicKey *pubKey)
 {
-    return 1 + /* Length */
-           pair->pubKey->u.ec.publicValue.len;
+    PORT_Assert(pubKey->keyType == ecKey);
+    return 1 + pubKey->u.ec.publicValue.len;
 }
 
 /* This function encodes the key_exchange field in
  * the KeyShareEntry structure. */
 SECStatus
-tls13_EncodeECDHEKeyShareKEX(sslSocket *ss, ssl3KeyPair *pair)
+tls13_EncodeECDHEKeyShareKEX(sslSocket *ss, const SECKEYPublicKey *pubKey)
 {
-    const SECItem *publicValue;
-
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
-
-    publicValue = &pair->pubKey->u.ec.publicValue;
+    PORT_Assert(pubKey->keyType == ecKey);
 
-    return ssl3_AppendHandshakeVariable(ss, publicValue->data,
-                                        publicValue->len, 1);
+    return ssl3_AppendHandshakeVariable(ss, pubKey->u.ec.publicValue.data,
+                                        pubKey->u.ec.publicValue.len, 1);
 }
 
 /*
 ** Called from ssl3_HandleClientKeyExchange()
 */
 SECStatus
 ssl3_HandleECDHClientKeyExchange(sslSocket *ss, SSL3Opaque *b,
                                  PRUint32 length,
-                                 SECKEYPublicKey *srvrPubKey,
-                                 SECKEYPrivateKey *srvrPrivKey)
+                                 sslKeyPair *serverKeyPair)
 {
     PK11SymKey *pms;
     SECStatus rv;
     SECKEYPublicKey clntPubKey;
     CK_MECHANISM_TYPE target;
     PRBool isTLS, isTLS12;
     int errCode = SSL_ERROR_RX_MALFORMED_CLIENT_KEY_EXCH;
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
     clntPubKey.keyType = ecKey;
     clntPubKey.u.ec.DEREncodedParams.len =
-        srvrPubKey->u.ec.DEREncodedParams.len;
+        serverKeyPair->pubKey->u.ec.DEREncodedParams.len;
     clntPubKey.u.ec.DEREncodedParams.data =
-        srvrPubKey->u.ec.DEREncodedParams.data;
+        serverKeyPair->pubKey->u.ec.DEREncodedParams.data;
 
     rv = ssl3_ConsumeHandshakeVariable(ss, &clntPubKey.u.ec.publicValue,
                                        1, &b, &length);
     if (rv != SECSuccess) {
         PORT_SetError(errCode);
         return SECFailure;
     }
 
-    // we have to catch the case when the client's public key has length 0
+    /* we have to catch the case when the client's public key has length 0. */
     if (!clntPubKey.u.ec.publicValue.len) {
         (void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
         PORT_SetError(errCode);
         return SECFailure;
     }
 
     isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0);
     isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
@@ -445,17 +340,18 @@ ssl3_HandleECDHClientKeyExchange(sslSock
         target = CKM_TLS12_MASTER_KEY_DERIVE_DH;
     } else if (isTLS) {
         target = CKM_TLS_MASTER_KEY_DERIVE_DH;
     } else {
         target = CKM_SSL3_MASTER_KEY_DERIVE_DH;
     }
 
     /*  Determine the PMS */
-    pms = PK11_PubDeriveWithKDF(srvrPrivKey, &clntPubKey, PR_FALSE, NULL, NULL,
+    pms = PK11_PubDeriveWithKDF(serverKeyPair->privKey, &clntPubKey,
+                                PR_FALSE, NULL, NULL,
                                 CKM_ECDH1_DERIVE, target, CKA_DERIVE, 0,
                                 CKD_NULL, NULL, NULL);
 
     if (pms == NULL) {
         /* last gasp.  */
         errCode = ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
         PORT_SetError(errCode);
         return SECFailure;
@@ -469,314 +365,280 @@ ssl3_HandleECDHClientKeyExchange(sslSock
     }
     return SECSuccess;
 }
 
 /*
 ** Take an encoded key share and make a public key out of it.
 ** returns NULL on error.
 */
-SECKEYPublicKey *
-tls13_ImportECDHKeyShare(sslSocket *ss, SSL3Opaque *b,
-                         PRUint32 length, ECName curve)
+SECStatus
+tls13_ImportECDHKeyShare(sslSocket *ss, SECKEYPublicKey *peerKey,
+                         SSL3Opaque *b, PRUint32 length,
+                         const namedGroupDef *ecGroup)
 {
-    PLArenaPool *arena = NULL;
-    SECKEYPublicKey *peerKey = NULL;
     SECStatus rv;
     SECItem ecPoint = { siBuffer, NULL, 0 };
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
     rv = ssl3_ConsumeHandshakeVariable(ss, &ecPoint, 1, &b, &length);
     if (rv != SECSuccess) {
-        tls13_FatalError(ss, SSL_ERROR_RX_MALFORMED_ECDHE_KEY_SHARE,
-                         illegal_parameter);
-        return NULL;
+        PORT_SetError(SSL_ERROR_RX_MALFORMED_ECDHE_KEY_SHARE);
+        return SECFailure;
     }
     if (length || !ecPoint.len) {
-        tls13_FatalError(ss, SSL_ERROR_RX_MALFORMED_ECDHE_KEY_SHARE,
-                         illegal_parameter);
-        return NULL;
+        PORT_SetError(SSL_ERROR_RX_MALFORMED_ECDHE_KEY_SHARE);
+        return SECFailure;
     }
 
     /* Fail if the ec point uses compressed representation */
     if (ecPoint.data[0] != EC_POINT_FORM_UNCOMPRESSED) {
-        tls13_FatalError(ss, SEC_ERROR_UNSUPPORTED_EC_POINT_FORM,
-                         illegal_parameter);
-        return NULL;
-    }
-
-    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
-    if (arena == NULL) {
-        goto no_memory;
+        PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM);
+        return SECFailure;
     }
 
-    peerKey = PORT_ArenaZNew(arena, SECKEYPublicKey);
-    if (peerKey == NULL) {
-        goto no_memory;
-    }
-
-    peerKey->arena = arena;
     peerKey->keyType = ecKey;
     /* Set up the encoded params */
-    rv = ssl3_ECName2Params(arena, curve, &peerKey->u.ec.DEREncodedParams);
+    rv = ssl_NamedGroup2ECParams(peerKey->arena, ecGroup,
+                                 &peerKey->u.ec.DEREncodedParams);
     if (rv != SECSuccess) {
-        goto no_memory;
+        ssl_MapLowLevelError(SSL_ERROR_RX_MALFORMED_ECDHE_KEY_SHARE);
+        return SECFailure;
     }
 
     /* copy publicValue in peerKey */
-    if (SECITEM_CopyItem(arena, &peerKey->u.ec.publicValue, &ecPoint) !=
-        SECSuccess) {
-        goto no_memory;
+    rv = SECITEM_CopyItem(peerKey->arena, &peerKey->u.ec.publicValue, &ecPoint);
+    if (rv != SECSuccess) {
+        return SECFailure;
     }
-    peerKey->pkcs11Slot = NULL;
-    peerKey->pkcs11ID = CK_INVALID_HANDLE;
+
+    return SECSuccess;
+}
+
+const namedGroupDef *
+ssl_GetECGroupWithStrength(PRUint32 curvemsk, int requiredECCbits)
+{
+    int i;
 
-    return peerKey;
-
-no_memory: /* no-memory error has already been set. */
-    PORT_FreeArena(arena, PR_FALSE);
-    ssl_MapLowLevelError(SSL_ERROR_RX_MALFORMED_ECDHE_KEY_SHARE);
+    for (i = 0; i < ssl_named_group_count; i++) {
+        if (ssl_named_groups[i].type != group_type_ec ||
+            ssl_named_groups[i].bits < requiredECCbits) {
+            continue;
+        }
+        if ((curvemsk & (1U << i))) {
+            return &ssl_named_groups[i];
+        }
+    }
+    PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
     return NULL;
 }
 
-PK11SymKey *
-tls13_ComputeECDHSharedKey(sslSocket *ss,
-                           SECKEYPrivateKey *myPrivKey,
-                           SECKEYPublicKey *peerKey)
+/* Find the "weakest link".  Get the strength of the signature and symmetric
+ * keys and choose a curve based on the weakest of those two. */
+const namedGroupDef *
+ssl_GetECGroupForServerSocket(sslSocket *ss)
 {
-    PK11SymKey *shared;
-
-    /* Determine the PMS */
-    shared = PK11_PubDeriveWithKDF(myPrivKey, peerKey, PR_FALSE, NULL, NULL,
-                                   CKM_ECDH1_DERIVE,
-                                   tls13_GetHkdfMechanism(ss), CKA_DERIVE, 0,
-                                   CKD_NULL, NULL, NULL);
-
-    if (!shared) {
-        ssl_MapLowLevelError(SSL_ERROR_KEY_EXCHANGE_FAILURE);
-        return NULL;
-    }
-
-    return shared;
-}
-
-ECName
-ssl3_GetCurveWithECKeyStrength(PRUint32 curvemsk, int requiredECCbits)
-{
-    int i;
-
-    for (i = 0; bits2curve[i].curve != ec_noName; i++) {
-        if (bits2curve[i].bits < requiredECCbits)
-            continue;
-        if (SSL_IS_CURVE_NEGOTIATED(curvemsk, bits2curve[i].curve)) {
-            return bits2curve[i].curve;
-        }
-    }
-    PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
-    return ec_noName;
-}
-
-/* find the "weakest link".  Get strength of signature key and of sym key.
- * choose curve for the weakest of those two.
- */
-ECName
-ssl3_GetCurveNameForServerSocket(sslSocket *ss)
-{
-    ECName ec_curve = ec_noName;
     const sslServerCert *cert = ss->sec.serverCert;
     int certKeySize;
     int requiredECCbits = ss->sec.secretKeyBits * 2;
 
     PORT_Assert(cert);
     if (!cert || !cert->serverKeyPair || !cert->serverKeyPair->pubKey) {
         PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
-        return ec_noName;
+        return NULL;
     }
 
     if (cert->certType.authType == ssl_auth_rsa_sign) {
         certKeySize = SECKEY_PublicKeyStrengthInBits(cert->serverKeyPair->pubKey);
         certKeySize =
             SSL_RSASTRENGTH_TO_ECSTRENGTH(certKeySize);
     } else if (cert->certType.authType == ssl_auth_ecdsa ||
                cert->certType.authType == ssl_auth_ecdh_rsa ||
                cert->certType.authType == ssl_auth_ecdh_ecdsa) {
-        ec_curve = cert->certType.u.namedCurve;
+        const namedGroupDef *groupDef = cert->certType.namedCurve;
 
         /* We won't select a certificate unless the named curve has been
          * negotiated (or supported_curves was absent), double check that. */
-        PORT_Assert(ec_curve != ec_noName);
-        PORT_Assert(SSL_IS_CURVE_NEGOTIATED(ss->ssl3.hs.negotiatedECCurves,
-                                            ec_curve));
-        if (!SSL_IS_CURVE_NEGOTIATED(ss->ssl3.hs.negotiatedECCurves,
-                                     ec_curve)) {
-            return ec_noName;
+        PORT_Assert(groupDef->type == group_type_ec);
+        PORT_Assert(ssl_NamedGroupEnabled(ss, groupDef));
+        if (!ssl_NamedGroupEnabled(ss, groupDef)) {
+            return NULL;
         }
-        certKeySize = curve2bits[ec_curve];
+        certKeySize = groupDef->bits;
     } else {
         PORT_Assert(0);
-        return ec_noName;
+        return NULL;
     }
     if (requiredECCbits > certKeySize) {
         requiredECCbits = certKeySize;
     }
 
-    return ssl3_GetCurveWithECKeyStrength(ss->ssl3.hs.negotiatedECCurves,
-                                          requiredECCbits);
+    return ssl_GetECGroupWithStrength(ss->namedGroups, requiredECCbits);
 }
 
 /* function to clear out the lists */
 static SECStatus
-ssl3_ShutdownECDHECurves(void *appData, void *nssData)
+ssl_ShutdownECDHECurves(void *appData, void *nssData)
 {
     int i;
-    ECDHEKeyPair *keyPair = &gECDHEKeyPairs[0];
 
-    for (i = 0; i < ec_pastLastName; i++, keyPair++) {
-        if (keyPair->pair) {
-            ssl3_FreeKeyPair(keyPair->pair);
+    for (i = 0; i < PR_ARRAY_SIZE(gECDHEKeyPairs); i++) {
+        if (gECDHEKeyPairs[i].pair) {
+            ssl_FreeEphemeralKeyPair(gECDHEKeyPairs[i].pair);
         }
     }
-    memset(gECDHEKeyPairs, 0, sizeof gECDHEKeyPairs);
+    memset(gECDHEKeyPairs, 0, sizeof(gECDHEKeyPairs));
     return SECSuccess;
 }
 
 static PRStatus
-ssl3_ECRegister(void)
+ssl_ECRegister(void)
 {
     SECStatus rv;
-    rv = NSS_RegisterShutdown(ssl3_ShutdownECDHECurves, gECDHEKeyPairs);
+    PORT_Assert(PR_ARRAY_SIZE(gECDHEKeyPairs) == ssl_named_group_count);
+    rv = NSS_RegisterShutdown(ssl_ShutdownECDHECurves, gECDHEKeyPairs);
     if (rv != SECSuccess) {
-        gECDHEKeyPairs[ec_noName].error = PORT_GetError();
+        gECDHEInitError = PORT_GetError();
     }
     return (PRStatus)rv;
 }
 
 /* Create an ECDHE key pair for a given curve */
 SECStatus
-ssl3_CreateECDHEphemeralKeyPair(ECName ec_curve, ssl3KeyPair **keyPair)
+ssl_CreateECDHEphemeralKeyPair(const namedGroupDef *ecGroup,
+                               sslEphemeralKeyPair **keyPair)
 {
     SECKEYPrivateKey *privKey = NULL;
     SECKEYPublicKey *pubKey = NULL;
     SECKEYECParams ecParams = { siBuffer, NULL, 0 };
+    sslEphemeralKeyPair *pair;
 
-    if (ssl3_ECName2Params(NULL, ec_curve, &ecParams) != SECSuccess) {
+    if (ssl_NamedGroup2ECParams(NULL, ecGroup, &ecParams) != SECSuccess) {
         return SECFailure;
     }
     privKey = SECKEY_CreateECPrivateKey(&ecParams, &pubKey, NULL);
     SECITEM_FreeItem(&ecParams, PR_FALSE);
 
-    if (!privKey || !pubKey || !(*keyPair = ssl3_NewKeyPair(privKey, pubKey))) {
+    if (!privKey || !pubKey ||
+        !(pair = ssl_NewEphemeralKeyPair(ecGroup, privKey, pubKey))) {
         if (privKey) {
             SECKEY_DestroyPrivateKey(privKey);
         }
         if (pubKey) {
             SECKEY_DestroyPublicKey(pubKey);
         }
         ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL);
         return SECFailure;
     }
 
+    *keyPair = pair;
     return SECSuccess;
 }
 
 /* CallOnce function, called once for each named curve. */
 static PRStatus
-ssl3_CreateECDHEphemeralKeyPairOnce(void *arg)
+ssl_CreateECDHEphemeralKeyPairOnce(void *arg)
 {
-    ECName ec_curve = (ECName)arg;
-    ssl3KeyPair *keyPair = NULL;
+    const namedGroupDef *groupDef = (const namedGroupDef *)arg;
+    sslEphemeralKeyPair *keyPair = NULL;
+    SECStatus rv;
 
-    PORT_Assert(gECDHEKeyPairs[ec_curve].pair == NULL);
+    PORT_Assert(groupDef->type == group_type_ec);
+    PORT_Assert(gECDHEKeyPairs[groupDef->index].pair == NULL);
 
     /* ok, no one has generated a global key for this curve yet, do so */
-    if (ssl3_CreateECDHEphemeralKeyPair(ec_curve, &keyPair) != SECSuccess) {
-        gECDHEKeyPairs[ec_curve].error = PORT_GetError();
+    rv = ssl_CreateECDHEphemeralKeyPair(groupDef, &keyPair);
+    if (rv != SECSuccess) {
+        gECDHEKeyPairs[groupDef->index].error = PORT_GetError();
         return PR_FAILURE;
     }
 
-    gECDHEKeyPairs[ec_curve].pair = keyPair;
+    gECDHEKeyPairs[groupDef->index].pair = keyPair;
     return PR_SUCCESS;
 }
 
 /*
  * Creates the ephemeral public and private ECDH keys used by
  * server in ECDHE_RSA and ECDHE_ECDSA handshakes.
  * For now, the elliptic curve is chosen to be the same
  * strength as the signing certificate (ECC or RSA).
  * We need an API to specify the curve. This won't be a real
  * issue until we further develop server-side support for ECC
  * cipher suites.
  */
 static SECStatus
-ssl3_CreateECDHEphemeralKeys(sslSocket *ss, ECName ec_curve)
+ssl_CreateECDHEphemeralKeys(sslSocket *ss, const namedGroupDef *ecGroup)
 {
-    ssl3KeyPair *keyPair = NULL;
+    sslEphemeralKeyPair *keyPair = NULL;
 
     /* if there's no global key for this curve, make one. */
-    if (gECDHEKeyPairs[ec_curve].pair == NULL) {
+    if (gECDHEKeyPairs[ecGroup->index].pair == NULL) {
         PRStatus status;
 
-        status = PR_CallOnce(&gECDHEKeyPairs[ec_noName].once, ssl3_ECRegister);
+        status = PR_CallOnce(&gECDHEInitOnce, ssl_ECRegister);
         if (status != PR_SUCCESS) {
-            PORT_SetError(gECDHEKeyPairs[ec_noName].error);
+            PORT_SetError(gECDHEInitError);
             return SECFailure;
         }
-        status = PR_CallOnceWithArg(&gECDHEKeyPairs[ec_curve].once,
-                                    ssl3_CreateECDHEphemeralKeyPairOnce,
-                                    (void *)ec_curve);
+        status = PR_CallOnceWithArg(&gECDHEKeyPairs[ecGroup->index].once,
+                                    ssl_CreateECDHEphemeralKeyPairOnce,
+                                    (void *)ecGroup);
         if (status != PR_SUCCESS) {
-            PORT_SetError(gECDHEKeyPairs[ec_curve].error);
+            PORT_SetError(gECDHEKeyPairs[ecGroup->index].error);
             return SECFailure;
         }
     }
 
-    keyPair = gECDHEKeyPairs[ec_curve].pair;
+    keyPair = ssl_CopyEphemeralKeyPair(gECDHEKeyPairs[ecGroup->index].pair);
     PORT_Assert(keyPair != NULL);
     if (!keyPair)
         return SECFailure;
-    ss->ephemeralECDHKeyPair = ssl3_GetKeyPairRef(keyPair);
 
+    PORT_Assert(PR_CLIST_IS_EMPTY(&ss->ephemeralKeyPairs));
+    PR_APPEND_LINK(&keyPair->link, &ss->ephemeralKeyPairs);
     return SECSuccess;
 }
 
 SECStatus
 ssl3_HandleECDHServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
 {
     PLArenaPool *arena = NULL;
     SECKEYPublicKey *peerKey = NULL;
-    PRBool isTLS, isTLS12;
+    PRBool isTLS;
     SECStatus rv;
     int errCode = SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH;
     SSL3AlertDescription desc = illegal_parameter;
     SSL3Hashes hashes;
     SECItem signature = { siBuffer, NULL, 0 };
+    SSLHashType hashAlg = ssl_hash_none;
 
     SECItem ec_params = { siBuffer, NULL, 0 };
     SECItem ec_point = { siBuffer, NULL, 0 };
     unsigned char paramBuf[3]; /* only for curve_type == named_curve */
-    SSLSignatureAndHashAlg sigAndHash;
-
-    sigAndHash.hashAlg = ssl_hash_none;
+    const namedGroupDef *ecGroup;
 
     isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0);
-    isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
 
     ec_params.len = sizeof paramBuf;
     ec_params.data = paramBuf;
     rv = ssl3_ConsumeHandshake(ss, ec_params.data, ec_params.len, &b, &length);
     if (rv != SECSuccess) {
         goto loser; /* malformed. */
     }
 
     /* Fail if the curve is not a named curve */
-    if ((ec_params.data[0] != ec_type_named) ||
-        (ec_params.data[1] != 0) ||
-        !supportedCurve(ec_params.data[2])) {
+    if (ec_params.data[0] != ec_type_named) {
+        errCode = SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE;
+        desc = handshake_failure;
+        goto alert_loser;
+    }
+    ecGroup = ssl_LookupNamedGroup(ec_params.data[1] << 8 | ec_params.data[2]);
+    if (!ecGroup || ecGroup->type != group_type_ec) {
         errCode = SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE;
         desc = handshake_failure;
         goto alert_loser;
     }
 
     rv = ssl3_ConsumeHandshakeVariable(ss, &ec_point, 1, &b, &length);
     if (rv != SECSuccess) {
         goto loser; /* malformed. */
@@ -790,27 +652,29 @@ ssl3_HandleECDHServerKeyExchange(sslSock
 
     /* Fail if the ec point uses compressed representation. */
     if (ec_point.data[0] != EC_POINT_FORM_UNCOMPRESSED) {
         errCode = SEC_ERROR_UNSUPPORTED_EC_POINT_FORM;
         desc = handshake_failure;
         goto alert_loser;
     }
 
-    if (isTLS12) {
+    if (ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
+        SSLSignatureAndHashAlg sigAndHash;
         rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length,
                                                    &sigAndHash);
         if (rv != SECSuccess) {
             goto loser; /* malformed or unsupported. */
         }
         rv = ssl3_CheckSignatureAndHashAlgorithmConsistency(
             ss, &sigAndHash, ss->sec.peerCert);
         if (rv != SECSuccess) {
             goto loser;
         }
+        hashAlg = sigAndHash.hashAlg;
     }
 
     rv = ssl3_ConsumeHandshakeVariable(ss, &signature, 2, &b, &length);
     if (rv != SECSuccess) {
         goto loser; /* malformed. */
     }
 
     if (length != 0) {
@@ -825,17 +689,17 @@ ssl3_HandleECDHServerKeyExchange(sslSock
 
     /* failures after this point are not malformed handshakes. */
     /* TLS: send decrypt_error if signature failed. */
     desc = isTLS ? decrypt_error : handshake_failure;
 
     /*
      *  check to make sure the hash is signed by right guy
      */
-    rv = ssl3_ComputeECDHKeyHash(sigAndHash.hashAlg, ec_params, ec_point,
+    rv = ssl3_ComputeECDHKeyHash(hashAlg, ec_params, ec_point,
                                  &ss->ssl3.hs.client_random,
                                  &ss->ssl3.hs.server_random,
                                  &hashes, ss->opt.bypassPKCS11);
 
     if (rv != SECSuccess) {
         errCode =
             ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
         goto alert_loser;
@@ -845,159 +709,158 @@ ssl3_HandleECDHServerKeyExchange(sslSock
     if (rv != SECSuccess) {
         errCode =
             ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
         goto alert_loser;
     }
 
     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
     if (arena == NULL) {
-        goto no_memory;
+        errCode = SEC_ERROR_NO_MEMORY;
+        goto loser;
     }
 
     peerKey = PORT_ArenaZNew(arena, SECKEYPublicKey);
     if (peerKey == NULL) {
-        goto no_memory;
+        errCode = SEC_ERROR_NO_MEMORY;
+        goto loser;
     }
 
     peerKey->arena = arena;
     peerKey->keyType = ecKey;
 
     /* set up EC parameters in peerKey */
-    if (ssl3_ECName2Params(arena, ec_params.data[2],
-                           &peerKey->u.ec.DEREncodedParams) !=
-        SECSuccess) {
+    rv = ssl_NamedGroup2ECParams(arena, ecGroup,
+                                 &peerKey->u.ec.DEREncodedParams);
+    if (rv != SECSuccess) {
         /* we should never get here since we already
          * checked that we are dealing with a supported curve
          */
         errCode = SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE;
         goto alert_loser;
     }
 
     /* copy publicValue in peerKey */
     if (SECITEM_CopyItem(arena, &peerKey->u.ec.publicValue, &ec_point)) {
-        goto no_memory;
+        errCode = SEC_ERROR_NO_MEMORY;
+        goto loser;
     }
     peerKey->pkcs11Slot = NULL;
     peerKey->pkcs11ID = CK_INVALID_HANDLE;
 
     ss->sec.peerKey = peerKey;
-    ss->ssl3.hs.ws = wait_cert_request;
-
     return SECSuccess;
 
 alert_loser:
     (void)SSL3_SendAlert(ss, alert_fatal, desc);
 loser:
     if (arena) {
         PORT_FreeArena(arena, PR_FALSE);
     }
     PORT_SetError(errCode);
     return SECFailure;
-
-no_memory: /* no-memory error has already been set. */
-    if (arena) {
-        PORT_FreeArena(arena, PR_FALSE);
-    }
-    ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
-    return SECFailure;
 }
 
 SECStatus
 ssl3_SendECDHServerKeyExchange(
     sslSocket *ss,
     const SSLSignatureAndHashAlg *sigAndHash)
 {
     SECStatus rv = SECFailure;
     int length;
     PRBool isTLS, isTLS12;
     SECItem signed_hash = { siBuffer, NULL, 0 };
     SSL3Hashes hashes;
 
-    SECKEYPublicKey *ecdhePub;
     SECItem ec_params = { siBuffer, NULL, 0 };
     unsigned char paramBuf[3];
-    ECName curve;
-    ssl3KeyPair *keyPair;
+    const namedGroupDef *ecGroup;
+    sslEphemeralKeyPair *keyPair;
+    SECKEYPublicKey *pubKey;
 
     /* Generate ephemeral ECDH key pair and send the public key */
-    curve = ssl3_GetCurveNameForServerSocket(ss);
-    if (curve == ec_noName) {
+    ecGroup = ssl_GetECGroupForServerSocket(ss);
+    if (!ecGroup) {
         goto loser;
     }
 
+    PORT_Assert(PR_CLIST_IS_EMPTY(&ss->ephemeralKeyPairs));
     if (ss->opt.reuseServerECDHEKey) {
-        rv = ssl3_CreateECDHEphemeralKeys(ss, curve);
+        rv = ssl_CreateECDHEphemeralKeys(ss, ecGroup);
+        if (rv != SECSuccess) {
+            goto loser;
+        }
+        keyPair = (sslEphemeralKeyPair *)PR_NEXT_LINK(&ss->ephemeralKeyPairs);
     } else {
-        rv = ssl3_CreateECDHEphemeralKeyPair(curve, &ss->ephemeralECDHKeyPair);
+        rv = ssl_CreateECDHEphemeralKeyPair(ecGroup, &keyPair);
+        if (rv != SECSuccess) {
+            goto loser;
+        }
+        PR_APPEND_LINK(&keyPair->link, &ss->ephemeralKeyPairs);
     }
     if (rv != SECSuccess) {
         goto loser;
     }
 
-    ecdhePub = ss->ephemeralECDHKeyPair->pubKey;
-    PORT_Assert(ecdhePub != NULL);
-    if (!ecdhePub) {
+    PORT_Assert(keyPair);
+    if (!keyPair) {
         PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
         return SECFailure;
     }
 
-    ec_params.len = sizeof paramBuf;
+    ec_params.len = sizeof(paramBuf);
     ec_params.data = paramBuf;
-    curve = ssl3_PubKey2ECName(ecdhePub);
-    if (curve != ec_noName) {
-        ec_params.data[0] = ec_type_named;
-        ec_params.data[1] = 0x00;
-        ec_params.data[2] = curve;
-    } else {
-        PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
-        goto loser;
-    }
+    PORT_Assert(keyPair->group);
+    PORT_Assert(keyPair->group->type == group_type_ec);
+    ec_params.data[0] = ec_type_named;
+    ec_params.data[1] = keyPair->group->name >> 8;
+    ec_params.data[2] = keyPair->group->name & 0xff;
 
+    pubKey = keyPair->keys->pubKey;
     rv = ssl3_ComputeECDHKeyHash(sigAndHash->hashAlg,
                                  ec_params,
-                                 ecdhePub->u.ec.publicValue,
+                                 pubKey->u.ec.publicValue,
                                  &ss->ssl3.hs.client_random,
                                  &ss->ssl3.hs.server_random,
                                  &hashes, ss->opt.bypassPKCS11);
     if (rv != SECSuccess) {
         ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
         goto loser;
     }
 
     isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0);
     isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
 
-    keyPair = ss->sec.serverCert->serverKeyPair;
-    rv = ssl3_SignHashes(&hashes, keyPair->privKey, &signed_hash, isTLS);
+    rv = ssl3_SignHashes(&hashes, ss->sec.serverCert->serverKeyPair->privKey,
+                         &signed_hash, isTLS);
     if (rv != SECSuccess) {
         goto loser; /* ssl3_SignHashes has set err. */
     }
     if (signed_hash.data == NULL) {
         /* how can this happen and rv == SECSuccess ?? */
         PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
         goto loser;
     }
 
     length = ec_params.len +
-             1 + ecdhePub->u.ec.publicValue.len +
+             1 + pubKey->u.ec.publicValue.len +
              (isTLS12 ? 2 : 0) + 2 + signed_hash.len;
 
     rv = ssl3_AppendHandshakeHeader(ss, server_key_exchange, length);
     if (rv != SECSuccess) {
         goto loser; /* err set by AppendHandshake. */
     }
 
     rv = ssl3_AppendHandshake(ss, ec_params.data, ec_params.len);
     if (rv != SECSuccess) {
         goto loser; /* err set by AppendHandshake. */
     }
 
-    rv = ssl3_AppendHandshakeVariable(ss, ecdhePub->u.ec.publicValue.data,
-                                      ecdhePub->u.ec.publicValue.len, 1);
+    rv = ssl3_AppendHandshakeVariable(ss, pubKey->u.ec.publicValue.data,
+                                      pubKey->u.ec.publicValue.len, 1);
     if (rv != SECSuccess) {
         goto loser; /* err set by AppendHandshake. */
     }
 
     if (isTLS12) {
         rv = ssl3_AppendSignatureAndHashAlgorithm(ss, sigAndHash);
         if (rv != SECSuccess) {
             goto loser; /* err set by AppendHandshake. */
@@ -1014,66 +877,18 @@ ssl3_SendECDHServerKeyExchange(
     return SECSuccess;
 
 loser:
     if (signed_hash.data != NULL)
         PORT_Free(signed_hash.data);
     return SECFailure;
 }
 
-/* Lists of ECC cipher suites for searching and disabling. */
-
-static const ssl3CipherSuite ecdh_ecdsa_suites[] = {
-    TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
-    TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
-    TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
-    TLS_ECDH_ECDSA_WITH_NULL_SHA,
-    TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
-    0 /* end of list marker */
-};
-
-static const ssl3CipherSuite ecdh_rsa_suites[] = {
-    TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
-    TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
-    TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
-    TLS_ECDH_RSA_WITH_NULL_SHA,
-    TLS_ECDH_RSA_WITH_RC4_128_SHA,
-    0 /* end of list marker */
-};
-
-static const ssl3CipherSuite ecdhe_ecdsa_suites[] = {
-    TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
-    TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
-    TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
-    TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
-    TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
-    TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
-    TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
-    TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
-    TLS_ECDHE_ECDSA_WITH_NULL_SHA,
-    TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
-    0 /* end of list marker */
-};
-
-static const ssl3CipherSuite ecdhe_rsa_suites[] = {
-    TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
-    TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
-    TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
-    TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
-    TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
-    TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
-    TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
-    TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
-    TLS_ECDHE_RSA_WITH_NULL_SHA,
-    TLS_ECDHE_RSA_WITH_RC4_128_SHA,
-    0 /* end of list marker */
-};
-
 /* List of all ECC cipher suites */
-static const ssl3CipherSuite ecSuites[] = {
+static const ssl3CipherSuite ssl_all_ec_suites[] = {
     TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
     TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
     TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
     TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
     TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
     TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
     TLS_ECDHE_ECDSA_WITH_NULL_SHA,
     TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
@@ -1097,251 +912,197 @@ static const ssl3CipherSuite ecSuites[] 
     TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
     TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
     TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
     TLS_ECDH_RSA_WITH_NULL_SHA,
     TLS_ECDH_RSA_WITH_RC4_128_SHA,
     0 /* end of list marker */
 };
 
-/* On this socket, Disable the ECC cipher suites in the argument's list */
-SECStatus
-ssl3_DisableECCSuites(sslSocket *ss, const ssl3CipherSuite *suite)
-{
-    if (!suite)
-        suite = ecSuites;
-    for (; *suite; ++suite) {
-        PORT_CheckSuccess(ssl3_CipherPrefSet(ss, *suite, PR_FALSE));
-    }
-    return SECSuccess;
-}
-
-static PRBool
-ssl_HasCertOfAuthType(sslSocket *ss, SSLAuthType authType)
-{
-    const sslServerCert *sc;
-
-    sc = ssl_FindServerCertByAuthType(ss, authType);
-    return sc && sc->serverCert;
-}
+static const ssl3CipherSuite ssl_dhe_suites[] = {
+    TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
+    TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
+    TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
+    TLS_DHE_DSS_WITH_AES_128_GCM_SHA256,
+    TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+    TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
+    TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
+    TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,
+    TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,
+    TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA,
+    TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
+    TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
+    TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
+    TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
+    TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA,
+    TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA,
+    TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
+    TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
+    TLS_DHE_DSS_WITH_RC4_128_SHA,
+    TLS_DHE_RSA_WITH_DES_CBC_SHA,
+    TLS_DHE_DSS_WITH_DES_CBC_SHA,
+    0
+};
 
-/* Look at the server certs configured on this socket, and disable any
- * ECC cipher suites that are not supported by those certs.
- *
- * libssl generally supports multiple ECDH certificates.  However,
- * this function will only filter based on the first of those certificates.
- */
-void
-ssl3_FilterECCipherSuitesByServerCerts(sslSocket *ss)
+/* Order(N^2).  Yuk. */
+static PRBool
+ssl_IsSuiteEnabled(sslSocket *ss, const ssl3CipherSuite *list)
 {
-    if (!ssl_HasCertOfAuthType(ss, ssl_auth_rsa_sign)) {
-        ssl3_DisableECCSuites(ss, ecdhe_rsa_suites);
+    const ssl3CipherSuite *suite;
+
+    for (suite = list; *suite; ++suite) {
+        PRBool enabled = PR_FALSE;
+        SECStatus rv = ssl3_CipherPrefGet(ss, *suite, &enabled);
+
+        PORT_Assert(rv == SECSuccess); /* else is coding error */
+        if (rv == SECSuccess && enabled)
+            return PR_TRUE;
     }
-
-    if (!ssl_HasCertOfAuthType(ss, ssl_auth_ecdsa)) {
-        ssl3_DisableECCSuites(ss, ecdhe_ecdsa_suites);
-    }
-
-    if (!ssl_HasCertOfAuthType(ss, ssl_auth_ecdh_rsa)) {
-        ssl3_DisableECCSuites(ss, ecdh_rsa_suites);
-    }
-
-    if (!ssl_HasCertOfAuthType(ss, ssl_auth_ecdh_ecdsa)) {
-        ssl3_DisableECCSuites(ss, ecdh_ecdsa_suites);
-    }
+    return PR_FALSE;
 }
 
 /* Ask: is ANY ECC cipher suite enabled on this socket? */
-/* Order(N^2).  Yuk.  Also, this ignores export policy. */
-PRBool
-ssl3_IsECCEnabled(sslSocket *ss)
+static PRBool
+ssl_IsECCEnabled(sslSocket *ss)
 {
-    const ssl3CipherSuite *suite;
     PK11SlotInfo *slot;
 
     /* make sure we can do ECC */
     slot = PK11_GetBestSlot(CKM_ECDH1_DERIVE, ss->pkcs11PinArg);
     if (!slot) {
         return PR_FALSE;
     }
     PK11_FreeSlot(slot);
 
     /* make sure an ECC cipher is enabled */
-    for (suite = ecSuites; *suite; ++suite) {
-        PRBool enabled = PR_FALSE;
-        SECStatus rv = ssl3_CipherPrefGet(ss, *suite, &enabled);
-
-        PORT_Assert(rv == SECSuccess); /* else is coding error */
-        if (rv == SECSuccess && enabled)
-            return PR_TRUE;
-    }
-    return PR_FALSE;
+    return ssl_IsSuiteEnabled(ss, ssl_all_ec_suites);
 }
 
-/* Prefabricated TLS client hello extension, Elliptic Curves List,
- * offers only 3 curves, the Suite B curves, 23-25
- */
-static const PRUint8 suiteBECList[] = {
-    23, 24, 25
-};
-
-/* Prefabricated TLS client hello extension, Elliptic Curves List,
- * offers curves 1-25.
- */
-/* clang-format off */
-static const PRUint8 tlsECList[] = {
-     1,  2,  3,  4,  5,  6,  7,  8,
-     9, 10, 11, 12, 13, 14, 15, 16,
-    17, 18, 19, 20, 21, 22, 23, 24,
-    25
-};
-/* clang-format on */
-
-/* This function already presumes we can do ECC, ssl3_IsECCEnabled must be
+/* This function already presumes we can do ECC, ssl_IsECCEnabled must be
  * called before this function. It looks to see if we have a token which
  * is capable of doing smaller than SuiteB curves. If the token can, we
  * presume the token can do the whole SSL suite of curves. If it can't we
  * presume the token that allowed ECC to be enabled can only do suite B
  * curves. */
-static PRBool
-ssl3_SuiteBOnly(sslSocket *ss)
+PRBool
+ssl_SuiteBOnly(sslSocket *ss)
 {
     /* See if we can support small curves (like 163). If not, assume we can
      * only support Suite-B curves (P-256, P-384, P-521). */
     PK11SlotInfo *slot =
         PK11_GetBestSlotWithAttributes(CKM_ECDH1_DERIVE, 0, 163,
                                        ss ? ss->pkcs11PinArg : NULL);
 
     if (!slot) {
         /* nope, presume we can only do suite B */
         return PR_TRUE;
     }
     /* we can, presume we can do all curves */
     PK11_FreeSlot(slot);
     return PR_FALSE;
 }
 
-#define APPEND_CURVE(CURVE_ID)                                       \
-    if ((NSS_GetAlgorithmPolicy(ecName2OIDTag[CURVE_ID], &policy) == \
-         SECFailure) ||                                              \
-        (policy & NSS_USE_ALG_IN_SSL_KX)) {                          \
-        enabledCurves[pos++] = 0;                                    \
-        enabledCurves[pos++] = CURVE_ID;                             \
+/* Send our Supported Groups extension. */
+PRInt32
+ssl_SendSupportedGroupsXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes)
+{
+    PRInt32 extension_length;
+    unsigned char enabledGroups[64];
+    unsigned int enabledGroupsLen = 0;
+    unsigned int i;
+    PRBool ec;
+    PRBool ff = PR_FALSE;
+
+    if (!ss)
+        return 0;
+
+    ec = ssl_IsECCEnabled(ss);
+    /* We only send FF supported groups if we require DH named groups or if TLS
+     * 1.3 is a possibility. */
+    if (ss->opt.requireDHENamedGroups ||
+        ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3) {
+        ff = ssl_IsSuiteEnabled(ss, ssl_dhe_suites);
+    }
+    if (!ec && !ff) {
+        return 0;
     }
 
-/* Send our "canned" (precompiled) Supported Elliptic Curves extension,
- * which says that we support all TLS-defined named curves.
- */
-PRInt32
-ssl3_SendSupportedCurvesXtn(
-    sslSocket *ss,
-    PRBool append,
-    PRUint32 maxBytes)
-{
-    unsigned char enabledCurves[64];
-    PRUint32 policy;
-    PRInt32 extension_length;
-    PRInt32 ecListSize = 0;
-    unsigned int pos = 0;
-    unsigned int i;
+    PORT_Assert(sizeof(enabledGroups) > ssl_named_group_count * 2);
+    for (i = 0; i < ssl_named_group_count; ++i) {
+        if (ssl_named_groups[i].type == group_type_ec && !ec) {
+            continue;
+        }
+        if (ssl_named_groups[i].type == group_type_ff && !ff) {
+            continue;
+        }
+        if (!ssl_NamedGroupEnabled(ss, &ssl_named_groups[i])) {
+            continue;
+        }
 
-    if (!ss || !ssl3_IsECCEnabled(ss))
-        return 0;
-
-    PORT_Assert(sizeof(enabledCurves) > sizeof(tlsECList) * 2);
-    if (ssl3_SuiteBOnly(ss)) {
-        for (i = 0; i < sizeof(suiteBECList); i++) {
-            APPEND_CURVE(suiteBECList[i]);
+        if (append) {
+            enabledGroups[enabledGroupsLen++] = ssl_named_groups[i].name >> 8;
+            enabledGroups[enabledGroupsLen++] = ssl_named_groups[i].name & 0xff;
+        } else {
+            enabledGroupsLen += 2;
         }
-        ecListSize = pos;
-    } else {
-        for (i = 0; i < sizeof(tlsECList); i++) {
-            APPEND_CURVE(tlsECList[i]);
-        }
-        ecListSize = pos;
     }
+
     extension_length =
         2 /* extension type */ +
         2 /* extension length */ +
-        2 /* elliptic curves length */ +
-        ecListSize;
+        2 /* enabled groups length */ +
+        enabledGroupsLen;
 
     if (maxBytes < (PRUint32)extension_length) {
         return 0;
     }
 
     if (append) {
         SECStatus rv;
-        rv = ssl3_AppendHandshakeNumber(ss, ssl_elliptic_curves_xtn, 2);
+        rv = ssl3_AppendHandshakeNumber(ss, ssl_supported_groups_xtn, 2);
         if (rv != SECSuccess)
             return -1;
         rv = ssl3_AppendHandshakeNumber(ss, extension_length - 4, 2);
         if (rv != SECSuccess)
             return -1;
-        rv = ssl3_AppendHandshakeVariable(ss, enabledCurves, ecListSize, 2);
+        rv = ssl3_AppendHandshakeVariable(ss, enabledGroups,
+                                          enabledGroupsLen, 2);
         if (rv != SECSuccess)
             return -1;
         if (!ss->sec.isServer) {
             TLSExtensionData *xtnData = &ss->xtnData;
             xtnData->advertised[xtnData->numAdvertised++] =
-                ssl_elliptic_curves_xtn;
+                ssl_supported_groups_xtn;
         }
     }
     return extension_length;
 }
 
-PRUint32
-ssl3_GetSupportedECCurveMask(sslSocket *ss)
-{
-    int i;
-    PRUint32 curves = 0;
-    PRUint32 policyFlags = 0;
-
-    PORT_Assert(ec_pastLastName < sizeof(PRUint32) * 8);
-
-    if (ssl3_SuiteBOnly(ss)) {
-        curves = SSL3_SUITE_B_SUPPORTED_CURVES_MASK;
-    } else {
-        curves = SSL3_ALL_SUPPORTED_CURVES_MASK;
-    }
-
-    for (i = ec_noName + 1; i < ec_pastLastName; i++) {
-        PRUint32 curve_bit = (1U << i);
-        if ((curves & curve_bit) &&
-            (NSS_GetAlgorithmPolicy(ecName2OIDTag[i], &policyFlags) ==
-             SECSuccess) &&
-            !(policyFlags & NSS_USE_ALG_IN_SSL_KX)) {
-            curves &= ~curve_bit;
-        }
-    }
-    return curves;
-}
-
 /* Send our "canned" (precompiled) Supported Point Formats extension,
  * which says that we only support uncompressed points.
  */
 PRInt32
 ssl3_SendSupportedPointFormatsXtn(
     sslSocket *ss,
     PRBool append,
     PRUint32 maxBytes)
 {
     static const PRUint8 ecPtFmt[6] = {
         0, 11, /* Extension type */
         0, 2,  /* octets that follow */
         1,     /* octets that follow */
         0      /* uncompressed type only */
     };
 
-    /* No point in doing this unless we have a socket that supports ECC.  Also,
-     * no point if we aren't going to do TLS 1.3 only (client) or we have
-     * already picked TLS 1.3.  TLS 1.3 doesn't use point formats. */
-    if (!ss || !ssl3_IsECCEnabled(ss) ||
-        (ss->sec.isServer && ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) ||
-        (!ss->sec.isServer && ss->vrange.min >= SSL_LIBRARY_VERSION_TLS_1_3))
+    /* No point in doing this unless we have a socket that supports ECC.
+     * Similarly, no point if we are going to do TLS 1.3 only or we have already
+     * picked TLS 1.3 (server) given that it doesn't use point formats. */
+    if (!ss || !ssl_IsECCEnabled(ss) ||
+        ss->vrange.min >= SSL_LIBRARY_VERSION_TLS_1_3 ||
+        (ss->sec.isServer && ss->version >= SSL_LIBRARY_VERSION_TLS_1_3))
         return 0;
     if (append && maxBytes >= (sizeof ecPtFmt)) {
         SECStatus rv = ssl3_AppendHandshake(ss, ecPtFmt, (sizeof ecPtFmt));
         if (rv != SECSuccess)
             return -1;
         if (!ss->sec.isServer) {
             TLSExtensionData *xtnData = &ss->xtnData;
             xtnData->advertised[xtnData->numAdvertised++] =
@@ -1369,91 +1130,93 @@ ssl3_HandleSupportedPointFormatsXtn(sslS
             /* indicate that we should send a reply */
             SECStatus rv;
             rv = ssl3_RegisterServerHelloExtensionSender(ss, ex_type,
                                                          &ssl3_SendSupportedPointFormatsXtn);
             return rv;
         }
     }
 
-    /* evil client doesn't support uncompressed */
-    ssl3_DisableECCSuites(ss, ecSuites);
-    return SECSuccess;
+    /* Poor client doesn't support uncompressed points. */
+    PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE);
+    return SECFailure;
 }
 
-/* Ensure that the curve in our server cert is one of the ones supported
- * by the remote client, and disable all ECC cipher suites if not.
- */
-SECStatus
-ssl3_HandleSupportedCurvesXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data)
+static SECStatus
+ssl_UpdateSupportedGroups(sslSocket *ss, SECItem *data)
 {
     PRInt32 list_len;
-    PRUint32 peerCurves = 0;
-    PRUint32 mutualCurves = 0;
-    PRCList *cursor;
-    PRBool foundECDH_RSA = PR_FALSE;
-    PRBool foundECDH_ECDSA = PR_FALSE;
-    PRBool foundECDSA = PR_FALSE;
+    PRUint32 peerGroups = 0;
 
     if (!data->data || data->len < 4) {
         (void)ssl3_DecodeError(ss);
         return SECFailure;
     }
 
     /* get the length of elliptic_curve_list */
     list_len = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
     if (list_len < 0 || data->len != list_len || (data->len % 2) != 0) {
         (void)ssl3_DecodeError(ss);
         return SECFailure;
     }
-    /* build bit vector of peer's supported curve names */
+
+    /* build bit vector of peer's supported groups */
     while (data->len) {
+        const namedGroupDef *group;
         PRInt32 curve_name =
             ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
         if (curve_name < 0) {
             return SECFailure; /* fatal alert already sent */
         }
-        if (curve_name > ec_noName && curve_name < ec_pastLastName) {
-            peerCurves |= (1U << curve_name);
+        group = ssl_LookupNamedGroup(curve_name);
+        if (group) {
+            peerGroups |= (1U << group->index);
+        }
+
+        /* "Codepoints in the NamedCurve registry with a high byte of 0x01 (that
+         * is, between 256 and 511 inclusive) are set aside for FFDHE groups,"
+         * -- https://tools.ietf.org/html/draft-ietf-tls-negotiated-ff-dhe-10
+         */
+        if ((curve_name & 0xff00) == 0x0100) {
+            ss->ssl3.hs.peerSupportsFfdheGroups = PR_TRUE;
         }
     }
-    /* What curves do we support in common? */
-    mutualCurves = ss->ssl3.hs.negotiatedECCurves &= peerCurves;
-    if (!mutualCurves) {
-        /* no mutually supported EC Curves, disable ECC */
-        ssl3_DisableECCSuites(ss, ecSuites);
-        return SECSuccess;
+    /* Note: if ss->opt.requireDHENamedGroups is set, we disable DHE cipher
+     * suites, but we do that in ssl3_config_match(). */
+    if (!ss->opt.requireDHENamedGroups && !ss->ssl3.hs.peerSupportsFfdheGroups) {
+        /* If we don't require that DHE use named groups, and no FFDHE was
+         * included, we pretend that they support all the FFDHE groups we do. */
+        unsigned int i;
+        for (i = 0; i < ssl_named_group_count; ++i) {
+            if (ssl_named_groups[i].type == group_type_ff) {
+                peerGroups |= (1U << ssl_named_groups[i].index);
+            }
+        }
     }
 
-    /* if we don't have a cert with one of these curves,
-     * disable ECC cipher suites that require an ECC cert.
-     */
-    for (cursor = PR_NEXT_LINK(&ss->serverCerts);
-         cursor != &ss->serverCerts;
-         cursor = PR_NEXT_LINK(cursor)) {
-        sslServerCert *cert = (sslServerCert *)cursor;
-        if (cert->certType.authType == ssl_auth_ecdh_rsa &&
-            (mutualCurves & (1U << cert->certType.u.namedCurve))) {
-            foundECDH_RSA = PR_TRUE;
-        }
-        if (cert->certType.authType == ssl_auth_ecdh_ecdsa &&
-            (mutualCurves & (1U << cert->certType.u.namedCurve))) {
-            foundECDH_ECDSA = PR_TRUE;
-        }
-        if (cert->certType.authType == ssl_auth_ecdsa &&
-            (mutualCurves & (1U << cert->certType.u.namedCurve))) {
-            foundECDSA = PR_TRUE;
+    /* What curves do we support in common? */
+    ss->namedGroups &= peerGroups;
+    return SECSuccess;
+}
+
+/* Ensure that the curve in our server cert is one of the ones supported
+ * by the remote client, and disable all ECC cipher suites if not.
+ */
+SECStatus
+ssl_HandleSupportedGroupsXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data)
+{
+    SECStatus rv;
+
+    rv = ssl_UpdateSupportedGroups(ss, data);
+    if (rv != SECSuccess)
+        return SECFailure;
+
+    /* TLS 1.3 permits the server to send this extension so make it so. */
+    if (ss->sec.isServer && ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
+        rv = ssl3_RegisterServerHelloExtensionSender(ss, ex_type,
+                                                     &ssl_SendSupportedGroupsXtn);
+        if (rv != SECSuccess) {
+            return SECFailure; /* error already set. */
         }
     }
-    /* Our EC cert doesn't contain a mutually supported curve.
-     * Disable the affected cipher suites.
-     */
-    if (!foundECDH_RSA) {
-        ssl3_DisableECCSuites(ss, ecdh_rsa_suites);
-    }
-    if (!foundECDH_ECDSA) {
-        ssl3_DisableECCSuites(ss, ecdh_ecdsa_suites);
-    }
-    if (!foundECDSA) {
-        ssl3_DisableECCSuites(ss, ecdhe_ecdsa_suites);
-    }
+
     return SECSuccess;
 }
--- a/security/nss/lib/ssl/ssl3ext.c
+++ b/security/nss/lib/ssl/ssl3ext.c
@@ -284,17 +284,17 @@ ssl3_GetSessionTicketKeys(const unsigned
 
 /* Table of handlers for received TLS hello extensions, one per extension.
  * In the second generation, this table will be dynamic, and functions
  * will be registered here.
  */
 /* This table is used by the server, to handle client hello extensions. */
 static const ssl3HelloExtensionHandler clientHelloHandlers[] = {
     { ssl_server_name_xtn, &ssl3_HandleServerNameXtn },
-    { ssl_elliptic_curves_xtn, &ssl3_HandleSupportedCurvesXtn },
+    { ssl_supported_groups_xtn, &ssl_HandleSupportedGroupsXtn },
     { ssl_ec_point_formats_xtn, &ssl3_HandleSupportedPointFormatsXtn },
     { ssl_session_ticket_xtn, &ssl3_ServerHandleSessionTicketXtn },
     { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn },
     { ssl_next_proto_nego_xtn, &ssl3_ServerHandleNextProtoNegoXtn },
     { ssl_app_layer_protocol_xtn, &ssl3_ServerHandleAppProtoXtn },
     { ssl_use_srtp_xtn, &ssl3_ServerHandleUseSRTPXtn },
     { ssl_cert_status_xtn, &ssl3_ServerHandleStatusRequestXtn },
     { ssl_signature_algorithms_xtn, &ssl3_ServerHandleSigAlgsXtn },
@@ -339,17 +339,17 @@ static const ssl3HelloExtensionHandler s
  * the client hello is empty (for example, the extended master secret
  * extension, if it were listed last). See bug 1243641.
  */
 static const ssl3HelloExtensionSender clientHelloSendersTLS[SSL_MAX_EXTENSIONS] =
     {
       { ssl_server_name_xtn, &ssl3_SendServerNameXtn },
       { ssl_extended_master_secret_xtn, &ssl3_SendExtendedMasterSecretXtn },
       { ssl_renegotiation_info_xtn, &ssl3_SendRenegotiationInfoXtn },
-      { ssl_elliptic_curves_xtn, &ssl3_SendSupportedCurvesXtn },
+      { ssl_supported_groups_xtn, &ssl_SendSupportedGroupsXtn },
       { ssl_ec_point_formats_xtn, &ssl3_SendSupportedPointFormatsXtn },
       { ssl_session_ticket_xtn, &ssl3_SendSessionTicketXtn },
       { ssl_next_proto_nego_xtn, &ssl3_ClientSendNextProtoNegoXtn },
       { ssl_app_layer_protocol_xtn, &ssl3_ClientSendAppProtoXtn },
       { ssl_use_srtp_xtn, &ssl3_ClientSendUseSRTPXtn },
       { ssl_cert_status_xtn, &ssl3_ClientSendStatusRequestXtn },
       { ssl_tls13_draft_version_xtn, &ssl3_ClientSendDraftVersionXtn },
       { ssl_signed_cert_timestamp_xtn, &ssl3_ClientSendSignedCertTimestampXtn },
@@ -1172,16 +1172,17 @@ ssl3_SendNewSessionTicket(sslSocket *ss)
     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 = ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 ? ss->ssl3.cwSpec : ss->ssl3.pwSpec;
+    const sslServerCertType *certType;
 
     SSL_TRC(3, ("%d: SSL3[%d]: send session_ticket handshake",
                 SSL_GETPID(), ss->fd));
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
     ticket.ticket_lifetime_hint = TLS_EX_SESS_TICKET_LIFETIME_HINT;
@@ -1309,26 +1310,29 @@ ssl3_SendNewSessionTicket(sslSocket *ss)
         goto loser;
     rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.keaType, 1);
     if (rv != SECSuccess)
         goto loser;
     rv = ssl3_AppendNumberToItem(&plaintext, ss->sec.keaKeyBits, 4);
     if (rv != SECSuccess)
         goto loser;
 
-    /* certificate slot */
-    PORT_Assert(ss->sec.serverCert->certType.authType == ss->sec.authType);
+    /* certificate type */
+    certType = &ss->sec.serverCert->certType;
+    PORT_Assert(certType->authType == ss->sec.authType);
     switch (ss->sec.authType) {
         case ssl_auth_ecdsa:
         case ssl_auth_ecdh_rsa:
         case ssl_auth_ecdh_ecdsa:
-            /* Too many curves and we will need two bytes here. */
-            PORT_Assert(ec_pastLastName < 256);
+            PORT_Assert(certType->namedCurve);
+            PORT_Assert(certType->namedCurve->type == group_type_ec);
+            /* EC curves only use the second of the two bytes. */
+            PORT_Assert(certType->namedCurve->name < 256);
             rv = ssl3_AppendNumberToItem(&plaintext,
-                                         ss->sec.serverCert->certType.u.namedCurve, 1);
+                                         certType->namedCurve->name, 1);
             break;
         default:
             rv = ssl3_AppendNumberToItem(&plaintext, 0, 1);
             break;
     }
     if (rv != SECSuccess)
         goto loser;
 
@@ -1826,17 +1830,22 @@ ssl3_ProcessSessionTicketCommon(sslSocke
     parsed_session_ticket->certType.authType = parsed_session_ticket->authType;
     temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
     if (temp < 0)
         goto no_ticket;
     switch (parsed_session_ticket->authType) {
         case ssl_auth_ecdsa:
         case ssl_auth_ecdh_rsa:
         case ssl_auth_ecdh_ecdsa:
-            parsed_session_ticket->certType.u.namedCurve = (ECName)temp;
+            parsed_session_ticket->certType.namedCurve =
+                ssl_LookupNamedGroup((NamedGroup)temp);
+            if (!parsed_session_ticket->certType.namedCurve ||
+                parsed_session_ticket->certType.namedCurve->type != group_type_ec) {
+                goto no_ticket;
+            }
             break;
         default:
             break;
     }
 
     /* Read wrapped master_secret. */
     temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
     if (temp < 0)
@@ -3049,123 +3058,171 @@ ssl3_ServerHandleSignedCertTimestampXtn(
  *         select (role) {
  *             case client:
  *                 KeyShareEntry client_shares<4..2^16-1>;
  *
  *             case server:
  *                 KeyShareEntry server_share;
  *         }
  *     } KeyShare;
+ *
+ * DH is Section 6.3.2.3.1.
+ *
+ *     opaque dh_Y<1..2^16-1>;
+ *
+ * ECDH is Section 6.3.2.3.2.
+ *
+ *     opaque point <1..2^8-1>;
  */
-static SECStatus
-tls13_SizeOfKeyShareEntry(ssl3KeyPair *pair)
+static PRUint32
+tls13_SizeOfKeyShareEntry(const SECKEYPublicKey *pubKey)
 {
-    return 2 + 2 + tls13_SizeOfECDHEKeyShareKEX(pair);
+    /* Size = NamedGroup(2) + length(2) + opaque<?> share */
+    switch (pubKey->keyType) {
+        case ecKey:
+            return 2 + 2 + tls13_SizeOfECDHEKeyShareKEX(pubKey);
+        case dhKey:
+            return 2 + 2 + 2 + pubKey->u.dh.prime.len;
+        default:
+            PORT_Assert(0);
+    }
+    return 0;
+}
+
+static PRUint32
+tls13_SizeOfClientKeyShareExtension(sslSocket *ss)
+{
+    PRCList *cursor;
+    /* Size is: extension(2) + extension_len(2) + client_shares(2) */
+    PRUint32 size = 2 + 2 + 2;
+    for (cursor = PR_NEXT_LINK(&ss->ephemeralKeyPairs);
+         cursor != &ss->ephemeralKeyPairs;
+         cursor = PR_NEXT_LINK(cursor)) {
+        sslEphemeralKeyPair *keyPair = (sslEphemeralKeyPair *)cursor;
+        size += tls13_SizeOfKeyShareEntry(keyPair->keys->pubKey);
+    }
+    return size;
 }
 
 static SECStatus
-tls13_EncodeKeyShareEntry(sslSocket *ss, ssl3KeyPair *pair)
+tls13_EncodeKeyShareEntry(sslSocket *ss, const sslEphemeralKeyPair *keyPair)
 {
     SECStatus rv;
-
-    /* This currently only works for ECC keys */
-    PORT_Assert(pair->pubKey->keyType == ecKey);
-    if (pair->pubKey->keyType != ecKey) {
-        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-        return SECFailure;
-    }
-
-    rv = ssl3_AppendHandshakeNumber(ss, tls13_GroupForECDHEKeyShare(pair), 2);
+    SECKEYPublicKey *pubKey = keyPair->keys->pubKey;
+    unsigned int size = tls13_SizeOfKeyShareEntry(pubKey);
+
+    rv = ssl3_AppendHandshakeNumber(ss, keyPair->group->name, 2);
+    if (rv != SECSuccess)
+        return rv;
+    rv = ssl3_AppendHandshakeNumber(ss, size - 4, 2);
     if (rv != SECSuccess)
         return rv;
 
-    rv = ssl3_AppendHandshakeNumber(ss, tls13_SizeOfECDHEKeyShareKEX(pair), 2);
-    if (rv != SECSuccess)
-        return rv;
-
-    rv = tls13_EncodeECDHEKeyShareKEX(ss, pair);
-    if (rv != SECSuccess)
-        return rv;
-
-    return SECSuccess;
+    switch (pubKey->keyType) {
+        case ecKey:
+            rv = tls13_EncodeECDHEKeyShareKEX(ss, pubKey);
+            break;
+        case dhKey:
+            rv = ssl_AppendPaddedDHKeyShare(ss, pubKey);
+            break;
+        default:
+            PORT_Assert(0);
+            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+            break;
+    }
+
+    return rv;
 }
 
 static PRInt32
 tls13_ClientSendKeyShareXtn(sslSocket *ss, PRBool append,
                             PRUint32 maxBytes)
 {
-    SECStatus rv;
-    PRUint32 entry_length;
     PRUint32 extension_length;
 
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
         return 0;
     }
 
     /* Optimistically try to send an ECDHE key using the
      * preexisting key (in future will be keys) */
     SSL_TRC(3, ("%d: TLS13[%d]: send client key share xtn",
                 SSL_GETPID(), ss->fd));
 
-    entry_length = tls13_SizeOfKeyShareEntry(ss->ephemeralECDHKeyPair);
-    /* Type + length + vector_length + entry */
-    extension_length = 2 + 2 + 2 + entry_length;
-
+    extension_length = tls13_SizeOfClientKeyShareExtension(ss);
     if (maxBytes < extension_length) {
         PORT_Assert(0);
         return 0;
     }
 
     if (append) {
+        SECStatus rv;
+        PRCList *cursor;
+
         rv = ssl3_AppendHandshakeNumber(ss, ssl_tls13_key_share_xtn, 2);
         if (rv != SECSuccess)
             goto loser;
-        rv = ssl3_AppendHandshakeNumber(ss, entry_length + 2, 2); /* Extension length */
+
+        /* The extension length */
+        rv = ssl3_AppendHandshakeNumber(ss, extension_length - 4, 2);
+        if (rv != SECSuccess)
+            goto loser;
+
+        /* The length of KeyShares */
+        rv = ssl3_AppendHandshakeNumber(ss, extension_length - 6, 2);
         if (rv != SECSuccess)
             goto loser;
-        rv = ssl3_AppendHandshakeNumber(ss, entry_length, 2); /* Vector length */
-        if (rv != SECSuccess)
-            goto loser;
-        rv = tls13_EncodeKeyShareEntry(ss, ss->ephemeralECDHKeyPair);
-        if (rv != SECSuccess)
-            goto loser;
+
+        for (cursor = PR_NEXT_LINK(&ss->ephemeralKeyPairs);
+             cursor != &ss->ephemeralKeyPairs;
+             cursor = PR_NEXT_LINK(cursor)) {
+            sslEphemeralKeyPair *keyPair = (sslEphemeralKeyPair *)cursor;
+            rv = tls13_EncodeKeyShareEntry(ss, keyPair);
+            if (rv != SECSuccess)
+                goto loser;
+        }
 
         ss->xtnData.advertised[ss->xtnData.numAdvertised++] =
             ssl_tls13_key_share_xtn;
     }
 
     return extension_length;
 
 loser:
     return -1;
 }
 
 static SECStatus
 tls13_HandleKeyShareEntry(sslSocket *ss, SECItem *data)
 {
     SECStatus rv;
     PRInt32 group;
+    const namedGroupDef *groupDef;
     TLS13KeyShareEntry *ks = NULL;
     SECItem share = { siBuffer, NULL, 0 };
 
     group = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
     if (group < 0) {
         PORT_SetError(SSL_ERROR_RX_MALFORMED_KEY_SHARE);
         goto loser;
     }
+    groupDef = ssl_LookupNamedGroup(group);
+    if (!groupDef) {
+        return SECSuccess;
+    }
 
     rv = ssl3_ConsumeHandshakeVariable(ss, &share, 2, &data->data,
                                        &data->len);
     if (rv != SECSuccess)
         goto loser;
 
     ks = PORT_ZNew(TLS13KeyShareEntry);
     if (!ks)
         goto loser;
-    ks->group = group;
+    ks->group = groupDef;
 
     rv = SECITEM_CopyItem(NULL, &ks->key_exchange, &share);
     if (rv != SECSuccess)
         goto loser;
 
     PR_APPEND_LINK(&ks->link, &ss->ssl3.hs.remoteKeyShares);
     return SECSuccess;
 
@@ -3252,48 +3309,42 @@ loser:
 
 PRInt32
 tls13_ServerSendKeyShareXtn(sslSocket *ss, PRBool append,
                             PRUint32 maxBytes)
 {
     PRUint32 extension_length;
     PRUint32 entry_length;
     SECStatus rv;
-
-    switch (ss->ssl3.hs.kea_def->exchKeyType) {
-        case ssl_kea_ecdh:
-        case ssl_kea_ecdh_psk:
-            PORT_Assert(ss->ephemeralECDHKeyPair);
-            break;
-        default:
-            /* got an unknown or unsupported Key Exchange Algorithm.
-             * Can't happen because tls13_HandleClientKeyShare
-             * enforces that we are ssl_kea_ecdh. */
-            PORT_Assert(0);
-            tls13_FatalError(ss, SEC_ERROR_UNSUPPORTED_KEYALG, internal_error);
-            return SECFailure;
-    }
-
-    entry_length = tls13_SizeOfKeyShareEntry(ss->ephemeralECDHKeyPair);
+    sslEphemeralKeyPair *keyPair;
+
+    /* There should be exactly one key share. */
+    PORT_Assert(!PR_CLIST_IS_EMPTY(&ss->ephemeralKeyPairs));
+    PORT_Assert(PR_PREV_LINK(&ss->ephemeralKeyPairs) ==
+                PR_NEXT_LINK(&ss->ephemeralKeyPairs));
+
+    keyPair = (sslEphemeralKeyPair *)PR_NEXT_LINK(&ss->ephemeralKeyPairs);
+
+    entry_length = tls13_SizeOfKeyShareEntry(keyPair->keys->pubKey);
     extension_length = 2 + 2 + entry_length; /* Type + length + entry_length */
     if (maxBytes < extension_length) {
         PORT_Assert(0);
         return 0;
     }
 
     if (append) {
         rv = ssl3_AppendHandshakeNumber(ss, ssl_tls13_key_share_xtn, 2);
         if (rv != SECSuccess)
             goto loser;
 
         rv = ssl3_AppendHandshakeNumber(ss, entry_length, 2);
         if (rv != SECSuccess)
             goto loser;
 
-        rv = tls13_EncodeKeyShareEntry(ss, ss->ephemeralECDHKeyPair);
+        rv = tls13_EncodeKeyShareEntry(ss, keyPair);
         if (rv != SECSuccess)
             goto loser;
     }
 
     return extension_length;
 
 loser:
     return -1;
--- a/security/nss/lib/ssl/ssl3prot.h
+++ b/security/nss/lib/ssl/ssl3prot.h
@@ -197,16 +197,17 @@ typedef enum {
     kea_dh_anon_export,
     kea_rsa_fips,
     kea_ecdh_ecdsa,
     kea_ecdhe_ecdsa,
     kea_ecdh_rsa,
     kea_ecdhe_rsa,
     kea_ecdh_anon,
     kea_ecdhe_psk,
+    kea_dhe_psk,
 } SSL3KeyExchangeAlgorithm;
 
 typedef struct {
     SECItem modulus;
     SECItem exponent;
 } SSL3ServerRSAParams;
 
 typedef struct {
@@ -233,16 +234,17 @@ typedef struct {
  * which, if |hashAlg==ssl_hash_none| is also a SSL3HashesIndividually
  * struct. */
 typedef struct {
     unsigned int len;
     SSLHashType hashAlg;
     union {
         PRUint8 raw[64];
         SSL3HashesIndividually s;
+        SECItem pointer_to_hash_input;
     } u;
 } SSL3Hashes;
 
 typedef struct {
     union {
         SSL3Opaque anonymous;
         SSL3Hashes certified;
     } u;
--- a/security/nss/lib/ssl/sslcert.c
+++ b/security/nss/lib/ssl/sslcert.c
@@ -74,17 +74,17 @@ ssl_CopyServerCert(const sslServerCert *
         if (!sc->serverCertChain)
             goto loser;
     } else {
         sc->serverCert = NULL;
         sc->serverCertChain = NULL;
     }
 
     if (oc->serverKeyPair) {
-        sc->serverKeyPair = ssl3_GetKeyPairRef(oc->serverKeyPair);
+        sc->serverKeyPair = ssl_GetKeyPairRef(oc->serverKeyPair);
         if (!sc->serverKeyPair)
             goto loser;
     } else {
         sc->serverKeyPair = NULL;
     }
     sc->serverKeyBits = oc->serverKeyBits;
 
     if (oc->certStatusArray) {
@@ -113,17 +113,17 @@ ssl_FreeServerCert(sslServerCert *sc)
 
     if (sc->serverCert) {
         CERT_DestroyCertificate(sc->serverCert);
     }
     if (sc->serverCertChain) {
         CERT_DestroyCertificateList(sc->serverCertChain);
     }
     if (sc->serverKeyPair) {
-        ssl3_FreeKeyPair(sc->serverKeyPair);
+        ssl_FreeKeyPair(sc->serverKeyPair);
     }
     if (sc->certStatusArray) {
         SECITEM_FreeArray(sc->certStatusArray, PR_TRUE);
     }
     if (sc->signedCertTimestamps.len) {
         SECITEM_FreeItem(&sc->signedCertTimestamps, PR_FALSE);
     }
     PORT_ZFree(sc, sizeof(*sc));
@@ -142,19 +142,19 @@ ssl_FindServerCert(const sslSocket *ss,
         if (cert->certType.authType != certType->authType) {
             continue;
         }
         switch (cert->certType.authType) {
             case ssl_auth_ecdsa:
             case ssl_auth_ecdh_rsa:
             case ssl_auth_ecdh_ecdsa:
                 /* Note: For deprecated APIs, we need to be able to find and
-                   match a slot with any named curve or sign type. */
-                if (certType->u.namedCurve != ec_noName &&
-                    cert->certType.u.namedCurve != certType->u.namedCurve) {
+                   match a slot with any named curve. */
+                if (certType->namedCurve &&
+                    cert->certType.namedCurve != certType->namedCurve) {
                     continue;
                 }
                 break;
             default:
                 break;
         }
         return cert;
     }
@@ -162,22 +162,22 @@ ssl_FindServerCert(const sslSocket *ss,
 }
 
 sslServerCert *
 ssl_FindServerCertByAuthType(const sslSocket *ss, SSLAuthType authType)
 {
     sslServerCertType certType;
     certType.authType = authType;
     switch (authType) {
-        /* Setting the named curve to ec_noName ensures that all EC certificates
+        /* Setting the named curve to NULL ensures that all EC certificates
          * are matched when searching for this slot. */
         case ssl_auth_ecdsa:
         case ssl_auth_ecdh_rsa:
         case ssl_auth_ecdh_ecdsa:
-            certType.u.namedCurve = ec_noName;
+            certType.namedCurve = NULL;
             break;
         default:
             break;
     }
     return ssl_FindServerCert(ss, &certType);
 }
 
 SECStatus
@@ -187,46 +187,36 @@ ssl_OneTimeCertSetup(sslSocket *ss, cons
     if (sc->certType.authType == ssl_auth_rsa_decrypt &&
         sc->serverKeyBits > 512 &&
         !ss->opt.noStepDown && !ss->stepDownKeyPair) {
         if (ssl3_CreateRSAStepDownKeys(ss) != SECSuccess) {
             return SECFailure;
         }
     }
 
-    /* DH parameters are only needed for DHE_RSA_* and DHE_DSS_* suites.  Make
-     * sure that they are properly setup here. */
-    if (sc->certType.authType == ssl_auth_rsa_sign ||
-        sc->certType.authType == ssl_auth_rsa_decrypt ||
-        sc->certType.authType == ssl_auth_dsa) {
-        if (ssl3_SelectDHParams(ss) != SECSuccess) {
-            return SECFailure;
-        }
-    }
-
     if (PR_SUCCESS != PR_CallOnceWithArg(&setupServerCAListOnce,
                                          &serverCAListSetup,
                                          (void *)(ss->dbHandle))) {
         return SECFailure;
     }
     return SECSuccess;
 }
 
 /* Determine which slot a certificate fits into.  SSLAuthType is known, but
  * extra information needs to be worked out from the cert and key. */
 static void
 ssl_PopulateCertType(sslServerCertType *certType, SSLAuthType authType,
-                     CERTCertificate *cert, ssl3KeyPair *keyPair)
+                     CERTCertificate *cert, sslKeyPair *keyPair)
 {
     certType->authType = authType;
     switch (authType) {
         case ssl_auth_ecdsa:
         case ssl_auth_ecdh_rsa:
         case ssl_auth_ecdh_ecdsa:
-            certType->u.namedCurve = ssl3_PubKey2ECName(keyPair->pubKey);
+            certType->namedCurve = ssl_ECPubKey2NamedGroup(keyPair->pubKey);
             break;
         default:
             break;
     }
 }
 
 static SECStatus
 ssl_PopulateServerCert(sslServerCert *sc, CERTCertificate *cert,
@@ -252,31 +242,31 @@ ssl_PopulateServerCert(sslServerCert *sc
         sc->serverCertChain =
             CERT_CertChainFromCert(sc->serverCert, certUsageSSLServer,
                                    PR_TRUE);
     }
     return sc->serverCertChain ? SECSuccess : SECFailure;
 }
 
 static SECStatus
-ssl_PopulateKeyPair(sslServerCert *sc, ssl3KeyPair *keyPair)
+ssl_PopulateKeyPair(sslServerCert *sc, sslKeyPair *keyPair)
 {
     /* Copy over the key pair. */
     if (sc->serverKeyPair) {
-        ssl3_FreeKeyPair(sc->serverKeyPair);
+        ssl_FreeKeyPair(sc->serverKeyPair);
     }
     if (keyPair) {
         /* Get the size of the cert's public key, and remember it. */
         sc->serverKeyBits = SECKEY_PublicKeyStrengthInBits(keyPair->pubKey);
         if (sc->serverKeyBits == 0) {
             return SECFailure;
         }
 
         SECKEY_CacheStaticFlags(keyPair->privKey);
-        sc->serverKeyPair = ssl3_GetKeyPairRef(keyPair);
+        sc->serverKeyPair = ssl_GetKeyPairRef(keyPair);
     } else {
         sc->serverKeyPair = NULL;
     }
     return SECSuccess;
 }
 
 static SECStatus
 ssl_PopulateOCSPResponses(sslServerCert *sc,
@@ -305,17 +295,17 @@ ssl_PopulateSignedCertTimestamps(sslServ
         return SECITEM_CopyItem(NULL, &sc->signedCertTimestamps,
                                 signedCertTimestamps);
     }
     return SECSuccess;
 }
 
 static SECStatus
 ssl_ConfigCert(sslSocket *ss, CERTCertificate *cert,
-               ssl3KeyPair *keyPair, const SSLExtraServerCertData *data)
+               sslKeyPair *keyPair, const SSLExtraServerCertData *data)
 {
     sslServerCert *oldsc;
     sslServerCertType certType;
     SECStatus rv;
     sslServerCert *sc = NULL;
     int error_code = SEC_ERROR_NO_MEMORY;
 
     PORT_Assert(cert);
@@ -412,17 +402,17 @@ ssl_GetEcdhAuthType(CERTCertificate *cer
  * configures a certificate based on that information.  For RSA certificates
  * only, this can mean that two certificates are configured.
  *
  * If the optional data argument contains an authType value other than
  * ssl_auth_null, then only that slot will be used.  If that choice is invalid,
  * then this will fail. */
 static SECStatus
 ssl_ConfigCertByUsage(sslSocket *ss, CERTCertificate *cert,
-                      ssl3KeyPair *keyPair, const SSLExtraServerCertData *data)
+                      sslKeyPair *keyPair, const SSLExtraServerCertData *data)
 {
     SECStatus rv = SECFailure;
     SSLExtraServerCertData arg = {
         ssl_auth_null, NULL, NULL, NULL
     };
     SECOidTag tag;
 
     if (data) {
@@ -496,20 +486,20 @@ ssl_ConfigCertByUsage(sslSocket *ss, CER
         data->authType != arg.authType) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return SECFailure;
     }
     return ssl_ConfigCert(ss, cert, keyPair, &arg);
 }
 
 /* This function adopts pubKey and destroys it if things go wrong. */
-static ssl3KeyPair *
+static sslKeyPair *
 ssl_MakeKeyPairForCert(SECKEYPrivateKey *key, SECKEYPublicKey *pubKey)
 {
-    ssl3KeyPair *keyPair = NULL;
+    sslKeyPair *keyPair = NULL;
     SECKEYPrivateKey *privKeyCopy = NULL;
     PK11SlotInfo *bestSlot;
 
     if (key->pkcs11Slot) {
         bestSlot = PK11_ReferenceSlot(key->pkcs11Slot);
         if (bestSlot) {
             privKeyCopy = PK11_CopyTokenPrivKeyToSessionPrivKey(bestSlot, key);
             PK11_FreeSlot(bestSlot);
@@ -523,17 +513,17 @@ ssl_MakeKeyPairForCert(SECKEYPrivateKey 
             privKeyCopy = PK11_CopyTokenPrivKeyToSessionPrivKey(bestSlot, key);
             PK11_FreeSlot(bestSlot);
         }
     }
     if (!privKeyCopy) {
         privKeyCopy = SECKEY_CopyPrivateKey(key);
     }
     if (privKeyCopy) {
-        keyPair = ssl3_NewKeyPair(privKeyCopy, pubKey);
+        keyPair = ssl_NewKeyPair(privKeyCopy, pubKey);
     }
     if (!keyPair) {
         if (privKeyCopy) {
             SECKEY_DestroyPrivateKey(privKeyCopy);
         }
         /* We adopted the public key, so we're responsible. */
         if (pubKey) {
             SECKEY_DestroyPublicKey(pubKey);
@@ -551,17 +541,17 @@ ssl_MakeKeyPairForCert(SECKEYPrivateKey 
  */
 SECStatus
 SSL_ConfigServerCert(PRFileDesc *fd, CERTCertificate *cert,
                      SECKEYPrivateKey *key,
                      const SSLExtraServerCertData *data, unsigned int data_len)
 {
     sslSocket *ss;
     SECKEYPublicKey *pubKey;
-    ssl3KeyPair *keyPair;
+    sslKeyPair *keyPair;
     SECStatus rv;
     SSLExtraServerCertData dataCopy = {
         ssl_auth_null, NULL, NULL, NULL
     };
 
     ss = ssl_FindSocket(fd);
     if (!ss) {
         return SECFailure;
@@ -588,17 +578,17 @@ SSL_ConfigServerCert(PRFileDesc *fd, CER
     keyPair = ssl_MakeKeyPairForCert(key, pubKey);
     if (!keyPair) {
         /* pubKey is adopted by ssl_MakeKeyPairForCert() */
         PORT_SetError(SEC_ERROR_NO_MEMORY);
         return SECFailure;
     }
 
     rv = ssl_ConfigCertByUsage(ss, cert, keyPair, &dataCopy);
-    ssl3_FreeKeyPair(keyPair);
+    ssl_FreeKeyPair(keyPair);
     return rv;
 }
 
 /*******************************************************************/
 /* Deprecated functions.
  *
  * The remainder of this file contains deprecated functions for server
  * certificate configuration.  These configure certificates incorrectly, but in
@@ -651,19 +641,19 @@ ssl_FindOrMakeCertType(sslSocket *ss, SS
     sslServerCert *sc;
     sslServerCertType certType;
 
     certType.authType = authType;
     switch (authType) {
         case ssl_auth_ecdsa:
         case ssl_auth_ecdh_rsa:
         case ssl_auth_ecdh_ecdsa:
-            /* Setting the named curve to ec_noName ensures that all EC certificates
+            /* Setting the named curve to NULL ensures that all EC certificates
              * are matched when searching for this slot. */
-            certType.u.namedCurve = ec_noName;
+            certType.namedCurve = NULL;
             break;
         default:
             break;
     }
     sc = ssl_FindServerCert(ss, &certType);
     if (sc) {
         PR_REMOVE_LINK(&sc->link);
         return sc;
@@ -688,17 +678,17 @@ ssl_RemoveCertAndKeyByAuthType(sslSocket
          * unchanged; the value will be updated when a key is added. */
     }
 }
 
 static SECStatus
 ssl_AddCertAndKeyByAuthType(sslSocket *ss, SSLAuthType authType,
                             CERTCertificate *cert,
                             const CERTCertificateList *certChainOpt,
-                            ssl3KeyPair *keyPair)
+                            sslKeyPair *keyPair)
 {
     sslServerCert *sc;
     SECStatus rv;
 
     if (!ssl_CertSuitableForAuthType(cert, authType)) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return SECFailure;
     }
@@ -709,17 +699,17 @@ ssl_AddCertAndKeyByAuthType(sslSocket *s
         return SECFailure;
     }
     rv = ssl_PopulateKeyPair(sc, keyPair);
     if (rv != SECSuccess) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         goto loser;
     }
     /* Now that we have a key pair, update the details of the slot. Many of the
-     * legacy functions create a slot with a namedCurve of ec_noName, which
+     * legacy functions create a slot with a namedCurve of NULL, which
      * makes the slot unusable; this corrects that. */
     ssl_PopulateCertType(&sc->certType, authType, cert, keyPair);
     rv = ssl_PopulateServerCert(sc, cert, certChainOpt);
     if (rv != SECSuccess) {
         PORT_SetError(SEC_ERROR_NO_MEMORY);
         goto loser;
     }
     PR_APPEND_LINK(&sc->link, &ss->serverCerts);
@@ -730,17 +720,17 @@ loser:
 }
 
 static SECStatus
 ssl_AddCertsByKEA(sslSocket *ss, CERTCertificate *cert,
                   const CERTCertificateList *certChainOpt,
                   SECKEYPrivateKey *key, SSLKEAType certType)
 {
     SECKEYPublicKey *pubKey;
-    ssl3KeyPair *keyPair;
+    sslKeyPair *keyPair;
     SECStatus rv;
 
     pubKey = CERT_ExtractPublicKey(cert);
     if (!pubKey) {
         return SECFailure;
     }
 
     keyPair = ssl_MakeKeyPairForCert(key, pubKey);
@@ -778,17 +768,17 @@ ssl_AddCertsByKEA(sslSocket *ss, CERTCer
             break;
 
         default:
             PORT_SetError(SEC_ERROR_INVALID_ARGS);
             rv = SECFailure;
             break;
     }
 
-    ssl3_FreeKeyPair(keyPair);
+    ssl_FreeKeyPair(keyPair);
     return rv;
 }
 
 /* Public deprecated function */
 SECStatus
 SSL_ConfigSecureServerWithCertChain(PRFileDesc *fd, CERTCertificate *cert,
                                     const CERTCertificateList *certChainOpt,
                                     SECKEYPrivateKey *key, SSLKEAType certType)
--- a/security/nss/lib/ssl/sslcert.h
+++ b/security/nss/lib/ssl/sslcert.h
@@ -17,34 +17,32 @@
 ** loaded.  The authType field determines the basic slot, then additional
 ** parameters further narrow the slot.
 **
 ** An EC key (ssl_auth_ecdsa or ssl_auth_ecdh_*) is assigned to a slot based on
 ** the named curve of the key.
 */
 typedef struct sslServerCertTypeStr {
     SSLAuthType authType;
-    union {
-        /* For ssl_auth_ecdsa and ssl_auth_ecdh_*.  This is only the named curve
-         * of the end-entity certificate key.  The keys in other certificates in
-         * the chain aren't directly relevant to the operation of TLS (though it
-         * might make certificate validation difficult, libssl doesn't care). */
-        ECName namedCurve;
-    } u;
+    /* For ssl_auth_ecdsa and ssl_auth_ecdh_*.  This is only the named curve
+     * of the end-entity certificate key.  The keys in other certificates in
+     * the chain aren't directly relevant to the operation of TLS (though it
+     * might make certificate validation difficult, libssl doesn't care). */
+    const namedGroupDef *namedCurve;
 } sslServerCertType;
 
 typedef struct sslServerCertStr {
     PRCList link; /* The linked list link */
 
     sslServerCertType certType; /* The certificate slot this occupies */
 
     /* Configuration state for server sockets */
     CERTCertificate *serverCert;
     CERTCertificateList *serverCertChain;
-    ssl3KeyPair *serverKeyPair;
+    sslKeyPair *serverKeyPair;
     unsigned int serverKeyBits;
     /* Each certificate needs its own status. */
     SECItemArray *certStatusArray;
     /* Serialized signed certificate timestamps to be sent to the client
     ** in a TLS extension (server only). Each certificate needs its own
     ** timestamps item.
     */
     SECItem signedCertTimestamps;
--- a/security/nss/lib/ssl/sslenum.c
+++ b/security/nss/lib/ssl/sslenum.c
@@ -53,16 +53,21 @@
  *      TLS_RSA_WITH_3DES_EDE_CBC_SHA { 0x00,0x0A }
  *      TLS_RSA_WITH_DES_CBC_SHA { 0x00,0x09 }
  * The broken server only supports the third and fourth ones and will select
  * the third one.
  */
 const PRUint16 SSL_ImplementedCiphers[] = {
     /* ECDHE-PSK from [draft-mattsson-tls-ecdhe-psk-aead]. */
     TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256,
+    TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256,
+    TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384,
+    TLS_DHE_PSK_WITH_AES_128_GCM_SHA256,
+    TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256,
+    TLS_DHE_PSK_WITH_AES_256_GCM_SHA384,
 
     TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
     TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
     TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
     TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
     TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
     TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
     /* TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA must appear before
--- a/security/nss/lib/ssl/sslimpl.h
+++ b/security/nss/lib/ssl/sslimpl.h
@@ -129,43 +129,38 @@ typedef enum { SSLAppOpRead = 0,
 /* number of wrap mechanisms potentially used to wrap master secrets. */
 #define SSL_NUM_WRAP_MECHS 16
 
 /* This makes the cert cache entry exactly 4k. */
 #define SSL_MAX_CACHED_CERT_LEN 4060
 
 #define NUM_MIXERS 9
 
-/* Mask of the 25 named curves we support. */
-#define SSL3_ALL_SUPPORTED_CURVES_MASK 0x3fffffe
-/* Mask of only 3 curves, suite B */
-#define SSL3_SUITE_B_SUPPORTED_CURVES_MASK 0x3800000
-
 #ifndef BPB
 #define BPB 8 /* Bits Per Byte */
 #endif
 
 #define EXPORT_RSA_KEY_LENGTH 64 /* bytes */
 
 /* The default value from RFC 4347 is 1s, which is too slow. */
 #define DTLS_RETRANSMIT_INITIAL_MS 50
 /* The maximum time to wait between retransmissions. */
 #define DTLS_RETRANSMIT_MAX_MS 10000
 /* Time to wait in FINISHED state for retransmissions. */
 #define DTLS_RETRANSMIT_FINISHED_MS 30000
 
 /* Types and names of elliptic curves used in TLS */
 typedef enum {
-    ec_type_explicitPrime = 1,
-    ec_type_explicitChar2Curve = 2,
-    ec_type_named
+    ec_type_explicitPrime = 1,      /* not supported */
+    ec_type_explicitChar2Curve = 2, /* not supported */
+    ec_type_named = 3
 } ECType;
 
+/* Previously known as NamedCurve. */
 typedef enum {
-    ec_noName = 0,
     ec_sect163k1 = 1,
     ec_sect163r1 = 2,
     ec_sect163r2 = 3,
     ec_sect193r1 = 4,
     ec_sect193r2 = 5,
     ec_sect233k1 = 6,
     ec_sect233r1 = 7,
     ec_sect239k1 = 8,
@@ -181,32 +176,60 @@ typedef enum {
     ec_secp192k1 = 18,
     ec_secp192r1 = 19,
     ec_secp224k1 = 20,
     ec_secp224r1 = 21,
     ec_secp256k1 = 22,
     ec_secp256r1 = 23,
     ec_secp384r1 = 24,
     ec_secp521r1 = 25,
-    ec_pastLastName
-} ECName;
+    ffdhe_2048 = 256, /* draft-ietf-tls-negotiated-ff-dhe-10 */
+    ffdhe_3072 = 257,
+    ffdhe_4096 = 258,
+    ffdhe_6144 = 259,
+    ffdhe_8192 = 260,
+    ffdhe_custom = 65537 /* special value */
+} NamedGroup;
+
+/* TODO: decide if SSLKEAType might be better here. */
+typedef enum {
+    group_type_ec,
+    group_type_ff
+} NamedGroupType;
+
+typedef struct {
+    /* This is the index of the curve into the bit mask that we use to track
+     * what has been negotiated on the socket. */
+    PRUint8 index;
+    /* The name is the value that is encoded on the wire in TLS. */
+    NamedGroup name;
+    /* The number of bits in the group. */
+    unsigned int bits;
+    /* Whether the group is Elliptic or Finite-Field. */
+    NamedGroupType type;
+    /* The OID that identifies the group to PKCS11.  This also determines
+     * whether the group is enabled in policy. */
+    SECOidTag oidTag;
+    /* Non-suite-B groups are enabled by patching NSS. Yuck. */
+    PRBool suiteb;
+} namedGroupDef;
 
 typedef struct sslBufferStr sslBuffer;
 typedef struct sslConnectInfoStr sslConnectInfo;
 typedef struct sslGatherStr sslGather;
 typedef struct sslSecurityInfoStr sslSecurityInfo;
 typedef struct sslSessionIDStr sslSessionID;
 typedef struct sslSocketStr sslSocket;
 typedef struct sslSocketOpsStr sslSocketOps;
 
 typedef struct ssl3StateStr ssl3State;
 typedef struct ssl3CertNodeStr ssl3CertNode;
 typedef struct ssl3BulkCipherDefStr ssl3BulkCipherDef;
 typedef struct ssl3MACDefStr ssl3MACDef;
-typedef struct ssl3KeyPairStr ssl3KeyPair;
+typedef struct sslKeyPairStr sslKeyPair;
 typedef struct ssl3DHParamsStr ssl3DHParams;
 
 struct ssl3CertNodeStr {
     struct ssl3CertNodeStr *next;
     CERTCertificate *cert;
 };
 
 typedef SECStatus (*sslHandshakeFunc)(sslSocket *ss);
@@ -307,17 +330,17 @@ typedef struct {
 #else
     ssl3CipherSuite cipher_suite;
     PRUint8 policy;
     unsigned char enabled : 1;
     unsigned char isPresent : 1;
 #endif
 } ssl3CipherSuiteCfg;
 
-#define ssl_V3_SUITES_IMPLEMENTED 75
+#define ssl_V3_SUITES_IMPLEMENTED 80
 
 #define MAX_DTLS_SRTP_CIPHER_SUITES 4
 
 /* MAX_SIGNATURE_ALGORITHMS allows for a large number of combinations of
  * SSLSignType and SSLHashType, but not all combinations (specifically, this
  * doesn't allow space for combinations with MD5). */
 #define MAX_SIGNATURE_ALGORITHMS 15
 
@@ -347,16 +370,17 @@ typedef struct sslOptionsStr {
     unsigned int enableOCSPStapling : 1;
     unsigned int enableNPN : 1;
     unsigned int enableALPN : 1;
     unsigned int reuseServerECDHEKey : 1;
     unsigned int enableFallbackSCSV : 1;
     unsigned int enableServerDhe : 1;
     unsigned int enableExtendedMS : 1;
     unsigned int enableSignedCertTimestamps : 1;
+    unsigned int requireDHENamedGroups : 1;
 } sslOptions;
 
 typedef enum { sslHandshakingUndetermined = 0,
                sslHandshakingAsClient,
                sslHandshakingAsServer
 } sslHandshakingType;
 
 #define SSL_LOCK_RANK_SPEC 255
@@ -624,30 +648,30 @@ struct sslSessionIDStr {
 
     PRUint32 creationTime;   /* seconds since Jan 1, 1970 */
     PRUint32 expirationTime; /* seconds since Jan 1, 1970 */
 
     SSLAuthType authType;
     PRUint32 authKeyBits;
     SSLKEAType keaType;
     PRUint32 keaKeyBits;
+    PRUint32 namedGroups;
 
     union {
         struct {
             /* values that are copied into the server's on-disk SID cache. */
             PRUint8 sessionIDLength;
             SSL3Opaque sessionID[SSL3_SESSIONID_BYTES];
 
             ssl3CipherSuite cipherSuite;
             SSLCompressionMethod compression;