TLS 1.3 Handshake Protocol

The handshake protocol is used to negotiate the security parameters of a connection. Handshake messages are passed to the TLS record layer, where they are encapsulated into one or more TLSPlaintext or TLSCiphertext structures and processed and transmitted according to the currently active connection state.

      enum {
          client_hello(1),
          server_hello(2),
          new_session_ticket(4),
          end_of_early_data(5),
          encrypted_extensions(8),
          certificate(11),
          certificate_request(13),
          certificate_verify(15),
          finished(20),
          key_update(24),
          message_hash(254),
          (255)
      } HandshakeType;

      struct {
          HandshakeType msg_type;    /* handshake type */
          uint24 length;             /* remaining bytes in message */
          select (Handshake.msg_type) {
              case client_hello:          ClientHello;
              case server_hello:          ServerHello;
              case end_of_early_data:     EndOfEarlyData;
              case encrypted_extensions:  EncryptedExtensions;
              case certificate_request:   CertificateRequest;
              case certificate:           Certificate;
              case certificate_verify:    CertificateVerify;
              case finished:              Finished;
              case new_session_ticket:    NewSessionTicket;
              case key_update:            KeyUpdate;
          };
      } Handshake;

Protocol messages must be sent in a specific order (see below for the order). If the peer detects that the received handshake messages are out of order, it must abort the handshake with an “unexpected_message” alert message.

In addition, IANA has assigned new handshake message types; see Chapter 11.

I. Key Exchange Messages

Key exchange messages are used to ensure the security of the Client and Server and to securely establish the communication keys used to protect the handshake and application data.

1. Cryptographic Negotiation

In the TLS protocol, during key negotiation, the Client can provide the following four options in ClientHello.

  • A list of cipher suites supported by the Client. The cipher suites indicate the AEAD algorithms or HKDF hash pairs supported by the Client.
  • The “supported_groups” extension and the “key_share” extension. The “supported_groups” extension indicates the (EC)DHE groups supported by the Client, and the “key_share” extension indicates whether the Client includes some or all of the (EC)DHE shares.
  • The “signature_algorithms” signature algorithms extension and the “signature_algorithms_cert” certificate signature algorithms extension. The “signature_algorithms” extension lists the signature algorithms supported by the Client. The “signature_algorithms_cert” extension lists the signature algorithms for specific certificates.
  • The “pre_shared_key” pre-shared key extension and the “psk_key_exchange_modes” extension. The pre-shared key extension contains identifiers for symmetric keys that the Client can recognize. The “psk_key_exchange_modes” extension indicates the key exchange modes that may be used together with the PSK.

If the Server does not select a PSK, then the first three of the four options above are orthogonal: the Server independently selects a cipher suite, independently selects an (EC)DHE group, independently selects a key share used to establish the connection, and independently selects a signature algorithm/certificate pair for the Client to authenticate the Server. If none of the algorithms in the “supported_groups” received by the Server are supported by the Server, it must return a “handshake_failure” or “insufficient_security” alert message.

If the Server selects a PSK, it must select a key establishment mode from the Client’s “psk_key_exchange_modes” extension message. At this point, PSK and (EC)DHE are separate. Because PSK and (EC)DHE are separate, the handshake will not be terminated even if there is no algorithm common to the Server and Client in “supported_groups”.

If the Server selects an (EC)DHE group and the Client did not provide an appropriate “key_share” extension in ClientHello, the Server must respond with a HelloRetryRequest message.

If the Server successfully selects the parameters, a HelloRetryRequest message is not needed. The Server will send a ServerHello message containing the following parameters:

  • If PSK is being used, the Server will send the “pre_shared_key” extension, which contains the selected key.
  • If PSK is not being used and (EC)DHE is selected, the Server will provide a “key_share” extension. Typically, if PSK is not used, (EC)DHE and certificate-based authentication are used.
  • When authenticating with certificates, the Server sends Certificate and CertificateVerify messages. In the official TLS 1.3 specification, PSK and certificates are both commonly used, but not together; future documents may define how to use them simultaneously.

If the Server cannot negotiate a supported set of parameters—that is, if there is no overlap between the parameter sets supported by the Client and the Server—then the Server must abort the handshake by sending a “handshake_failure” or “insufficient_security” message.

2. Client Hello

When a Client connects to a Server for the first time, it needs to send a ClientHello message as its first TLS message. When the Server sends a HelloRetryRequest message, the Client must also respond with a ClientHello message after receiving it. In this case, the Client must send the same unmodified ClientHello message, except in the following cases:

  • If the HelloRetryRequest message contains the “key_share” extension, replace the share list with a KeyShareEntry containing a single share from the indicated group.
  • If the “early_data” extension is present, remove it. “early_data” is not allowed to appear after HelloRetryRequest.
  • If HelloRetryRequest contains the cookie extension, one needs to be included.
  • If the “obfuscated_ticket_age” and binder values are recomputed, and any PSKs incompatible with the cipher suite presented by the Server are also (optionally) removed, update the “pre_shared_key” extension.
  • Optionally add, remove, or change the length of the ”padding” extension RFC 7685.
  • Some other modifications that may be permitted. For example, extension definitions and HelloRetryRequest behavior specified in the future.

Because TLS 1.3 strictly prohibits renegotiation, if the Server has already completed TLS 1.3 negotiation and later receives a ClientHello at some point, the Server should not process this message; it must immediately close the connection and send an “unexpected_message” alert message.

If a Server has established a TLS connection using an earlier version of TLS and receives a TLS 1.3 ClientHello during renegotiation, the Server must continue using the previous version and must not negotiate TLS 1.3.

The structure of the ClientHello message is

      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<8..2^16-1>;
      } ClientHello;

Some notes on the struct:

  • legacy_version:
    In versions before TLS 1.3, this field was used for version negotiation and to indicate the highest TLS version supported by the Client. Experience has shown that many Servers did not implement version negotiation correctly, leading to “version intolerance” — the Server rejected some ClientHello messages that it could otherwise have supported, simply because the version number in those messages was higher than the highest version the Server supported. In TLS 1.3, the Client indicates its version in the “supported_versions” extension. The legacy_version field must be set to 0x0303, which is the version number for TLS 1.2. In TLS 1.3, legacy_version in the ClientHello message is set to 0x0303, and the supported_versions extension is set to 0x0304. See Appendix D for more detailed information.

  • random:
    A 32-byte random value generated by a secure random number generator. See Appendix C for additional information.

  • legacy_session_id:
    Versions prior to TLS 1.3 supported the session resumption feature. In TLS 1.3, this feature has been merged with pre-shared keys, PSKs. If the Client has a cached Session ID set by a Server from before TLS 1.3, this field must be populated with that ID value. In compatibility mode, this value must be non-empty, so if a Client cannot provide a Session from before TLS 1.3, it must generate a new 32-byte value. This value is not required to be random, but it must be unpredictable, to prevent implementations from hard-coding it to a fixed value. Otherwise, this field must be set to a zero-length vector. (For example, a 0-byte length field.)

  • cipher_suites:
    This list contains the symmetric encryption options supported by the Client, specifically the record protection algorithms (including key lengths) and the hash algorithms used together with HKDF. It is ordered in descending order of the Client’s preference. If the list contains cipher suites that the Server does not recognize, cannot support, or does not wish to use, the Server must ignore those cipher suites and continue processing the remaining cipher suites as usual. If the Client attempts to establish a PSK key, it should include at least one PSK-compatible hash cipher suite.

  • legacy_compression_methods:
    TLS versions prior to TLS 1.3 supported compression and sent the list of supported compression methods in this field. For every ClientHello, this vector must contain a single byte set to 0, corresponding to the null compression method in earlier TLS versions. If this field in a TLS 1.3 ClientHello contains any other value, the Server must immediately send an “illegal_parameter” alert message and abort the handshake. Note that a TLS 1.3 Server may receive ClientHellos from TLS 1.2 or even older versions that contain other compression methods. If those earlier versions are being negotiated, the rules of the earlier TLS versions must be followed.

  • extensions:
    The Client requests extended functionality from the Server by sending data in the extensions field. “Extension” follows the format definition. In TLS 1.3, the use of certain extensions is mandatory, because functionality has been moved into extensions to preserve compatibility with ClientHello messages from earlier TLS versions. The Server must ignore any extensions it does not recognize.

All versions of TLS allow the optional inclusion of the compression_methods extension field. TLS 1.3 ClientHello messages usually contain extension messages (at least “supported_versions”; otherwise, the message will be interpreted as a TLS 1.2 ClientHello). However, a TLS 1.3 Server may also receive ClientHello messages from earlier TLS versions that do not include an extensions field. The presence of extensions can be determined by checking whether there are bytes in the compression_methods field at the end of the ClientHello. Note that this method of detecting optional data differs from the normal TLS approach for variable-length fields, but before extensions were defined, this method could be used for compatibility. A TLS 1.3 Server needs to perform this check first, and attempt to negotiate TLS 1.3 only if the “supported_versions” extension is present. If a version prior to TLS 1.3 is being negotiated, the Server must perform two checks: whether there is data after the legacy_compression_methods field; and whether no data follows a valid extensions block. If either of these two checks fails, it must immediately send a “decode_error” alert message and abort the handshake.

If the Client requests additional functionality through an extension but the Server does not provide that functionality, the Client may abort the handshake.

After sending the ClientHello message, the Client waits for a ServerHello or HelloRetryRequest message. If early data is in use, the Client may send early Application Data while waiting for the next handshake message.

3. Server Hello

If the Server and Client can negotiate a set of mutually acceptable handshake parameters in the ClientHello message, the Server responds to the ClientHello message by sending a Server Hello message.

