Subject: Re: When should server-chosen connection IDs be sent and how are they indicated?

From: Kyle Rose <[email-masked]>
Date: Wed, 1 Mar 2017 13:55:58 -0500

On Tue, Feb 28, 2017 at 8:07 PM, Lubashev, Igor <[email-masked]> wrote:

> -----Original Message-----
> >From: Martin Thomson [mailto:[email-masked]]
> >
> >> How would a server know which server to redirect this packet to?
> >
> > I assume that the server would have more state than the load balancer.
>
> Unfortunately, this means the server would need not only its own state but
> also the state of all of its peers behind that load balancer.
>

Not necessarily. It seems like we're trying to mash two requirements into
one mechanism. The two requirements are:

(1) Some cookie issued by the server farm to offload minimal state for the
load balancer so it doesn't have to track every connection attempt and
established connection
(2) A connection ID that the server needs in plaintext to find connection
state across 5-tuple changes, but that must actually be a set of unlinkable
connection IDs or a mechanism for generating unlinkable connection IDs for
privacy from observers

If the cookies are stable identifiers mostly bijective with actual servers,
and if there are many more servers than clients, then it doesn't reveal a
lot of information to an observer trying to correlate client IPs: it's
basically equivalent to the server IP in terms of information. (It's N
times worse than a single load-balanced IP fronting N servers.)

