Bug 1414735 - Update Firefox to NSS 3.35, r=franziskus draft
authorMartin Thomson <martin.thomson@gmail.com>
Mon, 06 Nov 2017 18:55:42 +1100
changeset 693434 060c22bd61acfbb2c63ba9d684539a2d30747cd9
parent 693433 bf6c31180422ea33ed1a7d50aaa5f99101782e67
child 739027 4b5200e897f4388dc1890d3872099c223b33fb61
push id87796
push usermartin.thomson@gmail.com
push dateMon, 06 Nov 2017 08:41:59 +0000
reviewersfranziskus
bugs1414735
milestone58.0a1
Bug 1414735 - Update Firefox to NSS 3.35, r=franziskus MozReview-Commit-ID: KRx6mpQC4rr
old-configure.in
security/manager/ssl/nsNSSIOLayer.cpp
security/nss/TAG-INFO
security/nss/automation/abi-check/expected-report-libnss3.so.txt
security/nss/automation/abi-check/expected-report-libssl3.so.txt
security/nss/automation/abi-check/previous-nss-release
security/nss/cmd/tstclnt/tstclnt.c
security/nss/coreconf/coreconf.dep
security/nss/gtests/common/util.h
security/nss/gtests/pk11_gtest/manifest.mn
security/nss/gtests/pk11_gtest/pk11_encrypt_derive_unittest.cc
security/nss/gtests/pk11_gtest/pk11_gtest.gyp
security/nss/gtests/ssl_gtest/libssl_internals.c
security/nss/gtests/ssl_gtest/manifest.mn
security/nss/gtests/ssl_gtest/ssl_alths_unittest.cc
security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc
security/nss/gtests/ssl_gtest/ssl_gtest.gyp
security/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc
security/nss/gtests/ssl_gtest/ssl_record_unittest.cc
security/nss/gtests/ssl_gtest/tls_agent.cc
security/nss/gtests/ssl_gtest/tls_filter.cc
security/nss/gtests/ssl_gtest/tls_filter.h
security/nss/lib/freebl/poly1305.h
security/nss/lib/nss/nss.h
security/nss/lib/softoken/pkcs11.c
security/nss/lib/softoken/pkcs11c.c
security/nss/lib/softoken/softkver.h
security/nss/lib/softoken/softoknt.h
security/nss/lib/ssl/ssl3con.c
security/nss/lib/ssl/ssl3ecc.c
security/nss/lib/ssl/ssl3exthandle.c
security/nss/lib/ssl/ssl3gthr.c
security/nss/lib/ssl/ssl3prot.h
security/nss/lib/ssl/sslexp.h
security/nss/lib/ssl/sslimpl.h
security/nss/lib/ssl/sslinfo.c
security/nss/lib/ssl/sslsock.c
security/nss/lib/ssl/tls13con.c
security/nss/lib/ssl/tls13con.h
security/nss/lib/ssl/tls13exthandle.c
security/nss/lib/ssl/tls13exthandle.h
security/nss/lib/util/nssutil.h
--- a/old-configure.in
+++ b/old-configure.in
@@ -1910,17 +1910,17 @@ dnl = If NSS was not detected in the sys
 dnl = use the one in the source tree (mozilla/security/nss)
 dnl ========================================================
 
 MOZ_ARG_WITH_BOOL(system-nss,
 [  --with-system-nss       Use system installed NSS],
     _USE_SYSTEM_NSS=1 )
 
 if test -n "$_USE_SYSTEM_NSS"; then