The message structure is:

      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<6..2^16-1>;
      } ServerHello;
  • legacy_version:
    In versions prior to TLS 1.3, this field was used for version negotiation and to identify the version selected by both peers when establishing the connection. Unfortunately, some middleboxes may fail when this field is assigned a new value. In TLS 1.3, the Server uses the “supported_versions” extension to indicate the versions it supports, and the legacy_version field must be set to 0x0303 (the value representing TLS 1.2). (For details on backward compatibility, see Appendix D.)

  • random:
    A random 32-byte value generated by a secure random number generator. If TLS 1.1 or TLS 1.2 is negotiated, the last 8 bytes must be overwritten, and the remaining 24 bytes must be random. This structure is generated by the Server and must be independent of ClientHello.random.

  • legacy_session_id_echo:
    The contents of the Client’s legacy_session_id field. Note that even if the Server decides not to resume a pre-TLS 1.3 session, the Client’s legacy_session_id field caches a pre-TLS 1.3 value; in this case, the legacy_session_id_echo field will also be echoed. If the legacy_session_id_echo value received by the Client does not match the value it sent in ClientHello, it must immediately abort the handshake with an “illegal_parameter” alert message.

  • cipher_suite:
    A cipher suite selected by the Server from the cipher_suites list in ClientHello. If the Client receives a cipher suite it did not offer, it should immediately abort the handshake with an “illegal_parameter” alert message.

  • legacy_compression_method:
    A single byte that must have the value 0.

  • extensions:
    The list of extensions. ServerHello must include only the extensions required to establish the cryptographic context and negotiate the protocol version. All TLS 1.3 ServerHello messages must contain the “supported_versions” extension. The current ServerHello message also includes the “pre_shared_key” extension, the “key_share” extension, or both (when establishing a connection using PSK and (EC)DHE). Other extensions are sent separately in the EncryptedExtensions message.

For backward compatibility with middleboxes, the HelloRetryRequest message and the ServerHello message use the same structure, but the random value must be set to the SHA-256-specific value for HelloRetryRequest:

     CF 21 AD 74 E5 9A 61 11 BE 1D 8C 02 1E 65 B8 91
     C2 A2 11 16 7A BB 8C 5E 07 9E 09 E2 C8 A8 33 9C

After receiving the server_hello message, the implementation must first check whether this random value matches the value above. If it is consistent with the value above, processing may continue.

TLS 1.3 includes a downgrade protection mechanism, implemented by embedding a value in the Server random. When a TLS 1.3 Server negotiates TLS 1.2 or an older version, in response to the ClientHello, the ServerHello message must place a specific random value in the last 8 bytes.

If TLS 1.2 is negotiated, the TLS 1.3 Server must set the last 8 bytes of the Random field in ServerHello to:

44 4F 57 4E 47 52 44 01
D  O  W  N  G  R  D

If TLS 1.1 or an older version is negotiated, a TLS 1.3 Server and a TLS 1.2 Server must change the value of the last 8 bytes of the Random field in ServerHello to:

44 4F 57 4E 47 52 44 00
D  O  W  N  G  R  D

After a TLS 1.3 Client receives a ServerHello message from TLS 1.2 or an older TLS version, it must check that the last 8 bytes of the Random field in the ServerHello are not equal to either of the two values above. A TLS 1.2 Client also needs to check the last 8 bytes. If the negotiated version is TLS 1.1 or older, the Random value must not be equal to the second value above. If none of these checks match, the Client must abort the handshake with an “illegal_parameter” alert message. This mechanism provides limited protection against downgrade attacks. The Finished exchange can extend beyond the scope of this protection mechanism: in TLS 1.2 or earlier, the ServerKeyExchange message contains a signature over the two random values. As long as an ephemeral key exchange is used, an attacker cannot modify the random values without being detected. Therefore, static RSA cannot provide downgrade-attack protection.

Please note that the changes above are described in RFC5246; in practice, many TLS 1.2 Clients and Servers do not implement them as specified above.

If a Client receives a TLS 1.3 ServerHello during renegotiation of TLS 1.2 or an older version, the Client must immediately send a “protocol_version” alert and abort the handshake. Please note that once TLS 1.3 negotiation has completed, renegotiation is no longer possible, because TLS 1.3 strictly forbids renegotiation.

4. Hello Retry Request

If the ClientHello message sent by the Client contains a mutually supported set of parameters, but the Client cannot provide enough information for the subsequent handshake, the Server needs to respond to the ClientHello message with a HelloRetryRequest message. In the previous section, we noted that HelloRetryRequest and ServerHello have the same data structure, and that the legacy_version, legacy_session_id_echo, cipher_suite, and legacy_compression_method fields have the same meanings. For ease of discussion, in the following text we treat the HelloRetryRequest message as a distinct message.

The Server’s extension set must contain “supported_versions”. In addition, it must contain the minimal set of extensions that enables the Client to generate the correct ClientHello response. Compared with ServerHello, HelloRetryRequest can only contain extensions that appeared in the first ClientHello, except for the optional “cookie” extension.

After receiving a HelloRetryRequest message, the Client must first validate the four parameters legacy_version, legacy_session_id_echo, cipher_suite, and legacy_compression_method. It must determine the version to use for the connection with the Server starting from “supported_versions”, and then process the extensions. If the HelloRetryRequest would not cause any change to the ClientHello, the Client must abort the handshake with an “illegal_parameter” alert message. If the Client receives a second HelloRetryRequest message on a connection (where the ClientHello itself was already a response to a HelloRetryRequest), it must abort the handshake with an “unexpected_message” alert message.

Otherwise, the Client must process all extensions in the HelloRetryRequest and send a second, updated ClientHello. The HelloRetryRequest extension names defined in this specification are:

  • supported_versions
  • cookie
  • key_share

If the Client receives a cipher suite that it did not offer, it must immediately abort the handshake. The Server must ensure that, after receiving a valid and updated ClientHello, they are negotiating the same cipher suite (if the Server treats cipher-suite selection as the first step of negotiation, this happens automatically). After receiving the ServerHello, the Client must check that the cipher suite provided in the ServerHello is the same as the cipher suite in the HelloRetryRequest; otherwise, it must abort the handshake with an “illegal_parameter” alert message.

In addition, in its updated ClientHello, the Client must not offer any pre-shared key associated with a hash other than the one for the selected cipher suite. This allows the Client to avoid computing partial transcript hashes for multiple hashes in the second ClientHello.

The value of the selected_version field in the “support_versions” extension of the HelloRetryRequest must be preserved in the ServerHello. If this value changes, the Client must abort the handshake with an “illegal_parameter” alert message.

II. Extensions

