Bug 1305970 - land NSS 5d2424d699a0, r=me
authorFranziskus Kiefer <franziskuskiefer@gmail.com>
Fri, 11 Nov 2016 14:32:54 +0100
changeset 322088 3f1dcd04bc47823809e7776ca852977c3ed2881d
parent 322087 bfd5335fa635ec73c18dde685db8385f1ef113c3
child 322089 3f11622c5a784b8789c220e4c10345d36dfc74f4
push id83785
push userfranziskuskiefer@gmail.com
push dateFri, 11 Nov 2016 14:02:58 +0000
treeherdermozilla-inbound@3f1dcd04bc47 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersme
bugs1305970
milestone52.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1305970 - land NSS 5d2424d699a0, r=me
security/nss/TAG-INFO
security/nss/automation/taskcluster/graph/src/extend.js
security/nss/coreconf/config.gypi
security/nss/coreconf/coreconf.dep
security/nss/gtests/ssl_gtest/databuffer.h
security/nss/gtests/ssl_gtest/libssl_internals.c
security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc
security/nss/gtests/ssl_gtest/ssl_fuzz_unittest.cc
security/nss/gtests/ssl_gtest/ssl_gtest.gyp
security/nss/gtests/ssl_gtest/tls_agent.cc
security/nss/gtests/ssl_gtest/tls_agent.h
security/nss/gtests/ssl_gtest/tls_connect.cc
security/nss/gtests/ssl_gtest/tls_connect.h
security/nss/gtests/ssl_gtest/tls_filter.cc
security/nss/gtests/ssl_gtest/tls_filter.h
security/nss/lib/ssl/ssl3con.c
security/nss/lib/ssl/ssl3ecc.c
security/nss/lib/ssl/ssl3ext.c
security/nss/lib/ssl/ssl3ext.h
security/nss/lib/ssl/ssl3exthandle.c
security/nss/lib/ssl/ssl3exthandle.h
security/nss/lib/ssl/sslimpl.h
security/nss/lib/ssl/sslsecur.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
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-457e3b2beeb9
+5d2424d699a0
--- a/security/nss/automation/taskcluster/graph/src/extend.js
+++ b/security/nss/automation/taskcluster/graph/src/extend.js
@@ -35,16 +35,21 @@ queue.filter(task => {
     }
 
     // No BoGo tests on ARM.
     if (task.collection == "arm-debug") {
       return false;
     }
   }
 
