The additional authenticated data, which we denote as additional_data, is defined as follows: <del> [[OPEN ISSUE: Fix length which gives us a problem here for algorithms which pad.  See: https://github.com/tlswg/tls13-spec/issues/47]] </del> where "+" denotes concatenation.  The AEAD output consists of the ciphertext output by the AEAD encryption operation.  The length will generally be larger than TLSPlaintext.length, but by an amount that varies with the AEAD

In order to support aead suites that pad or otherwise modify length, we need to stop using the plaintext length in the aead input. An implied requirement on the cipher is to validate length.
:+1: Also note that I have also opened a documentation errata for TLS 1.2 related to this. (Errata ID: 2390, URL)
It's been observed a number of times that the AEAD cipher suite definitions don't actually accommodate ciphers which pad. See: URL URL URL We should either fix this or remove padding. hi IETF folks-- If an AEAD mode is ever defined that must pad its input to a blocksize before encrypting, the current spec seems like it will break. This is a currently-theoretical concern, since (fixed authentication tag notwithstanding) GCM does not pad its input, and OCB and chacha20-poly1305 (and other AEAD modes i could find data on) also don't pad their input. (note that this question is independent of the various proposals for explicitly introducing padding into TLS, which i don't go into here) The 1.3 draft currently says: It goes on to define AEAD-Decrypt this way: Consider the decryption step. The decryptor knows: the AEAD mode (including the taglength) the nonce the write key the sequence number the record type the TLS version the ciphertext (including its length) To create additionaldata, it must be able to derive URL From the above information. All the AEAD modes i know about have a ciphertext expansion of a fixed-length tag. so: URL = URL - AEADmode.taglength But if an AEAD mode were to additionally pad its input ("Since the ciphers might incorporate padding, the amount of overhead could vary with different URL values"), there would be no clear way to derive additionaldata because the length of the plaintext is unknown before doing the decryption. So i think the fix is to specify that additional_data should be derived From the padded length of the TLSPlaintext.fragment, not from URL For GCM (and other AEAD modes i know of) these values are of course identical. Making this explicit seems like it would require a bit of gymnastics in the spec, all for the sake of holding open the door for future modes with variable-length ciphertext expansion. I can try to make a patch for this change, but i want to know if we think it's necessary. Alternately, we could decide that we won't accept modes that require this kind of padding (maybe stripping out the sentence about "might incorporate padding"). Have i missed an obvious solution or misunderstood the situation? What do people think we should do here? --dkg

The additional authenticated data, which we denote as additional_data, is defined as follows:  where "+" denotes concatenation. <ins> Note: In versions of TLS prior to 1.3, the additional_data included a length field.  This presents a problem for cipher constructions with data-dependent padding (such as CBC).  TLS 1.3 removes the length field and relies on the AEAD cipher to provide integrity for the length of the data. </ins> The AEAD output consists of the ciphertext output by the AEAD encryption operation.  The length will generally be larger than TLSPlaintext.length, but by an amount that varies with the AEAD


ticket_lifetime. A randomly generated 32-bit value that is used to obscure the age <del> of the ticket that the client includes in the "early_data" </del>  extension.  The client-side ticket age is added to this value modulo 2^32 to obtain the value that is transmitted by the client.

Fix incorrect suggestion that of NST affects extension.
NAME merged. Please provide a PR adding yourself to the acknowledgements list in alphabetical order.

ticket_lifetime. A randomly generated 32-bit value that is used to obscure the age  <ins> of the ticket that the client includes in the "pre_shared_key" </ins> extension.  The client-side ticket age is added to this value modulo 2^32 to obtain the value that is transmitted by the client.


The plaintext is the concatenation of TLSPlaintext.fragment, TLSPlaintext.type, and any padding bytes (zeros). <del> The AEAD output consists of the ciphertext output by the AEAD </del>  encryption operation.  The length of the plaintext is greater than TLSPlaintext.length due to the inclusion of TLSPlaintext.type and any padding supplied by the sender.  The length of the AEAD output will If the decryption fails, the receiver MUST terminate the connection with a "bad_record_mac" alert. <del> An AEAD algorithm used in TLS 1.3 MUST NOT produce an expansion of greater than 255 bytes.  An endpoint that receives a record from its </del>  peer with TLSCipherText.length larger than 2^14 + 256 octets MUST terminate the connection with a "record_overflow" alert.  This limit is derived from the maximum TLSPlaintext length of 2^14 octets + 1 The sequence number is incremented after reading or writing each record.  The first record transmitted under a particular set of <del> traffic keys record key MUST use sequence number 0. </del>  Sequence numbers do not wrap.  If a TLS implementation would need to wrap a sequence number, it MUST either rekey (key-update) or TLSInnerPlaintext.content. The padding sent is automatically verified by the record protection <del> mechanism: Upon successful decryption of a TLSCiphertext.fragment, the receiving implementation scans the field from the end toward the beginning until it finds a non-zero octet.  This non-zero octet is the content type of the message.  This padding scheme was selected because it allows padding of any encrypted TLS record by an arbitrary size (from zero up to TLS record size limits) without introducing new content types.  The design also enforces all-zero padding octets, which allows for quick detection of padding errors. </del>  Implementations MUST limit their scanning to the cleartext returned from the AEAD decryption.  If a receiving implementation does not

I forsee some merge conflicts in the future, as there's already and I have plans to rototill this section a bit more than you do here.
This won't conflict with . Git is good at detecting identical changes.

The plaintext is the concatenation of TLSPlaintext.fragment, TLSPlaintext.type, and any padding bytes (zeros).  <ins> The AEAD output consists of the ciphertext output from the AEAD </ins> encryption operation.  The length of the plaintext is greater than TLSPlaintext.length due to the inclusion of TLSPlaintext.type and any padding supplied by the sender.  The length of the AEAD output will If the decryption fails, the receiver MUST terminate the connection with a "bad_record_mac" alert.  <ins> An AEAD algorithm used in TLS 1.3 MUST NOT produce an expansion greater than 255 octets.  An endpoint that receives a record from its </ins> peer with TLSCipherText.length larger than 2^14 + 256 octets MUST terminate the connection with a "record_overflow" alert.  This limit is derived from the maximum TLSPlaintext length of 2^14 octets + 1 The sequence number is incremented after reading or writing each record.  The first record transmitted under a particular set of  <ins> traffic keys MUST use sequence number 0. </ins> Sequence numbers do not wrap.  If a TLS implementation would need to wrap a sequence number, it MUST either rekey (key-update) or TLSInnerPlaintext.content. The padding sent is automatically verified by the record protection  <ins> mechanism: upon successful decryption of a TLSCiphertext.encrypted_record, the receiving implementation scans the field from the end toward the beginning until it finds a non-zero octet.  This non-zero octet is the content type of the message.  This padding scheme was selected because it allows padding of any encrypted TLS record by an arbitrary size (from zero up to TLS record size limits) without introducing new content types.  The design also enforces all-zero padding octets, which allows for quick detection of padding errors. </ins> Implementations MUST limit their scanning to the cleartext returned from the AEAD decryption.  If a receiving implementation does not


send this message when authenticating via a certificate.  Clients MUST send this message whenever authenticating via a Certificate (i.e., when the Certificate message is non-empty).  When sent, this <del> message MUST appear immediately after the Certificate Message and </del>  immediately prior to the Finished message. Structure of this message: The digital signature is then computed using the signing key over the concatenation of: <del> 64 bytes of octet 32 </del>  The context string

It could be just me, but the previous wording was kind of confusing (YMMV).

send this message when authenticating via a certificate.  Clients MUST send this message whenever authenticating via a Certificate (i.e., when the Certificate message is non-empty).  When sent, this  <ins> message MUST appear immediately after the Certificate message and </ins> immediately prior to the Finished message. Structure of this message: The digital signature is then computed using the signing key over the concatenation of:  <ins> A string that consists of octet 32 (0x20) repeated 64 times </ins> The context string


0-RTT messages sent in the first flight have the same content types as their corresponding messages sent in other flights (handshake, application_data, and alert respectively) but are protected under <del> different keys.  After all the 0-RTT application data messages (if any) have been sent, an "end_of_early_data" alert of type "warning" is sent to indicate the end of the flight.  0-RTT MUST always be followed by an "end_of_early_data" alert, which will be encrypted with the 0-RTT traffic keys. </del>  A server which receives an "early_data" extension can behave in one of three ways: This alert is sent by the client to indicate that all 0-RTT application_data messages have been transmitted (or none will be <del> sent at all) and that this is the end of the flight.  This alert MUST be at the warning level.  Servers MUST NOT send this alert and clients receiving it MUST terminate the connection with an "unexpected_message" alert. </del>  This alert notifies the recipient that the sender is canceling the handshake for some reason unrelated to a protocol failure.  If a

The alert is described as being part of the first flight, but it is really sent when the server Finished is received, per the processing order section. Notably, servers MUST NOT wait for endofearlydata before sending ServerHello through Finished. Group it with the client Finished flight, and fix the text about it terminating the first flight. (The division between the first and second client flight isn't especially well-defined because early data may flow in parallel with the ServerHello flight. But if there is to be a division, endofearlydata certainly falls into the second one.)
Yes, this should help avoid one of the most common mistakes in 0-RTT implementations.
LGTM.

0-RTT messages sent in the first flight have the same content types as their corresponding messages sent in other flights (handshake, application_data, and alert respectively) but are protected under  <ins> different keys.  After receiving the server's Finished message, if the server has accepted early data, an "end_of_early_data" alert of type "warning" MUST be sent to indicate the key change.  This message will be encrypted with the 0-RTT traffic keys. </ins> A server which receives an "early_data" extension can behave in one of three ways: This alert is sent by the client to indicate that all 0-RTT application_data messages have been transmitted (or none will be  <ins> sent at all) and that the following records are protected under handshake traffic keys.  This alert MUST be at the warning level. Servers MUST NOT send this alert and clients receiving it MUST terminate the connection with an "unexpected_message" alert. </ins> This alert notifies the recipient that the sender is canceling the handshake for some reason unrelated to a protocol failure.  If a


Consolidate "ticket_early_data_info" and "early_data" into a single extension (*).  Remove spurious requirement to implement "pre_shared_key". Clarify location of "early_data" from server (it goes in EE, as as their corresponding messages sent in other flights (handshake, application_data, and alert respectively) but are protected under different keys.  After receiving the server's Finished message, if <del> the server has accepted early data, an "end_of_early_data" alert of type "warning" MUST be sent to indicate the key change.  This message will be encrypted with the 0-RTT traffic keys. </del>  A server which receives an "early_data" extension can behave in one of three ways: 4.2.8.2. Clients are permitted to "stream" 0-RTT data until they receive the <del> server's Finished, only then sending the "end_of_early_data" alert. In order to avoid deadlock, when accepting "early_data", servers MUST </del>  process the client's ClientHello and then immediately send the <del> ServerHello, rather than waiting for the client's "end_of_early_data" alert. </del>  4.2.8.3. 4.5.  TLS also allows other messages to be sent after the main handshake. These messages use a handshake content type and are encrypted under the application traffic key. <del> 4.5.1. </del>  At any time after the server has received the client Finished message, it MAY send a NewSessionTicket message.  This message max_early_data_size bytes of 0-RTT data SHOULD terminate the connection with an "unexpected_message" alert. <del> 4.5.2. </del>  The server is permitted to request client authentication at any time after the handshake has completed by sending a CertificateRequest certificate_request_context value allows the server to disambiguate the responses). <del> 4.5.3. </del>  %%% Updating Keys any more messages on this connection.  Any data received after a closure MUST be ignored. <del> This alert is sent by the client to indicate that all 0-RTT application_data messages have been transmitted (or none will be sent at all) and that the following records are protected under handshake traffic keys.  This alert MUST be at the warning level. Servers MUST NOT send this alert and clients receiving it MUST terminate the connection with an "unexpected_message" alert. </del> This alert notifies the recipient that the sender is canceling the handshake for some reason unrelated to a protocol failure.  If a user cancels an operation after the handshake is complete, just TLS Alert Registry: Future values are allocated via Standards Action RFC5226.  IANA [SHALL update/has updated] this registry to <del> include values for "end_of_early_data", "missing_extension", and "certificate_required". </del>  TLS HandshakeType Registry: Future values are allocated via Standards Action RFC5226.  IANA [SHALL update/has updated] this registry to rename item 4 from "NewSessionTicket" to "new_session_ticket" and to add the "hello_retry_request", <del> "encrypted_extensions", and "key_update" values. </del>  This document also uses a registry originally created in RFC4366. IANA has updated it to reference this document.  The registry and its

key changes happen at Handshake boundaries. Suggested by David Benjamin
I have one here, that could be a start: URL Also this is assuming PR URL is accepted ( becomes a message)
Merged.

Consolidate "ticket_early_data_info" and "early_data" into a single extension (*). <ins> Change end_of_early_data to be a handshake message (*). </ins> Remove spurious requirement to implement "pre_shared_key". Clarify location of "early_data" from server (it goes in EE, as as their corresponding messages sent in other flights (handshake, application_data, and alert respectively) but are protected under different keys.  After receiving the server's Finished message, if  <ins> the server has accepted early data, an EndOfEarlyData message will be sent to indicate the key change.  This message will be encrypted with the 0-RTT traffic keys. </ins> A server which receives an "early_data" extension can behave in one of three ways: 4.2.8.2. Clients are permitted to "stream" 0-RTT data until they receive the  <ins> server's Finished, only then sending the EndOfEarlyData message.  In order to avoid deadlock, when accepting "early_data", servers MUST </ins> process the client's ClientHello and then immediately send the  <ins> ServerHello, rather than waiting for the client's EndOfEarlyData message. </ins> 4.2.8.3. 4.5. <ins> %%% Updating Keys The EndOfEarlyData message is sent by the client to indicate that all 0-RTT application_data messages have been transmitted (or none will be sent at all) and that the following records are protected under handshake traffic keys.  Servers MUST NOT send this message and clients receiving it MUST terminate the connection with an "unexpected_message" alert. 4.6. </ins> TLS also allows other messages to be sent after the main handshake. These messages use a handshake content type and are encrypted under the application traffic key.  <ins> 4.6.1. </ins> At any time after the server has received the client Finished message, it MAY send a NewSessionTicket message.  This message max_early_data_size bytes of 0-RTT data SHOULD terminate the connection with an "unexpected_message" alert.  <ins> 4.6.2. </ins> The server is permitted to request client authentication at any time after the handshake has completed by sending a CertificateRequest certificate_request_context value allows the server to disambiguate the responses).  <ins> 4.6.3. </ins> %%% Updating Keys any more messages on this connection.  Any data received after a closure MUST be ignored.  This alert notifies the recipient that the sender is canceling the handshake for some reason unrelated to a protocol failure.  If a user cancels an operation after the handshake is complete, just TLS Alert Registry: Future values are allocated via Standards Action RFC5226.  IANA [SHALL update/has updated] this registry to  <ins> include values for "missing_extension" and "certificate_required". </ins> TLS HandshakeType Registry: Future values are allocated via Standards Action RFC5226.  IANA [SHALL update/has updated] this registry to rename item 4 from "NewSessionTicket" to "new_session_ticket" and to add the "hello_retry_request",  <ins> "encrypted_extensions", "end_of_early_data", and "key_update" values. </ins> This document also uses a registry originally created in RFC4366. IANA has updated it to reference this document.  The registry and its


order of client preference.  If the list contains cipher suites the server does not recognize, support, or wish to use, the server MUST ignore those cipher suites, and process the remaining ones as <del> usual.  Values are defined in cipher-suites. </del>  Versions of TLS before 1.3 supported compression with the list of supported compression methods being sent in this field.  For every 4.2.6. <del> The "pre_shared_key" extension is used to indicate the identity of the pre-shared key to be used with a given handshake in association with PSK key establishment. The "extension_data" field of this extension contains a "PreSharedKeyExtension" value: %%% Key Exchange Messages A label for a key.  For instance, a ticket defined in ticket- establishment, or a label for a pre-shared key established externally. For each ticket, the time since the client learned about the server configuration that it is using, in milliseconds.  This value is added modulo 2^32 to with the "ticket_age_add" value that was included with the ticket, see NewSessionTicket.  This addition prevents passive observers from correlating sessions unless tickets are reused.  Note: because ticket lifetimes are restricted to a week, 32 bits is enough to represent any plausible age, even in milliseconds.  For identities established externally an obfuscated_ticket_age of 0 SHOULD be used, and servers MUST ignore the value. A list of the identities that the client is willing to negotiate with the server.  If sent alongside the "early_data" extension (see early-data-indication), the first identity is the one used for 0-RTT data. A series of HMAC values, one for each PSK offered in the "pre_shared_keys" extension and in the same order, computed as described below. The server's chosen identity expressed as a (0-based) index into the identities in the client's list. Each PSK is associated with a single Hash algorithm.  For PSKs established via the ticket mechanism (NewSessionTicket), this is the Hash used for the KDF.  For externally established PSKs, the Hash algorithm MUST be set when the PSK is established. Prior to accepting PSK key establishment, the server MUST validate the corresponding binder value (see psk-binder below).  If this value is not present or does not validate, the server MUST abort the handshake.  Servers SHOULD NOT attempt to validate multiple binders; rather they SHOULD select a single PSK and validate solely the binder that corresponds to that PSK.  In order to accept PSK key establishment, the server sends a "pre_shared_key" extension indicating the selected identity. Clients MUST verify that the server's selected_identity is within the range supplied by the client, that the server selected the cipher suite associated with the PSK, and that the "key_share", and "signature_algorithms" extensions are consistent with the indicated ke_modes and auth_modes values.  If these values are not consistent, the client MUST abort the handshake with an "illegal_parameter" alert. If the server supplies an "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. This extension MUST be the last extension in the ClientHello (this facilitates implementation as described below).  Servers MUST check that it is the last extension and otherwise fail the handshake with an "illegal_parameter" alert. 4.2.6.1. The PSK binder value forms a binding between a PSK and the current handshake, as well as between the session where the PSK was established (if via a NewSessionTicket message) and the session where it was used.  Each entry in the binders list is computed as an HMAC over the portion of the ClientHello up to and including the PreSharedKeyExtension.identities field.  That is, it includes all of the ClientHello but not the binder list itself.  The length fields for the message (including the overall length, the length of the extensions block, and the length of the "pre_shared_key" extension) are all set as if the binder were present. The binding_value is computed in the same way as the Finished message (finished) but with the BaseKey being the binder_key (see key- schedule). If the handshake includes a HelloRetryRequest, the initial ClientHello and HelloRetryRequest are included in the transcript along with the new ClientHello.  For instance, if the client sends ClientHello1, its binder will be computed over: If the server responds with HelloRetryRequest, and the client then sends ClientHello2, its binder will be computed over: The full ClientHello is included in all other handshake hash computations. 4.2.7. </del> In order to use PSKs, clients MUST also send a "psk_key_exchange_modes" extension.  The semantics of this extension are that the client only supports the use of PSKs with these modes, PSK with (EC)DHE key establishment.  In this mode, the client and servers MUST supply "key_share" values as described in key-share. <del> 4.2.8. </del>  When a PSK is used, the client can send application data in its first flight of messages.  If the client opts to do so, it MUST supply an Similarly, if early data assumes anything about the connection state, it might be sent in error after the handshake completes.  4.2.8.1.  Clients are permitted to "stream" 0-RTT data until they receive the server's Finished, only then sending the "end_of_early_data" alert. In order to avoid deadlock, when accepting "early_data", servers MUST ServerHello, rather than waiting for the client's "end_of_early_data" alert. <del> 4.2.8.2. </del>  As noted in zero-rtt-data, TLS provides a limited mechanism for replay protection for data sent by the client in the first flight. %%% Record Layer <del> The cleartext of TLSPlaintext.fragment. </del>  The content type of the record. secrets and the handshake transcript.  Note that because the handshake transcript includes the random values in the Hello messages, any given handshake will have different traffic secrets, <del> even if the same input secrets are used, as is the case when +the same PSK is used for multiple connections </del>  7.1.

This is how NSS behaves as well. This seems like a reasonable argument.
added the changes previously discussed.
I did not verify that the moved text is only move and no edits, but the other chunks seem okay.
NAME are you OK with this SHOULD?
Sounds reasonable. Mostly I just don't want to encourage servers to enforce anything about this.

order of client preference.  If the list contains cipher suites the server does not recognize, support, or wish to use, the server MUST ignore those cipher suites, and process the remaining ones as  <ins> usual.  Values are defined in cipher-suites.  If the client is attempting a PSK key establishment, it SHOULD advertise at least one cipher suite containing a Hash associated with the PSK. </ins> Versions of TLS before 1.3 supported compression with the list of supported compression methods being sent in this field.  For every 4.2.6.  In order to use PSKs, clients MUST also send a "psk_key_exchange_modes" extension.  The semantics of this extension are that the client only supports the use of PSKs with these modes, PSK with (EC)DHE key establishment.  In this mode, the client and servers MUST supply "key_share" values as described in key-share.  <ins> 4.2.7. </ins> When a PSK is used, the client can send application data in its first flight of messages.  If the client opts to do so, it MUST supply an Similarly, if early data assumes anything about the connection state, it might be sent in error after the handshake completes. <ins> 4.2.8. The "pre_shared_key" extension is used to indicate the identity of the pre-shared key to be used with a given handshake in association with PSK key establishment. The "extension_data" field of this extension contains a "PreSharedKeyExtension" value: %%% Key Exchange Messages A label for a key.  For instance, a ticket defined in ticket- establishment, or a label for a pre-shared key established externally. For each ticket, the time since the client learned about the server configuration that it is using, in milliseconds.  This value is added modulo 2^32 to with the "ticket_age_add" value that was included with the ticket, see NewSessionTicket.  This addition prevents passive observers from correlating sessions unless tickets are reused.  Note: because ticket lifetimes are restricted to a week, 32 bits is enough to represent any plausible age, even in milliseconds.  For identities established externally an obfuscated_ticket_age of 0 SHOULD be used, and servers MUST ignore the value. A list of the identities that the client is willing to negotiate with the server.  If sent alongside the "early_data" extension (see early-data-indication), the first identity is the one used for 0-RTT data. A series of HMAC values, one for each PSK offered in the "pre_shared_keys" extension and in the same order, computed as described below. The server's chosen identity expressed as a (0-based) index into the identities in the client's list. Each PSK is associated with a single Hash algorithm.  For PSKs established via the ticket mechanism (NewSessionTicket), this is the Hash used for the KDF.  For externally established PSKs, the Hash algorithm MUST be set when the PSK is established. Prior to accepting PSK key establishment, the server MUST validate the corresponding binder value (see psk-binder below).  If this value is not present or does not validate, the server MUST abort the handshake.  Servers SHOULD NOT attempt to validate multiple binders; rather they SHOULD select a single PSK and validate solely the binder that corresponds to that PSK.  In order to accept PSK key establishment, the server sends a "pre_shared_key" extension indicating the selected identity. Clients MUST verify that the server's selected_identity is within the range supplied by the client, that the server selected a cipher suite containing a Hash associated with the PSK, and that the "key_share", and "signature_algorithms" extensions are consistent with the indicated ke_modes and auth_modes values.  If these values are not consistent, the client MUST abort the handshake with an "illegal_parameter" alert. If the server supplies an "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. This extension MUST be the last extension in the ClientHello (this facilitates implementation as described below).  Servers MUST check that it is the last extension and otherwise fail the handshake with an "illegal_parameter" alert. </ins> 4.2.8.1. <ins> The PSK binder value forms a binding between a PSK and the current handshake, as well as between the session where the PSK was established (if via a NewSessionTicket message) and the session where it was used.  Each entry in the binders list is computed as an HMAC over the portion of the ClientHello up to and including the PreSharedKeyExtension.identities field.  That is, it includes all of the ClientHello but not the binder list itself.  The length fields for the message (including the overall length, the length of the extensions block, and the length of the "pre_shared_key" extension) are all set as if the binder were present. The binding_value is computed in the same way as the Finished message (finished) but with the BaseKey being the binder_key (see key- schedule). If the handshake includes a HelloRetryRequest, the initial ClientHello and HelloRetryRequest are included in the transcript along with the new ClientHello.  For instance, if the client sends ClientHello1, its binder will be computed over: If the server responds with HelloRetryRequest, and the client then sends ClientHello2, its binder will be computed over: The full ClientHello is included in all other handshake hash computations. 4.2.8.2. </ins> Clients are permitted to "stream" 0-RTT data until they receive the server's Finished, only then sending the "end_of_early_data" alert. In order to avoid deadlock, when accepting "early_data", servers MUST ServerHello, rather than waiting for the client's "end_of_early_data" alert.  <ins> 4.2.8.3. </ins> As noted in zero-rtt-data, TLS provides a limited mechanism for replay protection for data sent by the client in the first flight. %%% Record Layer  <ins> The byte encoding of a handshake or an alert message, or the the raw bytes of the application's data to send. </ins> The content type of the record. secrets and the handshake transcript.  Note that because the handshake transcript includes the random values in the Hello messages, any given handshake will have different traffic secrets,  <ins> even if the same input secrets are used, as is the case when the same PSK is used for multiple connections </ins> 7.1.


RFC5705 defines keying material exporters for TLS in terms of the TLS pseudorandom function (PRF).  This document replaces the PRF with HKDF, thus requiring a new construction.  The exporter interface <del> remains the same.  If context is provided, the value is computed as: </del>  Where Secret is either the early_exporter_secret or the exporter_secret.  Implementations MUST use the exporter_secret unless <del> explicitly specified by the application.  When adding TLS 1.3 to TLS 1.2 stacks, the exporter_secret MUST be for the existing exporter interface. If no context is provided, the value is computed as above but with a zero-length context_value.  Note that providing no context computes the same value as providing an empty context.  As of this document's publication, no allocated exporter label is used with both modes. Future specifications MUST NOT provide an empty context and no context with the same label and SHOULD provide a context, possibly empty, in all exporter computations. </del>  8.

I found the wording a little hard to follow. This also by being very explicit about the presence of the change.
This changeset includes some "URL" cruft that isn't part of a reword.
In previous versions of TLS, passing no context was different to passing an empty context. TLS 1.3 doesn't distinguish between these. I don't know how important it is to highlight that minor difference, but it's probably worth mentioning.
So I should read more carefully: there is text about this, but it's not clear that this is a change from previous versions.

RFC5705 defines keying material exporters for TLS in terms of the TLS pseudorandom function (PRF).  This document replaces the PRF with HKDF, thus requiring a new construction.  The exporter interface  <ins> remains the same. The exporter value is computed as: </ins> Where Secret is either the early_exporter_secret or the exporter_secret.  Implementations MUST use the exporter_secret unless  <ins> explicitly specified by the application.  A separate interface for the early exporter is RECOMMENDED, especially on a server where a single interface can make the early exporter inaccessible. If no context is provided, the context_value is zero-length. Consequently, providing no context computes the same value as providing an empty context.  This is a change from previous versions of TLS where an empty context produced a different output to an absent context.  As of this document's publication, no allocated exporter label is used both with and without a context.  Future specifications MUST NOT define a use of exporters that permit both an empty context and no context with the same label.  New uses of exporters SHOULD provide a context in all exporter computations, though the value could be empty. </ins> 8.


The server processes the ClientHello and determines the appropriate cryptographic parameters for the connection.  It then responds with <del> its own ServerHello, which indicates the negotiated connection parameters. [server-hello].  The combination of the ClientHello and the ServerHello determines the shared keys.  If (EC)DHE key establishment is in use, then the ServerHello contains a "key_share" extension with the server's ephemeral Diffie-Hellman share which MUST be in the same group as one of the client's shares.  If PSK key establishment is in use, then the ServerHello contains a "pre_shared_key" extension indicating which of the client's offered PSKs was selected.  Note that implementations can use (EC)DHE and PSK together, in which case both extensions will be supplied. </del>  The server then sends two messages to establish the Server Parameters: to continue. Sent by a server in response to an invalid connection retry <del> attempt from a client. (see [RFC7507]) </del>  Sent by endpoints that receive a hello message not containing an extension that is mandatory to send for the offered TLS version or

Most of these are simple enough, kramdown treats all bracketed text as a reference. So these can be replaced with and the warnings go away. The biggest change here is slightly stylistic: a few places had , which kramdown complained about, but rendered correctly. However, this produced a non-sentence. Also, I fixed some inconsistent use of references and s/data/date in one of the references.
See comment

The server processes the ClientHello and determines the appropriate cryptographic parameters for the connection.  It then responds with  <ins> its own ServerHello (server-hello), which indicates the negotiated connection parameters.  The combination of the ClientHello and the ServerHello determines the shared keys.  If (EC)DHE key establishment is in use, then the ServerHello contains a "key_share" extension with the server's ephemeral Diffie-Hellman share which MUST be in the same group as one of the client's shares.  If PSK key establishment is in use, then the ServerHello contains a "pre_shared_key" extension indicating which of the client's offered PSKs was selected.  Note that implementations can use (EC)DHE and PSK together, in which case both extensions will be supplied. </ins> The server then sends two messages to establish the Server Parameters: to continue. Sent by a server in response to an invalid connection retry  <ins> attempt from a client RFC7507. </ins> Sent by endpoints that receive a hello message not containing an extension that is mandatory to send for the offered TLS version or


The algorithm field specifies the signature algorithm used (see signature-algorithms for the definition of this field).  The <del> signature is a digital signature using that algorithm that covers the hash output described in authentication-messages namely: </del>  <del> In TLS 1.3, the digital signature process takes as input: A signing key A context string The actual content to be signed The digital signature is then computed using the signing key over the concatenation of: </del>  A string that consists of octet 32 (0x20) repeated 64 times CertificateVerify". For example, if Hash(Handshake Context + Certificate) was 32 bytes of <del> 01 (this length would make sense for SHA-256), the input to the final signing process for a server CertificateVerify would be: </del>  <del> If sent by a server, the signature algorithm MUST be one offered in the client's "signature_algorithms" extension unless no valid certificate chain can be produced without unsupported algorithms (see signature-algorithms). </del>  If sent by a client, the signature algorithm used in the signature MUST be one of those present in the supported_signature_algorithms algorithms in this specification are defined solely for use in legacy certificates, and are not valid for CertificateVerify signatures.  Note: When used with non-certificate-based handshakes (e.g., PSK), the client's signature does not cover the server's certificate directly.  When the PSK was established through a NewSessionTicket, and of the computed keys. Recipients of Finished messages MUST verify that the contents are <del> correct.  Once a side has sent its Finished message and received and validated the Finished message from its peer, it may begin to send and receive application data over the connection.  Early data may be sent prior to the receipt of the peer's Finished message, per early- data-indication. </del>  The key used to compute the finished message is computed from the Base key defined in authentication-messages using HKDF (see key-

The client should be required to verify the CertificateVerify message. In addition I prefer to specify the alert type in case the verification fails (also for the Finished).
NAME can you please rebase this?
I tried my best to rebase the PR. Not sure though I did it the right way. NAME can you provide feedback?
I don't think it looks like the desired rebase. IIRC you have to use command-line git to do this rebase, and the workflow is something like: which assumes that origin is URL and the 'github' remote is your personal github fork; modify accordingly. I am not sure if there will be any rebase conflicts that need to be resolved (there may not be, since you just have merge commits for changes you want to rebase past), but if not, there should be some documentation online for generic git conflict resolution scenarios.
Ok, so some homework for me to do. :)
Hopefully the PR now looks better. Sorry for my missing git experience. :)
Yes, the commit structure is as desired, now. (No comment on the actual contents, yet, though ;) )
Probably worth saying, but I agree with MT that there's room for more detail about what exactly is verified, how it relates to the immediately prior Certificate message, how the x509 certificates therein are bound to any SNI in the handshake, etc.
btw, NAME pointed to me that was more ambiguous about this: I find that weird, but I'm happy that TLS 1.3 would change that to a MUST.
Some things need to be sorted out first. IMO there are several validations regarding the certficate: validation of the identity provided in the certificate. On the client side his can be a consistency check against the SNI, if provided by the application, but it can be something else as well (e.g. externally received fingerprint of the certificate). I believe it depends too much on the use case to turn this validation into a MUST. validation of the certificate's structure. This is out of scope of TLS, see section 4.4.1.4. verification that the sender possesses the private key. Here I agree this should be a MUST, and that is addressed by this PR.
The text in the PR could be a little more clear that that is what is being validated.
I just updated the PR and provided more details for the verification process (which required some restructuring of the CertificateVerify section).
NAME please provide a PR to add yourself to the contributors list.
A separate PR has been created (URL) to extend the distribution list.

