Draft: draft-ietf-tls-esni

Commentary: The PR contains several " TODOs " that must be resolved for merging this . 
 Three TODOs remain . Let me know before you merge , I 'd like to roll these into a single commit . 
 Section 6 : implementations to track , alongside each PSK established by a previous connection , whether the connection negotiated this extension with the " echaccept " response type . If so , this is referred to as an " ECH PSK " . Otherwise , it is a " non - ECH PSK " . This may be implemented by adding a new field to client and server session states . " echaccept " is not defined anywhere . 
 I suspect " the connection negotiated this extension with the ' ech_accept ' response type " is an incorrect way of saying that ECH was accepted . 
 Section 7.1 provides a bit of guidance on how ECH might interact with other extensions : " servername " extension . The ClientHelloOuter MUST NOT contain a " cached_info " extension { { ! RFC7924 } } with a CachedObject entry whose CachedInformationType is " cert " , since this indication would divulge the true server name . The remaining contents of the ClientHelloOuter MAY be identical to those in ClientHelloInner but MAY also differ . I think it 's worth expanding on this in " Security Considerations " . There may be other ways that private CH extensions get leaked , now or in the future . 
 Now that we 've switched to encrypting an entire ClientHello , I think the text wants to say something else anyway : if you want ECH + cached info , you simply include the cachedinfo extension in the ClientHelloInner , not the ClientHelloOuter . There would n't be much point in sending a true name cachedinfo in ClientHelloOuter since the true server would ignore it . Sending a public name cached_info in ClientHelloOuter is also plausible and also need n't be forbidden ( it reveals information about the public name , which is public ) . It 's also probably not that useful since it 's just a recovery mechanism , but maybe to avoid sticking out , for clients that normally send it ? More generally , anything dependent on the inner name goes in ClientHelloInner and not ClientHelloOuter . 
 I took a stab at replacement text in Thoughts ? 
 I 'm happy with it . 
 In Section 6.1 : if I were implementing this extension , I think the simplest thing would be to compress all copied extensions by default : 's not computationally intensive ; minimizes bandwidth overhead ; and 's simpler for future " big " extensions , since no code changes would be needed here . I suggest removing this guidance . 
 addresses this issue . 
 Field is computed as " digest of the complete ClientHelloInner " ( including presumably , the " outer_extensions " extension ) . I do n't understand the analytical value of this hash . Can anyone explain its reasoning ? 
 The hash is intended to prevent the attacker from influencing the reconstructed CHInner by manipulating CHOuter . Consider the contrived example of an extension which is separately protected but only works for SNI - A and not     , it 's constructed by doing E(K_sni , SNI ) . If that extension were included in CHOuter and then imported into CHInner via this mechanism , then an attacker could substitute it and use a reaction attack to determine whether the CH referred to A or B. However , with the hash ( which may be not well - specified ) , this attack gets caught by the client - facing server and the handshake is rejected without leaking information . 
 My initial understanding of this mechanism was incorrect . What happens is that the hash is computed over the ClientHelloInner that is consumed by the backend server . This is intended to ensure that if ECH accepts , then the backend server consumes the CH intended by the client . ( PR makes this more clear , I think . ) I wonder if this mechanism is redundant . Agreement on the CH between the client and backend server is provided by the binding of the transcript hash to the handshake traffic secret , so any attempt to manipulate the ClientHelloInner by fiddling with the ClientHelloOuter should be detected . On the other hand , the binding of the outer extensions to ClientHelloInner ensures agreement on the CH prior to the backend server consuming it . This is a strictly stronger property , which may or may not be useful . I agree that the attack works , but the example seems really contrived :) I 'd be interested if there are more natural extensions for which this extra layer of security would be useful . 
 From the interim meeting , the consensus seems to be that we should err on the conservative side . 
 Let 's close this issue and leave the mechanism as is . 
 Hrm , before closing I think it might be worth noting , in the spec , the stronger security property this provides . 
 I think we should also consider binding the CHInner to a hash of the whole CHOuter ( minus the ClientEncryptedCH extension ) . That would have the same size overhead , but would give us a stronger property : modifying anything in CHOuter ( not just one of the copied extensions ) invalidates the whole thing . 
 The point of hashing outer extensions is to provide integrity of the ClientHelloInner . What would be the point in hashing more of the ClientHelloOuter ? ( Not a rhetorical question :) It seems conceptually different , and I 'm curious what the security benefit might be . ) 
 If we authenticate the ClientHelloOuter , we 'd be authenticating all the inputs that go into the ClientHelloInner , so I think that would also provide integrity . I expect  is suggesting this in the context of , where GREASE can additionally be made a little stronger if we did that . Getting that to interact well with any PSK binders in ClientHelloOuter is tricky though , unless we decide to ban resumption attempts in outer ClientHellos . ( Probably best to keep the GREASE - related conversation in one place . Though I see I did n't help on that front because some discussion is also in . Ah , GitHub . ) 
 Yep , I 'm just echoing observation . See also 
 Today , the only thing that gets copied into ClientHelloInner is extensions , so I do n't see how it 's an improvement in terms of our primary security goal . ( Not sure about the " do n't stick out " benefit . ) 
 I do n't understand how hashing all of CHOuter is going to work . In split mode , the server never sees any of CHOuter . 
 Yes , the hash would be checked when reconstructing the inner ClientHello ( as here ) , and would not be present in the reconstructed ClientHello . 
 There 's not much discussion here . Unless there 's objection , shall we leave the mechanism as - is and close out this issue ? cc/ 
 Works for me . 
 Say we want the outer CH to have extensions a and b. Let 's write this as Say the inner CH should have extensions a , b , c , and d. But b is really big , so we want a shallow copy it . Then we write the compressed inner CH as The decompressed ClientHelloInner should be , but using destroys the intended order . 
 Extension order in TLS is n't meaningful , so I think that 's fine , provided the code producing the inner ClientHello and the code encoding it get to coordinate . ( I.e. a client that says " I do n't care about secrecy of and will send the same one on both sides " can probably live with being at the end . ) There have been cases where extension order has interop impacts due to server bugs . ( E.g. the last extension needs to be non - empty to avoid a bug in some old servers . ) But those old servers would n't see inner ClientHellos anyway . 
 I think maybe a concern is that the client and server wind up using extension lists with different orders , for whatever reasons , thereby yielding different transcripts . Would n't that be an issue ? 
 Right , hence " provided the code producing the inner ClientHello and the code encoding it get to coordinate " . If compression is done with inner + outer ClientHello being produced by the same thing , the client can simply take this into account and always put referenced extensions at the end . If it 's a proxying picture , where the client does not know it is doing ECH ( is that even possible ? I suspect the ech_nonce would be an issue ) , that may not work . 
 Right . I do n't expect the latter ( proxy case ) to be common , though perhaps modifying this to prevent misuse might be useful . 
 This make me worry about interoperability . For a client and server to speak to eachother they need to adopt the same convention that is not specified anywhere , but only evident when you look at existing implementations . My vote would be to modify compression so that extension order is preserved . 
 It is certainly necessary that the decompression function produces a deterministic ClientHello , down to what goes into the transcript . I think section 6.1 does that . That 's a different criteria from requiring that every possible input ClientHello be efficiently compressible . 
 I do n't compare about it being " efficiently " compressible , but I see your point about the transcript being the same . Just to clarify , my concern is in Section 6.1 : the client removes and and replaces extensions from ClientHelloInner with a single " outerextensions " extension . The list of outerextensions include those which were removed from ClientHelloInner , in the order in which they were removed . I interpret this as the following procedure : Is it clear what I mean here ? Do we agree that , in general , this procedure does n't preserve the order of extensions ? My concern had to do with servers being ossified around the order of extensions . If this is n't a problem , then I guess we 're good here . It 's worth flagging this , however ( from RFC 8446 ): extensions MAY appear in any order , with the exception of " presharedkey " ( Section 4.2.11 ) which MUST be the last extension in the ClientHello ( but can appear anywhere in the ServerHello extensions block ) . An order - preserving alternative would be something like this : This would have the benefit of not needing to define an additional extension point . 
 The alternative does n't quite work because extensions can legitimately be empty , so it 's ambiguous whether you meant to explicitly encode an empty extension or reference the outer one . For example , the old TLS 1.2 extension was empty to signal " I support tickets but am not sending one " and a non - empty string to send a ticket . That 's a good point though . The compression algorithm in 6.1 breaks if the removed extensions are non - contiguous , so it should either include that requirement , or we come up with a different goofy encoding . :-) 
 Ah , good point . I would be fine with adding the requirement , though it might be worth trying to come up with something more general . 
 One possible replacement paragraph : ( I 'm also fine with replacing with a more general encoding . ) 
 We should also require that the " outerextensions " extension appears where the contiguous extensions were . For example , to compress and , we encode as . Otherwise the " outer_extensions " MAY appear somewhere else . 
 In fact , that leads to a more general encoding . I guess the problem with this is that we can have multiple " outer_extension " extensions in the inner CH , so we would still need to ensure there is just one contiguous block . Or we can say " screw it " and decide that the encoded form of ClientHelloInner need not be a well - formed ClientHello . 
 The proposed change is here : . As suggested in the interim meeting , before changing this mechanism , we should look at real ClientHellos to see what we would actually want to compress . 
 My inclination is also that the contiguous constraint is probably fine , though we have played games with extension ordering before with the PSK extension . Although I would actually anticipate compressing most extensions , and just ordering things to match . Most of them are n't sensitive and , assuming you 're already compressing one extension , even an empty extension would cost just four bytes uncompressed and two bytes compressed . 
 I 'm pretty happy with the state of things . I 'm closing this issue . 
 From Section 6.1 : This assumes that the KDF specifies some underlying hash function . From the HPKE spec , it seems like all that 's required of the KDF is that it 's an " extract - then - expand " KDF : In fact , the currently assigned code points are all for HKDF : But there 's no requirement that the KDF always have some underlying hash function . As an alternative to HKDF , one can imagine a dedicated primitive that satisfies the extract - then - expand API but is not constructed from a hash function . 
 Impacted fields : ClientEncryptedCH.record_digest 
 We can probably replace with and be done with it . 
 Putting on my theorist hat , I 'd say that the extract function is a " randomness extractor " and not a collision resistant hash function . We want the latter in this context . From a practical stand point , using the extract function is more hashing than we need . I 'd suggest doing away with ( see ) and figuring something else out for . Could we simply require HKDF be used with HPKE ? 
 Sure , but in practice randomness extractors use a collision resistant hash or PRF ( CBC ) under the hood . I do n't think we can require HKDF for HPKE . That seems too restrictive . We might just say that ECH requires HKDF - based HPKE ciphersuites , as HKDF is already paramount for TLS 1.3 , and then just reference HKDF 's hash function . 
 addresses this issue . 
 As I mentioned on the list , we can use the KDF in place of a hash . 
 I tend to agree . I 'll create a new PR . 
 Have a look at , 
 Resolved in . Closing . 
 In just a few sentences , let 's define the anonymity set and say what it means for connections to end points in this set to be indistignuishable . We might also enumerate non - goals ( though we still need consensus on what these are ) . 
 I 've not yet gotten around to the PR yet , but here 's the gist : Attackers : Passive attackers are those which can not probe , e.g. ,   that filter based on plaintext packet contents . Active attackers can probe , e.g. , censors . Goals : ECH does not negatively affect any existing security properties of TLS 1.3 . ECH connections to servers in the same anonymity set are indistinguishable from one another for passive and active attackers , modulo traffic analysis . ( Note : an anonymity set is determined by the client and server parameters , e.g. , the SNI , supported application protocols , and so on . ) ECH support is secret from passive attackers who do n't know the ECH configuration , but not active attackers . ECH usage is secret from passive attackers who do n't know the ECH configuration , but not active attackers . More specifically : Passive attackers with a known ECH configuration can distinguish between a connection that negotiates ECH with that configuration and one which does not ( GREASEd or using a different configuration ) . Passive attackers without the ECH configuration can not distinguish between a connection that negotiates ECH and one which does not ( but GREASEd ) . Active attackers can distinguish between a connection that negotiates ECH and one which does not ( but GREASEd ) . 
 Yeah this looks good . 
 From the interim : merge this as a PR and then address censorship separately ( if desired ) . 
 There are several rationales provided about the need for : nonce ensures that the server 's encrypted Certificate can only be read by the entity which sent this ClientHello . servers process either  or ClientHelloOuter , and ClientHelloInner contains an HPKE - derived nonce , it is not possible for an attacker to " cut and paste " the ECH value in a different Client Hello and learn information from ClientHelloInner . This is because the attacker lacks access to the HPKE - derived nonce used to derive the handshake secrets . Reaction Attack Mitigation ... The " echnonce " extension in the inner ClientHello prevents this attack . In particular , since the attacker does not have access to this value , it can not produce the right transcript and handshake keys needed for encrypting the Certificate message . Thus , the client will fail to decrypt the Certificate and abort the connection . These rationales are all subtly different , and having read them all , I still do n't understand why the nonce is necessary , when the serverhandshaketrafficsecret already depends on the inner client random , which is not known to the attacker . I would appreciate some more explanation on this point . It also might make sense to move these rationales up into the echnonce section , or add forward references to them there . 
 I agree that the rationale is n't clear from the description . This needs to be cleaned up . However , it does seem to prevent a real attack ( see Sec . 10.8.1 ) . 
 As I noted above , the serverhandshaketraffic_secret already depends on the inner client random , which is not known to the attacker . It therefore seems to me that the attacker therefore can not produce a Certificate message that the client will decrypt , even without the nonce . If that 's true , I do n't see how the attack in Sec . 10.8.1 is possible . 
 What if the inner is the same as the outer This is currently allowed by the spec , i.e. , there 's no guidance on " copying " extensions from the outer CH to the inner . 
 That 's an interesting question that I think the spec should probably address . I assumed they could not be the same , because they are both required to be random . If they can be the same , I would suggest making them always the same , and remove the inner one to save 32 bytes and simplify the analysis . 
 The semantics of copying outer CH extensions into inner CH needs to be clarified : see also To my read , the intent is that any extension MAY be copied , bit - by - bit , into the inner CH . 
 The client random is a fixed field of the ClientHello , not an extension . 
  , I 'm not really a fan of this ( and bit shaving in general ) . The idea is to make the inner CH as close to a full CH as possible , so keeping the same encoding makes most sense to me . That said , even if they are random , there may be cases where the attacker can predict the randomness generated . 
 I think an attacker that can predict a random value generated by the TLS stack has much more exciting avenues of attack here . ( E.g. the client 's key share is lost . ) Though it is a good point that they are slightly different : the ECH nonce is exported from the HPKE context while the client random is simply random . I forget if that ends up being important anywhere . 
 Ah you 're right . Thanks ! 
 Exactly -- even if an attacker knew the client 's key share , random value , etc , it might not know the ECH nonce ( without access to the sever 's private key ) , depending on the KEM used . ( If  was used , it would know the client 's ephemeral private key , so the point is moot . ) All that said , we may be able to remove it . But I 'm hesitant to do so without backing analysis . 
 I think this is true for any KEM . If your KEM looks more like public key encryption , the attacker would instead know the shared secret the client generated . More generally , if we assume the client is incapable of generating random numbers , the attacker can simply run through the client 's implementation of SetupBaseS , replacing all non - determinism with the predicted random number . It will then end up with the same HPKE context . 
 That 's true ! 
 RFC 8446 Appendix C.1 says " Implementations can provide extra security against [ broken RNG ] attack by using separate CSPRNGs to generate public and private values . " . If that 's the motivation for the nonce , I think the spec should mention it . 
 For what it 's worth , the checks out after removing " echnonce . " 
 This is the current proposal for removing " ech_nonce " and clarifying behavior around choosing the 
 Closing now that landed . 
 Thanks for these editorial cleanups !
Paragraph (version A):
Upon receiving ClientHelloOuter, the client-facing server processes
the encrypted ClientHelloInner and either terminates the connection
(in Shared Mode) or forwards it to the backend server (in Split
Mode).
Paragraph (version A):
ClientHello encryption configuration information is conveyed with the
following ECHConfigs structure.
Paragraph (version A):
The ECHConfigs structure contains one or more ECHConfig structures in
decreasing order of preference.  This allows a server to support
multiple versions of ECH and multiple sets of ECH parameters.
Paragraph (version A):
The version of the structure.  For this specification, that value
SHALL be 0xff07.  Clients MUST ignore any ECHConfig structure with
a version they do not understand.
Paragraph (version A):
An opaque byte string whose contents depend on the version of the
structure.  For this specification, the contents are an
ECHConfigContents structure.
Paragraph (version A):
The non-empty name of the entity trusted to update these
encryption keys.  This is used to repair misconfigurations, as
described in handle-server-response.
Paragraph (version A):
The HPKE I-D.irtf-cfrg-hpke public key which can be used by the
client to encrypt the ClientHello.
Paragraph (version A):
The HPKE I-D.irtf-cfrg-hpke KEM identifier corresponding to
public_key.  Clients MUST ignore any ECHConfig structure with a
key using a KEM they do not support.
Paragraph (version B):
If it does not support ECH, it ignores the
"encrypted_client_hello" extension and proceeds with the handshake
as usual, per RFC8446, Section 4.1.2.
Paragraph (version B):
If it supports ECH but cannot decrypt it, then it ignores the
extension and proceeds with the handshake as usual.  This is
referred to as "ECH rejection".  When ECH is rejected, the server
sends an acceptable ECH configuration in its EncryptedExtensions
message.
Paragraph (version B):
If it supports ECH and can decrypt it, then it forwards the
CllientHelloInner to the backend, who terminates the connection.
This is referred to as "ECH acceptance".
Paragraph (version B):
ECH uses HPKE for public key encryption I-D.irtf-cfrg-hpke.  The ECH
configuration is defined by the following "ECHConfigs" structure.
Paragraph (version B):
The "ECHConfigs" structure contains one or more "ECHConfig"
structures in decreasing order of preference.  This allows a server
to support multiple versions of ECH and multiple sets of ECH
parameters.
Paragraph (version B):
The version of ECH for which this configuration is used.  The
version of this document SHALL be "0xff07".  (Future drafts and
the final version MUST define a version that has not already been
assigned.)  Clients MUST ignore any "ECHConfig" structure with a
version they do not support.
Paragraph (version B):
An opaque byte string whose contents depend on the version of the
structure.  For this specification, the contents are an
"ECHConfigContents" structure.
Paragraph (version B):
The non-empty name of client-facing server, i.e., the entity
trusted to update these encryption keys.  This is used to repair
misconfigurations, as described in handle-server-response.
Paragraph (version B):
The HPKE public key used by the client to encrypt
ClientHelloInner.
Paragraph (version B):
The HPKE KEM identifier corresponding to "public_key".  Clients
MUST ignore any "ECHConfig" structure with a key using a KEM they
do not support.
Paragraph (version B):
The list of HPKE AEAD and KDF identifier pairs clients can use for
encrypting ClientHelloInner.
Paragraph (version A):
A list of extensions that the client can take into consideration
when generating a ClientHello message.  The purpose of the field
is to provide room for additional functionality in the future.
See config-extensions for guidance on what type of extensions are
appropriate for this structure.
Paragraph (version A):
The format is defined in RFC8446, Section 4.2.  The same
interpretation rules apply: extensions MAY appear in any order, but
there MUST NOT be more than one extension of the same type in the
extensions block.  An extension can be tagged as mandatory by using
an extension type codepoint with the high order bit set to 1.  A
client which receives a mandatory extension they do not understand
MUST reject the ECHConfig content.
Paragraph (version A):
Clients MUST parse the extension list and check for unsupported
mandatory extensions.  If an unsupported mandatory extension is
present, clients MUST reject the ECHConfig value.
Paragraph (version A):
The HpkeCipherSuite cipher suite used to encrypt ClientHelloInner.
This MUST match a value provided in the corresponding
ECHConfig.cipher_suites list.
Paragraph (version A):
A cryptographic hash of the ECHConfig structure from which the ECH
key was obtained, i.e., from the first byte of "version" to the
end of the structure.  This hash is computed using the hash
function associated with "suite", i.e., the corresponding HPKE KDF
algorithm hash.
Paragraph (version A):
The HPKE encapsulated key, used by servers to decrypt the
corresponding encrypted_ch field.
Paragraph (version A):
An ECHConfigs structure containing one or more ECHConfig
structures in decreasing order of preference that the client
should use on subsequent connections to encrypt the
ClientHelloInner structure.
Paragraph (version A):
This protocol also defines the "ech_required" alert, which is sent by
the client when it offered an "encrypted_client_hello" extension
which was not accepted by the server.
Paragraph (version A):
A 16-byte nonce exported from the HPKE encryption context.  See
send-ech for details about its computation.
Paragraph (version A):
Finally, requirements in client-behavior and server-behavior require
implementations to track, alongside each PSK established by a
previous connection, whether the connection negotiated this extension
with the "ech_accept" response type.  If so, this is referred to as
an "ECH PSK".  Otherwise, it is a "non-ECH PSK".  This may be
implemented by adding a new field to client and server session
states.
Paragraph (version B):
A list of extensions that the client must take into consideration
when generating a ClientHello message.  These are described below
(config-extensions).
Paragraph (version B):
ECH configuration extensions are used to to provide room for
additional functionality as needed.  See config-extensions-guidance
for guidance on which types of extensions are appropriate for this
structure.
Paragraph (version B):
Clients MUST parse the extension list and check for unsupported
mandatory extensions.  If an unsupported mandatory extension is
present, clients MUST ignore the "ECHConfig".
Paragraph (version B):
The cipher suite used to encrypt ClientHelloInner.  This MUST
match a value provided in the corresponding
"ECHConfig.cipher_suites" list.
Paragraph (version B):
A cryptographic hash of the "ECHConfig" structure from which the
ECH key was obtained, i.e., from the first byte of "version" to
the end of the structure.  This hash is computed using the hash
function associated with "cipher_suite", i.e., the corresponding
HPKE KDF algorithm hash.
Paragraph (version B):
The HPKE encapsulated key, used by servers to decrypt the
corresponding "encrypted_ch" field.
Paragraph (version B):
The serialized and encrypted ClientHelloInner structure, encrypted
using HPKE as described in send-ech.
Paragraph (version B):
An ECHConfigs structure containing one or more ECHConfig
structures, in decreasing order of preference, to be used by the
client in subsequent connection attempts.
Paragraph (version B):
A 16-byte nonce exported from the HPKE encryption context, as
described in send-ech.
Paragraph (version B):
Per client-behavior and server-behavior, implementations are required
to track, alongside each PSK established by a previous connection,
whether the connection negotiated this extension with the
"ech_accept" response type.  If so, this is referred to as an "ECH
PSK".  Otherwise, it is a "non-ECH PSK".  This may be implemented by
adding a new field to client and server session states.
Paragraph (version A):
When sending ClientHello, the client first computes ClientHelloInner,
including any PSK binders, and then MAY substitute extensions which
it knows will be duplicated in ClientHelloOuter.  To do so, the
client computes a hash H of the entire ClientHelloInner message with
the same hash as for the KDF used to encrypt ClientHelloInner.  Then,
the client removes and and replaces extensions from ClientHelloInner
with a single "outer_extensions" extension.  The list of
outer_extensions include those which were removed from
ClientHelloInner, in the order in which they were removed.  The hash
contains the full ClientHelloInner hash H computed above.
Paragraph (version A):
This process is reversed by client-facing servers upon receipt.
Specifically, the server replaces the "outer_extensions" with
extensions contained in ClientHelloOuter.  The server then computes a
hash H' of the reconstructed ClientHelloInner.  If H' does not equal
OuterExtensions.hash, the server aborts the connection with an
"illegal_parameter" alert.
Paragraph (version B):
When sending ClientHello, the client first computes ClientHelloInner,
including any PSK binders, and then MAY substitute extensions which
it knows will be duplicated in ClientHelloOuter.  To do so, the
client computes a hash of the entire ClientHelloInner message with
the same hash as for the KDF used to encrypt ClientHelloInner.  Then,
the client removes and replaces extensions from ClientHelloInner with
a single "outer_extensions" extension.  The list of
"outer_extensions" include those which were removed from
ClientHelloInner, in the order in which they were removed.  The hash
contains the full ClientHelloInner hash computed above.
Paragraph (version B):
This process is reversed by client-facing server.  Specifically, the
server replaces the "outer_extensions" with extensions contained in
ClientHelloOuter.  The server then computes a hash of the
reconstructed ClientHelloInner.  If the hash does not equal
OuterExtensions.hash, the server aborts the connection with an
"illegal_parameter" alert.
Paragraph (version A):
In order to send an encrypted ClientHello, the client first
determines if it supports the server's chosen KEM, as identified by
ECHConfig.kem_id.  If one is supported, the client MUST select an
appropriate HpkeCipherSuite from the list of suites offered by the
server.  If the client does not support the corresponding KEM or is
unable to select an appropriate group or HpkeCipherSuite, it SHOULD
ignore that ECHConfig value and MAY attempt to use another value
provided by the server.  The client MUST NOT send ECH using HPKE
algorithms not advertised by the server.
Paragraph (version A):
Note that the HPKE algorithm identifiers are those which match the
client's chosen preference from ECHConfig.cipher_suites.  The client
MAY replace any large, duplicated extensions in ClientHelloInner with
the corresponding "outer_extensions" extension, as described in
outer-extensions.
Paragraph (version B):
In order to send an encrypted ClientHello, the client first
determines if it supports the server's chosen KEM, as identified by
"ECHConfig.kem_id".  If one is supported, the client MUST select an
appropriate "HpkeCipherSuite" from the list of suites offered by the
server.  If the client does not support the corresponding KEM or is
unable to select a suitable "HpkeCipherSuite", it SHOULD ignore that
"ECHConfig" value and MAY attempt to use another value provided by
the server.  The client MUST NOT send ECH using HPKE algorithms not
advertised by the server.
Paragraph (version B):
Note that the HPKE algorithm identifiers are those which match the
client's chosen preference from "ECHConfig.cipher_suites".
Paragraph (version A):
The client MUST place the value of ECHConfig.public_name in the
ClientHelloOuter "server_name" extension.  The ClientHelloOuter MUST
NOT contain a "cached_info" extension RFC7924 with a CachedObject
entry whose CachedInformationType is "cert", since this indication
would divulge the true server name.  The remaining contents of the
ClientHelloOuter MAY be identical to those in ClientHelloInner but
MAY also differ.
Paragraph (version B):
The client MUST place the value of "ECHConfig.public_name" in the
ClientHelloOuter "server_name" extension.  The ClientHelloOuter MUST
NOT contain a "cached_info" extension RFC7924 with a CachedObject
entry whose CachedInformationType is "cert", since this indication
would divulge the true server name.  The remaining contents of the
ClientHelloOuter MAY be identical to those in ClientHelloInner but
MAY also differ.
Paragraph (version A):
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 HpkeCipherSuite.
Paragraph (version B):
Set the "config_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 HpkeCipherSuite.
Paragraph (version A):
Compare ClientEncryptedCH.record_digest against cryptographic
hashes of known ECHConfig and choose the one that matches.
Paragraph (version A):
Some uses of ECH, such as local discovery mode, may omit the
ClientEncryptedCH.record_digest since it can be used as a tracking
vector.  In such cases, trial decryption should be used for matching
ClientEncryptedCH to known ECHConfig.  Unless specified by the
application using (D)TLS or externally configured on both sides,
implementations MUST use the first method.
Paragraph (version B):
Compare ClientEncryptedCH.config_digest against cryptographic
hashes of known ECHConfig and choose the one that matches.
Paragraph (version B):
Some uses of ECH, such as local discovery mode, may omit the
ClientEncryptedCH.config_digest since it can be used as a tracking
vector.  In such cases, trial decryption should be used for matching
ClientEncryptedCH to known ECHConfig.  Unless specified by the
application using (D)TLS or externally configured on both sides,
implementations MUST use the first method.
Paragraph (version A):
Note that an unrecognized ClientEncryptedCH.record_digest value may
be a GREASE ECH extension (see grease-extensions), so it is necessary
for servers to proceed with the connection and rely on the client to
abort if ECH was required.  In particular, the unrecognized value
alone does not indicate a misconfigured ECH advertisement
(misconfiguration).  Instead, servers can measure occurrences of the
"ech_required" alert to detect this case.
Paragraph (version B):
Note that an unrecognized ClientEncryptedCH.config_digest value may
be a GREASE ECH extension (see grease-extensions), so it is necessary
for servers to proceed with the connection and rely on the client to
abort if ECH was required.  In particular, the unrecognized value
alone does not indicate a misconfigured ECH advertisement
(misconfiguration).  Instead, servers can measure occurrences of the
"ech_required" alert to detect this case.
Paragraph (version A):
Client-facing server configuration determines the size of the
anonymity set.  For example, if a client-facing server uses distinct
ECHConfig values for each host, then each anonymity set has size k =
maximize the size of the anonymity set where possible.  This means
client-facing servers should use the same ECHConfig for as many hosts
as possible.  An attacker can distinguish two hosts that have
different ECHConfig values based on the
ClientEncryptedCH.record_digest value.  This also means public
information in a TLS handshake is also consistent across hosts.  For
example, if a client-facing server services many backend origin
hosts, only one of which supports some cipher suite, it may be
possible to identify that host based on the contents of unencrypted
handshake messages.
Paragraph (version B):
Client-facing server configuration determines the size of the
anonymity set.  For example, if a client-facing server uses distinct
ECHConfig values for each host, then each anonymity set has size k =
maximize the size of the anonymity set where possible.  This means
client-facing servers should use the same ECHConfig for as many hosts
as possible.  An attacker can distinguish two hosts that have
different ECHConfig values based on the
ClientEncryptedCH.config_digest value.  This also means public
information in a TLS handshake is also consistent across hosts.  For
example, if a client-facing server services many backend origin
hosts, only one of which supports some cipher suite, it may be
possible to identify that host based on the contents of unencrypted
handshake messages.
Paragraph (version A):
Optional record digests may be useful in scenarios where clients and
client-facing servers do not want to reveal information about the
client-facing server in the "encrypted_client_hello" extension.  In
such settings, clients send either an empty record_digest or a
randomly generated record_digest in the ClientEncryptedCH.  (The
precise implementation choice for this mechanism is out of scope for
this document.)  Servers in these settings must perform trial
decryption since they cannot identify the client's chosen ECH key
using the record_digest value.  As a result, support for optional
record digests may exacerbate DoS attacks.  Specifically, an
adversary may send malicious ClientHello messages, i.e., those which
will not decrypt with any known ECH key, in order to force wasteful
decryption.  Servers that support this feature should, for example,
implement some form of rate limiting mechanism to limit the damage
caused by such attacks.
Paragraph (version B):
Optional record digests may be useful in scenarios where clients and
client-facing servers do not want to reveal information about the
client-facing server in the "encrypted_client_hello" extension.  In
such settings, clients send either an empty config_digest or a
randomly generated config_digest in the ClientEncryptedCH.  (The
precise implementation choice for this mechanism is out of scope for
this document.)  Servers in these settings must perform trial
decryption since they cannot identify the client's chosen ECH key
using the config_digest value.  As a result, support for optional
record digests may exacerbate DoS attacks.  Specifically, an
adversary may send malicious ClientHello messages, i.e., those which
will not decrypt with any known ECH key, in order to force wasteful
decryption.  Servers that support this feature should, for example,
implement some form of rate limiting mechanism to limit the damage
caused by such attacks.