Subject: DoS during the handshake

From: Martin Thomson <[email-masked]>
Date: Wed, 12 Dec 2018 15:58:30 +1100

tl;dr: We previously agreed not to add specific defenses for off-path
denial of service attacks prior to the completion of the handshake
(see #645 [1]).  Can we move that point earlier from "handshake
completion" to "shared keys established"?

Read on for more...

PR #2045 suggests a change to the way in which encryption keys are
managed.  The observation there is that discarding Initial keys early
provides defense against a certain class of denial of service attack.

We previously agreed not to defend against denial of service until the
handshake is complete (see [1]).  In looking at the issue (#1951), we
realized that we weren't keeping that guarantee because a badly formed
Initial packet can trigger connection termination until the point that
Initial keys are disposed of.

We keep Initial keys 3RTO from the point that Handshake keys are
installed.  By then, a typical connection will be a few round trips
into active use.  The attack described would be approximately as easy
to generate as a TCP RST within that time.  Several people expressed
disappointment in this outcome and a strong desire to have
significantly better resilience against attacks of that nature.

PR #2045 therefore proposes moving the point that keys are discarded
earlier to the point where Handshake keys are available. Initial
packets would thereafter be ignored. This is possible because use of
Handshake keys implies that no additional Initial-level data is
needed. Discarding keys at that point limits denial of service to the
time before shared keys are established. It doesn't force an attacker
to win packet races in all cases, nor does prevent on-path attacks,
but it narrows the window where an attack like this is possible.

Of course, if an attacker can interfere with the key exchange, this is
ineffectual. Recognizing the difficulty of that sort of defense was -
I think - the intent of the previous agreement. But a lot of time has
passed since we agreed on this and we have made some changes that are
relevant.  In particular, at that time we didn't have any visibility
of the Handshake encryption level in the transport.

Can we agree to narrow the window we present an attacker to the time
prior to Handshake keys being confirmed?

If we don't agree, then I think that implies we are closing #1951 with
no change.  We could modify #2045 to trigger at handshake completion,
which would more closely meet the agreed goals, but in comparison to
the existing form, that seems to only have a downside (longer
exposure) and no upside that I can see.  Or we could discuss other
defensive strategies.

There's still a good amount of room for improvement here.  New
versions of the protocol can define better mechanisms.  Kazuho and
Christian are exploring some ideas that might allow the entire
handshake to be authenticated, for example.  That would seem to
require a more fundamental rework of the protocol than I think we're
ready for right now though.

PR #2076 proposes something more significant.  It levies requirements
on servers that might allow clients to sift through the set of packets
it gets, so that they might search for a combination of server packets
that produce an acceptable handshake. The goal there being to ensure
that winning a packet race is longer a viable attack strategy. Either
way this decision goes, I think that we should close PR #2076.

[1] https://github.com/quicwg/base-drafts/issues/645#issuecomment-326168485

---

From: Kazuho Oku <[email-masked]>
Date: Wed, 12 Dec 2018 16:09:17 +0900

Hi Martin,

Thank you for summarizing the discussion. My responses inline.

> significantly better resilience against attacks of that nature.

While I am fine with merging #2045 (assuming that the concerns in
relation to loss recovery and congestion control are resolved), I am
not sure if it would be an improvement in terms of security in
practice. IIUC, the practical attack scenario is a man-on-the-side
attacker observing the first Initial packet of a connection and
sending resets to both endpoints. #2045 does not provide protection
against that.

So while it is true that the window becomes smaller in terms of
"time", I wonder if there is a difference that actually matters.

> ready for right now though.

I agree that the protection against spoofed Initial packets should be
out-of-scope for QUIC v1.

Building countermeasures without the help of AEAD is (to some extent)
like building house of cards. I think we should close not only #2076
but also #2053.

-- 
Kazuho Oku

---

From: Ian Swett <[email-masked]>
Date: Wed, 12 Dec 2018 10:59:48 -0500

We intend to implement discarding data in Initial encryption, even if this
PR doesn't land.  We already have it in gQUIC, and it was useful in
preventing spurious retransmits on high-loss links there.

Originally I was excited about this because I thought it enabled a simpler
solution to Martin Duke's deadlock Issue #1764
<https://github.com/quicwg/base-drafts/issues/1764>.  I think that's still
true, and if it is, I think that alone is worth requiring this, because
this change is simpler and less error-prone than the text that required.
But if we can't revert those changes, I'm more neutral.

As I commented on the PR, either way we need some text in transport and
recovery about what to do when TLS drops keys, so some of the PR's text
definitely needs to be added.

Ian

On Wed, Dec 12, 2018 at 2:09 AM Kazuho Oku <[email-masked]> wrote:

> 2018年12月12日(水) 13:59 Martin Thomson <[email-masked]>:
> >
> > [1]
> https://github.com/quicwg/base-drafts/issues/645#issuecomment-326168485
> >
>
>
> --
> Kazuho Oku
>
>

---

From: Jana Iyengar <[email-masked]>
Date: Wed, 12 Dec 2018 17:17:30 -0800

Kazuho is spot-on: we can keep going around in circles, but without the
help of AEAD, we are bound to have some attack surface exposed. #2045
reduces that surface, and to that extent, I think it's better in than
not. We're not going to be free of Initial injection attacks without
something more elaborate.

I like that #2045 makes it clear that we do rely on an implicit ack for
Initial packets. Even with a 3RTO timer, if we didn't receive an ack for
the last packet, we would simply discard the Initial packets and assume
that everything got through. We are already doing implicit acking; #2045
identifies a more precise point in the handshake that can be considered as
an implicit ack for Initial packets.

On Wed, Dec 12, 2018 at 8:00 AM Ian Swett <ianswett=
[email-masked]> wrote:

> <https://github.com/quicwg/base-drafts/issues/1764>.  I think that's
> still true, and if it is, I think that alone is worth requiring this,
> because this change is simpler and less error-prone than the text that
> required.  But if we can't revert those changes, I'm more neutral.
>

---

From: Eric Rescorla <[email-masked]>
Date: Thu, 13 Dec 2018 17:32:40 -0800

> an implicit ack for Initial packets.

Jana

Can you elaborate on this some more? My naive assumption was that the way
you would implement retransmission of any data was you would retransmit up
to some maximum time/number and if not, you would fail the connection. Why
would you treat Initial packets post-handshake differently than that?

-Ekr

>> We intend to implement discarding data in Initial encryption, even if
>> this PR doesn't land.  We already have it in gQUIC, and it was useful in
>> Originally I was excited about this because I thought it enabled a
>> simpler solution to Martin Duke's deadlock Issue #1764

---

From: Martin Thomson <[email-masked]>
Date: Fri, 14 Dec 2018 13:14:31 +1100

On Fri, Dec 14, 2018 at 12:33 PM Eric Rescorla <[email-masked]> wrote:
> Can you elaborate on this some more? My naive assumption was that the way you would implement retransmission of any data was you would retransmit up to some maximum time/number and if not, you would fail the connection. Why would you treat Initial packets post-handshake differently than that?

Unfortunately, timers differ at each endpoint, both in their starting
points and their duration.  Say that a client was attempting to
retransmit parts of a ClientHello (after HelloRetryRequest).  The
server can start its timers for removing Initial keys much earlier
than the client in this case.  And the server might have a
different/smaller understanding of the RTO. That means that the server
is going to discard those packets and not acknowledge the packets from
the client sooner.  Do we want the client to fail the connection if it
fails to transmit those packets?  Or, as this PR suggests, can we just
use the presence of Handshake packets as a signal that Initial packets
aren't needed.

---

From: Eric Rescorla <[email-masked]>
Date: Thu, 13 Dec 2018 18:16:54 -0800

I think Martin's framing of this is on the right track. Specifically,
we need to decide what our threat model is against on-path attackers.

We all know that a powerful on-path attacker can just delete any
packet that it sent through it, so we're necessarily considering
weaker attackers or at least attackers which want to spend less.

I can think of two major classes of weaker attacker:

1. Attackers who can't delete packets at all ("man on the side")

2. Attackers who are just trying to minimize resources and so would
   like to be able to tear down or suppress a connection with
   less effort than filtering every packet. This class of attacker
   is harder to reason about because it's a matter of advantage
   ratio. I.e., if the attacker can block 2 packets and tear down
   the connection, that's clearly a lot better than having to
   block all the packets in a connection forever, but it's not
   clear how much advantage we think it's reasonable for the
   attacker to get. It's also clear that you can really throttle
   a connection with a small amount of packet loss, so that
   represents our upper limit.

One reasonable anchor point would be to say that we're ruling out of
scope an attacker who can do *any* message deletion, so we're just
considering man-on-the-side attackers. Then we have to ask what the
timing criteria are. I.e., if the attacker receives packet X and
wants to send X' that depends on knowing X, then we can have, in
increasing strength:

(1) X is always delivered before X'
(2) X is delivered before X' with probability P > 0
(3) X' is always delivered before X

Finally, we need to consider what we expect those attackers to be
able to do. The choices the spec seems to implicitly make now are:

- During the handshake even a class (1) attacker can tear down
  the connection (at minumum by injecting bogus Initials towards
  the client).
- After some reasonable time T after the handshake, even a class (3)
  attacker cannot force the connection to be torn down (the value
  of T is the start of this thread)
- After time T, a class (1) attacker cannot efficiently reduce
  the bandwidth of the connection (except by flooding the link).
  - If ECN is not in use, even a class (3) attacker cannot efficiently
    reduce the bandwidth of the connection
  - If ECN is in use, a class (3) attacker can efficiently reduce the
    bandwidth of the connection, and a class (2) attacker might be able
    to depending on P. [this is the implied effect of the ECN duplicate
suppression
    rule.]
- Maybe to rule deletion-capable attackers out of scope? But maybe
  not?

Does this seem like a fair characterization of the situation?

-Ekr

---

From: Eric Rescorla <[email-masked]>
Date: Thu, 13 Dec 2018 18:20:00 -0800

On Thu, Dec 13, 2018 at 6:14 PM Martin Thomson <[email-masked]>
wrote:

> > Can you elaborate on this some more? My naive assumption was that the
> way you would implement retransmission of any data was you would retransmit
> up to some maximum time/number and if not, you would fail the connection.
> Why would you treat Initial packets post-handshake differently than that?
>
> fails to transmit those packets?

Sure, but given reasonable values for key deletion and for giving up, any
situation in which you would tear down the connection is likely to basically
be inoperable anyway.

Or, as this PR suggests, can we just
> use the presence of Handshake packets as a signal that Initial packets

I think this depends partly on the question above.

-Ekr

---

From: Martin Thomson <[email-masked]>
Date: Fri, 14 Dec 2018 13:46:58 +1100

>   the connection (at minumum by injecting bogus Initials towards

Correct, though I think that we need a clear definition the conditions
that end this period.

The points in time that I have are:

A) shared keys available
B) shared keys available w/ confirmation that a peer has them too
C) handshake complete
D) handshake complete w/ confirmation that the peer is also complete
*+timer) any of the above plus our key cleanup timer