-    AM_PATH_NSS(3.34, [MOZ_SYSTEM_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
+    AM_PATH_NSS(3.35, [MOZ_SYSTEM_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
 fi
 
 if test -n "$MOZ_SYSTEM_NSS"; then
    NSS_LIBS="$NSS_LIBS -lcrmf"
 else
    NSS_CFLAGS="-I${DIST}/include/nss"
    case "${OS_ARCH}" in
         # Only few platforms have been tested with GYP
--- a/security/manager/ssl/nsNSSIOLayer.cpp
+++ b/security/manager/ssl/nsNSSIOLayer.cpp
@@ -70,17 +70,17 @@ namespace {
 // does not impact other normal sockets not using the flags.)
 //
 // Their current definitions are:
 //
 // bits 0-2 (mask 0x07) specify the max tls version
 //          0 means no override 1->4 are 1.0, 1.1, 1.2, 1.3, 4->7 unused
 // bits 3-5 (mask 0x38) specify the tls fallback limit
 //          0 means no override, values 1->4 match prefs
-// bit    6 (mask 0x40) specifies use of SSL_AltServerHelloType on handshake
+// bit    6 (mask 0x40) specifies use of SSL_AltHandshakeType on handshake
 
 enum {
   kTLSProviderFlagMaxVersion10   = 0x01,
   kTLSProviderFlagMaxVersion11   = 0x02,
   kTLSProviderFlagMaxVersion12   = 0x03,
   kTLSProviderFlagMaxVersion13   = 0x04,
 };
 
@@ -89,17 +89,17 @@ static uint32_t getTLSProviderFlagMaxVer
   return (flags & 0x07);
 }
 
 static uint32_t getTLSProviderFlagFallbackLimit(uint32_t flags)
 {
   return (flags & 0x38) >> 3;
 }
 
-static bool getTLSProviderFlagAltServerHello(uint32_t flags)
+static bool getTLSProviderFlagAltHandshake(uint32_t flags)
 {
   return (flags & 0x40);
 }
 
 #define MAX_ALPN_LENGTH 255
 
 void
 getSiteKey(const nsACString& hostName, uint16_t port,
@@ -2596,23 +2596,23 @@ nsSSLIOLayerSetOptions(PRFileDesc* fd, b
       range.max = SSL_LIBRARY_VERSION_TLS_1_3;
     } else {
       MOZ_LOG(gPIPNSSLog, LogLevel::Error,
               ("[%p] nsSSLIOLayerSetOptions: unknown version flags %d\n",
                fd, versionFlags));
     }
   }
 
-  // enabling alternative server hello
-  if (getTLSProviderFlagAltServerHello(infoObject->GetProviderTlsFlags())) {
+  // enabling alternative handshake
+  if (getTLSProviderFlagAltHandshake(infoObject->GetProviderTlsFlags())) {
     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
-            ("[%p] nsSSLIOLayerSetOptions: Use AltServerHello\n", fd));
-    if (SECSuccess != SSL_UseAltServerHelloType(fd, PR_TRUE)) {
+            ("[%p] nsSSLIOLayerSetOptions: Use AltHandshake\n", fd));
+    if (SECSuccess != SSL_UseAltHandshakeType(fd, PR_TRUE)) {
           MOZ_LOG(gPIPNSSLog, LogLevel::Error,
-                  ("[%p] nsSSLIOLayerSetOptions: Use AltServerHello failed\n", fd));
+                  ("[%p] nsSSLIOLayerSetOptions: Use AltHandshake failed\n", fd));
           // continue on default path
     }
   }
 
   if ((infoObject->GetProviderFlags() & nsISocketProvider::BE_CONSERVATIVE) &&
       (range.max > SSL_LIBRARY_VERSION_TLS_1_2)) {
     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
             ("[%p] nsSSLIOLayerSetOptions: range.max limited to 1.2 due to BE_CONSERVATIVE flag\n",
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-NSS_3_34_BETA1
+72ddcd9b1621
--- a/security/nss/automation/abi-check/expected-report-libnss3.so.txt
+++ b/security/nss/automation/abi-check/expected-report-libnss3.so.txt
@@ -1,11 +0,0 @@
-Functions changes summary: 0 Removed, 0 Changed, 4 Added functions
-Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
-
-4 Added functions:
-
-  'function SECItem* SEC_CreateSignatureAlgorithmParameters(SECItem*, SECOidTag, SECOidTag, const SECItem*, const SECKEYPrivateKey*)'    {SEC_CreateSignatureAlgorithmParameters@@NSS_3.34}
-  'function SECStatus SEC_DerSignDataWithAlgorithmID(SECItem*, const unsigned char*, int, SECKEYPrivateKey*, SECAlgorithmID*)'    {SEC_DerSignDataWithAlgorithmID@@NSS_3.34}
-  'function SECStatus SEC_SignDataWithAlgorithmID(SECItem*, const unsigned char*, int, SECKEYPrivateKey*, SECAlgorithmID*)'    {SEC_SignDataWithAlgorithmID@@NSS_3.34}
-  'function void SGN_NewContextWithAlgorithmID(SECAlgorithmID*, SECKEYPrivateKey*)'    {SGN_NewContextWithAlgorithmID@@NSS_3.34}
-
-
--- a/security/nss/automation/abi-check/expected-report-libssl3.so.txt
+++ b/security/nss/automation/abi-check/expected-report-libssl3.so.txt
@@ -1,15 +0,0 @@
-Functions changes summary: 0 Removed, 1 Changed, 0 Added function
-Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
-
-1 function with some indirect sub-type change:
-
-  [C]'function SECStatus SSL_GetChannelInfo(SSLChannelInfo*, PRUintn)' at sslinfo.c:26:1 has some indirect sub-type changes:
-    parameter 1 of type 'SSLChannelInfo*' has sub-type changes:
-      in pointed to type 'typedef SSLChannelInfo' at sslt.h:288:1:
-        underlying type 'struct SSLChannelInfoStr' at sslt.h:229:1 changed:
-          type size changed from 896 to 960 bits
-          2 data member insertions:
-            'SSLNamedGroup SSLChannelInfoStr::originalKeaGroup', at offset 864 (in bits) at sslt.h:281:1
-            'PRBool SSLChannelInfoStr::resumed', at offset 896 (in bits) at sslt.h:284:1
-
-
--- a/security/nss/automation/abi-check/previous-nss-release
+++ b/security/nss/automation/abi-check/previous-nss-release
@@ -1,1 +1,1 @@
-NSS_3_33_BRANCH
+NSS_3_34_BRANCH
--- a/security/nss/cmd/tstclnt/tstclnt.c
+++ b/security/nss/cmd/tstclnt/tstclnt.c
@@ -247,17 +247,17 @@ PrintParameterUsage(void)
     fprintf(stderr, "%-20s Require the use of FFDHE supported groups [RFC7919]\n", "-H");
     fprintf(stderr, "%-20s Read from a file instead of stdin\n", "-A");
     fprintf(stderr, "%-20s Allow 0-RTT data (TLS 1.3 only)\n", "-Z");
     fprintf(stderr, "%-20s Disconnect and reconnect up to N times total\n", "-L");
     fprintf(stderr, "%-20s Comma separated list of enabled groups for TLS key exchange.\n"
                     "%-20s The following values are valid:\n"
                     "%-20s P256, P384, P521, x25519, FF2048, FF3072, FF4096, FF6144, FF8192\n",
             "-I", "", "");
-    fprintf(stderr, "%-20s Enable alternate content type for TLS 1.3 ServerHello\n", "-X alt-server-hello");
+    fprintf(stderr, "%-20s Enable alternative TLS 1.3 handshake\n", "-X alt-server-hello");
 }
 
 static void
 Usage(const char *progName)
 {
     PrintUsageHeader(progName);
     PrintParameterUsage();
     exit(1);
@@ -1178,17 +1178,17 @@ run_client(void)
             SECU_PrintError(progName, "error enabling 0-RTT");
             error = 1;
             goto done;
         }
     }
 
     /* Alternate ServerHello content type (TLS 1.3 only) */
     if (enableAltServerHello) {
-        rv = SSL_UseAltServerHelloType(s, PR_TRUE);
+        rv = SSL_UseAltHandshakeType(s, PR_TRUE);
         if (rv != SECSuccess) {
             SECU_PrintError(progName, "error enabling alternate ServerHello type");
             error = 1;
             goto done;
         }
     }
 
     /* require the use of fixed finite-field DH groups */
--- a/security/nss/coreconf/coreconf.dep
+++ b/security/nss/coreconf/coreconf.dep
@@ -5,9 +5,8 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSS in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
-
--- a/security/nss/gtests/common/util.h
+++ b/security/nss/gtests/common/util.h
@@ -5,17 +5,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef util_h__
 #define util_h__
 
 #include <cassert>
 #include <vector>
 
-std::vector<uint8_t> hex_string_to_bytes(std::string s) {
+static inline std::vector<uint8_t> hex_string_to_bytes(std::string s) {
   std::vector<uint8_t> bytes;
   for (size_t i = 0; i < s.length(); i += 2) {
     bytes.push_back(std::stoul(s.substr(i, 2), nullptr, 16));
   }
   return bytes;
 }
 
 #endif  // util_h__
--- a/security/nss/gtests/pk11_gtest/manifest.mn
+++ b/security/nss/gtests/pk11_gtest/manifest.mn
@@ -6,16 +6,17 @@ CORE_DEPTH = ../..
 DEPTH      = ../..
 MODULE = nss
 
 CPPSRCS = \
       pk11_aeskeywrap_unittest.cc \
       pk11_chacha20poly1305_unittest.cc \
       pk11_curve25519_unittest.cc \
       pk11_ecdsa_unittest.cc \
+      pk11_encrypt_derive_unittest.cc \
       pk11_export_unittest.cc \
       pk11_pbkdf2_unittest.cc \
       pk11_prf_unittest.cc \
       pk11_prng_unittest.cc \
       pk11_rsapss_unittest.cc \
       pk11_der_private_key_import_unittest.cc \
       $(NULL)
 
new file mode 100644
--- /dev/null
+++ b/security/nss/gtests/pk11_gtest/pk11_encrypt_derive_unittest.cc
@@ -0,0 +1,210 @@
+/* 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 "pk11pub.h"
+#include "nssutil.h"
+#include <stdio.h>
+#include "prerror.h"
+#include "nss.h"
+#include "gtest/gtest.h"
+#include "scoped_ptrs.h"
+#include "cpputil.h"
+#include "databuffer.h"
+#include "util.h"
+
+#define MAX_KEY_SIZE 24
+
+namespace nss_test {
+
+static const uint8_t kIv[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+                              0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+                              0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+static const uint8_t kInput[] = {
+    0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00, 0xff, 0xee, 0xdd, 0xcc,
+    0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00};
+
+class EncryptDeriveTest
+    : public ::testing::Test,
+      public ::testing::WithParamInterface<CK_MECHANISM_TYPE> {
+ public:
+  void TestEncryptDerive() {
+    ScopedPK11SymKey derived_key(PK11_Derive(key_.get(), derive_mech(),
+                                             derive_param(), encrypt_mech(),
+                                             CKA_DECRYPT, keysize()));
+    ASSERT_TRUE(derived_key);
+
+    uint8_t derived_key_data[MAX_KEY_SIZE];
+    ASSERT_GE(sizeof(derived_key_data), keysize());
+    GetKeyData(derived_key, derived_key_data, keysize());
+    RemoveChecksum(derived_key_data);
+
+    uint8_t reference_key_data[MAX_KEY_SIZE];
+    unsigned int reference_len = 0;
+    SECStatus rv = PK11_Encrypt(key_.get(), encrypt_mech(), encrypt_param(),
+                                reference_key_data, &reference_len, keysize(),
+                                kInput, keysize());
+    ASSERT_EQ(SECSuccess, rv);
+    ASSERT_EQ(keysize(), static_cast<size_t>(reference_len));
+    RemoveChecksum(reference_key_data);
+
+    EXPECT_EQ(DataBuffer(reference_key_data, keysize()),
+              DataBuffer(derived_key_data, keysize()));
+  }
+
+ protected:
+  unsigned int keysize() const { return 16; }
+
+ private:
+  CK_MECHANISM_TYPE encrypt_mech() const { return GetParam(); }
+
+  CK_MECHANISM_TYPE derive_mech() const {
+    switch (encrypt_mech()) {
+      case CKM_DES3_ECB:
+        return CKM_DES3_ECB_ENCRYPT_DATA;
+      case CKM_DES3_CBC:
+        return CKM_DES3_CBC_ENCRYPT_DATA;
+      case CKM_AES_ECB:
+        return CKM_AES_ECB_ENCRYPT_DATA;
+      case CKM_AES_CBC:
+        return CKM_AES_CBC_ENCRYPT_DATA;
+      case CKM_CAMELLIA_ECB:
+        return CKM_CAMELLIA_ECB_ENCRYPT_DATA;
+      case CKM_CAMELLIA_CBC:
+        return CKM_CAMELLIA_CBC_ENCRYPT_DATA;
+      case CKM_SEED_ECB:
+        return CKM_SEED_ECB_ENCRYPT_DATA;
+      case CKM_SEED_CBC:
+        return CKM_SEED_CBC_ENCRYPT_DATA;
+      default:
+        ADD_FAILURE() << "Unknown mechanism";
+        break;
+    }
+    return CKM_INVALID_MECHANISM;
+  }
+
+  SECItem* derive_param() const {
+    static CK_AES_CBC_ENCRYPT_DATA_PARAMS aes_data;
+    static CK_DES_CBC_ENCRYPT_DATA_PARAMS des_data;
+    static CK_KEY_DERIVATION_STRING_DATA string_data;
+    static SECItem param = {siBuffer, NULL, 0};
+
+    switch (encrypt_mech()) {
+      case CKM_DES3_ECB:
+      case CKM_AES_ECB:
+      case CKM_CAMELLIA_ECB:
+      case CKM_SEED_ECB:
+        string_data.pData = toUcharPtr(kInput);
+        string_data.ulLen = keysize();
+        param.data = reinterpret_cast<uint8_t*>(&string_data);
+        param.len = sizeof(string_data);
+        break;
+
+      case CKM_DES3_CBC:
+        des_data.pData = toUcharPtr(kInput);
+        des_data.length = keysize();
+        PORT_Memcpy(des_data.iv, kIv, 8);
+        param.data = reinterpret_cast<uint8_t*>(&des_data);
+        param.len = sizeof(des_data);
+        break;
+
+      case CKM_AES_CBC:
+      case CKM_CAMELLIA_CBC:
+      case CKM_SEED_CBC:
+        aes_data.pData = toUcharPtr(kInput);
+        aes_data.length = keysize();
+        PORT_Memcpy(aes_data.iv, kIv, keysize());
+        param.data = reinterpret_cast<uint8_t*>(&aes_data);
+        param.len = sizeof(aes_data);
+        break;
+
+      default:
+        ADD_FAILURE() << "Unknown mechanism";
+        break;
+    }
+    return &param;
+  }
+
+  SECItem* encrypt_param() const {
+    static SECItem param = {siBuffer, NULL, 0};
+
+    switch (encrypt_mech()) {
+      case CKM_DES3_ECB:
+      case CKM_AES_ECB:
+      case CKM_CAMELLIA_ECB:
+      case CKM_SEED_ECB:
+        // No parameter needed here.
+        break;
+
+      case CKM_DES3_CBC:
+      case CKM_AES_CBC:
+      case CKM_CAMELLIA_CBC:
+      case CKM_SEED_CBC:
+        param.data = toUcharPtr(kIv);
+        param.len = keysize();
+        break;
+
+      default:
+        ADD_FAILURE() << "Unknown mechanism";
+        break;
+    }
+    return &param;
+  }
+
+  virtual void SetUp() {
+    slot_.reset(PK11_GetBestSlot(derive_mech(), NULL));
+    ASSERT_TRUE(slot_);
+
+    key_.reset(PK11_TokenKeyGenWithFlags(slot_.get(), encrypt_mech(), NULL,
+                                         keysize(), NULL,
+                                         CKF_ENCRYPT | CKF_DERIVE, 0, NULL));
+    ASSERT_TRUE(key_);
+  }
+
+  void GetKeyData(ScopedPK11SymKey& key, uint8_t* buf, size_t max_len) const {
+    ASSERT_EQ(SECSuccess, PK11_ExtractKeyValue(key.get()));
+    SECItem* data = PK11_GetKeyData(key.get());
+    ASSERT_TRUE(data);
+    ASSERT_EQ(max_len, static_cast<size_t>(data->len));
+    PORT_Memcpy(buf, data->data, data->len);
+  }
+
+  // Remove checksum if the key is a 3DES key.
+  void RemoveChecksum(uint8_t* key_data) const {
+    if (encrypt_mech() != CKM_DES3_CBC && encrypt_mech() != CKM_DES3_ECB) {
+      return;
+    }
+    for (size_t i = 0; i < keysize(); ++i) {
+      key_data[i] &= 0xfe;
+    }
+  }
+
+  ScopedPK11SlotInfo slot_;
+  ScopedPK11SymKey key_;
+};
+
+TEST_P(EncryptDeriveTest, Test) { TestEncryptDerive(); }
+
+static const CK_MECHANISM_TYPE kEncryptDeriveMechanisms[] = {
+    CKM_DES3_ECB,     CKM_DES3_CBC,     CKM_AES_ECB,  CKM_AES_ECB, CKM_AES_CBC,
+    CKM_CAMELLIA_ECB, CKM_CAMELLIA_CBC, CKM_SEED_ECB, CKM_SEED_CBC};
+
+INSTANTIATE_TEST_CASE_P(EncryptDeriveTests, EncryptDeriveTest,
+                        ::testing::ValuesIn(kEncryptDeriveMechanisms));
+
+// This class handles the case where 3DES takes a 192-bit key
+// where all 24 octets will be used.
+class EncryptDerive3Test : public EncryptDeriveTest {
+ protected:
+  unsigned int keysize() const { return 24; }
+};
+
+TEST_P(EncryptDerive3Test, Test) { TestEncryptDerive(); }
+
+static const CK_MECHANISM_TYPE kDES3EncryptDeriveMechanisms[] = {CKM_DES3_ECB,
+                                                                 CKM_DES3_CBC};
+
+INSTANTIATE_TEST_CASE_P(Encrypt3DeriveTests, EncryptDerive3Test,
+                        ::testing::ValuesIn(kDES3EncryptDeriveMechanisms));
+
+}  // namespace nss_test
--- a/security/nss/gtests/pk11_gtest/pk11_gtest.gyp
+++ b/security/nss/gtests/pk11_gtest/pk11_gtest.gyp
@@ -11,16 +11,17 @@
       'target_name': 'pk11_gtest',
       'type': 'executable',
       'sources': [
         'pk11_aeskeywrap_unittest.cc',
         'pk11_aes_gcm_unittest.cc',
         'pk11_chacha20poly1305_unittest.cc',
         'pk11_curve25519_unittest.cc',
         'pk11_ecdsa_unittest.cc',
+        'pk11_encrypt_derive_unittest.cc',
         'pk11_pbkdf2_unittest.cc',
         'pk11_prf_unittest.cc',
         'pk11_prng_unittest.cc',
         'pk11_rsapss_unittest.cc',
         'pk11_der_private_key_import_unittest.cc',
         '<(DEPTH)/gtests/common/gtests.cc'
       ],
       'dependencies': [
--- a/security/nss/gtests/ssl_gtest/libssl_internals.c
+++ b/security/nss/gtests/ssl_gtest/libssl_internals.c
@@ -35,22 +35,22 @@ SECStatus SSLInt_UpdateSSLv2ClientRandom
   }
 
   ssl3_InitState(ss);
   ssl3_RestartHandshakeHashes(ss);
 
   // Ensure we don't overrun hs.client_random.
   rnd_len = PR_MIN(SSL3_RANDOM_LENGTH, rnd_len);
 
-  // Zero the client_random struct.
-  PORT_Memset(&ss->ssl3.hs.client_random, 0, SSL3_RANDOM_LENGTH);
+  // Zero the client_random.
+  PORT_Memset(ss->ssl3.hs.client_random, 0, SSL3_RANDOM_LENGTH);
 
   // Copy over the challenge bytes.
   size_t offset = SSL3_RANDOM_LENGTH - rnd_len;
-  PORT_Memcpy(&ss->ssl3.hs.client_random.rand[offset], rnd, rnd_len);
+  PORT_Memcpy(ss->ssl3.hs.client_random + offset, rnd, rnd_len);
 
   // Rehash the SSLv2 client hello message.
   return ssl3_UpdateHandshakeHashes(ss, msg, msg_len);
 }
 
 PRBool SSLInt_ExtensionNegotiated(PRFileDesc *fd, PRUint16 ext) {
   sslSocket *ss = ssl_FindSocket(fd);
   return (PRBool)(ss && ssl3_ExtensionNegotiated(ss, ext));
--- a/security/nss/gtests/ssl_gtest/manifest.mn
+++ b/security/nss/gtests/ssl_gtest/manifest.mn
@@ -9,16 +9,17 @@ MODULE = nss
 # These sources have access to libssl internals
 CSRCS = \
       libssl_internals.c \
       $(NULL)
 
 CPPSRCS = \
       ssl_0rtt_unittest.cc \
       ssl_agent_unittest.cc \
+      ssl_alths_unittest.cc \
       ssl_auth_unittest.cc \
       ssl_cert_ext_unittest.cc \
       ssl_ciphersuite_unittest.cc \
       ssl_damage_unittest.cc \
       ssl_dhe_unittest.cc \
       ssl_drop_unittest.cc \
       ssl_ecdh_unittest.cc \
       ssl_ems_unittest.cc \
new file mode 100644
--- /dev/null
+++ b/security/nss/gtests/ssl_gtest/ssl_alths_unittest.cc
@@ -0,0 +1,189 @@
+/* -*- 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 <memory>
+#include <vector>
+#include "ssl.h"
+#include "sslerr.h"
+#include "sslproto.h"
+
+#include "gtest_utils.h"
+#include "tls_connect.h"
+#include "tls_filter.h"
+#include "tls_parser.h"
+
+namespace nss_test {
+
+static const uint32_t kServerHelloVersionAlt = SSL_LIBRARY_VERSION_TLS_1_2;
+static const uint16_t kServerHelloVersionRegular =
+    0x7f00 | TLS_1_3_DRAFT_VERSION;
+
+class AltHandshakeTest : public TlsConnectStreamTls13 {
+ protected:
+  void SetUp() {
+    TlsConnectStreamTls13::SetUp();
+    client_ccs_recorder_ =
+        std::make_shared<TlsRecordRecorder>(kTlsChangeCipherSpecType);
+    server_handshake_recorder_ =
+        std::make_shared<TlsRecordRecorder>(kTlsHandshakeType);
+    server_ccs_recorder_ =
+        std::make_shared<TlsRecordRecorder>(kTlsChangeCipherSpecType);
+    server_hello_recorder_ =
+        std::make_shared<TlsInspectorRecordHandshakeMessage>(
+            kTlsHandshakeServerHello);
+  }
+
+  void SetAltHandshakeTypeEnabled() {
+    client_->SetAltHandshakeTypeEnabled();
+    server_->SetAltHandshakeTypeEnabled();
+  }
+
+  void InstallFilters() {
+    client_->SetPacketFilter(client_ccs_recorder_);
+    auto chain = std::make_shared<ChainedPacketFilter>(ChainedPacketFilterInit(
+        {server_handshake_recorder_, server_ccs_recorder_,
+         server_hello_recorder_}));
+    server_->SetPacketFilter(chain);
+  }
+
+  void CheckServerHelloRecordVersion(uint16_t record_version) {
+    ASSERT_EQ(record_version,
+              server_handshake_recorder_->record(0).header.version());
+  }
+
+  void CheckServerHelloVersion(uint16_t server_hello_version) {
+    uint32_t ver;
+    ASSERT_TRUE(server_hello_recorder_->buffer().Read(0, 2, &ver));
+    ASSERT_EQ(server_hello_version, ver);
+  }
+
+  void CheckForRegularHandshake() {
+    EXPECT_EQ(0U, client_ccs_recorder_->count());
+    EXPECT_EQ(0U, server_ccs_recorder_->count());
+    CheckServerHelloVersion(kServerHelloVersionRegular);
+    CheckServerHelloRecordVersion(SSL_LIBRARY_VERSION_TLS_1_0);
+  }
+
+  void CheckForAltHandshake() {
+    EXPECT_EQ(1U, client_ccs_recorder_->count());
+    EXPECT_EQ(1U, server_ccs_recorder_->count());
+    CheckServerHelloVersion(kServerHelloVersionAlt);
+    CheckServerHelloRecordVersion(SSL_LIBRARY_VERSION_TLS_1_2);
+  }
+
+  std::shared_ptr<TlsRecordRecorder> client_ccs_recorder_;
+  std::shared_ptr<TlsRecordRecorder> server_handshake_recorder_;
+  std::shared_ptr<TlsRecordRecorder> server_ccs_recorder_;
+  std::shared_ptr<TlsInspectorRecordHandshakeMessage> server_hello_recorder_;
+};
+
+TEST_F(AltHandshakeTest, ClientOnly) {
+  client_->SetAltHandshakeTypeEnabled();
+  InstallFilters();
+  Connect();
+  CheckForRegularHandshake();
+}
+
+TEST_F(AltHandshakeTest, ServerOnly) {
+  server_->SetAltHandshakeTypeEnabled();
+  InstallFilters();
+  Connect();
+  CheckForRegularHandshake();
+}
+
+TEST_F(AltHandshakeTest, Enabled) {
+  SetAltHandshakeTypeEnabled();
+  InstallFilters();
+  Connect();
+  CheckForAltHandshake();
+}
+
+TEST_F(AltHandshakeTest, ZeroRtt) {
+  SetAltHandshakeTypeEnabled();
+  SetupForZeroRtt();
+  SetAltHandshakeTypeEnabled();
+  client_->Set0RttEnabled(true);
+  server_->Set0RttEnabled(true);
+
+  InstallFilters();
+
+  ExpectResumption(RESUME_TICKET);
+  ZeroRttSendReceive(true, true);
+  Handshake();
+  ExpectEarlyDataAccepted(true);
+  CheckConnected();
+
+  CheckForAltHandshake();
+}
+
+// Neither client nor server has the extension prior to resumption, so the
+// client doesn't send a CCS before its 0-RTT data.
+TEST_F(AltHandshakeTest, DisabledBeforeZeroRtt) {
+  SetupForZeroRtt();
+  SetAltHandshakeTypeEnabled();
+  client_->Set0RttEnabled(true);
+  server_->Set0RttEnabled(true);
+
+  InstallFilters();
+
+  ExpectResumption(RESUME_TICKET);
+  ZeroRttSendReceive(true, true);
+  Handshake();
+  ExpectEarlyDataAccepted(true);
+  CheckConnected();
+
+  EXPECT_EQ(0U, client_ccs_recorder_->count());
+  EXPECT_EQ(1U, server_ccs_recorder_->count());
+  CheckServerHelloVersion(kServerHelloVersionAlt);
+}
+
+// Both use the alternative in the initial handshake but only the server enables
+// it on resumption.
+TEST_F(AltHandshakeTest, ClientDisabledAfterZeroRtt) {
+  SetAltHandshakeTypeEnabled();
+  SetupForZeroRtt();
+  server_->SetAltHandshakeTypeEnabled();
+  client_->Set0RttEnabled(true);
+  server_->Set0RttEnabled(true);
+
+  InstallFilters();
+
+  ExpectResumption(RESUME_TICKET);
+  ZeroRttSendReceive(true, true);
+  Handshake();
+  ExpectEarlyDataAccepted(true);
+  CheckConnected();
+
+  CheckForRegularHandshake();
+}
+
+// If the alternative handshake isn't negotiated after 0-RTT, and the client has
+// it enabled, it will send a ChangeCipherSpec.  The server chokes on it if it
+// hasn't negotiated the alternative handshake.
+TEST_F(AltHandshakeTest, ServerDisabledAfterZeroRtt) {
+  SetAltHandshakeTypeEnabled();
+  SetupForZeroRtt();
+  client_->SetAltHandshakeTypeEnabled();
+  client_->Set0RttEnabled(true);
+  server_->Set0RttEnabled(true);
+
+  client_->ExpectSendAlert(kTlsAlertEndOfEarlyData);
+  client_->Handshake();  // Send ClientHello (and CCS)
+
+  server_->Handshake();  // Consume the ClientHello, which is OK.
+  client_->ExpectResumption();
+  client_->Handshake();  // Read the server handshake.
+  EXPECT_EQ(TlsAgent::STATE_CONNECTED, client_->state());
+
+  // Now the server reads the CCS instead of more handshake messages.
+  ExpectAlert(server_, kTlsAlertBadRecordMac);
+  server_->Handshake();
+  EXPECT_EQ(TlsAgent::STATE_ERROR, server_->state());
+  client_->Handshake();  // Consume the alert.
+  EXPECT_EQ(TlsAgent::STATE_ERROR, client_->state());
+}
+
+}  // nss_test
--- a/security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc
@@ -1074,20 +1074,16 @@ TEST_P(TlsBogusExtensionTest13, AddBogus
 
 TEST_P(TlsBogusExtensionTest13, AddBogusExtensionHelloRetryRequest) {
   static const std::vector<SSLNamedGroup> groups = {ssl_grp_ec_secp384r1};
   server_->ConfigNamedGroups(groups);
 
   Run(kTlsHandshakeHelloRetryRequest);
 }
 
-TEST_P(TlsBogusExtensionTest13, AddVersionExtensionServerHello) {
-  Run(kTlsHandshakeServerHello, ssl_tls13_supported_versions_xtn);
-}
-
 TEST_P(TlsBogusExtensionTest13, AddVersionExtensionEncryptedExtensions) {
   Run(kTlsHandshakeEncryptedExtensions, ssl_tls13_supported_versions_xtn);
 }
 
 TEST_P(TlsBogusExtensionTest13, AddVersionExtensionCertificate) {
   Run(kTlsHandshakeCertificate, ssl_tls13_supported_versions_xtn);
 }
 
--- a/security/nss/gtests/ssl_gtest/ssl_gtest.gyp
+++ b/security/nss/gtests/ssl_gtest/ssl_gtest.gyp
@@ -10,16 +10,17 @@
     {
       'target_name': 'ssl_gtest',
       'type': 'executable',
       'sources': [
         'libssl_internals.c',
         'selfencrypt_unittest.cc',
         'ssl_0rtt_unittest.cc',
         'ssl_agent_unittest.cc',
+        'ssl_alths_unittest.cc',
         'ssl_auth_unittest.cc',
         'ssl_cert_ext_unittest.cc',
         'ssl_ciphersuite_unittest.cc',
         'ssl_damage_unittest.cc',
         'ssl_dhe_unittest.cc',
         'ssl_drop_unittest.cc',
         'ssl_ecdh_unittest.cc',
         'ssl_ems_unittest.cc',
--- a/security/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc
@@ -6,17 +6,16 @@
 
 #include <functional>
 #include <memory>
 #include <vector>
 #include "secerr.h"
 #include "ssl.h"
 #include "sslerr.h"
 #include "sslproto.h"
-#include "ssl3prot.h"
 
 extern "C" {
 // This is not something that should make you happy.
 #include "libssl_internals.h"
 }
 
 #include "gtest_utils.h"
 #include "scoped_ptrs.h"
@@ -99,19 +98,19 @@ class HelloTruncator : public TlsHandsha
 };
 
 // Verify that when NSS reports that an alert is sent, it is actually sent.
 TEST_P(TlsConnectGeneric, CaptureAlertServer) {
   client_->SetPacketFilter(std::make_shared<HelloTruncator>());
   auto alert_recorder = std::make_shared<TlsAlertRecorder>();
   server_->SetPacketFilter(alert_recorder);
 
-  ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
+  ConnectExpectAlert(server_, kTlsAlertDecodeError);
   EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
-  EXPECT_EQ(kTlsAlertIllegalParameter, alert_recorder->description());
+  EXPECT_EQ(kTlsAlertDecodeError, alert_recorder->description());
 }
 
 TEST_P(TlsConnectGenericPre13, CaptureAlertClient) {
   server_->SetPacketFilter(std::make_shared<HelloTruncator>());
   auto alert_recorder = std::make_shared<TlsAlertRecorder>();
   client_->SetPacketFilter(alert_recorder);
 
   ConnectExpectAlert(client_, kTlsAlertDecodeError);
@@ -302,52 +301,16 @@ TEST_F(TlsConnectStreamTls13, Tls13Faile
 TEST_F(TlsConnectStreamTls13, NegotiateShortHeaders) {
   client_->SetShortHeadersEnabled();
   server_->SetShortHeadersEnabled();
   client_->ExpectShortHeaders();
   server_->ExpectShortHeaders();
   Connect();
 }
 
-TEST_F(TlsConnectStreamTls13, ClientAltHandshakeType) {
-  client_->SetAltHandshakeTypeEnabled();
-  auto filter = std::make_shared<TlsHeaderRecorder>();
-  server_->SetPacketFilter(filter);
-  Connect();
-  ASSERT_EQ(kTlsHandshakeType, filter->header(0)->content_type());
-}
-
-TEST_F(TlsConnectStreamTls13, ServerAltHandshakeType) {
-  server_->SetAltHandshakeTypeEnabled();
-  auto filter = std::make_shared<TlsHeaderRecorder>();
-  server_->SetPacketFilter(filter);
-  Connect();
-  ASSERT_EQ(kTlsHandshakeType, filter->header(0)->content_type());
-}
-
-TEST_F(TlsConnectStreamTls13, BothAltHandshakeType) {
-  client_->SetAltHandshakeTypeEnabled();
-  server_->SetAltHandshakeTypeEnabled();
-  auto header_filter = std::make_shared<TlsHeaderRecorder>();
-  auto sh_filter = std::make_shared<TlsInspectorRecordHandshakeMessage>(
-      kTlsHandshakeServerHello);
-  std::vector<std::shared_ptr<PacketFilter>> filters = {header_filter,
-                                                        sh_filter};
-  auto chained = std::make_shared<ChainedPacketFilter>(filters);
-  server_->SetPacketFilter(chained);
-  header_filter->SetAgent(server_.get());
-  header_filter->EnableDecryption();
-  Connect();
-  ASSERT_EQ(kTlsAltHandshakeType, header_filter->header(0)->content_type());
-  ASSERT_EQ(kTlsHandshakeType, header_filter->header(1)->content_type());
-  uint32_t ver;
-  ASSERT_TRUE(sh_filter->buffer().Read(0, 2, &ver));
-  ASSERT_EQ((uint32_t)(0x7a00 | TLS_1_3_DRAFT_VERSION), ver);
-}
-
 INSTANTIATE_TEST_CASE_P(
     GenericStream, TlsConnectGeneric,
     ::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
                        TlsConnectTestBase::kTlsVAll));
 INSTANTIATE_TEST_CASE_P(
     GenericDatagram, TlsConnectGeneric,
     ::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
                        TlsConnectTestBase::kTlsV11Plus));
--- a/security/nss/gtests/ssl_gtest/ssl_record_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_record_unittest.cc
@@ -5,16 +5,18 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nss.h"
 #include "ssl.h"
 #include "sslimpl.h"
 
 #include "databuffer.h"
 #include "gtest_utils.h"
+#include "tls_connect.h"
+#include "tls_filter.h"
 
 namespace nss_test {
 
 const static size_t kMacSize = 20;
 
 class TlsPaddingTest
     : public ::testing::Test,
       public ::testing::WithParamInterface<std::tuple<size_t, bool>> {
@@ -46,18 +48,18 @@ class TlsPaddingTest
   }
 
   void Unpad(bool expect_success) {
     std::cerr << "Content length=" << plaintext_len_
               << " padding length=" << pad_len_
               << " total length=" << plaintext_.len() << std::endl;
     std::cerr << "Plaintext: " << plaintext_ << std::endl;
     sslBuffer s;
-    s.buf = const_cast<unsigned char *>(
-        static_cast<const unsigned char *>(plaintext_.data()));
+    s.buf = const_cast<unsigned char*>(
+        static_cast<const unsigned char*>(plaintext_.data()));
     s.len = plaintext_.len();
     SECStatus rv = ssl_RemoveTLSCBCPadding(&s, kMacSize);
     if (expect_success) {
       EXPECT_EQ(SECSuccess, rv);
       EXPECT_EQ(plaintext_len_, static_cast<size_t>(s.len));
     } else {
       EXPECT_EQ(SECFailure, rv);
     }
@@ -94,16 +96,85 @@ TEST_P(TlsPaddingTest, FirstByteOfPadWro
 TEST_P(TlsPaddingTest, LastByteOfPadWrong) {
   if (pad_len_) {
     plaintext_.Write(plaintext_.len() - 2,
                      plaintext_.data()[plaintext_.len() - 1] + 1, 1);
     Unpad(false);
   }
 }
 
+class RecordReplacer : public TlsRecordFilter {
+ public:
+  RecordReplacer(size_t size)
+      : TlsRecordFilter(), enabled_(false), size_(size) {}
+
+  PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
+                                    const DataBuffer& data,
+                                    DataBuffer* changed) override {
+    if (!enabled_) {
+      return KEEP;
+    }
+
+    EXPECT_EQ(kTlsApplicationDataType, header.content_type());
+    changed->Allocate(size_);
+
+    for (size_t i = 0; i < size_; ++i) {
+      changed->data()[i] = i & 0xff;
+    }
+
+    enabled_ = false;
+    return CHANGE;
+  }
+
+  void Enable() { enabled_ = true; }
+
+ private:
+  bool enabled_;
+  size_t size_;
+};
+
+TEST_F(TlsConnectStreamTls13, LargeRecord) {
+  EnsureTlsSetup();
+
+  const size_t record_limit = 16384;
+  auto replacer = std::make_shared<RecordReplacer>(record_limit);
+  client_->SetTlsRecordFilter(replacer);
+  replacer->EnableDecryption();
+  Connect();
+
+  replacer->Enable();
+  client_->SendData(10);
+  WAIT_(server_->received_bytes() == record_limit, 2000);
+  ASSERT_EQ(record_limit, server_->received_bytes());
+}
+
+TEST_F(TlsConnectStreamTls13, TooLargeRecord) {
+  EnsureTlsSetup();
+
+  const size_t record_limit = 16384;
+  auto replacer = std::make_shared<RecordReplacer>(record_limit + 1);
+  client_->SetTlsRecordFilter(replacer);
+  replacer->EnableDecryption();
+  Connect();
+
+  replacer->Enable();
+  ExpectAlert(server_, kTlsAlertRecordOverflow);
+  client_->SendData(10);  // This is expanded.
+
+  uint8_t buf[record_limit + 2];
+  PRInt32 rv = PR_Read(server_->ssl_fd(), buf, sizeof(buf));
+  EXPECT_GT(0, rv);
+  EXPECT_EQ(SSL_ERROR_RX_RECORD_TOO_LONG, PORT_GetError());
+
+  // Read the server alert.
+  rv = PR_Read(client_->ssl_fd(), buf, sizeof(buf));
+  EXPECT_GT(0, rv);
+  EXPECT_EQ(SSL_ERROR_RECORD_OVERFLOW_ALERT, PORT_GetError());
+}
+
 const static size_t kContentSizesArr[] = {
     1, kMacSize - 1, kMacSize, 30, 31, 32, 36, 256, 257, 287, 288};
 
 auto kContentSizes = ::testing::ValuesIn(kContentSizesArr);
 const static bool kTrueFalseArr[] = {true, false};
 auto kTrueFalse = ::testing::ValuesIn(kTrueFalseArr);
 
 INSTANTIATE_TEST_CASE_P(TlsPadding, TlsPaddingTest,
--- a/security/nss/gtests/ssl_gtest/tls_agent.cc
+++ b/security/nss/gtests/ssl_gtest/tls_agent.cc
@@ -382,17 +382,17 @@ void TlsAgent::SetShortHeadersEnabled() 
 
   SECStatus rv = SSLInt_EnableShortHeaders(ssl_fd());
   EXPECT_EQ(SECSuccess, rv);
 }
 
 void TlsAgent::SetAltHandshakeTypeEnabled() {
   EXPECT_TRUE(EnsureTlsSetup());
 
-  SECStatus rv = SSL_UseAltServerHelloType(ssl_fd(), true);
+  SECStatus rv = SSL_UseAltHandshakeType(ssl_fd(), PR_TRUE);
   EXPECT_EQ(SECSuccess, rv);
 }
 
 void TlsAgent::SetVersionRange(uint16_t minver, uint16_t maxver) {
   vrange_.min = minver;
   vrange_.max = maxver;
 
   if (ssl_fd()) {
--- a/security/nss/gtests/ssl_gtest/tls_filter.cc
+++ b/security/nss/gtests/ssl_gtest/tls_filter.cc
@@ -358,16 +358,25 @@ PacketFilter::Action TlsInspectorReplace
   if (header.handshake_type() == handshake_type_) {
     *output = buffer_;
     return CHANGE;
   }
 
   return KEEP;
 }
 
+PacketFilter::Action TlsRecordRecorder::FilterRecord(
+    const TlsRecordHeader& header, const DataBuffer& input,
+    DataBuffer* output) {
+  if (!filter_ || (header.content_type() == ct_)) {
+    records_.push_back({header, input});
+  }
+  return KEEP;
+}
+
 PacketFilter::Action TlsConversationRecorder::FilterRecord(
     const TlsRecordHeader& header, const DataBuffer& input,
     DataBuffer* output) {
   buffer_.Append(input);
   return KEEP;
 }
 
 PacketFilter::Action TlsHeaderRecorder::FilterRecord(
--- a/security/nss/gtests/ssl_gtest/tls_filter.h
+++ b/security/nss/gtests/ssl_gtest/tls_filter.h
@@ -58,16 +58,21 @@ class TlsRecordHeader : public TlsVersio
   // Return the offset of the end of the write.
   size_t Write(DataBuffer* buffer, size_t offset, const DataBuffer& body) const;
 
  private:
   uint8_t content_type_;
   uint64_t sequence_number_;
 };
 
+struct TlsRecord {
+  const TlsRecordHeader header;
+  const DataBuffer buffer;
+};
+
 // Abstract filter that operates on entire (D)TLS records.
 class TlsRecordFilter : public PacketFilter {
  public:
   TlsRecordFilter() : agent_(nullptr), count_(0), cipher_spec_() {}
 
   void SetAgent(const TlsAgent* agent) { agent_ = agent; }
   const TlsAgent* agent() const { return agent_; }
 
@@ -216,16 +221,38 @@ class TlsInspectorReplaceHandshakeMessag
                                                const DataBuffer& input,
                                                DataBuffer* output);
 
  private:
   uint8_t handshake_type_;
   DataBuffer buffer_;
 };
 
+class TlsRecordRecorder : public TlsRecordFilter {
+ public:
+  TlsRecordRecorder(uint8_t ct) : filter_(true), ct_(ct), records_() {}
+  TlsRecordRecorder()
+      : filter_(false),
+        ct_(content_handshake),  // dummy (<optional> is C++14)
+        records_() {}
+  virtual PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
+                                            const DataBuffer& input,
+                                            DataBuffer* output);
+
+  size_t count() const { return records_.size(); }
+  void Clear() { records_.clear(); }
+
+  const TlsRecord& record(size_t i) const { return records_[i]; }
+
+ private:
+  bool filter_;
+  uint8_t ct_;
+  std::vector<TlsRecord> records_;
+};
+
 // Make a copy of the complete conversation.
 class TlsConversationRecorder : public TlsRecordFilter {
  public:
   TlsConversationRecorder(DataBuffer& buffer) : buffer_(buffer) {}
 
   virtual PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
                                             const DataBuffer& input,
                                             DataBuffer* output);
@@ -242,21 +269,26 @@ class TlsHeaderRecorder : public TlsReco
                                             DataBuffer* output);
   const TlsRecordHeader* header(size_t index);
 
  private:
   std::vector<TlsRecordHeader> headers_;
 };
 
 // Runs multiple packet filters in series.
+typedef std::initializer_list<std::shared_ptr<PacketFilter>>
+    ChainedPacketFilterInit;
+
+// Runs multiple packet filters in series.
 class ChainedPacketFilter : public PacketFilter {
  public:
   ChainedPacketFilter() {}
   ChainedPacketFilter(const std::vector<std::shared_ptr<PacketFilter>> filters)
       : filters_(filters.begin(), filters.end()) {}
+  ChainedPacketFilter(ChainedPacketFilterInit il) : filters_(il) {}
   virtual ~ChainedPacketFilter() {}
 
   virtual PacketFilter::Action Filter(const DataBuffer& input,
                                       DataBuffer* output);
 
   // Takes ownership of the filter.
   void Add(std::shared_ptr<PacketFilter> filter) { filters_.push_back(filter); }
 
--- a/security/nss/lib/freebl/poly1305.h
+++ b/security/nss/lib/freebl/poly1305.h
@@ -3,16 +3,18 @@
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef FREEBL_POLY1305_H_
 #define FREEBL_POLY1305_H_
 
+#include "stddef.h"
+
 typedef unsigned char poly1305_state[512];
 
 /* Poly1305Init sets up |state| so that it can be used to calculate an
  * authentication tag with the one-time key |key|. Note that |key| is a
  * one-time key and therefore there is no `reset' method because that would
  * enable several messages to be authenticated with the same key. */
 extern void Poly1305Init(poly1305_state* state, const unsigned char key[32]);
 
--- a/security/nss/lib/nss/nss.h
+++ b/security/nss/lib/nss/nss.h
@@ -17,19 +17,19 @@
 
 /*
  * 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.34" _NSS_CUSTOMIZED " Beta"
+#define NSS_VERSION "3.35" _NSS_CUSTOMIZED " Beta"
 #define NSS_VMAJOR 3
-#define NSS_VMINOR 34
+#define NSS_VMINOR 35
 #define NSS_VPATCH 0
 #define NSS_VBUILD 0
 #define NSS_BETA PR_TRUE
 
 #ifndef RC_INVOKED
 
 #include "seccomon.h"
 
--- a/security/nss/lib/softoken/pkcs11.c
+++ b/security/nss/lib/softoken/pkcs11.c
@@ -416,21 +416,30 @@ static const struct mechanismList mechan
     { CKM_IDEA_ECB, { 16, 16, CKF_EN_DE_WR_UN }, PR_TRUE },
     { CKM_IDEA_CBC, { 16, 16, CKF_EN_DE_WR_UN }, PR_TRUE },
     { CKM_IDEA_MAC, { 16, 16, CKF_SN_VR }, PR_TRUE },
     { CKM_IDEA_MAC_GENERAL, { 16, 16, CKF_SN_VR }, PR_TRUE },
     { CKM_IDEA_CBC_PAD, { 16, 16, CKF_EN_DE_WR_UN }, PR_TRUE },
 #endif
     /* --------------------- Secret Key Operations ------------------------ */
     { CKM_GENERIC_SECRET_KEY_GEN, { 1, 32, CKF_GENERATE }, PR_TRUE },
-    { CKM_CONCATENATE_BASE_AND_KEY, { 1, 32, CKF_GENERATE }, PR_FALSE },
-    { CKM_CONCATENATE_BASE_AND_DATA, { 1, 32, CKF_GENERATE }, PR_FALSE },
-    { CKM_CONCATENATE_DATA_AND_BASE, { 1, 32, CKF_GENERATE }, PR_FALSE },
-    { CKM_XOR_BASE_AND_DATA, { 1, 32, CKF_GENERATE }, PR_FALSE },
+    { CKM_CONCATENATE_BASE_AND_KEY, { 1, 32, CKF_DERIVE }, PR_FALSE },
+    { CKM_CONCATENATE_BASE_AND_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
+    { CKM_CONCATENATE_DATA_AND_BASE, { 1, 32, CKF_DERIVE }, PR_FALSE },
+    { CKM_XOR_BASE_AND_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
     { CKM_EXTRACT_KEY_FROM_KEY, { 1, 32, CKF_DERIVE }, PR_FALSE },
+    { CKM_DES3_ECB_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
+    { CKM_DES3_CBC_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
+    { CKM_AES_ECB_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
+    { CKM_AES_CBC_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
+    { CKM_CAMELLIA_ECB_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
+    { CKM_CAMELLIA_CBC_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
+    { CKM_SEED_ECB_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
+    { CKM_SEED_CBC_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
+
     /* ---------------------- SSL Key Derivations ------------------------- */
     { CKM_SSL3_PRE_MASTER_KEY_GEN, { 48, 48, CKF_GENERATE }, PR_FALSE },
     { CKM_SSL3_MASTER_KEY_DERIVE, { 48, 48, CKF_DERIVE }, PR_FALSE },
     { CKM_SSL3_MASTER_KEY_DERIVE_DH, { 8, 128, CKF_DERIVE }, PR_FALSE },
     { CKM_SSL3_KEY_AND_MAC_DERIVE, { 48, 48, CKF_DERIVE }, PR_FALSE },
     { CKM_SSL3_MD5_MAC, { 0, 16, CKF_DERIVE }, PR_FALSE },
     { CKM_SSL3_SHA1_MAC, { 0, 20, CKF_DERIVE }, PR_FALSE },
     { CKM_MD5_KEY_DERIVATION, { 0, 16, CKF_DERIVE }, PR_FALSE },
--- a/security/nss/lib/softoken/pkcs11c.c
+++ b/security/nss/lib/softoken/pkcs11c.c
@@ -1519,18 +1519,17 @@ NSC_DecryptUpdate(CK_SESSION_HANDLE hSes
             rv = (*context->update)(context->cipherInfo, pPart, &padoutlen,
                                     maxout, context->padBuf, context->blockSize);
             if (rv != SECSuccess)
                 return sftk_MapDecryptError(PORT_GetError());
             pPart += padoutlen;
             maxout -= padoutlen;
         }
         /* now save the final block for the next decrypt or the final */
-        PORT_Memcpy(context->padBuf, &pEncryptedPart[ulEncryptedPartLen -
-                                                     context->blockSize],
+        PORT_Memcpy(context->padBuf, &pEncryptedPart[ulEncryptedPartLen - context->blockSize],
                     context->blockSize);
         context->padDataLength = context->blockSize;
         ulEncryptedPartLen -= context->padDataLength;
     }
 
     /* do it: NOTE: this assumes buf size in is >= buf size out! */
     rv = (*context->update)(context->cipherInfo, pPart, &outlen,
                             maxout, pEncryptedPart, ulEncryptedPartLen);
@@ -6237,16 +6236,53 @@ sftk_ANSI_X9_63_kdf(CK_BYTE **key, CK_UL
     else if (kdf == CKD_SHA512_KDF)
         return sftk_compute_ANSI_X9_63_kdf(key, key_len, SharedSecret, SharedInfo,
                                            SharedInfoLen, SHA512_HashBuf, SHA512_LENGTH);
     else
         return CKR_MECHANISM_INVALID;
 }
 
 /*
+ *  Handle the derive from a block encryption cipher
+ */
+CK_RV
+sftk_DeriveEncrypt(SFTKCipher encrypt, void *cipherInfo,
+                   int blockSize, SFTKObject *key, CK_ULONG keySize,
+                   unsigned char *data, CK_ULONG len)
+{
+    /* large enough for a 512-bit key */
+    unsigned char tmpdata[SFTK_MAX_DERIVE_KEY_SIZE];
+    SECStatus rv;
+    unsigned int outLen;
+    CK_RV crv;
+
+    if ((len % blockSize) != 0) {
+        return CKR_MECHANISM_PARAM_INVALID;
+    }
+    if (len > SFTK_MAX_DERIVE_KEY_SIZE) {
+        return CKR_MECHANISM_PARAM_INVALID;
+    }
+    if (keySize && (len < keySize)) {
+        return CKR_MECHANISM_PARAM_INVALID;
+    }
+    if (keySize == 0) {
+        keySize = len;
+    }
+
+    rv = (*encrypt)(cipherInfo, &tmpdata, &outLen, len, data, len);
+    if (rv != SECSuccess) {
+        crv = sftk_MapCryptError(PORT_GetError());
+        return crv;
+    }
+
+    crv = sftk_forceAttribute(key, CKA_VALUE, tmpdata, keySize);
+    return crv;
+}
+
+/*
  * SSL Key generation given pre master secret
  */
 #define NUM_MIXERS 9
 static const char *const mixers[NUM_MIXERS] = {
     "A",
     "BB",
     "CCC",
     "DDDD",
@@ -6894,16 +6930,182 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession
             }
             MD5_DestroyContext(md5, PR_TRUE);
             SHA1_DestroyContext(sha, PR_TRUE);
             sftk_FreeObject(key);
             key = NULL;
             break;
         }
 
+        case CKM_DES3_ECB_ENCRYPT_DATA:
+        case CKM_DES3_CBC_ENCRYPT_DATA: {
+            void *cipherInfo;
+            unsigned char des3key[MAX_DES3_KEY_SIZE];
+            CK_DES_CBC_ENCRYPT_DATA_PARAMS *desEncryptPtr;
+            int mode;
+            unsigned char *iv;
+            unsigned char *data;
+            CK_ULONG len;
+
+            if (mechanism == CKM_DES3_ECB_ENCRYPT_DATA) {
+                stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)
+                                pMechanism->pParameter;
+                mode = NSS_DES_EDE3;
+                iv = NULL;
+                data = stringPtr->pData;
+                len = stringPtr->ulLen;
+            } else {
+                mode = NSS_DES_EDE3_CBC;
+                desEncryptPtr =
+                    (CK_DES_CBC_ENCRYPT_DATA_PARAMS *)
+                        pMechanism->pParameter;
+                iv = desEncryptPtr->iv;
+                data = desEncryptPtr->pData;
+                len = desEncryptPtr->length;
+            }
+            if (att->attrib.ulValueLen == 16) {
+                PORT_Memcpy(des3key, att->attrib.pValue, 16);
+                PORT_Memcpy(des3key + 16, des3key, 8);
+            } else if (att->attrib.ulValueLen == 24) {
+                PORT_Memcpy(des3key, att->attrib.pValue, 24);
+            } else {
+                crv = CKR_KEY_SIZE_RANGE;
+                break;
+            }
+            cipherInfo = DES_CreateContext(des3key, iv, mode, PR_TRUE);
+            PORT_Memset(des3key, 0, 24);
+            if (cipherInfo == NULL) {
+                crv = CKR_HOST_MEMORY;
+                break;
+            }
+            crv = sftk_DeriveEncrypt((SFTKCipher)DES_Encrypt,
+                                     cipherInfo, 8, key, keySize,
+                                     data, len);
+            DES_DestroyContext(cipherInfo, PR_TRUE);
+            break;
+        }
+
+        case CKM_AES_ECB_ENCRYPT_DATA:
+        case CKM_AES_CBC_ENCRYPT_DATA: {
+            void *cipherInfo;
+            CK_AES_CBC_ENCRYPT_DATA_PARAMS *aesEncryptPtr;
+            int mode;
+            unsigned char *iv;
+            unsigned char *data;
+            CK_ULONG len;
+
+            if (mechanism == CKM_AES_ECB_ENCRYPT_DATA) {
+                mode = NSS_AES;
+                iv = NULL;
+                stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)pMechanism->pParameter;
+                data = stringPtr->pData;
+                len = stringPtr->ulLen;
+            } else {
+                aesEncryptPtr =
+                    (CK_AES_CBC_ENCRYPT_DATA_PARAMS *)pMechanism->pParameter;
+                mode = NSS_AES_CBC;
+                iv = aesEncryptPtr->iv;
+                data = aesEncryptPtr->pData;
+                len = aesEncryptPtr->length;
+            }
+
+            cipherInfo = AES_CreateContext((unsigned char *)att->attrib.pValue,
+                                           iv, mode, PR_TRUE,
+                                           att->attrib.ulValueLen, 16);
+            if (cipherInfo == NULL) {
+                crv = CKR_HOST_MEMORY;
+                break;
+            }
+            crv = sftk_DeriveEncrypt((SFTKCipher)AES_Encrypt,
+                                     cipherInfo, 16, key, keySize,
+                                     data, len);
+            AES_DestroyContext(cipherInfo, PR_TRUE);
+            break;
+        }
+
+        case CKM_CAMELLIA_ECB_ENCRYPT_DATA:
+        case CKM_CAMELLIA_CBC_ENCRYPT_DATA: {
+            void *cipherInfo;
+            CK_AES_CBC_ENCRYPT_DATA_PARAMS *aesEncryptPtr;
+            int mode;
+            unsigned char *iv;
+            unsigned char *data;
+            CK_ULONG len;
+
+            if (mechanism == CKM_CAMELLIA_ECB_ENCRYPT_DATA) {
+                stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)
+                                pMechanism->pParameter;
+                aesEncryptPtr = NULL;
+                mode = NSS_CAMELLIA;
+                data = stringPtr->pData;
+                len = stringPtr->ulLen;
+                iv = NULL;
+            } else {
+                stringPtr = NULL;
+                aesEncryptPtr = (CK_AES_CBC_ENCRYPT_DATA_PARAMS *)
+                                    pMechanism->pParameter;
+                mode = NSS_CAMELLIA_CBC;
+                iv = aesEncryptPtr->iv;
+                data = aesEncryptPtr->pData;
+                len = aesEncryptPtr->length;
+            }
+
+            cipherInfo = Camellia_CreateContext((unsigned char *)att->attrib.pValue,
+                                                iv, mode, PR_TRUE,
+                                                att->attrib.ulValueLen);
+            if (cipherInfo == NULL) {
+                crv = CKR_HOST_MEMORY;
+                break;
+            }
+            crv = sftk_DeriveEncrypt((SFTKCipher)Camellia_Encrypt,
+                                     cipherInfo, 16, key, keySize,
+                                     data, len);
+            Camellia_DestroyContext(cipherInfo, PR_TRUE);
+            break;
+        }
+
+        case CKM_SEED_ECB_ENCRYPT_DATA:
+        case CKM_SEED_CBC_ENCRYPT_DATA: {
+            void *cipherInfo;
+            CK_AES_CBC_ENCRYPT_DATA_PARAMS *aesEncryptPtr;
+            int mode;
+            unsigned char *iv;
+            unsigned char *data;
+            CK_ULONG len;
+
+            if (mechanism == CKM_SEED_ECB_ENCRYPT_DATA) {
+                mode = NSS_SEED;
+                stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)
+                                pMechanism->pParameter;
+                aesEncryptPtr = NULL;
+                data = stringPtr->pData;
+                len = stringPtr->ulLen;
+                iv = NULL;
+            } else {
+                mode = NSS_SEED_CBC;
+                aesEncryptPtr = (CK_AES_CBC_ENCRYPT_DATA_PARAMS *)
+                                    pMechanism->pParameter;
+                iv = aesEncryptPtr->iv;
+                data = aesEncryptPtr->pData;
+                len = aesEncryptPtr->length;
+            }
+
+            cipherInfo = SEED_CreateContext((unsigned char *)att->attrib.pValue,
+                                            iv, mode, PR_TRUE);
+            if (cipherInfo == NULL) {
+                crv = CKR_HOST_MEMORY;
+                break;
+            }
+            crv = sftk_DeriveEncrypt((SFTKCipher)SEED_Encrypt,
+                                     cipherInfo, 16, key, keySize,
+                                     data, len);
+            SEED_DestroyContext(cipherInfo, PR_TRUE);
+            break;
+        }
+
         case CKM_CONCATENATE_BASE_AND_KEY: {
             SFTKObject *newKey;
 
             crv = sftk_DeriveSensitiveCheck(sourceKey, key);
             if (crv != CKR_OK)
                 break;
 
             session = sftk_SessionFromHandle(hSession);
--- a/security/nss/lib/softoken/softkver.h
+++ b/security/nss/lib/softoken/softkver.h
@@ -12,16 +12,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.34" SOFTOKEN_ECC_STRING " Beta"
+#define SOFTOKEN_VERSION "3.35" SOFTOKEN_ECC_STRING " Beta"
 #define SOFTOKEN_VMAJOR 3
-#define SOFTOKEN_VMINOR 34
+#define SOFTOKEN_VMINOR 35
 #define SOFTOKEN_VPATCH 0
 #define SOFTOKEN_VBUILD 0
 #define SOFTOKEN_BETA PR_TRUE
 
 #endif /* _SOFTKVER_H_ */
--- a/security/nss/lib/softoken/softoknt.h
+++ b/security/nss/lib/softoken/softoknt.h
@@ -4,16 +4,19 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef _SOFTOKNT_H_
 #define _SOFTOKNT_H_
 
 #define NSS_SOFTOKEN_DEFAULT_CHUNKSIZE 2048
+#define DES_BLOCK_SIZE 8     /* bytes */
+#define MAX_DES3_KEY_SIZE 24 /* DES_BLOCK_SIZE * 3 */
+#define SFTK_MAX_DERIVE_KEY_SIZE 64
 
 /*
  * FIPS 140-2 auditing
  */
 typedef enum {
     NSS_AUDIT_ERROR = 3,   /* errors */
     NSS_AUDIT_WARNING = 2, /* warning messages */
     NSS_AUDIT_INFO = 1     /* informational messages */
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -1,9 +1,8 @@
-
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /*
  * SSL3 Protocol
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
@@ -1042,16 +1041,29 @@ Null_Cipher(void *ctx, unsigned char *ou
     }
     return SECSuccess;
 }
 
 /*
  * SSL3 Utility functions
  */
 
+static void
+ssl_SetSpecVersions(sslSocket *ss, ssl3CipherSpec *spec)
+{
+    spec->version = ss->version;
+    if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
+        tls13_SetSpecRecordVersion(ss, spec);
+    } else if (IS_DTLS(ss)) {
+        spec->recordVersion = dtls_TLSVersionToDTLSVersion(ss->version);
+    } else {
+        spec->recordVersion = ss->version;
+    }
+}
+
 /* allowLargerPeerVersion controls whether the function will select the
  * highest enabled SSL version or fail when peerVersion is greater than the
  * highest enabled version.
  *
  * If allowLargerPeerVersion is true, peerVersion is the peer's highest
  * enabled version rather than the peer's selected version.
  */
 SECStatus
@@ -1091,49 +1103,48 @@ ssl_ClientReadVersion(sslSocket *ss, PRU
     }
 
 #ifdef TLS_1_3_DRAFT_VERSION
     if (temp == SSL_LIBRARY_VERSION_TLS_1_3) {
         (void)SSL3_SendAlert(ss, alert_fatal, protocol_version);
         PORT_SetError(SSL_ERROR_UNSUPPORTED_VERSION);
         return SECFailure;
     }
-    if (temp == tls13_EncodeDraftVersion(SSL_LIBRARY_VERSION_TLS_1_3) || (ss->opt.enableAltHandshaketype &&
-                                                                          (temp == tls13_EncodeAltDraftVersion(SSL_LIBRARY_VERSION_TLS_1_3)))) {
+    if (temp == tls13_EncodeDraftVersion(SSL_LIBRARY_VERSION_TLS_1_3)) {
+        v = SSL_LIBRARY_VERSION_TLS_1_3;
+    } else if (temp == tls13_EncodeAltDraftVersion(SSL_LIBRARY_VERSION_TLS_1_3)) {
+        if (!ss->opt.enableAltHandshaketype || IS_DTLS(ss)) {
+            (void)SSL3_SendAlert(ss, alert_fatal, protocol_version);
+            PORT_SetError(SSL_ERROR_UNSUPPORTED_VERSION);
+            return SECFailure;
+        }
+        ss->ssl3.hs.altHandshakeType = PR_TRUE;
         v = SSL_LIBRARY_VERSION_TLS_1_3;
     } else {
         v = (SSL3ProtocolVersion)temp;
     }
 #else
     v = (SSL3ProtocolVersion)temp;
 #endif
 
     if (IS_DTLS(ss)) {
         /* If this fails, we get 0 back and the next check to fails. */
         v = dtls_DTLSVersionToTLSVersion(v);
     }
 
-    PORT_Assert(!SSL_ALL_VERSIONS_DISABLED(&ss->vrange));
-    if (ss->vrange.min > v || ss->vrange.max < v) {
-        (void)SSL3_SendAlert(ss, alert_fatal,
-                             (v > SSL_LIBRARY_VERSION_3_0) ? protocol_version
-                                                           : handshake_failure);
-        PORT_SetError(SSL_ERROR_UNSUPPORTED_VERSION);
-        return SECFailure;
-    }
     *version = v;
     return SECSuccess;
 }
 
 static SECStatus
-ssl3_GetNewRandom(SSL3Random *random)
+ssl3_GetNewRandom(SSL3Random random)
 {
     SECStatus rv;
 
-    rv = PK11_GenerateRandom(random->rand, SSL3_RANDOM_LENGTH);
+    rv = PK11_GenerateRandom(random, SSL3_RANDOM_LENGTH);
     if (rv != SECSuccess) {
         ssl_MapLowLevelError(SSL_ERROR_GENERATE_RANDOM_FAILURE);
     }
     return rv;
 }
 
 /* Called by ssl3_SendServerKeyExchange and ssl3_SendCertificateVerify */
 SECStatus
@@ -1447,19 +1458,19 @@ ssl3_ComputeDHKeyHash(sslSocket *ss, SSL
         hashBuf = buf;
     } else {
         hashBuf = PORT_Alloc(bufLen);
         if (!hashBuf) {
             return SECFailure;
         }
     }
 
-    memcpy(hashBuf, &ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH);
+    memcpy(hashBuf, ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH);
     pBuf = hashBuf + SSL3_RANDOM_LENGTH;
-    memcpy(pBuf, &ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH);
+    memcpy(pBuf, ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH);
     pBuf += SSL3_RANDOM_LENGTH;
     pBuf = ssl_EncodeUintX(dh_p.len, 2, pBuf);
     memcpy(pBuf, dh_p.data, dh_p.len);
     pBuf += dh_p.len;
     pBuf = ssl_EncodeUintX(dh_g.len, 2, pBuf);
     memcpy(pBuf, dh_g.data, dh_g.len);
     pBuf += dh_g.len;
     pBuf = ssl_EncodeUintX(yLen, 2, pBuf);
@@ -1575,17 +1586,17 @@ ssl3_SetupPendingCipherSpec(sslSocket *s
 
     /* This hack provides maximal interoperability with SSL 3 servers. */
     cwSpec = ss->ssl3.cwSpec;
     if (cwSpec->mac_def->mac == mac_null) {
         /* SSL records are not being MACed. */
         cwSpec->version = ss->version;
     }
 
-    pwSpec->version = ss->version;
+    ssl_SetSpecVersions(ss, ss->ssl3.pwSpec);
     isTLS = (PRBool)(pwSpec->version > SSL_LIBRARY_VERSION_3_0);
 
     SSL_TRC(3, ("%d: SSL3[%d]: Set XXX Pending Cipher Suite to 0x%04x",
                 SSL_GETPID(), ss->fd, suite));
 
     suite_def = ssl_LookupCipherSuiteDef(suite);
     if (suite_def == NULL) {
         ssl_ReleaseSpecWriteLock(ss);
@@ -1770,61 +1781,58 @@ ssl3_InitCompressionContext(ssl3CipherSp
 }
 
 /* ssl3_BuildRecordPseudoHeader writes the SSL/TLS pseudo-header (the data
  * which is included in the MAC or AEAD additional data) to |out| and returns
  * its length. See https://tools.ietf.org/html/rfc5246#section-6.2.3.3 for the
  * definition of the AEAD additional data.
  *
  * TLS pseudo-header includes the record's version field, SSL's doesn't. Which
- * pseudo-header defintiion to use should be decided based on the version of
+ * pseudo-header definition to use should be decided based on the version of
  * the protocol that was negotiated when the cipher spec became current, NOT
  * based on the version value in the record itself, and the decision is passed
  * to this function as the |includesVersion| argument. But, the |version|
  * argument should be the record's version value.
  */
-static unsigned int
-ssl3_BuildRecordPseudoHeader(unsigned char *out,
+static SECStatus
+ssl3_BuildRecordPseudoHeader(PRUint8 *out, DTLSEpoch epoch,
                              sslSequenceNumber seq_num,
                              SSL3ContentType type,
                              PRBool includesVersion,
                              SSL3ProtocolVersion version,
                              PRBool isDTLS,
                              int length)
 {
-    out[0] = (unsigned char)(seq_num >> 56);
-    out[1] = (unsigned char)(seq_num >> 48);
+    if (isDTLS) {
+        out[0] = (unsigned char)(epoch >> 8);
+        out[1] = (unsigned char)(epoch >> 0);
+    } else {
+        out[0] = (unsigned char)(seq_num >> 56);
+        out[1] = (unsigned char)(seq_num >> 48);
+    }
     out[2] = (unsigned char)(seq_num >> 40);
     out[3] = (unsigned char)(seq_num >> 32);
     out[4] = (unsigned char)(seq_num >> 24);
     out[5] = (unsigned char)(seq_num >> 16);
     out[6] = (unsigned char)(seq_num >> 8);
     out[7] = (unsigned char)(seq_num >> 0);
     out[8] = type;
 
     /* SSL3 MAC doesn't include the record's version field. */
     if (!includesVersion) {
         out[9] = MSB(length);
         out[10] = LSB(length);
         return 11;
     }
-
     /* TLS MAC and AEAD additional data include version. */
-    if (isDTLS) {
-        SSL3ProtocolVersion dtls_version;
-
-        dtls_version = dtls_TLSVersionToDTLSVersion(version);
-        out[9] = MSB(dtls_version);
-        out[10] = LSB(dtls_version);
-    } else {
-        out[9] = MSB(version);
-        out[10] = LSB(version);
-    }
+    out[9] = MSB(version);
+    out[10] = LSB(version);
     out[11] = MSB(length);
     out[12] = LSB(length);
+    PRINT_BUF(50, (NULL, "Pseudoheader", out, 13));
     return 13;
 }
 
 static SECStatus
 ssl3_AESGCM(ssl3KeyMaterial *keys,
             PRBool doDecrypt,
             unsigned char *out,
             int *outlen,
@@ -2368,17 +2376,16 @@ ssl3_ClientAuthTokenPresent(sslSessionID
     return isPresent;
 }
 
 /* Caller must hold the spec read lock. */
 SECStatus
 ssl3_CompressMACEncryptRecord(ssl3CipherSpec *cwSpec,
                               PRBool isServer,
                               PRBool isDTLS,
-                              PRBool capRecordVersion,
                               SSL3ContentType type,
                               const PRUint8 *pIn,
                               PRUint32 contentLen,
                               sslBuffer *wrBuf)
 {
     const ssl3BulkCipherDef *cipher_def;
     SECStatus rv;
     PRUint32 macLen = 0;
@@ -2425,18 +2432,18 @@ ssl3_CompressMACEncryptRecord(ssl3Cipher
                                 &outlen, wrBuf->space - ivLen, pIn, contentLen);
         if (rv != SECSuccess)
             return rv;
         pIn = wrBuf->buf + ivLen;
         contentLen = outlen;
     }
 
     pseudoHeaderLen = ssl3_BuildRecordPseudoHeader(
-        pseudoHeader, cwSpec->write_seq_num, type,
-        cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_0, cwSpec->version,
+        pseudoHeader, cwSpec->epoch, cwSpec->write_seq_num, type,
+        cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_0, cwSpec->recordVersion,
         isDTLS, contentLen);
     PORT_Assert(pseudoHeaderLen <= sizeof(pseudoHeader));
     if (cipher_def->type == type_aead) {
         const int nonceLen = cipher_def->explicit_nonce_size;
         const int tagLen = cipher_def->tag_size;
 
         if (nonceLen + contentLen + tagLen > wrBuf->space) {
             PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
@@ -2537,24 +2544,22 @@ ssl3_CompressMACEncryptRecord(ssl3Cipher
             wrBuf->len += cipherBytesPart2;
         }
     }
 
     return SECSuccess;
 }
 
 SECStatus
-ssl_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec,
-                  PRBool capRecordVersion, SSL3ContentType type,
+ssl_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, SSL3ContentType type,
                   const PRUint8 *pIn, PRUint32 contentLen, sslBuffer *wrBuf)
 {
     const ssl3BulkCipherDef *cipher_def = cwSpec->cipher_def;
     PRUint16 headerLen;
     sslBuffer protBuf;
-    SSL3ProtocolVersion version = cwSpec->version;
     PRBool isTLS13;
     PRUint8 *ptr = wrBuf->buf;
     SECStatus rv;
 
     if (ss->ssl3.hs.shortHeaders) {
         PORT_Assert(!IS_DTLS(ss));
         PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
         headerLen = TLS13_RECORD_HEADER_LENGTH_SHORT;
@@ -2578,17 +2583,17 @@ ssl_ProtectRecord(sslSocket *ss, ssl3Cip
 #ifdef UNSAFE_FUZZER_MODE
     rv = Null_Cipher(NULL, protBuf.buf, (int *)&protBuf.len, protBuf.space,
                      pIn, contentLen);
 #else
     if (isTLS13) {
         rv = tls13_ProtectRecord(ss, cwSpec, type, pIn, contentLen, &protBuf);
     } else {
         rv = ssl3_CompressMACEncryptRecord(cwSpec, ss->sec.isServer,
-                                           IS_DTLS(ss), capRecordVersion, type,
+                                           IS_DTLS(ss), type,
                                            pIn, contentLen, &protBuf);
     }
 #endif
     if (rv != SECSuccess) {
         return SECFailure; /* error was set */
     }
 
     PORT_Assert(protBuf.len <= MAX_FRAGMENT_LENGTH + (isTLS13 ? 256 : 1024));
@@ -2602,35 +2607,27 @@ ssl_ProtectRecord(sslSocket *ss, ssl3Cip
         if (isTLS13 && cipher_def->calg != ssl_calg_null) {
             *ptr++ = content_application_data;
         } else
 #endif
         {
             *ptr++ = type;
         }
 
+        ptr = ssl_EncodeUintX(cwSpec->recordVersion, 2, ptr);
         if (IS_DTLS(ss)) {
-            version = isTLS13 ? SSL_LIBRARY_VERSION_TLS_1_1 : version;
-            version = dtls_TLSVersionToDTLSVersion(version);
-
-            ptr = ssl_EncodeUintX(version, 2, ptr);
-            ptr = ssl_EncodeUintX(cwSpec->write_seq_num, 8, ptr);
-        } else {
-            if (capRecordVersion || isTLS13) {
-                version = PR_MIN(SSL_LIBRARY_VERSION_TLS_1_0, version);
-            }
-            ptr = ssl_EncodeUintX(version, 2, ptr);
+            ptr = ssl_EncodeUintX(cwSpec->epoch, 2, ptr);
+            ptr = ssl_EncodeUintX(cwSpec->write_seq_num, 6, ptr);
         }
         (void)ssl_EncodeUintX(protBuf.len, 2, ptr);
     }
     ++cwSpec->write_seq_num;
 
     return SECSuccess;
 }
-
 /* Process the plain text before sending it.
  * Returns the number of bytes of plaintext that were successfully sent
  *  plus the number of bytes of plaintext that were copied into the
  *  output (write) buffer.
  * Returns SECFailure on a hard IO error, memory error, or crypto error.
  * Does NOT return SECWouldBlock.
  *
  * Notes on the use of the private ssl flags:
@@ -2641,65 +2638,43 @@ ssl_ProtectRecord(sslSocket *ss, ssl3Cip
  *    then buffer remaining bytes of ciphertext into pending buf,
  *    and continue to do that for all succssive records until all
  *    bytes are used.
  * ssl_SEND_FLAG_FORCE_INTO_BUFFER
  *    As above, except this suppresses all write attempts, and forces
  *    all ciphertext into the pending ciphertext buffer.
  * ssl_SEND_FLAG_USE_EPOCH (for DTLS)
  *    Forces the use of the provided epoch
- * ssl_SEND_FLAG_CAP_RECORD_VERSION
- *    Caps the record layer version number of TLS ClientHello to { 3, 1 }
- *    (TLS 1.0). Some TLS 1.0 servers (which seem to use F5 BIG-IP) ignore
- *    ClientHello.client_version and use the record layer version number
- *    (TLSPlaintext.version) instead when negotiating protocol versions. In
- *    addition, if the record layer version number of ClientHello is { 3, 2 }
- *    (TLS 1.1) or higher, these servers reset the TCP connections. Lastly,
- *    some F5 BIG-IP servers hang if a record containing a ClientHello has a
- *    version greater than { 3, 1 } and a length greater than 255. Set this
- *    flag to work around such servers.
  */
 PRInt32
 ssl3_SendRecord(sslSocket *ss,
                 ssl3CipherSpec *cwSpec, /* non-NULL for DTLS retransmits */
                 SSL3ContentType type,
                 const PRUint8 *pIn, /* input buffer */
                 PRInt32 nIn,        /* bytes of input */
                 PRInt32 flags)
 {
     sslBuffer *wrBuf = &ss->sec.writeBuf;
     SECStatus rv;
     PRInt32 totalSent = 0;
-    PRBool capRecordVersion;
     ssl3CipherSpec *spec;
 
     SSL_TRC(3, ("%d: SSL3[%d] SendRecord type: %s nIn=%d",
                 SSL_GETPID(), ss->fd, ssl3_DecodeContentType(type),
                 nIn));
     PRINT_BUF(50, (ss, "Send record (plain text)", pIn, nIn));
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
 
     if (ss->ssl3.fatalAlertSent) {
         SSL_TRC(3, ("%d: SSL3[%d] Suppress write, fatal alert already sent",
                     SSL_GETPID(), ss->fd));
         return SECFailure;
     }
 
-    capRecordVersion = ((flags & ssl_SEND_FLAG_CAP_RECORD_VERSION) != 0);
-
-    if (capRecordVersion) {
-        /* ssl_SEND_FLAG_CAP_RECORD_VERSION can only be used with the
-         * TLS initial ClientHello. */
-        PORT_Assert(!IS_DTLS(ss));
-        PORT_Assert(!ss->firstHsDone);
-        PORT_Assert(type == content_handshake);
-        PORT_Assert(ss->ssl3.hs.ws == wait_server_hello);
-    }
-
     if (ss->ssl3.initialized == PR_FALSE) {
         /* This can happen on a server if the very first incoming record
         ** looks like a defective ssl3 record (e.g. too long), and we're
         ** trying to send an alert.
         */
         PR_ASSERT(type == content_alert);
         ssl3_InitState(ss);
     }
@@ -2740,29 +2715,29 @@ ssl3_SendRecord(sslSocket *ss,
                 SSL_DBG(("%d: SSL3[%d]: SendRecord, tried to get %d bytes",
                          SSL_GETPID(), ss->fd, spaceNeeded));
                 goto spec_locked_loser; /* sslBuffer_Grow set error code. */
             }
         }
 
         if (numRecords == 2) {
             sslBuffer secondRecord;
-            rv = ssl_ProtectRecord(ss, ss->ssl3.cwSpec, capRecordVersion, type,
+            rv = ssl_ProtectRecord(ss, ss->ssl3.cwSpec, type,
                                    pIn, 1, wrBuf);
             if (rv != SECSuccess)
                 goto spec_locked_loser;
 
             PRINT_BUF(50, (ss, "send (encrypted) record data [1/2]:",
                            wrBuf->buf, wrBuf->len));
 
             secondRecord.buf = wrBuf->buf + wrBuf->len;
             secondRecord.len = 0;
             secondRecord.space = wrBuf->space - wrBuf->len;
 
-            rv = ssl_ProtectRecord(ss, ss->ssl3.cwSpec, capRecordVersion, type,
+            rv = ssl_ProtectRecord(ss, ss->ssl3.cwSpec, type,
                                    pIn + 1, contentLen - 1, &secondRecord);
             if (rv == SECSuccess) {
                 PRINT_BUF(50, (ss, "send (encrypted) record data [2/2]:",
                                secondRecord.buf, secondRecord.len));
                 wrBuf->len += secondRecord.len;
             }
         } else {
             if (cwSpec) {
@@ -2771,18 +2746,17 @@ ssl3_SendRecord(sslSocket *ss,
                 PORT_Assert(IS_DTLS(ss) &&
                             (type == content_handshake ||
                              type == content_change_cipher_spec));
                 spec = cwSpec;
             } else {
                 spec = ss->ssl3.cwSpec;
             }
 
-            rv = ssl_ProtectRecord(ss, spec, !IS_DTLS(ss) && capRecordVersion,
-                                   type, pIn, contentLen, wrBuf);
+            rv = ssl_ProtectRecord(ss, spec, type, pIn, contentLen, wrBuf);
             if (rv == SECSuccess) {
                 PRINT_BUF(50, (ss, "send (encrypted) record data:",
                                wrBuf->buf, wrBuf->len));
             }
         }
 
     spec_locked_loser:
         ssl_ReleaseSpecReadLock(ss); /************************************/
@@ -2975,40 +2949,33 @@ ssl3_FlushHandshake(sslSocket *ss, PRInt
  * This function returns SECSuccess or SECFailure, never SECWouldBlock.
  * Always set sendBuf.len to 0, even when returning SECFailure.
  *
  * Called from ssl3_FlushHandshake
  */
 static SECStatus
 ssl3_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags)
 {
-    static const PRInt32 allowedFlags = ssl_SEND_FLAG_FORCE_INTO_BUFFER |
-                                        ssl_SEND_FLAG_CAP_RECORD_VERSION;
+    static const PRInt32 allowedFlags = ssl_SEND_FLAG_FORCE_INTO_BUFFER;
     PRInt32 count = -1;
     SECStatus rv;
-    SSL3ContentType ct = content_handshake;
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
 
     if (!ss->sec.ci.sendBuf.buf || !ss->sec.ci.sendBuf.len)
         return SECSuccess;
 
     /* only these flags are allowed */
     PORT_Assert(!(flags & ~allowedFlags));
     if ((flags & ~allowedFlags) != 0) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return SECFailure;
     }
-    /* Maybe send the first message with alt handshake type. */
-    if (ss->ssl3.hs.altHandshakeType) {
-        ct = content_alt_handshake;
-        ss->ssl3.hs.altHandshakeType = PR_FALSE;
-    }
-    count = ssl3_SendRecord(ss, NULL, ct,
+    count = ssl3_SendRecord(ss, NULL, content_handshake,
                             ss->sec.ci.sendBuf.buf,
                             ss->sec.ci.sendBuf.len, flags);
     if (count < 0) {
         int err = PORT_GetError();
         PORT_Assert(err != PR_WOULD_BLOCK_ERROR);
         if (err == PR_WOULD_BLOCK_ERROR) {
             PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
         }
@@ -3407,45 +3374,59 @@ ssl3_HandleAlert(sslSocket *ss, sslBuffe
  * Called from ssl3_HandleServerHelloDone,
  *             ssl3_HandleClientHello,
  * and         ssl3_HandleFinished
  *
  * Acquires and releases spec write lock, to protect switching the current
  * and pending write spec pointers.
  */
 
-static SECStatus
-ssl3_SendChangeCipherSpecs(sslSocket *ss)
+SECStatus
+ssl3_SendChangeCipherSpecsInt(sslSocket *ss)
 {
     PRUint8 change = change_cipher_spec_choice;
-    ssl3CipherSpec *pwSpec;
     SECStatus rv;
-    PRInt32 sent;
 
     SSL_TRC(3, ("%d: SSL3[%d]: send change_cipher_spec record",
                 SSL_GETPID(), ss->fd));
 
+    rv = ssl3_FlushHandshake(ss, ssl_SEND_FLAG_FORCE_INTO_BUFFER);
+    if (rv != SECSuccess) {
+        return SECFailure; /* error code set by ssl3_FlushHandshake */
+    }
+
+    if (!IS_DTLS(ss)) {
+        PRInt32 sent;
+        sent = ssl3_SendRecord(ss, NULL, content_change_cipher_spec,
+                               &change, 1, ssl_SEND_FLAG_FORCE_INTO_BUFFER);
+        if (sent < 0) {
+            return SECFailure; /* error code set by ssl3_SendRecord */
+        }
+    } else {
+        SECStatus rv;
+        rv = dtls_QueueMessage(ss, content_change_cipher_spec, &change, 1);
+        if (rv != SECSuccess) {
+            return SECFailure;
+        }
+    }
+    return SECSuccess;
+}
+
+static SECStatus
+ssl3_SendChangeCipherSpecs(sslSocket *ss)
+{
+    ssl3CipherSpec *pwSpec;
+    SECStatus rv;
+
     PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
-    rv = ssl3_FlushHandshake(ss, ssl_SEND_FLAG_FORCE_INTO_BUFFER);
-    if (rv != SECSuccess) {
-        return rv; /* error code set by ssl3_FlushHandshake */
-    }
-    if (!IS_DTLS(ss)) {
-        sent = ssl3_SendRecord(ss, NULL, content_change_cipher_spec, &change, 1,
-                               ssl_SEND_FLAG_FORCE_INTO_BUFFER);
-        if (sent < 0) {
-            return (SECStatus)sent; /* error code set by ssl3_SendRecord */
-        }
-    } else {
-        rv = dtls_QueueMessage(ss, content_change_cipher_spec, &change, 1);
-        if (rv != SECSuccess) {
-            return rv;
-        }
+    rv = ssl3_SendChangeCipherSpecsInt(ss);
+    if (rv != SECSuccess) {
+        return rv; /* Error code set. */
     }
 
     /* swap the pending and current write specs. */
     ssl_GetSpecWriteLock(ss); /**************************************/
     pwSpec = ss->ssl3.pwSpec;
 
     ss->ssl3.pwSpec = ss->ssl3.cwSpec;
     ss->ssl3.cwSpec = pwSpec;
@@ -3659,18 +3640,16 @@ ssl3_ComputeMasterSecretFinish(sslSocket
  **
  ** Called from: ssl3_ComputeMasterSecret
  */
 static SECStatus
 ssl3_ComputeMasterSecretInt(sslSocket *ss, PK11SymKey *pms,
                             PK11SymKey **msp)
 {
     ssl3CipherSpec *pwSpec = ss->ssl3.pwSpec;
-    unsigned char *cr = (unsigned char *)&ss->ssl3.hs.client_random;
-    unsigned char *sr = (unsigned char *)&ss->ssl3.hs.server_random;
     PRBool isTLS = (PRBool)(pwSpec->version > SSL_LIBRARY_VERSION_3_0);
     PRBool isTLS12 =
         (PRBool)(isTLS && pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
     /*
      * Whenever isDH is true, we need to use CKM_TLS_MASTER_KEY_DERIVE_DH
      * which, unlike CKM_TLS_MASTER_KEY_DERIVE, converts arbitrary size
      * data into a 48-byte value, and does not expect to return the version.
      */
@@ -3709,19 +3688,19 @@ ssl3_ComputeMasterSecretInt(sslSocket *s
         keyFlags = 0;
     }
 
     if (!isDH) {
         pms_version_ptr = &pms_version;
     }
 
     master_params.pVersion = pms_version_ptr;
-    master_params.RandomInfo.pClientRandom = cr;
+    master_params.RandomInfo.pClientRandom = ss->ssl3.hs.client_random;
     master_params.RandomInfo.ulClientRandomLen = SSL3_RANDOM_LENGTH;
-    master_params.RandomInfo.pServerRandom = sr;
+    master_params.RandomInfo.pServerRandom = ss->ssl3.hs.server_random;
     master_params.RandomInfo.ulServerRandomLen = SSL3_RANDOM_LENGTH;
     if (isTLS12) {
         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);
     }
@@ -3861,19 +3840,17 @@ ssl3_DeriveMasterSecret(sslSocket *ss, P
  * Caller MUST hold the specWriteLock, and SSL3HandshakeLock.
  * ssl3_InitPendingCipherSpec does that.
  *
  */
 static SECStatus
 ssl3_DeriveConnectionKeys(sslSocket *ss)
 {
     ssl3CipherSpec *pwSpec = ss->ssl3.pwSpec;
-    unsigned char *cr = (unsigned char *)&ss->ssl3.hs.client_random;
-    unsigned char *sr = (unsigned char *)&ss->ssl3.hs.server_random;
-    PRBool isTLS = (PRBool)(pwSpec->version > SSL_LIBRARY_VERSION_3_0);
+    PRBool isTLS = (PRBool)(ss->version > SSL_LIBRARY_VERSION_3_0);
     PRBool isTLS12 =
         (PRBool)(isTLS && pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
     const ssl3BulkCipherDef *cipher_def = pwSpec->cipher_def;
     PK11SlotInfo *slot = NULL;
     PK11SymKey *symKey = NULL;
     void *pwArg = ss->pkcs11PinArg;
     int keySize;
     CK_TLS12_KEY_MAT_PARAMS key_material_params; /* may be used as a
@@ -3904,19 +3881,19 @@ ssl3_DeriveConnectionKeys(sslSocket *ss)
         pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1) {
         /* Block ciphers in >= TLS 1.1 use a per-record, explicit IV. */
         key_material_params.ulIVSizeInBits = 0;
         memset(pwSpec->client.write_iv, 0, cipher_def->iv_size);
         memset(pwSpec->server.write_iv, 0, cipher_def->iv_size);
     }
 
     key_material_params.bIsExport = PR_FALSE;
-    key_material_params.RandomInfo.pClientRandom = cr;
+    key_material_params.RandomInfo.pClientRandom = ss->ssl3.hs.client_random;
     key_material_params.RandomInfo.ulClientRandomLen = SSL3_RANDOM_LENGTH;
-    key_material_params.RandomInfo.pServerRandom = sr;
+    key_material_params.RandomInfo.pServerRandom = ss->ssl3.hs.server_random;
     key_material_params.RandomInfo.ulServerRandomLen = SSL3_RANDOM_LENGTH;
     key_material_params.pReturnedKeyMaterial = &returnedKeys;
 
     returnedKeys.pIVClient = pwSpec->client.write_iv;
     returnedKeys.pIVServer = pwSpec->server.write_iv;
     keySize = cipher_def->key_size;
 
     if (skipKeysAndIVs) {
@@ -4934,16 +4911,28 @@ ssl_ClientHelloTypeName(sslClientHelloTy
         CHTYPE(renegotiation); /* TLS <= 1.2 only */
     }
     PORT_Assert(0);
     return NULL;
 }
 #undef CHTYPE
 #endif
 
+PR_STATIC_ASSERT(SSL3_SESSIONID_BYTES == SSL3_RANDOM_LENGTH);
+static void
+ssl_MakeFakeSid(sslSocket *ss, PRUint8 *buf)
+{
+    PRUint8 x = 0x5a;
+    int i;
+    for (i = 0; i < SSL3_SESSIONID_BYTES; ++i) {
+        x += ss->ssl3.hs.client_random[i];
+        buf[i] = x;
+    }
+}
+
 /* Called from ssl3_HandleHelloRequest(),
  *             ssl3_RedoHandshake()
  *             ssl_BeginClientHandshake (when resuming ssl3 session)
  *             dtls_HandleHelloVerifyRequest(with resending=PR_TRUE)
  *
  * The |type| argument indicates what is going on here:
  * - client_hello_initial is set for the very first ClientHello
  * - client_hello_retry indicates that this is a second attempt after receiving
@@ -5245,21 +5234,24 @@ ssl3_SendClientHello(sslSocket *ss, sslC
     /* count compression methods */
     numCompressionMethods = 0;
     for (i = 0; i < ssl_compression_method_count; i++) {
         if (ssl_CompressionEnabled(ss, ssl_compression_methods[i]))
             numCompressionMethods++;
     }
 
     length = sizeof(SSL3ProtocolVersion) + SSL3_RANDOM_LENGTH +
-             1 + (sid->version >= SSL_LIBRARY_VERSION_TLS_1_3
-                      ? 0
-                      : sid->u.ssl3.sessionIDLength) +
+             1 + /* session id length */
              2 + num_suites * sizeof(ssl3CipherSuite) +
              1 + numCompressionMethods + total_exten_len;
+    if (sid->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+        length += sid->u.ssl3.sessionIDLength;
+    } else if (ss->opt.enableAltHandshaketype && !IS_DTLS(ss)) {
+        length += SSL3_SESSIONID_BYTES;
+    }
     if (IS_DTLS(ss)) {
         length += 1 + ss->ssl3.hs.cookie.len;
     }
 
     if (total_exten_len > 0) {
         ssl3_CalculatePaddingExtLen(ss, length);
         if (ss->xtnData.paddingLen) {
             total_exten_len += 4 + ss->xtnData.paddingLen;
@@ -5293,38 +5285,45 @@ ssl3_SendClientHello(sslSocket *ss, sslC
         if (sid->u.ssl3.lock) {
             PR_RWLock_Unlock(sid->u.ssl3.lock);
         }
         return rv; /* err set by ssl3_AppendHandshake* */
     }
 
     /* Generate a new random if this is the first attempt. */
     if (type == client_hello_initial) {
-        rv = ssl3_GetNewRandom(&ss->ssl3.hs.client_random);
+        rv = ssl3_GetNewRandom(ss->ssl3.hs.client_random);
         if (rv != SECSuccess) {
             if (sid->u.ssl3.lock) {
                 PR_RWLock_Unlock(sid->u.ssl3.lock);
             }
             return rv; /* err set by GetNewRandom. */
         }
     }
-    rv = ssl3_AppendHandshake(ss, &ss->ssl3.hs.client_random,
+    rv = ssl3_AppendHandshake(ss, ss->ssl3.hs.client_random,
                               SSL3_RANDOM_LENGTH);
     if (rv != SECSuccess) {
         if (sid->u.ssl3.lock) {
             PR_RWLock_Unlock(sid->u.ssl3.lock);
         }
         return rv; /* err set by ssl3_AppendHandshake* */
     }
 
-    if (sid->version < SSL_LIBRARY_VERSION_TLS_1_3)
+    if (sid->version < SSL_LIBRARY_VERSION_TLS_1_3) {
         rv = ssl3_AppendHandshakeVariable(
             ss, sid->u.ssl3.sessionID, sid->u.ssl3.sessionIDLength, 1);
-    else
+    } else if (ss->opt.enableAltHandshaketype && !IS_DTLS(ss)) {
+        /* We're faking session resumption, so rather than create new
+         * randomness, just mix up the client random a little. */
+        PRUint8 buf[SSL3_SESSIONID_BYTES];
+        ssl_MakeFakeSid(ss, buf);
+        rv = ssl3_AppendHandshakeVariable(ss, buf, SSL3_SESSIONID_BYTES, 1);
+    } else {
         rv = ssl3_AppendHandshakeNumber(ss, 0, 1);
+    }
     if (rv != SECSuccess) {
         if (sid->u.ssl3.lock) {
             PR_RWLock_Unlock(sid->u.ssl3.lock);
         }
         return rv; /* err set by ssl3_AppendHandshake* */
     }
 
     if (IS_DTLS(ss)) {
@@ -5458,19 +5457,16 @@ ssl3_SendClientHello(sslSocket *ss, sslC
     if (ss->ssl3.hs.sendingSCSV) {
         /* Since we sent the SCSV, pretend we sent empty RI extension. */
         TLSExtensionData *xtnData = &ss->xtnData;
         xtnData->advertised[xtnData->numAdvertised++] =
             ssl_renegotiation_info_xtn;
     }
 
     flags = 0;
-    if (!ss->firstHsDone && !IS_DTLS(ss)) {
-        flags |= ssl_SEND_FLAG_CAP_RECORD_VERSION;
-    }
     rv = ssl3_FlushHandshake(ss, flags);
     if (rv != SECSuccess) {
         return rv; /* error code set by ssl3_FlushHandshake */
     }
 
     if (version >= SSL_LIBRARY_VERSION_TLS_1_3) {
         rv = tls13_MaybeDo0RTTHandshake(ss);
         if (rv != SECSuccess) {
@@ -6551,52 +6547,96 @@ done:
     if (buf.data)
         PORT_Free(buf.data);
     return rv;
 }
 
 /* Once a cipher suite has been selected, make sure that the necessary secondary
  * information is properly set. */
 SECStatus
-ssl3_SetCipherSuite(sslSocket *ss, ssl3CipherSuite chosenSuite,
-                    PRBool initHashes)
-{
-    ss->ssl3.hs.cipher_suite = chosenSuite;
-    ss->ssl3.hs.suite_def = ssl_LookupCipherSuiteDef(chosenSuite);
+ssl3_SetupCipherSuite(sslSocket *ss, PRBool initHashes)
+{
+    ss->ssl3.hs.suite_def = ssl_LookupCipherSuiteDef(ss->ssl3.hs.cipher_suite);
     if (!ss->ssl3.hs.suite_def) {
         PORT_Assert(0);
         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
         return SECFailure;
     }
 
     ss->ssl3.hs.kea_def = &kea_defs[ss->ssl3.hs.suite_def->key_exchange_alg];
     ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_cipher_suite;
 
     if (!initHashes) {
         return SECSuccess;
     }
-    /* Now we've have a cipher suite, initialize the handshake hashes. */
+    /* Now we have a cipher suite, initialize the handshake hashes. */
     return ssl3_InitHandshakeHashes(ss);
 }
 
+/* Once a cipher suite has been selected, make sure that the necessary secondary
+ * information is properly set. */
+SECStatus
+ssl3_SetCipherSuite(sslSocket *ss, ssl3CipherSuite chosenSuite,
+                    PRBool initHashes)
+{
+    ss->ssl3.hs.cipher_suite = chosenSuite;
+    return ssl3_SetupCipherSuite(ss, initHashes);
+}
+
+SECStatus
+ssl_ClientSetCipherSuite(sslSocket *ss, SSL3ProtocolVersion version,
+                         ssl3CipherSuite suite, PRBool initHashes)
+{
+    int i;
+
+    i = ssl3_config_match_init(ss);
+    PORT_Assert(i > 0);
+    if (i <= 0) {
+        return SECFailure;
+    }
+    for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) {
+        ssl3CipherSuiteCfg *suiteCfg = &ss->cipherSuites[i];
+        if (suite == suiteCfg->cipher_suite) {
+            SSLVersionRange vrange = { version, version };
+            if (!config_match(suiteCfg, 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(suite, &vrange)) {
+                    PORT_SetError(SSL_ERROR_CIPHER_DISALLOWED_FOR_VERSION);
+                } else {
+                    PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
+                }
+                return SECFailure;
+            }
+            break;
+        }
+    }
+    if (i >= ssl_V3_SUITES_IMPLEMENTED) {
+        PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
+        return SECFailure;
+    }
+
+    ss->ssl3.hs.cipher_suite = (ssl3CipherSuite)suite;
+    return ssl3_SetupCipherSuite(ss, initHashes);
+}
+
 /* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
  * ssl3 ServerHello message.
  * Caller must hold Handshake and RecvBuf locks.
  */
 static SECStatus
 ssl3_HandleServerHello(sslSocket *ss, PRUint8 *b, PRUint32 length)
 {
-    PRUint32 temp;
-    PRBool suite_found = PR_FALSE;
-    int i;
+    PRUint32 cipher;
     int errCode = SSL_ERROR_RX_MALFORMED_SERVER_HELLO;
     SECStatus rv;
     SECItem sidBytes = { siBuffer, NULL, 0 };
-    PRBool isTLS = PR_FALSE;
     SSL3AlertDescription desc = illegal_parameter;
+    TLSExtension *versionExtension;
 #ifndef TLS_1_3_DRAFT_VERSION
     SSL3ProtocolVersion downgradeCheckVersion;
 #endif
 
     SSL_TRC(3, ("%d: SSL3[%d]: handle server_hello handshake",
                 SSL_GETPID(), ss->fd));
     PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
@@ -6617,21 +6657,101 @@ ssl3_HandleServerHello(sslSocket *ss, PR
         CERT_DestroyCertificate(ss->ssl3.clientCertificate);
         ss->ssl3.clientCertificate = NULL;
     }
     if (ss->ssl3.clientPrivateKey != NULL) {
         SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
         ss->ssl3.clientPrivateKey = NULL;
     }
 
+    /* Note that if we are doing the alternative handshake for TLS 1.3, this
+     * will set the version to TLS 1.2.  We will amend that once all other
+     * fields have been read. */
     rv = ssl_ClientReadVersion(ss, &b, &length, &ss->version);
     if (rv != SECSuccess) {
         goto loser; /* alert has been sent */
     }
 
+    rv = ssl3_ConsumeHandshake(
+        ss, ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH, &b, &length);
+    if (rv != SECSuccess) {
+        goto loser; /* alert has been sent */
+    }
+
+    if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+        rv = ssl3_ConsumeHandshakeVariable(ss, &sidBytes, 1, &b, &length);
+        if (rv != SECSuccess) {
+            goto loser; /* alert has been sent */
+        }
+        if (sidBytes.len > SSL3_SESSIONID_BYTES) {
+            if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_0)
+                desc = decode_error;
+            goto alert_loser; /* malformed. */
+        }
+    }
+
+    /* Read the cipher suite. */
+    rv = ssl3_ConsumeHandshakeNumber(ss, &cipher, 2, &b, &length);
+    if (rv != SECSuccess) {
+        goto loser; /* alert has been sent */
+    }
+
+    /* Compression method. */
+    if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+        PRUint32 compression;
+        rv = ssl3_ConsumeHandshakeNumber(ss, &compression, 1, &b, &length);
+        if (rv != SECSuccess) {
+            goto loser; /* alert has been sent */
+        }
+        if (compression != ssl_compression_null) {
+            desc = illegal_parameter;
+            errCode = SSL_ERROR_RX_MALFORMED_SERVER_HELLO;
+            goto alert_loser;
+        }
+    }
+
+    /* Parse extensions. */
+    if (length != 0) {
+        PRUint32 extensionLength;
+        rv = ssl3_ConsumeHandshakeNumber(ss, &extensionLength, 2, &b, &length);
+        if (rv != SECSuccess) {
+            goto loser; /* alert already sent */
+        }
+        if (extensionLength != length) {
+            desc = decode_error;
+            goto alert_loser;
+        }
+        rv = ssl3_ParseExtensions(ss, &b, &length);
+        if (rv != SECSuccess) {
+            goto alert_loser; /* malformed */
+        }
+    }
+
+    /* Update the version based on the extension, as necessary. */
+    versionExtension = ssl3_FindExtension(ss, ssl_tls13_supported_versions_xtn);
+    if (versionExtension) {
+        rv = ssl_ClientReadVersion(ss, &versionExtension->data.data,
+                                   &versionExtension->data.len,
+                                   &ss->version);
+        if (rv != SECSuccess) {
+            errCode = PORT_GetError();
+            goto loser; /* An alert is sent by ssl_ClientReadVersion */
+        }
+    }
+
+    PORT_Assert(!SSL_ALL_VERSIONS_DISABLED(&ss->vrange));
+    /* Check that the version is within the configured range. */
+    if (ss->vrange.min > ss->version || ss->vrange.max < ss->version) {
+        desc = (ss->version > SSL_LIBRARY_VERSION_3_0)
+                   ? protocol_version
+                   : handshake_failure;
+        errCode = SSL_ERROR_UNSUPPORTED_VERSION;
+        goto alert_loser;
+    }
+
     /* The server didn't pick 1.3 although we either received a
      * HelloRetryRequest, or we prepared to send early app data. */
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
         if (ss->ssl3.hs.helloRetry) {
             /* SSL3_SendAlert() will uncache the SID. */
             desc = illegal_parameter;
             errCode = SSL_ERROR_RX_MALFORMED_SERVER_HELLO;
             goto alert_loser;
@@ -6648,24 +6768,16 @@ ssl3_HandleServerHello(sslSocket *ss, PR
      * in the first handshake. This isn't really the best place for
      * us to be getting this version number, but it's what we have.
      * (1294697). */
     if (ss->firstHsDone && (ss->version != ss->ssl3.crSpec->version)) {
         desc = illegal_parameter;
         errCode = SSL_ERROR_UNSUPPORTED_VERSION;
         goto alert_loser;
     }
-    ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_version;
-    isTLS = (ss->version > SSL_LIBRARY_VERSION_3_0);
-
-    rv = ssl3_ConsumeHandshake(
-        ss, &ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH, &b, &length);
-    if (rv != SECSuccess) {
-        goto loser; /* alert has been sent */
-    }
 
 #ifndef TLS_1_3_DRAFT_VERSION
     /* Check the ServerHello.random per
      * [draft-ietf-tls-tls13-11 Section 6.3.1.1].
      *
      * TLS 1.3 clients receiving a TLS 1.2 or below ServerHello MUST check
      * that the top eight octets are not equal to either of these values.
      * TLS 1.2 clients SHOULD also perform this check if the ServerHello
@@ -6675,138 +6787,74 @@ ssl3_HandleServerHello(sslSocket *ss, PR
      * Disable this test during the TLS 1.3 draft version period.
      */
     downgradeCheckVersion = ss->ssl3.downgradeCheckVersion ? ss->ssl3.downgradeCheckVersion
                                                            : ss->vrange.max;
 
     if (downgradeCheckVersion >= SSL_LIBRARY_VERSION_TLS_1_2 &&
         downgradeCheckVersion > ss->version) {
         /* Both sections use the same sentinel region. */
-        unsigned char *downgrade_sentinel =
-            ss->ssl3.hs.server_random.rand +
+        PRUint8 *downgrade_sentinel =
+            ss->ssl3.hs.server_random +
             SSL3_RANDOM_LENGTH - sizeof(tls13_downgrade_random);
         if (!PORT_Memcmp(downgrade_sentinel,
                          tls13_downgrade_random,
                          sizeof(tls13_downgrade_random)) ||
             !PORT_Memcmp(downgrade_sentinel,
                          tls12_downgrade_random,
                          sizeof(tls12_downgrade_random))) {
             desc = illegal_parameter;
             errCode = SSL_ERROR_RX_MALFORMED_SERVER_HELLO;
             goto alert_loser;
         }
     }
 #endif
 
-    if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
-        rv = ssl3_ConsumeHandshakeVariable(ss, &sidBytes, 1, &b, &length);
-        if (rv != SECSuccess) {
-            goto loser; /* alert has been sent */
-        }
-        if (sidBytes.len > SSL3_SESSIONID_BYTES) {
-            if (isTLS)
-                desc = decode_error;
-            goto alert_loser; /* malformed. */
-        }
-    }
-
-    /* find selected cipher suite in our list. */
-    rv = ssl3_ConsumeHandshakeNumber(ss, &temp, 2, &b, &length);
-    if (rv != SECSuccess) {
-        goto loser; /* alert has been sent */
-    }
-    i = ssl3_config_match_init(ss);
-    PORT_Assert(i > 0);
-    if (i <= 0) {
+    /* Finally, now all the version-related checks have passed. */
+    ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_version;
+    /* Update the write cipher spec to match the version. */
+    if (!ss->firstHsDone) {
+        ssl_GetSpecWriteLock(ss);
+        ssl_SetSpecVersions(ss, ss->ssl3.cwSpec);
+        ssl_ReleaseSpecWriteLock(ss);
+    }
+
+    /* Check that the session ID is as expected. */
+    if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
+        PRUint8 buf[SSL3_SESSIONID_BYTES];
+        unsigned int expectedSidLen;
+        if (ss->ssl3.hs.altHandshakeType) {
+            expectedSidLen = SSL3_SESSIONID_BYTES;
+            ssl_MakeFakeSid(ss, buf);
+        } else {
+            expectedSidLen = 0;
+        }
+        if (sidBytes.len != expectedSidLen ||
+            PORT_Memcmp(buf, sidBytes.data, expectedSidLen) != 0) {
+            desc = illegal_parameter;
+            errCode = SSL_ERROR_RX_MALFORMED_SERVER_HELLO;
+            goto alert_loser;
+        }
+    }
+
+    /* Set compression (to be removed soon), and cipher suite. */
+    ss->ssl3.hs.compression = ssl_compression_null;
+    rv = ssl_ClientSetCipherSuite(ss, ss->version, cipher,
+                                  PR_TRUE /* init hashes */);
+    if (rv != SECSuccess) {
         errCode = PORT_GetError();
         goto loser;
     }
-    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, &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;
-                }
-
-                break; /* failure */
-            }
-
-            suite_found = PR_TRUE;
-            break; /* success */
-        }
-    }
-    if (!suite_found) {
-        desc = handshake_failure;
-        errCode = SSL_ERROR_NO_CYPHER_OVERLAP;
-        goto alert_loser;
-    }
-
-    rv = ssl3_SetCipherSuite(ss, (ssl3CipherSuite)temp, PR_TRUE);
-    if (rv != SECSuccess) {
-        desc = internal_error;
-        errCode = PORT_GetError();
+
+    rv = ssl3_HandleParsedExtensions(ss, server_hello);
+    ssl3_DestroyRemoteExtensions(&ss->ssl3.hs.remoteExtensions);
+    if (rv != SECSuccess) {
         goto alert_loser;
     }
 
-    if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
-        /* find selected compression method in our list. */
-        rv = ssl3_ConsumeHandshakeNumber(ss, &temp, 1, &b, &length);
-        if (rv != SECSuccess) {
-            goto loser; /* alert has been sent */
-        }
-        suite_found = PR_FALSE;
-        for (i = 0; i < ssl_compression_method_count; i++) {
-            if (temp == ssl_compression_methods[i]) {
-                if (!ssl_CompressionEnabled(ss, ssl_compression_methods[i])) {
-                    break; /* failure */
-                }
-                suite_found = PR_TRUE;
-                break; /* success */
-            }
-        }
-        if (!suite_found) {
-            desc = handshake_failure;
-            errCode = SSL_ERROR_NO_COMPRESSION_OVERLAP;
-            goto alert_loser;
-        }
-        ss->ssl3.hs.compression = (SSLCompressionMethod)temp;
-    } else {
-        ss->ssl3.hs.compression = ssl_compression_null;
-    }
-
-    /* Note that if !isTLS and the extra stuff is not extensions, we
-     * do NOT goto alert_loser.
-     * There are some old SSL 3.0 implementations that do send stuff
-     * after the end of the server hello, and we deliberately ignore
-     * such stuff in the interest of maximal interoperability (being
-     * "generous in what you accept").
-     * Update: Starting in NSS 3.12.6, we handle the renegotiation_info
-     * extension in SSL 3.0.
-     */
-    if (length != 0) {
-        SECItem extensions;
-        rv = ssl3_ConsumeHandshakeVariable(ss, &extensions, 2, &b, &length);
-        if (rv != SECSuccess || length != 0) {
-            if (isTLS)
-                goto alert_loser;
-        } else {
-            rv = ssl3_HandleExtensions(ss, &extensions.data,
-                                       &extensions.len, server_hello);
-            if (rv != SECSuccess)
-                goto alert_loser;
-        }
-    }
-
     if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
         rv = tls13_HandleServerHelloPart2(ss);
         if (rv != SECSuccess) {
             errCode = PORT_GetError();
             goto loser;
         }
     } else {
         rv = ssl3_HandleServerHelloPart2(ss, &sidBytes, &errCode);
@@ -7923,16 +7971,17 @@ ssl3_NewSessionID(sslSocket *ss, PRBool 
     sid->version = ss->version;
     sid->sigScheme = ssl_sig_none;
 
     sid->u.ssl3.keys.resumable = PR_TRUE;
     sid->u.ssl3.policy = SSL_ALLOWED;
     sid->u.ssl3.clientWriteKey = NULL;
     sid->u.ssl3.serverWriteKey = NULL;
     sid->u.ssl3.keys.extendedMasterSecretUsed = PR_FALSE;
+    sid->u.ssl3.altHandshakeType = ss->ssl3.hs.altHandshakeType;
 
     if (is_server) {
         SECStatus rv;
         int pid = SSL_GETPID();
 
         sid->u.ssl3.sessionIDLength = SSL3_SESSIONID_BYTES;
         sid->u.ssl3.sessionID[0] = (pid >> 8) & 0xff;
         sid->u.ssl3.sessionID[1] = pid & 0xff;
@@ -8339,17 +8388,17 @@ ssl3_HandleClientHello(sslSocket *ss, PR
         ss->clientHelloVersion = version =
             dtls_DTLSVersionToTLSVersion((SSL3ProtocolVersion)tmp);
     } else {
         ss->clientHelloVersion = version = (SSL3ProtocolVersion)tmp;
     }
 
     /* Grab the client random data. */
     rv = ssl3_ConsumeHandshake(
-        ss, &ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH, &b, &length);
+        ss, ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH, &b, &length);
     if (rv != SECSuccess) {
         goto loser; /* malformed */
     }
 
     /* Grab the client's SID, if present. */
     rv = ssl3_ConsumeHandshakeVariable(ss, &sidBytes, 1, &b, &length);
     if (rv != SECSuccess) {
         goto loser; /* malformed */
@@ -8379,24 +8428,25 @@ ssl3_HandleClientHello(sslSocket *ss, PR
      * we are restarting a previous session until extensions have been
      * parsed, since we might have received a SessionTicket extension.
      * Note: we allow extensions even when negotiating SSL3 for the sake
      * of interoperability (and backwards compatibility).
      */
 
     if (length) {
         /* Get length of hello extensions */
-        PRUint32 extension_length;
-        rv = ssl3_ConsumeHandshakeNumber(ss, &extension_length, 2, &b, &length);
+        PRUint32 extensionLength;
+        rv = ssl3_ConsumeHandshakeNumber(ss, &extensionLength, 2, &b, &length);
         if (rv != SECSuccess) {
             goto loser; /* alert already sent */
         }
-        if (extension_length != length) {
-            ssl3_DecodeError(ss); /* send alert */
-            goto loser;
+        if (extensionLength != length) {
+            errCode = SSL_ERROR_RX_MALFORMED_CLIENT_HELLO;
+            desc = decode_error;
+            goto alert_loser;
         }
 
         rv = ssl3_ParseExtensions(ss, &b, &length);
         if (rv != SECSuccess) {
             goto loser; /* malformed */
         }
     }
 
@@ -8417,27 +8467,44 @@ ssl3_HandleClientHello(sslSocket *ss, PR
                                    PR_TRUE);
         if (rv != SECSuccess) {
             desc = (version > SSL_LIBRARY_VERSION_3_0) ? protocol_version
                                                        : handshake_failure;
             errCode = SSL_ERROR_UNSUPPORTED_VERSION;
             goto alert_loser;
         }
     }
+
+    if (ss->firstHsDone && ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
+        desc = unexpected_message;
+        errCode = SSL_ERROR_RENEGOTIATION_NOT_ALLOWED;
+        goto alert_loser;
+    }
+
     isTLS13 = ss->version >= SSL_LIBRARY_VERSION_TLS_1_3;
     ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_version;
-
-    /* You can't resume TLS 1.3 like this. */
-    if (isTLS13 && sidBytes.len) {
-        goto alert_loser;
+    /* Update the write spec to match the selected version. */
+    if (!ss->firstHsDone) {
+        ssl_GetSpecWriteLock(ss);
+        ssl_SetSpecVersions(ss, ss->ssl3.cwSpec);
+        ssl_ReleaseSpecWriteLock(ss);
+    }
+
+    if (ss->ssl3.hs.altHandshakeType) {
+        rv = SECITEM_CopyItem(NULL, &ss->ssl3.hs.fakeSid, &sidBytes);
+        if (rv != SECSuccess) {
+            desc = internal_error;
+            errCode = PORT_GetError();
+            goto alert_loser;
+        }
     }
 
     /* Generate the Server Random now so it is available
      * when we process the ClientKeyShare in TLS 1.3 */
-    rv = ssl3_GetNewRandom(&ss->ssl3.hs.server_random);
+    rv = ssl3_GetNewRandom(ss->ssl3.hs.server_random);
     if (rv != SECSuccess) {
         errCode = SSL_ERROR_GENERATE_RANDOM_FAILURE;
         goto loser;
     }
 
 #ifndef TLS_1_3_DRAFT_VERSION
     /*
      * [draft-ietf-tls-tls13-11 Section 6.3.1.1].
@@ -8453,18 +8520,18 @@ ssl3_HandleClientHello(sslSocket *ss, PR
      *
      * 44 4F 57 4E 47 52 44 00
      *
      * TODO(ekr@rtfm.com): Note this change was not added in the SSLv2
      * compat processing code since that will most likely be removed before
      * we ship the final version of TLS 1.3. Bug 1306672.
      */
     if (ss->vrange.max > ss->version) {
-        unsigned char *downgrade_sentinel =
-            ss->ssl3.hs.server_random.rand +
+        PRUint8 *downgrade_sentinel =
+            ss->ssl3.hs.server_random +
             SSL3_RANDOM_LENGTH - sizeof(tls13_downgrade_random);
 
         switch (ss->vrange.max) {
             case SSL_LIBRARY_VERSION_TLS_1_3:
                 PORT_Memcpy(downgrade_sentinel,
                             tls13_downgrade_random,
                             sizeof(tls13_downgrade_random));
                 break;
@@ -8477,16 +8544,17 @@ ssl3_HandleClientHello(sslSocket *ss, PR
                 /* Do not change random. */
                 break;
         }
     }
 #endif
 
     /* Now parse the rest of the extensions. */
     rv = ssl3_HandleParsedExtensions(ss, client_hello);
+    ssl3_DestroyRemoteExtensions(&ss->ssl3.hs.remoteExtensions);
     if (rv != SECSuccess) {
         goto loser; /* malformed */
     }
 
     /* If the ClientHello version is less than our maximum version, check for a
      * TLS_FALLBACK_SCSV and reject the connection if found. */
     if (ss->vrange.max > ss->version) {
         for (i = 0; i + 1 < suites.len; i += 2) {
@@ -8517,26 +8585,18 @@ ssl3_HandleClientHello(sslSocket *ss, PR
                 PRUint8 *b2 = (PRUint8 *)emptyRIext;
                 PRUint32 L2 = sizeof emptyRIext;
                 (void)ssl3_HandleExtensions(ss, &b2, &L2, client_hello);
                 break;
             }
         }
     }
 
-    /* This is a second check for TLS 1.3 and re-handshake to stop us
-     * from re-handshake up to TLS 1.3, so it happens after version
-     * negotiation. */
-    if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
-        if (ss->firstHsDone) {
-            desc = unexpected_message;
-            errCode = SSL_ERROR_RENEGOTIATION_NOT_ALLOWED;
-            goto alert_loser;
-        }
-    } else {
+    /* The check for renegotiation in TLS 1.3 is earlier. */
+    if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
         if (ss->firstHsDone &&
             (ss->opt.enableRenegotiation == SSL_RENEGOTIATE_REQUIRES_XTN ||
              ss->opt.enableRenegotiation == SSL_RENEGOTIATE_TRANSITIONAL) &&
             !ssl3_ExtensionNegotiated(ss, ssl_renegotiation_info_xtn)) {
             desc = no_renegotiation;
             level = alert_warning;
             errCode = SSL_ERROR_RENEGOTIATION_NOT_ALLOWED;
             goto alert_loser;
@@ -9119,16 +9179,21 @@ ssl3_HandleV2ClientHello(sslSocket *ss, 
     if (rv != SECSuccess) {
         /* send back which ever alert client will understand. */
         desc = (version > SSL_LIBRARY_VERSION_3_0) ? protocol_version
                                                    : handshake_failure;
         errCode = SSL_ERROR_UNSUPPORTED_VERSION;
         goto alert_loser;
     }
     ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_version;
+    if (!ss->firstHsDone) {
+        ssl_GetSpecWriteLock(ss);
+        ssl_SetSpecVersions(ss, ss->ssl3.cwSpec);
+        ssl_ReleaseSpecWriteLock(ss);
+    }
 
     /* if we get a non-zero SID, just ignore it. */
     if (length != total) {
         SSL_DBG(("%d: SSL3[%d]: bad v2 client hello message, len=%d should=%d",
                  SSL_GETPID(), ss->fd, length, total));
         desc = illegal_parameter;
         errCode = SSL_ERROR_RX_MALFORMED_CLIENT_HELLO;
         goto alert_loser;
@@ -9141,22 +9206,21 @@ ssl3_HandleV2ClientHello(sslSocket *ss, 
         rand_length > SSL_MAX_CHALLENGE_BYTES) {
         desc = illegal_parameter;
         errCode = SSL_ERROR_RX_MALFORMED_CLIENT_HELLO;
         goto alert_loser;
     }
 
     PORT_Assert(SSL_MAX_CHALLENGE_BYTES == SSL3_RANDOM_LENGTH);
 
-    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],
+    PORT_Memset(ss->ssl3.hs.client_random, 0, SSL3_RANDOM_LENGTH);
+    PORT_Memcpy(&ss->ssl3.hs.client_random[SSL3_RANDOM_LENGTH - rand_length],
+                random, rand_length);
+
+    PRINT_BUF(60, (ss, "client random:", ss->ssl3.hs.client_random,
                    SSL3_RANDOM_LENGTH));
     i = ssl3_config_match_init(ss);
     if (i <= 0) {
         errCode = PORT_GetError(); /* error code is already set. */
         goto alert_loser;
     }
 
     /* Select a cipher suite.
@@ -9298,68 +9362,82 @@ ssl3_SendServerHello(sslSocket *ss)
 
     sid = ss->sec.ci.sid;
 
     extensions_len = ssl3_CallHelloExtensionSenders(
         ss, PR_FALSE, maxBytes, &ss->xtnData.serverHelloSenders[0]);
     if (extensions_len > 0)
         extensions_len += 2; /* Add sizeof total extension length */
 
-    /* TLS 1.3 doesn't use the session_id or compression_method
-     * fields in the ServerHello. */
     length = sizeof(SSL3ProtocolVersion) + SSL3_RANDOM_LENGTH;
+
+    /* Adjust for session ID.  In TLS 1.3 proper it isn't even present.  In the
+     * alternative TLS 1.3 handshake, it is copied from the client. */
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
-        length += 1 + ((sid == NULL) ? 0 : sid->u.ssl3.sessionIDLength);
+        length += 1; /* Session ID Length */
+        if (sid) {
+            length += sid->u.ssl3.sessionIDLength;
+        }
+    } else if (ss->ssl3.hs.altHandshakeType) {
+        length += 1 + ss->ssl3.hs.fakeSid.len;
     }
     length += sizeof(ssl3CipherSuite);
-    if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
-        length += 1; /* Compression */
+    if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3 ||
+        ss->ssl3.hs.altHandshakeType) {
+        length += 1; /* Compression. */
     }
     length += extensions_len;
 
     rv = ssl3_AppendHandshakeHeader(ss, server_hello, length);
     if (rv != SECSuccess) {
         return rv; /* err set by AppendHandshake. */
     }
 
     if (IS_DTLS(ss) && ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
         version = dtls_TLSVersionToDTLSVersion(ss->version);
-    } else {
-        version = ss->ssl3.hs.altHandshakeType ? tls13_EncodeAltDraftVersion(ss->version) : tls13_EncodeDraftVersion(ss->version);
+    } else if (ss->ssl3.hs.altHandshakeType) {
+        version = SSL_LIBRARY_VERSION_TLS_1_2;
+    } else {
+        version = tls13_EncodeDraftVersion(ss->version);
     }
 
     rv = ssl3_AppendHandshakeNumber(ss, version, 2);
     if (rv != SECSuccess) {
         return rv; /* err set by AppendHandshake. */
     }
     /* Random already generated in ssl3_HandleClientHello */
     rv = ssl3_AppendHandshake(
-        ss, &ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH);
+        ss, ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH);
     if (rv != SECSuccess) {
         return rv; /* err set by AppendHandshake. */
     }
 
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
         if (sid) {
             rv = ssl3_AppendHandshakeVariable(
                 ss, sid->u.ssl3.sessionID, sid->u.ssl3.sessionIDLength, 1);
         } else {
             rv = ssl3_AppendHandshakeNumber(ss, 0, 1);
         }
-        if (rv != SECSuccess) {
-            return rv; /* err set by AppendHandshake. */
-        }
+    } else if (ss->ssl3.hs.altHandshakeType) {
+        rv = ssl3_AppendHandshakeVariable(ss, ss->ssl3.hs.fakeSid.data,
+                                          ss->ssl3.hs.fakeSid.len, 1);
+        SECITEM_FreeItem(&ss->ssl3.hs.fakeSid, PR_FALSE);
+    }
+    if (rv != SECSuccess) {
+        return SECFailure; /* err set by AppendHandshake. */
     }
 
     rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.hs.cipher_suite, 2);
     if (rv != SECSuccess) {
         return rv; /* err set by AppendHandshake. */
     }
-    if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
-        rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.hs.compression, 1);
+    if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3 ||
+        ss->ssl3.hs.altHandshakeType) {
+        rv = ssl3_AppendHandshakeNumber(ss, ssl_compression_null, 1);
         if (rv != SECSuccess) {
             return rv; /* err set by AppendHandshake. */
         }
     }
     if (extensions_len) {
         PRInt32 sent_len;
 
         extensions_len -= 2;
@@ -11188,17 +11266,17 @@ ssl3_RecordKeyLog(sslSocket *ss, const c
 
     /* There could be multiple, concurrent writers to the
      * keylog, so we have to do everything in a single call to
      * fwrite. */
 
     strcpy(buf, label);
     offset = strlen(label);
     buf[offset++] += ' ';
-    hexEncode(buf + offset, ss->ssl3.hs.client_random.rand, SSL3_RANDOM_LENGTH);
+    hexEncode(buf + offset, ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH);
     offset += SSL3_RANDOM_LENGTH * 2;
     buf[offset++] = ' ';
     hexEncode(buf + offset, keyData->data, keyData->len);
     offset += keyData->len * 2;
     buf[offset++] = '\n';
 
     PORT_Assert(offset == len);
 
@@ -11557,16 +11635,17 @@ ssl3_FillInCachedSID(sslSocket *ss, sslS
 
     if (ss->xtnData.nextProtoState != SSL_NEXT_PROTO_NO_SUPPORT &&
         ss->xtnData.nextProto.data) {
         if (SECITEM_CopyItem(
                 NULL, &sid->u.ssl3.alpnSelection, &ss->xtnData.nextProto) != SECSuccess) {
             return SECFailure; /* error already set. */
         }
     }
+    sid->u.ssl3.altHandshakeType = ss->ssl3.hs.altHandshakeType;
 
     ssl_GetSpecReadLock(ss); /*************************************/
 
     /* Copy the master secret (wrapped or unwrapped) into the sid */
     if (ss->ssl3.crSpec->msItem.len && ss->ssl3.crSpec->msItem.data) {
         sid->u.ssl3.keys.wrapped_master_secret_len =
             ss->ssl3.crSpec->msItem.len;
         memcpy(sid->u.ssl3.keys.wrapped_master_secret,
@@ -12371,17 +12450,17 @@ ssl3_UnprotectRecord(sslSocket *ss, SSL3
         /* XXX For many AEAD ciphers, the plaintext is shorter than the
          * ciphertext by a fixed byte count, but it is not true in general.
          * Each AEAD cipher should provide a function that returns the
          * plaintext length for a given ciphertext. */
         unsigned int decryptedLen =
             cText->buf->len - cipher_def->explicit_nonce_size -
             cipher_def->tag_size;
         headerLen = ssl3_BuildRecordPseudoHeader(
-            header, IS_DTLS(ss) ? cText->seq_num : crSpec->read_seq_num,
+            header, crSpec->epoch, IS_DTLS(ss) ? cText->seq_num : crSpec->read_seq_num,
             rType, isTLS, cText->version, IS_DTLS(ss), decryptedLen);
         PORT_Assert(headerLen <= sizeof(header));
         rv = crSpec->aead(
             ss->sec.isServer ? &crSpec->client : &crSpec->server,
             PR_TRUE,                /* do decrypt */
             plaintext->buf,         /* out */
             (int *)&plaintext->len, /* outlen */
             plaintext->space,       /* maxout */
@@ -12420,17 +12499,18 @@ ssl3_UnprotectRecord(sslSocket *ss, SSL3
             } else {
                 good &= SECStatusToMask(ssl_RemoveTLSCBCPadding(
                     plaintext, macSize));
             }
         }
 
         /* compute the MAC */
         headerLen = ssl3_BuildRecordPseudoHeader(
-            header, IS_DTLS(ss) ? cText->seq_num : crSpec->read_seq_num,
+            header, crSpec->epoch,
+            IS_DTLS(ss) ? cText->seq_num : crSpec->read_seq_num,
             rType, isTLS, cText->version, IS_DTLS(ss),
             plaintext->len - crSpec->mac_size);
         PORT_Assert(headerLen <= sizeof(header));
         if (cipher_def->type == type_block) {
             rv = ssl3_ComputeRecordMACConstantTime(
                 crSpec, (PRBool)(!ss->sec.isServer), header, headerLen,
                 plaintext->buf, plaintext->len, originalLen,
                 hash, &hashBytes);
@@ -12611,21 +12691,36 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Cip
     if (rv != SECSuccess) {
         ssl_ReleaseSpecReadLock(ss); /***************************/
 
         SSL_DBG(("%d: SSL3[%d]: decryption failed", SSL_GETPID(), ss->fd));
 
         /* Clear the temp buffer used for decompression upon failure. */
         sslBuffer_Clear(&temp_buf);
 
+        /* Zero the input so that we don't process it again. */
+        databuf->len = 0;
+
+        /* Ignore a CCS if the alternative handshake is negotiated.  Note that
+         * this will fail if the server fails to negotiate the alternative
+         * handshake type in a 0-RTT session that is resumed from a session that
+         * did negotiate it.  We don't care about that corner case right now. */
+        if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 &&
+            cText->type == content_change_cipher_spec &&
+            ss->ssl3.hs.ws != idle_handshake &&
+            ss->ssl3.hs.altHandshakeType &&
+            cText->buf->len == 1 &&
+            cText->buf->buf[0] == change_cipher_spec_choice) {
+            /* Ignore the error. */
+            return SECSuccess;
+        }
         if (IS_DTLS(ss) ||
             (ss->sec.isServer &&
              ss->ssl3.hs.zeroRttIgnore == ssl_0rtt_ignore_trial)) {
             /* Silently drop the packet */
-            databuf->len = 0; /* Needed to ensure data not left around */
             return SECSuccess;
         } else {
             int errCode = PORT_GetError();
             SSL3_SendAlert(ss, alert_fatal, alert);
             /* Reset the error code in case SSL3_SendAlert called
              * PORT_SetError(). */
             PORT_SetError(errCode);
             return SECFailure;
@@ -12704,17 +12799,17 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Cip
         }
 
         sslBuffer_Clear(&temp_buf);
     }
 
     /*
     ** Having completed the decompression, check the length again.
     */
-    if (isTLS && databuf->len > (MAX_FRAGMENT_LENGTH + 1024)) {
+    if (isTLS && databuf->len > MAX_FRAGMENT_LENGTH) {
         SSL3_SendAlert(ss, alert_fatal, record_overflow);
         PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG);
         return SECFailure;
     }
 
     /* Application data records are processed by the caller of this
     ** function, not by this function.
     */
@@ -12854,17 +12949,37 @@ ssl3_InitState(sslSocket *ss)
 
     ssl_InitSecState(&ss->sec);
 
     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.crSpec->version = ss->vrange.max;
+    if (IS_DTLS(ss)) {
+        ss->ssl3.crSpec->recordVersion = SSL_LIBRARY_VERSION_DTLS_1_0_WIRE;
+    } else {
+        /* For new connections, cap the record layer version number of TLS
+         * ClientHello to { 3, 1 } (TLS 1.0). Some TLS 1.0 servers (which seem
+         * to use F5 BIG-IP) ignore ClientHello.client_version and use the
+         * record layer version number (TLSPlaintext.version) instead when
+         * negotiating protocol versions. In addition, if the record layer
+         * version number of ClientHello is { 3, 2 } (TLS 1.1) or higher, these
+         * servers reset the TCP connections. Lastly, some F5 BIG-IP servers
+         * hang if a record containing a ClientHello has a version greater than
+         * { 3, 1 } and a length greater than 255. Set this flag to work around
+         * such servers.
+         *
+         * We bump the version up when we settle on a version.  Before producing
+         * an initial ServerHello, or when processing it.
+         */
+        ss->ssl3.crSpec->recordVersion = PR_MIN(SSL_LIBRARY_VERSION_TLS_1_0,
+                                                ss->vrange.max);
+    }
     ssl_ReleaseSpecWriteLock(ss);
 
     ss->ssl3.hs.sendingSCSV = PR_FALSE;
     ss->ssl3.hs.preliminaryInfo = 0;
     ss->ssl3.hs.ws = (ss->sec.isServer) ? wait_client_hello : wait_server_hello;
 
     ssl3_ResetExtensionData(&ss->xtnData);
     PR_INIT_CLIST(&ss->ssl3.hs.remoteExtensions);
@@ -13223,16 +13338,17 @@ ssl3_DestroySSL3Info(sslSocket *ss)
         sslBuffer_Clear(&ss->ssl3.hs.messages);
     }
 
     /* free the SSL3Buffer (msg_body) */
     PORT_Free(ss->ssl3.hs.msg_body.buf);
 
     SECITEM_FreeItem(&ss->ssl3.hs.newSessionTicket.ticket, PR_FALSE);
     SECITEM_FreeItem(&ss->ssl3.hs.srvVirtName, PR_FALSE);
+    SECITEM_FreeItem(&ss->ssl3.hs.fakeSid, PR_FALSE);
 
     if (ss->ssl3.hs.certificateRequest) {
         PORT_FreeArena(ss->ssl3.hs.certificateRequest->arena, PR_FALSE);
         ss->ssl3.hs.certificateRequest = NULL;
     }
 
     /* free up the CipherSpecs */
     ssl3_DestroyCipherSpec(&ss->ssl3.specs[0], PR_TRUE /*freeSrvName*/);
--- a/security/nss/lib/ssl/ssl3ecc.c
+++ b/security/nss/lib/ssl/ssl3ecc.c
@@ -106,17 +106,17 @@ ssl_ECPubKey2NamedGroup(const SECKEYPubl
 
     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,
+                        PRUint8 *client_rand, PRUint8 *server_rand,
                         SSL3Hashes *hashes)
 {
     PRUint8 *hashBuf;
     PRUint8 *pBuf;
     SECStatus rv = SECSuccess;
     unsigned int bufLen;
     /*
      * We only support named curves (the appropriate checks are made before this
@@ -592,18 +592,18 @@ 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(hashAlg, ec_params, ec_point,
-                                 &ss->ssl3.hs.client_random,
-                                 &ss->ssl3.hs.server_random,
+                                 ss->ssl3.hs.client_random,
+                                 ss->ssl3.hs.server_random,
                                  &hashes);
 
     if (rv != SECSuccess) {
         errCode =
             ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
         goto alert_loser;
     }
     rv = ssl3_VerifySignedHashes(ss, sigScheme, &hashes, &signature);
@@ -706,18 +706,18 @@ ssl3_SendECDHServerKeyExchange(sslSocket
     if (ss->ssl3.pwSpec->version == SSL_LIBRARY_VERSION_TLS_1_2) {
         hashAlg = ssl_SignatureSchemeToHashType(ss->ssl3.hs.signatureScheme);
     } else {
         /* Use ssl_hash_none to represent the MD5+SHA1 combo. */
         hashAlg = ssl_hash_none;
     }
     rv = ssl3_ComputeECDHKeyHash(hashAlg, ec_params,
                                  pubKey->u.ec.publicValue,
-                                 &ss->ssl3.hs.client_random,
-                                 &ss->ssl3.hs.server_random,
+                                 ss->ssl3.hs.client_random,
+                                 ss->ssl3.hs.server_random,
                                  &hashes);
     if (rv != SECSuccess) {
         ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
         goto loser;
     }
 
     isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
 
--- a/security/nss/lib/ssl/ssl3exthandle.c
+++ b/security/nss/lib/ssl/ssl3exthandle.c
@@ -797,17 +797,17 @@ ssl3_ClientHandleStatusRequestXtn(const 
     }
 
     /* Keep track of negotiated extensions. */
     xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
     return SECSuccess;
 }
 
 PRUint32 ssl_ticket_lifetime = 2 * 24 * 60 * 60; /* 2 days in seconds */
-#define TLS_EX_SESS_TICKET_VERSION (0x0106)
+#define TLS_EX_SESS_TICKET_VERSION (0x0107)
 
 /*
  * Called from ssl3_SendNewSessionTicket, tls13_SendNewSessionTicket
  */
 SECStatus
 ssl3_EncodeSessionTicket(sslSocket *ss,
                          const NewSessionTicket *ticket,
                          SECItem *ticket_data)
@@ -889,16 +889,17 @@ ssl3_EncodeSessionTicket(sslSocket *ss,
         + 2                                    /* master_secret.length */
         + ms_item.len                          /* master_secret */
         + 1                                    /* client_auth_type */
         + cert_length                          /* cert */
         + 2 + srvName->len                     /* name len + length field */
         + 1                                    /* extendedMasterSecretUsed */
         + sizeof(ticket->ticket_lifetime_hint) /* ticket lifetime hint */
         + sizeof(ticket->flags)                /* ticket flags */
+        + 1                                    /* alt handshake type */
         + 1 + alpnSelection->len               /* alpn value + length field */
         + 4;                                   /* maxEarlyData */
 
     if (SECITEM_AllocItem(NULL, &plaintext_item, plaintext_length) == NULL)
         goto loser;
 
     plaintext = plaintext_item;
 
@@ -1035,16 +1036,21 @@ ssl3_EncodeSessionTicket(sslSocket *ss,
     if (rv != SECSuccess)
         goto loser;
     if (alpnSelection->len) {
         rv = ssl3_AppendToItem(&plaintext, alpnSelection->data,
                                alpnSelection->len);
         if (rv != SECSuccess)
             goto loser;
     }
+    /* Alternative handshake type. */
+    rv = ssl3_AppendNumberToItem(
+        &plaintext, ss->sec.ci.sid->u.ssl3.altHandshakeType, 1);
+    if (rv != SECSuccess)
+        goto loser;
 
     rv = ssl3_AppendNumberToItem(&plaintext, ssl_max_early_data_size, 4);
     if (rv != SECSuccess)
         goto loser;
 
     /* Check that we are totally full. */
     PORT_Assert(plaintext.len == 0);
 
@@ -1301,16 +1307,24 @@ ssl_ParseSessionTicket(sslSocket *ss, co
     rv = ssl3_ExtConsumeHandshakeVariable(ss, &parsedTicket->alpnSelection, 1,
                                           &buffer, &len);
     PORT_Assert(parsedTicket->alpnSelection.len < 256);
     if (rv != SECSuccess) {
         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
         return SECFailure;
     }
 
+    rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &len);
+    if (rv != SECSuccess) {
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        return SECFailure;
+    }
+    PORT_Assert(temp == PR_TRUE || temp == PR_FALSE);
+    parsedTicket->altHandshakeType = temp;
+
     rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &len);
     if (rv != SECSuccess) {
         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
         return SECFailure;
     }
     parsedTicket->maxEarlyData = temp;
 
 #ifndef UNSAFE_FUZZER_MODE
@@ -1365,16 +1379,17 @@ ssl_CreateSIDFromTicket(sslSocket *ss, c
     PORT_Memcpy(sid->u.ssl3.keys.wrapped_master_secret,
                 parsedTicket->master_secret, parsedTicket->ms_length);
     sid->u.ssl3.keys.wrapped_master_secret_len = parsedTicket->ms_length;
     sid->u.ssl3.masterWrapMech = parsedTicket->msWrapMech;
     sid->u.ssl3.keys.msIsWrapped = parsedTicket->ms_is_wrapped;
     sid->u.ssl3.masterValid = PR_TRUE;
     sid->u.ssl3.keys.resumable = PR_TRUE;
     sid->u.ssl3.keys.extendedMasterSecretUsed = parsedTicket->extendedMasterSecretUsed;
+    sid->u.ssl3.altHandshakeType = parsedTicket->altHandshakeType;
 
     /* Copy over client cert from session ticket if there is one. */
     if (parsedTicket->peer_cert.data != NULL) {
         PORT_Assert(!sid->peerCert);
         sid->peerCert = CERT_NewTempCertificate(ss->dbHandle,
                                                 &parsedTicket->peer_cert,
                                                 NULL, PR_FALSE, PR_TRUE);
         if (!sid->peerCert) {
--- a/security/nss/lib/ssl/ssl3gthr.c
+++ b/security/nss/lib/ssl/ssl3gthr.c
@@ -390,17 +390,18 @@ dtls_GatherData(sslSocket *ss, sslGather
  */
 int
 ssl3_GatherCompleteHandshake(sslSocket *ss, int flags)
 {
     int rv;
     SSL3Ciphertext cText;
     PRBool keepGoing = PR_TRUE;
 
-    SSL_TRC(30, ("ssl3_GatherCompleteHandshake"));
+    SSL_TRC(30, ("%d: SSL3[%d]: ssl3_GatherCompleteHandshake",
+                 SSL_GETPID(), ss->fd));
 
     /* ssl3_HandleRecord may end up eventually calling ssl_FinishHandshake,
      * which requires the 1stHandshakeLock, which must be acquired before the
      * RecvBufLock.
      */
     PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
 
@@ -503,17 +504,16 @@ ssl3_GatherCompleteHandshake(sslSocket *
                 } else {
                     cText.type = (SSL3ContentType)ss->gs.hdr[0];
                     cText.version = (ss->gs.hdr[1] << 8) | ss->gs.hdr[2];
                 }
 
                 if (IS_DTLS(ss)) {
                     sslSequenceNumber seq_num;
 
-                    cText.version = dtls_DTLSVersionToTLSVersion(cText.version);
                     /* DTLS sequence number */
                     PORT_Memcpy(&seq_num, &ss->gs.hdr[3], sizeof(seq_num));
                     cText.seq_num = PR_ntohll(seq_num);
                 }
 
                 cText.buf = &ss->gs.inbuf;
                 rv = ssl3_HandleRecord(ss, &cText, &ss->gs.buf);
             }
--- a/security/nss/lib/ssl/ssl3prot.h
+++ b/security/nss/lib/ssl/ssl3prot.h
@@ -146,19 +146,17 @@ typedef enum {
     certificate_status = 22,
     next_proto = 67
 } SSL3HandshakeType;
 
 typedef struct {
     PRUint8 empty;
 } SSL3HelloRequest;
 
-typedef struct {
-    PRUint8 rand[SSL3_RANDOM_LENGTH];
-} SSL3Random;
+typedef PRUint8 SSL3Random[SSL3_RANDOM_LENGTH];
 
 typedef struct {
     PRUint8 id[32];
     PRUint8 length;
 } SSL3SessionID;
 
 typedef struct {
     SSL3ProtocolVersion client_version;
--- a/security/nss/lib/ssl/sslexp.h
+++ b/security/nss/lib/ssl/sslexp.h
@@ -17,21 +17,20 @@ SEC_BEGIN_PROTOS
  * future NSS versions. Code that uses these functions needs to safeguard
  * against the function not being available. */
 
 #define SSL_EXPERIMENTAL_API(name, arglist, args)                   \
     (SSL_GetExperimentalAPI(name)                                   \
          ? ((SECStatus(*) arglist)SSL_GetExperimentalAPI(name))args \
          : SECFailure)
 
-/* Allow the ServerHello to be record type 24. Experiment to test:
- * https://github.com/tlswg/tls13-spec/pull/1051
+/* Make the TLS 1.3 handshake mimic TLS 1.2 session resumption.
  * This will either become part of the standard or be disabled
  * after we have tested it.
  */
-#define SSL_UseAltServerHelloType(fd, enable)                \
-    SSL_EXPERIMENTAL_API("SSL_UseAltServerHelloType",        \
+#define SSL_UseAltHandshakeType(fd, enable)                  \
+    SSL_EXPERIMENTAL_API("SSL_UseAltHandshakeType",          \
                          (PRFileDesc * _fd, PRBool _enable), \
                          (fd, enable))
 
 SEC_END_PROTOS
 
 #endif /* __sslexp_h_ */
--- a/security/nss/lib/ssl/sslimpl.h
+++ b/security/nss/lib/ssl/sslimpl.h
@@ -224,18 +224,16 @@ struct sslSocketOpsStr {
     int (*getpeername)(sslSocket *, PRNetAddr *);
     int (*getsockname)(sslSocket *, PRNetAddr *);
 };
 
 /* Flags interpreted by ssl send functions. */
 #define ssl_SEND_FLAG_FORCE_INTO_BUFFER 0x40000000
 #define ssl_SEND_FLAG_NO_BUFFER 0x20000000
 #define ssl_SEND_FLAG_NO_RETRANSMIT 0x08000000 /* DTLS only */
-#define ssl_SEND_FLAG_CAP_RECORD_VERSION \
-    0x04000000 /* TLS only */
 #define ssl_SEND_FLAG_MASK 0x7f000000
 
 /*
 ** A buffer object.
 */
 struct sslBufferStr {
     unsigned char *buf;
     unsigned int len;
@@ -495,16 +493,17 @@ struct ssl3CipherSpecStr {
     SSLDestroy destroyCompressContext;
     void *compressContext;
     SSLDestroy destroyDecompressContext;
     void *decompressContext;
     PK11SymKey *master_secret;
     sslSequenceNumber write_seq_num;
     sslSequenceNumber read_seq_num;
     SSL3ProtocolVersion version;
+    SSL3ProtocolVersion recordVersion;
     ssl3KeyMaterial client;
     ssl3KeyMaterial server;
     SECItem msItem;
     DTLSEpoch epoch;
     DTLSRecvdRecords recvdRecords;
     /* The number of 0-RTT bytes that can be sent or received in TLS 1.3. This
      * will be zero for everything but 0-RTT. */
     PRUint32 earlyDataRemaining;
@@ -604,16 +603,18 @@ struct sslSessionIDStr {
             ** (used only in client).
             */
             SECItem signedCertTimestamps;
 
             /* The NPN/ALPN value negotiated in the original connection.
              * Used for TLS 1.3. */
             SECItem alpnSelection;
 
+            PRBool altHandshakeType;
+
             /* This lock is lazily initialized by CacheSID when a sid is first
              * cached. Before then, there is no need to lock anything because
              * the sid isn't being shared by anything.
              */
             PRRWLock *lock;
 
             /* The lock must be held while reading or writing these members
              * because they change while the sid is cached.
@@ -881,17 +882,18 @@ typedef struct SSL3HandshakeStateStr {
     ssl3CipherSuite zeroRttSuite;   /* The cipher suite we used for 0-RTT. */
     PRCList bufferedEarlyData;      /* Buffered TLS 1.3 early data
                                      * on server.*/
     PRBool helloRetry;              /* True if HelloRetryRequest has been sent
                                      * or received. */
     ssl3KEADef kea_def_mutable;     /* Used to hold the writable kea_def
                                      * we use for TLS 1.3 */
     PRBool shortHeaders;            /* Assigned if we are doing short headers. */
-    PRBool altHandshakeType;        /* Assigned if we are doing the wrapped handshake. */
+    PRBool altHandshakeType;        /* Alternative ServerHello content type. */
+    SECItem fakeSid;                /* ... (server) the SID the client used. */
 } SSL3HandshakeState;
 
 /*
 ** This is the "ssl3" struct, as in "ss->ssl3".
 ** note:
 ** usually,   crSpec == cwSpec and prSpec == pwSpec.
 ** Sometimes, crSpec == pwSpec and prSpec == cwSpec.
 ** But there are never more than 2 actual specs.
@@ -1017,16 +1019,17 @@ typedef struct SessionTicketStr {
     PRUint8 master_secret[48];
     PRBool extendedMasterSecretUsed;
     ClientAuthenticationType client_auth_type;
     SECItem peer_cert;
     PRUint32 timestamp;
     PRUint32 flags;
     SECItem srvName; /* negotiated server name */
     SECItem alpnSelection;
+    PRBool altHandshakeType;
     PRUint32 maxEarlyData;
 } SessionTicket;
 
 /*
  * SSL2 buffers used in SSL3.
  *     writeBuf in the SecurityInfo maintained by sslsecur.c is used
  *              to hold the data just about to be passed to the kernel
  *     sendBuf in the ConnectInfo maintained by sslcon.c is used
@@ -1648,16 +1651,20 @@ extern SECStatus ssl3_HandleHandshakeMes
 extern void ssl3_DestroySSL3Info(sslSocket *ss);
 
 extern SECStatus ssl_ClientReadVersion(sslSocket *ss, PRUint8 **b,
                                        PRUint32 *length,
                                        SSL3ProtocolVersion *version);
 extern SECStatus ssl3_NegotiateVersion(sslSocket *ss,
                                        SSL3ProtocolVersion peerVersion,
                                        PRBool allowLargerPeerVersion);
+extern SECStatus ssl_ClientSetCipherSuite(sslSocket *ss,
+                                          SSL3ProtocolVersion version,
+                                          ssl3CipherSuite suite,
+                                          PRBool initHashes);
 
 extern SECStatus ssl_GetPeerInfo(sslSocket *ss);
 
 /* ECDH functions */
 extern SECStatus ssl3_SendECDHClientKeyExchange(sslSocket *ss,
                                                 SECKEYPublicKey *svrPubKey);
 extern SECStatus ssl3_HandleECDHServerKeyExchange(sslSocket *ss,
                                                   PRUint8 *b, PRUint32 length);
@@ -1821,16 +1828,17 @@ SECStatus ssl_GetCertificateRequestCAs(s
                                        SECItem **namesp, unsigned int *nnamesp);
 SECStatus ssl3_ParseCertificateRequestCAs(sslSocket *ss, PRUint8 **b,
                                           PRUint32 *length, PLArenaPool *arena,
                                           CERTDistNames *ca_list);
 SECStatus ssl3_CompleteHandleCertificateRequest(
     sslSocket *ss, const SSLSignatureScheme *signatureSchemes,
     unsigned int signatureSchemeCount, CERTDistNames *ca_list);
 SECStatus ssl3_SendServerHello(sslSocket *ss);
+SECStatus ssl3_SendChangeCipherSpecsInt(sslSocket *ss);
 SECStatus ssl3_ComputeHandshakeHashes(sslSocket *ss,
                                       ssl3CipherSpec *spec,
                                       SSL3Hashes *hashes,
                                       PRUint32 sender);
 SECStatus ssl_CreateECDHEphemeralKeyPair(const sslSocket *ss,
                                          const sslNamedGroupDef *ecGroup,
                                          sslEphemeralKeyPair **keyPair);
 SECStatus ssl_CreateStaticECDHEKey(sslSocket *ss,
--- a/security/nss/lib/ssl/sslinfo.c
+++ b/security/nss/lib/ssl/sslinfo.c
@@ -463,19 +463,19 @@ SSL_ExportKeyingMaterial(PRFileDesc *fd,
     if (hasContext) {
         valLen += 2 /* PRUint16 length */ + contextLen;
     }
     val = PORT_Alloc(valLen);
     if (!val) {
         return SECFailure;
     }
     i = 0;
-    PORT_Memcpy(val + i, &ss->ssl3.hs.client_random.rand, SSL3_RANDOM_LENGTH);
+    PORT_Memcpy(val + i, ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH);
     i += SSL3_RANDOM_LENGTH;
-    PORT_Memcpy(val + i, &ss->ssl3.hs.server_random.rand, SSL3_RANDOM_LENGTH);
+    PORT_Memcpy(val + i, ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH);
     i += SSL3_RANDOM_LENGTH;
     if (hasContext) {
         val[i++] = contextLen >> 8;
         val[i++] = contextLen;
         PORT_Memcpy(val + i, context, contextLen);
         i += contextLen;
     }
     PORT_Assert(i == valLen);
--- a/security/nss/lib/ssl/sslsock.c
+++ b/security/nss/lib/ssl/sslsock.c
@@ -3870,17 +3870,17 @@ SSL_CanBypass(CERTCertificate *cert, SEC
     {                      \
         "SSL_" #n, SSL_##n \
     }
 struct {
     const char *const name;
     void *function;
 } ssl_experimental_functions[] = {
 #ifndef SSL_DISABLE_EXPERIMENTAL_API
-    EXP(UseAltServerHelloType),
+    EXP(UseAltHandshakeType),
 #endif
     { "", NULL }
 };
 #undef EXP
 #undef PUB
 
 void *
 SSL_GetExperimentalAPI(const char *name)
--- a/security/nss/lib/ssl/tls13con.c
+++ b/security/nss/lib/ssl/tls13con.c
@@ -128,19 +128,16 @@ const char keylogLabelClientTrafficSecre
 const char keylogLabelServerTrafficSecret[] = "SERVER_TRAFFIC_SECRET_0";
 const char keylogLabelExporterSecret[] = "EXPORTER_SECRET";
 
 #define TRAFFIC_SECRET(ss, dir, name) ((ss->sec.isServer ^            \
                                         (dir == CipherSpecWrite))     \
                                            ? ss->ssl3.hs.client##name \
                                            : ss->ssl3.hs.server##name)
 
-const SSL3ProtocolVersion kTlsRecordVersion = SSL_LIBRARY_VERSION_TLS_1_0;
-const SSL3ProtocolVersion kDtlsRecordVersion = SSL_LIBRARY_VERSION_TLS_1_1;
-
 /* Belt and suspenders in case we ever add a TLS 1.4. */
 PR_STATIC_ASSERT(SSL_LIBRARY_VERSION_MAX_SUPPORTED <=
                  SSL_LIBRARY_VERSION_TLS_1_3);
 
 /* Use this instead of FATAL_ERROR when no alert shall be sent. */
 #define LOG_ERROR(ss, prError)                                                     \
     do {                                                                           \
         SSL_TRC(3, ("%d: TLS13[%d]: fatal error %d in %s (%s:%d)",                 \
@@ -1723,17 +1720,19 @@ tls13_HandleHelloRetryRequest(sslSocket 
         ssl_ReleaseSpecWriteLock(ss);
     } else {
         PORT_Assert(ss->ssl3.hs.zeroRttState == ssl_0rtt_none);
     }
 
     /* Version. */
     rv = ssl_ClientReadVersion(ss, &b, &length, &version);
     if (rv != SECSuccess) {
-        return SECFailure; /* alert already sent */
+        FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_HELLO_RETRY_REQUEST,
+                    protocol_version);
+        return SECFailure;
     }
     if (version > ss->vrange.max || version < SSL_LIBRARY_VERSION_TLS_1_3) {
         FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_HELLO_RETRY_REQUEST,
                     protocol_version);
         return SECFailure;
     }
 
     /* Extensions. */
@@ -1936,16 +1935,23 @@ tls13_SendServerHelloSequence(sslSocket 
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
 
     rv = ssl3_SendServerHello(ss);
     if (rv != SECSuccess) {
         return rv; /* err code is set. */
     }
 
+    if (ss->ssl3.hs.altHandshakeType) {
+        rv = ssl3_SendChangeCipherSpecsInt(ss);
+        if (rv != SECSuccess) {
+            return rv;
+        }
+    }
+
     rv = tls13_SendEncryptedServerSequence(ss);
     if (rv != SECSuccess) {
         err = PORT_GetError();
     }
     /* Even if we get an error, since the ServerHello was successfully
      * serialized, we should give it a chance to reach the network.  This gives
      * the client a chance to perform the key exchange and decrypt the alert
      * we're about to send. */
@@ -2699,37 +2705,74 @@ tls13_DeriveTrafficKeys(sslSocket *ss, s
         *prkp = NULL;
     }
     return SECSuccess;
 
 loser:
     return SECFailure;
 }
 
-static SECStatus
-tls13_SetupPendingCipherSpec(sslSocket *ss)
+void
+tls13_SetSpecRecordVersion(sslSocket *ss, ssl3CipherSpec *spec)
 {
-    ssl3CipherSpec *pSpec;
+    const SSL3ProtocolVersion kTlsRecordVersion = SSL_LIBRARY_VERSION_TLS_1_0;
+    const SSL3ProtocolVersion kTlsAltRecordVersion = SSL_LIBRARY_VERSION_TLS_1_2;
+    const SSL3ProtocolVersion kDtlsRecordVersion = SSL_LIBRARY_VERSION_DTLS_1_0_WIRE;
+
+    /* Set the record version. */
+    if (IS_DTLS(ss)) {
+        spec->recordVersion = kDtlsRecordVersion;
+    } else if (spec->epoch == TrafficKeyEarlyApplicationData) {
+        /* For early data, the previous session determines the record type that
+         * is used (and not what this session might negotiate). */
+        if (ss->sec.ci.sid && ss->sec.ci.sid->u.ssl3.altHandshakeType) {
+            spec->recordVersion = kTlsAltRecordVersion;
+        } else {
+            spec->recordVersion = kTlsRecordVersion;
+        }
+    } else if (ss->ssl3.hs.altHandshakeType) {
+        spec->recordVersion = kTlsAltRecordVersion;
+    } else {
+        spec->recordVersion = kTlsRecordVersion;
+    }
+    SSL_TRC(10, ("%d: TLS13[%d]: Set record version to 0x%04x",
+                 SSL_GETPID(), ss->fd, spec->recordVersion));
+}
+
+static SECStatus
+tls13_SetupPendingCipherSpec(sslSocket *ss, ssl3CipherSpec *spec)
+{
     ssl3CipherSuite suite = ss->ssl3.hs.cipher_suite;
-    const ssl3BulkCipherDef *bulk = ssl_GetBulkCipherDef(
-        ssl_LookupCipherSuiteDef(suite));
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
     ssl_GetSpecWriteLock(ss); /*******************************/
 
-    pSpec = ss->ssl3.pwSpec;
+    spec = ss->ssl3.pwSpec;
     /* Version isn't set when we send 0-RTT data. */
-    pSpec->version = PR_MAX(SSL_LIBRARY_VERSION_TLS_1_3, ss->version);
+    spec->version = PR_MAX(SSL_LIBRARY_VERSION_TLS_1_3, ss->version);
 
     SSL_TRC(3, ("%d: TLS13[%d]: Set Pending Cipher Suite to 0x%04x",
                 SSL_GETPID(), ss->fd, suite));
-    pSpec->cipher_def = bulk;
-
-    ssl_ReleaseSpecWriteLock(ss); /*******************************/
+
+    spec->cipher_def = ssl_GetBulkCipherDef(ssl_LookupCipherSuiteDef(suite));
+    switch (spec->cipher_def->calg) {
+        case ssl_calg_aes_gcm:
+            spec->aead = tls13_AESGCM;
+            break;
+        case ssl_calg_chacha20:
+            spec->aead = tls13_ChaCha20Poly1305;
+            break;
+        default:
+            PORT_Assert(0);
+            return SECFailure;
+            break;
+    }
+
+    tls13_SetSpecRecordVersion(ss, spec);
     return SECSuccess;
 }
 
 /* Install a new cipher spec for this direction. */
 static SECStatus
 tls13_SetCipherSpec(sslSocket *ss, TrafficKeyType type,
                     CipherSpecDirection direction, PRBool deleteSecret)
 {
@@ -2749,39 +2792,16 @@ tls13_SetCipherSpec(sslSocket *ss, Traff
     if (!spec) {
         PORT_SetError(SEC_ERROR_NO_MEMORY);
         return SECFailure;
     }
     spec->refCt = 1;
     PR_APPEND_LINK(&spec->link, &ss->ssl3.hs.cipherSpecs);
     ss->ssl3.pwSpec = ss->ssl3.prSpec = spec;
 
-    rv = tls13_SetupPendingCipherSpec(ss);
-    if (rv != SECSuccess)
-        return SECFailure;
-
-    switch (spec->cipher_def->calg) {
-        case calg_aes_gcm:
-            spec->aead = tls13_AESGCM;
-            break;
-        case calg_chacha20:
-            spec->aead = tls13_ChaCha20Poly1305;
-            break;
-        default:
-            PORT_Assert(0);
-            return SECFailure;
-            break;
-    }
-
-    rv = tls13_DeriveTrafficKeys(ss, spec, type, direction,
-                                 deleteSecret);
-    if (rv != SECSuccess) {
-        return SECFailure;
-    }
-
     /* We use the epoch for cipher suite identification, so increment
      * it in both TLS and DTLS. */
     if ((*specp)->epoch == PR_UINT16_MAX) {
         return SECFailure;
     }
     spec->epoch = (PRUint16)type;
 
     if (!IS_DTLS(ss)) {
@@ -2789,16 +2809,27 @@ tls13_SetCipherSpec(sslSocket *ss, Traff
     } else {
         /* The sequence number has the high 16 bits as the epoch. */
         spec->read_seq_num = spec->write_seq_num =
             (sslSequenceNumber)spec->epoch << 48;
 
         dtls_InitRecvdRecords(&spec->recvdRecords);
     }
 
+    /* This depends on spec having a valid direction and epoch. */
+    rv = tls13_SetupPendingCipherSpec(ss, spec);
+    if (rv != SECSuccess)
+        return SECFailure;
+
+    rv = tls13_DeriveTrafficKeys(ss, spec, type, direction,
+                                 deleteSecret);
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
+
     if (type == TrafficKeyEarlyApplicationData) {
         spec->earlyDataRemaining =
             ss->sec.ci.sid->u.ssl3.locked.sessionTicket.max_early_data_size;
     }
 
     /* Now that we've set almost everything up, finally cut over. */
     ssl_GetSpecWriteLock(ss);
     tls13_CipherSpecRelease(*specp); /* May delete old cipher. */
@@ -3740,16 +3771,24 @@ tls13_SendClientSecondRound(sslSocket *s
         return SECWouldBlock;
     }
 
     if (ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted) {
         rv = tls13_SendEndOfEarlyData(ss);
         if (rv != SECSuccess) {
             return SECFailure; /* Error code already set. */
         }
+    } else if (ss->ssl3.hs.zeroRttState == ssl_0rtt_none &&
+               ss->ssl3.hs.altHandshakeType) {
+        ssl_GetXmitBufLock(ss); /*******************************/
+        rv = ssl3_SendChangeCipherSpecsInt(ss);
+        ssl_ReleaseXmitBufLock(ss); /*******************************/
+        if (rv != SECSuccess) {
+            return rv;
+        }
     }
 
     rv = tls13_SetCipherSpec(ss, TrafficKeyHandshake,
                              CipherSpecWrite, PR_FALSE);
     if (rv != SECSuccess) {
         FATAL_ERROR(ss, SSL_ERROR_INIT_CIPHER_SUITE_FAILURE, internal_error);
         return SECFailure;
     }
@@ -4041,17 +4080,18 @@ static const struct {
     { ssl_tls13_pre_shared_key_xtn, ExtensionSendClear },
     { ssl_tls13_early_data_xtn, ExtensionSendEncrypted },
     { ssl_next_proto_nego_xtn, ExtensionNotUsed },
     { ssl_renegotiation_info_xtn, ExtensionNotUsed },
     { ssl_signed_cert_timestamp_xtn, ExtensionSendCertificate },
     { ssl_cert_status_xtn, ExtensionSendCertificate },
     { ssl_tls13_ticket_early_data_info_xtn, ExtensionNewSessionTicket },
     { ssl_tls13_cookie_xtn, ExtensionSendHrr },
-    { ssl_tls13_short_header_xtn, ExtensionSendClear }
+    { ssl_tls13_short_header_xtn, ExtensionSendClear },
+    { ssl_tls13_supported_versions_xtn, ExtensionSendClear }
 };
 
 PRBool
 tls13_ExtensionAllowed(PRUint16 extension, SSL3HandshakeType message)
 {
     unsigned int i;
 
     PORT_Assert((message == client_hello) ||
@@ -4234,19 +4274,18 @@ tls13_UnprotectRecord(sslSocket *ss, SSL
         SSL_TRC(3,
                 ("%d: TLS13[%d]: record has invalid exterior content type=%d",
                  SSL_GETPID(), ss->fd, cText->type));
         /* Do we need a better error here? */
         PORT_SetError(SSL_ERROR_BAD_MAC_READ);
         return SECFailure;
     }
 
-    /* Check the version number in the record */
-    if ((IS_DTLS(ss) && cText->version != kDtlsRecordVersion) ||
-        (!IS_DTLS(ss) && cText->version != kTlsRecordVersion)) {
+    /* Check the version number in the record. */
+    if (cText->version != crSpec->recordVersion) {
         /* Do we need a better error here? */
         SSL_TRC(3,
                 ("%d: TLS13[%d]: record has bogus version",
                  SSL_GETPID(), ss->fd));
         return SECFailure;
     }
 
     /* Decrypt */
@@ -4359,36 +4398,50 @@ tls13_MaybeDo0RTTHandshake(sslSocket *ss
     SSL_TRC(3, ("%d: TLS13[%d]: in 0-RTT mode", SSL_GETPID(), ss->fd));
 
     /* Set the ALPN data as if it was negotiated. We check in the ServerHello
      * handler that the server negotiates the same value. */
     if (ss->sec.ci.sid->u.ssl3.alpnSelection.len) {
         ss->xtnData.nextProtoState = SSL_NEXT_PROTO_EARLY_VALUE;
         rv = SECITEM_CopyItem(NULL, &ss->xtnData.nextProto,
                               &ss->sec.ci.sid->u.ssl3.alpnSelection);
-        if (rv != SECSuccess)
-            return rv;
+        if (rv != SECSuccess) {
+            return SECFailure;
+        }
+    }
+
+    /* If the alternative handshake type option is enabled and the last session
+     * had the alternative handshake type, then send CCS. */
+    if (ss->opt.enableAltHandshaketype &&
+        ss->sec.ci.sid->u.ssl3.altHandshakeType) {
+        ssl_GetXmitBufLock(ss);
+        rv = ssl3_SendChangeCipherSpecsInt(ss);
+        ssl_ReleaseXmitBufLock(ss);
+        if (rv != SECSuccess) {
+            return SECFailure;
+        }
     }
 
     /* Cipher suite already set in tls13_SetupClientHello. */
     ss->ssl3.hs.preliminaryInfo = 0;
 
     rv = tls13_DeriveSecret(ss, ss->ssl3.hs.currentSecret,
                             kHkdfLabelClient,
                             kHkdfLabelEarlyTrafficSecret,
                             keylogLabelClientEarlyTrafficSecret,
                             NULL,
                             &ss->ssl3.hs.clientEarlyTrafficSecret);
-    if (rv != SECSuccess)
+    if (rv != SECSuccess) {
         return SECFailure;
+    }
 
     rv = tls13_SetCipherSpec(ss, TrafficKeyEarlyApplicationData,
                              CipherSpecWrite, PR_TRUE);
     if (rv != SECSuccess) {
-        return rv;
+        return SECFailure;
     }
 
     return SECSuccess;
 }
 
 PRInt32
 tls13_Read0RttData(sslSocket *ss, void *buf, PRInt32 len)
 {
@@ -4499,17 +4552,17 @@ tls13_EncodeDraftVersion(SSL3ProtocolVer
     return (PRUint16)version;
 }
 
 PRUint16
 tls13_EncodeAltDraftVersion(SSL3ProtocolVersion version)
 {
 #ifdef TLS_1_3_DRAFT_VERSION
     if (version == SSL_LIBRARY_VERSION_TLS_1_3) {
-        return 0x7a00 | TLS_1_3_DRAFT_VERSION;
+        return 0x7e02;
     }
 #endif
     return (PRUint16)version;
 }
 
 /* Pick the highest version we support that is also advertised. */
 SECStatus
 tls13_NegotiateVersion(sslSocket *ss, const TLSExtension *supported_versions)
@@ -4536,37 +4589,44 @@ tls13_NegotiateVersion(sslSocket *ss, co
 
         for (offset = 0; offset < versions.len; offset += 2) {
             PRUint16 supported =
                 (versions.data[offset] << 8) | versions.data[offset + 1];
             if (supported == wire) {
                 ss->version = version;
                 return SECSuccess;
             }
-            if (ss->opt.enableAltHandshaketype && !IS_DTLS(ss) &&
+            if (ss->opt.enableAltHandshaketype &&
+                !IS_DTLS(ss) &&
                 supported == alt_wire) {
+                rv = ssl3_RegisterExtensionSender(ss, &ss->xtnData,
+                                                  ssl_tls13_supported_versions_xtn,
+                                                  tls13_ServerSendSupportedVersionsXtn);
+                if (rv != SECSuccess) {
+                    return SECFailure;
+                }
+                ss->ssl3.hs.altHandshakeType = PR_TRUE;
                 ss->version = version;
-                ss->ssl3.hs.altHandshakeType = PR_TRUE;
                 return SECSuccess;
             }
         }
     }
 
     FATAL_ERROR(ss, SSL_ERROR_UNSUPPORTED_VERSION, protocol_version);
     return SECFailure;
 }
 
 SECStatus
-SSLExp_UseAltServerHelloType(PRFileDesc *fd, PRBool enable)
+SSLExp_UseAltHandshakeType(PRFileDesc *fd, PRBool enable)
 {
     sslSocket *ss;
 
     ss = ssl_FindSocket(fd);
-    if (!ss) {
-        SSL_DBG(("%d: SSL[%d]: bad socket in SSLExp_UseAltServerHelloType",
+    if (!ss || IS_DTLS(ss)) {
+        SSL_DBG(("%d: SSL[%d]: bad socket in SSLExp_UseAltHandshakeType",
                  SSL_GETPID(), fd));
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return SECFailure;
     }
 
     ss->opt.enableAltHandshaketype = enable;
 
     return SECSuccess;
--- a/security/nss/lib/ssl/tls13con.h
+++ b/security/nss/lib/ssl/tls13con.h
@@ -80,11 +80,12 @@ PRInt32 tls13_Read0RttData(sslSocket *ss
 SECStatus tls13_HandleEndOfEarlyData(sslSocket *ss);
 SECStatus tls13_HandleEarlyApplicationData(sslSocket *ss, sslBuffer *origBuf);
 PRBool tls13_ClientAllow0Rtt(const sslSocket *ss, const sslSessionID *sid);
 PRUint16 tls13_EncodeDraftVersion(SSL3ProtocolVersion version);
 PRUint16 tls13_EncodeAltDraftVersion(SSL3ProtocolVersion version);
 SECStatus tls13_NegotiateVersion(sslSocket *ss,
                                  const TLSExtension *supported_versions);
 SECStatus tls13_SendNewSessionTicket(sslSocket *ss);
-SECStatus SSLExp_UseAltServerHelloType(PRFileDesc *fd, PRBool enable);
+SECStatus SSLExp_UseAltHandshakeType(PRFileDesc *fd, PRBool enable);
+void tls13_SetSpecRecordVersion(sslSocket *ss, ssl3CipherSpec *spec);
 
 #endif /* __tls13con_h_ */
--- a/security/nss/lib/ssl/tls13exthandle.c
+++ b/security/nss/lib/ssl/tls13exthandle.c
@@ -868,32 +868,37 @@ tls13_ClientHandleTicketEarlyDataInfoXtn
 
     xtnData->max_early_data_size = PR_ntohl(utmp);
 
     return SECSuccess;
 }
 
 /*
  *     struct {
+ *       select (Handshake.msg_type) {
+ *       case client_hello:
  *          ProtocolVersion versions<2..254>;
+ *       case server_hello:
+ *          ProtocolVersion version;
+ *       };
  *     } SupportedVersions;
  */
 PRInt32
 tls13_ClientSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
                                      PRUint32 maxBytes)
 {
     PRInt32 extensions_len;
     PRUint16 version;
     SECStatus rv;
 
     if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3) {
         return 0;
     }
 
-    SSL_TRC(3, ("%d: TLS13[%d]: send supported_versions extension",
+    SSL_TRC(3, ("%d: TLS13[%d]: client send supported_versions extension",
                 SSL_GETPID(), ss->fd));
 
     /* Extension type, extension len fiels, vector len field,
      * length of the values. */
     extensions_len = 2 + 2 + 1 +
                      2 * (ss->vrange.max - ss->vrange.min + 1);
 
     if (ss->opt.enableAltHandshaketype && !IS_DTLS(ss)) {
@@ -936,16 +941,60 @@ tls13_ClientSendSupportedVersionsXtn(con
 
         xtnData->advertised[xtnData->numAdvertised++] =
             ssl_tls13_supported_versions_xtn;
     }
 
     return extensions_len;
 }
 
+PRInt32
+tls13_ServerSendSupportedVersionsXtn(const sslSocket *ss,
+                                     TLSExtensionData *xtnData,
+                                     PRBool append, PRUint32 maxBytes)
+{
+    SECStatus rv;
+    PRInt32 extensions_len;
+
+    if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+        PORT_Assert(0); /* Can't happen. */
+        return SECSuccess;
+    }
+    if (!ss->ssl3.hs.altHandshakeType) {
+        PORT_Assert(0); /* Can't happen. */
+        return SECSuccess;
+    }
+
+    SSL_TRC(3, ("%d: TLS13[%d]: server send supported_versions extension",
+                SSL_GETPID(), ss->fd));
+
+    extensions_len = 2 + 2 + 2; /* type, len, version */
+    if (maxBytes < (PRUint32)extensions_len) {
+        PORT_Assert(0);
+        return 0;
+    }
+
+    if (append) {
+        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_supported_versions_xtn, 2);
+        if (rv != SECSuccess)
+            return -1;
+
+        rv = ssl3_ExtAppendHandshakeNumber(ss, 2, 2);
+        if (rv != SECSuccess)
+            return -1;
+
+        rv = ssl3_ExtAppendHandshakeNumber(
+            ss, tls13_EncodeAltDraftVersion(SSL_LIBRARY_VERSION_TLS_1_3), 2);
+        if (rv != SECSuccess) {
+            return -1;
+        }
+    }
+    return extensions_len;
+}
+
 /*
  *    struct {
  *        opaque cookie<1..2^16-1>;
  *    } Cookie;
  */
 SECStatus
 tls13_ClientHandleHrrCookie(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data)
 {
--- a/security/nss/lib/ssl/tls13exthandle.h
+++ b/security/nss/lib/ssl/tls13exthandle.h
@@ -48,16 +48,20 @@ PRInt32 tls13_ServerSendEarlyDataXtn(con
                                      PRBool append,
                                      PRUint32 maxBytes);
 SECStatus tls13_ClientHandleTicketEarlyDataInfoXtn(
     const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
     SECItem *data);
 PRInt32 tls13_ClientSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                              PRBool append,
                                              PRUint32 maxBytes);
+PRInt32 tls13_ServerSendSupportedVersionsXtn(const sslSocket *ss,
+                                             TLSExtensionData *xtnData,
+                                             PRBool append,
+                                             PRUint32 maxBytes);
 SECStatus tls13_ClientHandleHrrCookie(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
                                       SECItem *data);
 PRInt32 tls13_ClientSendHrrCookieXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                      PRBool append,
                                      PRUint32 maxBytes);
 PRInt32 tls13_ClientSendPskKeyExchangeModesXtn(const sslSocket *ss,
                                                TLSExtensionData *xtnData,
                                                PRBool append, PRUint32 maxBytes);
--- a/security/nss/lib/util/nssutil.h
+++ b/security/nss/lib/util/nssutil.h
@@ -14,19 +14,19 @@
 
 /*
  * NSS utilities'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>]][ <Beta>]"
  */
-#define NSSUTIL_VERSION "3.34 Beta"
+#define NSSUTIL_VERSION "3.35 Beta"
 #define NSSUTIL_VMAJOR 3
-#define NSSUTIL_VMINOR 34
+#define NSSUTIL_VMINOR 35
 #define NSSUTIL_VPATCH 0
 #define NSSUTIL_VBUILD 0
 #define NSSUTIL_BETA PR_TRUE
 
 SEC_BEGIN_PROTOS
 
 /*
  * Returns a const string of the UTIL library version.