Bug 1368980 - Refactor extension senders, r=ekr,ttaubert NSS_TLS13_DRAFT19_BRANCH
authorMartin Thomson <martin.thomson@gmail.com>
Wed, 31 May 2017 18:04:10 +1000
branchNSS_TLS13_DRAFT19_BRANCH
changeset 13456 c50689be15fc86fd1461f09cefd02c6c88a6f333
parent 13453 487757061622e440078e0b90cd46ce7d1611574e
child 13457 2d24546baff061a8c73e06e683678b5dcae7a143
push id2267
push usermartin.thomson@gmail.com
push dateWed, 12 Jul 2017 23:34:11 +0000
reviewersekr, ttaubert
bugs1368980
Bug 1368980 - Refactor extension senders, r=ekr,ttaubert
fuzz/tls_mutators.cc
gtests/ssl_gtest/libssl_internals.c
gtests/ssl_gtest/libssl_internals.h
gtests/ssl_gtest/ssl_loopback_unittest.cc
gtests/ssl_gtest/tls_agent.cc
gtests/ssl_gtest/tls_agent.h
lib/ssl/dtlscon.c
lib/ssl/manifest.mn
lib/ssl/selfencrypt.c
lib/ssl/ssl.gyp
lib/ssl/ssl3con.c
lib/ssl/ssl3ecc.c
lib/ssl/ssl3encode.c
lib/ssl/ssl3encode.h
lib/ssl/ssl3ext.c
lib/ssl/ssl3ext.h
lib/ssl/ssl3exthandle.c
lib/ssl/ssl3exthandle.h
lib/ssl/ssl3gthr.c
lib/ssl/ssl3prot.h
lib/ssl/sslencode.c
lib/ssl/sslencode.h
lib/ssl/sslimpl.h
lib/ssl/sslsecur.c
lib/ssl/sslsock.c
lib/ssl/sslt.h
lib/ssl/tls13con.c
lib/ssl/tls13con.h
lib/ssl/tls13exthandle.c
lib/ssl/tls13exthandle.h
--- a/fuzz/tls_mutators.cc
+++ b/fuzz/tls_mutators.cc
@@ -1,17 +1,19 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "shared.h"
 #include "tls_parser.h"
 
 #include "ssl.h"
+extern "C" {
 #include "sslimpl.h"
+}
 
 using namespace nss_test;
 
 // Number of additional bytes in the TLS header.
 // Used to properly skip DTLS seqnums.
 static size_t gExtraHeaderBytes = 0;
 
 // Helper class to simplify TLS record manipulation.
--- a/gtests/ssl_gtest/libssl_internals.c
+++ b/gtests/ssl_gtest/libssl_internals.c
@@ -346,40 +346,16 @@ SSLCipherAlgorithm SSLInt_CipherSpecToAl
                                                 ssl3CipherSpec *spec) {
   return spec->cipher_def->calg;
 }
 
 unsigned char *SSLInt_CipherSpecToIv(PRBool isServer, ssl3CipherSpec *spec) {
   return GetKeyingMaterial(isServer, spec)->write_iv;
 }
 
-SECStatus SSLInt_EnableShortHeaders(PRFileDesc *fd) {
-  sslSocket *ss;
-
-  ss = ssl_FindSocket(fd);
-  if (!ss) {
-    return SECFailure;
-  }
-
-  ss->opt.enableShortHeaders = PR_TRUE;
-  return SECSuccess;
-}
-
-SECStatus SSLInt_UsingShortHeaders(PRFileDesc *fd, PRBool *result) {
-  sslSocket *ss;
-
-  ss = ssl_FindSocket(fd);
-  if (!ss) {
-    return SECFailure;
-  }
-
-  *result = ss->ssl3.hs.shortHeaders;
-  return SECSuccess;
-}
-
 void SSLInt_SetTicketLifetime(uint32_t lifetime) {
   ssl_ticket_lifetime = lifetime;
 }
 
 void SSLInt_SetMaxEarlyDataSize(uint32_t size) {
   ssl_max_early_data_size = size;
 }
 
--- a/gtests/ssl_gtest/libssl_internals.h
+++ b/gtests/ssl_gtest/libssl_internals.h
@@ -43,15 +43,13 @@ SSLKEAType SSLInt_GetKEAType(SSLNamedGro
 
 SECStatus SSLInt_SetCipherSpecChangeFunc(PRFileDesc *fd,
                                          sslCipherSpecChangedFunc func,
                                          void *arg);
 PK11SymKey *SSLInt_CipherSpecToKey(PRBool isServer, ssl3CipherSpec *spec);
 SSLCipherAlgorithm SSLInt_CipherSpecToAlgorithm(PRBool isServer,
                                                 ssl3CipherSpec *spec);
 unsigned char *SSLInt_CipherSpecToIv(PRBool isServer, ssl3CipherSpec *spec);
-SECStatus SSLInt_EnableShortHeaders(PRFileDesc *fd);
-SECStatus SSLInt_UsingShortHeaders(PRFileDesc *fd, PRBool *result);
 void SSLInt_SetTicketLifetime(uint32_t lifetime);
 void SSLInt_SetMaxEarlyDataSize(uint32_t size);
 SECStatus SSLInt_SetSocketMaxEarlyDataSize(PRFileDesc *fd, uint32_t size);
 
 #endif  // ndef libssl_internals_h_
--- a/gtests/ssl_gtest/ssl_loopback_unittest.cc
+++ b/gtests/ssl_gtest/ssl_loopback_unittest.cc
@@ -310,24 +310,16 @@ TEST_F(TlsConnectStreamTls13, Tls13Faile
   server_->StartConnect();
   client_->Handshake();
   server_->Handshake();  // Send first flight.
   client_->adapter()->CloseWrites();
   client_->Handshake();  // This will get an error, but shouldn't crash.
   client_->CheckErrorCode(SSL_ERROR_SOCKET_WRITE_FAILURE);
 }
 
-TEST_F(TlsConnectStreamTls13, NegotiateShortHeaders) {
-  client_->SetShortHeadersEnabled();
-  server_->SetShortHeadersEnabled();
-  client_->ExpectShortHeaders();
-  server_->ExpectShortHeaders();
-  Connect();
-}
-
 INSTANTIATE_TEST_CASE_P(
     GenericStream, TlsConnectGeneric,
     ::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
                        TlsConnectTestBase::kTlsVAll));
 INSTANTIATE_TEST_CASE_P(
     GenericDatagram, TlsConnectGeneric,
     ::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
                        TlsConnectTestBase::kTlsV11Plus));
