Subject: [quicwg/base-drafts] GREASE the flags byte (#311)

From: ianswett <[email-masked]>
Date: Wed, 15 Feb 2017 05:00:21 -0800

Google-QUIC had an issue where post-handshake QUIC packets were being dropped, because a bit changed in the public flags, and a middlebox no longer identified it as QUIC.

In order to ensure the entire public flags byte is usable, I suggest we GREASE it by defining the entire space as valid.

Building on Jana's proposal for the public header with a flags byte as a set of codepoints: https://gist.github.com/janaiyengar/b05acb3af17d6e938d25befc69c11eae

The goal is to provide a simple mathematical mapping from any value of the public flags onto a frame type.  

My suggestion is to lookup the frame type, and if it's not defined, mod the flags value by the number of frame types defined in that phase(short or long form) and pick the type with that index when ordering the frame types by value.

If an initial packet number is chosen randomly, and the connection ID is as well, greasing the flags byte and version (#112 and #296) covers everything that is not encrypted.

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

---

From: Marten Seemann <[email-masked]>
Date: Wed, 15 Feb 2017 05:34:12 -0800

I like this idea very much. 

I thinkwe have to be a bit more careful when it comes to the long packets. Different QUIC versions might define a different number of packet types, so we can't grease before version negotiation is finished. If I understand that correctly, excluding the long packets from treason would solve that problem (we do slightly modified greasing here if we define a fixed modulo value that is guaranteed to stay constant between all QUIC versions). 

Furthermore, in order to simplify the mapping, if we define an ordering of the frame types anyway, wouldn't it be easier to get rid of the explicit values defined in Jana's proposal? I.e. the packet type would just be numbered 1 to n. 

Then the rule for the sender is easy: Just add *random number* x *number of frame types* to the type number (mod 256).

-- 
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/311#issuecomment-280011603

---

From: ianswett <[email-masked]>
Date: Wed, 15 Feb 2017 07:59:15 -0800

Consecutive numbers would be easier, but it does present deployment challenges for Google and anyone else who has Google-QUIC deployed, as we transition from one flags approach to another.  This might be solvable other ways, but it'd take some serious 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/311#issuecomment-280051235

---

From: martinduke <[email-masked]>
Date: Wed, 15 Feb 2017 15:58:12 -0800

It's worth pointing out that this absolutely requires authentication of the public header. Otherwise firewalls could zero out the greased bits to avoid potential information leakage.

-- 
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/311#issuecomment-280182360

---

From: Ryan Hamilton <[email-masked]>
Date: Wed, 15 Feb 2017 16:09:35 -0800

Agreed. I think we have consensus on that point, but we should confirm on the list. (Google QUIC authenticates the public header.)

-- 
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/311#issuecomment-280184936

---

From: Martin Thomson <[email-masked]>
Date: Wed, 15 Feb 2017 19:00:42 -0800

This requires positive identification of short vs. long form.  I think that it also fixes the size of the space in which long form packets can be sent.  If the next version of the protocol needs an additional long-form packet, then n_long increases and greased packets suddenly fall into different slots.

That's not workable if you ever want to change this protocol.  I believe that long form packets are most in need of this sort of protection - experience with TLS shows that issues are most likely to occur on the very first packet.  That doesn't mean that greasing the short form isn't valuable, it's just that greasing the initial packets is more important.  We need to balance that with having an escape valve - a way to deploy a new version of the protocol.

We could say that version has to be understood before identifying type (else, send a version negotiation packet and don't grease type there).  That requires that only long form packets either be distinct from short form or that only long form packets arrive prior to establishing state. The latter of these doesn't work in light of NAT rebinding, since short form packets will arrive with no context.  That leads me to conclude the distinguishing long and short is still useful.

So we say that long form packets are identified by some clearly defined operation.  Pick a permutation operation. &0x08 or &0x80 could work, or even something like n%3!=1 so that there can be twice as many long form layouts as short form.  After that you know that version is present and can use version to determine if you even have a hope of recovering the type.

Here is where I think @marten-seemann is right about packing the space of valid codepoints.  A sparsely populated space makes this easier to build.  A complicated PRP hurts, especially since this octet is likely to to need hardware implementation.  That accepts that greasing the type loses any hope of preserving bitwise compatibility with Google-QUIC (why didn't anyone pick up on that in Jana's proposal, or am I just being dense through severe lack of sleep?).

That means that adding a new long form packet layout and type requires a new version.  I think that's a perfectly reasonable compromise.

Short form packets are easier in a way: since those are only exchanged after version negotiation, the only wrinkle is how they are managed after NAT rebinding.  For that, the connection ID remains our best way to ensure that they can be correctly recovered.  Once the server can correlate the packet with a connection, then it's easy to recover type.

@martinduke, @RyanAtGoogle, see #302.

-- 
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/311#issuecomment-280216811

---

From: ianswett <[email-masked]>
Date: Thu, 16 Feb 2017 12:59:24 -0800

I believe a plausible solution is for the server to supply the client a list of all type byte codepoints in the ServerHello that have been defined in versions subsequent to this connection's version and the server supports, and hence should not be greased by the client.  And greasing would never be done until the handshake completes, of course.

This is not that elegant, but ensures all codepoints are in use at all times, either by valid connections or by greasing the value.

-- 
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/311#issuecomment-280458509

---

From: Mike Bishop <[email-masked]>
Date: Thu, 16 Feb 2017 14:27:26 -0800

Maybe I'm missing something, but if the handshake has completed and we know what version is in use, why do we care if the client collides with a value defined in a different version?  Server should interpret based on the agreed version, and if something that was grease becomes valid in a different version... that's kind of the 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/311#issuecomment-280482884

---

From: ianswett <[email-masked]>
Date: Fri, 17 Feb 2017 08:37:24 -0800

There is a very real practical concern Google and others may have in the near future, which is that we may want IETF-QUIC to not grease codepoints still in use by GQUIC.  But that's not the reason I came up with this originally.

Here's my weak argument, maybe others can do better: If a client comes in from a new IP/Port, then the server has to know how to decode the packet and it can't use version, because it's unknown(unless the server only supports one version, and this is moot).  If connection ID is always the same length in the same location, then I believe there's no issue, but otherwise mapping a packet back to it's connection is impossible or speculative.

I think this is more of a challenge for a load balancer that's not terminating the connection than one that is, particularly if one wants that load balancer to be relatively or completely stateless.

-- 
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/311#issuecomment-280699863

---

From: Mike Bishop <[email-masked]>
Date: Fri, 17 Feb 2017 09:52:57 -0800

Ah, so it's a migration issue:  When seeing a packet from a new source, the server has to first decide whether it's an existing connection that has migrated versus an initial packet from a new client, and this decision has to be made before it can know what version to use in interpreting the packet.

Whether it's a bit or a restricted set of values, that seems like an argument for the model of "These are handshake packets, and everything else is post-handshake."  The problem scenario seems to be that the client picks as a post-handshake-with-grease value something that a server thinks could be a handshake value in a different version.  Is that right?

-- 
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/311#issuecomment-280720091

---

From: Martin Thomson <[email-masked]>
Date: Sun, 19 Feb 2017 16:43:24 -0800

Yep, that's right Mike, that is what I had in mind when I said:

> That requires that only long form packets either be distinct from short form or that only long form packets arrive prior to establishing state. The latter of these doesn't work in light of NAT rebinding, since short form packets will arrive with no context.

I appreciate that GQUIC has a problem here.  The checksum could be sufficient though.

-- 
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/311#issuecomment-280963666