We need to allow for some disagreement between endpoints about these
times, but I think that that covers it.  To be clear, I don't think
that A and D are useful, but I was trying to be thorough.

Here #2045 says that this ends at B for Initial.  We add a
discretionary 3RTO timer to the cutoff for other transitions, because
those don't matter so much.

>   of T is the start of this thread)

Yep.  The question is how we define T.

#2045 contemplates moving that to the earliest possible point (B
above).  The current draft adds 3RTO to that.  Note that "handshake
complete" is not part of either calculation.

>     to depending on P. [this is the implied effect of the ECN duplicate suppression
>     rule.]

Yeah.  These seem right, though that doesn't read too much on the
current question.

> - Maybe to rule deletion-capable attackers out of scope? But maybe

I think that we're assuming that if you can delete messages prior to
the cutoff, then you win.  After that, you are just adding to packet
drops.  FWIW, defense here requires something like what Kazuho and
Christian have proposed in the last 15 minutes and I don't think that
should be in scope for QUICv1.

---

From: Mikkel Fahnøe Jørgensen <[email-masked]>
Date: Fri, 14 Dec 2018 04:02:26 -0800

On 14 December 2018 at 03.17.49, Eric Rescorla ([email-masked]) wrote:

I very important class of attackers are those that might be powerful but
wants to stay undetected and do selective interference.

This could be to provide time for a worm to spread, or to collect
intelligence, to subvert a specific target, or to suppress security alerts
and defensive software updates.

Such an attacker might look a lot like a man-on-the-side, but could
selectively rewrite packets, e.g. changing source or target IP address.