Tech-invite3GPPspaceIETFspace
959493929190898887868584838281807978777675747372717069686766656463626160595857565554535251504948474645444342414039383736353433323130292827262524232221201918171615141312111009080706050403020100
in Index   Prev   Next

RFC 8446

The Transport Layer Security (TLS) Protocol Version 1.3

Pages: 160
Proposed Standard
Errata
Obsoletes:  507752466961
Updates:  57056066
Part 5 of 8 – Pages 77 to 97
First   Prev   Next

Top   ToC   RFC8446 - Page 77   prevText

5. Record Protocol

The TLS record protocol takes messages to be transmitted, fragments the data into manageable blocks, protects the records, and transmits the result. Received data is verified, decrypted, reassembled, and then delivered to higher-level clients. TLS records are typed, which allows multiple higher-level protocols to be multiplexed over the same record layer. This document specifies four content types: handshake, application_data, alert, and change_cipher_spec. The change_cipher_spec record is used only for compatibility purposes (see Appendix D.4). An implementation may receive an unencrypted record of type change_cipher_spec consisting of the single byte value 0x01 at any time after the first ClientHello message has been sent or received and before the peer's Finished message has been received and MUST simply drop it without further processing. Note that this record may appear at a point at the handshake where the implementation is expecting protected records, and so it is necessary to detect this condition prior to attempting to deprotect the record. An implementation which receives any other change_cipher_spec value or which receives a protected change_cipher_spec record MUST abort the handshake with an "unexpected_message" alert. If an implementation detects a change_cipher_spec record received before the first ClientHello message or after the peer's Finished message, it MUST be treated as an unexpected record type (though stateless servers may not be able to distinguish these cases from allowed cases).
Top   ToC   RFC8446 - Page 78
   Implementations MUST NOT send record types not defined in this
   document unless negotiated by some extension.  If a TLS
   implementation receives an unexpected record type, it MUST terminate
   the connection with an "unexpected_message" alert.  New record
   content type values are assigned by IANA in the TLS ContentType
   registry as described in Section 11.

5.1. Record Layer

The record layer fragments information blocks into TLSPlaintext records carrying data in chunks of 2^14 bytes or less. Message boundaries are handled differently depending on the underlying ContentType. Any future content types MUST specify appropriate rules. Note that these rules are stricter than what was enforced in TLS 1.2. Handshake messages MAY be coalesced into a single TLSPlaintext record or fragmented across several records, provided that: - Handshake messages MUST NOT be interleaved with other record types. That is, if a handshake message is split over two or more records, there MUST NOT be any other records between them. - 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 ClientHello, EndOfEarlyData, ServerHello, Finished, and KeyUpdate messages can immediately precede a key change, implementations MUST send these messages in alignment with a record boundary. Implementations MUST NOT send zero-length fragments of Handshake types, even if those fragments contain padding. Alert messages (Section 6) MUST NOT be fragmented across records, and multiple alert messages MUST NOT be coalesced into a single TLSPlaintext record. In other words, a record with an Alert type MUST contain exactly one message. Application Data messages contain data that is opaque to TLS. Application Data messages are always protected. Zero-length fragments of Application Data MAY be sent, as they are potentially useful as a traffic analysis countermeasure. Application Data fragments MAY be split across multiple records or coalesced into a single record.
Top   ToC   RFC8446 - Page 79
      enum {
          invalid(0),
          change_cipher_spec(20),
          alert(21),
          handshake(22),
          application_data(23),
          (255)
      } ContentType;

      struct {
          ContentType type;
          ProtocolVersion legacy_record_version;
          uint16 length;
          opaque fragment[TLSPlaintext.length];
      } TLSPlaintext;

   type:  The higher-level protocol used to process the enclosed
      fragment.

   legacy_record_version:  MUST be set to 0x0303 for all records
      generated by a TLS 1.3 implementation other than an initial
      ClientHello (i.e., one not generated after a HelloRetryRequest),
      where it MAY also be 0x0301 for compatibility purposes.  This
      field is deprecated and MUST be ignored for all purposes.
      Previous versions of TLS would use other values in this field
      under some circumstances.

   length:  The length (in bytes) of the following
      TLSPlaintext.fragment.  The length MUST NOT exceed 2^14 bytes.  An
      endpoint that receives a record that exceeds this length MUST
      terminate the connection with a "record_overflow" alert.

   fragment:  The data being transmitted.  This value is transparent and
      is treated as an independent block to be dealt with by the higher-
      level protocol specified by the type field.

   This document describes TLS 1.3, which uses the version 0x0304.  This
   version value is historical, deriving from the use of 0x0301 for
   TLS 1.0 and 0x0300 for SSL 3.0.  In order to maximize backward
   compatibility, a record containing an initial ClientHello SHOULD have
   version 0x0301 (reflecting TLS 1.0) and a record containing a second
   ClientHello or a ServerHello MUST have version 0x0303 (reflecting
   TLS 1.2).  When negotiating prior versions of TLS, endpoints follow
   the procedure and requirements provided in Appendix D.
