The Transport Layer Security (TLS) Protocol Version 1.3
obsoletes
- rfc-5077 — Transport Layer Security (TLS) Session Resumption without Server-Side State
- rfc-5246 — The Transport Layer Security (TLS) Protocol Version 1.2
- rfc-6961 — The Transport Layer Security (TLS) Multiple Certificate Status Request Extension
updates
Extracted elements (31)
All TLS 1.3 cipher suites are AEAD-only to eliminate MAC-then-encrypt vulnerabilities (BEAST, Lucky13, POODLE). Static RSA and DH key exchange were removed to mandate forward secrecy. Compression was removed to prevent CRIME-class attacks. These changes collectively remove the largest classes of known TLS 1.2 attacks.
Post-ServerHello messages are all encrypted via EncryptedExtensions to extend confidentiality to extension parameters such as ALPN and SNI server responses, which were previously transmitted in plaintext in TLS 1.2. The version number is similarly hidden from the ServerHello field and carried only in the encrypted 'supported_versions' extension.
Middlebox compatibility mode (Appendix D.4): clients send a non-empty legacy_session_id and both peers send a ChangeCipherSpec record at specific points during the handshake. This makes TLS 1.3 traffic resemble TLS 1.2 session resumption, avoiding breakage by middleboxes that perform stateful TLS inspection.
CertificateVerify signature input is: 64 space bytes, context string ('TLS 1.3, client CertificateVerify' or server variant), a 0x00 separator, and the current transcript hash. The signing algorithm MUST be one advertised in 'signature_algorithms' and appropriate for the certificate's key.
If a client receives a second HelloRetryRequest in the same connection it MUST abort with 'unexpected_message'. A client MUST also abort with 'illegal_parameter' if the HelloRetryRequest would result in no change to the ClientHello.
Implementations MUST NOT encrypt more than 2^24.5 records under a given set of traffic keys; implementations SHOULD perform a KeyUpdate before this limit is reached to maintain AEAD security bounds.
Implementations MUST NOT send extension responses for extensions not requested by the remote endpoint (except 'cookie' in HelloRetryRequest). Upon receiving an unsolicited extension response, an endpoint MUST abort with 'unsupported_extension' alert.
Implementations MUST support TLS_AES_128_GCM_SHA256 and SHOULD support TLS_AES_256_GCM_SHA384 and TLS_CHACHA20_POLY1305_SHA256. All TLS 1.3 cipher suites pair an AEAD algorithm with an HKDF hash function; non-AEAD cipher suites from TLS 1.2 are not permitted.
Protocol messages MUST be sent in the order defined in Section 4.4.1. A peer receiving a handshake message in an unexpected order MUST abort the handshake with an 'unexpected_message' alert.
The Finished message contains HMAC(finished_key, Transcript-Hash(handshake messages). An incorrect Finished MUST cause the recipient to abort with 'decrypt_error'. Application Data MUST NOT be sent prior to sending the Finished message (except 0-RTT early data).
The 'pre_shared_key' extension MUST be the last extension in the ClientHello. There MUST NOT be more than one extension of the same type in any extension block. Implementations MUST abort with 'illegal_parameter' upon receiving an extension in a message where it is not permitted.
When PSK identities are provisioned out of band, the PSK identity and KDF hash algorithm MUST also be provisioned out of band. Low-entropy PSKs derived from passwords are not secure because the PSK binder enables offline dictionary attacks; the specified PSK authentication is not a password-authenticated key exchange.
When the 'supported_versions' extension is present in ClientHello, servers MUST NOT use ClientHello.legacy_version for version negotiation and MUST use only the extension to determine client preferences; servers MUST only select a version listed in that extension.
TLS 1.3 does not hide record lengths, leaving endpoints exposed to traffic-analysis attacks. Endpoints MAY use record padding (Section 5.4) to obscure true lengths. PSK identity labels in ClientHello are sent in plaintext, potentially enabling passive client tracking across connections (Section E.6).
KeyUpdate message (post-handshake): update_requested flag indicates whether the sender requests a reciprocal KeyUpdate from the receiver. Upon sending or receiving, the endpoint derives a new application traffic secret via HKDF-Expand-Label(..., 'traffic upd', '') and installs new keys.
NewSessionTicket (post-handshake): ticket_lifetime (uint32 seconds), ticket_age_add (uint32 random mask to obfuscate age in ClientHello), ticket_nonce, ticket (opaque PSK identity), extensions (including max_early_data_size for 0-RTT). Resumption PSK = HKDF-Expand-Label(resumption_master_secret, 'resumption', ticket_nonce, Hash.length).
Per-record nonce: the 64-bit sequence number is left-padded with zeros to the IV length, then XORed with the static per-direction IV derived from traffic key material. The sequence number is incremented by 1 after each record is processed.
Record padding: TLSInnerPlaintext = real content followed by zero or more zero bytes, followed by the actual ContentType byte. The AEAD covers all of this, hiding the true content type and allowing padding to obscure record lengths against traffic analysis.
The TLS 1.3 key schedule uses HKDF Extract-and-Expand to derive a chain of secrets: early_secret (from PSK or zeros), handshake_secret (from (EC)DHE shared secret), and master_secret (from zeros), each yielding directional traffic secrets, an exporter_master_secret, and a resumption_master_secret.
The transcript hash covers all Handshake-layer messages from ClientHello onward. When a HelloRetryRequest occurs, a synthetic message_hash message (HandshakeType 254) encoding Hash(ClientHello1) replaces the original ClientHello in the transcript, preventing the transcript from growing unboundedly.
TLS 1.3 defines a full handshake in three phases: Key Exchange (ClientHello/ServerHello establishing shared keys via (EC)DHE or PSK), Server Parameters (EncryptedExtensions, optional CertificateRequest), and Authentication (Certificate, CertificateVerify, Finished). All messages after ServerHello are encrypted using handshake traffic keys.
RFC 8446 creates and updates IANA TLS registries: adds entries to TLS ExtensionType (pre_shared_key(41), early_data(42), supported_versions(43), cookie(44), psk_key_exchange_modes(45), certificate_authorities(47), oid_filters(48), post_handshake_auth(49), signature_algorithms_cert(50), key_share(51)), creates a TLS SignatureScheme registry, and updates TLS Cipher Suite and HandshakeType registries.
0-RTT data is not forward secret (encrypted solely under PSK-derived keys) and provides no non-replay guarantees between connections. Servers MUST implement anti-replay mechanisms from Section 8 (single-use tickets, ClientHello recording, or freshness checks) to limit replay impact.
Downgrade protection: TLS 1.3 servers negotiating TLS 1.2 MUST set the last 8 bytes of ServerHello.Random to 44 4F 57 4E 47 52 44 01, and negotiating TLS 1.1 or below to 44 4F 57 4E 47 52 44 00. TLS 1.3 clients receiving a downgraded ServerHello MUST check for these sentinels and abort with 'illegal_parameter' if found.
Servers SHOULD implement one of three 0-RTT anti-replay mechanisms: (1) single-use tickets via a distributed cache, (2) ClientHello recording using the unique (random, binder) tuple within a time window, or (3) freshness checks using obfuscated ticket age with a server-side clock tolerance window.
Client state machine: START -[send ClientHello]-> WAIT_SH -[recv ServerHello]-> WAIT_EE -[recv EncryptedExtensions]-> WAIT_CERT_CR or WAIT_CV -[recv Certificate/CertificateVerify]-> WAIT_FINISHED -[recv Finished, send Finished]-> CONNECTED. HelloRetryRequest loops back to START.
Server state machine: START -[recv ClientHello]-> NEGOTIATED -[send ServerHello/EE/Cert/CV/Finished]-> WAIT_EOED (if 0-RTT accepted) or WAIT_FLIGHT2 -> WAIT_CERT/WAIT_CV (if client auth requested) -> WAIT_FINISHED -[recv Finished]-> CONNECTED.
ClientHello: legacy_version (uint16, fixed 0x0303), random (32 bytes), legacy_session_id (0..32 bytes), cipher_suites (2..2^16-2 bytes), legacy_compression_methods (1..2^8-1 bytes, MUST contain exactly {0x00} in TLS 1.3), extensions (8..2^16-1 bytes).
ServerHello: legacy_version (uint16, fixed 0x0303), random (32 bytes), legacy_session_id_echo (0..32 bytes), cipher_suite (2 bytes), legacy_compression_method (1 byte, fixed 0), extensions (6..2^16-1 bytes). HelloRetryRequest reuses this structure with Random set to SHA-256('HelloRetryRequest') = CF21AD74E59A6111BE1D8C021E65B891C2A211167ABB8C5E079E09E2C8A8339C.
The Handshake structure: HandshakeType msg_type (1 byte enum), uint24 length, followed by a select on msg_type yielding the appropriate body (ClientHello, ServerHello, Certificate, CertificateVerify, Finished, NewSessionTicket, KeyUpdate, etc.).
TLSPlaintext record: ContentType type (1 byte), ProtocolVersion legacy_record_version (2 bytes, 0x0303), uint16 length (max 2^14 bytes of plaintext), followed by fragment. TLSCiphertext uses opaque_type=23 (application_data) for all encrypted records to hide the inner ContentType from network observers.