Draft: draft-ietf-tls-esni

Commentary: The spec describes an optional trial decryption mode , but most of the text contradicts it . This PR fixes the text up and tries to unify their processing models . In doing so , it flips the error handling from decrypterror to fallback to be consistent . This , combined with the ClientHelloOuterAAD change , plugs an active sticking out attack for free . It also makes easier because GREASE configid collisions with real configids are now harmless . Along the way , and observed that we 're not authenticating the ECHConfig at all . ( It used to be authenticated by way of the configid , which was a digest . ) Instead , just pass the ECHConfig into the info field of the HPKE context . They also noticed the server rule about PSKs on ClientHelloOuter did n't work with GREASE . Instead , we can simply remove it . 
 This matches the acceptance signal length , and we 've already accepted that probability of collision .
Paragraph (version A):
If it supports ECH but does not recognize the configuration
specified by the client, then it ignores the extension and
terminates the handshake using the ClientHelloOuter.  This is
referred to as "ECH rejection".  When ECH is rejected, the server
sends an acceptable ECH configuration in its EncryptedExtensions
message.
Paragraph (version A):
If it supports ECH and recognizes the configuration, then it
attempts to decrypt the ClientHelloInner.  It aborts the handshake
if decryption fails; otherwise it forwards the ClientHelloInner to
the backend, who terminates the connection.  This is referred to
as "ECH acceptance".
Paragraph (version B):
If it supports ECH but cannot decrypt the extension, then it
terminates the handshake using the ClientHelloOuter.  This is
referred to as "ECH rejection".  When ECH is rejected, the server
sends an acceptable ECH configuration in its EncryptedExtensions
message.
Paragraph (version B):
If it supports ECH and decrypts the extension, it forwards the
ClientHelloInner to the backend, who terminates the connection.
This is referred to as "ECH acceptance".
Paragraph (version A):
The configuration identifier, equal to "Expand(Extract("",
config), "tls13 ech config id", Nh)", where "config" is the
"ECHConfig" structure and "Extract", "Expand", and "Nh" are as
specified by the cipher suite KDF.  (Passing the literal """" as
the salt is interpreted by "Extract" as no salt being provided.)
The length of this value SHOULD NOT be less than 16 bytes unless
it is optional for an application; see optional-configs.
Paragraph (version B):
The configuration identifier, equal to "Expand(Extract("",
config), "tls ech config id", Nh)", where "config" is the
"ECHConfig" structure and "Extract", "Expand", and "Nh" are as
specified by the cipher suite KDF.  (Passing the literal """" as
the salt is interpreted by "Extract" as no salt being provided.)
The length of this value SHOULD NOT be less than 16 bytes unless
it is optional for an application; see optional-configs.
Paragraph (version A):
Note that the HPKE functions Deserialize and SetupBaseS are those
which match "ECHConfig.kem_id" and the AEAD/KDF used with "context"
are those which match the client's chosen preference from
"ECHConfig.cipher_suites".
Paragraph (version B):
Note that the HPKE functions Deserialize and SetupBaseS are those
which match "ECHConfig.kem_id" and the AEAD/KDF used with "context"
are those which match the client's chosen preference from
"ECHConfig.cipher_suites".  The "info" parameter to SetupBaseS is the
concatenation of "tls ech", a zero byte, and the serialized
ECHConfig.
Paragraph (version B):
If optional configuration identifiers (see optional-configs)) are
used, the "config_id" field MAY be empty or randomly generated.
Unless specified by the application using (D)TLS or externally
configured on both sides, implementations MUST compute the field as
specified in encrypted-client-hello.
Paragraph (version A):
Clients then encrypt the second ClientHelloInner using this new HPKE
context.  In doing so, the encrypted value is also authenticated by
ech_hrr_key.  The rationale for this is described in flow-hrr-hijack.
Paragraph (version B):
The "info" parameter to SetupPSKS is the concatenation of "tls ech",
a zero byte, and the serialized ECHConfig.  Clients then encrypt the
second ClientHelloInner using this new HPKE context.  In doing so,
the encrypted value is also authenticated by ech_hrr_key.  The
rationale for this is described in flow-hrr-hijack.
Paragraph (version A):
ClientHelloOuterAAD is computed from the second ClientHelloOuter as
described in authenticating-outer.
Paragraph (version B):
ClientHelloOuterAAD is computed from the second ClientHelloOuter as
described in authenticating-outer.  The "info" parameter to SetupPSKR
is computed as above.
Paragraph (version A):
Compare ClientECH.config_id against identifiers of known ECHConfig
and choose the one that matches.
Paragraph (version A):
Use trial decryption of ClientECH.payload with known ECHConfig and
choose the one that succeeds.
Paragraph (version A):
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 A):
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):
If offered, the server MUST ignore the "pre_shared_key" extension
in the ClientHello.
Paragraph (version A):
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):
ClientHelloOuterAAD is computed from ClientHelloOuter as described in
authenticating-outer.  If decryption fails, the server MUST abort the
connection with a "decrypt_error" alert.  Otherwise, the server
reconstructs ClientHelloInner from EncodedClientHelloInner, as
described in encoding-inner.
Paragraph (version B):
Compare ClientECH.config_id against identifiers of known
ECHConfigs and select the one that matches, if any, as a
candidate.
Paragraph (version B):
Collect all known ECHConfigs as candidates, with trial decryption
below determining the final selection.
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, the second method should be used for matching ClientECH
to known ECHConfig.  See optional-configs.  Unless specified by the
application using (D)TLS or externally configured on both sides,
implementations MUST use the first method.
Paragraph (version B):
The server verifies that the ECHConfig supports the cipher suite
indicated by the ClientECH.cipher_suite and that the version of ECH
indicated by the client matches the ECHConfig.version.  If not, the
server continues to the next candidate ECHConfig.
Paragraph (version B):
ClientHelloOuterAAD is computed from ClientHelloOuter as described in
authenticating-outer.  The "info" parameter to SetupBaseS is the
concatenation "tls ech", a zero byte, and the serialized ECHConfig.
If decryption fails, the server continues to the next candidate
ECHConfig.  Otherwise, the server reconstructs ClientHelloInner from
EncodedClientHelloInner, as described in encoding-inner.  It then
stops consider candidate ECHConfigs.
Paragraph (version B):
Otherwise, if all candidate ECHConfigs fail to decrypt the extension,
the client-facing server MUST ignore the extension and proceed with
the connection using ClientHelloOuter.  This connection proceeds as
usual, except the server 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 B):
Note that decryption failure could indicate 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):
Suppose the "encrypted_client_hello" extension is sent in both CH1
and CH2, If the configuration identifier (see ech-configuration)
differs between CH1 and CH2, then the server MUST abort with an
"illegal_parameter" alert.
Paragraph (version B):
If the "encrypted_client_hello" extension is sent in CH2, the
server follows the procedure in client-facing-server to decrypt
the extension, but it uses the previously-selected ECHConfig as
the set of candidate ECHConfigs.  If decryption fails, the server
aborts the connection with a "decrypt_error" alert rather than
continuing the handshake with the second ClientHelloOuter.