Top   ToC   RFC8446 - Page 80
   When record protection has not yet been engaged, TLSPlaintext
   structures are written directly onto the wire.  Once record
   protection has started, TLSPlaintext records are protected and sent
   as described in the following section.  Note that Application Data
   records MUST NOT be written to the wire unprotected (see Section 2
   for details).

5.2. Record Payload Protection

The record protection functions translate a TLSPlaintext structure into a TLSCiphertext structure. The deprotection functions reverse the process. In TLS 1.3, as opposed to previous versions of TLS, all ciphers are modeled as "Authenticated Encryption with Associated Data" (AEAD) [RFC5116]. AEAD functions provide a unified encryption and authentication operation which turns plaintext into authenticated ciphertext and back again. Each encrypted record consists of a plaintext header followed by an encrypted body, which itself contains a type and optional padding. struct { opaque content[TLSPlaintext.length]; ContentType type; uint8 zeros[length_of_padding]; } TLSInnerPlaintext; struct { ContentType opaque_type = application_data; /* 23 */ ProtocolVersion legacy_record_version = 0x0303; /* TLS v1.2 */ uint16 length; opaque encrypted_record[TLSCiphertext.length]; } TLSCiphertext; content: The TLSPlaintext.fragment value, containing the byte encoding of a handshake or an alert message, or the raw bytes of the application's data to send. type: The TLSPlaintext.type value containing the content type of the record. zeros: An arbitrary-length run of zero-valued bytes may appear in the cleartext after the type field. This provides an opportunity for senders to pad any TLS record by a chosen amount as long as the total stays within record size limits. See Section 5.4 for more details.
Top   ToC   RFC8446 - Page 81
   opaque_type:  The outer opaque_type field of a TLSCiphertext record
      is always set to the value 23 (application_data) for outward
      compatibility with middleboxes accustomed to parsing previous
      versions of TLS.  The actual content type of the record is found
      in TLSInnerPlaintext.type after decryption.

   legacy_record_version:  The legacy_record_version field is always
      0x0303.  TLS 1.3 TLSCiphertexts are not generated until after
      TLS 1.3 has been negotiated, so there are no historical
      compatibility concerns where other values might be received.  Note
      that the handshake protocol, including the ClientHello and
      ServerHello messages, authenticates the protocol version, so this
      value is redundant.

   length:  The length (in bytes) of the following
      TLSCiphertext.encrypted_record, which is the sum of the lengths of
      the content and the padding, plus one for the inner content type,
      plus any expansion added by the AEAD algorithm.  The length
      MUST NOT exceed 2^14 + 256 bytes.  An endpoint that receives a
      record that exceeds this length MUST terminate the connection with
      a "record_overflow" alert.

   encrypted_record:  The AEAD-encrypted form of the serialized
      TLSInnerPlaintext structure.

   AEAD algorithms take as input a single key, a nonce, a plaintext, and
   "additional data" to be included in the authentication check, as
   described in Section 2.1 of [RFC5116].  The key is either the
   client_write_key or the server_write_key, the nonce is derived from
   the sequence number and the client_write_iv or server_write_iv (see
   Section 5.3), and the additional data input is the record header.

   I.e.,

      additional_data = TLSCiphertext.opaque_type ||
                        TLSCiphertext.legacy_record_version ||
                        TLSCiphertext.length

   The plaintext input to the AEAD algorithm is the encoded
   TLSInnerPlaintext structure.  Derivation of traffic keys is defined
   in Section 7.3.

   The AEAD output consists of the ciphertext output from the AEAD
   encryption operation.  The length of the plaintext is greater than
   the corresponding TLSPlaintext.length due to the inclusion of
   TLSInnerPlaintext.type and any padding supplied by the sender.  The
   length of the AEAD output will generally be larger than the
   plaintext, but by an amount that varies with the AEAD algorithm.
