Bug 1305970 - land NSS 5d2424d699a0, r=me
authorFranziskus Kiefer <franziskuskiefer@gmail.com>
Fri, 11 Nov 2016 14:32:54 +0100
changeset 322178 3f1dcd04bc47823809e7776ca852977c3ed2881d
parent 322177 bfd5335fa635ec73c18dde685db8385f1ef113c3
child 322179 3f11622c5a784b8789c220e4c10345d36dfc74f4
push id21
push usermaklebus@msu.edu
push dateThu, 01 Dec 2016 06:22:08 +0000
reviewersme
bugs1305970
milestone52.0a1
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