Draft: draft-ietf-tls-esni

Commentary: This change implements the ESNI -ECHO design discussed in Singapore . There a couple pending TODOs , particularly around cross - CH HRR binding , but the meat is what 's currently being analyzed . cc 
 This still seems a bit rough , but I think better in the spec than out .
Paragraph (version A):
The design in this document takes a different approach: it assumes
that private origins will co-locate with or hide behind a provider
(CDN, app server, etc.) which is able to activate encrypted SNI
(ESNI) for all of the domains it hosts.  Thus, the use of encrypted
SNI does not indicate that the client is attempting to reach a
private origin, but only that it is going to a particular service
provider, which the observer could already tell from the IP address.
Paragraph (version B):
The design in this document takes a different approach: it assumes
that private origins will co-locate with or hide behind a provider
(CDN, app server, etc.) which is able to activate encrypted SNI, by
encrypting the entire ClientHello (ECHO), for all of the domains it
hosts.  As a result, the use of ECHO to protect the SNI does not
indicate that the client is attempting to reach a private origin, but
only that it is going to a particular service provider, which the
observer could already tell from the IP address.
Paragraph (version A):
SNI encryption requires that each provider publish a public key and
metadata which is used for SNI encryption for all the domains for
which it serves directly or indirectly (via Split Mode).  This
document defines the format of the SNI encryption public key and
metadata, referred to as an ESNI configuration, and delegates DNS
publication details to HTTPSSVC, though other delivery mechanisms are
possible.  In particular, if some of the clients of a private server
are applications rather than Web browsers, those applications might
have the public key and metadata preconfigured.
Paragraph (version A):
When a client wants to form a TLS connection to any of the domains
served by an ESNI-supporting provider, it sends an
"encrypted_server_name" extension, which contains the true extension
encrypted under the provider's public key.  The provider can then
decrypt the extension and either terminate the connection (in Shared
Mode) or forward it to the backend server (in Split Mode).
Paragraph (version A):
The cipher suite used to encrypt the SNI.
Paragraph (version A):
The KeyShareEntry carrying the client's public ephemeral key share
used to derive the ESNI key.
Paragraph (version A):
A cryptographic hash of the ESNIConfig structure from which the
ESNI key was obtained, i.e., from the first byte of "version" to
the end of the structure.  This hash is computed using the hash
function associated with "suite".
Paragraph (version A):
The ClientESNIInner structure, AEAD-encrypted using cipher suite
"suite" and the key generated as described below.
Paragraph (version A):
One or more ESNIConfig structures containing the keys that the
client should use on subsequent connections to encrypt the
ClientESNIInner structure.
Paragraph (version A):
This protocol also defines the "esni_required" alert, which is sent
by the client when it offered an "encrypted_server_name" extension
which was not accepted by the server.
Paragraph (version A):
Finally, requirements in client-behavior and server-behavior require
implementations to track, alongside each PSK established by a
previous connection, whether the connection negotiated this extension
with the "esni_accept" response type.  If so, this is referred to as
an "ESNI PSK".  Otherwise, it is a "non-ESNI PSK".  This may be
implemented by adding a new field to client and server session
states.
Paragraph (version A):
When offering an encrypted SNI, the client MUST NOT offer to resume
any non-ESNI PSKs.  It additionally MUST NOT offer to resume any
sessions for TLS 1.2 or below.
Paragraph (version A):
A random 16-octet value to be echoed by the server in the
"encrypted_server_name" extension.
Paragraph (version A):
Where KeyShareClientHello is the "extension_data" field of the
"key_share" extension in a Client Hello (Section 4.2.8 of RFC8446)).
Including KeyShareClientHello in the AAD of AEAD-Encrypt binds the
ClientEncryptedSNI value to the ClientHello and prevents cut-and-
paste attacks.
Paragraph (version A):
This value is placed in an "encrypted_server_name" extension.
Paragraph (version A):
If the value is "esni_accept", the client MUST check that the
extension's "nonce" field matches ClientESNIInner.nonce and
otherwise abort the connection with an "illegal_parameter" alert.
The client then proceeds with the connection as usual,
authenticating the connection for the origin server.
Paragraph (version A):
Otherwise, when the handshake completes successfully with the
public name authenticated, the client MUST abort the connection
with an "esni_required" alert.  It then processes the "retry_keys"
field from the server's "encrypted_server_name" extension.
Paragraph (version A):
If one of the values contains a version supported by the client,
it can regard the ESNI keys as securely replaced by the server.
It SHOULD retry the handshake with a new transport connection,
using that value to encrypt the SNI.  The value may only be
applied to the retry connection.  The client MUST continue to use
the previously-advertised keys for subsequent connections.  This
avoids introducing pinning concerns or a tracking vector, should a
malicious server present client-specific retry keys to identify
clients.
Paragraph (version A):
If none of the values provided in "retry_keys" contains a
supported version, the client can regard ESNI as securely disabled
by the server.  As below, it SHOULD then retry the handshake with
a new transport connection and ESNI disabled.
Paragraph (version A):
Otherwise, when the handshake completes successfully with the public
name authenticated, the client MUST abort the connection with an
"esni_required" alert.  The client can then regard ESNI as securely
disabled by the server.  It SHOULD retry the handshake with a new
transport connection and ESNI disabled.
Paragraph (version A):
Clients SHOULD implement a limit on retries caused by
"esni_retry_request" or servers which do not acknowledge the
"encrypted_server_name" extension.  If the client does not retry in
either scenario, it MUST report an error to the calling application.
Paragraph (version A):
If the server sends a HelloRetryRequest in response to the
ClientHello and the client can send a second updated ClientHello per
the rules in RFC8446, the "encrypted_server_name" extension values
which do not depend on the (possibly updated) KeyShareClientHello,
i.e,, ClientEncryptedSNI.suite, ClientEncryptedSNI.key_share, and
ClientEncryptedSNI.record_digest, MUST NOT change across ClientHello
messages.  Moreover, ClientESNIInner MUST not change across
ClientHello messages.  Informally, the values of all unencrypted
extension information, as well as the inner extension plaintext, must
be consistent between the first and second ClientHello messages.
Paragraph (version A):
If the server resumed a session or negotiated a session that did
not use a certificate for authentication, the client MUST abort
the connection with an "illegal_parameter" alert.  This case is
invalid because send-esni requires the client to only offer ESNI-
established sessions, and server-behavior requires the server to
decline ESNI-established sessions if it did not accept ESNI.
Paragraph (version B):
ECHO works by encrypting the entire ClientHello, including the SNI
and any additional extensions such as ALPN.  This requires that each
provider publish a public key and metadata which is used for
ClientHello encryption for all the domains for which it serves
directly or indirectly (via Split Mode).  This document defines the
format of the SNI encryption public key and metadata, referred to as
an ECHO configuration, and delegates DNS publication details to
HTTPSSVC, though other delivery mechanisms are possible.  In
particular, if some of the clients of a private server are
applications rather than Web browsers, those applications might have
the public key and metadata preconfigured.
Paragraph (version B):
When a client wants to form a TLS connection to any of the domains
served by an ECHO-supporting provider, it constructs a ClientHello in
the regular fashion containing the true SNI value (ClientHelloInner)
and then encrypts it using the public key for the provider.  It then
constructs a new ClientHello (ClientHelloOuter) with an innocuous SNI
(and potentially innocuous versions of other extensions such as ALPN
RFC7301) and containing the encrypted ClientHelloInner as an
extension.  It sends ClientHelloOuter to the server.
Paragraph (version B):
Upon receiving ClientHelloOuter, the server can then decrypt
ClientHelloInner and either terminate the connection (in Shared Mode)
or forward it to the backend server (in Split Mode).
Paragraph (version B):
Note that both ClientHelloInner and ClientHelloOuter are both valid,
complete ClientHello messages.  ClientHelloOuter carries an encrypted
representation of ClientHelloInner in a "encrypted_client_hello"
extension, defined in encrypted-client-hello.
Paragraph (version B):
ClientHello encryption configuration information is conveyed with the
following ECHOConfigs structure.
Paragraph (version B):
The ECHOConfigs structure contains one or more ECHOConfig structures
in decreasing order of preference.  This allows a server to support
multiple versions of ECHO and multiple sets of ECHO parameters.
Paragraph (version B):
The version of the structure.  For this specification, that value
SHALL be 0xff03.  Clients MUST ignore any ECHOConfig structure
with a version they do not understand.
Paragraph (version B):
An opaque byte string whose contents depend on the version of the
structure.  For this specification, the contents are an
ECHOConfigContents structure.
Paragraph (version B):
The HPKE I-D.irtf-cfrg-hpke public key which can be used by the
client to encrypt the ClientHello.
Paragraph (version B):
The HPKE I-D.irtf-cfrg-hpke KEM identifier corresponding to
public_key.  Clients MUST ignore any ECHOConfig structure with a
key using a KEM they do not support.
Paragraph (version B):
A list of extensions that the client can take into consideration
when generating a Client Hello message.  The purpose of the field
is to provide room for additional features in the future.  The
format is defined in RFC8446; Section 4.2.  The same
interpretation rules apply: extensions MAY appear in any order,
but there MUST NOT be more than one extension of the same type in
the extensions block.  An extension may be tagged as mandatory by
using an extension type codepoint with the high order bit set to
1.  A client which receives a mandatory extension they do not
understand must reject the ECHOConfig content.
Paragraph (version B):
Clients MUST parse the extension list and check for unsupported
mandatory extensions.  If an unsupported mandatory extension is
present, clients MUST reject the ECHOConfig value.
Paragraph (version B):
The cipher suite used to encrypt ClientHelloInner.
Paragraph (version B):
A cryptographic hash of the ECHOConfig structure from which the
ECHO key was obtained, i.e., from the first byte of "version" to
the end of the structure.  This hash is computed using the hash
function associated with "suite".
Paragraph (version B):
The HPKE encapsulated key, used by servers to decrypt the
corresponding encrypted_ch field.
Paragraph (version B):
The serialized and encrypted ClientHelloInner structure, AEAD-
encrypted using cipher suite "suite" and the key generated as
described below.
Paragraph (version B):
An ESNIConfigs structure containing one or more ECHOConfig
structures in decreasing order of preference that the client
should use on subsequent connections to encrypt the
ClientHelloInner structure.
Paragraph (version B):
This protocol also defines the "echo_required" alert, which is sent
by the client when it offered an "encrypted_server_name" extension
which was not accepted by the server.
Paragraph (version B):
A 16-byte nonce exported from the HPKE encryption context.  See
send-echo for details about its computation.
Paragraph (version B):
Finally, requirements in client-behavior and server-behavior require
implementations to track, alongside each PSK established by a
previous connection, whether the connection negotiated this extension
with the "echo_accept" response type.  If so, this is referred to as
an "ECHO PSK".  Otherwise, it is a "non-ECHO PSK".  This may be
implemented by adding a new field to client and server session
states.
Paragraph (version B):
Some TLS 1.3 extensions can be quite large and having them both in
the inner and outer ClientHello will lead to a very large overall
size.  One particularly pathological example is "key_share" with
post-quantum algorithms.  In order to reduce the impact of duplicated
extensions, the client may use the "outer_extensions" extension.
Paragraph (version B):
OuterExtensions MUST only be used in ClientHelloInner.  It consists
of one or more ExtensionType values, each of which reference an
extension in ClientHelloOuter, and a digest of the complete
ClientHelloInner.
Paragraph (version B):
When sending ClientHello, the client first computes ClientHelloInner,
including any PSK binders, and then MAY substitute extensions which
it knows will be duplicated in ClientHelloOuter.  To do so, the
client computes a hash H of the entire ClientHelloInner message with
the same hash as for the KDF used to encrypt ClienHelloInner.  Then,
the client removes and and replaces extensions from ClientHelloInner
with a single "outer_extensions" extension.  The list of
outer_extensions include those which were removed from
ClientHelloInner, in the order in which they were removed.  The hash
contains the full ClientHelloInner hash H computed above.
Paragraph (version B):
This process is reversed by client-facing servers upon receipt.
Specifically, the server replaces the "outer_extensions" with
extensions contained in ClientHelloOuter.  The server then computes a
hash H' of the reconstructed ClientHelloInner.  If H' does not equal
OuterExtensions.hash, the server aborts the connection with an
"illegal_parameter" alert.
Paragraph (version B):
Clients SHOULD only use this mechanism for extensions which are
large.  All other extensions SHOULD appear in both ClientHelloInner
and ClientHelloOuter even if they have identical values.
Paragraph (version B):
In order to send an encrypted ClientHello, the client first
determines if it supports the server's chosen KEM, as identified by
ECHOConfig.kem_id.  If one is supported, the client MUST select an
appropriate cipher suite from the list of suites offered by the
server.  If the client does not support the corresponding KEM or is
unable to select an appropriate group or suite, it SHOULD ignore that
ECHOConfig value and MAY attempt to use another value provided by the
server.  The client MUST NOT send ECHO using HPKE algorithms not
advertised by the server.
Paragraph (version B):
When offering an encrypted ClientHello, the client MUST NOT offer to
resume any non-ECHO PSKs.  It additionally MUST NOT offer to resume
any sessions for TLS 1.2 or below.
Paragraph (version B):
Finally, the client MUST generate a ClientHelloOuter message
containing the "encrypted_client_hello" extension with the values as
indicated above.  In particular,
Paragraph (version B):
encrypted_ch contains the HPKE encapsulated key (enc) and the
ClientHelloInner ciphertext (encrypted_ch_inner).
Paragraph (version B):
The client MUST place the value of ECHOConfig.public_name in the
ClientHelloOuter "server_name" extension.  The remaining contents of
the ClientHelloOuter MAY be identical to those in ClientHelloInner
but MAY also differ.  The ClientHelloOuter MUST NOT contain a
"cached_info" extension RFC7924 with a CachedObject entry whose
CachedInformationType is "cert", since this indication would divulge
the true server name.
Paragraph (version B):
As described in server-behavior, the server MAY either accept ECHO
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):
If the server used ClientHelloInner, the client proceeds with the
connection as usual, authenticating the connection for the origin
server.
Paragraph (version B):
If the server used ClientHelloOuter, the client proceeds with the
handshake, authenticating for ECHOConfig.public_name as described in
auth-public-name.  If authentication or the handshake fails, the
client MUST return a failure to the calling application.  It MUST NOT
use the retry keys.
Paragraph (version B):
Otherwise, when the handshake completes successfully with the public
name authenticated, the client MUST abort the connection with an
"echo_required" alert.  It then processes the "retry_keys" field from
the server's "encrypted_server_name" extension.
Paragraph (version B):
If one of the values contains a version supported by the client, it
can regard the ECHO keys as securely replaced by the server.  It
SHOULD retry the handshake with a new transport connection, using
that value to encrypt the ClientHello.  The value may only be applied
to the retry connection.  The client MUST continue to use the
previously-advertised keys for subsequent connections.  This avoids
introducing pinning concerns or a tracking vector, should a malicious
server present client-specific retry keys to identify clients.
Paragraph (version B):
If none of the values provided in "retry_keys" contains a supported
version, the client can regard ECHO as securely disabled by the
server.  As below, it SHOULD then retry the handshake with a new
transport connection and ECHO disabled.
Paragraph (version B):
If the server negotiates an earlier version of TLS, or if it does not
provide an "encrypted_server_name" extension in EncryptedExtensions,
the client proceeds with the handshake, authenticating for
ECHOConfigContents.public_name as described in auth-public-name.  If
an earlier version was negotiated, the client MUST NOT enable the
False Start optimization RFC7918 for this handshake.  If
authentication or the handshake fails, the client MUST return a
failure to the calling application.  It MUST NOT treat this as a
secure signal to disable ECHO.
Paragraph (version B):
Otherwise, when the handshake completes successfully with the public
name authenticated, the client MUST abort the connection with an
"echo_required" alert.  The client can then regard ECHO as securely
disabled by the server.  It SHOULD retry the handshake with a new
transport connection and ECHO disabled.
Paragraph (version B):
Clients SHOULD implement a limit on retries caused by
"echo_retry_request" or servers which do not acknowledge the
"encrypted_server_name" extension.  If the client does not retry in
either scenario, it MUST report an error to the calling application.
Paragraph (version B):
If the server resumed a session or negotiated a session that did
not use a certificate for authentication, the client MUST abort
the connection with an "illegal_parameter" alert.  This case is
invalid because send-echo requires the client to only offer ECHO-
established sessions, and server-behavior requires the server to
decline ECHO-established sessions if it did not accept ECHO.
Paragraph (version B):
The client MUST verify that the certificate is valid for
ECHOConfigContents.public_name.  If invalid, it MUST abort the
connection with the appropriate alert.
Paragraph (version A):
Set the "key_share" field to a randomly-generated valid public key
for the named group.
Paragraph (version A):
Set the "encrypted_sni" field to a randomly-generated string of 16
+ padded_length + tag_length bytes, where tag_length is the tag
length of the chosen cipher suite's associated AEAD.
Paragraph (version A):
If the server sends an "encrypted_server_name" extension, the client
MUST check the extension syntactically and abort the connection with
a "decode_error" alert if it is invalid.  If the "response_type"
field contains "esni_retry_requested", the client MUST ignore the
extension and proceed with the handshake.  If it contains
"esni_accept" or any other value, the client MUST abort the
connection with an "illegal_parameter" alert.
Paragraph (version A):
Offering a GREASE extension is not considered offering an encrypted
SNI for purposes of requirements in client-behavior.  In particular,
the client MAY offer to resume sessions established without ESNI.
Paragraph (version A):
Upon receiving an "encrypted_server_name" extension, the client-
facing server MUST check that it is able to negotiate TLS 1.3 or
greater.  If not, it MUST abort the connection with a
"handshake_failure" alert.
Paragraph (version A):
Compare ClientEncryptedSNI.record_digest against cryptographic
hashes of known ESNIConfig and choose the one that matches.
Paragraph (version A):
Use trial decryption of ClientEncryptedSNI.encrypted_sni with
known ESNIConfig and choose the one that succeeds.
Paragraph (version A):
Some uses of ESNI, such as local discovery mode, may omit the
ClientEncryptedSNI.record_digest since it can be used as a tracking
vector.  In such cases, trial decryption should be used for matching
ClientEncryptedSNI to known ESNIConfig.  Unless specified by the
application using (D)TLS or externally configured on both sides,
implementations MUST use the first method.
Paragraph (version A):
The server MUST ignore all PSK identities in the ClientHello which
correspond to ESNI PSKs.  ESNI PSKs offered by the client are
associated with the ESNI name.  The server was unable to decrypt
then ESNI name, so it should not resume them when using the
cleartext SNI name.  This restriction allows a client to reject
resumptions in auth-public-name.
Paragraph (version A):
Note that an unrecognized ClientEncryptedSNI.record_digest value may
be a GREASE ESNI extension (see grease-extensions), so it is
necessary for servers to proceed with the connection and rely on the
client to abort if ESNI was required.  In particular, the
unrecognized value alone does not indicate a misconfigured ESNI
advertisement (misconfiguration).  Instead, servers can measure
occurrences of the "esni_required" alert to detect this case.
Paragraph (version A):
If the length of the "encrypted_server_name" extension is
inconsistent with the advertised padding length (plus AEAD
expansion) the server MAY abort the connection with an
"illegal_parameter" alert without attempting to decrypt.
Paragraph (version B):
If the server sends a HelloRetryRequest in response to the
ClientHello, the client sends a second updated ClientHello per the
rules in RFC8446.  However, at this point, the client does not know
whether the server processed ClientHelloOuter or ClientHelloInner,
and MUST regenerate both values to be acceptable.  Note: if the inner
and outer ClientHellos use different groups for their key shares or
differ in some other way, then the HelloRetryRequest may actually be
invalid for one or the other ClientHello, in which case a fresh
ClientHello MUST be generated, ignoring the instructions in
HelloRetryRequest.  Otherwise, the usual rules for HelloRetryRequest
processing apply.
Paragraph (version B):
Clients then encrypt the second ClientHelloInner using this new HPKE
context.  In doing so, the encrypted value is also authenticated by
echo_hrr_key.
Paragraph (version B):
Set the "enc" field to a randomly-generated valid encapsulated
public key output by the HPKE KEM.
Paragraph (version B):
If the server sends an "encrypted_client_hello" extension, the client
MUST check the extension syntactically and abort the connection with
a "decode_error" alert if it is invalid.
Paragraph (version B):
Offering a GREASE extension is not considered offering an encrypted
ClientHello for purposes of requirements in client-behavior.  In
particular, the client MAY offer to resume sessions established
without ECHO.
Paragraph (version B):
Upon receiving an "encrypted_client_hello" extension, the client-
facing server MUST check that it is able to negotiate TLS 1.3 or
greater.  If not, it MUST abort the connection with a
"handshake_failure" alert.
Paragraph (version B):
Compare ClientEncryptedCH.record_digest against cryptographic
hashes of known ECHOConfig and choose the one that matches.
Paragraph (version B):
Use trial decryption of ClientEncryptedCH.encrypted_ch with known
ECHOConfig and choose the one that succeeds.
Paragraph (version B):
Some uses of ECHO, such as local discovery mode, may omit the
ClientEncryptedCH.record_digest since it can be used as a tracking
vector.  In such cases, trial decryption should be used for matching
ClientEncryptedCH to known ECHOConfig.  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 with the
"retry_keys" field set to one or more ECHOConfig structures with
up-to-date keys.  Servers MAY supply multiple ECHOConfig values of
different versions.  This allows a server to support multiple
versions at once.
Paragraph (version B):
The server MUST ignore all PSK identities in the ClientHello which
correspond to ECHO PSKs.  ECHO PSKs offered by the client are
associated with the ECHO name.  The server was unable to decrypt
then ECHO name, so it should not resume them when using the
cleartext SNI name.  This restriction allows a client to reject
resumptions in auth-public-name.
Paragraph (version B):
Note that an unrecognized ClientEncryptedCH.record_digest value may
be a GREASE ECHO extension (see grease-extensions), so it is
necessary for servers to proceed with the connection and rely on the
client to abort if ECHO was required.  In particular, the
unrecognized value alone does not indicate a misconfigured ECHO
advertisement (misconfiguration).  Instead, servers can measure
occurrences of the "echo_required" alert to detect this case.
Paragraph (version B):
If decryption fails, the server MUST abort the connection with a
"decrypt_error" alert.  Moreover, if there is no "echo_nonce"
extension, or if its value does not match the derived echo_nonce, the
server MUST abort the connection with a "decrypt_error" alert.  Next,
the server MUST scan ClientHelloInner for any "outer_extension"
extensions and substitute their values with the values in
ClientHelloOuter.  It MUST first verify that the hash found in the
extension matches the hash of the extension to be interpolated in and
if it does not, abort the connections with a "decrypt_error" alert.
Paragraph (version A):
If the ClientHello is the result of a HelloRetryRequest, servers MUST
abort the connection with an "illegal_parameter" alert if any of the
ClientEncryptedSNI.suite, ClientEncryptedSNI.key_share,
ClientEncryptedSNI.record_digest, or decrypted ClientESNIInner values
from the second ClientHello do not match that of the first
ClientHello.
Paragraph (version A):
A server operating in Shared Mode uses PaddedServerNameList.sni as if
it were the "server_name" extension to finish the handshake.  It
SHOULD pad the Certificate message, via padding at the record layer,
such that its length equals the size of the largest possible
Certificate (message) covered by the same ESNI key.  Moreover, the
server MUST include the "encrypted_server_name" extension in
EncryptedExtensions with the "response_type" field set to
"esni_accept" and the "nonce" field set to the decrypted
PaddedServerNameList.nonce value from the client
"encrypted_server_name" extension.
Paragraph (version A):
If the server sends a NewSessionTicket message, the corresponding
ESNI PSK MUST be ignored by all other servers in the deployment when
not negotiating ESNI, including servers which do not implement this
specification.
Paragraph (version A):
This restriction provides robustness for rollbacks (see
misconfiguration).
Paragraph (version A):
In Split Mode, the backend server must know
PaddedServerNameList.nonce to echo it back in EncryptedExtensions and
complete the handshake.  communicating-sni describes one mechanism
for sending both PaddedServerNameList.sni and ClientESNIInner.nonce
to the backend server.  Thus, backend servers function the same as
servers operating in Shared Mode.
Paragraph (version A):
As in Shared Mode, if the backend server sends a NewSessionTicket
message, the corresponding ESNI PSK MUST be ignored by other servers
in the deployment when not negotiating ESNI, including servers which
do not implement this specification.
Paragraph (version A):
Unlike most TLS extensions, placing the SNI value in an ESNI
extension is not interoperable with existing servers, which expect
the value in the existing cleartext extension.  Thus server operators
SHOULD ensure servers understand a given set of ESNI keys before
advertising them.  Additionally, servers SHOULD retain support for
any previously-advertised keys for the duration of their validity.
Paragraph (version A):
However, in more complex deployment scenarios, this may be difficult
to fully guarantee.  Thus this protocol was designed to be robust in
case of inconsistencies between systems that advertise ESNI keys and
servers, at the cost of extra round-trips due to a retry.  Two
specific scenarios are detailed below.
Paragraph (version A):
It is possible for ESNI advertisements and servers to become
inconsistent.  This may occur, for instance, from DNS
misconfiguration, caching issues, or an incomplete rollout in a
multi-server deployment.  This may also occur if a server loses its
ESNI keys, or if a deployment of ESNI must be rolled back on the
server.
Paragraph (version A):
The retry mechanism repairs inconsistencies, provided the server is
authoritative for the public name.  If server and advertised keys
mismatch, the server will respond with esni_retry_requested.  If the
server does not understand the "encrypted_server_name" extension at
all, it will ignore it as required by RFC8446; Section 4.1.2.
Provided the server can present a certificate valid for the public
name, the client can safely retry with updated settings, as described
in handle-server-response.
Paragraph (version A):
Unless ESNI is disabled as a result of successfully establishing a
connection to the public name, the client MUST NOT fall back to
cleartext SNI, as this allows a network attacker to disclose the SNI.
It MAY attempt to use another server from the DNS results, if one is
provided.
Paragraph (version B):
If the server sends a NewSessionTicket message, the corresponding
ECHO PSK MUST be ignored by all other servers in the deployment when
not negotiating ECHO, including servers which do not implement this
specification.
Paragraph (version B):
However, in more complex deployment scenarios, this may be difficult
to fully guarantee.  Thus this protocol was designed to be robust in
case of inconsistencies between systems that advertise ECHO keys and
servers, at the cost of extra round-trips due to a retry.  Two
specific scenarios are detailed below.
Paragraph (version B):
It is possible for ECHO advertisements and servers to become
inconsistent.  This may occur, for instance, from DNS
misconfiguration, caching issues, or an incomplete rollout in a
multi-server deployment.  This may also occur if a server loses its
ECHO keys, or if a deployment of ECHO must be rolled back on the
server.
Paragraph (version B):
The retry mechanism repairs inconsistencies, provided the server is
authoritative for the public name.  If server and advertised keys
mismatch, the server will respond with echo_retry_requested.  If the
server does not understand the "encrypted_server_name" extension at
all, it will ignore it as required by RFC8446; Section 4.1.2.
Provided the server can present a certificate valid for the public
name, the client can safely retry with updated settings, as described
in handle-server-response.
Paragraph (version B):
Unless ECHO is disabled as a result of successfully establishing a
connection to the public name, the client MUST NOT fall back to using
unencrypted ClientHellos, as this allows a network attacker to
disclose the contents of this ClientHello, including the SNI.  It MAY
attempt to use another server from the DNS results, if one is
provided.
Paragraph (version B):
Client-facing servers with non-uniform cryptographic configurations
across backend origin servers segment the ECHO anonymity set based on
these configurations.  For example, if a client-facing server hosts k
backend origin servers, and exactly one of those backend origin
servers supports a different set of cryptographic algorithms than the
other (k - 1) servers, it may be possible to identify this single
server based on the contents of the ServerHello as this message is
not encrypted.
Paragraph (version A):
Depending on whether the client is configured to accept the proxy's
certificate as authoritative for the public name, this may trigger
the retry logic described in handle-server-response or result in a
connection failure.  A proxy which is not authoritative for the
public name cannot forge a signal to disable ESNI.
Paragraph (version A):
A non-conformant MITM proxy which instead forwards the ESNI
extension, substituting its own KeyShare value, will result in the
client-facing server recognizing the key, but failing to decrypt the
SNI.  This causes a hard failure.  Clients SHOULD NOT attempt to
repair the connection in this case.
Paragraph (version A):
In comparison to I-D.kazuho-protected-sni, wherein DNS Resource
Records are signed via a server private key, ESNI records have no
authenticity or provenance information.  This means that any attacker
which can inject DNS responses or poison DNS caches, which is a
common scenario in client access networks, can supply clients with
fake ESNI records (so that the client encrypts SNI to them) or strip
the ESNI record from the response.  However, in the face of an
attacker that controls DNS, no SNI encryption scheme can work because
the attacker can replace the IP address, thus blocking client
connections, or substituting a unique IP address which is 1:1 with
the DNS name that was looked up (modulo DNS wildcards).  Thus,
allowing the ESNI records in the clear does not make the situation
significantly worse.
Paragraph (version A):
Clearly, DNSSEC (if the client validates and hard fails) is a defense
against this form of attack, but DoH/DPRIVE are also defenses against
DNS attacks by attackers on the local network, which is a common case
where SNI is desired.  Moreover, as noted in the introduction, SNI
encryption is less useful without encryption of DNS queries in
transit via DoH or DPRIVE mechanisms.
Paragraph (version A):
Supporting optional record digests and trial decryption opens oneself
up to DoS attacks.  Specifically, an adversary may send malicious
ClientHello messages, i.e., those which will not decrypt with any
known ESNI key, in order to force 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):
Depending on whether the client is configured to accept the proxy's
certificate as authoritative for the public name, this may trigger
the retry logic described in handle-server-response or result in a
connection failure.  A proxy which is not authoritative for the
public name cannot forge a signal to disable ECHO.
Paragraph (version B):
A non-conformant MITM proxy which instead forwards the ECHO
extension, substituting its own KeyShare value, will result in the
client-facing server recognizing the key, but failing to decrypt the
SNI.  This causes a hard failure.  Clients SHOULD NOT attempt to
repair the connection in this case.
Paragraph (version B):
Clearly, DNSSEC (if the client validates and hard fails) is a defense
against this form of attack, but DoH/DPRIVE are also defenses against
DNS attacks by attackers on the local network, which is a common case
where ClientHello and SNI encryption are desired.  Moreover, as noted
in the introduction, SNI encryption is less useful without encryption
of DNS queries in transit via DoH or DPRIVE mechanisms.
Paragraph (version A):
I-D.ietf-tls-sni-encryption lists several requirements for SNI
encryption.  In this section, we re-iterate these requirements and
assess the ESNI design against them.
Paragraph (version A):
Since the SNI encryption key is derived from a (EC)DH operation
between the client's ephemeral and server's semi-static ESNI key, the
ESNI encryption is bound to the Client Hello.  It is not possible for
an attacker to "cut and paste" the ESNI value in a different Client
Hello, with a different ephemeral key share, as the terminating
server will fail to decrypt and verify the ESNI value.
Paragraph (version A):
This design depends upon DNS as a vehicle for semi-static public key
distribution.  Server operators may partition their private keys
however they see fit provided each server behind an IP address has
the corresponding private key to decrypt a key.  Thus, when one ESNI
key is provided, sharing is optimally bound by the number of hosts
that share an IP address.  Server operators may further limit sharing
by publishing different DNS records containing ESNIConfig values with
different keys using a short TTL.
Paragraph (version A):
This design requires servers to decrypt ClientHello messages with
ClientEncryptedSNI 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.
Paragraph (version A):
As more clients enable ESNI support, e.g., as normal part of Web
browser functionality, with keys supplied by shared hosting
providers, the presence of ESNI extensions becomes less suspicious
and part of common or predictable client behavior.  In other words,
if all Web browsers start using ESNI, the presence of this value does
not signal suspicious behavior to passive eavesdroppers.
Paragraph (version A):
Additionally, this specification allows for clients to send GREASE
ESNI extensions (see grease-extensions), which helps ensure the
ecosystem handles the values correctly.
Paragraph (version A):
This design is not forward secret because the server's ESNI key is
static.  However, the window of exposure is bound by the key
lifetime.  It is RECOMMENDED that servers rotate keys frequently.
Paragraph (version A):
IANA is requested to create an entry, esni_required(121) in the
existing registry for Alerts (defined in RFC8446), with the "DTLS-OK"
column being set to "Y".