Top   ToC   RFC8446 - Page 82
   Since the ciphers might incorporate padding, the amount of overhead
   could vary with different lengths of plaintext.  Symbolically,

      AEADEncrypted =
          AEAD-Encrypt(write_key, nonce, additional_data, plaintext)

   The encrypted_record field of TLSCiphertext is set to AEADEncrypted.

   In order to decrypt and verify, the cipher takes as input the key,
   nonce, additional data, and the AEADEncrypted value.  The output is
   either the plaintext or an error indicating that the decryption
   failed.  There is no separate integrity check.  Symbolically,

      plaintext of encrypted_record =
          AEAD-Decrypt(peer_write_key, nonce,
                       additional_data, AEADEncrypted)

   If the decryption fails, the receiver MUST terminate the connection
   with a "bad_record_mac" alert.

   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
   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 TLSInnerPlaintext length of 2^14 octets +
   1 octet for ContentType + the maximum AEAD expansion of 255 octets.

5.3. Per-Record Nonce

A 64-bit sequence number is maintained separately for reading and writing records. The appropriate sequence number is incremented by one after reading or writing each record. Each sequence number is set to zero at the beginning of a connection and whenever the key is changed; the first record transmitted under a particular traffic key MUST use sequence number 0. Because the size of sequence numbers is 64-bit, they should not wrap. If a TLS implementation would need to wrap a sequence number, it MUST either rekey (Section 4.6.3) or terminate the connection.
Top   ToC   RFC8446 - Page 83
   Each AEAD algorithm will specify a range of possible lengths for the
   per-record nonce, from N_MIN bytes to N_MAX bytes of input [RFC5116].
   The length of the TLS per-record nonce (iv_length) is set to the
   larger of 8 bytes and N_MIN for the AEAD algorithm (see [RFC5116],
   Section 4).  An AEAD algorithm where N_MAX is less than 8 bytes
   MUST NOT be used with TLS.  The per-record nonce for the AEAD
   construction is formed as follows:

   1.  The 64-bit record sequence number is encoded in network byte
       order and padded to the left with zeros to iv_length.

   2.  The padded sequence number is XORed with either the static
       client_write_iv or server_write_iv (depending on the role).

   The resulting quantity (of length iv_length) is used as the
   per-record nonce.

   Note: This is a different construction from that in TLS 1.2, which
   specified a partially explicit nonce.

5.4. Record Padding

All encrypted TLS records can be padded to inflate the size of the TLSCiphertext. This allows the sender to hide the size of the traffic from an observer. When generating a TLSCiphertext record, implementations MAY choose to pad. An unpadded record is just a record with a padding length of zero. Padding is a string of zero-valued bytes appended to the ContentType field before encryption. Implementations MUST set the padding octets to all zeros before encrypting. Application Data records may contain a zero-length TLSInnerPlaintext.content if the sender desires. This permits generation of plausibly sized cover traffic in contexts where the presence or absence of activity may be sensitive. Implementations MUST NOT send Handshake and Alert records that have a zero-length TLSInnerPlaintext.content; if such a message is received, the receiving implementation MUST terminate the connection with an "unexpected_message" alert.
Top   ToC   RFC8446 - Page 84
   The padding sent is automatically verified by the record protection
   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.

   Implementations MUST limit their scanning to the cleartext returned
   from the AEAD decryption.  If a receiving implementation does not
   find a non-zero octet in the cleartext, it MUST terminate the
   connection with an "unexpected_message" alert.

   The presence of padding does not change the overall record size
   limitations: the full encoded TLSInnerPlaintext MUST NOT exceed 2^14
   + 1 octets.  If the maximum fragment length is reduced -- as, for
   example, by the record_size_limit extension from [RFC8449] -- then
   the reduced limit applies to the full plaintext, including the
   content type and padding.

   Selecting a padding policy that suggests when and how much to pad is
   a complex topic and is beyond the scope of this specification.  If
   the application-layer protocol on top of TLS has its own padding, it
   may be preferable to pad Application Data TLS records within the
   application layer.  Padding for encrypted Handshake or Alert records
   must still be handled at the TLS layer, though.  Later documents may
   define padding selection algorithms or define a padding policy
   request mechanism through TLS extensions or some other means.

