Subject: Going STEK-less with QUIC?

From: Christian Huitema <[email-masked]>
Date: Tue, 27 Jul 2021 14:02:02 -0700

In theory, TLS 1.3 provides strong future secrecy guarantees, but the 
handling of session tickets can compromise that. In theory, the session 
Ticket could be a simple identifier, used by the server to retrieve the 
context of a past session. In practice, many servers encode the relevant 
session context data in the session ticket itself, using a Session 
Ticket Encryption Key (STEK). For server farms, there is no guarantee 
that the resumed session will hit the same server as the initial 
session, so in practice all servers in the farm share the STEK. And 
then, we have a serious future secrecy issue: if the STEK leaks, the 
attackers can decrypt all the sessions that were encrypted with that 
STEK, and might also be able to decrypt the initial sessions. In short, 
STEKs are convenient but risky.

The load balancing draft defines Connection ID formats that assure that 
packets get routed to the right server in a pool. I think that we could 
use these connection IDs to ensure that a resumed connection goes back 
to the same server as the initial server. The simplest implementation 
would be for the client to remember one of the "New connection IDs" 
received in the initial session, and use that as Initial Connection ID 
in the resumed session. Once we do that, we get options. The server 
could for example have a server specific STEK, which reduces the impact 
of leaking STEk to just the sessions handled by that server, instead of 
all the sessions by servers sharing the STEK. Or, the server could just 
remember contexts of past sessions locally, and just place an identifier 
of that context in the session ticket, effectively going STEK-less.

Would there be any interest in pursuing that idea?

-- Christian Huitema

---

From: Andrei Popov <[email-masked]>
Date: Tue, 27 Jul 2021 21:22:05 +0000

> if the STEK leaks, the attackers can decrypt all the sessions that were encrypted with that STEK, and might also be able to decrypt the initial sessions. In short, STEKs are convenient but risky.

This is only a problem if the client and server negotiate psk_ke mode, rather than psk_dhe_ke, correct?

Cheers,

Andrei

-----Original Message-----
From: QUIC <[email-masked]> On Behalf Of Christian Huitema
Sent: Tuesday, July 27, 2021 2:02 PM
To: IETF QUIC WG <[email-masked]>
Subject: [EXTERNAL] Going STEK-less with QUIC?

In theory, TLS 1.3 provides strong future secrecy guarantees, but the handling of session tickets can compromise that. In theory, the session Ticket could be a simple identifier, used by the server to retrieve the context of a past session. In practice, many servers encode the relevant session context data in the session ticket itself, using a Session Ticket Encryption Key (STEK). For server farms, there is no guarantee that the resumed session will hit the same server as the initial session, so in practice all servers in the farm share the STEK. And then, we have a serious future secrecy issue: if the STEK leaks, the attackers can decrypt all the sessions that were encrypted with that STEK, and might also be able to decrypt the initial sessions. In short, STEKs are convenient but risky.

The load balancing draft defines Connection ID formats that assure that packets get routed to the right server in a pool. I think that we could use these connection IDs to ensure that a resumed connection goes back to the same server as the initial server. The simplest implementation would be for the client to remember one of the "New connection IDs" 
received in the initial session, and use that as Initial Connection ID in the resumed session. Once we do that, we get options. The server could for example have a server specific STEK, which reduces the impact of leaking STEk to just the sessions handled by that server, instead of all the sessions by servers sharing the STEK. Or, the server could just remember contexts of past sessions locally, and just place an identifier of that context in the session ticket, effectively going STEK-less.

-- Christian Huitema

---

From: Christian Huitema <[email-masked]>
Date: Tue, 27 Jul 2021 15:30:42 -0700

Negotiating psk_dhe_ke does mitigate some of the issues, but not all. 
For example, using DHE does not mitigate the secrecy issues with 0RTT. 
Another related issue is ensuring that tickets are used exactly once for 
0RTT. That's a lot easier if the resumption server is the same as the 
initial server. Then for QUIC there is also the issue of clients 
remembering negotiated transport parameters from the initial session and 
reusing them in 0RTT, which breaks if the resumption server does not use 
the same parameters as the initial server.