--- a/gtests/ssl_gtest/tls_agent.cc
+++ b/gtests/ssl_gtest/tls_agent.cc
@@ -68,17 +68,16 @@ TlsAgent::TlsAgent(const std::string& na
       handshake_callback_called_(false),
       error_code_(0),
       send_ctr_(0),
       recv_ctr_(0),
       expect_readwrite_error_(false),
       handshake_callback_(),
       auth_certificate_callback_(),
       sni_callback_(),
-      expect_short_headers_(false),
       skip_version_checks_(false) {
   memset(&info_, 0, sizeof(info_));
   memset(&csinfo_, 0, sizeof(csinfo_));
   SECStatus rv = SSL_VersionRangeGetDefault(variant_, &vrange_);
   EXPECT_EQ(SECSuccess, rv);
 }
 
 TlsAgent::~TlsAgent() {
@@ -402,23 +401,16 @@ void TlsAgent::Set0RttEnabled(bool en) {
 void TlsAgent::SetFallbackSCSVEnabled(bool en) {
   EXPECT_TRUE(role_ == CLIENT && EnsureTlsSetup());
 
   SECStatus rv = SSL_OptionSet(ssl_fd(), SSL_ENABLE_FALLBACK_SCSV,
                                en ? PR_TRUE : PR_FALSE);
   EXPECT_EQ(SECSuccess, rv);
 }
 
-void TlsAgent::SetShortHeadersEnabled() {
-  EXPECT_TRUE(EnsureTlsSetup());
-
-  SECStatus rv = SSLInt_EnableShortHeaders(ssl_fd());
-  EXPECT_EQ(SECSuccess, rv);
-}
-
 void TlsAgent::SetVersionRange(uint16_t minver, uint16_t maxver) {
   vrange_.min = minver;
   vrange_.max = maxver;
 
   if (ssl_fd()) {
     SECStatus rv = SSL_VersionRangeSet(ssl_fd(), &vrange_);
     EXPECT_EQ(SECSuccess, rv);
   }
@@ -432,18 +424,16 @@ void TlsAgent::GetVersionRange(uint16_t*
 void TlsAgent::SetExpectedVersion(uint16_t version) {
   expected_version_ = version;
 }
 
 void TlsAgent::SetServerKeyBits(uint16_t bits) { server_key_bits_ = bits; }
 
 void TlsAgent::ExpectReadWriteError() { expect_readwrite_error_ = true; }
 
-void TlsAgent::ExpectShortHeaders() { expect_short_headers_ = true; }
-
 void TlsAgent::SkipVersionChecks() { skip_version_checks_ = true; }
 
 void TlsAgent::SetSignatureSchemes(const SSLSignatureScheme* schemes,
                                    size_t count) {
   EXPECT_TRUE(EnsureTlsSetup());
   EXPECT_LE(count, SSL_SignatureMaxCount());
   EXPECT_EQ(SECSuccess,
             SSL_SignatureSchemePrefSet(ssl_fd(), schemes,
@@ -759,20 +749,16 @@ void TlsAgent::Connected() {
       expected = info_.earlyDataAccepted ? 4 : 3;
     }
     EXPECT_EQ(expected, cipherSuites);
     if (expected != cipherSuites) {
       SSLInt_PrintTls13CipherSpecs(ssl_fd());
     }
   }
 
-  PRBool short_headers;
-  rv = SSLInt_UsingShortHeaders(ssl_fd(), &short_headers);
-  EXPECT_EQ(SECSuccess, rv);
-  EXPECT_EQ((PRBool)expect_short_headers_, short_headers);
   SetState(STATE_CONNECTED);
 }
 
 void TlsAgent::EnableExtendedMasterSecret() {
   ASSERT_TRUE(EnsureTlsSetup());
 
   SECStatus rv =
       SSL_OptionSet(ssl_fd(), SSL_ENABLE_EXTENDED_MASTER_SECRET, PR_TRUE);
--- a/gtests/ssl_gtest/tls_agent.h
+++ b/gtests/ssl_gtest/tls_agent.h
@@ -121,27 +121,25 @@ class TlsAgent : public PollTarget {
   void SetupClientAuth();
   void RequestClientAuth(bool requireAuth);
 
   void ConfigureSessionCache(SessionResumptionMode mode);
   void SetSessionTicketsEnabled(bool en);
   void SetSessionCacheEnabled(bool en);
   void Set0RttEnabled(bool en);
   void SetFallbackSCSVEnabled(bool en);
-  void SetShortHeadersEnabled();
   void SetVersionRange(uint16_t minver, uint16_t maxver);
   void GetVersionRange(uint16_t* minver, uint16_t* maxver);
   void CheckPreliminaryInfo();
   void ResetPreliminaryInfo();
   void SetExpectedVersion(uint16_t version);
   void SetServerKeyBits(uint16_t bits);
   void ExpectReadWriteError();
   void EnableFalseStart();
   void ExpectResumption();
-  void ExpectShortHeaders();
   void SkipVersionChecks();
   void SetSignatureSchemes(const SSLSignatureScheme* schemes, size_t count);
   void EnableAlpn(const uint8_t* val, size_t len);
   void CheckAlpn(SSLNextProtoState expected_state,
                  const std::string& expected = "") const;
   void EnableSrtp();
   void CheckSrtp() const;
   void CheckErrorCode(int32_t expected) const;
@@ -383,17 +381,16 @@ class TlsAgent : public PollTarget {
   SSLVersionRange vrange_;
   PRErrorCode error_code_;
   size_t send_ctr_;
   size_t recv_ctr_;
   bool expect_readwrite_error_;
   HandshakeCallbackFunction handshake_callback_;
   AuthCertificateCallbackFunction auth_certificate_callback_;
   SniCallbackFunction sni_callback_;
-  bool expect_short_headers_;
   bool skip_version_checks_;
 };
 
 inline std::ostream& operator<<(std::ostream& stream,
                                 const TlsAgent::State& state) {
   return stream << TlsAgent::state_str(state);
 }
 
--- a/lib/ssl/dtlscon.c
+++ b/lib/ssl/dtlscon.c
@@ -341,17 +341,17 @@ dtls_HandleHandshake(sslSocket *ss, sslB
          *
          * If it's the complete next message we accept it right away.
          * This is the common case for short messages
          */
         if ((message_seq == ss->ssl3.hs.recvMessageSeq) &&
             (fragment_offset == 0) &&
             (fragment_length == message_length)) {
             /* Complete next message. Process immediately */
-            ss->ssl3.hs.msg_type = (SSL3HandshakeType)type;
+            ss->ssl3.hs.msg_type = (SSLHandshakeType)type;
             ss->ssl3.hs.msg_len = message_length;
 
             rv = dtls_HandleHandshakeMessage(ss, buf.buf,
                                              buf.len == fragment_length);
             if (rv == SECFailure) {
                 break; /* Discard the remainder of the record. */
             }
         } else {
@@ -386,17 +386,17 @@ dtls_HandleHandshake(sslSocket *ss, sslB
                                         map_length);
                     if (rv != SECSuccess)
                         break;
 
                     /* Reset the reassembly map */
                     ss->ssl3.hs.recvdHighWater = 0;
                     PORT_Memset(ss->ssl3.hs.recvdFragments.buf, 0,
                                 ss->ssl3.hs.recvdFragments.space);
-                    ss->ssl3.hs.msg_type = (SSL3HandshakeType)type;
+                    ss->ssl3.hs.msg_type = (SSLHandshakeType)type;
                     ss->ssl3.hs.msg_len = message_length;
                 }
 
                 /* If we have a message length mismatch, abandon the reassembly
                  * in progress and hope that the next retransmit will give us
                  * something sane
                  */
                 if (message_length != ss->ssl3.hs.msg_len) {
--- a/lib/ssl/manifest.mn
+++ b/lib/ssl/manifest.mn
@@ -20,17 +20,17 @@ MAPFILE = $(OBJDIR)/ssl.def
 CSRCS = \
         dtlscon.c \
         prelib.c \
         ssl3con.c \
         ssl3gthr.c \
         sslauth.c \
         sslcon.c \
         ssldef.c \
-        ssl3encode.c \
+        sslencode.c \
         sslenum.c \
         sslerr.c \
         sslerrstrs.c \
         sslinit.c \
         ssl3ext.c \
         ssl3exthandle.c \
         sslmutex.c \
         sslnonce.c \
--- a/lib/ssl/selfencrypt.c
+++ b/lib/ssl/selfencrypt.c
@@ -6,17 +6,17 @@
  * 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 "nss.h"
 #include "blapit.h"
 #include "pk11func.h"
 #include "ssl.h"
 #include "sslt.h"
-#include "ssl3encode.h"
+#include "sslencode.h"
 #include "sslimpl.h"
 #include "selfencrypt.h"
 
 static SECStatus
 ssl_MacBuffer(PK11SymKey *key, CK_MECHANISM_TYPE mech,
               const unsigned char *in, unsigned int len,
               unsigned char *mac, unsigned int *macLen, unsigned int maxMacLen)
 {
--- a/lib/ssl/ssl.gyp
+++ b/lib/ssl/ssl.gyp
@@ -12,24 +12,24 @@
       'sources': [
         'authcert.c',
         'cmpcert.c',
         'dtlscon.c',
         'prelib.c',
         'selfencrypt.c',
         'ssl3con.c',
         'ssl3ecc.c',
-        'ssl3encode.c',
         'ssl3ext.c',
         'ssl3exthandle.c',
         'ssl3gthr.c',
         'sslauth.c',
         'sslcert.c',
         'sslcon.c',
         'ssldef.c',
+        'sslencode.c',
         'sslenum.c',
         'sslerr.c',
         'sslerrstrs.c',
         'sslgrp.c',
         'sslinfo.c',
         'sslinit.c',
         'sslmutex.c',
         'sslnonce.c',
--- a/lib/ssl/ssl3con.c
+++ b/lib/ssl/ssl3con.c
@@ -549,59 +549,59 @@ ssl3_Alg2Mech(SSLCipherAlgorithm calg)
 
 static char *
 ssl3_DecodeHandshakeType(int msgType)
 {
     char *rv;
     static char line[40];
 
     switch (msgType) {
-        case hello_request:
+        case ssl_hs_hello_request:
             rv = "hello_request (0)";
             break;
-        case client_hello:
+        case ssl_hs_client_hello:
             rv = "client_hello  (1)";
             break;
-        case server_hello:
+        case ssl_hs_server_hello:
             rv = "server_hello  (2)";
             break;
-        case hello_verify_request:
+        case ssl_hs_hello_verify_request:
             rv = "hello_verify_request (3)";
             break;
-        case new_session_ticket:
+        case ssl_hs_new_session_ticket:
             rv = "session_ticket (4)";
             break;
-        case end_of_early_data:
+        case ssl_hs_end_of_early_data:
             rv = "end_of_early_data (5)";
             break;
-        case hello_retry_request:
+        case ssl_hs_hello_retry_request:
             rv = "hello_retry_request (6)";
             break;
-        case encrypted_extensions:
+        case ssl_hs_encrypted_extensions:
             rv = "encrypted_extensions (8)";
             break;
-        case certificate:
+        case ssl_hs_certificate:
             rv = "certificate  (11)";
             break;
-        case server_key_exchange:
+        case ssl_hs_server_key_exchange:
             rv = "server_key_exchange (12)";
             break;
-        case certificate_request:
+        case ssl_hs_certificate_request:
             rv = "certificate_request (13)";
             break;
-        case server_hello_done:
+        case ssl_hs_server_hello_done:
             rv = "server_hello_done   (14)";
             break;
-        case certificate_verify:
+        case ssl_hs_certificate_verify:
             rv = "certificate_verify  (15)";
             break;
-        case client_key_exchange:
+        case ssl_hs_client_key_exchange:
             rv = "client_key_exchange (16)";
             break;
-        case finished:
+        case ssl_hs_finished:
             rv = "finished     (20)";
             break;
         default:
             sprintf(line, "*UNKNOWN* handshake type! (%d)", msgType);
             rv = line;
     }
     return rv;
 }
@@ -2545,23 +2545,17 @@ ssl_ProtectRecord(sslSocket *ss, ssl3Cip
     const ssl3BulkCipherDef *cipher_def = cwSpec->cipher_def;
     PRUint16 headerLen;
     sslBuffer protBuf;
     SSL3ProtocolVersion version = cwSpec->version;
     PRBool isTLS13;
     PRUint8 *ptr = wrBuf->buf;
     SECStatus rv;
 
-    if (ss->ssl3.hs.shortHeaders) {
-        PORT_Assert(!IS_DTLS(ss));
-        PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
-        headerLen = TLS13_RECORD_HEADER_LENGTH_SHORT;
-    } else {
-        headerLen = IS_DTLS(ss) ? DTLS_RECORD_HEADER_LENGTH : SSL3_RECORD_HEADER_LENGTH;
-    }
+    headerLen = IS_DTLS(ss) ? DTLS_RECORD_HEADER_LENGTH : SSL3_RECORD_HEADER_LENGTH;
     protBuf.buf = wrBuf->buf + headerLen;
     protBuf.len = 0;
     protBuf.space = wrBuf->space - headerLen;
 
     PORT_Assert(cipher_def->max_records <= RECORD_SEQ_MAX);
     if ((cwSpec->write_seq_num & RECORD_SEQ_MAX) >= cipher_def->max_records) {
         SSL_TRC(3, ("%d: SSL[-]: write sequence number at limit 0x%0llx",
                     SSL_GETPID(), cwSpec->write_seq_num));
@@ -2585,43 +2579,38 @@ ssl_ProtectRecord(sslSocket *ss, ssl3Cip
 #endif
     if (rv != SECSuccess) {
         return SECFailure; /* error was set */
     }
 
     PORT_Assert(protBuf.len <= MAX_FRAGMENT_LENGTH + (isTLS13 ? 256 : 1024));
     wrBuf->len = protBuf.len + headerLen;
 
-    if (ss->ssl3.hs.shortHeaders) {
-        PORT_Assert(!IS_DTLS(ss)); /* Decoder not yet implemented. */
-        (void)ssl_EncodeUintX(0x8000 | protBuf.len, 2, ptr);
-    } else {
 #ifndef UNSAFE_FUZZER_MODE
-        if (isTLS13 && cipher_def->calg != ssl_calg_null) {
-            *ptr++ = content_application_data;
-        } else
+    if (isTLS13 && cipher_def->calg != ssl_calg_null) {
+        *ptr++ = content_application_data;
+    } else
 #endif
-        {
-            *ptr++ = type;
-        }
-
-        if (IS_DTLS(ss)) {
-            version = isTLS13 ? SSL_LIBRARY_VERSION_TLS_1_1 : version;
-            version = dtls_TLSVersionToDTLSVersion(version);
-
-            ptr = ssl_EncodeUintX(version, 2, ptr);
-            ptr = ssl_EncodeUintX(cwSpec->write_seq_num, 8, ptr);
-        } else {
-            if (capRecordVersion || isTLS13) {
-                version = PR_MIN(SSL_LIBRARY_VERSION_TLS_1_0, version);
-            }
-            ptr = ssl_EncodeUintX(version, 2, ptr);
-        }
-        (void)ssl_EncodeUintX(protBuf.len, 2, ptr);
-    }
+    {
+        *ptr++ = type;
+    }
+
+    if (IS_DTLS(ss)) {
+        version = isTLS13 ? SSL_LIBRARY_VERSION_TLS_1_1 : version;
+        version = dtls_TLSVersionToDTLSVersion(version);
+
+        ptr = ssl_EncodeUintX(version, 2, ptr);
+        ptr = ssl_EncodeUintX(cwSpec->write_seq_num, 8, ptr);
+    } else {
+        if (capRecordVersion || isTLS13) {
+            version = PR_MIN(SSL_LIBRARY_VERSION_TLS_1_0, version);
+        }
+        ptr = ssl_EncodeUintX(version, 2, ptr);
+    }
+    (void)ssl_EncodeUintX(protBuf.len, 2, ptr);
     ++cwSpec->write_seq_num;
 
     return SECSuccess;
 }
 
 /* Process the plain text before sending it.
  * Returns the number of bytes of plaintext that were successfully sent
  *  plus the number of bytes of plaintext that were copied into the
@@ -4138,17 +4127,17 @@ ssl3_UpdateHandshakeHashes(sslSocket *ss
 }
 
 /**************************************************************************
  * Append Handshake functions.
  * All these functions set appropriate error codes.
  * Most rely on ssl3_AppendHandshake to set the error code.
  **************************************************************************/
 SECStatus
-ssl3_AppendHandshake(sslSocket *ss, const void *void_src, PRInt32 bytes)
+ssl3_AppendHandshake(sslSocket *ss, const void *void_src, unsigned int bytes)
 {
     unsigned char *src = (unsigned char *)void_src;
     int room = ss->sec.ci.sendBuf.space - ss->sec.ci.sendBuf.len;
     SECStatus rv;
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); /* protects sendBuf. */
 
     if (!bytes)
@@ -4181,46 +4170,27 @@ ssl3_AppendHandshake(sslSocket *ss, cons
         PORT_Assert(ss->sec.ci.sendBuf.len == 0);
     }
     PORT_Memcpy(ss->sec.ci.sendBuf.buf + ss->sec.ci.sendBuf.len, src, bytes);
     ss->sec.ci.sendBuf.len += bytes;
     return SECSuccess;
 }
 
 SECStatus
-ssl3_AppendHandshakeNumber(sslSocket *ss, PRInt32 num, PRInt32 lenSize)
-{
-    SECStatus rv;
-    PRUint8 b[4];
-    PRUint8 *p = b;
-
-    PORT_Assert(lenSize <= 4 && lenSize > 0);
-    if (lenSize < 4 && num >= (1L << (lenSize * 8))) {
-        PORT_SetError(SSL_ERROR_TX_RECORD_TOO_LONG);
-        return SECFailure;
-    }
-
-    switch (lenSize) {
-        case 4:
-            *p++ = (num >> 24) & 0xff;
-        case 3:
-            *p++ = (num >> 16) & 0xff;
-        case 2:
-            *p++ = (num >> 8) & 0xff;
-        case 1:
-            *p = num & 0xff;
-    }
+ssl3_AppendHandshakeNumber(sslSocket *ss, PRUint64 num, unsigned int lenSize)
+{
+    PRUint8 b[sizeof(num)];
     SSL_TRC(60, ("%d: number:", SSL_GETPID()));
-    rv = ssl3_AppendHandshake(ss, &b[0], lenSize);
-    return rv; /* error code set by AppendHandshake, if applicable. */
+    (void)ssl_EncodeUintX(num, lenSize, b);
+    return ssl3_AppendHandshake(ss, b, lenSize);
 }
 
 SECStatus
 ssl3_AppendHandshakeVariable(
-    sslSocket *ss, const PRUint8 *src, PRInt32 bytes, PRInt32 lenSize)
+    sslSocket *ss, const PRUint8 *src, unsigned int bytes, unsigned int lenSize)
 {
     SECStatus rv;
 
     PORT_Assert((bytes < (1 << 8) && lenSize == 1) ||
                 (bytes < (1L << 16) && lenSize == 2) ||
                 (bytes < (1L << 24) && lenSize == 3));
 
     SSL_TRC(60, ("%d: append variable:", SSL_GETPID()));
@@ -4229,17 +4199,30 @@ ssl3_AppendHandshakeVariable(
         return rv; /* error code set by AppendHandshake, if applicable. */
     }
     SSL_TRC(60, ("data:"));
     rv = ssl3_AppendHandshake(ss, src, bytes);
     return rv; /* error code set by AppendHandshake, if applicable. */
 }
 
 SECStatus
-ssl3_AppendHandshakeHeader(sslSocket *ss, SSL3HandshakeType t, PRUint32 length)
+ssl3_AppendBufferToHandshake(sslSocket *ss, sslBuffer *buf)
+{
+    return ssl3_AppendHandshake(ss, buf->buf, buf->len);
+}
+
+SECStatus
+ssl3_AppendBufferToHandshakeVariable(sslSocket *ss, sslBuffer *buf,
+                                     unsigned int lenSize)
+{
+    return ssl3_AppendHandshakeVariable(ss, buf->buf, buf->len, lenSize);
+}
+
+SECStatus
+ssl3_AppendHandshakeHeader(sslSocket *ss, SSLHandshakeType t, PRUint32 length)
 {
     SECStatus rv;
 
     /* If we already have a message in place, we need to enqueue it.
      * This empties the buffer. This is a convenient place to call
      * dtls_StageHandshakeMessage to mark the message boundary.
      */
     if (IS_DTLS(ss)) {
@@ -4941,17 +4924,18 @@ ssl3_SendClientHello(sslSocket *ss, sslC
     ssl3CipherSpec *cwSpec;
     SECStatus rv;
     int i;
     int length;
     int num_suites;
     int actual_count = 0;
     PRBool isTLS = PR_FALSE;
     PRBool requestingResume = PR_FALSE, fallbackSCSV = PR_FALSE;
-    PRInt32 total_exten_len = 0;
+    PRBool unlockNeeded = PR_FALSE;
+    sslBuffer extensionBuf = { NULL, 0, 0 };
     unsigned numCompressionMethods;
     PRUint16 version;
     PRInt32 flags;
 
     SSL_TRC(3, ("%d: SSL3[%d]: send %s ClientHello handshake", SSL_GETPID(),
                 ss->fd, ssl_ClientHelloTypeName(type)));
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
@@ -5167,57 +5151,45 @@ ssl3_SendClientHello(sslSocket *ss, sslC
         ss->ssl3.hs.sendingSCSV = PR_TRUE;
     }
 
     /* When we attempt session resumption (only), we must lock the sid to
      * prevent races with other resumption connections that receive a
      * NewSessionTicket that will cause the ticket in the sid to be replaced.
      * Once we've copied the session ticket into our ClientHello message, it
      * is OK for the ticket to change, so we just need to make sure we hold
-     * the lock across the calls to ssl3_CallHelloExtensionSenders.
+     * the lock across the calls to ssl_ConstructExtensions.
      */
     if (sid->u.ssl3.lock) {
+        unlockNeeded = PR_TRUE;
         PR_RWLock_Rlock(sid->u.ssl3.lock);
     }
 
     if (ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3 &&
         type == client_hello_initial) {
         rv = tls13_SetupClientHello(ss);
         if (rv != SECSuccess) {
-            return SECFailure;
+            goto loser;
         }
     }
     if (isTLS || (ss->firstHsDone && ss->peerRequestedProtection)) {
-        PRUint32 maxBytes = 65535; /* 2^16 - 1 */
-        PRInt32 extLen;
-
-        extLen = ssl3_CallHelloExtensionSenders(ss, PR_FALSE, maxBytes, NULL);
-        if (extLen < 0) {
-            if (sid->u.ssl3.lock) {
-                PR_RWLock_Unlock(sid->u.ssl3.lock);
-            }
-            return SECFailure;
-        }
-        total_exten_len += extLen;
-
-        if (total_exten_len > 0)
-            total_exten_len += 2;
+        rv = ssl_ConstructExtensions(ss, &extensionBuf, ssl_hs_client_hello);
+        if (rv != SECSuccess) {
+            goto loser;
+        }
     }
 
     if (IS_DTLS(ss)) {
         ssl3_DisableNonDTLSSuites(ss);
     }
 
     /* how many suites are permitted by policy and user preference? */
     num_suites = count_cipher_suites(ss, ss->ssl3.policy);
     if (!num_suites) {
-        if (sid->u.ssl3.lock) {
-            PR_RWLock_Unlock(sid->u.ssl3.lock);
-        }
-        return SECFailure; /* count_cipher_suites has set error code. */
+        goto loser; /* count_cipher_suites has set error code. */
     }
 
     fallbackSCSV = ss->opt.enableFallbackSCSV && (!requestingResume ||
                                                   version < sid->version);
     /* make room for SCSV */
     if (ss->ssl3.hs.sendingSCSV) {
         ++num_suites;
     }
@@ -5232,35 +5204,32 @@ ssl3_SendClientHello(sslSocket *ss, sslC
             numCompressionMethods++;
     }
 
     length = sizeof(SSL3ProtocolVersion) + SSL3_RANDOM_LENGTH +
              1 + (sid->version >= SSL_LIBRARY_VERSION_TLS_1_3
                       ? 0
                       : sid->u.ssl3.sessionIDLength) +
              2 + num_suites * sizeof(ssl3CipherSuite) +
-             1 + numCompressionMethods + total_exten_len;
+             1 + numCompressionMethods;
     if (IS_DTLS(ss)) {
         length += 1 + ss->ssl3.hs.cookie.len;
     }
 
-    if (total_exten_len > 0) {
-        ssl3_CalculatePaddingExtLen(ss, length);
-        if (ss->xtnData.paddingLen) {
-            total_exten_len += 4 + ss->xtnData.paddingLen;
-            length += 4 + ss->xtnData.paddingLen;
-        }
-    }
-
-    rv = ssl3_AppendHandshakeHeader(ss, client_hello, length);
-    if (rv != SECSuccess) {
-        if (sid->u.ssl3.lock) {
-            PR_RWLock_Unlock(sid->u.ssl3.lock);
-        }
-        return rv; /* err set by ssl3_AppendHandshake* */
+    if (extensionBuf.len) {
+        rv = ssl_InsertPaddingExtension(ss, length, &extensionBuf);
+        if (rv != SECSuccess) {
+            goto loser; /* err set by ssl_InsertPaddingExtension */
+        }
+        length += 2 + extensionBuf.len;
+    }
+
+    rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_client_hello, length);
+    if (rv != SECSuccess) {
+        goto loser; /* err set by ssl3_AppendHandshake* */
     }
 
     if (ss->firstHsDone) {
         /* The client hello version must stay unchanged to work around
          * the Windows SChannel bug described above. */
         PORT_Assert(version == ss->clientHelloVersion);
     }
     ss->clientHelloVersion = PR_MIN(version, SSL_LIBRARY_VERSION_TLS_1_2);
@@ -5268,174 +5237,127 @@ ssl3_SendClientHello(sslSocket *ss, sslC
         PRUint16 dtlsVersion;
 
         dtlsVersion = dtls_TLSVersionToDTLSVersion(ss->clientHelloVersion);
         rv = ssl3_AppendHandshakeNumber(ss, dtlsVersion, 2);
     } else {
         rv = ssl3_AppendHandshakeNumber(ss, ss->clientHelloVersion, 2);
     }
     if (rv != SECSuccess) {
-        if (sid->u.ssl3.lock) {
-            PR_RWLock_Unlock(sid->u.ssl3.lock);
-        }
-        return rv; /* err set by ssl3_AppendHandshake* */
+        goto loser; /* err set by ssl3_AppendHandshake* */
     }
 
     /* Generate a new random if this is the first attempt. */
     if (type == client_hello_initial) {
         rv = ssl3_GetNewRandom(&ss->ssl3.hs.client_random);
         if (rv != SECSuccess) {
-            if (sid->u.ssl3.lock) {
-                PR_RWLock_Unlock(sid->u.ssl3.lock);
-            }
-            return rv; /* err set by GetNewRandom. */
+            goto loser; /* err set by GetNewRandom. */
         }
     }
     rv = ssl3_AppendHandshake(ss, &ss->ssl3.hs.client_random,
                               SSL3_RANDOM_LENGTH);
     if (rv != SECSuccess) {
-        if (sid->u.ssl3.lock) {
-            PR_RWLock_Unlock(sid->u.ssl3.lock);
-        }
-        return rv; /* err set by ssl3_AppendHandshake* */
+        goto loser; /* err set by ssl3_AppendHandshake* */
     }
 
     if (sid->version < SSL_LIBRARY_VERSION_TLS_1_3)
         rv = ssl3_AppendHandshakeVariable(
             ss, sid->u.ssl3.sessionID, sid->u.ssl3.sessionIDLength, 1);
     else
         rv = ssl3_AppendHandshakeNumber(ss, 0, 1);
     if (rv != SECSuccess) {
-        if (sid->u.ssl3.lock) {
-            PR_RWLock_Unlock(sid->u.ssl3.lock);
-        }
-        return rv; /* err set by ssl3_AppendHandshake* */
+        goto loser; /* err set by ssl3_AppendHandshake* */
     }
 
     if (IS_DTLS(ss)) {
         rv = ssl3_AppendHandshakeVariable(
             ss, ss->ssl3.hs.cookie.data, ss->ssl3.hs.cookie.len, 1);
         if (rv != SECSuccess) {
-            if (sid->u.ssl3.lock) {
-                PR_RWLock_Unlock(sid->u.ssl3.lock);
-            }
-            return rv; /* err set by ssl3_AppendHandshake* */
+            goto loser; /* err set by ssl3_AppendHandshake* */
         }
     }
 
     rv = ssl3_AppendHandshakeNumber(ss, num_suites * sizeof(ssl3CipherSuite), 2);
     if (rv != SECSuccess) {
-        if (sid->u.ssl3.lock) {
-            PR_RWLock_Unlock(sid->u.ssl3.lock);
-        }
-        return rv; /* err set by ssl3_AppendHandshake* */
+        goto loser; /* err set by ssl3_AppendHandshake* */
     }
 
     if (ss->ssl3.hs.sendingSCSV) {
         /* Add the actual SCSV */
         rv = ssl3_AppendHandshakeNumber(ss, TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
                                         sizeof(ssl3CipherSuite));
         if (rv != SECSuccess) {
-            if (sid->u.ssl3.lock) {
-                PR_RWLock_Unlock(sid->u.ssl3.lock);
-            }
-            return rv; /* err set by ssl3_AppendHandshake* */
+            goto loser; /* err set by ssl3_AppendHandshake* */
         }
         actual_count++;
     }
     if (fallbackSCSV) {
         rv = ssl3_AppendHandshakeNumber(ss, TLS_FALLBACK_SCSV,
                                         sizeof(ssl3CipherSuite));
         if (rv != SECSuccess) {
-            if (sid->u.ssl3.lock) {
-                PR_RWLock_Unlock(sid->u.ssl3.lock);
-            }
-            return rv; /* err set by ssl3_AppendHandshake* */
+            goto loser; /* err set by ssl3_AppendHandshake* */
         }
         actual_count++;
     }
     for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) {
         ssl3CipherSuiteCfg *suite = &ss->cipherSuites[i];
         if (config_match(suite, ss->ssl3.policy, &ss->vrange, ss)) {
             actual_count++;
             if (actual_count > num_suites) {
-                if (sid->u.ssl3.lock) {
-                    PR_RWLock_Unlock(sid->u.ssl3.lock);
-                }
                 /* set error card removal/insertion error */
                 PORT_SetError(SSL_ERROR_TOKEN_INSERTION_REMOVAL);
-                return SECFailure;
+                goto loser;
             }
             rv = ssl3_AppendHandshakeNumber(ss, suite->cipher_suite,
                                             sizeof(ssl3CipherSuite));
             if (rv != SECSuccess) {
-                if (sid->u.ssl3.lock) {
-                    PR_RWLock_Unlock(sid->u.ssl3.lock);
-                }
-                return rv; /* err set by ssl3_AppendHandshake* */
+                goto loser; /* err set by ssl3_AppendHandshake* */
             }
         }
     }
 
     /* if cards were removed or inserted between count_cipher_suites and
      * generating our list, detect the error here rather than send it off to
      * the server.. */
     if (actual_count != num_suites) {
         /* Card removal/insertion error */
-        if (sid->u.ssl3.lock) {
-            PR_RWLock_Unlock(sid->u.ssl3.lock);
-        }
         PORT_SetError(SSL_ERROR_TOKEN_INSERTION_REMOVAL);
-        return SECFailure;
+        goto loser;
     }
 
     rv = ssl3_AppendHandshakeNumber(ss, numCompressionMethods, 1);
     if (rv != SECSuccess) {
-        if (sid->u.ssl3.lock) {
-            PR_RWLock_Unlock(sid->u.ssl3.lock);
-        }
-        return rv; /* err set by ssl3_AppendHandshake* */
+        goto loser; /* err set by ssl3_AppendHandshake* */
     }
     for (i = 0; i < ssl_compression_method_count; i++) {
         if (!ssl_CompressionEnabled(ss, ssl_compression_methods[i]))
             continue;
         rv = ssl3_AppendHandshakeNumber(ss, ssl_compression_methods[i], 1);
         if (rv != SECSuccess) {
-            if (sid->u.ssl3.lock) {
-                PR_RWLock_Unlock(sid->u.ssl3.lock);
-            }
-            return rv; /* err set by ssl3_AppendHandshake* */
-        }
-    }
-
-    if (total_exten_len) {
-        PRUint32 maxBytes = total_exten_len - 2;
-        PRInt32 extLen;
-
-        rv = ssl3_AppendHandshakeNumber(ss, maxBytes, 2);
-        if (rv != SECSuccess) {
-            if (sid->u.ssl3.lock) {
-                PR_RWLock_Unlock(sid->u.ssl3.lock);
-            }
-            return rv; /* err set by AppendHandshake. */
-        }
-
-        extLen = ssl3_CallHelloExtensionSenders(ss, PR_TRUE, maxBytes, NULL);
-        if (extLen < 0) {
-            if (sid->u.ssl3.lock) {
-                PR_RWLock_Unlock(sid->u.ssl3.lock);
-            }
-            return SECFailure;
-        }
-        maxBytes -= extLen;
-
-        PORT_Assert(!maxBytes);
-    }
-
+            goto loser; /* err set by ssl3_AppendHandshake* */
+        }
+    }
+
+    if (extensionBuf.len) {
+        /* If we are sending a PSK binder, replace the dummy value.  Note that
+         * we only set statelessResume on the client in TLS 1.3. */
+        if (ss->statelessResume &&
+            ss->xtnData.sentSessionTicketInClientHello) {
+            rv = tls13_WriteExtensionsWithBinder(ss, &extensionBuf);
+        } else {
+            rv = ssl3_AppendBufferToHandshakeVariable(ss, &extensionBuf, 2);
+        }
+        if (rv != SECSuccess) {
+            goto loser; /* err set by AppendHandshake. */
+        }
+    }
+
+    sslBuffer_Clear(&extensionBuf);
     if (sid->u.ssl3.lock) {
+        unlockNeeded = PR_FALSE;
         PR_RWLock_Unlock(sid->u.ssl3.lock);
     }
 
     if (ss->xtnData.sentSessionTicketInClientHello) {
         SSL_AtomicIncrementLong(&ssl3stats.sch_sid_stateless_resumes);
     }
 
     if (ss->ssl3.hs.sendingSCSV) {
@@ -5458,16 +5380,23 @@ ssl3_SendClientHello(sslSocket *ss, sslC
         rv = tls13_MaybeDo0RTTHandshake(ss);
         if (rv != SECSuccess) {
             return SECFailure; /* error code set already. */
         }
     }
 
     ss->ssl3.hs.ws = wait_server_hello;
     return SECSuccess;
+
+loser:
+    if (unlockNeeded) {
+        PR_RWLock_Unlock(sid->u.ssl3.lock);
+    }
+    sslBuffer_Clear(&extensionBuf);
+    return SECFailure;
 }
 
 /* Called from ssl3_HandlePostHelloHandshakeMessage() when it has deciphered a
  * complete ssl3 Hello Request.
  * Caller must hold Handshake and RecvBuf locks.
  */
 static SECStatus
 ssl3_HandleHelloRequest(sslSocket *ss)
@@ -6066,17 +5995,17 @@ ssl3_SendRSAClientKeyExchange(sslSocket 
                     fwrite(buf, sizeof(buf), 1, ssl_keylog_iob);
                     fflush(ssl_keylog_iob);
                 }
             }
         }
     }
 #endif
 
-    rv = ssl3_AppendHandshakeHeader(ss, client_key_exchange,
+    rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_client_key_exchange,
                                     isTLS ? enc_pms.len + 2
                                           : enc_pms.len);
     if (rv != SECSuccess) {
         goto loser; /* err set by ssl3_AppendHandshake* */
     }
     if (isTLS) {
         rv = ssl3_AppendHandshakeVariable(ss, enc_pms.data, enc_pms.len, 2);
     } else {
@@ -6105,37 +6034,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(const sslSocket *ss, const SECKEYPublicKey *pubKey,
+ssl_AppendPaddedDHKeyShare(sslBuffer *buf, const SECKEYPublicKey *pubKey,
                            PRBool appendLength)
 {
     SECStatus rv;
     unsigned int pad = pubKey->u.dh.prime.len - pubKey->u.dh.publicValue.len;
 
     if (appendLength) {
-        rv = ssl3_ExtAppendHandshakeNumber(ss, pubKey->u.dh.prime.len, 2);
+        rv = sslBuffer_AppendNumber(buf, pubKey->u.dh.prime.len, 2);
         if (rv != SECSuccess) {
             return rv;
         }
     }
     while (pad) {
-        rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 1);
+        rv = sslBuffer_AppendNumber(buf, 0, 1);
         if (rv != SECSuccess) {
             return rv;
         }
         --pad;
     }
-    rv = ssl3_ExtAppendHandshake(ss, pubKey->u.dh.publicValue.data,
-                                 pubKey->u.dh.publicValue.len);
+    rv = sslBuffer_Append(buf, pubKey->u.dh.publicValue.data,
+                          pubKey->u.dh.publicValue.len);
     if (rv != SECSuccess) {
         return rv;
     }
     return SECSuccess;
 }
 
 /* Called from ssl3_SendClientKeyExchange(). */
 static SECStatus
@@ -6149,16 +6078,17 @@ ssl3_SendDHClientKeyExchange(sslSocket *
     const ssl3DHParams *params;
     ssl3DHParams customParams;
     const sslNamedGroupDef *groupDef;
     static const sslNamedGroupDef customGroupDef = {
         ssl_grp_ffdhe_custom, 0, ssl_kea_dh, SEC_OID_TLS_DHE_CUSTOM, PR_FALSE
     };
     sslEphemeralKeyPair *keyPair = NULL;
     SECKEYPublicKey *pubKey;
+    sslBuffer dhBuf = { NULL, 0, 0 };
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
 
     isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0);
 
     /* Copy DH parameters from server key */
 
@@ -6208,41 +6138,47 @@ ssl3_SendDHClientKeyExchange(sslSocket *
                          target, CKA_DERIVE, 0, NULL);
 
     if (pms == NULL) {
         ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
         goto loser;
     }
 
     /* Note: send the DH share padded to avoid triggering bugs. */
-    rv = ssl3_AppendHandshakeHeader(ss, client_key_exchange,
+    rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_client_key_exchange,
                                     params->prime.len + 2);
     if (rv != SECSuccess) {
         goto loser; /* err set by ssl3_AppendHandshake* */
     }
-    rv = ssl_AppendPaddedDHKeyShare(ss, pubKey, PR_TRUE);
+    rv = ssl_AppendPaddedDHKeyShare(&dhBuf, pubKey, PR_TRUE);
     if (rv != SECSuccess) {
         goto loser; /* err set by ssl_AppendPaddedDHKeyShare */
     }
+    rv = ssl3_AppendBufferToHandshake(ss, &dhBuf);
+    if (rv != SECSuccess) {
+        goto loser; /* err set by ssl3_AppendBufferToHandshake */
+    }
 
     rv = ssl3_InitPendingCipherSpec(ss, pms);
     if (rv != SECSuccess) {
         ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
         goto loser;
     }
 
+    sslBuffer_Clear(&dhBuf);
     PK11_FreeSymKey(pms);
     ssl_FreeEphemeralKeyPair(keyPair);
     return SECSuccess;
 
 loser:
     if (pms)
         PK11_FreeSymKey(pms);
     if (keyPair)
         ssl_FreeEphemeralKeyPair(keyPair);
+    sslBuffer_Clear(&dhBuf);
     return SECFailure;
 }
 
 /* Called from ssl3_HandleServerHelloDone(). */
 static SECStatus
 ssl3_SendClientKeyExchange(sslSocket *ss)
 {
     SECKEYPublicKey *serverKey = NULL;
@@ -6531,17 +6467,17 @@ ssl3_SendCertificateVerify(sslSocket *ss
         PK11_FreeSlot(slot);
     }
     if (rv != SECSuccess) {
         goto done; /* err code was set by ssl3_SignHashes */
     }
 
     len = buf.len + 2 + (isTLS12 ? 2 : 0);
 
-    rv = ssl3_AppendHandshakeHeader(ss, certificate_verify, len);
+    rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_certificate_verify, len);
     if (rv != SECSuccess) {
         goto done; /* error code set by AppendHandshake */
     }
     if (isTLS12) {
         rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.hs.signatureScheme, 2);
         if (rv != SECSuccess) {
             goto done; /* err set by AppendHandshake. */
         }
@@ -6811,17 +6747,17 @@ ssl3_HandleServerHello(sslSocket *ss, PR
     if (length != 0) {
         SECItem extensions;
         rv = ssl3_ConsumeHandshakeVariable(ss, &extensions, 2, &b, &length);
         if (rv != SECSuccess || length != 0) {
             if (isTLS)
                 goto alert_loser;
         } else {
             rv = ssl3_HandleExtensions(ss, &extensions.data,
-                                       &extensions.len, server_hello);
+                                       &extensions.len, ssl_hs_server_hello);
             if (rv != SECSuccess)
                 goto alert_loser;
         }
     }
 
     if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
         rv = tls13_HandleServerHelloPart2(ss);
         if (rv != SECSuccess) {
@@ -7865,17 +7801,17 @@ ssl3_SendHelloRequest(sslSocket *ss)
     SECStatus rv;
 
     SSL_TRC(3, ("%d: SSL3[%d]: send hello_request handshake", SSL_GETPID(),
                 ss->fd));
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
 
-    rv = ssl3_AppendHandshakeHeader(ss, hello_request, 0);
+    rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_hello_request, 0);
     if (rv != SECSuccess) {
         return rv; /* err set by AppendHandshake */
     }
     rv = ssl3_FlushHandshake(ss, 0);
     if (rv != SECSuccess) {
         return rv; /* error code set by ssl3_FlushHandshake */
     }
     ss->ssl3.hs.ws = wait_client_hello;
@@ -8197,17 +8133,17 @@ ssl3_ServerCallSNICallback(sslSocket *ss
                     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_RegisterExtensionSender(ss, &ss->xtnData, ssl_server_name_xtn,
-                                             ssl3_SendServerNameXtn);
+                                             ssl_SendEmptyExtension);
             } 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;
             }
@@ -8494,17 +8430,17 @@ ssl3_HandleClientHello(sslSocket *ss, PR
             default:
                 /* Do not change random. */
                 break;
         }
     }
 #endif
 
     /* Now parse the rest of the extensions. */
-    rv = ssl3_HandleParsedExtensions(ss, client_hello);
+    rv = ssl3_HandleParsedExtensions(ss, ssl_hs_client_hello);
     if (rv != SECSuccess) {
         goto loser; /* malformed */
     }
 
     /* If the ClientHello version is less than our maximum version, check for a
      * TLS_FALLBACK_SCSV and reject the connection if found. */
     if (ss->vrange.max > ss->version) {
         for (i = 0; i + 1 < suites.len; i += 2) {
@@ -8529,17 +8465,17 @@ ssl3_HandleClientHello(sslSocket *ss, PR
          * and if found, treat it just like an empty RI extension
          * by processing a local copy of an empty RI extension.
          */
         for (i = 0; i + 1 < suites.len; i += 2) {
             PRUint16 suite_i = (suites.data[i] << 8) | suites.data[i + 1];
             if (suite_i == TLS_EMPTY_RENEGOTIATION_INFO_SCSV) {
                 PRUint8 *b2 = (PRUint8 *)emptyRIext;
                 PRUint32 L2 = sizeof emptyRIext;
-                (void)ssl3_HandleExtensions(ss, &b2, &L2, client_hello);
+                (void)ssl3_HandleExtensions(ss, &b2, &L2, ssl_hs_client_hello);
                 break;
             }
         }
     }
     /* This is a second check for TLS 1.3 and re-handshake to stop us
      * from re-handshake up to TLS 1.3, so it happens after version
      * negotiation. */
     if (ss->firstHsDone && ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
@@ -8994,19 +8930,18 @@ 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_RegisterExtensionSender(ss, &ss->xtnData,
-                                     ssl_session_ticket_xtn,
-                                     ssl3_SendSessionTicketXtn);
+        ssl3_RegisterExtensionSender(ss, &ss->xtnData, ssl_session_ticket_xtn,
+                                     ssl_SendEmptyExtension);
     }
 
     rv = ssl3_ServerCallSNICallback(ss);
     if (rv != SECSuccess) {
         /* The alert has already been sent. */
         errCode = PORT_GetError();
         goto loser;
     }
@@ -9217,17 +9152,17 @@ suite_found:
     /* Look for the SCSV, and if found, treat it just like an empty RI
      * extension by processing a local copy of an empty RI extension.
      */
     for (i = 0; i + 2 < suite_length; i += 3) {
         PRUint32 suite_i = (suites[i] << 16) | (suites[i + 1] << 8) | suites[i + 2];
         if (suite_i == TLS_EMPTY_RENEGOTIATION_INFO_SCSV) {
             PRUint8 *b2 = (PRUint8 *)emptyRIext;
             PRUint32 L2 = sizeof emptyRIext;
-            (void)ssl3_HandleExtensions(ss, &b2, &L2, client_hello);
+            (void)ssl3_HandleExtensions(ss, &b2, &L2, ssl_hs_client_hello);
             break;
         }
     }
 
     if (ss->opt.requireSafeNegotiation &&
         !ssl3_ExtensionNegotiated(ss, ssl_renegotiation_info_xtn)) {
         desc = handshake_failure;
         errCode = SSL_ERROR_UNSAFE_NEGOTIATION;
@@ -9285,121 +9220,117 @@ loser:
 **  ssl3_SendServerHelloSequence <- ssl3_HandleClientHello   (new session),
 **  ssl3_SendServerHelloSequence <- ssl3_HandleV2ClientHello (new session)
 */
 SECStatus
 ssl3_SendServerHello(sslSocket *ss)
 {
     sslSessionID *sid;
     SECStatus rv;
-    PRUint32 maxBytes = 65535;
+    sslBuffer extensionBuf = { NULL, 0, 0 };
     PRUint32 length;
-    PRInt32 extensions_len = 0;
     SSL3ProtocolVersion version;
 
     SSL_TRC(3, ("%d: SSL3[%d]: send server_hello handshake", SSL_GETPID(),
                 ss->fd));
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
     PORT_Assert(MSB(ss->version) == MSB(SSL_LIBRARY_VERSION_3_0));
     if (MSB(ss->version) != MSB(SSL_LIBRARY_VERSION_3_0)) {
         PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
         return SECFailure;
     }
 
     sid = ss->sec.ci.sid;
 
-    extensions_len = ssl3_CallHelloExtensionSenders(
-        ss, PR_FALSE, maxBytes, &ss->xtnData.serverHelloSenders[0]);
-    if (extensions_len > 0)
-        extensions_len += 2; /* Add sizeof total extension length */
+    rv = ssl_ConstructExtensions(ss, &extensionBuf, ssl_hs_server_hello);
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
 
     /* TLS 1.3 doesn't use the session_id or compression_method
      * fields in the ServerHello. */
     length = sizeof(SSL3ProtocolVersion) + SSL3_RANDOM_LENGTH;
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
         length += 1 + ((sid == NULL) ? 0 : sid->u.ssl3.sessionIDLength);
     }
     length += sizeof(ssl3CipherSuite);
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
         length += 1; /* Compression */
     }
-    length += extensions_len;
-
-    rv = ssl3_AppendHandshakeHeader(ss, server_hello, length);
-    if (rv != SECSuccess) {
-        return rv; /* err set by AppendHandshake. */
+    if (extensionBuf.len) {
+        length += 2 + extensionBuf.len;
+    }
+
+    rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_server_hello, length);
+    if (rv != SECSuccess) {
+        goto loser; /* err set by AppendHandshake. */
     }
 
     if (IS_DTLS(ss) && ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
         version = dtls_TLSVersionToDTLSVersion(ss->version);
     } else {
         version = tls13_EncodeDraftVersion(ss->version);
     }
 
     rv = ssl3_AppendHandshakeNumber(ss, version, 2);
     if (rv != SECSuccess) {
-        return rv; /* err set by AppendHandshake. */
+        goto loser; /* err set by AppendHandshake. */
     }
     /* Random already generated in ssl3_HandleClientHello */
     rv = ssl3_AppendHandshake(
         ss, &ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH);
     if (rv != SECSuccess) {
-        return rv; /* err set by AppendHandshake. */
+        goto loser; /* err set by AppendHandshake. */
     }
 
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
         if (sid) {
             rv = ssl3_AppendHandshakeVariable(
                 ss, sid->u.ssl3.sessionID, sid->u.ssl3.sessionIDLength, 1);
         } else {
             rv = ssl3_AppendHandshakeNumber(ss, 0, 1);
         }
         if (rv != SECSuccess) {
-            return rv; /* err set by AppendHandshake. */
+            goto loser; /* err set by AppendHandshake. */
         }
     }
 
     rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.hs.cipher_suite, 2);
     if (rv != SECSuccess) {
-        return rv; /* err set by AppendHandshake. */
+        goto loser; /* err set by AppendHandshake. */
     }
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
         rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.hs.compression, 1);
         if (rv != SECSuccess) {
-            return rv; /* err set by AppendHandshake. */
-        }
-    }
-    if (extensions_len) {
-        PRInt32 sent_len;
-
-        extensions_len -= 2;
-        rv = ssl3_AppendHandshakeNumber(ss, extensions_len, 2);
-        if (rv != SECSuccess)
-            return rv; /* err set by ssl3_AppendHandshakeNumber */
-        sent_len = ssl3_CallHelloExtensionSenders(ss, PR_TRUE, extensions_len,
-                                                  &ss->xtnData.serverHelloSenders[0]);
-        PORT_Assert(sent_len == extensions_len);
-        if (sent_len != extensions_len) {
-            if (sent_len >= 0)
-                PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-            return SECFailure;
+            goto loser; /* err set by AppendHandshake. */
+        }
+    }
+    if (extensionBuf.len) {
+        rv = ssl3_AppendBufferToHandshakeVariable(ss, &extensionBuf, 2);
+        if (rv != SECSuccess) {
+            goto loser; /* err set by ssl3_AppendHandshakeVariable */
         }
     }
 
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
         rv = ssl3_SetupPendingCipherSpec(ss);
         if (rv != SECSuccess) {
-            return rv; /* err set by ssl3_SetupPendingCipherSpec */
-        }
-    }
-
+            goto loser; /* err set by ssl3_SetupPendingCipherSpec */
+        }
+    }
+
+    sslBuffer_Clear(&extensionBuf);
     return SECSuccess;
+
+loser:
+    sslBuffer_Clear(&extensionBuf);
+    return SECFailure;
 }
 
 SECStatus
 ssl_CreateDHEKeyPair(const sslNamedGroupDef *groupDef,
                      const ssl3DHParams *params,
                      sslEphemeralKeyPair **keyPair)
 {
     SECKEYDHParams dhParam;
@@ -9446,16 +9377,17 @@ ssl3_SendDHServerKeyExchange(sslSocket *
     SSL3Hashes hashes;
     SSLHashType hashAlg;
 
     const ssl3DHParams *params;
     sslEphemeralKeyPair *keyPair;
     SECKEYPublicKey *pubKey;
     SECKEYPrivateKey *certPrivateKey;
     const sslNamedGroupDef *groupDef;
+    sslBuffer dhBuf = { NULL, 0, 0 };
 
     if (kea_def->kea != kea_dhe_dss && kea_def->kea != kea_dhe_rsa) {
         /* TODO: Support DH_anon. It might be sufficient to drop the signature.
                  See bug 1170510. */
         PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
         return SECFailure;
     }
 
@@ -9505,56 +9437,63 @@ ssl3_SendDHServerKeyExchange(sslSocket *
              2 + pubKey->u.dh.base.len +
              2 + pubKey->u.dh.prime.len +
              2 + signed_hash.len;
 
     if (ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
         length += 2;
     }
 
-    rv = ssl3_AppendHandshakeHeader(ss, server_key_exchange, length);
+    rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_server_key_exchange, length);
     if (rv != SECSuccess) {
         goto loser; /* err set by AppendHandshake. */
     }
 
     rv = ssl3_AppendHandshakeVariable(ss, pubKey->u.dh.prime.data,
                                       pubKey->u.dh.prime.len, 2);
     if (rv != SECSuccess) {
         goto loser; /* err set by AppendHandshake. */
     }
 
     rv = ssl3_AppendHandshakeVariable(ss, pubKey->u.dh.base.data,
                                       pubKey->u.dh.base.len, 2);
     if (rv != SECSuccess) {
         goto loser; /* err set by AppendHandshake. */
     }
 
-    rv = ssl_AppendPaddedDHKeyShare(ss, pubKey, PR_TRUE);
+    rv = ssl_AppendPaddedDHKeyShare(&dhBuf, pubKey, PR_TRUE);
+    if (rv != SECSuccess) {
+        goto loser; /* err set by AppendPaddedDHKeyShare. */
+    }
+    rv = ssl3_AppendBufferToHandshake(ss, &dhBuf);
     if (rv != SECSuccess) {
         goto loser; /* err set by AppendHandshake. */
     }
 
     if (ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
         rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.hs.signatureScheme, 2);
         if (rv != SECSuccess) {
             goto loser; /* err set by AppendHandshake. */
         }
     }
 
     rv = ssl3_AppendHandshakeVariable(ss, signed_hash.data,
                                       signed_hash.len, 2);
     if (rv != SECSuccess) {
         goto loser; /* err set by AppendHandshake. */
     }
+
+    sslBuffer_Clear(&dhBuf);
     PORT_Free(signed_hash.data);
     return SECSuccess;
 
 loser:
     if (signed_hash.data)
         PORT_Free(signed_hash.data);
+    sslBuffer_Clear(&dhBuf);
     return SECFailure;
 }
 
 static SECStatus
 ssl3_SendServerKeyExchange(sslSocket *ss)
 {
     const ssl3KEADef *kea_def = ss->ssl3.hs.kea_def;
 
@@ -9656,17 +9595,17 @@ ssl3_SendCertificateRequest(sslSocket *s
     if (isTLS12) {
         rv = ssl3_EncodeSigAlgs(ss, sigAlgs, sizeof(sigAlgs), &sigAlgsLength);
         if (rv != SECSuccess) {
             return rv;
         }
         length += 2 + sigAlgsLength;
     }
 
-    rv = ssl3_AppendHandshakeHeader(ss, certificate_request, length);
+    rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_certificate_request, length);
     if (rv != SECSuccess) {
         return rv; /* err set by AppendHandshake. */
     }
     rv = ssl3_AppendHandshakeVariable(ss, certTypes, certTypesLength, 1);
     if (rv != SECSuccess) {
         return rv; /* err set by AppendHandshake. */
     }
     if (isTLS12) {
@@ -9695,17 +9634,17 @@ ssl3_SendServerHelloDone(sslSocket *ss)
     SECStatus rv;
 
     SSL_TRC(3, ("%d: SSL3[%d]: send server_hello_done handshake",
                 SSL_GETPID(), ss->fd));
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
-    rv = ssl3_AppendHandshakeHeader(ss, server_hello_done, 0);
+    rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_server_hello_done, 0);
     if (rv != SECSuccess) {
         return rv; /* err set by AppendHandshake. */
     }
     rv = ssl3_FlushHandshake(ss, 0);
     if (rv != SECSuccess) {
         return rv; /* error code set by ssl3_FlushHandshake */
     }
     return SECSuccess;
@@ -9760,23 +9699,22 @@ ssl3_HandleCertificateVerify(sslSocket *
         if (rv != SECSuccess) {
             errCode = PORT_GetError();
             desc = decrypt_error;
             goto alert_loser;
         }
 
         hashAlg = ssl_SignatureSchemeToHashType(sigScheme);
 
-        if (hashes->u.pointer_to_hash_input.data) {
-            rv = ssl3_ComputeHandshakeHash(hashes->u.pointer_to_hash_input.data,
-                                           hashes->u.pointer_to_hash_input.len,
-                                           hashAlg, &localHashes);
-        } else {
-            rv = SECFailure;
-        }
+        /* Read from the message buffer, but we need to use only up to the end
+         * of the previous handshake message. The length of the transcript up to
+         * that point is saved in |hashes->u.transcriptLen|. */
+        rv = ssl3_ComputeHandshakeHash(ss->ssl3.hs.messages.buf,
+                                       hashes->u.transcriptLen,
+                                       hashAlg, &localHashes);
 
         if (rv == SECSuccess) {
             hashesForVerify = &localHashes;
         } else {
             errCode = SSL_ERROR_DIGEST_FAILURE;
             desc = decrypt_error;
             goto alert_loser;
         }
@@ -10178,17 +10116,17 @@ ssl3_SendEmptyCertificate(sslSocket *ss)
 
     if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
         PORT_Assert(ss->ssl3.hs.clientCertRequested);
         context = &ss->xtnData.certReqContext;
         len = context->len + 1;
         isTLS13 = PR_TRUE;
     }
 
-    rv = ssl3_AppendHandshakeHeader(ss, certificate, len + 3);
+    rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_certificate, len + 3);
     if (rv != SECSuccess) {
         return rv;
     }
 
     if (isTLS13) {
         rv = ssl3_AppendHandshakeVariable(ss, context->data, context->len, 1);
         if (rv != SECSuccess) {
             return rv;
@@ -10210,17 +10148,17 @@ ssl3_SendNewSessionTicket(sslSocket *ss)
     NewSessionTicket nticket = { 0 };
 
     rv = ssl3_EncodeSessionTicket(ss, &nticket, &ticket);
     if (rv != SECSuccess)
         goto loser;
 
     /* Serialize the handshake message. Length =
      * lifetime (4) + ticket length (2) + ticket. */
-    rv = ssl3_AppendHandshakeHeader(ss, new_session_ticket,
+    rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_new_session_ticket,
                                     4 + 2 + ticket.len);
     if (rv != SECSuccess)
         goto loser;
 
     /* This is a fixed value. */
     rv = ssl3_AppendHandshakeNumber(ss, ssl_ticket_lifetime, 4);
     if (rv != SECSuccess)
         goto loser;
@@ -10421,17 +10359,17 @@ ssl3_SendCertificate(sslSocket *ss)
                 certChainLen += certChain->certs[i].len + 3;
             }
 #else
             certChainLen += certChain->certs[i].len + 3;
 #endif
         }
     }
 
-    rv = ssl3_AppendHandshakeHeader(ss, certificate,
+    rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_certificate,
                                     contextLen + certChainLen + 3);
     if (rv != SECSuccess) {
         return rv; /* err set by AppendHandshake. */
     }
 
     if (isTLS13) {
         rv = ssl3_AppendHandshakeVariable(ss, context.data,
                                           context.len, 1);
@@ -10496,17 +10434,17 @@ ssl3_SendCertificateStatus(sslSocket *ss
         statusToSend = serverCert->certStatusArray;
     }
     if (!statusToSend)
         return SECSuccess;
 
     /* Use the array's first item only (single stapling) */
     len = 1 + statusToSend->items[0].len + 3;
 
-    rv = ssl3_AppendHandshakeHeader(ss, certificate_status, len);
+    rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_certificate_status, len);
     if (rv != SECSuccess) {
         return rv; /* err set by AppendHandshake. */
     }
     rv = ssl3_AppendHandshakeNumber(ss, 1 /*ocsp*/, 1);
     if (rv != SECSuccess)
         return rv; /* err set by AppendHandshake. */
 
     rv = ssl3_AppendHandshakeVariable(ss,
@@ -11136,17 +11074,17 @@ ssl3_SendNextProto(sslSocket *ss)
         return SECSuccess;
     }
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
     padding_len = 32 - ((ss->xtnData.nextProto.len + 2) % 32);
 
-    rv = ssl3_AppendHandshakeHeader(ss, next_proto, ss->xtnData.nextProto.len + 2 + padding_len);
+    rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_next_proto, ss->xtnData.nextProto.len + 2 + padding_len);
     if (rv != SECSuccess) {
         return rv; /* error code set by AppendHandshakeHeader */
     }
     rv = ssl3_AppendHandshakeVariable(ss, ss->xtnData.nextProto.data,
                                       ss->xtnData.nextProto.len, 1);
     if (rv != SECSuccess) {
         return rv; /* error code set by AppendHandshake */
     }