5.5. Limits on Key Usage

There are cryptographic limits on the amount of plaintext which can be safely encrypted under a given set of keys. [AEAD-LIMITS] provides an analysis of these limits under the assumption that the underlying primitive (AES or ChaCha20) has no weaknesses. Implementations SHOULD do a key update as described in Section 4.6.3 prior to reaching these limits. For AES-GCM, up to 2^24.5 full-size records (about 24 million) may be encrypted on a given connection while keeping a safety margin of approximately 2^-57 for Authenticated Encryption (AE) security. For ChaCha20/Poly1305, the record sequence number would wrap before the safety limit is reached.
Top   ToC   RFC8446 - Page 85

6. Alert Protocol

TLS provides an Alert content type to indicate closure information and errors. Like other messages, alert messages are encrypted as specified by the current connection state. Alert messages convey a description of the alert and a legacy field that conveyed the severity level of the message in previous versions of TLS. Alerts are divided into two classes: closure alerts and error alerts. In TLS 1.3, the severity is implicit in the type of alert being sent, and the "level" field can safely be ignored. The "close_notify" alert is used to indicate orderly closure of one direction of the connection. Upon receiving such an alert, the TLS implementation SHOULD indicate end-of-data to the application. Error alerts indicate abortive closure of the connection (see Section 6.2). Upon receiving an error alert, the TLS implementation SHOULD indicate an error to the application and MUST NOT allow any further data to be sent or received on the connection. Servers and clients MUST forget the secret values and keys established in failed connections, with the exception of the PSKs associated with session tickets, which SHOULD be discarded if possible. All the alerts listed in Section 6.2 MUST be sent with AlertLevel=fatal and MUST be treated as error alerts when received regardless of the AlertLevel in the message. Unknown Alert types MUST be treated as error alerts. Note: TLS defines two generic alerts (see Section 6) to use upon failure to parse a message. Peers which receive a message which cannot be parsed according to the syntax (e.g., have a length extending beyond the message boundary or contain an out-of-range length) MUST terminate the connection with a "decode_error" alert. Peers which receive a message which is syntactically correct but semantically invalid (e.g., a DHE share of p - 1, or an invalid enum) MUST terminate the connection with an "illegal_parameter" alert.
Top   ToC   RFC8446 - Page 86
      enum { warning(1), fatal(2), (255) } AlertLevel;

      enum {
          close_notify(0),
          unexpected_message(10),
          bad_record_mac(20),
          record_overflow(22),
          handshake_failure(40),
          bad_certificate(42),
          unsupported_certificate(43),
          certificate_revoked(44),
          certificate_expired(45),
          certificate_unknown(46),
          illegal_parameter(47),
          unknown_ca(48),
          access_denied(49),
          decode_error(50),
          decrypt_error(51),
          protocol_version(70),
          insufficient_security(71),
          internal_error(80),
          inappropriate_fallback(86),
          user_canceled(90),
          missing_extension(109),
          unsupported_extension(110),
          unrecognized_name(112),
          bad_certificate_status_response(113),
          unknown_psk_identity(115),
          certificate_required(116),
          no_application_protocol(120),
          (255)
      } AlertDescription;

      struct {
          AlertLevel level;
          AlertDescription description;
      } Alert;
