Subject: [quicwg/base-drafts] Looping with multiple Retry packets (#1451)

From: Martin Thomson <[email-masked]>
Date: Fri, 15 Jun 2018 08:59:00 -0700

Allowing multiple Retry packets creates a potential for regression of the address validation tokens.

Say that a client retransmits its first Initial packet without a token.  The server responds to both with the same token.  The second of these packets is delayed.

The client receives the first, sends another Initial packet and receives a second token in response.

Then the Retry that the server sent in response to the retransmission of the first Initial is received.  The client switches to that token as though it were new, but it's back to the first token.

If the server relies on multiple Retry packets and the progressive validation of the address using those tokens, then this will revert any progress that was made.  Because Retry can't be sent indefinitely (it has this arbitrary limit of 3 changes), this might cause that connection to fail.

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

---

From: MikkelFJ <[email-masked]>
Date: Fri, 15 Jun 2018 09:16:23 -0700

A client should know the initial CID used whether it is retry or not. If an old retry lands, its destinition CID would not match the ongoing session.

Client could choose to opt for the originally based on an informed decision - which could be if a handshake, rather than a retry is received. But otherwise I don't see how the client can get confused (except if extremely unfortunate to get a random collision).

If the client does multiple retry sequences using a received CID, then there is a potential conflict, but I don't think multiple retries is a good idea, nor 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/1451#issuecomment-397671032

---

From: Nick Banks <[email-masked]>
Date: Fri, 15 Jun 2018 09:22:54 -0700

The number one scenario I personally want to make sure we support (and requires multiple retry support possibly) is an independent DDoS protection device/component sitting in front of a QUIC server. One of the main reasons for the redesign of the Retry mechanics in the new Stream 0 design is this. When this device is in path, it is possible that it sends a Retry for the first client Initial packet, and then lets the second Initial packet through. The QUIC server receives the second client Initial, it may (for whatever reason) decide it wants to do a Retry. The client needs to be able to handle this scenario and respond to the second Retry packet with a third client Initial packet.

Now obviously, it would be best if the QUIC server doesn't need to send the second Retry packet but it might not (probably won't) know about the DDoS protection device sitting in front of it. If it does know about it, it could just assume all client Initial packets are validated, but I don't want to depend on this, as it's dependent on a particular deployment and infrastructure.

-- 
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/1451#issuecomment-397672726

---

From: Martin Thomson <[email-masked]>
Date: Fri, 15 Jun 2018 09:33:04 -0700

@mikkelfj, yes, a connection ID might allow this to be detected.  However, add one iteration and the problem remains.

@nibanks, you seem to have described a scenario where this gets even worse.  The retransmission has effectively forked the connection.  One of those forks is going to die, but you can't be certain which one.  We're reduced to relying on chance for having the connection complete.

-- 
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/1451#issuecomment-397675631

---

From: MikkelFJ <[email-masked]>
Date: Fri, 15 Jun 2018 09:44:03 -0700

@martinthomson yes - what if the source ID must be different from the previous source ID when responding to a retry? The initial SCID could be zero-length, but first, second etc. attempts cannot. The client can later revert to 0-length SCID.

This could mess with P2P server load balancers but then SCID would not be zero-length 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/issues/1451#issuecomment-397678272

---

From: ianswett <[email-masked]>
Date: Sun, 17 Jun 2018 23:16:41 -0700

@nibanks Your architectural description makes sense, but it doesn't seem that difficult to tell a server not to send RETRY if it's behind such a device.  Not only should it be possible, I think it's necessary for ideal performance?

Requiring a different source ID seems to fix the immediate issue here, but we'd also have to limit the number of RETRYs to 2, which may be sensible 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/issues/1451#issuecomment-397952286

---

From: Juha-Matti Tilli <[email-masked]>
Date: Mon, 18 Jun 2018 04:02:34 -0700