@@ -11251,30 +11189,30 @@ ssl3_SendFinished(sslSocket *ss, PRInt32
     }
 
     if (isTLS) {
         if (isServer)
             ss->ssl3.hs.finishedMsgs.tFinished[1] = tlsFinished;
         else
             ss->ssl3.hs.finishedMsgs.tFinished[0] = tlsFinished;
         ss->ssl3.hs.finishedBytes = sizeof tlsFinished;
-        rv = ssl3_AppendHandshakeHeader(ss, finished, sizeof tlsFinished);
+        rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_finished, sizeof tlsFinished);
         if (rv != SECSuccess)
             goto fail; /* err set by AppendHandshake. */
         rv = ssl3_AppendHandshake(ss, &tlsFinished, sizeof tlsFinished);
         if (rv != SECSuccess)
             goto fail; /* err set by AppendHandshake. */
     } else {
         if (isServer)
             ss->ssl3.hs.finishedMsgs.sFinished[1] = hashes.u.s;
         else
             ss->ssl3.hs.finishedMsgs.sFinished[0] = hashes.u.s;
         PORT_Assert(hashes.len == sizeof hashes.u.s);
         ss->ssl3.hs.finishedBytes = sizeof hashes.u.s;
-        rv = ssl3_AppendHandshakeHeader(ss, finished, sizeof hashes.u.s);
+        rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_finished, sizeof hashes.u.s);
         if (rv != SECSuccess)
             goto fail; /* err set by AppendHandshake. */
         rv = ssl3_AppendHandshake(ss, &hashes.u.s, sizeof hashes.u.s);
         if (rv != SECSuccess)
             goto fail; /* err set by AppendHandshake. */
     }
     rv = ssl3_FlushHandshake(ss, flags);
     if (rv != SECSuccess) {
@@ -11637,75 +11575,76 @@ ssl3_FinishHandshake(sslSocket *ss)
  * hanshake message.
  * Caller must hold Handshake and RecvBuf locks.
  */
 SECStatus
 ssl3_HandleHandshakeMessage(sslSocket *ss, PRUint8 *b, PRUint32 length,
                             PRBool endOfRecord)
 {
     SECStatus rv = SECSuccess;
-    SSL3HandshakeType type = ss->ssl3.hs.msg_type;
+    SSLHandshakeType type = ss->ssl3.hs.msg_type;
     SSL3Hashes hashes;            /* computed hashes are put here. */
     SSL3Hashes *hashesPtr = NULL; /* Set when hashes are computed */
     PRUint8 hdr[4];
     PRUint8 dtlsData[8];
     PRBool computeHashes = PR_FALSE;
     PRUint16 epoch;
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
     /*
      * We have to compute the hashes before we update them with the
      * current message.
      */
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
-        if ((type == finished) && (ss->ssl3.hs.ws == wait_finished)) {
+        if ((type == ssl_hs_finished) && (ss->ssl3.hs.ws == wait_finished)) {
             computeHashes = PR_TRUE;
-        } else if ((type == certificate_verify) && (ss->ssl3.hs.ws == wait_cert_verify)) {
+        } else if ((type == ssl_hs_certificate_verify) &&
+                   (ss->ssl3.hs.ws == wait_cert_verify)) {
             if (ss->ssl3.hs.hashType == handshake_hash_record) {
                 /* We cannot compute the hash yet. We must wait until we have
                  * decoded the certificate_verify message in
                  * ssl3_HandleCertificateVerify, which will tell us which
                  * hash function we must use.
                  *
                  * (ssl3_HandleCertificateVerify cannot simply look at the
                  * buffer length itself, because at the time we reach it,
                  * additional handshake messages will have been added to the
                  * buffer, e.g. the certificate_verify message itself.)
                  *
-                 * Therefore, we use SSL3Hashes.u.pointer_to_hash_input
-                 * to signal the current state of the buffer.
+                 * Therefore, we use SSL3Hashes.u.transcriptLen to save how much
+                 * data there is and read directly from ss->ssl3.hs.messages
+                 * when calculating the hashes.
                  *
                  * ssl3_HandleCertificateVerify will detect
                  *     hashType == handshake_hash_record
                  * and use that information to calculate the hash.
                  */
-                hashes.u.pointer_to_hash_input.data = ss->ssl3.hs.messages.buf;
-                hashes.u.pointer_to_hash_input.len = ss->ssl3.hs.messages.len;
+                hashes.u.transcriptLen = ss->ssl3.hs.messages.len;
                 hashesPtr = &hashes;
             } else {
                 computeHashes = PR_TRUE;
             }
         }
     } else {
-        if (type == certificate_verify) {
+        if (type == ssl_hs_certificate_verify) {
             computeHashes = TLS13_IN_HS_STATE(ss, wait_cert_verify);
-        } else if (type == finished) {
+        } else if (type == ssl_hs_finished) {
             computeHashes =
                 TLS13_IN_HS_STATE(ss, wait_cert_request, wait_finished);
         }
     }
 
     ssl_GetSpecReadLock(ss); /************************************/
     if (computeHashes) {
         SSL3Sender sender = (SSL3Sender)0;
         ssl3CipherSpec *rSpec = ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 ? ss->ssl3.crSpec
                                                                            : ss->ssl3.prSpec;
 
-        if (type == finished) {
+        if (type == ssl_hs_finished) {
             sender = ss->sec.isServer ? sender_client : sender_server;
             rSpec = ss->ssl3.crSpec;
         }
         rv = ssl3_ComputeHandshakeHashes(ss, rSpec, &hashes, sender);
         if (rv == SECSuccess) {
             hashesPtr = &hashes;
         }
     }
@@ -11718,23 +11657,23 @@ ssl3_HandleHandshakeMessage(sslSocket *s
 
     hdr[0] = (PRUint8)ss->ssl3.hs.msg_type;
     hdr[1] = (PRUint8)(length >> 16);
     hdr[2] = (PRUint8)(length >> 8);
     hdr[3] = (PRUint8)(length);
 
     /* Start new handshake hashes when we start a new handshake.  Unless this is
      * TLS 1.3 and we sent a HelloRetryRequest. */
-    if (ss->ssl3.hs.msg_type == client_hello && !ss->ssl3.hs.helloRetry) {
+    if (ss->ssl3.hs.msg_type == ssl_hs_client_hello && !ss->ssl3.hs.helloRetry) {
         ssl3_RestartHandshakeHashes(ss);
     }
     /* We should not include hello_request and hello_verify_request messages
      * in the handshake hashes */
-    if ((ss->ssl3.hs.msg_type != hello_request) &&
-        (ss->ssl3.hs.msg_type != hello_verify_request)) {
+    if ((ss->ssl3.hs.msg_type != ssl_hs_hello_request) &&
+        (ss->ssl3.hs.msg_type != ssl_hs_hello_verify_request)) {
         rv = ssl3_UpdateHandshakeHashes(ss, (unsigned char *)hdr, 4);
         if (rv != SECSuccess)
             return rv; /* err code already set. */
 
         /* Extra data to simulate a complete DTLS handshake fragment */
         if (IS_DTLS(ss)) {
             /* Sequence number */
             dtlsData[0] = MSB(ss->ssl3.hs.recvMessageSeq);
@@ -11760,42 +11699,42 @@ ssl3_HandleHandshakeMessage(sslSocket *s
         rv = ssl3_UpdateHandshakeHashes(ss, b, length);
         if (rv != SECSuccess)
             return rv; /* err code already set. */
     }
 
     PORT_SetError(0); /* each message starts with no error. */
 
     if (ss->ssl3.hs.ws == wait_certificate_status &&
-        ss->ssl3.hs.msg_type != certificate_status) {
+        ss->ssl3.hs.msg_type != ssl_hs_certificate_status) {
         /* If we negotiated the certificate_status extension then we deferred
          * certificate validation until we get the CertificateStatus messsage.
          * But the CertificateStatus message is optional. If the server did
          * not send it then we need to validate the certificate now. If the
          * server does send the CertificateStatus message then we will
          * authenticate the certificate in ssl3_HandleCertificateStatus.
          */
         rv = ssl3_AuthCertificate(ss); /* sets ss->ssl3.hs.ws */
         PORT_Assert(rv != SECWouldBlock);
         if (rv != SECSuccess) {
             return rv;
         }
     }
 
     epoch = ss->ssl3.crSpec->epoch;
     switch (ss->ssl3.hs.msg_type) {
-        case client_hello:
+        case ssl_hs_client_hello:
             if (!ss->sec.isServer) {
                 (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
                 PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CLIENT_HELLO);
                 return SECFailure;
             }
             rv = ssl3_HandleClientHello(ss, b, length);
             break;
-        case server_hello:
+        case ssl_hs_server_hello:
             if (ss->sec.isServer) {
                 (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
                 PORT_SetError(SSL_ERROR_RX_UNEXPECTED_SERVER_HELLO);
                 return SECFailure;
             }
             rv = ssl3_HandleServerHello(ss, b, length);
             break;
         default:
@@ -11826,104 +11765,104 @@ ssl3_HandleHandshakeMessage(sslSocket *s
 static SECStatus
 ssl3_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b,
                                      PRUint32 length, SSL3Hashes *hashesPtr)
 {
     SECStatus rv;
     PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3);
 
     switch (ss->ssl3.hs.msg_type) {
-        case hello_request:
+        case ssl_hs_hello_request:
             if (length != 0) {
                 (void)ssl3_DecodeError(ss);
                 PORT_SetError(SSL_ERROR_RX_MALFORMED_HELLO_REQUEST);
                 return SECFailure;
             }
             if (ss->sec.isServer) {
                 (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
                 PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HELLO_REQUEST);
                 return SECFailure;
             }
             rv = ssl3_HandleHelloRequest(ss);
             break;
 
-        case hello_retry_request:
+        case ssl_hs_hello_retry_request:
             /* This arrives here because - as a client - we haven't received a
              * final decision on the version from the server. */
             rv = tls13_HandleHelloRetryRequest(ss, b, length);
             break;
 
-        case hello_verify_request:
+        case ssl_hs_hello_verify_request:
             if (!IS_DTLS(ss) || ss->sec.isServer) {
                 (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
                 PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HELLO_VERIFY_REQUEST);
                 return SECFailure;
             }
             rv = dtls_HandleHelloVerifyRequest(ss, b, length);
             break;
-        case certificate:
+        case ssl_hs_certificate:
             rv = ssl3_HandleCertificate(ss, b, length);
             break;
-        case certificate_status:
+        case ssl_hs_certificate_status:
             rv = ssl3_HandleCertificateStatus(ss, b, length);
             break;
-        case server_key_exchange:
+        case ssl_hs_server_key_exchange:
             if (ss->sec.isServer) {
                 (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
                 PORT_SetError(SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH);
                 return SECFailure;
             }
             rv = ssl3_HandleServerKeyExchange(ss, b, length);
             break;
-        case certificate_request:
+        case ssl_hs_certificate_request:
             if (ss->sec.isServer) {
                 (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
                 PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST);
                 return SECFailure;
             }
             rv = ssl3_HandleCertificateRequest(ss, b, length);
             break;
-        case server_hello_done:
+        case ssl_hs_server_hello_done:
             if (length != 0) {
                 (void)ssl3_DecodeError(ss);
                 PORT_SetError(SSL_ERROR_RX_MALFORMED_HELLO_DONE);
                 return SECFailure;
             }
             if (ss->sec.isServer) {
                 (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
                 PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HELLO_DONE);
                 return SECFailure;
             }
             rv = ssl3_HandleServerHelloDone(ss);
             break;
-        case certificate_verify:
+        case ssl_hs_certificate_verify:
             if (!ss->sec.isServer) {
                 (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
                 PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY);
                 return SECFailure;
             }
             rv = ssl3_HandleCertificateVerify(ss, b, length, hashesPtr);
             break;
-        case client_key_exchange:
+        case ssl_hs_client_key_exchange:
             if (!ss->sec.isServer) {
                 (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
                 PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CLIENT_KEY_EXCH);
                 return SECFailure;
             }
             rv = ssl3_HandleClientKeyExchange(ss, b, length);
             break;
-        case new_session_ticket:
+        case ssl_hs_new_session_ticket:
             if (ss->sec.isServer) {
                 (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
                 PORT_SetError(SSL_ERROR_RX_UNEXPECTED_NEW_SESSION_TICKET);
                 return SECFailure;
             }
             rv = ssl3_HandleNewSessionTicket(ss, b, length);
             break;
-        case finished:
+        case ssl_hs_finished:
             rv = ssl3_HandleFinished(ss, b, length, hashesPtr);
             break;
         default:
             (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
             PORT_SetError(SSL_ERROR_RX_UNKNOWN_HANDSHAKE);
             rv = SECFailure;
     }
 
@@ -11955,17 +11894,17 @@ ssl3_HandleHandshake(sslSocket *ss, sslB
         *buf = *origBuf;
     }
     while (buf->len > 0) {
         if (ss->ssl3.hs.header_bytes < 4) {
             PRUint8 t;
             t = *(buf->buf++);
             buf->len--;
             if (ss->ssl3.hs.header_bytes++ == 0)
-                ss->ssl3.hs.msg_type = (SSL3HandshakeType)t;
+                ss->ssl3.hs.msg_type = (SSLHandshakeType)t;
             else
                 ss->ssl3.hs.msg_len = (ss->ssl3.hs.msg_len << 8) + t;
             if (ss->ssl3.hs.header_bytes < 4)
                 continue;
 
 #define MAX_HANDSHAKE_MSG_LEN 0x1ffff /* 128k - 1 */
             if (ss->ssl3.hs.msg_len > MAX_HANDSHAKE_MSG_LEN) {
                 (void)ssl3_DecodeError(ss);
--- a/lib/ssl/ssl3ecc.c
+++ b/lib/ssl/ssl3ecc.c
@@ -214,17 +214,17 @@ ssl3_SendECDHClientKeyExchange(sslSocket
                                 CKA_DERIVE, 0, CKD_NULL, NULL, NULL);
 
     if (pms == NULL) {
         (void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
         ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
         goto loser;
     }
 
-    rv = ssl3_AppendHandshakeHeader(ss, client_key_exchange,
+    rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_client_key_exchange,
                                     pubKey->u.ec.publicValue.len + 1);
     if (rv != SECSuccess) {
         goto loser; /* err set by ssl3_AppendHandshake* */
     }
 
     rv = ssl3_AppendHandshakeVariable(ss, pubKey->u.ec.publicValue.data,
                                       pubKey->u.ec.publicValue.len, 1);
 
@@ -245,29 +245,16 @@ ssl3_SendECDHClientKeyExchange(sslSocket
 loser:
     if (pms)
         PK11_FreeSymKey(pms);
     if (keyPair)
         ssl_FreeEphemeralKeyPair(keyPair);
     return SECFailure;
 }
 
-/* This function encodes the key_exchange field in
- * the KeyShareEntry structure. */
-SECStatus
-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_ExtAppendHandshake(ss, pubKey->u.ec.publicValue.data,
-                                   pubKey->u.ec.publicValue.len);
-}
-
 /*
 ** Called from ssl3_HandleClientKeyExchange()
 */
 SECStatus
 ssl3_HandleECDHClientKeyExchange(sslSocket *ss, PRUint8 *b,
                                  PRUint32 length,
                                  sslKeyPair *serverKeyPair)
 {
@@ -726,17 +713,17 @@ ssl3_SendECDHServerKeyExchange(sslSocket
     if (rv != SECSuccess) {
         goto loser; /* ssl3_SignHashes has set err. */
     }
 
     length = ec_params.len +
              1 + pubKey->u.ec.publicValue.len +
              (isTLS12 ? 2 : 0) + 2 + signed_hash.len;
 
-    rv = ssl3_AppendHandshakeHeader(ss, server_key_exchange, length);
+    rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_server_key_exchange, length);
     if (rv != SECSuccess) {
         goto loser; /* err set by AppendHandshake. */
     }
 
     rv = ssl3_AppendHandshake(ss, ec_params.data, ec_params.len);
     if (rv != SECSuccess) {
         goto loser; /* err set by AppendHandshake. */
     }
@@ -865,124 +852,97 @@ ssl_IsECCEnabled(const sslSocket *ss)
 
 PRBool
 ssl_IsDHEEnabled(const sslSocket *ss)
 {
     return ssl_IsSuiteEnabled(ss, ssl_dhe_suites);
 }
 
 /* Send our Supported Groups extension. */
-PRInt32
-ssl_SendSupportedGroupsXtn(const sslSocket *ss,
-                           TLSExtensionData *xtnData,
-                           PRBool append, PRUint32 maxBytes)
+SECStatus
+ssl_SendSupportedGroupsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                           sslBuffer *buf, PRBool *added)
 {
-    PRInt32 extension_length;
-    unsigned char enabledGroups[64];
-    unsigned int enabledGroupsLen = 0;
     unsigned int i;
     PRBool ec;
     PRBool ff = PR_FALSE;
-
-    if (!ss)
-        return 0;
+    SECStatus rv;
+    sslBuffer tmpBuf = { NULL, 0, 0 };
 
     /* We only send FF supported groups if we require DH named groups
      * or if TLS 1.3 is a possibility. */
     if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3) {
         ec = ssl_IsECCEnabled(ss);
         if (ss->opt.requireDHENamedGroups) {
             ff = ssl_IsDHEEnabled(ss);
         }
-        if (!ec && !ff)
-            return 0;
+        if (!ec && !ff) {
+            return SECSuccess;
+        }
     } else {
         ec = ff = PR_TRUE;
     }
 
-    PORT_Assert(sizeof(enabledGroups) > SSL_NAMED_GROUP_COUNT * 2);
+    /* Reserve space for the length. */
     for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) {
         const sslNamedGroupDef *group = ss->namedGroupPreferences[i];
         if (!group) {
             continue;
         }
         if (group->keaType == ssl_kea_ecdh && !ec) {
             continue;
         }
         if (group->keaType == ssl_kea_dh && !ff) {
             continue;
         }
 
-        if (append) {
-            (void)ssl_EncodeUintX(group->name, 2, &enabledGroups[enabledGroupsLen]);
+        rv = sslBuffer_AppendNumber(&tmpBuf, group->name, 2);
+        if (rv != SECSuccess) {
+            sslBuffer_Clear(&tmpBuf);
+            return SECFailure;
         }
-        enabledGroupsLen += 2;
-    }
-
-    if (enabledGroupsLen == 0) {
-        return 0;
     }
 
-    extension_length =
-        2 /* extension type */ +
-        2 /* extension length */ +
-        2 /* enabled groups length */ +
-        enabledGroupsLen;
-
-    if (maxBytes < (PRUint32)extension_length) {
-        return 0;
+    if (!tmpBuf.len) {
+        sslBuffer_Clear(&tmpBuf);
+        /* We added nothing, don't send the extension. */
+        return SECSuccess;
     }
 
-    if (append) {
-        SECStatus rv;
-        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_supported_groups_xtn, 2);
-        if (rv != SECSuccess)
-            return -1;
-        rv = ssl3_ExtAppendHandshakeNumber(ss, extension_length - 4, 2);
-        if (rv != SECSuccess)
-            return -1;
-        rv = ssl3_ExtAppendHandshakeVariable(ss, enabledGroups,
-                                             enabledGroupsLen, 2);
-        if (rv != SECSuccess)
-            return -1;
-        if (!ss->sec.isServer) {
-            xtnData->advertised[xtnData->numAdvertised++] =
-                ssl_supported_groups_xtn;
-        }
+    rv = sslBuffer_AppendBufferVariable(buf, &tmpBuf, 2);
+    sslBuffer_Clear(&tmpBuf);
+    if (rv != SECSuccess) {
+        return SECFailure;
     }
-    return extension_length;
+
+    *added = PR_TRUE;
+    return SECSuccess;
 }
 
 /* Send our "canned" (precompiled) Supported Point Formats extension,
  * which says that we only support uncompressed points.
  */
-PRInt32
-ssl3_SendSupportedPointFormatsXtn(
-    const sslSocket *ss,
-    TLSExtensionData *xtnData,
-    PRBool append,
-    PRUint32 maxBytes)
+SECStatus
+ssl3_SendSupportedPointFormatsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                                  sslBuffer *buf, PRBool *added)
 {
-    static const PRUint8 ecPtFmt[6] = {
-        0, 11, /* Extension type */
-        0, 2,  /* octets that follow */
-        1,     /* octets that follow */
-        0      /* uncompressed type only */
-    };
+    SECStatus rv;
 
     /* 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_ExtAppendHandshake(ss, ecPtFmt, (sizeof ecPtFmt));
-        if (rv != SECSuccess)
-            return -1;
-        if (!ss->sec.isServer) {
-            xtnData->advertised[xtnData->numAdvertised++] =
-                ssl_ec_point_formats_xtn;
-        }
+        (ss->sec.isServer && ss->version >= SSL_LIBRARY_VERSION_TLS_1_3)) {
+        return SECSuccess;
+    }
+    rv = sslBuffer_AppendNumber(buf, 1, 1); /* length */
+    if (rv != SECSuccess) {
+        return SECFailure;
     }
-    return sizeof(ecPtFmt);
+    rv = sslBuffer_AppendNumber(buf, 0, 1); /* uncompressed type only */
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
+
+    *added = PR_TRUE;
+    return SECSuccess;
 }
deleted file mode 100644
--- a/lib/ssl/ssl3encode.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/* -*- 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/. */
-
-#include "prnetdb.h"
-#include "seccomon.h"
-#include "secerr.h"
-#include "ssl3encode.h"
-
-SECStatus
-ssl3_AppendToItem(SECItem *item, const unsigned char *buf, PRUint32 bytes)
-{
-    if (bytes > item->len) {
-        PORT_SetError(SEC_ERROR_INVALID_ARGS);
-        return SECFailure;
-    }
-
-    PORT_Memcpy(item->data, buf, bytes);
-    item->data += bytes;
-    item->len -= bytes;
-    return SECSuccess;
-}
-
-SECStatus
-ssl3_AppendNumberToItem(SECItem *item, PRUint32 num, PRInt32 lenSize)
-{
-    SECStatus rv;
-    PRUint8 b[4];
-
-    ssl_EncodeUintX(num, lenSize, b);
-    rv = ssl3_AppendToItem(item, &b[0], lenSize);
-    return rv;
-}
-
-SECStatus
-ssl3_ConsumeFromItem(SECItem *item, unsigned char **buf, PRUint32 bytes)
-{
-    if (bytes > item->len) {
-        PORT_SetError(SEC_ERROR_BAD_DATA);
-        return SECFailure;
-    }
-
-    *buf = item->data;
-    item->data += bytes;
-    item->len -= bytes;
-    return SECSuccess;
-}
-
-SECStatus
-ssl3_ConsumeNumberFromItem(SECItem *item, PRUint32 *num, PRUint32 bytes)
-{
-    int i;
-
-    if (bytes > item->len || bytes > sizeof(*num)) {
-        PORT_SetError(SEC_ERROR_BAD_DATA);
-        return SECFailure;
-    }
-
-    *num = 0;
-    for (i = 0; i < bytes; i++) {
-        *num = (*num << 8) + item->data[i];
-    }
-
-    item->data += bytes;
-    item->len -= bytes;
-
-    return SECSuccess;
-}
-
-/* Helper function to encode an unsigned integer into a buffer. */
-PRUint8 *
-ssl_EncodeUintX(PRUint64 value, unsigned int bytes, PRUint8 *to)
-{
-    PRUint64 encoded;
-
-    PORT_Assert(bytes > 0 && bytes <= sizeof(encoded));
-
-    encoded = PR_htonll(value);
-    memcpy(to, ((unsigned char *)(&encoded)) + (sizeof(encoded) - bytes), bytes);
-    return to + bytes;
-}
deleted file mode 100644
--- a/lib/ssl/ssl3encode.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/* -*- 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 __ssl3encode_h_
-#define __ssl3encode_h_
-
-#include "seccomon.h"
-
-/* All of these functions modify the underlying SECItem, and so should
- * be performed on a shallow copy.*/
-SECStatus ssl3_AppendToItem(SECItem *item,
-                            const unsigned char *buf, PRUint32 bytes);
-SECStatus ssl3_AppendNumberToItem(SECItem *item,
-                                  PRUint32 num, PRInt32 lenSize);
-SECStatus ssl3_ConsumeFromItem(SECItem *item,
-                               unsigned char **buf, PRUint32 bytes);
-SECStatus ssl3_ConsumeNumberFromItem(SECItem *item,
-                                     PRUint32 *num, PRUint32 bytes);
-PRUint8 *ssl_EncodeUintX(PRUint64 value, unsigned int bytes, PRUint8 *to);
-
-#endif
--- a/lib/ssl/ssl3ext.c
+++ b/lib/ssl/ssl3ext.c
@@ -11,16 +11,27 @@
 #include "nssrenam.h"
 #include "nss.h"
 #include "ssl.h"
 #include "sslimpl.h"
 #include "sslproto.h"
 #include "ssl3exthandle.h"
 #include "tls13exthandle.h"
 
+/* Callback function that handles a received extension. */
+typedef SECStatus (*ssl3ExtensionHandlerFunc)(const sslSocket *ss,
+                                              TLSExtensionData *xtnData,
+                                              SECItem *data);
+
+/* Row in a table of hello extension handlers. */
+typedef struct {
+    SSLExtensionType ex_type;
+    ssl3ExtensionHandlerFunc ex_handler;
+} ssl3ExtensionHandler;
+
 /* Table of handlers for received TLS hello extensions, one per extension.
  * In the second generation, this table will be dynamic, and functions
  * will be registered here.
  */
 /* This table is used by the server, to handle client hello extensions. */
 static const ssl3ExtensionHandler clientHelloHandlers[] = {
     { ssl_server_name_xtn, &ssl3_HandleServerNameXtn },
     { ssl_supported_groups_xtn, &ssl_HandleSupportedGroupsXtn },
@@ -32,20 +43,18 @@ static const ssl3ExtensionHandler client
     { ssl_use_srtp_xtn, &ssl3_ServerHandleUseSRTPXtn },
     { ssl_cert_status_xtn, &ssl3_ServerHandleStatusRequestXtn },
     { ssl_signature_algorithms_xtn, &ssl3_HandleSigAlgsXtn },
     { ssl_extended_master_secret_xtn, &ssl3_HandleExtendedMasterSecretXtn },
     { ssl_signed_cert_timestamp_xtn, &ssl3_ServerHandleSignedCertTimestampXtn },
     { ssl_tls13_key_share_xtn, &tls13_ServerHandleKeyShareXtn },
     { ssl_tls13_pre_shared_key_xtn, &tls13_ServerHandlePreSharedKeyXtn },
     { ssl_tls13_early_data_xtn, &tls13_ServerHandleEarlyDataXtn },
-    { ssl_tls13_psk_key_exchange_modes_xtn,
-      &tls13_ServerHandlePskKeyExchangeModesXtn },
-    { ssl_tls13_short_header_xtn, &tls13_HandleShortHeaderXtn },
-    { -1, NULL }
+    { ssl_tls13_psk_key_exchange_modes_xtn, &tls13_ServerHandlePskModesXtn },
+    { 0, NULL }
 };
 
 /* These two tables are used by the client, to handle server hello
  * extensions. */
 static const ssl3ExtensionHandler serverHelloHandlersTLS[] = {
     { ssl_server_name_xtn, &ssl3_HandleServerNameXtn },
     /* TODO: add a handler for ssl_ec_point_formats_xtn */
     { ssl_session_ticket_xtn, &ssl3_ClientHandleSessionTicketXtn },
@@ -54,97 +63,99 @@ static const ssl3ExtensionHandler server
     { ssl_app_layer_protocol_xtn, &ssl3_ClientHandleAppProtoXtn },
     { ssl_use_srtp_xtn, &ssl3_ClientHandleUseSRTPXtn },
     { ssl_cert_status_xtn, &ssl3_ClientHandleStatusRequestXtn },
     { ssl_extended_master_secret_xtn, &ssl3_HandleExtendedMasterSecretXtn },
     { ssl_signed_cert_timestamp_xtn, &ssl3_ClientHandleSignedCertTimestampXtn },
     { ssl_tls13_key_share_xtn, &tls13_ClientHandleKeyShareXtn },
     { ssl_tls13_pre_shared_key_xtn, &tls13_ClientHandlePreSharedKeyXtn },
     { ssl_tls13_early_data_xtn, &tls13_ClientHandleEarlyDataXtn },
-    { ssl_tls13_short_header_xtn, &tls13_HandleShortHeaderXtn },
-    { -1, NULL }
+    { 0, NULL }
 };
 
 static const ssl3ExtensionHandler helloRetryRequestHandlers[] = {
     { ssl_tls13_key_share_xtn, tls13_ClientHandleKeyShareXtnHrr },
     { ssl_tls13_cookie_xtn, tls13_ClientHandleHrrCookie },
-    { -1, NULL }
+    { 0, NULL }
 };
 
 static const ssl3ExtensionHandler serverHelloHandlersSSL3[] = {
     { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn },
-    { -1, NULL }
+    { 0, NULL }
 };
 
 static const ssl3ExtensionHandler newSessionTicketHandlers[] = {
     { ssl_tls13_early_data_xtn,
       &tls13_ClientHandleTicketEarlyDataXtn },
-    { -1, NULL }
+    { 0, NULL }
 };
 
 /* This table is used by the client to handle server certificates in TLS 1.3 */
 static const ssl3ExtensionHandler serverCertificateHandlers[] = {
     { ssl_signed_cert_timestamp_xtn, &ssl3_ClientHandleSignedCertTimestampXtn },
     { ssl_cert_status_xtn, &ssl3_ClientHandleStatusRequestXtn },
-    { -1, NULL }
+    { 0, NULL }
 };
 
 static const ssl3ExtensionHandler certificateRequestHandlers[] = {
     { ssl_signature_algorithms_xtn, &ssl3_HandleSigAlgsXtn },
     { ssl_tls13_certificate_authorities_xtn,
       &tls13_ClientHandleCertAuthoritiesXtn },
-    { -1, NULL }
+    { 0, NULL }
 };
 
 /* Tables of functions to format TLS hello extensions, one function per
  * extension.
  * These static tables are for the formatting of client hello extensions.
  * The server's table of hello senders is dynamic, in the socket struct,
  * and sender functions are registered there.
  * NB: the order of these extensions can have an impact on compatibility. Some
  * servers (e.g. Tomcat) will terminate the connection if the last extension in
  * the client hello is empty (for example, the extended master secret
  * extension, if it were listed last). See bug 1243641.
  */
-static const ssl3HelloExtensionSender clientHelloSendersTLS[] =
+static const sslExtensionBuilder clientHelloSendersTLS[] =
     {
-      { ssl_server_name_xtn, &ssl3_SendServerNameXtn },
+      { ssl_server_name_xtn, &ssl3_ClientSendServerNameXtn },
       { ssl_extended_master_secret_xtn, &ssl3_SendExtendedMasterSecretXtn },
       { ssl_renegotiation_info_xtn, &ssl3_SendRenegotiationInfoXtn },
       { ssl_supported_groups_xtn, &ssl_SendSupportedGroupsXtn },
       { ssl_ec_point_formats_xtn, &ssl3_SendSupportedPointFormatsXtn },
-      { ssl_session_ticket_xtn, &ssl3_SendSessionTicketXtn },
+      { ssl_session_ticket_xtn, &ssl3_ClientSendSessionTicketXtn },
       { ssl_next_proto_nego_xtn, &ssl3_ClientSendNextProtoNegoXtn },
       { ssl_app_layer_protocol_xtn, &ssl3_ClientSendAppProtoXtn },
       { ssl_use_srtp_xtn, &ssl3_ClientSendUseSRTPXtn },
       { ssl_cert_status_xtn, &ssl3_ClientSendStatusRequestXtn },
       { ssl_signed_cert_timestamp_xtn, &ssl3_ClientSendSignedCertTimestampXtn },
       { ssl_tls13_key_share_xtn, &tls13_ClientSendKeyShareXtn },
       { ssl_tls13_early_data_xtn, &tls13_ClientSendEarlyDataXtn },
       /* Some servers (e.g. WebSphere Application Server 7.0 and Tomcat) will
        * time out or terminate the connection if the last extension in the
        * client hello is empty. They are not intolerant of TLS 1.2, so list
        * signature_algorithms at the end. See bug 1243641. */
       { ssl_tls13_supported_versions_xtn, &tls13_ClientSendSupportedVersionsXtn },
-      { ssl_tls13_short_header_xtn, &tls13_SendShortHeaderXtn },
       { ssl_signature_algorithms_xtn, &ssl3_SendSigAlgsXtn },
       { ssl_tls13_cookie_xtn, &tls13_ClientSendHrrCookieXtn },
-      { ssl_tls13_psk_key_exchange_modes_xtn,
-        &tls13_ClientSendPskKeyExchangeModesXtn },
-      { ssl_padding_xtn, &ssl3_ClientSendPaddingExtension },
+      { ssl_tls13_psk_key_exchange_modes_xtn, &tls13_ClientSendPskModesXtn },
       /* The pre_shared_key extension MUST be last. */
       { ssl_tls13_pre_shared_key_xtn, &tls13_ClientSendPreSharedKeyXtn },
       { 0, NULL }
     };
 
-static const ssl3HelloExtensionSender clientHelloSendersSSL3[] = {
+static const sslExtensionBuilder clientHelloSendersSSL3[] = {
     { ssl_renegotiation_info_xtn, &ssl3_SendRenegotiationInfoXtn },
     { 0, NULL }
 };
 
+static const sslExtensionBuilder tls13_cert_req_senders[] = {
+    { ssl_signature_algorithms_xtn, &ssl3_SendSigAlgsXtn },
+    { ssl_tls13_certificate_authorities_xtn, &tls13_SendCertAuthoritiesXtn },
+    { 0, NULL }
+};
+
 static PRBool
 arrayContainsExtension(const PRUint16 *array, PRUint32 len, PRUint16 ex_type)
 {
     unsigned int i;
     for (i = 0; i < len; i++) {
         if (ex_type == array[i])
             return PR_TRUE;
     }
@@ -249,70 +260,70 @@ ssl3_FindExtension(sslSocket *ss, SSLExt
  * Servers ignore any extensions with unknown extension types.
  * Clients reject any extensions with unadvertised extension types
  *
  * In TLS >= 1.3, the client checks that extensions appear in the
  * right phase.
  */
 SECStatus
 ssl3_HandleParsedExtensions(sslSocket *ss,
-                            SSL3HandshakeType handshakeMessage)
+                            SSLHandshakeType handshakeMessage)
 {
     const ssl3ExtensionHandler *handlers;
+    const ssl3ExtensionHandler *handler;
     /* HelloRetryRequest doesn't set ss->version. It might be safe to
      * do so, but we weren't entirely sure. TODO(ekr@rtfm.com). */
     PRBool isTLS13 = (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) ||
-                     (handshakeMessage == hello_retry_request);
+                     (handshakeMessage == ssl_hs_hello_retry_request);
     /* The following messages can include extensions that were not included in
      * the original ClientHello. */
-    PRBool allowNotOffered = (handshakeMessage == client_hello) ||
-                             (handshakeMessage == certificate_request) ||
-                             (handshakeMessage == new_session_ticket);
+    PRBool allowNotOffered = (handshakeMessage == ssl_hs_client_hello) ||
+                             (handshakeMessage == ssl_hs_certificate_request) ||
+                             (handshakeMessage == ssl_hs_new_session_ticket);
     PRCList *cursor;
 
     switch (handshakeMessage) {
-        case client_hello:
+        case ssl_hs_client_hello:
             handlers = clientHelloHandlers;
             break;
-        case new_session_ticket:
+        case ssl_hs_new_session_ticket:
             PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
             handlers = newSessionTicketHandlers;
             break;
-        case hello_retry_request:
+        case ssl_hs_hello_retry_request:
             handlers = helloRetryRequestHandlers;
             break;
-        case encrypted_extensions:
+        case ssl_hs_encrypted_extensions:
             PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
         /* fall through */
-        case server_hello:
+        case ssl_hs_server_hello:
             if (ss->version > SSL_LIBRARY_VERSION_3_0) {
                 handlers = serverHelloHandlersTLS;
             } else {
                 handlers = serverHelloHandlersSSL3;
             }
             break;
-        case certificate:
+        case ssl_hs_certificate:
             PORT_Assert(!ss->sec.isServer);
             handlers = serverCertificateHandlers;
             break;
-        case certificate_request:
+        case ssl_hs_certificate_request:
             PORT_Assert(!ss->sec.isServer);
             handlers = certificateRequestHandlers;
             break;
         default:
             PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
             PORT_Assert(0);
             return SECFailure;
     }
 
     for (cursor = PR_NEXT_LINK(&ss->ssl3.hs.remoteExtensions);
          cursor != &ss->ssl3.hs.remoteExtensions;
          cursor = PR_NEXT_LINK(cursor)) {
         TLSExtension *extension = (TLSExtension *)cursor;
-        const ssl3ExtensionHandler *handler;
 
         /* Check whether the server sent an extension which was not advertised
          * in the ClientHello.
          *
          * Note that a TLS 1.3 server should check if CertificateRequest
          * extensions were sent.  But the extensions used for CertificateRequest
          * do not have any response, so we rely on
          * ssl3_ClientExtensionAdvertised to return false on the server.  That
@@ -348,23 +359,22 @@ ssl3_HandleParsedExtensions(sslSocket *s
             (PR_NEXT_LINK(cursor) != &ss->ssl3.hs.remoteExtensions)) {
             tls13_FatalError(ss,
                              SSL_ERROR_RX_MALFORMED_CLIENT_HELLO,
                              illegal_parameter);
             return SECFailure;
         }
 
         /* find extension_type in table of Hello Extension Handlers */
-        for (handler = handlers; handler->ex_type >= 0; handler++) {
+        for (handler = handlers; handler->ex_handler; ++handler) {
             /* if found, call this handler */
             if (handler->ex_type == extension->type) {
                 SECStatus rv;
 
                 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;
                 }
@@ -375,17 +385,17 @@ ssl3_HandleParsedExtensions(sslSocket *s
     return SECSuccess;
 }
 
 /* Syntactic sugar around ssl3_ParseExtensions and
  * ssl3_HandleParsedExtensions. */
 SECStatus
 ssl3_HandleExtensions(sslSocket *ss,
                       PRUint8 **b, PRUint32 *length,
-                      SSL3HandshakeType handshakeMessage)
+                      SSLHandshakeType handshakeMessage)
 {
     SECStatus rv;
 
     rv = ssl3_ParseExtensions(ss, b, length);
     if (rv != SECSuccess)
         return rv;
 
     rv = ssl3_HandleParsedExtensions(ss, handshakeMessage);
@@ -397,32 +407,34 @@ ssl3_HandleExtensions(sslSocket *ss,
 }
 
 /* Add a callback function to the table of senders of server hello extensions.
  */
 SECStatus
 ssl3_RegisterExtensionSender(const sslSocket *ss,
                              TLSExtensionData *xtnData,
                              PRUint16 ex_type,
-                             ssl3HelloExtensionSenderFunc cb)
+                             sslExtensionBuilderFunc cb)
 {
     int i;
-    ssl3HelloExtensionSender *sender;
+    sslExtensionBuilder *sender;
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
         sender = &xtnData->serverHelloSenders[0];
     } else {
-        if (tls13_ExtensionStatus(ex_type, server_hello) ==
+        if (tls13_ExtensionStatus(ex_type, ssl_hs_server_hello) ==
             tls13_extension_allowed) {
-            PORT_Assert(tls13_ExtensionStatus(ex_type, encrypted_extensions) ==
+            PORT_Assert(tls13_ExtensionStatus(ex_type,
+                                              ssl_hs_encrypted_extensions) ==
                         tls13_extension_disallowed);
             sender = &xtnData->serverHelloSenders[0];
-        } else if (tls13_ExtensionStatus(ex_type, encrypted_extensions) ==
+        } else if (tls13_ExtensionStatus(ex_type,
+                                         ssl_hs_encrypted_extensions) ==
                    tls13_extension_allowed) {
             sender = &xtnData->encryptedExtensionsSenders[0];
-        } else if (tls13_ExtensionStatus(ex_type, certificate) ==
+        } else if (tls13_ExtensionStatus(ex_type, ssl_hs_certificate) ==
                    tls13_extension_allowed) {
             sender = &xtnData->certificateSenders[0];
         } else {
             PORT_Assert(0);
             PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
             return SECFailure;
         }
     }
@@ -439,41 +451,209 @@ ssl3_RegisterExtensionSender(const sslSo
             break;
         }
     }
     PORT_Assert(i < SSL_MAX_EXTENSIONS); /* table needs to grow */
     PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
     return SECFailure;
 }
 
-/* call each of the extension senders and return the accumulated length */
-PRInt32
-ssl3_CallHelloExtensionSenders(sslSocket *ss, PRBool append, PRUint32 maxBytes,
-                               const ssl3HelloExtensionSender *sender)
+/* Call extension handlers for the given message. */
+SECStatus
+ssl_ConstructExtensions(sslSocket *ss, sslBuffer *buf, SSLHandshakeType message)
 {
-    PRInt32 total_exten_len = 0;
+    const sslExtensionBuilder *sender;
+    SECStatus rv;
+
+    PORT_Assert(buf->len == 0);
+
+    switch (message) {
+        case ssl_hs_client_hello:
+            if (ss->vrange.max > SSL_LIBRARY_VERSION_3_0) {
+                sender = clientHelloSendersTLS;
+            } else {
+                sender = clientHelloSendersSSL3;
+            }
+            break;
+
+        case ssl_hs_server_hello:
+            sender = ss->xtnData.serverHelloSenders;
+            break;
+
+        case ssl_hs_certificate_request:
+            PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
+            sender = tls13_cert_req_senders;
+            break;
+
+        case ssl_hs_certificate:
+            PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
+            sender = ss->xtnData.certificateSenders;
+            break;
+
+        case ssl_hs_encrypted_extensions:
+            PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
+            sender = ss->xtnData.encryptedExtensionsSenders;
+            break;
 
-    if (!sender) {
-        if (ss->vrange.max > SSL_LIBRARY_VERSION_3_0) {
-            sender = &clientHelloSendersTLS[0];
-        } else {
-            sender = &clientHelloSendersSSL3[0];
+        default:
+            PORT_Assert(0);
+            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+            return SECFailure;
+    }
+
+    for (; sender->ex_sender; ++sender) {
+        PRBool append = PR_FALSE;
+        unsigned int start = buf->len;
+        unsigned int length;
+
+        /* Save space for the extension type and length. Note that we don't grow
+         * the buffer now; rely on sslBuffer_Append* to do that. */
+        buf->len += 4;
+        rv = (*sender->ex_sender)(ss, &ss->xtnData, buf, &append);
+        if (rv != SECSuccess) {
+            goto loser;
+        }
+
+        /* Save the length and go back to the start. */
+        length = buf->len - start - 4;
+        buf->len = start;
+        if (!append) {
+            continue;
+        }
+
+        buf->len = start;
+        rv = sslBuffer_AppendNumber(buf, sender->ex_type, 2);
+        if (rv != SECSuccess) {
+            goto loser; /* Code already set. */
+        }
+        rv = sslBuffer_AppendNumber(buf, length, 2);
+        if (rv != SECSuccess) {
+            goto loser; /* Code already set. */
+        }
+        /* Skip over the extension body. */
+        buf->len += length;
+
+        if (message == ssl_hs_client_hello) {
+            ss->xtnData.advertised[ss->xtnData.numAdvertised++] =
+                sender->ex_type;
         }
     }
 
-    while (sender->ex_sender) {
-        PRInt32 extLen = (*sender->ex_sender)(ss, &ss->xtnData, append, maxBytes);
-        if (extLen < 0) {
-            return -1;
+    if (buf->len > 0xffff) {
+        PORT_SetError(SSL_ERROR_TX_RECORD_TOO_LONG);
+        goto loser;
+    }
+
+    return SECSuccess;
+
+loser:
+    sslBuffer_Clear(buf);
+    return SECFailure;
+}
+
+/* This extension sender can be used anywhere that an always empty extension is
+ * needed. Mostly that is for ServerHello where sender registration is dynamic;
+ * ClientHello senders are usually conditional in some way. */
+SECStatus
+ssl_SendEmptyExtension(const sslSocket *ss, TLSExtensionData *xtnData,
+                       sslBuffer *buf, PRBool *append)
+{
+    *append = PR_TRUE;
+    return SECSuccess;
+}
+
+/* Takes the size of the ClientHello, less the record header, and determines how
+ * much padding is required. */
+static unsigned int
+ssl_CalculatePaddingExtLen(const sslSocket *ss, unsigned int clientHelloLength)
+{
+    unsigned int recordLength = 1 /* handshake message type */ +
+                                3 /* handshake message length */ +
+                                clientHelloLength;
+    unsigned int extensionLen;
+
+    /* Don't pad for DTLS, for SSLv3, or for renegotiation. */
+    if (IS_DTLS(ss) ||
+        ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_0 ||
+        ss->firstHsDone) {
+        return 0;
+    }
+
+    /* A padding extension may be included to ensure that the record containing
+     * the ClientHello doesn't have a length between 256 and 511 bytes
+     * (inclusive). Initial ClientHello records with such lengths trigger bugs
+     * in F5 devices. */
+    if (recordLength < 256 || recordLength >= 512) {
+        return 0;
+    }
+
+    extensionLen = 512 - recordLength;
+    /* Extensions take at least four bytes to encode. Always include at least
+     * one byte of data if we are padding. Some servers will time out or
+     * terminate the connection if the last ClientHello extension is empty. */
+    if (extensionLen < 5) {
+        extensionLen = 5;
+    }
+
+    return extensionLen - 4;
+}
+
+/* ssl3_SendPaddingExtension possibly adds an extension which ensures that a
+ * ClientHello record is either < 256 bytes or is >= 512 bytes. This ensures
+ * that we don't trigger bugs in F5 products.
+ *
+ * This takes an existing extension buffer, |buf|, and the length of the
+ * remainder of the ClientHello, |prefixLen|.  It modifies the extension buffer
+ * to insert padding at the right place.
+ */
+SECStatus
+ssl_InsertPaddingExtension(const sslSocket *ss, unsigned int prefixLen,
+                           sslBuffer *buf)
+{
+    static unsigned char padding[252] = { 0 };
+    unsigned int paddingLen;
+    unsigned int tailLen;
+    SECStatus rv;
+
+    /* Account for the size of the header, the length field of the extensions
+     * block and the size of the existing extensions. */
+    paddingLen = ssl_CalculatePaddingExtLen(ss, prefixLen + 2 + buf->len);
+    if (!paddingLen) {
+        return SECSuccess;
+    }
+
+    /* Move the tail if there is one. This only happens if we are sending the
+     * TLS 1.3 PSK extension, which needs to be at the end. */
+    if (ss->xtnData.paddingOffset) {
+        PORT_Assert(buf->len > ss->xtnData.paddingOffset);
+        tailLen = buf->len - ss->xtnData.paddingOffset;
+        rv = sslBuffer_Grow(buf, buf->len + 4 + paddingLen);
+        if (rv != SECSuccess) {
+            return SECFailure;
         }
-        maxBytes -= extLen;
-        total_exten_len += extLen;
-        ++sender;
+        PORT_Memmove(buf->buf + ss->xtnData.paddingOffset + 4 + paddingLen,
+                     buf->buf + ss->xtnData.paddingOffset,
+                     tailLen);
+        buf->len = ss->xtnData.paddingOffset;
+    } else {
+        tailLen = 0;
     }
-    return total_exten_len;
+
+    rv = sslBuffer_AppendNumber(buf, ssl_padding_xtn, 2);
+    if (rv != SECSuccess) {
+        return SECFailure; /* Code already set. */
+    }
+    rv = sslBuffer_AppendVariable(buf, padding, paddingLen, 2);
+    if (rv != SECSuccess) {
+        return SECFailure; /* Code already set. */
+    }
+
+    buf->len += tailLen;
+
+    return SECSuccess;
 }
 
 void
 ssl3_DestroyRemoteExtensions(PRCList *list)
 {
     PRCList *cur_p;
 
     while (!PR_CLIST_IS_EMPTY(list)) {
@@ -509,38 +689,16 @@ ssl3_ResetExtensionData(TLSExtensionData
         xtnData->certReqAuthorities.arena = NULL;
     }
 
     /* 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 PRUint8 *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
--- a/lib/ssl/ssl3ext.h
+++ b/lib/ssl/ssl3ext.h
@@ -4,64 +4,48 @@
  *
  * 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_
 
+#include "sslencode.h"
+
 typedef enum {
     sni_nametype_hostname
 } SNINameType;
 typedef struct TLSExtensionDataStr TLSExtensionData;
 
-/* registerable callback function that either appends extension to buffer
+/* 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);
+typedef SECStatus (*sslExtensionBuilderFunc)(const sslSocket *ss,
+                                             TLSExtensionData *xtnData,
+                                             sslBuffer *buf, PRBool *added);
 
 /* 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;
+    sslExtensionBuilderFunc ex_sender;
+} sslExtensionBuilder;
 
 struct TLSExtensionDataStr {
     /* registered callbacks that send server hello extensions */
-    ssl3HelloExtensionSender serverHelloSenders[SSL_MAX_EXTENSIONS];
-    ssl3HelloExtensionSender encryptedExtensionsSenders[SSL_MAX_EXTENSIONS];
-    ssl3HelloExtensionSender certificateSenders[SSL_MAX_EXTENSIONS];
+    sslExtensionBuilder serverHelloSenders[SSL_MAX_EXTENSIONS];
+    sslExtensionBuilder encryptedExtensionsSenders[SSL_MAX_EXTENSIONS];
+    sslExtensionBuilder certificateSenders[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];
 
-    /* Amount of padding we need to add. */
-    PRUint16 paddingLen;
-
     /* SessionTicket Extension related data. */
     PRBool ticketTimestampVerified;
     PRBool emptySessionTicket;
     PRBool sentSessionTicketInClientHello;
     SECItem psk_ke_modes;
     PRUint32 max_early_data_size;
 
     /* SNI Extension related data
@@ -97,61 +81,56 @@ struct TLSExtensionDataStr {
     /* 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 */
 
-    SECItem pskBinder;                /* The PSK binder for the first PSK (TLS 1.3) */
-    unsigned long pskBinderPrefixLen; /* The length of the binder input. */
-    PRCList remoteKeyShares;          /* The other side's public keys (TLS 1.3) */
+    unsigned int paddingOffset;      /* Where to insert padding. 0 = end. */
+    SECItem pskBinder;               /* The PSK binder for the first PSK (TLS 1.3) */
+    unsigned int pskBinderPrefixLen; /* The length of the binder input. */
+    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,
                                 PRUint8 **b, PRUint32 *length,
-                                SSL3HandshakeType handshakeMessage);
+                                SSLHandshakeType handshakeMessage);
 SECStatus ssl3_ParseExtensions(sslSocket *ss,
                                PRUint8 **b, PRUint32 *length);
 SECStatus ssl3_HandleParsedExtensions(sslSocket *ss,
-                                      SSL3HandshakeType handshakeMessage);
+                                      SSLHandshakeType 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);
-
-void ssl3_CalculatePaddingExtLen(sslSocket *ss,
-                                 unsigned int clientHelloLength);
+                                       sslExtensionBuilderFunc cb);
+SECStatus ssl_ConstructExtensions(sslSocket *ss, sslBuffer *buf,
+                                  SSLHandshakeType message);
+SECStatus ssl_SendEmptyExtension(const sslSocket *ss, TLSExtensionData *xtnData,
+                                 sslBuffer *buf, PRBool *append);
+SECStatus ssl_InsertPaddingExtension(const sslSocket *ss, unsigned int prefixLen,
+                                     sslBuffer *buf);
 
 /* 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 PRUint8 *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, PRUint32 bytes,
                                    PRUint8 **b, PRUint32 *length);
 SECStatus ssl3_ExtConsumeHandshakeNumber(const sslSocket *ss, PRUint32 *num,
                                          PRUint32 bytes, PRUint8 **b,
                                          PRUint32 *length);
--- a/lib/ssl/ssl3exthandle.c
+++ b/lib/ssl/ssl3exthandle.c
@@ -8,89 +8,66 @@
 #include "nss.h"
 #include "ssl.h"
 #include "sslproto.h"
 #include "sslimpl.h"
 #include "pk11pub.h"
 #include "blapit.h"
 #include "prinit.h"
 #include "selfencrypt.h"
-#include "ssl3encode.h"
 #include "ssl3ext.h"
 #include "ssl3exthandle.h"
 #include "tls13exthandle.h" /* For tls13_ServerSendStatusRequestXtn. */
 
 /* 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(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
-                       PRUint32 maxBytes)
+SECStatus
+ssl3_ClientSendServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                             sslBuffer *buf, PRBool *added)
 {
+    unsigned int len;
+    PRNetAddr netAddr;
     SECStatus rv;
-    if (!ss)
-        return 0;
-    if (!ss->sec.isServer) {
-        PRUint32 len;
-        PRNetAddr netAddr;
 
-        /* must have a hostname */
-        if (!ss->url || !ss->url[0])
-            return 0;
-        /* 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_ExtAppendHandshakeNumber(ss, ssl_server_name_xtn, 2);
-            if (rv != SECSuccess)
-                return -1;
-            /* length of extension_data */
-            rv = ssl3_ExtAppendHandshakeNumber(ss, len + 5, 2);
-            if (rv != SECSuccess)
-                return -1;
-            /* length of server_name_list */
-            rv = ssl3_ExtAppendHandshakeNumber(ss, len + 3, 2);
-            if (rv != SECSuccess)
-                return -1;
-            /* Name Type (sni_host_name) */
-            rv = ssl3_ExtAppendHandshake(ss, "\0", 1);
-            if (rv != SECSuccess)
-                return -1;
-            /* HostName (length and value) */
-            rv = ssl3_ExtAppendHandshakeVariable(ss, (PRUint8 *)ss->url, len, 2);
-            if (rv != SECSuccess)
-                return -1;
-            if (!ss->sec.isServer) {
-                xtnData->advertised[xtnData->numAdvertised++] =
-                    ssl_server_name_xtn;
-            }
-        }
-        return len + 9;
+    /* must have a hostname */
+    if (!ss->url || !ss->url[0]) {
+        return SECSuccess;
+    }
+    /* must not be an IPv4 or IPv6 address */
+    if (PR_SUCCESS == PR_StringToNetAddr(ss->url, &netAddr)) {
+        /* is an IP address (v4 or v6) */
+        return SECSuccess;
     }
-    /* Server side */
-    if (append && maxBytes >= 4) {
-        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_server_name_xtn, 2);
-        if (rv != SECSuccess)
-            return -1;
-        /* length of extension_data */
-        rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2);
-        if (rv != SECSuccess)
-            return -1;
+    len = PORT_Strlen(ss->url);
+    /* length of server_name_list */
+    rv = sslBuffer_AppendNumber(buf, len + 3, 2);
+    if (rv != SECSuccess) {
+        return SECFailure;
     }
-    return 4;
+    /* Name Type (sni_host_name) */
+    rv = sslBuffer_AppendNumber(buf, 0, 1);
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
+    /* HostName (length and value) */
+    rv = sslBuffer_AppendVariable(buf, (const PRUint8 *)ss->url, len, 2);
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
+
+    *added = PR_TRUE;
+    return SECSuccess;
 }
 
 /* Handle an incoming SNI extension. */
 SECStatus
-ssl3_HandleServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data)
+ssl3_HandleServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                         SECItem *data)
 {
     SECItem *names = NULL;
     PRUint32 listLenBytes = 0;
     SECStatus rv;
 
     if (!ss->sec.isServer) {
         return SECSuccess; /* ignore extension */
     }
@@ -189,98 +166,64 @@ ssl3_FreeSniNameArray(TLSExtensionData *
     xtnData->sniNameArrSize = 0;
 }
 
 /* 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(
-    const sslSocket *ss,
-    TLSExtensionData *xtnData,
-    PRBool append,
-    PRUint32 maxBytes)
+ssl3_ClientSendSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                                sslBuffer *buf, PRBool *added)
 {
-    PRInt32 extension_length;
     NewSessionTicket *session_ticket = NULL;
     sslSessionID *sid = ss->sec.ci.sid;
+    SECStatus rv;
+
+    PORT_Assert(!ss->sec.isServer);
 
     /* Never send an extension with a ticket for TLS 1.3, but
      * OK to send the empty one in case the server does 1.2. */
     if (sid->cached == in_client_cache &&
         sid->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
-        return 0;
+        return SECSuccess;
     }
 
     /* Ignore the SessionTicket extension if processing is disabled. */
-    if (!ss->opt.enableSessionTickets)
-        return 0;
-
-    /* Empty extension length = extension_type (2-bytes) +
-     * length(extension_data) (2-bytes)
-     */
-    extension_length = 4;
-
-    /* If we are a client then send a session ticket if one is availble.
-     * Servers that support the extension and are willing to negotiate the
-     * the extension always respond with an empty extension.
-     */
-    if (!ss->sec.isServer) {
-        /* The caller must be holding sid->u.ssl3.lock for reading. We cannot
-         * just acquire and release the lock within this function because the
-         * 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 (xtnData->ticketTimestampVerified) {
-                extension_length += session_ticket->ticket.len;
-            } else if (!append && ssl_TicketTimeValid(session_ticket)) {
-                extension_length += session_ticket->ticket.len;
-                xtnData->ticketTimestampVerified = PR_TRUE;
-            }
-        }
+    if (!ss->opt.enableSessionTickets) {
+        return SECSuccess;
     }
 
-    if (maxBytes < (PRUint32)extension_length) {
-        PORT_Assert(0);
-        return 0;
+    /* Send a session ticket if one is available.
+     *
+     * The caller must be holding sid->u.ssl3.lock for reading. We cannot
+     * just acquire and release the lock within this function because the
+     * 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 &&
+        (xtnData->ticketTimestampVerified ||
+         ssl_TicketTimeValid(session_ticket))) {
+
+        xtnData->ticketTimestampVerified = PR_FALSE;
+
+        rv = sslBuffer_Append(buf, session_ticket->ticket.data,
+                              session_ticket->ticket.len);
+        if (rv != SECSuccess) {
+            return SECFailure;
+        }
+
+        xtnData->sentSessionTicketInClientHello = PR_TRUE;
     }
-    if (append) {
-        SECStatus rv;
-        /* extension_type */
-        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_session_ticket_xtn, 2);
-        if (rv != SECSuccess)
-            goto loser;
-        if (session_ticket && session_ticket->ticket.data &&
-            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_ExtAppendHandshakeNumber(ss, 0, 2);
-        }
-        if (rv != SECSuccess)
-            goto loser;
 
-        if (!ss->sec.isServer) {
-            xtnData->advertised[xtnData->numAdvertised++] =
-                ssl_session_ticket_xtn;
-        }
-    }
-    return extension_length;
-
-loser:
-    xtnData->ticketTimestampVerified = PR_FALSE;
-    return -1;
+    *added = PR_TRUE;
+    return SECSuccess;
 }
 
 PRBool
 ssl_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;
@@ -296,28 +239,28 @@ ssl_AlpnTagAllowed(const sslSocket *ss, 
         offset += 1 + taglen;
     }
 
     return PR_FALSE;
 }
 
 /* handle an incoming Next Protocol Negotiation extension. */
 SECStatus
-ssl3_ServerHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
+ssl3_ServerHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                   SECItem *data)
 {
     PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3);
 
     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;
     }
 
-    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
+    xtnData->negotiated[xtnData->numNegotiated++] = ssl_next_proto_nego_xtn;
 
     /* TODO: server side NPN support would require calling
      * ssl3_RegisterServerHelloExtensionSender here in order to echo the
      * extension back to the client. */
 
     return SECSuccess;
 }
 
@@ -341,17 +284,17 @@ ssl3_ValidateNextProtoNego(const unsigne
     }
 
     return SECSuccess;
 }
 
 /* protocol selection handler for ALPN (server side) and NPN (client side) */
 static SECStatus
 ssl3_SelectAppProtocol(const sslSocket *ss, TLSExtensionData *xtnData,
-                       PRUint16 ex_type, SECItem *data)
+                       PRUint16 extension, SECItem *data)
 {
     SECStatus rv;
     unsigned char resultBuffer[255];
     SECItem result = { siBuffer, resultBuffer, 0 };
 
     rv = ssl3_ValidateNextProtoNego(data->data, data->len);
     if (rv != SECSuccess) {
         ssl3_ExtSendAlert(ss, alert_fatal, decode_error);
@@ -378,32 +321,33 @@ ssl3_SelectAppProtocol(const sslSocket *
     if (result.len > sizeof(resultBuffer)) {
         PORT_SetError(SEC_ERROR_OUTPUT_LEN);
         /* TODO: crash */
         return SECFailure;
     }
 
     SECITEM_FreeItem(&xtnData->nextProto, PR_FALSE);
 
-    if (ex_type == ssl_app_layer_protocol_xtn &&
+    if (extension == ssl_app_layer_protocol_xtn &&
         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. */
         ssl3_ExtSendAlert(ss, alert_fatal, no_application_protocol);
         PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_NO_PROTOCOL);
         return SECFailure;
     }
 
-    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
+    xtnData->negotiated[xtnData->numNegotiated++] = extension;
     return SECITEM_CopyItem(NULL, &xtnData->nextProto, &result);
 }
 
 /* handle an incoming ALPN extension at the server */
 SECStatus
-ssl3_ServerHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data)
+ssl3_ServerHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                             SECItem *data)
 {
     PRUint32 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. */
@@ -420,36 +364,37 @@ ssl3_ServerHandleAppProtoXtn(const sslSo
         return SECFailure;
     }
 
     if (!ss->nextProtoCallback) {
         /* we're not configured for it */
         return SECSuccess;
     }
 
-    rv = ssl3_SelectAppProtocol(ss, xtnData, ex_type, data);
+    rv = ssl3_SelectAppProtocol(ss, xtnData, ssl_app_layer_protocol_xtn, data);
     if (rv != SECSuccess) {
         return rv;
     }
 
     /* prepare to send back a response, if we negotiated */
     if (xtnData->nextProtoState == SSL_NEXT_PROTO_NEGOTIATED) {
-        rv = ssl3_RegisterExtensionSender(
-            ss, xtnData, ex_type, ssl3_ServerSendAppProtoXtn);
+        rv = ssl3_RegisterExtensionSender(ss, xtnData,
+                                          ssl_app_layer_protocol_xtn,
+                                          ssl3_ServerSendAppProtoXtn);
         if (rv != SECSuccess) {
             ssl3_ExtSendAlert(ss, alert_fatal, internal_error);
             PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
             return rv;
         }
     }
     return SECSuccess;
 }
 
 SECStatus
-ssl3_ClientHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
+ssl3_ClientHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                   SECItem *data)
 {
     PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3);
     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
@@ -468,21 +413,22 @@ ssl3_ClientHandleNextProtoNegoXtn(const 
      * we sent the ClientHello and now. */
     if (!ss->nextProtoCallback) {
         PORT_Assert(0);
         ssl3_ExtSendAlert(ss, alert_fatal, internal_error);
         PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_NO_CALLBACK);
         return SECFailure;
     }
 
-    return ssl3_SelectAppProtocol(ss, xtnData, ex_type, data);
+    return ssl3_SelectAppProtocol(ss, xtnData, ssl_next_proto_nego_xtn, data);
 }
 
 SECStatus
-ssl3_ClientHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data)
+ssl3_ClientHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                             SECItem *data)
 {
     SECStatus rv;
     PRUint32 list_len;
     SECItem protocol_name;
 
     if (ssl3_ExtensionNegotiated(ss, ssl_next_proto_nego_xtn)) {
         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
         return SECFailure;
@@ -519,275 +465,178 @@ ssl3_ClientHandleAppProtoXtn(const sslSo
     if (!ssl_AlpnTagAllowed(ss, &protocol_name)) {
         ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter);
         PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
         return SECFailure;
     }
 
     SECITEM_FreeItem(&xtnData->nextProto, PR_FALSE);
     xtnData->nextProtoState = SSL_NEXT_PROTO_SELECTED;
-    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
+    xtnData->negotiated[xtnData->numNegotiated++] = ssl_app_layer_protocol_xtn;
     return SECITEM_CopyItem(NULL, &xtnData->nextProto, &protocol_name);
 }
 
-PRInt32
-ssl3_ClientSendNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
-                                PRUint32 maxBytes)
+SECStatus
+ssl3_ClientSendNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                                sslBuffer *buf, PRBool *added)
 {
-    PRInt32 extension_length;
-
     /* Renegotiations do not send this extension. */
     if (!ss->opt.enableNPN || !ss->nextProtoCallback || ss->firstHsDone) {
-        return 0;
+        return SECSuccess;
     }
 
-    extension_length = 4;
-
-    if (maxBytes < (PRUint32)extension_length) {
-        return 0;
-    }
-    if (append) {
-        SECStatus rv;
-        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_next_proto_nego_xtn, 2);
-        if (rv != SECSuccess)
-            goto loser;
-        rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2);
-        if (rv != SECSuccess)
-            goto loser;
-        xtnData->advertised[xtnData->numAdvertised++] =
-            ssl_next_proto_nego_xtn;
-    }
-
-    return extension_length;
-
-loser:
-    return -1;
+    *added = PR_TRUE;
+    return SECSuccess;
 }
 
-PRInt32
-ssl3_ClientSendAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes)
+SECStatus
+ssl3_ClientSendAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                           sslBuffer *buf, PRBool *added)
 {
-    PRInt32 extension_length;
-    unsigned char *alpn_protos = NULL;
+    SECStatus rv;
+    const unsigned int len = ss->opt.nextProtoNego.len;
 
     /* Renegotiations do not send this extension. */
     if (!ss->opt.enableALPN || !ss->opt.nextProtoNego.data || ss->firstHsDone) {
-        return 0;
+        return SECSuccess;
     }
 
-    extension_length = 2 /* extension type */ + 2 /* extension length */ +
-                       2 /* protocol name list length */ +
-                       ss->opt.nextProtoNego.len;
-
-    if (maxBytes < (PRUint32)extension_length) {
-        return 0;
-    }
-    if (append) {
-        /* NPN requires that the client's fallback protocol is first in the
-         * list. However, ALPN sends protocols in preference order. So we
-         * allocate a buffer and move the first protocol to the end of the
-         * list. */
-        SECStatus rv;
-        const unsigned int len = ss->opt.nextProtoNego.len;
+    /* NPN requires that the client's fallback protocol is first in the
+     * list. However, ALPN sends protocols in preference order. So move the
+     * first protocol to the end of the list. */
 
-        alpn_protos = PORT_Alloc(len);
-        if (alpn_protos == NULL) {
+    if (len > 0) {
+        /* Each protocol string is prefixed with a single byte length. */
+        unsigned int i;
+
+        rv = sslBuffer_AppendNumber(buf, len, 2);
+        if (rv != SECSuccess) {
             return SECFailure;
         }
-        if (len > 0) {
-            /* Each protocol string is prefixed with a single byte length. */
-            unsigned int i = ss->opt.nextProtoNego.data[0] + 1;
-            if (i <= len) {
-                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_ExtAppendHandshakeNumber(ss, ssl_app_layer_protocol_xtn, 2);
-        if (rv != SECSuccess) {
-            goto loser;
-        }
-        rv = ssl3_ExtAppendHandshakeNumber(ss, extension_length - 4, 2);
-        if (rv != SECSuccess) {
-            goto loser;
+        i = ss->opt.nextProtoNego.data[0] + 1;
+        if (i <= len) {
+            rv = sslBuffer_Append(buf, &ss->opt.nextProtoNego.data[i], len - i);
+            if (rv != SECSuccess) {
+                return SECFailure;
+            }
+            rv = sslBuffer_Append(buf, ss->opt.nextProtoNego.data, i);
+            if (rv != SECSuccess) {
+                return SECFailure;
+            }
+        } else {
+            /* This seems to be invalid data so we'll send as-is. */
+            rv = sslBuffer_Append(buf, ss->opt.nextProtoNego.data, len);
+            if (rv != SECSuccess) {
+                return SECFailure;
+            }
         }
-        rv = ssl3_ExtAppendHandshakeVariable(ss, alpn_protos, len, 2);
-        PORT_Free(alpn_protos);
-        alpn_protos = NULL;
-        if (rv != SECSuccess) {
-            goto loser;
-        }
-        xtnData->advertised[xtnData->numAdvertised++] =
-            ssl_app_layer_protocol_xtn;
     }
 
-    return extension_length;
-
-loser:
-    if (alpn_protos) {
-        PORT_Free(alpn_protos);
-    }
-    return -1;
+    *added = PR_TRUE;
+    return SECSuccess;
 }
 
-PRInt32
-ssl3_ServerSendAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes)
+SECStatus
+ssl3_ServerSendAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                           sslBuffer *buf, PRBool *added)
 {
-    PRInt32 extension_length;
+    SECStatus rv;
 
-    /* we're in over our heads if any of these fail */
+    /* We're in over our heads if any of these fail */
     PORT_Assert(ss->opt.enableALPN);
     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 */ +
-                       xtnData->nextProto.len;
-
-    if (maxBytes < (PRUint32)extension_length) {
-        return 0;
+    rv = sslBuffer_AppendNumber(buf, xtnData->nextProto.len + 1, 2);
+    if (rv != SECSuccess) {
+        return SECFailure;
     }
-    if (append) {
-        SECStatus rv;
-        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_app_layer_protocol_xtn, 2);
-        if (rv != SECSuccess) {
-            return -1;
-        }
-        rv = ssl3_ExtAppendHandshakeNumber(ss, extension_length - 4, 2);
-        if (rv != SECSuccess) {
-            return -1;
-        }
-        rv = ssl3_ExtAppendHandshakeNumber(ss, xtnData->nextProto.len + 1, 2);
-        if (rv != SECSuccess) {
-            return -1;
-        }
-        rv = ssl3_ExtAppendHandshakeVariable(ss, xtnData->nextProto.data,
-                                             xtnData->nextProto.len, 1);
-        if (rv != SECSuccess) {
-            return -1;
-        }
+    rv = sslBuffer_AppendVariable(buf, xtnData->nextProto.data,
+                                  xtnData->nextProto.len, 1);
+    if (rv != SECSuccess) {
+        return SECFailure;
     }
 
-    return extension_length;
+    *added = PR_TRUE;
+    return SECSuccess;
 }
 
 SECStatus
-ssl3_ServerHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
+ssl3_ServerHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                   SECItem *data)
 {
-    ssl3HelloExtensionSenderFunc sender;
+    sslExtensionBuilderFunc sender;
 
     PORT_Assert(ss->sec.isServer);
 
     /* remember that we got this extension. */
-    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
+    xtnData->negotiated[xtnData->numNegotiated++] = ssl_cert_status_xtn;
 
     if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
         sender = tls13_ServerSendStatusRequestXtn;
     } else {
         sender = ssl3_ServerSendStatusRequestXtn;
     }
-    return ssl3_RegisterExtensionSender(ss, xtnData, ex_type, sender);
+    return ssl3_RegisterExtensionSender(ss, xtnData, ssl_cert_status_xtn, sender);
 }
 
-PRInt32
-ssl3_ServerSendStatusRequestXtn(
-    const sslSocket *ss,
-    TLSExtensionData *xtnData,
-    PRBool append,
-    PRUint32 maxBytes)
+SECStatus
+ssl3_ServerSendStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                                sslBuffer *buf, PRBool *added)
 {
-    PRInt32 extension_length;
     const sslServerCert *serverCert = ss->sec.serverCert;
-    SECStatus rv;
 
     if (!serverCert->certStatusArray ||
         !serverCert->certStatusArray->len) {
-        return 0;
+        return SECSuccess;
     }
 
-    extension_length = 2 + 2;
-    if (maxBytes < (PRUint32)extension_length) {
-        return 0;
-    }
-    if (append) {
-        /* extension_type */
-        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_cert_status_xtn, 2);
-        if (rv != SECSuccess)
-            return -1;
-        /* length of extension_data */
-        rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2);
-        if (rv != SECSuccess)
-            return -1;
-        /* The certificate status data is sent in ssl3_SendCertificateStatus. */
-    }
-
-    return extension_length;
+    *added = PR_TRUE;
+    return SECSuccess;
 }
 
 /* ssl3_ClientSendStatusRequestXtn builds the status_request extension on the
  * client side. See RFC 6066 section 8. */
-PRInt32
-ssl3_ClientSendStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
-                                PRUint32 maxBytes)
+SECStatus
+ssl3_ClientSendStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                                sslBuffer *buf, PRBool *added)
 {
-    PRInt32 extension_length;
-
-    if (!ss->opt.enableOCSPStapling)
-        return 0;
+    SECStatus rv;
 
-    /* extension_type (2-bytes) +
-     * length(extension_data) (2-bytes) +
-     * status_type (1) +
-     * responder_id_list length (2) +
-     * request_extensions length (2)
-     */
-    extension_length = 9;
-
-    if (maxBytes < (PRUint32)extension_length) {
-        PORT_Assert(0);
-        return 0;
+    if (!ss->opt.enableOCSPStapling) {
+        return SECSuccess;
     }
-    if (append) {
-        SECStatus rv;
 
-        /* extension_type */
-        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_cert_status_xtn, 2);
-        if (rv != SECSuccess)
-            return -1;
-        rv = ssl3_ExtAppendHandshakeNumber(ss, extension_length - 4, 2);
-        if (rv != SECSuccess)
-            return -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_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_ExtAppendHandshakeNumber(ss, 0, 2);
-        if (rv != SECSuccess)
-            return -1;
+    rv = sslBuffer_AppendNumber(buf, 1 /* status_type ocsp */, 1);
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
+    /* A zero length responder_id_list means that the responders are
+     * implicitly known to the server. */
+    rv = sslBuffer_AppendNumber(buf, 0, 2);
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
+    /* 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 = sslBuffer_AppendNumber(buf, 0, 2);
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
 
-        xtnData->advertised[xtnData->numAdvertised++] = ssl_cert_status_xtn;
-    }
-    return extension_length;
+    *added = PR_TRUE;
+    return SECSuccess;
 }
 
 SECStatus
-ssl3_ClientHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
+ssl3_ClientHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                   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(CONST_CAST(sslSocket, ss),
                                        data->data, data->len);
         if (rv != SECSuccess) {
@@ -795,17 +644,17 @@ ssl3_ClientHandleStatusRequestXtn(const 
         }
     } else if (data->len != 0) {
         ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter);
         PORT_SetError(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
         return SECFailure;
     }
 
     /* Keep track of negotiated extensions. */
-    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
+    xtnData->negotiated[xtnData->numNegotiated++] = ssl_cert_status_xtn;
     return SECSuccess;
 }
 
 PRUint32 ssl_ticket_lifetime = 2 * 24 * 60 * 60; /* 2 days in seconds */
 #define TLS_EX_SESS_TICKET_VERSION (0x0105)
 
 /*
  * Called from ssl3_SendNewSessionTicket, tls13_SendNewSessionTicket
@@ -1065,27 +914,27 @@ loser:
 
     return SECFailure;
 }
 
 /* When a client receives a SessionTicket extension a NewSessionTicket
  * message is expected during the handshake.
  */
 SECStatus
-ssl3_ClientHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
+ssl3_ClientHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                   SECItem *data)
 {
     PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3);
 
     if (data->len != 0) {
         return SECSuccess; /* Ignore the extension. */
     }
 
     /* Keep track of negotiated extensions. */
