Draft: draft-ietf-tls-esni

Commentary: After having written so many variations of ClientHelloOuterAAD construction ( client and server , test and production ) , I think this may be simpler . A little bit less ClientHello rewriting . The cost is predicting the payload length on the client ( same as PSK binders ) , but that prediction is just adding the tag length to len(EncodedClientHelloInner ) . The server , in particular , needs to parse and then re - encode an arbitrary incoming ClientHelloOuter with transforms . Thoughts ? 
 That 's exactly what this PR does . is the encrypted portion . ( The whole extension body is in RFC8446 . Guessing that was the disconnect ? ) 
 Ah , precise terminology is useful up until the point that you are n't intimately familiar with each and every term . That would be OK , but as I said , it 's not an improvement for us . 
 Hehe . I 'm mostly hoping it 'd tidy up the server side . When you decide to do ECH , you 've already got to have parsed the ClientHello and found the ECH extension . Instead of going back , trimming out the ECH extension , preserving the surrounding extensions , and then updating the extensions length prefix , you can just take the offset of the payload field you just found , zero that and leave the rest alone . 
 Yeah , if it is a server - side improvement ( we do n't heavily optimize any of this stuff , so we do n't care much ) , then I wo n't stand in the way . 
 The benefit of this change , IIRC , is that you do n't need to reserialize anything . But the new proposed text still talks about reserializing . It would be good to find a way to reword it so it does n't imply that reserialization is needed . 
 Rephrased . 
 LGTM ! Thanks for making that change . 
 would you mind resolving conflicts here ? 
 Rebased . 
 Thanks ! Paging and for additional reviews . 
 Apart from my question about clarification , makes sense to me . 
 LGTM    idea . I went to make that more precise and , in the process , realized a whole lot of the client procedure was specified funny so fixes that up . ( Those issues apply to the existing text too , so if we end up not merging this PR , I 'll write an equivalent PR with just those bits . ) [ edit : changed commit hash . old one had a typo . ] [ edit : so did the second one . bah , okay , going to stop force - pushing now ... ] 
 This would n't be easier for us to implement ; we insert the extension . Yes , with . We use extension insertion in a few places ( padding ) , so it 's not that difficult . It 's doable , and not that much more work to do it this way . Did I miss the rationale for not including the HPKE parameters ? I know that some of these are in HPKE and so they are redundant here , but they are encoded in the ech extension , so maybe there is a different spelling of this that only drops / zeros - out the encrypted portion . I'm happy with this .
Paragraph (version A):
The first three parameters are equal to, respectively, the
"ClientECH.cipher_suite", "ClientECH.config_id", and "ClientECH.enc"
fields of the payload of the "encrypted_client_hello" extension.  The
last parameter, "outer_hello", is computed by serializing
ClientHelloOuter with the "encrypted_client_hello" extension set to
the empty string, i.e., the "extension_data" list has zero length.
This serialization uses the ClientHello structure from Section 4.1.2
of RFC8446, which does not include the four-byte header included in
the Handshake structure.
Paragraph (version B):
To prevent a network attacker from modifying the reconstructed
ClientHelloInner (see flow-clienthello-malleability), ECH
authenticates ClientHelloOuter by passing ClientHelloOuterAAD as the
associated data for HPKE sealing and opening operations.  The
ClientHelloOuterAAD is a serialized ClientHello structure, defined in
Section 4.1.2 of RFC8446, which matches the ClientHelloOuter except
the "payload" field of the "encrypted_client_hello" is replaced with
a byte string of the same length but whose contents are zeros.  This
value does not include the four-byte header from the Handshake
structure.
Paragraph (version B):
The client follows the procedure in encrypting-clienthello to first
construct ClientHelloOuterAAD with a placeholder "payload" field,
then replace the field with the encrypted value to compute
ClientHelloOuter.
Paragraph (version B):
The server then receives ClientHelloOuter and computes
ClientHelloOuterAAD by making a copy and replacing the portion
corresponding to the "payload" field with zeros.
Paragraph (version B):
The payload and the placeholder strings have the same length, so it
is not necessary for either side to recompute length prefixes when
applying the above transformations.
Paragraph (version A):
It MUST include an "encrypted_client_hello" extension with a
payload constructed as described below.
Paragraph (version B):
It MUST include an "encrypted_client_hello" extension with a
payload constructed as described in encrypting-clienthello.
Paragraph (version A):
To encrypt EncodedClientHelloInner, the client first computes
ClientHelloOuterAAD as described in authenticating-outer.  Note this
requires the "encrypted_client_hello" be computed after all other
extensions.  In particular, this is possible because the
"pre_shared_key" extension is forbidden in ClientHelloOuter.
Paragraph (version A):
Note that the HPKE functions DeserializePublicKey and SetupBaseS are
those which match "ECHConfig.contents.kem_id" and the AEAD/KDF used
with "context" are those which match the client's chosen preference
from "ECHConfig.contents.cipher_suites".  The "info" parameter to
SetupBaseS is the concatenation of "tls ech", a zero byte, and the
serialized ECHConfig.
Paragraph (version B):
If constructing the second ClientHelloOuter (client-hrr), it reuses
the encryption context computed for the first ClientHelloOuter, and
sets "enc" to the empty string.  Note that the HPKE context maintains
a sequence number, so this operation internally uses a fresh nonce
for each AEAD operation.  Reusing the HPKE context avoids an attack
described in flow-hrr-hijack.
Paragraph (version B):
The client then computes ClientHelloOuterAAD (authenticating-outer)
by constructing a ClientHello with all other extensions determined as
in real-ech.
Paragraph (version A):
"payload", as computed above.
Paragraph (version A):
If optional configuration identifiers (see optional-configs) are
used, "config_id" SHOULD be set to a randomly generated byte.  Unless
specified by the application using (D)TLS or externally configured on
both sides, implementations MUST set the field as specified in
encrypted-client-hello.
Paragraph (version B):
"payload", a placeholder byte string containing L zeros.
Paragraph (version B):
If optional configuration identifiers (see optional-configs) are
used, "config_id" SHOULD be set to a randomly generated byte in the
first ClientHelloOuter and MUST be left unchanged for the second
ClientHelloOuter.
Paragraph (version B):
Finally, the client replaces "payload" with "final_payload" to obtain
ClientHelloOuter.  The two values have the same length, so it is not
necessary to recompute length prefixes in the serialized structure.
Paragraph (version B):
Note this construction requires the "encrypted_client_hello" be
computed after all other extensions.  This is possible because the
ClientHelloOuter's "pre_shared_key" extension is either omitted, or
uses a random binder (grease-psk).
Paragraph (version A):
If the server replies with a "pre_shared_key" extension in its
SeverHello, then the client MUST abort the handshake with an
"illegal_parameter" alert.
Paragraph (version B):
If the server replies with a "pre_shared_key" extension in its
ServerHello, then the client MUST abort the handshake with an
"illegal_parameter" alert.
Paragraph (version A):
ClientHelloOuterAAD is computed as described in authenticating-outer,
but again using the second ClientHelloOuter.  Note that the HPKE
context maintains a sequence number, so this operation internally
uses a fresh nonce for each AEAD operation.  Reusing the HPKE context
avoids an attack described in flow-hrr-hijack.
Paragraph (version B):
The client encodes the second ClientHelloInner as in encoding-inner,
using the second ClientHelloOuter for any referenced extensions.  It
then encrypts the new EncodedClientHelloInner value as a second
message with the previous HPKE context as described in encrypting-
clienthello.
Paragraph (version B):
Unless specified by the application using (D)TLS or externally
configured on both sides, implementations MUST NOT use this mode.