I read the QUIC specifications, aiming to add QUIC support to a layer 2 TCP SYN proxy I have implemented (https://github.com/Aalto5G/nmsynproxy). I realized it may very well require supporting multiple RETRY packets (I'm not 100% certain about this yet), which the latest QUIC Internet Draft does not permit.

I'm not at all convinced by the suggestion of @ianswett that servers could be told to not send RETRY if behind a DoS protection device. If you want to deploy such a DoS protection device to a network having hundreds or thousands of server machines, surely you cannot turn the switch on all servers that RETRY is not required, exactly at the same second you deploy the DoS protection device! Worse, some of the servers may not be in your control (think about Amazon AWS), and some QUIC implementations may lack a switch to turn off sending of the RETRY.

Furthermore, limiting the number of retries to 2 might work badly if such DoS protection devices are nested. It may be the case that there will be a RETRY from first DoS protection device, from second DoS protection device, ..., from N:th DoS protecton device and then eventually from the server. Performance is going to suck, but such a deployment should in my opinion be supported by QUIC. Such a deployment works perfectly well with TCP (you can nest TCP SYN proxies), and I don't believe QUIC should be a step backwards from TCP.

I hope QUIC can support a DoS protection middlebox, like TCP already does. I also hope such DoS protection middleboxes could be nested nearly infinitely (ok, TTL issues might affect you once you have dozens of such middleboxes, if operating on layer 3, but there are solutions such as layer 2 middleboxes that don't decrement TTL).

Remember that firewalls are a very common form of middlebox. Today, a firewall can implement TCP SYN proxy, meaning it doesn't have to keep state for connections from unvalidated addresses. With QUIC, the firewall could use normal UDP support without special support for QUIC, but then a UDP flood will fill the state tables of the firewall (and only the endpoint server's state tables will be protected from exhaustion by the RETRY mechanism). The only possibility to save from memory exhaustion is for the firewall to send a RETRY packet with cryptographically validated token the client should repeat, and then after validating the client's address, add the connection to the state table. Many enterprises have nested firewalls. Some of the nested firewalls may be in control of different entities (operator's firewall, common company firewall, some department's firewall).

I'm not going to implement a full firewall, but I'm definitely looking forward to be able to add QUIC support to my TCP SYN proxy that lacks the rulesets and other features of a firewall, but has fully functional SYN proxy features. I'm also looking forward to be able to nest the QUIC version of the SYN proxy semi-infinitely.

Now, the following kind of architecture might (or might not) work, I have to investigate it further:

    [client] -> ClientHello -> [middlebox]                   [server]
    [client] <- RETRY       <- [middlebox]                   [server]
    [client] -> ClientHello -> [middlebox]                   [server]
    [client]                   [middlebox] -> ClientHello -> [server]
    [client]                   [middlebox] <- RETRY       <- [server]
    [client]                   [middlebox] -> ClientHello -> [server]
    ...

This architecture would work without having to fully propagate the RETRY back to the client. I'm not certain if some of the cryptographic mechanisms would make this architecture invalid.

-- 
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/1451#issuecomment-398018381

---

From: Marten Seemann <[email-masked]>
Date: Mon, 18 Jun 2018 07:12:20 -0700

In an end-to-end protocol, we generally don't want "helpful" middleboxes to interfere with handshakes by performing a Retry (and thereby introducing latency). Obviously, this statement depends on the definition of "middlebox", which I here use as any node on the path that neither belongs to the server's nor the client's architecture. 
We should design QUIC's retry mechanism such that a retry can **only** be performed by devices that are under the control of the server operator.

Limiting the number of retries on the client side is an insufficient solution here, since under normal conditions, the server won't perform a retry, so the client would accept the any performed by the middlebox, and only fail in the rare case when both the middlebox and the server perform a retry.

I agree with @ianswett here, that any architecture that performs multiple retries for a single connection is so suboptimal for performance that you probably wouldn't want to deploy it, and I think QUIC should only support it if we can at the same time prevent retries by "helpful" middleboxes. 
In fact, if we only allow a single retry, the solution is straightforward: a server (or whatever device is responsible for the DoS projection) would simply reject all Initial packets that contain a token that it didn't issue itself.

-- 
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/1451#issuecomment-398067827

---

From: Nick Banks <[email-masked]>
Date: Mon, 18 Jun 2018 07:21:11 -0700

I agree that we don't want to introduce unnecessary latency but I disagree with your suggestion to only allow the end server to perform the Retry for the reasons I previously stated, and that @jmtilli built upon. I don't think we should necessarily allow an infinite number of Retry packets, but more than 2 does seem necessary to me.

-- 
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/1451#issuecomment-398070805

---

From: ianswett <[email-masked]>
Date: Mon, 18 Jun 2018 08:33:36 -0700

If we're going to allow more than 2, I'm not at all clear on how we're going to guarantee forward progress.

I'll point out that if a server is under DoS and thinks a QUIC connection is a potential attack, it can close the connection and force the client to fall back to TCP.  This isn't optimal, but it avoids a lot of edge cases involving multiple retries and rollout issues where the server expects to be behind a DoS prevention device, but isn't temporarily.

I'll remind everyone that QUIC's requirement of a full-sized INITIAL should make it much less prone to issues than TCP syn attacks, so one layer of defense really should be enough.

-- 
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/1451#issuecomment-398096042

---

From: Mike Bishop <[email-masked]>
Date: Mon, 18 Jun 2018 10:55:14 -0700

Would it make sense to carry a sequence number on the token?  The server increments every time it sends a Retry; the client ignores Retries which don't exactly increment the sequence number of its most recent Initial.  If the Initial gets duplicated, the client will latch onto whichever Retry it receives first and ignore the subsequent one; if the Retry gets duplicated/delayed, the client will ignore 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/issues/1451#issuecomment-398140825

---

From: Nick Banks <[email-masked]>
Date: Mon, 18 Jun 2018 11:02:46 -0700

@MikeBishop for that to work, the QUIC server would need to read the Retry packet it gets from the client (that it sent in response to the DoS protection device's Retry) and then increment from there. But what happen if there was spurious retransmission? For instance, the DoS protection device ends up sending two Retry packets, and both are eventually responded to by the client and both responses end up getting to the QUIC server. The server would send seq_num=2 for its first Retry, but the client would ignore 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/issues/1451#issuecomment-398143072

---

From: Nick Banks <[email-masked]>
Date: Mon, 18 Jun 2018 18:04:44 +0000 (UTC)

Maybe, instead of the server incrementing the sequence counter, the client does and the server just echoes it back?

-- 
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/1451#issuecomment-398143629

---

From: Nick Banks <[email-masked]>
Date: Mon, 18 Jun 2018 11:06:02 -0700

I'm afraid this could get easily ossified though, and I really don't want to encrypt yet another thing to prevent ossification.

-- 
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/1451#issuecomment-398143962

---

From: Mike Bishop <[email-masked]>
Date: Mon, 18 Jun 2018 11:18:35 -0700

@nibanks, if the DoS device sends two Retry packets, the client would ignore the second:

- Client sends Initial, stored token, SN = 0
- DoS device responds Retry, token A, SN = 1
- DoS device spuriously sends Retry, token B, SN = 1
- Client processes either Retry, sends new Initial with SN = 1 and token A or B
- Client receives other Retry, ignores because SN != 2.
- Server responds to the Initial with SN = 1 with a Retry, SN = 2
- Client processes Retry, sends another Initial with SN = 2, etc.

Ossification is definitely a concern; someone could come to expect that this field is always zero on the client's first packet.  Encryption would be preferable, but the point of this is to avoid doing decryption work on the server until it's reasonably confident that the client is genuine, so that's problematic.

However, GREASE is an option.  Nothing requires this to start at 0/1 -- client could randomize the value on the first Initial, simply checking that the server incremented.  If we permit wrapping when the server increments, all initial values are acceptable.

-- 
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/1451#issuecomment-398147736

---

From: Martin Thomson <[email-masked]>
Date: Mon, 18 Jun 2018 23:33:31 -0700

An alternative is to include the packet number from the Initial in the Retry packet.  That makes Retry very-much more version-specific than it was, but it would allow the client to learn which Initial triggered the Retry, so that it can avoid going backwards.

-- 
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/1451#issuecomment-398289684

---

From: Kazuho Oku <[email-masked]>
Date: Tue, 19 Jun 2018 01:25:11 -0700

@marten-seemann 

+1

I agree to what Marten says.

Allowing middleboxes that send retries without sharing secrets with the servers has two issues:
* the feature can be abused by somebody other than server operator
* that in turn may lead to ossification, considering the fact that Retry is not a invariant

Considering that, I'd prefer having a retry mechanism that enforces sharing a secret between the middlebox (that sends a retry) and the server. Which in turns would mean that multiple retries are unnecessary.

-- 
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/1451#issuecomment-398317321

---

From: MikkelFJ <[email-masked]>
Date: Tue, 19 Jun 2018 06:05:19 -0700

> An alternative is to include the packet number from the Initial in the Retry packet. That makes Retry very-much more version-specific than it was, but it would allow the client to learn which Initi…

Isn't this always 0? Following retry, a new connection is made, so PN starts over, and we did drop that the random offset at start I suppose. Of course the encrypted PN would vary but not in any secret way, and the initial CID would vary too.

-- 
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/1451#issuecomment-398391564

---

From: Mike Bishop <[email-masked]>
Date: Tue, 19 Jun 2018 16:49:03 -0700

Discussed on the editors' call, and then a follow-up conversation with @janaiyengar and a whiteboard.  When there are multiple retry sources on the path, if the server's CID does not change between Retries, you are highly likely but not guaranteed to make forward progress and eventually get a response from the server.  The client gets confused about two things in this scenario:

- It doesn't know which Initial-with-token actually made it to the origin and got a server Initial rather than a Retry.  However, this doesn't matter, because the token isn't bound into the TLS handshake or protocol state, so if it ever gets a response from the origin the connection will proceed successfully.
- It can believe there were more (potentially many more) rounds of Retry than the server infrastructure has layers; if we keep the arbitrary limit of three it's easy to blow right past that.  In fact, for *any* finite limit, there are conceivable situations where the client would see more retries with the right chances of packet loss and spurious retransmission.

If the server *does* change CIDs on a Retry, however, you ratchet forward at each layer and ignore any extra Retry packets from the previous layer, which fixes both problems.  The proposal on the call was to say that not only may each Retry change the CID, each Retry MUST change the CID unless the sender knows for sure that it's the last layer.

-- 
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/1451#issuecomment-398580384

---

From: ekr <[email-masked]>
Date: Tue, 19 Jun 2018 20:15:15 -0700

Let me see if I understand correctly. Are you saying it looks like this?

```
Initial [SCID=X, DCID=Y] ->
<- Retry[SCID=A, DCID=X]
Initial [SCID=X, DCID=A] ->
<- Retry [SCID=B, DCID=X]
Initial [SCID=X, DCID=B] ->
```

Is that what you are proposing?

-- 
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/1451#issuecomment-398611100

---

From: Martin Thomson <[email-masked]>
Date: Tue, 19 Jun 2018 21:46:30 -0700

I pointed this out, but it was lost on transcription.  We need to also require that the SCID in a Retry is >N octets (the same restrictions as on the client-generated DCID would work, but it's probably OK to use the 4 octet minimum).

-- 
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/1451#issuecomment-398622910

---

From: ekr <[email-masked]>
Date: Tue, 19 Jun 2018 21:54:44 -0700

Actually, I think it would be better to abandon the use of the SCID as a nonce here.

instead, I propose we say that Retry has to contain the last 8 octets of the Initial packet it's responding to. That's high entropy by definition (it's a hash of CH), and then we won't need any other rule

-- 
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/1451#issuecomment-398623929

---

From: Martin Thomson <[email-masked]>
Date: Tue, 19 Jun 2018 22:13:42 -0700

That's fine with me.  It means that senders of Initial packets need to remember those octets, but it simplifies things (to the point that we don't need a length field even).

-- 
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/1451#issuecomment-398626480

---

From: MikkelFJ <[email-masked]>
Date: Tue, 19 Jun 2018 22:19:51 -0700

The sender might not have access to the encrypted packet if delegates that part.

-- 
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/1451#issuecomment-398627329

---

From: Martin Thomson <[email-masked]>
Date: Tue, 19 Jun 2018 22:24:45 -0700

Yes, but don't do that then.

-- 
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/1451#issuecomment-398627975

---

From: ekr <[email-masked]>
Date: Tue, 19 Jun 2018 22:24:59 -0700

Or delegate the processing of the Retry.

-- 
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/1451#issuecomment-398628006

---

From: MikkelFJ <[email-masked]>
Date: Tue, 19 Jun 2018 22:31:18 -0700

I appreciate the simplicity, but consider an IoT device with crypto hw radio - or a transputer with many cores and few hw crypto units.

-- 
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/1451#issuecomment-398628967

---

From: ekr <[email-masked]>
Date: Tue, 19 Jun 2018 22:41:08 -0700

Said device can stuff the last bytes somewhere and pass them to the CPU.

-- 
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/1451#issuecomment-398630424

---

From: Martin Thomson <[email-masked]>
Date: Tue, 19 Jun 2018 22:42:38 -0700

Worst case, you can ask for the packet to be delivered back to yourself so that you can copy the octets and send it out again.

-- 
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/1451#issuecomment-398630643

---

From: MikkelFJ <[email-masked]>
Date: Tue, 19 Jun 2018 23:30:10 -0700

> Worst case, you can ask for the packet to be delivered back to yourself so that you can copy the octets and send it out again.

This can profoundly change the architecture of a QUIC deployment. It is far from easy to synchronize and send back data in a distributed pipeline. For the same reason I'm not too keen on PNE in its current form, but as long as the encrypted PNE has no semantic meaning, it is less of an issue as it can be delegated.

-- 
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/1451#issuecomment-398638958

---

From: ekr <[email-masked]>
Date: Tue, 19 Jun 2018 23:33:55 -0700

@mikkelfj: I'm not finding this objection particularly compelling, but feel free to propose an alternate design.

-- 
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/1451#issuecomment-398639604

---

From: MikkelFJ <[email-masked]>
Date: Tue, 19 Jun 2018 23:46:18 -0700

One could include a retry serial number (or retry TTL) in the long header. That TTL could also be the start packet number (sort of what @martinthomson suggested earlier but in the explicit form: a client initial packet starts with packet number zero. Any retry MUST increase the packer number by one and start a new initial packet with the peer provided destination CID. A retry must reflect the source packet number. The client can choose how many retries it is willing to pursue, but it MUST not respond to a retry of a serial number older than once or to a number older than the latest initial request transmitted.

There is still a chance of receiving a valid handshake on an older serial number racing a retry packet. A client may choose to accept that handshake and discard all other connenction attempts on the same line of serial numbers. This to protect against man on side attacks.

There is a chance that a client receives multiple retries on the same serial number either through network packet duplication, attacks, or through competing infrastructure. In that case only one retry must be responded to - but this is already covered in the above.

The serial number alone is insufficient to distinguish between different connections. The client must therefore issue a SCID that it can associate with each retry or handshake response, but it can be the same, different, or zero length, depending on the clients configuration. (I think this would work, but need more thought).

-- 
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/1451#issuecomment-398642239

---

From: ekr <[email-masked]>
Date: Tue, 19 Jun 2018 23:49:07 -0700

I don't see how this protects against an off-path attacker injecting a fake Retry with serial number = 1. In order to have that, you need entropy from the client.

-- 
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/1451#issuecomment-398642853

---

From: MikkelFJ <[email-masked]>
Date: Tue, 19 Jun 2018 23:53:41 -0700

Yes that is correct. I suppose that problem also exists today with a single retry?

-- 
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/1451#issuecomment-398643846

---

From: ekr <[email-masked]>
Date: Tue, 19 Jun 2018 23:54:44 -0700

No, it doesn't, because the server has to echo the client's original DCID, and that is high entropy.

-- 
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/1451#issuecomment-398644109

---

From: MikkelFJ <[email-masked]>
Date: Tue, 19 Jun 2018 23:58:10 -0700

OK two things then: the original case: if the client has random initial DCID and a SCID the retry must respond with a new CID used for server routing, and the SCID to route to the client (if any), AND and additional copy of the origin random DCID for entropy. That is 3 three CIDS in a retry repsonse if that is to work.

If the above works, it also works with retries with serial numbers, but it does require 3 CIDS in a retry 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/1451#issuecomment-398644842

---

From: ekr <[email-masked]>
Date: Wed, 20 Jun 2018 00:08:09 -0700

The server is stateless and so cannot send the original DCID in the second retry.

-- 
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/1451#issuecomment-398647021

---

From: MikkelFJ <[email-masked]>
Date: Wed, 20 Jun 2018 00:12:41 -0700

Yes I realized. It is necessary to have an extra nonce field in the intial packet, at least on secondary attempts, unless you derive from the encrypted packet. I see the complexity of adding an extra field here, and also the elegance of using the (non-secret) encrypted packet sample as nonce instead.
I still prefer an extra nonce field to allow encryption to be pipelined, but I see your point.

-- 
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/1451#issuecomment-398648113

---

From: Kazuho Oku <[email-masked]>
Date: Wed, 20 Jun 2018 00:15:05 -0700

> [OK, not a hash, actually the auth tag...]

@ekr Instead, can we require Retry packets to always contain SCID longer than eight octets? I'd assume that the server can switch to the final SCID when it sends an Initial packet.

I think that approach might be simpler than requiring the client to remember the last 8 octets of the Initial packet that it has sent.

-- 
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/1451#issuecomment-398648636

---

From: ekr <[email-masked]>
Date: Wed, 20 Jun 2018 00:22:44 -0700

@kazuho: I think that might work. yes, but I'd need to noodle on it a bit.

-- 
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/1451#issuecomment-398650432

---

From: MikkelFJ <[email-masked]>
Date: Wed, 20 Jun 2018 00:26:38 -0700

Another observation: When the initial random DCID is used for routing, it can be used to attack a specific subset of infrastructure. If the initial DCID is zero length and a separate nonce is provided. The peers LB is responsible for distribution of traffic and the nonce becomes the same in both cases. Additionally, on secondary attempts the LB can verify the DCID now present from the retry packet.

That nonce could be part of the early SCID as @kazuho suggests, but that is a matter of framing.

-- 
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/1451#issuecomment-398651339

---

From: ianswett <[email-masked]>
Date: Wed, 20 Jun 2018 05:29:29 -0700

@kazuho why longer than 8 octets and not >=8 octets?

I would like the simple RETRY case to work as well, which is the server doesn't want to change the CID at all, and it is the terminal node, so I don't want to require senders of RETRY to be required to change CID.

Related question: What CID is the client deriving the key for INITIAL packets from?  I was thinking all INITIAL packets used the same key, but if the terminal server may not have seen the client's first DCID, that doesn't work unless the original DCID is put somewhere the final server can read in the 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/1451#issuecomment-398731413

---

From: Nick Banks <[email-masked]>
Date: Wed, 20 Jun 2018 06:52:31 -0700

I agree with @mikkelfj here that relying on the encrypted packet makes a hw offload solution much more difficult, and I would prefer not to do that. The Initial packet is the one packet that we generally have extra room, so I don't think we should be afraid to add an additional nonce.

-- 
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/1451#issuecomment-398757226

---

From: Mike Bishop <[email-masked]>
Date: Wed, 20 Jun 2018 17:27:27 +0000 (UTC)

I'm fine with either an explicit nonce or continuing to use ODCID as the PR currently does and including a minimum SCID length along with the "MUST change unless" text.  The Initial packet does have extra room, in theory, but coalesced packets means we can use that extra room for 0-RTT data in the common case, so I'd rather not burn *too* many bytes that are only needed in this exceptional path.  That makes an explicit nonce less preferred in my view.

I'm sympathetic to the offload issue -- this is worse than PNE because it doesn't just take the encrypted bytes as input, it requires remembering 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/1451#issuecomment-398831433

---

From: Kazuho Oku <[email-masked]>
Date: Wed, 20 Jun 2018 15:24:45 -0700

> I would like the simple RETRY case to work as well, which is the server doesn't want to change the CID at all, and it is the terminal node, so I don't want to require senders of RETRY to be require…

I agree. My intent was to say `>= 8`. Sorry for the confusion.

> Related question: What CID is the client deriving the key for INITIAL packets from? I was thinking all INITIAL packets used the same key, but if the terminal server may not have seen the client's f…

I agree with your observation, and think it would make sense to state that the DCID field of the Initial packet that carries the first Client Hello (i.e. the one that also gets padded up to 1280 octets) will be used as the key material.

-- 
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/1451#issuecomment-398917049

---

From: Kazuho Oku <[email-masked]>
Date: Wed, 20 Jun 2018 15:49:27 -0700

> Related question: What CID is the client deriving the key for INITIAL packets from? I was thinking all INITIAL packets used the same key, but if the terminal server may not have seen the client's f…

This is an interesting question.

If we are to permit running DOS mitigation devices that do not share some secrets with the servers, we would be required to state that the Initial keys would match to the DCID field of the Initial packet that carries the first ClientHello.

However, I am not sure if that is the right path forward, because defining such behavior would mean that somebody else can setup a middlebox that sets the Initial key to the same value for all connections that it sees (e.g., by sending a Retry with SCID field of `0000000000000000` for all connections), effectively nullifying the merit of having obfuscation.

Admittedly, this kind of attack can only be applied to server deployments that does not validate the token field generated by an on-path device (e.g., by sharing the secret between the DoS mitigation device and the server).

But my question is: do we want to even allow such server deployments to be set up?

-- 
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/1451#issuecomment-398921875

---

From: Nick Banks <[email-masked]>
Date: Wed, 20 Jun 2018 16:20:06 -0700

It is our (Microsoft's) goal to use Retry for DDoS mitigation and possibly load balancing. In both cases the middle box operating on behalf of the QUIC server would likely have little or no shared state with the QUIC server. This is a very high priority for our Azure scenarios. In order to support these scenarios, we would need the Retry packet to not rely on some shared secret.

-- 
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/1451#issuecomment-398927508

---

From: Kazuho Oku <[email-masked]>
Date: Wed, 20 Jun 2018 22:40:29 -0700

> It is our (Microsoft's) goal to use Retry for DDoS mitigation and possibly load balancing.

That's understandable. I'd anticipate that others will do the same thing.

> In both cases the middle box operating on behalf of the QUIC server would likely have little or no shared state with the QUIC server.

May I ask why you think that it is not a good idea to require every one of us to share some small amount of secret (e.g. encryption key) between the middleboxes and the servers than we would be running?

As stated in my previous comment, not sharing opens an attack vector. There could be other attack vectors since lack of shared state allows anyone to run the middlebox. Considering that, I think it makes sense to *require* sharing state, under the assumption that doing so is not hard.

-- 
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/1451#issuecomment-398982420

---

From: MikkelFJ <[email-masked]>
Date: Wed, 20 Jun 2018 22:58:02 -0700

I believe the initial packet should always contain 1280 bytes, also after RETRY, otherwise an attacker might learn how to construct retry SCID's and use a second flight INITIAL as a DDoS vector.

The initial key should also be derived based on the NONCE in the current INITIAL packet. So, as I suggested before, it makes sense to carry the NONCE separately and make the initial DCID empty - at cannot be used for safe routing anyway and it simplifies routing logic because LB's don't have to know if the INITIAL DCID is random or not, they just have to take a decision based on emptiness.

The source SCID cannot be used as that NONCE without adding complexity to the clients LB infrastructure in a P2P server configuration. So I believe the NONCE should be a separate field. And it will not waste any space if the premise holds that all initial packets must be 1280 to prevent attacks.

-- 
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/1451#issuecomment-398985376

---

From: MikkelFJ <[email-masked]>
Date: Wed, 20 Jun 2018 23:14:58 -0700

With the iteration specific NONCE reflected in RETRY, a client can easily drop secondary retry responses to older iterations of retries. But the NONCE does not have be reflected because the response would use a key derived from that NONCE thus failing verification if it doesn't match.

Using packet numbers to count iterations would simplify operations, but are not strictly necessary. I n this form the INITIAL packet must have  packet number that identifies the retry attempt number, starting at 0 and the retry response must reflect that packet number.

Late handshake responses to older iterations may be preferable to new retry responses due to man-on-side races. This can be detected via trial decryption of older NONCE derived keys, but it is simpler if the first server handshake packet number reflects the clients INITIAL packet number.

A NONCE could be generated randomly, or it could be using counter mode encryption such that the INITIAL packet number is an IV encrypting a base NONCE. Using counter mode avoids having to store several NONCE's in case an old handshake is received.

-- 
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/1451#issuecomment-398988314

---

From: MikkelFJ <[email-masked]>
Date: Wed, 20 Jun 2018 23:27:16 -0700

> May I ask why you think that it is not a good idea to require every one of us to share some small amount of secret (e.g. encryption key) between the middleboxes and the servers than we would be run…

If you are in a cloud hosted setup (like Azure or Digital Ocean) the servers are operated by customers while load balancers and DDoS mitigation devices might be operated by the cloud provider. Requiring shared secrets here is messy. Sometimes this is done with TLS termination today, but it is still messy - some moving towards auto-configuration via LetsEncrypt - which of course would be an option for QUIC as well - but there are many moving parts making automation 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/1451#issuecomment-398990515

---

From: Kazuho Oku <[email-masked]>
Date: Thu, 21 Jun 2018 00:14:25 -0700

@mikkelfj:
> If you are in a cloud hosted setup (like Azure or Digital Ocean) the servers are operated by customers while load balancers and DDoS mitigation devices might be operated by the cloud provider. Requiring shared secrets here is messy.

Thank you for pointing out that. I must say that that is a compelling argument. It's the use case where a network operator wants to protect a server administered by a different person / entity.

Though I am not sure about the security properties.

-- 
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/1451#issuecomment-399000486

---

From: Nick Banks <[email-masked]>
Date: Thu, 21 Jun 2018 06:13:04 -0700

The case that @mikkelfj points out is exactly the case we are trying to solve for Azure. Azure owns the DDoS mitigation devices and load balancers, while the 3rd party owns the QUIC server, which could be from any implementation.

I agree we should look at the security properties and enumerate all the threats/attacks this design could expose. Then it's a matter of weighting the impact of those threats vs the cost/complexity if we decided to fix them. Personally, I haven't seen an attack that would really benefit a middle box any more than any other handshake disruption tactic.

-- 
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/1451#issuecomment-399098726

---

From: Mike Bishop <[email-masked]>
Date: Thu, 21 Jun 2018 09:22:55 -0700

While I can't claim it's a committed product plan to do exactly this, Akamai has a DDoS mitigation product that I could envision working this way when facing QUIC traffic.  I don't know what the token format would look like 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/1451#issuecomment-399162677

---

From: Kazuho Oku <[email-masked]>
Date: Thu, 21 Jun 2018 21:32:15 -0700

@nibanks @MikeBishop It's good to know that we have interest in such deployments. Thank you.

> I agree we should look at the security properties and enumerate all the threats/attacks this design could expose. Then it's a matter of weighting the impact of those threats vs the cost/complexity…

The issue about simply allowing the existence of an uncoordinated middlebox is that it becomes impossible for _any_ server to detect somebody on-path altering the handshake traffic.

For example, a middlebox can alter the server CID by sending a Retry, and the server will not notice the alternation if the middlebox also drops the token field of the 2nd Initial packet sent from the client that traverses through the middlebox to the server.

While I understand that you cannot care about the issue in the deployments that you are interested in, I think that others would be worried about the possible impact on security as well as the ossification concern including the one that I have described in https://github.com/quicwg/base-drafts/issues/1451#issuecomment-398982420.

Fortunately, there are ways to define a signal for detecting tampering that _can_ be implemented by server operators who will not have uncoordinated DOS detection devices.

One way is to add an "Original_DCID" field to Transport Parameters, and state that "a server SHOULD check that the value of the Original_DCID field matches that of the packet that it saw in the first packet that belonged to the connection". Servers running behind an uncoordinated middlebox will turn this check off.

Note that having a configuration knob is mandatory for servers running behind such a middlebox, even if we do not introduce the "Original_DCID" field. This is because Retry is version-specific (which means that uncoordinated DOS mitigation devices might need to send a Version Negotiation packet). To support that, the servers need to have a knob that changes how the downgrade protection logic works (FWIW, end-to-end version downgrade protection is currently a MUST; we need to change it as well to allow the existence of uncoordinated DOS mitigation devices).

-- 
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/1451#issuecomment-399317602