| rfc9849.original.md | rfc9849.md | |||
|---|---|---|---|---|
| --- | --- | |||
| title: TLS Encrypted Client Hello | title: TLS Encrypted Client Hello | |||
| abbrev: TLS Encrypted Client Hello | abbrev: TLS Encrypted Client Hello | |||
| docname: draft-ietf-tls-esni-latest | docname: draft-ietf-tls-esni-25 | |||
| category: std | category: std | |||
| number: 9849 | ||||
| ipr: trust200902 | ipr: trust200902 | |||
| submissiontype: IETF | submissiontype: IETF | |||
| updates: | ||||
| obsoletes: | ||||
| date: 2025-11 | ||||
| consensus: true | ||||
| v: 3 | ||||
| area: SEC | area: SEC | |||
| workgroup: tls | workgroup: tls | |||
| keyword: Internet-Draft | keyword: | |||
| stand_alone: yes | stand_alone: yes | |||
| pi: [toc, sortrefs, symrefs] | pi: [toc, sortrefs, symrefs] | |||
| author: | author: | |||
| - | - name: Eric Rescorla | |||
| ins: E. Rescorla | ins: E. Rescorla | |||
| name: Eric Rescorla | org: Independent | |||
| organization: Independent | ||||
| email: ekr@rtfm.com | email: ekr@rtfm.com | |||
| - | - name: Kazuho Oku | |||
| ins: K. Oku | ins: K. Oku | |||
| name: Kazuho Oku | org: Fastly | |||
| organization: Fastly | ||||
| email: kazuhooku@gmail.com | email: kazuhooku@gmail.com | |||
| - | - name: Nick Sullivan | |||
| ins: N. Sullivan | ins: N. Sullivan | |||
| name: Nick Sullivan | org: Cryptography Consulting LLC | |||
| organization: Cryptography Consulting LLC | ||||
| email: nicholas.sullivan+ietf@gmail.com | email: nicholas.sullivan+ietf@gmail.com | |||
| - | - name: Christopher A. Wood | |||
| ins: C. A. Wood | ins: C. A. Wood | |||
| name: Christopher A. Wood | org: Cloudflare | |||
| organization: Cloudflare | ||||
| email: caw@heapingbits.net | email: caw@heapingbits.net | |||
| normative: | normative: | |||
| RFC2119: | RFC2119: | |||
| RFC7918: | RFC7918: | |||
| RFCYYY1: | ||||
| title: > | ||||
| Bootstrapping TLS Encrypted ClientHello with DNS Service Bindings | ||||
| target: https://www.rfc-editor.org/info/rfcYYY1 | ||||
| seriesinfo: | ||||
| RFC: YYY1 | ||||
| DOI: 10.17487/RFCYYY1 | ||||
| date: November 2025 | ||||
| author: | ||||
| - | ||||
| ins: B. Schwartz | ||||
| surname: Schwartz | ||||
| fullname: Benjamin M. Schwartz | ||||
| - | ||||
| ins: M. Bishop | ||||
| surname: Bishop | ||||
| fullname: Mike Bishop | ||||
| - | ||||
| ins: E. Nygren | ||||
| surname: Nygren | ||||
| fullname: Erik Nygren | ||||
| RFC9180: | ||||
| display: HPKE | ||||
| informative: | informative: | |||
| WHATWG-IPV4: | WHATWG-IPV4: | |||
| title: "URL Living Standard - IPv4 Parser" | author: | |||
| - | ||||
| org: WHATWG | ||||
| title: "URL - IPv4 Parser" | ||||
| target: https://url.spec.whatwg.org/#concept-ipv4-parser | target: https://url.spec.whatwg.org/#concept-ipv4-parser | |||
| date: May 2021 | date: May 2021 | |||
| refcontent: | ||||
| "WHATWG Living Standard" | ||||
| ECH-Analysis: | ECH-Analysis: | |||
| title: "A Symbolic Analysis of Privacy for TLS 1.3 with Encrypted Client Hello" | title: "A Symbolic Analysis of Privacy for TLS 1.3 with Encrypted Client Hello" | |||
| target: https://www.cs.ox.ac.uk/people/vincent.cheval/publis/BCW-ccs22.pdf | target: https://www.cs.ox.ac.uk/people/vincent.cheval/publis/BCW-ccs22.pdf | |||
| date: November 2022 | date: November 2022 | |||
| authors: | seriesinfo: | |||
| DOI: 10.1145/3548606.3559360 | ||||
| refcontent: | ||||
| "CCS '22: Proceedings of the 2022 ACM SIGSAC Conference on Computer and Communi | ||||
| cations Security, pp. 365-379" | ||||
| author: | ||||
| - | - | |||
| ins: K. Bhargavan | ins: K. Bhargavan | |||
| org: Inria | org: Inria | |||
| - | - | |||
| ins: V. Cheval | ins: V. Cheval | |||
| org: Inria | org: Inria | |||
| - | - | |||
| ins: C. Wood | ins: C. Wood | |||
| org: Cloudflare | org: Cloudflare | |||
| RFC9499: | ||||
| display: DNS-TERMS | ||||
| I-D.kazuho-protected-sni: | ||||
| display: PROTECTED-SNI | ||||
| --- abstract | --- abstract | |||
| <!-- [rfced] References | ||||
| a) Regarding [WHATWG-IPV4], this reference's date is May 2021. | ||||
| The URL provided resolves to a page with "Last Updated 12 May 2025". | ||||
| Note that WHATWG provides "commit snapshots" of their living standards and | ||||
| there are several commit snapshots from May 2021 with the latest being from 20 | ||||
| May 2021. For example: 20 May 2021 | ||||
| (https://url.spec.whatwg.org/commit-snapshots/1b8b8c55eb4bed9f139c9a439fb1c1bf5566b61 | ||||
| 9/#concept-ipv4-parser) | ||||
| We recommend updating this reference to the most current version of the WHATWG | ||||
| Living Standard, replacing the URL with the more general URL to the standard | ||||
| (https://url.spec.whatwg.org/), and adding a "commit snapshot" URL to the | ||||
| reference. | ||||
| Current: | ||||
| [WHATWG-IPV4] | ||||
| WHATWG, "URL - IPv4 Parser", WHATWG Living Standard, May | ||||
| 2021, <https://url.spec.whatwg.org/#concept-ipv4-parser>. | ||||
| b) RFC 6125 has been obsoleted by RFC 9525. May we replace RFC 6125 | ||||
| with RFC 9525? | ||||
| c) Informative Reference RFC 5077 has been obsoleted by RFC 8446. We | ||||
| recommend replacing RFC 5077 with RFC 8446. However, if RFC 5077 must be | ||||
| referenced, we suggest mentioning RFC 8446 (e.g., RFC 5077 has been obsoleted | ||||
| by RFC 8446). See Section 4.8.6 in the RFC Style Guide (RFC 7322). | ||||
| d) FYI, RFCYYY1 (draft-ietf-tls-svcb-ech) will be updated during the XML stage. | ||||
| --> | ||||
| <!-- [rfced] Please insert any keywords (beyond those that appear in | ||||
| the title) for use on https://www.rfc-editor.org/search. --> | ||||
| This document describes a mechanism in Transport Layer Security (TLS) for | This document describes a mechanism in Transport Layer Security (TLS) for | |||
| encrypting a ClientHello message under a server public key. | encrypting a ClientHello message under a server public key. | |||
| --- middle | --- middle | |||
| # Introduction {#intro} | # Introduction {#intro} | |||
| Although TLS 1.3 {{!RFC8446}} encrypts most of the handshake, including the | Although TLS 1.3 {{!RFC8446}} encrypts most of the handshake, including the | |||
| server certificate, there are several ways in which an on-path attacker can | server certificate, there are several ways in which an on-path attacker can | |||
| learn private information about the connection. The plaintext Server Name | learn private information about the connection. The plaintext Server Name | |||
| Indication (SNI) extension in ClientHello messages, which leaks the target | Indication (SNI) extension in ClientHello messages, which leaks the target | |||
| domain for a given connection, is perhaps the most sensitive information | domain for a given connection, is perhaps the most sensitive information | |||
| left unencrypted in TLS 1.3. | left unencrypted in TLS 1.3. | |||
| This document specifies a new TLS extension, called Encrypted Client Hello | This document specifies a new TLS extension called Encrypted Client Hello | |||
| (ECH), that allows clients to encrypt their ClientHello to the TLS server. | (ECH) that allows clients to encrypt their ClientHello to the TLS server. | |||
| This protects the SNI and other potentially sensitive fields, such as the | This protects the SNI and other potentially sensitive fields, such as the | |||
| Application Layer Protocol Negotiation (ALPN) | Application-Layer Protocol Negotiation (ALPN) list {{?RFC7301}}. Co-located servers w | |||
| list {{?RFC7301}}. Co-located servers with consistent externally visible TLS | ith consistent externally visible TLS | |||
| configurations and behavior, including supported versions and cipher suites and | configurations and behavior, including supported versions and cipher suites and | |||
| how they respond to incoming client connections, form an anonymity set. (Note | how they respond to incoming client connections, form an anonymity set. (Note | |||
| that implementation-specific choices, such as extension ordering within TLS | that implementation-specific choices, such as extension ordering within TLS | |||
| messages or division of data into record-layer boundaries, can result in | messages or division of data into record-layer boundaries, can result in | |||
| different externally visible behavior, even for servers with consistent TLS | different externally visible behavior, even for servers with consistent TLS | |||
| configurations.) Usage of this mechanism reveals that a client is connecting | configurations.) Usage of this mechanism reveals that a client is connecting | |||
| to a particular service provider, but does not reveal which server from the | to a particular service provider, but does not reveal which server from the | |||
| anonymity set terminates the connection. Deployment implications of this | anonymity set terminates the connection. Deployment implications of this | |||
| feature are discussed in {{deployment}}. | feature are discussed in {{deployment}}. | |||
| skipping to change at line 167 ¶ | skipping to change at line 241 ¶ | |||
| {: #split-mode title="Split Mode Topology"} | {: #split-mode title="Split Mode Topology"} | |||
| In Split Mode, the provider is not the origin server for private domains. | In Split Mode, the provider is not the origin server for private domains. | |||
| Rather, the DNS records for private domains point to the provider, and the | Rather, the DNS records for private domains point to the provider, and the | |||
| provider's server relays the connection back to the origin server, who | provider's server relays the connection back to the origin server, who | |||
| terminates the TLS connection with the client. Importantly, the service provider | terminates the TLS connection with the client. Importantly, the service provider | |||
| does not have access to the plaintext of the connection beyond the unencrypted | does not have access to the plaintext of the connection beyond the unencrypted | |||
| portions of the handshake. | portions of the handshake. | |||
| In the remainder of this document, we will refer to the ECH-service provider as | In the remainder of this document, we will refer to the ECH-service provider as | |||
| the "client-facing server" and to the TLS terminator as the "backend server". | the "client-facing server" and the TLS terminator as the "backend server". | |||
| These are the same entity in Shared Mode, but in Split Mode, the client-facing | These are the same entity in Shared Mode, but in Split Mode, the client-facing | |||
| and backend servers are physically separated. | and backend servers are physically separated. | |||
| See {{security-considerations}} for more discussion about the ECH threat model | See {{security-considerations}} for more discussion about the ECH threat model | |||
| and how it relates to the client, client-facing server, and backend server. | and how it relates to the client, client-facing server, and backend server. | |||
| ## Encrypted ClientHello (ECH) | ## Encrypted ClientHello (ECH) | |||
| A client-facing server enables ECH by publishing an ECH configuration, which | A client-facing server enables ECH by publishing an ECH configuration, which | |||
| is an encryption public key and associated metadata. Domains which wish to | is an encryption public key and associated metadata. Domains which wish to | |||
| use ECH must publish this configuration, using the key associated | use ECH must publish this configuration, using the key associated | |||
| with the client-facing server. This document | with the client-facing server. This document | |||
| defines the ECH configuration's format, but delegates DNS publication details | defines the ECH configuration's format, but delegates DNS publication details | |||
| to {{!RFC9460}}. See | to {{!RFC9460}}. See | |||
| {{!ECH-IN-DNS=I-D.ietf-tls-svcb-ech}} for specifics about how ECH configurations | {{RFCYYY1}} for specifics about how ECH configurations | |||
| are advertised in SVCB and HTTPS records. Other delivery mechanisms are | are advertised in SVCB and HTTPS records. Other delivery mechanisms are | |||
| also possible. For example, the client may have the ECH configuration | also possible. For example, the client may have the ECH configuration | |||
| preconfigured. | preconfigured. | |||
| When a client wants to establish a TLS session with some backend server, it | When a client wants to establish a TLS session with some backend server, it | |||
| constructs a private ClientHello, referred to as the ClientHelloInner. | constructs a private ClientHello, referred to as the ClientHelloInner. | |||
| The client then constructs a public ClientHello, referred to as the | The client then constructs a public ClientHello, referred to as the | |||
| ClientHelloOuter. The ClientHelloOuter contains innocuous values for | ClientHelloOuter. The ClientHelloOuter contains innocuous values for | |||
| sensitive extensions and an "encrypted_client_hello" extension | sensitive extensions and an "encrypted_client_hello" extension | |||
| ({{encrypted-client-hello}}), which carries the encrypted ClientHelloInner. | ({{encrypted-client-hello}}), which carries the encrypted ClientHelloInner. | |||
| skipping to change at line 216 ¶ | skipping to change at line 290 ¶ | |||
| the client for application data. Instead, ECH rejection allows the client to | the client for application data. Instead, ECH rejection allows the client to | |||
| retry with up-to-date configuration ({{rejected-ech}}). | retry with up-to-date configuration ({{rejected-ech}}). | |||
| The primary goal of ECH is to ensure that connections to servers in the same | The primary goal of ECH is to ensure that connections to servers in the same | |||
| anonymity set are indistinguishable from one another. Moreover, it should | anonymity set are indistinguishable from one another. Moreover, it should | |||
| achieve this goal without affecting any existing security properties of TLS 1.3. | achieve this goal without affecting any existing security properties of TLS 1.3. | |||
| See {{goals}} for more details about the ECH security and privacy goals. | See {{goals}} for more details about the ECH security and privacy goals. | |||
| # Encrypted ClientHello Configuration {#ech-configuration} | # Encrypted ClientHello Configuration {#ech-configuration} | |||
| ECH uses HPKE for public key encryption {{!HPKE=RFC9180}}. | ECH uses Hybrid Public Key Encryption (HPKE) for public key encryption {{RFC9180}}. | |||
| The ECH configuration is defined by the following `ECHConfig` structure. | The ECH configuration is defined by the following `ECHConfig` structure. | |||
| ~~~~ | ~~~~ | |||
| opaque HpkePublicKey<1..2^16-1>; | opaque HpkePublicKey<1..2^16-1>; | |||
| uint16 HpkeKemId; // Defined in RFC9180 | uint16 HpkeKemId; // Defined in RFC 9180 | |||
| uint16 HpkeKdfId; // Defined in RFC9180 | uint16 HpkeKdfId; // Defined in RFC 9180 | |||
| uint16 HpkeAeadId; // Defined in RFC9180 | uint16 HpkeAeadId; // Defined in RFC 9180 | |||
| uint16 ECHConfigExtensionType; // Defined in Section 11.3 | uint16 ECHConfigExtensionType; // Defined in Section 11.3 | |||
| struct { | struct { | |||
| HpkeKdfId kdf_id; | HpkeKdfId kdf_id; | |||
| HpkeAeadId aead_id; | HpkeAeadId aead_id; | |||
| } HpkeSymmetricCipherSuite; | } HpkeSymmetricCipherSuite; | |||
| struct { | struct { | |||
| uint8 config_id; | uint8 config_id; | |||
| HpkeKemId kem_id; | HpkeKemId kem_id; | |||
| skipping to change at line 261 ¶ | skipping to change at line 335 ¶ | |||
| uint16 version; | uint16 version; | |||
| uint16 length; | uint16 length; | |||
| select (ECHConfig.version) { | select (ECHConfig.version) { | |||
| case 0xfe0d: ECHConfigContents contents; | case 0xfe0d: ECHConfigContents contents; | |||
| } | } | |||
| } ECHConfig; | } ECHConfig; | |||
| ~~~~ | ~~~~ | |||
| The structure contains the following fields: | The structure contains the following fields: | |||
| version | version: | |||
| : The version of ECH for which this configuration is used. The version | : The version of ECH for which this configuration is used. The version | |||
| is the same as the code point for the | is the same as the code point for the | |||
| "encrypted_client_hello" extension. Clients MUST ignore any `ECHConfig` | "encrypted_client_hello" extension. Clients MUST ignore any `ECHConfig` | |||
| structure with a version they do not support. | structure with a version they do not support. | |||
| length | length: | |||
| : The length, in bytes, of the next field. This length field allows | : The length, in bytes, of the next field. This length field allows | |||
| implementations to skip over the elements in such a list where they cannot | implementations to skip over the elements in such a list where they cannot | |||
| parse the specific version of ECHConfig. | parse the specific version of ECHConfig. | |||
| contents | contents: | |||
| : An opaque byte string whose contents depend on the version. For this | : An opaque byte string whose contents depend on the version. For this | |||
| specification, the contents are an `ECHConfigContents` structure. | specification, the contents are an `ECHConfigContents` structure. | |||
| The `ECHConfigContents` structure contains the following fields: | The `ECHConfigContents` structure contains the following fields: | |||
| key_config | key_config: | |||
| : A `HpkeKeyConfig` structure carrying the configuration information | : A `HpkeKeyConfig` structure carrying the configuration information | |||
| associated with the HPKE public key (an "ECH key"). Note that this | associated with the HPKE public key (an "ECH key"). Note that this | |||
| structure contains the `config_id` field, which applies to the entire | structure contains the `config_id` field, which applies to the entire | |||
| ECHConfigContents. | ECHConfigContents. | |||
| maximum_name_length | maximum_name_length: | |||
| : The longest name of a backend server, if known. If not known, this value can | : The longest name of a backend server, if known. If not known, this value can | |||
| be set to zero. It is used to compute padding ({{padding}}) and does not | be set to zero. It is used to compute padding ({{padding}}) and does not | |||
| constrain server name lengths. Names may exceed this length if, e.g., | constrain server name lengths. Names may exceed this length if, e.g., | |||
| the server uses wildcard names or added new names to the anonymity set. | the server uses wildcard names or added new names to the anonymity set. | |||
| public_name | public_name: | |||
| : The DNS name of the client-facing server, i.e., the entity trusted | : The DNS name of the client-facing server, i.e., the entity trusted | |||
| to update the ECH configuration. This is used to correct misconfigured clients, | to update the ECH configuration. This is used to correct misconfigured clients, | |||
| as described in {{rejected-ech}}. | as described in {{rejected-ech}}. | |||
| : See {{auth-public-name}} for how the client interprets and validates the | : See {{auth-public-name}} for how the client interprets and validates the | |||
| public_name. | public_name. | |||
| extensions | extensions: | |||
| : A list of ECHConfigExtension values that the client must take into | : A list of ECHConfigExtension values that the client must take into | |||
| consideration when generating a ClientHello message. Each ECHConfigExtension | consideration when generating a ClientHello message. Each ECHConfigExtension | |||
| has a 2-octet type and opaque data value, where the data value is encoded | has a 2-octet type and opaque data value, where the data value is encoded | |||
| with a 2-octet integer representing the length of the data, in network byte | with a 2-octet integer representing the length of the data, in network byte | |||
| order. ECHConfigExtension values are described below ({{config-extensions}}). | order. ECHConfigExtension values are described below ({{config-extensions}}). | |||
| The `HpkeKeyConfig` structure contains the following fields: | The `HpkeKeyConfig` structure contains the following fields: | |||
| config_id | config_id: | |||
| : A one-byte identifier for the given HPKE key configuration. This is used by | : A one-byte identifier for the given HPKE key configuration. This is used by | |||
| clients to indicate the key used for ClientHello encryption. {{config-ids}} | clients to indicate the key used for ClientHello encryption. {{config-ids}} | |||
| describes how client-facing servers allocate this value. | describes how client-facing servers allocate this value. | |||
| kem_id | kem_id: | |||
| : The HPKE Key Encapsulation Mechanism (KEM) identifier corresponding | : The HPKE Key Encapsulation Mechanism (KEM) identifier corresponding | |||
| to `public_key`. Clients MUST ignore any `ECHConfig` structure with a | to `public_key`. Clients MUST ignore any `ECHConfig` structure with a | |||
| key using a KEM they do not support. | key using a KEM they do not support. | |||
| public_key | public_key: | |||
| : The HPKE public key used by the client to encrypt ClientHelloInner. | : The HPKE public key used by the client to encrypt ClientHelloInner. | |||
| cipher_suites | cipher_suites: | |||
| : The list of HPKE KDF and AEAD identifier pairs clients can use for encrypting | : The list of HPKE Key Derivation Function (KDF) and Authenticated Encryption with As | |||
| sociated Data (AEAD) identifier pairs clients can use for encrypting | ||||
| ClientHelloInner. See {{real-ech}} for how clients choose from this list. | ClientHelloInner. See {{real-ech}} for how clients choose from this list. | |||
| The client-facing server advertises a sequence of ECH configurations to clients, | The client-facing server advertises a sequence of ECH configurations to clients, | |||
| serialized as follows. | serialized as follows. | |||
| ~~~~ | ~~~~ | |||
| ECHConfig ECHConfigList<4..2^16-1>; | ECHConfig ECHConfigList<4..2^16-1>; | |||
| ~~~~ | ~~~~ | |||
| The `ECHConfigList` structure contains one or more `ECHConfig` structures in | The `ECHConfigList` structure contains one or more `ECHConfig` structures in | |||
| decreasing order of preference. This allows a server to support multiple | decreasing order of preference. This allows a server to support multiple | |||
| versions of ECH and multiple sets of ECH parameters. | versions of ECH and multiple sets of ECH parameters. | |||
| ## Configuration Identifiers {#config-ids} | ## Configuration Identifiers {#config-ids} | |||
| A client-facing server has a set of known ECHConfig values, with corresponding | A client-facing server has a set of known ECHConfig values with corresponding | |||
| private keys. This set SHOULD contain the currently published values, as well as | private keys. This set SHOULD contain the currently published values, as well as | |||
| previous values that may still be in use, since clients may cache DNS records | previous values that may still be in use, since clients may cache DNS records | |||
| up to a TTL or longer. | up to a TTL or longer. | |||
| {{client-facing-server}} describes a trial decryption process for decrypting the | {{client-facing-server}} describes a trial decryption process for decrypting the | |||
| ClientHello. This can impact performance when the client-facing server maintains | ClientHello. This can impact performance when the client-facing server maintains | |||
| many known ECHConfig values. To avoid this, the client-facing server SHOULD | many known ECHConfig values. To avoid this, the client-facing server SHOULD | |||
| allocate distinct `config_id` values for each ECHConfig in its known set. The | allocate distinct `config_id` values for each ECHConfig in its known set. The | |||
| RECOMMENDED strategy is via rejection sampling, i.e., to randomly select | RECOMMENDED strategy is via rejection sampling, i.e., to randomly select | |||
| `config_id` repeatedly until it does not match any known ECHConfig. | `config_id` repeatedly until it does not match any known ECHConfig. | |||
| skipping to change at line 375 ¶ | skipping to change at line 449 ¶ | |||
| can be tagged as mandatory by using an extension type codepoint with | can be tagged as mandatory by using an extension type codepoint with | |||
| the high order bit set to 1. | the high order bit set to 1. | |||
| Clients MUST parse the extension list and check for unsupported mandatory | Clients MUST parse the extension list and check for unsupported mandatory | |||
| extensions. If an unsupported mandatory extension is present, clients MUST | extensions. If an unsupported mandatory extension is present, clients MUST | |||
| ignore the `ECHConfig`. | ignore the `ECHConfig`. | |||
| Any future information or hints that influence ClientHelloOuter SHOULD be | Any future information or hints that influence ClientHelloOuter SHOULD be | |||
| specified as ECHConfig extensions. This is primarily because the outer | specified as ECHConfig extensions. This is primarily because the outer | |||
| ClientHello exists only in support of ECH. Namely, it is both an envelope for | ClientHello exists only in support of ECH. Namely, it is both an envelope for | |||
| the encrypted inner ClientHello and enabler for authenticated key mismatch | the encrypted inner ClientHello and an enabler for authenticated key mismatch | |||
| signals (see {{server-behavior}}). In contrast, the inner ClientHello is the | signals (see {{server-behavior}}). In contrast, the inner ClientHello is the | |||
| true ClientHello used upon ECH negotiation. | true ClientHello used upon ECH negotiation. | |||
| # The "encrypted_client_hello" Extension {#encrypted-client-hello} | # The "encrypted_client_hello" Extension {#encrypted-client-hello} | |||
| To offer ECH, the client sends an "encrypted_client_hello" extension in the | To offer ECH, the client sends an "encrypted_client_hello" extension in the | |||
| ClientHelloOuter. When it does, it MUST also send the extension in | ClientHelloOuter. When it does, it MUST also send the extension in | |||
| ClientHelloInner. | ClientHelloInner. | |||
| ~~~ | ~~~ | |||
| skipping to change at line 416 ¶ | skipping to change at line 490 ¶ | |||
| }; | }; | |||
| } ECHClientHello; | } ECHClientHello; | |||
| ~~~~ | ~~~~ | |||
| The outer extension uses the `outer` variant and the inner extension uses the | The outer extension uses the `outer` variant and the inner extension uses the | |||
| `inner` variant. The inner extension has an empty payload, which is included | `inner` variant. The inner extension has an empty payload, which is included | |||
| because TLS servers are not allowed to provide extensions in ServerHello | because TLS servers are not allowed to provide extensions in ServerHello | |||
| which were not included in ClientHello. The outer extension has the following | which were not included in ClientHello. The outer extension has the following | |||
| fields: | fields: | |||
| config_id | config_id: | |||
| : The ECHConfigContents.key_config.config_id for the chosen ECHConfig. | : The ECHConfigContents.key_config.config_id for the chosen ECHConfig. | |||
| cipher_suite | cipher_suite: | |||
| : The cipher suite used to encrypt ClientHelloInner. This MUST match a value | : The cipher suite used to encrypt ClientHelloInner. This MUST match a value | |||
| provided in the corresponding `ECHConfigContents.cipher_suites` list. | provided in the corresponding `ECHConfigContents.cipher_suites` list. | |||
| enc | enc: | |||
| : The HPKE encapsulated key, used by servers to decrypt the corresponding | : The HPKE encapsulated key used by servers to decrypt the corresponding | |||
| `payload` field. This field is empty in a ClientHelloOuter sent in response to | `payload` field. This field is empty in a ClientHelloOuter sent in response to | |||
| HelloRetryRequest. | HelloRetryRequest. | |||
| payload | payload: | |||
| : The serialized and encrypted EncodedClientHelloInner structure, encrypted | : The serialized and encrypted EncodedClientHelloInner structure, encrypted | |||
| using HPKE as described in {{real-ech}}. | using HPKE as described in {{real-ech}}. | |||
| When a client offers the `outer` version of an "encrypted_client_hello" | When a client offers the `outer` version of an "encrypted_client_hello" | |||
| extension, the server MAY include an "encrypted_client_hello" extension in its | extension, the server MAY include an "encrypted_client_hello" extension in its | |||
| EncryptedExtensions message, as described in {{client-facing-server}}, with the | EncryptedExtensions message, as described in {{client-facing-server}}, with the | |||
| following payload: | following payload: | |||
| ~~~ | ~~~ | |||
| struct { | struct { | |||
| ECHConfigList retry_configs; | ECHConfigList retry_configs; | |||
| } ECHEncryptedExtensions; | } ECHEncryptedExtensions; | |||
| ~~~ | ~~~ | |||
| The response is valid only when the server used the ClientHelloOuter. If the | The response is valid only when the server used the ClientHelloOuter. If the | |||
| server sent this extension in response to the `inner` variant, then the client | server sent this extension in response to the `inner` variant, then the client | |||
| MUST abort with an "unsupported_extension" alert. | MUST abort with an "unsupported_extension" alert. | |||
| retry_configs | retry_configs: | |||
| : An ECHConfigList structure containing one or more ECHConfig structures, in | : An ECHConfigList structure containing one or more ECHConfig structures, in | |||
| decreasing order of preference, to be used by the client as described in | decreasing order of preference, to be used by the client as described in | |||
| {{rejected-ech}}. These are known as the server's "retry configurations". | {{rejected-ech}}. These are known as the server's "retry configurations". | |||
| Finally, when the client offers the "encrypted_client_hello", if the payload is | Finally, when the client offers the "encrypted_client_hello", if the payload is | |||
| the `inner` variant and the server responds with HelloRetryRequest, it MUST | the `inner` variant and the server responds with HelloRetryRequest, it MUST | |||
| include an "encrypted_client_hello" extension with the following payload: | include an "encrypted_client_hello" extension with the following payload: | |||
| ~~~ | ~~~ | |||
| struct { | struct { | |||
| skipping to change at line 472 ¶ | skipping to change at line 546 ¶ | |||
| The value of ECHHelloRetryRequest.confirmation is set to | The value of ECHHelloRetryRequest.confirmation is set to | |||
| `hrr_accept_confirmation` as described in {{backend-server-hrr}}. | `hrr_accept_confirmation` as described in {{backend-server-hrr}}. | |||
| This document also defines the "ech_required" alert, which the client MUST send | This document also defines the "ech_required" alert, which the client MUST send | |||
| when it offered an "encrypted_client_hello" extension that was not accepted by | when it offered an "encrypted_client_hello" extension that was not accepted by | |||
| the server. (See {{alerts}}.) | the server. (See {{alerts}}.) | |||
| ## Encoding the ClientHelloInner {#encoding-inner} | ## Encoding the ClientHelloInner {#encoding-inner} | |||
| Before encrypting, the client pads and optionally compresses ClientHelloInner | Before encrypting, the client pads and optionally compresses ClientHelloInner | |||
| into a EncodedClientHelloInner structure, defined below: | into an EncodedClientHelloInner structure, defined below: | |||
| ~~~ | ~~~ | |||
| struct { | struct { | |||
| ClientHello client_hello; | ClientHello client_hello; | |||
| uint8 zeros[length_of_padding]; | uint8 zeros[length_of_padding]; | |||
| } EncodedClientHelloInner; | } EncodedClientHelloInner; | |||
| ~~~ | ~~~ | |||
| The `client_hello` field is computed by first making a copy of ClientHelloInner | The `client_hello` field is computed by first making a copy of ClientHelloInner | |||
| and setting the `legacy_session_id` field to the empty string. In TLS, this | and setting the `legacy_session_id` field to the empty string. In TLS, this | |||
| skipping to change at line 510 ¶ | skipping to change at line 584 ¶ | |||
| ExtensionType OuterExtensions<2..254>; | ExtensionType OuterExtensions<2..254>; | |||
| ~~~ | ~~~ | |||
| OuterExtensions contains the removed ExtensionType values. Each value references | OuterExtensions contains the removed ExtensionType values. Each value references | |||
| the matching extension in ClientHelloOuter. The values MUST be ordered | the matching extension in ClientHelloOuter. The values MUST be ordered | |||
| contiguously in ClientHelloInner, and the "ech_outer_extensions" extension MUST | contiguously in ClientHelloInner, and the "ech_outer_extensions" extension MUST | |||
| be inserted in the corresponding position in EncodedClientHelloInner. | be inserted in the corresponding position in EncodedClientHelloInner. | |||
| Additionally, the extensions MUST appear in ClientHelloOuter in the same | Additionally, the extensions MUST appear in ClientHelloOuter in the same | |||
| relative order. However, there is no requirement that they be contiguous. For | relative order. However, there is no requirement that they be contiguous. For | |||
| example, OuterExtensions may contain extensions A, B, C, while ClientHelloOuter | example, OuterExtensions may contain extensions A, B, and C, while ClientHelloOuter | |||
| contains extensions A, D, B, C, E, F. | contains extensions A, D, B, C, E, and F. | |||
| The "ech_outer_extensions" extension can only be included in | The "ech_outer_extensions" extension can only be included in | |||
| EncodedClientHelloInner, and MUST NOT appear in either ClientHelloOuter or | EncodedClientHelloInner and MUST NOT appear in either ClientHelloOuter or | |||
| ClientHelloInner. | ClientHelloInner. | |||
| Finally, the client pads the message by setting the `zeros` field to a byte | Finally, the client pads the message by setting the `zeros` field to a byte | |||
| string whose contents are all zeros and whose length is the amount of padding | string whose contents are all zeros and whose length is the amount of padding | |||
| to add. {{padding}} describes a recommended padding scheme. | to add. {{padding}} describes a recommended padding scheme. | |||
| The client-facing server computes ClientHelloInner by reversing this process. | The client-facing server computes ClientHelloInner by reversing this process. | |||
| First it parses EncodedClientHelloInner, interpreting all bytes after | First, it parses EncodedClientHelloInner, interpreting all bytes after | |||
| `client_hello` as padding. If any padding byte is non-zero, the server MUST | `client_hello` as padding. If any padding byte is non-zero, the server MUST | |||
| abort the connection with an "illegal_parameter" alert. | abort the connection with an "illegal_parameter" alert. | |||
| Next it makes a copy of the `client_hello` field and copies the | Next, it makes a copy of the `client_hello` field and copies the | |||
| `legacy_session_id` field from ClientHelloOuter. It then looks for an | `legacy_session_id` field from ClientHelloOuter. It then looks for an | |||
| "ech_outer_extensions" extension. If found, it replaces the extension with the | "ech_outer_extensions" extension. If found, it replaces the extension with the | |||
| corresponding sequence of extensions in the ClientHelloOuter. The server MUST | corresponding sequence of extensions in the ClientHelloOuter. The server MUST | |||
| abort the connection with an "illegal_parameter" alert if any of the following | abort the connection with an "illegal_parameter" alert if any of the following | |||
| are true: | are true: | |||
| * Any referenced extension is missing in ClientHelloOuter. | * Any referenced extension is missing in ClientHelloOuter. | |||
| * Any extension is referenced in OuterExtensions more than once. | * Any extension is referenced in OuterExtensions more than once. | |||
| * "encrypted_client_hello" is referenced in OuterExtensions. | * "encrypted_client_hello" is referenced in OuterExtensions. | |||
| * The extensions in ClientHelloOuter corresponding to those in OuterExtensions | * The extensions in ClientHelloOuter corresponding to those in OuterExtensions | |||
| do not occur in the same order. | do not occur in the same order. | |||
| These requirements prevent an attacker from performing a packet amplification | These requirements prevent an attacker from performing a packet amplification | |||
| attack, by crafting a ClientHelloOuter which decompresses to a much larger | attack by crafting a ClientHelloOuter which decompresses to a much larger | |||
| ClientHelloInner. This is discussed further in {{decompression-amp}}. | ClientHelloInner. This is discussed further in {{decompression-amp}}. | |||
| Implementations SHOULD construct the ClientHelloInner in linear | Implementations SHOULD construct the ClientHelloInner in linear | |||
| time. Quadratic time implementations (such as may happen via naive | time. Quadratic time implementations (such as may happen via naive | |||
| copying) create a denial of service risk. | copying) create a denial-of-service risk. | |||
| {{linear-outer-extensions}} describes a linear-time procedure that may be used | {{linear-outer-extensions}} describes a linear-time procedure that may be used | |||
| for this purpose. | for this purpose. | |||
| ## Authenticating the ClientHelloOuter {#authenticating-outer} | ## Authenticating the ClientHelloOuter {#authenticating-outer} | |||
| To prevent a network attacker from modifying the `ClientHelloOuter` | To prevent a network attacker from modifying the `ClientHelloOuter` | |||
| while keeping the same encrypted `ClientHelloInner` | while keeping the same encrypted `ClientHelloInner` | |||
| (see {{flow-clienthello-malleability}}), ECH authenticates ClientHelloOuter | (see {{flow-clienthello-malleability}}), ECH authenticates ClientHelloOuter | |||
| by passing ClientHelloOuterAAD as the associated data for HPKE sealing | by passing ClientHelloOuterAAD as the associated data for HPKE sealing | |||
| and opening operations. The ClientHelloOuterAAD is a serialized | and opening operations. The ClientHelloOuterAAD is a serialized | |||
| ClientHello structure, defined in {{Section 4.1.2 of RFC8446}} for TLS and | ClientHello structure, defined in {{Section 4.1.2 of RFC8446}} for TLS and | |||
| {{Section 5.3 of RFC9147}} for DTLS, which matches the ClientHelloOuter except | {{Section 5.3 of RFC9147}} for DTLS, which matches the ClientHelloOuter except | |||
| that the `payload` field of the "encrypted_client_hello" is replaced with a byte | that the `payload` field of the "encrypted_client_hello" is replaced with a byte | |||
| string of the same length but whose contents are zeros. This value does not | string of the same length but whose contents are zeros. This value does not | |||
| include Handshake structure's four-byte header in TLS nor twelve-byte header in | include Handshake structure's four-byte header in TLS nor twelve-byte header in | |||
| DTLS. | DTLS. | |||
| # Client Behavior | # Client Behavior | |||
| Clients that implement the ECH extension behave in one of two ways: either they | Clients that implement the ECH extension behave in one of two ways: either they | |||
| offer a real ECH extension, as described in {{real-ech}}; or they send a | offer a real ECH extension, as described in {{real-ech}}, or they send a | |||
| Generate Random Extensions And Sustain Extensibility (GREASE) {{?RFC8701}} | Generate Random Extensions And Sustain Extensibility (GREASE) {{?RFC8701}} | |||
| ECH extension, as described in {{grease-ech}}. Clients of the latter type do not | ECH extension, as described in {{grease-ech}}. Clients of the latter type do not | |||
| negotiate ECH. Instead, they generate a dummy ECH extension that is ignored by | negotiate ECH. Instead, they generate a dummy ECH extension that is ignored by | |||
| the server. (See {{dont-stick-out}} for an explanation.) The client offers ECH | the server. (See {{dont-stick-out}} for an explanation.) The client offers ECH | |||
| if it is in possession of a compatible ECH configuration and sends GREASE ECH | if it is in possession of a compatible ECH configuration and sends GREASE ECH | |||
| (see {{grease-ech}}) otherwise. | (see {{grease-ech}}) otherwise. | |||
| ## Offering ECH {#real-ech} | ## Offering ECH {#real-ech} | |||
| To offer ECH, the client first chooses a suitable ECHConfig from the server's | To offer ECH, the client first chooses a suitable ECHConfig from the server's | |||
| skipping to change at line 637 ¶ | skipping to change at line 711 ¶ | |||
| ClientHelloOuter.random using a secure random number generator. (See | ClientHelloOuter.random using a secure random number generator. (See | |||
| {{flow-client-reaction}}.) | {{flow-client-reaction}}.) | |||
| 1. It SHOULD place the value of `ECHConfig.contents.public_name` in the | 1. It SHOULD place the value of `ECHConfig.contents.public_name` in the | |||
| "server_name" extension. Clients that do not follow this step, or place a | "server_name" extension. Clients that do not follow this step, or place a | |||
| different value in the "server_name" extension, risk breaking the retry | different value in the "server_name" extension, risk breaking the retry | |||
| mechanism described in {{rejected-ech}} or failing to interoperate with | mechanism described in {{rejected-ech}} or failing to interoperate with | |||
| servers that require this step to be done; see {{client-facing-server}}. | servers that require this step to be done; see {{client-facing-server}}. | |||
| 1. When the client offers the "pre_shared_key" extension in ClientHelloInner, it | 1. When the client offers the "pre_shared_key" extension in ClientHelloInner, it | |||
| SHOULD also include a GREASE "pre_shared_key" extension in ClientHelloOuter, | SHOULD also include a GREASE "pre_shared_key" extension in ClientHelloOuter, | |||
| generated in the manner described in {{grease-psk}}. The client MUST NOT use | generated in the manner described in {{grease-psk}}. The client MUST NOT use | |||
| this extension to advertise a PSK to the client-facing server. (See | this extension to advertise a Pre-Shared Key (PSK) to the client-facing server. (S ee | |||
| {{flow-clienthello-malleability}}.) When the client includes a GREASE | {{flow-clienthello-malleability}}.) When the client includes a GREASE | |||
| "pre_shared_key" extension, it MUST also copy the "psk_key_exchange_modes" | "pre_shared_key" extension, it MUST also copy the "psk_key_exchange_modes" | |||
| from the ClientHelloInner into the ClientHelloOuter. | from the ClientHelloInner into the ClientHelloOuter. | |||
| 1. When the client offers the "early_data" extension in ClientHelloInner, it | 1. When the client offers the "early_data" extension in ClientHelloInner, it | |||
| MUST also include the "early_data" extension in ClientHelloOuter. This | MUST also include the "early_data" extension in ClientHelloOuter. This | |||
| allows servers that reject ECH and use ClientHelloOuter to safely ignore any | allows servers that reject ECH and use ClientHelloOuter to safely ignore any | |||
| early data sent by the client per {{RFC8446, Section 4.2.10}}. | early data sent by the client per {{RFC8446, Section 4.2.10}}. | |||
| The client might duplicate non-sensitive extensions in both messages. However, | The client might duplicate non-sensitive extensions in both messages. However, | |||
| implementations need to take care to ensure that sensitive extensions are not | implementations need to take care to ensure that sensitive extensions are not | |||
| offered in the ClientHelloOuter. See {{outer-clienthello}} for additional | offered in the ClientHelloOuter. See {{outer-clienthello}} for additional | |||
| guidance. | guidance. | |||
| Finally, the client encrypts the EncodedClientHelloInner with the above values, | Finally, the client encrypts the EncodedClientHelloInner with the above values, | |||
| as described in {{encrypting-clienthello}}, to construct a ClientHelloOuter. It | as described in {{encrypting-clienthello}}, to construct a ClientHelloOuter. It | |||
| sends this to the server, and processes the response as described in | sends this to the server and processes the response as described in | |||
| {{determining-ech-acceptance}}. | {{determining-ech-acceptance}}. | |||
| ### Encrypting the ClientHello {#encrypting-clienthello} | ### Encrypting the ClientHello {#encrypting-clienthello} | |||
| Given an EncodedClientHelloInner, an HPKE encryption context and `enc` value, | Given an EncodedClientHelloInner, an HPKE encryption context and `enc` value, | |||
| and a partial ClientHelloOuterAAD, the client constructs a ClientHelloOuter as | and a partial ClientHelloOuterAAD, the client constructs a ClientHelloOuter as | |||
| follows. | follows. | |||
| First, the client determines the length L of encrypting EncodedClientHelloInner | First, the client determines the length L of encrypting EncodedClientHelloInner | |||
| with the selected HPKE AEAD. This is typically the sum of the plaintext length | with the selected HPKE AEAD. This is typically the sum of the plaintext length | |||
| skipping to change at line 697 ¶ | skipping to change at line 771 ¶ | |||
| to the `ClientHelloInner`, thus preventing attackers from modifying | to the `ClientHelloInner`, thus preventing attackers from modifying | |||
| `ClientHelloOuter` while keeping the same `ClientHelloInner`, as described in | `ClientHelloOuter` while keeping the same `ClientHelloInner`, as described in | |||
| {{flow-clienthello-malleability}}. | {{flow-clienthello-malleability}}. | |||
| Finally, the client replaces `payload` with `final_payload` to obtain | Finally, the client replaces `payload` with `final_payload` to obtain | |||
| ClientHelloOuter. The two values have the same length, so it is not necessary | ClientHelloOuter. The two values have the same length, so it is not necessary | |||
| to recompute length prefixes in the serialized structure. | to recompute length prefixes in the serialized structure. | |||
| Note this construction requires the "encrypted_client_hello" be computed after | Note this construction requires the "encrypted_client_hello" be computed after | |||
| all other extensions. This is possible because the ClientHelloOuter's | all other extensions. This is possible because the ClientHelloOuter's | |||
| "pre_shared_key" extension is either omitted, or uses a random binder | "pre_shared_key" extension is either omitted or uses a random binder | |||
| ({{grease-psk}}). | ({{grease-psk}}). | |||
| ### GREASE PSK {#grease-psk} | ### GREASE PSK {#grease-psk} | |||
| When offering ECH, the client is not permitted to advertise PSK identities in | When offering ECH, the client is not permitted to advertise PSK identities in | |||
| the ClientHelloOuter. However, the client can send a "pre_shared_key" extension | the ClientHelloOuter. However, the client can send a "pre_shared_key" extension | |||
| in the ClientHelloInner. In this case, when resuming a session with the client, | in the ClientHelloInner. In this case, when resuming a session with the client, | |||
| the backend server sends a "pre_shared_key" extension in its ServerHello. This | the backend server sends a "pre_shared_key" extension in its ServerHello. This | |||
| would appear to a network observer as if the server were sending this | would appear to a network observer as if the server were sending this | |||
| extension without solicitation, which would violate the extension rules | extension without solicitation, which would violate the extension rules | |||
| skipping to change at line 729 ¶ | skipping to change at line 803 ¶ | |||
| Per the rules of {{real-ech}}, the server is not permitted to resume a | Per the rules of {{real-ech}}, the server is not permitted to resume a | |||
| connection in the outer handshake. If ECH is rejected and the client-facing | connection in the outer handshake. If ECH is rejected and the client-facing | |||
| server replies with a "pre_shared_key" extension in its ServerHello, then the | server replies with a "pre_shared_key" extension in its ServerHello, then the | |||
| client MUST abort the handshake with an "illegal_parameter" alert. | client MUST abort the handshake with an "illegal_parameter" alert. | |||
| ### Recommended Padding Scheme {#padding} | ### Recommended Padding Scheme {#padding} | |||
| If the ClientHelloInner is encrypted without padding, then the length of | If the ClientHelloInner is encrypted without padding, then the length of | |||
| the `ClientHelloOuter.payload` can leak information about `ClientHelloInner`. | the `ClientHelloOuter.payload` can leak information about `ClientHelloInner`. | |||
| In order to prevent this the `EncodedClientHelloInner` structure | In order to prevent this, the `EncodedClientHelloInner` structure | |||
| has a padding field. This section describes a deterministic mechanism for | has a padding field. This section describes a deterministic mechanism for | |||
| computing the required amount of padding based on the following | computing the required amount of padding based on the following | |||
| observation: individual extensions can reveal sensitive information through | observation: individual extensions can reveal sensitive information through | |||
| their length. Thus, each extension in the inner ClientHello may require | their length. Thus, each extension in the inner ClientHello may require | |||
| different amounts of padding. This padding may be fully determined by the | different amounts of padding. This padding may be fully determined by the | |||
| client's configuration or may require server input. | client's configuration or may require server input. | |||
| By way of example, clients typically support a small number of application | By way of example, clients typically support a small number of application | |||
| profiles. For instance, a browser might support HTTP with ALPN values | profiles. For instance, a browser might support HTTP with ALPN values | |||
| ["http/1.1", "h2"] and WebRTC media with ALPNs ["webrtc", "c-webrtc"]. Clients | ["http/1.1", "h2"] and WebRTC media with ALPNs ["webrtc", "c-webrtc"]. Clients | |||
| skipping to change at line 796 ¶ | skipping to change at line 870 ¶ | |||
| ECH. Otherwise, if it has a length other than 8, the client aborts the handshake | ECH. Otherwise, if it has a length other than 8, the client aborts the handshake | |||
| with a "decode_error" alert. Otherwise, the client computes | with a "decode_error" alert. Otherwise, the client computes | |||
| `hrr_accept_confirmation` as described in {{backend-server-hrr}}. If this value | `hrr_accept_confirmation` as described in {{backend-server-hrr}}. If this value | |||
| matches the extension payload, the server has accepted ECH. Otherwise, it has | matches the extension payload, the server has accepted ECH. Otherwise, it has | |||
| rejected ECH. | rejected ECH. | |||
| If the server accepts ECH, the client handshakes with ClientHelloInner as | If the server accepts ECH, the client handshakes with ClientHelloInner as | |||
| described in {{accepted-ech}}. Otherwise, the client handshakes with | described in {{accepted-ech}}. Otherwise, the client handshakes with | |||
| ClientHelloOuter as described in {{rejected-ech}}. | ClientHelloOuter as described in {{rejected-ech}}. | |||
| <!-- [rfced] In the following sentence, does "length other than 8" refer to | ||||
| bytes? If yes, may we update as follows? | ||||
| Current: | ||||
| Otherwise, if it has a length other than 8, the client aborts the | ||||
| handshake with a "decode_error" alert. | ||||
| Perhaps: | ||||
| Otherwise, if it has a length other than 8 bytes, the client aborts | ||||
| the handshake with a "decode_error" alert. --> | ||||
| ### Handshaking with ClientHelloInner {#accepted-ech} | ### Handshaking with ClientHelloInner {#accepted-ech} | |||
| If the server accepts ECH, the client proceeds with the connection as in | If the server accepts ECH, the client proceeds with the connection as in | |||
| {{RFC8446}}, with the following modifications: | {{RFC8446}}, with the following modifications: | |||
| The client behaves as if it had sent ClientHelloInner as the ClientHello. That | The client behaves as if it had sent ClientHelloInner as the ClientHello. That | |||
| is, it evaluates the handshake using the ClientHelloInner's preferences, and, | is, it evaluates the handshake using the ClientHelloInner's preferences, and, | |||
| when computing the transcript hash ({{Section 4.4.1 of RFC8446}}), it uses | when computing the transcript hash ({{Section 4.4.1 of RFC8446}}), it uses | |||
| ClientHelloInner as the first ClientHello. | ClientHelloInner as the first ClientHello. | |||
| skipping to change at line 817 ¶ | skipping to change at line 902 ¶ | |||
| ClientHello message as follows: | ClientHello message as follows: | |||
| 1. It computes a second ClientHelloInner based on the first ClientHelloInner, as | 1. It computes a second ClientHelloInner based on the first ClientHelloInner, as | |||
| in {{Section 4.1.4 of RFC8446}}. The ClientHelloInner's | in {{Section 4.1.4 of RFC8446}}. The ClientHelloInner's | |||
| "encrypted_client_hello" extension is left unmodified. | "encrypted_client_hello" extension is left unmodified. | |||
| 1. It constructs EncodedClientHelloInner as described in {{encoding-inner}}. | 1. It constructs EncodedClientHelloInner as described in {{encoding-inner}}. | |||
| 1. It constructs a second partial ClientHelloOuterAAD message. This message MUST | 1. It constructs a second partial ClientHelloOuterAAD message. This message MUST | |||
| be syntactically valid. The extensions MAY be copied from the original | be syntactically valid. The extensions MAY be copied from the original | |||
| ClientHelloOuter unmodified, or omitted. If not sensitive, the client MAY | ClientHelloOuter unmodified or omitted. If not sensitive, the client MAY | |||
| copy updated extensions from the second ClientHelloInner for compression. | copy updated extensions from the second ClientHelloInner for compression. | |||
| 1. It encrypts EncodedClientHelloInner as described in | 1. It encrypts EncodedClientHelloInner as described in | |||
| {{encrypting-clienthello}}, using the second partial ClientHelloOuterAAD, to | {{encrypting-clienthello}}, using the second partial ClientHelloOuterAAD, to | |||
| obtain a second ClientHelloOuter. It reuses the original HPKE encryption | obtain a second ClientHelloOuter. It reuses the original HPKE encryption | |||
| context computed in {{real-ech}} and uses the empty string for `enc`. | context computed in {{real-ech}} and uses the empty string for `enc`. | |||
| The HPKE context maintains a sequence number, so this operation internally | The HPKE context maintains a sequence number, so this operation internally | |||
| uses a fresh nonce for each AEAD operation. Reusing the HPKE context avoids | uses a fresh nonce for each AEAD operation. Reusing the HPKE context avoids | |||
| an attack described in {{flow-hrr-hijack}}. | an attack described in {{flow-hrr-hijack}}. | |||
| skipping to change at line 851 ¶ | skipping to change at line 936 ¶ | |||
| return a failure to the calling application. It MUST NOT use the retry | return a failure to the calling application. It MUST NOT use the retry | |||
| configurations. It MUST NOT treat this as a secure signal to | configurations. It MUST NOT treat this as a secure signal to | |||
| disable ECH. | disable ECH. | |||
| If the server supplied an "encrypted_client_hello" extension in its | If the server supplied an "encrypted_client_hello" extension in its | |||
| EncryptedExtensions message, the client MUST check that it is syntactically | EncryptedExtensions message, the client MUST check that it is syntactically | |||
| valid and the client MUST abort the connection with a "decode_error" alert | valid and the client MUST abort the connection with a "decode_error" alert | |||
| otherwise. If an earlier TLS version was negotiated, the client MUST NOT enable | otherwise. If an earlier TLS version was negotiated, the client MUST NOT enable | |||
| the False Start optimization {{RFC7918}} for this handshake. If both | the False Start optimization {{RFC7918}} for this handshake. If both | |||
| authentication and the handshake complete successfully, the client MUST perform | authentication and the handshake complete successfully, the client MUST perform | |||
| the processing described below then abort the connection with an "ech_required" | the processing described below and then abort the connection with an "ech_required" | |||
| alert before sending any application data to the server. | alert before sending any application data to the server. | |||
| If the server provided "retry_configs" and if at least one of the | If the server provided "retry_configs" and if at least one of the | |||
| values contains a version supported by the client, the client can | values contains a version supported by the client, the client can | |||
| regard the ECH configuration as securely replaced by the server. It | regard the ECH configuration as securely replaced by the server. It | |||
| SHOULD retry the handshake with a new transport connection, using the | SHOULD retry the handshake with a new transport connection using the | |||
| retry configurations supplied by the server. | retry configurations supplied by the server. | |||
| Clients can implement a new transport connection in a way that best | Clients can implement a new transport connection in a way that best | |||
| suits their deployment. For example, clients can reuse the same server | suits their deployment. For example, clients can reuse the same server | |||
| IP address when establishing the new transport connection or they can | IP address when establishing the new transport connection or they can | |||
| choose to use a different IP address if provided with options from | choose to use a different IP address if provided with options from | |||
| DNS. ECH does not mandate any specific implementation choices when | DNS. ECH does not mandate any specific implementation choices when | |||
| establishing this new connection. | establishing this new connection. | |||
| The retry configurations are meant to be used for retried connections. Further | The retry configurations are meant to be used for retried connections. Further | |||
| skipping to change at line 896 ¶ | skipping to change at line 981 ¶ | |||
| a node with configuration B in the second. Note that this guidance | a node with configuration B in the second. Note that this guidance | |||
| does not apply to the cases in the previous paragraph where the server | does not apply to the cases in the previous paragraph where the server | |||
| has securely disabled ECH. | has securely disabled ECH. | |||
| If a client does not retry, it MUST report an error to the calling | If a client does not retry, it MUST report an error to the calling | |||
| application. | application. | |||
| ### Authenticating for the Public Name {#auth-public-name} | ### Authenticating for the Public Name {#auth-public-name} | |||
| When the server rejects ECH, it continues with the handshake using the plaintext | When the server rejects ECH, it continues with the handshake using the plaintext | |||
| "server_name" extension instead (see {{server-behavior}}). Clients that offer | "server_name" extension instead (see {{server-behavior}}). Then, clients that offer | |||
| ECH then authenticate the connection with the public name, as follows: | ECH authenticate the connection with the public name as follows: | |||
| - The client MUST verify that the certificate is valid for | - The client MUST verify that the certificate is valid for | |||
| ECHConfig.contents.public_name. If invalid, it MUST abort the connection with | ECHConfig.contents.public_name. If invalid, it MUST abort the connection with | |||
| the appropriate alert. | the appropriate alert. | |||
| - If the server requests a client certificate, the client MUST respond with an | - If the server requests a client certificate, the client MUST respond with an | |||
| empty Certificate message, denoting no client certificate. | empty Certificate message, denoting no client certificate. | |||
| In verifying the client-facing server certificate, the client MUST | In verifying the client-facing server certificate, the client MUST | |||
| interpret the public name as a DNS-based reference identity | interpret the public name as a DNS-based reference identity | |||
| skipping to change at line 924 ¶ | skipping to change at line 1009 ¶ | |||
| Note that authenticating a connection for the public name does not authenticate | Note that authenticating a connection for the public name does not authenticate | |||
| it for the origin. The TLS implementation MUST NOT report such connections as | it for the origin. The TLS implementation MUST NOT report such connections as | |||
| successful to the application. It additionally MUST ignore all session tickets | successful to the application. It additionally MUST ignore all session tickets | |||
| and session IDs presented by the server. These connections are only used to | and session IDs presented by the server. These connections are only used to | |||
| trigger retries, as described in {{rejected-ech}}. This may be implemented, for | trigger retries, as described in {{rejected-ech}}. This may be implemented, for | |||
| instance, by reporting a failed connection with a dedicated error code. | instance, by reporting a failed connection with a dedicated error code. | |||
| Prior to attempting a connection, a client SHOULD validate the `ECHConfig`. | Prior to attempting a connection, a client SHOULD validate the `ECHConfig`. | |||
| Clients SHOULD ignore any | Clients SHOULD ignore any | |||
| `ECHConfig` structure with a public_name that is not a valid host name in | `ECHConfig` structure with a public_name that is not a valid host name in | |||
| preferred name syntax (see {{Section 2 of ?DNS-TERMS=RFC9499}}). That is, to be | preferred name syntax (see {{Section 2 of RFC9499}}). That is, to be | |||
| valid, the public_name needs to be a dot-separated sequence of LDH labels, as | valid, the public_name needs to be a dot-separated sequence of LDH labels, as | |||
| defined in {{Section 2.3.1 of !RFC5890}}, where: | defined in {{Section 2.3.1 of !RFC5890}}, where: | |||
| * the sequence does not begin or end with an ASCII dot, and | * the sequence does not begin or end with an ASCII dot, and | |||
| * all labels are at most 63 octets. | * all labels are at most 63 octets. | |||
| Clients additionally SHOULD ignore the structure if the final LDH | Clients additionally SHOULD ignore the structure if the final LDH | |||
| label either consists of all ASCII digits (i.e. '0' through '9') or is | label either consists of all ASCII digits (i.e., '0' through '9') or is | |||
| "0x" or "0X" followed by some, possibly empty, sequence of ASCII | "0x" or "0X" followed by some, possibly empty, sequence of ASCII | |||
| hexadecimal digits (i.e. '0' through '9', 'a' through 'f', and 'A' | hexadecimal digits (i.e., '0' through '9', 'a' through 'f', and 'A' | |||
| through 'F'). This avoids public_name values that may be interpreted | through 'F'). This avoids public_name values that may be interpreted | |||
| as IPv4 literals. | as IPv4 literals. | |||
| ### Impact of Retry on Future Connections | ### Impact of Retry on Future Connections | |||
| Clients MAY use information learned from a rejected ECH for future | Clients MAY use information learned from a rejected ECH for future | |||
| connections to avoid repeatedly connecting to the same server and | connections to avoid repeatedly connecting to the same server and | |||
| being forced to retry. However, they MUST handle ECH rejection for | being forced to retry. However, they MUST handle ECH rejection for | |||
| those connections as if it were a fresh connection, rather than | those connections as if it were a fresh connection, rather than | |||
| enforcing the single retry limit from {{rejected-ech}}. The reason | enforcing the single retry limit from {{rejected-ech}}. The reason | |||
| for this requirement is that if the server sends a "retry_config" | for this requirement is that if the server sends a "retry_config" | |||
| and then immediately rejects the resulting connection, it is | and then immediately rejects the resulting connection, it is | |||
| most likely misconfigured. However, if the server sends a "retry_config" | most likely misconfigured. However, if the server sends a "retry_config" | |||
| and then the client tries to use that to connect some time | and then the client tries to use that to connect some time | |||
| later, it is possible that the server has changed | later, it is possible that the server has changed | |||
| its configuration again and is now trying to recover. | its configuration again and is now trying to recover. | |||
| Any persisted information MUST be associated with the ECHConfig source | Any persisted information MUST be associated with the ECHConfig source | |||
| used to bootstrap the connection, such as a DNS SVCB ServiceMode record | used to bootstrap the connection, such as a DNS SVCB ServiceMode record | |||
| {{ECH-IN-DNS}}. Clients MUST limit any sharing of persisted ECH-related | {{RFCYYY1}}. Clients MUST limit any sharing of persisted ECH-related | |||
| state to connections that use the same ECHConfig source. Otherwise, it | state to connections that use the same ECHConfig source. Otherwise, it | |||
| might become possible for the client to have the wrong public name for | might become possible for the client to have the wrong public name for | |||
| the server, making recovery impossible. | the server, making recovery impossible. | |||
| ECHConfigs learned from ECH rejection can be used as a tracking | ECHConfigs learned from ECH rejection can be used as a tracking | |||
| vector. Clients SHOULD impose the same lifetime and scope restrictions | vector. Clients SHOULD impose the same lifetime and scope restrictions | |||
| that they apply to other server-based | that they apply to other server-based | |||
| tracking vectors such as PSKs. | tracking vectors such as PSKs. | |||
| In general, the safest way for clients to minimize ECH retries is to | In general, the safest way for clients to minimize ECH retries is to | |||
| skipping to change at line 987 ¶ | skipping to change at line 1072 ¶ | |||
| structure available for the server, it SHOULD send a GREASE {{?RFC8701}} | structure available for the server, it SHOULD send a GREASE {{?RFC8701}} | |||
| "encrypted_client_hello" extension in the first ClientHello as follows: | "encrypted_client_hello" extension in the first ClientHello as follows: | |||
| - Set the `config_id` field to a random byte. | - Set the `config_id` field to a random byte. | |||
| - Set the `cipher_suite` field to a supported HpkeSymmetricCipherSuite. The | - Set the `cipher_suite` field to a supported HpkeSymmetricCipherSuite. The | |||
| selection SHOULD vary to exercise all supported configurations, but MAY be | selection SHOULD vary to exercise all supported configurations, but MAY be | |||
| held constant for successive connections to the same server in the same | held constant for successive connections to the same server in the same | |||
| session. | session. | |||
| - Set the `enc` field to a randomly-generated valid encapsulated public key | - Set the `enc` field to a randomly generated valid encapsulated public key | |||
| output by the HPKE KEM. | output by the HPKE KEM. | |||
| - Set the `payload` field to a randomly-generated string of L+C bytes, where C | - Set the `payload` field to a randomly generated string of L+C bytes, where C | |||
| is the ciphertext expansion of the selected AEAD scheme and L is the size of | is the ciphertext expansion of the selected AEAD scheme and L is the size of | |||
| the EncodedClientHelloInner the client would compute when offering ECH, padded | the EncodedClientHelloInner the client would compute when offering ECH, padded | |||
| according to {{padding}}. | according to {{padding}}. | |||
| If sending a second ClientHello in response to a HelloRetryRequest, the | If sending a second ClientHello in response to a HelloRetryRequest, the | |||
| client copies the entire "encrypted_client_hello" extension from the first | client copies the entire "encrypted_client_hello" extension from the first | |||
| ClientHello. The identical value will reveal to an observer that the value of | ClientHello. The identical value will reveal to an observer that the value of | |||
| "encrypted_client_hello" was fake, but this only occurs if there is a | "encrypted_client_hello" was fake, but this only occurs if there is a | |||
| HelloRetryRequest. | HelloRetryRequest. | |||
| If the server sends an "encrypted_client_hello" extension in either | If the server sends an "encrypted_client_hello" extension in either | |||
| HelloRetryRequest or EncryptedExtensions, the client MUST check the extension | HelloRetryRequest or EncryptedExtensions, the client MUST check the extension | |||
| syntactically and abort the connection with a "decode_error" alert if it is | syntactically and abort the connection with a "decode_error" alert if it is | |||
| invalid. It otherwise ignores the extension. It MUST NOT save the | invalid. It otherwise ignores the extension. It MUST NOT save the | |||
| "retry_configs" value in EncryptedExtensions. | "retry_configs" value in EncryptedExtensions. | |||
| Offering a GREASE extension is not considered offering an encrypted ClientHello | Offering a GREASE extension is not considered offering an encrypted ClientHello | |||
| for purposes of requirements in {{real-ech}}. In particular, the client | for purposes of requirements in {{real-ech}}. In particular, the client | |||
| MAY offer to resume sessions established without ECH. | MAY offer to resume sessions established without ECH. | |||
| <!-- [rfced] It seems that "client" was intended to be "clients" (plural) in | ||||
| the sentence below and updated as follows. Please let us know if that is not | ||||
| accurate. | ||||
| Original: | ||||
| Correctly-implemented client will ignore those extensions. | ||||
| Current: | ||||
| Correctly implemented clients will ignore those extensions. | ||||
| --> | ||||
| ### Server Greasing | ### Server Greasing | |||
| {{config-extensions-iana}} describes a set of Reserved extensions | {{config-extensions-iana}} describes a set of Reserved extensions | |||
| which will never be registered. These can be used by servers to | which will never be registered. These can be used by servers to | |||
| "grease" the contents of the ECH configuration, as inspired by | "grease" the contents of the ECH configuration, as inspired by | |||
| {{?RFC8701}}. This helps ensure clients process ECH extensions | {{?RFC8701}}. This helps ensure clients process ECH extensions | |||
| correctly. When constructing ECH configurations, servers SHOULD | correctly. When constructing ECH configurations, servers SHOULD | |||
| randomly select from reserved values with the high-order bit | randomly select from reserved values with the high-order bit | |||
| clear. Correctly-implemented client will ignore those extensions. | clear. Correctly implemented clients will ignore those extensions. | |||
| The reserved values with the high-order bit set are mandatory, as | The reserved values with the high-order bit set are mandatory, as | |||
| defined in {{config-extensions}}. Servers SHOULD randomly select from | defined in {{config-extensions}}. Servers SHOULD randomly select from | |||
| these values and include them in extraneous ECH configurations. | these values and include them in extraneous ECH configurations. | |||
| Correctly-implemented clients will ignore these configurations because | Correctly implemented clients will ignore these configurations because | |||
| they do not recognize the mandatory extension. Servers SHOULD ensure | they do not recognize the mandatory extension. Servers SHOULD ensure | |||
| that any client using these configurations encounters a warning or error | that any client using these configurations encounters a warning or error | |||
| message. This can be accomplished in several ways, including: | message. This can be accomplished in several ways, including: | |||
| * By giving the extraneous configurations distinctive config IDs or | * By giving the extraneous configurations distinctive config IDs or | |||
| public names, and rejecting the TLS connection or inserting an | public names, and rejecting the TLS connection or inserting an | |||
| application-level warning message when these are observed. | application-level warning message when these are observed. | |||
| * By giving the extraneous configurations an invalid public | * By giving the extraneous configurations an invalid public | |||
| key and a public name not associated with the server, so that | key and a public name not associated with the server so that | |||
| the initial ClientHelloOuter will not be decryptable and | the initial ClientHelloOuter will not be decryptable and | |||
| the server cannot perform the recovery flow described | the server cannot perform the recovery flow described | |||
| in {{rejected-ech}}. | in {{rejected-ech}}. | |||
| # Server Behavior {#server-behavior} | # Server Behavior {#server-behavior} | |||
| As described in {{topologies}}, servers can play two roles, either as | As described in {{topologies}}, servers can play two roles, either as | |||
| the client-facing server or as the back-end server. | the client-facing server or as the back-end server. | |||
| Depending on the server role, the `ECHClientHello` will be different: | Depending on the server role, the `ECHClientHello` will be different: | |||
| * A client-facing server expects a `ECHClientHello.type` of `outer`, and | * A client-facing server expects an `ECHClientHello.type` of `outer`, and | |||
| proceeds as described in {{client-facing-server}} to extract a | proceeds as described in {{client-facing-server}} to extract a | |||
| ClientHelloInner, if available. | ClientHelloInner, if available. | |||
| * A backend server expects a `ECHClientHello.type` of `inner`, and | * A backend server expects an `ECHClientHello.type` of `inner`, and | |||
| proceeds as described in {{backend-server}}. | proceeds as described in {{backend-server}}. | |||
| In split mode, a client-facing server which receives a `ClientHello` | In split mode, a client-facing server which receives a `ClientHello` | |||
| with `ECHClientHello.type` of `inner` MUST abort with an | with `ECHClientHello.type` of `inner` MUST abort with an | |||
| "illegal_parameter" alert. Similarly, in split mode, a backend server | "illegal_parameter" alert. Similarly, in split mode, a backend server | |||
| which receives a `ClientHello` with `ECHClientHello.type` of `outer` | which receives a `ClientHello` with `ECHClientHello.type` of `outer` | |||
| MUST abort with an "illegal_parameter" alert. | MUST abort with an "illegal_parameter" alert. | |||
| In shared mode, a server plays both roles, first decrypting the | In shared mode, a server plays both roles, first decrypting the | |||
| `ClientHelloOuter` and then using the contents of the | `ClientHelloOuter` and then using the contents of the | |||
| skipping to change at line 1074 ¶ | skipping to change at line 1170 ¶ | |||
| If `ECHClientHello.type` is not a valid `ECHClientHelloType`, then | If `ECHClientHello.type` is not a valid `ECHClientHelloType`, then | |||
| the server MUST abort with an "illegal_parameter" alert. | the server MUST abort with an "illegal_parameter" alert. | |||
| If the "encrypted_client_hello" is not present, then the server completes the | If the "encrypted_client_hello" is not present, then the server completes the | |||
| handshake normally, as described in {{RFC8446}}. | handshake normally, as described in {{RFC8446}}. | |||
| ## Client-Facing Server {#client-facing-server} | ## Client-Facing Server {#client-facing-server} | |||
| Upon receiving an "encrypted_client_hello" extension in an initial | Upon receiving an "encrypted_client_hello" extension in an initial | |||
| ClientHello, the client-facing server determines if it will accept ECH, prior | ClientHello, the client-facing server determines if it will accept ECH prior | |||
| to negotiating any other TLS parameters. Note that successfully decrypting the | to negotiating any other TLS parameters. Note that successfully decrypting the | |||
| extension will result in a new ClientHello to process, so even the client's TLS | extension will result in a new ClientHello to process, so even the client's TLS | |||
| version preferences may have changed. | version preferences may have changed. | |||
| First, the server collects a set of candidate ECHConfig values. This list is | First, the server collects a set of candidate ECHConfig values. This list is | |||
| determined by one of the two following methods: | determined by one of the two following methods: | |||
| 1. Compare ECHClientHello.config_id against identifiers of each known ECHConfig | 1. Compare ECHClientHello.config_id against identifiers of each known ECHConfig | |||
| and select the ones that match, if any, as candidates. | and select the ones that match, if any, as candidates. | |||
| 2. Collect all known ECHConfig values as candidates, with trial decryption | 2. Collect all known ECHConfig values as candidates, with trial decryption | |||
| skipping to change at line 1122 ¶ | skipping to change at line 1218 ¶ | |||
| ClientHelloOuterAAD is computed from ClientHelloOuter as described in | ClientHelloOuterAAD is computed from ClientHelloOuter as described in | |||
| {{authenticating-outer}}. The `info` parameter to SetupBaseR is the | {{authenticating-outer}}. The `info` parameter to SetupBaseR is the | |||
| concatenation "tls ech", a zero byte, and the serialized ECHConfig. If | concatenation "tls ech", a zero byte, and the serialized ECHConfig. If | |||
| decryption fails, the server continues to the next candidate ECHConfig. | decryption fails, the server continues to the next candidate ECHConfig. | |||
| Otherwise, the server reconstructs ClientHelloInner from | Otherwise, the server reconstructs ClientHelloInner from | |||
| EncodedClientHelloInner, as described in {{encoding-inner}}. It then stops | EncodedClientHelloInner, as described in {{encoding-inner}}. It then stops | |||
| iterating over the candidate ECHConfig values. | iterating over the candidate ECHConfig values. | |||
| Once the server has chosen the correct ECHConfig, it MAY verify that the value | Once the server has chosen the correct ECHConfig, it MAY verify that the value | |||
| in the ClientHelloOuter "server_name" extension matches the value of | in the ClientHelloOuter "server_name" extension matches the value of | |||
| ECHConfig.contents.public_name, and abort with an "illegal_parameter" alert if | ECHConfig.contents.public_name and abort with an "illegal_parameter" alert if | |||
| these do not match. This optional check allows the server to limit ECH | these do not match. This optional check allows the server to limit ECH | |||
| connections to only use the public SNI values advertised in its ECHConfigs. | connections to only use the public SNI values advertised in its ECHConfigs. | |||
| The server MUST be careful not to unnecessarily reject connections if the same | The server MUST be careful not to unnecessarily reject connections if the same | |||
| ECHConfig id or keypair is used in multiple ECHConfigs with distinct public | ECHConfig id or keypair is used in multiple ECHConfigs with distinct public | |||
| names. | names. | |||
| Upon determining the ClientHelloInner, the client-facing server checks that the | Upon determining the ClientHelloInner, the client-facing server checks that the | |||
| message includes a well-formed "encrypted_client_hello" extension of type | message includes a well-formed "encrypted_client_hello" extension of type | |||
| `inner` and that it does not offer TLS 1.2 or below. If either of these checks | `inner` and that it does not offer TLS 1.2 or below. If either of these checks | |||
| fails, the client-facing server MUST abort with an "illegal_parameter" alert. | fails, the client-facing server MUST abort with an "illegal_parameter" alert. | |||
| skipping to change at line 1144 ¶ | skipping to change at line 1240 ¶ | |||
| If these checks succeed, the client-facing server then forwards the | If these checks succeed, the client-facing server then forwards the | |||
| ClientHelloInner to the appropriate backend server, which proceeds as in | ClientHelloInner to the appropriate backend server, which proceeds as in | |||
| {{backend-server}}. If the backend server responds with a HelloRetryRequest, the | {{backend-server}}. If the backend server responds with a HelloRetryRequest, the | |||
| client-facing server forwards it, decrypts the client's second ClientHelloOuter | client-facing server forwards it, decrypts the client's second ClientHelloOuter | |||
| using the procedure in {{client-facing-server-hrr}}, and forwards the resulting | using the procedure in {{client-facing-server-hrr}}, and forwards the resulting | |||
| second ClientHelloInner. The client-facing server forwards all other TLS | second ClientHelloInner. The client-facing server forwards all other TLS | |||
| messages between the client and backend server unmodified. | messages between the client and backend server unmodified. | |||
| Otherwise, if all candidate ECHConfig values fail to decrypt the extension, the | Otherwise, if all candidate ECHConfig values fail to decrypt the extension, the | |||
| client-facing server MUST ignore the extension and proceed with the connection | client-facing server MUST ignore the extension and proceed with the connection | |||
| using ClientHelloOuter, with the following modifications: | using ClientHelloOuter with the following modifications: | |||
| * If sending a HelloRetryRequest, the server MAY include an | * If sending a HelloRetryRequest, the server MAY include an | |||
| "encrypted_client_hello" extension with a payload of 8 random bytes; see | "encrypted_client_hello" extension with a payload of 8 random bytes; see | |||
| {{dont-stick-out}} for details. | {{dont-stick-out}} for details. | |||
| * If the server is configured with any ECHConfigs, it MUST include the | * If the server is configured with any ECHConfigs, it MUST include the | |||
| "encrypted_client_hello" extension in its EncryptedExtensions with the | "encrypted_client_hello" extension in its EncryptedExtensions with the | |||
| "retry_configs" field set to one or more ECHConfig structures with up-to-date | "retry_configs" field set to one or more ECHConfig structures with up-to-date | |||
| keys. Servers MAY supply multiple ECHConfig values of different versions. | keys. Servers MAY supply multiple ECHConfig values of different versions. | |||
| This allows a server to support multiple versions at once. | This allows a server to support multiple versions at once. | |||
| skipping to change at line 1170 ¶ | skipping to change at line 1266 ¶ | |||
| ({{misconfiguration}}). Instead, servers can measure occurrences of the | ({{misconfiguration}}). Instead, servers can measure occurrences of the | |||
| "ech_required" alert to detect this case. | "ech_required" alert to detect this case. | |||
| ### Sending HelloRetryRequest {#client-facing-server-hrr} | ### Sending HelloRetryRequest {#client-facing-server-hrr} | |||
| After sending or forwarding a HelloRetryRequest, the client-facing server does | After sending or forwarding a HelloRetryRequest, the client-facing server does | |||
| not repeat the steps in {{client-facing-server}} with the second | not repeat the steps in {{client-facing-server}} with the second | |||
| ClientHelloOuter. Instead, it continues with the ECHConfig selection from the | ClientHelloOuter. Instead, it continues with the ECHConfig selection from the | |||
| first ClientHelloOuter as follows: | first ClientHelloOuter as follows: | |||
| If the client-facing server accepted ECH, it checks the second ClientHelloOuter | If the client-facing server accepted ECH, it checks that the second ClientHelloOuter | |||
| also contains the "encrypted_client_hello" extension. If not, it MUST abort the | also contains the "encrypted_client_hello" extension. If not, it MUST abort the | |||
| handshake with a "missing_extension" alert. Otherwise, it checks that | handshake with a "missing_extension" alert. Otherwise, it checks that | |||
| ECHClientHello.cipher_suite and ECHClientHello.config_id are unchanged, and that | ECHClientHello.cipher_suite and ECHClientHello.config_id are unchanged, and that | |||
| ECHClientHello.enc is empty. If not, it MUST abort the handshake with an | ECHClientHello.enc is empty. If not, it MUST abort the handshake with an | |||
| "illegal_parameter" alert. | "illegal_parameter" alert. | |||
| Finally, it decrypts the new ECHClientHello.payload as a second message with the | Finally, it decrypts the new ECHClientHello.payload as a second message with the | |||
| previous HPKE context: | previous HPKE context: | |||
| ~~~ | ~~~ | |||
| skipping to change at line 1211 ¶ | skipping to change at line 1307 ¶ | |||
| "encrypted_client_hello" extension in its EncryptedExtensions with the | "encrypted_client_hello" extension in its EncryptedExtensions with the | |||
| "retry_configs" field set to one or more ECHConfig structures with up-to-date | "retry_configs" field set to one or more ECHConfig structures with up-to-date | |||
| keys, as described in {{client-facing-server}}. | keys, as described in {{client-facing-server}}. | |||
| Note that a client-facing server that forwards the first ClientHello cannot | Note that a client-facing server that forwards the first ClientHello cannot | |||
| include its own "cookie" extension if the backend server sends a | include its own "cookie" extension if the backend server sends a | |||
| HelloRetryRequest. This means that the client-facing server either needs to | HelloRetryRequest. This means that the client-facing server either needs to | |||
| maintain state for such a connection or it needs to coordinate with the backend | maintain state for such a connection or it needs to coordinate with the backend | |||
| server to include any information it requires to process the second ClientHello. | server to include any information it requires to process the second ClientHello. | |||
| <!-- [rfced] May we rephrase the following text for an improved sentence flow? | ||||
| Original: | ||||
| The backend server embeds in ServerHello.random a string derived from | ||||
| the inner handshake. | ||||
| Perhaps: | ||||
| A string derived from the inner handshake is embedded into | ||||
| ServerHello.random by the backend server. --> | ||||
| ## Backend Server {#backend-server} | ## Backend Server {#backend-server} | |||
| Upon receipt of an "encrypted_client_hello" extension of type `inner` in a | Upon receipt of an "encrypted_client_hello" extension of type `inner` in a | |||
| ClientHello, if the backend server negotiates TLS 1.3 or higher, then it MUST | ClientHello, if the backend server negotiates TLS 1.3 or higher, then it MUST | |||
| confirm ECH acceptance to the client by computing its ServerHello as described | confirm ECH acceptance to the client by computing its ServerHello as described | |||
| here. | here. | |||
| The backend server embeds in ServerHello.random a string derived from the inner | The backend server embeds in ServerHello.random a string derived from the inner | |||
| handshake. It begins by computing its ServerHello as usual, except the last 8 | handshake. It begins by computing its ServerHello as usual, except the last 8 | |||
| bytes of ServerHello.random are set to zero. It then computes the transcript | bytes of ServerHello.random are set to zero. It then computes the transcript | |||
| skipping to change at line 1286 ¶ | skipping to change at line 1392 ¶ | |||
| Beyond coordination difficulties, ECH deployments may also induce challenges | Beyond coordination difficulties, ECH deployments may also induce challenges | |||
| for use cases of information that ECH protects. In particular, | for use cases of information that ECH protects. In particular, | |||
| use cases which depend on this unencrypted information may no longer work | use cases which depend on this unencrypted information may no longer work | |||
| as desired. This is elaborated upon in {{no-sni}}. | as desired. This is elaborated upon in {{no-sni}}. | |||
| ## Compatibility Issues {#compat-issues} | ## Compatibility Issues {#compat-issues} | |||
| Unlike most TLS extensions, placing the SNI value in an ECH extension is not | Unlike most TLS extensions, placing the SNI value in an ECH extension is not | |||
| interoperable with existing servers, which expect the value in the existing | interoperable with existing servers, which expect the value in the existing | |||
| plaintext extension. Thus server operators SHOULD ensure servers understand a | plaintext extension. Thus, server operators SHOULD ensure servers understand a | |||
| given set of ECH keys before advertising them. Additionally, servers SHOULD | given set of ECH keys before advertising them. Additionally, servers SHOULD | |||
| retain support for any previously-advertised keys for the duration of their | retain support for any previously advertised keys for the duration of their | |||
| validity. | validity. | |||
| However, in more complex deployment scenarios, this may be difficult to fully | However, in more complex deployment scenarios, this may be difficult to fully | |||
| guarantee. Thus this protocol was designed to be robust in case of | guarantee. Thus, this protocol was designed to be robust in case of | |||
| inconsistencies between systems that advertise ECH keys and servers, at the cost | inconsistencies between systems that advertise ECH keys and servers, at the cost | |||
| of extra round-trips due to a retry. Two specific scenarios are detailed below. | of extra round-trips due to a retry. Two specific scenarios are detailed below. | |||
| ### Misconfiguration and Deployment Concerns {#misconfiguration} | ### Misconfiguration and Deployment Concerns {#misconfiguration} | |||
| It is possible for ECH advertisements and servers to become inconsistent. This | It is possible for ECH advertisements and servers to become inconsistent. This | |||
| may occur, for instance, from DNS misconfiguration, caching issues, or an | may occur, for instance, from DNS misconfiguration, caching issues, or an | |||
| incomplete rollout in a multi-server deployment. This may also occur if a server | incomplete rollout in a multi-server deployment. This may also occur if a server | |||
| loses its ECH keys, or if a deployment of ECH must be rolled back on the server. | loses its ECH keys, or if a deployment of ECH must be rolled back on the server. | |||
| The retry mechanism repairs inconsistencies, provided the TLS server | The retry mechanism repairs inconsistencies, provided the TLS server | |||
| has a certificate for the public name. If server and advertised keys | has a certificate for the public name. If server and advertised keys | |||
| mismatch, the server will reject ECH and respond with | mismatch, the server will reject ECH and respond with | |||
| "retry_configs". If the server does | "retry_configs". If the server does | |||
| not understand | not understand the "encrypted_client_hello" extension at all, it will ignore it | |||
| the "encrypted_client_hello" extension at all, it will ignore it as required by | as required by {{Section 4.1.2 of RFC8446}}. Provided the server can present a certif | |||
| {{Section 4.1.2 of RFC8446}}. Provided the server can present a certificate | icate | |||
| valid for the public name, the client can safely retry with updated settings, | valid for the public name, the client can safely retry with updated settings, | |||
| as described in {{rejected-ech}}. | as described in {{rejected-ech}}. | |||
| Unless ECH is disabled as a result of successfully establishing a connection to | Unless ECH is disabled as a result of successfully establishing a connection to | |||
| the public name, the client MUST NOT fall back to using unencrypted | the public name, the client MUST NOT fall back to using unencrypted | |||
| ClientHellos, as this allows a network attacker to disclose the contents of this | ClientHellos, as this allows a network attacker to disclose the contents of this | |||
| ClientHello, including the SNI. It MAY attempt to use another server from the | ClientHello, including the SNI. It MAY attempt to use another server from the | |||
| DNS results, if one is provided. | DNS results, if one is provided. | |||
| In order to ensure that the retry mechanism works successfully servers | In order to ensure that the retry mechanism works successfully, servers | |||
| SHOULD ensure that every endpoint which might receive a TLS connection | SHOULD ensure that every endpoint which might receive a TLS connection | |||
| is provisioned with an appropriate certificate for the public name. | is provisioned with an appropriate certificate for the public name. | |||
| This is especially important during periods of server reconfiguration | This is especially important during periods of server reconfiguration | |||
| when different endpoints might have different configurations. | when different endpoints might have different configurations. | |||
| ### Middleboxes | ### Middleboxes | |||
| <!--[rfced] How may we update this sentence to make it clear whether | ||||
| all the requirements or only some of the requirements require | ||||
| proxies to act as conforming TLS client and server? | ||||
| For background, in general, the RPC recommends using nonrestrictive "which" | ||||
| and restrictive "that". (More details are on | ||||
| https://www.rfc-editor.org/styleguide/tips/) However, edits to that | ||||
| usage have not been made in this document. In this specific sentence, | ||||
| we are asking about the usage because it can affect the understanding | ||||
| of the statement. | ||||
| Original: | ||||
| The requirements in [RFC8446], Section 9.3 which require proxies to | ||||
| act as conforming TLS client and server provide interoperability with | ||||
| TLS-terminating proxies even in cases where the server supports ECH | ||||
| but the proxy does not, as detailed below. | ||||
| Option A (all requirements require it): | ||||
| The requirements in [RFC8446], Section 9.3, which require proxies to | ||||
| act as conforming TLS client and server, provide interoperability with | ||||
| TLS-terminating proxies even in cases where the server supports ECH | ||||
| but the proxy does not, as detailed below. | ||||
| Option B (some requirements require it): | ||||
| The requirements in [RFC8446], Section 9.3 that require proxies to | ||||
| act as conforming TLS client and server provide interoperability with | ||||
| TLS-terminating proxies even in cases where the server supports ECH | ||||
| but the proxy does not, as detailed below. | ||||
| --> | ||||
| The requirements in {{RFC8446, Section 9.3}} which require proxies to | The requirements in {{RFC8446, Section 9.3}} which require proxies to | |||
| act as conforming TLS client and server provide interoperability | act as conforming TLS client and server provide interoperability | |||
| with TLS-terminating proxies even in cases where the server supports | with TLS-terminating proxies even in cases where the server supports | |||
| ECH but the proxy does not, as detailed below. | ECH but the proxy does not, as detailed below. | |||
| The proxy must ignore unknown parameters, and | The proxy must ignore unknown parameters and | |||
| generate its own ClientHello containing only parameters it understands. Thus, | generate its own ClientHello containing only parameters it understands. Thus, | |||
| when presenting a certificate to the client or sending a ClientHello to the | when presenting a certificate to the client or sending a ClientHello to the | |||
| server, the proxy will act as if connecting to the ClientHelloOuter | server, the proxy will act as if connecting to the ClientHelloOuter | |||
| server_name, which SHOULD match the public name (see {{real-ech}}), without | server_name, which SHOULD match the public name (see {{real-ech}}) without | |||
| echoing the "encrypted_client_hello" extension. | echoing the "encrypted_client_hello" extension. | |||
| Depending on whether the client is configured to accept the proxy's certificate | Depending on whether the client is configured to accept the proxy's certificate | |||
| as authoritative for the public name, this may trigger the retry logic described | as authoritative for the public name, this may trigger the retry logic described | |||
| in {{rejected-ech}} or result in a connection failure. A proxy which is not | in {{rejected-ech}} or result in a connection failure. A proxy which is not | |||
| authoritative for the public name cannot forge a signal to disable ECH. | authoritative for the public name cannot forge a signal to disable ECH. | |||
| ## Deployment Impact {#no-sni} | ## Deployment Impact {#no-sni} | |||
| Some use cases which depend on information ECH encrypts may break with the | Some use cases which depend on information ECH encrypts may break with the | |||
| skipping to change at line 1370 ¶ | skipping to change at line 1505 ¶ | |||
| In the context of {{rejected-ech}}, another approach may be to | In the context of {{rejected-ech}}, another approach may be to | |||
| intercept and decrypt client TLS connections. The feasibility of alternative | intercept and decrypt client TLS connections. The feasibility of alternative | |||
| solutions is specific to individual deployments. | solutions is specific to individual deployments. | |||
| # Compliance Requirements {#compliance} | # Compliance Requirements {#compliance} | |||
| In the absence of an application profile standard specifying otherwise, | In the absence of an application profile standard specifying otherwise, | |||
| a compliant ECH application MUST implement the following HPKE cipher suite: | a compliant ECH application MUST implement the following HPKE cipher suite: | |||
| - KEM: DHKEM(X25519, HKDF-SHA256) (see {{Section 7.1 of HPKE}}) | - KEM: DHKEM(X25519, HKDF-SHA256) (see {{Section 7.1 of RFC9180}}) | |||
| - KDF: HKDF-SHA256 (see {{Section 7.2 of HPKE}}) | - KDF: HKDF-SHA256 (see {{Section 7.2 of RFC9180}}) | |||
| - AEAD: AES-128-GCM (see {{Section 7.3 of HPKE}}) | - AEAD: AES-128-GCM (see {{Section 7.3 of RFC9180}}) | |||
| AEAD: AES-128-GCM (see {{Section 7.3 of <span class="insert">RFC9180}})</span> | ||||
| # Security Considerations | # Security Considerations | |||
| This section contains security considerations for ECH. | This section contains security considerations for ECH. | |||
| ## Security and Privacy Goals {#goals} | ## Security and Privacy Goals {#goals} | |||
| ECH considers two types of attackers: passive and active. Passive attackers can | ECH considers two types of attackers: passive and active. Passive attackers can | |||
| read packets from the network, but they cannot perform any sort of active | read packets from the network, but they cannot perform any sort of active | |||
| behavior such as probing servers or querying DNS. A middlebox that filters based | behavior such as probing servers or querying DNS. A middlebox that filters based | |||
| skipping to change at line 1398 ¶ | skipping to change at line 1533 ¶ | |||
| Passive and active attackers can exist anywhere in the network, including | Passive and active attackers can exist anywhere in the network, including | |||
| between the client and client-facing server, as well as between the | between the client and client-facing server, as well as between the | |||
| client-facing and backend servers when running ECH in Split Mode. However, | client-facing and backend servers when running ECH in Split Mode. However, | |||
| for Split Mode in particular, ECH makes two additional assumptions: | for Split Mode in particular, ECH makes two additional assumptions: | |||
| 1. The channel between each client-facing and each backend server is | 1. The channel between each client-facing and each backend server is | |||
| authenticated such that the backend server only accepts messages from trusted | authenticated such that the backend server only accepts messages from trusted | |||
| client-facing servers. The exact mechanism for establishing this authenticated | client-facing servers. The exact mechanism for establishing this authenticated | |||
| channel is out of scope for this document. | channel is out of scope for this document. | |||
| 1. The attacker cannot correlate messages between client and client-facing | 1. The attacker cannot correlate messages between a client and client-facing | |||
| server with messages between client-facing and backend server. Such correlation | server with messages between client-facing and backend server. Such correlation | |||
| could allow an attacker to link information unique to a backend server, such as | could allow an attacker to link information unique to a backend server, such as | |||
| their server name or IP address, with a client's encrypted ClientHelloInner. | their server name or IP address, with a client's encrypted ClientHelloInner. | |||
| Correlation could occur through timing analysis of messages across the | Correlation could occur through timing analysis of messages across the | |||
| client-facing server, or via examining the contents of messages sent between | client-facing server, or via examining the contents of messages sent between | |||
| client-facing and backend servers. The exact mechanism for preventing this sort | client-facing and backend servers. The exact mechanism for preventing this sort | |||
| of correlation is out of scope for this document. | of correlation is out of scope for this document. | |||
| Given this threat model, the primary goals of ECH are as follows. | Given this threat model, the primary goals of ECH are as follows. | |||
| skipping to change at line 1434 ¶ | skipping to change at line 1569 ¶ | |||
| SHOULD deploy ECH in such a way so as to maximize the size of the | SHOULD deploy ECH in such a way so as to maximize the size of the | |||
| anonymity set where possible. This means client-facing servers should | anonymity set where possible. This means client-facing servers should | |||
| use the same ECHConfig for as many server names as possible. An | use the same ECHConfig for as many server names as possible. An | |||
| attacker can distinguish two server names that have different | attacker can distinguish two server names that have different | |||
| ECHConfig values based on the ECHClientHello.config_id value. | ECHConfig values based on the ECHClientHello.config_id value. | |||
| This also means public information in a TLS handshake should be | This also means public information in a TLS handshake should be | |||
| consistent across server names. For example, if a client-facing server | consistent across server names. For example, if a client-facing server | |||
| services many backend origin server names, only one of which supports some | services many backend origin server names, only one of which supports some | |||
| cipher suite, it may be possible to identify that server name based on the | cipher suite, it may be possible to identify that server name based on the | |||
| contents of unencrypted handshake message. Similarly, if a backend | contents of the unencrypted handshake message. Similarly, if a backend | |||
| origin reuses KeyShare values, then that provides a unique identifier | origin reuses KeyShare values, then that provides a unique identifier | |||
| for that server. | for that server. | |||
| Beyond these primary security and privacy goals, ECH also aims to hide, to some | Beyond these primary security and privacy goals, ECH also aims to hide, to some | |||
| extent, the fact that it is being used at all. Specifically, the GREASE ECH | extent, the fact that it is being used at all. Specifically, the GREASE ECH | |||
| extension described in {{grease-ech}} does not change the security properties of | extension described in {{grease-ech}} does not change the security properties of | |||
| the TLS handshake at all. Its goal is to provide "cover" for the real ECH | the TLS handshake at all. Its goal is to provide "cover" for the real ECH | |||
| protocol ({{real-ech}}), as a means of addressing the "do not stick out" | protocol ({{real-ech}}), as a means of addressing the "do not stick out" | |||
| requirements of {{?RFC8744}}. See {{dont-stick-out}} for details. | requirements of {{?RFC8744}}. See {{dont-stick-out}} for details. | |||
| ## Unauthenticated and Plaintext DNS {#plaintext-dns} | ## Unauthenticated and Plaintext DNS {#plaintext-dns} | |||
| ECH supports delivery of configurations through the DNS using SVCB or HTTPS | ECH supports delivery of configurations through the DNS using SVCB or HTTPS | |||
| records, without requiring any verifiable authenticity or provenance | records without requiring any verifiable authenticity or provenance | |||
| information {{ECH-IN-DNS}}. This means that any attacker which can inject | information {{RFCYYY1}}. This means that any attacker which can inject | |||
| DNS responses or poison DNS caches, which is a common scenario in | DNS responses or poison DNS caches, which is a common scenario in | |||
| client access networks, can supply clients with fake ECH configurations (so | client access networks, can supply clients with fake ECH configurations (so | |||
| that the client encrypts data to them) or strip the ECH configurations from | that the client encrypts data to them) or strip the ECH configurations from | |||
| the response. However, in the face of an attacker that controls DNS, | the response. However, in the face of an attacker that controls DNS, | |||
| no encryption scheme can work because the attacker can replace the IP | no encryption scheme can work because the attacker can replace the IP | |||
| address, thus blocking client connections, or substitute a unique IP | address, thus blocking client connections, or substitute a unique IP | |||
| address for each DNS name that was looked up. Thus, using DNS records | address for each DNS name that was looked up. Thus, using DNS records | |||
| without additional authentication does not make the situation significantly | without additional authentication does not make the situation significantly | |||
| worse. | worse. | |||
| skipping to change at line 1552 ¶ | skipping to change at line 1687 ¶ | |||
| In particular, timing side channels can reveal information about the contents | In particular, timing side channels can reveal information about the contents | |||
| of ClientHelloInner. Implementations should take such side channels into | of ClientHelloInner. Implementations should take such side channels into | |||
| consideration when reasoning about the privacy properties that ECH provides. | consideration when reasoning about the privacy properties that ECH provides. | |||
| ## Related Privacy Leaks | ## Related Privacy Leaks | |||
| ECH requires encrypted DNS to be an effective privacy protection mechanism. | ECH requires encrypted DNS to be an effective privacy protection mechanism. | |||
| However, verifying the server's identity from the Certificate message, | However, verifying the server's identity from the Certificate message, | |||
| particularly when using the X509 CertificateType, may result in additional | particularly when using the X509 CertificateType, may result in additional | |||
| network traffic that may reveal the server identity. Examples of this traffic | network traffic that may reveal the server identity. Examples of this traffic | |||
| may include requests for revocation information, such as OCSP or CRL traffic, or | may include requests for revocation information, such as Online Certificate Status Pr | |||
| requests for repository information, such as authorityInformationAccess. It may | otocol (OCSP) or Certificate Revocation List (CRL) traffic, or requests for repositor | |||
| also include implementation-specific traffic for additional information sources | y information, such as authorityInformationAccess. It may also include implementation | |||
| as part of verification. | -specific traffic for additional information sources as part of verification. | |||
| Implementations SHOULD avoid leaking information that may identify the server. | Implementations SHOULD avoid leaking information that may identify the server. | |||
| Even when sent over an encrypted transport, such requests may result in indirect | Even when sent over an encrypted transport, such requests may result in indirect | |||
| exposure of the server's identity, such as indicating a specific CA or service | exposure of the server's identity, such as indicating a specific CA or service | |||
| being used. To mitigate this risk, servers SHOULD deliver such information | being used. To mitigate this risk, servers SHOULD deliver such information | |||
| in-band when possible, such as through the use of OCSP stapling, and clients | in-band when possible, such as through the use of OCSP stapling, and clients | |||
| SHOULD take steps to minimize or protect such requests during certificate | SHOULD take steps to minimize or protect such requests during certificate | |||
| validation. | validation. | |||
| Attacks that rely on non-ECH traffic to infer server identity in an ECH | Attacks that rely on non-ECH traffic to infer server identity in an ECH | |||
| skipping to change at line 1590 ¶ | skipping to change at line 1722 ¶ | |||
| Backend servers in an anonymity set SHOULD NOT reveal information in the cookie | Backend servers in an anonymity set SHOULD NOT reveal information in the cookie | |||
| which identifies the server. This may be done by handling HelloRetryRequest | which identifies the server. This may be done by handling HelloRetryRequest | |||
| statefully, thus not sending cookies, or by using the same cookie construction | statefully, thus not sending cookies, or by using the same cookie construction | |||
| for all backend servers. | for all backend servers. | |||
| Note that, if the cookie includes a key name, analogous to {{Section 4 of | Note that, if the cookie includes a key name, analogous to {{Section 4 of | |||
| ?RFC5077}}, this may leak information if different backend servers issue | ?RFC5077}}, this may leak information if different backend servers issue | |||
| cookies with different key names at the time of the connection. In particular, | cookies with different key names at the time of the connection. In particular, | |||
| if the deployment operates in Split Mode, the backend servers may not share | if the deployment operates in Split Mode, the backend servers may not share | |||
| cookie encryption keys. Backend servers may mitigate this by either handling | cookie encryption keys. Backend servers may mitigate this either by handling | |||
| key rotation with trial decryption, or coordinating to match key names. | key rotation with trial decryption or by coordinating to match key names. | |||
| ## Attacks Exploiting Acceptance Confirmation | ## Attacks Exploiting Acceptance Confirmation | |||
| To signal acceptance, the backend server overwrites 8 bytes of its | To signal acceptance, the backend server overwrites 8 bytes of its | |||
| ServerHello.random with a value derived from the ClientHelloInner.random. (See | ServerHello.random with a value derived from the ClientHelloInner.random. (See | |||
| {{backend-server}} for details.) This behavior increases the likelihood of the | {{backend-server}} for details.) This behavior increases the likelihood of the | |||
| ServerHello.random colliding with the ServerHello.random of a previous session, | ServerHello.random colliding with the ServerHello.random of a previous session, | |||
| potentially reducing the overall security of the protocol. However, the | potentially reducing the overall security of the protocol. However, the | |||
| remaining 24 bytes provide enough entropy to ensure this is not a practical | remaining 24 bytes provide enough entropy to ensure this is not a practical | |||
| avenue of attack. | avenue of attack. | |||
| skipping to change at line 1620 ¶ | skipping to change at line 1752 ¶ | |||
| smaller than the probability of network connection failures in practice. | smaller than the probability of network connection failures in practice. | |||
| Note that the same bytes of the ServerHello.random are used to implement | Note that the same bytes of the ServerHello.random are used to implement | |||
| downgrade protection for TLS 1.3 (see {{RFC8446, Section 4.1.3}}). These | downgrade protection for TLS 1.3 (see {{RFC8446, Section 4.1.3}}). These | |||
| mechanisms do not interfere because the backend server only signals ECH | mechanisms do not interfere because the backend server only signals ECH | |||
| acceptance in TLS 1.3 or higher. | acceptance in TLS 1.3 or higher. | |||
| ## Comparison Against Criteria | ## Comparison Against Criteria | |||
| {{?RFC8744}} lists several requirements for SNI encryption. | {{?RFC8744}} lists several requirements for SNI encryption. | |||
| In this section, we re-iterate these requirements and assess the ECH design | In this section, we reiterate these requirements and assess the ECH design | |||
| against them. | against them. | |||
| ### Mitigate Cut-and-Paste Attacks | ### Mitigate Cut-and-Paste Attacks | |||
| Since servers process either ClientHelloInner or ClientHelloOuter, and because | Since servers process either ClientHelloInner or ClientHelloOuter, and because | |||
| ClientHelloInner.random is encrypted, it is not possible for an attacker to "cut | ClientHelloInner.random is encrypted, it is not possible for an attacker to "cut | |||
| and paste" the ECH value in a different Client Hello and learn information from | and paste" the ECH value in a different Client Hello and learn information from | |||
| ClientHelloInner. | ClientHelloInner. | |||
| ### Avoid Widely Shared Secrets | ### Avoid Widely Shared Secrets | |||
| skipping to change at line 1671 ¶ | skipping to change at line 1803 ¶ | |||
| underlying theory is that if GREASE ECH is deployable without triggering | underlying theory is that if GREASE ECH is deployable without triggering | |||
| middlebox misbehavior, and real ECH looks enough like GREASE ECH, then ECH | middlebox misbehavior, and real ECH looks enough like GREASE ECH, then ECH | |||
| should be deployable as well. Thus, the strategy for mitigating network | should be deployable as well. Thus, the strategy for mitigating network | |||
| ossification is to deploy GREASE ECH widely enough to disincentivize | ossification is to deploy GREASE ECH widely enough to disincentivize | |||
| differential treatment of the real ECH protocol by the network. | differential treatment of the real ECH protocol by the network. | |||
| Ensuring that networks do not differentiate between real ECH and GREASE ECH may | Ensuring that networks do not differentiate between real ECH and GREASE ECH may | |||
| not be feasible for all implementations. While most middleboxes will not treat | not be feasible for all implementations. While most middleboxes will not treat | |||
| them differently, some operators may wish to block real ECH usage but allow | them differently, some operators may wish to block real ECH usage but allow | |||
| GREASE ECH. This specification aims to provide a baseline security level that | GREASE ECH. This specification aims to provide a baseline security level that | |||
| most deployments can achieve easily, while providing implementations enough | most deployments can achieve easily while providing implementations enough | |||
| flexibility to achieve stronger security where possible. Minimally, real ECH is | flexibility to achieve stronger security where possible. Minimally, real ECH is | |||
| designed to be indifferentiable from GREASE ECH for passive adversaries with | designed to be indifferentiable from GREASE ECH for passive adversaries with | |||
| following capabilities: | following capabilities: | |||
| 1. The attacker does not know the ECHConfigList used by the server. | 1. The attacker does not know the ECHConfigList used by the server. | |||
| 1. The attacker keeps per-connection state only. In particular, it does not | 1. The attacker keeps per-connection state only. In particular, it does not | |||
| track endpoints across connections. | track endpoints across connections. | |||
| Moreover, real ECH and GREASE ECH are designed so that the following features | Moreover, real ECH and GREASE ECH are designed so that the following features | |||
| do not noticeably vary to the attacker, i.e., they are not distinguishers: | do not noticeably vary to the attacker, i.e., they are not distinguishers: | |||
| skipping to change at line 1783 ¶ | skipping to change at line 1915 ¶ | |||
| ServerHello | ServerHello | |||
| + key_share | + key_share | |||
| {EncryptedExtensions} | {EncryptedExtensions} | |||
| {CertificateRequest*} | {CertificateRequest*} | |||
| {Certificate*} | {Certificate*} | |||
| {CertificateVerify*} | {CertificateVerify*} | |||
| <------ | <------ | |||
| Alert | Alert | |||
| ------> | ------> | |||
| ~~~ | ~~~ | |||
| {: #flow-diagram-client-reaction title="Client reaction attack"} | {: #flow-diagram-client-reaction title="Client Reaction Attack"} | |||
| ClientHelloInner.random prevents this attack. In particular, since the attacker | ClientHelloInner.random prevents this attack. In particular, since the attacker | |||
| does not have access to this value, it cannot produce the right transcript and | does not have access to this value, it cannot produce the right transcript and | |||
| handshake keys needed for encrypting the Certificate message. Thus, the client | handshake keys needed for encrypting the Certificate message. Thus, the client | |||
| will fail to decrypt the Certificate and abort the connection. | will fail to decrypt the Certificate and abort the connection. | |||
| ### HelloRetryRequest Hijack Mitigation {#flow-hrr-hijack} | ### HelloRetryRequest Hijack Mitigation {#flow-hrr-hijack} | |||
| This attack aims to exploit server HRR state management to recover information | This attack aims to exploit server HRR state management to recover information | |||
| about a legitimate ClientHello using its own attacker-controlled ClientHello. | about a legitimate ClientHello using its own attacker-controlled ClientHello. | |||
| skipping to change at line 1826 ¶ | skipping to change at line 1958 ¶ | |||
| ServerHello | ServerHello | |||
| + key_share | + key_share | |||
| {EncryptedExtensions} | {EncryptedExtensions} | |||
| {CertificateRequest*} | {CertificateRequest*} | |||
| {Certificate*} | {Certificate*} | |||
| {CertificateVerify*} | {CertificateVerify*} | |||
| {Finished} | {Finished} | |||
| <------- | <------- | |||
| (process server flight) | (process server flight) | |||
| ~~~ | ~~~ | |||
| {: #flow-diagram-hrr-hijack title="HelloRetryRequest hijack attack"} | {: #flow-diagram-hrr-hijack title="HelloRetryRequest Hijack Attack"} | |||
| This attack is mitigated by using the same HPKE context for both ClientHello | This attack is mitigated by using the same HPKE context for both ClientHello | |||
| messages. The attacker does not possess the context's keys, so it cannot | messages. The attacker does not possess the context's keys, so it cannot | |||
| generate a valid encryption of the second inner ClientHello. | generate a valid encryption of the second inner ClientHello. | |||
| If the attacker could manipulate the second ClientHello, it might be possible | If the attacker could manipulate the second ClientHello, it might be possible | |||
| for the server to act as an oracle if it required parameters from the first | for the server to act as an oracle if it required parameters from the first | |||
| ClientHello to match that of the second ClientHello. For example, imagine the | ClientHello to match that of the second ClientHello. For example, imagine the | |||
| client's original SNI value in the inner ClientHello is "example.com", and the | client's original SNI value in the inner ClientHello is "example.com", and the | |||
| attacker's hijacked SNI value in its inner ClientHello is "test.com". A server | attacker's hijacked SNI value in its inner ClientHello is "test.com". A server | |||
| skipping to change at line 1885 ¶ | skipping to change at line 2017 ¶ | |||
| + ech_outer_extensions(pre_shared_key) | + ech_outer_extensions(pre_shared_key) | |||
| + pre_shared_key' | + pre_shared_key' | |||
| --------> | --------> | |||
| Alert | Alert | |||
| -or- | -or- | |||
| ServerHello | ServerHello | |||
| ... | ... | |||
| Finished | Finished | |||
| <-------- | <-------- | |||
| ~~~ | ~~~ | |||
| {: #tls-clienthello-malleability title="Message flow for malleable ClientHello"} | {: #tls-clienthello-malleability title="Message Flow for Malleable ClientHello"} | |||
| This attack may be generalized to any parameter which the server varies by | This attack may be generalized to any parameter which the server varies by | |||
| server name, such as ALPN preferences. | server name, such as ALPN preferences. | |||
| ECH mitigates this attack by only negotiating TLS parameters from | ECH mitigates this attack by only negotiating TLS parameters from | |||
| ClientHelloInner and authenticating all inputs to the ClientHelloInner | ClientHelloInner and authenticating all inputs to the ClientHelloInner | |||
| (EncodedClientHelloInner and ClientHelloOuter) with the HPKE AEAD. See | (EncodedClientHelloInner and ClientHelloOuter) with the HPKE AEAD. See | |||
| {{authenticating-outer}}. The decompression process in {{encoding-inner}} | {{authenticating-outer}}. The decompression process in {{encoding-inner}} | |||
| forbids "encrypted_client_hello" in OuterExtensions. This ensures the | forbids "encrypted_client_hello" in OuterExtensions. This ensures the | |||
| unauthenticated portion of ClientHelloOuter is not incorporated into | unauthenticated portion of ClientHelloOuter is not incorporated into | |||
| ClientHelloInner. | ClientHelloInner. An earlier iteration of this specification only | |||
| An earlier iteration of this specification only | ||||
| encrypted and authenticated the "server_name" extension, which left the overall | encrypted and authenticated the "server_name" extension, which left the overall | |||
| ClientHello vulnerable to an analogue of this attack. | ClientHello vulnerable to an analogue of this attack. | |||
| ### ClientHelloInner Packet Amplification Mitigation {#decompression-amp} | ### ClientHelloInner Packet Amplification Mitigation {#decompression-amp} | |||
| Client-facing servers must decompress EncodedClientHelloInners. A malicious | Client-facing servers must decompress EncodedClientHelloInners. A malicious | |||
| attacker may craft a packet which takes excessive resources to decompress | attacker may craft a packet which takes excessive resources to decompress | |||
| or may be much larger than the incoming packet: | or may be much larger than the incoming packet: | |||
| * If looking up a ClientHelloOuter extension takes time linear in the number of | * If looking up a ClientHelloOuter extension takes time linear in the number of | |||
| extensions, the overall decoding process would take O(M\*N) time, where | extensions, the overall decoding process would take O(M\*N) time, where | |||
| M is the number of extensions in ClientHelloOuter and N is the | M is the number of extensions in ClientHelloOuter and N is the | |||
| size of OuterExtensions. | size of OuterExtensions. | |||
| * If the same ClientHelloOuter extension can be copied multiple times, | * If the same ClientHelloOuter extension can be copied multiple times, | |||
| an attacker could cause the client-facing server to construct a large | an attacker could cause the client-facing server to construct a large | |||
| ClientHelloInner by including a large extension in ClientHelloOuter, | ClientHelloInner by including a large extension in ClientHelloOuter | |||
| of length L, and an OuterExtensions list referencing N copies of that | of length L and an OuterExtensions list referencing N copies of that | |||
| extension. The client-facing server would then use O(N\*L) memory in | extension. The client-facing server would then use O(N\*L) memory in | |||
| response to O(N+L) bandwidth from the client. In split-mode, an | response to O(N+L) bandwidth from the client. In split-mode, an | |||
| O(N\*L) sized packet would then be transmitted to the | O(N\*L)-sized packet would then be transmitted to the | |||
| backend server. | backend server. | |||
| ECH mitigates this attack by requiring that OuterExtensions be referenced in | ECH mitigates this attack by requiring that OuterExtensions be referenced in | |||
| order, that duplicate references be rejected, and by recommending that | order, that duplicate references be rejected, and by recommending that | |||
| client-facing servers use a linear scan to perform decompression. These | client-facing servers use a linear scan to perform decompression. These | |||
| requirements are detailed in {{encoding-inner}}. | requirements are detailed in {{encoding-inner}}. | |||
| # IANA Considerations | # IANA Considerations | |||
| ## Update of the TLS ExtensionType Registry | ## Update of the TLS ExtensionType Registry | |||
| IANA is requested to create the following entries in the existing registry for | IANA has created the following entries in the existing | |||
| ExtensionType (defined in {{!RFC8446}}): | "TLS ExtensionType Values" registry (defined in {{!RFC8446}}): | |||
| 1. encrypted_client_hello(0xfe0d), with "TLS 1.3" column values set to | 1. encrypted_client_hello (0xfe0d), with "TLS 1.3" column values set to | |||
| "CH, HRR, EE", "DTLS-Only" column set to "N", and "Recommended" column set | "CH, HRR, EE", "DTLS-Only" column set to "N", and "Recommended" column set | |||
| to "Yes". | to "Y". | |||
| 1. ech_outer_extensions(0xfd00), with the "TLS 1.3" column values set to "CH", | 1. ech_outer_extensions (0xfd00), with the "TLS 1.3" column values set to "CH", | |||
| "DTLS-Only" column set to "N", "Recommended" column set to "Yes", and the | "DTLS-Only" column set to "N", "Recommended" column set to "Y", and the | |||
| "Comment" column set to "Only appears in inner CH." | "Comment" column set to "Only appears in inner CH." | |||
| ## Update of the TLS Alert Registry {#alerts} | ## Update of the TLS Alert Registry {#alerts} | |||
| IANA is requested to create an entry, ech_required(121) in the existing registry | IANA has created an entry, ech_required (121) in the existing "TLS Alerts" registry ( | |||
| for Alerts (defined in {{!RFC8446}}), with the "DTLS-OK" column set to | defined in {{!RFC8446}}), with the "DTLS-OK" column set to | |||
| "Y". | "Y". | |||
| ## ECH Configuration Extension Registry {#config-extensions-iana} | ## ECH Configuration Extension Registry {#config-extensions-iana} | |||
| IANA is requested to create a new "ECHConfig Extension" registry in a new | IANA has created a new "TLS ECHConfig Extension" registry in a new | |||
| "TLS Encrypted Client Hello (ECH) Configuration Extensions" page. New | "TLS Encrypted Client Hello (ECH) Configuration Extensions" registry group. New | |||
| registrations need to list the following attributes: | registrations will list the following attributes: | |||
| Value: | Value: | |||
| : The two-byte identifier for the ECHConfigExtension, i.e., the | : The two-byte identifier for the ECHConfigExtension, i.e., the | |||
| ECHConfigExtensionType | ECHConfigExtensionType | |||
| Extension Name: | Extension Name: | |||
| : Name of the ECHConfigExtension | : Name of the ECHConfigExtension | |||
| Recommended: | Recommended: | |||
| : A "Y" or "N" value indicating if the extension is TLS WG recommends that the | : A "Y" or "N" value indicating if the extension is TLS WG recommends that the | |||
| skipping to change at line 1972 ¶ | skipping to change at line 2102 ¶ | |||
| explicitly requested. Adding a value with a value of "Y" requires Standards | explicitly requested. Adding a value with a value of "Y" requires Standards | |||
| Action {{RFC8126}}. | Action {{RFC8126}}. | |||
| Reference: | Reference: | |||
| : The specification where the ECHConfigExtension is defined | : The specification where the ECHConfigExtension is defined | |||
| Notes: | Notes: | |||
| : Any notes associated with the entry | : Any notes associated with the entry | |||
| {: spacing="compact"} | {: spacing="compact"} | |||
| New entries in the "ECHConfig Extension" registry are subject to the | New entries in the "TLS ECHConfig Extension" registry are subject to the | |||
| Specification Required registration policy ({{!RFC8126, Section | Specification Required registration policy ({{!RFC8126, Section | |||
| 4.6}}), with the policies described in {{!RFC8447, Section 17}}. IANA | 4.6}}), with the policies described in {{!RFC8447, Section 17}}. IANA | |||
| [shall add/has added] the following note to the TLS ECHConfig Extension | has added the following note to the "TLS ECHConfig Extension" | |||
| registry: | registry: | |||
| Note: The role of the designated expert is described in RFC 8447. | Note: The role of the designated expert is described in RFC 8447. | |||
| The designated expert [RFC8126] ensures that the specification is | The designated expert [RFC8126] ensures that the specification is | |||
| publicly available. It is sufficient to have an Internet-Draft | publicly available. It is sufficient to have an Internet-Draft | |||
| (that is posted and never published as an RFC) or a document from | (that is posted and never published as an RFC) or a document from | |||
| another standards body, industry consortium, university site, etc. | another standards body, industry consortium, university site, etc. | |||
| The expert may provide more in depth reviews, but their approval | The expert may provide more in-depth reviews, but their approval | |||
| should not be taken as an endorsement of the extension. | should not be taken as an endorsement of the extension. | |||
| This document defines several Reserved values for ECH configuration extensions | This document defines several Reserved values for ECH configuration extensions | |||
| to be used for "greasing" as described in {{server-greasing}}. | to be used for "greasing" as described in {{server-greasing}}. | |||
| The initial contents for this registry consists of multiple reserved values, | The initial contents for this registry consists of multiple reserved values | |||
| with the following attributes, which are repeated for each registration: | with the following attributes, which are repeated for each registration: | |||
| Value: | Value: | |||
| : 0x0000, 0x1A1A, 0x2A2A, 0x3A3A, 0x4A4A, 0x5A5A, 0x6A6A, 0x7A7A, 0x8A8A, | : 0x0000, 0x1A1A, 0x2A2A, 0x3A3A, 0x4A4A, 0x5A5A, 0x6A6A, 0x7A7A, 0x8A8A, | |||
| 0x9A9A, 0xAAAA, 0xBABA, 0xCACA, 0xDADA, 0xEAEA, 0xFAFA | 0x9A9A, 0xAAAA, 0xBABA, 0xCACA, 0xDADA, 0xEAEA, 0xFAFA | |||
| Extension Name: | Extension Name: | |||
| : RESERVED | : RESERVED | |||
| Recommended: | Recommended: | |||
| : Y | : Y | |||
| Reference: | Reference: | |||
| : This document | : RFC 9849 | |||
| Notes: | Notes: | |||
| : Grease entries. | : Grease entries | |||
| {: spacing="compact"} | {: spacing="compact"} | |||
| <!-- [rfced] We note that the following terms use fixed-width font | ||||
| inconsistently. Please review these terms and let us know how we should update | ||||
| or if there are any specific patterns that should be followed (e.g., | ||||
| fixed-width font used for field names, variants, etc.). | ||||
| accept_confirmation | ||||
| cipher_suite | ||||
| ClientHello | ||||
| ClientHelloInner | ||||
| ClientHelloOuter | ||||
| ClientHelloOuterAAD | ||||
| config_id | ||||
| ECHClientHello | ||||
| ECHConfig | ||||
| ECHConfig.contents.public_name | ||||
| ECHConfigContents | ||||
| ECHConfigList | ||||
| EncodedClientHelloInner | ||||
| inner | ||||
| maximum_name_length | ||||
| outer | ||||
| payload | ||||
| public_key | ||||
| ServerHello.random | ||||
| zeros | ||||
| --> | ||||
| <!-- [rfced] We note that these terms are used inconsistently. Please let us | ||||
| know which form you prefer. | ||||
| split-mode vs. Split Mode | ||||
| GREASE vs. Grease (IANA Section) | ||||
| --> | ||||
| <!-- [rfced] FYI - We have added expansions for abbreviations upon first use | ||||
| per Section 3.6 of RFC 7322 ("RFC Style Guide"). Please review each | ||||
| expansion in the document carefully to ensure correctness. | ||||
| --> | ||||
| <!-- [rfced] Please review the "Inclusive Language" portion of the online | ||||
| Style Guide <https://www.rfc-editor.org/styleguide/part2/#inclusive_language> | ||||
| and let us know if any changes are needed. Updates of this nature typically | ||||
| result in more precise language, which is helpful for readers. Note that our | ||||
| script did not flag any words in particular, but this should still be reviewed | ||||
| as a best practice. --> | ||||
| --- back | --- back | |||
| # Linear-time Outer Extension Processing {#linear-outer-extensions} | # Linear-Time Outer Extension Processing {#linear-outer-extensions} | |||
| The following procedure processes the "ech_outer_extensions" extension (see | The following procedure processes the "ech_outer_extensions" extension (see | |||
| {{encoding-inner}}) in linear time, ensuring that each referenced extension | {{encoding-inner}}) in linear time, ensuring that each referenced extension | |||
| in the ClientHelloOuter is included at most once: | in the ClientHelloOuter is included at most once: | |||
| 1. Let I be initialized to zero and N be set to the number of extensions | 1. Let I be initialized to zero and N be set to the number of extensions | |||
| in ClientHelloOuter. | in ClientHelloOuter. | |||
| 1. For each extension type, E, in OuterExtensions: | 1. For each extension type, E, in OuterExtensions: | |||
| skipping to change at line 2035 ¶ | skipping to change at line 2211 ¶ | |||
| * While I is less than N and the I-th extension of | * While I is less than N and the I-th extension of | |||
| ClientHelloOuter does not have type E, increment I. | ClientHelloOuter does not have type E, increment I. | |||
| * If I is equal to N, abort the connection with an "illegal_parameter" | * If I is equal to N, abort the connection with an "illegal_parameter" | |||
| alert and terminate this procedure. | alert and terminate this procedure. | |||
| * Otherwise, the I-th extension of ClientHelloOuter has type E. Copy | * Otherwise, the I-th extension of ClientHelloOuter has type E. Copy | |||
| it to the EncodedClientHelloInner and increment I. | it to the EncodedClientHelloInner and increment I. | |||
| # Acknowledgements | # Acknowledgements | |||
| {:numbered="false"} | ||||
| This document draws extensively from ideas in {{?I-D.kazuho-protected-sni}}, but | This document draws extensively from ideas in {{?I-D.kazuho-protected-sni}}, but | |||
| is a much more limited mechanism because it depends on the DNS for the | is a much more limited mechanism because it depends on the DNS for the | |||
| protection of the ECH key. Richard Barnes, Christian Huitema, Patrick McManus, | protection of the ECH key. {{{Richard Barnes}}}, {{{Christian Huitema}}}, {{{Patrick | |||
| Matthew Prince, Nick Sullivan, Martin Thomson, and David Benjamin also provided | McManus}}}, | |||
| {{{Matthew Prince}}}, {{{Nick Sullivan}}}, {{{Martin Thomson}}}, and {{{David Benjami | ||||
| n}}} also provided | ||||
| important ideas and contributions. | important ideas and contributions. | |||
| # Change Log | ||||
| > **RFC Editor's Note:** Please remove this section prior to publication of a | ||||
| > final version of this document. | ||||
| Issue and pull request numbers are listed with a leading octothorp. | ||||
| ## Since draft-ietf-tls-esni-16 | ||||
| - Keep-alive | ||||
| ## Since draft-ietf-tls-esni-15 | ||||
| - Add CCS2022 reference and summary (#539) | ||||
| ## Since draft-ietf-tls-esni-14 | ||||
| - Keep-alive | ||||
| ## Since draft-ietf-tls-esni-13 | ||||
| - Editorial improvements | ||||
| ## Since draft-ietf-tls-esni-12 | ||||
| - Abort on duplicate OuterExtensions (#514) | ||||
| - Improve EncodedClientHelloInner definition (#503) | ||||
| - Clarify retry configuration usage (#498) | ||||
| - Expand on config_id generation implications (#491) | ||||
| - Server-side acceptance signal extension GREASE (#481) | ||||
| - Refactor overview, client implementation, and middlebox | ||||
| sections (#480, #478, #475, #508) | ||||
| - Editorial iprovements (#485, #488, #490, #495, #496, #499, #500, | ||||
| #501, #504, #505, #507, #510, #511) | ||||
| ## Since draft-ietf-tls-esni-11 | ||||
| - Move ClientHello padding to the encoding (#443) | ||||
| - Align codepoints (#464) | ||||
| - Relax OuterExtensions checks for alignment with RFC8446 (#467) | ||||
| - Clarify HRR acceptance and rejection logic (#470) | ||||
| - Editorial improvements (#468, #465, #462, #461) | ||||
| ## Since draft-ietf-tls-esni-10 | ||||
| - Make HRR confirmation and ECH acceptance explicit (#422, #423) | ||||
| - Relax computation of the acceptance signal (#420, #449) | ||||
| - Simplify ClientHelloOuterAAD generation (#438, #442) | ||||
| - Allow empty enc in ECHClientHello (#444) | ||||
| - Authenticate ECHClientHello extensions position in ClientHelloOuterAAD (#410) | ||||
| - Allow clients to send a dummy PSK and early_data in ClientHelloOuter when | ||||
| applicable (#414, #415) | ||||
| - Compress ECHConfigContents (#409) | ||||
| - Validate ECHConfig.contents.public_name (#413, #456) | ||||
| - Validate ClientHelloInner contents (#411) | ||||
| - Note split-mode challenges for HRR (#418) | ||||
| - Editorial improvements (#428, #432, #439, #445, #458, #455) | ||||
| ## Since draft-ietf-tls-esni-09 | ||||
| - Finalize HPKE dependency (#390) | ||||
| - Move from client-computed to server-chosen, one-byte config | ||||
| identifier (#376, #381) | ||||
| - Rename ECHConfigs to ECHConfigList (#391) | ||||
| - Clarify some security and privacy properties (#385, #383) | ||||
| End of changes. 115 change blocks. | ||||
| 133 lines changed or deleted | 320 lines changed or added | |||
This html diff was produced by rfcdiff 1.48. | ||||