rfc9849v3.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 Independent
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 Apple
December 2025 February 2026
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 35 skipping to change at line 35
received public review and has been approved for publication by the received public review and has been approved for publication by the
Internet Engineering Steering Group (IESG). Further information on Internet Engineering Steering Group (IESG). Further information on
Internet Standards is available in Section 2 of RFC 7841. Internet Standards is available in Section 2 of RFC 7841.
Information about the current status of this document, any errata, Information about the current status of this document, any errata,
and how to provide feedback on it may be obtained at and how to provide feedback on it may be obtained at
https://www.rfc-editor.org/info/rfc9849. https://www.rfc-editor.org/info/rfc9849.
Copyright Notice Copyright Notice
Copyright (c) 2025 IETF Trust and the persons identified as the Copyright (c) 2026 IETF Trust and the persons identified as the
document authors. All rights reserved. document authors. All rights reserved.
This document is subject to BCP 78 and the IETF Trust's Legal This document is subject to BCP 78 and the IETF Trust's Legal
Provisions Relating to IETF Documents Provisions Relating to IETF Documents
(https://trustee.ietf.org/license-info) in effect on the date of (https://trustee.ietf.org/license-info) in effect on the date of
publication of this document. Please review these documents publication of this document. Please review these documents
carefully, as they describe your rights and restrictions with respect carefully, as they describe your rights and restrictions with respect
to this document. Code Components extracted from this document must to this document. Code Components extracted from this document must
include Revised BSD License text as described in Section 4.e of the include Revised BSD License text as described in Section 4.e of the
Trust Legal Provisions and are provided without warranty as described Trust Legal Provisions and are provided without warranty as described
skipping to change at line 433 skipping to change at line 433
enabler for authenticated key mismatch signals (see Section 7). In enabler for authenticated key mismatch signals (see Section 7). In
contrast, the inner ClientHello is the true ClientHello used upon ECH contrast, the inner ClientHello is the true ClientHello used upon ECH
negotiation. negotiation.
5. The "encrypted_client_hello" Extension 5. The "encrypted_client_hello" Extension
To offer ECH, the client sends an "encrypted_client_hello" extension To offer ECH, the client sends an "encrypted_client_hello" extension
in the ClientHelloOuter. When it does, it MUST also send the in the ClientHelloOuter. When it does, it MUST also send the
extension in ClientHelloInner. extension in ClientHelloInner.
enum { ~~ enum { encrypted_client_hello(0xfe0d), (65535) } ExtensionType; ~~
encrypted_client_hello(0xfe0d), (65535)
} ExtensionType;
The payload of the extension has the following structure: The payload of the extension has the following structure:
enum { outer(0), inner(1) } ECHClientHelloType; enum { outer(0), inner(1) } ECHClientHelloType;
struct { struct {
ECHClientHelloType type; ECHClientHelloType type;
select (ECHClientHello.type) { select (ECHClientHello.type) {
case outer: case outer:
HpkeSymmetricCipherSuite cipher_suite; HpkeSymmetricCipherSuite cipher_suite;
skipping to change at line 479 skipping to change at line 477
ClientHelloOuter sent in response to HelloRetryRequest. ClientHelloOuter sent in response to HelloRetryRequest.
payload: The serialized and encrypted EncodedClientHelloInner payload: The serialized and encrypted EncodedClientHelloInner
structure, encrypted using HPKE as described in Section 6.1. structure, encrypted using HPKE as described in Section 6.1.
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, the server MAY include an "encrypted_client_hello"
extension in its EncryptedExtensions message, as described in extension in its EncryptedExtensions message, as described in
Section 7.1, with the following payload: Section 7.1, with the following payload:
struct { ~~ struct { ECHConfigList retry_configs; } ECHEncryptedExtensions; ~~
ECHConfigList retry_configs;
} ECHEncryptedExtensions;
The response is valid only when the server used the ClientHelloOuter. The response is valid only when the server used the ClientHelloOuter.
If the server sent this extension in response to the inner variant, If the server sent this extension in response to the inner variant,
then the client MUST abort with an "unsupported_extension" alert. then the client MUST abort with an "unsupported_extension" alert.
retry_configs: An ECHConfigList structure containing one or more retry_configs: An ECHConfigList structure containing one or more
ECHConfig structures, in decreasing order of preference, to be ECHConfig structures, in decreasing order of preference, to be
used by the client as described in Section 6.1.6. These are known used by the client as described in Section 6.1.6. These are known
as the server's "retry configurations". as the server's "retry configurations".
Finally, when the client offers the "encrypted_client_hello", if the Finally, when the client offers the "encrypted_client_hello", if the
payload is the inner variant and the server responds with payload is the inner variant and the server responds with
HelloRetryRequest, it MUST include an "encrypted_client_hello" HelloRetryRequest, it MUST include an "encrypted_client_hello"
extension with the following payload: extension with the following payload:
struct { ~~ struct { opaque confirmation[8]; } ECHHelloRetryRequest; ~~
opaque confirmation[8];
} ECHHelloRetryRequest;
The value of ECHHelloRetryRequest.confirmation is set to The value of ECHHelloRetryRequest.confirmation is set to
hrr_accept_confirmation as described in Section 7.2.1. hrr_accept_confirmation as described in Section 7.2.1.
This document also defines the "ech_required" alert, which the client This document also defines the "ech_required" alert, which the client
MUST send when it offered an "encrypted_client_hello" extension that MUST send when it offered an "encrypted_client_hello" extension that
was not accepted by the server. (See Section 11.2.) was not accepted by the server. (See Section 11.2.)
5.1. Encoding the ClientHelloInner 5.1. Encoding the ClientHelloInner
Before encrypting, the client pads and optionally compresses Before encrypting, the client pads and optionally compresses
ClientHelloInner into an EncodedClientHelloInner structure, defined ClientHelloInner into an EncodedClientHelloInner structure, defined
below: below:
struct { ~~ struct { ClientHello client_hello; uint8 zeros[length_of_padding];
ClientHello client_hello; } EncodedClientHelloInner; ~~
uint8 zeros[length_of_padding];
} 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
structure defined in Section 5.3 of [RFC9147]. This does not include structure defined in Section 5.3 of [RFC9147]. This does not include
Handshake structure's four-byte header in TLS, nor twelve-byte header Handshake structure's four-byte header in TLS, nor twelve-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:
enum { ~~ enum { ech_outer_extensions(0xfd00), (65535) } ExtensionType;
ech_outer_extensions(0xfd00), (65535)
} ExtensionType;
ExtensionType OuterExtensions<2..254>; ExtensionType OuterExtensions<2..254>; ~~
OuterExtensions contains the removed ExtensionType values. Each OuterExtensions contains the removed ExtensionType values. Each
value references the matching extension in ClientHelloOuter. The value references the matching extension in ClientHelloOuter. The
values MUST be ordered contiguously in ClientHelloInner, and the values MUST be ordered contiguously in ClientHelloInner, and the
"ech_outer_extensions" extension MUST be inserted in the "ech_outer_extensions" extension MUST be inserted in the
corresponding position in EncodedClientHelloInner. Additionally, the corresponding position in EncodedClientHelloInner. Additionally, the
extensions MUST appear in ClientHelloOuter in the same relative extensions MUST appear in ClientHelloOuter in the same relative
order. However, there is no requirement that they be contiguous. order. However, there is no requirement that they be contiguous.
For example, OuterExtensions may contain extensions A, B, and C, For example, OuterExtensions may contain extensions A, B, and C,
while ClientHelloOuter contains extensions A, D, B, C, E, and F. while ClientHelloOuter contains extensions A, D, B, C, E, and F.
skipping to change at line 627 skipping to change at line 617
in possession of a compatible ECH configuration and sends GREASE ECH in possession of a compatible ECH configuration and sends GREASE ECH
(see Section 6.2) otherwise. (see Section 6.2) otherwise.
6.1. Offering ECH 6.1. Offering ECH
To offer ECH, the client first chooses a suitable ECHConfig from the To offer ECH, the client first chooses a suitable ECHConfig from the
server's ECHConfigList. To determine if a given ECHConfig is server's ECHConfigList. To determine if a given ECHConfig is
suitable, it checks that it supports the KEM algorithm identified by suitable, it checks that it supports the KEM algorithm identified by
ECHConfig.contents.kem_id, at least one KDF/AEAD algorithm identified ECHConfig.contents.kem_id, at least one KDF/AEAD algorithm identified
by ECHConfig.contents.cipher_suites, and the version of ECH indicated by ECHConfig.contents.cipher_suites, and the version of ECH indicated
by ECHConfig.contents.version. Once a suitable configuration is by ECHConfig.version. Once a suitable configuration is found, the
found, the client selects the cipher suite it will use for client selects the cipher suite it will use for encryption. It MUST
encryption. It MUST NOT choose a cipher suite or version not NOT choose a cipher suite or version not advertised by the
advertised by the configuration. If no compatible configuration is configuration. If no compatible configuration is found, then the
found, then the client SHOULD proceed as described in Section 6.2. client SHOULD proceed as described in Section 6.2.
Next, the client constructs the ClientHelloInner message just as it Next, the client constructs the ClientHelloInner message just as it
does a standard ClientHello, with the exception of the following does a standard ClientHello, with the exception of the following
rules: rules:
1. It MUST NOT offer to negotiate TLS 1.2 or below. This is 1. It MUST NOT offer to negotiate TLS 1.2 or below. This is
necessary to ensure the backend server does not negotiate a TLS necessary to ensure the backend server does not negotiate a TLS
version that is incompatible with ECH. version that is incompatible with ECH.
2. It MUST NOT offer to resume any session for TLS 1.2 and below. 2. It MUST NOT offer to resume any session for TLS 1.2 and below.
skipping to change at line 655 skipping to change at line 645
4. It MUST include the "encrypted_client_hello" extension of type 4. It MUST include the "encrypted_client_hello" extension of type
inner as described in Section 5. (This requirement is not inner as described in Section 5. (This requirement is not
applicable when the "encrypted_client_hello" extension is applicable when the "encrypted_client_hello" extension is
generated as described in Section 6.2.) generated as described in Section 6.2.)
The client then constructs EncodedClientHelloInner as described in The client then constructs EncodedClientHelloInner as described in
Section 5.1. It also computes an HPKE encryption context and enc Section 5.1. It also computes an HPKE encryption context and enc
value as: value as:
pkR = DeserializePublicKey(ECHConfig.contents.public_key) ~~ pkR = DeserializePublicKey(ECHConfig.contents.public_key) enc,
enc, context = SetupBaseS(pkR, context = SetupBaseS(pkR, "tls ech" || 0x00 || ECHConfig) ~~
"tls ech" || 0x00 || ECHConfig)
Next, it constructs a partial ClientHelloOuterAAD as it does a Next, it constructs a partial ClientHelloOuterAAD as it does a
standard ClientHello, with the exception of the following rules: standard ClientHello, with the exception of the following rules:
1. It MUST offer to negotiate TLS 1.3 or above. 1. It MUST offer to negotiate TLS 1.3 or above.
2. If it compressed any extensions in EncodedClientHelloInner, it 2. If it compressed any extensions in EncodedClientHelloInner, it
MUST copy the corresponding extensions from ClientHelloInner. MUST copy the corresponding extensions from ClientHelloInner.
The copied extensions additionally MUST be in the same relative The copied extensions additionally MUST be in the same relative
order as in ClientHelloInner. order as in ClientHelloInner.
skipping to change at line 744 skipping to change at line 733
* payload, a placeholder byte string containing L zeros. * payload, a placeholder byte string containing L zeros.
If configuration identifiers (see Section 10.4) are to be ignored, If configuration identifiers (see Section 10.4) are to be ignored,
config_id SHOULD be set to a randomly generated byte in the first config_id SHOULD be set to a randomly generated byte in the first
ClientHelloOuter and, in the event of a HelloRetryRequest (HRR), MUST ClientHelloOuter and, in the event of a HelloRetryRequest (HRR), MUST
be left unchanged for the second ClientHelloOuter. be left unchanged for the second ClientHelloOuter.
The client serializes this structure to construct the The client serializes this structure to construct the
ClientHelloOuterAAD. It then computes the final payload as: ClientHelloOuterAAD. It then computes the final payload as:
final_payload = context.Seal(ClientHelloOuterAAD, ~~ final_payload = context.Seal(ClientHelloOuterAAD,
EncodedClientHelloInner) EncodedClientHelloInner) ~~
Including ClientHelloOuterAAD as the HPKE AAD binds the Including ClientHelloOuterAAD as the HPKE AAD binds the
ClientHelloOuter to the ClientHelloInner, thus preventing attackers ClientHelloOuter to the ClientHelloInner, thus preventing attackers
from modifying ClientHelloOuter while keeping the same from modifying ClientHelloOuter while keeping the same
ClientHelloInner, as described in Section 10.12.3. ClientHelloInner, as described in Section 10.12.3.
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 ClientHelloOuter. The two values have the same length, so it is not
necessary to recompute length prefixes in the serialized structure. necessary to recompute length prefixes in the serialized structure.
skipping to change at line 812 skipping to change at line 801
By way of example, clients typically support a small number of By way of example, clients typically support a small number of
application profiles. For instance, a browser might support HTTP application profiles. For instance, a browser might support HTTP
with ALPN values ["http/1.1", "h2"] and WebRTC media with ALPNs with ALPN values ["http/1.1", "h2"] and WebRTC media with ALPNs
["webrtc", "c-webrtc"]. Clients SHOULD pad this extension by ["webrtc", "c-webrtc"]. Clients SHOULD pad this extension by
rounding up to the total size of the longest ALPN extension across rounding up to the total size of the longest ALPN extension across
all application profiles. The target padding length of most all application profiles. The target padding length of most
ClientHello extensions can be computed in this way. ClientHello extensions can be computed in this way.
In contrast, clients do not know the longest SNI value in the client- In contrast, clients do not know the longest SNI value in the client-
facing server's anonymity set without server input. Clients SHOULD facing server's anonymity set without server input. Clients SHOULD
use the ECHConfig's maximum_name_length field as follows, where L is use the ECHConfig's maximum_name_length field as follows, where M is
the maximum_name_length value. the maximum_name_length value.
1. If the ClientHelloInner contained a "server_name" extension with 1. If the ClientHelloInner contained a "server_name" extension with
a name of length D, add max(0, L - D) bytes of padding. a name of length D, add max(0, M - D) bytes of padding.
2. If the ClientHelloInner did not contain a "server_name" extension 2. If the ClientHelloInner did not contain a "server_name" extension
(e.g., if the client is connecting to an IP address), add L + 9 (e.g., if the client is connecting to an IP address), add M + 9
bytes of padding. This is the length of a "server_name" bytes of padding. This is the length of a "server_name"
extension with an L-byte name. extension with an M-byte name.
Finally, the client SHOULD pad the entire message as follows: Finally, the client SHOULD pad the entire message as follows:
1. Let L be the length of the EncodedClientHelloInner with all the 1. Let L be the length of the EncodedClientHelloInner with all the
padding computed so far. padding computed so far.
2. Let N = 31 - ((L - 1) % 32) and add N bytes of padding. 2. Let N = 31 - ((L - 1) % 32) and add N bytes of padding.
This rounds the length of EncodedClientHelloInner up to a multiple of This rounds the length of EncodedClientHelloInner up to a multiple of
32 bytes, reducing the set of possible lengths across all clients. 32 bytes, reducing the set of possible lengths across all clients.
skipping to change at line 1198 skipping to change at line 1187
follows. follows.
The server verifies that the ECHConfig supports the cipher suite The server verifies that the ECHConfig supports the cipher suite
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 ||
"tls ech" || 0x00 || ECHConfig) ECHConfig) EncodedClientHelloInner =
EncodedClientHelloInner = context.Open(ClientHelloOuterAAD, 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 1277 skipping to change at line 1265
ClientHelloOuter also contains the "encrypted_client_hello" ClientHelloOuter also contains the "encrypted_client_hello"
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 1324 skipping to change at line 1312
The backend server embeds in ServerHello.random a string derived from The backend server embeds in ServerHello.random a string derived from
the inner handshake. It begins by computing its ServerHello as the inner handshake. It begins by computing its ServerHello as
usual, except the last 8 bytes of ServerHello.random are set to zero. usual, except the last 8 bytes of ServerHello.random are set to zero.
It then computes the transcript hash for ClientHelloInner up to and It then computes the transcript hash for ClientHelloInner up to and
including the modified ServerHello, as described in [RFC8446], including the modified ServerHello, as described in [RFC8446],
Section 4.4.1. Let transcript_ech_conf denote the output. Finally, Section 4.4.1. Let transcript_ech_conf denote the output. Finally,
the backend server overwrites the last 8 bytes of the the backend server overwrites the last 8 bytes of the
ServerHello.random with the following string: ServerHello.random with the following string:
accept_confirmation = HKDF-Expand-Label( ~~ accept_confirmation = HKDF-Expand-Label( HKDF-Extract(0,
HKDF-Extract(0, ClientHelloInner.random), ClientHelloInner.random), "ech accept confirmation",
"ech accept confirmation", transcript_ech_conf, 8) ~~
transcript_ech_conf,
8)
where HKDF-Expand-Label is defined in [RFC8446], Section 7.1, "0" where HKDF-Expand-Label is defined in [RFC8446], Section 7.1, "0"
indicates a string of Hash.length bytes set to zero, and Hash is the indicates a string of Hash.length bytes set to zero, and Hash is the
hash function used to compute the transcript hash. In DTLS, the hash function used to compute the transcript hash. In DTLS, the
modified version of HKDF-Expand-Label defined in [RFC9147], modified version of HKDF-Expand-Label defined in [RFC9147],
Section 5.9 is used instead. Section 5.9 is used instead.
The backend server MUST NOT perform this operation if it negotiated The backend server MUST NOT perform this operation if it negotiated
TLS 1.2 or below. Note that doing so would overwrite the downgrade TLS 1.2 or below. Note that doing so would overwrite the downgrade
signal for TLS 1.3 (see [RFC8446], Section 4.1.3). signal for TLS 1.3 (see [RFC8446], Section 4.1.3).
skipping to change at line 1358 skipping to change at line 1344
The backend server begins by computing HelloRetryRequest as usual, The backend server begins by computing HelloRetryRequest as usual,
except that it also contains an "encrypted_client_hello" extension except that it also contains an "encrypted_client_hello" extension
with a payload of 8 zero bytes. It then computes the transcript hash with a payload of 8 zero bytes. It then computes the transcript hash
for the first ClientHelloInner, denoted ClientHelloInner1, up to and for the first ClientHelloInner, denoted ClientHelloInner1, up to and
including the modified HelloRetryRequest. Let including the modified HelloRetryRequest. Let
transcript_hrr_ech_conf denote the output. Finally, the backend transcript_hrr_ech_conf denote the output. Finally, the backend
server overwrites the payload of the "encrypted_client_hello" server overwrites the payload of the "encrypted_client_hello"
extension with the following string: extension with the following string:
hrr_accept_confirmation = HKDF-Expand-Label( ~~ hrr_accept_confirmation = HKDF-Expand-Label( HKDF-Extract(0,
HKDF-Extract(0, ClientHelloInner1.random), ClientHelloInner1.random), "hrr ech accept confirmation",
"hrr ech accept confirmation", transcript_hrr_ech_conf, 8) ~~
transcript_hrr_ech_conf,
8)
In the subsequent ServerHello message, the backend server sends the In the subsequent ServerHello message, the backend server sends the
accept_confirmation value as described in Section 7.2. accept_confirmation value as described in Section 7.2.
8. Deployment Considerations 8. Deployment Considerations
The design of ECH as specified in this document necessarily requires The design of ECH as specified in this document necessarily requires
changes to client, client-facing server, and backend server. changes to client, client-facing server, and backend server.
Coordination between client-facing and backend server requires care, Coordination between client-facing and backend server requires care,
as deployment mistakes can lead to compatibility issues. These are as deployment mistakes can lead to compatibility issues. These are
skipping to change at line 1919 skipping to change at line 1903
the attacker learns that its test certificate name was incorrect. As the attacker learns that its test certificate name was incorrect. As
an example, suppose the client's SNI value in its inner ClientHello an example, suppose the client's SNI value in its inner ClientHello
is "example.com," and the attacker replied with a Certificate for is "example.com," and the attacker replied with a Certificate for
"test.com". If the client produces a verification failure alert "test.com". If the client produces a verification failure alert
because of the mismatch faster than it would due to the Certificate because of the mismatch faster than it would due to the Certificate
signature validation, information about the name leaks. Note that signature validation, information about the name leaks. Note that
the attacker can also withhold the CertificateVerify message. In the attacker can also withhold the CertificateVerify message. In
that scenario, a client which first verifies the Certificate would that scenario, a client which first verifies the Certificate would
then respond similarly and leak the same information. then respond similarly and leak the same information.
Client Attacker Server ~~ Client Attacker Server ClientHello + key_share + ech ------>
ClientHello (intercept) -----> X (drop)
+ key_share
+ ech ------> (intercept) -----> X (drop)
ServerHello ServerHello
+ key_share + key_share
{EncryptedExtensions} {EncryptedExtensions}
{CertificateRequest*} {CertificateRequest*}
{Certificate*} {Certificate*}
{CertificateVerify*} {CertificateVerify*}
<------ <------ Alert
Alert ------> ~~
------>
Figure 3: Client Reaction Attack Figure 3: Client Reaction Attack
ClientHelloInner.random prevents this attack. In particular, since ClientHelloInner.random prevents this attack. In particular, since
the attacker does not have access to this value, it cannot produce the attacker does not have access to this value, it cannot produce
the right transcript and handshake keys needed for encrypting the the right transcript and handshake keys needed for encrypting the
Certificate message. Thus, the client will fail to decrypt the Certificate message. Thus, the client will fail to decrypt the
Certificate and abort the connection. Certificate and abort the connection.
10.12.2. HelloRetryRequest Hijack Mitigation 10.12.2. HelloRetryRequest Hijack Mitigation
skipping to change at line 1958 skipping to change at line 1939
(ech) extension to the server, which triggers a legitimate (ech) extension to the server, which triggers a legitimate
HelloRetryRequest in return. Rather than forward the retry to the HelloRetryRequest in return. Rather than forward the retry to the
client, the attacker attempts to generate its own ClientHello in client, the attacker attempts to generate its own ClientHello in
response based on the contents of the first ClientHello and response based on the contents of the first ClientHello and
HelloRetryRequest exchange with the result that the server encrypts HelloRetryRequest exchange with the result that the server encrypts
the Certificate to the attacker. If the server used the SNI from the the Certificate to the attacker. If the server used the SNI from the
first ClientHello and the key share from the second (attacker- first ClientHello and the key share from the second (attacker-
controlled) ClientHello, the Certificate produced would leak the controlled) ClientHello, the Certificate produced would leak the
client's chosen SNI to the attacker. client's chosen SNI to the attacker.
Client Attacker Server ~~ Client Attacker Server ClientHello + key_share + ech ------>
ClientHello (forward) -------> HelloRetryRequest + key_share (intercept) <-------
+ key_share
+ ech ------> (forward) ------->
HelloRetryRequest
+ key_share
(intercept) <-------
ClientHello ClientHello
+ key_share' + key_share'
+ ech' -------> + ech' ------->
ServerHello ServerHello
+ key_share + key_share
{EncryptedExtensions} {EncryptedExtensions}
{CertificateRequest*} {CertificateRequest*}
{Certificate*} {Certificate*}
{CertificateVerify*} {CertificateVerify*}
{Finished} {Finished}
<------- <-------
(process server flight) (process server flight) ~~
Figure 4: HelloRetryRequest Hijack Attack Figure 4: HelloRetryRequest Hijack Attack
This attack is mitigated by using the same HPKE context for both This attack is mitigated by using the same HPKE context for both
ClientHello messages. The attacker does not possess the context's ClientHello messages. The attacker does not possess the context's
keys, so it cannot generate a valid encryption of the second inner keys, so it cannot generate a valid encryption of the second inner
ClientHello. ClientHello.
If the attacker could manipulate the second ClientHello, it might be If the attacker could manipulate the second ClientHello, it might be
possible for the server to act as an oracle if it required parameters possible for the server to act as an oracle if it required parameters
skipping to change at line 2015 skipping to change at line 1991
To begin, the attacker first interacts with a server to obtain a To begin, the attacker first interacts with a server to obtain a
resumption ticket for a given test domain, such as "example.com". resumption ticket for a given test domain, such as "example.com".
Later, upon receipt of a ClientHelloOuter, it modifies it such that Later, upon receipt of a ClientHelloOuter, it modifies it such that
the server will process the resumption ticket with ClientHelloInner. the server will process the resumption ticket with ClientHelloInner.
If the server only accepts resumption PSKs that match the server If the server only accepts resumption PSKs that match the server
name, it will fail the PSK binder check with an alert when name, it will fail the PSK binder check with an alert when
ClientHelloInner is for "example.com" but silently ignore the PSK and ClientHelloInner is for "example.com" but silently ignore the PSK and
continue when ClientHelloInner is for any other name. This continue when ClientHelloInner is for any other name. This
introduces an oracle for testing encrypted SNI values. introduces an oracle for testing encrypted SNI values.
Client Attacker Server ~~ Client Attacker Server
handshake and ticket handshake and ticket
for "example.com" for "example.com"
<--------> <-------->
ClientHello ClientHello
+ key_share + key_share
+ ech + ech
+ ech_outer_extensions(pre_shared_key) + ech_outer_extensions(pre_shared_key)
+ pre_shared_key + pre_shared_key
--------> -------->
(intercept) (intercept)
ClientHello ClientHello
+ key_share + key_share
+ ech + ech
+ 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
<-------- <-------- ~~
Figure 5: Message Flow for Malleable ClientHello Figure 5: Message Flow for Malleable ClientHello
This attack may be generalized to any parameter which the server This attack may be generalized to any parameter which the server
varies by server name, such as ALPN preferences. varies by 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 and authenticating all inputs to the
ClientHelloInner (EncodedClientHelloInner and ClientHelloOuter) with ClientHelloInner (EncodedClientHelloInner and ClientHelloOuter) with
the HPKE AEAD. See Section 5.2. The decompression process in the HPKE AEAD. See Section 5.2. The decompression process in
skipping to change at line 2323 skipping to change at line 2299
This document draws extensively from ideas in [PROTECTED-SNI], but is This document draws extensively from ideas in [PROTECTED-SNI], but is
a much more limited mechanism because it depends on the DNS for the a much more limited mechanism because it depends on the DNS for the
protection of the ECH key. Richard Barnes, Christian Huitema, protection of the ECH key. Richard Barnes, Christian Huitema,
Patrick McManus, Matthew Prince, Nick Sullivan, Martin Thomson, and Patrick McManus, Matthew Prince, Nick Sullivan, Martin Thomson, and
David Benjamin also provided important ideas and contributions. David Benjamin also provided important ideas and contributions.
Authors' Addresses Authors' Addresses
Eric Rescorla Eric Rescorla
Knight-Georgetown Institute Independent
Email: ekr@rtfm.com Email: ekr@rtfm.com
Kazuho Oku Kazuho Oku
Fastly Fastly
Email: kazuhooku@gmail.com Email: kazuhooku@gmail.com
Nick Sullivan Nick Sullivan
Cryptography Consulting LLC Cryptography Consulting LLC
Email: nicholas.sullivan+ietf@gmail.com Email: nicholas.sullivan+ietf@gmail.com
Christopher A. Wood Christopher A. Wood
Cloudflare Apple
Email: caw@heapingbits.net Email: caw@heapingbits.net
 End of changes. 29 change blocks. 
108 lines changed or deleted 84 lines changed or added

This html diff was produced by rfcdiff 1.48.