Subject: [quicwg/base-drafts] Avoid attack on address validation during connection migration (#746)

From: Martin Thomson <[email-masked]>
Date: Tue, 22 Aug 2017 18:51:34 -0700

The attack here is that an attacker might duplicate a legitimate packet and
send that packet from an invalid address such that it arrives before the real
copy.  That causes the recipient to think that there was a connection
migration.  They will attempt to validate that address and this will fail.  The
connection is then closed.

The fix is to cause a migration back to the original, legitimate address.  For
this to work, you need two things:

1. when a migration happens, abandon any validation on the old address on the
   expectation that it will fail

2. when a migration happens, make sure that you try to trigger packets from the
   old address first

For the second point, I decided to mandate address validation, rather than an
ordinary PING.  The reason being that you have to retransmit the packet on that
path and I doubt that implementations will want to have two sets of special
machinery for transmiting - and retransmitting - frames on a specific path.
Maybe this is too much of a constraint on implementations, so I'd like to hear
from people about whether they would prefer a more generic requirement (send
any packet that demands acknowledgment would work, it doesn't even have to be
the same packet every time, though the usual situation will be that the packet
will be lost, so you probably don't want to send anything important).
You can view, comment on, or merge this pull request online at:

  https://github.com/quicwg/base-drafts/pull/746

-- Commit Summary --

  * Avoid attack on address validation during connection migration

-- File Changes --

    M draft-ietf-quic-transport.md (47)

-- Patch Links --

https://github.com/quicwg/base-drafts/pull/746.patch
https://github.com/quicwg/base-drafts/pull/746.diff

-- 
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/pull/746

---

From: Martin Thomson <[email-masked]>
Date: Wed, 23 Aug 2017 01:52:13 +0000 (UTC)

@huitema, does this address your concerns on #732?

-- 
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/pull/746#issuecomment-324198455

---

From: Christian Huitema <[email-masked]>
Date: Wed, 23 Aug 2017 03:54:21 +0000 (UTC)

huitema commented on this pull request.

I think we are still missing something. We need to somehow tie the packets to the new path, in a cryptographic way. One potential solution is to use a new connection ID for the new path. That way, third parties cannot forward a PING or PONG meant for one path to the other path. But this needs work. And yes, it is very close to multipath.

> @@ -1453,6 +1453,10 @@ return.  A PING frame containing 12 randomly generated {{?RFC4086}} octets is
 sufficient to ensure that it is easier to receive the packet than it is to guess
 the value correctly.
 
+Note:
+
+: Retransmissions of the PING frame MUST also use the same remote address.
+
 If validation of the new remote address fails, after allowing enough time for

Really? That seems to contradict what you are saying later.

> +received, but it could also mean ceasing retransmissions of the PING frame.  An
+endpoint that doesn't retransmit a PING frame might receive a PONG frame, which
+it MUST ignore.
+
+
+## Spurious Connection Migrations
+
+A connection migration could be triggered by an attacker that is able to capture
+and forward a packet such that it arrives before the legitimate copy of that
+packet.  Such a packet will appear to be a legitimate connection migration and
+the legitimate copy will be dropped as a duplicate.
+
+After a spurious migration, validation of the source address will fail because
+the entity at the source address does not have the necessary cryptographic keys
+to read or respond to the PING frame that is sent to it, even if it wanted to.
+Such a spurious connection migration could result in the connection being

The text is correct, except if the man on the side manages to play "man in the middle". It knows that the first packet to the new address will be a PING. It could forward it to the old address, capture the next packet from that old address, and forward it again to the target. Bingo, the PONG succeeds.

-- 
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/pull/746#pullrequestreview-57967334

---

From: Martin Thomson <[email-masked]>
Date: Wed, 23 Aug 2017 04:27:44 +0000 (UTC)

martinthomson commented on this pull request.

+Note:
+

I assume that you refer to the text about checking the old address as well?  I don't see the conflict.  This is talking about retransmissions.

The point is that the PING frame cannot be sent to multiple addresses or it only validates one of those addresses.

-- 
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/pull/746#discussion_r134654784

---

From: Martin Thomson <[email-masked]>
Date: Wed, 23 Aug 2017 04:34:06 +0000 (UTC)

I don't quite know how to use connection IDs in the current protocol.  Maybe if we had asymmetric connection IDs.  I think that we might end up there, but it's challenging for a range of reasons.  Let's say that it's a client that migrates, which seems to be the common case.  The client needs to provision the server with enough NEW_CONNECTION_ID frames that the server won't run out if the client ever inadvertently moves.

Maybe we can instead insist that the PONG be sent on the path on which the PING was received and that the PING contains a source address validation token with the same sort of protections we have on the one used in the handshake.  That's not simpler, but it should work.  It does precludes the use of asymmetric addressing, though I suspect that was something we didn't have anyway.

-- 
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/pull/746#issuecomment-324218385

---

From: Christian Huitema <[email-masked]>
Date: Wed, 23 Aug 2017 04:41:26 +0000 (UTC)

+Note:
+

No, it is just my poor Github skillz showing. I was commenting on the next paragraph, "If validation of the new remote address fails, after allowing enough time for...(etc.)" And then, "should terminate the connection." So you are leaving untouched the requirement that I find problematic.

-- 
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/pull/746#discussion_r134655866

---

From: Martin Thomson <[email-masked]>
Date: Tue, 22 Aug 2017 21:47:37 -0700

+Note:
+

Ahh, that isn't necessarily your fault...

I think that this is OK, given the qualification about abandoning validation attempts.

-- 
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/pull/746#discussion_r134656348

---

From: Christian Huitema <[email-masked]>
Date: Wed, 23 Aug 2017 04:55:18 +0000 (UTC)

You want the mechanism to protect the receiver against a malicious peer, and Ping/Pong does that. But you also want a protection against man on the side playing replay and race games, and that is much harder.

It may well be that the real answer is multipath. Accept that the peers are managing several parallel paths. Manage separate sequence number space and loss detection for each path -- but of course allow frames to be transmitted or retransmitted on any of the paths, as the sender sees fit. Validate any path before using it -- that will take care of the malicious senders. Do not close an old path implicitly if a new one is found -- that should eliminate the man on the side games.

But of course there is a catch. Doing that requires having explicit path information in ACK frames and maybe PING frames, plus managing sequence number, retransmit queue and sack dashboard for each path. Congestion control, too. Plus maybe a new type of frame for explicitly closing a path.

Costly, but then piling hacks to make the simpler solution work may not be worth it.

-- 
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/pull/746#issuecomment-324220825

---

From: Martin Thomson <[email-masked]>
Date: Wed, 23 Aug 2017 04:59:20 +0000 (UTC)

I missed something... If the attacker can reliably win the race, then increasing the rigour of the source address validation won't fix that problem.  You need to have to have the client in the loop somehow, and you can't just tell the client that it moved.  Otherwise, this forwarding attack that you describe looks no different to a NAT rebinding (which is a situation we want to permit).

The primary concern here is that the attacker just put themselves on-path, right?  It's tempting to shrug and not worry about this one.  The performance of that path is clearly uniformly better than that of the old path and the address can't be spoofed or the bidirectional forwarding wouldn't work.

-- 
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/pull/746#issuecomment-324221300

---

From: Martin Thomson <[email-masked]>
Date: Wed, 23 Aug 2017 05:04:52 +0000 (UTC)

I agree re: multipath.  You definitely need explicit path information for PING (and maybe PONG now), but I don't see why you need that for ACK or a separate sequence number space - you need to track where you sent something, but where it is acknowledged only matters for the purposes of RTT measurement on that path.

Whoa, I just started down the multipath path again...

How about this then: we make this change, but explicitly call out this hack (checking the old path first) as being necessary only because we don't do proper multipath.  Is that reasonable, or is this overdesigned in that light?

-- 
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/pull/746#issuecomment-324221904

---

From: Christian Huitema <[email-masked]>
Date: Tue, 22 Aug 2017 22:13:15 -0700

On the need for per-path ACK -- maybe we should take time to discuss that face to face in Seattle. I am starting from where TCPM ended, which is basically an independent connection on each path, and  mechanism to merge the content. The good news is that QUIC already has the mechansim to merge the content.

Yeah, let's call this a hack and be done.

-- 
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/pull/746#issuecomment-324223047

---

From: mirjak <[email-masked]>
Date: Wed, 23 Aug 2017 12:11:04 +0000 (UTC)

Fine with this hack and call it done for now. However, I still like to comment on multipath (also inline with the MPTCP thinking): QUIC already has a pretty nice split between connection and stream state. If you want to make it look like two different connections on the wire, everything that is related to the connection needs to be per path, however all stream state can be shared (as hidden from the path). That means e.g. different packet numbers and ACK frames on each path, but the use of a common stream id set and respectively retransmission that are done on a per stream frame and not a per packets basis can be go on a different path. 

-- 
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/pull/746#issuecomment-324309535