Top   ToC   RFC8446 - Page 87

6.1. Closure Alerts

The client and the server must share knowledge that the connection is ending in order to avoid a truncation attack. close_notify: This alert notifies the recipient that the sender will not send any more messages on this connection. Any data received after a closure alert has been received MUST be ignored. user_canceled: 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 closing the connection by sending a "close_notify" is more appropriate. This alert SHOULD be followed by a "close_notify". This alert generally has AlertLevel=warning. Either party MAY initiate a close of its write side of the connection by sending a "close_notify" alert. Any data received after a closure alert has been received MUST be ignored. If a transport-level close is received prior to a "close_notify", the receiver cannot know that all the data that was sent has been received. Each party MUST send a "close_notify" alert before closing its write side of the connection, unless it has already sent some error alert. This does not have any effect on its read side of the connection. Note that this is a change from versions of TLS prior to TLS 1.3 in which implementations were required to react to a "close_notify" by discarding pending writes and sending an immediate "close_notify" alert of their own. That previous requirement could cause truncation in the read side. Both parties need not wait to receive a "close_notify" alert before closing their read side of the connection, though doing so would introduce the possibility of truncation. If the application protocol using TLS provides that any data may be carried over the underlying transport after the TLS connection is closed, the TLS implementation MUST receive a "close_notify" alert before indicating end-of-data to the application layer. No part of this standard should be taken to dictate the manner in which a usage profile for TLS manages its data transport, including when connections are opened or closed. Note: It is assumed that closing the write side of a connection reliably delivers pending data before destroying the transport.
Top   ToC   RFC8446 - Page 88

6.2. Error Alerts

Error handling in TLS is very simple. When an error is detected, the detecting party sends a message to its peer. Upon transmission or receipt of a fatal alert message, both parties MUST immediately close the connection. Whenever an implementation encounters a fatal error condition, it SHOULD send an appropriate fatal alert and MUST close the connection without sending or receiving any additional data. In the rest of this specification, when the phrases "terminate the connection" and "abort the handshake" are used without a specific alert it means that the implementation SHOULD send the alert indicated by the descriptions below. The phrases "terminate the connection with an X alert" and "abort the handshake with an X alert" mean that the implementation MUST send alert X if it sends any alert. All alerts defined below in this section, as well as all unknown alerts, are universally considered fatal as of TLS 1.3 (see Section 6). The implementation SHOULD provide a way to facilitate logging the sending and receiving of alerts. The following error alerts are defined: unexpected_message: An inappropriate message (e.g., the wrong handshake message, premature Application Data, etc.) was received. This alert should never be observed in communication between proper implementations. bad_record_mac: This alert is returned if a record is received which cannot be deprotected. Because AEAD algorithms combine decryption and verification, and also to avoid side-channel attacks, this alert is used for all deprotection failures. This alert should never be observed in communication between proper implementations, except when messages were corrupted in the network. record_overflow: A TLSCiphertext record was received that had a length more than 2^14 + 256 bytes, or a record decrypted to a TLSPlaintext record with more than 2^14 bytes (or some other negotiated limit). This alert should never be observed in communication between proper implementations, except when messages were corrupted in the network. handshake_failure: Receipt of a "handshake_failure" alert message indicates that the sender was unable to negotiate an acceptable set of security parameters given the options available. bad_certificate: A certificate was corrupt, contained signatures that did not verify correctly, etc.
Top   ToC   RFC8446 - Page 89
   unsupported_certificate:  A certificate was of an unsupported type.

   certificate_revoked:  A certificate was revoked by its signer.

   certificate_expired:  A certificate has expired or is not currently
      valid.

   certificate_unknown:  Some other (unspecified) issue arose in
      processing the certificate, rendering it unacceptable.

   illegal_parameter:  A field in the handshake was incorrect or
      inconsistent with other fields.  This alert is used for errors
      which conform to the formal protocol syntax but are otherwise
      incorrect.

   unknown_ca:  A valid certificate chain or partial chain was received,
      but the certificate was not accepted because the CA certificate
      could not be located or could not be matched with a known trust
      anchor.

   access_denied:  A valid certificate or PSK was received, but when
      access control was applied, the sender decided not to proceed with
      negotiation.

   decode_error:  A message could not be decoded because some field was
      out of the specified range or the length of the message was
      incorrect.  This alert is used for errors where the message does
      not conform to the formal protocol syntax.  This alert should
      never be observed in communication between proper implementations,
      except when messages were corrupted in the network.

   decrypt_error:  A handshake (not record layer) cryptographic
      operation failed, including being unable to correctly verify a
      signature or validate a Finished message or a PSK binder.

   protocol_version:  The protocol version the peer has attempted to
      negotiate is recognized but not supported (see Appendix D).

   insufficient_security:  Returned instead of "handshake_failure" when
      a negotiation has failed specifically because the server requires
      parameters more secure than those supported by the client.

   internal_error:  An internal error unrelated to the peer or the
      correctness of the protocol (such as a memory allocation failure)
      makes it impossible to continue.

   inappropriate_fallback:  Sent by a server in response to an invalid
      connection retry attempt from a client (see [RFC7507]).