-- Christian Huitema

---

From: Andrei Popov <[email-masked]>
Date: Tue, 27 Jul 2021 22:44:12 +0000

> Another related issue is ensuring that tickets are used exactly once for 0RTT. That's a lot easier if the resumption server is the same as the initial server.
Certainly, but this is not always achievable as server VMs rotate in and out of existence. Also, maintaining affinity between TLS clients and servers complicates load-balancing.

> Then for QUIC there is also the issue of clients remembering negotiated transport parameters from the initial session and reusing them in 0RTT, which breaks if the resumption server does not use the same parameters as the initial server.
This can be solved without creating affinity between TLS clients and servers. E.g., by including the negotiated QUIC parameters in the ticket.

Cheers,

Andrei

-----Original Message-----
From: Christian Huitema <[email-masked]> 
Sent: Tuesday, July 27, 2021 3:31 PM
To: Andrei Popov <[email-masked]>; [email-masked]
Subject: Re: [EXTERNAL] Going STEK-less with QUIC?

Negotiating psk_dhe_ke does mitigate some of the issues, but not all. 
For example, using DHE does not mitigate the secrecy issues with 0RTT. 
Another related issue is ensuring that tickets are used exactly once for 0RTT. That's a lot easier if the resumption server is the same as the initial server. Then for QUIC there is also the issue of clients remembering negotiated transport parameters from the initial session and reusing them in 0RTT, which breaks if the resumption server does not use the same parameters as the initial server.

-- Christian Huitema

---

From: Kazuho Oku <[email-masked]>
Date: Wed, 28 Jul 2021 08:02:54 +0900

> Would there be any interest in pursuing that idea?

I'm not sure if we'd be interested in deploying this sort of stuff, due to
the following two reasons:

* Most if not all of large-scale HTTP deployments use STEK for
TLS-over-TCP. Therefore, even if we address the issue on the QUIC side, the
low bar remains as-is on the TCP side.
* By allowing clients to "stick" to reusing the same server across multiple
connections, we are creating a new DoS attack vector that allows attackers
to target a particular host behind a load balancer. While we can implement
mitigations, that is an additional complexity.

That said, if we are to pursue this, I wonder if it would be better to
solve the issue entirely on the load-balancer & server side rather than
making a protocol change to QUIC.

To give an example, I think the same result can be achieved in practice by
designing a format of NEW_TOKEN tokens that is to be shared by the load
balancer and the server. That token would contain the server-id. When the
load balancer receives an Initial packet conveying such a token, it can
parse the server-id contained in that token, and forward the packet to the
specified backend.

-- 
Kazuho Oku

---

From: "Martin Thomson" <[email-masked]>
Date: Wed, 28 Jul 2021 11:28:36 +1000

On Wed, Jul 28, 2021, at 09:02, Kazuho Oku wrote:
> [...] I think the same result can be achieved in practice 
> by designing a format of NEW_TOKEN tokens that is to be shared by the 
> load balancer and the server. That token would contain the server-id. 
> When the load balancer receives an Initial packet conveying such a 
> token, it can parse the server-id contained in that token, and forward 
> the packet to the specified backend.

Yep, that would work.  And the load balancer might choose not to honour the server selection choice if that instance was looking a little overloaded.

In other words, no standard needed in all cases, but maybe another something for QUIC-LB to manage.

---

From: Christian Huitema <[email-masked]>
Date: Tue, 27 Jul 2021 18:55:37 -0700

> In other words, no standard needed in all cases, but maybe another something for QUIC-LB to manage.