+  // GYP builds with -Ddisable_libpkix=1 by default.
+  if (task.collection == "gyp" && task.tests == "chains") {
+    return false;
+  }
+
   return true;
 });
 
 queue.map(task => {
   if (task.collection == "asan") {
     // CRMF and FIPS tests still leak, unfortunately.
     if (task.tests == "crmf" || task.tests == "fips") {
       task.env.ASAN_OPTIONS = "detect_leaks=0";
--- a/security/nss/coreconf/config.gypi
+++ b/security/nss/coreconf/config.gypi
@@ -85,17 +85,17 @@
     'dll_prefix': '<(dll_prefix)',
     'dll_suffix': '<(dll_suffix)',
     'freebl_name': '<(freebl_name)',
     'cc_is_clang%': '<(cc_is_clang)',
     # Some defaults
     'disable_tests%': 0,
     'disable_chachapoly%': 0,
     'disable_dbm%': 0,
-    'disable_libpkix%': 0,
+    'disable_libpkix%': 1,
     'disable_werror%': 0,
     'mozilla_client%': 0,
     'moz_fold_libs%': 0,
     'moz_folded_library_name%': '',
     'ssl_enable_zlib%': 1,
     'use_asan%': 0,
     'test_build%': 0,
     'fuzz%': 0,
--- 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/ssl_gtest/databuffer.h
+++ b/security/nss/gtests/ssl_gtest/databuffer.h
@@ -127,17 +127,19 @@ class DataBuffer {
 
     // The amount of stuff remaining from the tail of the old.
     size_t tail_len = old_len - std::min(old_len, index + remove);
     // The new length: the head of the old, the new, and the tail of the old.
     len_ = index + ins_len + tail_len;
     data_ = new uint8_t[len_ ? len_ : 1];
 
     // The head of the old.
-    Write(0, old_value, std::min(old_len, index));
+    if (old_value) {
+      Write(0, old_value, std::min(old_len, index));
+    }
     // Maybe a gap.
     if (index > old_len) {
       memset(old_value + index, 0, index - old_len);
     }
     // The new.
     Write(index, ins, ins_len);
     // The tail of the old.
     if (tail_len > 0) {
--- a/security/nss/gtests/ssl_gtest/libssl_internals.c
+++ b/security/nss/gtests/ssl_gtest/libssl_internals.c
@@ -174,22 +174,22 @@ PRBool SSLInt_DamageEarlyTrafficSecret(P
 }
 
 SECStatus SSLInt_Set0RttAlpn(PRFileDesc *fd, PRUint8 *data, unsigned int len) {
   sslSocket *ss = ssl_FindSocket(fd);
   if (!ss) {
     return SECFailure;
   }
 
-  ss->ssl3.nextProtoState = SSL_NEXT_PROTO_EARLY_VALUE;
-  if (ss->ssl3.nextProto.data) {
-    SECITEM_FreeItem(&ss->ssl3.nextProto, PR_FALSE);
+  ss->xtnData.nextProtoState = SSL_NEXT_PROTO_EARLY_VALUE;
+  if (ss->xtnData.nextProto.data) {
+    SECITEM_FreeItem(&ss->xtnData.nextProto, PR_FALSE);
   }
-  if (!SECITEM_AllocItem(NULL, &ss->ssl3.nextProto, len)) return SECFailure;
-  PORT_Memcpy(ss->ssl3.nextProto.data, data, len);
+  if (!SECITEM_AllocItem(NULL, &ss->xtnData.nextProto, len)) return SECFailure;
+  PORT_Memcpy(ss->xtnData.nextProto.data, data, len);
 
   return SECSuccess;
 }
 
 PRBool SSLInt_HasCertWithAuthType(PRFileDesc *fd, SSLAuthType authType) {
   sslSocket *ss = ssl_FindSocket(fd);
   if (!ss) {
     return PR_FALSE;
--- a/security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc
@@ -149,16 +149,35 @@ class TlsExtensionTestBase : public TlsC
     const char* name = "host.name";
     const size_t namelen = PL_strlen(name);
     extension->Allocate(namelen + 5);
     extension->Write(0, namelen + 3, 2);
     extension->Write(2, static_cast<uint32_t>(0), 1);  // 0 == hostname
     extension->Write(3, namelen, 2);
     extension->Write(5, reinterpret_cast<const uint8_t*>(name), namelen);
   }
+
+  void HrrThenRemoveExtensionsTest(SSLExtensionType type, PRInt32 client_error,
+                                   PRInt32 server_error) {
+    static const std::vector<SSLNamedGroup> client_groups = {
+        ssl_grp_ec_secp384r1, ssl_grp_ec_curve25519};
+    static const std::vector<SSLNamedGroup> server_groups = {
+        ssl_grp_ec_curve25519, ssl_grp_ec_secp384r1};
+    client_->ConfigNamedGroups(client_groups);
+    server_->ConfigNamedGroups(server_groups);
+    EnsureTlsSetup();
+    client_->StartConnect();
+    server_->StartConnect();
+    client_->Handshake();  // Send ClientHello
+    server_->Handshake();  // Send HRR.
+    client_->SetPacketFilter(new TlsExtensionDropper(type));
+    Handshake();
+    client_->CheckErrorCode(client_error);
+    server_->CheckErrorCode(server_error);
+  }
 };
 
 class TlsExtensionTestDtls : public TlsExtensionTestBase,
                              public ::testing::WithParamInterface<uint16_t> {
  public:
   TlsExtensionTestDtls() : TlsExtensionTestBase(DGRAM, GetParam()) {}
 };
 
@@ -767,16 +786,34 @@ TEST_P(TlsExtensionTest13, RemoveTls13Fr
   client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
   server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
 #else
   client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
   server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
 #endif
 }
 
+TEST_P(TlsExtensionTest13, HrrThenRemoveSignatureAlgorithms) {
+  HrrThenRemoveExtensionsTest(ssl_signature_algorithms_xtn,
+                              SSL_ERROR_MISSING_EXTENSION_ALERT,
+                              SSL_ERROR_MISSING_SIGNATURE_ALGORITHMS_EXTENSION);
+}
+
+TEST_P(TlsExtensionTest13, HrrThenRemoveKeyShare) {
+  HrrThenRemoveExtensionsTest(ssl_tls13_key_share_xtn,
+                              SSL_ERROR_ILLEGAL_PARAMETER_ALERT,
+                              SSL_ERROR_BAD_2ND_CLIENT_HELLO);
+}
+
+TEST_P(TlsExtensionTest13, HrrThenRemoveSupportedGroups) {
+  HrrThenRemoveExtensionsTest(ssl_supported_groups_xtn,
+                              SSL_ERROR_MISSING_EXTENSION_ALERT,
+                              SSL_ERROR_MISSING_SUPPORTED_GROUPS_EXTENSION);
+}
+
 TEST_P(TlsExtensionTest13, EmptyVersionList) {
   static const uint8_t ext[] = {0x00, 0x00};
   ConnectWithBogusVersionList(ext, sizeof(ext));
 }
 
 TEST_P(TlsExtensionTest13, OddVersionList) {
   static const uint8_t ext[] = {0x00, 0x01, 0x00};
   ConnectWithBogusVersionList(ext, sizeof(ext));
--- a/security/nss/gtests/ssl_gtest/ssl_fuzz_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_fuzz_unittest.cc
@@ -1,24 +1,100 @@
 /* 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 "blapi.h"
 #include "ssl.h"
 #include "sslimpl.h"
+#include "tls_connect.h"
 
 #include "gtest/gtest.h"
 
 namespace nss_test {
 
 #ifdef UNSAFE_FUZZER_MODE
 
 class TlsFuzzTest : public ::testing::Test {};
 
+void ResetState() {
+  // Clear the list of RSA blinding params.
+  BL_Cleanup();
+
+  // Reinit the list of RSA blinding params.
+  EXPECT_EQ(SECSuccess, BL_Init());
+
+  // Reset the RNG state.
+  EXPECT_EQ(SECSuccess, RNG_ResetForFuzzing());
+}
+
 // Ensure that ssl_Time() returns a constant value.
 TEST_F(TlsFuzzTest, Fuzz_SSL_Time_Constant) {
   PRInt32 now = ssl_Time();
   PR_Sleep(PR_SecondsToInterval(2));
   EXPECT_EQ(ssl_Time(), now);
 }
 
+// Check that due to the deterministic PRNG we derive
+// the same master secret in two consecutive TLS sessions.
+TEST_P(TlsConnectGeneric, Fuzz_DeterministicExporter) {
+  const char kLabel[] = "label";
+  std::vector<unsigned char> out1(32), out2(32);
+
+  ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
+  DisableECDHEServerKeyReuse();
+
+  ResetState();
+  Connect();
+
+  // Export a key derived from the MS and nonces.
+  SECStatus rv =
+      SSL_ExportKeyingMaterial(client_->ssl_fd(), kLabel, strlen(kLabel), false,
+                               NULL, 0, out1.data(), out1.size());
+  EXPECT_EQ(SECSuccess, rv);
+
+  Reset();
+  ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
+  DisableECDHEServerKeyReuse();
+
+  ResetState();
+  Connect();
+
+  // Export another key derived from the MS and nonces.
+  rv = SSL_ExportKeyingMaterial(client_->ssl_fd(), kLabel, strlen(kLabel),
+                                false, NULL, 0, out2.data(), out2.size());
+  EXPECT_EQ(SECSuccess, rv);
+
+  // The two exported keys should be the same.
+  EXPECT_EQ(out1, out2);
+}
+
+// Check that due to the deterministic RNG two consecutive
+// TLS sessions will have the exact same transcript.
+TEST_P(TlsConnectGeneric, Fuzz_DeterministicTranscript) {
+  // Connect a few times and compare the transcripts byte-by-byte.
+  DataBuffer last;
+  for (size_t i = 0; i < 5; i++) {
+    Reset();
+    ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
+    DisableECDHEServerKeyReuse();
+
+    DataBuffer buffer;
+    client_->SetPacketFilter(new TlsConversationRecorder(buffer));
+    server_->SetPacketFilter(new TlsConversationRecorder(buffer));
+
+    ResetState();
+    Connect();
+
+    // Ensure the filters go away before |buffer| does.
+    client_->SetPacketFilter(nullptr);
+    server_->SetPacketFilter(nullptr);
+
+    if (last.len() > 0) {
+      EXPECT_EQ(last, buffer);
+    }
+
+    last = buffer;
+  }
+}
+
 #endif
 }
--- a/security/nss/gtests/ssl_gtest/ssl_gtest.gyp
+++ b/security/nss/gtests/ssl_gtest/ssl_gtest.gyp
@@ -55,17 +55,17 @@
         '<(DEPTH)/lib/certhigh/certhigh.gyp:certhi',
         '<(DEPTH)/lib/cryptohi/cryptohi.gyp:cryptohi',
         '<(DEPTH)/lib/pk11wrap/pk11wrap.gyp:pk11wrap',
         '<(DEPTH)/lib/softoken/softoken.gyp:softokn',
         '<(DEPTH)/lib/certdb/certdb.gyp:certdb',
         '<(DEPTH)/lib/pki/pki.gyp:nsspki',
         '<(DEPTH)/lib/dev/dev.gyp:nssdev',
         '<(DEPTH)/lib/base/base.gyp:nssb',
-        '<(DEPTH)/lib/freebl/freebl.gyp:freebl',
+        '<(DEPTH)/lib/freebl/freebl.gyp:<(freebl_name)',
         '<(DEPTH)/lib/nss/nss.gyp:nss_static',
         '<(DEPTH)/lib/pk11wrap/pk11wrap.gyp:pk11wrap',
         '<(DEPTH)/lib/certhigh/certhigh.gyp:certhi',
         '<(DEPTH)/lib/zlib/zlib.gyp:nss_zlib'
       ],
       'conditions': [
         [ 'disable_dbm==0', {
           'dependencies': [
--- a/security/nss/gtests/ssl_gtest/tls_agent.cc
+++ b/security/nss/gtests/ssl_gtest/tls_agent.cc
@@ -814,16 +814,22 @@ void TlsAgent::ConfigureSessionCache(Ses
                                mode & RESUME_SESSIONID ? PR_FALSE : PR_TRUE);
   EXPECT_EQ(SECSuccess, rv);
 
   rv = SSL_OptionSet(ssl_fd_, SSL_ENABLE_SESSION_TICKETS,
                      mode & RESUME_TICKET ? PR_TRUE : PR_FALSE);
   EXPECT_EQ(SECSuccess, rv);
 }
 
+void TlsAgent::DisableECDHEServerKeyReuse() {
+  ASSERT_EQ(TlsAgent::SERVER, role_);
+  SECStatus rv = SSL_OptionSet(ssl_fd_, SSL_REUSE_SERVER_ECDHE_KEY, PR_FALSE);
+  EXPECT_EQ(SECSuccess, rv);
+}
+
 static const std::string kTlsRolesAllArr[] = {"CLIENT", "SERVER"};
 ::testing::internal::ParamGenerator<std::string>
     TlsAgentTestBase::kTlsRolesAll = ::testing::ValuesIn(kTlsRolesAllArr);
 
 void TlsAgentTestBase::SetUp() {
   SSL_ConfigServerSessionIDCache(1024, 0, 0, g_working_dir_path.c_str());
 }
 
--- a/security/nss/gtests/ssl_gtest/tls_agent.h
+++ b/security/nss/gtests/ssl_gtest/tls_agent.h
@@ -145,16 +145,17 @@ class TlsAgent : public PollTarget {
   void EnableExtendedMasterSecret();
   void CheckExtendedMasterSecret(bool expected);
   void CheckEarlyDataAccepted(bool expected);
   void DisableRollbackDetection();
   void EnableCompression();
   void SetDowngradeCheckVersion(uint16_t version);
   void CheckSecretsDestroyed();
   void ConfigNamedGroups(const std::vector<SSLNamedGroup>& groups);
+  void DisableECDHEServerKeyReuse();
 
   const std::string& name() const { return name_; }
 
   Role role() const { return role_; }
   std::string role_str() const { return role_ == SERVER ? "server" : "client"; }
 
   State state() const { return state_; }
 
--- a/security/nss/gtests/ssl_gtest/tls_connect.cc
+++ b/security/nss/gtests/ssl_gtest/tls_connect.cc
@@ -590,16 +590,20 @@ void TlsConnectTestBase::ExpectEarlyData
   expect_early_data_accepted_ = expected;
 }
 
 void TlsConnectTestBase::CheckEarlyDataAccepted() {
   client_->CheckEarlyDataAccepted(expect_early_data_accepted_);
   server_->CheckEarlyDataAccepted(expect_early_data_accepted_);
 }
 
+void TlsConnectTestBase::DisableECDHEServerKeyReuse() {
+  server_->DisableECDHEServerKeyReuse();
+}
+
 TlsConnectGeneric::TlsConnectGeneric()
     : TlsConnectTestBase(std::get<0>(GetParam()), std::get<1>(GetParam())) {}
 
 TlsConnectPre12::TlsConnectPre12()
     : TlsConnectTestBase(std::get<0>(GetParam()), std::get<1>(GetParam())) {}
 
 TlsConnectTls12::TlsConnectTls12()
     : TlsConnectTestBase(GetParam(), SSL_LIBRARY_VERSION_TLS_1_2) {}
--- a/security/nss/gtests/ssl_gtest/tls_connect.h
+++ b/security/nss/gtests/ssl_gtest/tls_connect.h
@@ -102,16 +102,17 @@ class TlsConnectTestBase : public ::test
   void SetupForZeroRtt();
   void SetupForResume();
   void ZeroRttSendReceive(
       bool expect_writable, bool expect_readable,
       std::function<bool()> post_clienthello_check = nullptr);
   void Receive(size_t amount);
   void ExpectExtendedMasterSecret(bool expected);
   void ExpectEarlyDataAccepted(bool expected);
+  void DisableECDHEServerKeyReuse();
 
  protected:
   Mode mode_;
   TlsAgent* client_;
   TlsAgent* server_;
   TlsAgent* client_model_;
   TlsAgent* server_model_;
   uint16_t version_;
--- a/security/nss/gtests/ssl_gtest/tls_filter.cc
+++ b/security/nss/gtests/ssl_gtest/tls_filter.cc
@@ -238,16 +238,22 @@ PacketFilter::Action TlsInspectorReplace
   if (header.handshake_type() == handshake_type_) {
     *output = buffer_;
     return CHANGE;
   }
 
   return KEEP;
 }
 
+PacketFilter::Action TlsConversationRecorder::FilterRecord(
+    const RecordHeader& header, const DataBuffer& input, DataBuffer* output) {
+  buffer_.Append(input);
+  return KEEP;
+}
+
 PacketFilter::Action TlsAlertRecorder::FilterRecord(const RecordHeader& header,
                                                     const DataBuffer& input,
                                                     DataBuffer* output) {
   if (level_ == kTlsAlertFatal) {  // already fatal
     return KEEP;
   }
   if (header.content_type() != kTlsAlertType) {
     return KEEP;
--- a/security/nss/gtests/ssl_gtest/tls_filter.h
+++ b/security/nss/gtests/ssl_gtest/tls_filter.h
@@ -157,16 +157,29 @@ class TlsInspectorReplaceHandshakeMessag
                                                const DataBuffer& input,
                                                DataBuffer* output);
 
  private:
   uint8_t handshake_type_;
   DataBuffer buffer_;
 };
 
+// Make a copy of the complete conversation.
+class TlsConversationRecorder : public TlsRecordFilter {
+ public:
+  TlsConversationRecorder(DataBuffer& buffer) : buffer_(buffer) {}
+
+  virtual PacketFilter::Action FilterRecord(const RecordHeader& header,
+                                            const DataBuffer& input,
+                                            DataBuffer* output);
+
+ private:
+  DataBuffer& buffer_;
+};
+
 // Records an alert.  If an alert has already been recorded, it won't save the
 // new alert unless the old alert is a warning and the new one is fatal.
 class TlsAlertRecorder : public TlsRecordFilter {
  public:
   TlsAlertRecorder() : level_(255), description_(255) {}
 
   virtual PacketFilter::Action FilterRecord(const RecordHeader& header,
                                             const DataBuffer& input,
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -14,16 +14,18 @@
 #include "keyhi.h"
 #include "secder.h"
 #include "secitem.h"
 #include "sechash.h"
 
 #include "sslimpl.h"
 #include "sslproto.h"
 #include "sslerr.h"
+#include "ssl3ext.h"
+#include "ssl3exthandle.h"
 #include "prtime.h"
 #include "prinrval.h"
 #include "prerror.h"
 #include "pratom.h"
 #include "prthread.h"
 #include "nss.h"
 #include "nssoptions.h"
 
@@ -754,29 +756,37 @@ ssl_LookupCipherSuiteDef(ssl3CipherSuite
     PORT_Assert(PR_FALSE); /* We should never get here. */
     PORT_SetError(SSL_ERROR_UNKNOWN_CIPHER_SUITE);
     return NULL;
 }
 
 /* Find the cipher configuration struct associate with suite */
 /* XXX This does a linear search.  A binary search would be better. */
 static ssl3CipherSuiteCfg *
-ssl_LookupCipherSuiteCfg(ssl3CipherSuite suite, ssl3CipherSuiteCfg *suites)
+ssl_LookupCipherSuiteCfgMutable(ssl3CipherSuite suite,
+                                ssl3CipherSuiteCfg *suites)
 {
     int i;
 
     for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) {
         if (suites[i].cipher_suite == suite)
             return &suites[i];
     }
     /* return NULL and let the caller handle it.  */
     PORT_SetError(SSL_ERROR_UNKNOWN_CIPHER_SUITE);
     return NULL;
 }
 
+const static ssl3CipherSuiteCfg *
+ssl_LookupCipherSuiteCfg(ssl3CipherSuite suite, const ssl3CipherSuiteCfg *suites)
+{
+    return ssl_LookupCipherSuiteCfgMutable(suite,
+                                           CONST_CAST(ssl3CipherSuiteCfg, suites));
+}
+
 static PRBool
 ssl_NamedGroupTypeEnabled(const sslSocket *ss, SSLKEAType keaType)
 {
     unsigned int i;
     for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) {
         if (ss->namedGroupPreferences[i] &&
             ss->namedGroupPreferences[i]->keaType == keaType) {
             return PR_TRUE;
@@ -798,27 +808,27 @@ ssl_KEAEnabled(const sslSocket *ss, SSLK
                 return PR_FALSE;
             }
 
             if (ss->sec.isServer) {
                 /* If the server requires named FFDHE groups, then the client
                  * must have included an FFDHE group. peerSupportsFfdheGroups
                  * is set to true in ssl_HandleSupportedGroupsXtn(). */
                 if (ss->opt.requireDHENamedGroups &&
-                    !ss->ssl3.hs.peerSupportsFfdheGroups) {
+                    !ss->xtnData.peerSupportsFfdheGroups) {
                     return PR_FALSE;
                 }
 
                 /* We can use the weak DH group if all of these are true:
                  * 1. We don't require named groups.
                  * 2. The peer doesn't support named groups.
                  * 3. This isn't TLS 1.3.
                  * 4. The weak group is enabled. */
                 if (!ss->opt.requireDHENamedGroups &&
-                    !ss->ssl3.hs.peerSupportsFfdheGroups &&
+                    !ss->xtnData.peerSupportsFfdheGroups &&
                     ss->version < SSL_LIBRARY_VERSION_TLS_1_3 &&
                     ss->ssl3.dheWeakGroupEnabled) {
                     return PR_TRUE;
                 }
             } else {
                 if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3 &&
                     !ss->opt.requireDHENamedGroups) {
                     /* The client enables DHE cipher suites even if no DHE groups
@@ -4991,17 +5001,17 @@ ssl3_SendClientHello(sslSocket *ss, sslC
     }
 
     /* These must be reset every handshake. */
     ss->ssl3.hs.sendingSCSV = PR_FALSE;
     ss->ssl3.hs.preliminaryInfo = 0;
     PORT_Assert(IS_DTLS(ss) || type != client_hello_retransmit);
     SECITEM_FreeItem(&ss->ssl3.hs.newSessionTicket.ticket, PR_FALSE);
     ss->ssl3.hs.receivedNewSessionTicket = PR_FALSE;
-    PORT_Memset(&ss->xtnData, 0, sizeof(TLSExtensionData));
+    ssl3_ResetExtensionData(&ss->xtnData);
 
     /* How many suites does our PKCS11 support (regardless of policy)? */
     num_suites = ssl3_config_match_init(ss);
     if (!num_suites) {
         return SECFailure; /* ssl3_config_match_init has set error code. */
     }
 
     /*
@@ -6126,37 +6136,37 @@ loser:
         PK11_FreeSymKey(pms);
     }
     return rv;
 }
 
 /* DH shares need to be padded to the size of their prime.  Some implementations
  * require this.  TLS 1.3 also requires this. */
 SECStatus
-ssl_AppendPaddedDHKeyShare(sslSocket *ss, SECKEYPublicKey *pubKey,
+ssl_AppendPaddedDHKeyShare(const sslSocket *ss, const SECKEYPublicKey *pubKey,
                            PRBool appendLength)
 {
     SECStatus rv;
     unsigned int pad = pubKey->u.dh.prime.len - pubKey->u.dh.publicValue.len;
 
     if (appendLength) {
-        rv = ssl3_AppendHandshakeNumber(ss, pubKey->u.dh.prime.len, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, pubKey->u.dh.prime.len, 2);
         if (rv != SECSuccess) {
             return rv;
         }
     }
     while (pad) {
-        rv = ssl3_AppendHandshakeNumber(ss, 0, 1);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 1);
         if (rv != SECSuccess) {
             return rv;
         }
         --pad;
     }
-    rv = ssl3_AppendHandshake(ss, pubKey->u.dh.publicValue.data,
-                              pubKey->u.dh.publicValue.len);
+    rv = ssl3_ExtAppendHandshake(ss, pubKey->u.dh.publicValue.data,
+                                 pubKey->u.dh.publicValue.len);
     if (rv != SECSuccess) {
         return rv;
     }
     return SECSuccess;
 }
 
 /* Called from ssl3_SendClientKeyExchange(). */
 static SECStatus
@@ -6191,17 +6201,17 @@ ssl3_SendDHClientKeyExchange(sslSocket *
     /* Work out the parameters. */
     rv = ssl_ValidateDHENamedGroup(ss, &svrPubKey->u.dh.prime,
                                    &svrPubKey->u.dh.base,
                                    &groupDef, &params);
     if (rv != SECSuccess) {
         /* If we require named groups, we will have already validated the group
          * in ssl_HandleDHServerKeyExchange() */
         PORT_Assert(!ss->opt.requireDHENamedGroups &&
-                    !ss->ssl3.hs.peerSupportsFfdheGroups);
+                    !ss->xtnData.peerSupportsFfdheGroups);
 
         customParams.name = ssl_grp_ffdhe_custom;
         customParams.prime.data = svrPubKey->u.dh.prime.data;
         customParams.prime.len = svrPubKey->u.dh.prime.len;
         customParams.base.data = svrPubKey->u.dh.base.data;
         customParams.base.len = svrPubKey->u.dh.base.len;
         params = &customParams;
         groupDef = &customGroupDef;
@@ -6426,18 +6436,18 @@ ssl3_PickServerSignatureScheme(sslSocket
                 PORT_SetError(SEC_ERROR_INVALID_KEY);
                 return SECFailure;
         }
         return SECSuccess;
     }
 
     /* Sets error code, if needed. */
     return ssl_PickSignatureScheme(ss, keyPair->pubKey, keyPair->privKey,
-                                   ss->ssl3.hs.clientSigSchemes,
-                                   ss->ssl3.hs.numClientSigScheme,
+                                   ss->xtnData.clientSigSchemes,
+                                   ss->xtnData.numClientSigScheme,
                                    PR_FALSE /* requireSha1 */);
 }
 
 static SECStatus
 ssl_PickClientSignatureScheme(sslSocket *ss, const SSLSignatureScheme *schemes,
                               unsigned int numSchemes)
 {
     SECKEYPrivateKey *privKey = ss->ssl3.clientPrivateKey;
@@ -7328,53 +7338,53 @@ alert_loser:
     (void)SSL3_SendAlert(ss, alert_fatal,
                          ss->version < SSL_LIBRARY_VERSION_TLS_1_0 ? illegal_parameter
                                                                    : decode_error);
     PORT_SetError(SSL_ERROR_RX_MALFORMED_CERT_REQUEST);
     return SECFailure;
 }
 
 SECStatus
-ssl_ParseSignatureSchemes(sslSocket *ss, PLArenaPool *arena,
+ssl_ParseSignatureSchemes(const sslSocket *ss, PLArenaPool *arena,
                           SSLSignatureScheme **schemesOut,
                           unsigned int *numSchemesOut,
                           unsigned char **b, unsigned int *len)
 {
     SECStatus rv;
     SECItem buf;
     SSLSignatureScheme *schemes;
     unsigned int numSchemes = 0;
     unsigned int max;
 
-    rv = ssl3_ConsumeHandshakeVariable(ss, &buf, 2, b, len);
+    rv = ssl3_ExtConsumeHandshakeVariable(ss, &buf, 2, b, len);
     if (rv != SECSuccess) {
         return SECFailure;
     }
     /* An empty or odd-length value is invalid. */
     if (buf.len == 0 || (buf.len & 1) != 0) {
-        (void)SSL3_SendAlert(ss, alert_fatal, decode_error);
+        ssl3_ExtSendAlert(ss, alert_fatal, decode_error);
         return SECFailure;
     }
 
     /* Limit the number of schemes we read. */
     max = PR_MIN(buf.len / 2, MAX_SIGNATURE_SCHEMES);
 
     if (arena) {
         schemes = PORT_ArenaZNewArray(arena, SSLSignatureScheme, max);
     } else {
         schemes = PORT_ZNewArray(SSLSignatureScheme, max);
     }
     if (!schemes) {
-        (void)SSL3_SendAlert(ss, alert_fatal, internal_error);
+        ssl3_ExtSendAlert(ss, alert_fatal, internal_error);
         return SECFailure;
     }
 
     for (; max; --max) {
         PRInt32 tmp;
-        tmp = ssl3_ConsumeHandshakeNumber(ss, 2, &buf.data, &buf.len);
+        tmp = ssl3_ExtConsumeHandshakeNumber(ss, 2, &buf.data, &buf.len);
         if (tmp < 0) {
             PORT_Assert(0);
             PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
             return SECFailure;
         }
         if (ssl_IsSupportedSignatureScheme((SSLSignatureScheme)tmp)) {
             schemes[numSchemes++] = (SSLSignatureScheme)tmp;
         }
@@ -8152,18 +8162,18 @@ ssl3_ServerCallSNICallback(sslSocket *ss
                     errCode = PORT_GetError();
                     desc = handshake_failure;
                     ret = SSL_SNI_SEND_ALERT;
                     break;
                 }
                 /* Need to tell the client that application has picked
                  * the name from the offered list and reconfigured the socket.
                  */
-                ssl3_RegisterServerHelloExtensionSender(ss, ssl_server_name_xtn,
-                                                        ssl3_SendServerNameXtn);
+                ssl3_RegisterExtensionSender(ss, &ss->xtnData, ssl_server_name_xtn,
+                                             ssl3_SendServerNameXtn);
             } else {
                 /* Callback returned index outside of the boundary. */
                 PORT_Assert((unsigned int)ret < ss->xtnData.sniNameArrSize);
                 errCode = SSL_ERROR_INTERNAL_ERROR_ALERT;
                 desc = internal_error;
                 ret = SSL_SNI_SEND_ALERT;
                 break;
             }
@@ -8280,17 +8290,17 @@ ssl3_HandleClientHello(sslSocket *ss, SS
     rv = ssl_GetPeerInfo(ss);
     if (rv != SECSuccess) {
         return rv; /* error code is set. */
     }
 
     /* We might be starting session renegotiation in which case we should
      * clear previous state.
      */
-    PORT_Memset(&ss->xtnData, 0, sizeof(TLSExtensionData));
+    ssl3_ResetExtensionData(&ss->xtnData);
     ss->statelessResume = PR_FALSE;
 
     if (IS_DTLS(ss)) {
         dtls_RehandshakeCleanup(ss);
     }
 
     tmp = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length);
     if (tmp < 0)
@@ -8938,19 +8948,19 @@ compression_found:
      * TODO: send a session ticket if performing a stateful
      * resumption.  (As per RFC4507, a server may issue a session
      * ticket while doing a (stateless or stateful) session resume,
      * but OpenSSL-0.9.8g does not accept session tickets while
      * resuming.)
      */
     if (ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn) &&
         ssl3_KEASupportsTickets(ss->ssl3.hs.kea_def)) {
-        ssl3_RegisterServerHelloExtensionSender(ss,
-                                                ssl_session_ticket_xtn,
-                                                ssl3_SendSessionTicketXtn);
+        ssl3_RegisterExtensionSender(ss, &ss->xtnData,
+                                     ssl_session_ticket_xtn,
+                                     ssl3_SendSessionTicketXtn);
     }
 
     rv = ssl3_ServerCallSNICallback(ss);
     if (rv != SECSuccess) {
         /* The alert has already been sent. */
         errCode = PORT_GetError();
         goto loser;
     }
@@ -9036,17 +9046,17 @@ ssl3_HandleV2ClientHello(sslSocket *ss, 
     unsigned int total = SSL_HL_CLIENT_HELLO_HBYTES;
 
     SSL_TRC(3, ("%d: SSL3[%d]: handle v2 client_hello", SSL_GETPID(), ss->fd));
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
 
     ssl_GetSSL3HandshakeLock(ss);
 
-    PORT_Memset(&ss->xtnData, 0, sizeof(TLSExtensionData));
+    ssl3_ResetExtensionData(&ss->xtnData);
 
     version = (buffer[1] << 8) | buffer[2];
     if (version < SSL_LIBRARY_VERSION_3_0) {
         goto loser;
     }
 
     rv = ssl3_InitState(ss);
     if (rv != SECSuccess) {
@@ -9535,17 +9545,17 @@ ssl3_SendServerKeyExchange(sslSocket *ss
             PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
             break;
     }
 
     return SECFailure;
 }
 
 SECStatus
-ssl3_EncodeSigAlgs(sslSocket *ss, PRUint8 *buf, unsigned maxLen, PRUint32 *len)
+ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint8 *buf, unsigned maxLen, PRUint32 *len)
 {
     unsigned int i;
     PRUint8 *p = buf;
 
     PORT_Assert(maxLen >= ss->ssl3.signatureSchemeCount * 2);
     if (maxLen < ss->ssl3.signatureSchemeCount * 2) {
         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
         return SECFailure;
@@ -11103,34 +11113,34 @@ ssl3_TLSPRFWithMasterSecret(ssl3CipherSp
  */
 static SECStatus
 ssl3_SendNextProto(sslSocket *ss)
 {
     SECStatus rv;
     int padding_len;
     static const unsigned char padding[32] = { 0 };
 
-    if (ss->ssl3.nextProto.len == 0 ||
-        ss->ssl3.nextProtoState == SSL_NEXT_PROTO_SELECTED) {
+    if (ss->xtnData.nextProto.len == 0 ||
+        ss->xtnData.nextProtoState == SSL_NEXT_PROTO_SELECTED) {
         return SECSuccess;
     }
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
-    padding_len = 32 - ((ss->ssl3.nextProto.len + 2) % 32);
-
-    rv = ssl3_AppendHandshakeHeader(ss, next_proto, ss->ssl3.nextProto.len +
+    padding_len = 32 - ((ss->xtnData.nextProto.len + 2) % 32);
+
+    rv = ssl3_AppendHandshakeHeader(ss, next_proto, ss->xtnData.nextProto.len +
                                                         2 +
                                                         padding_len);
     if (rv != SECSuccess) {
         return rv; /* error code set by AppendHandshakeHeader */
     }
-    rv = ssl3_AppendHandshakeVariable(ss, ss->ssl3.nextProto.data,
-                                      ss->ssl3.nextProto.len, 1);
+    rv = ssl3_AppendHandshakeVariable(ss, ss->xtnData.nextProto.data,
+                                      ss->xtnData.nextProto.len, 1);
     if (rv != SECSuccess) {
         return rv; /* error code set by AppendHandshake */
     }
     rv = ssl3_AppendHandshakeVariable(ss, padding, padding_len, 1);
     if (rv != SECSuccess) {
         return rv; /* error code set by AppendHandshake */
     }
     return rv;
@@ -11530,20 +11540,20 @@ ssl3_FillInCachedSID(sslSocket *ss, sslS
     sid->expirationTime = sid->creationTime + ssl3_sid_timeout;
     sid->localCert = CERT_DupCertificate(ss->sec.localCert);
     if (ss->sec.isServer) {
         memcpy(&sid->certType, &ss->sec.serverCert->certType, sizeof(sid->certType));
     } else {
         sid->certType.authType = ssl_auth_null;
     }
 
-    if (ss->ssl3.nextProtoState != SSL_NEXT_PROTO_NO_SUPPORT &&
-        ss->ssl3.nextProto.data) {
+    if (ss->xtnData.nextProtoState != SSL_NEXT_PROTO_NO_SUPPORT &&
+        ss->xtnData.nextProto.data) {
         if (SECITEM_CopyItem(
-                NULL, &sid->u.ssl3.alpnSelection, &ss->ssl3.nextProto) != SECSuccess) {
+                NULL, &sid->u.ssl3.alpnSelection, &ss->xtnData.nextProto) != SECSuccess) {
             return SECFailure; /* error already set. */
         }
     }
 
     ssl_GetSpecReadLock(ss); /*************************************/
 
     /* Copy the master secret (wrapped or unwrapped) into the sid */
     if (ss->ssl3.crSpec->msItem.len && ss->ssl3.crSpec->msItem.data) {
@@ -12836,33 +12846,31 @@ ssl3_InitState(sslSocket *ss)
     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;
     ssl_ReleaseSpecWriteLock(ss);
 
     ss->ssl3.hs.sendingSCSV = PR_FALSE;
     ss->ssl3.hs.preliminaryInfo = 0;
-    ss->ssl3.hs.peerSupportsFfdheGroups = PR_FALSE;
     ss->ssl3.hs.ws = (ss->sec.isServer) ? wait_client_hello : wait_server_hello;
 
-    PORT_Memset(&ss->xtnData, 0, sizeof(TLSExtensionData));
+    ssl3_ResetExtensionData(&ss->xtnData);
     PR_INIT_CLIST(&ss->ssl3.hs.remoteExtensions);
     if (IS_DTLS(ss)) {
         ss->ssl3.hs.sendMessageSeq = 0;
         ss->ssl3.hs.recvMessageSeq = 0;
         ss->ssl3.hs.rtTimeoutMs = DTLS_RETRANSMIT_INITIAL_MS;
         ss->ssl3.hs.rtRetries = 0;
         ss->ssl3.hs.recvdHighWater = -1;
         PR_INIT_CLIST(&ss->ssl3.hs.lastMessageFlight);
         dtls_SetMTU(ss, 0); /* Set the MTU to the highest plateau */
     }
 
     ss->ssl3.hs.clientHelloHash = NULL;
-    PR_INIT_CLIST(&ss->ssl3.hs.remoteKeyShares);
     ss->ssl3.hs.currentSecret = NULL;
     ss->ssl3.hs.resumptionPsk = NULL;
     ss->ssl3.hs.resumptionContext = nullItem;
     ss->ssl3.hs.dheSecret = NULL;
     ss->ssl3.hs.clientEarlyTrafficSecret = NULL;
     ss->ssl3.hs.clientHsTrafficSecret = NULL;
     ss->ssl3.hs.serverHsTrafficSecret = NULL;
     ss->ssl3.hs.clientTrafficSecret = NULL;
@@ -12887,29 +12895,29 @@ ssl3_InitState(sslSocket *ss)
 }
 
 /* record the export policy for this cipher suite */
 SECStatus
 ssl3_SetPolicy(ssl3CipherSuite which, int policy)
 {
     ssl3CipherSuiteCfg *suite;
 
-    suite = ssl_LookupCipherSuiteCfg(which, cipherSuites);
+    suite = ssl_LookupCipherSuiteCfgMutable(which, cipherSuites);
     if (suite == NULL) {
         return SECFailure; /* err code was set by ssl_LookupCipherSuiteCfg */
     }
     suite->policy = policy;
 
     return SECSuccess;
 }
 
 SECStatus
 ssl3_GetPolicy(ssl3CipherSuite which, PRInt32 *oPolicy)
 {
-    ssl3CipherSuiteCfg *suite;
+    const ssl3CipherSuiteCfg *suite;
     PRInt32 policy;
     SECStatus rv;
 
     suite = ssl_LookupCipherSuiteCfg(which, cipherSuites);
     if (suite) {
         policy = suite->policy;
         rv = SECSuccess;
     } else {
@@ -12921,29 +12929,29 @@ ssl3_GetPolicy(ssl3CipherSuite which, PR
 }
 
 /* record the user preference for this suite */
 SECStatus
 ssl3_CipherPrefSetDefault(ssl3CipherSuite which, PRBool enabled)
 {
     ssl3CipherSuiteCfg *suite;
 
-    suite = ssl_LookupCipherSuiteCfg(which, cipherSuites);
+    suite = ssl_LookupCipherSuiteCfgMutable(which, cipherSuites);
     if (suite == NULL) {
         return SECFailure; /* err code was set by ssl_LookupCipherSuiteCfg */
     }
     suite->enabled = enabled;
     return SECSuccess;
 }
 
 /* return the user preference for this suite */
 SECStatus
 ssl3_CipherPrefGetDefault(ssl3CipherSuite which, PRBool *enabled)
 {
-    ssl3CipherSuiteCfg *suite;
+    const ssl3CipherSuiteCfg *suite;
     PRBool pref;
     SECStatus rv;
 
     suite = ssl_LookupCipherSuiteCfg(which, cipherSuites);
     if (suite) {
         pref = suite->enabled;
         rv = SECSuccess;
     } else {
@@ -12954,28 +12962,28 @@ ssl3_CipherPrefGetDefault(ssl3CipherSuit
     return rv;
 }
 
 SECStatus
 ssl3_CipherPrefSet(sslSocket *ss, ssl3CipherSuite which, PRBool enabled)
 {
     ssl3CipherSuiteCfg *suite;
 
-    suite = ssl_LookupCipherSuiteCfg(which, ss->cipherSuites);
+    suite = ssl_LookupCipherSuiteCfgMutable(which, ss->cipherSuites);
     if (suite == NULL) {
         return SECFailure; /* err code was set by ssl_LookupCipherSuiteCfg */
     }
     suite->enabled = enabled;
     return SECSuccess;
 }
 
 SECStatus
-ssl3_CipherPrefGet(sslSocket *ss, ssl3CipherSuite which, PRBool *enabled)
-{
-    ssl3CipherSuiteCfg *suite;
+ssl3_CipherPrefGet(const sslSocket *ss, ssl3CipherSuite which, PRBool *enabled)
+{
+    const ssl3CipherSuiteCfg *suite;
     PRBool pref;
     SECStatus rv;
 
     suite = ssl_LookupCipherSuiteCfg(which, ss->cipherSuites);
     if (suite) {
         pref = suite->enabled;
         rv = SECSuccess;
     } else {
@@ -13192,19 +13200,16 @@ ssl3_DestroySSL3Info(sslSocket *ss)
 
     /* clean up handshake */
     if (ss->ssl3.hs.md5) {
         PK11_DestroyContext(ss->ssl3.hs.md5, PR_TRUE);
     }
     if (ss->ssl3.hs.sha) {
         PK11_DestroyContext(ss->ssl3.hs.sha, PR_TRUE);
     }
-    if (ss->ssl3.hs.clientSigSchemes) {
-        PORT_Free(ss->ssl3.hs.clientSigSchemes);
-    }
     if (ss->ssl3.hs.messages.buf) {
         sslBuffer_Clear(&ss->ssl3.hs.messages);
     }
 
     /* free the SSL3Buffer (msg_body) */
     PORT_Free(ss->ssl3.hs.msg_body.buf);
 
     SECITEM_FreeItem(&ss->ssl3.hs.newSessionTicket.ticket, PR_FALSE);
@@ -13224,19 +13229,17 @@ ssl3_DestroySSL3Info(sslSocket *ss)
         dtls_FreeHandshakeMessages(&ss->ssl3.hs.lastMessageFlight);
         if (ss->ssl3.hs.recvdFragments.buf) {
             PORT_Free(ss->ssl3.hs.recvdFragments.buf);
         }
     }
 
     /* Destroy remote extensions */
     ssl3_DestroyRemoteExtensions(&ss->ssl3.hs.remoteExtensions);
-
-    /* Destroy TLS 1.3 handshake shares */
-    tls13_DestroyKeyShares(&ss->ssl3.hs.remoteKeyShares);
+    ssl3_ResetExtensionData(&ss->xtnData);
 
     /* Destroy the stored hash. */
     if (ss->ssl3.hs.clientHelloHash) {
         PK11_DestroyContext(ss->ssl3.hs.clientHelloHash, PR_TRUE);
     }
 
     /* Destroy TLS 1.3 cipher specs */
     tls13_DestroyCipherSpecs(&ss->ssl3.hs.cipherSpecs);
@@ -13262,17 +13265,17 @@ ssl3_DestroySSL3Info(sslSocket *ss)
         PK11_FreeSymKey(ss->ssl3.hs.serverTrafficSecret);
 
     ss->ssl3.hs.zeroRttState = ssl_0rtt_none;
     /* Destroy TLS 1.3 buffered early data. */
     tls13_DestroyEarlyData(&ss->ssl3.hs.bufferedEarlyData);
 
     ss->ssl3.initialized = PR_FALSE;
 
-    SECITEM_FreeItem(&ss->ssl3.nextProto, PR_FALSE);
+    SECITEM_FreeItem(&ss->xtnData.nextProto, PR_FALSE);
 }
 
 #define MAP_NULL(x) (((x) != 0) ? (x) : SEC_OID_NULL_CIPHER)
 
 SECStatus
 ssl3_ApplyNSSPolicy(void)
 {
     unsigned i;
--- a/security/nss/lib/ssl/ssl3ecc.c
+++ b/security/nss/lib/ssl/ssl3ecc.c
@@ -13,16 +13,17 @@
 #include "cryptohi.h" /* for DSAU_ stuff */
 #include "keyhi.h"
 #include "secder.h"
 #include "secitem.h"
 
 #include "sslimpl.h"
 #include "sslproto.h"
 #include "sslerr.h"
+#include "ssl3ext.h"
 #include "prtime.h"
 #include "prinrval.h"
 #include "prerror.h"
 #include "pratom.h"
 #include "prthread.h"
 #include "prinit.h"
 
 #include "pk11func.h"
@@ -264,24 +265,24 @@ tls13_SizeOfECDHEKeyShareKEX(const SECKE
 {
     PORT_Assert(pubKey->keyType == ecKey);
     return pubKey->u.ec.publicValue.len;
 }
 
 /* This function encodes the key_exchange field in
  * the KeyShareEntry structure. */
 SECStatus
-tls13_EncodeECDHEKeyShareKEX(sslSocket *ss, const SECKEYPublicKey *pubKey)
+tls13_EncodeECDHEKeyShareKEX(const sslSocket *ss, const SECKEYPublicKey *pubKey)
 {
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
     PORT_Assert(pubKey->keyType == ecKey);
 
-    return ssl3_AppendHandshake(ss, pubKey->u.ec.publicValue.data,
-                                pubKey->u.ec.publicValue.len);
+    return ssl3_ExtAppendHandshake(ss, pubKey->u.ec.publicValue.data,
+                                   pubKey->u.ec.publicValue.len);
 }
 
 /*
 ** Called from ssl3_HandleClientKeyExchange()
 */
 SECStatus
 ssl3_HandleECDHClientKeyExchange(sslSocket *ss, SSL3Opaque *b,
                                  PRUint32 length,
@@ -855,57 +856,59 @@ static const ssl3CipherSuite ssl_dhe_sui
     TLS_DHE_DSS_WITH_RC4_128_SHA,
     TLS_DHE_RSA_WITH_DES_CBC_SHA,
     TLS_DHE_DSS_WITH_DES_CBC_SHA,
     0
 };
 
 /* Order(N^2).  Yuk. */
 static PRBool
-ssl_IsSuiteEnabled(sslSocket *ss, const ssl3CipherSuite *list)
+ssl_IsSuiteEnabled(const sslSocket *ss, const ssl3CipherSuite *list)
 {
     const ssl3CipherSuite *suite;
 
     for (suite = list; *suite; ++suite) {
         PRBool enabled = PR_FALSE;
         SECStatus rv = ssl3_CipherPrefGet(ss, *suite, &enabled);
 
         PORT_Assert(rv == SECSuccess); /* else is coding error */
         if (rv == SECSuccess && enabled)
             return PR_TRUE;
     }
     return PR_FALSE;
 }
 
 /* Ask: is ANY ECC cipher suite enabled on this socket? */
 PRBool
-ssl_IsECCEnabled(sslSocket *ss)
+ssl_IsECCEnabled(const sslSocket *ss)
 {
     PK11SlotInfo *slot;
 
     /* make sure we can do ECC */
     slot = PK11_GetBestSlot(CKM_ECDH1_DERIVE, ss->pkcs11PinArg);
     if (!slot) {
         return PR_FALSE;
     }
     PK11_FreeSlot(slot);
 
     /* make sure an ECC cipher is enabled */
     return ssl_IsSuiteEnabled(ss, ssl_all_ec_suites);
 }
 
 PRBool
-ssl_IsDHEEnabled(sslSocket *ss)
+ssl_IsDHEEnabled(const sslSocket *ss)
 {
     return ssl_IsSuiteEnabled(ss, ssl_dhe_suites);
 }
 
 /* Send our Supported Groups extension. */
 PRInt32
-ssl_SendSupportedGroupsXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes)
+ssl_SendSupportedGroupsXtn(const sslSocket *ss,
+                           TLSExtensionData *xtnData,
+                           PRBool append, PRUint32 maxBytes)
 {
     PRInt32 extension_length;
     unsigned char enabledGroups[64];
     unsigned int enabledGroupsLen = 0;
     unsigned int i;
     PRBool ec;
     PRBool ff = PR_FALSE;
 
@@ -955,41 +958,41 @@ ssl_SendSupportedGroupsXtn(sslSocket *ss
         enabledGroupsLen;
 
     if (maxBytes < (PRUint32)extension_length) {
         return 0;
     }
 
     if (append) {
         SECStatus rv;
-        rv = ssl3_AppendHandshakeNumber(ss, ssl_supported_groups_xtn, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_supported_groups_xtn, 2);
         if (rv != SECSuccess)
             return -1;
-        rv = ssl3_AppendHandshakeNumber(ss, extension_length - 4, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, extension_length - 4, 2);
         if (rv != SECSuccess)
             return -1;
-        rv = ssl3_AppendHandshakeVariable(ss, enabledGroups,
-                                          enabledGroupsLen, 2);
+        rv = ssl3_ExtAppendHandshakeVariable(ss, enabledGroups,
+                                             enabledGroupsLen, 2);
         if (rv != SECSuccess)
             return -1;
         if (!ss->sec.isServer) {
-            TLSExtensionData *xtnData = &ss->xtnData;
             xtnData->advertised[xtnData->numAdvertised++] =
                 ssl_supported_groups_xtn;
         }
     }
     return extension_length;
 }
 
 /* Send our "canned" (precompiled) Supported Point Formats extension,
  * which says that we only support uncompressed points.
  */
 PRInt32
 ssl3_SendSupportedPointFormatsXtn(
-    sslSocket *ss,
+    const sslSocket *ss,
+    TLSExtensionData *xtnData,
     PRBool append,
     PRUint32 maxBytes)
 {
     static const PRUint8 ecPtFmt[6] = {
         0, 11, /* Extension type */
         0, 2,  /* octets that follow */
         1,     /* octets that follow */
         0      /* uncompressed type only */
@@ -998,143 +1001,18 @@ ssl3_SendSupportedPointFormatsXtn(
     /* No point in doing this unless we have a socket that supports ECC.
      * Similarly, no point if we are going to do TLS 1.3 only or we have already
      * picked TLS 1.3 (server) given that it doesn't use point formats. */
     if (!ss || !ssl_IsECCEnabled(ss) ||
         ss->vrange.min >= SSL_LIBRARY_VERSION_TLS_1_3 ||
         (ss->sec.isServer && ss->version >= SSL_LIBRARY_VERSION_TLS_1_3))
         return 0;
     if (append && maxBytes >= (sizeof ecPtFmt)) {
-        SECStatus rv = ssl3_AppendHandshake(ss, ecPtFmt, (sizeof ecPtFmt));
+        SECStatus rv = ssl3_ExtAppendHandshake(ss, ecPtFmt, (sizeof ecPtFmt));
         if (rv != SECSuccess)
             return -1;
         if (!ss->sec.isServer) {
-            TLSExtensionData *xtnData = &ss->xtnData;
             xtnData->advertised[xtnData->numAdvertised++] =
                 ssl_ec_point_formats_xtn;
         }
     }
     return sizeof(ecPtFmt);
 }
-
-/* Just make sure that the remote client supports uncompressed points,
- * Since that is all we support.  Disable ECC cipher suites if it doesn't.
- */
-SECStatus
-ssl3_HandleSupportedPointFormatsXtn(sslSocket *ss, PRUint16 ex_type,
-                                    SECItem *data)
-{
-    int i;
-
-    if (data->len < 2 || data->len > 255 || !data->data ||
-        data->len != (unsigned int)data->data[0] + 1) {
-        return ssl3_DecodeError(ss);
-    }
-    for (i = data->len; --i > 0;) {
-        if (data->data[i] == 0) {
-            /* indicate that we should send a reply */
-            SECStatus rv;
-            rv = ssl3_RegisterServerHelloExtensionSender(ss, ex_type,
-                                                         &ssl3_SendSupportedPointFormatsXtn);
-            return rv;
-        }
-    }
-
-    /* Poor client doesn't support uncompressed points. */
-    PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE);
-    return SECFailure;
-}
-
-static SECStatus
-ssl_UpdateSupportedGroups(sslSocket *ss, SECItem *data)
-{
-    PRInt32 list_len;
-    unsigned int i;
-    const sslNamedGroupDef *enabled[SSL_NAMED_GROUP_COUNT] = { 0 };
-    PORT_Assert(SSL_NAMED_GROUP_COUNT == PR_ARRAY_SIZE(enabled));
-
-    if (!data->data || data->len < 4) {
-        (void)ssl3_DecodeError(ss);
-        return SECFailure;
-    }
-
-    /* get the length of elliptic_curve_list */
-    list_len = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
-    if (list_len < 0 || data->len != list_len || (data->len % 2) != 0) {
-        (void)ssl3_DecodeError(ss);
-        return SECFailure;
-    }
-
-    /* disable all groups and remember the enabled groups */
-    for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) {
-        enabled[i] = ss->namedGroupPreferences[i];
-        ss->namedGroupPreferences[i] = NULL;
-    }
-
-    /* Read groups from data and enable if in |enabled| */
-    while (data->len) {
-        const sslNamedGroupDef *group;
-        PRInt32 curve_name =
-            ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
-        if (curve_name < 0) {
-            return SECFailure; /* fatal alert already sent */
-        }
-        group = ssl_LookupNamedGroup(curve_name);
-        if (group) {
-            for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) {
-                if (enabled[i] && group == enabled[i]) {
-                    ss->namedGroupPreferences[i] = enabled[i];
-                    break;
-                }
-            }
-        }
-
-        /* "Codepoints in the NamedCurve registry with a high byte of 0x01 (that
-         * is, between 256 and 511 inclusive) are set aside for FFDHE groups,"
-         * -- https://tools.ietf.org/html/draft-ietf-tls-negotiated-ff-dhe-10
-         */
-        if ((curve_name & 0xff00) == 0x0100) {
-            ss->ssl3.hs.peerSupportsFfdheGroups = PR_TRUE;
-        }
-    }
-
-    /* Note: if ss->opt.requireDHENamedGroups is set, we disable DHE cipher
-     * suites, but we do that in ssl3_config_match(). */
-    if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3 &&
-        !ss->opt.requireDHENamedGroups && !ss->ssl3.hs.peerSupportsFfdheGroups) {
-        /* If we don't require that DHE use named groups, and no FFDHE was
-         * included, we pretend that they support all the FFDHE groups we do. */
-        for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) {
-            if (enabled[i] && enabled[i]->keaType == ssl_kea_dh) {
-                ss->namedGroupPreferences[i] = enabled[i];
-            }
-        }
-    }
-
-    return SECSuccess;
-}
-
-/* Ensure that the curve in our server cert is one of the ones supported
- * by the remote client, and disable all ECC cipher suites if not.
- */
-SECStatus
-ssl_HandleSupportedGroupsXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data)
-{
-    SECStatus rv;
-
-    rv = ssl_UpdateSupportedGroups(ss, data);
-    if (rv != SECSuccess)
-        return SECFailure;
-
-    /* TLS 1.3 permits the server to send this extension so make it so. */
-    if (ss->sec.isServer && ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
-        rv = ssl3_RegisterServerHelloExtensionSender(ss, ex_type,
-                                                     &ssl_SendSupportedGroupsXtn);
-        if (rv != SECSuccess) {
-            return SECFailure; /* error already set. */
-        }
-    }
-
-    /* Remember that we negotiated this extension. */
-    ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
-
-    return SECSuccess;
-}
--- a/security/nss/lib/ssl/ssl3ext.c
+++ b/security/nss/lib/ssl/ssl3ext.c
@@ -125,27 +125,27 @@ arrayContainsExtension(const PRUint16 *a
     for (i = 0; i < len; i++) {
         if (ex_type == array[i])
             return PR_TRUE;
     }
     return PR_FALSE;
 }
 
 PRBool
-ssl3_ExtensionNegotiated(sslSocket *ss, PRUint16 ex_type)
+ssl3_ExtensionNegotiated(const sslSocket *ss, PRUint16 ex_type)
 {
-    TLSExtensionData *xtnData = &ss->xtnData;
+    const TLSExtensionData *xtnData = &ss->xtnData;
     return arrayContainsExtension(xtnData->negotiated,
                                   xtnData->numNegotiated, ex_type);
 }
 
 PRBool
-ssl3_ClientExtensionAdvertised(sslSocket *ss, PRUint16 ex_type)
+ssl3_ClientExtensionAdvertised(const sslSocket *ss, PRUint16 ex_type)
 {
-    TLSExtensionData *xtnData = &ss->xtnData;
+    const TLSExtensionData *xtnData = &ss->xtnData;
     return arrayContainsExtension(xtnData->advertised,
                                   xtnData->numAdvertised, ex_type);
 }
 
 /* Go through hello extensions in |b| and deserialize
  * them into the list in |ss->ssl3.hs.remoteExtensions|.
  * The only checking we do in this point is for duplicates.
  *
@@ -292,17 +292,18 @@ ssl3_HandleParsedExtensions(sslSocket *s
         }
 
         /* find extension_type in table of Hello Extension Handlers */
         for (handler = handlers; handler->ex_type >= 0; handler++) {
             /* if found, call this handler */
             if (handler->ex_type == extension->type) {
                 SECStatus rv;
 
-                rv = (*handler->ex_handler)(ss, (PRUint16)extension->type,
+                rv = (*handler->ex_handler)(ss, &ss->xtnData,
+                                            (PRUint16)extension->type,
                                             &extension->data);
                 if (rv != SECSuccess) {
                     if (!ss->ssl3.fatalAlertSent) {
                         /* send a generic alert if the handler didn't already */
                         (void)SSL3_SendAlert(ss, alert_fatal, handshake_failure);
                     }
                     return SECFailure;
                 }
@@ -331,30 +332,32 @@ ssl3_HandleExtensions(sslSocket *ss,
 
     ssl3_DestroyRemoteExtensions(&ss->ssl3.hs.remoteExtensions);
     return SECSuccess;
 }
 
 /* Add a callback function to the table of senders of server hello extensions.
  */
 SECStatus
-ssl3_RegisterServerHelloExtensionSender(sslSocket *ss, PRUint16 ex_type,
-                                        ssl3HelloExtensionSenderFunc cb)
+ssl3_RegisterExtensionSender(const sslSocket *ss,
+                             TLSExtensionData *xtnData,
+                             PRUint16 ex_type,
+                             ssl3HelloExtensionSenderFunc cb)
 {
     int i;
     ssl3HelloExtensionSender *sender;
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
-        sender = &ss->xtnData.serverHelloSenders[0];
+        sender = &xtnData->serverHelloSenders[0];
     } else {
         if (tls13_ExtensionAllowed(ex_type, server_hello)) {
             PORT_Assert(!tls13_ExtensionAllowed(ex_type, encrypted_extensions));
-            sender = &ss->xtnData.serverHelloSenders[0];
+            sender = &xtnData->serverHelloSenders[0];
         } else {
             PORT_Assert(tls13_ExtensionAllowed(ex_type, encrypted_extensions));
-            sender = &ss->xtnData.encryptedExtensionsSenders[0];
+            sender = &xtnData->encryptedExtensionsSenders[0];
         }
     }
 
     for (i = 0; i < SSL_MAX_EXTENSIONS; ++i, ++sender) {
         if (!sender->ex_sender) {
             sender->ex_type = ex_type;
             sender->ex_sender = cb;
             return SECSuccess;
@@ -384,17 +387,17 @@ ssl3_CallHelloExtensionSenders(sslSocket
             sender = &clientHelloSendersTLS[0];
         } else {
             sender = &clientHelloSendersSSL3[0];
         }
     }
 
     for (i = 0; i < SSL_MAX_EXTENSIONS; ++i, ++sender) {
         if (sender->ex_sender) {
-            PRInt32 extLen = (*sender->ex_sender)(ss, append, maxBytes);
+            PRInt32 extLen = (*sender->ex_sender)(ss, &ss->xtnData, append, maxBytes);
             if (extLen < 0)
                 return -1;
             maxBytes -= extLen;
             total_exten_len += extLen;
         }
     }
     return total_exten_len;
 }
@@ -405,8 +408,91 @@ ssl3_DestroyRemoteExtensions(PRCList *li
     PRCList *cur_p;
 
     while (!PR_CLIST_IS_EMPTY(list)) {
         cur_p = PR_LIST_TAIL(list);
         PR_REMOVE_LINK(cur_p);
         PORT_Free(cur_p);
     }
 }
+
+/* Initialize the extension data block. */
+void
+ssl3_InitExtensionData(TLSExtensionData *xtnData)
+{
+    /* Set things up to the right starting state. */
+    PORT_Memset(xtnData, 0, sizeof(*xtnData));
+    xtnData->peerSupportsFfdheGroups = PR_FALSE;
+    PR_INIT_CLIST(&xtnData->remoteKeyShares);
+}
+
+/* Free everything that has been allocated and then reset back to
+ * the starting state. */
+void
+ssl3_ResetExtensionData(TLSExtensionData *xtnData)
+{
+    /* Clean up. */
+    ssl3_FreeSniNameArray(xtnData);
+    PORT_Free(xtnData->clientSigSchemes);
+    SECITEM_FreeItem(&xtnData->nextProto, PR_FALSE);
+    tls13_DestroyKeyShares(&xtnData->remoteKeyShares);
+
+    /* Now reinit. */
+    ssl3_InitExtensionData(xtnData);
+}
+
+/* Thunks to let extension handlers operate on const sslSocket* objects. */
+SECStatus
+ssl3_ExtAppendHandshake(const sslSocket *ss, const void *void_src,
+                        PRInt32 bytes)
+{
+    return ssl3_AppendHandshake((sslSocket *)ss, void_src, bytes);
+}
+
+SECStatus
+ssl3_ExtAppendHandshakeNumber(const sslSocket *ss, PRInt32 num,
+                              PRInt32 lenSize)
+{
+    return ssl3_AppendHandshakeNumber((sslSocket *)ss, num, lenSize);
+}
+
+SECStatus
+ssl3_ExtAppendHandshakeVariable(const sslSocket *ss,
+                                const SSL3Opaque *src, PRInt32 bytes,
+                                PRInt32 lenSize)
+{
+    return ssl3_AppendHandshakeVariable((sslSocket *)ss, src, bytes, lenSize);
+}
+
+void
+ssl3_ExtSendAlert(const sslSocket *ss, SSL3AlertLevel level,
+                  SSL3AlertDescription desc)
+{
+    (void)SSL3_SendAlert((sslSocket *)ss, level, desc);
+}
+
+void
+ssl3_ExtDecodeError(const sslSocket *ss)
+{
+    (void)ssl3_DecodeError((sslSocket *)ss);
+}
+
+SECStatus
+ssl3_ExtConsumeHandshake(const sslSocket *ss, void *v, PRInt32 bytes,
+                         SSL3Opaque **b, PRUint32 *length)
+{
+    return ssl3_ConsumeHandshake((sslSocket *)ss, v, bytes, b, length);
+}
+
+PRInt32
+ssl3_ExtConsumeHandshakeNumber(const sslSocket *ss, PRInt32 bytes,
+                               SSL3Opaque **b, PRUint32 *length)
+{
+    return ssl3_ConsumeHandshakeNumber((sslSocket *)ss, bytes, b, length);
+}
+
+SECStatus
+ssl3_ExtConsumeHandshakeVariable(const sslSocket *ss, SECItem *i,
+                                 PRInt32 bytes, SSL3Opaque **b,
+                                 PRUint32 *length)
+{
+    return ssl3_ConsumeHandshakeVariable((sslSocket *)ss, i, bytes, b, length);
+}
new file mode 100644
--- /dev/null
+++ b/security/nss/lib/ssl/ssl3ext.h
@@ -0,0 +1,155 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is PRIVATE to SSL.
+ *
+ * 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 __ssl3ext_h_
+#define __ssl3ext_h_
+
+typedef enum {
+    sni_nametype_hostname
+} SNINameType;
+typedef struct TLSExtensionDataStr TLSExtensionData;
+
+/* registerable callback function that either appends extension to buffer
+ * or returns length of data that it would have appended.
+ */
+typedef PRInt32 (*ssl3HelloExtensionSenderFunc)(const sslSocket *ss,
+                                                TLSExtensionData *xtnData,
+                                                PRBool append,
+                                                PRUint32 maxBytes);
+
+/* registerable callback function that handles a received extension,
+ * of the given type.
+ */
+typedef SECStatus (*ssl3ExtensionHandlerFunc)(const sslSocket *ss,
+                                              TLSExtensionData *xtnData,
+                                              PRUint16 ex_type,
+                                              SECItem *data);
+
+/* row in a table of hello extension senders */
+typedef struct {
+    PRInt32 ex_type;
+    ssl3HelloExtensionSenderFunc ex_sender;
+} ssl3HelloExtensionSender;
+
+/* row in a table of hello extension handlers */
+typedef struct {
+    PRInt32 ex_type;
+    ssl3ExtensionHandlerFunc ex_handler;
+} ssl3ExtensionHandler;
+
+struct TLSExtensionDataStr {
+    /* registered callbacks that send server hello extensions */
+    ssl3HelloExtensionSender serverHelloSenders[SSL_MAX_EXTENSIONS];
+    ssl3HelloExtensionSender encryptedExtensionsSenders[SSL_MAX_EXTENSIONS];
+
+    /* Keep track of the extensions that are negotiated. */
+    PRUint16 numAdvertised;
+    PRUint16 numNegotiated;
+    PRUint16 advertised[SSL_MAX_EXTENSIONS];
+    PRUint16 negotiated[SSL_MAX_EXTENSIONS];
+
+    /* SessionTicket Extension related data. */
+    PRBool ticketTimestampVerified;
+    PRBool emptySessionTicket;
+    PRBool sentSessionTicketInClientHello;
+    SECItem psk_ke_modes;
+    SECItem psk_auth_modes;
+    PRUint32 ticket_age_add;
+    PRBool ticket_age_add_found;
+
+    /* SNI Extension related data
+     * Names data is not coppied from the input buffer. It can not be
+     * used outside the scope where input buffer is defined and that
+     * is beyond ssl3_HandleClientHello function. */
+    SECItem *sniNameArr;
+    PRUint32 sniNameArrSize;
+
+    /* Signed Certificate Timestamps extracted from the TLS extension.
+     * (client only).
+     * This container holds a temporary pointer to the extension data,
+     * until a session structure (the sec.ci.sid of an sslSocket) is setup
+     * that can hold a permanent copy of the data
+     * (in sec.ci.sid.u.ssl3.signedCertTimestamps).
+     * The data pointed to by this structure is neither explicitly allocated
+     * nor copied: the pointer points to the handshake message buffer and is
+     * only valid in the scope of ssl3_HandleServerHello.
+     */
+    SECItem signedCertTimestamps;
+
+    PRBool peerSupportsFfdheGroups; /* if the peer supports named ffdhe groups */
+
+    /* clientSigAndHash contains the contents of the signature_algorithms
+     * extension (if any) from the client. This is only valid for TLS 1.2
+     * or later. */
+    SSLSignatureScheme *clientSigSchemes;
+    unsigned int numClientSigScheme;
+
+    /* In a client: if the server supports Next Protocol Negotiation, then
+     * this is the protocol that was negotiated.
+     */
+    SECItem nextProto;
+    SSLNextProtoState nextProtoState;
+
+    PRUint16 dtlsSRTPCipherSuite; /* 0 if not selected */
+
+    PRCList remoteKeyShares; /* The other side's public keys (TLS 1.3) */
+};
+
+typedef struct TLSExtensionStr {
+    PRCList link;  /* The linked list link */
+    PRUint16 type; /* Extension type */
+    SECItem data;  /* Pointers into the handshake data. */
+} TLSExtension;
+
+SECStatus ssl3_HandleExtensions(sslSocket *ss,
+                                SSL3Opaque **b, PRUint32 *length,
+                                SSL3HandshakeType handshakeMessage);
+SECStatus ssl3_ParseExtensions(sslSocket *ss,
+                               SSL3Opaque **b, PRUint32 *length);
+SECStatus ssl3_HandleParsedExtensions(sslSocket *ss,
+                                      SSL3HandshakeType handshakeMessage);
+TLSExtension *ssl3_FindExtension(sslSocket *ss,
+                                 SSLExtensionType extension_type);
+void ssl3_DestroyRemoteExtensions(PRCList *list);
+void ssl3_InitExtensionData(TLSExtensionData *xtnData);
+void ssl3_ResetExtensionData(TLSExtensionData *xtnData);
+
+PRBool ssl3_ExtensionNegotiated(const sslSocket *ss, PRUint16 ex_type);
+PRBool ssl3_ClientExtensionAdvertised(const sslSocket *ss, PRUint16 ex_type);
+
+SECStatus ssl3_RegisterExtensionSender(const sslSocket *ss,
+                                       TLSExtensionData *xtnData,
+                                       PRUint16 ex_type,
+                                       ssl3HelloExtensionSenderFunc cb);
+PRInt32 ssl3_CallHelloExtensionSenders(sslSocket *ss, PRBool append, PRUint32 maxBytes,
+                                       const ssl3HelloExtensionSender *sender);
+
+unsigned int ssl3_CalculatePaddingExtensionLength(unsigned int clientHelloLength);
+PRInt32 ssl3_AppendPaddingExtension(sslSocket *ss, unsigned int extensionLen,
+                                    PRUint32 maxBytes);
+
+/* Thunks to let us operate on const sslSocket* objects. */
+SECStatus ssl3_ExtAppendHandshake(const sslSocket *ss, const void *void_src,
+                                  PRInt32 bytes);
+SECStatus ssl3_ExtAppendHandshakeNumber(const sslSocket *ss, PRInt32 num,
+                                        PRInt32 lenSize);
+SECStatus ssl3_ExtAppendHandshakeVariable(const sslSocket *ss,
+                                          const SSL3Opaque *src, PRInt32 bytes,
+                                          PRInt32 lenSize);
+void ssl3_ExtSendAlert(const sslSocket *ss, SSL3AlertLevel level,
+                       SSL3AlertDescription desc);
+void ssl3_ExtDecodeError(const sslSocket *ss);
+SECStatus ssl3_ExtConsumeHandshake(const sslSocket *ss, void *v, PRInt32 bytes,
+                                   SSL3Opaque **b, PRUint32 *length);
+PRInt32 ssl3_ExtConsumeHandshakeNumber(const sslSocket *ss, PRInt32 bytes,
+                                       SSL3Opaque **b, PRUint32 *length);
+SECStatus ssl3_ExtConsumeHandshakeVariable(const sslSocket *ss, SECItem *i,
+                                           PRInt32 bytes, SSL3Opaque **b,
+                                           PRUint32 *length);
+
+#endif
--- a/security/nss/lib/ssl/ssl3exthandle.c
+++ b/security/nss/lib/ssl/ssl3exthandle.c
@@ -7,16 +7,17 @@
 #include "nssrenam.h"
 #include "nss.h"
 #include "ssl.h"
 #include "sslproto.h"
 #include "sslimpl.h"
 #include "pk11pub.h"
 #include "blapit.h"
 #include "prinit.h"
+#include "ssl3ext.h"
 #include "ssl3exthandle.h"
 #include "tls13exthandle.h" /* For tls13_ServerSendStatusRequestXtn. */
 
 static unsigned char key_name[SESS_TICKET_KEY_NAME_LEN];
 static PK11SymKey *session_ticket_enc_key = NULL;
 static PK11SymKey *session_ticket_mac_key = NULL;
 
 static PRCallOnceType generate_session_keys_once;
@@ -25,16 +26,17 @@ static SECStatus ssl3_ParseEncryptedSess
                                                   SECItem *data, EncryptedSessionTicket *enc_session_ticket);
 static SECStatus ssl3_AppendToItem(SECItem *item, const unsigned char *buf,
                                    PRUint32 bytes);
 static SECStatus ssl3_ConsumeFromItem(SECItem *item, unsigned char **buf, PRUint32 bytes);
 static SECStatus ssl3_AppendNumberToItem(SECItem *item, PRUint32 num,
                                          PRInt32 lenSize);
 static SECStatus ssl3_GetSessionTicketKeys(sslSocket *ss,
                                            PK11SymKey **aes_key, PK11SymKey **mac_key);
+static SECStatus ssl3_ConsumeFromItem(SECItem *item, unsigned char **buf, PRUint32 bytes);
 
 /*
  * Write bytes.  Using this function means the SECItem structure
  * cannot be freed.  The caller is expected to call this function
  * on a shallow copy of the structure.
  */
 static SECStatus
 ssl3_AppendToItem(SECItem *item, const unsigned char *buf, PRUint32 bytes)
@@ -145,22 +147,23 @@ ssl3_GetSessionTicketKeys(sslSocket *ss,
     if (session_ticket_enc_key == NULL ||
         session_ticket_mac_key == NULL)
         return SECFailure;
 
     *aes_key = session_ticket_enc_key;
     *mac_key = session_ticket_mac_key;
     return SECSuccess;
 }
+
 /* Format an SNI extension, using the name from the socket's URL,
  * unless that name is a dotted decimal string.
  * Used by client and server.
  */
 PRInt32
-ssl3_SendServerNameXtn(sslSocket *ss, PRBool append,
+ssl3_SendServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
                        PRUint32 maxBytes)
 {
     SECStatus rv;
     if (!ss)
         return 0;
     if (!ss->sec.isServer) {
         PRUint32 len;
         PRNetAddr netAddr;
@@ -171,98 +174,96 @@ ssl3_SendServerNameXtn(sslSocket *ss, PR
         /* must not be an IPv4 or IPv6 address */
         if (PR_SUCCESS == PR_StringToNetAddr(ss->url, &netAddr)) {
             /* is an IP address (v4 or v6) */
             return 0;
         }
         len = PORT_Strlen(ss->url);
         if (append && maxBytes >= len + 9) {
             /* extension_type */
-            rv = ssl3_AppendHandshakeNumber(ss, ssl_server_name_xtn, 2);
+            rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_server_name_xtn, 2);
             if (rv != SECSuccess)
                 return -1;
             /* length of extension_data */
-            rv = ssl3_AppendHandshakeNumber(ss, len + 5, 2);
+            rv = ssl3_ExtAppendHandshakeNumber(ss, len + 5, 2);
             if (rv != SECSuccess)
                 return -1;
             /* length of server_name_list */
-            rv = ssl3_AppendHandshakeNumber(ss, len + 3, 2);
+            rv = ssl3_ExtAppendHandshakeNumber(ss, len + 3, 2);
             if (rv != SECSuccess)
                 return -1;
             /* Name Type (sni_host_name) */
-            rv = ssl3_AppendHandshake(ss, "\0", 1);
+            rv = ssl3_ExtAppendHandshake(ss, "\0", 1);
             if (rv != SECSuccess)
                 return -1;
             /* HostName (length and value) */
-            rv = ssl3_AppendHandshakeVariable(ss, (PRUint8 *)ss->url, len, 2);
+            rv = ssl3_ExtAppendHandshakeVariable(ss, (PRUint8 *)ss->url, len, 2);
             if (rv != SECSuccess)
                 return -1;
             if (!ss->sec.isServer) {
-                TLSExtensionData *xtnData = &ss->xtnData;
                 xtnData->advertised[xtnData->numAdvertised++] =
                     ssl_server_name_xtn;
             }
         }
         return len + 9;
     }
     /* Server side */
     if (append && maxBytes >= 4) {
-        rv = ssl3_AppendHandshakeNumber(ss, ssl_server_name_xtn, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_server_name_xtn, 2);
         if (rv != SECSuccess)
             return -1;
         /* length of extension_data */
-        rv = ssl3_AppendHandshakeNumber(ss, 0, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2);
         if (rv != SECSuccess)
             return -1;
     }
     return 4;
 }
 
 /* Handle an incoming SNI extension. */
 SECStatus
-ssl3_HandleServerNameXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data)
+ssl3_HandleServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data)
 {
     SECItem *names = NULL;
-    TLSExtensionData *xtnData = &ss->xtnData;
     PRInt32 listLenBytes = 0;
 
     if (!ss->sec.isServer) {
         return SECSuccess; /* ignore extension */
     }
 
     /* Server side - consume client data and register server sender. */
     /* do not parse the data if don't have user extension handling function. */
     if (!ss->sniSocketConfig) {
         return SECSuccess;
     }
 
     /* length of server_name_list */
-    listLenBytes = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
+    listLenBytes = ssl3_ExtConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
     if (listLenBytes < 0) {
         goto loser; /* alert already sent */
     }
     if (listLenBytes == 0 || listLenBytes != data->len) {
         goto alert_loser;
     }
 
     /* Read ServerNameList. */
     while (data->len > 0) {
         SECItem tmp;
         SECStatus rv;
         PRInt32 type;
 
         /* Read Name Type. */
-        type = ssl3_ConsumeHandshakeNumber(ss, 1, &data->data, &data->len);
+        type = ssl3_ExtConsumeHandshakeNumber(ss, 1, &data->data, &data->len);
         if (type < 0) { /* i.e., SECFailure cast to PRint32 */
             /* alert sent in ConsumeHandshakeNumber */
             goto loser;
         }
 
         /* Read ServerName (length and value). */
-        rv = ssl3_ConsumeHandshakeVariable(ss, &tmp, 2, &data->data, &data->len);
+        rv = ssl3_ExtConsumeHandshakeVariable(ss, &tmp, 2, &data->data, &data->len);
         if (rv != SECSuccess) {
             goto loser;
         }
 
         /* Record the value for host_name(0). */
         if (type == sni_nametype_hostname) {
             /* Fail if we encounter a second host_name entry. */
             if (names) {
@@ -291,17 +292,17 @@ ssl3_HandleServerNameXtn(sslSocket *ss, 
         ssl3_FreeSniNameArray(xtnData);
         xtnData->sniNameArr = names;
         xtnData->sniNameArrSize = 1;
         xtnData->negotiated[xtnData->numNegotiated++] = ssl_server_name_xtn;
     }
     return SECSuccess;
 
 alert_loser:
-    (void)ssl3_DecodeError(ss);
+    ssl3_ExtDecodeError(ss);
 loser:
     if (names) {
         PORT_Free(names);
     }
     return SECFailure;
 }
 
 /* Frees a given xtnData->sniNameArr and its elements. */
@@ -324,17 +325,18 @@ ssl3_FreeSniNameArray(TLSExtensionData *
 }
 
 /* Called by both clients and servers.
  * Clients sends a filled in session ticket if one is available, and otherwise
  * sends an empty ticket.  Servers always send empty tickets.
  */
 PRInt32
 ssl3_SendSessionTicketXtn(
-    sslSocket *ss,
+    const sslSocket *ss,
+    TLSExtensionData *xtnData,
     PRBool append,
     PRUint32 maxBytes)
 {
     PRInt32 extension_length;
     NewSessionTicket *session_ticket = NULL;
     sslSessionID *sid = ss->sec.ci.sid;
 
     /* Never send an extension with a ticket for TLS 1.3, but
@@ -363,61 +365,60 @@ ssl3_SendSessionTicketXtn(
          * caller will call this function twice, and we need the inputs to be
          * consistent between the two calls. Note that currently the caller
          * will only be holding the lock when we are the client and when we're
          * attempting to resume an existing session.
          */
 
         session_ticket = &sid->u.ssl3.locked.sessionTicket;
         if (session_ticket->ticket.data) {
-            if (ss->xtnData.ticketTimestampVerified) {
+            if (xtnData->ticketTimestampVerified) {
                 extension_length += session_ticket->ticket.len;
             } else if (!append &&
                        (session_ticket->ticket_lifetime_hint == 0 ||
                         (session_ticket->ticket_lifetime_hint +
                              session_ticket->received_timestamp >
                          ssl_Time()))) {
                 extension_length += session_ticket->ticket.len;
-                ss->xtnData.ticketTimestampVerified = PR_TRUE;
+                xtnData->ticketTimestampVerified = PR_TRUE;
             }
         }
     }
 
     if (maxBytes < (PRUint32)extension_length) {
         PORT_Assert(0);
         return 0;
     }
     if (append) {
         SECStatus rv;
         /* extension_type */
-        rv = ssl3_AppendHandshakeNumber(ss, ssl_session_ticket_xtn, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_session_ticket_xtn, 2);
         if (rv != SECSuccess)
             goto loser;
         if (session_ticket && session_ticket->ticket.data &&
-            ss->xtnData.ticketTimestampVerified) {
-            rv = ssl3_AppendHandshakeVariable(ss, session_ticket->ticket.data,
-                                              session_ticket->ticket.len, 2);
-            ss->xtnData.ticketTimestampVerified = PR_FALSE;
-            ss->xtnData.sentSessionTicketInClientHello = PR_TRUE;
+            xtnData->ticketTimestampVerified) {
+            rv = ssl3_ExtAppendHandshakeVariable(ss, session_ticket->ticket.data,
+                                                 session_ticket->ticket.len, 2);
+            xtnData->ticketTimestampVerified = PR_FALSE;
+            xtnData->sentSessionTicketInClientHello = PR_TRUE;
         } else {
-            rv = ssl3_AppendHandshakeNumber(ss, 0, 2);
+            rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2);
         }
         if (rv != SECSuccess)
             goto loser;
 
         if (!ss->sec.isServer) {
-            TLSExtensionData *xtnData = &ss->xtnData;
             xtnData->advertised[xtnData->numAdvertised++] =
                 ssl_session_ticket_xtn;
         }
     }
     return extension_length;
 
 loser:
-    ss->xtnData.ticketTimestampVerified = PR_FALSE;
+    xtnData->ticketTimestampVerified = PR_FALSE;
     return -1;
 }
 
 static SECStatus
 ssl3_ParseEncryptedSessionTicket(sslSocket *ss, SECItem *data,
                                  EncryptedSessionTicket *enc_session_ticket)
 {
     if (ssl3_ConsumeFromItem(data, &enc_session_ticket->key_name,
@@ -439,26 +440,26 @@ ssl3_ParseEncryptedSessionTicket(sslSock
     if (data->len != 0) /* Make sure that we have consumed all bytes. */
         return SECFailure;
 
     return SECSuccess;
 }
 
 /* handle an incoming Next Protocol Negotiation extension. */
 SECStatus
-ssl3_ServerHandleNextProtoNegoXtn(sslSocket *ss, PRUint16 ex_type,
+ssl3_ServerHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
                                   SECItem *data)
 {
     if (ss->firstHsDone || data->len != 0) {
         /* Clients MUST send an empty NPN extension, if any. */
         PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
         return SECFailure;
     }
 
-    ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
+    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
 
     /* TODO: server side NPN support would require calling
      * ssl3_RegisterServerHelloExtensionSender here in order to echo the
      * extension back to the client. */
 
     return SECSuccess;
 }
 
@@ -481,226 +482,227 @@ ssl3_ValidateNextProtoNego(const unsigne
         offset = newOffset;
     }
 
     return SECSuccess;
 }
 
 /* protocol selection handler for ALPN (server side) and NPN (client side) */
 static SECStatus
-ssl3_SelectAppProtocol(sslSocket *ss, PRUint16 ex_type, SECItem *data)
+ssl3_SelectAppProtocol(const sslSocket *ss, TLSExtensionData *xtnData,
+                       PRUint16 ex_type, SECItem *data)
 {
     SECStatus rv;
     unsigned char resultBuffer[255];
     SECItem result = { siBuffer, resultBuffer, 0 };
 
     rv = ssl3_ValidateNextProtoNego(data->data, data->len);
     if (rv != SECSuccess) {
-        (void)SSL3_SendAlert(ss, alert_fatal, decode_error);
+        ssl3_ExtSendAlert(ss, alert_fatal, decode_error);
         PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
         return rv;
     }
 
     PORT_Assert(ss->nextProtoCallback);
     /* For ALPN, the cipher suite isn't selected yet.  Note that extensions
      * sometimes affect what cipher suite is selected, e.g., for ECC. */
     PORT_Assert((ss->ssl3.hs.preliminaryInfo &
                  ssl_preinfo_all & ~ssl_preinfo_cipher_suite) ==
                 (ssl_preinfo_all & ~ssl_preinfo_cipher_suite));
     rv = ss->nextProtoCallback(ss->nextProtoArg, ss->fd, data->data, data->len,
                                result.data, &result.len, sizeof(resultBuffer));
     if (rv != SECSuccess) {
         /* Expect callback to call PORT_SetError() */
-        (void)SSL3_SendAlert(ss, alert_fatal, internal_error);
+        ssl3_ExtSendAlert(ss, alert_fatal, internal_error);
         return SECFailure;
     }
 
     /* If the callback wrote more than allowed to |result| it has corrupted our
      * stack. */
     if (result.len > sizeof(resultBuffer)) {
         PORT_SetError(SEC_ERROR_OUTPUT_LEN);
         /* TODO: crash */
         return SECFailure;
     }
 
-    SECITEM_FreeItem(&ss->ssl3.nextProto, PR_FALSE);
+    SECITEM_FreeItem(&xtnData->nextProto, PR_FALSE);
 
     if (ex_type == ssl_app_layer_protocol_xtn &&
-        ss->ssl3.nextProtoState != SSL_NEXT_PROTO_NEGOTIATED) {
+        xtnData->nextProtoState != SSL_NEXT_PROTO_NEGOTIATED) {
         /* The callback might say OK, but then it picks a default value - one
          * that was not listed.  That's OK for NPN, but not ALPN. */
-        (void)SSL3_SendAlert(ss, alert_fatal, no_application_protocol);
+        ssl3_ExtSendAlert(ss, alert_fatal, no_application_protocol);
         PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_NO_PROTOCOL);
         return SECFailure;
     }
 
-    ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
-    return SECITEM_CopyItem(NULL, &ss->ssl3.nextProto, &result);
+    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
+    return SECITEM_CopyItem(NULL, &xtnData->nextProto, &result);
 }
 
 /* handle an incoming ALPN extension at the server */
 SECStatus
-ssl3_ServerHandleAppProtoXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data)
+ssl3_ServerHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data)
 {
     int count;
     SECStatus rv;
 
     /* We expressly don't want to allow ALPN on renegotiation,
      * despite it being permitted by the spec. */
     if (ss->firstHsDone || data->len == 0) {
         /* Clients MUST send a non-empty ALPN extension. */
-        (void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
+        ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter);
         PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
         return SECFailure;
     }
 
     /* Unlike NPN, ALPN has extra redundant length information so that
      * the extension is the same in both ClientHello and ServerHello. */
-    count = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
+    count = ssl3_ExtConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
     if (count != data->len) {
-        (void)ssl3_DecodeError(ss);
+        ssl3_ExtDecodeError(ss);
         return SECFailure;
     }
 
     if (!ss->nextProtoCallback) {
         /* we're not configured for it */
         return SECSuccess;
     }
 
-    rv = ssl3_SelectAppProtocol(ss, ex_type, data);
+    rv = ssl3_SelectAppProtocol(ss, xtnData, ex_type, data);
     if (rv != SECSuccess) {
         return rv;
     }
 
     /* prepare to send back a response, if we negotiated */
-    if (ss->ssl3.nextProtoState == SSL_NEXT_PROTO_NEGOTIATED) {
-        rv = ssl3_RegisterServerHelloExtensionSender(
-            ss, ex_type, ssl3_ServerSendAppProtoXtn);
+    if (xtnData->nextProtoState == SSL_NEXT_PROTO_NEGOTIATED) {
+        rv = ssl3_RegisterExtensionSender(
+            ss, xtnData, ex_type, ssl3_ServerSendAppProtoXtn);
         if (rv != SECSuccess) {
-            (void)SSL3_SendAlert(ss, alert_fatal, internal_error);
+            ssl3_ExtSendAlert(ss, alert_fatal, internal_error);
             PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
             return rv;
         }
     }
     return SECSuccess;
 }
 
 SECStatus
-ssl3_ClientHandleNextProtoNegoXtn(sslSocket *ss, PRUint16 ex_type,
+ssl3_ClientHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
                                   SECItem *data)
 {
     PORT_Assert(!ss->firstHsDone);
 
     if (ssl3_ExtensionNegotiated(ss, ssl_app_layer_protocol_xtn)) {
         /* If the server negotiated ALPN then it has already told us what
          * protocol to use, so it doesn't make sense for us to try to negotiate
          * a different one by sending the NPN handshake message. However, if
          * we've negotiated NPN then we're required to send the NPN handshake
          * message. Thus, these two extensions cannot both be negotiated on the
          * same connection. */
-        (void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
+        ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter);
         PORT_SetError(SSL_ERROR_BAD_SERVER);
         return SECFailure;
     }
 
     /* We should only get this call if we sent the extension, so
      * ss->nextProtoCallback needs to be non-NULL.  However, it is possible
      * that an application erroneously cleared the callback between the time
      * we sent the ClientHello and now. */
     if (!ss->nextProtoCallback) {
         PORT_Assert(0);
-        (void)SSL3_SendAlert(ss, alert_fatal, internal_error);
+        ssl3_ExtSendAlert(ss, alert_fatal, internal_error);
         PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_NO_CALLBACK);
         return SECFailure;
     }
 
-    return ssl3_SelectAppProtocol(ss, ex_type, data);
+    return ssl3_SelectAppProtocol(ss, xtnData, ex_type, data);
 }
 
 SECStatus
-ssl3_ClientHandleAppProtoXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data)
+ssl3_ClientHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data)
 {
     SECStatus rv;
     PRInt32 list_len;
     SECItem protocol_name;
 
     if (ssl3_ExtensionNegotiated(ss, ssl_next_proto_nego_xtn)) {
         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
         return SECFailure;
     }
 
     /* The extension data from the server has the following format:
      *   uint16 name_list_len;
      *   uint8 len;  // where len >= 1
      *   uint8 protocol_name[len]; */
     if (data->len < 4 || data->len > 2 + 1 + 255) {
-        (void)SSL3_SendAlert(ss, alert_fatal, decode_error);
+        ssl3_ExtSendAlert(ss, alert_fatal, decode_error);
         PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
         return SECFailure;
     }
 
-    list_len = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
+    list_len = ssl3_ExtConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
     /* The list has to be the entire extension. */
     if (list_len != data->len) {
-        (void)SSL3_SendAlert(ss, alert_fatal, decode_error);
+        ssl3_ExtSendAlert(ss, alert_fatal, decode_error);
         PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
         return SECFailure;
     }
 
-    rv = ssl3_ConsumeHandshakeVariable(ss, &protocol_name, 1,
-                                       &data->data, &data->len);
+    rv = ssl3_ExtConsumeHandshakeVariable(ss, &protocol_name, 1,
+                                          &data->data, &data->len);
     /* The list must have exactly one value. */
     if (rv != SECSuccess || data->len != 0) {
-        (void)SSL3_SendAlert(ss, alert_fatal, decode_error);
+        ssl3_ExtSendAlert(ss, alert_fatal, decode_error);
         PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
         return SECFailure;
     }
 
-    SECITEM_FreeItem(&ss->ssl3.nextProto, PR_FALSE);
-    ss->ssl3.nextProtoState = SSL_NEXT_PROTO_SELECTED;
-    ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
-    return SECITEM_CopyItem(NULL, &ss->ssl3.nextProto, &protocol_name);
+    SECITEM_FreeItem(&xtnData->nextProto, PR_FALSE);
+    xtnData->nextProtoState = SSL_NEXT_PROTO_SELECTED;
+    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
+    return SECITEM_CopyItem(NULL, &xtnData->nextProto, &protocol_name);
 }
 
 PRInt32
-ssl3_ClientSendNextProtoNegoXtn(sslSocket *ss, PRBool append,
+ssl3_ClientSendNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
                                 PRUint32 maxBytes)
 {
     PRInt32 extension_length;
 
     /* Renegotiations do not send this extension. */
     if (!ss->opt.enableNPN || !ss->nextProtoCallback || ss->firstHsDone) {
         return 0;
     }
 
     extension_length = 4;
 
     if (maxBytes < (PRUint32)extension_length) {
         return 0;
     }
     if (append) {
         SECStatus rv;
-        rv = ssl3_AppendHandshakeNumber(ss, ssl_next_proto_nego_xtn, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_next_proto_nego_xtn, 2);
         if (rv != SECSuccess)
             goto loser;
-        rv = ssl3_AppendHandshakeNumber(ss, 0, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2);
         if (rv != SECSuccess)
             goto loser;
-        ss->xtnData.advertised[ss->xtnData.numAdvertised++] =
+        xtnData->advertised[xtnData->numAdvertised++] =
             ssl_next_proto_nego_xtn;
     }
 
     return extension_length;
 
 loser:
     return -1;
 }
 
 PRInt32
-ssl3_ClientSendAppProtoXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes)
+ssl3_ClientSendAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes)
 {
     PRInt32 extension_length;
     unsigned char *alpn_protos = NULL;
 
     /* Renegotiations do not send this extension. */
     if (!ss->opt.enableALPN || !ss->opt.nextProtoNego.data || ss->firstHsDone) {
         return 0;
     }
@@ -731,108 +733,109 @@ ssl3_ClientSendAppProtoXtn(sslSocket *ss
                 memcpy(alpn_protos, &ss->opt.nextProtoNego.data[i], len - i);
                 memcpy(alpn_protos + len - i, ss->opt.nextProtoNego.data, i);
             } else {
                 /* This seems to be invalid data so we'll send as-is. */
                 memcpy(alpn_protos, ss->opt.nextProtoNego.data, len);
             }
         }
 
-        rv = ssl3_AppendHandshakeNumber(ss, ssl_app_layer_protocol_xtn, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_app_layer_protocol_xtn, 2);
         if (rv != SECSuccess) {
             goto loser;
         }
-        rv = ssl3_AppendHandshakeNumber(ss, extension_length - 4, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, extension_length - 4, 2);
         if (rv != SECSuccess) {
             goto loser;
         }
-        rv = ssl3_AppendHandshakeVariable(ss, alpn_protos, len, 2);
+        rv = ssl3_ExtAppendHandshakeVariable(ss, alpn_protos, len, 2);
         PORT_Free(alpn_protos);
         alpn_protos = NULL;
         if (rv != SECSuccess) {
             goto loser;
         }
-        ss->xtnData.advertised[ss->xtnData.numAdvertised++] =
+        xtnData->advertised[xtnData->numAdvertised++] =
             ssl_app_layer_protocol_xtn;
     }
 
     return extension_length;
 
 loser:
     if (alpn_protos) {
         PORT_Free(alpn_protos);
     }
     return -1;
 }
 
 PRInt32
-ssl3_ServerSendAppProtoXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes)
+ssl3_ServerSendAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes)
 {
     PRInt32 extension_length;
 
     /* we're in over our heads if any of these fail */
     PORT_Assert(ss->opt.enableALPN);
-    PORT_Assert(ss->ssl3.nextProto.data);
-    PORT_Assert(ss->ssl3.nextProto.len > 0);
-    PORT_Assert(ss->ssl3.nextProtoState == SSL_NEXT_PROTO_NEGOTIATED);
+    PORT_Assert(xtnData->nextProto.data);
+    PORT_Assert(xtnData->nextProto.len > 0);
+    PORT_Assert(xtnData->nextProtoState == SSL_NEXT_PROTO_NEGOTIATED);
     PORT_Assert(!ss->firstHsDone);
 
     extension_length = 2 /* extension type */ + 2 /* extension length */ +
                        2 /* protocol name list */ + 1 /* name length */ +
-                       ss->ssl3.nextProto.len;
+                       xtnData->nextProto.len;
 
     if (maxBytes < (PRUint32)extension_length) {
         return 0;
     }
     if (append) {
         SECStatus rv;
-        rv = ssl3_AppendHandshakeNumber(ss, ssl_app_layer_protocol_xtn, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_app_layer_protocol_xtn, 2);
         if (rv != SECSuccess) {
             return -1;
         }
-        rv = ssl3_AppendHandshakeNumber(ss, extension_length - 4, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, extension_length - 4, 2);
         if (rv != SECSuccess) {
             return -1;
         }
-        rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.nextProto.len + 1, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, xtnData->nextProto.len + 1, 2);
         if (rv != SECSuccess) {
             return -1;
         }
-        rv = ssl3_AppendHandshakeVariable(ss, ss->ssl3.nextProto.data,
-                                          ss->ssl3.nextProto.len, 1);
+        rv = ssl3_ExtAppendHandshakeVariable(ss, xtnData->nextProto.data,
+                                             xtnData->nextProto.len, 1);
         if (rv != SECSuccess) {
             return -1;
         }
     }
 
     return extension_length;
 }
 
 SECStatus
-ssl3_ServerHandleStatusRequestXtn(sslSocket *ss, PRUint16 ex_type,
+ssl3_ServerHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
                                   SECItem *data)
 {
     ssl3HelloExtensionSenderFunc sender;
 
     PORT_Assert(ss->sec.isServer);
 
     /* remember that we got this extension. */
-    ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
+    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
 
     if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
         sender = tls13_ServerSendStatusRequestXtn;
     } else {
         sender = ssl3_ServerSendStatusRequestXtn;
     }
-    return ssl3_RegisterServerHelloExtensionSender(ss, ex_type, sender);
+    return ssl3_RegisterExtensionSender(ss, xtnData, ex_type, sender);
 }
 
 PRInt32
 ssl3_ServerSendStatusRequestXtn(
-    sslSocket *ss,
+    const sslSocket *ss,
+    TLSExtensionData *xtnData,
     PRBool append,
     PRUint32 maxBytes)
 {
     PRInt32 extension_length;
     const sslServerCert *serverCert = ss->sec.serverCert;
     SECStatus rv;
 
     if (!serverCert->certStatusArray ||
@@ -841,33 +844,33 @@ ssl3_ServerSendStatusRequestXtn(
     }
 
     extension_length = 2 + 2;
     if (maxBytes < (PRUint32)extension_length) {
         return 0;
     }
     if (append) {
         /* extension_type */
-        rv = ssl3_AppendHandshakeNumber(ss, ssl_cert_status_xtn, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_cert_status_xtn, 2);
         if (rv != SECSuccess)
             return -1;
         /* length of extension_data */
-        rv = ssl3_AppendHandshakeNumber(ss, 0, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2);
         if (rv != SECSuccess)
             return -1;
         /* The certificate status data is sent in ssl3_SendCertificateStatus. */
     }
 
     return extension_length;
 }
 
 /* ssl3_ClientSendStatusRequestXtn builds the status_request extension on the
  * client side. See RFC 6066 section 8. */
 PRInt32
-ssl3_ClientSendStatusRequestXtn(sslSocket *ss, PRBool append,
+ssl3_ClientSendStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
                                 PRUint32 maxBytes)
 {
     PRInt32 extension_length;
 
     if (!ss->opt.enableOCSPStapling)
         return 0;
 
     /* extension_type (2-bytes) +
@@ -879,65 +882,64 @@ ssl3_ClientSendStatusRequestXtn(sslSocke
     extension_length = 9;
 
     if (maxBytes < (PRUint32)extension_length) {
         PORT_Assert(0);
         return 0;
     }
     if (append) {
         SECStatus rv;
-        TLSExtensionData *xtnData;
 
         /* extension_type */
-        rv = ssl3_AppendHandshakeNumber(ss, ssl_cert_status_xtn, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_cert_status_xtn, 2);
         if (rv != SECSuccess)
             return -1;
-        rv = ssl3_AppendHandshakeNumber(ss, extension_length - 4, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, extension_length - 4, 2);
         if (rv != SECSuccess)
             return -1;
-        rv = ssl3_AppendHandshakeNumber(ss, 1 /* status_type ocsp */, 1);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, 1 /* status_type ocsp */, 1);
         if (rv != SECSuccess)
             return -1;
         /* A zero length responder_id_list means that the responders are
          * implicitly known to the server. */
-        rv = ssl3_AppendHandshakeNumber(ss, 0, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2);
         if (rv != SECSuccess)
             return -1;
         /* A zero length request_extensions means that there are no extensions.
          * Specifically, we don't set the id-pkix-ocsp-nonce extension. This
          * means that the server can replay a cached OCSP response to us. */
-        rv = ssl3_AppendHandshakeNumber(ss, 0, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2);
         if (rv != SECSuccess)
             return -1;
 
-        xtnData = &ss->xtnData;
         xtnData->advertised[xtnData->numAdvertised++] = ssl_cert_status_xtn;
     }
     return extension_length;
 }
 
 SECStatus
-ssl3_ClientHandleStatusRequestXtn(sslSocket *ss, PRUint16 ex_type,
+ssl3_ClientHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
                                   SECItem *data)
 {
     /* In TLS 1.3, the extension carries the OCSP response. */
     if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
         SECStatus rv;
-        rv = ssl_ReadCertificateStatus(ss, data->data, data->len);
+        rv = ssl_ReadCertificateStatus(CONST_CAST(sslSocket, ss),
+                                       data->data, data->len);
         if (rv != SECSuccess) {
             return SECFailure; /* code already set */
         }
     } else if (data->len != 0) {
-        (void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
+        ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter);
         PORT_SetError(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
         return SECFailure;
     }
 
     /* Keep track of negotiated extensions. */
-    ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
+    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
     return SECSuccess;
 }
 
 /*
  * Called from ssl3_SendNewSessionTicket, tls13_SendNewSessionTicket
  */
 SECStatus
 ssl3_EncodeSessionTicket(sslSocket *ss,
@@ -1032,19 +1034,19 @@ ssl3_EncodeSessionTicket(sslSocket *ss,
         ms_is_wrapped = PR_TRUE;
     }
     /* Prep to send negotiated name */
     srvName = &ss->sec.ci.sid->u.ssl3.srvName;
     if (srvName->data && srvName->len) {
         srvNameLen = 2 + srvName->len; /* len bytes + name len */
     }
 
-    if (ss->ssl3.nextProtoState != SSL_NEXT_PROTO_NO_SUPPORT &&
-        ss->ssl3.nextProto.data) {
-        alpnSelection = ss->ssl3.nextProto;
+    if (ss->xtnData.nextProtoState != SSL_NEXT_PROTO_NO_SUPPORT &&
+        ss->xtnData.nextProto.data) {
+        alpnSelection = ss->xtnData.nextProto;
     }
 
     ciphertext_length =
         sizeof(PRUint16)                       /* ticket_version */
         + sizeof(SSL3ProtocolVersion)          /* ssl_version */
         + sizeof(ssl3CipherSuite)              /* ciphersuite */
         + 1                                    /* compression */
         + 10                                   /* cipher spec parameters */
@@ -1319,25 +1321,25 @@ loser:
 
     return rv;
 }
 
 /* When a client receives a SessionTicket extension a NewSessionTicket
  * message is expected during the handshake.
  */
 SECStatus
-ssl3_ClientHandleSessionTicketXtn(sslSocket *ss, PRUint16 ex_type,
+ssl3_ClientHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
                                   SECItem *data)
 {
     if (data->len != 0) {
         return SECSuccess; /* Ignore the extension. */
     }
 
     /* Keep track of negotiated extensions. */
-    ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
+    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
     return SECSuccess;
 }
 
 /* Generic ticket processing code, common to TLS 1.0-1.2 and
  * TLS 1.3. */
 SECStatus
 ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data)
 {
@@ -1492,61 +1494,61 @@ ssl3_ProcessSessionTicketCommon(sslSocke
 
     parsed_session_ticket = PORT_ZAlloc(sizeof(SessionTicket));
     if (parsed_session_ticket == NULL) {
         rv = SECFailure;
         goto loser;
     }
 
     /* Read ticket_version and reject if the version is wrong */
-    temp = ssl3_ConsumeHandshakeNumber(ss, 2, &buffer, &buffer_len);
+    temp = ssl3_ExtConsumeHandshakeNumber(ss, 2, &buffer, &buffer_len);
     if (temp != TLS_EX_SESS_TICKET_VERSION)
         goto no_ticket;
 
     parsed_session_ticket->ticket_version = (SSL3ProtocolVersion)temp;
 
     /* Read SSLVersion. */
-    temp = ssl3_ConsumeHandshakeNumber(ss, 2, &buffer, &buffer_len);
+    temp = ssl3_ExtConsumeHandshakeNumber(ss, 2, &buffer, &buffer_len);
     if (temp < 0)
         goto no_ticket;
     parsed_session_ticket->ssl_version = (SSL3ProtocolVersion)temp;
 
     /* Read cipher_suite. */
-    temp = ssl3_ConsumeHandshakeNumber(ss, 2, &buffer, &buffer_len);
+    temp = ssl3_ExtConsumeHandshakeNumber(ss, 2, &buffer, &buffer_len);
     if (temp < 0)
         goto no_ticket;
     parsed_session_ticket->cipher_suite = (ssl3CipherSuite)temp;
 
     /* Read compression_method. */
-    temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
+    temp = ssl3_ExtConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
     if (temp < 0)
         goto no_ticket;
     parsed_session_ticket->compression_method = (SSLCompressionMethod)temp;
 
     /* Read cipher spec parameters. */
-    temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
+    temp = ssl3_ExtConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
     if (temp < 0)
         goto no_ticket;
     parsed_session_ticket->authType = (SSLAuthType)temp;
-    temp = ssl3_ConsumeHandshakeNumber(ss, 4, &buffer, &buffer_len);
+    temp = ssl3_ExtConsumeHandshakeNumber(ss, 4, &buffer, &buffer_len);
     if (temp < 0)
         goto no_ticket;
     parsed_session_ticket->authKeyBits = (PRUint32)temp;
-    temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
+    temp = ssl3_ExtConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
     if (temp < 0)
         goto no_ticket;
     parsed_session_ticket->keaType = (SSLKEAType)temp;
-    temp = ssl3_ConsumeHandshakeNumber(ss, 4, &buffer, &buffer_len);
+    temp = ssl3_ExtConsumeHandshakeNumber(ss, 4, &buffer, &buffer_len);
     if (temp < 0)
         goto no_ticket;
     parsed_session_ticket->keaKeyBits = (PRUint32)temp;
 
     /* Read certificate slot */
     parsed_session_ticket->certType.authType = parsed_session_ticket->authType;
-    temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
+    temp = ssl3_ExtConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
     if (temp < 0)
         goto no_ticket;
     switch (parsed_session_ticket->authType) {
         case ssl_auth_ecdsa:
         case ssl_auth_ecdh_rsa:
         case ssl_auth_ecdh_ecdsa: {
             const sslNamedGroupDef *group =
                 ssl_LookupNamedGroup((SSLNamedGroup)temp);
@@ -1555,27 +1557,27 @@ ssl3_ProcessSessionTicketCommon(sslSocke
             }
             parsed_session_ticket->certType.namedCurve = group;
         } break;
         default:
             break;
     }
 
     /* Read wrapped master_secret. */
-    temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
+    temp = ssl3_ExtConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
     if (temp < 0)
         goto no_ticket;
     parsed_session_ticket->ms_is_wrapped = (PRBool)temp;
 
-    temp = ssl3_ConsumeHandshakeNumber(ss, 4, &buffer, &buffer_len);
+    temp = ssl3_ExtConsumeHandshakeNumber(ss, 4, &buffer, &buffer_len);
     if (temp < 0)
         goto no_ticket;
     parsed_session_ticket->msWrapMech = (CK_MECHANISM_TYPE)temp;
 
-    temp = ssl3_ConsumeHandshakeNumber(ss, 2, &buffer, &buffer_len);
+    temp = ssl3_ExtConsumeHandshakeNumber(ss, 2, &buffer, &buffer_len);
     if (temp < 0)
         goto no_ticket;
     parsed_session_ticket->ms_length = (PRUint16)temp;
     if (parsed_session_ticket->ms_length == 0 || /* sanity check MS. */
         parsed_session_ticket->ms_length >
             sizeof(parsed_session_ticket->master_secret))
         goto no_ticket;
 
@@ -1583,73 +1585,73 @@ ssl3_ProcessSessionTicketCommon(sslSocke
     if (buffer_len < parsed_session_ticket->ms_length)
         goto no_ticket;
     PORT_Memcpy(parsed_session_ticket->master_secret, buffer,
                 parsed_session_ticket->ms_length);
     buffer += parsed_session_ticket->ms_length;
     buffer_len -= parsed_session_ticket->ms_length;
 
     /* Read client_identity */
-    temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
+    temp = ssl3_ExtConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
     if (temp < 0)
         goto no_ticket;
     parsed_session_ticket->client_identity.client_auth_type =
         (ClientAuthenticationType)temp;
     switch (parsed_session_ticket->client_identity.client_auth_type) {
         case CLIENT_AUTH_ANONYMOUS:
             break;
         case CLIENT_AUTH_CERTIFICATE:
-            rv = ssl3_ConsumeHandshakeVariable(ss, &cert_item, 3,
-                                               &buffer, &buffer_len);
+            rv = ssl3_ExtConsumeHandshakeVariable(ss, &cert_item, 3,
+                                                  &buffer, &buffer_len);
             if (rv != SECSuccess)
                 goto no_ticket;
             rv = SECITEM_CopyItem(NULL, &parsed_session_ticket->peer_cert,
                                   &cert_item);
             if (rv != SECSuccess)
                 goto no_ticket;
             break;
         default:
             goto no_ticket;
     }
     /* Read timestamp. */
-    temp = ssl3_ConsumeHandshakeNumber(ss, 4, &buffer, &buffer_len);
+    temp = ssl3_ExtConsumeHandshakeNumber(ss, 4, &buffer, &buffer_len);
     if (temp < 0)
         goto no_ticket;
     parsed_session_ticket->timestamp = (PRUint32)temp;
 
     /* Read server name */
     nameType =
-        ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
+        ssl3_ExtConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
     if (nameType != TLS_STE_NO_SERVER_NAME) {
         SECItem name_item;
-        rv = ssl3_ConsumeHandshakeVariable(ss, &name_item, 2, &buffer,
-                                           &buffer_len);
+        rv = ssl3_ExtConsumeHandshakeVariable(ss, &name_item, 2, &buffer,
+                                              &buffer_len);
         if (rv != SECSuccess)
             goto no_ticket;
         rv = SECITEM_CopyItem(NULL, &parsed_session_ticket->srvName,
                               &name_item);
         if (rv != SECSuccess)
             goto no_ticket;
         parsed_session_ticket->srvName.type = nameType;
     }
 
     /* Read extendedMasterSecretUsed */
-    temp = ssl3_ConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
+    temp = ssl3_ExtConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len);
     if (temp < 0)
         goto no_ticket;
     PORT_Assert(temp == PR_TRUE || temp == PR_FALSE);
     parsed_session_ticket->extendedMasterSecretUsed = (PRBool)temp;
 
-    rv = ssl3_ConsumeHandshake(ss, &parsed_session_ticket->flags, 4,
-                               &buffer, &buffer_len);
+    rv = ssl3_ExtConsumeHandshake(ss, &parsed_session_ticket->flags, 4,
+                                  &buffer, &buffer_len);
     if (rv != SECSuccess)
         goto no_ticket;
     parsed_session_ticket->flags = PR_ntohl(parsed_session_ticket->flags);
 
-    rv = ssl3_ConsumeHandshakeVariable(ss, &alpn_item, 1, &buffer, &buffer_len);
+    rv = ssl3_ExtConsumeHandshakeVariable(ss, &alpn_item, 1, &buffer, &buffer_len);
     if (rv != SECSuccess)
         goto no_ticket;
     if (alpn_item.len != 0) {
         rv = SECITEM_CopyItem(NULL, &parsed_session_ticket->alpnSelection,
                               &alpn_item);
         if (rv != SECSuccess)
             goto no_ticket;
         if (alpn_item.len >= 256)
@@ -1762,43 +1764,43 @@ loser:
         }
         PORT_ZFree(parsed_session_ticket, sizeof(SessionTicket));
     }
 
     return rv;
 }
 
 SECStatus
-ssl3_ServerHandleSessionTicketXtn(sslSocket *ss, PRUint16 ex_type,
+ssl3_ServerHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
                                   SECItem *data)
 {
 
     /* Ignore the SessionTicket extension if processing is disabled. */
     if (!ss->opt.enableSessionTickets) {
         return SECSuccess;
     }
 
     /* If we are doing TLS 1.3, then ignore this. */
     if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
         return SECSuccess;
     }
 
     /* Keep track of negotiated extensions. */
-    ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
+    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
 
     /* Parse the received ticket sent in by the client.  We are
      * lenient about some parse errors, falling back to a fullshake
      * instead of terminating the current connection.
      */
     if (data->len == 0) {
-        ss->xtnData.emptySessionTicket = PR_TRUE;
+        xtnData->emptySessionTicket = PR_TRUE;
         return SECSuccess;
     }
 
-    return ssl3_ProcessSessionTicketCommon(ss, data);
+    return ssl3_ProcessSessionTicketCommon(CONST_CAST(sslSocket, ss), data);
 }
 
 /*
  * Read bytes.  Using this function means the SECItem structure
  * cannot be freed.  The caller is expected to call this function
  * on a shallow copy of the structure.
  */
 static SECStatus
@@ -1817,17 +1819,18 @@ ssl3_ConsumeFromItem(SECItem *item, unsi
  * Extension number:   2 bytes
  * Extension length:   2 bytes
  * Verify Data Length: 1 byte
  * Verify Data (TLS): 12 bytes (client) or 24 bytes (server)
  * Verify Data (SSL): 36 bytes (client) or 72 bytes (server)
  */
 PRInt32
 ssl3_SendRenegotiationInfoXtn(
-    sslSocket *ss,
+    const sslSocket *ss,
+    TLSExtensionData *xtnData,
     PRBool append,
     PRUint32 maxBytes)
 {
     PRInt32 len = 0;
     PRInt32 needed;
 
     /* In draft-ietf-tls-renegotiation-03, it is NOT RECOMMENDED to send
      * both the SCSV and the empty RI, so when we send SCSV in
@@ -1841,331 +1844,332 @@ ssl3_SendRenegotiationInfoXtn(
     }
     needed = 5 + len;
     if (maxBytes < (PRUint32)needed) {
         return 0;
     }
     if (append) {
         SECStatus rv;
         /* extension_type */
-        rv = ssl3_AppendHandshakeNumber(ss, ssl_renegotiation_info_xtn, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_renegotiation_info_xtn, 2);
         if (rv != SECSuccess)
             return -1;
         /* length of extension_data */
-        rv = ssl3_AppendHandshakeNumber(ss, len + 1, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, len + 1, 2);
         if (rv != SECSuccess)
             return -1;
         /* verify_Data from previous Finished message(s) */
-        rv = ssl3_AppendHandshakeVariable(ss,
-                                          ss->ssl3.hs.finishedMsgs.data, len, 1);
+        rv = ssl3_ExtAppendHandshakeVariable(ss,
+                                             ss->ssl3.hs.finishedMsgs.data, len, 1);
         if (rv != SECSuccess)
             return -1;
         if (!ss->sec.isServer) {
-            TLSExtensionData *xtnData = &ss->xtnData;
             xtnData->advertised[xtnData->numAdvertised++] =
                 ssl_renegotiation_info_xtn;
         }
     }
     return needed;
 }
 
 /* This function runs in both the client and server.  */
 SECStatus
-ssl3_HandleRenegotiationInfoXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data)
+ssl3_HandleRenegotiationInfoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data)
 {
     SECStatus rv = SECSuccess;
     PRUint32 len = 0;
 
     if (ss->firstHsDone) {
         len = ss->sec.isServer ? ss->ssl3.hs.finishedBytes
                                : ss->ssl3.hs.finishedBytes * 2;
     }
     if (data->len != 1 + len || data->data[0] != len) {
-        (void)ssl3_DecodeError(ss);
+        ssl3_ExtDecodeError(ss);
         return SECFailure;
     }
     if (len && NSS_SecureMemcmp(ss->ssl3.hs.finishedMsgs.data,
                                 data->data + 1, len)) {
-        (void)SSL3_SendAlert(ss, alert_fatal, handshake_failure);
+        ssl3_ExtSendAlert(ss, alert_fatal, handshake_failure);
         PORT_SetError(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
         return SECFailure;
     }
     /* remember that we got this extension and it was correct. */
-    ss->peerRequestedProtection = 1;
-    ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
+    CONST_CAST(sslSocket, ss)
+        ->peerRequestedProtection = 1;
+    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
     if (ss->sec.isServer) {
         /* prepare to send back the appropriate response */
-        rv = ssl3_RegisterServerHelloExtensionSender(ss, ex_type,
-                                                     ssl3_SendRenegotiationInfoXtn);
+        rv = ssl3_RegisterExtensionSender(ss, xtnData, ex_type,
+                                          ssl3_SendRenegotiationInfoXtn);
     }
     return rv;
 }
 
 PRInt32
-ssl3_ClientSendUseSRTPXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes)
+ssl3_ClientSendUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes)
 {
     PRUint32 ext_data_len;
     PRInt16 i;
     SECStatus rv;
 
     if (!ss)
         return 0;
 
     if (!IS_DTLS(ss) || !ss->ssl3.dtlsSRTPCipherCount)
         return 0; /* Not relevant */
 
     ext_data_len = 2 + 2 * ss->ssl3.dtlsSRTPCipherCount + 1;
 
     if (append && maxBytes >= 4 + ext_data_len) {
         /* Extension type */
-        rv = ssl3_AppendHandshakeNumber(ss, ssl_use_srtp_xtn, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_use_srtp_xtn, 2);
         if (rv != SECSuccess)
             return -1;
         /* Length of extension data */
-        rv = ssl3_AppendHandshakeNumber(ss, ext_data_len, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, ext_data_len, 2);
         if (rv != SECSuccess)
             return -1;
         /* Length of the SRTP cipher list */
-        rv = ssl3_AppendHandshakeNumber(ss,
-                                        2 * ss->ssl3.dtlsSRTPCipherCount,
-                                        2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss,
+                                           2 * ss->ssl3.dtlsSRTPCipherCount,
+                                           2);
         if (rv != SECSuccess)
             return -1;
         /* The SRTP ciphers */
         for (i = 0; i < ss->ssl3.dtlsSRTPCipherCount; i++) {
-            rv = ssl3_AppendHandshakeNumber(ss,
-                                            ss->ssl3.dtlsSRTPCiphers[i],
-                                            2);
+            rv = ssl3_ExtAppendHandshakeNumber(ss,
+                                               ss->ssl3.dtlsSRTPCiphers[i],
+                                               2);
             if (rv != SECSuccess)
                 return -1;
         }
         /* Empty MKI value */
-        ssl3_AppendHandshakeVariable(ss, NULL, 0, 1);
+        ssl3_ExtAppendHandshakeVariable(ss, NULL, 0, 1);
 
-        ss->xtnData.advertised[ss->xtnData.numAdvertised++] =
+        xtnData->advertised[xtnData->numAdvertised++] =
             ssl_use_srtp_xtn;
     }
 
     return 4 + ext_data_len;
 }
 
 PRInt32
-ssl3_ServerSendUseSRTPXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes)
+ssl3_ServerSendUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes)
 {
     SECStatus rv;
 
     /* Server side */
     if (!append || maxBytes < 9) {
         return 9;
     }
 
     /* Extension type */
-    rv = ssl3_AppendHandshakeNumber(ss, ssl_use_srtp_xtn, 2);
+    rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_use_srtp_xtn, 2);
     if (rv != SECSuccess)
         return -1;
     /* Length of extension data */
-    rv = ssl3_AppendHandshakeNumber(ss, 5, 2);
+    rv = ssl3_ExtAppendHandshakeNumber(ss, 5, 2);
     if (rv != SECSuccess)
         return -1;
     /* Length of the SRTP cipher list */
-    rv = ssl3_AppendHandshakeNumber(ss, 2, 2);
+    rv = ssl3_ExtAppendHandshakeNumber(ss, 2, 2);
     if (rv != SECSuccess)
         return -1;
     /* The selected cipher */
-    rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.dtlsSRTPCipherSuite, 2);
+    rv = ssl3_ExtAppendHandshakeNumber(ss, xtnData->dtlsSRTPCipherSuite, 2);
     if (rv != SECSuccess)
         return -1;
     /* Empty MKI value */
-    ssl3_AppendHandshakeVariable(ss, NULL, 0, 1);
+    ssl3_ExtAppendHandshakeVariable(ss, NULL, 0, 1);
 
     return 9;
 }
 
 SECStatus
-ssl3_ClientHandleUseSRTPXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data)
+ssl3_ClientHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data)
 {
     SECStatus rv;
     SECItem ciphers = { siBuffer, NULL, 0 };
     PRUint16 i;
     PRUint16 cipher = 0;
     PRBool found = PR_FALSE;
     SECItem litem;
 
     if (!data->data || !data->len) {
-        (void)ssl3_DecodeError(ss);
+        ssl3_ExtDecodeError(ss);
         return SECFailure;
     }
 
     /* Get the cipher list */
-    rv = ssl3_ConsumeHandshakeVariable(ss, &ciphers, 2,
-                                       &data->data, &data->len);
+    rv = ssl3_ExtConsumeHandshakeVariable(ss, &ciphers, 2,
+                                          &data->data, &data->len);
     if (rv != SECSuccess) {
         return SECFailure; /* fatal alert already sent */
     }
     /* Now check that the server has picked just 1 (i.e., len = 2) */
     if (ciphers.len != 2) {
-        (void)ssl3_DecodeError(ss);
+        ssl3_ExtDecodeError(ss);
         return SECFailure;
     }
 
     /* Get the selected cipher */
     cipher = (ciphers.data[0] << 8) | ciphers.data[1];
 
     /* Now check that this is one of the ciphers we offered */
     for (i = 0; i < ss->ssl3.dtlsSRTPCipherCount; i++) {
         if (cipher == ss->ssl3.dtlsSRTPCiphers[i]) {
             found = PR_TRUE;
             break;
         }
     }
 
     if (!found) {
-        (void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
+        ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter);
         PORT_SetError(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
         return SECFailure;
     }
 
     /* Get the srtp_mki value */
-    rv = ssl3_ConsumeHandshakeVariable(ss, &litem, 1,
-                                       &data->data, &data->len);
+    rv = ssl3_ExtConsumeHandshakeVariable(ss, &litem, 1,
+                                          &data->data, &data->len);
     if (rv != SECSuccess) {
         return SECFailure; /* alert already sent */
     }
 
     /* We didn't offer an MKI, so this must be 0 length */
     if (litem.len != 0) {
-        (void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
+        ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter);
         PORT_SetError(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
         return SECFailure;
     }
 
     /* extra trailing bytes */
     if (data->len != 0) {
-        (void)ssl3_DecodeError(ss);
+        ssl3_ExtDecodeError(ss);
         return SECFailure;
     }
 
     /* OK, this looks fine. */
-    ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ssl_use_srtp_xtn;
-    ss->ssl3.dtlsSRTPCipherSuite = cipher;
+    xtnData->negotiated[xtnData->numNegotiated++] = ssl_use_srtp_xtn;
+    xtnData->dtlsSRTPCipherSuite = cipher;
     return SECSuccess;
 }
 
 SECStatus
-ssl3_ServerHandleUseSRTPXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data)
+ssl3_ServerHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data)
 {
     SECStatus rv;
     SECItem ciphers = { siBuffer, NULL, 0 };
     PRUint16 i;
     unsigned int j;
     PRUint16 cipher = 0;
     PRBool found = PR_FALSE;
     SECItem litem;
 
     if (!IS_DTLS(ss) || !ss->ssl3.dtlsSRTPCipherCount) {
         /* Ignore the extension if we aren't doing DTLS or no DTLS-SRTP
          * preferences have been set. */
         return SECSuccess;
     }
 
     if (!data->data || data->len < 5) {
-        (void)ssl3_DecodeError(ss);
+        ssl3_ExtDecodeError(ss);
         return SECFailure;
     }
 
     /* Get the cipher list */
-    rv = ssl3_ConsumeHandshakeVariable(ss, &ciphers, 2,
-                                       &data->data, &data->len);
+    rv = ssl3_ExtConsumeHandshakeVariable(ss, &ciphers, 2,
+                                          &data->data, &data->len);
     if (rv != SECSuccess) {
         return SECFailure; /* alert already sent */
     }
     /* Check that the list is even length */
     if (ciphers.len % 2) {
-        (void)ssl3_DecodeError(ss);
+        ssl3_ExtDecodeError(ss);
         return SECFailure;
     }
 
     /* Walk through the offered list and pick the most preferred of our
      * ciphers, if any */
     for (i = 0; !found && i < ss->ssl3.dtlsSRTPCipherCount; i++) {
         for (j = 0; j + 1 < ciphers.len; j += 2) {
             cipher = (ciphers.data[j] << 8) | ciphers.data[j + 1];
             if (cipher == ss->ssl3.dtlsSRTPCiphers[i]) {
                 found = PR_TRUE;
                 break;
             }
         }
     }
 
     /* Get the srtp_mki value */
-    rv = ssl3_ConsumeHandshakeVariable(ss, &litem, 1, &data->data, &data->len);
+    rv = ssl3_ExtConsumeHandshakeVariable(ss, &litem, 1, &data->data, &data->len);
     if (rv != SECSuccess) {
         return SECFailure;
     }
 
     if (data->len != 0) {
-        (void)ssl3_DecodeError(ss); /* trailing bytes */
+        ssl3_ExtDecodeError(ss); /* trailing bytes */
         return SECFailure;
     }
 
     /* Now figure out what to do */
     if (!found) {
         /* No matching ciphers, pretend we don't support use_srtp */
         return SECSuccess;
     }
 
     /* OK, we have a valid cipher and we've selected it */
-    ss->ssl3.dtlsSRTPCipherSuite = cipher;
-    ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ssl_use_srtp_xtn;
+    xtnData->dtlsSRTPCipherSuite = cipher;
+    xtnData->negotiated[xtnData->numNegotiated++] = ssl_use_srtp_xtn;
 
-    return ssl3_RegisterServerHelloExtensionSender(ss, ssl_use_srtp_xtn,
-                                                   ssl3_ServerSendUseSRTPXtn);
+    return ssl3_RegisterExtensionSender(ss, xtnData,
+                                        ssl_use_srtp_xtn,
+                                        ssl3_ServerSendUseSRTPXtn);
 }
 
 /* ssl3_ServerHandleSigAlgsXtn handles the signature_algorithms extension
  * from a client.
  * See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */
 SECStatus
-ssl3_ServerHandleSigAlgsXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data)
+ssl3_ServerHandleSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data)
 {
     SECStatus rv;
 
     /* Ignore this extension if we aren't doing TLS 1.2 or greater. */
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_2) {
         return SECSuccess;
     }
 
-    if (ss->ssl3.hs.clientSigSchemes) {
-        PORT_Free(ss->ssl3.hs.clientSigSchemes);
-        ss->ssl3.hs.clientSigSchemes = NULL;
+    if (xtnData->clientSigSchemes) {
+        PORT_Free(xtnData->clientSigSchemes);
+        xtnData->clientSigSchemes = NULL;
     }
     rv = ssl_ParseSignatureSchemes(ss, NULL,
-                                   &ss->ssl3.hs.clientSigSchemes,
-                                   &ss->ssl3.hs.numClientSigScheme,
+                                   &xtnData->clientSigSchemes,
+                                   &xtnData->numClientSigScheme,
                                    &data->data, &data->len);
     if (rv != SECSuccess) {
         PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
         return SECFailure;
     }
     /* Check for trailing data. */
     if (data->len != 0) {
-        (void)SSL3_SendAlert(ss, alert_fatal, decode_error);
+        ssl3_ExtSendAlert(ss, alert_fatal, decode_error);
         PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
         return SECFailure;
     }
 
     /* Keep track of negotiated extensions. */
-    ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
+    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
     return SECSuccess;
 }
 
 /* ssl3_ClientSendSigAlgsXtn sends the signature_algorithm extension for TLS
  * 1.2 ClientHellos. */
 PRInt32
