ECH will be GREASEd. To prevent those who might want the capability to stop ECH in the future from getting a head start while it's uncommon, implementations would always pretend to be doing it anyway.
So talking to any TLS server, even one that has no idea about ECH, the client says basically "Hi, here is a normal unencrypted TLS 1.3 Hello message for this.server.example, also, here's an Encrypted Client Hello message". If the server actually does offer ECH, there could be a real Client Hello, perhaps addressed to another.server.example, encrypted inside the Encrypted Client Hello, but if not there's just random noise. An eavesdropper doesn't have the key, so they don't can't tell which is the case.
Obviously if your server can't do ECH, the Encrypted Client Hello is just a mysterious unintelligible extension with noise inside it, no further inspection needed.
And in some setups the server knows how to tell easily which key would have been used for any valid ECH, so if that key doesn't work then it was just noise, and can be ignored.
But in other cases the server knows two or more keys that might be valid, yet the client either can't or has chosen not to be open about which (if any) was used, so the server has to try them all until it finds out.
This is Section 10.4 of the current draft:
In GPG:
/* if KeyID is empty... */
if (!k->keyid[0] && !k->keyid[1])
{
log_info (_("anonymous recipient; trying secret key %s ...\n"), keystr (keyid));
}
err = get_it (ctrl, k, dek, sk, keyid);
k->result = err;
if (!err)
{
/* If get_it() succeeds */
if (!opt.quiet && !k->keyid[0] && !k->keyid[1])
{
log_info (_("okay, we are the anonymous recipient.\n"));
}
}
And in get_it()... if (sk->pubkey_algo == PUBKEY_ALGO_ECDH)
{
/* Now the frame are the bytes decrypted but padded session key. */
if (!nframe || nframe <= 8
|| frame[nframe-1] > nframe)
{
err = gpg_error (GPG_ERR_WRONG_SECKEY);
goto leave;
}
}
else
{
if (padding)
{
if (n + 7 > nframe)
{
err = gpg_error (GPG_ERR_WRONG_SECKEY);
goto leave;
}
}
if (n + 4 > nframe)
{
err = gpg_error (GPG_ERR_WRONG_SECKEY);
goto leave;
}
if (dek->keylen != openpgp_cipher_get_algo_keylen (dek->algo))
{
err = gpg_error (GPG_ERR_WRONG_SECKEY);
goto leave;
}
/* Copy the key to DEK and compare the checksum. */
csum = buf16_to_u16 (frame+nframe-2);
memcpy (dek->key, frame + n, dek->keylen);
for (csum2 = 0, n = 0; n < dek->keylen; n++)
csum2 += dek->key[n];
if (csum != csum2)
{
err = gpg_error (GPG_ERR_WRONG_SECKEY);
goto leave;
}
}
You get the idea.BTW, did I just "break GPG encryption and deanonymize users" according to Cellebrite because I found the correct function in the code? And no, I didn't "review dozens of code classes", I just grepped the word "anonymous"... /s
So maybe more like the person who works the key cloning machine at the hardware store.