It is a matter of expectations. Suppose that the server goes STEK-less. 
It is only capable of honoring 0-RTT if the resumed session is routed to 
the same server as the initial server. Yes, the clients can unilaterally 
decide to reuse one of the NEW TOKENS as Initial CID, no new standard 
required there. But if they don't, and pick a random ID, the resumed 
connections will arrive at a random server, and 0-RTT will fail. So, if 
we want to encourage the "new token as initial" behavior, we may want to 
write something.

-- Christian Huitema

---

From: "Martin Thomson" <[email-masked]>
Date: Wed, 28 Jul 2021 16:42:36 +1000

On Wed, Jul 28, 2021, at 11:55, Christian Huitema wrote:
> [...] reuse one of the NEW TOKENS as Initial CID, [...]

Are you talking about NEW_CONNECTION_ID here?

If you are talking about the client taking a connection ID from an old connection and using that when establishing a new connection, that's an interesting choice.  I don't think it works because it undermines the return routeability check for the subsequent connection.  The server now knows what the connection ID might be.  I can't think of an exploit for that given that the server has already demonstrated that it is on path, but we do pretty much say that the connection ID can't be predictable like that, and there are no firm requirements that the subsequent connection attempt follow the same network path in any way.

I had assumed that the load balancer would be able to identify an initial and then route based on the Token field in that packet, rather than the connection ID.  Maybe that's too complicated, but it is something that could be used without protocol modifications.

---

From: Christian Huitema <[email-masked]>
Date: Wed, 28 Jul 2021 10:07:54 -0700

> Are you talking about NEW_CONNECTION_ID here?

Yes. Sorry for the confusion. (Skipping comments on the progressive 
effect of aging on Christian's brain cells.) My initial idea was for 
creating an extension frame, with the server providing a new connection 
ID for the specific purpose of use in resumption of this connection. In 
a private message, Martin Duke suggested that clients could just as well 
use one of the NEW CONNECTION ID provided by the server. Clients can do 
that today, no change in spec required.

> If you are talking about the client taking a connection ID from an old connection and using that when establishing a new connection, that's an interesting choice.  I don't think it works because it…

I was not suggesting that placing a specific value in the ICID replaces 
the need for tokens and checking return routeability. Now, it is true 
that the servers and the load balancers could also coordinate their 
handling of token, and achieve the desired effect of sending connection 
resumption attempts to the same server as the original connection. That 
may very well be a better design than relying on the client to put 
specific values in the ICID.

> I had assumed that the load balancer would be able to identify an initial and then route based on the Token field in that packet, rather than the connection ID.  Maybe that's too complicated, but i…

Yes. Looks like the way to go if we want to experiment with STEK-less.

I think placing the NEW CONNECTION ID in an ICID has a different usage 
-- testing the robustness of load balancing...

-- Christian Huitema

---

From: Martin Duke <[email-masked]>
Date: Thu, 29 Jul 2021 14:33:59 -0700

I can't speak to the security concerns MT raised, but if we do use
NEW_CONNECTION_ID to populate the initial DCID in later connections, I *do*
think we need to write down this expectation somewhere, and QUIC-LB may be
as good a place as any.

1. How does the client know that the resumption state is local, and
therefore that it should use a previously provided connection ID?

2. A Retry would hopefully not divert this to a different server (but maybe
under Retry conditions killing resumptions is acceptable)

On Wed, Jul 28, 2021 at 10:08 AM Christian Huitema <[email-masked]>
wrote:

> > If you are talking about the client taking a connection ID from an old
> connection and using that when establishing a new connection, that's an
> interesting choice.  I don't think it works because it undermines the
> return routeability check for the subsequent connection.  The server now
> knows what the connection ID might be.  I can't think of an exploit for
> that given that the server has already demonstrated that it is on path, but
> we do pretty much say that the connection ID can't be predictable like
> that, and there are no firm requirements that the subsequent connection
> attempt follow the same network path in any way.
>
> > I had assumed that the load balancer would be able to identify an
> initial and then route based on the Token field in that packet, rather than
> the connection ID.  Maybe that's too complicated, but it is something that
> could be used without protocol modifications.
>