The algorithm field specifies the signature algorithm used (see signature-algorithms for the definition of this field).  The  <ins> signature is a digital signature using that algorithm.  The content to be signed is the hash output as described in authentication- messages namely: </ins>  <ins> The digital signature is then computed over the concatenation of: </ins> A string that consists of octet 32 (0x20) repeated 64 times CertificateVerify". For example, if Hash(Handshake Context + Certificate) was 32 bytes of  <ins> 01 (this length would make sense for SHA-256), the content covered by the digital signature for a server CertificateVerify would be: </ins>  <ins> On the sender side the process for computing 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 a server, the signature algorithm MUST be one offered in the client's "signature_algorithms" extension unless no valid certificate chain can be produced without unsupported algorithms (see signature-algorithms). </ins> If sent by a client, the signature algorithm used in the signature MUST be one of those present in the supported_signature_algorithms algorithms in this specification are defined solely for use in legacy certificates, and are not valid for CertificateVerify signatures. <ins> The receiver of a CertificateVerify MUST verify the signature field. The verification process takes as input: The content covered by the digital signature The public key received with the previous Certificate message The digital signature received in the signature field of the CertificateVerify message If the verification fails, the connection MUST be terminated with an "illegal_parameter" alert. </ins> Note: When used with non-certificate-based handshakes (e.g., PSK), the client's signature does not cover the server's certificate directly.  When the PSK was established through a NewSessionTicket, and of the computed keys. Recipients of Finished messages MUST verify that the contents are  <ins> correct.  If the verification fails, the connection MUST be terminated with an "illegal_parameter" alert. Once a side has sent its Finished message and received and validated the Finished message from its peer, it may begin to send and receive application data over the connection.  Early data may be sent prior to the receipt of the peer's Finished message, per early-data- indication. </ins> The key used to compute the finished message is computed from the Base key defined in authentication-messages using HKDF (see key-


