Draft: draft-ietf-tls-esni

Commentary: A related PR that we probably should make sure flow together : 
 If a server implements ECH decryption via an RPC call , it 's possible for the client 's ECH keys to be valid for CH1 but invalid for CH2 , perhaps due to a race condition that updates the server 's keys across these messages . This should be exceedingly rare in practice , so failing the connection with an alert is probably fine , but we should probably be clear about this . cc 
 There are two ways a accept - then - HRR - then - reject can happen : client sends a after  that differs from the it sent before  . is the same , but the server no longer recognizes it . The latter is the server 's fault , and I think the only thing to do is abort with " internalerror " . However , I think requiring that the does n't change is a good idea . I wonder if this is implied by the client behavior ? In any case , I think we should have the server abort with " illegalparameter " if the changes over  . 
 Is this any different from , say , the server 's cipher suite capabilities changing in between CH1 and CH2 and thus the server not being able to meet what they said with  ? I guess I 've always assumed that , within the context of a single " handshake " from the perspective of the client , we expect the server to behave self - consistently and , if it ca n't , I guess the server can internal_error and live with failing one or two connections across server restarts . 
 I think this is a little different , since it can be triggered by changing the set of ECHConfigs the server knows , and not necessarily the set of cipher suites . I agree . And even though the situation is a bit different , I think " internalerror " is appropriate here as well . However , I also think the client SHOULD NOT change the ECHConfig across HRR . If it does , I think the server SHOULD abort with " illegalparamter " . Do you think this would be hard for the server to enforce ? In particular , a QUIC server might want to handle the  path statelessly , and this check requires remembering the previous . 
 I think that 's already true . The client ca n't change things across HRR unless explicitly allowed . ( ) Exactly what the server enforces on HRR is ... all over the place . I 'm normally in favor of maximal enforcement , but enforcing all the rules of HRR is such a mess . It 's especially messy for folks who do stateless  , because any state carried over across the two increases the size of the cookie . So I think we need to be a little careful here . Honestly , I think we did n't really get  right . QUIC does not care about stateless HRR . It did in the original design , but that 's been dropped . DTLS does , though . And I believe NSS always implements it statelessly ? ( BoringSSL currently only does stateful . ) 
 It sounds like a weak " MAY " would be most appropriate . 
 Can you elaborate ? 
 Looking at this again , I suspect the minimal thing that needs to be checked across CH1 and CH2 is that the server can not change its mind on whether it used ECH in CH2 and , if using ECH , it needs to have remembered echhrrkey ( and HPKE cipher suites ? ) to bind the two . Dunno if it makes sense to just also remember the config_id at that point . 
 I agree , but I do n't think tracking the is sufficient . Suppose the client sends an acceptable in CH1 but a rejecting in CH2 . In this case does n't provide the binding we need , since the client - facing server wo n't attempt to decrypt the payload in CH2 . A conservative way to ensure the server does n't change its mind is as follows : that the does not change across HRR . If it does , then abort with " illegalparameter " alert.\ that the does not change across HRR . If it does , then abort with " illegalparameter " alert . is n't recognized after  --- say because of key rotation -- then abort with " internalerror " alert .  I 'm not sure 1 . is strictly necessary . If the is n't supported by the ECH configuration , then the server would abort with " illegalparameter " . ( This is already specified . ) Moreover , I do n't think we have any agility issues here , given that the derived AEAD key is bound to the cipher suite . However , this does ensure that the server chooses the HPKE cipher suite and KEM key in the same way before and after  . This may turn out to be useful . 
 Right , this is what I mean by " the server can not change its mind on whether it used ECH in CH2 " . If you declined ECH in CH1 , you ignore ECH in CH2 . If you accepted ECH in CH1 , failure to handle ECH in CH2 is fatal . But , yeah , if you remember the config used , you can check a bit more accurately , so maybe we should just do that and ask stateless HRRs make an even larger cookie . ( Need to be a bit careful about itself because we allow a trial decryption flow too . ) 
 For what it 's worth , I 'm not a huge fan of CH2 having a fresh HPKE exchange in the first place . That seems an unnecessary asymmetric operation . Were it not for stateless  , I think I 'd advocate we just make CH2 's ECH payload a second pop at the HPKE context 's Seal ( ) function ( next sequence number ) , with the rest ignored . But with stateless  , we need to serialize the HPKE context into the cookie , which is mildly annoying . 
 I do n't see how you can avoid CH2 having a new payload . Unless you are looking to just perform address validation ( DTLS ) , you only send  to correct something in the ClientHello . 
 I think what means is that the AEAD ciphertext could change without changing the encapsulating key . Hence , the ClientHelloInner can be changed without updating the HPKE shared secret . Would n't this leak the HPKE encryption key ? The cookie extension is transmitted in the HRR in plaintext , right ? 
 I do n't see how you can avoid CH2 having a new payload . Unless you are looking to just perform address validation ( DTLS ) , you only send  to correct something in the ClientHello . Specifically , HPKE supports multiple sequential encryption calls on a context with an internal sequence number . But with stateless  , we need to serialize the HPKE context into the cookie , which is mildly annoying . The cookie already needs to encrypted and authenticated by the server like tickets . It certainly needs to be authenticated independent of ECH , otherwise the attacker can manipulate it anyway . And then the existing echhrrkey construction requires encryption too . ( If you did n't encrypt the cookie for some reason and only MAC'd it , this design would allow you to , rather than serializing the HPKE encryption key , remember the expected HPKE config , redo the KEM operation , and bump the sequence number up . But if you 're remembering some secret for the MAC , may as well encrypt it ... ) 
 Right , thanks for again clarifying a misunderstanding of mine about the TLS spec :) Incidentally , I brought up specifying HPKE context serialization here : There does n't seem to be a lot of appetite for it . I suppose we could specify it in ECH , but there are so many use cases for it that I think it would be worth specifying it in the HPKE draft . 
 Given the uncertainty about stateless HRR pointed out in , let 's permit the client - facing server to abort if ECH usage changes after  . This allows stateful - HRR servers to enforce this behavior , but leaves it as an " OPEN ISSUE " about how stateful - hRR servers will enforce this . I 'll prepare a PR tomorrow or Thursday .
Paragraph (version A):
It is an error for the client to offer ECH before the
HelloRetryRequest but not after.  Likewise, it is an error for the
client to offer ECH after the HelloRetryRequest but not before.  If
either of these conditions occurs, then the client-facing server MUST
abort the handshake with an "illegal_parameter" alert.
Paragraph (version B):
If CH1 contains the "encrypted_client_hello" extension but CH2
does not, or if CH2 contains the "encrypted_client_hello"
extension but CH1 does not, then the server MUST abort the
handshake with an "illegal_parameter" alert.
Paragraph (version B):
Suppose the "encrypted_client_hello" extension is sent in both CH1
and CH2, If the configuration identifier (see ech-configuration)
differs between CH1 and CH2, then the server MUST abort with an
"illegal_parameter" alert.