Subject: [quicwg/base-drafts] handling of coalesced packets with decryption errors creates DoS opportunity (#2308)

From: Marten Seemann <[email-masked]>
Date: Sun, 06 Jan 2019 20:33:02 -0800

The spec says
> For example, if decryption fails (because the keys are not available or any other reason) [...], the receiver MAY either discard or buffer the packet for later processing and MUST attempt to process the remaining packets.

It makes sense to continue processing if the keys are not available. However, if the keys are available, and decryption fails, this means that the peer sent an invalid packet (or that we're dealing with an on-path attacker, which we can't do anything against anyway). It seems that it would be equally valid to stop processing the datagram in that case.

Since it's possible to coalesce about 70 QUIC packets into a single 1200 byte datagram, an attacker could cause a peer to attempt 70 AEAD operations with a single datagram.

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

---

From: Kazuho Oku <[email-masked]>
Date: Sun, 06 Jan 2019 20:41:35 -0800

> However, if the keys are available, and decryption fails, this means that the peer sent an invalid packet (or that we're dealing with an on-path attacker, which we can't do anything against anyway).

Doesn't decryption failure happen also when the packet gets corrupt while being transmitted? 

Consider a coalesced packet sent by client that contains Initial (for ACKing ServerHello) and a Handshake packet. I'd assume that we'd prefer processing Handshake packet even if Initial was corrupt.

> Since it's possible to coalesce about 70 QUIC packets into a single 1200 byte datagram, an attacker could cause a peer to attempt 70 AEAD operations with a single datagram.

Does that matter, considering the fact that an attacker can force AEAD operation for every 21 bytes by using a short header packet (1 type + 4 byte space + 16 byte AEAD 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/2308#issuecomment-451820314

---

From: Marten Seemann <[email-masked]>
Date: Sun, 06 Jan 2019 20:58:23 -0800

> Doesn't decryption failure happen also when the packet gets corrupt while being transmitted?

I assumed those to be **very** rare, so treating the whole datagram as corrupted might be a valid response. I don't have any numbers about that though. Maybe we can ask @ianswett if he can share some measurements?

> Does that matter, considering the fact that an attacker can force AEAD operation for every 21 bytes by using a short header packet (1 type + 4 byte space + 16 byte AEAD tag)?

The assumption here is that sending a lot of small packet is more expensive than sending one large packet of the same payload size. First, there's UDP and IP overhead that we're not counting here, and second (and probably more importantly), you only need a single syscall.

Looking at the numbers, I think I messed up my calculation of how many coalesced packets fit into a single datagram, since I failed to account for the AEAD tag. This brings the number QUIC packets per datagram down to about 35.

-- 
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/2308#issuecomment-451822218

---

From: Kazuho Oku <[email-masked]>
Date: Sun, 06 Jan 2019 21:18:18 -0800

> The assumption here is that sending a lot of small packet is more expensive than sending one large packet of the same payload size. First, there's UDP and IP overhead that we're not counting here,…

That could be true, though I am still not sure if we need to talk specifically about the attack. For example, an attacker can also send a packet that successfully decrypts, that contains many tiny CRYPTO frames (4-bytes each).  I'd assume that processing of that would be more costly than AEAD-decrypting every 35 bytes.

Having said that, the state of the endpoints are guaranteed to progress even if the following QUIC packets of a coalesced datagram are corrupt. Therefore, I won't disagree to relaxing the requirement from MUST to SHOULD.

-- 
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/2308#issuecomment-451824672

---

From: Marten Seemann <[email-masked]>
Date: Sun, 06 Jan 2019 21:47:43 -0800

> That could be true, though I am still not sure if we need to talk specifically about the attack.

I was not suggesting to add language about this attack. My suggestion was to stop processing a datagram once unprotecting one of the QUIC packets fails, although you have the keys available for that encryption level.

> For example, an attacker can also send a packet that successfully decrypts, that contains many tiny CRYPTO frames (4-bytes each). I'd assume that processing of that would be more costly than AEAD-decrypting every 35 bytes.

I don't understand this. Why is processing CRYPTO frames expensive? In my implementation, assembling stream (and crypto stream) data is not an expensive operation.

-- 
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/2308#issuecomment-451828441

---

From: Kazuho Oku <[email-masked]>
Date: Sun, 06 Jan 2019 22:08:32 -0800

> I don't understand this. Why is processing CRYPTO frames expensive? In my implementation, assembling stream (and crypto stream) data is not an expensive operation.

Because for every 4-byte CRYPTO frame (containing 1 octet of data), you need to decode 2 varints (length and offset fields), check if it's newly received data, and then write it to the buffer. If the data is new, there would be a call to TLS stack that causes the TLS stack to see if the entire handshake message is available, which would turn out not to be true. TLS stack will then buffer the data. After that, the transport layer will remove the newly received data from the transport-level buffer.

My assumption is that doing this amount of processing is more heavyweight than running two AES operations and one GCM operation per every 35 bytes.

Based on that, I do not think we need a statement that specifies how to handle these tiny CRYPTO frames, or similar types of attacks (e.g., a packet payload containing many ACK frames). The same goes for not specifying how to handle tiny QUIC packets.

-- 
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/2308#issuecomment-451831439

---

From: ianswett <[email-masked]>
Date: Mon, 07 Jan 2019 20:21:04 -0800

>From my experience, decryption failure is extraordinarily rare.  Sufficiently so it's not worth worrying about or optimizing for cases when one QUIC packet decrypts and another does not.

-- 
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/2308#issuecomment-452170585

---

From: Igor Lubashev <[email-masked]>
Date: Fri, 11 Jan 2019 22:33:55 -0800

We also talked in Kista about using just such coalesced packets for PMTU probing.  I.e. coalescing a short long-header packet that will not decrypt but contains Server's Connection ID with a short-header packet that has the actual payload.

If the UDP datagram does get delivered, the long-header packet will be discarded and the short-header packet -- ACKed.  If this UDP datagram runs into an MTU problem, the response ICMP will contain Server Connection ID, and it will be routed to the correct backend.

-- 
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/2308#issuecomment-453724206

---

From: Martin Thomson <[email-masked]>
Date: Tue, 29 Jan 2019 17:41:49 -0800

Discussed in Tokyo; @marten-seemann will make a PR to prohibit senders from coalescing packets of different encryption levels and to permit (but not require) receivers to enforce this constraint.

-- 
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/2308#issuecomment-458778039

---

From: MikkelFJ <[email-masked]>
Date: Thu, 31 Jan 2019 02:25:08 -0800

>  permit (but not require) receivers to enforce this constraint.

Fine, as long as a violation will not DoS the connection, since a middle box can add random data to a UDP datagram.

-- 
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/2308#issuecomment-459293372

---

From: Martin Thomson <[email-masked]>
Date: Thu, 31 Jan 2019 03:02:16 -0800

That is a good point.  I think that the idea would be that a connection error would only be permissible if there were multiple packets of the same encryption level that could be successfully authenticated.  Endpoints would otherwise be permitted to drop any extra packets.  Note that you can just drop extra packets without checking if they decrypt.

-- 
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/2308#issuecomment-459304099

---

From: Igor Lubashev <[email-masked]>
Date: Thu, 31 Jan 2019 05:36:31 -0800

> prohibit senders from coalescing packets of different encryption levels

What's going to prevent a man-on-a-side from recording a long-header packet and a short-header packet with different encryption levels and then sending a coalesced packet? Both will decrypt. You do not want to kill a connection that way.

-- 
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/2308#issuecomment-459346106

---

From: ianswett <[email-masked]>
Date: Thu, 31 Jan 2019 16:16:20 -0800

@martinthomson I believe you meant prohibit senders from coalescing packets of the same(not different) encryption level, correct?

-- 
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/2308#issuecomment-459557503

---

From: Martin Thomson <[email-masked]>
Date: Thu, 31 Jan 2019 17:51:42 -0800

Yes, but @igorlord's point made me reconsider.  I think that the rule would need to be: a) senders MUST NOT coalesce packets of the same encryption level (there is no need to do so, so this is basically a no-op requirement); b) receivers SHOULD/MAY/MUST? discard packets if a packet of the same encryption level was received in the same datagram.  Unfortunately we can't do any more than this because an attacker has complete control over coalescing.

I realize now that this dovetails nicely with the requirement we already added here to require exactly one Retry or Version Negotiation in response to a 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/2308#issuecomment-459576215

---

From: Kazuho Oku <[email-masked]>
Date: Thu, 31 Jan 2019 18:00:36 -0800

> a) senders MUST NOT coalesce packets of the same encryption level (there is no need to do so, so this is basically a no-op requirement); b) receivers SHOULD/MAY/MUST? discard packets if a packet of the same encryption level was received in the same datagram

I think _b_ being MAY is what we agreed at the Interim. While I understand that some are concerned about this being used as an attack vector, there are people who do not care about this (including me), because there are more attractive ways to enforce the server to do more calculation. MAY is a good compromise.

-- 
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/2308#issuecomment-459577830