Draft: draft-ietf-tls-esni

Commentary: We need to decide if we want to allow a GREASE+ticket distinguisher , and if not , how we GREASE the " presharedkey " extension in a meaningful way . The latter seems like somewhat of a cat and mouse game , so I 'm not really enthusiastic about trying to specify that behavior , but I 'd like to hear what others think . cc 
 This looks good . I still feel that there are a lot of ways that ECH usage might stick out , even to passive observers . " presharedkey " is one of many . If anything I would change the " OPEN ISSUE " to encompass top - to - bottom " do n't stick out " review . 
 We previously decided not to bind the outer ClientHello to the ECH decryption , because doing so is rather a hassle . We 'd need something similar to the TLS 1.3 PSK binder mess , with the complexity of ordering relative to the PSK binders themselves . Additionally , while the binding helps with some of the do n't stick out properties , there were other attacks on distinguishability anyway . So , instead , we mitigated the inner ClientHello malleability with OuterExtensions.innerdigest and left the outer ClientHello unbound . However , we 've since decided not to allow PSKs in the outer ClientHello . Perhaps we should revisit this . Suppose the AD parameter to the ECH decryption were the entire outer ClientHello , minus the ECH extension . I believe this means we no longer need OuterExtensions.innerdigest . That would give an immediate 33 - byte savings . It would then unlock a further 32 byte savings by amending to say : Client always encodes an empty legacysessionid in ECH plaintext . Client - facing server copies outer legacysessionid to inner ClientHello as part of decompression . ( The reason we ca n't do this easily right now is that , if the inner ClientHello lacks outerextension , nothing 's authenticating legacysessionid . Since the field in TLS 1.3 is all but ignored , it 's " obvious " that the malleability does n't matter , but it 's nicer to not need to think about such things . ) From looking at Chrome 's ClientHellos and working through what we 'd send ( drop 1.2 - only extensions , compress most ) , it looks like the inner ClientHello will be maybe 130 - 140 bytes , plus a padded servername . The 65 bytes above would almost halve the overhead . In some sense what 's going on here is our 16 - byte tag on the AEAD in the ECH ciphertext is going to waste . We did n't authenticate everything that goes into reconstructing the inner ClientHello ( outerextensions ) , so instead we authenticate another hash ( OuterExtensions.innerdigest ) and check that afterwards . ( To that end , if we do this , we probably need to say the server MUST reject encryptedclienthello showing up in outer_extensions , that way all inputs to decompression are authenticated . Equivalently , decompression is done relative to the ECH - extension - less AD input rather than the original outer ClientHello . ) 
 I like this idea . How do you think the AD ought to be structured ? The ClientHelloOuter , but with an an empty " encryptedclienthello " extension ? 
 Yeah , that 's seems the simplest to me . Filling it with zeros , as pointed out to me , requires predicting the length of the encrypted inner ClientHello . This is n't strictly impossible ( ADs do n't change ciphertext length ) , but it seems needlessly fussy and ECH is already requiring we be able re - encode ClientHellos , lengths and all . Note this assumes there are no computed PSK binders in the outer ClientHello because otherwise there 's a circular dependency . ( If we wanted to allow that , the AD would need to zero / trim the binders or so . ) 
 Another benefit is it stops the attacker from probing information about compressed extensions . Currently an attacker can learn which extensions are compressed in the inner ClientHello by removing them from the outer ClientHello and seeing if the server still responds . This is n't a huge deal , as compressed extensions are assumed public , but this way we remove that vector and leave only the fuzzier signal from the ciphertext length . 
 On second thought , a lot of implementations will need to do that prediction anyway . The workaround for the old F5 bug means we 'll need to know the eventual size for the padding extension . ( On the other hand , you can probably assume anyone doing ECH is not running those things . On the other hand , turning off the workaround would stick out . ) Ah well . We did it for PSK already . ( I wonder if we can do drop that workaround now that TLS 1.0 and 1.1 are gone ... ) 
 What 's the " old F5 bug " ? What 's the value in authenticating the length of the " encryptedclienthello " extension ? This is authenticated by the handshake already , no ? 
 It 's why we have a padding extension . There is n't . It 's just a question of what 's easier to deal with . Filling it with zeros means that , when computing the AD on the receiving side , you do n't need to fully reconstruct a modified outer ClientHello with updated length prefixes . We avoided this when computing the PSK binder in RFC8446 . It 's a mild hassle but not a huge deal . More importantly , we 've thoroughly given up on that elsewhere in the spec . The F5 padding business also means computing this AD will likely take some length prediction anyway , but so it goes . 
 I agree , it 's not a big hassle . 
 Rather than make the extension empty , can we just omit the and fields ? ( The and should arguably be included , a la ) . 
 That works , though it 's even more fussy for the client to construct , since it needs to half - encode the ECH extension before fully encoding it . is already bound into HPKE itself . is less clear , but I thought our model already said all this did n't matter ? Is n't the binding here just to replace and provide malleability ? If there 's something more going on , I 'd like us to have some principled answer here , so we can answer questions like ... what about the handshake transcript , which may not be empty on  ? If we do that , what 's going on with echhrr_key ? 
 The principle I was following is : include as much as possible in the AD . Yeah , it 's more of a pain , and we 've gotten away with no binding whatsoever up to now , so maybe we do n't need it . I 'm happy to start with an empty ECH extension and then consider the other parts later , if that 'll help . 
 I do n't feel very strongly either way . 
 Let 's just do the simpler thing now , then ! :-) 
 The current draft contains various rules around ECH and resumption . These rules date to before we started encrypting the entire ClientHello and were intended to avoid mixing up session resumptions between the public and private name , since the same presharedkey extension was used for both , and amount to saying implementations must add a boolean to their session state . Now that the public and private names correspond to different ClientHellos altogether , the client can ( and should ) only send inner name tickets in the inner ClientHello and outer name tickets in the outer ClientHello . ( ) I suspect that means we no longer need further ECH special cases here . 
 This seems like a good simplification , but we should probably be careful about the interaction with cross - SNI resumption . 
 I think it just composes as expected ? If you offer a PSK in the outer ClientHello , cross - SNI or no , it means that you are satisfied with it as an alternative to the certificate covering the public name . If you offer a PSK in the inner ClientHello , cross - SNI or no , it means you are satisfied with it as an alternative to the certificate covering the true name . Your ClientHellos should be consistent with this , which means that servers resuming is n't an issue . TBH I forgotten some of the details for why this was here . I found this long comment I wrote , but apparently past me was just unsatisfied that a case ( 4 ) was " weird " . So that was very unhelpful , past me . Regardless , I think the ambiguity is moot now . ( I also expect clients just wo n't offer PSKs in the outer  . It 's unlikely that you 'll get any to offer anyway . And if your API has an external session cache , the caller needs to go out of their way to do two lookups . ) 
 I was thinking about clients that might mistakenly use inner tickets for the outer name when given the cross - SNI signal . ( I agree that it composes naturally . ) A simple note would probably suffice . For outer tickets , I tend to think they should just be discouraged . What 's the benefit of resuming a TLS 1.3 connection you 'd tear down anyway ? 
 I 'm not sure I fully understand the ( historical ) need to distinguish between ECH - PSKs and non - ECH - PSKs . But why would a client offer PSK to a client - facing server at all ? In other words , will it ever be useful to send a PSK extension in the ClientHelloOuter ? It seems to me that this feature is only meaningful to the intended backend server , and so should only appear in the ClientHelloInner . The same question applies to all other extensions . If the client - facing server terminates the connection , then the only action the client will take is to close the connection . Hence , the only functionality we will ever need for the client<-client - facing server connection is to complete a full , server - authenticated handshake . If I were implementing the client , I would restrict the contents of the ClientHelloOuter to only those extensions that are necessary to implement this functionality . I wonder if it makes sense to enforce this in the spec . Something like : " When offering the ' ech ' extension , the client MAY include the following extensions in the ClientHelloOuter : ' supportedversions ' , ' servername ' . ' keyshares ' , ' signaturealgorithms ' , [ and so on ] . It MUST NOT include any other extension . " What are the downsides to doing something like this ? I think the upside is that it simplifies the problem of deciding what to put in the ClientHelloInner versus the ClientHelloOuter . I suppose one downside is that it potentially sticks out a bit . 
 Based on this week 's interim , we decided it was fine to prohibit PSKs in the outer CH for ECH connections , so the current draft text prohibits " presharedkey " extensions in the outer CH . A connection using GREASE may , however , decide to resume its connection to the outer name . This gives a passive adversary a pretty easy distinguisher between GREASE and non - GREASE : if there 's a ticket present , the connection is definitely GREASE . It seems that if we want to maintain our current indistinguishability properties , there always needs to be some ticket . So perhaps that means : ECH ( non - GREASE ) clients would generate a bogus ( GREASEd ) ticket GREASE clients that do n't have a ticket would generate a bogus ticket GREASE clients that have a ticket would use it penny for your thoughts ? 
 I mostly figure there wo n't be a ticket in the initial connection to a server , or any connections made after long time , so intolerance to ticket - less ClientHellos will likely be noticed quickly . Though it is true that probably a lot of connections offer tickets . There may be something to be said for allowing clients to send bogus tickets if they want , but it 's worth noting an active attacker can tell if the ticket is ( most likely ) bogus by simply trying to resume it . ( A tangent : we actually saw a very old TLS 1.0 server implementation that broke with TLS 1.3 because it would take the client 's session IDs and unconditionally echo it back . I 'm not sure what was going on there . It did n't actually switch to a resumption handshake or implement resumption at all . It just echoed back the session ID for some reason . Only reason this did n't break before was that it never issued session IDs , so this codepath had never been tested before . ) 
 True , but that 's already the case for active attackers . What I 'm concerned about are passive attackers . 
 I think this gets at a larger " do n't stick out " problem currently only addressed in bits and pieces . Just as dummy ( i.e. , greased ) ECH is used to provide covertext for real ECH , real - ECH connections also need to provide covertext for the real extensions offered in dummy - ECH connections . In particular , the spec should provide guidance on how to generate dummy extensions in the ClientHelloOuter .