-    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
+    xtnData->negotiated[xtnData->numNegotiated++] = ssl_session_ticket_xtn;
     return SECSuccess;
 }
 
 static SECStatus
 ssl_ParseSessionTicket(sslSocket *ss, const SECItem *decryptedTicket,
                        SessionTicket *parsedTicket)
 {
     PRUint32 temp;
@@ -1451,33 +1300,33 @@ ssl3_ProcessSessionTicketCommon(sslSocke
 
 loser:
     SECITEM_ZfreeItem(&decryptedTicket, PR_FALSE);
     PORT_Memset(&parsedTicket, 0, sizeof(parsedTicket));
     return SECFailure;
 }
 
 SECStatus
-ssl3_ServerHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
+ssl3_ServerHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                   SECItem *data)
 {
     PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3);
 
     /* 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. */
-    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
+    xtnData->negotiated[xtnData->numNegotiated++] = ssl_session_ticket_xtn;
 
     /* 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) {
         xtnData->emptySessionTicket = PR_TRUE;
         return SECSuccess;
@@ -1488,67 +1337,51 @@ ssl3_ServerHandleSessionTicketXtn(const 
 
 /* Extension format:
  * 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(
-    const sslSocket *ss,
-    TLSExtensionData *xtnData,
-    PRBool append,
-    PRUint32 maxBytes)
+SECStatus
+ssl3_SendRenegotiationInfoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                              sslBuffer *buf, PRBool *added)
 {
     PRInt32 len = 0;
-    PRInt32 needed;
+    SECStatus rv;
 
     /* 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
      * the initial handshake, we don't also send RI.
      */
