Draft: draft-ietf-tls-esni

Commentary: This change provides an explicit confirmation of ECH acceptance . To do so , the backend server overwrites the last 8 bytes of the with a value derived from and the first 24 bytes of This addresses . REVISED 9/21 . 
 Is n't there an issue with spoof and replay ? Suppose an MITM observes a transaction and block the server 's response . Instead , the MITM constructs its own SH , as a response to the outer CH , but sets the first 8 bytes of the server random to a copy of the 1st 8 bytes in the response of the original server . If the server was doing ECH , the connection between client and MITM will fail -- other wise it will succeed , or at least progress . The MITM has thus detected whether the server was doing ECH . 
 Providing details of the attack mentioned above , in QUIC context : 
 I am thinking of solutions that are robust against this kind of MITM attack , but they are more complicated than just copying the 8 bytes . You need to make the 8 byte some kind of hash of both the client 's hint and the server 's key share . That way , anyone replaying the hint has to use the same key share , and can not hope to decrypt the responses . 
 This mechanism is n't designed to prevent an active attacker from deducing whether ECH was used . Note that there are much simpler attacks for doing so : just probe the target server for the ECH configuration , then observe a handshake between the target client and the server . 
 I agree that it boils down to " do we care " . The current ECH design does stick out quite a bit . The MITM can find whether the client sent an ECH extension . So it may make sense to keep it simple , accept the vulnerability , and document it in the ECH security considerations . 
 For that matter , you could replay the ClientHello several times and check whether the interesting bytes of the server 's keyshare or the extension remain constant for any of these designs , assuming the server does n't have more general defenses against a replayed ClientHello . As long as it 's a simple echo , I think that criticism is fair against all of these proposals . Which means either complexity or accepting that such detection is inevitable anyway . 
 We can fix the constant aspect by incorporating the rest of the But yeah , it 's a question of what kind of attacker we 're interested in for GREASE . If we want to defeat active attacks , I think we 'd need to do things like : Bind the entire outer CH into the ECH decryption . Otherwise , there 's attacks ranging from the key shares to simply replacing the cipher suite list with garbage . ( If the server responds , the server must not have looked at the outer cipher suite . ) Switch decryption failure to fallback rather than error ( ) , otherwise the attacker could perturb the ciphertext and see if the server noticed . Then there 's whether the attacker is allowed to compare configids in two connections , or look up and recognize the particular server 's ECH config . For example , if you do a DNS lookup or just trigger the retry flow , you can learn the expected configid and look for it . The trial decryption option or could work . From there , there 's still recognizing the public name from the queried ECH config . ( Though that depends on whether the public name is one you 'd expect in normal traffic or not . ) 
 Regarding the " do n't stick out " requirement , the goal of this proposal is not to thwart an active distinguisher , but merely to trick a dumb middlebox , which we presume to be passive and ignorant of the configuration . It would be helpful if folks would limit discussion of attacks / mitigations to this narrow threat model and resume discussion of the threat model itself in . 
 I think what is suggesting is that we address attack by computing SH.Random as follows : However , as he says , there seem to be a lot of active attacks to determine if ECH was used on a single connection . 
 I do not think that the fix suggested by and solves the problem . The only change in the attack would be : Can we keep this discussion in issue ? 
 From the interim : merge this , and address " extended " trial HMAC variants in a followup PR ( or extension in the ECHConfig ) . 
 Two sections suggest to ignore the extension on decryption failure , but one suggests to send an alert . What should happen ? Ignoring the extension on unrecognized failures sounds reasonable in order to " not stick out " . However , it is not entirely unambiguous what to do if a valid ECHConfig is found but decryption fails . says : says : says : 
 I think the first two statements apply when the config_digest does n't correspond to a known ECHConfig ( i.e. , " I ca n't decrypt this " ) ; the last is when the ECHConfig is known , but decryption fails ( " I should be able to decrypt this , but the ciphertext is invalid " ) . The text could be a lot clearer here . 
 Yes , your interpretation is correct . I think this is the result of a number of uncoordinated changes . 
 Closing as resolved . 
 In the current spec , the server provides no indication of whether the inner or outer ClientHello ( CH ) was used . This means the client must do trial decryption to make this determination , which creates complexity and potentially raises security concerns . As such , it would be useful to explore possible alternatives . In order to drive the discussion , I 'll provide a few simple alternatives below , which we can refine as folks provide feedback . ( The current spec , draft-07 , is listed as option ( 0 ) for comparison . ) Besides implementation complexity , one of our design considerations is ensuring that middleboxes do n't ossify on ECH . As such , indication of ECH usage should " stick out " ( see ) as little as possible . For our purposes , " do not stick out " means a middlebox who observes connections between the client and the client - facing server ca n't distinguish between real ECH and " dummy " ECH ( i.e. , a " GREASEd " extension , as described ) . We assume the middlebox does n't know the ECH configuration or the public - facing name . ( Note that this rules out adversaries such as the GFW , which can actively probe to discover this information . ) Protocol flow : On input of the client 's outer CH . If the server accepts ( i.e. , ) , it uses the inner CH ; and if the server rejects or does not support ECH , then it uses the outer CH . It proceeds with the handshake as normal , except that in case of rejection , it sends an extension in its EE with the updated configuration . On input of the server 's SH , EE , … , Finished . The client determines whether the inner CH or outer CH was used by computing the decryption key for each scenario and attempting to decrypt EE . It then proceeds with the handshake as usual , updating its configuration if applicable .   out the least . Is the least complex for servers to implement ( same for Option ( 2 ) ) .  Is the most complex for clients to implement . Spec changes : None . Protocol flow : On input of the client 's outer CH . If the server accepts , it uses the inner CH ; and if the server rejects or does not support , then it uses the outer CH . If the server accepts , then it adds an empty extension to its SH ; if the server rejects , then it adds an extension to its EE with the updated configuration ; and If the server does n't support , then it proceeds as normal . On input of the server 's SH , EE , … , Finished . If the SH has the extension , then the client proceeds as normal , assuming the inner CH was used ; otherwise , the client proceeds as if the outer CH was used , updating its configuration if applicable .  Is the least complex for clients to implement .     : the backend server must indicate acceptance in its SH but does not know whether the client - facing server accepted or not . ( We could ameliorate this problem by adding an indication of acceptance to the inner CH . ) Sticks out the most . ( See Option ( 3 ) . )  changes : Semantics of the extension changes ; changes are needed to accommodate "   " . Protocol flow : On input of the client 's outer CH . If the server accepts , it uses the inner CH ; and if the server rejects or does not support , then it uses the outer CH . If the server accepts or does not support , then it proceeds as usual ; and if the server rejects , then it adds an extension to its SH with the updated configuration . On input of the server 's SH , EE , … , Finished . If the SH has the extension , then the client proceeds as if the outer CH was used and updates its configuration ; otherwise , the client proceeds as if the inner CH was used . Decryption failure indicates either that the server does not support ( i.e. , outer CH was used ) or the connection is under attack .  Is the least complex for the server to implement ( same as Option ( 0 ) ) .   out , but only on rejection . Complicates deployment : if the client offers to a server that has turned off support for the extension , then the connection will fail hard , as the client assumes lack of signal means that was accepted . ( We could ameliorate this problem , at the cost of complexity on the client side implementation . )  changes : Semantics of the extension changes ; configuration update is sent in the clear . ( We could avoid this by sending the new configuration in a new extension in the EE . ) It may be worth considering an alternative to Option ( 1 ) that does n't stick out as much . Namely , it 's possible to make acceptance in the SH indistinguishable from rejection . 
 Thanks for writing this up ! We 've also been pondering this issue in the context of QUIC . In particular , the status quo ( option ( 0 ) ) requires the handshake and record layer coordinate to implement the trial decryption . This would need to happen separately in TLS , DTLS , and QUIC . This is especially a nuisance for QUIC as it will typically cross the TLS library ’s public API . TLS must configure two different keys for QUIC , then QUIC must do some trial decryption , and it must report back to TLS which keys were used . Public APIs and changes in them require coordination across groups , so ideally such interfaces stay as simple as possible . As in , I think an option that stays entirely in the handshake would apply to QUIC better . 
 That ( option ( 1 ) or something like it ) would be my preference as well . 
 I would prefer Option 3 , or something like it , if trial decryption is not acceptable .    proposal from March ( placing a signal in ) seems like the logical approach to me . There were about an active attack that can distinguish acceptance from rejection , but that 's still much better than a cleartext signal . 
 To clarify , I think any of ( 1 - 3 ) would avoid the QUIC issues . The deployment concerns of ( 2 ) worry me , and the extent to which ( 1 ) sticks out makes me a little uncomfortable . I 'm interested in exploring option ( 3 ) . 
 Here 's a suggestion for Option ( 3 ) , worked out by me and some folks at Cloudflare . ( Others might have had a similar idea , I do n't mean to take credit ! ) The indication is a pseudorandom value output by the HPKE state . ( If is not accepted , then a random value is used instead . ) Let denote the HPKE state shared by the client and server when is accepted . Its output can be treated as pseudorandom , e.g. , in Section 7.1 is treated as being indistinguishable from random . Protocol flow : On input of the client 's outer CH . If the server accepts , it uses the inner CH ; and if the server rejects or does not support , then it uses the outer CH . If the server accepts , then it adds an extension to its SH with as the value ; if the server rejects , then it adds an extension to its SH with a random , 16 - byte string and an " echretry " extension to its EE with the updated configuration ; if the server does not support , then it proceeds as normal , but MAY mimic rejection . On input of the server 's SH , EE , … , Finished . If the SH has the extension with payload , then it proceeds as if the inner CH was used ; otherwise it proceeds as if the outer CH was used , updating its configuration if applicable .   to Option ( 1 )   to Option ( 1 ) , but does n't stick out as much . ( It sticks out as much as the CH when dummy is used as described in Section 7.4 . )  changes : Semantics of extension changes ; adds ( i.e. , ) extension . 
 ( FWIW , I think the ServerHello . Random trick is due to or 
 Weighing in : my vote goes to something like ( 3 ) as a means of not sticking out . 
 Before I even finished reading the opening post , I was thinking ( 3 ) , so that seems like an obvious win . What this does is signals support for ECH at a server , but does n't indicate anything more . It 's an expensive way to signal a single bit , but that 's not terrible . Note that this can be used to indicate support in - principle without any config , because servers ( or stacks ) that want to join the crowd can always produce this random string . That would increase the number of servers that appear to support ECH , at very little cost . 
 I 'm pleasantly surprised by how much consensus there is for Option ( 3 ) . ( BTW , kudos to the HPKE authors for designing a really nice API ! ) Does anyone have comments on the suggestion for Option ( 3 ) above ? 
 Signalling that the server supports ECH in cleartext seems like a significant loss to me , and I think we can avoid it . For example , if the first ~8 bytes of were replaced by a MAC of the rest of the ServerHello , keyed from the HPKE context , that would be a tamperproof signal that the inner ClientHello was used . 
 This would require security analysis to be sure it 's actually safe . But beyond that , what type of adversary are you considering ? 
 Of course , if every stack produced the 16 byte extension in ServerHello , how is that materially different than 8 bytes embedded in 
  the this way is likely to violate assumptions made in existing security analyses for TLS 1.3 . suggestion might turn out to be OK , but it would be safer to stick this in our own extension . That point notwithstanding , I 'm worried about the broader precedent this could set , since overloading the semantics of and got us into trouble in earlier versions of TLS . 
 I do n't know that this is necessarily the case , but unless we need to , avoiding more use of those bits is desirable . We could run out , and with 32 bytes , that 's saying something . 
 I think what 's clear is that the trick requires analysis , whereas the SH extension variant does not . Right ? 
 I think they both need analysis , but the trick is much more invasive and likely to break things . In addition , if more " users " of the come along , then we would need to vet the interaction of our extension with theirs . ( As points out . ) 
 +1 to option 3 , and I tend to think that use of a SH extension is not a big concern . It 's correct that the extension might indicate the use of ECH . But from the perspective of a middlebox , that would always be the case when the client sends an ECH extension . Also , there would be other ways to determine if a large - scale server supports ECH ( note : ECH is about hiding a tree in the wood , so it 's about the cost of finding such woods ) . Therefore , in practice there 's marginal benefit in making the server support signal indistinguishable . 
 From I agree that analysis is needed , but I think using 8 bytes of is not a weird hack . It 's at least a well - understood hack , because it 's nicely parallel to the downgrade sentinel , and they never coexist . From TLS 1.2 middleboxes frequently take action based on the certificate , so ServerHello extensions seem likely to be used as well . If there 's a ServerHello extension , I expect that some firewall vendor will offer a checkbox labeled " Block Encrypted ClientHello " based on this extension , in the " Security " section , and some admins will turn it on without understanding what it does . If the local network is normally used to access a small set of services , and none of them support ECH yet , then this will appear to work fine , perhaps for years . Then , if one of those services tries to enable ECH , they 'll get angry phone calls from customers who can no longer access the service . For them , ECH will be ossified . For QUIC , I agree that a visible extension is OK , since it 's not too late to get it into 1.0 . For TLS , I worry that it is too late . 
 given that servers can respond with rejection even without actual ECH support , would your concern be alleviated if some servers started rejecting the GREASE ECH extensions in the near future ? 
 Hi thread , since there 's largely consensus here , I 'm going to start working on a PR for Option ( 3 ) . I 'll post it here when it 's ready . Thanks for your input ! 
 Sure , the sooner many servers become " ECH - aware " , the better . However , I expect that conservative institutional services will be very slow to update . In the extreme case , if a network is only used to access one service , then the broader ecosystem has limited direct impact . I do n't mean to claim that this ossification is inevitable , but I 'd prefer to reduce the risk if we can find a reasonable alternative . 
 Regarding your second - extension proposal above , it seems to me that there are two options here . In the one you wrote ( " echretry " ) , the second extension ( empty from the client ) is paired with the retry configs . Syntactically , this makes the retry functionality optional : a client that does n't support retry could omit the " echretry " extension . An alternative would be to pair the retries with the " ech " extension ( as in the current draft ) , and pair the context tag response with a new empty extension . I would call it " contexttag " . Syntactically , this makes the context tag functionality optional : clients that support trial decryption could omit it . I think the " contexttag " arrangement is preferable . It 's not explicitly connected to ECH , which I think makes it more likely to be implemented and less likely to be blocked . In principle , it could be used for any future situation where the cryptographic context is ambiguous . It would also give clients the option to use trial decryption in TLS / TCP , and avoid it for QUIC . ( Support would be mandatory for ECH and QUIC servers , but optional for clients . ) 
 this sounds like an alternative to Option ( 3 ) that makes the explicit indication of acceptance optional . Just so we 're on the same page , we think this is what you mean ( and I really like this idea , if this is in fact what you intend ): Protocol flow : On input of the client 's outer CH . If the server accepts , it uses the inner CH ; and if the server rejects or does not support , then it uses the outer CH . If the client requested a context tag in its : If the server accepts , then it adds an extension to its SH with as the value . if the server rejects , then it adds an extension to its SH with a random , 16 - byte string . If the server rejects , then it adds and an extension to its EE with the updated configuration . if the server does not support , then it proceeds as normal , but MAY mimic rejection . On input of the server 's SH , EE , … , Finished . If the client did n't request a context tag , then it proceeds as in Option ( 0 ) . If the client requested a context tag and the SH has the extension with payload , then it proceeds as if the inner CH was used ; otherwise it proceeds as if the outer CH was used , updating its configuration if applicable . 
 I think that 's about what I mean , but I 'm not clear on what you 're saying the client would send . Here 's what I was thinking : The extension is not changed at all from the current draft . We define a new extension : . In the ClientHello , it is empty . The response ( in the ServerHello ) contains 16 random bytes by default . If the server is using an ECH context , the value is instead . A ClientHello may contain either or both of and . The client should include in all their ClientHellos ( inner and outer , ECH and GREASE ) or none , for a given protocol ( TCP or QUIC ) . Servers that implement must also support . All other servers should support ( which is trivial ) . All QUIC servers must implement . ( Possibly not something we can specify in this draft . ) 
 This seems fine , except that it does n't make sense to offer the extension without the extension , since the response is derived from the HPKE state . I 'm suggesting that the client " requests " a context tag in its extension . In particular , there 's a flag in the extension that is " true ' if it requests a tag and " false " otherwise . Doing this in a separate extension is fine , but you would n't want to offer that extension without also offering . 
 I 'm not sure this is : I also think this formulation is clearer from the perspective of a server that does not implement ECH . BTW , here 's a variation that 's even simpler , and might work better with split mode : If the ClientHello 's is empty , the server responds with 16 random bytes . Otherwise , the server echoes the contents . The client includes an empty in the outer ClientHello , and one containing 16 random bytes in the inner ClientHello . 
 Yup , I agree ! This will be what the PR does . 
 PR is underway , I just need to revise the client and server behavior . Should be done tomorrow ! 
 Another possibility is that in the ECH message the client sends a FLAGS extension with a bunch of bits set , and the server responds with a FLAGS extension that has one of those bits set . The plaintext CH could have a superset of the ECH flags . 
 Right , that would the flags - encoded of option ( 1 ) . It does , however , stick out . 
 I thought my " plaintext CH could have a superset of the ECH flags " handled the sticking out part . 
 Oh I see . Sorry , I misunderstood . Though that seems to also stick out : you can tell by just checking the flags for the superset , etc . , rule or however we decide to encode it . 
 I 'm not pushing on this very hard , but if you grease flag - bits in the CH and pick one of those bits in the ECH . Maybe that does n't work , so I 'm willing to let this drop . 
 My model of the implementation here is that the server is made up of two components in a stack : ECH - unwrapping portion of the server can broadly be thought of as the proxy frontend , think large proxy provider pointed to by the site 's DNS has access to the ECH key and the fallback key only forwards the inner client hello to the backend service if encryption works finishes the handshake with updated ECH config with the updated key if ECH does n't decrypt can be deployed on a global edge network close to eyeballs ( even places where TLS termination is n't safe ) Backend service associated with the site certificate owner , think individual dedicated host behind proxy provider has access to private key for the certificate standard TLS 1.3 implementation , answers inner CHs or non - ECH CHs can be deployed in a hardened / trusted datacenter ( no need to put on global edge where content is n't decrypted ) could even be something like an AWS LB or other service that has no incentive to implement anything ECH - related These two components communicate over the network , or in the degenerate case , are in the same machine . My understanding is that Option ( 1 ) a ) requires there to be signaling between the front - end and the back - end , and b ) requires changes to the backend service to support ECH and the signaling This additional complexity seems hard to justify and could hinder many deployment scenarios ( especially ones we have n't thought of yet ) . What is the proposed mechanism for signaling whether an inner client hello was used or an outer client hello ? This eliminates the ability to use existing TLS stacks without modification , and on top to support a signaling layer . Option ( 1 ) seems fraught . It seems like Option ( 3 ) does not require signaling ( signaling would come in - handshake from the new extension ) , but it does require backend changes to implement the new extension . This would n't work in situations where a third party does n't have any motivation to implement ECH - related extensions , a tough loss , but not fatal . The problem here is that the combination of the presence of the client extension ( signaling client support for ECH ) and the server extensions ( signaling server support for ECH ) is going to make ECH - enabled traffic stick out from non - ECH - enabled traffic , even if dummy ECHs are sent 100 % of the time from supporting clients . The ossification risk is huge . Option ( 2 ) is my strong preference because it does n't require backend changes and does n't stick out unless ECH fails to be decrypted ( which is a degenerate case ) . 
 It seems to me that we are trading off between three things : Ability / difficulty of an adversary to determine that ECH is in use ( as opposed to that ECH is possible with a server ) Compatibility with split mode . Ease of client implementation As I understand the situation we have ( Y is good in each column ) ~ Except on rejection , for what that 's worth . Unless I misunderstand ,  's proposals are just different spellings of ( 3 ) . I do n't think anyone likes 1 so that leaves us with Current , 2 , and 3 . I 'm not that concerned about the " implementation " issues of Current , but I am quite concerned about the QUIC / DTLS issues , so I think we should strive to avoid that . That leaves us with 2 and 3 . As I understand it , the complexity issue is that if the server has turned off support for ECH entirely , then the connection will hard fail . However , with the current state of the spec I believe that this is effectively the state anyway . Here 's the relevant text : Note that authenticating a connection for the public name does not authenticate it for the origin . The TLS implementation MUST NOT report such connections as successful to the application . It additionally MUST ignore all session tickets and session IDs presented by the server . These connections are only used to trigger retries , as described in { { handle - server - response } } . This may be implemented , for instance , by reporting a failed connection with a dedicated error code . IOW , we do n't try to recover for cases where the client - facing server has just forgotten about ECH but rather where it has forgotten the ECH key . So , hard fail is actually not a problem here . I 'm similarly not worried about signaling that the server is ECH - capable ( especially in this case where it 's actually not ) . So , I think my ? under " Easy Client Impl " turns out to be a Y. With that said , I do find Option 3 aesthetically cleaner , though I 'd struggle a bit to explain why and there is an obvious appeal to not having any * public signaling in terms of being able to analyze it , though I 'm not sure how strong an argument that is . I 'm also not that worried about the sticking out piece , as I would expect that we can rapidly make a lot of servers accept and pretend do respond to grease - ECH -- which we would want to do in any case . I 'd like to hear from some other people about why they prefer ( 3 ) to ( 2 ) and whether there is some split mode - compatible variant of ( 3 ) . 
 Option ( 2 ) means ECH becomes much riskier to deploy . In options ( 0 ) , ( 1 ) , or ( 3 ) , a service can advertise ECH in the DNS and not largely panic about inconsistencies between hard - to - predict DNS cache behavior , and hard - to - predict future or present rollout decisions on individual servers . The only hard commitment is that the servers advertised in DNS are able to speak on behalf of the public name . As long as that that 's true , the client has an authenticated signal to recover from any DNS / server mismatches . In particular , if there is a problem and the service needs to roll back ECH ( or if the service was in the process of rolling out ECH and missed a few spots initially ) , the existing TLS server behavior will be correctly interpreted by the client as an authenticated rollback , and the client can recover . This is true for every TLS feature I can think of to date : it is always safe to rollback . With the exception that proves the rule being 0 - RTT , which got a note in the spec ( RFC8446 , appendix D.3 . ) to describe client behavior to restore safety . Option ( 2 ) breaks this invariant . 
 Sorry , I had misread the specification and I agree with you . To recap for those following at home presently the client 's algorithm is : It 's point 4 that is relevant here . I had read the spec as requiring a hard failure , but it in fact recovers . That pushes me more towards ( 3 ) . 
 I believe I described one above . I 'll rephrase , in case it was unclear : is an extension that appears in ClientHello and ServerHello . If the ClientHello contains a with empty contents , the server replies with a containing 16 random bytes . Otherwise , the ServerHello 's echoes the contents of the ClientHello 's . The client includes an empty in the outer ClientHello , and a containing 16 random bytes in the inner ClientHello . 
 this is only partially split - mode compatible in that it requires changing every origin server . It just does n't require coordination between the servers . 
 True ! For any extension implementing Option 3 , I think we want those changes anyway . If a ServerHello extension is only implemented by ECH terminating servers , then its presence distinguishes real ECH from GREASE . If it 's widely implemented , then that signal is diminished . Alternatively , we could say that the new extension is only for QUIC , and make TLS / TCP stick to trial decryption . 
 Sure . I 'm comparing it to ( 2 ) . 
 Hi all , see PR for our proposal for Option ( 3 ) , with improvements incorporated . The main points : The client may request confirmation of ECH acceptance ( Option ( 3 ) ) , but the default behavior is Option ( 0 ) . Acceptance is indistinguishable from rejection , which is the primary motivation for choosing Option ( 3 ) over Option ( 1 ) .   works for Option ( 3 ) , but the backend server needs to support ECH . ( All it has to do is echo an extension sent by the client - facing server . ) There 's no change to the backend if confirmation is n't requested . 
 I do n't understand why this is better than ( 3 ) . Wo n't every client just send ech_confirm , in which case this is isomorphic to 3 ? 
 Option ( 0 ) sticks out less than option ( 3 ) , which is why a client might opt to not send " ech_confirm " . 
  ... I think there should be away to resolve the deployment issues between ( 2 ) and ( 3 ) . Will post on Monday . 
 ( 3 ' ) This seems strictly worse than either ( 0 ) or ( 3 ) . We 'll have an odd mix of people doing one or the other and every server will have to do and test both . 
 You 're suggesting that confirmation SHOULD NOT be optional , correct ? I 'm Ok with this , but it seems to me that it 's not especially complicated to implement this correctly on the server side . The hard bit is the client , since it has to do trial decryption . I 'd like to drill down on the problem of rolling back ECH . The essence of the problem is that an ECH server that advertised a configuration in the past must support ECH for as long as that configuration is valid . What are some " bad " events that may lead to this contract being violated ? The ECH secret key has been compromised , so the service needs to be shut off until a new key is rolled . In the meantime , the service can explicitly reject ECH without providing a new configuration . The client would take this as a signal of ECH being disabled by the server . A bug is found somewhere in the TLS stack , and the quick fix is to revert to a point before the ECH code was committed . This is definitely a risk , but I wonder if there are ways to mitigate it . For example , if the configuration is valid for the next hour , say , then we must delay the rollback until the hour has lapsed . Alternatively , we can roll - back right away , and when the client aborts because of decryption failure , it might make a DNS query to see if ECH support has been turned off . 
 I agree that the first issue is fine by option ( 2 ) . ( Though probably the mitigation would be to roll out a new key . One hopes that pipeline is already built out and regularly exercised by routine key rotation . ) I 'm worried about the second one , but I think the characterization is too simple . TLS implementations are part of a complex system , both within the service and on the internet as a whole . Complex systems break unpredictably . Maybe it 's a TLS bug . Maybe ECH inadvertently broke some assumption in some other part of the stack . Maybe some large client had a bug that only triggered due here to some quirk of the server . Maybe some printer happened to be and now breaks . Maybe it had nothing to do with TLS at all , but some other concurrent server change broke and the entire release needs to be rolled back . Anything which interferes with the default response ( rollback to a known good configuration ) is expensive and risky . This risk needs to be communicated across a long game of telephone from ... the people who wrote the ECH to spec , to ... the people who implemented it in the TLS library , to ... the people who integrated it into some server software , to ... the people who perhaps packaged the server software into some OS release , to ... the people who perhaps shipped the OS release in some server appliance , to ... the people who manage the rollout of the change in some deployment , to ... the people who noticed a failure in a faraway system and are trying to mitigate it This is not practical , especially if we want ECH to be widely adopted . To the alternatives you list , when things go wrong , the priority is to get the service working again . Leaving it broken until the ECH config expires is thus not great . Moreover , expiry itself is a property of a complex system ( DNS ) , so it may not be clear when it actually expires . Mandating a client retry on decryption failure is more plausible ( compatible with rollback ) , but it relies on caching properties of the DNS , which is where much of the deployment mismatch risk comes from in the first place . 
 Can you elaborate on this issue a bit more ? Suppose the DNS and ECH provider are the same entity , and suppose that entity can synchronize the DNS response with the rollback . I guess one potential pitfall is that the client could use a DNS response cached by its operating system ? Any others ? 
 That 's a simplifying assumption and does n't always hold . Even within an enterprise , it 's not uncommon for the DNS folks to be a separate group from those running the webservers . 
 Even when they are the same entity , I do n't think synchronizing the DNS response with the rollback is meaningful . As you note , the OS has a cache . The client may have a cache in front of that . The recursive resolver may have a cache . There are probably other caches in various DNS middleware . There is also no guarantee that the same server instance and will serve the client 's DNS query and the client 's TLS connection , which means that during the course of a rollout or rollback , there will be mismatches . 
 caches all the way down ! 
 Er , by " mismatch " here , I mean that the client will see DNS and TLS configs from different generations . If a very careful server operator carefully controls changes based on TTLs and deployment times , they may be able to arrange for all observed cross - generation configs to be compatible . ( And indeed they should arrange for TLS servers to know about ECH keys before advertising them , etc . ) But this is the careful , happy case , not a failure recovery case . 
 Very true , and I do n't think we should assume this is the case . I think ( 3 ) is the best option for many deployments , but there are use cases for which ( 2 ) is much better , assuming the server can manage the DNS / TLS synchronization complexity . It might be worth exploring a hybrid approach : in its ECHConfig , the server might indicate what it confirms : acceptance a la ( 3 ) , or rejection al a ( 2 ) . The main concern I have with ( 2 ) is that the client needs to evict its cache before making the DNS request , and I 'm not sure how platform - dependent this behavior is . 
 The client ca n't evict the recursive resolver 's cache . I 'm not sure if even the OSes provide APIs to clear caches . ( I do n't see an obvious flag to pass into . ) We also should not have two different spellings of the same thing in the protocol . It is complex enough as it is . 
 So the only way to safely rollback for option ( 2 ) is to wait until the DNS record expires . Does anyone have a sense of the degree to which clients respect the record 's TTL ? Google measured clock skew among  clients years ago and found it was pretty dismal . Is the state of affairs any better today ? In any case , counting on clients to get DNS right appears to be risky . If we go with ( 2 ) , then it seems the best option on the table so far is to use trial decryption to distinguish between ECH acceptance and ( the unlikely case of ) ECH rollback . Let me make one more pitch for ( something like ) option ( 2 ) . As pointed out , we have largely ignored a potentially important " do n't stick out " consideration . The goal of ( 3 ) is to make connections from a real ECH client to an ECH server look like connections from a dummy ECH client ( i.e. , one that sends a GREASEd extension ) to an ECH server . A property that ( 0,2 ) have that ( 1,3 ) do n't is that connections from a real ECH client to an ECH server look like connections from a dummy ECH client to a non - ECH server . In other words , options ( 1,3 ) do n't provide covertext for non - ECH servers , whereas ( 0,2 ) do . ( ECH rejection sticks out for ( 2 ) , but the happy path does n't . ) Do we regard this as a risk to deployment ? 
 If we do that , we have n't addressed this issue . If clients still need to implement trial decryption for one case , however unlikely , we 're still paying for it and there 's no point in building a separate thing . How common a codepath is affects performance considerations , but not complexity considerations . The issue with trial decryption is complexity , not performance . ( Trial decryption also breaks some in - place decryption strategies , so there can be a performance concern too , but it 's just one record so I 'm not concerned about that . ) Right , I think this is the vs. new extension question for ( 3 ) . Sticking the indicator in makes the full cross product of { ECH - client , GREASE - client } x { ECH - server , non - ECH - server } look the same , provided the server supports TLS 1.3 . This is nice , but it 's a weird one - off trick we ca n't do again . Sticking the indicator in a new extension also makes the same cross product look the same , provided the server supports TLS 1.3 and has been updated to send this extension . It can send this extension independent of ECH support , but it 's not a thing anyone does today because the extension does n't exist , so the deployment curve will be different . In contrast , ( 2 ) is missing coverage . It makes the following tuples look the same : ( ECH - client , ECH - server ) , ( ECH - client , non - ECH - server ) , ( GREASE - client , non - ECH - server ) . It misses ( GREASE - client , ECH - server ) . In particular , clients may be ECH - capable ( and thus know to send GREASE extensions ) but not configured with a DoH resolver and unable to get HTTPS records over Do53 ( either due to cleartext problems or ossification ) . 
 Agreed , I 'm just reiterating that we have n't solved the problem with ( 2 ) if we ca n't solve the problem with client - side DNS . 
 do you expect clients to send GREASE on all connections or only connections for which DoH is available ? If you expect clients to send a dummy ECH in situations where the ECHConfig is potentially unavailable , do you expect the server to send ECHConfig back in the handshake and the client to restart the handshake ? That seems like a pretty big performance hit . 
 I think they should send it for all connections . That was a big part of the motivation . No , clients do n't process retry configs on GREASE connections . Possibly the spec should be clearer here . The intent is that this is a different mode altogether . ( Edit : filed ) That was an intentional limitation in at least the first iteration of the retry flow . Picking up a retry config without a DNS lookup is odd for several reasons . As you note , there is a performance penalty to the retry . More importantly , the client has already leaked the name at that point . It 'd really only be useful for subsequent connections and the text intentionally only applies the retry to one connection attempt . Trying to solve it for subsequent connections would be interesting , but there are several nuisances to resolve : State is a tracking vector . This is easy enough to address — adjust the scope of the state to meet your privacy goals , same as resumption itself — but we 'd need to discuss it and reducing scope also reduces effectiveness . Remembering TLS - level state , rather than SVCB- or      state breaks the multi - CDN story . ( At the time this text was written , we had n't even figured out the multi - CDN story . ) Even if the retry keys contained a full SVCB record , one CDN wo n't know the config of the other CDN , so it ends up being a CDN pin , which seems awkward . Any cache for subsequent connections needs to deal with the larger lifetimes necessary for effectiveness ( see ) Given all that mess , I omitted it from the PR when proposing this mechanism and figured we 'd think about these issues later if the WG wanted to pursue a non - DNS flow . 
 The DNS expiration complaint seems like overthinking a bit . Step 1 : Update Registry to remove DS Step 2 : Wait until DNS caches expire Step 3 : Remove zone  ( KSK , ZSK , RRSIG , etc . ) This is done pretty frequently , and the servers take the risk of the site having an outage if the client has record synchronization issues . In fact , RRSIG records have explicit expiration times , which makes them less flimsy with respect to expiration . If we follow the lead of RRSIG and add an expiration time to ECHConfig , then we 're only relying on clock synchronization during rollover rather than DNS cache expiration . How about : 1 ) add a time box to the ECHConfig record 2 ) recommend only sending GREASE in the same situations as 10.2 . describes : when you expect to reliably get the ECHConfig record if it exists ( i.e.  or DoH ) 
 I think this is not quite right . When all RRSIGs in the zone are expired , , not . In other words , DNSSEC fails hard when the validation expires , and relies on caches to respect TTL . This is a security feature to prevent an attacker from resurrecting expired data . This arguably supports your overall argument , but not your proposed mitigation . From this discussion , it sounds like trial decryption ( Option 0 ) is only modestly inconvenient for TLS / TCP . If so , that makes me think that we should focus on a simple , separate Option 3 extension only for QUIC , and keep TLS / TCP at Option 0 . 
 Hi folks , in order to help drive the discussion , I 've created PRs for the options currently being discussed . : option ( 3 ) , but incorporates various changes and improvements . : based on , but with fallback to option ( 2 ) . In case option ( 3 ) sticks out too much and gets blocked , then we can fall back to option ( 2 ) at the cost of deployment complexity . : based on , but the indication of acceptance appears in the instead of a new SH extension . This stick out less than ( 3 ) , but requires security considerations . Based on the discussion on , most people seem to not favor supporting this behavior . 
 Hi all , a quick update for those who have n't been following the proposals : adds an explicit confirmation of acceptance as an extension to the SH . is the same as , except the server can opt to only explicitly confirm rejection . adds an explicit confirmation of acceptance by hijacking It seems that consensus is coalescing around because it minimizes deployment coimplexity and sticks out less than . The open issue for this change is security . and I reached out to a variety of people who have worked on security proofs of TLS 1.3 to see how this change might impact their analysis . While this change is significant enough to requires generating fresh proofs , no one expects it to lead to an attack if the confirmation string is sufficiently short . The current proposal uses the last 8 bytes of the , which leaves 24 bytes of entropy to ensure uniqueness of the session i d. I discussion of this point to the PR ... it would be helpful to get more eyes on this . 
 2 and 3 talk to the same PR ? ( edited to remove the email cruft ) 
 Oops , fixed ! 
 To follow up on the comment I made at the mic and then decided did n't work . Assuming we accept PR , and decide the CHInner . Random is secret then can we just say that the ESNI accepted signal is to have the low order bytes of SH.Random be derived from CHInner . Random ( copied might work , but hashed would make me feel better ) . I have n't done any real analysis of this , but it seems like it would not permit an attacker who does not know CHInner . Random to determine whether ECH was accepted . 
 I think we should consider a construction like , i.e. to make the tag dependent on the rest of . This would at least partly address concern about replays . 
 I do n't see the replay concern as important , since all it does is reveal if ECH was used . There are easier ways for an attacker to learn this information . In fact , it does n't need to interfere with the connection at all : all it needs to do is learn the ECH configuration . I think it 's best to keep the mechanism as simple as possible . In particular , I 'd like to do everything we can to not increase the requirements for the backend server in   . Of course , if there is an attack that violates the intended security goal of ECH ( confidentiality of CH extensions ) , then we should take that seriously . But I do n't think this change ( i.e. , ) increases this risk compared to the status quo . 
 These attacks are n't part of our core threat model , but it seems like we have an opportunity to defeat some or all of them at low cost , so I think we should consider doing so . This is true in the main deployment models we 're discussing , but I can also imagine use cases where the ECHConfig is not available to the attacker . 
 That does n't work . The attacker just needs to replay the entire server random . If you want protection you need to mix in the server 's key share . 
 If we 're going to go down this road , then I think we need to take a step back and think about our " do n't stick out " threat model in more detail . Currently our requirement is that a passive observer , who does n't know the configuration , is unable distinguish real ECH usage from the " cover traffic " provided by clients who " GREASE " the ECH extension . The attackers mentioned so far are active and may know the config . So let 's start here : do we anticipate an attacker this powerful ? So far we 've mostly been talking about " do n't stick out " in terms of dumb middleboxes that we do n't want ossifying on our extension . The current threat model captures this pretty well , I think . If we want to go for something stronger , then we clearly need to re - think the design of ( or decide we should n't do it ) . Something to keep in mind is that indistinguishability of the " real " protocol from some " cover " protocol is a property that TLS was never designed to have . It seems to me that the task of endowing TLS with some sort of stegonagraphic security property goes way beyond this one extension . It 's an interesting and valuable goal , but one that should be addressed in a more general way . For ECH , I think we should focus our efforts on coming up with a design that we feel we can deploy today , and iterate and re - deploy as needed . 
 I agree with that there is value in simplicity . A really stealthy ESNI would be a different design than ECH . 
 +1 -- ECH is not about censorship circumvention , or being stealthy . 
 you should maybe expand a bit on that . If you are not trying to defeat some form of censorship , then why are you hiding the SNI in the first place ? 
 The problem I 'm focusing on is an " attack " so trivial it could almost happen by accident . If a ClientHello is issued twice , verbatim , and elicits two independent ServerHellos , an observer can see whether the last 8 bytes of .Random are the same in both responses . This might happen sporadically to DTLS or QUIC in some configurations , even without an active attacker . The formula I proposed above avoids this repetition . If we 're going to use a hash , as EKR suggested , this calculation seems like a pretty natural way to do it . I definitely do n't want to slow down progress , and I 'm not proposing that we substantially expand our threat model . I do think closing trivial attacks has some value even if more advanced ones still exist . For example , the other attacks may be more difficult or less deniable . 
 Censorship is , for example , active blocking of a connection based on the name , whereas ECH hides SNI ( and other things ) from those that just passively snoop and try to learn about clients . 
 EDITED TO FIX PROPOSAL 3 . I agree that it would be worth mitigating this attack , as long as the mechanism is n't too complicated . Let 's consider the " replay protection " properties of the current proposals . Suppose the attacker wants to learn if a client offered ECH , so it replays the ClientHelloOuter to the server . Here are the proposals ( please chime in if I got this wrong ! ) proposal : proposes : proposes : where is something like . ( Though since the ikm is a random string , I think it would suffice to just call . ) Neither 1 nor 2 mitigates the attack , but 3 does . All options " stick out " the same if the ClientHelloInner is known , e.g. , if the adversary is on - path from the client - facing server to the backend server . Incidentally , proposals 2 and 3 are an improvement over 1 since we do n't have to send an extension in the ClientHelloInner . On the down side , the backend server needs to know how to instantiate , i.e. , it needs to know the HPKE cipher suite . We could get around this by using the hash from the TLS cipher suite . 
 In this shorthand , my proposal is more like . This avoids the leak that you identified . 
 Ah , you 're right . My apologies ! Fixing above . 
 I 'd be fine with 2 or 3 , though we should use the TLS cipher suite instead of the HPKE cipher suite so that the backend server does n't need to know the latter . 
 proposes My proposal would be : The rationale is that merely hashing the reminder of the server random is insufficient . The attacker could just do the attack I delineated in issue by copying the whole instead of just copying . But if you mix the server key share in the hash , then the attacker can not do that without also copying a key share for which the private key is unknown . 
 EDITED AFTER DISCUSSION WITH  that . Here 's what we have on the table : : Let 's instantiate with , where is for the TLS cipher suite ( and not HPKE ) . Proposal 1 and 2 are for the status - quo threat model , i.e. , the " do n't stick out " distinguisher is passive ; proposal 3 provides additional " do n't stick out " protection in case the CH is replayed ; and proposal 4 improves on 3 by providing some protection against manipulation of the SH . My preference is proposal 2 , since it simplifies the extension . I would be fine with 3 or 4 , though I 'm not convinced that either fully addresses the stronger threat model . 
  , on second thought I 'm not so sure how much simpler 2 is than 1 . The ClientHelloInner would still have to carry some sort of indication of ECH acceptance so that the backend server knows to confirm . But an empty " encryptedclienthello " extension ( or maybe a new code point ? ) would do just fine . Something weird about 4 is that the backend server has to wait to finish the until it generates a key share . This might add a bit of complexity , though it depends on the code base . 
 Yes , incorporating the key share is more complex . But let 's look at what we are doing , replacing trial decryption by a hint . Trial decryption generates complexity , especially in the QUIC mapping , but the result is unambiguous and hard to fool . The client knows for sure whether the key was generated from the inner CH or the outer CH , and it is very hard for third parties to partially fool the client . The hint introduces another failure mode , i.e. wrong hint value , and I believe it can be exploited . For protection , the code has to be almost as hard to fool as trial decryption . That 's what I am trying to achieve by incorporating the server key share in the mix . There are of course implementation issues . The server has to know what key share it will use before generating . That may or may not be easy to do , depending on implementation . The value do not depend on the value , so this is definitely possible . But the code path depends on the implementation , and it may be more difficult for some stacks than for others . 
 HI all , I a commit to that implements suggestion . Specifically , ( i.e. , the last 8 bytes of is computed as ~ where HKDF - Extract and HKDF - Expand - Label are as defined in RFC8446 . Doing Extract - then - Expand ensures that we do n't run into any issues with the length of the not matching the in the TLS stack . Please have a look to make sure it 's spelled correctly . 
 adds a " tls13 " prefix to the label , so I think you can shorten the label . I agree , we need for ( e.g. SHA-512 ) . Given the need for , it would seem more natural to me to put in the extraction salt , and use instead of . 
 Good call !  . This reminds me that we need to do a pass of the spec to ensure all the constants have the same structure . I disagree . In any case , the salt being bytes long avoids indifferentiability issues [ 1 ] . What does this buy us ? [ 1 ] 
 I 'm not familiar with that paper , but Section 4.3 seems to say that HKDF is suitably indifferentiable without any such restriction on the salt length . Using HKDF - Expand instead of HKDF - Expand - Label would seem to make use of fewer , better - analyzed constructions , but I 'm not aware of a practical difference , so if HKDF - Expand - Label is more convenient to implement for some reason then that seems like enough justification . 
 There are many " safe " salt lengths . I 'm not sure 24 is " safe " , but I know is . I do n't think one is any harder than the other . The only difference between them is that exposes an additional parameter , which I think aligns a bit better with what we 're doing here . If you 'd like to keep pushing for these changes , then please follow up by making a comment on the PR . 
 I appreciate the safety concerns , but you are going to extract an 8 bytes hint from the hash . That 's a serious step down from 32 or even 16 bytes , and with such a short length I would be really surprised if two different hash constructs resulted in any security difference ! 
  , yeah . We need the 8 bytes to be pseudorandom , and I think the current design is defensible from a provable security perspective . We may be able to do a bit better . What do you think of this , This is valid as long as = 24 , which I believe is guaranteed by RFC8446 . 
 That 's fine with me , although I 'm not sure why you need to pad the salt . ( HKDF - Extract will pad it for you . ) 
  that . Are you happy with this 
  , looking at RFC5869 , it 's not clear to me that the salt is padded by this function . I think I prefer the following : 
 Updated with this change . 
 I think that 's a fine implementation of the suggestion made by . I am waiting for the resolution of the " do n't stick out " issue on the TLS mailing list . 
 The decision in today 's interim meeting is to merge as - is and reconsider the " do n't stick out " threat model later on . In particular , we wo n't be adopting Karthik 's suggestion from the mailing list for this PR . also pointed out that it could be done as an ECH extension . 
 Closing now that landed .
Paragraph (version B):
TLS padding RFC7685 (see padding).
Paragraph (version A):
As described in server-behavior, the server MAY either accept ECH and
use ClientHelloInner or reject it and use ClientHelloOuter.  However,
there is no indication in ServerHello of which one the server has
done and the client must therefore use trial decryption in order to
determine this.
Paragraph (version B):
As described in server-behavior, the server MAY either accept ECH and
use ClientHelloInner or reject it and use ClientHelloOuter.  In
handling the server's response, the client's first step is to
determine which value was used.  The client presumes acceptance if
the last 8 bytes of ServerHello.random are equal to
"accept_confirmation" as defined in backend-server-behavior.
Otherwise, it presumes rejection.
Paragraph (version A):
Compare ClientEncryptedCH.config_id against identifiers of known
ECHConfig and choose the one that matches.
Paragraph (version A):
Use trial decryption of ClientEncryptedCH.encrypted_ch with known
ECHConfig and choose the one that succeeds.
Paragraph (version A):
Some uses of ECH, such as local discovery mode, may omit the
ClientEncryptedCH.config_id since it can be used as a tracking
vector.  In such cases, trial decryption should be used for matching
ClientEncryptedCH to known ECHConfig.  Unless specified by the
application using (D)TLS or externally configured on both sides,
implementations MUST use the first method.
Paragraph (version A):
It MUST include the "encrypted_client_hello" extension with the
"retry_configs" field set to one or more ECHConfig structures with
up-to-date keys.  Servers MAY supply multiple ECHConfig values of
different versions.  This allows a server to support multiple
versions at once.
Paragraph (version B):
Compare ClientECH.config_id against identifiers of known ECHConfig
and choose the one that matches.
Paragraph (version B):
Use trial decryption of ClientECH.encrypted_ch with known
ECHConfig and choose the one that succeeds.
Paragraph (version B):
Some uses of ECH, such as local discovery mode, may omit the
ClientECH.config_id since it can be used as a tracking vector.  In
such cases, trial decryption should be used for matching ClientECH to
known ECHConfig.  Unless specified by the application using (D)TLS or
externally configured on both sides, implementations MUST use the
first method.
Paragraph (version B):
It MUST include the "encrypted_client_hello" extension in its
EncryptedExtensions with the "retry_configs" field set to one or
more ECHConfig structures with up-to-date keys.  Servers MAY
supply multiple ECHConfig values of different versions.  This
allows a server to support multiple versions at once.
Paragraph (version A):
Note that an unrecognized ClientEncryptedCH.config_id value may be a
GREASE ECH extension (see grease-extensions), so it is necessary for
servers to proceed with the connection and rely on the client to
abort if ECH was required.  In particular, the unrecognized value
alone does not indicate a misconfigured ECH advertisement
(misconfiguration).  Instead, servers can measure occurrences of the
"ech_required" alert to detect this case.
Paragraph (version B):
Note that an unrecognized ClientECH.config_id value may be a GREASE
ECH extension (see grease-extensions), so it is necessary for servers
to proceed with the connection and rely on the client to abort if ECH
was required.  In particular, the unrecognized value alone does not
indicate a misconfigured ECH advertisement (misconfiguration).
Instead, servers can measure occurrences of the "ech_required" alert
to detect this case.
Paragraph (version A):
Client-facing server configuration determines the size of the
anonymity set.  For example, if a client-facing server uses distinct
ECHConfig values for each host, then each anonymity set has size k =
maximize the size of the anonymity set where possible.  This means
client-facing servers should use the same ECHConfig for as many hosts
as possible.  An attacker can distinguish two hosts that have
different ECHConfig values based on the ClientEncryptedCH.config_id
value.  This also means public information in a TLS handshake is also
consistent across hosts.  For example, if a client-facing server
services many backend origin hosts, only one of which supports some
cipher suite, it may be possible to identify that host based on the
contents of unencrypted handshake messages.
Paragraph (version B):
Client-facing server configuration determines the size of the
anonymity set.  For example, if a client-facing server uses distinct
ECHConfig values for each host, then each anonymity set has size k =
maximize the size of the anonymity set where possible.  This means
client-facing servers should use the same ECHConfig for as many hosts
as possible.  An attacker can distinguish two hosts that have
different ECHConfig values based on the ClientECH.config_id value.
This also means public information in a TLS handshake is also
consistent across hosts.  For example, if a client-facing server
services many backend origin hosts, only one of which supports some
cipher suite, it may be possible to identify that host based on the
contents of unencrypted handshake messages.
Paragraph (version A):
Optional configuration identifiers may be useful in scenarios where
clients and client-facing servers do not want to reveal information
about the client-facing server in the "encrypted_client_hello"
extension.  In such settings, clients send either an empty config_id
or a randomly generated config_id in the ClientEncryptedCH.  (The
precise implementation choice for this mechanism is out of scope for
this document.)  Servers in these settings must perform trial
decryption since they cannot identify the client's chosen ECH key
using the config_id value.  As a result, support for optional
configuration identifiers may exacerbate DoS attacks.  Specifically,
an adversary may send malicious ClientHello messages, i.e., those
which will not decrypt with any known ECH key, in order to force
wasteful decryption.  Servers that support this feature should, for
example, implement some form of rate limiting mechanism to limit the
damage caused by such attacks.
Paragraph (version B):
Optional configuration identifiers may be useful in scenarios where
clients and client-facing servers do not want to reveal information
about the client-facing server in the "encrypted_client_hello"
extension.  In such settings, clients send either an empty config_id
or a randomly generated config_id in the ClientECH.  (The precise
implementation choice for this mechanism is out of scope for this
document.)  Servers in these settings must perform trial decryption
since they cannot identify the client's chosen ECH key using the
config_id value.  As a result, support for optional configuration
identifiers may exacerbate DoS attacks.  Specifically, an adversary
may send malicious ClientHello messages, i.e., those which will not
decrypt with any known ECH key, in order to force wasteful
decryption.  Servers that support this feature should, for example,
implement some form of rate limiting mechanism to limit the damage
caused by such attacks.
Paragraph (version B):
To signal acceptance, the backend server overwrites 8 bytes of its
ServerHello.random with a value derived from the
ClientHelloInner.random.  (See backend-server-behavior for details.)
This behavior increases the likelihood of the ServerHello.random
colliding with the ServerHello.random of a previous session,
potentially reducing the overall security of the protocol.  However,
the remaining 24 bytes provide enough entropy to ensure this is not a
practical avenue of attack.
Paragraph (version B):
On the other hand, the probability that two 8-byte strings are the
same is non-negligible.  This poses a modest operational risk.
Suppose the client-facing server terminates the connection (i.e., ECH
is rejected or bypassed): if the last 8 bytes of its
ServerHello.random coincide with the confirmation signal, then the
client will incorrectly presume acceptance and proceed as if the
backend server terminated the connection.  However, the probability
of a false positive occurring for a given connection is only 1 in
2^64.
Paragraph (version B):
Note that the same bytes of the ServerHello.random are used to
implement downgrade protection for TLS 1.3 (see RFC8446,
Section 4.1.3).  The backend server's signal of acceptance does not
interfere with this mechanism because ECH is only supported in TLS
1.3 or higher.
Paragraph (version B):
This design requires servers to decrypt ClientHello messages with
ClientECH extensions carrying valid digests.  Thus, it is possible
for an attacker to force decryption operations on the server.  This
attack is bound by the number of valid TCP connections an attacker
can open.