Subject: [quicwg/base-drafts] Backoff of CONNECTION_CLOSE needs to be a MUST (#3095)

From: Kazuho Oku <[email-masked]>
Date: Tue, 15 Oct 2019 17:15:22 -0700

At the moment, the backoff is merely a recommendation. Quoting from [section 10.3](https://quicwg.org/base-drafts/draft-ietf-quic-transport.html#rfc.section.10.3): _endpoints SHOULD limit the number of packets they generate containing a CONNECTION_CLOSE frame._

However, there is a DoS attack vector unless we make this a MUST, as an attacker can create bounce of packets carrying CONNECTION_CLOSE frames between two servers.

Consider the case where you have two servers (A, B) that use the original DCIDs supplied by the client as the server CIDs.

The attacker sends the following two Initial packets:
* srcaddr=A, destaddr=B, srcCID=X, destCID=Y
* srcaddr=B, destaddr=A, srcCID=Y, destCID=X

Both of the two packets would contain an invalid payload.

Then, both server A and server B would enter the CLOSING state sending CONNECTION_CLOSE frame to the peer. While in the CLOSING state, the specification allows endpoints to respond to packets from peer without decrypting them. Therefore, this creates a ping-pong.

To prevent this type of attack, I think we need to change "SHOULD limit" of the quoted text to "MUST limit". The alternative might be to forbid servers adopting the DCID given by the clients as their server 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/3095

---

From: ianswett <[email-masked]>
Date: Wed, 16 Oct 2019 07:55:50 -0700

In this case, I believe both sides are in the server role.  Servers don't need to pad Initial packets and servers drop Initials less than 1200 bytes, so I believe the other 'Server' would drop the Initial CONNECTION_CLOSE and this would stop quickly.

However, if an implementation padded all Initials, this could be a problem, so more clarity on Initial padding may be necessary?  ie: Servers SHOULD NOT pad Initial packets containing only CONNECTION_CLOSE.

-- 
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/3095#issuecomment-542741957

---

From: Kazuho Oku <[email-masked]>
Date: Wed, 16 Oct 2019 08:10:33 -0700

> Servers don't need to pad Initial packets and servers drop Initials less than 1200 bytes, so I believe the other 'Server' would drop the Initial CONNECTION_CLOSE and this would stop quickly.

Oh I missed that point. Thank you for pointing it out.

Though it is still possible to mount this attack by sending an invalid 0-RTT packet

Consider the case where an attacker obtains a session ticket from both servers beforehand, and sends datagrams to the servers, each consisting of Initial and 0-RTT packets (of which 0-RTT packet contains an invalid frame). Then, assuming that both servers accept 0-RTT, they would send to each other a series of Initial, Handshake, and 1-RTT packets, of which the 1-RTT packet would contain an CONNECTION_CLOSE frame.

So that would cause a ping-pong.

-- 
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/3095#issuecomment-542749202

---

From: Kazuho Oku <[email-masked]>
Date: Wed, 16 Oct 2019 09:38:16 -0700

PS. Though I now realize that the maximum about of bytes that each server would ping-pong is limited to 3x the size of the datagram that the attacker sends.

So it might be possible to call this a non-issue, though the number of UDP packets that the servers would send might be less concerning (it would be like 30 UDP packets, assuming that the packets containing CONNECTION_CLOSE would be around 100 bytes each).

-- 
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/3095#issuecomment-542788331

---

From: Lars Eggert <[email-masked]>
Date: Wed, 16 Oct 2019 15:40:22 -0700

Discussed in Cupertino. @kazuho to write up a PR that replaces SHOULD by MUST in this 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/3095#issuecomment-542920544

---

From: Martin Thomson <[email-masked]>
Date: Wed, 16 Oct 2019 15:41:06 -0700

Note that this is only MUST in the case where the server drops state and uses a canned packet.

-- 
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/3095#issuecomment-542920719

---

From: Jana Iyengar <[email-masked]>
Date: Wed, 16 Oct 2019 15:41:54 -0700

I would suggest saying that impls MUST implement one of the two solutions: MUST NOT use the client's DCID as the SCID, or MUST do an exponential backoff if it does.

-- 
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/3095#issuecomment-542920940

---

From: Jana Iyengar <[email-masked]>
Date: Wed, 16 Oct 2019 15:46:37 -0700

An alternative would be to simply require backoff always. Whether or not a canned packet is used. Not backing off seems like a live wire, and it might be better to neutralize it in general.

-- 
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/3095#issuecomment-542922121

---

From: Martin Thomson <[email-masked]>
Date: Wed, 16 Oct 2019 16:06:20 -0700

I think that a "SHOULD" is enough generally; the problem only exists because you are blindly sending packets without understanding the packet that triggers them.

-- 
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/3095#issuecomment-542927019

---

From: Kazuho Oku <[email-masked]>
Date: Mon, 28 Oct 2019 01:00:11 -0700

In #3157, I've gone with
* SHOULD limit when you retain packet protection keys (as you can stop sending packets once you receive CONNECTION_CLOSE)
* MUST limit when you drop packet protection keys (as you do not know when to stop)

Re https://github.com/quicwg/base-drafts/issues/3095#issuecomment-542920940, while we can define a rule based on how endpoints use CIDs, I think I prefer having a rule based on how a stack is implemented (i.e. when you drop packet protection keys) rather than how a stack is configured (i.e. the way CIDs are used). IMO, the latter is harder to test and therefore fragile.

-- 
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/3095#issuecomment-546833078