Subject: [quicwg/base-drafts] Stateless Reset becomes a larger risk of amplification with longer CIDs (#2770)

From: ianswett <[email-masked]>
Date: Tue, 04 Jun 2019 15:56:14 -0700

The two principles previously espoused were:
1) MUST ensure every stateless reset is smaller than the packet received to prevent looping: https://tools.ietf.org/html/draft-ietf-quic-transport-20#section-10.4.3
2) Stateless resets MUST be 69 bytes with #2749 in order to make them non-identifiable.

This means clients that want stateless resets in response to keepalives(ie: PINGs) must send 70 byte packets or risk getting nothing in response, therefore waiting for an RTO.

This seems like an unnecessary risk/complexity, when we could decrease the minimum size of the stateless reset being processed by a client.  The risk/cost to the client seems very low of processing stateless resets after a packet has already failed decryption.

Additionally, it's difficult to imagine a client ever use a 16 byte connection ID, and even more implausible the client will use a 48 byte connection ID, given most clients are expected to have one connection per port and even those with multiple likely won't have so many they need >8 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/2770

---

From: Martin Thomson <[email-masked]>
Date: Tue, 04 Jun 2019 16:06:04 -0700

In many cases even largish connection IDs will be around 20 bytes, meaning that minimal (PING) packets come to around 40 bytes.  Adding 30 bytes of padding is a little annoying.

@ianswett, the error in your description is here:
> when we could decrease the minimum size of the stateless reset being processed by a client

We don't stipulate any size constraints on *processing* packets, just generating them.  The sending constraints exist to prevent indefinite looping of stateless reset. They also eliminate amplification as a side-effect.

The reason we have this recommendation is to keep the stateless reset indistinguishable from "real" packets.  Though it might be a little unusual, a 70 byte packet isn't implausible, no matter what the situation.  But sending a 23 byte packet when every other packet included the same 40 byte connection ID will stand out badly.

-- 
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/2770#issuecomment-498875179

---

From: ianswett <[email-masked]>
Date: Tue, 04 Jun 2019 16:17:51 -0700

Reading that full section, though we specify a length of the stateless reset to be sent in the wire format, we don't use any normative language about size except: "Endpoints MUST discard packets that are too small to be valid QUIC packets." so I guess if, as a server, I believe sending a stateless reset of a certain size is unlikely to be distinguishable from a "real" packet, I can do that?

If so, that's not obvious, but it would seem there's no normative text change necessary.

-- 
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/2770#issuecomment-498877966

---

From: Martin Thomson <[email-masked]>
Date: Wed, 05 Jun 2019 19:02:41 -0700

Yes, there are a lot of places where the sizes are mere suggestions rather than concrete requirements.  That's intentional.  We could just say "oh well", but the problem here is that the gap between min and max has increased dramatically as a result of #2749.  That makes the choice to pad to a size that will trigger a stateless reset a harder call.

-- 
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/2770#issuecomment-499320030

---

From: Mike Bishop <[email-masked]>
Date: Thu, 06 Jun 2019 15:57:44 -0700

The problem is that while you as a server can do that, the question here is what size packet the client needs to send to provoke that behavior from a _generic_ server.  And the server can't just base it on the CID size that it uses locally, because what really matters is size relative to other packets flowing in that direction, i.e. the client's CID.  Which will often be zero, but can be immense and we need to account for that.

We currently say:
> An endpoint can increase the odds that a packet will trigger a Stateless Reset if it cannot be processed by padding it to at least 40 bytes.

There's a crazy way out by embedding your own minimum CID size (either unencrypted or non-privately) in every packet so that a server can use that to determine whether it could safely send you a smaller SR.  But adding an extra byte to all packets to save ~30 bytes per keepalive doesn't seem likely to work out well.

-- 
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/2770#issuecomment-499697994

---

From: MikkelFJ <[email-masked]>
Date: Thu, 06 Jun 2019 22:11:42 -0700

I can see the need for issuing a SRT ASAP in order for fast client side connection recovery. This is one reason there has been strong pushback against probabilistic resets as I have proposed before. Another reason is probably esthetical and because it wasn't that important when SRT's could be made small enough.

However, when you are facing a guessing game on how large to make packets and arbitrarily making payload larger than need be, and possible only some of the payload to eventually ensure a high chance of reset, I think this is really doing probabilistic resets the wrong way around.

I suggest that as long as you can send a SRT that is smaller than inbound you should. If you cannot do that are only permitted to send a SRT with a probability no larger than size(inbound)/size(SRT).

-- 
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/2770#issuecomment-499758754

---