Many TLS messages contain tag-length-value encoded extension data structures:

    struct {
        ExtensionType extension_type;
        opaque extension_data<0..2^16-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 */
        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 */
        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;

Here:

  • “extension_type” identifies the specific extension state.
  • “extension_data” contains information specific to that particular extension type.

All extension types are maintained by IANA; see the appendix for details.

Extensions are typically structured as request/response, although some extensions are merely indicators and do not have any response. The Client sends its extension requests in ClientHello, and the Server sends the corresponding extension responses in ServerHello, EncryptedExtensions, HelloRetryRequest, and Certificate messages. The Server sends extension requests in the CertificateRequest message, and the Client may respond with a Certificate message. The Server may also send an unsolicited extension request directly in a NewSessionTicket message, and the Client does not need to respond directly to that message.

If the peer did not send the corresponding extension request, implementations MUST NOT send an extension response, except for the “cookie” extension in the HelloRetryRequest message. Upon receiving such an extension, the endpoint MUST abort the handshake with an “unsupported_extension” alert message.

The following table lists the extension names for the messages in which they may appear, using the following notation: CH (ClientHello), SH (ServerHello), EE (EncryptedExtensions), CT (Certificate), CR (CertificateRequest), NST (NewSessionTicket), and HRR (HelloRetryRequest). If an implementation receives a message it recognizes, but the occurrence of the extension is not specified for that message, it MUST abort the handshake with an “illegal_parameter” alert message.

   +--------------------------------------------------+-------------+
   | Extension                                        |     TLS 1.3 |
   +--------------------------------------------------+-------------+
   | server_name [RFC6066]                            |      CH, EE |
   |                                                  |             |
   | max_fragment_length [RFC6066]                    |      CH, EE |
   |                                                  |             |
   | status_request [RFC6066]                         |  CH, CR, CT |
   |                                                  |             |
   | supported_groups [RFC7919]                       |      CH, EE |
   |                                                  |             |
   | signature_algorithms (RFC 8446)                  |      CH, CR |
   |                                                  |             |
   | use_srtp [RFC5764]                               |      CH, EE |
   |                                                  |             |
   | heartbeat [RFC6520]                              |      CH, EE |
   |                                                  |             |
   | application_layer_protocol_negotiation [RFC7301] |      CH, EE |
   |                                                  |             |
   | signed_certificate_timestamp [RFC6962]           |  CH, CR, CT |
   |                                                  |             |
   | client_certificate_type [RFC7250]                |      CH, EE |
   |                                                  |             |
   | server_certificate_type [RFC7250]                |      CH, EE |
   |                                                  |             |
   | padding [RFC7685]                                |          CH |
   |                                                  |             |
   | key_share (RFC 8446)                             | CH, SH, HRR |
   |                                                  |             |
   | pre_shared_key (RFC 8446)                        |      CH, SH |
   |                                                  |             |
   | psk_key_exchange_modes (RFC 8446)                |          CH |
   |                                                  |             |
   | early_data (RFC 8446)                            | CH, EE, NST |
   |                                                  |             |
   | cookie (RFC 8446)                                |     CH, HRR |
   |                                                  |             |
   | supported_versions (RFC 8446)                    | CH, SH, HRR |
   |                                                  |             |
   | certificate_authorities (RFC 8446)               |      CH, CR |
   |                                                  |             |
   | oid_filters (RFC 8446)                           |          CR |
   |                                                  |             |
   | post_handshake_auth (RFC 8446)                   |          CH |
   |                                                  |             |
   | signature_algorithms_cert (RFC 8446)             |      CH, CR |
   +--------------------------------------------------+-------------+

When multiple extensions of different types are present, the ordering of extensions can be arbitrary, except that "pre_shared_key" MUST be the last extension in the ClientHello. ("pre_shared_key" can appear anywhere in the extension block in ServerHello.) There MUST NOT be more than one extension of the same type.

In TLS 1.3, unlike TLS 1.2, extensions need to be negotiated on every handshake, even in PSK resumption mode. However, the parameters for 0-RTT are negotiated in the previous handshake. If the parameters do not match, 0-RTT needs to be rejected.

In TLS 1.3, there are subtle interactions between new features and legacy features that can significantly degrade overall security. The following are factors to consider when designing new extensions:

  • Some cases where the Server does not agree to an extension are errors (for example, the handshake cannot continue), while others simply indicate lack of support for a particular feature. In general, the former should be handled with an appropriate alert, and the latter should be handled with a field in the Server’s extension response.

  • Extensions should, as much as possible, be designed to prevent attacks that can force the use (or non-use) of a particular feature by manipulating handshake messages. This principle must be followed regardless of whether the feature introduces security concerns. In general, extension fields included in the hash input to the Finished message are not a concern, but extra care is required when an extension attempts to change the semantics of messages sent during the handshake phase. Designers and implementers should be aware that, before handshake authentication is complete, an attacker can modify messages and insert, delete, or replace extensions.

1. Supported Versions

      struct {
          select (Handshake.msg_type) {
              case client_hello:
                   ProtocolVersion versions<2..254>;

              case server_hello: /* and HelloRetryRequest */
                   ProtocolVersion selected_version;
          };
      } SupportedVersions;

“supported_versions” is used by the client to indicate the TLS versions it can support, and by the server to indicate the TLS version currently in use. This extension contains a list of supported versions ordered by preference. The most preferred version is placed first. The TLS 1.3 specification requires this extension to be included when sending a ClientHello message, and the extension must contain all TLS versions intended for negotiation. (For this specification, that means at least 0x0304; however, if earlier versions of TLS are to be negotiated, this extension must be included.)

If the “supported_versions” extension is absent, a server that complies with TLS 1.3 and is also compatible with the TLS 1.2 specification needs to negotiate TLS 1.2 or an earlier version, even if ClientHello.legacy_version is 0x0304 or a later version. When the server receives a ClientHello whose legacy_version value is 0x0304 or later, it may need to abort the handshake immediately.

If the “supported_versions” extension is present in the ClientHello, the server is prohibited from using the value of ClientHello.legacy_version for version negotiation; it must use only “supported_versions” to determine the client’s preferences. The server must select only a TLS version present in this extension and must ignore any unknown versions. Note that if one peer supports a sparse range, this mechanism allows negotiation among versions earlier than TLS 1.2. TLS 1.3 implementations that choose to support earlier versions of TLS should support TLS 1.2. The server should be prepared to receive ClientHello messages containing this extension but not containing 0x0304 in the viersions list.

When negotiating a version prior to TLS 1.3, the server must set ServerHello.version and must not send the “supported_versions” extension. When negotiating TLS 1.3, the server must send the “supported_versions” extension in response, and the extension must contain the selected TLS 1.3 version number (0x0304). It must also set ServerHello.legacy_version to 0x0303 (TLS 1.2). The client must check this extension before processing the ServerHello (although it needs to parse the ServerHello first in order to read the extensions). If the “supported_versions” extension is present, the client must ignore the value of ServerHello.legacy_version and use only the value in “supported_versions” to determine the selected version. If the “supported_versions” extension in the ServerHello contains a version the client did not offer, or contains a version prior to TLS 1.3 (i.e., TLS 1.3 is being negotiated, but the extension contains a pre-TLS 1.3 version), the client must immediately send an “illegal_parameter” alert and abort the handshake.

      struct {
          opaque cookie<1..2^16-1>;
      } Cookie;

Cookies have two primary purposes:

  • Allow the Server to force the Client to demonstrate reachability at its network address (thereby providing a mechanism for DoS protection), primarily for connectionless transports (see the example in RFC 6347).

  • Allow the Server to offload state, thereby enabling the Server to avoid storing any state when sending a HelloRetryRequest message to the Client. To achieve this, the Server can store the hash of the ClientHello in the cookie of the HelloRetryRequest (protected with an appropriate integrity algorithm).

When sending a HelloRetryRequest message, the Server may provide a “cookie” extension to the Client (this is an exception to the usual rule, which is that only extensions that might be sent can appear in the ClientHello). When sending the new ClientHello message, the Client MUST copy the contents of the extension received in the HelloRetryRequest into the “cookie” extension in the new ClientHello. The Client MUST NOT use the Cookie from the initial ClientHello in subsequent connections.

When the Server is operating statelessly, it may receive unprotected change_cipher_spec messages between the first and second ClientHello. Because the Server has not stored any state, it will treat them as if they were the first messages received. A stateless Server MUST ignore these records.

3. Signature Algorithms

TLS 1.3 provides two extensions for indicating the signature algorithms that may be used in digital signatures. The “signature_algorithms_cert” extension provides the signature algorithms used in certificates. The “signature_algorithms” extension (which already existed in TLS 1.2) provides the signature algorithms used in CertificateVerify messages. The key in the certificate must be of an appropriate type for the signature algorithm being used. This is a particular issue for RSA keys and PSS signatures, as described below: if the “signature_algorithms_cert” extension is absent, then the “signature_algorithms” extension also applies to signatures in certificates. A Client that wants the Server to authenticate itself with a certificate MUST send the “signature_algorithms” extension. If the Server is performing certificate authentication and the Client has not provided the “signature_algorithms” extension, the Server MUST abort the handshake with a “missing_extension” message.

The intent of adding the “signature_algorithms_cert” extension is to allow implementations that already support different algorithm sets for certificates to explicitly indicate their capabilities. TLS 1.2 implementations should also handle this extension. Implementations with the same policy in both cases may omit the “signature_algorithms_cert” extension.

The “extension_data” field in these extensions contains a SignatureSchemeList value:

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 */
          private_use(0xFE00..0xFFFF),
          (0xFFFF)
      } SignatureScheme;

      struct {
          SignatureScheme supported_signature_algorithms<2..2^16-2>;
      } SignatureSchemeList;

Note: this enum is named “SignatureScheme” because a “SignatureAlgorithm” type already existed in TLS 1.2 and is replaced by it. In this article, we use the term “signature algorithm” throughout.

Each listed SignatureScheme value is a single signature algorithm that the Client is willing to verify. These values are listed in descending order of preference. Note that signature algorithms take a message of arbitrary length as input, rather than a digest. Algorithms that traditionally operate on digests should be defined in TLS as first hashing the input with the specified hash algorithm and then performing the usual processing. The codes listed above have the following meanings:

  • RSASSA-PKCS1-v1_5 algorithms: Indicates signature algorithms that use RSASSA-PKCS1-v1_5 RFC8017 and the corresponding hash algorithms defined in SHS. These values refer only to signatures that appear in certificates and are not defined for signing TLS handshake messages. These values appear in “signature_algorithms” and “signature_algorithms_cert” for backward compatibility with TLS 1.2.

  • ECDSA algorithms: Indicates signature algorithms that use ECDSA, with the corresponding curves defined in ANSI X9.62 ECDSA and FIPS 186-4 DSS, and the corresponding hash algorithms defined in SHS. Signatures are represented as DER-encoded ECDSA-Sig-Value structures.

  • RSASSA-PSS RSAE algorithms: Indicates RSASSA-PSS signature algorithms using mask generation function 1. Both the digest used in the mask generation function and the digest being signed are the corresponding hash algorithms defined in SHS. The salt length MUST be equal to the length of the digest algorithm output. If the public key is in an X.509 certificate, the rsaEncryption OID RFC5280 MUST be used.

  • EdDSA algorithms: Indicates the EdDSA algorithms defined in RFC 8032, or their successor algorithms. Note that these corresponding algorithms are the “PureEdDSA” algorithms, not the “prehash” variants.

  • RSASSA-PSS PSS algorithms: Indicates RSASSA-PSS RFC 8017 signature algorithms using mask generation function 1. Both the digest used in the mask generation function and the digest being signed are the corresponding hash algorithms defined in SHS. The salt length MUST be equal to the length of the digest algorithm. If the public key is in an X.509 certificate, the RSASSA-PSS OID RFC5756 MUST be used. When used in certificate signatures, the algorithm parameters MUST be DER-encoded. If corresponding public key parameters are present, then the parameters in the signature MUST be the same as the parameters in the public key.

  • Legacy algorithms: Indicates algorithms that are being deprecated because they have known weaknesses. In particular, SHA-1 is used together with the RSASSA-PKCS1-v1_5 and ECDSA algorithms mentioned above. These values refer only to signatures that appear in certificates and are not defined for signing TLS handshake messages. These values appear in “signature_algorithms” and “signature_algorithms_cert” for backward compatibility with TLS 1.2. Endpoints SHOULD NOT negotiate these algorithms, but are allowed to do so solely for backward compatibility. Clients that offer these values MUST list them at the lowest priority (after all other algorithms in the SignatureSchemeList). A TLS 1.3 Server MUST NOT offer SHA-1-signed certificates unless a valid certificate chain cannot be produced without them.

Signatures on self-signed certificates or certificates of trust anchors are not validated, because they begin a certification path (see RFC 5280). A certificate that begins a certification path may use a signature algorithm that is not recommended for support in the “signature_algorithms” extension.

Note that the definition of this extension in TLS 1.2 differs from its definition in TLS 1.3. When negotiating TLS 1.2, TLS 1.3 implementations that are willing to negotiate TLS 1.2 MUST comply with the requirements of RFC5246, especially:

  • TLS 1.2 ClientHellos may omit this extension.

  • In TLS 1.2, the extension contains hash/signature pairs. These pairs are encoded as two octets, so the allocated SignatureScheme values align with the TLS 1.2 encoding. Some legacy pairs remain unallocated. These algorithms have been deprecated in TLS 1.3. They MUST NOT be offered or negotiated by any implementation. In particular, MD5 [SLOTH], SHA-224, and DSA MUST NOT be used.

  • ECDSA signature schemes are consistent with TLS 1.2 hash/signature pairs. However, the old semantics did not constrain the signing curve. If TLS 1.2 is negotiated, implementations MUST be prepared to accept signatures using any curve in the “supported_groups” extension.

  • Even when TLS 1.2 is negotiated, implementations that support RSASSA-PSS (which is mandatory in TLS 1.3) are prepared to accept signatures for that scheme. In TLS 1.2, RSASSA-PSS is used with RSA cipher suites.

4. Certificate Authorities

The “certificate_authorities” extension is used to indicate the CAs supported by an endpoint, and the receiving endpoint should use it to guide certificate selection.

The body of the “certificate_authorities” extension contains a CertificateAuthoritiesExtension structure:

      opaque DistinguishedName<1..2^16-1>;

      struct {
          DistinguishedName authorities<3..2^16-1>;
      } CertificateAuthoritiesExtension;
  • authorities: A list of distinguished names X501 for acceptable certificate authorities, represented in DER X690 encoding. These distinguished names specify the required distinguished names for trust anchors or subordinate CAs. Therefore, this message can be used to describe known trust anchors as well as the desired authorization space.

The Client MAY send the “certificate_authorities” extension in the ClientHello message, and the Server MAY send the “certificate_authorities” extension in the CertificateRequest message.

The “trusted_ca_keys” extension serves the same purpose as the “certificate_authorities” extension but is more complex. The “trusted_ca_keys” extension cannot be used in TLS 1.3, but in versions prior to TLS 1.3, it may appear in the Client’s ClientHello message.

5. OID Filters

The “oid_filters” extension allows the Server to provide a set of OID/value pairs for matching the Client’s certificate. If the Server wants to send this extension, it may be sent only in the CertificateRequest message.

      struct {
          opaque certificate_extension_oid<1..2^8-1>;
          opaque certificate_extension_values<0..2^16-1>;
      } OIDFilter;

      struct {
          OIDFilter filters<0..2^16-1>;
      } OIDFilterExtension;
  • filters: A list of certificate extension OIDs with allowed values, represented in DER-encoded X690 format RFC 5280. Some certificate extension OIDs allow multiple values (for example, Extended Key Usage). If the Server includes a non-empty filters list, the Client certificate included in the response must contain all specified extension OIDs that the Client recognizes. For each extension OID recognized by the Client, all specified values must be present in the Client certificate (although the certificate may also have other values). However, the Client must ignore and skip any certificate extension OID it does not recognize. If the Client ignores some required certificate extension OIDs and provides a certificate that does not satisfy the request, the Server may, at its discretion, either continue the connection with the Client unauthenticated or abort the handshake with an “unsupported_certificate” alert message. Any given OID must not appear more than once in the filters list.

The PKIX RFCs define various certificate extension OIDs and their corresponding value types. Depending on the type, matching certificate extension values are not necessarily bitwise equal. TLS implementations are expected to rely on their PKI libraries to perform certificate selection using certificate extension OIDs.

This document defines matching rules for two standard certificate extensions defined in RFC5280:

  • The Key Usage extension in a certificate matches the request when all Key Usage bits asserted in the request are also asserted in the Key Usage certificate extension.

  • The Extended Key Usage in a certificate matches the request when all key OIDs in the request are also present in the Extended Key Usage certificate extension. The special anyExtendedKeyUsage OID must not be used in the request.

Separate specifications may define matching rules for other certificate extensions.

6. Post-Handshake Client Authentication

The “post_handshake_auth” extension is used to indicate that the Client is willing to authenticate after the handshake. The Server must not send a post-handshake-authentication CertificateRequest message to a Client that did not provide this extension. The Server must not send this extension.

      struct {} PostHandshakeAuth;

The “extension_data” field in the “post_handshake_auth” extension is zero length.

7. Supported Groups

When the Client sends the “supported_groups” extension, this extension indicates the named groups supported by the Client for key exchange, in descending order of preference.

Note: In versions prior to TLS 1.3, this extension was originally called “elliptic_curves” and contained only elliptic curve groups. For details, see RFC8422 and RFC7919. This extension can also be used to negotiate ECDSA curves. Signature algorithms are now negotiated independently.

The “extension_data” field in this extension contains a “NamedGroupList” value:

      enum {

          /* Elliptic Curve Groups (ECDHE) */
          secp256r1(0x0017), secp384r1(0x0018), secp521r1(0x0019),
          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),
          (0xFFFF)
      } NamedGroup;

      struct {
          NamedGroup named_group_list<2..2^16-1>;
      } NamedGroupList;
  • Elliptic Curve Groups (ECDHE): Indicates support for the corresponding named curves defined in FIPS 186-4 [DSS] or [RFC7748]. Values from 0xFE00 to 0xFEFF are reserved for use by [RFC8126].

  • Finite Field Groups (DHE): Indicates support for the corresponding finite field groups, as defined in [RFC7919]. Values from 0x01FC to 0x01FF are reserved for use.

Entries in named_group_list are ordered according to the sender’s preference (most preferred first).

In TLS 1.3, the Server is allowed to send a “supported_groups” extension to the Client. The Client MUST NOT act on any information found in “supported_groups” before the handshake has completed successfully, but MAY use information obtained from a successfully completed handshake to change the groups used in the “key_share” extension on subsequent connections. If the Server has a group that it would prefer to accept over the values in the “key_share” extension, but is still willing to accept the ClientHello message, it SHOULD send “supported_groups” to update the Client’s view of its preferences. This extension SHOULD include all groups supported by the Server, regardless of whether the Client supports them.

8. Key Share

The “key_share” extension contains the endpoint’s cryptographic parameters.

The Client MAY send an empty client_shares vector to request the Server to select a group, at the cost of an additional round trip.

      struct {
          NamedGroup group;
          opaque key_exchange<1..2^16-1>;
      } KeyShareEntry;
  • group: The named group for the key to be exchanged.

  • key_exchange: Key exchange information. The contents of this field are determined by the specific group and the corresponding definition. Finite-field Diffie-Hellman parameters are described below. Elliptic-curve Diffie-Hellman parameters are also described below.

In a ClientHello message, the “extension_data” in the “key_share” extension contains a KeyShareClientHello value:

      struct {
          KeyShareEntry client_shares<0..2^16-1>;
      } KeyShareClientHello;
  • client_shares: A list of KeyShareEntry values provided in descending order of Client preference.

If the Client is requesting a HelloRetryRequest, this vector MAY be empty. Each KeyShareEntry value MUST correspond to a group provided in the “supported_groups” extension and MUST appear in the same order. However, when the highest-priority combinations are new and it is not feasible to provide pregenerated key shares for all of them, the values MAY be a non-contiguous subset of the “supported_groups” extension and MAY omit the most preferred groups; this situation can occur.

The Client MAY provide as many KeyShareEntry values as the supported groups it offers. Each value represents a set of key exchange parameters. For example, the Client might provide shares for multiple elliptic curves or multiple FFDHE groups. The key_exchange value in each KeyShareEntry MUST be generated independently. The Client MUST NOT provide multiple KeyShareEntry values for the same group. The Client MUST NOT provide any KeyShareEntry value for a group that does not appear in the Client’s “supported_group” extension. The Server checks these rules and, if any are violated, aborts the handshake immediately by sending an “illegal_parameter” alert message.

In a HelloRetryRequest message, the “extension_data” field of the “key_share” extension contains a KeyShareHelloRetryRequest value.

      struct {
          NamedGroup selected_group;
      } KeyShareHelloRetryRequest;
  • selected_group: The mutually supported group that the Server intends to negotiate and for which it is requesting a retry of the ClientHello / KeyShare.

After receiving this extension in a HelloRetryRequest message, the Client must validate two things. First, selected_group must have appeared in “supported_groups” in the original ClientHello. Second, selected_group must not have appeared in “key_share” in the original ClientHello. If both of the above checks fail, the Client must abort the handshake with an “illegal_parameter” alert message. Otherwise, when sending the new ClientHello, the Client must replace the original “key_share” extension with one that contains only the group indicated by the selected_group field that triggered the HelloRetryRequest, and that group contains only the new KeyShareEntry.

In a ServerHello message, the “extension_data” field in the “key_share” extension contains a KeyShareServerHello value.

      struct {
          KeyShareEntry server_share;
      } KeyShareServerHello;
  • server_share: A single KeyShareEntry value in the same group shared with the Client.

If the connection is established using an (EC)DHE key exchange, the Server provides exactly one KeyShareEntry in ServerHello. This value must be in the same group as the value selected by the Server from the KeyShareEntry values provided by the Client for negotiating the key exchange. The Server must not send a KeyShareEntry value for any group specified in the Client’s “supported_groups” extension. The Server also must not send a KeyShareEntry value when using the “psk_ke” PskKeyExchangeMode. If the connection is established using (EC)DHE and the Client receives a HelloRetryRequest message containing a “key_share” extension, the Client must verify that the NameGroup selected in ServerHello is the same as the one in HelloRetryRequest. If they are not the same, the Client must immediately send an “illegal_parameter” alert message and abort the handshake.

(1) Diffie-Hellman Parameters

The Diffie-Hellman [DH76] parameters for both the Client and the Server are encoded in the opaque key_exchange field of the KeyShare data structure within KeyShareEntry. The opaque value contains the Diffie-Hellman public key (Y = g^X mod p) for the specified group, encoded as a big-endian integer. This value is p bytes in size; if there are not enough bytes, 0s must be added on the left.

Note: For a given Diffie-Hellman group, padding ensures that all public keys have the same length.

Peers must validate each other’s public keys to ensure that 1 < Y < p-1. This check ensures that the remote peer is operating correctly and also prevents the local system from being forced into a smaller subgroup.

(2) ECDHE Parameters

The ECDHE parameters for both the Client and the Server are encoded in the opaque key_exchange field of the KeyShare data structure within KeyShareEntry.

For secp256r1, secp384r1, and secp521r1, the content is the serialized value of the following structure:

      struct {
          uint8 legacy_form = 4;
          opaque X[coordinate_length];
          opaque Y[coordinate_length];
      } UncompressedPointRepresentation;

X and Y are the binary representations of the X and Y values, respectively, in network byte order. Because there is no internal length marker, each number occupies the number of octets implied by the curve parameters. For P-256, this means each of X and Y occupies 32 octets, left-padded with zeros if necessary. For P-384, they each occupy 48 octets; for P-521, they each occupy 66 octets.