-    if (!ss || ss->ssl3.hs.sendingSCSV)
-        return 0;
+    if (!ss || ss->ssl3.hs.sendingSCSV) {
+        return SECSuccess;
+    }
+
     if (ss->firstHsDone) {
         len = ss->sec.isServer ? ss->ssl3.hs.finishedBytes * 2
                                : ss->ssl3.hs.finishedBytes;
     }
-    needed = 5 + len;
-    if (maxBytes < (PRUint32)needed) {
-        return 0;
+
+    /* verify_Data from previous Finished message(s) */
+    rv = sslBuffer_AppendVariable(buf,
+                                  ss->ssl3.hs.finishedMsgs.data, len, 1);
+    if (rv != SECSuccess) {
+        return SECFailure;
     }
-    if (append) {
-        SECStatus rv;
-        /* extension_type */
-        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_renegotiation_info_xtn, 2);
-        if (rv != SECSuccess)
-            return -1;
-        /* length of extension_data */
-        rv = ssl3_ExtAppendHandshakeNumber(ss, len + 1, 2);
-        if (rv != SECSuccess)
-            return -1;
-        /* verify_Data from previous Finished message(s) */
-        rv = ssl3_ExtAppendHandshakeVariable(ss,
-                                             ss->ssl3.hs.finishedMsgs.data, len, 1);
-        if (rv != SECSuccess)
-            return -1;
-        if (!ss->sec.isServer) {
-            xtnData->advertised[xtnData->numAdvertised++] =
-                ssl_renegotiation_info_xtn;
-        }
-    }
-    return needed;
+
+    *added = PR_TRUE;
+    return SECSuccess;
 }
 
 /* This function runs in both the client and server.  */
 SECStatus
 ssl3_HandleRenegotiationInfoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
-                                PRUint16 ex_type, SECItem *data)
+                                SECItem *data)
 {
     SECStatus rv = SECSuccess;
     PRUint32 len = 0;
 
     PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3);
 
     if (ss->firstHsDone) {
         len = ss->sec.isServer ? ss->ssl3.hs.finishedBytes
@@ -1562,107 +1395,88 @@ ssl3_HandleRenegotiationInfoXtn(const ss
                                 data->data + 1, len)) {
         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. */
     CONST_CAST(sslSocket, ss)
         ->peerRequestedProtection = 1;
-    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
+    xtnData->negotiated[xtnData->numNegotiated++] = ssl_renegotiation_info_xtn;
     if (ss->sec.isServer) {
         /* prepare to send back the appropriate response */
-        rv = ssl3_RegisterExtensionSender(ss, xtnData, ex_type,
+        rv = ssl3_RegisterExtensionSender(ss, xtnData,
+                                          ssl_renegotiation_info_xtn,
                                           ssl3_SendRenegotiationInfoXtn);
     }
     return rv;
 }
 
-PRInt32
-ssl3_ClientSendUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes)
+SECStatus
+ssl3_ClientSendUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                          sslBuffer *buf, PRBool *added)
 {
-    PRUint32 ext_data_len;
-    PRInt16 i;
+    unsigned int 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_ExtAppendHandshakeNumber(ss, ssl_use_srtp_xtn, 2);
-        if (rv != SECSuccess)
-            return -1;
-        /* Length of extension data */
-        rv = ssl3_ExtAppendHandshakeNumber(ss, ext_data_len, 2);
-        if (rv != SECSuccess)
-            return -1;
-        /* Length of the SRTP cipher list */
-        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_ExtAppendHandshakeNumber(ss,
-                                               ss->ssl3.dtlsSRTPCiphers[i],
-                                               2);
-            if (rv != SECSuccess)
-                return -1;
-        }
-        /* Empty MKI value */
-        ssl3_ExtAppendHandshakeVariable(ss, NULL, 0, 1);
-
-        xtnData->advertised[xtnData->numAdvertised++] =
-            ssl_use_srtp_xtn;
+    if (!IS_DTLS(ss) || !ss->ssl3.dtlsSRTPCipherCount) {
+        return SECSuccess; /* Not relevant */
     }
 
-    return 4 + ext_data_len;
+    /* Length of the SRTP cipher list */
+    rv = sslBuffer_AppendNumber(buf, 2 * ss->ssl3.dtlsSRTPCipherCount, 2);
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
+    /* The SRTP ciphers */
+    for (i = 0; i < ss->ssl3.dtlsSRTPCipherCount; i++) {
+        rv = sslBuffer_AppendNumber(buf, ss->ssl3.dtlsSRTPCiphers[i], 2);
+        if (rv != SECSuccess) {
+            return SECFailure;
+        }
+    }
+    /* Empty MKI value */
+    rv = sslBuffer_AppendNumber(buf, 0, 1);
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
+
+    *added = PR_TRUE;
+    return SECSuccess;
 }
 
-PRInt32
-ssl3_ServerSendUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes)
+SECStatus
+ssl3_ServerSendUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                          sslBuffer *buf, PRBool *added)
 {
     SECStatus rv;
 
-    /* Server side */
-    if (!append || maxBytes < 9) {
-        return 9;
+    /* Length of the SRTP cipher list */
+    rv = sslBuffer_AppendNumber(buf, 2, 2);
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
+    /* The selected cipher */
+    rv = sslBuffer_AppendNumber(buf, xtnData->dtlsSRTPCipherSuite, 2);
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
+    /* Empty MKI value */
+    rv = sslBuffer_AppendNumber(buf, 0, 1);
+    if (rv != SECSuccess) {
+        return SECFailure;
     }
 
-    /* Extension type */
-    rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_use_srtp_xtn, 2);
-    if (rv != SECSuccess)
-        return -1;
-    /* Length of extension data */
-    rv = ssl3_ExtAppendHandshakeNumber(ss, 5, 2);
-    if (rv != SECSuccess)
-        return -1;
-    /* Length of the SRTP cipher list */
-    rv = ssl3_ExtAppendHandshakeNumber(ss, 2, 2);
-    if (rv != SECSuccess)
-        return -1;
-    /* The selected cipher */
-    rv = ssl3_ExtAppendHandshakeNumber(ss, xtnData->dtlsSRTPCipherSuite, 2);
-    if (rv != SECSuccess)
-        return -1;
-    /* Empty MKI value */
-    ssl3_ExtAppendHandshakeVariable(ss, NULL, 0, 1);
-
-    return 9;
+    *added = PR_TRUE;
+    return SECSuccess;
 }
 
 SECStatus
-ssl3_ClientHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data)
+ssl3_ClientHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                            SECItem *data)
 {
     SECStatus rv;
     SECItem ciphers = { siBuffer, NULL, 0 };
     PRUint16 i;
     PRUint16 cipher = 0;
     PRBool found = PR_FALSE;
     SECItem litem;
 
@@ -1722,17 +1536,18 @@ ssl3_ClientHandleUseSRTPXtn(const sslSoc
 
     /* OK, this looks fine. */
     xtnData->negotiated[xtnData->numNegotiated++] = ssl_use_srtp_xtn;
     xtnData->dtlsSRTPCipherSuite = cipher;
     return SECSuccess;
 }
 
 SECStatus
-ssl3_ServerHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data)
+ssl3_ServerHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                            SECItem *data)
 {
     SECStatus rv;
     SECItem ciphers = { siBuffer, NULL, 0 };
     PRUint16 i;
     unsigned int j;
     PRUint16 cipher = 0;
     PRBool found = PR_FALSE;
     SECItem litem;
@@ -1798,17 +1613,17 @@ ssl3_ServerHandleUseSRTPXtn(const sslSoc
                                         ssl3_ServerSendUseSRTPXtn);
 }
 
 /* ssl3_HandleSigAlgsXtn handles the signature_algorithms extension from a
  * client.  In TLS 1.3, the client uses this to parse CertificateRequest
  * extensions.  See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */
 SECStatus
 ssl3_HandleSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
-                      PRUint16 ex_type, SECItem *data)
+                      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;
     }
 
@@ -1828,186 +1643,64 @@ ssl3_HandleSigAlgsXtn(const sslSocket *s
     /* Check for trailing data. */
     if (data->len != 0) {
         ssl3_ExtSendAlert(ss, alert_fatal, decode_error);
         PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
         return SECFailure;
     }
 
     /* Keep track of negotiated extensions. */
-    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
+    xtnData->negotiated[xtnData->numNegotiated++] = ssl_signature_algorithms_xtn;
     return SECSuccess;
 }
 
 /* ssl3_ClientSendSigAlgsXtn sends the signature_algorithm extension for TLS
  * 1.2 ClientHellos. */
-PRInt32
+SECStatus
 ssl3_SendSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
-                    PRBool append, PRUint32 maxBytes)
+                    sslBuffer *buf, PRBool *added)
 {
-    PRInt32 extension_length;
-    PRUint8 buf[MAX_SIGNATURE_SCHEMES * 2];
+    PRUint8 schemes[MAX_SIGNATURE_SCHEMES * 2];
     PRUint32 len;
     SECStatus rv;
 
     if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_2) {
-        return 0;
+        return SECSuccess;
     }
 
-    rv = ssl3_EncodeSigAlgs(ss, buf, sizeof(buf), &len);
+    rv = ssl3_EncodeSigAlgs(ss, schemes, sizeof(schemes), &len);
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
+    rv = sslBuffer_AppendVariable(buf, schemes, len, 2);
     if (rv != SECSuccess) {
         return -1;
     }
 
-    extension_length =
-        2 /* extension type */ +
-        2 /* extension length */ +
-        2 /* supported_signature_algorithms length */ +
-        len;
-
-    if (maxBytes < extension_length) {
-        PORT_Assert(0);
-        return 0;
-    }
-
-    if (append) {
-        SECStatus rv;
-        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_signature_algorithms_xtn, 2);
-        if (rv != SECSuccess) {
-            return -1;
-        }
-        rv = ssl3_ExtAppendHandshakeNumber(ss, len + 2, 2);
-        if (rv != SECSuccess) {
-            return -1;
-        }
-
-        rv = ssl3_ExtAppendHandshakeVariable(ss, buf, len, 2);
-        if (rv != SECSuccess) {
-            return -1;
-        }
-
-        xtnData->advertised[xtnData->numAdvertised++] =
-            ssl_signature_algorithms_xtn;
-    }
-
-    return extension_length;
+    *added = PR_TRUE;
+    return SECSuccess;
 }
 
-/* Takes the size of the ClientHello, less the record header, and determines how
- * much padding is required. */
-void
-ssl3_CalculatePaddingExtLen(sslSocket *ss,
-                            unsigned int clientHelloLength)
+SECStatus
+ssl3_SendExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                                 sslBuffer *buf, PRBool *added)
 {
-    unsigned int recordLength = 1 /* handshake message type */ +
-                                3 /* handshake message length */ +
-                                clientHelloLength;
-    unsigned int extensionLen;
-
-    /* Don't pad for DTLS, for SSLv3, or for renegotiation. */
-    if (IS_DTLS(ss) ||
-        ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_0 ||
-        ss->firstHsDone) {
-        return;
-    }
-
-    /* A padding extension may be included to ensure that the record containing
-     * the ClientHello doesn't have a length between 256 and 511 bytes
-     * (inclusive). Initial ClientHello records with such lengths trigger bugs
-     * in F5 devices. */
-    if (recordLength < 256 || recordLength >= 512) {
-        return;
-    }
-
-    extensionLen = 512 - recordLength;
-    /* Extensions take at least four bytes to encode. Always include at least
-     * one byte of data if we are padding. Some servers will time out or
-     * terminate the connection if the last ClientHello extension is empty. */
-    if (extensionLen < 4 + 1) {
-        extensionLen = 4 + 1;
-    }
-
-    ss->xtnData.paddingLen = extensionLen - 4;
-}
-
-/* ssl3_SendPaddingExtension possibly adds an extension which ensures that a
- * ClientHello record is either < 256 bytes or is >= 512 bytes. This ensures
- * that we don't trigger bugs in F5 products. */
-PRInt32
-ssl3_ClientSendPaddingExtension(const sslSocket *ss, TLSExtensionData *xtnData,
-                                PRBool append, PRUint32 maxBytes)
-{
-    static unsigned char padding[252] = { 0 };
-    unsigned int extensionLen;
-    SECStatus rv;
-
-    /* On the length-calculation pass, report zero total length.  The record
-     * will be larger on the second pass if needed. */
-    if (!append || !xtnData->paddingLen) {
-        return 0;
-    }
-
-    extensionLen = xtnData->paddingLen + 4;
-    if (extensionLen > maxBytes ||
-        xtnData->paddingLen > sizeof(padding)) {
-        PORT_Assert(0);
-        return -1;
-    }
-
-    rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_padding_xtn, 2);
-    if (rv != SECSuccess) {
-        return -1;
-    }
-    rv = ssl3_ExtAppendHandshakeVariable(ss, padding, xtnData->paddingLen, 2);
-    if (rv != SECSuccess) {
-        return -1;
-    }
-
-    return extensionLen;
-}
-
-PRInt32
-ssl3_SendExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
-                                 PRUint32 maxBytes)
-{
-    PRInt32 extension_length;
-
     if (!ss->opt.enableExtendedMS) {
-        return 0;
+        return SECSuccess;
     }
 
     /* Always send the extension in this function, since the
      * client always sends it and this function is only called on
      * the server if we negotiated the extension. */
-    extension_length = 4; /* Type + length (0) */
-    if (maxBytes < extension_length) {
-        PORT_Assert(0);
-        return 0;
-    }
-
-    if (append) {
-        SECStatus rv;
-        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_extended_master_secret_xtn, 2);
-        if (rv != SECSuccess)
-            goto loser;
-        rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2);
-        if (rv != SECSuccess)
-            goto loser;
-        xtnData->advertised[xtnData->numAdvertised++] =
-            ssl_extended_master_secret_xtn;
-    }
-
-    return extension_length;
-
-loser:
-    return -1;
+    *added = PR_TRUE;
+    return SECSuccess;
 }
 
 SECStatus
-ssl3_HandleExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
+ssl3_HandleExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                    SECItem *data)
 {
     PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3);
 
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_0) {
         return SECSuccess;
     }
 
@@ -2021,64 +1714,44 @@ ssl3_HandleExtendedMasterSecretXtn(const
         ssl3_ExtSendAlert(ss, alert_fatal, decode_error);
         return SECFailure;
     }
 
     SSL_DBG(("%d: SSL[%d]: Negotiated extended master secret extension.",
              SSL_GETPID(), ss->fd));
 
     /* Keep track of negotiated extensions. */
-    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
+    xtnData->negotiated[xtnData->numNegotiated++] = ssl_extended_master_secret_xtn;
 
     if (ss->sec.isServer) {
-        return ssl3_RegisterExtensionSender(
-            ss, xtnData, ex_type, ssl3_SendExtendedMasterSecretXtn);
+        return ssl3_RegisterExtensionSender(ss, xtnData,
+                                            ssl_extended_master_secret_xtn,
+                                            ssl_SendEmptyExtension);
     }
     return SECSuccess;
 }
 
 /* ssl3_ClientSendSignedCertTimestampXtn sends the signed_certificate_timestamp
  * extension for TLS ClientHellos. */
-PRInt32
-ssl3_ClientSendSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
-                                      PRUint32 maxBytes)
+SECStatus
+ssl3_ClientSendSignedCertTimestampXtn(const sslSocket *ss,
+                                      TLSExtensionData *xtnData,
+                                      sslBuffer *buf, PRBool *added)
 {
-    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_ExtAppendHandshakeNumber(ss,
-                                           ssl_signed_cert_timestamp_xtn,
-                                           2);
-        if (rv != SECSuccess)
-            goto loser;
-        /* zero length */
-        rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2);
-        if (rv != SECSuccess)
-            goto loser;
-        xtnData->advertised[xtnData->numAdvertised++] =
-            ssl_signed_cert_timestamp_xtn;
-    } else if (maxBytes < extension_length) {
-        PORT_Assert(0);
-        return 0;
+    if (!ss->opt.enableSignedCertTimestamps) {
+        return SECSuccess;
     }
 
-    return extension_length;
-loser:
-    return -1;
+    *added = PR_TRUE;
+    return SECSuccess;
 }
 
 SECStatus
-ssl3_ClientHandleSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
+ssl3_ClientHandleSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                         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
@@ -2088,102 +1761,81 @@ ssl3_ClientHandleSignedCertTimestampXtn(
     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. */
-    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
+    xtnData->negotiated[xtnData->numNegotiated++] = ssl_signed_cert_timestamp_xtn;
     return SECSuccess;
 }
 
-PRInt32
+SECStatus
 ssl3_ServerSendSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData,
-                                      PRBool append,
-                                      PRUint32 maxBytes)
+                                      sslBuffer *buf, PRBool *added)
 {
-    PRInt32 extension_length;
     const SECItem *scts = &ss->sec.serverCert->signedCertTimestamps;
+    SECStatus rv;
 
     if (!scts->len) {
         /* No timestamps to send */
-        return 0;
+        return SECSuccess;
     }
 
-    extension_length = 2 /* extension_type */ +
-                       2 /* length(extension_data) */ +
-                       scts->len;
-
-    if (maxBytes < extension_length) {
-        PORT_Assert(0);
-        return 0;
-    }
-    if (append) {
-        SECStatus rv;
-        /* extension_type */
-        rv = ssl3_ExtAppendHandshakeNumber(ss,
-                                           ssl_signed_cert_timestamp_xtn,
-                                           2);
-        if (rv != SECSuccess) {
-            return -1;
-        }
-        /* extension_data */
-        rv = ssl3_ExtAppendHandshakeVariable(ss, scts->data, scts->len, 2);
-        if (rv != SECSuccess) {
-            return -1;
-        }
+    rv = sslBuffer_Append(buf, scts->data, scts->len);
+    if (rv != SECSuccess) {
+        return SECFailure;
     }
 
-    return extension_length;
+    *added = PR_TRUE;
+    return SECSuccess;
 }
 
 SECStatus
 ssl3_ServerHandleSignedCertTimestampXtn(const sslSocket *ss,
                                         TLSExtensionData *xtnData,
-                                        PRUint16 ex_type,
                                         SECItem *data)
 {
     if (data->len != 0) {
         ssl3_ExtSendAlert(ss, alert_fatal, decode_error);
         PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
         return SECFailure;
     }
 
-    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
+    xtnData->negotiated[xtnData->numNegotiated++] = ssl_signed_cert_timestamp_xtn;
     PORT_Assert(ss->sec.isServer);
-    return ssl3_RegisterExtensionSender(
-        ss, xtnData, ex_type, ssl3_ServerSendSignedCertTimestampXtn);
+    return ssl3_RegisterExtensionSender(ss, xtnData,
+                                        ssl_signed_cert_timestamp_xtn,
+                                        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;
 
     PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3);
 
     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;
+            return ssl3_RegisterExtensionSender(
+                ss, xtnData, ssl_ec_point_formats_xtn,
+                &ssl3_SendSupportedPointFormatsXtn);
         }
     }
 
     /* Poor client doesn't support uncompressed points. */
     PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE);
     return SECFailure;
 }
 
@@ -2258,30 +1910,30 @@ ssl_UpdateSupportedGroups(sslSocket *ss,
     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)
+                             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,
+        rv = ssl3_RegisterExtensionSender(ss, xtnData, ssl_supported_groups_xtn,
                                           &ssl_SendSupportedGroupsXtn);
         if (rv != SECSuccess) {
             return SECFailure; /* error already set. */
         }
     }
 
     /* Remember that we negotiated this extension. */
-    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
+    xtnData->negotiated[xtnData->numNegotiated++] = ssl_supported_groups_xtn;
 
     return SECSuccess;
 }
--- a/lib/ssl/ssl3exthandle.h
+++ b/lib/ssl/ssl3exthandle.h
@@ -4,95 +4,118 @@
  *
  * 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(const sslSocket *ss, TLSExtensionData *xtnData,
-                                      PRBool append, PRUint32 maxBytes);
-SECStatus ssl3_HandleRenegotiationInfoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
-                                          PRUint16 ex_type, SECItem *data);
-SECStatus ssl3_ClientHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
-                                            PRUint16 ex_type, SECItem *data);
-SECStatus ssl3_ClientHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
-                                       PRUint16 ex_type, SECItem *data);
-SECStatus ssl3_ServerHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
-                                            PRUint16 ex_type, SECItem *data);
-SECStatus ssl3_ServerHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
+#include "sslencode.h"
+
+SECStatus ssl3_SendRenegotiationInfoXtn(const sslSocket *ss,
+                                        TLSExtensionData *xtnData,
+                                        sslBuffer *buf, PRBool *added);
+SECStatus ssl3_HandleRenegotiationInfoXtn(const sslSocket *ss,
+                                          TLSExtensionData *xtnData,
+                                          SECItem *data);
+SECStatus ssl3_ClientHandleNextProtoNegoXtn(const sslSocket *ss,
+                                            TLSExtensionData *xtnData,
+                                            SECItem *data);
+SECStatus ssl3_ClientHandleAppProtoXtn(const sslSocket *ss,
+                                       TLSExtensionData *xtnData,
                                        SECItem *data);
-PRInt32 ssl3_ClientSendNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
-                                        PRUint32 maxBytes);
-PRInt32 ssl3_ClientSendAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
-                                   PRUint32 maxBytes);
-PRInt32 ssl3_ServerSendAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
-                                   PRUint32 maxBytes);
-PRInt32 ssl3_ClientSendUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
-                                  PRUint32 maxBytes);
-PRInt32 ssl3_ServerSendUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
-                                  PRUint32 maxBytes);
-SECStatus ssl3_ClientHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
-                                      SECItem *data);
-SECStatus ssl3_ServerHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
+SECStatus ssl3_ServerHandleNextProtoNegoXtn(const sslSocket *ss,
+                                            TLSExtensionData *xtnData,
+                                            SECItem *data);
+SECStatus ssl3_ServerHandleAppProtoXtn(const sslSocket *ss,
+                                       TLSExtensionData *xtnData,
+                                       SECItem *data);
+SECStatus ssl3_ClientSendNextProtoNegoXtn(const sslSocket *ss,
+                                          TLSExtensionData *xtnData,
+                                          sslBuffer *buf, PRBool *added);
+SECStatus ssl3_ClientSendAppProtoXtn(const sslSocket *ss,
+                                     TLSExtensionData *xtnData,
+                                     sslBuffer *buf, PRBool *added);
+SECStatus ssl3_ServerSendAppProtoXtn(const sslSocket *ss,
+                                     TLSExtensionData *xtnData,
+                                     sslBuffer *buf, PRBool *added);
+SECStatus ssl3_ClientSendUseSRTPXtn(const sslSocket *ss,
+                                    TLSExtensionData *xtnData,
+                                    sslBuffer *buf, PRBool *added);
+SECStatus ssl3_ServerSendUseSRTPXtn(const sslSocket *ss,
+                                    TLSExtensionData *xtnData,
+                                    sslBuffer *buf, PRBool *added);
+SECStatus ssl3_ClientHandleUseSRTPXtn(const sslSocket *ss,
+                                      TLSExtensionData *xtnData,
                                       SECItem *data);
-PRInt32 ssl3_ServerSendStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData,
-                                        PRBool append, PRUint32 maxBytes);
-SECStatus ssl3_ServerHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData,
-                                            PRUint16 ex_type, SECItem *data);
-SECStatus ssl3_ClientHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData,
-                                            PRUint16 ex_type,
+SECStatus ssl3_ServerHandleUseSRTPXtn(const sslSocket *ss,
+                                      TLSExtensionData *xtnData,
+                                      SECItem *data);
+SECStatus ssl3_ServerSendStatusRequestXtn(const sslSocket *ss,
+                                          TLSExtensionData *xtnData,
+                                          sslBuffer *buf, PRBool *added);
+SECStatus ssl3_ServerHandleStatusRequestXtn(const sslSocket *ss,
+                                            TLSExtensionData *xtnData,
                                             SECItem *data);
-PRInt32 ssl3_ClientSendStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
-                                        PRUint32 maxBytes);
-PRInt32 ssl3_SendSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
-                            PRBool append, PRUint32 maxBytes);
+SECStatus ssl3_ClientHandleStatusRequestXtn(const sslSocket *ss,
+                                            TLSExtensionData *xtnData,
+                                            SECItem *data);
+SECStatus ssl3_ClientSendStatusRequestXtn(const sslSocket *ss,
+                                          TLSExtensionData *xtnData,
+                                          sslBuffer *buf, PRBool *added);
+SECStatus ssl3_SendSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                              sslBuffer *buf, PRBool *added);
 SECStatus ssl3_HandleSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
-                                PRUint16 ex_type, SECItem *data);
-
-PRInt32 ssl3_ClientSendPaddingExtension(const sslSocket *ss, TLSExtensionData *xtnData,
-                                        PRBool append, PRUint32 maxBytes);
+                                SECItem *data);
 
-PRInt32 ssl3_ClientSendSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData,
-                                              PRBool append,
-                                              PRUint32 maxBytes);
-SECStatus ssl3_ClientHandleSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData,
-                                                  PRUint16 ex_type,
+SECStatus ssl3_ClientSendPaddingExtension(const sslSocket *ss,
+                                          TLSExtensionData *xtnData,
+                                          sslBuffer *buf, PRBool *added);
+
+SECStatus ssl3_ClientSendSignedCertTimestampXtn(const sslSocket *ss,
+                                                TLSExtensionData *xtnData,
+                                                sslBuffer *buf, PRBool *added);
+SECStatus ssl3_ClientHandleSignedCertTimestampXtn(const sslSocket *ss,
+                                                  TLSExtensionData *xtnData,
                                                   SECItem *data);
-PRInt32 ssl3_ServerSendSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData,
-                                              PRBool append,
-                                              PRUint32 maxBytes);
-SECStatus ssl3_ServerHandleSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData,
-                                                  PRUint16 ex_type,
+SECStatus ssl3_ServerSendSignedCertTimestampXtn(const sslSocket *ss,
+                                                TLSExtensionData *xtnData,
+                                                sslBuffer *buf, PRBool *added);
+SECStatus ssl3_ServerHandleSignedCertTimestampXtn(const sslSocket *ss,
+                                                  TLSExtensionData *xtnData,
                                                   SECItem *data);
-PRInt32 ssl3_SendExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
-                                         PRUint32 maxBytes);
-SECStatus ssl3_HandleExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnData,
-                                             PRUint16 ex_type,
+SECStatus ssl3_SendExtendedMasterSecretXtn(const sslSocket *ss,
+                                           TLSExtensionData *xtnData,
+                                           sslBuffer *buf, PRBool *added);
+SECStatus ssl3_HandleExtendedMasterSecretXtn(const sslSocket *ss,
+                                             TLSExtensionData *xtnData,
                                              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);
+SECStatus ssl3_ClientSendServerNameXtn(const sslSocket *ss,
+                                       TLSExtensionData *xtnData,
+                                       sslBuffer *buf, PRBool *added);
+SECStatus ssl3_HandleServerNameXtn(const sslSocket *ss,
+                                   TLSExtensionData *xtnData,
+                                   SECItem *data);
+SECStatus ssl_HandleSupportedGroupsXtn(const sslSocket *ss,
+                                       TLSExtensionData *xtnData,
+                                       SECItem *data);
+SECStatus ssl3_HandleSupportedPointFormatsXtn(const sslSocket *ss,
+                                              TLSExtensionData *xtnData,
+                                              SECItem *data);
+SECStatus ssl3_ClientHandleSessionTicketXtn(const sslSocket *ss,
+                                            TLSExtensionData *xtnData,
+                                            SECItem *data);
+SECStatus ssl3_ServerHandleSessionTicketXtn(const sslSocket *ss,
+                                            TLSExtensionData *xtnData,
+                                            SECItem *data);
+SECStatus ssl3_ClientSendSessionTicketXtn(const sslSocket *ss,
+                                          TLSExtensionData *xtnData,
+                                          sslBuffer *buf, PRBool *added);
 
-PRInt32 ssl_SendSupportedGroupsXtn(const sslSocket *ss,
-                                   TLSExtensionData *xtnData,
-                                   PRBool append, PRUint32 maxBytes);
-PRInt32 ssl3_SendSupportedPointFormatsXtn(const sslSocket *ss,
-                                          TLSExtensionData *xtnData,
-                                          PRBool append, PRUint32 maxBytes);
+SECStatus ssl_SendSupportedGroupsXtn(const sslSocket *ss,
+                                     TLSExtensionData *xtnData,
+                                     sslBuffer *buf, PRBool *added);
+SECStatus ssl3_SendSupportedPointFormatsXtn(const sslSocket *ss,
+                                            TLSExtensionData *xtnData,
+                                            sslBuffer *buf, PRBool *added);
 #endif
