Subject: [TLS] ECH Padding

From: Christopher Patton <[email-masked]>
Date: Tue, 22 Jun 2021 14:27:16 -0700

Hi all,

One of the last design questions for Encrypted ClientHello (ECH) is to
decide how to pad encrypted handshake messages so that their length does
not leak privacy-sensitive handshake-parameters. The current approach is to
insert padding into the record layer as needed. However, the consensus
reached in [1] is that computing record-layer padding based on the contents
of handshake messages entails implementation complexity that is untenable,
particularly for QUIC and DTLS. The alternative that most folks are happy
with is to insert padding into the handshake messages themselves, as this
prevents details of the handshake logic from bleeding into the record layer
code.

There are a few PRs for adding handshake-level padding that we could use
feedback on.

    (1) https://github.com/tlswg/draft-ietf-tls-esni/pull/443 Adds padding
to EncodedClientHelloInner, the message that is encrypted and stuck into
the ECH extension of the ClientHelloOuter. This prevents leakage of
sensitive parameters in ClientHelloInner.

    (2) https://github.com/tlswg/draft-ietf-tls-esni/pull/313 Defines a new
extension, which the client sends in ClientHelloInner in order to solicit a
response in the backend server's EncryptedExtensions message. The server''s
response contains padding it can use to prevent leakage of sensitive
parameters in its first flight of handshake messages.

    (3) https://github.com/tlswg/draft-ietf-tls-esni/pull/457 (alternative
to (2)) Defines a new handshake message, Padding, which the client and
backend server always send just before Finished in case of ECH acceptance.
One advantage of this approach over (2) is that the length of the padding
can be evaluated after the Certificate/CertificateVerify messages have been
chosen, making it possible to account for sensitive parameters in these
messages without needing to buffer the whole flight of messages. The
downside is that it may add complexity to the state machine of TLS 1.3
implementations.

There are some open questions regarding how to compute the padding length,
but these should be orthogonal to deciding the mechanism.

Thanks on behalf of (some of) the contributors,

Chris P.
____
[1] "Handshake-level vs record-level padding."
https://github.com/tlswg/draft-ietf-tls-esni/issues/264

---

From: Stephen Farrell <[email-masked]>
Date: Tue, 22 Jun 2021 22:39:49 +0100

(1) aka #443 is the way to go here I think. (Such an aptly
numbered PR has to be accepted I'd say:-) I'm only convinced
of that because of QUIC, but that seems like enough or a
rationale.

I'm against (3) - it'd break too much and cost too much.

WRT (2) I'd prefer to drop that extensibility rather than
try use it because it's there.

Cheers,
S.

On 22/06/2021 22:27, Christopher Patton wrote:
> _______________________________________________
> TLS mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/tls
>

---

From: Christopher Patton <[email-masked]>
Date: Tue, 22 Jun 2021 14:57:53 -0700

> try use it because it's there.

Just to be clear, (1), (2) and (3) are not alternatives to the same
problem. (1) solves client-side padding, whereas (2) and (3) are
alternatives for solving server-side padding.

---

From: David Benjamin <[email-masked]>
Date: Tue, 22 Jun 2021 17:59:03 -0400

I think there might be some confusion here. It probably doesn't help that
(1) and [1] are different things. :-)

(1) is a standalone change, unrelated to QUIC, [1], (2), or (3). It's about
changing how we pad the *ClientHelloInner*, which is carried in the ECH
encrypted payload. We currently use the ClientHello padding extension
(RFC7685). The PR moves it to the EncodedClientHelloInner structure. This
removes the need to carefully integrate your padding computation with the
rest of your ClientHelloInner computation, which makes whole-message
padding strategies easier but doesn't particularly help or harm QUIC.

(2) and (3) are two possible solutions for [1] and mutually exclusive,
which is about padding the *other messages*, notably the server Certificate
message, which are carried in normal TLS records. We currently use TLS 1.3
record-level padding. However, the observation in [1] is that, since QUIC
replaces the record layer, this does not work very well. I suspect DTLS,
having an unreliable transport, will also find the record-level padding
tricky. The proposed fix is to embed the padding into the handshake
somewhere. (2) and (3) are different possible spellings for this, either
using the EncryptedExtensions message (2), or by introducing a new Padding
message into the handshake flight (3).

Regarding dropping extensibility, whether or not we go with (2), we
*definitely* cannot drop the server EncryptedExtensions message! That one
is used throughout TLS! Just look for "EE" in the registry. :-P

Between (2), (3), and nothing, I would prefer (3). Doing nothing would be
problematic for QUIC deployments, and we shouldn't force servers to pick
between ECH and QUIC. (They won't pick ECH.) Either (2) or (3) would be
invisible to the record layer, so QUIC and DTLS will work without any
effort. However, unlike (2), (3) comes after the messages we would like to
pad, so you don't need to predictively size things, or generate messages in
the wrong order. In particular, ECDSA signatures are variable-length, so if
you aim to pad different key types together, (2) won't even work. (Though
doing so is an anonymity set size vs. bandwidth tradeoff, since part of the
point of ECDSA is the smaller signatures.) It also more naturally extends
to the client certificate. Finally, I think part of the original thinking
with (2) was that we'd reuse the RFC7685 mechanism, but between (1) and
compat issues on the PR, (2) cannot actually achieve that anyway.