Top   ToC   RFC8446 - Page 90
   missing_extension:  Sent by endpoints that receive a handshake
      message not containing an extension that is mandatory to send for
      the offered TLS version or other negotiated parameters.

   unsupported_extension:  Sent by endpoints receiving any handshake
      message containing an extension known to be prohibited for
      inclusion in the given handshake message, or including any
      extensions in a ServerHello or Certificate not first offered in
      the corresponding ClientHello or CertificateRequest.

   unrecognized_name:  Sent by servers when no server exists identified
      by the name provided by the client via the "server_name" extension
      (see [RFC6066]).

   bad_certificate_status_response:  Sent by clients when an invalid or
      unacceptable OCSP response is provided by the server via the
      "status_request" extension (see [RFC6066]).

   unknown_psk_identity:  Sent by servers when PSK key establishment is
      desired but no acceptable PSK identity is provided by the client.
      Sending this alert is OPTIONAL; servers MAY instead choose to send
      a "decrypt_error" alert to merely indicate an invalid PSK
      identity.

   certificate_required:  Sent by servers when a client certificate is
      desired but none was provided by the client.

   no_application_protocol:  Sent by servers when a client
      "application_layer_protocol_negotiation" extension advertises only
      protocols that the server does not support (see [RFC7301]).

   New Alert values are assigned by IANA as described in Section 11.

7. Cryptographic Computations

The TLS handshake establishes one or more input secrets which are combined to create the actual working keying material, as detailed below. The key derivation process incorporates both the input secrets and the handshake transcript. Note that because the handshake transcript includes the random values from the Hello messages, any given handshake will have different traffic secrets, even if the same input secrets are used, as is the case when the same PSK is used for multiple connections.
Top   ToC   RFC8446 - Page 91

7.1. Key Schedule

The key derivation process makes use of the HKDF-Extract and HKDF-Expand functions as defined for HKDF [RFC5869], as well as the functions defined below: HKDF-Expand-Label(Secret, Label, Context, Length) = HKDF-Expand(Secret, HkdfLabel, Length) Where HkdfLabel is specified as: struct { uint16 length = Length; opaque label<7..255> = "tls13 " + Label; opaque context<0..255> = Context; } HkdfLabel; Derive-Secret(Secret, Label, Messages) = HKDF-Expand-Label(Secret, Label, Transcript-Hash(Messages), Hash.length) The Hash function used by Transcript-Hash and HKDF is the cipher suite hash algorithm. Hash.length is its output length in bytes. Messages is the concatenation of the indicated handshake messages, including the handshake message type and length fields, but not including record layer headers. Note that in some cases a zero- length Context (indicated by "") is passed to HKDF-Expand-Label. The labels specified in this document are all ASCII strings and do not include a trailing NUL byte. Note: With common hash functions, any label longer than 12 characters requires an additional iteration of the hash function to compute. The labels in this specification have all been chosen to fit within this limit.
Top   ToC   RFC8446 - Page 92
   Keys are derived from two input secrets using the HKDF-Extract and
   Derive-Secret functions.  The general pattern for adding a new secret
   is to use HKDF-Extract with the Salt being the current secret state
   and the Input Keying Material (IKM) being the new secret to be added.
   In this version of TLS 1.3, the two input secrets are:

   -  PSK (a pre-shared key established externally or derived from the
      resumption_master_secret value from a previous connection)

   -  (EC)DHE shared secret (Section 7.4)

   This produces a full key derivation schedule shown in the diagram
   below.  In this diagram, the following formatting conventions apply:

   -  HKDF-Extract is drawn as taking the Salt argument from the top and
      the IKM argument from the left, with its output to the bottom and
      the name of the output on the right.

   -  Derive-Secret's Secret argument is indicated by the incoming
      arrow.  For instance, the Early Secret is the Secret for
      generating the client_early_traffic_secret.

   -  "0" indicates a string of Hash.length bytes set to zero.
