Transport Layer Security (TLS) Session Resumption without Server-Side State
obsoleted by
- rfc-8446 — The Transport Layer Security (TLS) Protocol Version 1.3
obsoletes
- rfc-4507 — Transport Layer Security (TLS) Session Resumption without Server-Side State
updated by
- rfc-8447 — IANA Registry Updates for TLS and DTLS
Extracted elements (29)
If a server is planning to issue a session ticket to a client that does not present one, it SHOULD include an empty Session ID in the ServerHello to avoid the client caching a session by Session ID that the server will not maintain, keeping stateful and stateless resumption cleanly separated.
The key_name field in the recommended ticket format is randomly generated per server startup to avoid collisions between servers and to allow efficient identification of tickets the server issued before attempting decryption.
The ticket is opaque to the client and its internal structure is not subject to interoperability requirements; this allows server implementations to diverge from the recommended format as long as security properties are maintained.
This document obsoletes RFC 4507 to correct an encoding error: RFC 4507 included a redundant length field (one for extension contents and one for the ticket itself), but all known deployed implementations omitted the inner ticket length field. The update aligns the specification with actual implementations.
A server implemented per RFC 4507 receiving a ticket from an RFC 5077 client will misinterpret the first two bytes of the ticket as a length field, causing the ticket to be rejected as malformed or due to failed decryption. The two encodings are not interoperable.
A server wishing to support RFC 4507 clients should respond to an empty SessionTicket extension encoded the same way it was received, since the encoding of an empty extension was ambiguous in RFC 4507 (it could include a zero-length inner field or omit it).
A client SHOULD delete the ticket and associated state when the ticket_lifetime_hint expires. A value of zero in ticket_lifetime_hint indicates unspecified lifetime.
A client that does not possess a ticket but is prepared to receive one MUST include a zero-length ticket in the SessionTicket extension of the ClientHello.
A client that is not prepared to receive a ticket in the NewSessionTicket message MUST NOT include a SessionTicket extension unless it is sending a non-empty ticket obtained by other means.
A TLS server MUST use strong encryption and integrity protection for the ticket to prevent brute-force attacks that could reveal ticket contents.
Clients MUST NOT examine the ticket under the assumption that it complies with the recommended format in Section 4, since the ticket is opaque to the client.
If confidential information such as a secret key is transferred to the client in an alternate distribution scheme, it MUST be done using secure communication. The ticket MUST have its integrity and confidentiality protected with strong cryptographic techniques.
If the ticket is accepted by the server but the handshake fails, the client SHOULD delete the ticket.
The client MUST NOT treat the ticket as valid until it has verified the server's Finished message.
The NewSessionTicket message MUST be sent if the server included a SessionTicket extension in the ServerHello, and MUST NOT be sent otherwise. In a full handshake, the server MUST verify the client's Finished message before sending the ticket.
The server MUST send a SessionTicket extension in the ServerHello if it wishes to issue a new ticket via NewSessionTicket, and MUST NOT send this extension if it did not receive one in the ClientHello.
When accepting a ticket where the client included a non-empty Session ID in ClientHello, the server MUST respond with the same Session ID. The server MUST NOT rely on the Session ID having a particular value when validating the ticket, and MUST NOT use the Session ID for stateful session resumption when a ticket is presented.
The NewSessionTicket handshake message (assigned HandshakeType number 4) is sent by the server before ChangeCipherSpec to deliver a session ticket to the client. It contains a ticket_lifetime_hint (uint32, seconds) and a variable-length opaque ticket field.
The SessionTicket TLS extension (assigned extension number 35) is used by the client to signal support for stateless session resumption and to present a previously obtained ticket. An empty extension indicates the client is prepared to receive a new ticket; a non-empty extension carries a ticket to resume a session.
IANA assigned TLS extension number 35 to the SessionTicket TLS extension from the TLS ExtensionType values registry defined in RFC 4366.
IANA assigned TLS HandshakeType number 4 to the NewSessionTicket handshake type from the TLS HandshakeType values registry defined in RFC 4346.
An on-path adversary observing multiple TLS handshakes using the same ticket can correlate them to the same communication endpoints, so unlinkability is not guaranteed. Issuing new tickets via TLS renegotiation after tunnel establishment may mitigate some privacy and unlinkability concerns.
Forged or altered tickets could allow session resumption, lifetime extension, user impersonation, or privilege escalation. This attack is prevented by protecting tickets with strong integrity (e.g., HMAC-SHA-256).
Stolen tickets do not enable session resumption because the ticket is encrypted with a key known only to the server. However, the server must use strong encryption and integrity protection to prevent brute-force recovery of ticket contents.
The key_name field helps the server efficiently reject tickets it did not issue, reducing DoS risk. Ticket verification should use lightweight symmetric cryptographic operations to avoid amplifying denial-of-service attacks.
Ticket protection keys should be at least 128 bits in strength, generated securely, used only for ticket operations, and rotated regularly or whenever the ticket format or algorithms change.
The NewSessionTicket message encodes as: ticket_lifetime_hint (uint32, 4 octets, network byte order) followed by ticket (opaque, length-prefixed, up to 2^16-1 octets). The HandshakeType value for session_ticket is 4.
The recommended ticket structure is: key_name (16 octets), iv (16 octets), encrypted_state (variable, up to 2^16-1 octets), mac (32 octets). The MAC covers key_name, IV, 2-octet length of encrypted_state, and encrypted_state contents using HMAC-SHA-256.
The StatePlaintext structure (AES-128-CBC encrypted inside the ticket) stores: protocol_version, cipher_suite, compression_method, master_secret (48 octets), ClientIdentity, and a uint32 timestamp for expiry.