-ssl3_ClientSendSigAlgsXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes)
+ssl3_ClientSendSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes)
 {
     PRInt32 extension_length;
     PRUint8 buf[MAX_SIGNATURE_SCHEMES * 2];
     PRUint32 len;
     SECStatus rv;
 
     if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_2) {
         return 0;
@@ -2184,31 +2188,31 @@ ssl3_ClientSendSigAlgsXtn(sslSocket *ss,
 
     if (maxBytes < extension_length) {
         PORT_Assert(0);
         return 0;
     }
 
     if (append) {
         SECStatus rv;
-        rv = ssl3_AppendHandshakeNumber(ss, ssl_signature_algorithms_xtn, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_signature_algorithms_xtn, 2);
         if (rv != SECSuccess) {
             return -1;
         }
-        rv = ssl3_AppendHandshakeNumber(ss, len + 2, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, len + 2, 2);
         if (rv != SECSuccess) {
             return -1;
         }
 
-        rv = ssl3_AppendHandshakeVariable(ss, buf, len, 2);
+        rv = ssl3_ExtAppendHandshakeVariable(ss, buf, len, 2);
         if (rv != SECSuccess) {
             return -1;
         }
 
-        ss->xtnData.advertised[ss->xtnData.numAdvertised++] =
+        xtnData->advertised[xtnData->numAdvertised++] =
             ssl_signature_algorithms_xtn;
     }
 
     return extension_length;
 }
 
 /* Takes the size of the ClientHello, less the record header, and determines how
  * much padding is required. */
@@ -2252,26 +2256,26 @@ ssl3_AppendPaddingExtension(sslSocket *s
 
     if (extensionLen > maxBytes ||
         !paddingLen ||
         paddingLen > sizeof(padding)) {
         PORT_Assert(0);
         return -1;
     }
 
-    if (SECSuccess != ssl3_AppendHandshakeNumber(ss, ssl_padding_xtn, 2))
+    if (SECSuccess != ssl3_ExtAppendHandshakeNumber(ss, ssl_padding_xtn, 2))
         return -1;
-    if (SECSuccess != ssl3_AppendHandshakeVariable(ss, padding, paddingLen, 2))
+    if (SECSuccess != ssl3_ExtAppendHandshakeVariable(ss, padding, paddingLen, 2))
         return -1;
 
     return extensionLen;
 }
 
 PRInt32
-ssl3_SendExtendedMasterSecretXtn(sslSocket *ss, PRBool append,
+ssl3_SendExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
                                  PRUint32 maxBytes)
 {
     PRInt32 extension_length;
 
     if (!ss->opt.enableExtendedMS) {
         return 0;
     }
 
@@ -2281,34 +2285,34 @@ ssl3_SendExtendedMasterSecretXtn(sslSock
     extension_length = 4; /* Type + length (0) */
     if (maxBytes < extension_length) {
         PORT_Assert(0);
         return 0;
     }
 
     if (append) {
         SECStatus rv;
-        rv = ssl3_AppendHandshakeNumber(ss, ssl_extended_master_secret_xtn, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_extended_master_secret_xtn, 2);
         if (rv != SECSuccess)
             goto loser;
-        rv = ssl3_AppendHandshakeNumber(ss, 0, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2);
         if (rv != SECSuccess)
             goto loser;
-        ss->xtnData.advertised[ss->xtnData.numAdvertised++] =
+        xtnData->advertised[xtnData->numAdvertised++] =
             ssl_extended_master_secret_xtn;
     }
 
     return extension_length;
 
 loser:
     return -1;
 }
 
 SECStatus
-ssl3_HandleExtendedMasterSecretXtn(sslSocket *ss, PRUint16 ex_type,
+ssl3_HandleExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
                                    SECItem *data)
 {
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_0) {
         return SECSuccess;
     }
 
     if (!ss->opt.enableExtendedMS) {
         return SECSuccess;
@@ -2319,89 +2323,89 @@ ssl3_HandleExtendedMasterSecretXtn(sslSo
                      SSL_GETPID(), ss->fd));
         return SECFailure;
     }
 
     SSL_DBG(("%d: SSL[%d]: Negotiated extended master secret extension.",
              SSL_GETPID(), ss->fd));
 
     /* Keep track of negotiated extensions. */
-    ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
+    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
 
     if (ss->sec.isServer) {
-        return ssl3_RegisterServerHelloExtensionSender(
-            ss, ex_type, ssl3_SendExtendedMasterSecretXtn);
+        return ssl3_RegisterExtensionSender(
+            ss, xtnData, ex_type, ssl3_SendExtendedMasterSecretXtn);
     }
     return SECSuccess;
 }
 
 /* ssl3_ClientSendSignedCertTimestampXtn sends the signed_certificate_timestamp
  * extension for TLS ClientHellos. */
 PRInt32
