Draft: draft-ietf-tls-esni

Commentary: Per suggestion , this replaces computations involving the " hash underlying the KDF " with evaluation of the KDF itself . This respects the API defined in the HPKE draft . This supersedes . 
 Hey and I rolled up your changes ! Please have another look before merging . 
 Rebased and rolled up . 
 Thanks -- let 's let this stew until Friday , at which point we can merge . 
 Rebased . 
 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 . 
 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 .
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 "cipher_suite", i.e., the corresponding
HPKE KDF algorithm hash.
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 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):
where "inner" is the ClientHelloInner structure and "Extract",
"Expand", and "Nh" are as defined by the KDF API in I-D.irtf-cfrg-
hpke.  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 A):
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.config_digest against cryptographic
hashes of known ECHConfig and choose the one that matches.
Paragraph (version B):
Compare ClientEncryptedCH.config_digest against digests of known
ECHConfig and choose the one that matches.