One advantage of this approach is that the connection ID is really only
needed when establishing a new flow: otherwise, the server just uses
5-tuple to index into the connection context. If the client knows it's
changing flows or adding a new flow, it can send an unused connection ID to
the server to link that new flow into the connection context; if it doesn't
know (e.g., NAT rebinding), the server can drop alien packets until the
client decides to re-establish the flow with an unused connection ID.
(There could also be some signal from the server to the client that "you
are alien", but authentication with PKC would be expensive.)

One disadvantage is that you have two conflicting forces around the size of
this cookie: limiting the size of this space to prevent servers from
issuing unique plaintext client identifiers, vs. keeping the space large
and sparse so an attacker can't walk it. There's no way to really enforce
what the server puts here: we can only provide guidance that this cookie
space is for server identification *only*, and that care must be taken to
make sure it does not enable tracking of individual clients. In any event,
this is no worse from that perspective than an arbitrary server-chosen
connection ID that appears in every single packet and is subject to the
problem of flow changes unknown to the client.

There's also a general problem with load balancers: without a
pre-established cookie, the client is probably limited to a single datagram
for 0-RTT unless the load balancing algorithm is a function of connection
information that doesn't vary across 0-RTT packets from a single
connection. Load balancers probably want to balance load, not randomly
assign.

As with so many of the privacy discussions on transport topics, I don't
really have a strong opinion about whether this is a good idea or not:
preventing every kind of client tracking at this layer is probably futile.
I do, however, think it's important to discuss the entire space of
alternatives and pick something that actually achieves a balance of
privacy, security, and operability that users will for the most part be
satisfied with.

Kyle

---

From: "Lubashev, Igor" <[email-masked]>
Date: Fri, 3 Mar 2017 16:06:11 +0000

Your proposal has two parts:

Part 1. Have the client select a ConnectionID that does NOT show up in the clear in packets. It is only sent by the client encrypted by either 0-RTT or 1-RTT keys.  Connection tracking is done only using the 5-tuple.  Then, there would need to be a “resumption” phase if the client changes its 5-tuple.
The goal here is to reduce linkability (and maybe gain a few bits in the packets).

Part 2. To compensate for the lack of Server-Contributed ConnectionID, because load balancers may need it, we add cleartext Server-Contributed ServerID into all client→server packets if the Server provides one during the handshake.
This part about Server-Contributed ServerID field is closely related to Issue 205 (https://github.com/quicwg/base-drafts/issues/205).

Is that correct?

Now, if I understand it correctly, the proposed operation of the protocol would be:

1. Client initiates the handshake (1-RTT or 0-RTT).  At this point, the connection is only identified by the 5-tuple and cannot migrate.

2. When client has 0-RTT or 1-RTT keys, the client tells the server that this is a new connection and what its ConnectionID is.

3. Sometime during the handshake, the Server MAY send the client its ServerID that the client MUST include in plaintext in all subsequent packets.

4. If a server receives a non-handshake packet from an unknown 5-tuple, it sends a PUBLIC_RESET (?) with “unknown 5-tuple” error code.

5. If a client receives a PUBLIC_RESET (?) with “unknown 5-tuple”, it initiates 0-RTT handshake and using 0-RTT keys it tells the server that this is a resumption of connection with ConnectionID.

-          Igor

From: Kyle Rose [mailto:[email-masked]]
Sent: Wednesday, March 01, 2017 1:56 PM
To: Lubashev, Igor <[email-masked]>
Cc: Martin Thomson <[email-masked]>; Ryan Hamilton <[email-masked]>; IETF QUIC WG <[email-masked]>; Kazuho Oku <[email-masked]>
Subject: Re: When should server-chosen connection IDs be sent and how are they indicated?

On Tue, Feb 28, 2017 at 8:07 PM, Lubashev, Igor <[email-masked]<mailto:[email-masked]>> wrote:
-----Original Message-----
>From: Martin Thomson [mailto:[email-masked]<mailto:[email-masked]>]
>

Unfortunately, this means the server would need not only its own state but also the state of all of its peers behind that load balancer.

Not necessarily. It seems like we're trying to mash two requirements into one mechanism. The two requirements are:
(1) Some cookie issued by the server farm to offload minimal state for the load balancer so it doesn't have to track every connection attempt and established connection
(2) A connection ID that the server needs in plaintext to find connection state across 5-tuple changes, but that must actually be a set of unlinkable connection IDs or a mechanism for generating unlinkable connection IDs for privacy from observers
If the cookies are stable identifiers mostly bijective with actual servers, and if there are many more servers than clients, then it doesn't reveal a lot of information to an observer trying to correlate client IPs: it's basically equivalent to the server IP in terms of information. (It's N times worse than a single load-balanced IP fronting N servers.)
One advantage of this approach is that the connection ID is really only needed when establishing a new flow: otherwise, the server just uses 5-tuple to index into the connection context. If the client knows it's changing flows or adding a new flow, it can send an unused connection ID to the server to link that new flow into the connection context; if it doesn't know (e.g., NAT rebinding), the server can drop alien packets until the client decides to re-establish the flow with an unused connection ID. (There could also be some signal from the server to the client that "you are alien", but authentication with PKC would be expensive.)
One disadvantage is that you have two conflicting forces around the size of this cookie: limiting the size of this space to prevent servers from issuing unique plaintext client identifiers, vs. keeping the space large and sparse so an attacker can't walk it. There's no way to really enforce what the server puts here: we can only provide guidance that this cookie space is for server identification *only*, and that care must be taken to make sure it does not enable tracking of individual clients. In any event, this is no worse from that perspective than an arbitrary server-chosen connection ID that appears in every single packet and is subject to the problem of flow changes unknown to the client.
There's also a general problem with load balancers: without a pre-established cookie, the client is probably limited to a single datagram for 0-RTT unless the load balancing algorithm is a function of connection information that doesn't vary across 0-RTT packets from a single connection. Load balancers probably want to balance load, not randomly assign.

As with so many of the privacy discussions on transport topics, I don't really have a strong opinion about whether this is a good idea or not: preventing every kind of client tracking at this layer is probably futile. I do, however, think it's important to discuss the entire space of alternatives and pick something that actually achieves a balance of privacy, security, and operability that users will for the most part be satisfied with.

Kyle

---

From: Kyle Rose <[email-masked]>
Date: Fri, 3 Mar 2017 13:42:17 -0500

On Fri, Mar 3, 2017 at 11:06 AM, Lubashev, Igor <[email-masked]> wrote:

> Part 1. Have the client select a ConnectionID that does NOT show up in the
> clear in packets. It is only sent by the client encrypted by either 0-RTT
> or 1-RTT keys.  Connection tracking is done only using the 5-tuple.  Then,
> there would need to be a “resumption” phase if the client changes its
> 5-tuple.
>
> Part 2. To compensate for the lack of Server-Contributed ConnectionID,
> because load balancers may need it, we add cleartext Server-Contributed
> ServerID into all client→server packets if the Server provides one during
> the handshake.
>
> This part about Server-Contributed ServerID field is closely related to
> Issue 205 (https://github.com/quicwg/base-drafts/issues/205).
>
>
>
> Is that correct?
>

Basically. It explicitly uncouples load balancing state from connection ID,
allowing the connection ID to uniquely identify that client and server but
not be passively observable.

> 1. Client initiates the handshake (1-RTT or 0-RTT).  At this point, the
> connection is only identified by the 5-tuple and cannot migrate.
>
>
>
> 2. When client has 0-RTT or 1-RTT keys, the client tells the server that
> this is a new connection and what its ConnectionID is.
>
>
>
> 3. Sometime during the handshake, the Server MAY send the client its
> ServerID that the client MUST include in plaintext in all subsequent
> packets.
>
>
>
> 4. If a server receives a non-handshake packet from an unknown 5-tuple, it
> sends a PUBLIC_RESET (?) with “unknown 5-tuple” error code.
>
>
>
> 5. If a client receives a PUBLIC_RESET (?) with “unknown 5-tuple”, it
> initiates 0-RTT handshake and using 0-RTT keys it tells the server that
> this is a resumption of connection with ConnectionID.
>

Steps 1-3 reflect my thinking. 4 and 5 are where things get tricky.

If the client knows the 5-tuple has changed, it can skip the step of
sending with the old connection ID and do one of the following:

 - Immediately initiate a new connection with 0-RTT and present the unique
connection ID so the server can transfer all connection state to that new
5-tuple.
 - Skip PKC and send a previously-unused shared secret in the clear to the
server (e.g., using a rolling code on the connection ID) as weak proof that
this new 5-tuple is the legit owner of the connection state. (Strong proof
comes in the form of being able to speak over the encrypted channel.)

Doing this preemptively reveals less information about the client's
movements, but is not always possible.

If the client *doesn't* know the 5-tuple is changing, you run into the
situation in step 4. Sending a public reset then signals to a passive
observer that a client has probably changed its address, likely making for
easy traffic analysis to link the two connections, but this seems no worse
than any of the other proposals short of always sending a different
connection ID in every packet. (Sending different connection IDs in every
packet is still probably feasible at the cost of either wire or state
space, depending on how it's implemented. Not sure if it's worth the
complexity, but the same can be said for anything other than a static
plaintext connection ID in all packets.)

Part of the difficulty of explaining this is the over-use of the word
"connection", which is why I used "flow" in my original reply. With TLS we
talk about a "session" when referring to resumption, but that term
describes the security context, and has nothing to do with the application
data streams being protected, which are 1:1 with TCP connections and so do
not resume across connections without application support. I think what
we're all proposing, irrespective of mechanism, is that with QUIC the
entire connection context, including the state of all streams, be resumed
with a new 5-tuple once ownership of the connection context has been
transferred to that new 5-tuple.

Kyle