Draft: draft-ietf-tls-esni

Commentary: While at it , remove the redundant " ClientHello . " prefix , the name KeyShareClientHello implies this . _ I did not explicitly mention that " extensiondata " is a list of key shares , but hope that the suggested phrase is strong enough to imply that . Do you think that is sufficient or should it become something like : ( By the way , the list of client key shares could contain one or more entries , but it could also be empty if the client would like to trigger a HRR . That should still be OK since the key / nonce is derived from the client hello random . ) 
 Those changes seem okish though could maybe be better . My issue was that OpenSSL ( afaics ) previously ignored all the key shares except the one used , so handling two of 'em as the AAD meant adding some new state . No idea if other implementations are like that though . I guess it might help someone else if it explicitly said that there can be 1 key share to include in the AAD . ( BTW , on your BTW , I need to think more about ESNI and  handling , have n't tested that yet so not sure if there 's a case where the encoding of 0 key shares would be used as ESNI AAD . ) 
 If this adds so much complication , why not drop the KeyShareClientHello completely ? If the purpose is to bind this to the original   , then the Client Random should be sufficient . An implementation that creates the encrypted_sni field is also responsible for generating a random client hello and a new ESNI key share . Assuming that these are always unique between   , then removing the KeyShareClientHello extension should still preserve the binding property . And even if for some reason the ESNI key share is reused ( e.g. shared between different client hello , or reusing one from KeyShareClientHello ) , the derived key / nonce would still be different if Client   is unique . what was the reason for mixing the client key shares list in addition to the existing client random ( commit ) ? 
 If you do n't bind in the client key share , there is a trivial attack in which the attacker replaces the key share with their own , causing the server 's certificate to be encrypted to them . 
 What said above . :-) 
 Thanks for the clarifying text ! 
 Oh I see , the sender of the ESNI extension does not have to prove its knowledge about the ESNI private key , so an attacker could trivially copy the victim 's ESNI extension and client random into the attacker 's handshake , and recover the certificate if the client key shares were not included . Even if the attacker can not decrypt SNI , they can still observe the side - effects . Thanks ! I think the text could be clarified to highlight this , I 'll prepare a proposal for this . 
 A second point in issue was n't addressed very clearly by . " ... HKDF - Extract(0 , Z ) should probably become HKDF - Extract ( " " , Z ) or be explicit about the salt as is done in ( or ) . " The current draft does clarify this in the text below , but I initially missed that . The reader has to know that the first argument to HKDF - Extract is named " salt " to put it together . I did end up getting it right , figuring this was intended to mean a buffer of zeros . I think it would be clearer to say : 
 a PR to clarify this point is most welcome ! 
 It would be ok to take this suggestion into consideration under the terms of the IETF 's " Note Well " blue sheet terms , and incorporate it into a PR by the editors . 
 I agree ! Could you please provide that PR ? 
 Oh , I was asking you folks to do it . If there 's a reason I need to do it , I 'd be happy to . 
 I do n't think this is necessary , so while I 'm willing to look at a PR , I 'm not going to make one at this time . 
 It was initially not clear to me what should be included in the AAD for encrypting ClientESNIInner into ClientEncryptedSNI.encryptedsni . The spec currently says : ClientHello . KeyShareClientHello is not defined in this document . At first I thought it would cover ClientEncryptedSNI.keyshare , but that seemed odd . Later I found that it refers to the Key Share extension defined in . Perhaps this reference could be ? On a related note , should probably become or be explicit about the salt as is done in ( or ) . 
 FWIW , I also had a little trouble with this . My initial interpretation was to use the h / s key share that ends up being used as the AAD , which worked fine for my client ( vs cloudflare ) and for my server ( vs. NSS ' tstclnt ) . In each of those cases though only one key share was sent by the client . FF nightly however sends two key shares in the h / s so I had to change my code to do the right thing . Could be worth a note in the internet - draft e.g. saying to use ( the encoding of ) all key shares from the h / s and that some clients do send more than one .
Paragraph (version A):
where ESNIContents is as specified below and Hash is the hash
function associated with the HKDF instantiation.
Paragraph (version B):
where ESNIContents is as specified below and Hash is the hash
function associated with the HKDF instantiation.  The salt argument
for HKDF-Extract is a string consisting of Hash.length bytes set to
zeros.
Paragraph (version A):
Where ClientHello.KeyShareClientHello is the body of the extension
but not including the extension header.  Including
ClientHello.KeyShareClientHello in the AAD of AEAD-Encrypt binds the
ClientEncryptedSNI value to the ClientHello and prevents cut-and-
paste attacks.
Paragraph (version B):
Where KeyShareClientHello is the "extension_data" field of the
"key_share" extension in a Client Hello (Section 4.2.8 of RFC8446)).
Including KeyShareClientHello in the AAD of AEAD-Encrypt binds the
ClientEncryptedSNI value to the ClientHello and prevents cut-and-
paste attacks.
Paragraph (version A):
If the server sends a HelloRetryRequest in response to the
ClientHello and the client can send a second updated ClientHello per
the rules in RFC8446, the "encrypted_server_name" extension values
which do not depend on the (possibly updated)
ClientHello.KeyShareClientHello, i.e,, ClientEncryptedSNI.suite,
ClientEncryptedSNI.key_share, and ClientEncryptedSNI.record_digest,
MUST NOT change across ClientHello messages.  Moreover,
ClientESNIInner.nonce and ClientESNIInner.realSNI MUST not change
across ClientHello messages.  Informally, the values of all
unencrypted extension information, as well as the inner extension
plaintext, must be consistent between the first and second
ClientHello messages.
Paragraph (version B):
If the server sends a HelloRetryRequest in response to the
ClientHello and the client can send a second updated ClientHello per
the rules in RFC8446, the "encrypted_server_name" extension values
which do not depend on the (possibly updated) KeyShareClientHello,
i.e,, ClientEncryptedSNI.suite, ClientEncryptedSNI.key_share, and
ClientEncryptedSNI.record_digest, MUST NOT change across ClientHello
messages.  Moreover, ClientESNIInner.nonce and
ClientESNIInner.realSNI MUST not change across ClientHello messages.
Informally, the values of all unencrypted extension information, as
well as the inner extension plaintext, must be consistent between the
first and second ClientHello messages.