Asymmetric CIDs

Eric Rescorla <> Fri, 16 February 2018 17:01 UTC

Return-Path: <>
Received: from localhost (localhost []) by (Postfix) with ESMTP id 77B5C129C6A for <>; Fri, 16 Feb 2018 09:01:58 -0800 (PST)
X-Virus-Scanned: amavisd-new at
X-Spam-Flag: NO
X-Spam-Score: -1.899
X-Spam-Status: No, score=-1.899 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, HTML_MESSAGE=0.001, RCVD_IN_DNSWL_NONE=-0.0001] autolearn=ham autolearn_force=no
Authentication-Results: (amavisd-new); dkim=pass (2048-bit key)
Received: from ([]) by localhost ( []) (amavisd-new, port 10024) with ESMTP id 7sijMtAW5hAW for <>; Fri, 16 Feb 2018 09:01:55 -0800 (PST)
Received: from ( [IPv6:2607:f8b0:4002:c09::229]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by (Postfix) with ESMTPS id 840A112D893 for <>; Fri, 16 Feb 2018 09:01:55 -0800 (PST)
Received: by with SMTP id o1-v6so797567ybk.10 for <>; Fri, 16 Feb 2018 09:01:55 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;; s=20150623; h=mime-version:from:date:message-id:subject:to; bh=QP+YoJnoxBMGauvmmciWEZIy+u4ssxpP4Bo9oKVsfII=; b=1CofVnCTkwXqiT9qd6jMnZjbGX3lk+hkZ+LKXLCxpOJlShixkT1ICi/UfqQVOYLQ8I vpkD2jVEnIUMCRh/rk4dZSf1Tf8+CYn3StozeSVjgKJGh/19kVyXnJFGdR3byOwcNoQs asISZ/YVjBHxxNkSynYooCiIddCH6NBkQdWoRYip5MgTXUJdSMttcDxarF/ybrCvFJNx S17cJCkzJhn9kg6Xan/iNrPUbg6zxQWDht/HpSyMDwRvHZvJ8/Pl7j9DEUjr5uWT4YJT IfIF6Nx3Vh7r46HpJ1y4HxjahHTfNG5tfk5VXqgj5JJ9k6zGu/NKW0h5rY24X3DONP8y 9XSw==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;; s=20161025; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=QP+YoJnoxBMGauvmmciWEZIy+u4ssxpP4Bo9oKVsfII=; b=gE0q3mwSC0GtR1JIb31Y40QyYDnEhgQFvMJF5Ik7n0xhZc6HGyyZiZOVm4vx+iJMTH Ie+WLGZi6CkBqnv3CNvDfGMH7r0Q3vZ6DSBU0G+nRu2dMH4HqSWU5ikn+Zgo4ZWsJmVh HJsRHltEWTt3/5n3f80L7ngGo2GvGVsfSs6KcKstolynIm4Ae5gMT5sKt1OvpERIMZP7 x172DTkgcprB4dQxWxfBnbWfJl8prPxpEVuwx3Yj2QSsWEg+C2euGTAv8CfRAZQrhBfl QdsmPMY/oSITMiMs+UQgFwgKGkRru0d9bFprelVdaIhqlTI9+AwSiy3NB+O+cm5g7ulm MbNg==
X-Gm-Message-State: APf1xPApRqxzIz/pIoBDRDJ1/B8ilqR/pDbgjEna97SNmJn00Zqv5Oxv EQmBkAvEijsPKI/RbjPc3HRMC62InItss3OkHa2ln4Y+jrw=
X-Google-Smtp-Source: AH8x226hoAQ5U6ioz5LUu7IzVvL3Up0YOwh/bgoTWC73eHmOLf5ked54miTCNn96j5Q+5h7R4/cD+k4HeICzZKR51mo=
X-Received: by with SMTP id n1mr5132377ybm.413.1518800513984; Fri, 16 Feb 2018 09:01:53 -0800 (PST)
MIME-Version: 1.0
Received: by with HTTP; Fri, 16 Feb 2018 09:01:13 -0800 (PST)
From: Eric Rescorla <>
Date: Fri, 16 Feb 2018 09:01:13 -0800
Message-ID: <>
Subject: Asymmetric CIDs
Content-Type: multipart/alternative; boundary="089e08264fa41f02d00565574dc5"
Archived-At: <>
X-Mailman-Version: 2.1.22
Precedence: list
List-Id: Main mailing list of the IETF QUIC working group <>
List-Unsubscribe: <>, <>
List-Archive: <>
List-Post: <>
List-Help: <>
List-Subscribe: <>, <>
X-List-Received-Date: Fri, 16 Feb 2018 17:01:59 -0000

Hi folks,

After a bunch of discussion, the CID task force came down to rough
consensus that asymmetric conn IDs were probably the right
direction (CID task force members, please feel free to voice dissent
here). Here's a complete writeup of what I think would be needed
for asymmetric connection IDs. It's not a PR, because I think
something self-contained is cleaner.

Note that if we adopt this direction, we would be sacrificing
public reset under some conditions (see previous emails to the
list) and we would need to decide if it was worth keeping at all.

The basic idea is that each side gets to dictate the connection IDs
that are used to send to it. During the handshake, you establish those
CIDs and then each side can issue new CIDs during the connection.  The
main advantage of this is that it allows for symmetric topologies in which
the client is also behind some kind of stateless LB/router rather than
just the server. See Issue #1091 for more info on this.

The overall handshake looks something like this:

Client                                      Server

Initial [CID=XXX] {recv-CID=YYY} ---------------->
<-------------- Cleartext [CID=YYY] {recv-CID=ZZZ}
Cleartext [CID=ZZZ], {recv-CID=YYY} ------------->
<-------------------------- Short header [CID=YYY]
Short header [CID=ZZZ] -------------------------->

The client's initial CID (XXX) is special, and either consists of

    (a) a randomly chosen dummy CID. Proposal: require this to be
        8 bytes or at least a minimum. This should be the same
        for all Initial packets in a connection (unless a stateless
        reject is received, as below).
    (b) a CID which it received from the server in a stateless reject

All the server's packets are sent with the client's receive CID (YYY)
and all subsequent client packets are sent with the server's receive
CID (ZZZ). The general rule is that you should send with the
connection ID that you most recently received (where recently
is defined as highest PN).

Note: I believe it's safe to just use the sending CID as the mixin
for the KDF, but I haven't thought this entirely through yet.

Finally, you can send NEW_CONNECTION_ID in either direction to provide
a new connection ID for the other side to use. The general assumption
is that you can do this at any time, just as with current QUIC, and
that any time you send to a new remote 3-tuple you should change CIDs
if you can. Note that this means that endpoints should try to make
sure that the other side has spare CIDs in case they need to migrate.

As we discussed in the meeting the short header should just have
an implicit length CID. This gives us the following short header:

   |0|C|K| Type (5)|
   |                                                               |
   +                     [Connection ID (*)]                       +  <-
change from 64
   |                                                               |
   |                      Packet Number (8/16/32)                ...
   |                     Protected Payload (*)                   ...

Note that we may also be able to dispense with the C bit, if each
side just gets to say "send me this CID exactly", why do we want
to say "here is my CID but you can omit it".

We have several options about the long header. The first question
is where recv-CIDs go. In previous versions I suggested putting
them in transport parameters, or elsewhere in the TLS handshake,
and that might still be viable, though it has some drawbacks [0],
so the other alternative is to put both CIDs in in the long header.
This would look something like:

   |1|   Type (7)  |
   |  DCID-Length  |                                               |
   +-+-+-+-+-+-+-+-+   Dst Connection ID (*)                       +
   |                                                               |
   |  SCID-Length  |                                               |
   +-+-+-+-+-+-+-+-+   Src Connection ID (*)                       +
   |                                                               |
   |                         Version (32)                          |
   |                       Packet Number (32)                      |
   |                          Payload (*)                        ...

The semantics here are that the first value is the CID you want to
send to and the second one is the value you want used to send to you
(I've inverted these to keep the order the same as short header).

Two notes about this encoding:

1. I think we agreed that we didn't want arbitrary length CIDs up to
255 bytes, and yet we have room in this length byte. I propose we
limit it to 31 bytes and then grease the remaining 3 bits [1].

2. Because the client sends its CID first, there's no way to get the
current QUIC semantics of the server just dictates the CID.  I propose
we fix that by defining a special sentinel CID (all 1s, all 0s,
whatever) of whatever our maximum length is that means "just use your
own CID".

We can endlessly bikeshed on this structure.

Finally, we will need to update NEW_CONNECTION_ID to allow a variable
length CID. This would look like this:

    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   |                          Sequence (i)                       ...
   |  CID-Length   |                                               |
   +-+-+-+-+-+-+-+-+       Connection ID (*)                       +
   |                                                               |
   |                                                               |
   +                                                               +
   |                                                               |
   +                   Stateless Reset Token (128)                 +
   |                                                               |
   +                                                               +
   |                                                               |

[0] However, in the transport parameters design, if the server's
handshake gets reordered, the client might need to send some ACKs with
the initial CID. However, we've agreed that the client's IP address
has to be stable, so this isn't a problem. Alternately, you could
change C->S CIDs in the short header if that was easier.

[1] An alternative would be to have a sparse range (e.g., you can
express 0-7 and then 8-22 by 2s, assuming I have counted correctly)
and then we could pack both lengths into a single byte. As I said,
lots of opportunities for bikeshedding here.