jiebi/CodeConvo huggingface dataset:
Change:
Issue .
I was thinking about and the discussion on server HRR checks started by URL, and I'm not sure HRR cookies even work in split mode right now. First off, suppose we don't merge something like . The current text says: This means if you get a cookied HRR only good for ClientHelloInner, there's no requirement to stick the cookie in ClientHelloOuter! But now the client-facing server can't see the cookie, so it can't be stateless. It would seem like fixes this, but now we have a more fundamental problem: whose cookie? Suppose the client-facing server wishes to handle HRR statelessly. It decrypts the first ClientHelloInner and forwards it to the backend server. If the backend server responds with HRR, the client-facing server must forward the HRR as-is, or the transcript breaks. But the client-facing server has no opportunity to bind its state (echhrrkey) into the HRR cookie. (Perhaps there isn't even one. If there is, it's encrypted with the backend server's key anyway. Either way, it's fixed now.) The simplest solution to all this is to only support stateful client-facing servers in split mode, unless the client-facing and backend servers can coordinate enough to share one cookie. I don't know if that would satisfy everyone. I could imagine doing something horrific to URL, akin to what we did to URL, but that sounds really messy.
Let's mark this as an "OPEN ISSUE" in the draft.
Done. URL

Discussion:
the one hand, the requirements on info seem weaker, but maybe actually this needs to be secret?  Analysis needed.]] <ins> [[OPEN ISSUE: If the client-facing server implements stateless HRR, it has no way to send a cookie, short of as-yet-unspecified integration with the backend server.  Stateless HRR on the client- facing server works fine, however.  See issue #333.]] </ins> 6.4. If the client attempts to connect to a server and does not have an
Change:
This clause is a remnant of when we tried to partition the resumption space across ECH negotiation, which was simplified in .

Discussion:
case, it does not make any changes to the TLS messages, but just blindly forwards them. <del> If the server sends a NewSessionTicket message, the corresponding PSK MUST be ignored by all other servers in the deployment when not negotiating ECH, including servers which do not implement this specification. </del> 7.1.1. It is an error for the client to offer ECH before the
Change:
This fixes a few issues with the "Upon determining the true SNI" paragraph: It talkes about determining the "true SNI", but we should probably talk about the ClientHelloInner more generally. It refers to behavior in "the following section" which no longer matches. This is a remnant of before Shared Mode was described as a special case of Split Mode, so remove it. It says the server forwards messages unmodified, which isn't true. It needs to forward the decrypted ClientHello. It also needs to process HRR. I've cited the HRR section for the modified decryption procedure, which doesn't really exist right now, but is handling that.
Yup, this aligns with my understanding!

Discussion:
To encrypt EncodedClientHelloInner, the client first needs to generate the HPKE encryption context.  It computes the encapsulated <del> key, context, HRR key (see hrr), and payload as: </del> <ins> key, context, HRR key (see client-hrr), and payload as: </ins> Note that the HPKE functions Deserialize and SetupBaseS are those which match "ECHConfig.kem_id" and the AEAD/KDF used with "context"

ClientHelloInner from EncodedClientHelloInner, as described in outer- extensions. <del> Upon determining the true SNI, the client-facing server then either serves the connection directly (if in Shared Mode), in which case it executes the steps in the following section, or forwards the TLS connection to the backend server (if in Split Mode).  In the latter case, it does not make any changes to the TLS messages, but just blindly forwards them. </del> <ins> Upon determining the ClientHelloInner, the client-facing server then forwards the ClientHelloInner to the appropriate backend server, which proceeds as in backend-server-behavior.  If the backend server responds with a HelloRetryRequest, the client-facing server forwards it, decrypts the client's second ClientHelloOuter using the modified procedure in server-hrr, and forwards the resulting second ClientHelloInner.  The client-facing server forwards all other TLS messages between the client and backend server unmodified. </ins> 7.1.1.
Change:
cc NAME NAME
Yeah, that's what I figured. I doubt we'll need more than 8, but we can pick a different range if that works?
Yeah, this works for me. I don't see any reason why we should keep the code points dense.
Note to self. Let's pick a set and range that works.

Discussion:
IANA is requested to create the following two entries in the existing registry for ExtensionType (defined in RFC8446): <del> encrypted_client_hello(0xff08), with "TLS 1.3" column values being </del> <ins> encrypted_client_hello(0xfe08), with "TLS 1.3" column values being </ins> set to "CH, EE", and "Recommended" column being set to "Yes". <del> outer_extensions(0xff04), with the "TLS 1.3" column values being </del> <ins> outer_extensions(0xfd00), with the "TLS 1.3" column values being </ins> set to "", and "Recommended" column being set to "Yes". 11.2.
Change:
This doesn't bind anything, so no sense wasting bytes. (Note: this is orthogonal to , but it makes more sense with that PR.)
I guess this makes the text in a little odd because "Compare ClientECH.config_id against identifiers of known ECHConfigs and select the one that matches, if any, as a candidate.", is a little less clear. If we want to do this, it maybe should say "and select any that match", even though there'll really just be one match.
(Rebased and made the text talk about multiple potential matches.)
This matches the acceptance signal length, and we've already accepted that probability of collision.
I agree this is fine.

Discussion:
"ECHConfig.cipher_suites" list. The configuration identifier, equal to "Expand(Extract("", <del> config), "tls ech config id", Nh)", where "config" is the "ECHConfig" structure and "Extract", "Expand", and "Nh" are as specified by the cipher suite KDF.  (Passing the literal """" as the salt is interpreted by "Extract" as no salt being provided.) The length of this value SHOULD NOT be less than 16 bytes unless it is optional for an application; see optional-configs. </del> <ins> config), "tls ech config id", 8)", unless it is optional for an application; see optional-configs. "config" is the "ECHConfig" structure.  "Extract" and "Expand" are as specified by the cipher suite KDF.  (Passing the literal """" as the salt is interpreted by "Extract" as no salt being provided.) </ins> The HPKE encapsulated key, used by servers to decrypt the corresponding "payload" field.

but MAY be held constant for successive connections to the same server in the same session. <del> Set the "config_id" field to a randomly-generated string of "Nh" bytes, where "Nh" is the output length of the "Extract" function of the KDF associated with the chosen cipher suite.  (The KDF API is specified in I-D.irtf-cfrg-hpke.) </del> <ins> Set the "config_id" field to a randomly-generated 8-byte string. </ins> Set the "enc" field to a randomly-generated valid encapsulated public key output by the HPKE KEM.

is determined by one of the two following methods: Compare ClientECH.config_id against identifiers of known <del> ECHConfigs and select the one that matches, if any, as a candidate. </del> <ins> ECHConfigs and select the ones that match, if any, as candidates. </ins> Collect all known ECHConfigs as candidates, with trial decryption below determining the final selection.
Change:
As written, the backend server performs this URL modification unconditionally when it sees an empty ECH extension. Although the client is required to only offer TLS 1.3, the backend server doesn't check this. However, as noted elsewhere in the document, these same 8 bytes are used for the TLS 1.3 downgrade protection mechanism. That mechanism only works if the server never produces a TLS 1.2 ServerKeyExchange signature without the signal, so it's important that the server not signal ECH acceptance. Write this down.
Oops. Good catch!Yup, this is a good idea.

Discussion:
When the client-facing server accepts ECH, it forwards the ClientHelloInner to the backend server, who terminates the <del> connection.  If the ClientHelloInner contains an empty "encrypted_client_hello" extension, then the backend server MUST confirm ECH acceptance by setting ServerHello.random[24:32] to </del> <ins> connection.  If the backend server negotiates TLS 1.3 or higher and the ClientHelloInner contains an empty "encrypted_client_hello" extension, then the backend server MUST confirm ECH acceptance by setting ServerHello.random[24:32] to </ins> where HKDF-Expand-Label and HKDF-Extract are as defined in RFC8446. The value of ServerHello.random[0:24] is generated as usual by invoking a secure random number generator (see RFC8446, Section 4.1.2). <ins> The backend server MUST NOT perform this operation if it negotiated TLS 1.2 or below.  Note that doing so would overwrite the downgrade signal for TLS 1.3 (see RFC8446, Section 4.1.3). </ins> 8. Unlike most TLS extensions, placing the SNI value in an ECH extension

Note that the same bytes of the ServerHello.random are used to implement downgrade protection for TLS 1.3 (see RFC8446, <del> Section 4.1.3).  The backend server's signal of acceptance does not interfere with this mechanism because ECH is only supported in TLS 1.3 or higher. </del> <ins> Section 4.1.3).  These mechanisms do not interfere because the backend server only signals ECH acceptance in TLS 1.3 or higher. </ins> 10.8.
Change:
Now that we have separate client HRR and server HRR sections, move some server text to the server section. Also clarify that the second ClientHelloOuterAAD is computed from the second ClientHelloOuter, not reusing the first value. (Some cleanup in advance of writing up the HPKE context reuse version.)
Can we merge this? The number of PRs is getting confusing. NAME

Discussion:
HelloRetryRequest processing apply. Clients bind encryption of the second ClientHelloInner to encryption <del> of the first ClientHelloInner via the derived ech_hrr_key by modifying HPKE setup as follows: </del> <ins> of the first ClientHelloInner via the derived ech_hrr_key by running a modified encryption process: </ins> The "info" parameter to SetupPSKS is the concatenation of "tls ech", <del> a zero byte, and the serialized ECHConfig.  Clients then encrypt the second ClientHelloInner using this new HPKE context.  In doing so, the encrypted value is also authenticated by ech_hrr_key.  The rationale for this is described in flow-hrr-hijack. Client-facing servers perform the corresponding process when decrypting second ClientHelloInner messages.  In particular, upon receipt of a second ClientHello message with a ClientECH value, servers set up their HPKE context and decrypt ClientECH as follows: ClientHelloOuterAAD is computed from the second ClientHelloOuter as described in authenticating-outer.  The "info" parameter to SetupPSKR is computed as above. </del> <ins> a zero byte, and the serialized ECHConfig.  ClientHelloOuterAAD is computed from the second ClientHelloOuter as described in authenticating-outer.  Note the encrypted value is also authenticated by ech_hrr_key.  The rationale for this is described in flow-hrr- hijack. </ins> If the client offered ECH in the first ClientHello, then it MUST offer ECH in the second.  Likewise, if the client did not offer ECH

aborts the connection with a "decrypt_error" alert rather than continuing the handshake with the second ClientHelloOuter. <ins> When decrypting the second ClientECH.payload, the client-facing server performs a corresponding process to client-hrr: ClientHelloOuterAAD is computed from the second ClientHelloOuter as described in authenticating-outer.  The "info" parameter to SetupPSKR is the concatenation of "tls ech", a zero byte, and the serialized ECHConfig. </ins> [[OPEN ISSUE: If the client-facing server implements stateless HRR, it has no way to send a cookie, short of as-yet-unspecified integration with the backend server.  Stateful HRR on the client-
Change:
ESNI seems to rely on TLS 1.3 KeyShareEntry which makes it incompatible with TLS 1.2. That's unfortunate with that "The protocol designed in this document is quite straightforward." The gist of ESNI comes down to "encryptedservername extension, which contains the true extension encrypted under the provider’s public key." That seems pretty generic and backwards compatible.
To prevent cut-and-paste attacks, you need to bind ESNI to the CH. That means we’d need 1.2 clients to send a key share in the CH to use when deriving encryption keying material, and that’s not currently done.
Since TLS 1.2 sends the server certificate in plaintext it seems like ESNI wouldn't be particularly useful there anyway, no?
Indeed. I guess someone could argue about wildcard certificates or when multiple names are present but the names are usually related so I agree there’s no significant benefit from encrypting the SNI.

Discussion:
4. <del> ECH uses draft-05 of HPKE for public key encryption I-D.irtf-cfrg- </del> <ins> ECH uses draft-06 of HPKE for public key encryption I-D.irtf-cfrg- </ins> hpke.  The ECH configuration is defined by the following "ECHConfig" structure.
Change:
The text for servers rejecting both extensions present is under Backend Server, but the Server Behavior text gates that section under just the one extension. Likewise, the client-facing server text allows for both extensions to be present. Move the illegal_parameter text around and write out the four cases.

Discussion:
7. <del> Servers that support ECH play one of two roles, depending on the extension in the ClientHello.  If the "encrypted_client_hello" extension is present, the server acts as a client-facing server and proceeds as described in client-facing-server to extract a ClientHelloInner, if available.  If the "ech_is_inner" extension is present and the "encrypted_client_hello" extension is not present, the server acts as a backend server and proceeds as described in backend-server. </del> <ins> Servers that support ECH play one of two roles, depending on which of the "ech_is_inner" and "encrypted_client_hello" extensions are present in the ClientHello: If both the "ech_is_inner" and "encrypted_client_hello" extensions are present in the ClientHello, the backend server MUST abort with an "illegal_parameter" alert. If only the "encrypted_client_hello" extension is present, the server acts as a client-facing server and proceeds as described in client-facing-server to extract a ClientHelloInner, if available. If only the "ech_is_inner" extension is present and the "encrypted_client_hello" extension is not present, the server acts as a backend server and proceeds as described in backend-server. If neither extension is present, the server completes the handshake normally, as described in RFC8446. </ins> 7.1.

Upon receipt of an "ech_is_inner" extension in a 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 <del> here.  If both the "ech_is_inner" and "encrypted_client_hello" extensions are present in the ClientHello, the backend server MUST abort with an "illegal_parameter" alert. </del> <ins> here. </ins> The backend server begins by generating a message ServerHelloECHConf, which is identical in content to a ServerHello message with the
Change:
The backtick-quoted empty string translates to """" in the text output.
Not sure if this is the best solution, but the quadruple quote in the txt is goofy.
This seems fine, yeah. Thanks for catching it!

Discussion:
config), "tls ech config id", 8)", unless it is optional for an application; see optional-configs. "config" is the "ECHConfig" structure.  "Extract" and "Expand" are as specified by the cipher <del> suite KDF.  (Passing the literal """" as the salt is interpreted by "Extract" as no salt being provided.) </del> <ins> suite KDF.  (Passing the literal "" as the salt is interpreted by "Extract" as no salt being provided.) </ins> The HPKE encapsulated key, used by servers to decrypt the corresponding "payload" field.
Change:
~It's sufficient to ignore it, I think.~ The backend server enforces the extension's emptiness.

Discussion:
TLS 1.2 or below.  Note that doing so would overwrite the downgrade signal for TLS 1.3 (see RFC8446, Section 4.1.3). <ins> The "ech_is_inner" is expected to have an empty payload.  If the payload is non-empty (i.e., the length of the "extension_data" field is non-zero) then the backend server MUST abort the handshake with an "illegal_parameter" alert. </ins> 8. Unlike most TLS extensions, placing the SNI value in an ECH extension
Change:
Clarifies that serialization of this structure doesn't include the message type and length. We do the same thing for the serialization of EncodedClientHelloInner, but this makes it explicit in case it's not clear from context.

Discussion:
fields of the payload of the "encrypted_client_hello" extension.  The last parameter, "outer_hello", is computed by serializing ClientHelloOuter with the "encrypted_client_hello" extension removed. <ins> Note this does not include the four-byte header included in the Handshake structure. </ins> Note the decompression process in encoding-inner forbids "encrypted_client_hello" in OuterExtensions.  This ensures the
Change:
The reference to "retry keys" comes from when the field was called retrykeys and the type ESNIKeys. We've since renamed them to retryconfig and ECHConfig, so the prose should match.

Discussion:
An ECHConfigs structure containing one or more ECHConfig structures, in decreasing order of preference, to be used by the <del> client in subsequent connection attempts. </del> <ins> client in subsequent connection attempts.  These are known as the server's "retry configurations". </ins> This document also defines the "ech_required" alert, which the client MUST send when it offered an "encrypted_client_hello" extension that

handshake, authenticating for ECHConfig.contents.public_name as described in auth-public-name.  If authentication or the handshake fails, the client MUST return a failure to the calling application. <del> It MUST NOT use the retry keys. </del> <ins> It MUST NOT use the retry configurations. </ins> <del> Otherwise, when the handshake completes successfully with the public name authenticated, the client MUST abort the connection with an </del> <ins> Otherwise, if both authentication and the handshake complete successfully, the client MUST abort the connection with an </ins> "ech_required" alert.  It then processes the "retry_configs" field from the server's "encrypted_client_hello" extension.

The client MUST continue to use the previously-advertised configurations for subsequent connections.  This avoids introducing pinning concerns or a tracking vector, should a malicious server <del> present client-specific retry keys in order to identify the client in a subsequent ECH handshake. </del> <ins> present client-specific retry configurations in order to identify the client in a subsequent ECH handshake. </ins> If none of the values provided in "retry_configs" contains a supported version, the client can regard ECH as securely disabled by
Change:
cc NAME
(Filing this as a separate ticket so I don't forget to propose new text.) added this text: I think this statement is a bit strong and overstates the issue. It reads as if resuming connections across ECH and non-ECH links the two connections. If we're talking about someone other than the server, this isn't true. Tickets are issued encrypted and, in ECH, even sent encrypted. Even if they were sent in the clear, TLS 1.3's protects against such correlations. Rather, the correlation in is a much weaker one: based on either the size of the ClientHello or whether the server accepted the ticket, you learn a single bit for whether it was some previous connection made by that client. You don't know which previous connection it was, and you don't know if it was an ECH connection or a non-ECH connection. In fact what you learn... more-or-less aligns with the anonymity set. See URL (If we're talking about the server, yes, resuming allows the server to link the two connections. That's fundamental to resumption and is in the purview of URL I don't think most applications would consider ECH vs non-ECH a correlation boundary w.r.t. the server itself.)
The original text doesn't necessarily imply that on-the-wire tickets are the linking factor. Rather that the shape of the handshake, time it takes to complete, etc, can be a proxy for whether or not resumption occurred. I don't think we need to change anything here. (But I also would not object to someone else sending a PR!)
(This came up in a discussion between me and NAME So, the current text says "For example, a client that [does X] may [do Y], thereby linking the resulting ECH connection to the original non-ECH connection". That implies that doing X and Y allows linking the two connections together. You're right that tickets may not be the only linking factor, but the other channels don't let you link connections, only, as you say, whether or not resumption occurred. That single boolean doesn't tell you which non-ECH connection corresponded to the ECH connection, or what the name was. It only tells you that it's the same name as some previous connection to the anonymity set. It might be a non-ECH one (but you don't know which) or it might be an ECH one.
Feel free to suggest text to reword this. I think the example was meant to be general enough to suggest that side channels exist. I definitely do not feel strongly about the exact wording here.
I agree that the text as-is overstates the issue.
Thanks!LGTM -- thanks!

Discussion:
Attacks that rely on non-ECH traffic to infer server identity in an ECH connection are out of scope for this document.  For example, a client that connects to a particular host prior to ECH deployment may <del> later resume a connection to that same host after ECH deployment, thereby linking the resulting ECH connection to the original non-ECH connection. </del> <ins> later resume a connection to that same host after ECH deployment.  An adversary that observes this can deduce that the ECH-enabled connection was made to a host that the client previously connected to and which is within the same anonymity set. </ins> 10.7.
Change:
and also updates the ECH version. I didn't bump the extension codepoint for "echisinner," since that seems harmless. cc NAME NAME
This new version of the draft removes the version-vector dependency, so this should be the last time we update the pinned version.
Works for me!

Discussion:
4. <del> ECH uses draft-07 of HPKE for public key encryption I-D.irtf-cfrg- </del> <ins> ECH uses draft-08 of HPKE for public key encryption I-D.irtf-cfrg- </ins> hpke.  The ECH configuration is defined by the following "ECHConfig" structure.

IANA is requested to create the following three entries in the existing registry for ExtensionType (defined in RFC8446): <del> encrypted_client_hello(0xfe09), with "TLS 1.3" column values set </del> <ins> encrypted_client_hello(0xfe0a), with "TLS 1.3" column values set </ins> to "CH, EE", and "Recommended" column set to "Yes". ech_is_inner (0xda09), with "TLS 1.3" column values set to "CH",