Top   ToC   RFC8446 - Page 93
             0
             |
             v
   PSK ->  HKDF-Extract = Early Secret
             |
             +-----> Derive-Secret(., "ext binder" | "res binder", "")
             |                     = binder_key
             |
             +-----> Derive-Secret(., "c e traffic", ClientHello)
             |                     = client_early_traffic_secret
             |
             +-----> Derive-Secret(., "e exp master", ClientHello)
             |                     = early_exporter_master_secret
             v
       Derive-Secret(., "derived", "")
             |
             v
   (EC)DHE -> HKDF-Extract = Handshake Secret
             |
             +-----> Derive-Secret(., "c hs traffic",
             |                     ClientHello...ServerHello)
             |                     = client_handshake_traffic_secret
             |
             +-----> Derive-Secret(., "s hs traffic",
             |                     ClientHello...ServerHello)
             |                     = server_handshake_traffic_secret
             v
       Derive-Secret(., "derived", "")
             |
             v
   0 -> HKDF-Extract = Master Secret
             |
             +-----> Derive-Secret(., "c ap traffic",
             |                     ClientHello...server Finished)
             |                     = client_application_traffic_secret_0
             |
             +-----> Derive-Secret(., "s ap traffic",
             |                     ClientHello...server Finished)
             |                     = server_application_traffic_secret_0
             |
             +-----> Derive-Secret(., "exp master",
             |                     ClientHello...server Finished)
             |                     = exporter_master_secret
             |
             +-----> Derive-Secret(., "res master",
                                   ClientHello...client Finished)
                                   = resumption_master_secret
Top   ToC   RFC8446 - Page 94
   The general pattern here is that the secrets shown down the left side
   of the diagram are just raw entropy without context, whereas the
   secrets down the right side include Handshake Context and therefore
   can be used to derive working keys without additional context.  Note
   that the different calls to Derive-Secret may take different Messages
   arguments, even with the same secret.  In a 0-RTT exchange,
   Derive-Secret is called with four distinct transcripts; in a
   1-RTT-only exchange, it is called with three distinct transcripts.

   If a given secret is not available, then the 0-value consisting of a
   string of Hash.length bytes set to zeros is used.  Note that this
   does not mean skipping rounds, so if PSK is not in use, Early Secret
   will still be HKDF-Extract(0, 0).  For the computation of the
   binder_key, the label is "ext binder" for external PSKs (those
   provisioned outside of TLS) and "res binder" for resumption PSKs
   (those provisioned as the resumption master secret of a previous
   handshake).  The different labels prevent the substitution of one
   type of PSK for the other.

   There are multiple potential Early Secret values, depending on which
   PSK the server ultimately selects.  The client will need to compute
   one for each potential PSK; if no PSK is selected, it will then need
   to compute the Early Secret corresponding to the zero PSK.

   Once all the values which are to be derived from a given secret have
   been computed, that secret SHOULD be erased.

7.2. Updating Traffic Secrets

