Draft: draft-ietf-tls-esni

Commentary: We previously derived the acceptance signal from the handshake secret . This meant that clients which used the wrong ECHConfig might need to process ServerHello extensions twice before computing the signal , which can be problematic for some libraries . Given that the signal 's secrecy is entirely dependent on , we can relax the signal computation and base it on the transcript alone , which includes , rather than a secret derived from that transcript . cc 
 Yep , good change . Thanks ,    the " ECH worked " signal in the lower octets is , at best , ugly . It also arguably causes violation of internal API designs in at least the OpenSSL code . And I 'm not sure if there might be some interaction between that and ticket handling ( just from the look of some code I 've yet to understand really . ) Do we really need such a hacky solution ? Given the ECH sticks out in the CH , we could just define a non - encrypted extension in the SH to include the confirmation value maybe ( though even that is pretty hacky ) . 
 I have some sympathy for this , but the point of this signal design was to make it difficult to distinguish GREASE from non - GREASE ECH . 
 Could you elaborate on the concern with ticket handling ? I 'm not sure I see how tickets would relate to this . 
 Sorry for being slow - should get to looking again at that bit of code in a few days . S 
 Just to synchronize the discussion across list / GitHub a bit , this was discussed a bit in I agree with now that there 's some fiddly interactions from two ClientHellos and ServerHello . I sketched out a possible change sketched out in We could compute ClientHelloInner ... ServerHelloECHConf as in the draft right now . But then rather than feed that into the handshake secret computation , just rely on that transcript containing a secret and computing F(transcript ) . ( Hash it down , KDF it with zero secret , whatever . ) One observation is that , while this relies oddly on a secret , the existing construction does too . An attacker constructing a ServerHello gets to pick ServerHello.keyshare and , with knowledge of ClientHello.keyshare , compute the resulting shared secret . 
 One further observation here is that if the client uses the same shares for CHInner and CHOuter , the double key derivation piece does n't really need to apply . 
 For my own reference , I just wanted to flag something that we 've discussed on the list : the current acceptance signal interacts with PSK in a way that could easily cause a bug in an implementation that has n't carefully vetted this interaction . 
 dns records are 8 bit clean and rfc 6763 is an example of a TXT record carrying arbitrary data 
 : +1 : Base64 is not only complication . It is a space overhead for a large object like ESNIKeys . Seeing corruption of binary will be rare ; we can detect them by validating the checksum and fallback to non - ESNI in such case . So why not go for binary ? FWIW ,  was introduced in . 
 This is solved in which removes base64 with new ESNI RR type . 
 We only this since TXT records were claimed to not work well with binary , per Christian ’s suggestion . I ’m fine either way . 
 Thanks for the info . I found , in which asks : We know that we can store more than 128 octets in TXT record , and that we have a precedent that uses TXT to store binary data , as has pointed out . Regarding configurability , my understanding is that RFC 1035 defines how binary TXT records can be specified in a zone file , and therefore many DNS server " softwares " support having such records . Googling also tells me that managed DNS services like Route 53 and Azure DNS provide the capability , although surprisingly they use different escape sequences ( uses + 3 octal , uses + 3 decimal ) . 
 I do not think it ’s a complication , and I ’m not convinced space is an issue as per your comment above . 
 only tangentially related - do you know why your txt record is broken into 127 char strings instead of 255 ? Is there a bug being worked around somewhere ? 
 Oh I did not notice that . I am using tinydns ( of djbdns ) , and it seems like tinydns works that way ( see ) . 
 The issue about the size is that with  we might hit the 512 - octet threshold when publishing keys of multiple strengths . As an example , query for currently returns a 186 - byte response , which contains just secp256r1 key . If we add secp384r1 and secp521r1 , I 'd assume that the size will come near to 490 octets . In other words , for longer hostnames we will hit the 512 - octet threshold if we publish three keys . If we avoid the  encoding , we will have enough room to store 3 ECDH keys that can provide 128- , 192- , 256 - bit - level security . I do not think this argument is strong enough to prohibit the use of base64 for the following reasons : we will be using DoH / DNS over TLS between the client and the resolver we might be using DNS over UDP that has the 512 - octet threshold between the resolver and the authoritative server , but we would want that to migrate to DNSSEC or something even better we might be just fine with publishing only two keys : X25519 , X448 But it does make me prefer not to have the overhead of  , if that is possible . 
 Fixed in . 
 Seems fine to me .