-ssl3_ClientSendSignedCertTimestampXtn(sslSocket *ss, PRBool append,
+ssl3_ClientSendSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
                                       PRUint32 maxBytes)
 {
     PRInt32 extension_length = 2 /* extension_type */ +
                                2 /* length(extension_data) */;
 
     /* Only send the extension if processing is enabled. */
     if (!ss->opt.enableSignedCertTimestamps)
         return 0;
 
     if (append && maxBytes >= extension_length) {
         SECStatus rv;
         /* extension_type */
-        rv = ssl3_AppendHandshakeNumber(ss,
-                                        ssl_signed_cert_timestamp_xtn,
-                                        2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss,
+                                           ssl_signed_cert_timestamp_xtn,
+                                           2);
         if (rv != SECSuccess)
             goto loser;
         /* zero length */
-        rv = ssl3_AppendHandshakeNumber(ss, 0, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2);
         if (rv != SECSuccess)
             goto loser;
-        ss->xtnData.advertised[ss->xtnData.numAdvertised++] =
+        xtnData->advertised[xtnData->numAdvertised++] =
             ssl_signed_cert_timestamp_xtn;
     } else if (maxBytes < extension_length) {
         PORT_Assert(0);
         return 0;
     }
 
     return extension_length;
 loser:
     return -1;
 }
 
 SECStatus
-ssl3_ClientHandleSignedCertTimestampXtn(sslSocket *ss, PRUint16 ex_type,
+ssl3_ClientHandleSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
                                         SECItem *data)
 {
     /* We do not yet know whether we'll be resuming a session or creating
      * a new one, so we keep a pointer to the data in the TLSExtensionData
      * structure. This pointer is only valid in the scope of
      * ssl3_HandleServerHello, and, if not resuming a session, the data is
      * copied once a new session structure has been set up.
      * All parsing is currently left to the application and we accept
      * everything, including empty data.
      */
-    SECItem *scts = &ss->xtnData.signedCertTimestamps;
+    SECItem *scts = &xtnData->signedCertTimestamps;
     PORT_Assert(!scts->data && !scts->len);
 
     if (!data->len) {
         /* Empty extension data: RFC 6962 mandates non-empty contents. */
         return SECFailure;
     }
     *scts = *data;
     /* Keep track of negotiated extensions. */
-    ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
+    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
     return SECSuccess;
 }
 
 PRInt32
-ssl3_ServerSendSignedCertTimestampXtn(sslSocket *ss,
+ssl3_ServerSendSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                       PRBool append,
                                       PRUint32 maxBytes)
 {
     PRInt32 extension_length;
     const SECItem *scts = &ss->sec.serverCert->signedCertTimestamps;
 
     if (!scts->len) {
         /* No timestamps to send */
@@ -2414,34 +2418,163 @@ ssl3_ServerSendSignedCertTimestampXtn(ss
 
     if (maxBytes < extension_length) {
         PORT_Assert(0);
         return 0;
     }
     if (append) {
         SECStatus rv;
         /* extension_type */
-        rv = ssl3_AppendHandshakeNumber(ss,
-                                        ssl_signed_cert_timestamp_xtn,
-                                        2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss,
+                                           ssl_signed_cert_timestamp_xtn,
+                                           2);
         if (rv != SECSuccess)
             goto loser;
         /* extension_data */
-        rv = ssl3_AppendHandshakeVariable(ss, scts->data, scts->len, 2);
+        rv = ssl3_ExtAppendHandshakeVariable(ss, scts->data, scts->len, 2);
         if (rv != SECSuccess)
             goto loser;
     }
 
     return extension_length;
 
 loser:
     return -1;
 }
 
 SECStatus
-ssl3_ServerHandleSignedCertTimestampXtn(sslSocket *ss, PRUint16 ex_type,
+ssl3_ServerHandleSignedCertTimestampXtn(const sslSocket *ss,
+                                        TLSExtensionData *xtnData,
+                                        PRUint16 ex_type,
                                         SECItem *data)
 {
-    ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
+    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
     PORT_Assert(ss->sec.isServer);
-    return ssl3_RegisterServerHelloExtensionSender(ss, ex_type,
-                                                   ssl3_ServerSendSignedCertTimestampXtn);
+    return ssl3_RegisterExtensionSender(
+        ss, xtnData, ex_type, ssl3_ServerSendSignedCertTimestampXtn);
+}
+
+/* Just make sure that the remote client supports uncompressed points,
+ * Since that is all we support.  Disable ECC cipher suites if it doesn't.
+ */
+SECStatus
+ssl3_HandleSupportedPointFormatsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                                    PRUint16 ex_type,
+                                    SECItem *data)
+{
+    int i;
+
+    if (data->len < 2 || data->len > 255 || !data->data ||
+        data->len != (unsigned int)data->data[0] + 1) {
+        ssl3_ExtDecodeError(ss);
+        return SECFailure;
+    }
+    for (i = data->len; --i > 0;) {
+        if (data->data[i] == 0) {
+            /* indicate that we should send a reply */
+            SECStatus rv;
+            rv = ssl3_RegisterExtensionSender(ss, xtnData, ex_type,
+                                              &ssl3_SendSupportedPointFormatsXtn);
+            return rv;
+        }
+    }
+
+    /* Poor client doesn't support uncompressed points. */
+    PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE);
+    return SECFailure;
 }
+
+static SECStatus
+ssl_UpdateSupportedGroups(sslSocket *ss, SECItem *data)
+{
+    PRInt32 list_len;
+    unsigned int i;
+    const sslNamedGroupDef *enabled[SSL_NAMED_GROUP_COUNT] = { 0 };
+    PORT_Assert(SSL_NAMED_GROUP_COUNT == PR_ARRAY_SIZE(enabled));
+
+    if (!data->data || data->len < 4) {
+        (void)ssl3_DecodeError(ss);
+        return SECFailure;
+    }
+
+    /* get the length of elliptic_curve_list */
+    list_len = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
+    if (list_len < 0 || data->len != list_len || (data->len % 2) != 0) {
+        (void)ssl3_DecodeError(ss);
+        return SECFailure;
+    }
+
+    /* disable all groups and remember the enabled groups */
+    for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) {
+        enabled[i] = ss->namedGroupPreferences[i];
+        ss->namedGroupPreferences[i] = NULL;
+    }
+
+    /* Read groups from data and enable if in |enabled| */
+    while (data->len) {
+        const sslNamedGroupDef *group;
+        PRInt32 curve_name =
+            ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
+        if (curve_name < 0) {
+            return SECFailure; /* fatal alert already sent */
+        }
+        group = ssl_LookupNamedGroup(curve_name);
+        if (group) {
+            for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) {
+                if (enabled[i] && group == enabled[i]) {
+                    ss->namedGroupPreferences[i] = enabled[i];
+                    break;
+                }
+            }
+        }
+
+        /* "Codepoints in the NamedCurve registry with a high byte of 0x01 (that
+         * is, between 256 and 511 inclusive) are set aside for FFDHE groups,"
+         * -- https://tools.ietf.org/html/draft-ietf-tls-negotiated-ff-dhe-10
+         */
+        if ((curve_name & 0xff00) == 0x0100) {
+            ss->xtnData.peerSupportsFfdheGroups = PR_TRUE;
+        }
+    }
+
+    /* Note: if ss->opt.requireDHENamedGroups is set, we disable DHE cipher
+     * suites, but we do that in ssl3_config_match(). */
+    if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3 &&
+        !ss->opt.requireDHENamedGroups && !ss->xtnData.peerSupportsFfdheGroups) {
+        /* If we don't require that DHE use named groups, and no FFDHE was
+         * included, we pretend that they support all the FFDHE groups we do. */
+        for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) {
+            if (enabled[i] && enabled[i]->keaType == ssl_kea_dh) {
+                ss->namedGroupPreferences[i] = enabled[i];
+            }
+        }
+    }
+
+    return SECSuccess;
+}
+
+/* Ensure that the curve in our server cert is one of the ones supported
+ * by the remote client, and disable all ECC cipher suites if not.
+ */
+SECStatus
+ssl_HandleSupportedGroupsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                             PRUint16 ex_type, SECItem *data)
+{
+    SECStatus rv;
+
+    rv = ssl_UpdateSupportedGroups(CONST_CAST(sslSocket, ss), data);
+    if (rv != SECSuccess)
+        return SECFailure;
+
+    /* TLS 1.3 permits the server to send this extension so make it so. */
+    if (ss->sec.isServer && ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
+        rv = ssl3_RegisterExtensionSender(ss, xtnData, ex_type,
+                                          &ssl_SendSupportedGroupsXtn);
+        if (rv != SECSuccess) {
+            return SECFailure; /* error already set. */
+        }
+    }
+
+    /* Remember that we negotiated this extension. */
+    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
+
+    return SECSuccess;
+}
--- a/security/nss/lib/ssl/ssl3exthandle.h
+++ b/security/nss/lib/ssl/ssl3exthandle.h
@@ -4,68 +4,92 @@
  *
  * 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 __ssl3exthandle_h_
 #define __ssl3exthandle_h_
 
-PRInt32 ssl3_SendRenegotiationInfoXtn(sslSocket *ss,
+PRInt32 ssl3_SendRenegotiationInfoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                       PRBool append, PRUint32 maxBytes);
-SECStatus ssl3_HandleRenegotiationInfoXtn(sslSocket *ss,
+SECStatus ssl3_HandleRenegotiationInfoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                           PRUint16 ex_type, SECItem *data);
-SECStatus ssl3_ClientHandleNextProtoNegoXtn(sslSocket *ss,
+SECStatus ssl3_ClientHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                             PRUint16 ex_type, SECItem *data);
-SECStatus ssl3_ClientHandleAppProtoXtn(sslSocket *ss,
+SECStatus ssl3_ClientHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                        PRUint16 ex_type, SECItem *data);
-SECStatus ssl3_ServerHandleNextProtoNegoXtn(sslSocket *ss,
+SECStatus ssl3_ServerHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                             PRUint16 ex_type, SECItem *data);
-SECStatus ssl3_ServerHandleAppProtoXtn(sslSocket *ss, PRUint16 ex_type,
+SECStatus ssl3_ServerHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
                                        SECItem *data);
-PRInt32 ssl3_ClientSendNextProtoNegoXtn(sslSocket *ss, PRBool append,
+PRInt32 ssl3_ClientSendNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
                                         PRUint32 maxBytes);
-PRInt32 ssl3_ClientSendAppProtoXtn(sslSocket *ss, PRBool append,
+PRInt32 ssl3_ClientSendAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
                                    PRUint32 maxBytes);
-PRInt32 ssl3_ServerSendAppProtoXtn(sslSocket *ss, PRBool append,
+PRInt32 ssl3_ServerSendAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
                                    PRUint32 maxBytes);
-PRInt32 ssl3_ClientSendUseSRTPXtn(sslSocket *ss, PRBool append,
+PRInt32 ssl3_ClientSendUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
                                   PRUint32 maxBytes);
-PRInt32 ssl3_ServerSendUseSRTPXtn(sslSocket *ss, PRBool append,
+PRInt32 ssl3_ServerSendUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
                                   PRUint32 maxBytes);
-SECStatus ssl3_ClientHandleUseSRTPXtn(sslSocket *ss, PRUint16 ex_type,
+SECStatus ssl3_ClientHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
                                       SECItem *data);
-SECStatus ssl3_ServerHandleUseSRTPXtn(sslSocket *ss, PRUint16 ex_type,
+SECStatus ssl3_ServerHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
                                       SECItem *data);
-PRInt32 ssl3_ServerSendStatusRequestXtn(sslSocket *ss,
+PRInt32 ssl3_ServerSendStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                         PRBool append, PRUint32 maxBytes);
-SECStatus ssl3_ServerHandleStatusRequestXtn(sslSocket *ss,
+SECStatus ssl3_ServerHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                             PRUint16 ex_type, SECItem *data);
-SECStatus ssl3_ClientHandleStatusRequestXtn(sslSocket *ss,
+SECStatus ssl3_ClientHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                             PRUint16 ex_type,
                                             SECItem *data);
-PRInt32 ssl3_ClientSendStatusRequestXtn(sslSocket *ss, PRBool append,
+PRInt32 ssl3_ClientSendStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
                                         PRUint32 maxBytes);
-PRInt32 ssl3_ClientSendSigAlgsXtn(sslSocket *ss, PRBool append,
+PRInt32 ssl3_ClientSendSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
                                   PRUint32 maxBytes);
-SECStatus ssl3_ServerHandleSigAlgsXtn(sslSocket *ss, PRUint16 ex_type,
+SECStatus ssl3_ServerHandleSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
                                       SECItem *data);
 
-PRInt32 ssl3_ClientSendSignedCertTimestampXtn(sslSocket *ss,
+PRInt32 ssl3_ClientSendSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                               PRBool append,
                                               PRUint32 maxBytes);
-SECStatus ssl3_ClientHandleSignedCertTimestampXtn(sslSocket *ss,
+SECStatus ssl3_ClientHandleSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                                   PRUint16 ex_type,
                                                   SECItem *data);
-PRInt32 ssl3_ServerSendSignedCertTimestampXtn(sslSocket *ss,
+PRInt32 ssl3_ServerSendSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                               PRBool append,
                                               PRUint32 maxBytes);
-SECStatus ssl3_ServerHandleSignedCertTimestampXtn(sslSocket *ss,
+SECStatus ssl3_ServerHandleSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                                   PRUint16 ex_type,
                                                   SECItem *data);
-PRInt32 ssl3_SendExtendedMasterSecretXtn(sslSocket *ss, PRBool append,
+PRInt32 ssl3_SendExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
                                          PRUint32 maxBytes);
-SECStatus ssl3_HandleExtendedMasterSecretXtn(sslSocket *ss,
+SECStatus ssl3_HandleExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                              PRUint16 ex_type,
                                              SECItem *data);
 SECStatus ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data);
+PRInt32 ssl3_SendServerNameXtn(const sslSocket *ss,
+                               TLSExtensionData *xtnData,
+                               PRBool append,
+                               PRUint32 maxBytes);
+SECStatus ssl3_HandleServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                                   PRUint16 ex_type, SECItem *data);
+SECStatus ssl_HandleSupportedGroupsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                                       PRUint16 ex_type, SECItem *data);
+SECStatus ssl3_HandleSupportedPointFormatsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                                              PRUint16 ex_type, SECItem *data);
+SECStatus ssl3_ClientHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                                            PRUint16 ex_type, SECItem *data);
+SECStatus ssl3_ServerHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                                            PRUint16 ex_type, SECItem *data);
+PRInt32 ssl3_SendSessionTicketXtn(const sslSocket *ss,
+                                  TLSExtensionData *xtnData,
+                                  PRBool append,
+                                  PRUint32 maxBytes);
 
+PRInt32 ssl_SendSupportedGroupsXtn(const sslSocket *ss,
+                                   TLSExtensionData *xtnData,
+                                   PRBool append, PRUint32 maxBytes);
+PRInt32 ssl3_SendSupportedPointFormatsXtn(const sslSocket *ss,
+                                          TLSExtensionData *xtnData,
+                                          PRBool append, PRUint32 maxBytes);
 #endif
--- a/security/nss/lib/ssl/sslimpl.h
+++ b/security/nss/lib/ssl/sslimpl.h
@@ -28,16 +28,20 @@
 #endif
 #include "nssrwlk.h"
 #include "prthread.h"
 #include "prclist.h"
 #include "private/pprthred.h"
 
 #include "sslt.h" /* for some formerly private types, now public */
 
+typedef struct sslSocketStr sslSocket;
+
+#include "ssl3ext.h"
+
 /* to make some of these old enums public without namespace pollution,
 ** it was necessary to prepend ssl_ to the names.
 ** These #defines preserve compatibility with the old code here in libssl.
 */
 typedef SSLMACAlgorithm SSL3MACAlgorithm;
 
 #define calg_null ssl_calg_null
 #define calg_rc4 ssl_calg_rc4
@@ -97,16 +101,18 @@ extern int Debug;
     ssl_Trace b
 #else
 #define SSL_DBG(b)
 #endif
 
 #define LSB(x) ((unsigned char)((x)&0xff))
 #define MSB(x) ((unsigned char)(((unsigned)(x)) >> 8))
 
+#define CONST_CAST(T, X) ((T *)(X))
+
 /************************************************************************/
 
 typedef enum { SSLAppOpRead = 0,
                SSLAppOpWrite,
                SSLAppOpRDWR,
                SSLAppOpPost,
                SSLAppOpHeader
 } SSLAppOperation;
