| Internet-Draft | Extended Extensions in TLS 1.3 | July 2026 |
| Smyslov | Expires 7 January 2027 | [Page] |
Protocol TLS 1.3 is widely used to protect traffic in the Internet. However, the format of the TLS 1.3 ClientHello, ServerHello, and EncryptedExtensions handshake messages limits the size of extensions to 64 Kbytes.¶
This specification extends TLS 1.3 to allow extensions in ClientHello, ServerHello, and EncryptedExtensions have size larget than 64 Kbytes.¶
This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.¶
Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.¶
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."¶
This Internet-Draft will expire on 7 January 2027.¶
Copyright (c) 2026 IETF Trust and the persons identified as the document authors. All rights reserved.¶
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License.¶
TLS 1.3 [RFC8446] was standardized in 2018 and since then has become a widely used security protocol for protecting Internet traffic.¶
During TLS 1.3 handshake the client first sends the ClientHello message and the server responds with the ServerHello message followed by the EncryptedExtensions message ([RFC8446], Section 2). These messages contain various data needed to establish security connection, e.g., key shares for ephemeral key exchange. The ClientHello and ServerHello messages have few mandatory fields followed by the optional extensions ([RFC8446], Sections 4.1.2 and 4.1.3) and the EncryptedExtensions message contains only optional extensions ([RFC8446], Sections 4.3.1). Which extensions are included is situation-dependant, so whether a particular extension is sent or not depends on the protocol variant.¶
While the size of TLS 1.3 handshake messages can be up to 2^24 -1 bytes, the total size of extensions is limited to 2^16 - 1 bytes. This makes it impossible to use TLS 1.3 if the data needed to be transferred in an extension exceeds this limitation. One of possible example of such situation is using postquantum KEMS with large public keys or ciphertexts (like Classic MCEliece [I-D.josefsson-mceliece]).¶
This specification extends TLS 1.3 in to allow transferring extension data larget than 64 Kbytes.¶
Due to increased message size and additional round trip, this extension, when used, will lead to longer TLS handshake that might not be appropriate for some use cases, like interactive web surfing. For this reason, it is mostly aimed for long-lived TLS connections, when the longer handshake is amortized by the longevity of the connection.¶
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.¶
It is assumed that readers are familiar with TLS 1.3 [RFC8446].¶
This document introduces a variable-size length encoding of extensions blocks and individual extensions, as well as the content of each extension that contains data limited to 2^16 bytes. The idea is inspired by QUIC [RFC9000] and MLS [RFC9420].¶
Unlike encodings in QUIC and MLS, this document allocates only one most significant bit to indicate what is the size of the length field, so that the length field occupies either 2 or 3 bytes. There is no need to have TLS extensions larger than 2^24, since this is the hard limit on the size of the TLS messages. The encoding is summarized in Table 1.¶
| MSB | Length | Usable Bits | Range |
|---|---|---|---|
| 0 | 2 | 15 | 0-32767 |
| 1 | 3 | 23 | 0-8388607 |
As in QUIC, there is no requirement that length is encoded on the minimum number of bytes.¶
When this specification is in use by TLS 1.3 endpoints, the encoding of extensions blocks and individual extensions, as well as the content of any extension inside the handshake messages that contain the "extensions" field is modified as shown in Appendix A, where the variable-size length encoding is defined as <V>.¶
If there is a need for a client to send TLS extension that do not fit into the existing TLS 1.3 handshake messages extensions block in ClienHello (e.g. in case PQ KEM with large public keys, like Classic NcEliece) then the client indicates this with new extension of type extended_extensions (Figure 1) in the ClientHello message. This extension contains no data.¶
enum {
...
extended_extensions(TBD),
(65535)
} ExtensionType;
If the server supports this extension, it replies with the HelloRetryRequest that also includes the extended_extensions extension.¶
Once HelloRetryRequest has been received, the client repeats ClienHello re-formatting it in such a way, that the extensions block with the variable-size length encoding as per Appendix A. Note that unless the extension exceeds 32767 bytes in size, no changes of the bits on the wire occured with new encoding.¶
The server then responds with ServerHello that also includes the extensions block encoded in accordance with Appendix A.¶
Client Server
ClientHello
+ key_share
+ extended_extensions -------->
HelloRetryRequest
+ key_share
<-------- + extended_extensions
<ClientHello>
+ key_share
+ extended_extensions -------->
<ServerHello>
+ key_share
+ extended_extensions
AuxHandshakeData*
{<EncryptedExtensions>}
{CertificateRequest*}
{<Certificate>*}
{CertificateVerify*}
{Finished}
<-------- [Application Data*]
{<Certificate>*}
{CertificateVerify*}
{Finished} -------->
[Application Data] <-------> [Application Data]
<> Indicates messages that contain extension
blocks encoded with variable-size length encoding.
Note that once the extended extensions are negotiated, all susequent TLS handshake messages for this TLS session that include the extensions blocks MUST use the variable-size length encodings for them.¶
IANA is requested to assign a new value from the TLS ExtensionType Values registry:¶
* The Extension Name should be extended_extensions
* The TLS 1.3 value should be CH,SH,HRR
* The DTLS-Only value should be N
* The Recommended value should be Y
¶
The extended extensions mechanism defined in this document only affects the encoding of TLS 1.3 messages. It does not change security properties of TLS 1.3 defined in [RFC8446].¶
This appendix contains an excerpt from Appendix B.3 of [RFC8446], with the changes in encoding that this specification defines. The numeration of subsections from [RFC8446] is preserved and for convenience numbers are quoted.¶
"B.3.1." Key Exchange Messages
uint16 ProtocolVersion;
opaque Random[32];
uint8 CipherSuite[2]; /* Cryptographic suite selector */
struct {
ProtocolVersion legacy_version = 0x0303; /* TLS v1.2 */
Random random;
opaque legacy_session_id<0..32>;
CipherSuite cipher_suites<2..2^16-2>;
opaque legacy_compression_methods<1..2^8-1>;
Extension extensions<V>; /* 8..2^23-1 */
} ClientHello;
struct {
ProtocolVersion legacy_version = 0x0303; /* TLS v1.2 */
Random random;
opaque legacy_session_id_echo<0..32>;
CipherSuite cipher_suite;
uint8 legacy_compression_method = 0;
Extension extensions<V>; /* 6..2^23-1 */
} ServerHello;
struct {
ExtensionType extension_type;
opaque extension_data<V>; /* 0..2^23-1 */
} Extension;
enum {
server_name(0), /* RFC 6066 */
max_fragment_length(1), /* RFC 6066 */
status_request(5), /* RFC 6066 */
supported_groups(10), /* RFC 8422, 7919 */
signature_algorithms(13), /* RFC 8446 */
use_srtp(14), /* RFC 5764 */
heartbeat(15), /* RFC 6520 */
application_layer_protocol_negotiation(16), /* RFC 7301 */
signed_certificate_timestamp(18), /* RFC 6962 */
client_certificate_type(19), /* RFC 7250 */
server_certificate_type(20), /* RFC 7250 */
padding(21), /* RFC 7685 */
RESERVED(40), /* Used but never
assigned */
pre_shared_key(41), /* RFC 8446 */
early_data(42), /* RFC 8446 */
supported_versions(43), /* RFC 8446 */
cookie(44), /* RFC 8446 */
psk_key_exchange_modes(45), /* RFC 8446 */
RESERVED(46), /* Used but never
assigned */
certificate_authorities(47), /* RFC 8446 */
oid_filters(48), /* RFC 8446 */
post_handshake_auth(49), /* RFC 8446 */
signature_algorithms_cert(50), /* RFC 8446 */
key_share(51), /* RFC 8446 */
(65535)
} ExtensionType;
struct {
NamedGroup group;
opaque key_exchange<V>; /* 1..2^23-1 */
} KeyShareEntry;
struct {
KeyShareEntry client_shares<V>; /* 0..2^23-1 */
} KeyShareClientHello;
struct {
NamedGroup selected_group;
} KeyShareHelloRetryRequest;
struct {
KeyShareEntry server_share;
} KeyShareServerHello;
struct {
uint8 legacy_form = 4;
opaque X[coordinate_length];
opaque Y[coordinate_length];
} UncompressedPointRepresentation;
enum { psk_ke(0), psk_dhe_ke(1), (255) } PskKeyExchangeMode;
struct {
PskKeyExchangeMode ke_modes<1..255>;
} PskKeyExchangeModes;
struct {} Empty;
struct {
select (Handshake.msg_type) {
case new_session_ticket: uint32 max_early_data_size;
case client_hello: Empty;
case encrypted_extensions: Empty;
};
} EarlyDataIndication;
struct {
opaque identity<V>; /* 1..2^23-1 */
uint32 obfuscated_ticket_age;
} PskIdentity;
opaque PskBinderEntry<32..255>;
struct {
PskIdentity identities<V>; /* 7..2^23-1 */
PskBinderEntry binders<V>; /* 33..2^23-1 */
} OfferedPsks;
struct {
select (Handshake.msg_type) {
case client_hello: OfferedPsks;
case server_hello: uint16 selected_identity;
};
} PreSharedKeyExtension;
"B.3.1.1." Version Extension
struct {
select (Handshake.msg_type) {
case client_hello:
ProtocolVersion versions<2..254>;
case server_hello: /* and HelloRetryRequest */
ProtocolVersion selected_version;
};
} SupportedVersions;
"B.3.1.2." Cookie Extension
struct {
opaque cookie<V>; /* 1..2^23-1 */
} Cookie;
"B.3.1.3." Signature Algorithm Extension
enum {
/* RSASSA-PKCS1-v1_5 algorithms */
rsa_pkcs1_sha256(0x0401),
rsa_pkcs1_sha384(0x0501),
rsa_pkcs1_sha512(0x0601),
/* ECDSA algorithms */
ecdsa_secp256r1_sha256(0x0403),
ecdsa_secp384r1_sha384(0x0503),
ecdsa_secp521r1_sha512(0x0603),
/* RSASSA-PSS algorithms with public key OID rsaEncryption */
rsa_pss_rsae_sha256(0x0804),
rsa_pss_rsae_sha384(0x0805),
rsa_pss_rsae_sha512(0x0806),
/* EdDSA algorithms */
ed25519(0x0807),
ed448(0x0808),
/* RSASSA-PSS algorithms with public key OID RSASSA-PSS */
rsa_pss_pss_sha256(0x0809),
rsa_pss_pss_sha384(0x080a),
rsa_pss_pss_sha512(0x080b),
/* Legacy algorithms */
rsa_pkcs1_sha1(0x0201),
ecdsa_sha1(0x0203),
/* Reserved Code Points */
obsolete_RESERVED(0x0000..0x0200),
dsa_sha1_RESERVED(0x0202),
obsolete_RESERVED(0x0204..0x0400),
dsa_sha256_RESERVED(0x0402),
obsolete_RESERVED(0x0404..0x0500),
dsa_sha384_RESERVED(0x0502),
obsolete_RESERVED(0x0504..0x0600),
dsa_sha512_RESERVED(0x0602),
obsolete_RESERVED(0x0604..0x06FF),
private_use(0xFE00..0xFFFF),
(0xFFFF)
} SignatureScheme;
struct {
SignatureScheme supported_signature_algorithms<V>;
/* 2..2^23-2 */
} SignatureSchemeList;
"B.3.1.4." Supported Groups Extension
enum {
unallocated_RESERVED(0x0000),
/* Elliptic Curve Groups (ECDHE) */
obsolete_RESERVED(0x0001..0x0016),
secp256r1(0x0017), secp384r1(0x0018), secp521r1(0x0019),
obsolete_RESERVED(0x001A..0x001C),
x25519(0x001D), x448(0x001E),
/* Finite Field Groups (DHE) */
ffdhe2048(0x0100), ffdhe3072(0x0101), ffdhe4096(0x0102),
ffdhe6144(0x0103), ffdhe8192(0x0104),
/* Reserved Code Points */
ffdhe_private_use(0x01FC..0x01FF),
ecdhe_private_use(0xFE00..0xFEFF),
obsolete_RESERVED(0xFF01..0xFF02),
(0xFFFF)
} NamedGroup;
struct {
NamedGroup named_group_list<V>; /* 2..2^23-1 */
} NamedGroupList;
"B.3.2." Server Parameters Messages
opaque DistinguishedName<V>; /* 1..2^23-1 */
struct {
DistinguishedName authorities<V>; /* 3..2^23-1 */
} CertificateAuthoritiesExtension;
struct {
opaque certificate_extension_oid<1..2^8-1>;
opaque certificate_extension_values<V>; /* 0..2^23-1 */
} OIDFilter;
struct {
OIDFilter filters<V>; /* 0..2^23-1 */
} OIDFilterExtension;
struct {} PostHandshakeAuth;
struct {
Extension extensions<V>; /* 0..2^23-1 */
} EncryptedExtensions;
struct {
opaque certificate_request_context<0..2^8-1>;
Extension extensions<V>; /* 2..2^23-1 */
} CertificateRequest;
"B.3.3." Authentication Messages
enum {
X509(0),
OpenPGP_RESERVED(1),
RawPublicKey(2),
(255)
} CertificateType;
struct {
select (certificate_type) {
case RawPublicKey:
/* From RFC 7250 ASN.1_subjectPublicKeyInfo */
opaque ASN1_subjectPublicKeyInfo<1..2^24-1>;
case X509:
opaque cert_data<1..2^24-1>;
};
Extension extensions<V>; /* 0..2^23-1 */
} CertificateEntry;
struct {
opaque certificate_request_context<0..2^8-1>;
CertificateEntry certificate_list<0..2^24-1>;
} Certificate;
struct {
SignatureScheme algorithm;
opaque signature<0..2^16-1>;
} CertificateVerify;
struct {
opaque verify_data[Hash.length];
} Finished;
"B.3.4." Ticket Establishment
struct {
uint32 ticket_lifetime;
uint32 ticket_age_add;
opaque ticket_nonce<0..255>;
opaque ticket<1..2^16-1>;
Extension extensions<V>; /* 0..2^23-2 */
} NewSessionTicket;
"B.3.5." Updating Keys
struct {} EndOfEarlyData;
enum {
update_not_requested(0), update_requested(1), (255)
} KeyUpdateRequest;
struct {
KeyUpdateRequest request_update;
} KeyUpdate;
¶
Eric Rescorla proposed the idea to use QUIC- and MLS-like variable-size length encoding in TLS 1.3.¶