Once the handshake is complete, it is possible for either side to update its sending traffic keys using the KeyUpdate handshake message defined in Section 4.6.3. The next generation of traffic keys is computed by generating client_/server_application_traffic_secret_N+1 from client_/server_application_traffic_secret_N as described in this section and then re-deriving the traffic keys as described in Section 7.3. The next-generation application_traffic_secret is computed as: application_traffic_secret_N+1 = HKDF-Expand-Label(application_traffic_secret_N, "traffic upd", "", Hash.length) 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.
Top   ToC   RFC8446 - Page 95

7.3. Traffic Key Calculation

The traffic keying material is generated from the following input values: - A secret value - A purpose value indicating the specific value being generated - The length of the key being generated The traffic keying material is generated from an input traffic secret value using: [sender]_write_key = HKDF-Expand-Label(Secret, "key", "", key_length) [sender]_write_iv = HKDF-Expand-Label(Secret, "iv", "", iv_length) [sender] denotes the sending side. The value of Secret for each record type is shown in the table below. +-------------------+---------------------------------------+ | Record Type | Secret | +-------------------+---------------------------------------+ | 0-RTT Application | client_early_traffic_secret | | | | | Handshake | [sender]_handshake_traffic_secret | | | | | Application Data | [sender]_application_traffic_secret_N | +-------------------+---------------------------------------+ All the traffic keying material is recomputed whenever the underlying Secret changes (e.g., when changing from the handshake to Application Data keys or upon a key update).

7.4. (EC)DHE Shared Secret Calculation

7.4.1. Finite Field Diffie-Hellman

For finite field groups, a conventional Diffie-Hellman [DH76] computation is performed. The negotiated key (Z) is converted to a byte string by encoding in big-endian form and left-padded with zeros up to the size of the prime. This byte string is used as the shared secret in the key schedule as specified above. Note that this construction differs from previous versions of TLS which removed leading zeros.
Top   ToC   RFC8446 - Page 96

7.4.2. Elliptic Curve Diffie-Hellman

For secp256r1, secp384r1, and secp521r1, ECDH calculations (including parameter and key generation as well as the shared secret calculation) are performed according to [IEEE1363] using the ECKAS-DH1 scheme with the identity map as the key derivation function (KDF), so that the shared secret is the x-coordinate of the ECDH shared secret elliptic curve point represented as an octet string. Note that this octet string ("Z" in IEEE 1363 terminology) as output by FE2OSP (the Field Element to Octet String Conversion Primitive) has constant length for any given field; leading zeros found in this octet string MUST NOT be truncated. (Note that this use of the identity KDF is a technicality. The complete picture is that ECDH is employed with a non-trivial KDF because TLS does not directly use this secret for anything other than for computing other secrets.) For X25519 and X448, the ECDH calculations are as follows: - The public key to put into the KeyShareEntry.key_exchange structure is the result of applying the ECDH scalar multiplication function to the secret key of appropriate length (into scalar input) and the standard public basepoint (into u-coordinate point input). - The ECDH shared secret is the result of applying the ECDH scalar multiplication function to the secret key (into scalar input) and the peer's public key (into u-coordinate point input). The output is used raw, with no processing. For these curves, implementations SHOULD use the approach specified in [RFC7748] to calculate the Diffie-Hellman shared secret. Implementations MUST check whether the computed Diffie-Hellman shared secret is the all-zero value and abort if so, as described in Section 6 of [RFC7748]. If implementors use an alternative implementation of these elliptic curves, they SHOULD perform the additional checks specified in Section 7 of [RFC7748].
Top   ToC   RFC8446 - Page 97

7.5. Exporters

[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 remains the same. The exporter value is computed as: TLS-Exporter(label, context_value, key_length) = HKDF-Expand-Label(Derive-Secret(Secret, label, ""), "exporter", Hash(context_value), key_length) 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 defined for use in settings where an exporter is needed for 0-RTT data. A separate interface for the early exporter is RECOMMENDED; this avoids the exporter user accidentally using an early exporter when a regular one is desired or vice versa. 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 than 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. Requirements for the format of exporter labels are defined in Section 4 of [RFC5705].


(next page on part 6)

Next Section