@@ -167,17 +173,16 @@ typedef struct {
     PRBool assumeSupported;
 } sslNamedGroupDef;
 
 typedef struct sslBufferStr sslBuffer;
 typedef struct sslConnectInfoStr sslConnectInfo;
 typedef struct sslGatherStr sslGather;
 typedef struct sslSecurityInfoStr sslSecurityInfo;
 typedef struct sslSessionIDStr sslSessionID;
-typedef struct sslSocketStr sslSocket;
 typedef struct sslSocketOpsStr sslSocketOps;
 
 typedef struct ssl3StateStr ssl3State;
 typedef struct ssl3CertNodeStr ssl3CertNode;
 typedef struct ssl3BulkCipherDefStr ssl3BulkCipherDef;
 typedef struct ssl3MACDefStr ssl3MACDef;
 typedef struct sslKeyPairStr sslKeyPair;
 typedef struct ssl3DHParamsStr ssl3DHParams;
@@ -191,56 +196,16 @@ typedef SECStatus (*sslHandshakeFunc)(ss
 
 typedef void (*sslSessionIDCacheFunc)(sslSessionID *sid);
 typedef void (*sslSessionIDUncacheFunc)(sslSessionID *sid);
 typedef sslSessionID *(*sslSessionIDLookupFunc)(const PRIPv6Addr *addr,
                                                 unsigned char *sid,
                                                 unsigned int sidLen,
                                                 CERTCertDBHandle *dbHandle);
 
-/* registerable callback function that either appends extension to buffer
- * or returns length of data that it would have appended.
- */
-typedef PRInt32 (*ssl3HelloExtensionSenderFunc)(sslSocket *ss, PRBool append,
-                                                PRUint32 maxBytes);
-
-/* registerable callback function that handles a received extension,
- * of the given type.
- */
-typedef SECStatus (*ssl3ExtensionHandlerFunc)(sslSocket *ss,
-                                              PRUint16 ex_type,
-                                              SECItem *data);
-
-/* row in a table of hello extension senders */
-typedef struct {
-    PRInt32 ex_type;
-    ssl3HelloExtensionSenderFunc ex_sender;
-} ssl3HelloExtensionSender;
-
-/* row in a table of hello extension handlers */
-typedef struct {
-    PRInt32 ex_type;
-    ssl3ExtensionHandlerFunc ex_handler;
-} ssl3ExtensionHandler;
-
-extern SECStatus
-ssl3_RegisterServerHelloExtensionSender(sslSocket *ss, PRUint16 ex_type,
-                                        ssl3HelloExtensionSenderFunc cb);
-
-extern PRInt32
-ssl3_CallHelloExtensionSenders(sslSocket *ss, PRBool append, PRUint32 maxBytes,
-                               const ssl3HelloExtensionSender *sender);
-
-extern unsigned int
-ssl3_CalculatePaddingExtensionLength(unsigned int clientHelloLength);
-
-extern PRInt32
-ssl3_AppendPaddingExtension(sslSocket *ss, unsigned int extensionLen,
-                            PRUint32 maxBytes);
-
 /* Socket ops */
 struct sslSocketOpsStr {
     int (*connect)(sslSocket *, const PRNetAddr *);
     PRFileDesc *(*accept)(sslSocket *, PRNetAddr *);
     int (*bind)(sslSocket *, const PRNetAddr *);
     int (*listen)(sslSocket *, int);
     int (*shutdown)(sslSocket *, int);
     int (*close)(sslSocket *);
@@ -749,63 +714,18 @@ typedef enum {
     client_hello_retry,        /* If we receive HelloRetryRequest. */
     client_hello_retransmit,   /* In DTLS, if we receive HelloVerifyRequest. */
     client_hello_renegotiation /* A renegotiation attempt. */
 } sslClientHelloType;
 
 /*
  * TLS extension related constants and data structures.
  */
-typedef struct TLSExtensionDataStr TLSExtensionData;
 typedef struct SessionTicketDataStr SessionTicketData;
 
-struct TLSExtensionDataStr {
-    /* registered callbacks that send server hello extensions */
-    ssl3HelloExtensionSender serverHelloSenders[SSL_MAX_EXTENSIONS];
-    ssl3HelloExtensionSender encryptedExtensionsSenders[SSL_MAX_EXTENSIONS];
-
-    /* Keep track of the extensions that are negotiated. */
-    PRUint16 numAdvertised;
-    PRUint16 numNegotiated;
-    PRUint16 advertised[SSL_MAX_EXTENSIONS];
-    PRUint16 negotiated[SSL_MAX_EXTENSIONS];
-
-    /* SessionTicket Extension related data. */
-    PRBool ticketTimestampVerified;
-    PRBool emptySessionTicket;
-    PRBool sentSessionTicketInClientHello;
-    SECItem psk_ke_modes;
-    SECItem psk_auth_modes;
-    PRUint32 ticket_age_add;
-    PRBool ticket_age_add_found;
-
-    /* SNI Extension related data
-     * Names data is not coppied from the input buffer. It can not be
-     * used outside the scope where input buffer is defined and that
-     * is beyond ssl3_HandleClientHello function. */
-    SECItem *sniNameArr;
-    PRUint32 sniNameArrSize;
-
-    /* Signed Certificate Timestamps extracted from the TLS extension.
-     * (client only).
-     * This container holds a temporary pointer to the extension data,
-     * until a session structure (the sec.ci.sid of an sslSocket) is setup
-     * that can hold a permanent copy of the data
-     * (in sec.ci.sid.u.ssl3.signedCertTimestamps).
-     * The data pointed to by this structure is neither explicitly allocated
-     * nor copied: the pointer points to the handshake message buffer and is
-     * only valid in the scope of ssl3_HandleServerHello.
-     */
-    SECItem signedCertTimestamps;
-};
-
-typedef enum {
-    sni_nametype_hostname
-} SNINameType;
-
 typedef SECStatus (*sslRestartTarget)(sslSocket *);
 
 /*
 ** A DTLS queued message (potentially to be retransmitted)
 */
 typedef struct DTLSQueuedMessageStr {
     PRCList link;           /* The linked list link */
     ssl3CipherSpec *cwSpec; /* The cipher spec to use, null for none */
@@ -825,22 +745,16 @@ typedef struct TLS13EarlyDataStr {
     SECItem data; /* The data */
 } TLS13EarlyData;
 
 typedef struct {
     PRUint8 hash[HASH_LENGTH_MAX * 2];
     unsigned int len;
 } TLS13CombinedHash;
 
-typedef struct TLSExtensionStr {
-    PRCList link;  /* The linked list link */
-    PRUint16 type; /* Extension type */
-    SECItem data;  /* Pointers into the handshake data. */
-} TLSExtension;
-
 typedef enum {
     handshake_hash_unknown = 0,
     handshake_hash_combo = 1,  /* The MD5/SHA-1 combination */
     handshake_hash_single = 2, /* A single hash */
     handshake_hash_record
 } SSL3HandshakeHashType;
 
 /* This holds state for TLS 1.3 CertificateRequest handling. */
@@ -908,24 +822,16 @@ typedef struct SSL3HandshakeStateStr {
     sslRestartTarget restartTarget;
     /* Shared state between ssl3_HandleFinished and ssl3_FinishHandshake */
     PRBool cacheSID;
 
     PRBool canFalseStart; /* Can/did we False Start */
     /* Which preliminaryinfo values have been set. */
     PRUint32 preliminaryInfo;
 
-    PRBool peerSupportsFfdheGroups; /* if the peer supports named ffdhe groups */
-
-    /* clientSigAndHash contains the contents of the signature_algorithms
-     * extension (if any) from the client. This is only valid for TLS 1.2
-     * or later. */
-    SSLSignatureScheme *clientSigSchemes;
-    unsigned int numClientSigScheme;
-
     /* Parsed extensions */
     PRCList remoteExtensions; /* Parsed incoming extensions */
 
     /* This group of values is used for DTLS */
     PRUint16 sendMessageSeq;       /* The sending message sequence
                                     * number */
     PRCList lastMessageFlight;     /* The last message flight we
                                     * sent */
@@ -945,17 +851,16 @@ typedef struct SSL3HandshakeStateStr {
     PRUint32 rtRetries;            /* The retry counter */
     SECItem srvVirtName;           /* for server: name that was negotiated
                           * with a client. For client - is
                           * always set to NULL.*/
 
     /* This group of values is used for TLS 1.3 and above */
     PK11Context *clientHelloHash;         /* The client hello hash state, used
                                         * by the server for 0-RTT. */
-    PRCList remoteKeyShares;              /* The other side's public keys */
     PK11SymKey *currentSecret;            /* The secret down the "left hand side"
                                         * of the TLS 1.3 key schedule. */
     PK11SymKey *resumptionPsk;            /* The resumption PSK. */
     SECItem resumptionContext;            /* The resumption context. */
     PK11SymKey *dheSecret;                /* The (EC)DHE shared secret. */
     PK11SymKey *clientEarlyTrafficSecret; /* The secret we use for 0-RTT. */
     PK11SymKey *clientHsTrafficSecret;    /* The source keys for handshake */
     PK11SymKey *serverHsTrafficSecret;    /* traffic keys. */
@@ -1009,28 +914,21 @@ struct ssl3StateStr {
     void *peerCertChain;
     /* chain while we are trying to validate it.   */
     CERTDistNames *ca_list;
     /* used by server.  trusted CAs for this socket. */
     PRBool initialized;
     SSL3HandshakeState hs;
     ssl3CipherSpec specs[2]; /* one is current, one is pending. */
 
-    /* In a client: if the server supports Next Protocol Negotiation, then
-     * this is the protocol that was negotiated.
-     */
-    SECItem nextProto;
-    SSLNextProtoState nextProtoState;
-
     PRUint16 mtu; /* Our estimate of the MTU */
 
     /* DTLS-SRTP cipher suite preferences (if any) */
     PRUint16 dtlsSRTPCiphers[MAX_DTLS_SRTP_CIPHER_SUITES];
     PRUint16 dtlsSRTPCipherCount;
-    PRUint16 dtlsSRTPCipherSuite; /* 0 if not selected */
     PRBool fatalAlertSent;
     PRBool dheWeakGroupEnabled; /* used by server */
     const sslNamedGroupDef *dhePreferredGroup;
 
     /* TLS 1.2 introduces separate signature algorithm negotiation.
      * TLS 1.3 combined signature and hash into a single enum.
      * This is our preference order. */
     SSLSignatureScheme signatureSchemes[MAX_SIGNATURE_SCHEMES];
@@ -1659,36 +1557,38 @@ extern void ssl_FreeKeyPair(sslKeyPair *
 extern sslEphemeralKeyPair *ssl_NewEphemeralKeyPair(
     const sslNamedGroupDef *group,
     SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey);
 extern sslEphemeralKeyPair *ssl_CopyEphemeralKeyPair(
     sslEphemeralKeyPair *keyPair);
 extern void ssl_FreeEphemeralKeyPair(sslEphemeralKeyPair *keyPair);
 extern sslEphemeralKeyPair *ssl_LookupEphemeralKeyPair(
     sslSocket *ss, const sslNamedGroupDef *groupDef);
+extern PRBool ssl_HaveEphemeralKeyPair(const sslSocket *ss,
+                                       const sslNamedGroupDef *groupDef);
 extern void ssl_FreeEphemeralKeyPairs(sslSocket *ss);
 
-extern SECStatus ssl_AppendPaddedDHKeyShare(sslSocket *ss,
-                                            SECKEYPublicKey *pubKey,
+extern SECStatus ssl_AppendPaddedDHKeyShare(const sslSocket *ss,
+                                            const SECKEYPublicKey *pubKey,
                                             PRBool appendLength);
 extern const ssl3DHParams *ssl_GetDHEParams(const sslNamedGroupDef *groupDef);
 extern SECStatus ssl_SelectDHEGroup(sslSocket *ss,
                                     const sslNamedGroupDef **groupDef);
 extern SECStatus ssl_CreateDHEKeyPair(const sslNamedGroupDef *groupDef,
                                       const ssl3DHParams *params,
                                       sslEphemeralKeyPair **keyPair);
 extern PRBool ssl_IsValidDHEShare(const SECItem *dh_p, const SECItem *dh_Ys);
 extern SECStatus ssl_ValidateDHENamedGroup(sslSocket *ss,
                                            const SECItem *dh_p,
                                            const SECItem *dh_g,
                                            const sslNamedGroupDef **groupDef,
                                            const ssl3DHParams **dhParams);
 
-extern PRBool ssl_IsECCEnabled(sslSocket *ss);
-extern PRBool ssl_IsDHEEnabled(sslSocket *ss);
+extern PRBool ssl_IsECCEnabled(const sslSocket *ss);
+extern PRBool ssl_IsDHEEnabled(const sslSocket *ss);
 
 /* Macro for finding a curve equivalent in strength to RSA key's */
 #define SSL_RSASTRENGTH_TO_ECSTRENGTH(s)                            \
     ((s <= 1024) ? 160                                              \
                  : ((s <= 2048) ? 224                               \
                                 : ((s <= 3072) ? 256                \
                                                : ((s <= 7168) ? 384 \
                                                               : 521))))
@@ -1703,17 +1603,17 @@ extern const sslNamedGroupDef *ssl_ECPub
 
 extern const sslNamedGroupDef *ssl_GetECGroupForServerSocket(sslSocket *ss);
 extern void ssl_FilterSupportedGroups(sslSocket *ss);
 
 extern SECStatus ssl3_CipherPrefSetDefault(ssl3CipherSuite which, PRBool on);
 extern SECStatus ssl3_CipherPrefGetDefault(ssl3CipherSuite which, PRBool *on);
 
 extern SECStatus ssl3_CipherPrefSet(sslSocket *ss, ssl3CipherSuite which, PRBool on);
-extern SECStatus ssl3_CipherPrefGet(sslSocket *ss, ssl3CipherSuite which, PRBool *on);
+extern SECStatus ssl3_CipherPrefGet(const sslSocket *ss, ssl3CipherSuite which, PRBool *on);
 
 extern SECStatus ssl3_SetPolicy(ssl3CipherSuite which, PRInt32 policy);
 extern SECStatus ssl3_GetPolicy(ssl3CipherSuite which, PRInt32 *policy);
 
 extern void ssl3_InitSocketPolicy(sslSocket *ss);
 
 extern SECStatus ssl3_RedoHandshake(sslSocket *ss, PRBool flushCache);
 extern SECStatus ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b,
@@ -1739,17 +1639,17 @@ extern SECStatus ssl3_HandleECDHServerKe
 extern SECStatus ssl3_HandleECDHClientKeyExchange(sslSocket *ss,
                                                   SSL3Opaque *b, PRUint32 length,
                                                   sslKeyPair *serverKeys);
 extern SECStatus ssl3_SendECDHServerKeyExchange(sslSocket *ss);
 extern SECStatus ssl_ImportECDHKeyShare(
     sslSocket *ss, SECKEYPublicKey *peerKey,
     SSL3Opaque *b, PRUint32 length, const sslNamedGroupDef *curve);
 unsigned int tls13_SizeOfECDHEKeyShareKEX(const SECKEYPublicKey *pubKey);
-SECStatus tls13_EncodeECDHEKeyShareKEX(sslSocket *ss,
+SECStatus tls13_EncodeECDHEKeyShareKEX(const sslSocket *ss,
                                        const SECKEYPublicKey *pubKey);
 
 extern SECStatus ssl3_ComputeCommonKeyHash(SSLHashType hashAlg,
                                            PRUint8 *hashBuf,
                                            unsigned int bufLen,
                                            SSL3Hashes *hashes);
 extern void ssl3_DestroyCipherSpec(ssl3CipherSpec *spec, PRBool freeSrvName);
 extern SECStatus ssl3_InitPendingCipherSpec(sslSocket *ss, PK11SymKey *pms);
@@ -1770,76 +1670,33 @@ extern PRInt32 ssl3_ConsumeHandshakeNumb
 extern SECStatus ssl3_ConsumeHandshakeVariable(sslSocket *ss, SECItem *i,
                                                PRInt32 bytes, SSL3Opaque **b,
                                                PRUint32 *length);
 extern PRUint8 *ssl_EncodeUintX(PRUint64 value, unsigned int bytes,
                                 PRUint8 *to);
 extern PRBool ssl_IsSupportedSignatureScheme(SSLSignatureScheme scheme);
 extern SECStatus ssl_CheckSignatureSchemeConsistency(
     sslSocket *ss, SSLSignatureScheme scheme, CERTCertificate *cert);
-extern SECStatus ssl_ParseSignatureSchemes(sslSocket *ss, PLArenaPool *arena,
+extern SECStatus ssl_ParseSignatureSchemes(const sslSocket *ss, PLArenaPool *arena,
                                            SSLSignatureScheme **schemesOut,
                                            unsigned int *numSchemesOut,
                                            unsigned char **b,
                                            unsigned int *len);
 extern SECStatus ssl_ConsumeSignatureScheme(
     sslSocket *ss, SSL3Opaque **b, PRUint32 *length, SSLSignatureScheme *out);
 extern SECStatus ssl3_SignHashes(sslSocket *ss, SSL3Hashes *hash,
                                  SECKEYPrivateKey *key, SECItem *buf);
 extern SECStatus ssl3_VerifySignedHashes(sslSocket *ss, SSLSignatureScheme scheme,
                                          SSL3Hashes *hash, SECItem *buf);
 extern SECStatus ssl3_CacheWrappedMasterSecret(
     sslSocket *ss, sslSessionID *sid,
     ssl3CipherSpec *spec, SSLAuthType authType);
 extern void ssl3_FreeSniNameArray(TLSExtensionData *xtnData);
 
-/* Functions that handle ClientHello and ServerHello extensions. */
-extern SECStatus ssl3_HandleServerNameXtn(sslSocket *ss,
-                                          PRUint16 ex_type, SECItem *data);
-extern SECStatus ssl_HandleSupportedGroupsXtn(sslSocket *ss,
-                                              PRUint16 ex_type, SECItem *data);
-extern SECStatus ssl3_HandleSupportedPointFormatsXtn(sslSocket *ss,
-                                                     PRUint16 ex_type, SECItem *data);
-extern SECStatus ssl3_ClientHandleSessionTicketXtn(sslSocket *ss,
-                                                   PRUint16 ex_type, SECItem *data);
-extern SECStatus ssl3_ServerHandleSessionTicketXtn(sslSocket *ss,
-                                                   PRUint16 ex_type, SECItem *data);
-
-/* ClientHello and ServerHello extension senders.
- * Note that not all extension senders are exposed here; only those that
- * that need exposure.
- */
-extern PRInt32 ssl3_SendSessionTicketXtn(sslSocket *ss, PRBool append,
-                                         PRUint32 maxBytes);
-
-/* ClientHello and ServerHello extension senders.
- * The code is in ssl3ext.c.
- */
-extern PRInt32 ssl3_SendServerNameXtn(sslSocket *ss, PRBool append,
-                                      PRUint32 maxBytes);
-
-extern PRInt32 ssl_SendSupportedGroupsXtn(sslSocket *ss,
-                                          PRBool append, PRUint32 maxBytes);
-extern PRInt32 ssl3_SendSupportedPointFormatsXtn(sslSocket *ss,
-                                                 PRBool append, PRUint32 maxBytes);
-
-/* call the registered extension handlers. */
-extern SECStatus ssl3_HandleExtensions(sslSocket *ss,
-                                       SSL3Opaque **b, PRUint32 *length,
-                                       SSL3HandshakeType handshakeMessage);
-extern SECStatus ssl3_ParseExtensions(sslSocket *ss,
-                                      SSL3Opaque **b, PRUint32 *length);
-extern SECStatus ssl3_HandleParsedExtensions(sslSocket *ss,
-                                             SSL3HandshakeType handshakeMessage);
-extern TLSExtension *ssl3_FindExtension(sslSocket *ss,
-                                        SSLExtensionType extension_type);
-extern void ssl3_DestroyRemoteExtensions(PRCList *list);
-
 /* Hello Extension related routines. */
-extern PRBool ssl3_ExtensionNegotiated(sslSocket *ss, PRUint16 ex_type);
 extern void ssl3_SetSIDSessionTicket(sslSessionID *sid,
                                      /*in/out*/ NewSessionTicket *session_ticket);
 SECStatus ssl3_EncodeSessionTicket(sslSocket *ss,
                                    const NewSessionTicket *ticket_input,
                                    SECItem *ticket_data);
 extern PRBool ssl_GetSessionTicketKeys(SECKEYPrivateKey *svrPrivKey,
                                        SECKEYPublicKey *svrPubKey, void *pwArg,
                                        unsigned char *keyName, PK11SymKey **aesKey,
@@ -1935,54 +1792,42 @@ SECStatus ssl3_SetupPendingCipherSpec(ss
 SECStatus ssl3_FlushHandshake(sslSocket *ss, PRInt32 flags);
 SECStatus ssl3_SendCertificate(sslSocket *ss);
 SECStatus ssl3_CompleteHandleCertificate(sslSocket *ss,
                                          SSL3Opaque *b, PRUint32 length);
 SECStatus ssl3_SendEmptyCertificate(sslSocket *ss);
 SECStatus ssl3_SendCertificateStatus(sslSocket *ss);
 SECStatus ssl_ReadCertificateStatus(sslSocket *ss, SSL3Opaque *b,
                                     PRUint32 length);
-SECStatus ssl3_EncodeSigAlgs(sslSocket *ss, PRUint8 *buf,
+SECStatus ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint8 *buf,
                              unsigned maxLen, PRUint32 *len);
 void ssl3_GetCertificateRequestCAs(sslSocket *ss, int *calenp, SECItem **namesp,
                                    int *nnamesp);
 SECStatus ssl3_ParseCertificateRequestCAs(sslSocket *ss, SSL3Opaque **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_ComputeHandshakeHashes(sslSocket *ss,
                                       ssl3CipherSpec *spec,
                                       SSL3Hashes *hashes,
                                       PRUint32 sender);
-PRInt32 tls13_ServerSendKeyShareXtn(sslSocket *ss, PRBool append,
-                                    PRUint32 maxBytes);
 SECStatus ssl_CreateECDHEphemeralKeyPair(const sslSocket *ss,
                                          const sslNamedGroupDef *ecGroup,
                                          sslEphemeralKeyPair **keyPair);
 SECStatus ssl_CreateStaticECDHEKey(sslSocket *ss,
                                    const sslNamedGroupDef *ecGroup);
 SECStatus ssl3_FlushHandshake(sslSocket *ss, PRInt32 flags);
 PK11SymKey *ssl3_GetWrappingKey(sslSocket *ss,
                                 PK11SlotInfo *masterSecretSlot,
                                 const sslServerCert *serverCert,
                                 CK_MECHANISM_TYPE masterWrapMech,
                                 void *pwArg);
-PRInt32 tls13_ServerSendPreSharedKeyXtn(sslSocket *ss,
-                                        PRBool append,
-                                        PRUint32 maxBytes);
-PRInt32 tls13_ServerSendEarlyDataXtn(sslSocket *ss,
-                                     PRBool append,
-                                     PRUint32 maxBytes);
-PRInt32 tls13_ServerSendSigAlgsXtn(sslSocket *ss,
-                                   PRBool append,
-                                   PRUint32 maxBytes);
-PRBool ssl3_ClientExtensionAdvertised(sslSocket *ss, PRUint16 ex_type);
 SECStatus ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid);
 const ssl3CipherSuiteDef *ssl_LookupCipherSuiteDef(ssl3CipherSuite suite);
 const ssl3BulkCipherDef *
 ssl_GetBulkCipherDef(const ssl3CipherSuiteDef *cipher_def);
 SECStatus ssl3_SelectServerCert(sslSocket *ss);
 SECStatus ssl_PickSignatureScheme(sslSocket *ss,
                                   SECKEYPublicKey *pubKey,
                                   SECKEYPrivateKey *privKey,
--- a/security/nss/lib/ssl/sslsecur.c
+++ b/security/nss/lib/ssl/sslsecur.c
@@ -195,16 +195,17 @@ SSL_ResetHandshake(PRFileDesc *s, PRBool
     ssl_ResetSecurityInfo(&ss->sec, PR_TRUE);
     status = ssl_CreateSecurityInfo(ss);
     ssl_ReleaseXmitBufLock(ss);
 
     ssl_ReleaseSSL3HandshakeLock(ss);
     ssl_Release1stHandshakeLock(ss);
 
     ssl3_DestroyRemoteExtensions(&ss->ssl3.hs.remoteExtensions);
+    ssl3_ResetExtensionData(&ss->xtnData);
 
     if (!ss->TCPconnected)
         ss->TCPconnected = (PR_SUCCESS == ssl_DefGetpeername(ss, &addr));
 
 loser:
     SSL_UNLOCK_WRITER(ss);
     SSL_UNLOCK_READER(ss);
 
--- a/security/nss/lib/ssl/sslsock.c
+++ b/security/nss/lib/ssl/sslsock.c
@@ -1755,17 +1755,17 @@ ssl_SelectDHEGroup(sslSocket *ss, const 
         ssl_grp_ffdhe_custom, WEAK_DHE_SIZE, ssl_kea_dh,
         SEC_OID_TLS_DHE_CUSTOM, PR_TRUE
     };
 
     /* Only select weak groups in TLS 1.2 and earlier, but not if the client has
      * indicated that it supports an FFDHE named group. */
     if (ss->ssl3.dheWeakGroupEnabled &&
         ss->version < SSL_LIBRARY_VERSION_TLS_1_3 &&
-        !ss->ssl3.hs.peerSupportsFfdheGroups) {
+        !ss->xtnData.peerSupportsFfdheGroups) {
         *groupDef = &weak_group_def;
         return SECSuccess;
     }
     if (ss->ssl3.dhePreferredGroup &&
         ssl_NamedGroupEnabled(ss, ss->ssl3.dhePreferredGroup)) {
         *groupDef = ss->ssl3.dhePreferredGroup;
         return SECSuccess;
     }
@@ -1884,30 +1884,30 @@ ssl_NextProtoNegoCallback(void *arg, PRF
 
     /* For each protocol in server preference, see if we support it. */
     for (i = 0; i < protos_len;) {
         for (j = 0; j < ss->opt.nextProtoNego.len;) {
             if (protos[i] == ss->opt.nextProtoNego.data[j] &&
                 PORT_Memcmp(&protos[i + 1], &ss->opt.nextProtoNego.data[j + 1],
                             protos[i]) == 0) {
                 /* We found a match. */
-                ss->ssl3.nextProtoState = SSL_NEXT_PROTO_NEGOTIATED;
+                ss->xtnData.nextProtoState = SSL_NEXT_PROTO_NEGOTIATED;
                 result = &protos[i];
                 goto found;
             }
             j += 1 + (unsigned int)ss->opt.nextProtoNego.data[j];
         }
         i += 1 + (unsigned int)protos[i];
     }
 
     /* The other side supports the extension, and either doesn't have any
      * protocols configured, or none of its options match ours. In this case we
      * request our favoured protocol. */
     /* This will be treated as a failure for ALPN. */
-    ss->ssl3.nextProtoState = SSL_NEXT_PROTO_NO_OVERLAP;
+    ss->xtnData.nextProtoState = SSL_NEXT_PROTO_NO_OVERLAP;
     result = ss->opt.nextProtoNego.data;
 
 found:
     if (protoMaxLen < result[0]) {
         PORT_SetError(SEC_ERROR_OUTPUT_LEN);
         return SECFailure;
     }
     memcpy(protoOut, result + 1, result[0]);
@@ -1956,26 +1956,26 @@ SSL_GetNextProto(PRFileDesc *fd, SSLNext
         return SECFailure;
     }
 
     if (!state || !buf || !bufLen) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return SECFailure;
     }
 
-    *state = ss->ssl3.nextProtoState;
-
-    if (ss->ssl3.nextProtoState != SSL_NEXT_PROTO_NO_SUPPORT &&
-        ss->ssl3.nextProto.data) {
-        if (ss->ssl3.nextProto.len > bufLenMax) {
+    *state = ss->xtnData.nextProtoState;
+
+    if (ss->xtnData.nextProtoState != SSL_NEXT_PROTO_NO_SUPPORT &&
+        ss->xtnData.nextProto.data) {
+        if (ss->xtnData.nextProto.len > bufLenMax) {
             PORT_SetError(SEC_ERROR_OUTPUT_LEN);
             return SECFailure;
         }
-        PORT_Memcpy(buf, ss->ssl3.nextProto.data, ss->ssl3.nextProto.len);
-        *bufLen = ss->ssl3.nextProto.len;
+        PORT_Memcpy(buf, ss->xtnData.nextProto.data, ss->xtnData.nextProto.len);
+        *bufLen = ss->xtnData.nextProto.len;
     } else {
         *bufLen = 0;
     }
 
     return SECSuccess;
 }
 
 SECStatus
@@ -2035,22 +2035,22 @@ SSL_GetSRTPCipher(PRFileDesc *fd, PRUint
     ss = ssl_FindSocket(fd);
     if (!ss) {
         SSL_DBG(("%d: SSL[%d]: bad socket in SSL_GetSRTPCipher",
                  SSL_GETPID(), fd));
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return SECFailure;
     }
 
-    if (!ss->ssl3.dtlsSRTPCipherSuite) {
+    if (!ss->xtnData.dtlsSRTPCipherSuite) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return SECFailure;
     }
 
-    *cipher = ss->ssl3.dtlsSRTPCipherSuite;
+    *cipher = ss->xtnData.dtlsSRTPCipherSuite;
     return SECSuccess;
 }
 
 PRFileDesc *
 SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd)
 {
     sslSocket *sm = NULL, *ss = NULL;
     PRCList *cursor;
@@ -3601,16 +3601,22 @@ ssl_CopyEphemeralKeyPair(sslEphemeralKey
 void
 ssl_FreeEphemeralKeyPair(sslEphemeralKeyPair *keyPair)
 {
     ssl_FreeKeyPair(keyPair->keys);
     PR_REMOVE_LINK(&keyPair->link);
     PORT_Free(keyPair);
 }
 
+PRBool
+ssl_HaveEphemeralKeyPair(const sslSocket *ss, const sslNamedGroupDef *groupDef)
+{
+    return ssl_LookupEphemeralKeyPair((sslSocket *)ss, groupDef) != NULL;
+}
+
 sslEphemeralKeyPair *
 ssl_LookupEphemeralKeyPair(sslSocket *ss, const sslNamedGroupDef *groupDef)
 {
     PRCList *cursor;
     for (cursor = PR_NEXT_LINK(&ss->ephemeralKeyPairs);
          cursor != &ss->ephemeralKeyPairs;
          cursor = PR_NEXT_LINK(cursor)) {
         sslEphemeralKeyPair *keyPair = (sslEphemeralKeyPair *)cursor;
@@ -3683,31 +3689,30 @@ ssl_NewSocket(PRBool makeLocks, SSLProto
     ssl_ChooseOps(ss);
     ssl3_InitSocketPolicy(ss);
     for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) {
         ss->namedGroupPreferences[i] = &ssl_named_groups[i];
     }
     ss->additionalShares = 0;
     PR_INIT_CLIST(&ss->ssl3.hs.remoteExtensions);
     PR_INIT_CLIST(&ss->ssl3.hs.lastMessageFlight);
-    PR_INIT_CLIST(&ss->ssl3.hs.remoteKeyShares);
     PR_INIT_CLIST(&ss->ssl3.hs.cipherSpecs);
     PR_INIT_CLIST(&ss->ssl3.hs.bufferedEarlyData);
     if (makeLocks) {
         rv = ssl_MakeLocks(ss);
         if (rv != SECSuccess)
             goto loser;
     }
     rv = ssl_CreateSecurityInfo(ss);
     if (rv != SECSuccess)
         goto loser;
     rv = ssl3_InitGather(&ss->gs);
     if (rv != SECSuccess)
         goto loser;
-
+    ssl3_InitExtensionData(&ss->xtnData);
     return ss;
 
 loser:
     ssl_DestroySocketContents(ss);
     ssl_DestroyLocks(ss);
     PORT_Free(ss);
     return NULL;
 }
--- a/security/nss/lib/ssl/tls13con.c
+++ b/security/nss/lib/ssl/tls13con.c
@@ -14,16 +14,17 @@
 #include "prerr.h"
 #include "secitem.h"
 #include "secmod.h"
 #include "sslimpl.h"
 #include "sslproto.h"
 #include "sslerr.h"
 #include "tls13hkdf.h"
 #include "tls13con.h"
+#include "tls13exthandle.h"
 
 typedef enum {
     TrafficKeyEarlyHandshake,
     TrafficKeyEarlyApplicationData,
     TrafficKeyHandshake,
     TrafficKeyApplicationData
 } TrafficKeyType;
 
@@ -971,17 +972,17 @@ tls13_CanResume(sslSocket *ss, const ssl
     if (!sc || !sc->serverCert) {
         return PR_FALSE;
     }
 
     return PR_TRUE;
 }
 
 static PRBool
-tls13_AlpnTagAllowed(sslSocket *ss, const SECItem *tag)
+tls13_AlpnTagAllowed(const sslSocket *ss, const SECItem *tag)
 {
     const unsigned char *data = ss->opt.nextProtoNego.data;
     unsigned int length = ss->opt.nextProtoNego.len;
     unsigned int offset = 0;
 
     if (!tag->len)
         return PR_TRUE;
 
@@ -1025,17 +1026,17 @@ tls13_NegotiateZeroRtt(sslSocket *ss, co
         ss->ssl3.hs.zeroRttState = ssl_0rtt_none;
         ss->ssl3.hs.zeroRttIgnore = ssl_0rtt_ignore_none;
         return;
     }
 
     PORT_Assert(ss->ssl3.hs.zeroRttState == ssl_0rtt_sent);
     if (sid && ss->opt.enable0RttData &&
         (sid->u.ssl3.locked.sessionTicket.flags & ticket_allow_early_data) != 0 &&
-        SECITEM_CompareItem(&ss->ssl3.nextProto, &sid->u.ssl3.alpnSelection) == 0) {
+        SECITEM_CompareItem(&ss->xtnData.nextProto, &sid->u.ssl3.alpnSelection) == 0) {
         SSL_TRC(3, ("%d: TLS13[%d]: enable 0-RTT",
                     SSL_GETPID(), ss->fd));
         PORT_Assert(ss->statelessResume);
         ss->ssl3.hs.zeroRttState = ssl_0rtt_accepted;
         ss->ssl3.hs.zeroRttIgnore = ssl_0rtt_ignore_none;
     } else {
         SSL_TRC(3, ("%d: TLS13[%d]: ignore 0-RTT",
                     SSL_GETPID(), ss->fd));
@@ -1063,18 +1064,18 @@ tls13_isGroupAcceptable(const sslNamedGr
     return PR_FALSE;
 }
 
 /* Find remote key share for given group and return it.
  * Returns NULL if no key share is found. */
 static TLS13KeyShareEntry *
 tls13_FindKeyShareEntry(sslSocket *ss, const sslNamedGroupDef *group)
 {
-    PRCList *cur_p = PR_NEXT_LINK(&ss->ssl3.hs.remoteKeyShares);
-    while (cur_p != &ss->ssl3.hs.remoteKeyShares) {
+    PRCList *cur_p = PR_NEXT_LINK(&ss->xtnData.remoteKeyShares);
+    while (cur_p != &ss->xtnData.remoteKeyShares) {
         TLS13KeyShareEntry *offer = (TLS13KeyShareEntry *)cur_p;
         if (offer->group == group) {
             return offer;
         }
         cur_p = PR_NEXT_LINK(cur_p);
     }
     return NULL;
 }
@@ -1150,18 +1151,16 @@ tls13_NegotiateKeyExchange(sslSocket *ss
 
     if (!preferredGroup) {
         FATAL_ERROR(ss, SSL_ERROR_NO_CYPHER_OVERLAP, handshake_failure);
         return SECFailure;
     }
     SSL_TRC(3, ("%d: TLS13[%d]: group = %d", SSL_GETPID(), ss->fd,
                 preferredGroup->name));
 
-    SSL_TRC(3, ("%d: TLS13[%d]: group = %d", preferredGroup->name));
-
     if (!entry) {
         return tls13_SendHelloRetryRequest(ss, preferredGroup);
     }
 
     PORT_Assert(preferredGroup == entry->group);
     *clientShare = entry;
 
     return SECSuccess;
@@ -1193,18 +1192,18 @@ tls13_SelectServerCert(sslSocket *ss)
         if (cert->certType.authType == ssl_auth_rsa_pss ||
             cert->certType.authType == ssl_auth_rsa_decrypt) {
             continue;
         }
 
         rv = ssl_PickSignatureScheme(ss,
                                      cert->serverKeyPair->pubKey,
                                      cert->serverKeyPair->privKey,
-                                     ss->ssl3.hs.clientSigSchemes,
-                                     ss->ssl3.hs.numClientSigScheme,
+                                     ss->xtnData.clientSigSchemes,
+                                     ss->xtnData.numClientSigScheme,
                                      PR_FALSE);
         if (rv == SECSuccess) {
             /* Found one. */
             ss->sec.serverCert = cert;
             ss->sec.authType = cert->certType.authType;
             ss->ssl3.hs.kea_def_mutable.authKeyType = cert->certType.authType;
             ss->sec.authKeyBits = cert->serverKeyBits;
             return SECSuccess;
@@ -1236,18 +1235,18 @@ tls13_NegotiateAuthentication(sslSocket 
         SSL_TRC(3, ("%d: TLS13[%d]: rejected PSK authentication",
                     SSL_GETPID(), ss->fd));
 
         ss->statelessResume = PR_FALSE;
     }
 
     SSL_TRC(3, ("%d: TLS13[%d]: selected certificate authentication",
                 SSL_GETPID(), ss->fd));
-    rv = ssl3_RegisterServerHelloExtensionSender(
-        ss, ssl_signature_algorithms_xtn,
+    rv = ssl3_RegisterExtensionSender(
+        ss, &ss->xtnData, ssl_signature_algorithms_xtn,
         tls13_ServerSendSigAlgsXtn);
     if (rv != SECSuccess) {
         return SECFailure; /* Error code set already. */
     }
 
     /* We've now established that we need to sign.... */
     rv = tls13_SelectServerCert(ss);
     if (rv != SECSuccess) {
@@ -1267,16 +1266,30 @@ tls13_HandleClientHelloPart2(sslSocket *
                              sslSessionID *sid)
 {
     SECStatus rv;
     SSL3Statistics *ssl3stats = SSL_GetStatistics();
     TLS13KeyShareEntry *clientShare = NULL;
     int j;
     ssl3CipherSuite previousCipherSuite;
 
+    if (ssl3_ExtensionNegotiated(ss, ssl_tls13_early_data_xtn)) {
+        ss->ssl3.hs.zeroRttState = ssl_0rtt_sent;
+
+        if (IS_DTLS(ss)) {
+            /* Save the null spec, which we should be currently reading.  We will
+             * use this when 0-RTT sending is over. */
+            ssl_GetSpecReadLock(ss);
+            ss->ssl3.hs.nullSpec = ss->ssl3.crSpec;
+            tls13_CipherSpecAddRef(ss->ssl3.hs.nullSpec);
+            PORT_Assert(ss->ssl3.hs.nullSpec->cipher_def->cipher == cipher_null);
+            ssl_ReleaseSpecReadLock(ss);
+        }
+    }
+
 #ifndef PARANOID
     /* Look for a matching cipher suite. */
     j = ssl3_config_match_init(ss);
     if (j <= 0) { /* no ciphers are working/supported by PK11 */
         FATAL_ERROR(ss, PORT_GetError(), internal_error);
         goto loser;
     }
 #endif
@@ -1362,18 +1375,19 @@ tls13_HandleClientHelloPart2(sslSocket *
         tls13_RestoreCipherInfo(ss, sid);
 
         ss->sec.serverCert = ssl_FindServerCert(ss, &sid->certType);
         PORT_Assert(ss->sec.serverCert);
         ss->sec.localCert = CERT_DupCertificate(ss->sec.serverCert->serverCert);
         if (sid->peerCert != NULL) {
             ss->sec.peerCert = CERT_DupCertificate(sid->peerCert);
         }
-        ssl3_RegisterServerHelloExtensionSender(
-            ss, ssl_tls13_pre_shared_key_xtn, tls13_ServerSendPreSharedKeyXtn);
+        ssl3_RegisterExtensionSender(
+            ss, &ss->xtnData,
+            ssl_tls13_pre_shared_key_xtn, tls13_ServerSendPreSharedKeyXtn);
 
         tls13_NegotiateZeroRtt(ss, sid);
     } else {
         if (sid) { /* we had a sid, but it's no longer valid, free it */
             SSL_AtomicIncrementLong(&ssl3stats->hch_sid_cache_not_ok);
             if (ss->sec.uncache)
                 ss->sec.uncache(sid);
             ssl_FreeSID(sid);
@@ -1575,18 +1589,18 @@ tls13_HandleClientKeyShare(sslSocket *ss
     PORT_Assert(!PR_CLIST_IS_EMPTY(&ss->ephemeralKeyPairs));
     PORT_Assert(PR_PREV_LINK(&ss->ephemeralKeyPairs) ==
                 PR_NEXT_LINK(&ss->ephemeralKeyPairs));
 
     keyPair = ((sslEphemeralKeyPair *)PR_NEXT_LINK(&ss->ephemeralKeyPairs));
     ss->sec.keaKeyBits = SECKEY_PublicKeyStrengthInBits(keyPair->keys->pubKey);
 
     /* Register the sender */
-    rv = ssl3_RegisterServerHelloExtensionSender(ss, ssl_tls13_key_share_xtn,
-                                                 tls13_ServerSendKeyShareXtn);
+    rv = ssl3_RegisterExtensionSender(ss, &ss->xtnData, ssl_tls13_key_share_xtn,
+                                      tls13_ServerSendKeyShareXtn);
     if (rv != SECSuccess) {
         return SECFailure; /* Error code set already. */
     }
 
     rv = tls13_HandleKeyShare(ss, peerShare, keyPair->keys);
     return rv; /* Error code set already. */
 }
 
@@ -1852,18 +1866,18 @@ tls13_SendEncryptedServerSequence(sslSoc
     rv = tls13_SetCipherSpec(ss, TrafficKeyHandshake,
                              CipherSpecWrite, PR_FALSE);
     if (rv != SECSuccess) {
         LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
         return SECFailure;
     }
 
     if (ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted) {
-        rv = ssl3_RegisterServerHelloExtensionSender(ss, ssl_tls13_early_data_xtn,
-                                                     tls13_ServerSendEarlyDataXtn);
+        rv = ssl3_RegisterExtensionSender(ss, &ss->xtnData, ssl_tls13_early_data_xtn,
+                                          tls13_ServerSendEarlyDataXtn);
         if (rv != SECSuccess) {
             return SECFailure; /* Error code set already. */
         }
     }
 
     rv = tls13_SendEncryptedExtensions(ss);
     if (rv != SECSuccess) {
         return SECFailure; /* error code is set. */
@@ -2162,23 +2176,23 @@ tls13_HandleServerKeyShare(sslSocket *ss
     sslEphemeralKeyPair *keyPair;
 
     SSL_TRC(3, ("%d: TLS13[%d]: handle server_key_share handshake",
                 SSL_GETPID(), ss->fd));
     PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
     /* This list should have one entry. */
-    if (PR_CLIST_IS_EMPTY(&ss->ssl3.hs.remoteKeyShares)) {
+    if (PR_CLIST_IS_EMPTY(&ss->xtnData.remoteKeyShares)) {
         FATAL_ERROR(ss, SSL_ERROR_MISSING_KEY_SHARE, missing_extension);
         return SECFailure;
     }
 
-    entry = (TLS13KeyShareEntry *)PR_NEXT_LINK(&ss->ssl3.hs.remoteKeyShares);
-    PORT_Assert(PR_NEXT_LINK(&entry->link) == &ss->ssl3.hs.remoteKeyShares);
+    entry = (TLS13KeyShareEntry *)PR_NEXT_LINK(&ss->xtnData.remoteKeyShares);
+    PORT_Assert(PR_NEXT_LINK(&entry->link) == &ss->xtnData.remoteKeyShares);
 
     PORT_Assert(ssl_NamedGroupEnabled(ss, entry->group));
 
     /* Now get our matching key. */
     keyPair = ssl_LookupEphemeralKeyPair(ss, entry->group);
     if (!keyPair) {
         FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_KEY_SHARE, illegal_parameter);
         return SECFailure;
@@ -2864,29 +2878,38 @@ tls13_HandleEncryptedExtensions(sslSocke
         FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_ENCRYPTED_EXTENSIONS,
                     illegal_parameter);
         return SECFailure;
     }
 
     /* If we are doing 0-RTT, then we already have an NPN value. Stash
      * it for comparison. */
     if (ss->ssl3.hs.zeroRttState == ssl_0rtt_sent &&
-        ss->ssl3.nextProtoState == SSL_NEXT_PROTO_EARLY_VALUE) {
-        oldNpn = ss->ssl3.nextProto;
-        ss->ssl3.nextProto.data = NULL;
-        ss->ssl3.nextProtoState = SSL_NEXT_PROTO_NO_SUPPORT;
+        ss->xtnData.nextProtoState == SSL_NEXT_PROTO_EARLY_VALUE) {
+        oldNpn = ss->xtnData.nextProto;
+        ss->xtnData.nextProto.data = NULL;
+        ss->xtnData.nextProtoState = SSL_NEXT_PROTO_NO_SUPPORT;
     }
     rv = ssl3_HandleExtensions(ss, &b, &length, encrypted_extensions);
     if (rv != SECSuccess) {
         return SECFailure; /* Error code set below */
     }
 
-    if (ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted) {
+    /* We can only get here if we offered 0-RTT. */
+    if (ssl3_ExtensionNegotiated(ss, ssl_tls13_early_data_xtn)) {
+        PORT_Assert(ss->ssl3.hs.zeroRttState == ssl_0rtt_sent);
+        if (!ss->statelessResume) {
+            /* Illegal to accept 0-RTT without also accepting PSK. */
+            FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_ENCRYPTED_EXTENSIONS,
+                        illegal_parameter);
+        }
+        ss->ssl3.hs.zeroRttState = ssl_0rtt_accepted;
+
         /* Check that the server negotiated the same ALPN (if any). */
-        if (SECITEM_CompareItem(&oldNpn, &ss->ssl3.nextProto)) {
+        if (SECITEM_CompareItem(&oldNpn, &ss->xtnData.nextProto)) {
             SECITEM_FreeItem(&oldNpn, PR_FALSE);
             FATAL_ERROR(ss, SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID,
                         illegal_parameter);
             return SECFailure;
         }
     } else if (ss->ssl3.hs.zeroRttState == ssl_0rtt_sent) {
         /* Though we sent 0-RTT, the early_data extension wasn't present so the
          * state is unmodified; the server must have rejected 0-RTT. */
@@ -4070,17 +4093,17 @@ tls13_UnprotectRecord(sslSocket *ss, SSL
  * 4. We have a valid ticket.
  * 5. The server is willing to accept 0-RTT.
  * 6. We have not changed our ALPN settings to disallow the ALPN tag
  *    in the ticket.
  *
  * Called from tls13_ClientSendEarlyDataXtn().
  */
 PRBool
-tls13_ClientAllow0Rtt(sslSocket *ss, const sslSessionID *sid)
+tls13_ClientAllow0Rtt(const sslSocket *ss, const sslSessionID *sid)
 {
     if (sid->version < SSL_LIBRARY_VERSION_TLS_1_3)
         return PR_FALSE;
     if (ss->ssl3.hs.helloRetry)
         return PR_FALSE;
     if (!ss->opt.enable0RttData)
         return PR_FALSE;
     if (!ss->statelessResume)
@@ -4091,35 +4114,36 @@ tls13_ClientAllow0Rtt(sslSocket *ss, con
 }
 
 SECStatus
 tls13_MaybeDo0RTTHandshake(sslSocket *ss)
 {
     SECStatus rv;
     int bufferLen = ss->ssl3.hs.messages.len;
 
-    /* Don't do anything if this is the second ClientHello or we decided not to
-     * do 0-RTT (which means that there is no early_data extension). */
-    if (ss->ssl3.hs.zeroRttState != ssl_0rtt_sent) {
+    /* Don't do anything if there is no early_data xtn, which means we're
+     * not doing early data. */
+    if (!ssl3_ClientExtensionAdvertised(ss, ssl_tls13_early_data_xtn)) {
         return SECSuccess;
     }
+    ss->ssl3.hs.zeroRttState = ssl_0rtt_sent;
 
     SSL_TRC(3, ("%d: TLS13[%d]: in 0-RTT mode", SSL_GETPID(), ss->fd));
 
     rv = tls13_RecoverWrappedSharedSecret(ss, ss->sec.ci.sid);
     if (rv != SECSuccess) {
         FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
         return SECFailure;
     }
 
     /* 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->ssl3.nextProtoState = SSL_NEXT_PROTO_EARLY_VALUE;
-        rv = SECITEM_CopyItem(NULL, &ss->ssl3.nextProto,
+        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;
     }
 
     /* Need to do this first so we know the PRF for the early secret
      * computation. */
     rv = ssl3_SetCipherSuite(ss, ss->sec.ci.sid->u.ssl3.cipherSuite, PR_FALSE);
--- a/security/nss/lib/ssl/tls13con.h
+++ b/security/nss/lib/ssl/tls13con.h
@@ -64,16 +64,16 @@ SECStatus tls13_ProtectRecord(sslSocket 
                               ssl3CipherSpec *cwSpec,
                               SSL3ContentType type,
                               const SSL3Opaque *pIn,
                               PRUint32 contentLen,
                               sslBuffer *wrBuf);
 PRInt32 tls13_Read0RttData(sslSocket *ss, void *buf, PRInt32 len);
 SECStatus tls13_HandleEndOfEarlyData(sslSocket *ss);
 SECStatus tls13_HandleEarlyApplicationData(sslSocket *ss, sslBuffer *origBuf);
-PRBool tls13_ClientAllow0Rtt(sslSocket *ss, const sslSessionID *sid);
+PRBool tls13_ClientAllow0Rtt(const sslSocket *ss, const sslSessionID *sid);
 PRUint16 tls13_EncodeDraftVersion(SSL3ProtocolVersion version);
 PRUint16 tls13_DecodeDraftVersion(PRUint16 version);
 SECStatus tls13_NegotiateVersion(sslSocket *ss,
                                  const TLSExtension *supported_versions);
 SECStatus tls13_SendNewSessionTicket(sslSocket *ss);
 
 #endif /* __tls13con_h_ */
--- a/security/nss/lib/ssl/tls13exthandle.c
+++ b/security/nss/lib/ssl/tls13exthandle.c
@@ -5,22 +5,24 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nssrenam.h"
 #include "nss.h"
 #include "ssl.h"
 #include "sslproto.h"
 #include "sslimpl.h"
 #include "pk11pub.h"
+#include "ssl3ext.h"
 #include "ssl3exthandle.h"
 #include "tls13exthandle.h"
 
 PRInt32
 tls13_ServerSendStatusRequestXtn(
-    sslSocket *ss,
+    const sslSocket *ss,
+    TLSExtensionData *xtnData,
     PRBool append,
     PRUint32 maxBytes)
 {
     PRInt32 extension_length;
     const sslServerCert *serverCert = ss->sec.serverCert;
     const SECItem *item;
     SECStatus rv;
 
@@ -33,29 +35,29 @@ tls13_ServerSendStatusRequestXtn(
 
     /* Only send the first entry. */
     extension_length = 2 + 2 + 1 /* status_type */ + 3 + item->len;
     if (maxBytes < (PRUint32)extension_length) {
         return 0;
     }
     if (append) {
         /* extension_type */
-        rv = ssl3_AppendHandshakeNumber(ss, ssl_cert_status_xtn, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_cert_status_xtn, 2);
         if (rv != SECSuccess)
             return -1;
         /* length of extension_data */
-        rv = ssl3_AppendHandshakeNumber(ss, extension_length - 4, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, extension_length - 4, 2);
         if (rv != SECSuccess)
             return -1;
         /* status_type == ocsp */
-        rv = ssl3_AppendHandshakeNumber(ss, 1 /*ocsp*/, 1);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, 1 /*ocsp*/, 1);
         if (rv != SECSuccess)
             return rv; /* err set by AppendHandshake. */
         /* opaque OCSPResponse<1..2^24-1> */
-        rv = ssl3_AppendHandshakeVariable(ss, item->data, item->len, 3);
+        rv = ssl3_ExtAppendHandshakeVariable(ss, item->data, item->len, 3);
         if (rv != SECSuccess)
             return rv; /* err set by AppendHandshake. */
     }
 
     return extension_length;
 }
 
 /*
@@ -79,57 +81,57 @@ tls13_ServerSendStatusRequestXtn(
  * DH is Section 6.3.2.3.1.
  *
  *     opaque dh_Y<1..2^16-1>;
  *
  * ECDH is Section 6.3.2.3.2.
  *
  *     opaque point <1..2^8-1>;
  */
-PRUint32
+static PRUint32
 tls13_SizeOfKeyShareEntry(const SECKEYPublicKey *pubKey)
 {
     /* Size = NamedGroup(2) + length(2) + opaque<?> share */
     switch (pubKey->keyType) {
         case ecKey:
             return 2 + 2 + pubKey->u.ec.publicValue.len;
         case dhKey:
             return 2 + 2 + pubKey->u.dh.prime.len;
         default:
             PORT_Assert(0);
     }
     return 0;
 }
 
-PRUint32
-tls13_SizeOfClientKeyShareExtension(sslSocket *ss)
+static PRUint32
+tls13_SizeOfClientKeyShareExtension(const sslSocket *ss)
 {
     PRCList *cursor;
     /* Size is: extension(2) + extension_len(2) + client_shares(2) */
     PRUint32 size = 2 + 2 + 2;
     for (cursor = PR_NEXT_LINK(&ss->ephemeralKeyPairs);
          cursor != &ss->ephemeralKeyPairs;
          cursor = PR_NEXT_LINK(cursor)) {
         sslEphemeralKeyPair *keyPair = (sslEphemeralKeyPair *)cursor;
         size += tls13_SizeOfKeyShareEntry(keyPair->keys->pubKey);
     }
     return size;
 }
 
-SECStatus
-tls13_EncodeKeyShareEntry(sslSocket *ss, const sslEphemeralKeyPair *keyPair)
+static SECStatus
+tls13_EncodeKeyShareEntry(const sslSocket *ss, const sslEphemeralKeyPair *keyPair)
 {
     SECStatus rv;
     SECKEYPublicKey *pubKey = keyPair->keys->pubKey;
     unsigned int size = tls13_SizeOfKeyShareEntry(pubKey);
 
-    rv = ssl3_AppendHandshakeNumber(ss, keyPair->group->name, 2);
+    rv = ssl3_ExtAppendHandshakeNumber(ss, keyPair->group->name, 2);
     if (rv != SECSuccess)
         return rv;
-    rv = ssl3_AppendHandshakeNumber(ss, size - 4, 2);
+    rv = ssl3_ExtAppendHandshakeNumber(ss, size - 4, 2);
     if (rv != SECSuccess)
         return rv;
 
     switch (pubKey->keyType) {
         case ecKey:
             rv = tls13_EncodeECDHEKeyShareKEX(ss, pubKey);
             break;
         case dhKey:
@@ -140,17 +142,17 @@ tls13_EncodeKeyShareEntry(sslSocket *ss,
             PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
             break;
     }
 
     return rv;
 }
 
 PRInt32
-tls13_ClientSendKeyShareXtn(sslSocket *ss, PRBool append,
+tls13_ClientSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
                             PRUint32 maxBytes)
 {
     PRUint32 extension_length;
 
     if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3) {
         return 0;
     }
 
@@ -164,66 +166,66 @@ tls13_ClientSendKeyShareXtn(sslSocket *s
         PORT_Assert(0);
         return 0;
     }
 
     if (append) {
         SECStatus rv;
         PRCList *cursor;
 
-        rv = ssl3_AppendHandshakeNumber(ss, ssl_tls13_key_share_xtn, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_key_share_xtn, 2);
         if (rv != SECSuccess)
             goto loser;
 
         /* The extension length */
-        rv = ssl3_AppendHandshakeNumber(ss, extension_length - 4, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, extension_length - 4, 2);
         if (rv != SECSuccess)
             goto loser;
 
         /* The length of KeyShares */
-        rv = ssl3_AppendHandshakeNumber(ss, extension_length - 6, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, extension_length - 6, 2);
         if (rv != SECSuccess)
             goto loser;
 
         for (cursor = PR_NEXT_LINK(&ss->ephemeralKeyPairs);
              cursor != &ss->ephemeralKeyPairs;
              cursor = PR_NEXT_LINK(cursor)) {
             sslEphemeralKeyPair *keyPair = (sslEphemeralKeyPair *)cursor;
             rv = tls13_EncodeKeyShareEntry(ss, keyPair);
             if (rv != SECSuccess)
                 goto loser;
         }
 
-        ss->xtnData.advertised[ss->xtnData.numAdvertised++] =
+        xtnData->advertised[xtnData->numAdvertised++] =
             ssl_tls13_key_share_xtn;
     }
 
     return extension_length;
 
 loser:
     return -1;
 }
 
-SECStatus
-tls13_HandleKeyShareEntry(sslSocket *ss, SECItem *data)
+static SECStatus
+tls13_HandleKeyShareEntry(const sslSocket *ss, TLSExtensionData *xtnData, SECItem *data)
 {
     SECStatus rv;
     PRInt32 group;
     const sslNamedGroupDef *groupDef;
     TLS13KeyShareEntry *ks = NULL;
     SECItem share = { siBuffer, NULL, 0 };
 
-    group = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
+    group = ssl3_ExtConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
     if (group < 0) {
         PORT_SetError(SSL_ERROR_RX_MALFORMED_KEY_SHARE);
         goto loser;
     }
     groupDef = ssl_LookupNamedGroup(group);
-    rv = ssl3_ConsumeHandshakeVariable(ss, &share, 2, &data->data,
-                                       &data->len);
+    rv = ssl3_ExtConsumeHandshakeVariable(ss, &share, 2, &data->data,
+                                          &data->len);
     if (rv != SECSuccess) {
         goto loser;
     }
     /* If the group is disabled, continue. */
     if (!groupDef) {
         return SECSuccess;
     }
 
@@ -231,145 +233,147 @@ tls13_HandleKeyShareEntry(sslSocket *ss,
     if (!ks)
         goto loser;
     ks->group = groupDef;
 
     rv = SECITEM_CopyItem(NULL, &ks->key_exchange, &share);
     if (rv != SECSuccess)
         goto loser;
 
-    PR_APPEND_LINK(&ks->link, &ss->ssl3.hs.remoteKeyShares);
+    PR_APPEND_LINK(&ks->link, &xtnData->remoteKeyShares);
     return SECSuccess;
 
 loser:
     if (ks)
         tls13_DestroyKeyShareEntry(ks);
     return SECFailure;
 }
-
 /* Handle an incoming KeyShare extension at the client and copy to
- * |ss->ssl3.hs.remoteKeyShares| for future use. The key
+ * |xtnData->remoteKeyShares| for future use. The key
  * share is processed in tls13_HandleServerKeyShare(). */
 SECStatus
-tls13_ClientHandleKeyShareXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data)
+tls13_ClientHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data)
 {
     SECStatus rv;
+    PORT_Assert(PR_CLIST_IS_EMPTY(&xtnData->remoteKeyShares));
 
     PORT_Assert(!ss->sec.isServer);
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
         /* This can't happen because the extension processing
          * code filters out TLS 1.3 extensions when not in
          * TLS 1.3 mode. */
         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
         return SECFailure;
     }
 
     SSL_TRC(3, ("%d: SSL3[%d]: handle key_share extension",
                 SSL_GETPID(), ss->fd));
 
-    rv = tls13_HandleKeyShareEntry(ss, data);
+    rv = tls13_HandleKeyShareEntry(ss, xtnData, data);
     if (rv != SECSuccess) {
         PORT_SetError(SSL_ERROR_RX_MALFORMED_KEY_SHARE);
         return SECFailure;
     }
 
     if (data->len) {
         PORT_SetError(SSL_ERROR_RX_MALFORMED_KEY_SHARE);
         return SECFailure;
     }
 
     return SECSuccess;
 }
 
 SECStatus
-tls13_ClientHandleKeyShareXtnHrr(sslSocket *ss, PRUint16 ex_type, SECItem *data)
+tls13_ClientHandleKeyShareXtnHrr(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data)
 {
     SECStatus rv;
     PRInt32 tmp;
     const sslNamedGroupDef *group;
 
     PORT_Assert(!ss->sec.isServer);
     PORT_Assert(ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3);
 
     SSL_TRC(3, ("%d: SSL3[%d]: handle key_share extension in HRR",
                 SSL_GETPID(), ss->fd));
 
-    tmp = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
+    tmp = ssl3_ExtConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
     if (tmp < 0) {
         return SECFailure; /* error code already set */
     }
     if (data->len) {
-        (void)SSL3_SendAlert(ss, alert_fatal, decode_error);
+        ssl3_ExtSendAlert(ss, alert_fatal, decode_error);
         PORT_SetError(SSL_ERROR_RX_MALFORMED_HELLO_RETRY_REQUEST);
         return SECFailure;
     }
 
     group = ssl_LookupNamedGroup((SSLNamedGroup)tmp);
     /* If the group is not enabled, or we already have a share for the
      * requested group, abort. */
     if (!ssl_NamedGroupEnabled(ss, group) ||
-        ssl_LookupEphemeralKeyPair(ss, group)) {
-        (void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
+        ssl_HaveEphemeralKeyPair(ss, group)) {
+        ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter);
         PORT_SetError(SSL_ERROR_RX_MALFORMED_HELLO_RETRY_REQUEST);
         return SECFailure;
     }
 
-    rv = tls13_CreateKeyShare(ss, group);
+    rv = tls13_CreateKeyShare(CONST_CAST(sslSocket, ss), group);
     if (rv != SECSuccess) {
-        (void)SSL3_SendAlert(ss, alert_fatal, internal_error);
+        ssl3_ExtSendAlert(ss, alert_fatal, internal_error);
         PORT_SetError(SEC_ERROR_KEYGEN_FAIL);
         return SECFailure;
     }
 
     return SECSuccess;
 }
 
 /* Handle an incoming KeyShare extension at the server and copy to
- * |ss->ssl3.hs.remoteKeyShares| for future use. The key
+ * |xtnData->remoteKeyShares| for future use. The key
  * share is processed in tls13_HandleClientKeyShare(). */
 SECStatus
-tls13_ServerHandleKeyShareXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data)
+tls13_ServerHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data)
 {
     SECStatus rv;
     PRInt32 length;
 
     PORT_Assert(ss->sec.isServer);
+    PORT_Assert(PR_CLIST_IS_EMPTY(&xtnData->remoteKeyShares));
+
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
         return SECSuccess;
     }
 
     SSL_TRC(3, ("%d: SSL3[%d]: handle key_share extension",
                 SSL_GETPID(), ss->fd));
 
     /* Redundant length because of TLS encoding (this vector consumes
      * the entire extension.) */
-    length = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data,
-                                         &data->len);
+    length = ssl3_ExtConsumeHandshakeNumber(ss, 2, &data->data,
+                                            &data->len);
     if (length < 0)
         goto loser;
     if (length != data->len) {
         /* Check for consistency */
         PORT_SetError(SSL_ERROR_RX_MALFORMED_KEY_SHARE);
         goto loser;
     }
 
     while (data->len) {
-        rv = tls13_HandleKeyShareEntry(ss, data);
+        rv = tls13_HandleKeyShareEntry(ss, xtnData, data);
         if (rv != SECSuccess)
             goto loser;
     }
     return SECSuccess;
 
 loser:
-    tls13_DestroyKeyShares(&ss->ssl3.hs.remoteKeyShares);
+    tls13_DestroyKeyShares(&xtnData->remoteKeyShares);
     return SECFailure;
 }
 
 PRInt32
-tls13_ServerSendKeyShareXtn(sslSocket *ss, PRBool append,
+tls13_ServerSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
                             PRUint32 maxBytes)
 {
     PRUint32 extension_length;
     PRUint32 entry_length;
     SECStatus rv;
     sslEphemeralKeyPair *keyPair;
 
     /* There should be exactly one key share. */
@@ -382,21 +386,21 @@ tls13_ServerSendKeyShareXtn(sslSocket *s
     entry_length = tls13_SizeOfKeyShareEntry(keyPair->keys->pubKey);
     extension_length = 2 + 2 + entry_length; /* Type + length + entry_length */
     if (maxBytes < extension_length) {
         PORT_Assert(0);
         return 0;
     }
 
     if (append) {
-        rv = ssl3_AppendHandshakeNumber(ss, ssl_tls13_key_share_xtn, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_key_share_xtn, 2);
         if (rv != SECSuccess)
             goto loser;
 
-        rv = ssl3_AppendHandshakeNumber(ss, entry_length, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, entry_length, 2);
         if (rv != SECSuccess)
             goto loser;
 
         rv = tls13_EncodeKeyShareEntry(ss, keyPair);
         if (rv != SECSuccess)
             goto loser;
     }
 
@@ -422,17 +426,17 @@ loser:
  *               uint16 selected_identity;
  *       }
  *   } PreSharedKeyExtension;
  *
  * Presently the only way to get a PSK is by resumption, so this is
  * really a ticket label and there wll be at most one.
  */
 PRInt32
-tls13_ClientSendPreSharedKeyXtn(sslSocket *ss,
+tls13_ClientSendPreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                 PRBool append,
                                 PRUint32 maxBytes)
 {
     PRInt32 extension_length;
     static const PRUint8 auth_modes[] = { tls13_psk_auth };
     static const unsigned long auth_modes_len = sizeof(auth_modes);
     static const PRUint8 ke_modes[] = { tls13_psk_dh_ke };
     static const unsigned long ke_modes_len = sizeof(ke_modes);
@@ -455,214 +459,215 @@ tls13_ClientSendPreSharedKeyXtn(sslSocke
     if (maxBytes < (PRUint32)extension_length) {
         PORT_Assert(0);
         return 0;
     }
 
     if (append) {
         SECStatus rv;
         /* extension_type */
-        rv = ssl3_AppendHandshakeNumber(ss, ssl_tls13_pre_shared_key_xtn, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_pre_shared_key_xtn, 2);
         if (rv != SECSuccess)
             goto loser;
-        rv = ssl3_AppendHandshakeNumber(ss, extension_length - 4, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, extension_length - 4, 2);
         if (rv != SECSuccess)
             goto loser;
-        rv = ssl3_AppendHandshakeNumber(ss, extension_length - 6, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, extension_length - 6, 2);
         if (rv != SECSuccess)
             goto loser;
-        rv = ssl3_AppendHandshakeVariable(ss, ke_modes, ke_modes_len, 1);
+        rv = ssl3_ExtAppendHandshakeVariable(ss, ke_modes, ke_modes_len, 1);
         if (rv != SECSuccess)
             goto loser;
-        rv = ssl3_AppendHandshakeVariable(ss, auth_modes, auth_modes_len, 1);
+        rv = ssl3_ExtAppendHandshakeVariable(ss, auth_modes, auth_modes_len, 1);
         if (rv != SECSuccess)
             goto loser;
-        rv = ssl3_AppendHandshakeVariable(ss, session_ticket->ticket.data,
-                                          session_ticket->ticket.len, 2);
+        rv = ssl3_ExtAppendHandshakeVariable(ss, session_ticket->ticket.data,
+                                             session_ticket->ticket.len, 2);
         PRINT_BUF(50, (ss, "Sending PreSharedKey value",
                        session_ticket->ticket.data,
                        session_ticket->ticket.len));
-        ss->xtnData.sentSessionTicketInClientHello = PR_TRUE;
+        xtnData->sentSessionTicketInClientHello = PR_TRUE;
         if (rv != SECSuccess)
             goto loser;
 
-        ss->xtnData.advertised[ss->xtnData.numAdvertised++] =
+        xtnData->advertised[xtnData->numAdvertised++] =
             ssl_tls13_pre_shared_key_xtn;
     }
     return extension_length;
 
 loser:
-    ss->xtnData.ticketTimestampVerified = PR_FALSE;
+    xtnData->ticketTimestampVerified = PR_FALSE;
     return -1;
 }
 
 /* Handle a TLS 1.3 PreSharedKey Extension. We only accept PSKs
  * that contain session tickets. */
 SECStatus
-tls13_ServerHandlePreSharedKeyXtn(sslSocket *ss, PRUint16 ex_type,
+tls13_ServerHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
                                   SECItem *data)
 {
     PRInt32 len;
     PRBool first = PR_TRUE;
     SECStatus rv;
 
     SSL_TRC(3, ("%d: SSL3[%d]: handle pre_shared_key extension",
                 SSL_GETPID(), ss->fd));
 
     /* If we are doing < TLS 1.3, then ignore this. */
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
         return SECSuccess;
     }
 
-    len = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
+    len = ssl3_ExtConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
     if (len < 0)
         return SECFailure;
 
     if (len != data->len) {
         PORT_SetError(SSL_ERROR_MALFORMED_PRE_SHARED_KEY);
         return SECFailure;
     }
 
     while (data->len) {
         SECItem label;
 
         /* IMPORTANT: We aren't copying these values, just setting pointers.
          * They will only be valid as long as the ClientHello is in memory. */
-        rv = ssl3_ConsumeHandshakeVariable(ss, &ss->xtnData.psk_ke_modes, 1,
-                                           &data->data, &data->len);
+        rv = ssl3_ExtConsumeHandshakeVariable(ss, &xtnData->psk_ke_modes, 1,
+                                              &data->data, &data->len);
         if (rv != SECSuccess)
             return rv;
-        if (!ss->xtnData.psk_ke_modes.len) {
+        if (!xtnData->psk_ke_modes.len) {
             goto alert_loser;
         }
-        rv = ssl3_ConsumeHandshakeVariable(ss, &ss->xtnData.psk_auth_modes, 1,
-                                           &data->data, &data->len);
+        rv = ssl3_ExtConsumeHandshakeVariable(ss, &xtnData->psk_auth_modes, 1,
+                                              &data->data, &data->len);
         if (rv != SECSuccess)
             return rv;
-        if (!ss->xtnData.psk_auth_modes.len) {
+        if (!xtnData->psk_auth_modes.len) {
             goto alert_loser;
         }
-        rv = ssl3_ConsumeHandshakeVariable(ss, &label, 2,
-                                           &data->data, &data->len);
+        rv = ssl3_ExtConsumeHandshakeVariable(ss, &label, 2,
+                                              &data->data, &data->len);
         if (rv != SECSuccess)
             return rv;
         if (!label.len) {
             goto alert_loser;
         }
         if (first) {
             first = PR_FALSE; /* Continue to read through the extension to check
                                * the format. */
 
             PRINT_BUF(50, (ss, "Handling PreSharedKey value",
                            label.data, label.len));
-            rv = ssl3_ProcessSessionTicketCommon(ss, &label);
+            rv = ssl3_ProcessSessionTicketCommon(CONST_CAST(sslSocket, ss),
+                                                 &label);
             /* This only happens if we have an internal error, not
              * a malformed ticket. Bogus tickets just don't resume
              * and return SECSuccess. */
             if (rv != SECSuccess)
                 return rv;
         }
     }
 
     /* Keep track of negotiated extensions. Note that this does not
      * mean we are resuming. */
-    ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
+    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
 
     return SECSuccess;
 
 alert_loser:
-    (void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
+    ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter);
     PORT_SetError(SSL_ERROR_MALFORMED_PRE_SHARED_KEY);
     return SECFailure;
 }
 
 PRInt32
-tls13_ServerSendPreSharedKeyXtn(sslSocket *ss,
+tls13_ServerSendPreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                 PRBool append,
                                 PRUint32 maxBytes)
 {
     PRInt32 extension_length =
         2 + 2 + 2; /* type + len + index */
     SECStatus rv;
 
     if (maxBytes < (PRUint32)extension_length) {
         PORT_Assert(0);
         return 0;
     }
 
     if (append) {
-        rv = ssl3_AppendHandshakeNumber(ss, ssl_tls13_pre_shared_key_xtn, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_pre_shared_key_xtn, 2);
         if (rv != SECSuccess)
             return -1;
 
-        rv = ssl3_AppendHandshakeNumber(ss, 2, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, 2, 2);
         if (rv != SECSuccess)
             return -1;
 
         /* We only process the first session ticket the client sends,
          * so the index is always 0. */
-        rv = ssl3_AppendHandshakeNumber(ss, 0, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2);
         if (rv != SECSuccess)
             return -1;
     }
 
     return extension_length;
 }
 
 /* Handle a TLS 1.3 PreSharedKey Extension. We only accept PSKs
  * that contain session tickets. */
 SECStatus
-tls13_ClientHandlePreSharedKeyXtn(sslSocket *ss, PRUint16 ex_type,
+tls13_ClientHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
                                   SECItem *data)
 {
     PRInt32 index;
 
     SSL_TRC(3, ("%d: SSL3[%d]: handle pre_shared_key extension",
                 SSL_GETPID(), ss->fd));
 
     /* If we are doing < TLS 1.3, then ignore this. */
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
         return SECSuccess;
     }
 
-    index = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
+    index = ssl3_ExtConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
     if (index < 0)
         return SECFailure;
 
     /* This should be the end of the extension. */
     if (data->len) {
         PORT_SetError(SSL_ERROR_MALFORMED_PRE_SHARED_KEY);
         return SECFailure;
     }
 
     /* We only sent one PSK label so index must be equal to 0 */
     if (index) {
         PORT_SetError(SSL_ERROR_MALFORMED_PRE_SHARED_KEY);
         return SECFailure;
     }
 
     /* Keep track of negotiated extensions. */
-    ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
+    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
 
     return SECSuccess;
 }
 
 /*
  *  struct {
  *       select (Role) {
  *           case client:
  *               uint32 obfuscated_ticket_age;
  *
  *           case server:
  *              struct {};
  *       }
  *   } EarlyDataIndication;
  */
 PRInt32
-tls13_ClientSendEarlyDataXtn(sslSocket *ss,
+tls13_ClientSendEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                              PRBool append,
                              PRUint32 maxBytes)
 {
     PRInt32 extension_length;
     SECStatus rv;
     NewSessionTicket *session_ticket;
 
     if (!tls13_ClientAllow0Rtt(ss, ss->sec.ci.sid))
@@ -675,117 +680,104 @@ tls13_ClientSendEarlyDataXtn(sslSocket *
         PORT_Assert(0);
         return 0;
     }
 
     session_ticket = &ss->sec.ci.sid->u.ssl3.locked.sessionTicket;
     if (append) {
         PRUint32 age;
 
-        rv = ssl3_AppendHandshakeNumber(ss, ssl_tls13_early_data_xtn, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_early_data_xtn, 2);
         if (rv != SECSuccess)
             return -1;
 
-        rv = ssl3_AppendHandshakeNumber(ss, extension_length - 4, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, extension_length - 4, 2);
         if (rv != SECSuccess)
             return -1;
 
         /* Obfuscated age. */
         age = ssl_Time() - session_ticket->received_timestamp;
         age += session_ticket->ticket_age_add;
 
-        rv = ssl3_AppendHandshakeNumber(ss, age, 4);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, age, 4);
         if (rv != SECSuccess)
             return -1;
     }
 
-    ss->ssl3.hs.zeroRttState = ssl_0rtt_sent;
-    ss->xtnData.advertised[ss->xtnData.numAdvertised++] =
+    xtnData->advertised[xtnData->numAdvertised++] =
         ssl_tls13_early_data_xtn;
 
     return extension_length;
 }
 
 SECStatus
-tls13_ServerHandleEarlyDataXtn(sslSocket *ss, PRUint16 ex_type,
+tls13_ServerHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
                                SECItem *data)
 {
     PRUint32 obfuscated_ticket_age;
     SECStatus rv;
 
     SSL_TRC(3, ("%d: TLS13[%d]: handle early_data extension",
                 SSL_GETPID(), ss->fd));
 
     /* If we are doing < TLS 1.3, then ignore this. */
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
         return SECSuccess;
     }
 
     /* Obfuscated ticket age. Ignore. Bug 1295163. */
-    rv = ssl3_ConsumeHandshake(ss, &obfuscated_ticket_age, 4,
-                               &data->data, &data->len);
+    rv = ssl3_ExtConsumeHandshake(ss, &obfuscated_ticket_age, 4,
+                                  &data->data, &data->len);
     if (rv != SECSuccess) {
         return SECFailure;
     }
 
     if (data->len) {
         PORT_SetError(SSL_ERROR_MALFORMED_EARLY_DATA);
         return SECFailure;
     }
 
-    if (IS_DTLS(ss)) {
-        /* Save the null spec, which we should be currently reading.  We will
-         * use this when 0-RTT sending is over. */
-        ssl_GetSpecReadLock(ss);
-        ss->ssl3.hs.nullSpec = ss->ssl3.crSpec;
-        tls13_CipherSpecAddRef(ss->ssl3.hs.nullSpec);
-        PORT_Assert(ss->ssl3.hs.nullSpec->cipher_def->cipher == cipher_null);
-        ssl_ReleaseSpecReadLock(ss);
-    }
-
-    ss->ssl3.hs.zeroRttState = ssl_0rtt_sent;
-
-    ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
+    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
 
     return SECSuccess;
 }
 
 /* This is only registered if we are sending it. */
-SECStatus
-tls13_ServerSendEarlyDataXtn(sslSocket *ss,
+PRInt32
+tls13_ServerSendEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                              PRBool append,
                              PRUint32 maxBytes)
 {
     SSL_TRC(3, ("%d: TLS13[%d]: send early_data extension",
                 SSL_GETPID(), ss->fd));
 
     PORT_Assert(ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted);
     if (maxBytes < 4) {
         PORT_Assert(0);
         return 0;
     }
 
     if (append) {
         SECStatus rv;
 
-        rv = ssl3_AppendHandshakeNumber(ss, ssl_tls13_early_data_xtn, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_early_data_xtn, 2);
         if (rv != SECSuccess)
             return -1;
 
-        rv = ssl3_AppendHandshakeNumber(ss, 0, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2);
         if (rv != SECSuccess)
             return -1;
     }
 
     return 4;
 }
 
 /* This will only be called if we also offered the extension. */
 SECStatus
-tls13_ClientHandleEarlyDataXtn(sslSocket *ss, PRUint16 ex_type,
+tls13_ClientHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
                                SECItem *data)
 {
     SSL_TRC(3, ("%d: TLS13[%d]: handle early_data extension",
                 SSL_GETPID(), ss->fd));
 
     /* If we are doing < TLS 1.3, then ignore this. */
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
         PORT_SetError(SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION);
@@ -793,86 +785,85 @@ tls13_ClientHandleEarlyDataXtn(sslSocket
     }
 
     if (data->len) {
         PORT_SetError(SSL_ERROR_MALFORMED_EARLY_DATA);
         return SECFailure;
     }
 
     /* Keep track of negotiated extensions. */
-    ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
-    ss->ssl3.hs.zeroRttState = ssl_0rtt_accepted;
+    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
 
     return SECSuccess;
 }
 
 SECStatus
-tls13_ClientHandleTicketEarlyDataInfoXtn(sslSocket *ss, PRUint16 ex_type,
+tls13_ClientHandleTicketEarlyDataInfoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
                                          SECItem *data)
 {
     PRUint32 utmp;
     SECStatus rv;
 
     SSL_TRC(3, ("%d: TLS13[%d]: handle early_data_info extension",
                 SSL_GETPID(), ss->fd));
 
     /* If we are doing < TLS 1.3, then ignore this. */
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
         PORT_SetError(SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION);
         return SECFailure;
     }
 
-    rv = ssl3_ConsumeHandshake(ss, &utmp, sizeof(utmp),
-                               &data->data, &data->len);
+    rv = ssl3_ExtConsumeHandshake(ss, &utmp, sizeof(utmp),
+                                  &data->data, &data->len);
     if (rv != SECSuccess) {
         PORT_SetError(SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET);
         return SECFailure;
     }
     if (data->len) {
         PORT_SetError(SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET);
         return SECFailure;
     }
 
-    ss->xtnData.ticket_age_add_found = PR_TRUE;
-    ss->xtnData.ticket_age_add = PR_ntohl(utmp);
+    xtnData->ticket_age_add_found = PR_TRUE;
+    xtnData->ticket_age_add = PR_ntohl(utmp);
 
     return SECSuccess;
 }
 
 /* This is only registered if we are sending it. */
-SECStatus
-tls13_ServerSendSigAlgsXtn(sslSocket *ss,
+PRInt32
+tls13_ServerSendSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                            PRBool append,
                            PRUint32 maxBytes)
 {
     SSL_TRC(3, ("%d: TLS13[%d]: send signature_algorithms extension",
                 SSL_GETPID(), ss->fd));
 
     if (maxBytes < 4) {
         PORT_Assert(0);
     }
 
     if (append) {
         SECStatus rv;
 
-        rv = ssl3_AppendHandshakeNumber(ss, ssl_signature_algorithms_xtn, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_signature_algorithms_xtn, 2);
         if (rv != SECSuccess)
             return -1;
 
-        rv = ssl3_AppendHandshakeNumber(ss, 0, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2);
         if (rv != SECSuccess)
             return -1;
     }
 
     return 4;
 }
 
 /* This will only be called if we also offered the extension. */
 SECStatus
-tls13_ClientHandleSigAlgsXtn(sslSocket *ss, PRUint16 ex_type,
+tls13_ClientHandleSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
                              SECItem *data)
 {
     SSL_TRC(3, ("%d: TLS13[%d]: handle signature_algorithms extension",
                 SSL_GETPID(), ss->fd));
 
     /* If we are doing < TLS 1.3, then ignore this. */
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
         PORT_SetError(SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION);
@@ -880,28 +871,28 @@ tls13_ClientHandleSigAlgsXtn(sslSocket *
     }
 
     if (data->len != 0) {
         PORT_SetError(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
         return SECFailure;
     }
 
     /* Keep track of negotiated extensions. */
-    ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
+    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
 
     return SECSuccess;
 }
 
 /*
  *     struct {
  *          ProtocolVersion versions<2..254>;
  *     } SupportedVersions;
  */
 PRInt32
-tls13_ClientSendSupportedVersionsXtn(sslSocket *ss, PRBool append,
+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;
@@ -916,72 +907,73 @@ tls13_ClientSendSupportedVersionsXtn(ssl
                      2 * (ss->vrange.max - ss->vrange.min + 1);
 
     if (maxBytes < (PRUint32)extensions_len) {
         PORT_Assert(0);
         return 0;
     }
 
     if (append) {
-        rv = ssl3_AppendHandshakeNumber(ss, ssl_tls13_supported_versions_xtn, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_supported_versions_xtn, 2);
         if (rv != SECSuccess)
             return -1;
 
-        rv = ssl3_AppendHandshakeNumber(ss, extensions_len - 4, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, extensions_len - 4, 2);
         if (rv != SECSuccess)
             return -1;
 
-        rv = ssl3_AppendHandshakeNumber(ss, extensions_len - 5, 1);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, extensions_len - 5, 1);
         if (rv != SECSuccess)
             return -1;
 
         for (version = ss->vrange.max; version >= ss->vrange.min; --version) {
-            rv = ssl3_AppendHandshakeNumber(
+            rv = ssl3_ExtAppendHandshakeNumber(
                 ss, tls13_EncodeDraftVersion(version), 2);
             if (rv != SECSuccess)
                 return -1;
         }
     }
 
     return extensions_len;
 }
 
 /*
  *    struct {
  *        opaque cookie<1..2^16-1>;
  *    } Cookie;
  */
 SECStatus
-tls13_ClientHandleHrrCookie(sslSocket *ss, PRUint16 ex_type, SECItem *data)
+tls13_ClientHandleHrrCookie(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data)
 {
     SECStatus rv;
 
     SSL_TRC(3, ("%d: TLS13[%d]: handle cookie extension",
                 SSL_GETPID(), ss->fd));
 
     PORT_Assert(ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3);
 
     /* IMPORTANT: this is only valid while the HelloRetryRequest is still valid. */
-    rv = ssl3_ConsumeHandshakeVariable(ss, &ss->ssl3.hs.cookie, 2,
-                                       &data->data, &data->len);
+    rv = ssl3_ExtConsumeHandshakeVariable(
+        ss, &CONST_CAST(sslSocket, ss)->ssl3.hs.cookie, 2,
+        &data->data, &data->len);
     if (rv != SECSuccess) {
         PORT_SetError(SSL_ERROR_RX_MALFORMED_HELLO_RETRY_REQUEST);
         return SECFailure;
     }
     if (!ss->ssl3.hs.cookie.len || data->len) {
-        (void)SSL3_SendAlert(ss, alert_fatal, decode_error);
+        ssl3_ExtSendAlert(ss, alert_fatal, decode_error);
         PORT_SetError(SSL_ERROR_RX_MALFORMED_HELLO_RETRY_REQUEST);
         return SECFailure;
     }
 
     return SECSuccess;
 }
 
 PRInt32
-tls13_ClientSendHrrCookieXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes)
+tls13_ClientSendHrrCookieXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes)
 {
     PRInt32 extension_len;
 
     if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3 ||
         !ss->ssl3.hs.cookie.len) {
         return 0;
     }
 
@@ -991,23 +983,23 @@ tls13_ClientSendHrrCookieXtn(sslSocket *
     extension_len = 2 + 2 + 2 + ss->ssl3.hs.cookie.len;
 
     if (maxBytes < (PRUint32)extension_len) {
         PORT_Assert(0);
         return 0;
     }
 
     if (append) {
-        SECStatus rv = ssl3_AppendHandshakeNumber(ss, ssl_tls13_cookie_xtn, 2);
+        SECStatus rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_cookie_xtn, 2);
         if (rv != SECSuccess)
             return -1;
 
-        rv = ssl3_AppendHandshakeNumber(ss, extension_len - 4, 2);
+        rv = ssl3_ExtAppendHandshakeNumber(ss, extension_len - 4, 2);
         if (rv != SECSuccess)
             return -1;
 
-        rv = ssl3_AppendHandshakeVariable(ss, ss->ssl3.hs.cookie.data,
-                                          ss->ssl3.hs.cookie.len, 2);
+        rv = ssl3_ExtAppendHandshakeVariable(ss, ss->ssl3.hs.cookie.data,
+                                             ss->ssl3.hs.cookie.len, 2);
         if (rv != SECSuccess)
             return -1;
     }
     return extension_len;
 }
--- a/security/nss/lib/ssl/tls13exthandle.h
+++ b/security/nss/lib/ssl/tls13exthandle.h
@@ -4,51 +4,64 @@
  *
  * 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 __tls13exthandle_h_
 #define __tls13exthandle_h_
 
-PRInt32 tls13_ServerSendStatusRequestXtn(sslSocket *ss,
+PRInt32 tls13_ServerSendStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                          PRBool append, PRUint32 maxBytes);
-PRInt32 tls13_ClientSendKeyShareXtn(sslSocket *ss, PRBool append,
+PRInt32 tls13_ClientSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
                                     PRUint32 maxBytes);
-SECStatus tls13_ClientHandleKeyShareXtn(sslSocket *ss,
+SECStatus tls13_ClientHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                         PRUint16 ex_type,
                                         SECItem *data);
-SECStatus tls13_ClientHandleKeyShareXtnHrr(sslSocket *ss,
+SECStatus tls13_ClientHandleKeyShareXtnHrr(const sslSocket *ss, TLSExtensionData *xtnData,
                                            PRUint16 ex_type,
                                            SECItem *data);
-SECStatus tls13_ServerHandleKeyShareXtn(sslSocket *ss,
+SECStatus tls13_ServerHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                         PRUint16 ex_type,
                                         SECItem *data);
-PRInt32 tls13_ClientSendPreSharedKeyXtn(sslSocket *ss, PRBool append,
+PRInt32 tls13_ServerSendKeyShareXtn(const sslSocket *ss,
+                                    TLSExtensionData *xtnData,
+                                    PRBool append,
+                                    PRUint32 maxBytes);
+PRInt32 tls13_ClientSendPreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
                                         PRUint32 maxBytes);
-SECStatus tls13_ServerHandlePreSharedKeyXtn(sslSocket *ss,
+SECStatus tls13_ServerHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                                            PRUint16 ex_type,
+                                            SECItem *data);
+SECStatus tls13_ClientHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                             PRUint16 ex_type,
                                             SECItem *data);
-SECStatus tls13_ClientHandlePreSharedKeyXtn(sslSocket *ss,
-                                            PRUint16 ex_type,
-                                            SECItem *data);
-PRInt32 tls13_ClientSendEarlyDataXtn(sslSocket *ss,
+PRInt32 tls13_ServerSendPreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                                        PRBool append,
+                                        PRUint32 maxBytes);
+PRInt32 tls13_ClientSendEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                                     PRBool append,
+                                     PRUint32 maxBytes);
+SECStatus tls13_ServerHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
+                                         SECItem *data);
+SECStatus tls13_ClientHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
+                                         SECItem *data);
+PRInt32 tls13_ServerSendEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                      PRBool append,
                                      PRUint32 maxBytes);
-SECStatus tls13_ServerHandleEarlyDataXtn(sslSocket *ss, PRUint16 ex_type,
-                                         SECItem *data);
-SECStatus tls13_ClientHandleEarlyDataXtn(sslSocket *ss, PRUint16 ex_type,
-                                         SECItem *data);
 SECStatus tls13_ClientHandleTicketEarlyDataInfoXtn(
-    sslSocket *ss, PRUint16 ex_type,
+    const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
     SECItem *data);
-SECStatus tls13_ClientHandleSigAlgsXtn(sslSocket *ss, PRUint16 ex_type,
+SECStatus tls13_ClientHandleSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
                                        SECItem *data);
-PRInt32 tls13_ClientSendSupportedVersionsXtn(sslSocket *ss,
+PRInt32 tls13_ServerSendSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                                   PRBool append,
+                                   PRUint32 maxBytes);
+PRInt32 tls13_ClientSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                              PRBool append,
                                              PRUint32 maxBytes);
-SECStatus tls13_ClientHandleHrrCookie(sslSocket *ss, PRUint16 ex_type,
+SECStatus tls13_ClientHandleHrrCookie(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
                                       SECItem *data);
-PRInt32 tls13_ClientSendHrrCookieXtn(sslSocket *ss,
+PRInt32 tls13_ClientSendHrrCookieXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                      PRBool append,
                                      PRUint32 maxBytes);
 
 #endif