Code change:
The intent was that the server always sends the retry keys (it cannot distinguish stale keys from GREASE when the client is actually trying to connect to the public name), while the client just ignores them, but I did a poor job of describing this, so add a key sentence. This addresses .
(EDITED.) To recap the discussion on , your point is that the client-facing server needn't attempt to distinguish GREASE from non-GREASE based on outer SNI, because if the outer SNI != public name, then the client knows to ignore the retry config and continue as usual. I think this is weird because if rejection was the intent, then the client is supposed to abort with "ech_required". So the server only knows that non-GREASE was intended once it receives this signal.
I mean, yeah, that's how this was designed and is what we merged to the spec. :-) This formulation, in particular, does not break if the client tries to connect to the public name (it's a perfectly valid URL) without knowing the ECH config (maybe it the HTTPS record didn't get through Do53) but still sends GREASE (because the intent is that every client can GREASE). It seems to me breaks this. Do you have an alternate formulation which keeps this working? Connecting to the public name is especially important if the public name is a non-throwaway domain. The only requirement on the public name is that it's some name which knows about and serves the client-facing server's config. (I.e. this particular backend server is the same entity as the client-facing server.) doesn't relax this requirement, since the public name continues to be the entity trusted to replace, and possibly disable, ECH on config mismatch.
I don't see this as an issue. If the client sends GREASE, it doesn't expect to use ECH, so it won't abort. The text here only requires that the client check the extension if present, and ignore it if absent.
I don't have an alternative formulation. I was evnisioning the public name only being verified on the ECH rejection path, or when neither real nor dummy ECH was offered to the client-facing server. I'm fine with rejection not being known until "ech_required". I support this PR as the resolution to .
NAME and I were sitting down and thinking and we realized the following scenario can happen: URL is on URL, which supports ECH URL has an HTTPS record, an A record, AAAA record pointing at the IP for URL A user of a browsers latest release that supports ECH and greases the extension is using a resolver that doesn't resolve HTTPS records This results in an ECH request being made with URL, and a rejection of the ECH. So now the question is what the client should do and what should servers expect? Try again, with the outer SNI the one matching the one in the new config Use the connection authoritatively for URL since the connection has already revealed the issue.
The intention was the latter, but the text could probably be clearer. I don't think there's much point in trying again since the name has already been revealed. See URL
NAME is this still an issue now that is merged?
I think the client behavior remains equally unspecified. In particular the lengthy argument NAME and I had about server enforcement of the client behavior I think isn't changed.
Care to file a PR, presuming the latter behavior is intended?
A proposed resolution is here: .
NAME a proposed fix has been merged. See .
I think this text works.

Related discussion:
text: If the server sends an "encrypted_client_hello" extension, the client MUST check the extension syntactically and abort the connection with <del> a "decode_error" alert if it is invalid. </del> <ins> a "decode_error" alert if it is invalid.  It otherwise ignores the extension and MUST NOT use the retry keys. </ins> Offering a GREASE extension is not considered offering an encrypted ClientHello for purposes of requirements in client-behavior.  In