--- a/lib/ssl/ssl3gthr.c
+++ b/lib/ssl/ssl3gthr.c
@@ -93,17 +93,17 @@ ssl3_GatherData(sslSocket *ss, sslGather
     int nb;
     int err;
     int rv = 1;
     PRUint8 v2HdrLength = 0;
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
     if (gs->state == GS_INIT) {
         gs->state = GS_HEADER;
-        gs->remainder = ss->ssl3.hs.shortHeaders ? 2 : 5;
+        gs->remainder = 5;
         gs->offset = 0;
         gs->writeOffset = 0;
         gs->readOffset = 0;
         gs->inbuf.len = 0;
     }
 
     lbp = gs->inbuf.buf;
     for (;;) {
@@ -151,29 +151,17 @@ ssl3_GatherData(sslSocket *ss, sslGather
                  * support SSLv2 handshakes only when ssl2gs != NULL.
                  * Always assume v3 after we received the first record. */
                 if (!ssl2gs ||
                     ss->gs.rejectV2Records ||
                     ssl3_isLikelyV3Hello(gs->hdr)) {
                     /* Should have a non-SSLv2 record header in gs->hdr. Extract
                      * the length of the following encrypted data, and then
                      * read in the rest of the record into gs->inbuf. */
-                    if (ss->ssl3.hs.shortHeaders) {
-                        PRUint16 len = (gs->hdr[0] << 8) | gs->hdr[1];
-                        if (!(len & 0x8000)) {
-                            SSL_DBG(("%d: SSL3[%d]: incorrectly formatted header"));
-                            SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
-                            gs->state = GS_INIT;
-                            PORT_SetError(SSL_ERROR_BAD_MAC_READ);
-                            return SECFailure;
-                        }
-                        gs->remainder = len & ~0x8000;
-                    } else {
-                        gs->remainder = (gs->hdr[3] << 8) | gs->hdr[4];
-                    }
+                    gs->remainder = (gs->hdr[3] << 8) | gs->hdr[4];
                 } else {
                     /* Probably an SSLv2 record header. No need to handle any
                      * security escapes (gs->hdr[0] & 0x40) as we wouldn't get
                      * here if one was set. See ssl3_isLikelyV3Hello(). */
                     gs->remainder = ((gs->hdr[0] & 0x7f) << 8) | gs->hdr[1];
                     ssl2gs->isV2 = PR_TRUE;
                     v2HdrLength = 2;
 
@@ -488,23 +476,18 @@ ssl3_GatherCompleteHandshake(sslSocket *
                     return rv;
                 }
             } else {
                 /* decipher it, and handle it if it's a handshake.
                  * If it's application data, ss->gs.buf will not be empty upon return.
                  * If it's a change cipher spec, alert, or handshake message,
                  * ss->gs.buf.len will be 0 when ssl3_HandleRecord returns SECSuccess.
                  */
-                if (ss->ssl3.hs.shortHeaders) {
-                    cText.type = content_application_data;
-                    cText.version = SSL_LIBRARY_VERSION_TLS_1_0;
-                } else {
-                    cText.type = (SSL3ContentType)ss->gs.hdr[0];
-                    cText.version = (ss->gs.hdr[1] << 8) | ss->gs.hdr[2];
-                }
+                cText.type = (SSL3ContentType)ss->gs.hdr[0];
+                cText.version = (ss->gs.hdr[1] << 8) | ss->gs.hdr[2];
 
                 if (IS_DTLS(ss)) {
                     sslSequenceNumber seq_num;
 
                     cText.version = dtls_DTLSVersionToTLSVersion(cText.version);
                     /* DTLS sequence number */
                     PORT_Memcpy(&seq_num, &ss->gs.hdr[3], sizeof(seq_num));
                     cText.seq_num = PR_ntohll(seq_num);
--- a/lib/ssl/ssl3prot.h
+++ b/lib/ssl/ssl3prot.h
@@ -25,17 +25,16 @@ typedef PRUint16 ssl3CipherSuite;
 #define MAX_COMPRESSION_METHODS 10
 #define MAX_MAC_LENGTH 64
 #define MAX_PADDING_LENGTH 64
 #define MAX_KEY_LENGTH 64
 #define EXPORT_KEY_LENGTH 5
 #define SSL3_RANDOM_LENGTH 32
 
 #define SSL3_RECORD_HEADER_LENGTH 5
-#define TLS13_RECORD_HEADER_LENGTH_SHORT 2
 
 /* SSL3_RECORD_HEADER_LENGTH + epoch/sequence_number */
 #define DTLS_RECORD_HEADER_LENGTH 13
 
 #define MAX_FRAGMENT_LENGTH 16384
 
 typedef enum {
     content_change_cipher_spec = 20,
@@ -121,36 +120,16 @@ typedef enum {
     no_alert = 256
 } SSL3AlertDescription;
 
 typedef struct {
     SSL3AlertLevel level;
     SSL3AlertDescription description;
 } SSL3Alert;
 
-typedef enum {
-    hello_request = 0,
-    client_hello = 1,
-    server_hello = 2,
-    hello_verify_request = 3,
-    new_session_ticket = 4,
-    end_of_early_data = 5,
-    hello_retry_request = 6,
-    encrypted_extensions = 8,
-    certificate = 11,
-    server_key_exchange = 12,
-    certificate_request = 13,
-    server_hello_done = 14,
-    certificate_verify = 15,
-    client_key_exchange = 16,
-    finished = 20,
-    certificate_status = 22,
-    next_proto = 67,
-} SSL3HandshakeType;
-
 typedef struct {
     PRUint8 empty;
 } SSL3HelloRequest;
 
 typedef struct {
     PRUint8 rand[SSL3_RANDOM_LENGTH];
 } SSL3Random;
 
@@ -230,17 +209,17 @@ typedef struct {
  * which, if |hashAlg==ssl_hash_none| is also a SSL3HashesIndividually
  * struct. */
 typedef struct {
     unsigned int len;
     SSLHashType hashAlg;
     union {
         PRUint8 raw[64];
         SSL3HashesIndividually s;
-        SECItem pointer_to_hash_input;
+        unsigned int transcriptLen;
     } u;
 } SSL3Hashes;
 
 typedef struct {
     union {
         PRUint8 anonymous;
         SSL3Hashes certified;
     } u;
new file mode 100644
--- /dev/null
+++ b/lib/ssl/sslencode.c
@@ -0,0 +1,170 @@
+/* -*- 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/. */
+
+#include "nss.h"
+#include "prnetdb.h"
+#include "ssl.h"
+#include "sslimpl.h"
+
+/* Helper function to encode an unsigned integer into a buffer. */
+PRUint8 *
+ssl_EncodeUintX(PRUint64 value, unsigned int bytes, PRUint8 *to)
+{
+    PRUint64 encoded;
+
+    PORT_Assert(bytes > 0 && bytes <= sizeof(encoded));
+
+    encoded = PR_htonll(value);
+    memcpy(to, ((unsigned char *)(&encoded)) + (sizeof(encoded) - bytes), bytes);
+    return to + bytes;
+}
+
+/* Grow a buffer to hold newLen bytes of data.  When used for recv/xmit buffers,
+ * the caller must hold xmitBufLock or recvBufLock, as appropriate. */
+SECStatus
+sslBuffer_Grow(sslBuffer *b, unsigned int newLen)
+{
+    newLen = PR_MAX(newLen, b->len + 1024);
+    if (newLen > b->space) {
+        unsigned char *newBuf;
+        if (b->buf) {
+            newBuf = (unsigned char *)PORT_Realloc(b->buf, newLen);
+        } else {
+            newBuf = (unsigned char *)PORT_Alloc(newLen);
+        }
+        if (!newBuf) {
+            return SECFailure;
+        }
+        b->buf = newBuf;
+        b->space = newLen;
+    }
+    return SECSuccess;
+}
+
+SECStatus
+sslBuffer_Append(sslBuffer *b, const void *data, unsigned int len)
+{
+    SECStatus rv = sslBuffer_Grow(b, b->len + len);
+    if (rv != SECSuccess) {
+        return rv; /* Code already set. */
+    }
+    PORT_Memcpy(b->buf + b->len, data, len);
+    b->len += len;
+    return SECSuccess;
+}
+
+SECStatus
+sslBuffer_AppendNumber(sslBuffer *b, PRUint64 v, unsigned int size)
+{
+    SECStatus rv = sslBuffer_Grow(b, b->len + size);
+    if (rv != SECSuccess) {
+        return rv;
+    }
+    (void)ssl_EncodeUintX(v, size, b->buf + b->len);
+    b->len += size;
+    return SECSuccess;
+}
+
+SECStatus
+sslBuffer_AppendVariable(sslBuffer *b, const PRUint8 *data, unsigned int len,
+                         unsigned int size)
+{
+    SECStatus rv = sslBuffer_Grow(b, b->len + len + size);
+    if (rv != SECSuccess) {
+        return rv;
+    }
+    (void)ssl_EncodeUintX(len, size, b->buf + b->len);
+    b->len += size;
+    PORT_Memcpy(b->buf + b->len, data, len);
+    b->len += len;
+    return SECSuccess;
+}
+
+SECStatus
+sslBuffer_AppendBuffer(sslBuffer *b, const sslBuffer *append)
+{
+    return sslBuffer_Append(b, append->buf, append->len);
+}
+
+SECStatus
+sslBuffer_AppendBufferVariable(sslBuffer *b, const sslBuffer *append,
+                               unsigned int size)
+{
+    return sslBuffer_AppendVariable(b, append->buf, append->len, size);
+}
+
+void
+sslBuffer_Clear(sslBuffer *b)
+{
+    if (b->buf) {
+        PORT_Free(b->buf);
+        b->buf = NULL;
+        b->len = 0;
+        b->space = 0;
+    }
+}
+
+SECStatus
+ssl3_AppendToItem(SECItem *item, const unsigned char *buf, PRUint32 bytes)
+{
+    if (bytes > item->len) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
+    PORT_Memcpy(item->data, buf, bytes);
+    item->data += bytes;
+    item->len -= bytes;
+    return SECSuccess;
+}
+
+SECStatus
+ssl3_AppendNumberToItem(SECItem *item, PRUint32 num, PRInt32 lenSize)
+{
+    SECStatus rv;
+    PRUint8 b[sizeof(num)];
+
+    ssl_EncodeUintX(num, lenSize, b);
+    rv = ssl3_AppendToItem(item, &b[0], lenSize);
+    return rv;
+}
+
+SECStatus
+ssl3_ConsumeFromItem(SECItem *item, unsigned char **buf, PRUint32 bytes)
+{
+    if (bytes > item->len) {
+        PORT_SetError(SEC_ERROR_BAD_DATA);
+        return SECFailure;
+    }
+
+    *buf = item->data;
+    item->data += bytes;
+    item->len -= bytes;
+    return SECSuccess;
+}
+
+SECStatus
+ssl3_ConsumeNumberFromItem(SECItem *item, PRUint32 *num, PRUint32 bytes)
+{
+    int i;
+
+    if (bytes > item->len || bytes > sizeof(*num)) {
+        PORT_SetError(SEC_ERROR_BAD_DATA);
+        return SECFailure;
+    }
+
+    *num = 0;
+    for (i = 0; i < bytes; i++) {
+        *num = (*num << 8) + item->data[i];
+    }
+
+    item->data += bytes;
+    item->len -= bytes;
+
+    return SECSuccess;
+}
new file mode 100644
--- /dev/null
+++ b/lib/ssl/sslencode.h
@@ -0,0 +1,44 @@
+/* -*- 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 __sslencode_h_
+#define __sslencode_h_
+
+PRUint8 *ssl_EncodeUintX(PRUint64 value, unsigned int bytes, PRUint8 *to);
+
+/*
+ ** A buffer object.
+ */
+typedef struct sslBufferStr {
+    PRUint8 *buf;
+    unsigned int len;
+    unsigned int space;
+} sslBuffer;
+
+SECStatus sslBuffer_Grow(sslBuffer *b, unsigned int newLen);
+SECStatus sslBuffer_Append(sslBuffer *b, const void *data, unsigned int len);
+SECStatus sslBuffer_AppendNumber(sslBuffer *b, PRUint64 v, unsigned int size);
+SECStatus sslBuffer_AppendVariable(sslBuffer *b, const PRUint8 *data,
+                                   unsigned int len, unsigned int size);
+SECStatus sslBuffer_AppendBuffer(sslBuffer *b, const sslBuffer *append);
+SECStatus sslBuffer_AppendBufferVariable(sslBuffer *b, const sslBuffer *append,
+                                         unsigned int size);
+void sslBuffer_Clear(sslBuffer *b);
+
+/* All of these functions modify the underlying SECItem, and so should
+ * be performed on a shallow copy.*/
+SECStatus ssl3_AppendToItem(SECItem *item,
+                            const unsigned char *buf, PRUint32 bytes);
+SECStatus ssl3_AppendNumberToItem(SECItem *item,
+                                  PRUint32 num, PRInt32 lenSize);
+SECStatus ssl3_ConsumeFromItem(SECItem *item,
+                               unsigned char **buf, PRUint32 bytes);
+SECStatus ssl3_ConsumeNumberFromItem(SECItem *item,
+                                     PRUint32 *num, PRUint32 bytes);
+
+#endif /* __sslencode_h_ */
--- a/lib/ssl/sslimpl.h
+++ b/lib/ssl/sslimpl.h
@@ -31,16 +31,17 @@
 #include "prclist.h"
 #include "private/pprthred.h"
 
 #include "sslt.h" /* for some formerly private types, now public */
 
 typedef struct sslSocketStr sslSocket;
 typedef struct ssl3CipherSpecStr ssl3CipherSpec;
 #include "ssl3ext.h"
+#include "sslencode.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
@@ -169,17 +170,16 @@ typedef struct {
     SSLKEAType keaType;
     /* The OID that identifies the group to PKCS11.  This also determines
      * whether the group is enabled in policy. */
     SECOidTag oidTag;
     /* Assume that the group is always supported. */
     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 sslSocketOpsStr sslSocketOps;
 
 typedef struct ssl3StateStr ssl3State;
 typedef struct ssl3CertNodeStr ssl3CertNode;
@@ -229,25 +229,16 @@ struct sslSocketOpsStr {
 #define ssl_SEND_FLAG_FORCE_INTO_BUFFER 0x40000000
 #define ssl_SEND_FLAG_NO_BUFFER 0x20000000
 #define ssl_SEND_FLAG_NO_RETRANSMIT 0x08000000 /* DTLS only */
 #define ssl_SEND_FLAG_CAP_RECORD_VERSION \
     0x04000000 /* TLS only */
 #define ssl_SEND_FLAG_MASK 0x7f000000
 
 /*
-** A buffer object.
-*/
-struct sslBufferStr {
-    unsigned char *buf;
-    unsigned int len;
-    unsigned int space;
-};
-
-/*
 ** SSL3 cipher suite policy and preference struct.
 */
 typedef struct {
 #if !defined(_WIN32)
     unsigned int cipher_suite : 16;
     unsigned int policy : 8;
     unsigned int enabled : 1;
     unsigned int isPresent : 1;
@@ -784,17 +775,17 @@ typedef struct SSL3HandshakeStateStr {
     ssl3CipherSuite cipher_suite;
     const ssl3CipherSuiteDef *suite_def;
     SSLCompressionMethod compression;
     sslBuffer msg_body; /* protected by recvBufLock */
                         /* partial handshake message from record layer */
     unsigned int header_bytes;
     /* number of bytes consumed from handshake */
     /* message for message type and header length */
-    SSL3HandshakeType msg_type;
+    SSLHandshakeType msg_type;
     unsigned long msg_len;
     PRBool isResuming;  /* we are resuming (not used in TLS 1.3) */
     PRBool sendingSCSV; /* instead of empty RI */
     sslBuffer msgState; /* current state for handshake messages*/
                         /* protected by recvBufLock */
 
     /* The session ticket received in a NewSessionTicket message is temporarily
      * stored in newSessionTicket until the handshake is finished; then it is
@@ -868,17 +859,16 @@ typedef struct SSL3HandshakeStateStr {
     ssl3CipherSuite zeroRttSuite;         /* The cipher suite we used for 0-RTT. */
     PRCList bufferedEarlyData;            /* Buffered TLS 1.3 early data
                                      * on server.*/
     PRBool helloRetry;                    /* True if HelloRetryRequest has been sent
                                      * or received. */
     PRBool clientCertRequested;           /* True if CertificateRequest received. */
     ssl3KEADef kea_def_mutable;           /* Used to hold the writable kea_def
                                      * we use for TLS 1.3 */
-    PRBool shortHeaders;                  /* Assigned if we are doing short headers. */
 } SSL3HandshakeState;
 
 /*
 ** This is the "ssl3" struct, as in "ss->ssl3".
 ** note:
 ** usually,   crSpec == cwSpec and prSpec == pwSpec.
 ** Sometimes, crSpec == pwSpec and prSpec == cwSpec.
 ** But there are never more than 2 actual specs.
@@ -1137,16 +1127,17 @@ struct sslSocketStr {
     void *badCertArg;
     SSLHandshakeCallback handshakeCallback;
     void *handshakeCallbackData;
     SSLCanFalseStartCallback canFalseStartCallback;
     void *canFalseStartCallbackData;
     void *pkcs11PinArg;
     SSLNextProtoCallback nextProtoCallback;
     void *nextProtoArg;
+    PRCList extensionHandlers;
 
     PRIntervalTime rTimeout; /* timeout for NSPR I/O */
     PRIntervalTime wTimeout; /* timeout for NSPR I/O */
     PRIntervalTime cTimeout; /* timeout for NSPR I/O */
 
     PZLock *recvLock; /* lock against multiple reader threads. */
     PZLock *sendLock; /* lock against multiple sender threads. */
 
@@ -1317,21 +1308,16 @@ extern void ssl_PrintKey(const sslSocket
 
 extern int ssl_SendSavedWriteData(sslSocket *ss);
 extern SECStatus ssl_SaveWriteData(sslSocket *ss,
                                    const void *p, unsigned int l);
 extern SECStatus ssl_BeginClientHandshake(sslSocket *ss);
 extern SECStatus ssl_BeginServerHandshake(sslSocket *ss);
 extern int ssl_Do1stHandshake(sslSocket *ss);
 
-extern SECStatus sslBuffer_Grow(sslBuffer *b, unsigned int newLen);
-extern SECStatus sslBuffer_Append(sslBuffer *b, const void *data,
-                                  unsigned int len);
-extern void sslBuffer_Clear(sslBuffer *b);
-
 extern void ssl_ChooseSessionIDProcs(sslSecurityInfo *sec);
 
 extern void ssl3_InitCipherSpec(ssl3CipherSpec *spec);
 extern sslSessionID *ssl3_NewSessionID(sslSocket *ss, PRBool is_server);
 extern sslSessionID *ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port,
                                    const char *peerID, const char *urlSvrName);
 extern void ssl_FreeSID(sslSessionID *sid);
 
@@ -1569,17 +1555,17 @@ extern sslEphemeralKeyPair *ssl_CopyEphe
     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(const sslSocket *ss,
+extern SECStatus ssl_AppendPaddedDHKeyShare(sslBuffer *buf,
                                             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);
@@ -1650,45 +1636,44 @@ extern SECStatus ssl3_HandleECDHServerKe
                                                   PRUint8 *b, PRUint32 length);
 extern SECStatus ssl3_HandleECDHClientKeyExchange(sslSocket *ss,
                                                   PRUint8 *b, PRUint32 length,
                                                   sslKeyPair *serverKeys);
 extern SECStatus ssl3_SendECDHServerKeyExchange(sslSocket *ss);
 extern SECStatus ssl_ImportECDHKeyShare(
     sslSocket *ss, SECKEYPublicKey *peerKey,
     PRUint8 *b, PRUint32 length, const sslNamedGroupDef *curve);
-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);
 extern SECStatus ssl3_AppendHandshake(sslSocket *ss, const void *void_src,
-                                      PRInt32 bytes);
+                                      unsigned int bytes);
 extern SECStatus ssl3_AppendHandshakeHeader(sslSocket *ss,
-                                            SSL3HandshakeType t, PRUint32 length);
-extern SECStatus ssl3_AppendHandshakeNumber(sslSocket *ss, PRInt32 num,
-                                            PRInt32 lenSize);
-extern SECStatus ssl3_AppendHandshakeVariable(sslSocket *ss,
-                                              const PRUint8 *src, PRInt32 bytes, PRInt32 lenSize);
+                                            SSLHandshakeType t, unsigned int length);
+extern SECStatus ssl3_AppendHandshakeNumber(sslSocket *ss, PRUint64 num,
+                                            unsigned int lenSize);
+extern SECStatus ssl3_AppendHandshakeVariable(sslSocket *ss, const PRUint8 *src,
+                                              unsigned int bytes, unsigned int lenSize);
+extern SECStatus ssl3_AppendBufferToHandshake(sslSocket *ss, sslBuffer *buf);
+extern SECStatus ssl3_AppendBufferToHandshakeVariable(sslSocket *ss, sslBuffer *buf,
+                                                      unsigned int lenSize);
 extern SECStatus ssl3_AppendSignatureAndHashAlgorithm(
     sslSocket *ss, const SSLSignatureAndHashAlg *sigAndHash);
 extern SECStatus ssl3_ConsumeHandshake(sslSocket *ss, void *v, PRUint32 bytes,
                                        PRUint8 **b, PRUint32 *length);
 extern SECStatus ssl3_ConsumeHandshakeNumber(sslSocket *ss, PRUint32 *num,
                                              PRUint32 bytes, PRUint8 **b,
                                              PRUint32 *length);
 extern SECStatus ssl3_ConsumeHandshakeVariable(sslSocket *ss, SECItem *i,
                                                PRUint32 bytes, PRUint8 **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(const sslSocket *ss, PLArenaPool *arena,
                                            SSLSignatureScheme **schemesOut,
                                            unsigned int *numSchemesOut,
                                            unsigned char **b,
                                            unsigned int *len);
--- a/lib/ssl/sslsecur.c
+++ b/lib/ssl/sslsecur.c
@@ -1,8 +1,9 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /*
  * Various SSL functions.
  *
  * 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 "cert.h"
 #include "secitem.h"
@@ -430,68 +431,16 @@ SSL_ForceHandshakeWithTimeout(PRFileDesc
         return SECFailure;
     }
     return SSL_ForceHandshake(fd);
 }
 
 /************************************************************************/
 
 /*
-** Grow a buffer to hold newLen bytes of data.
-** Called for both recv buffers and xmit buffers.
-** Caller must hold xmitBufLock or recvBufLock, as appropriate.
-*/
-SECStatus
-sslBuffer_Grow(sslBuffer *b, unsigned int newLen)
-{
-    newLen = PR_MAX(newLen, MAX_FRAGMENT_LENGTH + 2048);
-    if (newLen > b->space) {
-        unsigned char *newBuf;
-        if (b->buf) {
-            newBuf = (unsigned char *)PORT_Realloc(b->buf, newLen);
-        } else {
-            newBuf = (unsigned char *)PORT_Alloc(newLen);
-        }
-        if (!newBuf) {
-            return SECFailure;
-        }
-        SSL_TRC(10, ("%d: SSL: grow buffer from %d to %d",
-                     SSL_GETPID(), b->space, newLen));
-        b->buf = newBuf;
-        b->space = newLen;
-    }
-    return SECSuccess;
-}
-
-SECStatus
-sslBuffer_Append(sslBuffer *b, const void *data, unsigned int len)
-{
-    unsigned int newLen = b->len + len;
-    SECStatus rv;
-
-    rv = sslBuffer_Grow(b, newLen);
-    if (rv != SECSuccess)
-        return rv;
-    PORT_Memcpy(b->buf + b->len, data, len);
-    b->len += len;
-    return SECSuccess;
-}
-
-void
-sslBuffer_Clear(sslBuffer *b)
-{
-    if (b->buf) {
-        PORT_Free(b->buf);
-        b->buf = NULL;
-        b->len = 0;
-        b->space = 0;
-    }
-}
-
-/*
 ** Save away write data that is trying to be written before the security
 ** handshake has been completed. When the handshake is completed, we will
 ** flush this data out.
 ** Caller must hold xmitBufLock
 */
 SECStatus
 ssl_SaveWriteData(sslSocket *ss, const void *data, unsigned int len)
 {
--- a/lib/ssl/sslsock.c
+++ b/lib/ssl/sslsock.c
@@ -73,22 +73,17 @@ static sslOptions ssl_defaults = {
     PR_FALSE,              /* enableNPN          */
     PR_TRUE,               /* enableALPN         */
     PR_TRUE,               /* reuseServerECDHEKey */
     PR_FALSE,              /* enableFallbackSCSV */
     PR_TRUE,               /* enableServerDhe */
     PR_FALSE,              /* enableExtendedMS    */
     PR_FALSE,              /* enableSignedCertTimestamps */
     PR_FALSE,              /* requireDHENamedGroups */
-    PR_FALSE,              /* enable0RttData */
-#ifdef NSS_ENABLE_TLS13_SHORT_HEADERS
-    PR_TRUE /* enableShortHeaders */
-#else
-    PR_FALSE /* enableShortHeaders */
-#endif
+    PR_FALSE               /* enable0RttData */
 };
 
 /*
  * default range of enabled SSL/TLS protocols
  */
 static SSLVersionRange versions_defaults_stream = {
     SSL_LIBRARY_VERSION_TLS_1_0,
     SSL_LIBRARY_VERSION_TLS_1_2
--- a/lib/ssl/sslt.h
+++ b/lib/ssl/sslt.h
@@ -8,16 +8,36 @@
 
 #ifndef __sslt_h_
 #define __sslt_h_
 
 #include "prtypes.h"
 #include "secitem.h"
 #include "certt.h"
 
+typedef enum {
+    ssl_hs_hello_request = 0,
+    ssl_hs_client_hello = 1,
+    ssl_hs_server_hello = 2,
+    ssl_hs_hello_verify_request = 3,
+    ssl_hs_new_session_ticket = 4,
+    ssl_hs_end_of_early_data = 5,
+    ssl_hs_hello_retry_request = 6,
+    ssl_hs_encrypted_extensions = 8,
+    ssl_hs_certificate = 11,
+    ssl_hs_server_key_exchange = 12,
+    ssl_hs_certificate_request = 13,
+    ssl_hs_server_hello_done = 14,
+    ssl_hs_certificate_verify = 15,
+    ssl_hs_client_key_exchange = 16,
+    ssl_hs_finished = 20,
+    ssl_hs_certificate_status = 22,
+    ssl_hs_next_proto = 67
+} SSLHandshakeType;
+
 typedef struct SSL3StatisticsStr {
     /* statistics from ssl3_SendClientHello (sch) */
     long sch_sid_cache_hits;
     long sch_sid_cache_misses;
     long sch_sid_cache_not_ok;
 
     /* statistics from ssl3_HandleServerHello (hsh) */
     long hsh_sid_cache_hits;
--- a/lib/ssl/tls13con.c
+++ b/lib/ssl/tls13con.c
@@ -82,20 +82,19 @@ tls13_DeriveSecret(sslSocket *ss, PK11Sy
                    const char *label,
                    unsigned int labelLen,
                    const SSL3Hashes *hashes,
                    PK11SymKey **dest);
 static SECStatus tls13_SendEndOfEarlyData(sslSocket *ss);
 static SECStatus tls13_HandleEndOfEarlyData(sslSocket *ss, PRUint8 *b,
                                             PRUint32 length);
 static SECStatus tls13_SendFinished(sslSocket *ss, PK11SymKey *baseKey);
-static SECStatus tls13_ComputePskBinderHash(sslSocket *ss,
-                                            unsigned long prefixLength,
+static SECStatus tls13_ComputePskBinderHash(sslSocket *ss, unsigned int prefix,
                                             SSL3Hashes *hashes);
-static SECStatus tls13_VerifyFinished(sslSocket *ss, SSL3HandshakeType message,
+static SECStatus tls13_VerifyFinished(sslSocket *ss, SSLHandshakeType message,
                                       PK11SymKey *secret,
                                       PRUint8 *b, PRUint32 length,
                                       const SSL3Hashes *hashes);
 static SECStatus tls13_ClientHandleFinished(sslSocket *ss,
                                             PRUint8 *b, PRUint32 length,
                                             const SSL3Hashes *hashes);
 static SECStatus tls13_ServerHandleFinished(sslSocket *ss,
                                             PRUint8 *b, PRUint32 length,
@@ -594,46 +593,46 @@ tls13_HandlePostHelloHandshakeMessage(ss
         SSL_TRC(3, ("%d: TLS13[%d]: %s successfully decrypted handshake after"
                     "failed 0-RTT",
                     SSL_GETPID(), ss->fd));
         ss->ssl3.hs.zeroRttIgnore = ssl_0rtt_ignore_none;
     }
 
     /* TODO(ekr@rtfm.com): Would it be better to check all the states here? */
     switch (ss->ssl3.hs.msg_type) {
-        case certificate:
+        case ssl_hs_certificate:
             return tls13_HandleCertificate(ss, b, length);
 
-        case certificate_request:
+        case ssl_hs_certificate_request:
             return tls13_HandleCertificateRequest(ss, b, length);
 
-        case certificate_verify:
+        case ssl_hs_certificate_verify:
             if (!hashesPtr) {
                 FATAL_ERROR(ss, SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY, unexpected_message);
                 return SECFailure;
             }
             return tls13_HandleCertificateVerify(ss, b, length, hashesPtr);
 
-        case encrypted_extensions:
+        case ssl_hs_encrypted_extensions:
             return tls13_HandleEncryptedExtensions(ss, b, length);
 
-        case new_session_ticket:
+        case ssl_hs_new_session_ticket:
             return tls13_HandleNewSessionTicket(ss, b, length);
 
-        case finished:
+        case ssl_hs_finished:
             if (!hashesPtr) {
                 FATAL_ERROR(ss, SSL_ERROR_RX_UNEXPECTED_FINISHED, unexpected_message);
                 return SECFailure;
             }
             if (ss->sec.isServer) {
                 return tls13_ServerHandleFinished(ss, b, length, hashesPtr);
             }
             return tls13_ClientHandleFinished(ss, b, length, hashesPtr);
 
-        case end_of_early_data:
+        case ssl_hs_end_of_early_data:
             return tls13_HandleEndOfEarlyData(ss, b, length);
 
         default:
             FATAL_ERROR(ss, SSL_ERROR_RX_UNKNOWN_HANDSHAKE, unexpected_message);
             return SECFailure;
     }
 
     PORT_Assert(0); /* Unreached */
@@ -1418,17 +1417,17 @@ tls13_HandleClientHelloPart2(sslSocket *
 
         rv = tls13_ComputePskBinderHash(ss, ss->xtnData.pskBinderPrefixLen,
                                         &hashes);
         if (rv != SECSuccess) {
             FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
             goto loser;
         }
 
-        rv = tls13_VerifyFinished(ss, client_hello,
+        rv = tls13_VerifyFinished(ss, ssl_hs_client_hello,
                                   ss->ssl3.hs.pskBinderKey,
                                   ss->xtnData.pskBinder.data,
                                   ss->xtnData.pskBinder.len,
                                   &hashes);
         if (rv != SECSuccess) {
             goto loser;
         }
     }
@@ -1512,17 +1511,17 @@ tls13_SendHelloRetryRequest(sslSocket *s
 
     /* We asked already, but made no progress. */
     if (ss->ssl3.hs.helloRetry) {
         FATAL_ERROR(ss, SSL_ERROR_BAD_2ND_CLIENT_HELLO, illegal_parameter);
         return SECFailure;
     }
 
     ssl_GetXmitBufLock(ss);
-    rv = ssl3_AppendHandshakeHeader(ss, hello_retry_request,
+    rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_hello_retry_request,
                                     2 +     /* version */
                                         2 + /* cipher suite */
                                         2 + /* extension length */
                                         2 + /* group extension id */
                                         2 + /* group extension length */
                                         2 /* group */);
     if (rv != SECSuccess) {
         FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
@@ -1628,22 +1627,16 @@ tls13_HandleClientKeyShare(sslSocket *ss
     if (rv != SECSuccess) {
         return SECFailure; /* Error code set already. */
     }
 
     rv = tls13_HandleKeyShare(ss, peerShare, keyPair->keys);
     return rv; /* Error code set already. */
 }
 
-static const ssl3HelloExtensionSender tls13_cert_req_senders[] = {
-    { ssl_signature_algorithms_xtn, &ssl3_SendSigAlgsXtn },
-    { ssl_tls13_certificate_authorities_xtn, &tls13_SendCertAuthoritiesXtn },
-    { 0, NULL }
-};
-
 /*
  *     [draft-ietf-tls-tls13-11] Section 6.3.3.2
  *
  *     opaque DistinguishedName<1..2^16-1>;
  *
  *     struct {
  *         opaque certificate_extension_oid<1..2^8-1>;
  *         opaque certificate_extension_values<0..2^16-1>;
@@ -1656,49 +1649,52 @@ static const ssl3HelloExtensionSender tl
  *         DistinguishedName certificate_authorities<0..2^16-1>;
  *         CertificateExtension certificate_extensions<0..2^16-1>;
  *     } CertificateRequest;
  */
 static SECStatus
 tls13_SendCertificateRequest(sslSocket *ss)
 {
     SECStatus rv;
-    PRInt32 extLen;
+    sslBuffer extensionBuf = { NULL, 0, 0 };
 
     SSL_TRC(3, ("%d: TLS13[%d]: begin send certificate_request",
                 SSL_GETPID(), ss->fd));
 
-    extLen = ssl3_CallHelloExtensionSenders(ss, PR_FALSE, 0xffff,
-                                            tls13_cert_req_senders);
-    PORT_Assert(extLen > 0); /* These can't be empty. */
-
-    rv = ssl3_AppendHandshakeHeader(ss, certificate_request,
+    rv = ssl_ConstructExtensions(ss, &extensionBuf, ssl_hs_certificate_request);
+    if (rv != SECSuccess) {
+        return SECFailure; /* Code already set. */
+    }
+    PORT_Assert(extensionBuf.len > 0); /* These can't be empty. */
+
+    rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_certificate_request,
                                     1 + 0 + /* empty request context */
-                                        2 + extLen /* len + extensions */);
+                                        2 + /* extension length */
+                                        extensionBuf.len /* extensions */);
     if (rv != SECSuccess) {
-        return rv; /* err set by AppendHandshake. */
+        goto loser; /* err set by AppendHandshake. */
     }
 
     /* Context. */
     rv = ssl3_AppendHandshakeNumber(ss, 0, 1);
     if (rv != SECSuccess) {
-        return rv; /* err set by AppendHandshake. */
+        goto loser; /* err set by AppendHandshake. */
     }
     /* Extensions. */
-    rv = ssl3_AppendHandshakeNumber(ss, extLen, 2);
+    rv = ssl3_AppendBufferToHandshakeVariable(ss, &extensionBuf, 2);
     if (rv != SECSuccess) {
-        return rv; /* err set by AppendHandshake. */
-    }
-    extLen = ssl3_CallHelloExtensionSenders(ss, PR_TRUE, extLen,
-                                            tls13_cert_req_senders);
-    if (extLen < 0) {
-        return SECFailure; /* rely on the extension sender setting code */
-    }
-
+        goto loser; /* err set by AppendHandshake. */
+    }
+
+    sslBuffer_Clear(&extensionBuf);
     return SECSuccess;
+
+loser:
+    sslBuffer_Clear(&extensionBuf);
+    return SECFailure;
 }
 
 SECStatus
 tls13_HandleHelloRetryRequest(sslSocket *ss, PRUint8 *b, PRUint32 length)
 {
     SECStatus rv;
     PRUint32 tmp;
     SSL3ProtocolVersion version;
@@ -1768,17 +1764,17 @@ tls13_HandleHelloRetryRequest(sslSocket 
      * for HelloRetryRequest, and all the extensions we permit cause us to
      * modify our ClientHello in some way. */
     if (!tmp || tmp != length) {
         FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_HELLO_RETRY_REQUEST,
                     decode_error);
         return SECFailure;
     }
 
-    rv = ssl3_HandleExtensions(ss, &b, &length, hello_retry_request);
+    rv = ssl3_HandleExtensions(ss, &b, &length, ssl_hs_hello_retry_request);
     if (rv != SECSuccess) {
         return SECFailure; /* Error code set below */
     }
 
     ss->ssl3.hs.helloRetry = PR_TRUE;
 
     ssl_GetXmitBufLock(ss);
     rv = ssl3_SendClientHello(ss, client_hello_retry);
@@ -1834,17 +1830,17 @@ tls13_HandleCertificateRequest(sslSocket
 
     if (length) {
         FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_REQUEST, decode_error);
         return SECFailure;
     }
 
     /* Process all the extensions. */
     rv = ssl3_HandleExtensions(ss, &extensionsData.data, &extensionsData.len,
-                               certificate_request);
+                               ssl_hs_certificate_request);
     if (rv != SECSuccess) {
         return SECFailure;
     }
 
     if (!ss->xtnData.numSigSchemes) {
         FATAL_ERROR(ss, SSL_ERROR_MISSING_SIGNATURE_ALGORITHMS_EXTENSION,
                     missing_extension);
         return SECFailure;
@@ -1872,22 +1868,20 @@ tls13_SendEncryptedServerSequence(sslSoc
 
     rv = tls13_SetCipherSpec(ss, TrafficKeyHandshake,
                              CipherSpecWrite, PR_FALSE);
     if (rv != SECSuccess) {
         LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
         return SECFailure;
     }
 
-    ss->ssl3.hs.shortHeaders = ssl3_ExtensionNegotiated(
-        ss, ssl_tls13_short_header_xtn);
-
     if (ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted) {
-        rv = ssl3_RegisterExtensionSender(ss, &ss->xtnData, ssl_tls13_early_data_xtn,
-                                          tls13_ServerSendEarlyDataXtn);
+        rv = ssl3_RegisterExtensionSender(ss, &ss->xtnData,
+                                          ssl_tls13_early_data_xtn,
+                                          ssl_SendEmptyExtension);
         if (rv != SECSuccess) {
             return SECFailure; /* Error code set already. */
         }
     }
 
     rv = tls13_SendEncryptedExtensions(ss);
     if (rv != SECSuccess) {
         return SECFailure; /* error code is set. */
@@ -2082,19 +2076,16 @@ tls13_HandleServerHelloPart2(sslSocket *
     if (rv != SECSuccess) {
         return SECFailure;
     }
     rv = tls13_ComputeHandshakeSecrets(ss);
     if (rv != SECSuccess) {
         return SECFailure; /* error code is set. */
     }
 
-    ss->ssl3.hs.shortHeaders = ssl3_ExtensionNegotiated(
-        ss, ssl_tls13_short_header_xtn);
-
     rv = tls13_SetCipherSpec(ss, TrafficKeyHandshake,
                              CipherSpecRead, PR_FALSE);
     if (rv != SECSuccess) {
         FATAL_ERROR(ss, SSL_ERROR_INIT_CIPHER_SUITE_FAILURE, internal_error);
         return SECFailure;
     }
     TLS13_SET_HS_STATE(ss, wait_encrypted_extensions);
 
@@ -2185,18 +2176,17 @@ tls13_HandleServerKeyShare(sslSocket *ss
 static SECStatus
 tls13_SendCertificate(sslSocket *ss)
 {
     SECStatus rv;
     CERTCertificateList *certChain;
     int certChainLen = 0;
     int i;
     SECItem context = { siBuffer, NULL, 0 };
-    PRInt32 extensionsLen = 0;
-    PRUint32 maxBytes = 65535;
+    sslBuffer extensionBuf = { NULL, 0, 0 };
 
     SSL_TRC(3, ("%d: TLS1.3[%d]: send certificate handshake",
                 SSL_GETPID(), ss->fd));
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
     if (ss->sec.isServer) {
@@ -2209,86 +2199,83 @@ tls13_SendCertificate(sslSocket *ss)
     } else {
         if (ss->sec.localCert)
             CERT_DestroyCertificate(ss->sec.localCert);
 
         certChain = ss->ssl3.clientCertChain;
         ss->sec.localCert = CERT_DupCertificate(ss->ssl3.clientCertificate);
     }
 
-    /* Get the extensions length. This only applies to the leaf cert,
-     * because we don't yet send extensions for non-leaf certs. */
-    extensionsLen = ssl3_CallHelloExtensionSenders(
-        ss, PR_FALSE, maxBytes, &ss->xtnData.certificateSenders[0]);
-
     if (!ss->sec.isServer) {
         PORT_Assert(ss->ssl3.hs.clientCertRequested);
         context = ss->xtnData.certReqContext;
     }
     if (certChain) {
         for (i = 0; i < certChain->len; i++) {
-            certChainLen +=
-                3 + certChain->certs[i].len + /* cert length + cert */
-                2 + (!i ? extensionsLen : 0); /* extensions length + extensions */
+            /* Each cert is 3 octet length, cert, and extensions */
+            certChainLen += 3 + certChain->certs[i].len + 2;
         }
-    }
-
-    rv = ssl3_AppendHandshakeHeader(ss, certificate,
+
+        /* Build the extensions. This only applies to the leaf cert, because we
+         * don't yet send extensions for non-leaf certs. */
+        rv = ssl_ConstructExtensions(ss, &extensionBuf, ssl_hs_certificate);
+        if (rv != SECSuccess) {
+            return SECFailure; /* code already set */
+        }
+        /* extensionBuf.len is only added once, for the leaf cert. */
+        certChainLen += extensionBuf.len;
+    }
+
+    rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_certificate,
                                     1 + context.len + 3 + certChainLen);
     if (rv != SECSuccess) {
         return SECFailure; /* err set by AppendHandshake. */
     }
 
     rv = ssl3_AppendHandshakeVariable(ss, context.data,
                                       context.len, 1);
     if (rv != SECSuccess) {
-        return SECFailure; /* err set by AppendHandshake. */
+        goto loser; /* err set by AppendHandshake. */
     }
 
     rv = ssl3_AppendHandshakeNumber(ss, certChainLen, 3);
     if (rv != SECSuccess) {
-        return SECFailure; /* err set by AppendHandshake. */
+        goto loser; /* err set by AppendHandshake. */
     }
     if (certChain) {
         for (i = 0; i < certChain->len; i++) {
-            PRInt32 sentLen;
-
             rv = ssl3_AppendHandshakeVariable(ss, certChain->certs[i].data,
                                               certChain->certs[i].len, 3);
             if (rv != SECSuccess) {
-                return SECFailure; /* err set by AppendHandshake. */
+                goto loser; /* err set by AppendHandshake. */
             }
 
             if (i) {
                 /* Not end-entity. */
                 rv = ssl3_AppendHandshakeNumber(ss, 0, 2);
                 if (rv != SECSuccess) {
-                    return SECFailure; /* err set by AppendHandshake. */
+                    goto loser; /* err set by AppendHandshake. */
                 }
                 continue;
             }
 
             /* End-entity, send extensions. */
-            rv = ssl3_AppendHandshakeNumber(ss, extensionsLen, 2);
+            rv = ssl3_AppendBufferToHandshakeVariable(ss, &extensionBuf, 2);
             if (rv != SECSuccess) {
-                return SECFailure; /* err set by AppendHandshake. */
-            }
-
-            sentLen = ssl3_CallHelloExtensionSenders(
-                ss, PR_TRUE, extensionsLen,
-                &ss->xtnData.certificateSenders[0]);
-            PORT_Assert(sentLen == extensionsLen);
-            if (sentLen != extensionsLen) {
-                LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
-                return SECFailure;
+                goto loser; /* err set by AppendHandshake. */
             }
         }
     }
 
+    sslBuffer_Clear(&extensionBuf);
     return SECSuccess;
+
+loser:
+    sslBuffer_Clear(&extensionBuf);
+    return SECFailure;
 }
 
 static SECStatus
 tls13_HandleCertificateEntry(sslSocket *ss, SECItem *data, PRBool first,
                              CERTCertificate **certp)
 {
     SECStatus rv;
     SECItem certData;
@@ -2306,17 +2293,17 @@ tls13_HandleCertificateEntry(sslSocket *
     if (rv != SECSuccess) {
         return SECFailure;
     }
 
     /* Parse all the extensions. */
     if (first && !ss->sec.isServer) {
         rv = ssl3_HandleExtensions(ss, &extensionsData.data,
                                    &extensionsData.len,
-                                   certificate);
+                                   ssl_hs_certificate);
         if (rv != SECSuccess) {
             return SECFailure;
         }
 
         /* TODO(ekr@rtfm.com): Copy out SCTs. Bug 1315727. */
     }
 
     cert = CERT_NewTempCertificate(ss->dbHandle, &certData, NULL,
@@ -3104,17 +3091,17 @@ tls13_HandleEncryptedExtensions(sslSocke
     /* 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->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);
+    rv = ssl3_HandleExtensions(ss, &b, &length, ssl_hs_encrypted_extensions);
     if (rv != SECSuccess) {
         return SECFailure; /* Error code set below */
     }
 
     /* 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) {
@@ -3156,52 +3143,47 @@ tls13_HandleEncryptedExtensions(sslSocke
     }
 
     return SECSuccess;
 }
 
 static SECStatus
 tls13_SendEncryptedExtensions(sslSocket *ss)
 {
+    sslBuffer extensions = { NULL, 0, 0 };
     SECStatus rv;
-    PRInt32 extensions_len = 0;
-    PRInt32 sent_len = 0;
-    PRUint32 maxBytes = 65535;
 
     SSL_TRC(3, ("%d: TLS13[%d]: send encrypted extensions handshake",
                 SSL_GETPID(), ss->fd));
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
 
-    extensions_len = ssl3_CallHelloExtensionSenders(
-        ss, PR_FALSE, maxBytes, &ss->xtnData.encryptedExtensionsSenders[0]);
-
-    rv = ssl3_AppendHandshakeHeader(ss, encrypted_extensions,
-                                    extensions_len + 2);
+    rv = ssl_ConstructExtensions(ss, &extensions, ssl_hs_encrypted_extensions);
     if (rv != SECSuccess) {
-        LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
         return SECFailure;
     }
-    rv = ssl3_AppendHandshakeNumber(ss, extensions_len, 2);
+
+    rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_encrypted_extensions,
+                                    extensions.len + 2);
     if (rv != SECSuccess) {
         LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
-        return SECFailure;
-    }
-    sent_len = ssl3_CallHelloExtensionSenders(
-        ss, PR_TRUE, extensions_len,
-        &ss->xtnData.encryptedExtensionsSenders[0]);
-    PORT_Assert(sent_len == extensions_len);
-    if (sent_len != extensions_len) {
+        goto loser;
+    }
+    rv = ssl3_AppendBufferToHandshakeVariable(ss, &extensions, 2);
+    if (rv != SECSuccess) {
         LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
-        PORT_Assert(sent_len == 0);
-        return SECFailure;
-    }
-
+        goto loser;
+    }
+    sslBuffer_Clear(&extensions);
     return SECSuccess;
+
+loser:
+    sslBuffer_Clear(&extensions);
+    return SECFailure;
 }
 
 SECStatus
 tls13_SendCertificateVerify(sslSocket *ss, SECKEYPrivateKey *privKey)
 {
     SECStatus rv = SECFailure;
     SECItem buf = { siBuffer, NULL, 0 };
     unsigned int len;
@@ -3252,17 +3234,17 @@ tls13_SendCertificateVerify(sslSocket *s
         PK11_FreeSlot(slot);
     }
     if (rv != SECSuccess) {
         goto done; /* err code was set by ssl3_SignHashes */
     }
 
     len = buf.len + 2 + 2;
 
-    rv = ssl3_AppendHandshakeHeader(ss, certificate_verify, len);
+    rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_certificate_verify, len);
     if (rv != SECSuccess) {
         goto done; /* error code set by AppendHandshake */
     }
 
     rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.hs.signatureScheme, 2);
     if (rv != SECSuccess) {
         goto done; /* err set by AppendHandshakeNumber */
     }
@@ -3360,60 +3342,97 @@ tls13_HandleCertificateVerify(sslSocket 
     }
 
     TLS13_SET_HS_STATE(ss, wait_finished);
 
     return SECSuccess;
 }
 
 static SECStatus
-tls13_ComputePskBinderHash(sslSocket *ss, unsigned long prefixLength,
+tls13_ComputePskBinderHash(sslSocket *ss, unsigned int prefixLength,
                            SSL3Hashes *hashes)
 {
     SECStatus rv;
 
     PORT_Assert(ss->ssl3.hs.hashType == handshake_hash_unknown);
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
     PORT_Assert(prefixLength <= ss->ssl3.hs.messages.len);
 
     PRINT_BUF(10, (NULL, "Handshake hash computed over ClientHello prefix",
                    ss->ssl3.hs.messages.buf, prefixLength));
     rv = PK11_HashBuf(ssl3_HashTypeToOID(tls13_GetHash(ss)),
-                      hashes->u.raw,
-                      ss->ssl3.hs.messages.buf, prefixLength);
+                      hashes->u.raw, ss->ssl3.hs.messages.buf, prefixLength);
     if (rv != SECSuccess) {
         ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
-        goto loser;
-    }
+        return SECFailure;
+    }
+
     hashes->len = tls13_GetHashSize(ss);
-
-    PRINT_BUF(10, (NULL, "PSK Binder hash",
-                   hashes->u.raw, hashes->len));
+    PRINT_BUF(10, (NULL, "PSK Binder hash", hashes->u.raw, hashes->len));
 
     return SECSuccess;
-
-loser:
-    return SECFailure;
 }
-/* Compute the PSK Binder This is kind of sneaky.*/
+
+/* Compute and inject the PSK Binder for sending.
+ *
+ * When sending a ClientHello, we construct all the extensions with a dummy
+ * value for the binder.  To construct the binder, we commit the entire message
+ * up to the point where the binders start.  Then we calculate the hash using
+ * the saved message (in ss->ssl3.hs.messages).  This is written over the dummy
+ * binder, after which we write the remainder of the binder extension. */
 SECStatus
-tls13_ComputePskBinder(sslSocket *ss, PRBool sending,
-                       unsigned int prefixLength,
-                       PRUint8 *output, unsigned int *outputLen,
-                       unsigned int maxOutputLen)
+tls13_WriteExtensionsWithBinder(sslSocket *ss, sslBuffer *extensions)
 {
     SSL3Hashes hashes;
     SECStatus rv;
-
-    rv = tls13_ComputePskBinderHash(ss, prefixLength, &hashes);
-    if (rv != SECSuccess)
+    unsigned int size = tls13_GetHashSize(ss);
+    unsigned int prefixLen = extensions->len - size - 3;
+    unsigned int finishedLen;
+
+    PORT_Assert(extensions->len - size - 3 >= 0);
+
+    rv = ssl3_AppendHandshakeNumber(ss, extensions->len, 2);
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
+
+    /* Only write the extension up to the point before the binders.  Assume that
+     * the pre_shared_key extension is at the end of the buffer.  Don't write
+     * the binder, or the lengths that precede it (a 2 octet length for the list
+     * of all binders, plus a 1 octet length for the binder length). */
+    rv = ssl3_AppendHandshake(ss, extensions->buf, prefixLen);
+    if (rv != SECSuccess) {
         return SECFailure;
-
-    return tls13_ComputeFinished(ss, ss->ssl3.hs.pskBinderKey, &hashes,
-                                 sending, output, outputLen, maxOutputLen);
+    }
+
+    /* Calculate the binder based on what has been written out. */
+    rv = tls13_ComputePskBinderHash(ss, ss->ssl3.hs.messages.len, &hashes);
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
+
+    /* Write the binder into the extensions buffer, over the zeros we reserved
+     * previously.  This avoids an allocation and means that we don't need a
+     * separate write for the extra bits that precede the binder. */
+    rv = tls13_ComputeFinished(ss, ss->ssl3.hs.pskBinderKey, &hashes, PR_TRUE,
+                               extensions->buf + extensions->len - size,
+                               &finishedLen, size);
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
+    PORT_Assert(finishedLen == size);
+
+    /* Write out the remainder of the extension. */
+    rv = ssl3_AppendHandshake(ss, extensions->buf + prefixLen,
+                              extensions->len - prefixLen);
+    if (rv != SECSuccess) {
+        return SECFailure;
+    }
+
+    return SECSuccess;
 }
 
 static SECStatus
 tls13_ComputeFinished(sslSocket *ss, PK11SymKey *baseKey,
                       const SSL3Hashes *hashes,
                       PRBool sending, PRUint8 *output, unsigned int *outputLen,
                       unsigned int maxOutputLen)
 {
@@ -3502,32 +3521,32 @@ tls13_SendFinished(sslSocket *ss, PK11Sy
     rv = tls13_ComputeFinished(ss, baseKey, &hashes, PR_TRUE,
                                finishedBuf, &finishedLen, sizeof(finishedBuf));
     ssl_ReleaseSpecReadLock(ss);
     if (rv != SECSuccess) {
         LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
         return SECFailure;
     }
 
-    rv = ssl3_AppendHandshakeHeader(ss, finished, finishedLen);
+    rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_finished, finishedLen);
     if (rv != SECSuccess) {
         return SECFailure; /* Error code already set. */
     }
 
     rv = ssl3_AppendHandshake(ss, finishedBuf, finishedLen);
     if (rv != SECSuccess) {
         return SECFailure; /* Error code already set. */
     }
 
     /* TODO(ekr@rtfm.com): Record key log */
     return SECSuccess;
 }
 
 static SECStatus
-tls13_VerifyFinished(sslSocket *ss, SSL3HandshakeType message,
+tls13_VerifyFinished(sslSocket *ss, SSLHandshakeType message,
                      PK11SymKey *secret,
                      PRUint8 *b, PRUint32 length,
                      const SSL3Hashes *hashes)
 {
     SECStatus rv;
     PRUint8 finishedBuf[TLS13_MAX_FINISHED_SIZE];
     unsigned int finishedLen;
 
@@ -3540,17 +3559,17 @@ tls13_VerifyFinished(sslSocket *ss, SSL3
                                finishedBuf, &finishedLen, sizeof(finishedBuf));
     if (rv != SECSuccess) {
         FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
         return SECFailure;
     }
 
     if (length != finishedLen) {
 #ifndef UNSAFE_FUZZER_MODE
-        FATAL_ERROR(ss, message == finished ? SSL_ERROR_RX_MALFORMED_FINISHED : SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
+        FATAL_ERROR(ss, message == ssl_hs_finished ? SSL_ERROR_RX_MALFORMED_FINISHED : SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
         return SECFailure;
 #endif
     }
 
     if (NSS_SecureMemcmp(b, finishedBuf, finishedLen) != 0) {
 #ifndef UNSAFE_FUZZER_MODE
         FATAL_ERROR(ss, SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE,
                     decrypt_error);
@@ -3574,17 +3593,17 @@ tls13_ClientHandleFinished(sslSocket *ss
                 SSL_GETPID(), ss->fd));
 
     rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_FINISHED,
                               wait_finished);
     if (rv != SECSuccess) {
         return SECFailure;
     }
 
-    rv = tls13_VerifyFinished(ss, finished,
+    rv = tls13_VerifyFinished(ss, ssl_hs_finished,
                               ss->ssl3.hs.serverHsTrafficSecret,
                               b, length, hashes);
     if (rv != SECSuccess)
         return SECFailure;
 
     return tls13_SendClientSecondRound(ss);
 }
 
@@ -3607,17 +3626,17 @@ tls13_ServerHandleFinished(sslSocket *ss
     }
 
     if (TLS13_IN_HS_STATE(ss, wait_finished)) {
         secret = ss->ssl3.hs.clientHsTrafficSecret;
     } else {
         secret = ss->ssl3.hs.clientEarlyTrafficSecret;
     }
 
-    rv = tls13_VerifyFinished(ss, finished, secret, b, length, hashes);
+    rv = tls13_VerifyFinished(ss, ssl_hs_finished, secret, b, length, hashes);
     if (rv != SECSuccess)
         return SECFailure;
 
     rv = tls13_SetCipherSpec(ss, TrafficKeyApplicationData,
                              CipherSpecRead, PR_TRUE);
     if (rv != SECSuccess) {
         FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
         return SECFailure;
@@ -3858,17 +3877,17 @@ tls13_SendNewSessionTicket(sslSocket *ss
 
     message_length =
         4 +                           /* lifetime */
         4 +                           /* ticket_age_add */
         2 + max_early_data_size_len + /* max_early_data_size_len */
         2 +                           /* ticket length */
         ticket_data.len;
 
-    rv = ssl3_AppendHandshakeHeader(ss, new_session_ticket,
+    rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_new_session_ticket,
                                     message_length);
     if (rv != SECSuccess)
         goto loser;
 
     /* This is a fixed value. */
     rv = ssl3_AppendHandshakeNumber(ss, ssl_ticket_lifetime, 4);
     if (rv != SECSuccess)
         goto loser;
@@ -3973,17 +3992,17 @@ tls13_HandleNewSessionTicket(sslSocket *
     rv = ssl3_ConsumeHandshakeVariable(ss, &data, 2, &b, &length);
     if (rv != SECSuccess || length) {
         FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET,
                     decode_error);
         return SECFailure;
     }
 
     rv = ssl3_HandleExtensions(ss, &data.data,
-                               &data.len, new_session_ticket);
+                               &data.len, ssl_hs_new_session_ticket);
     if (rv != SECSuccess) {
         FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET,
                     decode_error);
         return SECFailure;
     }
     if (ss->xtnData.max_early_data_size) {
         ticket.flags |= ticket_allow_early_data;
         ticket.max_early_data_size = ss->xtnData.max_early_data_size;
@@ -4032,17 +4051,18 @@ tls13_HandleNewSessionTicket(sslSocket *
 
         /* Cache the session. */
         ss->sec.cache(ss->sec.ci.sid);
     }
 
     return SECSuccess;
 }
 
-#define _M1(a) (1 << PR_MIN(a, 31))
+#define _M(a) (1 << PR_MIN(a, 31))
+#define _M1(a) (_M(ssl_hs_##a))
 #define _M2(a, b) (_M1(a) | _M1(b))
 #define _M3(a, b, c) (_M1(a) | _M2(b, c))
 
 static const struct {
     PRUint16 ex_value;
     PRUint32 messages;
 } KnownExtensions[] = {
     { ssl_server_name_xtn, _M2(client_hello, encrypted_extensions) },
@@ -4063,50 +4083,51 @@ static const struct {
                                certificate) },
     { ssl_tls13_cookie_xtn, _M2(client_hello, hello_retry_request) },
     { ssl_tls13_short_header_xtn, _M2(client_hello, server_hello) },
     { ssl_tls13_certificate_authorities_xtn, _M1(certificate_request) },
     { ssl_tls13_supported_versions_xtn, _M1(client_hello) }
 };
 
 tls13ExtensionStatus
-tls13_ExtensionStatus(PRUint16 extension, SSL3HandshakeType message)
+tls13_ExtensionStatus(PRUint16 extension, SSLHandshakeType message)
 {
     unsigned int i;
 
-    PORT_Assert((message == client_hello) ||
-                (message == server_hello) ||
-                (message == hello_retry_request) ||
-                (message == encrypted_extensions) ||
-                (message == new_session_ticket) ||
-                (message == certificate) ||
-                (message == certificate_request));
+    PORT_Assert((message == ssl_hs_client_hello) ||
+                (message == ssl_hs_server_hello) ||
+                (message == ssl_hs_hello_retry_request) ||
+                (message == ssl_hs_encrypted_extensions) ||
+                (message == ssl_hs_new_session_ticket) ||
+                (message == ssl_hs_certificate) ||
+                (message == ssl_hs_certificate_request));
 
     for (i = 0; i < PR_ARRAY_SIZE(KnownExtensions); i++) {
         /* Hacky check for message numbers > 30. */
         PORT_Assert(!(KnownExtensions[i].messages & (1U << 31)));
         if (KnownExtensions[i].ex_value == extension) {
             break;
         }
     }
     if (i >= PR_ARRAY_SIZE(KnownExtensions)) {
         return tls13_extension_unknown;
     }
 
     /* Return "disallowed" if the message mask bit isn't set. */
-    if (!(_M1(message) & KnownExtensions[i].messages)) {
+    if (!(_M(message) & KnownExtensions[i].messages)) {
         SSL_TRC(3, ("%d: TLS13: unexpected extension %d in message %d",
                     SSL_GETPID(), extension, message));
 
         return tls13_extension_disallowed;
     }
 
     return tls13_extension_allowed;
 }
 
+#undef _M
 #undef _M1
 #undef _M2
 #undef _M3
 
 /* TLS 1.3 doesn't actually have additional data but the aead function
  * signature overloads additional data to carry the record sequence
  * number and that's what we put here. The TLS 1.3 AEAD functions
  * just use this input as the sequence number and not as additional
@@ -4414,17 +4435,17 @@ tls13_Read0RttData(sslSocket *ss, void *
 static SECStatus
 tls13_SendEndOfEarlyData(sslSocket *ss)
 {
     SECStatus rv;
 
     SSL_TRC(3, ("%d: TLS13[%d]: send EndOfEarlyData", SSL_GETPID(), ss->fd));
     PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
 
-    rv = ssl3_AppendHandshakeHeader(ss, end_of_early_data, 0);
+    rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_end_of_early_data, 0);
     if (rv != SECSuccess) {
         return rv; /* err set by AppendHandshake. */
     }
 
     ss->ssl3.hs.zeroRttState = ssl_0rtt_done;
     return SECSuccess;
 }
 
--- a/lib/ssl/tls13con.h
+++ b/lib/ssl/tls13con.h
@@ -56,20 +56,17 @@ SECStatus tls13_DeriveSecretNullHash(ssl
 void tls13_FatalError(sslSocket *ss, PRErrorCode prError,
                       SSL3AlertDescription desc);
 SECStatus tls13_SetupClientHello(sslSocket *ss);
 SECStatus tls13_MaybeDo0RTTHandshake(sslSocket *ss);
 PRInt32 tls13_LimitEarlyData(sslSocket *ss, SSL3ContentType type, PRInt32 toSend);
 PRBool tls13_AllowPskCipher(const sslSocket *ss,
                             const ssl3CipherSuiteDef *cipher_def);
 PRBool tls13_PskSuiteEnabled(sslSocket *ss);
-SECStatus tls13_ComputePskBinder(sslSocket *ss, PRBool sending,
-                                 unsigned int prefixLength,
-                                 PRUint8 *output, unsigned int *outputLen,
-                                 unsigned int maxOutputLen);
+SECStatus tls13_WriteExtensionsWithBinder(sslSocket *ss, sslBuffer *extensions);
 SECStatus tls13_HandleClientHelloPart2(sslSocket *ss,
                                        const SECItem *suites,
                                        sslSessionID *sid);
 SECStatus tls13_HandleServerHelloPart2(sslSocket *ss);
 SECStatus tls13_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b,
                                                 PRUint32 length,
                                                 SSL3Hashes *hashesPtr);
 SECStatus tls13_HandleHelloRetryRequest(sslSocket *ss, PRUint8 *b,
@@ -77,17 +74,17 @@ SECStatus tls13_HandleHelloRetryRequest(
 void tls13_DestroyKeyShareEntry(TLS13KeyShareEntry *entry);
 void tls13_DestroyKeyShares(PRCList *list);
 SECStatus tls13_CreateKeyShare(sslSocket *ss, const sslNamedGroupDef *groupDef);
 void tls13_DestroyEarlyData(PRCList *list);
 void tls13_CipherSpecAddRef(ssl3CipherSpec *spec);
 void tls13_CipherSpecRelease(ssl3CipherSpec *spec);
 void tls13_DestroyCipherSpecs(PRCList *list);
 tls13ExtensionStatus tls13_ExtensionStatus(PRUint16 extension,
-                                           SSL3HandshakeType message);
+                                           SSLHandshakeType message);
 SECStatus tls13_ProtectRecord(sslSocket *ss,
                               ssl3CipherSpec *cwSpec,
                               SSL3ContentType type,
                               const PRUint8 *pIn,
                               PRUint32 contentLen,
                               sslBuffer *wrBuf);
 PRInt32 tls13_Read0RttData(sslSocket *ss, void *buf, PRInt32 len);
 SECStatus tls13_HandleEarlyApplicationData(sslSocket *ss, sslBuffer *origBuf);
--- a/lib/ssl/tls13exthandle.c
+++ b/lib/ssl/tls13exthandle.c
@@ -9,60 +9,45 @@
 #include "ssl.h"
 #include "sslproto.h"
 #include "sslimpl.h"
 #include "pk11pub.h"
 #include "ssl3ext.h"
 #include "ssl3exthandle.h"
 #include "tls13exthandle.h"
 
-PRInt32
-tls13_ServerSendStatusRequestXtn(
-    const sslSocket *ss,
-    TLSExtensionData *xtnData,
-    PRBool append,
-    PRUint32 maxBytes)
+SECStatus
+tls13_ServerSendStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                                 sslBuffer *buf, PRBool *added)
 {
-    PRInt32 extension_length;
     const sslServerCert *serverCert = ss->sec.serverCert;
     const SECItem *item;
     SECStatus rv;
 
     if (!serverCert->certStatusArray ||
         !serverCert->certStatusArray->len) {
-        return 0;
+        return SECSuccess;
     }
 
     item = &serverCert->certStatusArray->items[0];
 
     /* Only send the first entry. */
-    extension_length = 2 + 2 + 1 /* status_type */ + 3 + item->len;
-    if (maxBytes < (PRUint32)extension_length) {
-        return 0;
+    /* status_type == ocsp */
+    rv = sslBuffer_AppendNumber(buf, 1 /*ocsp*/, 1);
+    if (rv != SECSuccess) {
+        return SECFailure;
     }
-    if (append) {
-        /* extension_type */
-        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_cert_status_xtn, 2);
-        if (rv != SECSuccess)
-            return -1;
-        /* length of extension_data */
-        rv = ssl3_ExtAppendHandshakeNumber(ss, extension_length - 4, 2);
-        if (rv != SECSuccess)
-            return -1;
-        /* status_type == ocsp */
-        rv = ssl3_ExtAppendHandshakeNumber(ss, 1 /*ocsp*/, 1);
-        if (rv != SECSuccess)
-            return rv; /* err set by AppendHandshake. */
-        /* opaque OCSPResponse<1..2^24-1> */
-        rv = ssl3_ExtAppendHandshakeVariable(ss, item->data, item->len, 3);
-        if (rv != SECSuccess)
-            return rv; /* err set by AppendHandshake. */
+    /* opaque OCSPResponse<1..2^24-1> */
+    rv = sslBuffer_AppendVariable(buf, item->data, item->len, 3);
+    if (rv != SECSuccess) {
+        return SECFailure;
     }
 
-    return extension_length;
+    *added = PR_TRUE;
+    return SECSuccess;
 }
 
 /*
  *     [draft-ietf-tls-tls13-11] Section 6.3.2.3.
  *
  *     struct {
  *         NamedGroup group;
  *         opaque key_exchange<1..2^16-1>;
@@ -96,117 +81,83 @@ tls13_SizeOfKeyShareEntry(const SECKEYPu
         case dhKey:
             return 2 + 2 + pubKey->u.dh.prime.len;
         default:
             PORT_Assert(0);
     }
     return 0;
 }
 
-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;
-}
-
 static SECStatus
-tls13_EncodeKeyShareEntry(const sslSocket *ss, const sslEphemeralKeyPair *keyPair)
+tls13_EncodeKeyShareEntry(sslBuffer *buf, const sslEphemeralKeyPair *keyPair)
 {
     SECStatus rv;
     SECKEYPublicKey *pubKey = keyPair->keys->pubKey;
     unsigned int size = tls13_SizeOfKeyShareEntry(pubKey);
 
-    rv = ssl3_ExtAppendHandshakeNumber(ss, keyPair->group->name, 2);
+    rv = sslBuffer_AppendNumber(buf, keyPair->group->name, 2);
     if (rv != SECSuccess)
         return rv;
-    rv = ssl3_ExtAppendHandshakeNumber(ss, size - 4, 2);
+    rv = sslBuffer_AppendNumber(buf, size - 4, 2);
     if (rv != SECSuccess)
         return rv;
 
     switch (pubKey->keyType) {
         case ecKey:
-            rv = tls13_EncodeECDHEKeyShareKEX(ss, pubKey);
+            rv = sslBuffer_Append(buf, pubKey->u.ec.publicValue.data,
+                                  pubKey->u.ec.publicValue.len);
             break;
         case dhKey:
-            rv = ssl_AppendPaddedDHKeyShare(ss, pubKey, PR_FALSE);
+            rv = ssl_AppendPaddedDHKeyShare(buf, pubKey, PR_FALSE);
             break;
         default:
             PORT_Assert(0);
             PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
             break;
     }
 
     return rv;
 }
 
-PRInt32
-tls13_ClientSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
-                            PRUint32 maxBytes)
+SECStatus
+tls13_ClientSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                            sslBuffer *buf, PRBool *added)
 {
-    PRUint32 extension_length;
+    SECStatus rv;
+    PRCList *cursor;
+    unsigned int lengthOffset;
 
     if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3) {
-        return 0;
+        return SECSuccess;
     }
 
     /* Optimistically try to send an ECDHE key using the
      * preexisting key (in future will be keys) */
     SSL_TRC(3, ("%d: TLS13[%d]: send client key share xtn",
                 SSL_GETPID(), ss->fd));
 
-    extension_length = tls13_SizeOfClientKeyShareExtension(ss);
-    if (maxBytes < extension_length) {
-        PORT_Assert(0);
-        return 0;
-    }
-
-    if (append) {
-        SECStatus rv;
-        PRCList *cursor;
-
-        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_key_share_xtn, 2);
-        if (rv != SECSuccess)
-            goto loser;
-
-        /* The extension length */
-        rv = ssl3_ExtAppendHandshakeNumber(ss, extension_length - 4, 2);
-        if (rv != SECSuccess)
-            goto loser;
+    /* Save the offset to the length. */
+    lengthOffset = buf->len;
+    buf->len += 2;
 
-        /* The length of KeyShares */
-        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(buf, keyPair);
+        if (rv != SECSuccess) {
+            return SECFailure;
+        }
+    }
+    PORT_Assert(buf->len >= lengthOffset + 2);
+    (void)ssl_EncodeUintX(buf->len - lengthOffset - 2, 2,
+                          buf->buf + lengthOffset);
 
-        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;
-        }
-
-        xtnData->advertised[xtnData->numAdvertised++] =
-            ssl_tls13_key_share_xtn;
-    }
-
-    return extension_length;
-
-loser:
-    return -1;
+    *added = PR_TRUE;
+    return SECSuccess;
 }
 
 static SECStatus
 tls13_HandleKeyShareEntry(const sslSocket *ss, TLSExtensionData *xtnData, SECItem *data)
 {
     SECStatus rv;
     PRUint32 group;
     const sslNamedGroupDef *groupDef;
@@ -245,17 +196,18 @@ loser:
     if (ks)
         tls13_DestroyKeyShareEntry(ks);
     return SECFailure;
 }
 /* Handle an incoming KeyShare extension at the client and copy to
  * |xtnData->remoteKeyShares| for future use. The key
  * share is processed in tls13_HandleServerKeyShare(). */
 SECStatus
-tls13_ClientHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data)
+tls13_ClientHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                              SECItem *data)
 {
     SECStatus rv;
     PORT_Assert(PR_CLIST_IS_EMPTY(&xtnData->remoteKeyShares));
 
     PORT_Assert(!ss->sec.isServer);
 
     /* The server must not send this extension when negotiating < TLS 1.3. */
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
@@ -276,17 +228,18 @@ tls13_ClientHandleKeyShareXtn(const sslS
         PORT_SetError(SSL_ERROR_RX_MALFORMED_KEY_SHARE);
         return SECFailure;
     }
 
     return SECSuccess;
 }
 
 SECStatus
-tls13_ClientHandleKeyShareXtnHrr(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data)
+tls13_ClientHandleKeyShareXtnHrr(const sslSocket *ss, TLSExtensionData *xtnData,
+                                 SECItem *data)
 {
     SECStatus rv;
     PRUint32 tmp;
     const sslNamedGroupDef *group;
 
     PORT_Assert(!ss->sec.isServer);
     PORT_Assert(ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3);
 
@@ -326,17 +279,18 @@ tls13_ClientHandleKeyShareXtnHrr(const s
 
     return SECSuccess;
 }
 
 /* Handle an incoming KeyShare extension at the server and copy to
  * |xtnData->remoteKeyShares| for future use. The key
  * share is processed in tls13_HandleClientKeyShare(). */
 SECStatus
-tls13_ServerHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data)
+tls13_ServerHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                              SECItem *data)
 {
     SECStatus rv;
     PRUint32 length;
 
     PORT_Assert(ss->sec.isServer);
     PORT_Assert(PR_CLIST_IS_EMPTY(&xtnData->remoteKeyShares));
 
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
@@ -376,57 +330,37 @@ tls13_ServerHandleKeyShareXtn(const sslS
 
     return SECSuccess;
 
 loser:
     tls13_DestroyKeyShares(&xtnData->remoteKeyShares);
     return SECFailure;
 }
 
-PRInt32
-tls13_ServerSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
-                            PRUint32 maxBytes)
+SECStatus
+tls13_ServerSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                            sslBuffer *buf, PRBool *added)
 {
-    PRUint32 extension_length;
-    PRUint32 entry_length;
     SECStatus rv;
     sslEphemeralKeyPair *keyPair;
 
     /* There should be exactly one key share. */
     PORT_Assert(!PR_CLIST_IS_EMPTY(&ss->ephemeralKeyPairs));
     PORT_Assert(PR_PREV_LINK(&ss->ephemeralKeyPairs) ==
                 PR_NEXT_LINK(&ss->ephemeralKeyPairs));
 
     keyPair = (sslEphemeralKeyPair *)PR_NEXT_LINK(&ss->ephemeralKeyPairs);
 
-    entry_length = tls13_SizeOfKeyShareEntry(keyPair->keys->pubKey);
-    extension_length = 2 + 2 + entry_length; /* Type + length + entry_length */
-    if (maxBytes < extension_length) {
-        PORT_Assert(0);
-        return 0;
+    rv = tls13_EncodeKeyShareEntry(buf, keyPair);
+    if (rv != SECSuccess) {
+        return SECFailure;
     }
 
-    if (append) {
-        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_key_share_xtn, 2);
-        if (rv != SECSuccess)
-            goto loser;
-
-        rv = ssl3_ExtAppendHandshakeNumber(ss, entry_length, 2);
-        if (rv != SECSuccess)
-            goto loser;
-
-        rv = tls13_EncodeKeyShareEntry(ss, keyPair);
-        if (rv != SECSuccess)
-            goto loser;
-    }
-
-    return extension_length;
-
-loser:
-    return -1;
+    *added = PR_TRUE;
+    return SECSuccess;
 }
 
 /* Called by clients.
  *
  *      struct {
  *         opaque identity<0..2^16-1>;
  *         uint32 obfuscated_ticket_age;
  *     } PskIdentity;
@@ -443,117 +377,86 @@ 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 will be at most one.
  */
-PRInt32
+SECStatus
 tls13_ClientSendPreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData,
-                                PRBool append,
-                                PRUint32 maxBytes)
+                                sslBuffer *buf, PRBool *added)
 {
-    PRInt32 extension_length;
-    PRInt32 identities_length;
-    PRInt32 binders_length;
     NewSessionTicket *session_ticket;
+    PRTime age;
+    const static PRUint8 binder[TLS13_MAX_FINISHED_SIZE] = { 0 };
+    unsigned int binderLen;
+    SECStatus rv;
 
     /* We only set statelessResume on the client in TLS 1.3 code. */
-    if (!ss->statelessResume)
-        return 0;
+    if (!ss->statelessResume) {
+        return SECSuccess;
+    }
+
+    /* Save where this extension starts so that if we have to add padding, it
+     * can be inserted before this extension. */
+    PORT_Assert(buf->len >= 4);
+    xtnData->paddingOffset = buf->len - 4;
 
     PORT_Assert(ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3);
 
-    /* The length computations are simplified by the fact that there
-     * is just one ticket at most. */
+    /* Send a single ticket identity. */
     session_ticket = &ss->sec.ci.sid->u.ssl3.locked.sessionTicket;
-    identities_length =
-        2 +                              /* vector length */
-        2 + session_ticket->ticket.len + /* identity length + ticket len */
-        4;                               /* obfuscated_ticket_age */
-    binders_length =
-        2 + /* vector length */
-        1 + tls13_GetHashSizeForHash(
-                tls13_GetHashForCipherSuite(ss->sec.ci.sid->u.ssl3.cipherSuite));
-    extension_length =
-        2 + 2 + /* Type + length */
-        identities_length + binders_length;
-
-    if (maxBytes < (PRUint32)extension_length) {
-        PORT_Assert(0);
-        return 0;
-    }
-
-    if (append) {
-        SECStatus rv;
-        PRTime age;
-        unsigned int prefixLength;
-        PRUint8 binder[TLS13_MAX_FINISHED_SIZE];
-        unsigned int binderLen;
+    rv = sslBuffer_AppendNumber(buf, 2 +                              /* identity length */
+                                         session_ticket->ticket.len + /* ticket */
+                                         4 /* obfuscated_ticket_age */,
+                                2);
+    if (rv != SECSuccess)
+        goto loser;
+    rv = sslBuffer_AppendVariable(buf, session_ticket->ticket.data,
+                                  session_ticket->ticket.len, 2);
+    if (rv != SECSuccess)
+        goto loser;
 
-        /* extension_type */
-        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_pre_shared_key_xtn, 2);
-        if (rv != SECSuccess)
-            goto loser;
-        rv = ssl3_ExtAppendHandshakeNumber(ss, extension_length - 4, 2);
-        if (rv != SECSuccess)
-            goto loser;
-        rv = ssl3_ExtAppendHandshakeNumber(ss, identities_length - 2, 2);
-        if (rv != SECSuccess)
-            goto loser;
-        rv = ssl3_ExtAppendHandshakeVariable(ss, session_ticket->ticket.data,
-                                             session_ticket->ticket.len, 2);
-        if (rv != SECSuccess)
-            goto loser;
-
-        /* Obfuscated age. */
-        age = PR_Now() - session_ticket->received_timestamp;
-        age /= PR_USEC_PER_MSEC;
-        age += session_ticket->ticket_age_add;
-        rv = ssl3_ExtAppendHandshakeNumber(ss, age, 4);
-        if (rv != SECSuccess)
-            goto loser;
+    /* Obfuscated age. */
+    age = PR_Now() - session_ticket->received_timestamp;
+    age /= PR_USEC_PER_MSEC;
+    age += session_ticket->ticket_age_add;
+    rv = sslBuffer_AppendNumber(buf, age, 4);
+    if (rv != SECSuccess)
+        goto loser;
 
-        /* Now the binders. */
-        prefixLength = ss->ssl3.hs.messages.len;
-        rv = tls13_ComputePskBinder(CONST_CAST(sslSocket, ss), PR_TRUE,
-                                    prefixLength, binder, &binderLen,
-                                    sizeof(binder));
-        if (rv != SECSuccess)
-            goto loser;
-        PORT_Assert(binderLen == tls13_GetHashSize(ss));
-        rv = ssl3_ExtAppendHandshakeNumber(ss, binders_length - 2, 2);
-        if (rv != SECSuccess)
-            goto loser;
-        rv = ssl3_ExtAppendHandshakeVariable(ss,
-                                             binder, binderLen, 1);
-        if (rv != SECSuccess)
-            goto loser;
+    /* Write out the binder list length. */
+    binderLen = tls13_GetHashSize(ss);
+    rv = sslBuffer_AppendNumber(buf, binderLen + 1, 2);
+    if (rv != SECSuccess)
+        goto loser;
+    /* Write zeroes for the binder for the moment. */
+    rv = sslBuffer_AppendVariable(buf, binder, binderLen, 1);
+    if (rv != SECSuccess)
+        goto loser;
 
-        PRINT_BUF(50, (ss, "Sending PreSharedKey value",
-                       session_ticket->ticket.data,
-                       session_ticket->ticket.len));
+    PRINT_BUF(50, (ss, "Sending PreSharedKey value",
+                   session_ticket->ticket.data,
+                   session_ticket->ticket.len));
 
-        xtnData->sentSessionTicketInClientHello = PR_TRUE;
-        xtnData->advertised[xtnData->numAdvertised++] =
-            ssl_tls13_pre_shared_key_xtn;
-    }
-    return extension_length;
+    xtnData->sentSessionTicketInClientHello = PR_TRUE;
+    *added = PR_TRUE;
+    return SECSuccess;
 
 loser:
     xtnData->ticketTimestampVerified = PR_FALSE;
-    return -1;
+    return SECFailure;
 }
 
 /* Handle a TLS 1.3 PreSharedKey Extension. We only accept PSKs
  * that contain session tickets. */
 SECStatus
-tls13_ServerHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
+tls13_ServerHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                   SECItem *data)
 {
     SECItem inner;
     SECStatus rv;
     unsigned int numIdentities = 0;
     unsigned int numBinders = 0;
 
     SSL_TRC(3, ("%d: SSL3[%d]: handle pre_shared_key extension",
@@ -630,63 +533,47 @@ tls13_ServerHandlePreSharedKeyXtn(const 
         ++numBinders;
     }
 
     if (numBinders != numIdentities)
         goto alert_loser;
 
     /* Keep track of negotiated extensions. Note that this does not
      * mean we are resuming. */
-    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
+    xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_pre_shared_key_xtn;
 
     return SECSuccess;
 
 alert_loser:
     ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter);
     PORT_SetError(SSL_ERROR_MALFORMED_PRE_SHARED_KEY);
     return SECFailure;
 }
 
-PRInt32
+SECStatus
 tls13_ServerSendPreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData,
-                                PRBool append,
-                                PRUint32 maxBytes)
+                                sslBuffer *buf, PRBool *added)
 {
-    PRInt32 extension_length =
-        2 + 2 + 2; /* type + len + index */
     SECStatus rv;
 
-    if (maxBytes < (PRUint32)extension_length) {
-        PORT_Assert(0);
-        return 0;
+    /* We only process the first session ticket the client sends,
+     * so the index is always 0. */
+    rv = sslBuffer_AppendNumber(buf, 0, 2);
+    if (rv != SECSuccess) {
+        return SECFailure;
     }
 
-    if (append) {
-        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_pre_shared_key_xtn, 2);
-        if (rv != SECSuccess)
-            return -1;
-
-        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_ExtAppendHandshakeNumber(ss, 0, 2);
-        if (rv != SECSuccess)
-            return -1;
-    }
-
-    return extension_length;
+    *added = PR_TRUE;
+    return SECSuccess;
 }
 
 /* Handle a TLS 1.3 PreSharedKey Extension. We only accept PSKs
  * that contain session tickets. */
 SECStatus
-tls13_ClientHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
+tls13_ClientHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                   SECItem *data)
 {
     PRUint32 index;
     SECStatus rv;
 
     SSL_TRC(3, ("%d: SSL3[%d]: handle pre_shared_key extension",
                 SSL_GETPID(), ss->fd));
 
@@ -708,61 +595,38 @@ tls13_ClientHandlePreSharedKeyXtn(const 
 
     /* 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. */
-    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
+    xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_pre_shared_key_xtn;
 
     return SECSuccess;
 }
 
 /*
  *  struct { } EarlyDataIndication;
  */
-PRInt32
+SECStatus
 tls13_ClientSendEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData,
-                             PRBool append,
-                             PRUint32 maxBytes)
+                             sslBuffer *buf, PRBool *added)
 {
-    SECStatus rv;
-    PRInt32 extension_length;
-
-    if (!tls13_ClientAllow0Rtt(ss, ss->sec.ci.sid))
-        return 0;
-
-    /* type + length */
-    extension_length = 2 + 2;
-
-    if (maxBytes < (PRUint32)extension_length) {
-        PORT_Assert(0);
-        return 0;
+    if (!tls13_ClientAllow0Rtt(ss, ss->sec.ci.sid)) {
+        return SECSuccess;
     }
 
-    if (append) {
-        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_early_data_xtn, 2);
-        if (rv != SECSuccess)
-            return -1;
-
-        rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2);
-        if (rv != SECSuccess)
-            return -1;
-
-        xtnData->advertised[xtnData->numAdvertised++] =
-            ssl_tls13_early_data_xtn;
-    }
-
-    return extension_length;
+    *added = PR_TRUE;
+    return SECSuccess;
 }
 
 SECStatus
-tls13_ServerHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
+tls13_ServerHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                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) {
         return SECSuccess;
@@ -774,54 +638,24 @@ tls13_ServerHandleEarlyDataXtn(const ssl
         return SECFailure;
     }
 
     if (data->len) {
         PORT_SetError(SSL_ERROR_MALFORMED_EARLY_DATA);
         return SECFailure;
     }
 
-    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
+    xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_early_data_xtn;
 
     return SECSuccess;
 }
 
-/* This is only registered if we are sending it. */
-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_ExtAppendHandshakeNumber(ss, ssl_tls13_early_data_xtn, 2);
-        if (rv != SECSuccess)
-            return -1;
-
-        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(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
+tls13_ClientHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                                SECItem *data)
 {
     SSL_TRC(3, ("%d: TLS13[%d]: handle early_data extension",
                 SSL_GETPID(), ss->fd));
 
     /* The server must not send this extension when negotiating < TLS 1.3. */
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
         PORT_SetError(SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION);
@@ -829,24 +663,24 @@ tls13_ClientHandleEarlyDataXtn(const ssl
     }
 
     if (data->len) {
         PORT_SetError(SSL_ERROR_MALFORMED_EARLY_DATA);
         return SECFailure;
     }
 
     /* Keep track of negotiated extensions. */
-    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
+    xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_early_data_xtn;
 
     return SECSuccess;
 }
 
 SECStatus
 tls13_ClientHandleTicketEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData,
-                                     PRUint16 ex_type, SECItem *data)
+                                     SECItem *data)
 {
     PRUint32 utmp;
     SECStatus rv;
 
     SSL_TRC(3, ("%d: TLS13[%d]: handle ticket early_data extension",
                 SSL_GETPID(), ss->fd));
 
     /* The server must not send this extension when negotiating < TLS 1.3. */
@@ -871,75 +705,54 @@ tls13_ClientHandleTicketEarlyDataXtn(con
     return SECSuccess;
 }
 
 /*
  *     struct {
  *          ProtocolVersion versions<2..254>;
  *     } SupportedVersions;
  */
-PRInt32
-tls13_ClientSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
-                                     PRUint32 maxBytes)
+SECStatus
+tls13_ClientSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                                     sslBuffer *buf, PRBool *added)
 {
-    PRInt32 extensions_len;
     PRUint16 version;
+    unsigned int size;
     SECStatus rv;
 
     if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3) {
-        return 0;
+        return SECSuccess;
     }
 
     SSL_TRC(3, ("%d: TLS13[%d]: send supported_versions extension",
                 SSL_GETPID(), ss->fd));
 