For the secp256r1, secp384r1, and secp521r1 curves, each peer MUST validate the other peer’s public key Q to ensure that the point is a valid point on the elliptic curve. Appropriate validation methods are defined in [ECDSA] or [KEYAGREEMENT]. This process consists of three steps. First, verify that Q is not the point at infinity (O). Second, verify that the two integers x and y in Q = (x, y) are in the correct range. Third, verify that (x, y) is a valid solution to the elliptic curve equation. For these curves, implementations do not need to further verify membership in the correct subgroup.

For X25519 and X448, the contents of the public value are the byte-string inputs and outputs of the corresponding functions defined in [RFC7748]: 32 bytes for X25519 and 56 bytes for X448.

Note: Versions prior to TLS 1.3 allowed point format negotiation; TLS 1.3 removed this feature in favor of a single point format for each curve.

9. Pre-Shared Key Exchange Modes

To use PSKs, the client MUST also send a “psk_key_exchange_modes” extension. The semantics of this extension are that the client only supports using PSKs with these modes. This restricts both the use of PSKs offered in this ClientHello and the use of PSKs provided by the server via NewSessionTicket.

If the client offers a “pre_shared_key” extension, it MUST also offer a “psk_key_exchange_modes” extension. If the client sends “pre_shared_key” without a “psk_key_exchange_modes” extension, the server MUST abort the handshake immediately. The server MUST NOT select a key exchange mode that the client did not list. This extension also restricts the modes used with PSK resumption. The server also MUST NOT send a NewSessionTicket that is incompatible with the proposed modes. However, if the server does so anyway, the only effect is that the client will fail when attempting to resume the session.

The server MUST NOT send the “psk_key_exchange_modes” extension:

      enum { psk_ke(0), psk_dhe_ke(1), (255) } PskKeyExchangeMode;

      struct {
          PskKeyExchangeMode ke_modes<1..255>;
      } PskKeyExchangeModes;
  • psk_ke: PSK-only key establishment. In this mode, the Server cannot provide a “key_share” value.

  • psk_dhe_ke: PSK with (EC)DHE establishment. In this mode, the Client and Server must provide “key_share” values.

Any values allocated in the future must ensure that the transmitted protocol messages can unambiguously identify the mode selected by the Server. Currently, the value selected by the Server is indicated by the presence of “key_share” in the ServerHello.

10. Early Data Indication

When using a PSK and the PSK permits the use of early_data, the Client may send application data in its first message. If the Client chooses to do so, it must send the “pre_shared_key” and “early_data” extensions.

The “extension_data” field in the Early Data Indication extension contains an EarlyDataIndication value.

      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;

For the use of the max_early_data_size field, see the New Session Ticket Message section.

The parameters for 0-RTT data (version, symmetric cipher suite, Application-Layer Protocol Negotiation protocol [RFC7301], and so on) are associated with the PSK parameters in use. For externally configured PSKs, the associated values are provided with the key. For PSKs established via the NewSessionTicket message, the associated values are those negotiated when the PSK connection was established. The PSK used to encrypt early data MUST be the first PSK listed by the Client in the “pre_shared_key” extension.

For PSKs provided via NewSessionTicket, the Server MUST verify that the ticket age in the selected PSK identity (computed by subtracting ticket_age_add from PskIdentity.obfuscated_ticket_age modulo 2^32) is within a small tolerance of the time elapsed since the ticket was issued. If the time difference is large, the Server SHOULD continue the handshake, but reject 0-RTT, and also assume that this ClientHello is fresh and take no other action.

0-RTT messages sent in the first flight have the same (encrypted) content type as messages of the same type sent in other flights (handshake and application data), but are protected with different keys. If the Server has accepted early data, then after receiving the Server’s Finished message, the Client sends an EndOfEarlyData message to indicate the key change. This message is encrypted using the 0-RTT traffic keys.

A Server receiving the “early_data” extension MUST operate in one of the following three ways:

  • Ignore the “early_data” extension and return a normal 1-RTT response. The Server attempts to decrypt the received records using the traffic keys from the handshake and ignores the early data. Records that fail to decrypt are discarded (subject to the configured max_early_data_size). Once a record is decrypted successfully, the Server treats it as the start of the Client’s second flight and processes it as normal 1-RTT data.

  • Request that the Client send another ClientHello by responding with HelloRetryRequest. The Client MUST NOT include the “early_data” extension in this ClientHello. The Server ignores the early data by skipping all records whose outer content type is “application_data” (indicating that they are encrypted), again subject to the configured max_early_data_size.

  • Return its own “early_data” extension in EncryptedExtensions, indicating that it is prepared to process early data. The Server cannot accept only part of the early data messages. Even if the Server sends a message accepting early data, the early data may in fact already be in flight when the Server generates that message.

To accept early data, the Server MUST have accepted a PSK cipher suite and selected the first key offered in the Client’s “pre_shared_key” extension. In addition, the Server needs to verify that the following values match the values associated with the selected PSK:

  • TLS version number
  • Selected cipher suite
  • Selected ALPN protocol, if one was selected

These requirements are a superset of what is required to perform a 1-RTT handshake using the associated PSK. For externally established PSKs, the associated values are those provided with the key. For PSKs established via the NewSessionTicket message, the associated values are those negotiated in the connection during which the ticket was established.

Future extensions MUST define their interaction with 0-RTT.

If any of these checks fail, the Server MUST NOT include the extension in its response and MUST use one of the first two mechanisms listed above, discarding all first-flight data (thereby falling back to 1-RTT or 2-RTT). If the Client attempts a 0-RTT handshake but the Server rejects it, the Server typically will not have 0-RTT record protection keys and MUST use trial decryption (using the 1-RTT handshake keys, or by looking for the plaintext ClientHello when a HelloRetryRequest message is involved) to find the first non-0-RTT message.

If the Server chooses to accept the early_data extension, then when processing early data records, the Server MUST process all records according to the same criteria (with the same specified error-handling requirements). In particular, if the Server cannot decrypt a record in an accepted “early_data” extension, it MUST send a “bad_record_mac” alert message and abort the handshake.

If the Server rejects the “early_data” extension, the Client application may choose to resend, after the handshake completes, the application data that it previously sent as early data. Note that automatic retransmission of early data can lead to incorrect assumptions about connection state. For example, when the negotiated connection selects an ALPN protocol different from the one used for early data, the application may need to construct a different message. Similarly, if the early data assumed anything about the connection state, that data may be sent incorrectly after the handshake completes.

TLS implementations SHOULD NOT automatically resend early data; the application is in a much better position to decide when to retransmit. Unless the negotiated connection selects the same ALPN protocol, TLS implementations MUST NOT automatically resend early data.

11. Pre-Shared Key Extension

The “pre_shared_key” extension is used to negotiate the identity of the pre-shared key associated with the PSK key and used for the given handshake.

The “extension_data” field in this extension contains a PreSharedKeyExtension value:

      struct {
          opaque identity<1..2^16-1>;
          uint32 obfuscated_ticket_age;
      } PskIdentity;

      opaque PskBinderEntry<32..255>;

      struct {
          PskIdentity identities<7..2^16-1>;
          PskBinderEntry binders<33..2^16-1>;
      } OfferedPsks;

      struct {
          select (Handshake.msg_type) {
              case client_hello: OfferedPsks;
              case server_hello: uint16 selected_identity;
          };
      } PreSharedKeyExtension;
  • identity: Label for the key. For example, a ticket or a label for an externally established pre-shared key.

  • obfuscated_ticket_age: An obfuscated version of the age of the key. This section describes how this value is generated for identities established via a NewSessionTicket message. For externally established identities, obfuscated_ticket_age SHOULD be 0, and the Server MUST ignore this value.

  • identities: The list of identities that the Client is willing to negotiate with the Server. If sent together with “early_data”, the first identity is used to identify the 0-RTT data.

  • binders: A series of HMAC values. Each value corresponds one-to-one with an entry in the identities list, in the same order.

  • selected_identity: The identity selected by the Server, represented as a zero-based index into the Client’s list of identities.

Each PSK is associated with a single hash algorithm. For PSKs established via tickets, the hash algorithm is the KDF hash algorithm used when the ticket was established in the connection. For externally established PSKs, the hash algorithm MUST be set when the PSK is established; if it is not set, the default algorithm is SHA-256. The Server MUST ensure that it selects a compatible PSK, if any, and cipher suite.

In versions prior to TLS 1.3, the Server Name Identification (SNI) value was intended to be associated with the session. The Server was required to ensure that the SNI value associated with the session matched the SNI value specified in the resumption handshake. In practice, however, implementations and the two SNI values they used were inconsistent, which meant that the Client needed to enforce the consistency requirement. In TLS 1.3, the SNI value is always explicitly indicated in the resumption handshake, and the Server does not need to associate the SNI value with the ticket. However, the Client needs to store the SNI together with the PSK in order to satisfy the requirements of [Section 4.6.1].

Note to implementers: session resumption is the primary use case for PSKs. The most straightforward way to implement the PSK/cipher suite matching requirement is to negotiate the cipher suite first, and then exclude any incompatible PSKs. Any unknown PSKs (for example, those not in the PSK database, or those encoded with an unknown key) MUST be ignored. If no acceptable PSK can be found, the Server SHOULD perform a non-PSK handshake if possible. If backward compatibility is important, externally established PSKs offered by the Client SHOULD influence cipher suite selection.

Before accepting PSK-based key establishment, the Server MUST first validate the corresponding binder value (see [Section 4.2.11.2]). If this value is absent or fails validation, the Server MUST immediately abort the handshake. The Server SHOULD NOT attempt to validate multiple binders; instead, it should select a single PSK and validate only the binder corresponding to that PSK. See Appendix E.6 and [Section 8.2] for the security rationale behind this requirement. To accept PSK-based key establishment for the connection, the Server sends the “pre_shared_key” extension indicating the identity it selected.

The Client MUST verify that the Server’s selected_identity is within the range provided by the Client. The cipher suite selected by the Server indicates the hash algorithm associated with the PSK, and if required by the ClientHello “psk_key_exchange_modes”, the Server should also send the “key_share” extension. If these values are inconsistent, the Client MUST immediately abort the handshake with an “illegal_parameter” alert message.