From: ianswett <[email-masked]>
Date: Fri, 07 Jun 2019 06:55:52 -0700

I remember a few goals for stateless rejects(there are probably more):
 1) Cannot be spoofed
 2) Ideally an active attacker cannot cause a server to generate one for an active connection
 3) Indistinguishable from other traffic
 4) No amplification attacks
 5) No endless loops
 6) Can be sent in response to any packet that can't be associated with an active connection.

We compromised 6 in order to achieve 3 more often.  I think we can tweak the existing design to not compromise 6 and still provide 3.

We can put a bit more burden on the client and add text to indicate that if the client wants a stateless reject that's indistinguishable from other traffic, it needs to send a packet that's at least 1 byte larger than the minimum plausible incoming packet.  In most circumstances, I expect this to naturally occur because the server connection ID will be longer than the client's.

-- 
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/2770#issuecomment-499894384

---

From: MikkelFJ <[email-masked]>
Date: Fri, 07 Jun 2019 07:02:13 -0700

I think you messed two key goals

7. Allow peer to fail fast on dead connections.
8. Reduce unwanted inbound traffic from dead 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/2770#issuecomment-499896677

---

From: Kazuho Oku <[email-masked]>
Date: Sun, 09 Jun 2019 14:34:45 -0700

@ianswett 
> We can put a bit more burden on the client and add text to indicate that if the client wants a stateless reject that's indistinguishable from other traffic, it needs to send a packet that's at leas…

I think this would be the logical outcome, even though I am not sure I like the complexity.

At the moment, minimum packet size is calculated like: 1 + len(dcid) + 4 + len(aead_tag). Changing this to 1 + max(len(dcid), len(scid)) + 4 + len(aead_tag) is not _that_ difficult.

-- 
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/2770#issuecomment-500247440

---

From: Martin Thomson <[email-masked]>
Date: Mon, 10 Jun 2019 17:15:35 -0700

@kazuho add one to your calculation.

That would cause peers to generate packets that can be responded to with a stateless reset, but it wouldn't help the peer generating the stateless reset if it received a bogus packet.  It would be ignorant of a critical value.  That's not strictly a problem, and it might be that this is better than any alternative, but I do wonder about what sort of perverse incentives we're creating (with or without the clever hack).

-- 
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/2770#issuecomment-500638548

---

From: David Schinazi <[email-masked]>
Date: Tue, 11 Jun 2019 16:10:04 -0700

At the end of the day, I think the tradeoff is between the stateless reset sticking out and wasting padding bytes. Adding some text saying that endpoints that use longer connection IDs than their peers should pad their very short packets if they care about stateless resets not sticking out is the least awkward solution here? I don't think this is a really bad issue in practice.

-- 
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/2770#issuecomment-501057045

---

From: Ryan Hamilton <[email-masked]>
Date: Tue, 11 Jun 2019 16:31:41 -0700

To clarify, is it "longer connection IDs than their peers" or is it "peer's connection ID is smaller than a stateless reset token"?

-- 
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/2770#issuecomment-501062062

---

From: Martin Thomson <[email-masked]>
Date: Tue, 11 Jun 2019 16:49:53 -0700

It's smaller than their peer's.  The stateless reset token conveniently fits in the space we would ordinarily dedicate to an authentication tag.

-- 
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/2770#issuecomment-501065818

---

From: David Schinazi <[email-masked]>
Date: Mon, 17 Jun 2019 09:49:59 -0700

>From an offline conversation with @RyanAtGoogle , 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 indistinguishable from a stateless reset.

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.

This also means that the conversation about changing the maximum connection ID length is now orthogonal to stateless resets.

-- 
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/2770#issuecomment-502763574

---

From: Marten Seemann <[email-masked]>
Date: Tue, 18 Jun 2019 18:26:18 -0700

> 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 indistinguishable from a stateless reset.

That’s technically correct, but I‘m having doubts if this is s realistic scenario in practice. Realistically, a client would only pay the price of having a 18 byte overhead on every packet if it absolutely has to - i.e. if it’s behind an architecture that performs connection ID based routing and requires that many bits to do so. If that’s the case, changing to a 4 byte connection ID is not a realistic option. 

-- 
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/2770#issuecomment-503369786

---

From: David Schinazi <[email-masked]>
Date: Wed, 19 Jun 2019 14:11:39 -0700

@marten-seemann I'm not sure what you mean by "realistic scenario". The only property we need from a stateless reset is that it *could* be real traffic. The fact that it's unlikely traffic is not really relevant. The stateless reset is already going to stick out due to the fact that there are no subsequent packets after it since it closes the connection.

-- 
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/2770#issuecomment-503748150