A list of offered KeyShareEntry values in descending order of client preference.  This vector MAY be empty if the client is <del> requesting a HelloRetryRequest.  The ordering of values here SHOULD match that of the ordering of offered support in the "supported_groups" extension. </del>  The mutually supported group the server intends to negotiate and is requesting a retried ClientHello/KeyShare for.

This is a redo of PR now that PR has removed the appending rule and resolved issue .

A list of offered KeyShareEntry values in descending order of client preference.  This vector MAY be empty if the client is  <ins> requesting a HelloRetryRequest.  Each KeyShareEntry value MUST correspond to a group offered in the "supported_groups" extension and MUST appear in the same order.  However, the values MAY be a non-contiguous subset of the "supported_groups" extension and MAY omit the most preferred groups. </ins> The mutually supported group the server intends to negotiate and is requesting a retried ClientHello/KeyShare for.


PSK (a pre-shared key established externally or a resumption_master_secret value from a previous connection) <del> (EC)DHE shared secret </del>  This produces a full key derivation schedule shown in the diagram below.  In this diagram, the following formatting conventions apply: Secret changes (e.g., when changing from the handshake to application data keys or upon a key update). <del> 7.3.1. </del>  <del> A conventional Diffie-Hellman computation is performed.  The negotiated key (Z) is converted to byte string by encoding in big- endian, padded with zeros up to the size of the prime.  This byte string is used as the shared secret, and is used in the key schedule as specified above. </del>  Note that this construction differs from previous versions of TLS which remove leading zeros. <del> 7.3.2. </del>  For secp256r1, secp384r1 and secp521r1, ECDH calculations (including parameter and key generation as well as the shared secret For X25519 and X448, see RFC7748. <del> 7.3.3. </del>  RFC5705 defines keying material exporters for TLS in terms of the TLS pseudorandom function (PRF).  This document replaces the PRF with

Exporters and (EC)DHE secrets are not traffic secrets. Group the two (EC)DHE sections under a name which matches what the key schedule section calls it (the "(EC)DHE shared secret") and link to it from the key schedule.

PSK (a pre-shared key established externally or a resumption_master_secret value from a previous connection)  <ins> (EC)DHE shared secret (ecdhe-shared-secret-calculation) </ins> This produces a full key derivation schedule shown in the diagram below.  In this diagram, the following formatting conventions apply: Secret changes (e.g., when changing from the handshake to application data keys or upon a key update).  <ins> 7.4. </ins>  <ins> 7.4.1. For finite field groups, a conventional Diffie-Hellman computation is performed.  The negotiated key (Z) is converted to byte string by encoding in big-endian, padded with zeros up to the size of the prime.  This byte string is used as the shared secret, and is used in the key schedule as specified above. </ins> Note that this construction differs from previous versions of TLS which remove leading zeros.  <ins> 7.4.2. </ins> For secp256r1, secp384r1 and secp521r1, ECDH calculations (including parameter and key generation as well as the shared secret For X25519 and X448, see RFC7748.  <ins> 7.5. </ins> RFC5705 defines keying material exporters for TLS in terms of the TLS pseudorandom function (PRF).  This document replaces the PRF with


the server to allow the server to decline resumption and fall back to a full handshake, if needed.  The server responds with a "pre_shared_key" extension to negotiate use of PSK key establishment <del> and can (as shown here) to negotiate use of PSK key establishment and can (as shown here) respond with a "key_share" extension to do </del>  (EC)DHE key establishment, thus providing forward secrecy. When PSKs are provisioned out of band, the PSK identity and the KDF The Server Name Indication (SNI), if any is to be used <del> As shown in tls-0-rtt, the Zero-RTT data is just added to the 1-RTT </del>  handshake in the first flight.  The rest of the handshake uses the same messages as with a 1-RTT handshake with PSK resumption. the elements of the enumerated are not ordered, they can be assigned any unique value, in any order. <del> Future extension or additions to the protocol may define new values. </del>  Implementations need to be able to parse and ignore unknown values unless the definition of the field states otherwise. extensions which are required to establish the cryptographic context.  Currently the only such extensions are "key_share" and "pre_shared_key".  All current TLS 1.3 ServerHello messages will <del> contain one of these two extensions. </del>  TLS 1.3 has a downgrade protection mechanism embedded in the server's random value.  TLS 1.3 servers which negotiate TLS 1.2 or below in

Reading through the spec again I found a few tiny things to fix. I'm suggesting to replace "Zero-RTT" with "0-RTT" in the paragraph because I found "Zero-RTT" used only in headlines, but "0-RTT" consistently in paragraphs.
NAME Please provide a PR to add yourself to acknowledgements.

the server to allow the server to decline resumption and fall back to a full handshake, if needed.  The server responds with a "pre_shared_key" extension to negotiate use of PSK key establishment  <ins> and can (as shown here) respond with a "key_share" extension to do </ins> (EC)DHE key establishment, thus providing forward secrecy. When PSKs are provisioned out of band, the PSK identity and the KDF The Server Name Indication (SNI), if any is to be used  <ins> As shown in tls-0-rtt, the 0-RTT data is just added to the 1-RTT </ins> handshake in the first flight.  The rest of the handshake uses the same messages as with a 1-RTT handshake with PSK resumption. the elements of the enumerated are not ordered, they can be assigned any unique value, in any order.  <ins> Future extensions or additions to the protocol may define new values. </ins> Implementations need to be able to parse and ignore unknown values unless the definition of the field states otherwise. extensions which are required to establish the cryptographic context.  Currently the only such extensions are "key_share" and "pre_shared_key".  All current TLS 1.3 ServerHello messages will  <ins> contain one of these two extensions, or both when using a PSK with (EC)DHE key establishment. </ins> TLS 1.3 has a downgrade protection mechanism embedded in the server's random value.  TLS 1.3 servers which negotiate TLS 1.2 or below in


This structure is intended to prevent an attack on previous versions of TLS in which the ServerKeyExchange format meant that attackers <del> could obtain a signature of a message with a chosen, 32-byte prefix. The initial 64 byte pad clears that prefix. </del>  The context string for a server signature is "TLS 1.3, server CertificateVerify" and for a client signature is "TLS 1.3, client <del> CertificateVerify". </del>  For example, if Hash(Handshake Context + Certificate) was 32 bytes of 01 (this length would make sense for SHA-256), the content covered by

minor additions, the context string wasn't explained anywhere as well so I thought a mini-line would help.

This structure is intended to prevent an attack on previous versions of TLS in which the ServerKeyExchange format meant that attackers  <ins> could obtain a signature of a message with a chosen 32-byte prefix (ClientHello.random).  The initial 64 byte pad clears that prefix. </ins> The context string for a server signature is "TLS 1.3, server CertificateVerify" and for a client signature is "TLS 1.3, client  <ins> CertificateVerify".  It is used to provide separation between signatures made in different contexts, helping against potential cross-protocol attacks. </ins> For example, if Hash(Handshake Context + Certificate) was 32 bytes of 01 (this length would make sense for SHA-256), the content covered by


4.1.3. The server will send this message in response to a ClientHello <del> message when it was able to find an acceptable set of algorithms and the client's "key_share" extension was acceptable.  If it is not able to find an acceptable set of parameters, the server will respond with a "handshake_failure" fatal alert. </del>  Structure of this message: 4.1.4. <del> Servers send this message in response to a ClientHello message if they were able to find an acceptable set of algorithms and groups that are mutually supported, but the client's ClientHello did not contain sufficient information to proceed with the handshake.  If a server cannot successfully select algorithms and groups, it MUST abort the handshake with a "handshake_failure" alert. </del>  Structure of this message:

This is a giant pile of nitpicks, loosely inspired by the FFDHE alert discussion. The old text specifies a handshakefailure which is redundant with and contradicts the Cryptographic Negotiation section. The old text says only handshakefailure is allowed while Cryptographic Negotiation allows both handshakefailure and insufficientsecurity. Fix this by avoiding redundancy as the failure cases are global to the overall negotiation algorithm. Next, align the tense with itself and the rest of the text. Most of the text appears to be written in present tense. The old text for SH said: The server will send [...] when it was able to [...] which is a little odd. Also align the wording between the two. Talk about a server (singular) to match Cryptographic Negotiation and say "parameters" rather than "algorithms" or "algorithms and groups". Also be consistent about the SH vs. HRR condition. The SH section said "the client’s key_share extension was acceptable" while the HRR section said "the client’s ClientHello did not contain sufficient information to proceed with the handshake". Use the more general one.
Seems reasonable. I a little bit wondered whether to replace "it" with "the server", but the pronoun's meaning should be clear, here.
Seems clear enough to me, but I'm equally happy with the other wording. shrug
This does seem clearer. And shorter!

4.1.3. The server will send this message in response to a ClientHello  <ins> message if it is able to find an acceptable set of parameters and the ClientHello contains sufficient information to proceed with the handshake. </ins> Structure of this message: 4.1.4.  <ins> The server will send this message in response to a ClientHello message if it is able to find an acceptable set of parameters but the ClientHello does not contain sufficient information to proceed with the handshake. </ins> Structure of this message:


data in the extensions field.  The actual "Extension" format is defined in extensions.  In TLS 1.3, use of certain extensions is mandatory, as functionality is moved into extensions to preserve <del> ClientHello compatibility with previous versions of TLS. </del>  In the event that a client requests additional functionality using extensions, and this functionality is not supplied by the server, the An optional set of extensions describing the parameters of the certificate being requested.  The "signature_algorithms" extension <del> MUST be specified. </del>  In prior versions of TLS, the CertificateRequest message carried a list of signature algorithms and certificate authorities which the

Per the recent thread. I could have sworn this was in here, but can't find it... The NewSessionTicket section explicitly says to ignore unknown extensions, so I've added the analogous text to ClientHello and CertificateRequest.

data in the extensions field.  The actual "Extension" format is defined in extensions.  In TLS 1.3, use of certain extensions is mandatory, as functionality is moved into extensions to preserve  <ins> ClientHello compatibility with previous versions of TLS.  Servers MUST ignore unrecognized extensions. </ins> In the event that a client requests additional functionality using extensions, and this functionality is not supplied by the server, the An optional set of extensions describing the parameters of the certificate being requested.  The "signature_algorithms" extension  <ins> MUST be specified.  Clients MUST ignore unrecognized extensions. </ins> In prior versions of TLS, the CertificateRequest message carried a list of signature algorithms and certificate authorities which the


exporters SHOULD provide a context in all exporter computations, though the value could be empty.  8. 8.1.

Add reference to label format in 5705. address issue
refer the reader to exporter requirements in RFC 5705 "Requirements for the format of Exporter labels are defined in section 4 of RFC5705." Creating pull request.
NAME should we expect a PR?
This appears to be done.
yes I submitted PR which has been merged already.

exporters SHOULD provide a context in all exporter computations, though the value could be empty. <ins> Requirements for the format of exporter labels are defined in section 4 of RFC5705. </ins> 8. 8.1.


Change end_of_early_data to be a handshake message (*).  Remove spurious requirement to implement "pre_shared_key". Clarify location of "early_data" from server (it goes in EE, as

benefits: (1) Restoring extract/expand parity, thus cleaning up the theoretical treatment wrt HKDF and future replacements. (2) Futureproofing against someone being able to force the ECDHE value in the second HKDF-Extract to collide with one of the labels. This seems unlikely with current groups, but might be possible with some future algorithm. (Issue due to Trevor Perrin).
This is mostly a cosmetic thing, and I'm not sure if I actually like all of my proposals below: With the current scheme, the key schedule is very simple and neatly encompassed into a box with a shape like this: NewTLS13KeySchedule(hash) => creates a new schedule with base secret = 0 AddEntropy(sched, ikm) => HKDF-Extract ikm into the current base secret DeriveSecret(sched, label) => take the current base secret and handshake transcript and derive a particular secret with the label This breaks the symmetry in a few ways: Incorporating a new IKM requires an extra label for the Derive-Secret operation in the middle. Going from 0 to Early Secret does not involve a Derive-Secret. We use Derive-Secret, Derive-Secret no longer always uses the current state of the handshake transcript (1) could be resolved by just using the same label for both, like "prepare extract" or something. I don't believe this breaks anything? We're just trying to fix the problem where HKDF-Extract and HKDF-Expand can't be used on the same key. (3) is actually kind of odd because Derive-Secret is defined as: Derive-Secret(Secret, Label, Messages) = HKDF-Expand-Label(Secret, Label, Hash(Messages), Hash.Length) So we're actually putting Hash("") into HKDF-Expand-Label, not the empty string. Then again, it feels odd making them ClientHello...ServerHello and ClientHello...Server Finished, respectively. We could use HKDF-Expand-Label directly which still gives us the separation, but it's not as obvious. Adding an extra Derive-Secret just to fix (2) feels a little pointless but would increase symmetry. (Alternatively, the answer could just be "deal with it, your key schedule box should have slightly richer methods on it". Like I said, this is just cosmetic.)
I'm ambivalent on David's gripe. This seems fine to me. One editorial suggestion though. This is now a very tall diagram. You can save a few lines by changing to something like this
About this PR, there is a con: complicating the already complicated key schedule
It does not seem especially complicated compared to, e.g., Kerberos. Or maybe that's just me.
well, you're comparing it to Kerberos :rofl:
NAME I fixed . I think we can live without . We already have this "empty hash" construct for the binder keys, so while it's a bit goofy it's no more goofy than here.
We seem to have reached consensus that the record layer will use the AEAD form only. The stream and CBC forms will be removed.
Fixed.

Change end_of_early_data to be a handshake message (*). <ins> Add pre-extract Derive-Secret stages to key schedule (*). </ins> Remove spurious requirement to implement "pre_shared_key". Clarify location of "early_data" from server (it goes in EE, as


Defined structures may have variants based on some knowledge that is available within the environment.  The selector must be an enumerated <del> type that defines the possible variants the structure defines.  There must be a case arm for every element of the enumeration declared in the select.  Case arms have limited fall-through: if two case arms follow in immediate succession with no fields in between, then they both contain the same fields.  Thus, in the example below, "orange" and "banana" both contain V2.  Note that this piece of syntax was added in TLS 1.2 RFC5246.  Each case arm can have one or more fields. The body of the variant structure may be given a label for reference. </del>  The mechanism by which the variant is selected at runtime is not prescribed by the presentation language.

To let's add semi-colons to EarlyDataIndication. To make the presentation language simpler, let's remove fall-through which is not used in other places.
LGTM
One more thing: This is not true anymore. For instance does not cover all handshake types. How can we improve this explanation?
Hi folks. Sorry it took me so long to weigh in, but I'm not really excited about this set of changes. As far as I can tell, the primary impetus for this is the need to specify an empty value for a case. The simplest thing to do here is just to define struct {} Empty; and then put Empty; in the relevant case arms. It's not new syntax, it's just a new type definition. As for fallthrough, IMO it makes things easier to read. I'm happy to remove the requirement to cover all types, because that also makes things easier to read.
I think I had managed to squint enough that I could convince myself that only all values of the enum being used as a selector that are valid in the current context need to be enumerated. So, when talking about, e.g., KeyShare, it's okay to only list case arms for clienthello, helloretryrequest, and serverhello, since other handshake messages would not contain a KeyShare. But, maybe that requires too much squinting.
yeah NAME is right, KeyShare does list all the possible options relevant to KeyShare. But yeah the quote is hard to read. NAME I think it's a matter of what you're most used to read, but I find the PR easier to understand while defining a new struct {} Empty or having the fall through would be cumbersome in my opinion.
NAME I pushed three more commits. I hope that you like these.
I have removed the tag and comment.
NAME I think this PR is ready to be merged.
The current syntax of is broken because case arms must be terminated by . If we respect to TLS 1.2's syntax, I would suggest to change this into:
I think this is more confusing than the . The presentation language is not a formally specified syntax so I don't think it matters. I remember tripping while reading this part of the specs because of the two cases following each other, I would rather replace them by this:
I don't like the comment, I'd rather have a syntactic token there and I don't care what it is.
What about just removing the cases for and ?
Don't care. :) Just don't want comments to be semantically meaningful.
Removing the cases is wrong, as then it leaves unspecified a structure that needs to be sent in a wire protocol message.
is actually used to express empty in RFC 5246. Let's just define its semantics in Section 3. But I recommend most is to define :
Any other opinions on this? Possibilities I see: an field could be defined in the presentation language → but it's more text to the presentation language for few usages the text in the presentation language about cases that must cover all the cases could be relaxed → but now that I think more about it, it's nicer for the implementer to see all the cases in this snippet this could be defined → I don't like it so much, I think a more casual is actually clearer. This makes me thing we should probably drop this issue. PS: or if anyone else was tripped by this double cases (I know it's defined in the presentation language, but it's weird to see it since there are no breaks) we could also use this:
How about this? P.S. Fall through is not used in other parts.
It looks good to me, also if fall through is not used anywhere else it could be removed from the presentation language section.
"Fall-through" was added in TLS 1.2. We can copy-and-pase Section 4.6.1 of RFC 4346 to remove fall-through. If this is consensus, I will make a PR.
I've sent PR .

Defined structures may have variants based on some knowledge that is available within the environment.  The selector must be an enumerated  <ins> type that defines the possible variants the structure defines.  The body of the variant structure may be given a label for reference. </ins> The mechanism by which the variant is selected at runtime is not prescribed by the presentation language.


Note: For a given Diffie-Hellman group, the padding results in all public keys having the same length. <del> Peers SHOULD validate each other's public key Y by ensuring that 1 < Y < p-1.  This check ensures that the remote peer is properly behaved </del>  and isn't forcing the local system into a small subgroup. 4.2.5.2.

I wonder why this was only a before. Am I right to assume that this is because TLS 1.3 has removed support for static DH and leaking an ephemeral key is not considered to be a security problem?
Gotta say, I don't know why this was SHOULD. That check is very easy to implement.
says .
This text was adapted from some old draft of 7919 which had should and never got updated (see for instance: URL). Good catch.
NAME Please provide a PR adding yourself to contributors.

Note: For a given Diffie-Hellman group, the padding results in all public keys having the same length.  <ins> Peers MUST validate each other's public key Y by ensuring that 1 < Y < p-1.  This check ensures that the remote peer is properly behaved </ins> and isn't forcing the local system into a small subgroup. 4.2.5.2.


records, there MUST NOT be any other records between them. Handshake messages MUST NOT span key changes.  Because the <del> ServerHello, Finished, and KeyUpdate messages signal a key change, upon receiving these messages a receiver MUST verify that the end of these messages aligns with a record boundary; if not, then it MUST terminate the connection with an "unexpected_message" alert. </del>  Implementations MUST NOT send zero-length fragments of Handshake types, even if those fragments contain padding.

An EndOfEarlyData message signals a key change. A ClientHello can be the last message read before a key is changed, and it never makes sense for a ClientHello to have more data after it in the record.

records, there MUST NOT be any other records between them. Handshake messages MUST NOT span key changes.  Because the  <ins> ClientHello, EndOfEarlyData, ServerHello, Finished, and KeyUpdate messages can arrive immediately prior to a key change, upon receiving these messages a receiver MUST verify that the end of these messages aligns with a record boundary; if not, then it MUST terminate the connection with an "unexpected_message" alert. </ins> Implementations MUST NOT send zero-length fragments of Handshake types, even if those fragments contain padding.


%%% Key Exchange Messages <del> The server_version and extensions fields have the same meanings as their corresponding values in the ServerHello.  The server SHOULD send only the extensions necessary for the client to generate a correct ClientHello pair.  As with ServerHello, a HelloRetryRequest MUST NOT contain any extensions that were not first offered by the client in its ClientHello, with the exception of optionally the "cookie" (see cookie) extension. </del>  Upon receipt of a HelloRetryRequest, the client MUST verify that the extensions block is not empty and otherwise MUST abort the handshake key_share (see key-share)  4.2. A number of TLS messages contain tag-length-value encoded extensions KeyShareEntry for any group not indicated in the "supported_groups" extension and MUST NOT send a KeyShareEntry when using the "psk_ke" PskKeyExchangeMode.  If a HelloRetryRequest was received by the <del> client, the client MUST verify that the selected NamedGroup matches one that the client sent in its supported_groups extension and MUST abort the handshake with an "illegal_parameter" alert otherwise. </del>  4.2.5.1.

client to implement because it knows what hash the server will select. Also clarify the language about HRR and Key Shares.
NAME is this what you had in mind?
I did consider bogus binders, but dropping seems more sensible, and it seems like the only impact of the bogus binder would be that if the server didn't follow a consistent rule, then you would get a handshake failure at the server. It's not like it could pick them in any case.
(Agreed. This version feels way less weird.)
NAME comments welcome

%%% Key Exchange Messages  <ins> The version, cipher_suite, and extensions fields have the same meanings as their corresponding values in the ServerHello.  The server SHOULD send only the extensions necessary for the client to generate a correct ClientHello pair.  As with ServerHello, a HelloRetryRequest MUST NOT contain any extensions that were not first offered by the client in its ClientHello, with the exception of optionally the "cookie" (see cookie) extension. </ins> Upon receipt of a HelloRetryRequest, the client MUST verify that the extensions block is not empty and otherwise MUST abort the handshake key_share (see key-share) <ins> In addition, in its updated ClientHello, the client SHOULD NOT offer any pre-shared keys associated with a hash other than that of the selected cipher suite.  This allows the client to avoid having to compute partial hash transcripts for multiple hashes in the second ClientHello.  A client which receives a cipher suite that was not offered MUST abort the handshake.  Servers MUST ensure that they negotiate the same cipher suite when receiving a conformant updated ClientHello (if the server selects the cipher suite as the first step in the negotiation, then this will happen automatically).  Upon receiving the ServerHello, clients MUST check that the cipher suite supplied in the ServerHello is the same as that in the HelloRetryRequest and otherwise abort the handshake with an "illegal_parameter" alert. </ins> 4.2. A number of TLS messages contain tag-length-value encoded extensions KeyShareEntry for any group not indicated in the "supported_groups" extension and MUST NOT send a KeyShareEntry when using the "psk_ke" PskKeyExchangeMode.  If a HelloRetryRequest was received by the  <ins> client, the client MUST verify that the selected NamedGroup in the ServerHello is the same as that in the HelloRetryRequest.  If this check fails, the client MUST abort the handshake with an "illegal_parameter" alert. </ins> 4.2.5.1.


When (EC)DHE is in use, the server will also provide a "key_share" extension. <del> When authenticating via a certificate (i.e., when a PSK is not in use), the server will send the Certificate (certificate) and CertificateVerify (certificate-verify) messages. </del>  If the server is unable to negotiate a supported set of parameters (i.e., there is no overlap between the client and server parameters),

I think this addresses the issue raised by Russ Housley without changing the semantics of the protocol.
I will give a post-merge "seems fine", since I was so vocal in trying to nail down what Russ wanted.
Mentions of non-existent yet RFCs look weird to me but heh

When (EC)DHE is in use, the server will also provide a "key_share" extension.  <ins> When authenticating via a certificate, the server will send the Certificate (certificate) and CertificateVerify (certificate- verify) messages.  In TLS 1.3 as defined by this document, either a PSK or a certificate is always used, but not both.  Future documents may define how to use them together. </ins> If the server is unable to negotiate a supported set of parameters (i.e., there is no overlap between the client and server parameters),


types.  That is, if a handshake message is split over two or more records, there MUST NOT be any other records between them. <del> Handshake messages MUST NOT span key changes.  Because the </del>  ClientHello, EndOfEarlyData, ServerHello, Finished, and KeyUpdate <del> messages can arrive immediately prior to a key change, upon receiving these messages a receiver MUST verify that the end of these messages aligns with a record boundary; if not, then it MUST terminate the connection with an "unexpected_message" alert. </del>  Implementations MUST NOT send zero-length fragments of Handshake types, even if those fragments contain padding.

…appens rather than on receipt of handshake messages. It is only actually necessary to verify that a handshake message aligns with a key change when changing keys, not when receiving the message, and it can be simpler to implement the check in this way. This change requires senders to align all these messages with a record boundary as before, but only requires recipients to verify the record boundary when the key change actually happens.

types.  That is, if a handshake message is split over two or more records, there MUST NOT be any other records between them.  <ins> Handshake messages MUST NOT span key changes.  Implementations MUST verify that all messages immediately preceding a key change align with a record boundary; if not, then they MUST terminate the connection with an "unexpected_message" alert.  Because the </ins> ClientHello, EndOfEarlyData, ServerHello, Finished, and KeyUpdate  <ins> messages can immediately precede a key change, implementations MUST send these messages in alignment with a record boundary. </ins> Implementations MUST NOT send zero-length fragments of Handshake types, even if those fragments contain padding.


%%% Updating Keys <del> The EndOfEarlyData message is sent by the client to indicate that all 0-RTT application_data messages have been transmitted (or none will be sent at all) and that the following records are protected under </del>  handshake traffic keys.  Servers MUST NOT send this message and clients receiving it MUST terminate the connection with an "unexpected_message" alert.  This message is encrypted under keys

31f836238e5968a85c9e4d64d8ab23c0bbed8061 missed a spot.
NAME
:+1: Having a definition on when EOED must be sent is good for both interoperability and as a guildeline of how 0RTT support should be implemented.

%%% Updating Keys  <ins> If the server sent an "early_data" extension, the client MUST send an EndOfEarlyData after receiving the server Finished.  This indicates that all 0-RTT application_data messages, if any, have been transmitted and that the following records are protected under </ins> handshake traffic keys.  Servers MUST NOT send this message and clients receiving it MUST terminate the connection with an "unexpected_message" alert.  This message is encrypted under keys


%%% Key Exchange Messages <del> All versions of TLS allow extensions to optionally follow the compression_methods field as an extensions field.  TLS 1.3 ClientHellos will contain at least two extensions, "supported_versions" and either "key_share" or "pre_shared_key".  The presence of extensions can be detected by determining whether there are bytes following the compression_methods at the end of the ClientHello.  Note that this method of detecting optional data differs from the normal TLS method of having a variable-length field, but it is used for compatibility with TLS before extensions were defined.  TLS 1.3 servers will need to perform this check first and only attempt to negotiate TLS 1.3 if a "supported_version" extension is present. </del> In previous versions of TLS, this field was used for version negotiation and represented the highest version number supported by the client.  Experience has shown that many servers do not ClientHello compatibility with previous versions of TLS.  Servers MUST ignore unrecognized extensions.  In the event that a client requests additional functionality using extensions, and this functionality is not supplied by the server, the <del> client MAY abort the handshake.  Note that TLS 1.3 ClientHello messages always contain extensions (minimally they must contain "supported_versions" or they will be interpreted as TLS 1.2 ClientHello messages).  TLS 1.3 servers might receive ClientHello messages from versions of TLS prior to 1.3 that do not contain extensions.  If negotiating a version of TLS prior to 1.3, a server MUST check that the message either contains no data after legacy_compression_methods or that it contains a valid extensions block with no data following.  If not, then it MUST abort the handshake with a "decode_error" alert. </del>  After sending the ClientHello message, the client waits for a ServerHello or HelloRetryRequest message.

This tweaks some text in ClientHello with regard to handling the extensions field. The two blocks of text on it in this section are merged together, dropping a little repeated information and putting it in one paragraph after definition of the relevant field instead of covering this in two places in the same section.

%%% Key Exchange Messages  In previous versions of TLS, this field was used for version negotiation and represented the highest version number supported by the client.  Experience has shown that many servers do not ClientHello compatibility with previous versions of TLS.  Servers MUST ignore unrecognized extensions. <ins> All versions of TLS allow extensions to optionally follow the compression_methods field as an extensions field.  TLS 1.3 ClientHello messages always contain extensions (minimally, "supported_versions" or they will be interpreted as TLS 1.2 ClientHello messages), however TLS 1.3 servers might receive ClientHello messages without an extensions field from prior versions of TLS.  The presence of extensions can be detected by determining whether there are bytes following the compression_methods field at the end of the ClientHello.  Note that this method of detecting optional data differs from the normal TLS method of having a variable-length field, but it is used for compatibility with TLS before extensions were defined.  TLS 1.3 servers will need to perform this check first and only attempt to negotiate TLS 1.3 if a "supported_version" extension is present.  If negotiating a version of TLS prior to 1.3, a server MUST check that the message either contains no data after legacy_compression_methods or that it contains a valid extensions block with no data following.  If not, then it MUST abort the handshake with a "decode_error" alert. </ins> In the event that a client requests additional functionality using extensions, and this functionality is not supplied by the server, the  <ins> client MAY abort the handshake. </ins> After sending the ClientHello message, the client waits for a ServerHello or HelloRetryRequest message.


case of server authentication), this field SHALL be zero length. This is a sequence (chain) of CertificateEntry structures, each <del> containing a single certificate and set of extensions.  The sender's certificate MUST come in the first CertificateEntry in the list.  Each following certificate SHOULD directly certify one preceding it.  Because certificate validation requires that trust anchors be distributed independently, a certificate that specifies a trust anchor MAY be omitted from the chain, provided that supported peers are known to possess any omitted certificates. </del>  A set of extension values for the CertificateEntry.  The "Extension" format is defined in extensions.  Valid extensions applies to the entire chain, it SHOULD be included in the first CertificateEntry.  Note: Prior to TLS 1.3, "certificate_list" ordering required each certificate to certify the one immediately preceding it; however, some implementations allowed some flexibility.  Servers sometimes TLS version, with the exception of the end-entity certificate which MUST be first.  The server's certificate_list MUST always be non-empty.  A client will send an empty certificate_list if it does not have an appropriate certificate to send in response to the server's

Explicitly define RFC 7250 certificate support.
Seems reasonable. (I did not try to audit the rest of the text to see if there are other places that need updating.)
This captures what we talked about in Chicago.
Shucks, this hasn't landed yet, so I'll have to remember to update my editorial changes pull request that puts the numbers for these into the enumerated type definition for extensions.

case of server authentication), this field SHALL be zero length. This is a sequence (chain) of CertificateEntry structures, each  <ins> containing a single certificate and set of extensions. </ins> A set of extension values for the CertificateEntry.  The "Extension" format is defined in extensions.  Valid extensions applies to the entire chain, it SHOULD be included in the first CertificateEntry. <ins> If the corresponding certificate type extension ("server_certificate_type" or "client_certificate_type") was not used or the X.509 certificate type was negotiated, then each CertificateEntry contains an X.509 certificate.  The sender's certificate MUST come in the first CertificateEntry in the list. Each following certificate SHOULD directly certify one preceding it. Because certificate validation requires that trust anchors be distributed independently, a certificate that specifies a trust anchor MAY be omitted from the chain, provided that supported peers are known to possess any omitted certificates. </ins> Note: Prior to TLS 1.3, "certificate_list" ordering required each certificate to certify the one immediately preceding it; however, some implementations allowed some flexibility.  Servers sometimes TLS version, with the exception of the end-entity certificate which MUST be first. <ins> If the RawPublicKey certificate type was negotiated, then the certificate_list MUST contain no more than one CertificateEntry, which contains an ASN1_subjectPublicKeyInfo value as defined in RFC7250, Section 3. </ins> The server's certificate_list MUST always be non-empty.  A client will send an empty certificate_list if it does not have an appropriate certificate to send in response to the server's


establishment, or a label for a pre-shared key established externally. <del> For each ticket, the time since the client learned about the server configuration that it is using, in milliseconds.  This value is added modulo 2^32 to the "ticket_age_add" value that was included with the ticket, see NSTMessage.  This addition prevents passive observers from correlating connections unless tickets are reused.  Note: because ticket lifetimes are restricted to a week, 32 bits is enough to represent any plausible age, even in milliseconds.  For identities established externally an obfuscated_ticket_age of 0 SHOULD be used, and servers MUST ignore the value. </del>  A list of the identities that the client is willing to negotiate with the server.  If sent alongside the "early_data" extension 4.2.10.1.  The PSK binder value forms a binding between a PSK and the current handshake, as well as between the handshake in which the PSK was generated (if via a NewSessionTicket message) and the handshake where and then reinjected as a "handshake_hash" message, as described in the-transcript-hash. <del> 4.2.10.2. </del>  Clients are permitted to "stream" 0-RTT data until they receive the server's Finished, only then sending the EndOfEarlyData message.  In ServerHello, rather than waiting for the client's EndOfEarlyData message. <del> 4.2.10.3. </del>  As noted in zero-rtt-data, TLS provides a limited mechanism for replay protection for data sent by the client in the first flight. <del> The "obfuscated_ticket_age" parameter in the client's "pre_shared_key" extension SHOULD be used by servers to limit the time over which the first flight might be replayed.  A server can store the time at which it sends a ticket to the client, or encode the time in the ticket.  Then, each time it receives an "pre_shared_key" extension, it can un-obfuscate the ticket age and compare it to the difference between the current time and the ticket creation time, to see if the value for the time elapsed sent by the client is consistent with the time since the ticket was issued. The ticket age (the value with "ticket_age_add" subtracted) provided by the client will be shorter than the actual time elapsed on the server by a single round trip time.  This difference is comprised of the delay in sending the NewSessionTicket message to the client, plus the time taken to send the ClientHello to the server.  For this reason, a server SHOULD measure the round trip time prior to sending the NewSessionTicket message and account for that in the value it saves. To properly validate the ticket age, a server needs to save at least two items: The time that the server generated the session ticket and the estimated round trip time can be added together to form a baseline time. The "ticket_age_add" parameter from the NewSessionTicket is needed to recover the ticket age from the "obfuscated_ticket_age" parameter. </del>  There are several potential sources of error that make an exact measurement of time difficult.  Variations in client and server clock corrections.  Network propagation delays are the most likely causes of a mismatch in legitimate values for elapsed time.  Both the NewSessionTicket and ClientHello messages might be retransmitted and <del> therefore delayed, which might be hidden by TCP. A small allowance for errors in clocks and variations in measurements is advisable.  However, any allowance also increases the opportunity for replay.  In this case, it is better to reject early data and fall back to a full 1-RTT handshake than to risk greater exposure to replay attacks.  In common network topologies for browser clients, small allowances on the order of ten seconds are reasonable.  Clock skew distributions are not symmetric, so the optimal tradeoff may involve an asymmetric replay window. </del>  4.3.

…s , , .
NAME if you want to propose some revised text, I will TAL.
From Nikos's comment:
This is relating to . I will try to resolve both issues.
It is hard to understand the current text of Section 4.2.9.3 (Replay Properties). NAME explained me that a server should check: The server can tell: serverrecvtime == now serversendtime == one parameter in the ticket clientsendtime - clientrecvtime == ticketage == obfuscatedticketage + ticketage_add If this understanding is correct, I would suggest to add more explanation to the section.
Yes, that's correct. PRs welcome
I made a tweak to avoid referring to the "base value", in , though more changes may still be helpful.

establishment, or a label for a pre-shared key established externally.  <ins> An obfuscated version of the age of the key.  ticket-age describes how to form this value for identities established via the NewSessionTicket message.  For identities established externally an obfuscated_ticket_age of 0 SHOULD be used, and servers MUST ignore the value. </ins> A list of the identities that the client is willing to negotiate with the server.  If sent alongside the "early_data" extension 4.2.10.1. <ins> The client's view of the age of a ticket is the time since the receipt of the NewSessionTicket message.  Clients MUST NOT attempt to use tickets which have ages greater than the "ticket_lifetime" value which was provided with the ticket.  The "obfuscated_ticket_age" field of each PskIdentity contains an obfuscated version of the ticket age formed by taking the age in milliseconds and adding the "ticket_age_add" value that was included with the ticket, see NSTMessage modulo 2^32.  This addition prevents passive observers from correlating connections unless tickets are reused.  Note that the "ticket_lifetime" field in the NewSessionTicket message is in seconds but the "obfuscated_ticket_age" is in milliseconds.  Because ticket lifetimes are restricted to a week, 32 bits is enough to represent any plausible age, even in milliseconds. 4.2.10.2. </ins> The PSK binder value forms a binding between a PSK and the current handshake, as well as between the handshake in which the PSK was generated (if via a NewSessionTicket message) and the handshake where and then reinjected as a "handshake_hash" message, as described in the-transcript-hash.  <ins> 4.2.10.3. </ins> Clients are permitted to "stream" 0-RTT data until they receive the server's Finished, only then sending the EndOfEarlyData message.  In ServerHello, rather than waiting for the client's EndOfEarlyData message.  <ins> 4.2.10.4. </ins> As noted in zero-rtt-data, TLS provides a limited mechanism for replay protection for data sent by the client in the first flight.  <ins> This mechanism is intended to ensure that attackers cannot replay ClientHello messages at a time substantially after the original ClientHello was sent. To properly validate the ticket age, a server needs to store the following values, either locally or by encoding them in the ticket: The time that the server generated the session ticket. The estimated round trip time between the client and server; this can be estimated by measuring the time between sending the Finished message and receiving the first message in the client's second flight, or potentially using information from the operating system. The "ticket_age_add" parameter from the NewSessionTicket message in which the ticket was established. The server can determine the client's view of the age of the ticket by subtracting the ticket's "ticket_age_add value" from the "obfuscated_ticket_age" parameter in the client's "pre_shared_key" extension.  The server can independently determine its view of the age of the ticket by subtracting the the time the ticket was issued from the curren time.  If the client and server clocks were running at the same rate, the client's view of would be shorter than the actual time elapsed on the server by a single round trip time.  This difference is comprised of the delay in sending the NewSessionTicket message to the client, plus the time taken to send the ClientHello to the server. The mismatch between the client's and server's views of age is thus given by: </ins> There are several potential sources of error that make an exact measurement of time difficult.  Variations in client and server clock corrections.  Network propagation delays are the most likely causes of a mismatch in legitimate values for elapsed time.  Both the NewSessionTicket and ClientHello messages might be retransmitted and  <ins> therefore delayed, which might be hidden by TCP.  Thus, an an allowance on the order of ten seconds to account for errors in clocks and variations in measurements is advisable.  Outside this range, the server SHOULD reject early data and fall back to a full 1-RTT handshake.  Clock skew distributions are not symmetric, so the optimal tradeoff may involve an asymmetric range of permissible mismatch values. </ins> 4.3.


this connection (thus preventing replay of client CertificateVerify messages).  This field SHALL be zero length unless used for the post-handshake authentication exchanges <del> described in post-handshake-authentication. </del>  A set of extensions describing the parameters of the certificate being requested.  The "signature_algorithms" extension MUST be

be unpredictable in order to prevent pre-computation of CertificateVerify. Maybe this should actually be a MUST?
Note: an attacker can of course forge a complete handshake but maybe for some quirk of the environment that's not as good.

this connection (thus preventing replay of client CertificateVerify messages).  This field SHALL be zero length unless used for the post-handshake authentication exchanges  <ins> described in post-handshake-authentication.  When requesting post- handshake authentication, the server SHOULD make the context unpredictable to the client (e.g., by randomly generating it) in order to prevent an attacker who has temporary access to the client's private key from pre-computing valid CertificateVerify messages. </ins> A set of extensions describing the parameters of the certificate being requested.  The "signature_algorithms" extension MUST be


ECDHE parameters for both clients and servers are encoded in the the opaque key_exchange field of a KeyShareEntry in a KeyShare structure. <del> For secp256r1, secp384r1 and secp521r1, the contents are the byte string representation of an elliptic curve public value following the conversion routine in Section 4.3.6 of ANSI X9.62 X962. Although X9.62 supports multiple point formats, any given curve MUST specify only a single point format.  All curves currently specified in this document MUST only be used with the uncompressed point format (the format for all ECDH functions is considered uncompressed). Peers MUST validate each other's public value Y by ensuring that the point is a valid point on the elliptic curve. For the curves secp256r1, secp384r1 and secp521r1, the appropriate validation procedures are defined in Section 4.3.7 of X962 and alternatively in Section 5.6.2.6 of KEYAGREEMENT.  This process consists of three steps: (1) verify that Y is not the point at infinity (O), (2) verify that for Y = (x, y) both integers are in the correct interval, (3) ensure that (x, y) is a correct solution to the elliptic curve equation.  For these curves, implementers do not need to verify membership in the correct subgroup. </del>  For X25519 and X448, the contents of the public value are the byte string inputs and outputs of the corresponding functions defined in

As suggested by Nikos, provide a formal description of the point format modelled on 4492-bis.
Per Nikos's comment.

ECDHE parameters for both clients and servers are encoded in the the opaque key_exchange field of a KeyShareEntry in a KeyShare structure.  <ins> For secp256r1, secp384r1 and secp521r1, the contents are the serialized value of the following struct: X and Y respectively are the binary representations of the X and Y values in network byte order.  There are no internal length markers, so each number representation occupies as many octets as implied by the curve parameters.  For P-256 this means that each of X and Y use 32 octets, padded on the left by zeros if necessary.  For P-384 they take 48 octets each, and for P-521 they take 66 octets each. For the curves secp256r1, secp384r1 and secp521r1, peers MUST validate each other's public value Y by ensuring that the point is a valid point on the elliptic curve.  The appropriate validation procedures are defined in Section 4.3.7 of X962 and alternatively in Section 5.6.2.6 of KEYAGREEMENT.  This process consists of three steps: (1) verify that Y is not the point at infinity (O), (2) verify that for Y = (x, y) both integers are in the correct interval, (3) ensure that (x, y) is a correct solution to the elliptic curve equation.  For these curves, implementers do not need to verify membership in the correct subgroup. </ins> For X25519 and X448, the contents of the public value are the byte string inputs and outputs of the corresponding functions defined in


0-RTT data to ensure that an application is always aware that it is sending or receiving data that might be replayed. <del> The same warnings apply to any use of the early_exporter_secret. </del>  The remainder of this document provides a detailed description of TLS. Once the handshake is complete, it is possible for either side to update its sending traffic keys using the KeyUpdate handshake message defined in key-update.  The next generation of traffic keys is <del> computed by generating client_/server_traffic_secret_N+1 from client_/server_traffic_secret_N as described in this section then re- deriving the traffic keys as described in traffic-key-calculation. </del>  <del> The next-generation traffic_secret is computed as: </del>  <del> Once client/server_traffic_secret_N+1 and its associated traffic keys have been computed, implementations SHOULD delete client_/ server_traffic_secret_N and its associated traffic keys. </del>  7.3. The exporter value is computed as: <del> Where Secret is either the early_exporter_secret or the exporter_secret.  Implementations MUST use the exporter_secret unless explicitly specified by the application.  The early_exporter_secret is define for use in settings where an exporter is needed for 0-RTT data.  A separate interface for the early exporter is RECOMMENDED, especially on a server where a single interface can make the early exporter inaccessible. </del>  If no context is provided, the context_value is zero-length. Consequently, providing no context computes the same value as

Make the variable names of various secrets correspond to the labels used for Derive-Secret(). This is not a wire format change, but just a change in the internal variable names.
NAME NAME you see any misses here?
The legends for the message flows still say "trafficsecretN" for the "[]" parts. Also, "Updating Traffic Keys and IVs" still uses "trafficsecretN" in the formula and text prior to it.
In the key schedule

0-RTT data to ensure that an application is always aware that it is sending or receiving data that might be replayed.  <ins> The same warnings apply to any use of the early_exporter_master_secret. </ins> The remainder of this document provides a detailed description of TLS. Once the handshake is complete, it is possible for either side to update its sending traffic keys using the KeyUpdate handshake message defined in key-update.  The next generation of traffic keys is  <ins> computed by generating client_/server_application_traffic_secret_N+1 from client_/server_application_traffic_secret_N as described in this section then re-deriving the traffic keys as described in traffic- key-calculation. </ins>  <ins> The next-generation application_traffic_secret is computed as: </ins>  <ins> Once client/server_application_traffic_secret_N+1 and its associated traffic keys have been computed, implementations SHOULD delete client_/server_application_traffic_secret_N and its associated traffic keys. </ins> 7.3. The exporter value is computed as:  <ins> Where Secret is either the early_exporter_master_secret or the exporter_master_secret.  Implementations MUST use the exporter_master_secret unless explicitly specified by the application.  The early_exporter_master_secret is define for use in settings where an exporter is needed for 0-RTT data.  A separate interface for the early exporter is RECOMMENDED, especially on a server where a single interface can make the early exporter inaccessible. </ins> If no context is provided, the context_value is zero-length. Consequently, providing no context computes the same value as