Change:
implemented, for instance, by reporting a failed connection with a dedicated error code. <del> 5.1.4. </del> <ins> 7.2.3. If the server sends a HelloRetryRequest in response to the ClientHello, the client sends a second updated ClientHello per the rules in RFC8446.  However, at this point, the client does not know whether the server processed ClientHelloOuter or ClientHelloInner, and MUST regenerate both values to be acceptable.  Note: if the inner and outer ClientHellos use different groups for their key shares or differ in some other way, then the HelloRetryRequest may actually be invalid for one or the other ClientHello, in which case a fresh ClientHello MUST be generated, ignoring the instructions in HelloRetryRequest.  Otherwise, the usual rules for HelloRetryRequest processing apply. Clients bind encryption of the second ClientHelloInner to encryption of the first ClientHelloInner via the derived echo_hrr_key by modifying HPKE setup as follows: Clients then encrypt the second ClientHelloInner using this new HPKE context.  In doing so, the encrypted value is also authenticated by echo_hrr_key. Client-facing servers perform the corresponding process when decrypting second ClientHelloInner messages.  In particular, upon receipt of a second ClientHello message with a ClientEncryptedCH value, servers setup their HPKE context and decrypt ClientEncryptedCH as follows: [[OPEN ISSUE: Should we be using the PSK input or the info input?  On the one hand, the requirements on info seem weaker, but maybe actually this needs to be secret?  Analysis needed.]] [[OPEN ISSUE: This, along with trial decryption is pretty gross.  It would just be a lot easier if we were willing to have the server indicate whether ECHO had been accepted or not.  Given that the server is supposed to only reject ECHO when it doesn't know the key, and this is easy to probe for, can we just instead have an extension to indicate what has happened.]] 7.3. </ins> If the client attempts to connect to a server and does not have an <del> ESNIConfig structure available for the server, it SHOULD send a GREASE I-D.ietf-tls-grease "encrypted_server_name" extension as </del> <ins> ECHOConfig structure available for the server, it SHOULD send a GREASE I-D.ietf-tls-grease "encrypted_client_hello" extension as </ins> follows: Select a supported cipher suite, named group, and padded_length <del> value.  The padded_length value SHOULD be 260 or a multiple of 16 less than Set the "suite" field to the selected cipher suite.  These selections SHOULD vary to exercise all supported configurations, but MAY be held constant for successive connections to the same server in the same session. </del> <ins> value.  The padded_length value SHOULD be 260 (sum of the maximum DNS name length and TLS encoding overhead) or a multiple of 16 less than 260.  Set the "suite" field to the selected cipher suite.  These selections SHOULD vary to exercise all supported configurations, but MAY be held constant for successive connections to the same server in the same session. </ins> <del> Set the "key_share" field to a randomly-generated valid public key for the named group. </del> <ins> Set the "enc" field to a randomly-generated valid encapsulated public key output by the HPKE KEM. </ins> Set the "record_digest" field to a randomly-generated string of hash_length bytes, where hash_length is the length of the hash function associated with the chosen cipher suite. <del> Set the "encrypted_sni" field to a randomly-generated string of 16 + padded_length + tag_length bytes, where tag_length is the tag length of the chosen cipher suite's associated AEAD. </del> <ins> Set the "encrypted_client_hello" field to a randomly-generated string of [TODO] bytes. </ins> <del> If the server sends an "encrypted_server_name" extension, the client </del> <ins> If the server sends an "encrypted_client_hello" extension, the client </ins> MUST check the extension syntactically and abort the connection with <del> a "decode_error" alert if it is invalid.  If the "response_type" field contains "esni_retry_requested", the client MUST ignore the extension and proceed with the handshake.  If it contains "esni_accept" or any other value, the client MUST abort the connection with an "illegal_parameter" alert. </del> <ins> a "decode_error" alert if it is invalid. </ins> Offering a GREASE extension is not considered offering an encrypted <del> SNI for purposes of requirements in client-behavior.  In particular, the client MAY offer to resume sessions established without ESNI. </del> <ins> ClientHello for purposes of requirements in client-behavior.  In particular, the client MAY offer to resume sessions established without ECHO. </ins> <del> 5.2. </del> <ins> 8. </ins> <del> Upon receiving an "encrypted_server_name" extension, the client- </del> <ins> Upon receiving an "encrypted_client_hello" extension, the client- </ins> facing server MUST check that it is able to negotiate TLS 1.3 or greater.  If not, it MUST abort the connection with a "handshake_failure" alert. <del> The ClientEncryptedSNI value is said to match a known ESNIConfig if there exists an ESNIConfig that can be used to successfully decrypt ClientEncryptedSNI.encrypted_sni.  This matching procedure should be </del> <ins> The ClientEncryptedCH value is said to match a known ECHOConfig if there exists an ECHOConfig that can be used to successfully decrypt ClientEncryptedCH.encrypted_ch.  This matching procedure should be </ins> done using one of the following two checks: <del> Compare ClientEncryptedSNI.record_digest against cryptographic hashes of known ESNIConfig and choose the one that matches. </del> <ins> Compare ClientEncryptedCH.record_digest against cryptographic hashes of known ECHOConfig and choose the one that matches. </ins> <del> Use trial decryption of ClientEncryptedSNI.encrypted_sni with known ESNIConfig and choose the one that succeeds. </del> <ins> Use trial decryption of ClientEncryptedCH.encrypted_ch with known ECHOConfig and choose the one that succeeds. </ins> <del> Some uses of ESNI, such as local discovery mode, may omit the ClientEncryptedSNI.record_digest since it can be used as a tracking </del> <ins> Some uses of ECHO, such as local discovery mode, may omit the ClientEncryptedCH.record_digest since it can be used as a tracking </ins> vector.  In such cases, trial decryption should be used for matching <del> ClientEncryptedSNI to known ESNIConfig.  Unless specified by the </del> <ins> ClientEncryptedCH to known ECHOConfig.  Unless specified by the </ins> application using (D)TLS or externally configured on both sides, implementations MUST use the first method. <del> If the ClientEncryptedSNI value does not match any known ESNIConfig </del> <ins> If the ClientEncryptedCH value does not match any known ECHOConfig </ins> structure, it MUST ignore the extension and proceed with the connection, with the following added behavior: <del> It MUST include the "encrypted_server_name" extension in EncryptedExtensions message with the "response_type" field set to "esni_retry_requested" and the "retry_keys" field set to one or more ESNIConfig structures with up-to-date keys.  Servers MAY supply multiple ESNIConfig values of different versions.  This allows a server to support multiple versions at once. </del> <ins> It MUST include the "encrypted_client_hello" extension with the "retry_keys" field set to one or more ECHOConfig structures with up-to-date keys.  Servers MAY supply multiple ECHOConfig values of different versions.  This allows a server to support multiple versions at once. </ins> The server MUST ignore all PSK identities in the ClientHello which <del> correspond to ESNI PSKs.  ESNI PSKs offered by the client are associated with the ESNI name.  The server was unable to decrypt then ESNI name, so it should not resume them when using the </del> <ins> correspond to ECHO PSKs.  ECHO PSKs offered by the client are associated with the ECHO name.  The server was unable to decrypt then ECHO name, so it should not resume them when using the </ins> cleartext SNI name.  This restriction allows a client to reject resumptions in auth-public-name. <del> Note that an unrecognized ClientEncryptedSNI.record_digest value may be a GREASE ESNI extension (see grease-extensions), so it is </del> <ins> Note that an unrecognized ClientEncryptedCH.record_digest value may be a GREASE ECHO extension (see grease-extensions), so it is </ins> necessary for servers to proceed with the connection and rely on the <del> client to abort if ESNI was required.  In particular, the unrecognized value alone does not indicate a misconfigured ESNI </del> <ins> client to abort if ECHO was required.  In particular, the unrecognized value alone does not indicate a misconfigured ECHO </ins> advertisement (misconfiguration).  Instead, servers can measure <del> occurrences of the "esni_required" alert to detect this case. If the ClientEncryptedSNI value does match a known ESNIConfig, the server performs the following checks: If the ClientEncryptedSNI.key_share group does not match one in the ESNIConfig.keys, it MUST abort the connection with an "illegal_parameter" alert. If the length of the "encrypted_server_name" extension is inconsistent with the advertised padding length (plus AEAD expansion) the server MAY abort the connection with an "illegal_parameter" alert without attempting to decrypt. Assuming these checks succeed, the server then computes K_sni and decrypts the ServerName value.  If decryption fails, the server MUST abort the connection with a "decrypt_error" alert. If the decrypted value's length is different from the advertised ESNIConfig.padded_length or the padding consists of any value other than 0, then the server MUST abort the connection with an "illegal_parameter" alert.  Otherwise, the server uses the PaddedServerNameList.sni value as if it were the "server_name" extension.  Any actual "server_name" extension is ignored, which also means the server MUST NOT send the "server_name" extension to the client. </del> <ins> occurrences of the "echo_required" alert to detect this case. If the ClientEncryptedCH value does match a known ECHOConfig, the server then decrypts ClientEncryptedCH.encrypted_ch, using the private key skR corresponding to ESNIConfig, as follows: If decryption fails, the server MUST abort the connection with a "decrypt_error" alert.  Moreover, if there is no "echo_nonce" extension, or if its value does not match the derived echo_nonce, the server MUST abort the connection with a "decrypt_error" alert.  Next, the server MUST scan ClientHelloInner for any "outer_extension" extensions and substitute their values with the values in ClientHelloOuter.  It MUST first verify that the hash found in the extension matches the hash of the extension to be interpolated in and if it does not, abort the connections with a "decrypt_error" alert. </ins> Upon determining the true SNI, the client-facing server then either serves the connection directly (if in Shared Mode), in which case it

Discussion:
This change implements the ESNI -> ECHO design discussed in Singapore. There a couple pending TODOs, particularly around cross-CH HRR binding, but the meat is what's currently being analyzed. cc NAME NAME NAME NAME
This still seems a bit rough, but I think better in the spec than out.