New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
GREASE ESNI extensions are easily distinguished from real ones #177
Comments
Mostly a note to myself for the actual PR: the draft should also discuss padding of the EncryptedExtensions message. |
I think we really need to go back to first principles here and ask what it is we are trying to accomplish. First, it's public information whether a given server supports ECHO, so if an attacker wants to know that, it can mostly just ask [there is some complexity around getting candidate names, but note that you can always get the public name from the SNI value and any real attacker will see a lot of non-ECHO traffic and so will know a bunch of SNI values]. What's not public information is whether a given connection uses ECHO. The attacker might not know this either because:
In case (1) I would also expect that the attacker is not going to go to the trouble of doing probe connections, as determining if the server is ECHO supporting is easier. This leaves us with the case where the attacker knows that the server is ECHO supporting and that the client knows about ECHO (otherwise it couldn't generate GREASE) but doesn't know if the client is actually doing ECHO. Do we expect there to be a lot of clients like this? Why not just do ECHO? |
As per today's call, we're going to revisit the GREASE threat model and then reconvene if further work is needed. |
I'm moving to closes this issue as resolved by #235. If we need to do something against connection blocking adversaries, perhaps we should look into MASQUE for that. |
Closing for now. @davidben, please re-open if you still think we should address this! |
The trial decryption mode is specified oddly. It says to use trial decryption, but the process following it only works in the config_id mode (it says decryption failure is fatal). It also behaves differently because decryption failure is an ECH rejection rather than a fatal error. Unify them by instead saying the server gathers a (possibly singleton) set of candidate ECHConfig values and then tries them in succession. Note this aligns the config_id mode's error handling with the trial decryption mode, since the other direction is not possible. (So it goes the other direction on tlswg#290.) This should tidy up the oddity in tlswg#339 (comment), and meshes well with GREASE and ClientHelloOuterAAD.
The draft has provisions for GREASE ESNI extensions, per "Do not stick out". However, this is not very effective if an attacker can distinguish a GREASE ESNI extension from a real one.
#154 tried to address this, but it doesn't work if the (public) ESNI record is known. There's also a simpler attack: replay the ClientHello with one byte of ciphertext corrupted. ESNI currently distinguishes key mismatch from decrypt failure, with the latter resulting in an alert. We can fix that by saying decrypt failure should behave like key mismatch. This still leaves record_digest.
The natural fix is to drop record_digest in favor of trial decryption. The cost is the server must perform a DH operation per known key. The number of keys the server needs depends on its DNS TTLs and key rotation. (I think it's 1 + ceil(dns_ttl / time_between_rotation), plus some leeway[*].)
Instead, we can keep a key name, but make the space dense. Suppose we replace it with a B-bit "key phase". The server picks a random starting key phase. Then, each time it rotates the keys, it increments the phase, with wraparound. The server then gets 2B keys for free. If it needs more, it still needs trial decryption but gains a 2B multiplicative factor in the cost. On the flip side, an individual GREASE extension with a random key phase has a 1/2B chance of colliding with a particular ESNI key.
I'm not sure we actually need that many live keys, so B = 2 is probably plenty. Or even B = 1 if we say you should just rotate slower than your DNS TTL.
[*] Note the robustness mechanism means that server doesn't need to cover all clients with stale keys. The retry is expensive, so the server still needs to cover almost all of them, but it can cut off the long tail.
The text was updated successfully, but these errors were encountered: