Subject: [quicwg/base-drafts] Does it make sense to try 0-RTT after Retry? (#2842)

From: Marten Seemann <[email-masked]>
Date: Mon, 24 Jun 2019 16:48:28 -0700

In https://github.com/quicwg/base-drafts/pull/2831#pullrequestreview-253535028, @MikeBishop points out that after a Retry, all 0-RTT packets sent in the first flight are still valid, although they will probably have been dropped by the server (unless there's significant reordering). That means that a client SHOULD retransmit all 0-RTT packets in the second flight.

We now have two different scenarios:

1. In the case of a HelloRetryRequest, the client is prohibited from sending 0-RTT, and has to cancel retransmissions for all outstanding 0-RTT packets.
2. In the case of Retry, the 0-RTT packets from the first flight are declared lost (without any effect on the cwnd though) and retransmitted.

Considering that Retry adds a roundtrip anyway (and thereby limits the usefulness of 0-RTT), and that we only expect it to be used by a server that's under attack (which makes it likely to refuse 0-RTT later in the handshake), does it really make sense to send 0-RTT in that case?

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/2842

---

From: Kazuho Oku <[email-masked]>
Date: Mon, 24 Jun 2019 17:50:32 -0700

@marten-seemann 
> In #2831 (review), @MikeBishop points out that after a Retry, all 0-RTT packets sent in the first flight are still valid, although they will probably have been dropped by the server (unless there's significant reordering).

I am not sure if I agree with the observation. The transport draft states that _a server MAY send Retry packets in response to Initial and 0-RTT packets. A server can either discard or buffer 0-RTT packets that it receives ([section 17.2.5](https://quicwg.org/base-drafts/draft-ietf-quic-transport.html#rfc.section.17.2.5))_.

I am not sure if I like this ambiguity (because I think most if not all of us will be dropping 0-RTT packets that carry the original DCID when sending a Retry), but IMO the draft is clear.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/2842#issuecomment-505233944

---

From: Marten Seemann <[email-masked]>
Date: Mon, 24 Jun 2019 19:12:55 -0700

@kazuho, thanks for pointing that out. My point is that we should change the draft (i.e. this is a design issue, not an editorial issue).

> I am not sure if I like this ambiguity (because I think most if not all of us will be dropping 0-RTT packets that carry the original DCID when sending a Retry), but IMO the draft is clear.

The reason a server (or a LB) performs a Retry is that it either

- has reasons to suspect that the client isn't reachable at the 2-tuple it sent the packet from, or
- that it is under load, and either uses the Retry to redirect traffic to a different backend server, or just to buy itself some time

Under both circumstances, a server wouldn't want to allocate additional state for buffering 0-RTT packets.

I'm therefore suggesting to change the draft such that:
1. A server that performs a Retry MUST discard 0-RTT packets.
2. A client MUST NOT use 0-RTT after a Retry was performed.

Does that make sense to you?

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/2842#issuecomment-505249709

---

From: Kazuho Oku <[email-masked]>
Date: Mon, 24 Jun 2019 19:30:39 -0700

Yeah, I can envision a server that considers buffering some number of packets to be cheaper than doing a TLS handshake. For such servers, delaying the TLS handshake until client proves it's existence but buffering the 0-RTT packets in the meantime would make sense.

That said,

> 1. A server that performs a Retry MUST discard 0-RTT packets.

I'd be fine with this, assuming that the discarded 0-RTT packets are the ones that carry the original DCID.

>  2. A client MUST NOT use 0-RTT after a Retry was performed.

I would prefer not having this requirement. Once the client is known to exist, a server needs to communicate with the client. Use of 0-RTT helps reduce the server load, because when used, average lifetime of connections becomes 1-RTT less. That leads us to having less concurrent connections.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/2842#issuecomment-505253920

---

From: Nick Banks <[email-masked]>
Date: Mon, 24 Jun 2019 19:49:48 -0700

When our implementation does Retry, it's because we've hit a memory pressure limit and we want to protect ourselves from attack. If a client supplies us with a valid token, we will accept 0-RTT still, but we won't buffer it from the previous Initial (without a token). So, if the client gets a Retry and still wants to do 0-RTT then need to retransmit it, with the new CID, in a new packet (with a new packet number). I don't see why that design should be prevented.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/2842#issuecomment-505258243

---

From: Marten Seemann <[email-masked]>
Date: Tue, 25 Jun 2019 00:36:28 -0700

Ok, I see that there's value in doing 0-RTT after a Retry, and furthermore, there seem to be good reasons (prevention of tampering by middle boxes) to disallow 0-RTT after a HelloRetryRequest in TLS 1.3, as @kazuho pointed out OOB.

Since we can assume that most (all?) server implementation will drop 0-RTT packets when sending a Retry, the only reasonable thing to do for a client is to treat all 0-RTT packets as lost and retransmit them. Considering that, it would make sense to require servers to drop all Retry packets from the first flight, as @kazuho suggests.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/2842#issuecomment-505325239

---

From: Kazuho Oku <[email-masked]>
Date: Tue, 25 Jun 2019 03:45:54 -0700

@marten-seemann 
> Since we can assume that most (all?) server implementation will drop 0-RTT packets when sending a Retry, the only reasonable thing to do for a client is to treat all 0-RTT packets as lost and retra…

Thank you for suggesting a path forward.

I think my weak preference goes to something slightly different.

I think we are in agreement that most if not all the servers would not buffer the 0-RTT packets carrying the original DCIDs when they send Retrys. It makes sense to acknowledge the fact in the specification and suggest clients to retransmit 0-RTT data it has already sent.

What I am not sure is if there is a reason to forbid servers from buffering such 0-RTT packets.

>From client's point of view, sending 0-RTT data once per connection is an optimization. Retransmitting 0-RTT data when the server sends a Retry is further optimization. If we think that way, servers that buffer 0-RTT packets when sending a Retry has increased chance of utilizing 0-RTT data. Compared to that, there is no reason to mandate servers to drop 0-RTT packets.

To summarize, I think all we need to clarify is that servers responding with Retries are likely to discard 0-RTT packets that carry the original DCIDs and therefore that retransmitting 0-RTT data makes sense. But nothing more.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/2842#issuecomment-505390494

---

From: MikkelFJ <[email-masked]>
Date: Tue, 25 Jun 2019 04:35:10 -0700

What if client takes action on Retry, and the old 0-RTT state lingers - wouldn't that make servers more vulnerable to DDoS attacks from packet sniffers?

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/2842#issuecomment-505405242

---

From: Mike Bishop <[email-masked]>
Date: Tue, 25 Jun 2019 11:19:54 -0700

This also bears on #2837.  If the DCID doesn't change, then the server won't be able to differentiate the first flight of 0-RTT packets, which you're proposing to drop, from the second flight of 0-RTT packets which it accepts.

The current text says that the server MAY buffer and process them later; you're saying that servers probably won't.  I think that's fine, but some might -- hence, I favor @kazuho's suggestion to retain the permission to buffer but the caution to the client that the packets were quite possibly lost/dropped.  In terms of actual spec change, I think that means this text in [17.2.3](https://quicwg.org/base-drafts/draft-ietf-quic-transport.html#packet-0rtt):

> After a client receives a Retry packet, 0-RTT packets are likely to have been lost or discarded by the server. A client MAY attempt to resend data in 0-RTT packets after it sends a new Initial packet.

...becomes a SHOULD instead of a MAY.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/2842#issuecomment-505562759

---

From: Martin Thomson <[email-masked]>
Date: Wed, 26 Jun 2019 02:45:34 -0700

It seems like you have sorted this out.  I have no problem with using "SHOULD" over "MAY" here.

Note that the reason we have this distinction is logical separation of the mechanism of Retry and 0-RTT acceptance.  Retry strictly precedes the connection attempt.  No point in blocking 0-RTT if you have to Retry.  HelloRetryRequest is different in that certain characteristics it might cause to reset affect whether the 0-RTT works.  Retry is required to use the same ClientHello, so there is no need to have the two interact; you can treat a Retry almost as a loss event for the first Initial and everything works fine.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/2842#issuecomment-505802977