| rfc9849v2.txt | rfc9849.txt | |||
|---|---|---|---|---|
| Internet Engineering Task Force (IETF) E. Rescorla | Internet Engineering Task Force (IETF) E. Rescorla | |||
| Request for Comments: 9849 Knight-Georgetown Institute | Request for Comments: 9849 Knight-Georgetown Institute | |||
| Category: Standards Track K. Oku | Category: Standards Track K. Oku | |||
| ISSN: 2070-1721 Fastly | ISSN: 2070-1721 Fastly | |||
| N. Sullivan | N. Sullivan | |||
| Cryptography Consulting LLC | Cryptography Consulting LLC | |||
| C. A. Wood | C. A. Wood | |||
| Cloudflare | Cloudflare | |||
| November 2025 | December 2025 | |||
| TLS Encrypted Client Hello | TLS Encrypted Client Hello | |||
| Abstract | Abstract | |||
| This document describes a mechanism in Transport Layer Security (TLS) | This document describes a mechanism in Transport Layer Security (TLS) | |||
| for encrypting a ClientHello message under a server public key. | for encrypting a ClientHello message under a server public key. | |||
| Status of This Memo | Status of This Memo | |||
| skipping to change at line 191 ¶ | skipping to change at line 191 ¶ | |||
| Client <-----> | private.example.org | | Client <-----> | private.example.org | | |||
| | | | | | | |||
| | public.example.com | | | public.example.com | | |||
| | | | | | | |||
| +---------------------+ | +---------------------+ | |||
| Server | Server | |||
| (Client-Facing and Backend Combined) | (Client-Facing and Backend Combined) | |||
| Figure 1: Shared Mode Topology | Figure 1: Shared Mode Topology | |||
| In Shared Mode, the provider is the origin server for all the domains | In shared mode, the provider is the origin server for all the domains | |||
| whose DNS records point to it. In this mode, the TLS connection is | whose DNS records point to it. In this mode, the TLS connection is | |||
| terminated by the provider. | terminated by the provider. | |||
| +--------------------+ +---------------------+ | +--------------------+ +---------------------+ | |||
| | | | | | | | | | | |||
| | 2001:DB8::1111 | | 2001:DB8::EEEE | | | 2001:DB8::1111 | | 2001:DB8::EEEE | | |||
| Client <----------------------------->| | | Client <----------------------------->| | | |||
| | public.example.com | | private.example.org | | | public.example.com | | private.example.org | | |||
| | | | | | | | | | | |||
| +--------------------+ +---------------------+ | +--------------------+ +---------------------+ | |||
| skipping to change at line 216 ¶ | skipping to change at line 216 ¶ | |||
| In split mode, the provider is not the origin server for private | In split mode, the provider is not the origin server for private | |||
| domains. Rather, the DNS records for private domains point to the | domains. Rather, the DNS records for private domains point to the | |||
| provider, and the provider's server relays the connection back to the | provider, and the provider's server relays the connection back to the | |||
| origin server, who terminates the TLS connection with the client. | origin server, who terminates the TLS connection with the client. | |||
| Importantly, the service provider does not have access to the | Importantly, the service provider does not have access to the | |||
| plaintext of the connection beyond the unencrypted portions of the | plaintext of the connection beyond the unencrypted portions of the | |||
| handshake. | handshake. | |||
| In the remainder of this document, we will refer to the ECH-service | 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 | provider as the "client-facing server" and to the TLS terminator as | |||
| the "backend server". These are the same entity in Shared Mode, but | the "backend server". These are the same entity in shared mode, but | |||
| in split mode, the client-facing and backend servers are physically | in split mode, the client-facing and backend servers are physically | |||
| separated. | separated. | |||
| See Section 10 for more discussion about the ECH threat model and how | See Section 10 for more discussion about the ECH threat model and how | |||
| it relates to the client, client-facing server, and backend server. | it relates to the client, client-facing server, and backend server. | |||
| 3.2. Encrypted ClientHello (ECH) | 3.2. Encrypted ClientHello (ECH) | |||
| A client-facing server enables ECH by publishing an ECH | A client-facing server enables ECH by publishing an ECH | |||
| configuration, which is an encryption public key and associated | configuration, which is an encryption public key and associated | |||
| skipping to change at line 523 ¶ | skipping to change at line 523 ¶ | |||
| 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 | The client_hello field is computed by first making a copy of | |||
| ClientHelloInner and setting the legacy_session_id field to the empty | ClientHelloInner and setting the legacy_session_id field to the empty | |||
| string. In TLS, this field uses the ClientHello structure defined in | string. In TLS, this field uses the ClientHello structure defined in | |||
| Section 4.1.2 of [RFC8446]. In DTLS, it uses the ClientHello | Section 4.1.2 of [RFC8446]. In DTLS, it uses the ClientHello | |||
| structured defined in Section 5.3 of [RFC9147]. This does not | structure defined in Section 5.3 of [RFC9147]. This does not include | |||
| include Handshake structure's four-byte header in TLS, nor twelve- | Handshake structure's four-byte header in TLS, nor twelve-byte header | |||
| byte header in DTLS. The zeros field MUST be all zeroes of length | in DTLS. The zeros field MUST be all zeroes of length | |||
| length_of_padding (see Section 6.1.3). | length_of_padding (see Section 6.1.3). | |||
| Repeating large extensions, such as "key_share" with post-quantum | Repeating large extensions, such as "key_share" with post-quantum | |||
| algorithms, between ClientHelloInner and ClientHelloOuter can lead to | algorithms, between ClientHelloInner and ClientHelloOuter can lead to | |||
| excessive size. To reduce the size impact, the client MAY substitute | excessive size. To reduce the size impact, the client MAY substitute | |||
| extensions which it knows will be duplicated in ClientHelloOuter. It | extensions which it knows will be duplicated in ClientHelloOuter. It | |||
| does so by removing and replacing extensions from | does so by removing and replacing extensions from | |||
| EncodedClientHelloInner with a single "ech_outer_extensions" | EncodedClientHelloInner with a single "ech_outer_extensions" | |||
| extension, defined as follows: | extension, defined as follows: | |||
| skipping to change at line 677 ¶ | skipping to change at line 677 ¶ | |||
| order as in ClientHelloInner. | order as in ClientHelloInner. | |||
| 3. It MUST copy the legacy_session_id field from ClientHelloInner. | 3. It MUST copy the legacy_session_id field from ClientHelloInner. | |||
| This allows the server to echo the correct session ID for TLS | This allows the server to echo the correct session ID for TLS | |||
| 1.3's compatibility mode (see Appendix D.4 of [RFC8446]) when ECH | 1.3's compatibility mode (see Appendix D.4 of [RFC8446]) when ECH | |||
| is negotiated. Note that compatibility mode is not used in DTLS | is negotiated. Note that compatibility mode is not used in DTLS | |||
| 1.3, but following this rule will produce the correct results for | 1.3, but following this rule will produce the correct results for | |||
| both TLS 1.3 and DTLS 1.3. | both TLS 1.3 and DTLS 1.3. | |||
| 4. It MAY copy any other field from the ClientHelloInner except | 4. It MAY copy any other field from the ClientHelloInner except | |||
| ClientHelloInner.random. Instead, It MUST generate a fresh | ClientHelloInner.random. Instead, it MUST generate a fresh | |||
| ClientHelloOuter.random using a secure random number generator. | ClientHelloOuter.random using a secure random number generator. | |||
| (See Section 10.12.1.) | (See Section 10.12.1.) | |||
| 5. It SHOULD place the value of ECHConfig.contents.public_name in | 5. It SHOULD place the value of ECHConfig.contents.public_name in | |||
| the "server_name" extension. Clients that do not follow this | the "server_name" extension. Clients that do not follow this | |||
| step, or place a different value in the "server_name" extension, | step, or place a different value in the "server_name" extension, | |||
| risk breaking the retry mechanism described in Section 6.1.6 or | risk breaking the retry mechanism described in Section 6.1.6 or | |||
| failing to interoperate with servers that require this step to be | failing to interoperate with servers that require this step to be | |||
| done; see Section 7.1. | done; see Section 7.1. | |||
| skipping to change at line 1131 ¶ | skipping to change at line 1131 ¶ | |||
| application-level warning message when these are observed. | application-level warning message when these are observed. | |||
| * By giving the extraneous configurations an invalid public key and | * By giving the extraneous configurations an invalid public key and | |||
| a public name not associated with the server so that the initial | a public name not associated with the server so that the initial | |||
| ClientHelloOuter will not be decryptable and the server cannot | ClientHelloOuter will not be decryptable and the server cannot | |||
| perform the recovery flow described in Section 6.1.6. | perform the recovery flow described in Section 6.1.6. | |||
| 7. Server Behavior | 7. Server Behavior | |||
| As described in Section 3.1, servers can play two roles, either as | As described in Section 3.1, servers can play two roles, either as | |||
| the client-facing server or as the back-end server. Depending on the | the client-facing server or as the backend server. Depending on the | |||
| server role, the ECHClientHello will be different: | server role, the ECHClientHello will be different: | |||
| * A client-facing server expects an ECHClientHello.type of outer, | * A client-facing server expects an ECHClientHello.type of outer, | |||
| and proceeds as described in Section 7.1 to extract a | and proceeds as described in Section 7.1 to extract a | |||
| ClientHelloInner, if available. | ClientHelloInner, if available. | |||
| * A backend server expects an ECHClientHello.type of inner, and | * A backend server expects an ECHClientHello.type of inner, and | |||
| proceeds as described in Section 7.2. | proceeds as described in Section 7.2. | |||
| In split mode, a client-facing server which receives a ClientHello | In split mode, a client-facing server which receives a ClientHello | |||
| skipping to change at line 1201 ¶ | skipping to change at line 1201 ¶ | |||
| indicated by the ECHClientHello.cipher_suite and that the version of | indicated by the ECHClientHello.cipher_suite and that the version of | |||
| ECH indicated by the client matches the ECHConfig.version. If not, | ECH indicated by the client matches the ECHConfig.version. If not, | |||
| the server continues to the next candidate ECHConfig. | the server continues to the next candidate ECHConfig. | |||
| Next, the server decrypts ECHClientHello.payload, using the private | Next, the server decrypts ECHClientHello.payload, using the private | |||
| key skR corresponding to ECHConfig, as follows: | key skR corresponding to ECHConfig, as follows: | |||
| context = SetupBaseR(ECHClientHello.enc, skR, | context = SetupBaseR(ECHClientHello.enc, skR, | |||
| "tls ech" || 0x00 || ECHConfig) | "tls ech" || 0x00 || ECHConfig) | |||
| EncodedClientHelloInner = context.Open(ClientHelloOuterAAD, | EncodedClientHelloInner = context.Open(ClientHelloOuterAAD, | |||
| ECHClientHello.payload) | ECHClientHello.payload) | |||
| ClientHelloOuterAAD is computed from ClientHelloOuter as described in | ClientHelloOuterAAD is computed from ClientHelloOuter as described in | |||
| Section 5.2. The info parameter to SetupBaseR is the concatenation | Section 5.2. The info parameter to SetupBaseR is the concatenation | |||
| "tls ech", a zero byte, and the serialized ECHConfig. If decryption | "tls ech", a zero byte, and the serialized ECHConfig. If decryption | |||
| fails, the server continues to the next candidate ECHConfig. | 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 Section 5.1. It then stops | EncodedClientHelloInner, as described in Section 5.1. 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 | Once the server has chosen the correct ECHConfig, it MAY verify that | |||
| skipping to change at line 1278 ¶ | skipping to change at line 1278 ¶ | |||
| extension. If not, it MUST abort the handshake with a | extension. If not, it MUST abort the handshake with a | |||
| "missing_extension" alert. Otherwise, it checks that | "missing_extension" alert. Otherwise, it checks that | |||
| ECHClientHello.cipher_suite and ECHClientHello.config_id are | ECHClientHello.cipher_suite and ECHClientHello.config_id are | |||
| unchanged, and that ECHClientHello.enc is empty. If not, it MUST | unchanged, and that ECHClientHello.enc is empty. If not, it MUST | |||
| abort the handshake with an "illegal_parameter" alert. | abort the handshake with an "illegal_parameter" alert. | |||
| Finally, it decrypts the new ECHClientHello.payload as a second | Finally, it decrypts the new ECHClientHello.payload as a second | |||
| message with the previous HPKE context: | message with the previous HPKE context: | |||
| EncodedClientHelloInner = context.Open(ClientHelloOuterAAD, | EncodedClientHelloInner = context.Open(ClientHelloOuterAAD, | |||
| ECHClientHello.payload) | ECHClientHello.payload) | |||
| ClientHelloOuterAAD is computed as described in Section 5.2, but | ClientHelloOuterAAD is computed as described in Section 5.2, but | |||
| using the second ClientHelloOuter. If decryption fails, the client- | using the second ClientHelloOuter. If decryption fails, the client- | |||
| facing server MUST abort the handshake with a "decrypt_error" alert. | facing server MUST abort the handshake with a "decrypt_error" alert. | |||
| Otherwise, it reconstructs the second ClientHelloInner from the new | Otherwise, it reconstructs the second ClientHelloInner from the new | |||
| EncodedClientHelloInner as described in Section 5.1, using the second | EncodedClientHelloInner as described in Section 5.1, using the second | |||
| ClientHelloOuter for any referenced extensions. | ClientHelloOuter for any referenced extensions. | |||
| The client-facing server then forwards the resulting ClientHelloInner | The client-facing server then forwards the resulting ClientHelloInner | |||
| to the backend server. It forwards all subsequent TLS messages | to the backend server. It forwards all subsequent TLS messages | |||
| skipping to change at line 1709 ¶ | skipping to change at line 1709 ¶ | |||
| adversary that observes this can deduce that the ECH-enabled | adversary that observes this can deduce that the ECH-enabled | |||
| connection was made to a host that the client previously connected to | connection was made to a host that the client previously connected to | |||
| and which is within the same anonymity set. | and which is within the same anonymity set. | |||
| 10.8. Cookies | 10.8. Cookies | |||
| Section 4.2.2 of [RFC8446] defines a cookie value that servers may | Section 4.2.2 of [RFC8446] defines a cookie value that servers may | |||
| send in HelloRetryRequest for clients to echo in the second | send in HelloRetryRequest for clients to echo in the second | |||
| ClientHello. While ECH encrypts the cookie in the second | ClientHello. While ECH encrypts the cookie in the second | |||
| ClientHelloInner, the backend server's HelloRetryRequest is | ClientHelloInner, the backend server's HelloRetryRequest is | |||
| unencrypted.This means differences in cookies between backend | unencrypted. This means differences in cookies between backend | |||
| servers, such as lengths or cleartext components, may leak | servers, such as lengths or cleartext components, may leak | |||
| information about the server identity. | information about the server identity. | |||
| Backend servers in an anonymity set SHOULD NOT reveal information in | Backend servers in an anonymity set SHOULD NOT reveal information in | |||
| the cookie which identifies the server. This may be done by handling | the cookie which identifies the server. This may be done by handling | |||
| HelloRetryRequest statefully, thus not sending cookies, or by using | HelloRetryRequest statefully, thus not sending cookies, or by using | |||
| the same cookie construction for all backend servers. | the same cookie construction for all backend servers. | |||
| Note that, if the cookie includes a key name, analogous to Section 4 | Note that, if the cookie includes a key name, analogous to Section 4 | |||
| of [RFC5077], this may leak information if different backend servers | of [RFC5077], this may leak information if different backend servers | |||
| skipping to change at line 2113 ¶ | skipping to change at line 2113 ¶ | |||
| 11.3. ECH Configuration Extension Registry | 11.3. ECH Configuration Extension Registry | |||
| IANA has created a new "TLS 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" registry | "TLS Encrypted Client Hello (ECH) Configuration Extensions" registry | |||
| group. New registrations will list the following attributes: | group. New registrations will list the following attributes: | |||
| Value: The two-byte identifier for the ECHConfigExtension, i.e., the | Value: The two-byte identifier for the ECHConfigExtension, i.e., the | |||
| ECHConfigExtensionType | ECHConfigExtensionType | |||
| Extension Name: Name of the ECHConfigExtension | Extension Name: Name of the ECHConfigExtension | |||
| Recommended: A "Y" or "N" value indicating if the extension is TLS | Recommended: A "Y" or "N" value indicating if the TLS Working Group | |||
| WG recommends that the extension be supported. This column is | recommends that the extension be supported. This column is | |||
| assigned a value of "N" unless explicitly requested. Adding a | assigned a value of "N" unless explicitly requested. Adding a | |||
| value with a value of "Y" requires Standards Action [RFC8126]. | value of "Y" requires Standards Action [RFC8126]. | |||
| Reference: The specification where the ECHConfigExtension is defined | Reference: The specification where the ECHConfigExtension is defined | |||
| Notes: Any notes associated with the entry | Notes: Any notes associated with the entry | |||
| New entries in the "TLS ECHConfig Extension" registry are subject to | New entries in the "TLS ECHConfig Extension" registry are subject to | |||
| the Specification Required registration policy ([RFC8126], | the Specification Required registration policy ([RFC8126], | |||
| Section 4.6), with the policies described in [RFC8447], Section 17. | Section 4.6), with the policies described in [RFC8447], Section 17. | |||
| IANA has added the following note to the "TLS ECHConfig Extension" | IANA 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. | |||
| skipping to change at line 2281 ¶ | skipping to change at line 2281 ¶ | |||
| DOI 10.17487/RFC8744, July 2020, | DOI 10.17487/RFC8744, July 2020, | |||
| <https://www.rfc-editor.org/info/rfc8744>. | <https://www.rfc-editor.org/info/rfc8744>. | |||
| [RFC9250] Huitema, C., Dickinson, S., and A. Mankin, "DNS over | [RFC9250] Huitema, C., Dickinson, S., and A. Mankin, "DNS over | |||
| Dedicated QUIC Connections", RFC 9250, | Dedicated QUIC Connections", RFC 9250, | |||
| DOI 10.17487/RFC9250, May 2022, | DOI 10.17487/RFC9250, May 2022, | |||
| <https://www.rfc-editor.org/info/rfc9250>. | <https://www.rfc-editor.org/info/rfc9250>. | |||
| [RFCYYY1] Schwartz, B., Bishop, M., and E. Nygren, "Bootstrapping | [RFCYYY1] Schwartz, B., Bishop, M., and E. Nygren, "Bootstrapping | |||
| TLS Encrypted ClientHello with DNS Service Bindings", | TLS Encrypted ClientHello with DNS Service Bindings", | |||
| RFC YYY1, DOI 10.17487/RFCYYY1, November 2025, | RFC YYY1, DOI 10.17487/RFCYYY1, December 2025, | |||
| <https://www.rfc-editor.org/info/rfcYYY1>. | <https://www.rfc-editor.org/info/rfcYYY1>. | |||
| [WHATWG-IPV4] | [WHATWG-IPV4] | |||
| WHATWG, "URL - IPv4 Parser", WHATWG Living Standard, May | WHATWG, "URL - IPv4 Parser", WHATWG Living Standard, May | |||
| 2021, <https://url.spec.whatwg.org/#concept-ipv4-parser>. | 2021, <https://url.spec.whatwg.org/#concept-ipv4-parser>. | |||
| Appendix A. Linear-Time Outer Extension Processing | Appendix A. Linear-Time Outer Extension Processing | |||
| The following procedure processes the "ech_outer_extensions" | The following procedure processes the "ech_outer_extensions" | |||
| extension (see Section 5.1) in linear time, ensuring that each | extension (see Section 5.1) in linear time, ensuring that each | |||
| End of changes. 12 change blocks. | ||||
| 15 lines changed or deleted | 15 lines changed or added | |||
This html diff was produced by rfcdiff 1.48. | ||||