If the Server provides the “early_data” extension, the Client MUST verify that the Server’s selected_identity is 0. If any other value is returned, the Client MUST abort the handshake with an “illegal_parameter” alert message.

The “pre_shared_key” extension MUST be the last extension in the ClientHello (this facilitates the implementation described below). The Server MUST check that it is the last extension; otherwise, it MUST abort the handshake with an “illegal_parameter” alert message.

(1) Ticket Age

From the Client’s perspective, the age of a ticket is the amount of time between receipt of the NewSessionTicket message and the current time. The Client MUST NOT use a ticket whose age is greater than the “ticket_lifetime” indicated by the ticket itself. The “obfuscated_ticket_age” field in each PskIdentity MUST contain an obfuscated version of the ticket age. The obfuscation is computed by adding the ticket age (in milliseconds) to the “ticket_age_add” field and then taking the result modulo 2^32. Unless the ticket is reused, this obfuscation can prevent passive observers from correlating connections. Note that the “ticket_lifetime” field in the NewSessionTicket message is in seconds, whereas “obfuscated_ticket_age” is in milliseconds. Because ticket lifetime is limited to one week, 32 bits is sufficient to represent any reasonable time value, even in milliseconds.

(2) PSK Binder

The PSK binder value establishes two bindings: one between the PSK and the current handshake, and another between the handshake after the PSK was generated (if it was generated via a NewSessionTicket message) and the current handshake. Each entry in the binder list computes an HMAC over a transcript hash of part of the ClientHello, and the final HMAC includes the PreSharedKeyExtension.identities field. In other words, the HMAC covers the entire ClientHello, but not the binder list. If binders of the correct length are present, the message length fields (including the total length, the extension block length, and the length of the “pre_shared_key” extension) are set.

PskBinderEntry is computed in the same way as the Finished message. However, the BaseKey is the derived binder_key, which is derived from the corresponding supplied PSK.

If the handshake includes a HelloRetryRequest message, the initial ClientHello and HelloRetryRequest are included in the transcript along with the new ClientHello. For example, if the Client sends a ClientHello, its binder is computed as follows:

      Transcript-Hash(Truncate(ClientHello1))

The purpose of the Truncate() function is to remove the binders list from ClientHello.

If the Server responds with HelloRetryRequest, the Client sends ClientHello2, whose binder is computed as follows:

      Transcript-Hash(ClientHello1,
                      HelloRetryRequest,
                      Truncate(ClientHello2))

The complete ClientHello1/ClientHello2 are included in the other handshake hash computations. Note that on the first transmission, Truncate(ClientHello1) is hashed directly, but on the second transmission, ClientHello1 is hashed, and a “message_hash” message is also injected.

(3) Processing Order

The Client is allowed to stream 0-RTT data until it receives the Server’s Finished message. After receiving the Finished message, the Client needs to send an EndOfEarlyData message at the end of the handshake. To prevent deadlock, when the Server receives an “early_data” message, it must immediately process the Client’s ClientHello message and then immediately respond with ServerHello, rather than waiting until it has received the Client’s EndOfEarlyData message before sending ServerHello.

III. Server Parameters

The Server’s next two messages, EncryptedExtensions and CertificateRequest, contain messages from the Server, which determine the remainder of the handshake. These messages are encrypted using keys derived from server_handshake_traffic_secret.

1. Encrypted Extensions

In all handshakes, the Server must send an EncryptedExtensions message immediately after the ServerHello message. This is the first message encrypted under keys derived from server_handshake_traffic_secret.

The EncryptedExtensions message contains extensions that should be protected. That is, any extension that does not need to establish an encryption context but is not associated with individual certificates. The Client must check whether the EncryptedExtensions message contains any prohibited extensions; if any prohibited extension is found, it must immediately abort the handshake with an “illegal_parameter” alert message.

   Structure of this message:

      struct {
          Extension extensions<0..2^16-1>;
      } EncryptedExtensions;
  • extensions: List of extensions.

2. Certificate Request

A Server that uses certificates for authentication may optionally request a certificate from the Client. This request message (if sent) must follow the EncryptedExtensions message.

Message structure:

      struct {
          opaque certificate_request_context<0..2^8-1>;
          Extension extensions<2..2^16-1>;
      } CertificateRequest;
  • certificate_request_context: An opaque string used to identify the certificate request and echoed in the Client’s Certificate message. certificate_request_context must be unique within this connection (thereby preventing replay attacks against the Client’s CertificateVerify). This field is generally zero length, except when used for the post-handshake authentication exchange described in [4.6.2]. When requesting post-handshake authentication, the Server should send an unpredictable context to the Client (for example, generated from a random number) to prevent attacks. An attacker could precompute a valid CertificateVerify message and thereby gain access to the temporary Client private key.

  • extensions: A set of extensions describing the parameters required for the requested certificate. The "signature_algorithms" extension must be specified; if other extensions are defined for this message, those other extensions may optionally be included as well. The Client must ignore unrecognized extensions.

In versions prior to TLS 1.3, the CertificateRequest message carried a list of signature algorithms and a list of certificate authorities acceptable to the Server. In TLS 1.3, the signature algorithm list can be represented by the "signature_algorithms" extension and the optional "signature_algorithms_cert" extension. The latter certificate authority list can be represented by sending the "certificate_authorities" extension.

A Server authenticated using PSK must not send a CertificateRequest message in the main handshake, though it may send a CertificateRequest message for post-handshake authentication, provided that the Client has sent the "post_handshake_auth" extension.

IV. Authentication Messages

As we discussed in section 2, TLS uses a common set of messages for authentication, key confirmation, and handshake integrity: Certificate, CertificateVerify, and Finished. (PSK binders also provide key confirmation in a similar way.) These three messages are always the last three messages in the handshake. The Certificate and CertificateVerify messages, as described below, are sent only in certain cases. The Finished message is always sent as part of the authentication block. These messages are encrypted using keys derived from sender_handshake_traffic_secret.

Authentication messages are computed using the following inputs uniformly:

  • The certificate and signing key to use
  • The handshake context, consisting of a set of messages in a hash copy
  • The base key used to compute the MAC key

Based on these inputs, the messages contain:

  • Certificate: the certificate used for authentication and any supporting certificates in the chain. Note that certificate-based Client authentication is not available in PSK handshake flows (including 0-RTT).

  • CertificateVerify: a signature derived from the value of Transcript-Hash(Handshake Context, Certificate)

  • Finished: a MAC derived from the value of Transcript-Hash(Handshake Context, Certificate, CertificateVerify). The MAC value is computed using the MAC key derived from the Base key.

For each scenario, the following table defines the handshake context and the MAC Base Key.

   +-----------+-------------------------+-----------------------------+
   | Mode      | Handshake Context       | Base Key                    |
   +-----------+-------------------------+-----------------------------+
   | Server    | ClientHello ... later   | server_handshake_traffic_   |
   |           | of EncryptedExtensions/ | secret                      |
   |           | CertificateRequest      |                             |
   |           |                         |                             |
   | Client    | ClientHello ... later   | client_handshake_traffic_   |
   |           | of server               | secret                      |
   |           | Finished/EndOfEarlyData |                             |
   |           |                         |                             |
   | Post-     | ClientHello ... client  | client_application_traffic_ |
   | Handshake | Finished +              | secret_N                    |
   |           | CertificateRequest      |                             |
   +-----------+-------------------------+-----------------------------+

1. The Transcript Hash

Many cryptographic computations in TLS use the transcript hash. This value is computed by hashing the concatenation of each included handshake message, including the handshake message type and length fields carried in the handshake message header, but excluding the record layer header. For example:

Transcript-Hash(M1, M2, ... Mn) = Hash(M1 || M2 || ... || Mn)

As an exception to this general rule, when the Server responds to a ClientHello message with a HelloRetryRequest message, the value of ClientHello1 is replaced with a special synthetic handshake message whose handshake type is “message_hash” and which contains Hash(ClientHello1). For example:

  Transcript-Hash(ClientHello1, HelloRetryRequest, ... Mn) =
      Hash(message_hash ||        /* Handshake type */
           00 00 Hash.length  ||  /* Handshake message length (bytes) */
           Hash(ClientHello1) ||  /* Hash of ClientHello1 */
           HelloRetryRequest  || ... || Mn)

The reason for designing the structure this way is to allow the Server to perform a stateless HelloRetryRequest by storing only the hash of ClientHello1 in the cookie, rather than requiring it to export the entire intermediate hash state.

Specifically, the hash copy is always taken over the following sequence of handshake messages, starting with the first ClientHello and including only messages that have been sent: ClientHello, HelloRetryRequest, ClientHello, ServerHello, EncryptedExtensions, server CertificateRequest, server Certificate, server CertificateVerify, server Finished, EndOfEarlyData, client Certificate, client CertificateVerify, client Finished.

Typically, implementations can produce the hash copy as follows: maintain a running hash copy according to the negotiated hash. Note that subsequent post-handshake authentications do not include one another; they only include messages through the end of the main handshake.

2. Certificate

This message sends the endpoint’s certificate chain to the peer.

Whenever the negotiated key exchange method is authenticated using certificates (this includes all key exchange methods defined in this document other than PSK), the Server MUST send a Certificate message.

The Client MUST send a Certificate message if and only if the Server requests Client authentication by sending a CertificateRequest message.

If the Server requests Client authentication but no suitable certificate is available, the Client MUST send a Certificate message containing no certificates (for example, with a “certificate_list” field of length 0). The Finished message MUST be sent regardless of whether the Certificate message is empty.

The structure of the Certificate message is:

      enum {
          X509(0),
          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<0..2^16-1>;
      } CertificateEntry;

      struct {
          opaque certificate_request_context<0..2^8-1>;
          CertificateEntry certificate_list<0..2^24-1>;
      } Certificate;
  • certificate_request_context: If this message is in response to a CertificateRequest message, the value of certificate_request_context in this message is non-zero. Otherwise (in the case of Server authentication), this field SHALL be zero length.

  • certificate_list: This is a sequence (chain) of CertificateEntry structures, each containing a single certificate and a set of extensions.

  • extensions: A set of extension values for the CertificateEntry. The format of “Extension” is defined in [Section 4.2]. Valid extensions include the OCSP status extension [RFC6066] and the SignedCertificateTimestamp [RFC6962] extension. New extensions may be defined for this message in the future. Extensions in the Server’s Certificate message MUST correspond to extensions in the ClientHello message. Extensions in the Client’s Certificate message MUST correspond to extensions in the Server’s CertificateRequest message. If an extension applies to the entire chain, it should be included in the first CertificateEntry.