Mailing list commentary: I do n't think I 'd agree that most of the work is in the secret computation per se . Actually doing trial decryption with the secret requires reaching down into the record layer . This is especially onerous for QUIC , where the record layer is offloaded to another protocol ( often outside the TLS library ) . I think going back to full trial decryption would still considerably increase the cost of implementing ECH over the current draft . That said , I do agree that even the first part seems more onerous than expected and it 's worth reconsidering things . We switched using just the randoms to the full handshake secret to mitigate some issues . Perhaps there 's an intermediate point that still mitigates those issues but avoids the expensive part of the secret computation ? What if we kept the ClientHelloInner ... ServerHelloECHConf transcript as in the current draft , but derived the signal exclusively from that ? ( Or from the client random and that transcript , though the transcript includes the client random anyway . ) We 'll still bind in the ServerHello extensions , and it still includes the encrypted inner ClientHello random , as in the randoms formulation . It does n't do the job as clearly as the handshake secret did , but maybe it 'll work ? Implementation - wise , this variant would not require actually processing the ServerHello extensions .
Hi all , I raised a github issue [ 1 ] related to ( but different from ) this but would prefer a discussion via email if that 's ok . Depending how this goes , I can create a new GH issue I guess . ECH draft-09 ( and -10 ) requires the client to verify that the server has processed ECH by comparing 8 octets in the with a value one can only know if you know the inner CH octets and ( pretty much all ) the rest of the h / s so far . That seemingly removes the need for the client to maybe decrypt twice ( once based on inner CH , once based on outer ) to see what works . That can be implemented ok for the nominal case . As far as I can see that was the result of github issue # 274 [ 2 ] back in Aug / Sep 2020 . But in error cases that seems to require the client to possibly process the same ServerHello extensions twice , which could have side effects , is generally ickky and I think shows that this aspect of the design maybe needs a change . That 's not much different from trial decryption really . In my current , ( and still horrible;- ) , OpenSSL code the minimal effect is memory leaks for error cases that are tricky to handle , but can be handled , although at the expense of probably making the code even more brittle . ( Note : I ' m neither defending nor attacking the way OpenSSL handles extensions here:- ) The specific problem is one needs the handshake secret to calculate the 8 octets one expects in the , but generating the handshake secret typically involves a key share ServerHello extension and might in future involve some PQC stuff , so I think we ca n't say for sure which subset of extensions are needed for the calculation . And if the first time does n't give the right answer ( e.g. if the client used the wrong ECHConfig ) then you got ta process the ServerHello incl . its extensions a 2nd time . I think the requirement we ought try meet here is that any confirmation value needs to be something the client can calculate using values known before the SH is rx'd plus the ServerHello as a ( mostly ) unprocessed buffer . That could be e.g. some hash of the encoded inner CH , ECHConfig and the ServerHello maybe . Some of those issues were discussed in [ 2 ] already and in an interim meeting I missed but I reckon it might be worthwhile thinking again . Thanks , S. [ 1 ] [ 2 ]
Paragraph (version A):
where Derive-Secret and Handshake Secret are as specified in RFC8446,
Section 7.1, and ClientHelloInner...ServerHelloECHConf refers to the
sequence of handshake messages beginning with the first ClientHello
and ending with ServerHelloECHConf.  Finally, the backend server
constructs its ServerHello message so that it is equal to
ServerHelloECHConf but with the last 8 bytes of ServerHello.random
set to the first 8 bytes of accept_confirmation.
Paragraph (version B):
where HKDF-Expand-Label and Transcript-Hash are as defined in
RFC8446, Section 7.1, "0" indicates a string of Hash.length bytes set
to zero, and ClientHelloInner...ServerHelloECHConf refers to the
sequence of handshake messages beginning with the first
ClientHelloInner and ending with ServerHelloECHConf.  (Note that
ClientHelloInner and ServerHelloECHConf messages replace the
ClientHello and ServerHello messages in the transcript hash sequence
as specified in Section 4.1.1 of RFC8446.  Finally, the backend
server constructs its ServerHello message so that it is equal to
ServerHelloECHConf but with the last 8 bytes of ServerHello.random
set to "accept_confirmation".