David

---

From: Stephen Farrell <[email-masked]>
Date: Tue, 22 Jun 2021 23:12:20 +0100

> alternatives for solving server-side padding.

Apologies. (Though I put part of the blame on excessive
githubbery leading to a lack of clarity and ambiguity, as
is my habit:-)

I can live with (1) and (2) but only see any need to change
because of the QUIC argument(s) - absent those we can work
around things and get ECH out the door IMO.

(3) is a mistake - a new handshake message shouldn't be
adopted until after that's been tested and shown not to
be problematic and I bet it would be problematic as well
as lots more work

S.

---

From: David Benjamin <[email-masked]>
Date: Tue, 22 Jun 2021 18:44:36 -0400

> be problematic and I bet it would be problematic as well

Could you clarify what sorts of problems you'd like to test for?

In my experience, beyond just correctly handling extensibility, the main
problem to watch for with handshake messages is optionality. That is, when
it is not defined what the next message is, your state machine needs to
branch on the received message type. (Although we've certainly done that
before, e.g. CertificateRequest.) The formulation in (3) avoids this
because the message's presence is fully determined by whether ECH was
negotiated. Gating it on some negotiation is also how you handle
extensibility. When we do that, my experience is that the implementation is
reasonable.

What we gain from that is computing padding in the right order. Unlike (3),
(2) computes the padding *before* the data being padded. It also has no way
to pad the client certificate. How tricky that is will vary based on the
padding strategy you wish to use, and padding strategies are where we have
a lot of unknowns in ECH. That seems risky to me. Needing to predict
lengths is also a source of complexity, and indeed part of the aim of (1)
was to remove a case of this.

David

---

From: "Martin Thomson" <[email-masked]>
Date: Wed, 23 Jun 2021 08:55:14 +1000

So I like #443 as I have said.  It simplifies padding for CHInner a lot.

I also like #457 (option 3).  My initial reaction was not positive, but I've come to appreciate the value of it.  I don't like that this has to be in the transcript (QUIC doesn't need it by virtue of a design that separates protection levels from content type), but as far as solutions go it is the easiest to implement.  In other words, it has the fewest awful shortcomings - a benchmark that has come to define ECH.

On Wed, Jun 23, 2021, at 07:27, Christopher Patton wrote:
> decide how to pad encrypted handshake messages so that their length 
> does not leak privacy-sensitive handshake-parameters. The current 
> approach is to insert padding into the record layer as needed. However, 
> the consensus reached in [1] is that computing record-layer padding 
> based on the contents of handshake messages entails implementation 
> complexity that is untenable, particularly for QUIC and DTLS. The 
> alternative that most folks are happy with is to insert padding into 
> the handshake messages themselves, as this prevents details of the 
> handshake logic from bleeding into the record layer code.
> 
> There are a few PRs for adding handshake-level padding that we could 
> use feedback on.
> 
>     (1) https://github.com/tlswg/draft-ietf-tls-esni/pull/443 Adds 
> padding to EncodedClientHelloInner, the message that is encrypted and 
> stuck into the ECH extension of the ClientHelloOuter. This prevents 
> leakage of sensitive parameters in ClientHelloInner.
> 
>     (2) https://github.com/tlswg/draft-ietf-tls-esni/pull/313 Defines a 
> new extension, which the client sends in ClientHelloInner in order to 
> solicit a response in the backend server's EncryptedExtensions message. 
> The server''s response contains padding it can use to prevent leakage 
> of sensitive parameters in its first flight of handshake messages.
> 
>     (3) https://github.com/tlswg/draft-ietf-tls-esni/pull/457 
> (alternative to (2)) Defines a new handshake message, Padding, which 
> the client and backend server always send just before Finished in case 
> of ECH acceptance. One advantage of this approach over (2) is that the 
> length of the padding can be evaluated after the 
> Certificate/CertificateVerify messages have been chosen, making it 
> possible to account for sensitive parameters in these messages without 
> needing to buffer the whole flight of messages. The downside is that it 
> may add complexity to the state machine of TLS 1.3 implementations.
> 
> There are some open questions regarding how to compute the padding 
> length, but these should be orthogonal to deciding the mechanism.
>

---

From: Christopher Patton <[email-masked]>
Date: Wed, 23 Jun 2021 16:23:56 -0700

I support adopting #443. For the server side, I have a weak preference for
#457 (2) over #313 (3) because it makes it easier to implement a complete
solution. I have not yet assessed how hard it is to implement ... perhaps
it would be best if we all tried it out in our respective stacks and report
back on the complexity?

Chris P.

On Tue, Jun 22, 2021 at 3:56 PM Martin Thomson <[email-masked]> wrote:

> I also like #457 (option 3).  My initial reaction was not positive, but
> I've come to appreciate the value of it.  I don't like that this has to be
> in the transcript (QUIC doesn't need it by virtue of a design that
> separates protection levels from content type), but as far as solutions go
> it is the easiest to implement.  In other words, it has the fewest awful
> shortcomings - a benchmark that has come to define ECH.
>