-    /* Extension type, extension len fiels, vector len field,
-     * length of the values. */
-    extensions_len = 2 + 2 + 1 +
-                     2 * (ss->vrange.max - ss->vrange.min + 1);
+    size = 2 * (ss->vrange.max - ss->vrange.min + 1);
+    rv = sslBuffer_AppendNumber(buf, size, 1);
+    if (rv != SECSuccess)
+        return -1;
 
-    if (maxBytes < (PRUint32)extensions_len) {
-        PORT_Assert(0);
-        return 0;
+    for (version = ss->vrange.max; version >= ss->vrange.min; --version) {
+        rv = sslBuffer_AppendNumber(buf, tls13_EncodeDraftVersion(version), 2);
+        if (rv != SECSuccess)
+            return SECFailure;
     }
 
-    if (append) {
-        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_supported_versions_xtn, 2);
-        if (rv != SECSuccess)
-            return -1;
-
-        rv = ssl3_ExtAppendHandshakeNumber(ss, extensions_len - 4, 2);
-        if (rv != SECSuccess)
-            return -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_ExtAppendHandshakeNumber(
-                ss, tls13_EncodeDraftVersion(version), 2);
-            if (rv != SECSuccess)
-                return -1;
-        }
-
-        xtnData->advertised[xtnData->numAdvertised++] =
-            ssl_tls13_supported_versions_xtn;
-    }
-
-    return extensions_len;
+    *added = PR_TRUE;
+    return SECSuccess;
 }
 
 /*
  *    struct {
  *        opaque cookie<1..2^16-1>;
  *    } Cookie;
  */
 SECStatus