Mailing list commentary: It is a little bit more calculation than that and related to some historic reasons , aka SSLv2 . For SSL records , the SSLv3 and TLS ClientHello headers are as follows : If this is interpreted as an SSLv2 header , it will be considered as a 3 byte header : The value for Client Hello message type is  which is 1 . When there is an SSLv3 / TLS client - hello of length 256 - 511 bytes , this is ambiguous as " message type " is 1 or it is the " length high bits " to be 1 . Out implementation before the patch was to prefer SSLv2 and thus the issue . As I am explaining this in detail , I would say that another work around on this would be making a client hello that exceeds 512 in length .
Paragraph (version A):
Per client-behavior and server-behavior, implementations are required
to track, alongside each PSK established by a previous connection,
whether ECH was accepted for this connection.  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):
Some TLS 1.3 extensions can be quite large and having them both in
the inner and outer ClientHello will lead to a very large overall
size.  One particularly pathological example is "key_share" with
post-quantum algorithms.  In order to reduce the impact of duplicated
extensions, the client may use the "outer_extension" extension.
Paragraph (version B):
Some TLS 1.3 extensions can be quite large and having them both in
ClientHelloInner and ClientHelloOuter will lead to a very large
overall size.  One particularly pathological example is "key_share"
with post-quantum algorithms.  In order to reduce the impact of
duplicated extensions, the client may use the "outer_extension"
extension.
Paragraph (version B):
It MUST NOT offer to resume any session for TLS 1.2 and below.
Paragraph (version A):
If the server sends a HelloRetryRequest in response to the
ClientHello, the client sends a second updated ClientHello per the
rules in RFC8446.  However, at this point, the client does not know
whether the server processed ClientHelloOuter or ClientHelloInner,
and MUST regenerate both values to be acceptable.  Note: if the inner
and outer ClientHellos use different groups for their key shares or
differ in some other way, then the HelloRetryRequest may actually be
invalid for one or the other ClientHello, in which case a fresh
ClientHello MUST be generated, ignoring the instructions in
HelloRetryRequest.  Otherwise, the usual rules for HelloRetryRequest
processing apply.
Paragraph (version B):
If the server sends a HelloRetryRequest in response to the
ClientHello, the client sends a second updated ClientHello per the
rules in RFC8446.  However, at this point, the client does not know
whether the server processed ClientHelloOuter or ClientHelloInner,
and MUST regenerate both values to be acceptable.  Note: if
ClientHelloOuter and ClientHelloInner use different groups for their
key shares or differ in some other way, then the HelloRetryRequest
may actually be invalid for one or the other ClientHello, in which
case a fresh ClientHello MUST be generated, ignoring the instructions
in HelloRetryRequest.  Otherwise, the usual rules for
HelloRetryRequest processing apply.
Paragraph (version A):
If the server sends a NewSessionTicket message, the corresponding ECH
PSK MUST be ignored by all other servers in the deployment when not
negotiating ECH, including servers which do not implement this
specification.
Paragraph (version B):
If the server sends a NewSessionTicket message, the corresponding PSK
MUST be ignored by all other servers in the deployment when not
negotiating ECH, including servers which do not implement this
specification.
Paragraph (version A):
This attack uses resumption PSKs as an oracle for dictionary attacks
against a given ClientHello's true SNI.  To begin, the attacker first
interacts with a server to obtain a resumption ticket for a given
test domain, such as "test.com".  Later, upon receipt of a legitimate
ClientHello without a PSK binder, it computes a PSK binder using its
own ticket and forwards the resulting ClientHello.  Assume the server
then validates the PSK binder on the outer ClientHello and chooses
connection parameters based on the inner ClientHello.  A server which
then validates information in the outer ClientHello ticket against
information in the inner ClientHello, such as the SNI, introduces an
oracle that can be used to test the encrypted SNI value of specific
ClientHello messages.
Paragraph (version A):
ECH mitigates against this attack by requiring servers not mix-and-
match information from the inner and outer ClientHello.  For example,
if the server accepts the inner ClientHello, it does not validate
binders in the outer ClientHello.  This means that ECH PSKs are used
within the HPKE encryption envelope.
Paragraph (version B):
This attack uses resumption PSKs as an oracle for dictionary attacks
against a given ClientHello's true SNI.  To begin, the attacker first
interacts with a server to obtain a resumption ticket for a given
test domain, such as "test.com".  Later, upon receipt of a legitimate
ClientHello without a PSK binder, it computes a PSK binder using its
own ticket and forwards the resulting ClientHello.  Assume the server
then validates the PSK binder on the outer ClientHello and chooses
connection parameters based on the inner ClientHello.  A server which
then validates information in ClientHelloOuter ticket against
information in ClientHelloInner, such as the SNI, introduces an
oracle that can be used to test the encrypted SNI value of specific
ClientHello messages.
Paragraph (version B):
ECH mitigates against this attack by (1) prohibiting the
"pre_shared_key" extension in ClientHelloOuter and (2) requiring
servers ignore this extension when processing ClientHelloOuter.
Thus, if the server accepts the inner ClientHello, it only validates
binders in the inner ClientHello.  This means that PSKs are used
within the HPKE encryption envelope.