If the corresponding certificate type extension (“server_certificate_type” or “client_certificate_type”) was not negotiated in EncryptedExtensions, or if the X.509 certificate type was negotiated, then each CertificateEntry must contain a DER-encoded X.509 certificate. The sender’s certificate MUST be in the first CertificateEntry in the list. Each subsequent certificate SHOULD directly certify the certificate preceding it. Because certificate validation requires trust anchors to be distributed independently, the certificate that specifies the trust anchor MAY be omitted from the chain (provided that the supported peer is known to possess the omitted certificate).

Note: In versions prior to TLS 1.3, the ordering of “certificate_list” required each certificate to certify the certificate immediately preceding it; however, some implementations allowed some flexibility. Servers sometimes send both current and deprecated intermediates for transition purposes, while other configurations are incorrect but can still be validated successfully. For maximum compatibility, all implementations SHOULD be prepared to handle arbitrary ordering of certificates and TLS versions that may be irrelevant, but the end-entity certificate (in the ordering) MUST be first.

If the RawPublicKey certificate type is negotiated, then certificate_list MUST contain no more than one CertificateEntry, which contains the ASN1_subjectPublicKeyInfo value defined in [RFC7250], Section 3.

The OpenPGP certificate type is prohibited in TLS 1.3.

The Server’s certificate_list MUST always be non-empty. If the Client has no suitable certificate to send in response to the Server’s authentication request, it sends an empty certificate_list.

(1) OCSP Status and SCT Extensions

[RFC6066] and [RFC6961] provide extensions for negotiating that the Server sends an OCSP response to the Client. In TLS 1.2 and earlier, the Server replies with an empty extension to indicate negotiation of this extension, and carries OCSP information in the CertificateStatus message. In TLS 1.3, the Server’s OCSP information is in an extension in the CertificateEntry that contains the relevant certificate. In particular, the body of the “status_request” extension from the Server MUST be the CertificateStatus structure defined in [RFC6066] and [RFC6960], respectively.

Note: The status_request_v2 extension [RFC6961] has been deprecated, and TLS 1.3 cannot process a ClientHello message based on whether it is present or on its contents. In particular, sending the status_request_v2 extension in EncryptedExtensions, CertificateRequest, and Certificate messages is prohibited. A TLS 1.3 Server MUST be able to handle a ClientHello message that contains it, since that message may have been sent by a Client that wishes to use it in an earlier protocol version.

The Server may request that the Client provide an OCSP response for its certificate by sending an empty “status_request” extension in its CertificateRequest message. If the Client elects to send an OCSP response, the body of its “status_request” extension MUST be the CertificateStatus structure defined in [RFC6966].

Similarly, [RFC6962] provides a mechanism for the Server, used in TLS 1.2 and earlier, to send Signed Certificate Timestamps (SCTs) in an extension in ServerHello. In TLS 1.3, the Server’s SCT information is in an extension in the CertificateEntry.

(2) Server Certificate Selection

The following rules apply to certificates sent by the Server:

  • The certificate type MUST be X.509v3 [RFC5280], unless explicitly negotiated otherwise (for example, [RFC5081]).

  • The public key (and associated restrictions) of the Server’s end-entity certificate MUST be compatible with the selected authentication algorithm in the Client’s “signature_algorithms” extension (currently RSA, ECDSA, or EdDSA).

  • The certificate MUST allow the key to be used for signing (i.e., if the key usage extension is present, the digitalSignature bit MUST be set), and the signature scheme MUST be indicated in the Client’s “signature_algorithms”/“signature_algorithms_cert” extension.

  • The “server_name” [RFC6066] and “certificate_authorities” extensions are used to guide certificate selection. Because the Server may require the “server_name” extension to be present, the Client SHOULD send this extension when applicable.

If the Server can provide a certificate chain, all certificates in the Server’s chain MUST be signed using signature algorithms provided by the Client. Self-signed certificates or certificates expected to be trust anchors are not validated as part of the chain and therefore may be signed using any algorithm.

If the Server cannot produce a certificate chain signed only by the indicated supported algorithms, it SHOULD continue the handshake by sending the Client a certificate chain of its choice, which may include algorithms that the Client is not known to support. This fallback chain may use the deprecated SHA-1 hash algorithm only if the Client permits it; in all other cases, use of the SHA-1 hash algorithm MUST be prohibited.

If the Client cannot construct an acceptable certificate chain using the provided certificates, it MUST abort the handshake. It aborts the handshake and sends a certificate-related alert message (by default, the “unsupported_certificate” alert message).

If the Server has multiple certificates, it selects one of them according to the criteria above (among other criteria, such as the transport-layer endpoint, local configuration, and preferences).

(3) Client Certificate Selection

The following rules apply to certificates sent by the Client:

  • The certificate type MUST be X.509v3 [RFC5280], unless explicitly negotiated otherwise (for example, [RFC5081]).

  • If the “certificate_authorities” extension in the CertificateRequest message is non-empty, at least one certificate in the certificate chain SHOULD be issued by one of the listed CAs.

  • The certificate MUST be signed using an acceptable signature algorithm, as described in Section 4.3.2. Note that this relaxes the constraints on certificate signature algorithms found in previous versions of TLS.

  • If the CertificateRequest message contains a non-empty “oid_filters” extension, the end-entity certificate MUST match the extension OIDs recognized by the Client, as described in Section 4.2.5.

(4) Receiving a Certificate Message

In general, detailed certificate validation procedures are outside the scope of TLS (see [RFC5280]). This section provides TLS-specific requirements.

If the Server provides an empty Certificate message, the Client MUST abort the handshake with a “decode_error” alert message.

If the Client does not send any certificates (i.e., it sends an empty Certificate message), the Server may, at its discretion, either continue the handshake without Client authentication or abort the handshake with a “certificate_required” alert message. In addition, if some aspect of the certificate chain is unacceptable (for example, it is not signed by a known trusted CA), the Server may, at its discretion, either continue the handshake (treating the Client as not authenticated) or abort the handshake.

Any endpoint that receives any certificate that needs to be verified using any signature algorithm with the MD5 hash MUST abort the handshake with a “bad_certificate” alert message. SHA-1 is deprecated, and it is recommended that any endpoint receiving any certificate that is verified using any signature algorithm with the SHA-1 hash abort the handshake with a “bad_certificate” alert message. For clarity, this means that endpoints may accept these algorithms for self-signed certificates or trust-anchor certificates.

It is recommended that all endpoints transition to SHA-256 or better algorithms as soon as possible to maintain interoperability with implementations that are currently phasing out SHA-1 support.

Note that a certificate containing a key for one signature algorithm may be signed using a different signature algorithm (for example, an RSA key signed with an ECDSA key).

3. Certificate Verify

This message is used to provide explicit evidence that the endpoint possesses the private key corresponding to its certificate. The CertificateVerify message also provides integrity for the handshake up to this point. The Server MUST send this message when authenticating with a certificate. Whenever the Client authenticates with a certificate (i.e., when the Certificate message is non-empty), the Client MUST send this message. When sent, this message MUST appear immediately after the Certificate message and immediately before the Finished message. The struct for this message is:

      struct {
          SignatureScheme algorithm;
          opaque signature<0..2^16-1>;
      } CertificateVerify;

The algorithm field specifies the signature algorithm to use (see Section 4.2.3 for the definition of this type). The signature field is the digital signature generated using that algorithm. The content covered by the signature is the hash output described in Section 4.4.1, namely:

      Transcript-Hash(Handshake Context, Certificate)

The digital signature is computed over the concatenation of:

  • A string consisting of octet 32 (0x20) repeated 64 times
  • The context string
  • A single 0 byte used as a separator
  • The content to be signed

This structure is designed to prevent attacks against earlier versions of TLS, where the ServerKeyExchange format meant that an attacker could obtain a signature over a message with a chosen 32-byte prefix (ClientHello.random). The initial 64-byte padding clears the prefix in the server-controlled ServerHello.random.

The context string for the server signature is “TLS 1.3, Server CertificateVerify”. The context string for the client signature is “TLS 1.3, Client CertificateVerify”. It is used to provide separation between signatures in different contexts, helping defend against potential cross-protocol attacks.

For example, if the hash copy is 32 bytes of 01 (this length makes sense for SHA-256), the content covered by the digital signature for the server’s CertificateVerify would be:

      2020202020202020202020202020202020202020202020202020202020202020
      2020202020202020202020202020202020202020202020202020202020202020
      544c5320312e332c207365727665722043657274696669636174655665726966
      79
      00
      0101010101010101010101010101010101010101010101010101010101010101

On the sender side, the process used to compute the signature field of the CertificateVerify message takes as input:

  • The content covered by the digital signature

  • The private signing key corresponding to the certificate sent in the previous message

If the CertificateVerify message is sent by the Server, the signature algorithm must be one offered in the Client’s “signature_algorithms” extension, unless a valid certificate chain cannot be generated without unsupported algorithms (i.e., unless none of the currently supported algorithms can generate a valid certificate chain).

If it is sent by the Client, the signature algorithm used in the signature must be one of the signature algorithms present in the supported_signature_algorithms field of the “signature_algorithms” extension in the CertificateRequest message.

In addition, the signature algorithm must be compatible with the key in the sender’s end-entity certificate. Regardless of whether the RSASSA-PKCS1-v1_5 algorithm appears in “signature_algorithms”, RSA signatures must use the RSASSA-PSS algorithm. The SHA-1 algorithm is prohibited for any signature in the CertificateVerify message.

All SHA-1 signature algorithms in this specification are defined only for legacy certificates and are invalid for CertificateVerify signatures.

The recipient of the CertificateVerify message must verify the signature field. The verification process takes as input:

  • The content covered by the digital signature

  • The public key contained in the end-entity certificate found in the associated Certificate message

  • The digital signature received in the signature field of the CertificateVerify message