-tls13_ClientHandleHrrCookie(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data)
+tls13_ClientHandleHrrCookie(const sslSocket *ss, TLSExtensionData *xtnData,
+                            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);
 
@@ -955,108 +768,72 @@ tls13_ClientHandleHrrCookie(const sslSoc
         ssl3_ExtSendAlert(ss, alert_fatal, decode_error);
         PORT_SetError(SSL_ERROR_RX_MALFORMED_HELLO_RETRY_REQUEST);
         return SECFailure;
     }
 
     return SECSuccess;
 }
 
-PRInt32
-tls13_ClientSendHrrCookieXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes)
+SECStatus
+tls13_ClientSendHrrCookieXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                             sslBuffer *buf, PRBool *added)
 {
-    PRInt32 extension_len;
+    SECStatus rv;
 
     if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3 ||
         !ss->ssl3.hs.cookie.len) {
-        return 0;
+        return SECSuccess;
     }
 
     SSL_TRC(3, ("%d: TLS13[%d]: send cookie extension", SSL_GETPID(), ss->fd));
-
-    /* Extension type, length, cookie length, cookie value. */
-    extension_len = 2 + 2 + 2 + ss->ssl3.hs.cookie.len;
-
-    if (maxBytes < (PRUint32)extension_len) {
-        PORT_Assert(0);
-        return 0;
+    rv = sslBuffer_AppendVariable(buf, ss->ssl3.hs.cookie.data,
+                                  ss->ssl3.hs.cookie.len, 2);
+    if (rv != SECSuccess) {
+        return SECFailure;
     }
 
-    if (append) {
-        SECStatus rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_cookie_xtn, 2);
-        if (rv != SECSuccess)
-            return -1;
-
-        rv = ssl3_ExtAppendHandshakeNumber(ss, extension_len - 4, 2);
-        if (rv != SECSuccess)
-            return -1;
-
-        rv = ssl3_ExtAppendHandshakeVariable(ss, ss->ssl3.hs.cookie.data,
-                                             ss->ssl3.hs.cookie.len, 2);
-        if (rv != SECSuccess)
-            return -1;
-    }
-    return extension_len;
+    *added = PR_TRUE;
+    return SECSuccess;
 }
 
 /*
  *     enum { psk_ke(0), psk_dhe_ke(1), (255) } PskKeyExchangeMode;
  *
  *     struct {
  *         PskKeyExchangeMode ke_modes<1..255>;
  *     } PskKeyExchangeModes;
  */
-PRInt32
-tls13_ClientSendPskKeyExchangeModesXtn(const sslSocket *ss,
-                                       TLSExtensionData *xtnData,
-                                       PRBool append, PRUint32 maxBytes)
+SECStatus
+tls13_ClientSendPskModesXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                            sslBuffer *buf, PRBool *added)
 {
     static const PRUint8 ke_modes[] = { tls13_psk_dh_ke };
-    static const unsigned long ke_modes_len = sizeof(ke_modes);
-    PRInt32 extension_len;
+    SECStatus rv;
 
     if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3 ||
         ss->opt.noCache) {
-        return 0;
+        return SECSuccess;
     }
 
-    extension_len =
-        2 + 2 +           /* Type + length */
-        1 + ke_modes_len; /* key exchange modes vector */
-
     SSL_TRC(3, ("%d: TLS13[%d]: send psk key exchange modes extension",
                 SSL_GETPID(), ss->fd));
 
-    if (maxBytes < (PRUint32)extension_len) {
-        PORT_Assert(0);
-        return 0;
+    rv = sslBuffer_AppendVariable(buf, ke_modes, sizeof(ke_modes), 1);
+    if (rv != SECSuccess) {
+        return SECFailure;
     }
 
-    if (append) {
-        SECStatus rv = ssl3_ExtAppendHandshakeNumber(
-            ss, ssl_tls13_psk_key_exchange_modes_xtn, 2);
-        if (rv != SECSuccess)
-            return -1;
-
-        rv = ssl3_ExtAppendHandshakeNumber(ss, extension_len - 4, 2);
-        if (rv != SECSuccess)
-            return -1;
-
-        rv = ssl3_ExtAppendHandshakeVariable(
-            ss, ke_modes, ke_modes_len, 1);
-        if (rv != SECSuccess)
-            return -1;
-    }
-    return extension_len;
+    *added = PR_TRUE;
+    return SECSuccess;
 }
 
 SECStatus
-tls13_ServerHandlePskKeyExchangeModesXtn(const sslSocket *ss,
-                                         TLSExtensionData *xtnData,
-                                         PRUint16 ex_type, SECItem *data)
+tls13_ServerHandlePskModesXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                              SECItem *data)
 {
     SECStatus rv;
 
     /* If we are doing < TLS 1.3, then ignore this. */
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
         return SECSuccess;
     }
 
@@ -1071,184 +848,64 @@ tls13_ServerHandlePskKeyExchangeModesXtn
     if (rv != SECSuccess)
         return rv;
     if (!xtnData->psk_ke_modes.len || data->len) {
         PORT_SetError(SSL_ERROR_MALFORMED_PSK_KEY_EXCHANGE_MODES);
         return SECFailure;
     }
 
     /* Keep track of negotiated extensions. */
-    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
+    xtnData->negotiated[xtnData->numNegotiated++] =
+        ssl_tls13_psk_key_exchange_modes_xtn;
 
     return SECSuccess;
 }
 
-PRInt32
-tls13_SendShortHeaderXtn(const sslSocket *ss,
-                         TLSExtensionData *xtnData,
-                         PRBool append, PRUint32 maxBytes)
+SECStatus
+tls13_SendCertAuthoritiesXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+                             sslBuffer *buf, PRBool *added)
 {
-    PRUint32 extension_len = 2 + 2; /* Type + length (0). */
-
-    if (!ss->opt.enableShortHeaders) {
-        return 0;
-    }
-
-    /* Presently this is incompatible with 0-RTT. We will fix if
-     * it becomes more than an experiment. */
-    if (ss->opt.enable0RttData) {
-        return 0;
-    }
-
-    if (IS_DTLS(ss)) {
-        return 0;
-    }
-
-    /* Don't send this if TLS 1.3 isn't at least possible. */
-    if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3) {
-        /* This should only happen on the client. */
-        PORT_Assert(!ss->sec.isServer);
-        return 0;
-    }
-
-    SSL_TRC(3, ("%d: TLS13[%d]: send short_header extension",
-                SSL_GETPID(), ss->fd));
-
-    if (maxBytes < extension_len) {
-        PORT_Assert(0);
-        return 0;
-    }
-
-    if (append) {
-        SECStatus rv;
-
-        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_short_header_xtn, 2);
-        if (rv != SECSuccess)
-            return -1;
-
-        rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2);
-        if (rv != SECSuccess)
-            return -1;
-
-        xtnData->advertised[xtnData->numAdvertised++] =
-            ssl_tls13_short_header_xtn;
-    }
-
-    return extension_len;
-}
-
-SECStatus
-tls13_HandleShortHeaderXtn(
-    const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
-    SECItem *data)
-{
-    SSL_TRC(3, ("%d: TLS13[%d]: handle short_header extension",
-                SSL_GETPID(), ss->fd));
-
-    /* The client might have asked for this, but we didn't negotiate TLS 1.3. */
-    if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
-        return SECSuccess;
-    }
-
-    /* Presently this is incompatible with 0-RTT. We will fix if
-     * it becomes more than an experiment. */
-    if (ss->opt.enable0RttData) {
-        return SECSuccess;
-    }
-
-    if (IS_DTLS(ss)) {
-        PORT_SetError(SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION);
-        return SECFailure;
-    }
-
-    if (data->len) {
-        PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE);
-        return SECFailure;
-    }
-
-    if (!ss->opt.enableShortHeaders) {
-        /* Ignore. */
-        return SECSuccess;
-    }
-
-    /* Keep track of negotiated extensions. */
-    xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
-
-    if (ss->sec.isServer) {
-        SECStatus rv;
-
-        rv = ssl3_RegisterExtensionSender(ss, xtnData,
-                                          ssl_tls13_short_header_xtn,
-                                          tls13_SendShortHeaderXtn);
-        if (rv != SECSuccess) {
-            return SECFailure;
-        }
-    }
-
-    return SECSuccess;
-}
-
-PRInt32
-tls13_SendCertAuthoritiesXtn(const sslSocket *ss, TLSExtensionData *xtnData,
-                             PRBool append, PRUint32 maxBytes)
-{
-    unsigned int extensionLen;
     unsigned int calen;
     const SECItem *name;
     unsigned int nnames;
     SECStatus rv;
 
     PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
 
     rv = ssl_GetCertificateRequestCAs(ss, &calen, &name, &nnames);
     if (rv != SECSuccess) {
-        return -1;
+        return SECFailure;
     }
 
     if (!calen) {
-        return 0;
+        return SECSuccess;
     }
 
-    extensionLen = 2 + 2 + 2 + calen; /* type, length, inner length, CA list */
-    if (maxBytes < extensionLen) {
-        PORT_Assert(0);
-        return 0;
+    rv = sslBuffer_AppendNumber(buf, calen, 2);
+    if (rv != SECSuccess) {
+        return SECFailure;
     }
 
-    if (append) {
-        rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_certificate_authorities_xtn, 2);
-        if (rv != SECSuccess) {
-            return -1;
-        }
-        rv = ssl3_ExtAppendHandshakeNumber(ss, calen + 2, 2);
-        if (rv != SECSuccess) {
-            return -1;
-        }
-        rv = ssl3_ExtAppendHandshakeNumber(ss, calen, 2);
+    while (nnames) {
+        rv = sslBuffer_AppendVariable(buf, name->data, name->len, 2);
         if (rv != SECSuccess) {
-            return -1;
+            return SECFailure;
         }
-
-        while (nnames) {
-            rv = ssl3_ExtAppendHandshakeVariable(ss, name->data, name->len, 2);
-            if (rv != SECSuccess) {
-                return -1;
-            }
-            ++name;
-            --nnames;
-        }
+        ++name;
+        --nnames;
     }
 
-    return extensionLen;
+    *added = PR_TRUE;
+    return SECSuccess;
 }
 
 SECStatus
 tls13_ClientHandleCertAuthoritiesXtn(const sslSocket *ss,
                                      TLSExtensionData *xtnData,
-                                     PRUint16 ex_type, SECItem *data)
+                                     SECItem *data)
 {
     SECStatus rv;
     PLArenaPool *arena;
 
     if (!data->len) {
         ssl3_ExtSendAlert(ss, alert_fatal, decode_error);
         PORT_SetError(SSL_ERROR_RX_MALFORMED_CERT_REQUEST);
         return SECFailure;
--- a/lib/ssl/tls13exthandle.h
+++ b/lib/ssl/tls13exthandle.h
@@ -4,78 +4,73 @@
  *
  * 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(const sslSocket *ss, TLSExtensionData *xtnData,
-                                         PRBool append, PRUint32 maxBytes);
-PRInt32 tls13_ClientSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append,
-                                    PRUint32 maxBytes);
-SECStatus tls13_ClientHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData,
-                                        PRUint16 ex_type,
+SECStatus tls13_ServerSendStatusRequestXtn(const sslSocket *ss,
+                                           TLSExtensionData *xtnData,
+                                           sslBuffer *buf, PRBool *append);
+SECStatus tls13_ClientSendKeyShareXtn(const sslSocket *ss,
+                                      TLSExtensionData *xtnData,
+                                      sslBuffer *buf, PRBool *append);
+SECStatus tls13_ClientHandleKeyShareXtn(const sslSocket *ss,
+                                        TLSExtensionData *xtnData,
                                         SECItem *data);
-SECStatus tls13_ClientHandleKeyShareXtnHrr(const sslSocket *ss, TLSExtensionData *xtnData,
-                                           PRUint16 ex_type,
+SECStatus tls13_ClientHandleKeyShareXtnHrr(const sslSocket *ss,
+                                           TLSExtensionData *xtnData,
                                            SECItem *data);
-SECStatus tls13_ServerHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData,
-                                        PRUint16 ex_type,
+SECStatus tls13_ServerHandleKeyShareXtn(const sslSocket *ss,
+                                        TLSExtensionData *xtnData,
                                         SECItem *data);
-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(const sslSocket *ss, TLSExtensionData *xtnData,
-                                            PRUint16 ex_type,
+SECStatus tls13_ServerSendKeyShareXtn(const sslSocket *ss,
+                                      TLSExtensionData *xtnData,
+                                      sslBuffer *buf, PRBool *append);
+SECStatus tls13_ClientSendPreSharedKeyXtn(const sslSocket *ss,
+                                          TLSExtensionData *xtnData,
+                                          sslBuffer *buf, PRBool *append);
+SECStatus tls13_ServerHandlePreSharedKeyXtn(const sslSocket *ss,
+                                            TLSExtensionData *xtnData,
                                             SECItem *data);
-SECStatus tls13_ClientHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData,
-                                            PRUint16 ex_type,
+SECStatus tls13_ClientHandlePreSharedKeyXtn(const sslSocket *ss,
+                                            TLSExtensionData *xtnData,
                                             SECItem *data);
-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,
+SECStatus tls13_ServerSendPreSharedKeyXtn(const sslSocket *ss,
+                                          TLSExtensionData *xtnData,
+                                          sslBuffer *buf, PRBool *append);
+SECStatus tls13_ClientSendEarlyDataXtn(const sslSocket *ss,
+                                       TLSExtensionData *xtnData,
+                                       sslBuffer *buf, PRBool *append);
+SECStatus tls13_ServerHandleEarlyDataXtn(const sslSocket *ss,
+                                         TLSExtensionData *xtnData,
                                          SECItem *data);
-SECStatus tls13_ClientHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
+SECStatus tls13_ClientHandleEarlyDataXtn(const sslSocket *ss,
+                                         TLSExtensionData *xtnData,
                                          SECItem *data);
-PRInt32 tls13_ServerSendEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData,
-                                     PRBool append,
-                                     PRUint32 maxBytes);
-SECStatus tls13_ClientHandleTicketEarlyDataXtn(
-    const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
-    SECItem *data);
-PRInt32 tls13_ClientSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
-                                             PRBool append,
-                                             PRUint32 maxBytes);
-SECStatus tls13_ClientHandleHrrCookie(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
+SECStatus tls13_ClientHandleTicketEarlyDataXtn(const sslSocket *ss,
+                                               TLSExtensionData *xtnData,
+                                               SECItem *data);
+SECStatus tls13_ClientSendSupportedVersionsXtn(const sslSocket *ss,
+                                               TLSExtensionData *xtnData,
+                                               sslBuffer *buf, PRBool *append);
+SECStatus tls13_ClientHandleHrrCookie(const sslSocket *ss,
+                                      TLSExtensionData *xtnData,
                                       SECItem *data);
-PRInt32 tls13_ClientSendHrrCookieXtn(const sslSocket *ss, TLSExtensionData *xtnData,
-                                     PRBool append,
-                                     PRUint32 maxBytes);
-PRInt32 tls13_ClientSendPskKeyExchangeModesXtn(const sslSocket *ss,
-                                               TLSExtensionData *xtnData,
-                                               PRBool append, PRUint32 maxBytes);
-SECStatus tls13_ServerHandlePskKeyExchangeModesXtn(const sslSocket *ss,
-                                                   TLSExtensionData *xtnData,
-                                                   PRUint16 ex_type, SECItem *data);
-PRInt32 tls13_SendShortHeaderXtn(const sslSocket *ss,
-                                 TLSExtensionData *xtnData,
-                                 PRBool append, PRUint32 maxBytes);
-SECStatus tls13_HandleShortHeaderXtn(
-    const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type,
-    SECItem *data);
-
-PRInt32 tls13_SendCertAuthoritiesXtn(const sslSocket *ss,
-                                     TLSExtensionData *xtnData,
-                                     PRBool append, PRUint32 maxBytes);
+SECStatus tls13_ClientSendHrrCookieXtn(const sslSocket *ss,
+                                       TLSExtensionData *xtnData,
+                                       sslBuffer *buf, PRBool *append);
+SECStatus tls13_ClientSendPskModesXtn(const sslSocket *ss,
+                                      TLSExtensionData *xtnData,
+                                      sslBuffer *buf, PRBool *append);
+SECStatus tls13_ServerHandlePskModesXtn(const sslSocket *ss,
+                                        TLSExtensionData *xtnData,
+                                        SECItem *data);
+SECStatus tls13_SendCertAuthoritiesXtn(const sslSocket *ss,
+                                       TLSExtensionData *xtnData,
+                                       sslBuffer *buf, PRBool *append);
 SECStatus tls13_ClientHandleCertAuthoritiesXtn(const sslSocket *ss,
                                                TLSExtensionData *xtnData,
-                                               PRUint16 ex_type, SECItem *data);
+                                               SECItem *data);
 
 #endif