Subject: [quicwg/base-drafts] Stateless Reset packet sizes should not depend on the maximum connection ID length (#2869)

From: David Schinazi <[email-masked]>
Date: Tue, 02 Jul 2019 12:54:08 -0700

Currently, the spec recommends sending Stateless Reset packets of at least 39 bytes. The number is the minimum packet size when using the maximum connection ID length of 18:
- type byte: 1
- client connection ID: 18
- packet number + payload: 4
- auth tag: 16

39 = 1 + 18 + 4 + 16.

The intention there was to make Stateless Resets harder to distinguish from regular server-to-client traffic on a given QUIC connection.

However, when client connection IDs are in use, Stateless Resets are inherently distinguishable from regular traffic because they do not carry the previously-used client connection ID. One might say that they could be confused for a change in connection ID, which is true. But let's assume we just changed from an 18 byte client connection ID to a 4-byte connection ID (which is specifically allowed by the spec), then that new packet is still equally indistinguishable from a Stateless Reset. It is true that a client connection ID length change from 18 to 4 is unlikely, but that's not a problem. We just need it to be possible for this to be a valid packet to observers without keys.

So I propose that instead of having a minimum required size for stateless resets of 21 and a recommended minimum of 39, we can just say the minimum required size is 25. The important value here is the minimum non-zero connection ID length, not the maximum connection ID length.

At the end of the day, a Stateless Reset will stick out to observers who will notice that the client stops sending on that particular connection. The current value of 39 is harming the protocol by increasing the odds of servers not sending Stateless Resets which will cause timeouts on clients instead of failing fast. This is a tradeoff, and we should strive to avoid timeouts instead of trying to hide a packet that can't be hidden.

-- 
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/2869

---

From: ianswett <[email-masked]>
Date: Tue, 02 Jul 2019 13:43:51 -0700

This is related to Issue #2770 

-- 
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/2869#issuecomment-507837274

---

From: Martin Thomson <[email-masked]>
Date: Tue, 02 Jul 2019 15:31:30 -0700

> assume we just changed from an 18 byte client connection ID to a 4-byte connection ID 

This does not permit the attacker any knowledge of the client.  If a client always selects an 18 byte connection ID, a stateless reset will stand out.

> a Stateless Reset will stick out to observers who will notice that the client stops sending on that particular connection

The goal is to avoid having the message interfered with in transit.  After it gets through and is processed, what happens after doesn't matter.

-- 
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/2869#issuecomment-507868613

---

From: ianswett <[email-masked]>
Date: Tue, 02 Jul 2019 15:38:42 -0700

#2153 is also related I believe.

-- 
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/2869#issuecomment-507870224

---

From: ianswett <[email-masked]>
Date: Tue, 02 Jul 2019 15:51:35 -0700

The goal is not to avoid the attacker dropping the packet(I'm not sure what other type of interference is possible here?).  If they can do that, they can drop all packets and that's likely even worse.  The goal is to ensure the packet can't be reliably identified as a stateless reset, which is a much lower bar.

As I stated on #2770, if the client wants to ensure it's reset is always large enough to be indistinguishable, it needs to send a packet size that's one byte larger than the smallest packet it expects to receive.  Typically, this is a no-op for the client, so compliance is trivial.

No matter what happens, a server may send a stateless reset in response to any QUIC packet that's large enough to be valid, and it's not sensible to try to prevent a server from doing that.

Even if the packet is smaller than other packets, it's just odd, not invalid, as David said.

If we don't do this, I fear clients will increase their effective minimum packet size substantially, which is a cost everyone has to bear, when a large number of clients will use 0 byte CIDs.

-- 
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/2869#issuecomment-507873146

---

From: Martin Thomson <[email-masked]>
Date: Tue, 02 Jul 2019 18:16:48 -0700

My point is that the packet *is* invalid, if it is sent to a client that you know uses longer connection IDs.  The middlebox can then *reliably* identify the packet as being a stateless reset.  All it needs to know is that that client never uses shorter connection IDs.  That's not difficult; we don't assume that this sort of information is a secret.

-- 
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/2869#issuecomment-507900254

---

From: ianswett <[email-masked]>
Date: Tue, 02 Jul 2019 19:07:17 -0700

The only rule is that the CID can't become 0 length, so why is it invalid?  If the middlebox can't reliably identify the packet as invalid, it's all a matter of statistics and how much of an anomaly it is.  Sure, maybe it's an anomaly for CIDs to go from 18 to 1, but I don't think that's the most likely anomaly on the internet(see below).

I think the existing rule is actively harmful in multiple ways, one of which is a possible escalation of the minimum client packet size mentioned above.

The more problematic issue is that the goal is to have stateless reset not stick out and be clearly identifiable.  If so, we want the widest selection of sizes possible.  Given servers are going to want to send stateless resets smaller than the client's packet, a fixed size is going to stick out and the larger the minimum fixed size, the more it's going to stick out.  In particular, 40 is enough larger than the typical 'small' server to client packet(ie: ACK) that it's relatively unlikely on a typical connection.  If 90%+ of 40 byte payloads are stateless rejects, then we have failed at our goal and I think that's where we're at today.

To come back to my previous suggestion, why can't the client enforce this?

-- 
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/2869#issuecomment-507909237

---

From: Martin Thomson <[email-masked]>
Date: Tue, 02 Jul 2019 20:31:40 -0700

It's not generically invalid, it's only invalid in a particular context.  And we have to assume that our adversary understands that context better than the endpoint that generates the stateless reset.  That's all.

To be clear, we don't expressly forbid sending of a smaller stateless reset, only strongly imply that it won't be effective.  So I'm struggling to understand what you would concretely do here.

-- 
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/2869#issuecomment-507923774

---

From: David Schinazi <[email-masked]>
Date: Wed, 03 Jul 2019 13:18:34 -0700

@martinthomson What is this adversary trying to accomplish here? Can you elaborate on threat vector? The number 39 is reducing the reliability of the protocol, what security property does it give us in exchange?

-- 
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/2869#issuecomment-508240533

---

From: Martin Thomson <[email-masked]>
Date: Wed, 03 Jul 2019 18:34:04 -0700

I believe that we wanted to avoid the observer from being able to recognize resets.  The idea being that recognition preceded some sort of action.  The worst I can imagine here is dropping state prior to the endpoints being ready for that.  For instance, forwarding the packet and then dropping NAT bindings immediately, which - if that packet is lost - might leave the recipient with the belief that it still has an active connection when it does not.

The point being that we're attempting to avoid facilitation of bad behaviour.

Perhaps you can talk about the way in which you perceive reliability being reduced.  39 isn't exactly a very large number, nor is it a hard limit.

-- 
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/2869#issuecomment-508306030

---

From: David Schinazi <[email-masked]>
Date: Fri, 05 Jul 2019 17:39:33 -0700

I agree with this threat model. We really want to avoid NATs reacting to stateless resets the way they react to TCP RSTs today.

However, we've heard from implementors that the majority of QUIC traffic will not use client connection IDs. But there will be an implementation that uses them (either all the time, or at least some of the time, to apply grease to servers to make sure they support them). Let's assume there is a client implementation called CLIENT_18 that always uses 18-byte client CIDs. Do you think someone will go out of their way to implement code that detects CLIENT_18 traffic, and then installs a rule for those connections only where the detection of a server-to-client packet shorter than 39 bytes will drop the NAT mapping? This sounds about as likely as a NAT implementation that drops packets whose connection IDs are prime numbers...

To answer your question on reliability: I think it will be common to have a client establish a connection, send some requests, get the responses, then idle for a few minutes, then after user action, sends another request. Assuming the server uses 8-byte CIDs, this will cause the client to send a packet than can easily be under 39 bytes (assuming a short request). Let's assume the server has restarted during the idle period. It won't recognize the connection ID. If the server decides that this packet is too short to trigger a stateless reset, then the client will timeout causing user-visible delays. For a protocol with such a goal of improving latency, a timeout is a critical failure.

The issue here is that the spec doesn't mandate the client to pad its packets, and allows servers to not respond to short packets. Giving both implementations too much leeway is dangerous here.

It would be in the spirit of the spec to be more prescriptive. We remove the 39-byte requirement, and tell servers that their stateless resets should be of length in the range `[min(39, client_packet_size - 1), max(39, client_packet_size - 1)]`. We then tell clients to pad their packets such that `packet_number_length + payload_length >= 4 + max(0, max_used_client_cid_length - server_cid_length)`.

-- 
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/2869#issuecomment-508884624

---

From: Martin Thomson <[email-masked]>
Date: Sun, 07 Jul 2019 16:31:13 -0700

I could live with that.  That is a lot harder to write down, but I think that it might work.  I wouldn't make the calculation so complex (just say that the minimum packet size is `maxcid+19` to account for 1 type byte, 1 data byte, and 16 auth tag bytes plus the connection ID length and the one extra byte we lose for the stateless reset) and I wouldn't tie it to a particular role (stateless reset is supposed to be symmetric, it's just that one direction in particular is more likely by far).  We can leave the details to implementations.

I was concerned about clients that were also identifiable by means easier than fingerprinting.  Say someone who deployed client code in their server cluster, where connection IDs are far more likely as a client, for whom any packet (to a client or server) could be readily identified as a stateless reset by virtue of its size.  Profiling by IP address would be easy for someone to do 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/2869#issuecomment-509039192

---

From: MikkelFJ <[email-masked]>
Date: Sun, 07 Jul 2019 23:41:12 -0700

What about small ACK-only packets? Would they have to be padded - and what would the avg. cost be of that?

-- 
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/2869#issuecomment-509099218

---

From: ianswett <[email-masked]>
Date: Mon, 08 Jul 2019 03:26:47 -0700

I also agree that not recognizing resets is the goal, but I don't think we're currently achieving that for reasons stated above.  And as David pointed out, I think there are allowed behaviors that would not elicit a stateless reset when you'd really like to have one sent.

Why maxcid length, not mincid length if we're trying to establish the lower bound on the packet size that could have been sent previously in the connection?  Either way, mincid+19 works for me, since I'm mostly concerned about cases with 0, or small fixed CID lengths.

-- 
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/2869#issuecomment-509170795

---

From: Martin Thomson <[email-masked]>
Date: Mon, 08 Jul 2019 04:45:27 -0700

You are right, it's the minimum length.  For 0, that means 0.

-- 
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/2869#issuecomment-509192281