If verification fails, the receiving party must terminate the handshake with a “decrypt_error” alert.

4. Finished

The Finished message is the last message in the authentication block. It plays a critical role in authenticating the handshake and the computed keys.

The recipient of a Finished message must verify that the contents are correct; if they are not, it must terminate the connection with a “decrypt_error” alert message.

Once a party has sent its Finished message and has received and verified the Finished message from its peer, it can begin sending and receiving application data over the connection. There are two settings that allow data to be sent before receiving the peer’s Finished:

  1. As described in Section 4.2.10, the Client can send 0-RTT data.
  2. The Server can send data after the first flight, but because the handshake has not yet completed, there is no guarantee of the peer’s identity or even whether the peer is still online. (The ClientHello may be replayed.)

The key used to compute the Finished message is derived using HKDF from the Base Key defined in Section 4.4 (see Section 7.1). Specifically:

   finished_key =
       HKDF-Expand-Label(BaseKey, "finished", "", Hash.length)

The data structure of this message is:

      struct {
          opaque verify_data[Hash.length];
      } Finished;

verify_data is computed as follows:

      verify_data =
          HMAC(finished_key,
               Transcript-Hash(Handshake Context,
                               Certificate*, CertificateVerify*))

      * Only included if present.

HMAC [RFC2104] uses the Hash algorithm for the handshake. As noted above, the HMAC input is typically implemented via a running hash; that is, at this point it is simply the handshake hash.

In earlier versions of TLS, the length of verify_data was always 12 octets. In TLS 1.3, it is the size of the HMAC output used to represent the handshake hash.

Note: Alerts and any other non-handshake record types are not handshake messages and are not included in the hash computation.

Any record after the Finished message must be encrypted under the appropriate application traffic keys, as described in Section 7.2. In particular, this includes any alert sent by the Server in response to the Client’s Certificate and CertificateVerify messages.

5. End of Early Data

      struct {} EndOfEarlyData;

If the Server sends the “early_data” extension in EncryptedExtensions, the Client must send an EndOfEarlyData message after receiving the Server’s Finished message. If the Server does not send the “early_data” extension in EncryptedExtensions, the Client must not send an EndOfEarlyData message. This message indicates that all 0-RTT application_data messages, if any, have been transmitted, and that subsequent records are protected with the handshake traffic keys. The Server must not send this message; if the Client receives it, it must terminate the connection with an “unexpected_message” alert. This message is encrypted and protected using keys derived from client_early_traffic_secret.

6. Post-Handshake Messages

TLS also allows additional messages to be sent after the main handshake. These messages use the handshake content type and are encrypted with the appropriate application traffic keys.

(1) New Session Ticket Message

At any time after the Server receives the Client’s Finished message, it may send a NewSessionTicket message. This message creates a unique association between the ticket value and a PSK derived from the resumption master secret.

If the Client includes the “pre_shared_key” extension in the ClientHello message and includes the ticket in that extension, the Client may use the PSK in a future handshake. The Server may send multiple tickets on a single connection, either immediately one after another or after some specific event. For example, the Server might send a new ticket after post-handshake authentication to encapsulate additional Client authentication state. Multiple tickets can be used by the Client for various purposes, such as:

  • Opening multiple parallel HTTP connections

  • Racing connections across interfaces and address families via, for example, Happy Eyeballs [RFC8305] or related techniques

Any ticket must only be used to resume a session with a cipher suite that uses the same KDF hash algorithm as the one used to establish the original connection.

The Client must resume only if the new SNI value is valid for the Server certificate presented in the original session, and should resume only if the SNI value matches the SNI value used in the original session. The latter is a performance optimization: in general, there is no reason to expect different Servers covered by a single certificate to accept each other’s tickets; therefore, attempting session resumption in such cases would waste a single-use ticket. If such an indication is provided (externally or by any other means), the Client may be able to resume the session using a different SNI value.

When resuming a session, if the SNI value is reported to the calling application, implementations must use the value sent in the resumption ClientHello rather than the value sent in the previous session. Note that if the Server implementation rejects all PSK identities with different SNI values, these two values will always be the same.

Note: Although the resumption master secret depends on the Client’s second flight, a Server that does not request Client authentication can independently compute the remaining portion of the transcript hash and then send NewSessionTicket immediately after sending its Finished message, rather than waiting for the Client’s Finished message. This may be useful when the Client needs to open multiple TLS connections in parallel and can benefit from reducing the overhead of resumption handshakes.

      struct {
          uint32 ticket_lifetime;
          uint32 ticket_age_add;
          opaque ticket_nonce<0..255>;
          opaque ticket<1..2^16-1>;
          Extension extensions<0..2^16-2>;
      } NewSessionTicket;
  • ticket_lifetime: This field indicates the lifetime of the ticket. This time is represented as a 32-bit unsigned integer in network byte order, in seconds, relative to the ticket issuance time. Servers MUST NOT use any value greater than 604800 seconds (7 days). A value of zero indicates that the ticket should be discarded immediately. Regardless of ticket_lifetime, clients MUST NOT cache tickets for more than 7 days, and may delete tickets earlier according to local policy. Servers may treat a ticket as valid for a shorter period than the period stated in ticket_lifetime.

  • ticket_age_add: A securely generated random 32-bit value used to obfuscate the age of the ticket that the client includes in the “pre_shared_key” extension. The client adds this value to the ticket age modulo 2 ^ 32 to compute the value it transmits. The server MUST generate a fresh value for each ticket it issues.

  • ticket_nonce: A per-ticket value that is unique among all tickets issued in this connection.

  • ticket: This value is used as the PSK identity. The ticket itself is an opaque label. It may be a database lookup key, or a self-encrypted and self-authenticated value.

  • extensions: A set of extension values for the ticket. The extension format is defined in Section 4.2. Clients MUST ignore unrecognized extensions.

The only extension currently defined for NewSessionTicket is “early_data”, which indicates that the ticket may be used to send 0-RTT data (Section 4.2.10). It contains the following value:

  • max_early_data_size: This field indicates the maximum amount of 0-RTT data, in bytes, that the client is allowed to send when using the ticket. The amount of data counts only the application data payload (that is, the plaintext, but not padding or the inner content type byte). If the server receives 0-RTT data whose size exceeds max_early_data_size bytes, it SHOULD immediately terminate the connection with an “unexpected_message” alert. Note that a server that rejects early data because it lacks the encryption material will not be able to distinguish padding from content, so clients should not rely on being able to send large amounts of padding in early data records.

The ticket associated with the PSK is computed as follows:

       HKDF-Expand-Label(resumption_master_secret,
                        "resumption", ticket_nonce, Hash.length)

Because the ticket_nonce value is different for each NewSessionTicket message, each ticket derives a different PSK.

Note that, in principle, new tickets can continue to be issued, indefinitely extending the lifetime of keying material that was originally derived from the initial non-PSK handshake (most likely associated with the peer certificate).

Implementations are advised to impose an overall lifetime limit on such keying material. These limits should take into account the lifetime of the peer certificate, the possibility of intervening revocation, and the amount of time that has elapsed since the peer’s online CertificateVerify signature.

(2) Post-Handshake Authentication

When the Client has sent the “post_handshake_auth” extension (see Section 4.2.6), the Server can request client authentication at any time after the handshake completes by sending a CertificateRequest message. The Client must respond with the appropriate authentication messages (see Section 4.4). If the Client chooses to authenticate, it must send Certificate, CertificateVerify, and Finished messages. If the Client declines authentication, it must send a Certificate message containing no certificates, followed by a Finished message. All Client messages in response to the Server must appear consecutively on the wire, with no other types of messages interleaved.

A Client that receives a CertificateRequest message without having sent the “post_handshake_auth” extension must terminate the connection with an “unexpected_message” alert.

Note: Because Client authentication may involve prompting the user, the Server must be prepared for some delay, including receiving any number of other messages between sending the CertificateRequest and receiving the response. In addition, if the Client receives multiple CertificateRequest messages in succession, the Client may respond to them in an order different from the order in which they were received (the certificate_request_context value allows the server to disambiguate the responses).

(3) Key and Initialization Vector Update

The KeyUpdate handshake message is used to indicate that the sender is updating its own sending encryption keys. Either peer may send this message after sending its Finished message. An implementation that receives a KeyUpdate message before receiving the Finished message must terminate the connection with an “unexpected_message” alert. After sending a KeyUpdate message, the sender should use the next generation of keys for all of its traffic, computed as described in Section 7.2. Upon receiving a KeyUpdate, the receiver must update its receiving keys.

      enum {
          update_not_requested(0), update_requested(1), (255)
      } KeyUpdateRequest;

      struct {
          KeyUpdateRequest request_update;
      } KeyUpdate;
  • request_update: This field indicates whether the recipient of the KeyUpdate should respond with its own KeyUpdate. If an implementation receives any other value, it MUST terminate the connection with an “illegal_parameter” alert message.

If the request_update field is set to “update_requested”, the receiver MUST send its own KeyUpdate with request_update set to “update_not_requested” before sending its next application data record. This mechanism allows either side to force an update of the entire connection, but causes an implementation that receives multiple KeyUpdates while it is silent to respond with a single update. Note that an implementation might receive any number of messages between sending a KeyUpdate (with request_update set to “update_requested”) and receiving the peer’s KeyUpdate, because those messages may already have been in transit. However, because the sending and receiving keys are derived from independent traffic keys, retaining the receiving traffic keys does not affect the forward secrecy of data sent before the sender changes keys.

If implementations independently send their own KeyUpdates with request_update set to “update_requested” and their messages are both in transit, the result is that both sides will respond and both sides will update their keys.

Both the sender and the receiver MUST encrypt their KeyUpdate messages using the old keys. In addition, before accepting any messages encrypted with the new keys, both sides MUST enforce receipt of a KeyUpdate protected with the old keys. Failure to do so may lead to message truncation attacks.


Reference:

RFC 8446

GitHub Repo: Halfrost-Field

Follow: halfrost · GitHub

Source: https://halfrost.com/TLS_1.3_Handshake_Protocol/