Subject: [TLS] Connection ID Draft

From: Eric Rescorla <[email-masked]>
Date: Thu, 12 Oct 2017 16:13:41 -0700

Hi folks,

I have just posted a first cut at a connection ID draft.
https://tools.ietf.org/html/draft-rescorla-tls-dtls-connection-id-00

Comments welcome.

-Ekr

---

From: Martin Thomson <[email-masked]>
Date: Fri, 13 Oct 2017 10:33:06 +1100

This seems like a pretty solid design.  (Better in many ways to the
QUIC design, but then I might concede that the constraints are
different.)

The example shows the connection ID only being used after the
handshake completes (that is, on epoch=3), but handshake records
(epoch=2) use the same record format and we already know the
preference of the peer when sending them.  I can see why you opted for
this design (there is no way for the server to signal that it intends
to use the connection ID before it starts to send it), but that could
be addressed by moving the extension to the ServerHello.  The value is
sent on every subsequent record, so there is no real gain in having
the extension in EncryptedExtensions.  There is value in having record
construction be consistent.

The design for new connection IDs is clearly to handle the linkability
issue, but the draft doesn't propose a solution for linking based on
the monotonic increase of sequence numbers, or acknowledge the
problem.

We had comments about the length of the connection ID and the value
being used as a covert channel.  That issue should at least be
addressed in the security considerations.

On Fri, Oct 13, 2017 at 10:13 AM, Eric Rescorla <[email-masked]> wrote:
> _______________________________________________
> TLS mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/tls
>

---

From: Eric Rescorla <[email-masked]>
Date: Thu, 12 Oct 2017 16:49:20 -0700

> construction be consistent.

Oops. It *is* in the ServerHello. This is an inconsistency because an early
draft
had it in EncryptedExtensions and I just didn't update the example right.

"enables encryption early in the handshake phase the connection ID will
be enabled earlier. For this reason, the connection ID needs to go in
the DTLS 1.3 ServerHello.
"

It's fixed in the draft.

> the monotonic increase of sequence numbers, or acknowledge the

Sorry, that's a good point that somehow didn't make it from my head into the
draft. In DTLS, it's actually pretty easy to handle this in DTLS b/c you
don't
need contiguous ranges except for anti-replay, so the sender can just jump
forward and then the receiver can keep a per-connid table. I've filed
https://github.com/ekr/dtls-conn-id/issues/2 to address this.

> addressed in the security considerations.

I filed:
https://github.com/ekr/dtls-conn-id/issues/3

That said, I'm not sure that any plausible length CID can avoid this.

-Ekr

---

From: Martin Thomson <[email-masked]>
Date: Fri, 13 Oct 2017 11:07:07 +1100

> https://github.com/ekr/dtls-conn-id/issues/2 to address this.

That only true if we don't truncate the sequence number.

> That said, I'm not sure that any plausible length CID can avoid this.

I agree.  Anything too short is going to be useless for the use cases
we care about, but anything long enough to be useful is ripe for
abuse.  We can acknowledge the problem though; and maybe suggest that
endpoints that care about this could at least disable the extension.

---

From: Eric Rescorla <[email-masked]>
Date: Thu, 12 Oct 2017 17:21:16 -0700

> That only true if we don't truncate the sequence number.

Maybe I'm missing something, but I don't think that that's correct. as long
as you're
willing to (a) restrict the jump to the same size as the transmitted part
of the sequence
number and (b) do a little trial decryption.

We could, of course, also adopt the sequence number hopping scheme that we
use for QUIC, which works without trial decryption.

---

From: Martin Thomson <[email-masked]>
Date: Fri, 13 Oct 2017 11:44:23 +1100

On Fri, Oct 13, 2017 at 11:21 AM, Eric Rescorla <[email-masked]> wrote:
> willing to (a) restrict the jump to the same size as the transmitted part of
> the sequence

Either works for me (I was operating on the assumption that we would
avoid trial decryption).

---

From: Eric Rescorla <[email-masked]>
Date: Thu, 12 Oct 2017 17:59:51 -0700

> Either works for me (I was operating on the assumption that we would

Yeah, I think we should probably import the scheme from QUIC.

-Ekr

---

From: Nikos Mavrogiannopoulos <[email-masked]>
Date: Fri, 13 Oct 2017 08:21:05 +0200

> https://tools.ietf.org/html/draft-rescorla-tls-dtls-connection-id-00

I believe the major issue with that is the fact that the record packet
format changes, but there is no way for a party in between to be able
to determine the record packet format without keeping session state.
Think not only of middle boxes, but of super-servers which may receive
of a stray udp packet which they have to forward to the appropriate
server [0]. With that change, they cannot figure whether the packet
contains the CID or not in a deterministic way for a random CID.

One can hack around that limitation by providing a CID which starts
with 0xffff which is an illegal size currently for TLS or DTLS, but
would have to worry with future extensions to the protocol which may
increase the maximum size.

Another worrying feature is that the client can make the server send up
to 255 verbatim bytes on the wire of his choice. Why was this feature
added? Are there use cases related with it (intro doesn't mention any),
or it was only thought as a make it as generic as possible approach? If
it is the latter, I'd recommend to provide a simple approach that
covers the described use cases.

The same argument applies to the server being able to set such a long
sequence of verbatim bytes to each of the client packets.

regards,
Nikos

[0]. That was exactly my use case for introducing the CID info, as in
openconnect server, the super-server receives the stray UDP packets
arriving after a NAT disassociates existing connections.

---

From: "Fossati, Thomas (Nokia - GB/Cambridge, UK)" <[email-masked]>
Date: Fri, 13 Oct 2017 06:31:13 +0000

First, thanks for the draft.

As discussed off-list, wrt framing / wire format, we probably have an opportunity to do slightly better than this, at least for 1.2.

The thing is that, since there is no flag in the record that says: "I'm carrying a CID", a receiver has no explicit way to know whether a record is coming from a CID-enabled session or a legacy-DTLS.

This ambiguity complicates the decoder because the receiving end now needs to implement a heuristic like:

-          let's first assume at offset +11 we have a CID

-          and then lookup the SAs store using this "maybe" CID

-          if found, OK (*), go on with the parsing

-          if not, fall back to assuming at offset +11 we have the length field and go on parsing

This is not ideal for a bunch of reasons:
    1. For every incoming record, the receiver needs to lookup the CID store just to parse the record;
    2. The implementation is more complicate;
    3. Heuristics are intrinsically fragile and are known to deal badly with corner cases (think the many creative ways the many moving parts can conspire: 5-tuple reshuffling because of NAT rebinding, lost state due to reboot/restart of one or more nodes, co-existing CID and legacy DTLS);
    4. Wireshark & co will choke because they typically don't have enough context to handle the two different framings;

To solve this, we'd need a place in the wire image of the record with semantics: "I'm carrying a CID."

In 1.2, we could use CT or version.  (In 1.3, that would not be possible because the diet header doesn't have them - too bad.)  To me it'd make slightly more sense to use the version. (I had previous discussions on this topic with Nikos and he told me that though anyconnect does this version override for some reasons, there is no reported conflict with middle-boxes.)  Also, there would be only one code-point to allocate, instead of separate code-points for each CID-enabled content type variant.  I'm happy to be convinced of the opposite, though.

I guess my main point here is to make sure we do as much as we can to allow simple, efficient, robust implementations, which are also, en passant, Wireshark-friendly, and leave heuristics-based approaches only for when there is no real alternative.

Cheers, t

(*) assuming CID is entropic enough, which may or may not be the case.

On 13/10/2017, 00:13, "TLS on behalf of Eric Rescorla" <[email-masked]<mailto:[email-masked]> on behalf of [email-masked]<mailto:[email-masked]>> wrote:

Hi folks,

Comments welcome.

-Ekr

---

From: Eric Rescorla <[email-masked]>
Date: Fri, 13 Oct 2017 05:53:15 -0700

> increase the maximum size.

Yes, Thomas raised this issue as well. Unfortunately, we need to take the
structure of existing TLS records as it is, and at least in DTLS 1.3 we're
going to effort to shorten the header and I'm not eager to make everyone
pay on the wire whether they want to use connection ids or not.

In DTLS 1.2, as you say, it seems most straightforward to just provide
what would be an illegal length, as it seems pretty unlikely that any
future DTLS extension is going to allow 65k-sized packets. In DTLS 1.3,
we could probably steal one code point for this if we had to.

> covers the described use cases.

Well, any connection ID feature of this type involves forcing the other
side to
send a certain amount of fixed verbatim data, so we're really just debating
how long that value ought to be. There are good reasons to allow at least
16 octets (in the super-server case you suggest, you might want the
connection ID
to to be an encrypted label for the actual server, and it's much more
convenient
to encrypt 16-byte quantities because that's AES's block size and many of
those machines will have AES-NI). And once you're carrying 16 bytes,
I don't see a big point in minimizing it below that. If people want an upper
limit that is greater than 16 (32?) I would be fine with that.

-Ekr

---

From: Matt Caswell <[email-masked]>
Date: Fri, 13 Oct 2017 14:15:02 +0100

On 13 October 2017 at 07:31, Fossati, Thomas (Nokia - GB/Cambridge,
UK) <[email-masked]> wrote:
> In 1.2, we could use CT or version.  (In 1.3, that would not be possible
> because the diet header doesn't have them - too bad.)  To me it'd make
> slightly more sense to use the version. (I had previous discussions on this
> topic with Nikos and he told me that though anyconnect does this version
> override for some reasons, there is no reported conflict with middle-boxes.)
> Also, there would be only one code-point to allocate, instead of separate
> code-points for each CID-enabled content type variant.  I'm happy to be
> convinced of the opposite, though.

Recently I met with Yin Xinxing and we have had much the same
conversation about what a Connection ID draft would need to do, and
how we could detect its use on the wire. Mechanisms we talked about
included setting something in the "length" field, using ContentType or
using version. IMO using "length" is just horrible. I'm also not keen
on version - it further complicates the "is this version greater than,
equal to, or less than this other version" question. It's already
slightly complicated in code that implements both TLS and DTLS due to
DTLS versions being high and decrementing for a new version. I foresee
lots of subtle bugs and problems from reusing "version". In my mind
ContentType is the way to go.

> I guess my main point here is to make sure we do as much as we can to allow
> simple, efficient, robust implementations, which are also, en passant,
> Wireshark-friendly, and leave heuristics-based approaches only for when
> there is no real alternative.

I fully agree here! It does occur to me that we could go further along
that road by swapping the order of the "length" and "cid" fields in
the new record header format, so that the new fields appear at the
end. Middlebox/wireshark code would then still be able to interpret it
because the beginning of the header is identical. The length would be
wrong of course (too short by cid_length bytes), but it would still be
parseable. That could be fixed (by adding the cid_length to the
payload length) but I'm not sure if its worth it.

Matt

---

From: Stephen Farrell <[email-masked]>
Date: Fri, 13 Oct 2017 14:37:09 +0100

> https://tools.ietf.org/html/draft-rescorla-tls-dtls-connection-id-00

As a near-nit, I don't think "dismissed" is a good way
to describe the analysis of some of the ideas that came
up earlier.

In particular, I still think there's merit in some use
of a hash chains, to decrease linkability, even if that's
not done for every packet.

For example, considering a client that might detect an
occasional change of 5-tuple, it could use something like

   id_n=H(foo||id_(n-1)) where foo is something dependent
   on the TLS session secrets (exporter-like)

That way the TLS stacks can pre-calculate the next id
(or a bunch of those) and then only lookups are needed
(though the tables are bigger of course) just as with a
static connection id.

I'd argue that such designs not be dismissed.

I accept that the design needs to end up being efficient
enough to get used but I don't think that we need to go
for the simplest possible design, if that exposes 5-tuple
linkages in ways that setting up new TLS sessions would
not.

Cheers,
S.

---

From: Eric Rescorla <[email-masked]>
Date: Fri, 13 Oct 2017 06:56:46 -0700

> I'd argue that such designs not be dismissed.

I've seen a number of designs like these, but in general they
have quite poor scaling properties. Can you describe the precise
design you have in mind so that we can analyze it.

-Ekr

---

From: Stephen Farrell <[email-masked]>
Date: Fri, 13 Oct 2017 15:16:31 +0100

Hiya,

> design you have in mind so that we can analyze it.

Sure, I can try...

What I'm suggesting is that we define a way that a TLS
node can change the connection ID to a new value that
is hard to link to the old, as a function that can be
used when the implementation chooses to use it.

I'm not currently arguing that the ids should be changed
for each packet. E.g. if a node is able to detect that the
5-tuple has just changed, it could use this then. If a
node sends one packet per day over say an nb-IoT network
where it might have a different IP address each time (not
that we know how nb-IoT will operate, so I'm guessing:-)
then it might make sense to do this for every packet.

I assume ids are initialised in some reasonable way.

To change an id, pick a value foo that depends on the TLS
session, e.g. like an extractor, and that is not visible
to the network. Then set next-id to H(foo||prev-id) or
some similar construct.

Receivers can store a set of ids calculated when the
session is established. I'd guess storing two (current
and next) might be a sensible thing to do.

The inefficiently compared to simply incrementing the
id value is to add another column to the lookup table I
guess. I don't know if that's a big scaling deal or not.

Cheers,
S.

---

From: Eric Rescorla <[email-masked]>
Date: Fri, 13 Oct 2017 07:29:17 -0700

> guess. I don't know if that's a big scaling deal or not.

There are a number of cases where this is actually much harder to implement
than a design where one side dictates the connection ID. For instance,
consider a design where you have a pool of servers P1, P2, ... P_n with a
load balancer in front.
Each server i generates connection IDs of the form i || Random. The load
balancer then just looks at the first byte and routes to the appropriate
load balancer [0]. In this design, the LB can be totally stateless, whereas
in the design you propose, it has to (a) have a back-channel to the server
to get the initial conn-id (b), do crypto (c) store state for all the live
connections.

In addition, consider what happens when you get a CID you don't recognize.
It might be nonsense but it might be that there was a cryptic CID change
(e.g., the client did two changes but you missed a packet). You need to
decide the number of changes you're willing to tolerate and then the table
has to be that big times the number of connections (or you need to fill it
in whenever you get an unknown CID, which the attacker can send you at any
time).

-Ekr

[0] This has non-ideal topology-hiding properties, but there are obvious
extensions with better properties.

---

From: Stephen Farrell <[email-masked]>
Date: Fri, 13 Oct 2017 15:52:54 +0100

Hiya,

> to get the initial conn-id (b), do crypto (c) store state for all the live

Pre-pending a fixed length (known to both sides) load-balancer
ID would be fine, sure. That'd change the function to something
like:
    next-id = lb-id || H(foo||prev-id)

So long as each load balancer is busy enough that still has the
hard-to-link property I think. The length of the lb-id could be
fixed or part of the negotiation, with zero being a fine length
when there's no lb-id needed.

I think this'd work ok regardless of who controls the initial id
value, so long as we don't need ids to work like tickets (where
the id value would be the ciphertext of some state info).

> in whenever you get an unknown CID, which the attacker can send you at any

Yes, schemes like this can be worse when packets go missing
around the time of an id change.

However, I think with this scheme (which isn't even on a napkin
yet, just these mails:-), the sending side would just make the
change when they want, and wouldn't signal that it's changed the
id. So, in some cases (say if receivers store current and next,
and id changes and packet losses are infrequent) a single packet
drop would be just that and the id change wouldn't affect things
at all. In the putative nb-IoT case I mentioned before then it
could be a good bit worse unless the receiver stores a bunch of
future ids. (I agree some work is needed to figure out if there's
an acceptable scheme here, so for now I'm arguing that we not
preclude such schemes when adopting your draft.)

In figuring this out, I'd argue that we ought be comparing ideas
like this against two things: 1) the simplest solution that does
allow linkabillity and 2) the costs of setting up a new TLS
session to avoid linkability. While this or similar schemes will
look bad compared to (1), they will likely look pretty good
compared to (2).

Of course, how one evaluates such comparisons will depend on how
serious a threat one considers linkabillity. I'd argue that many
devices that'll need connections ids will be devices where the
possibility of linkability could be a significant threat and where
new TLS session establishment will be rare, so we therefore ought
provide some good method of avoiding linkability.

Cheers,
S.

---

From: Eric Rescorla <[email-masked]>
Date: Fri, 13 Oct 2017 08:58:24 -0700

> when there's no lb-id needed.

Well, this is a lot more complicated for the client and unless you place
very strict limits on lb-id, it ends up with the server just dictating an
identifier to the client so you have the scheme in this draft.

> the id value would be the ciphertext of some state info).

That's actually a design that people consider quite often and has been
discussed
for QUIC.

> yet, just these mails:-),

Sure but we contemplated a number of these designs for QUIC, so we're not
starting from scratch here.

> he sending side would just make the

I'd say three things here:

1. First, as I said we considered a lot of different designs for providing
better unlinkability than the design in this draft, and none of the
ones that did significantly better had reasonable scaling properties.

2. The precise point of designing this as an extension is that if we
had a better design we could drop it in with a new extension code point,
so accepting this design doesn't preclude anything.

3. You seem to be claiming that your design has better linkability
properties than the design in this draft, but as far as I can tell that's
not correct. In both cases, either side can occasionally change
conn-ids (you can't change in each packet for the scaling reasons
I indicated). In your design one side does so unilaterally, but there
are packet loss concerns, and in the draft, you have to solicit new
conn-ids from the peer but as long as you have one you can change
unilaterally.

The primary difference in your design is that the IDs are opaque
rather than containing data contributed by the other side, but that
difference is immediately weakened as soon as you try to introduce
structure to handle things like the server topology and also comes
at the cost of needing a much larger ID space in each packet to
avoid hash collisions.

-Ekr

---

From: yinxinxing <[email-masked]>
Date: Sat, 14 Oct 2017 02:00:02 +0000

I agree with Stephen. It is essential to ensure the new connection ID couldn't be linked to the old one to avoid tracking risk.

However, it is some sort of implementation issues, and there are more ways to do that(not only hash method). Maybe we can at least give suggestions or warning in the draft.

Regards,
Yin Xinxing 

-----邮件原件-----
发件人: TLS [mailto:[email-masked]] 代表 Stephen Farrell
发送时间: 2017年10月13日 22:17
收件人: Eric Rescorla
抄送: [email-masked]
主题: Re: [TLS] Connection ID Draft

Hiya,

On 13/10/17 14:56, Eric Rescorla wrote:
> I've seen a number of designs like these, but in general they have 
> quite poor scaling properties. Can you describe the precise design you 
> have in mind so that we can analyze it.

Sure, I can try...

What I'm suggesting is that we define a way that a TLS node can change the connection ID to a new value that is hard to link to the old, as a function that can be used when the implementation chooses to use it.

I'm not currently arguing that the ids should be changed for each packet. E.g. if a node is able to detect that the 5-tuple has just changed, it could use this then. If a node sends one packet per day over say an nb-IoT network where it might have a different IP address each time (not that we know how nb-IoT will operate, so I'm guessing:-) then it might make sense to do this for every packet.

To change an id, pick a value foo that depends on the TLS session, e.g. like an extractor, and that is not visible to the network. Then set next-id to H(foo||prev-id) or some similar construct.

Receivers can store a set of ids calculated when the session is established. I'd guess storing two (current and next) might be a sensible thing to do.

The inefficiently compared to simply incrementing the id value is to add another column to the lookup table I guess. I don't know if that's a big scaling deal or not.

Cheers,
S.

---

From: Benjamin Kaduk <[email-masked]>
Date: Sat, 14 Oct 2017 11:54:20 -0500

On 10/12/2017 06:13 PM, Eric Rescorla wrote:
> <https://urldefense.proofpoint.com/v2/url?u=https-3A__tools.ietf.org_html_draft-2Drescorla-2Dtls-2Ddtls-2Dconnection-2Did-2D00&d=DwMFaQ&c=96ZbZZcaMF4w0F4jpN6LZg&r=sssDLkeEEBWNIXmTsdpw8TZ3tAJx-Job4p1unc7rOhM&m=CDf7zAKso3W-qOi8wQqK6uWaBGWhWCn6w5Q5gFHEjUY&s=1hkGM7Hn4fhvL0vEqnLxYGyRwan9tjm4IICGPgXS4eo&e=>
>
> Comments welcome.
>

I see it already got some good comments, so I'll try to stick to just
new ones.

Since a participant that wants to make use of DTLS CIDs might expect to
talk to many peers, some of which do and some of which do not support
the CID extension, it seems like the participant might want to always
use the same cid_length for all its peers that support CIDs, to ease the
parsing decision and CID lookup process, and we could mention this
expectation. Or am I missing some reason why the CID would be easy to
pick out of the ciphertext otherwise?

In the security/privacy considerations:

   An on-path adversary, who is able to observe the DTLS 1.2 protocol
   exchanges between the DTLS client and the DTLS server, is able to
   link the initial handshake to all subsequent payloads carrying the
   same connection id pair (for bi-directional communication).

My first time reading this I thought that the text was only claiming that linkability was possible if the initial handshake was observed, which is not really needed.  It might be better to avoid mentioning the handshake at all and just say that the attacker is able to link all observed payloads carrying the same connection id pair as being exchanges between the same client and server.

-Ben

---

From: Eric Rescorla <[email-masked]>
Date: Sat, 14 Oct 2017 13:40:12 -0700

On Sat, Oct 14, 2017 at 9:54 AM, Benjamin Kaduk <[email-masked]> wrote:

> I see it already got some good comments, so I'll try to stick to just new
> ones.
>
> talk to many peers, some of which do and some of which do not support the
> CID extension, it seems like the participant might want to always use the
> same cid_length for all its peers that support CIDs, to ease the parsing
> decision and CID lookup process, and we could mention this expectation. Or
> am I missing some reason why the CID would be easy to pick out of the
> ciphertext otherwise?
>

No, I think that's a good suggestion. PR Welcome :)

> My first time reading this I thought that the text was only claiming that linkability was possible if the initial handshake was observed, which is not really needed.  It might be better to avoid me…
Yeah, that seems like a good point.

-Ekr

---

From: "Fossati, Thomas (Nokia - GB/Cambridge, UK)" <[email-masked]>
Date: Mon, 16 Oct 2017 13:11:11 +0000

Hi Matt,

> ContentType is the way to go.

Re: the length hack.  I agree with you that it is not the right way to
go here.

Re: CT vs version, a couple of quick thoughts:
- I'm still unconvinced that CT is the right place to signify a change
  in the parsing logics that effectively spans all CTs;
- Besides, ISTM that version is the only field that would potentially
  work for 1.3 as well as 1.2?

Cheers,

---

From: Eric Rescorla <[email-masked]>
Date: Mon, 16 Oct 2017 06:15:51 -0700

On Mon, Oct 16, 2017 at 6:11 AM, Fossati, Thomas (Nokia - GB/Cambridge, UK)
<[email-masked]> wrote:

> Hi Matt,
>
> On 13/10/2017, 14:15, "TLS on behalf of Matt Caswell" <
> [email-masked] on behalf of [email-masked]> wrote:

We expect to remove version in the 1.3 encrypted record format,

-Ekr

---

From: Martin Thomson <[email-masked]>
Date: Tue, 17 Oct 2017 10:42:24 +1100

Going back to the start, it seems like there is an implied problem
with the draft in that connections with the identifier are hard to
distinguish from connections without.  Is that the main problem?

I can't see how an explicit marking helps.  If we admit the
possibility that some connections will not support this new feature,
then the recipient of packets is forced to identify those connections
by 5-tuple.  That's invariant.  Mixed deployments have some
challenges, but it's not completely unworkable.

My conclusion is that peers without connection ID support monopolize
the 5-tuple that they use, so that other connections can't migrate to
that 5-tuple.  They also cannot migrate to another 5-tuple.
Otherwise, things work out.

To reach that point, you have to realize that a mixed deployment has
to use 5-tuple as a primary key.  Packets that come in on a new
5-tuple are matched to connections opportunistically on what might or
might not be a connection ID.  If it is, then great (better make sure
you ask for the same length ID from all peers, or match on
prefixes...).  If it isn't, then the ciphertext will be read as a
connection ID, but even if it does identify a connection it will fail
to decrypt.

Thomas mentioned a heuristic, but I don't think that we need that.
The only case that is difficult, and it's one that you might not care
about, is one where a connection migrates to the same 5-tuple as an
another connection.  There, you will match to an existing connection
and find that the packet doesn't decrypt.  If the connection that you
have associated with the 5-tuple supports and uses a connection ID,
you can recover without trial decryption.  Otherwise, you just have to
drop the packet when it doesn't decrypt.  (You could look up all the
connections without connection IDs and use trial decryption, but why
bother spending the effort and undermine the strength of your ciphers
in that way.)

You can only truly dispense with the 5-tuple mapping if you can
guarantee that all of your clients support connection ID; at which
point you can drop that table and route on connection ID alone.

Packet inspection boxes will have maintain state, I don't see a way
around that.  The point here being that you need state to know how
long the connection ID is, as well as how long it is.

The middlebox issue is somewhat more interesting.  If it is *your*
middlebox, then there might be a case for routing connections with a
connection ID differently.  Based on the above, I would have said that
it might be better to only deploy that sort of configuration when you
can insist on receiving a connection ID.  An explicit marking helps,
but the cost is pretty high if we care about saving bits.

My suggestion for the middlebox is to use a longer connection ID and
include a MAC inside the connection ID.  It ends up being a longer
connection ID than the one QUIC uses, but it would allow the stateless
routing middlebox to identify packets with and without a connection ID
without any explicit marking.  That doesn't require any change to the
design.

---

From: Christian Huitema <[email-masked]>
Date: Mon, 16 Oct 2017 19:54:28 -0700

On 10/13/2017 7:29 AM, Eric Rescorla wrote:
>
>
> On Fri, Oct 13, 2017 at 7:16 AM, Stephen Farrell
> <[email-masked] <mailto:[email-masked]>> wrote:
>
>
>     Hiya,
>
>     ...

The problem with these encrypted or hashed schemes is the scaling part.
When you receive a packet from a yet-uncategorized 5-tuple, you have to
find the context. It can be "any of the contexts currently establish",
so you end up having to try them all, or maybe 1/2 of them in average.
That can be a lot of hashes or encryptions. If the sender can only send
some token that the recipient already expects, the demuxing becomes much
simpler.

I  like EKR's design. But it is a scheme that can be implemented, and
will work. There are edge cases, like controlling how many connection ID
a peer is willing to provide in advance.  And it tends to fall in the
"sharp knife" category of tools, i.e., you have better understand what
you are doing. In particular, you need a strategy for breaking the
linkability of sequence numbers, otherwise connection-id changes will
not accomplish much. But there may well be other issues, like time
correlation, or traffic patterns.

By the way, the often considered scenario is "what happens if the NAT
rebinds and the client does not know." I think a simple heuristic of
changing the connection ID when coming out of long sleeps would help a
lot there. NAT  bindings don't change much if the traffic is sustained.
But if the last packet was many seconds ago, the client would be wise to
just rotate the connection ID before sending anything new.

The other often considered scenarios are variations of the "mobile
network". The NAT rebinds because the mobile router moved to a new
connection, but the client does not know. I can't think of a good
heuristic there, but it certainly would be helpful if the mobile router
somehow informed the clients. That's probably easier to engineer than
changing connection ID on every packet.

-- 
Christian Huitema

---

From: "Fossati, Thomas (Nokia - GB/Cambridge, UK)" <[email-masked]>
Date: Tue, 17 Oct 2017 10:26:06 +0000

Hi Martin,

> bother spending the effort and undermine the strength of your ciphers

The following case (NAT box reboot) is problematic:

1. Application '1' on host A (A.1) uses DTLS+CID with application '1' on
   host B (B.1);
2. Application '2' on host A (A.2) uses plain-old DTLS with B.1;
3. The NAT box reboots (all previous 5-tuple mappings are lost);
4. B.1 receives a record from A.1 (whose 5-tuple has changed in the
   meanwhile);
 
How is B.1 supposed to correctly interpret the bytes starting at offset
+11?  (For what it knows, it could be CID from A.1 or the length field
from A.2.)
 
That's where the heuristic I mentioned in the other email comes in,
I think.

> long the connection ID is, as well as how long it is.

I might be missing something fundamental here, but isn't the length
encoded in the CID field on the wire?

Cheers

---

From: Martin Thomson <[email-masked]>
Date: Wed, 18 Oct 2017 08:35:39 +1100

On Tue, Oct 17, 2017 at 9:26 PM, Fossati, Thomas (Nokia -
> +11?  (For what it knows, it could be CID from A.1 or the length field

I don't think that this is a problem.

connection = five_tuples.lookup(packet.five_tuple)
if (!connection) {
  connection = connection_ids.lookup(packet[connection_id_offset:connection_id_offset+connection_id_length])
}
if (!connection) {
  // is this a ClientHello?  otherwise drop it
}

Of course this doesn't help you with A.2, but that's why this draft exists.

If the server can insist on connection IDs from all clients (in the
far future perhaps, or for an entirely new protocol), then the code is
more simply:

connection = connection_ids.lookup(packet[connection_id_offset:connection_id_offset+connection_id_length])
if (!connection) {
  // is this a ClientHello?  otherwise drop it
}

> encoded in the CID field on the wire?

Not by my understanding.  There isn't any need (the intent is to have
the CID only consumable by the entity that created it, and any others
that it collaborates with, like a load balancer).

---

From: "Fossati, Thomas (Nokia - GB/Cambridge, UK)" <[email-masked]>
Date: Wed, 18 Oct 2017 06:43:52 +0000

Hi Nikos,

On 13/10/2017, 07:21, "TLS on behalf of Nikos Mavrogiannopoulos" <[email-masked] on behalf of [email-masked]> wrote:
> Another worrying feature is that the client can make the server send
> up to 255 verbatim bytes on the wire of his choice. Why was this
> feature added? Are there use cases related with it (intro doesn't
> mention any), or it was only thought as a make it as generic as
> possible approach? If it is the latter, I'd recommend to provide a
> simple approach that covers the described use cases.
> 

I'd like to get a better understanding of your concern here.

Is it size?

Or is that it creates a potential sub-channel for sending identifying
information?

If the latter, it doesn't look much different from Random (except it's
larger)?  And then it gets hashed in the finished message, so, the room
for a third party to fiddle with it seems really limited.

Exactly, what risk do you foresee?

---

From: "Fossati, Thomas (Nokia - GB/Cambridge, UK)" <[email-masked]>
Date: Wed, 18 Oct 2017 06:44:00 +0000

On 17/10/2017, 22:35, "Martin Thomson" <[email-masked]> wrote:
> > 1. Application '1' on host A (A.1) uses DTLS+CID with application
> >    '1' on host B (B.1);
> > How is B.1 supposed to correctly interpret the bytes starting at
> > offset +11?  (For what it knows, it could be CID from A.1 or the
> > length field from A.2.)
> 

This is quite similar to the trial and error / heuristic that I was
mentioning in [1].

Note that if A.1 and A.2's 5-tuples are swapped, the algorithm fails to
recognise A.1 as CID-enabled and sends it forward to the crypto handler
when it shouldn't. 

It looks simple, but it introduces subtle complexity in that parsing is
not self-contained anymore: it depends on a couple of things (the
connection_ids and five_tuples stores) that in principle should have
nothing to do with making sense of an incoming record.

And the already discussed limitations:
- Fragility on corner cases (e.g., the 5-tuple swap above);
- Forcing middleware to keep state;
- Breaking wireshark & co unless they can see the whole session;
- (Depending on the use case, the cost of the two lookups per record
  on the parsing might have a performance impact.)

> that it collaborates with, like a load balancer).

You are right.  For some reasons, I was implying cid was encoded as a
variable-length array.  That said, I don't think saving 1 byte here is
worth the self-inflicted pain of making tshark unusable :-)

Cheers

[1] https://www.ietf.org/mail-archive/web/tls/current/msg24575.html

---

From: Martin Thomson <[email-masked]>
Date: Wed, 18 Oct 2017 19:08:24 +1100

On Wed, Oct 18, 2017 at 5:44 PM, Fossati, Thomas (Nokia -
> This is quite similar to the trial and error / heuristic that I was

You didn't mention 5-tuples.  And it isn't trial and error: you use
5-tuple as your primary key and use connection ID to latch.

> recognise A.1 as CID-enabled and sends it forward to the crypto handler

As I said before, any connection without a connection ID monopolizes
that 5-tuple making it inaccessible to other connections.  I think
that in this case: too bad.

> - Fragility on corner cases (e.g., the 5-tuple swap above);

I don't see how you can avoid this in the general case.  Any
connection without connection ID is going to be hard to correlate if
it moves.  As for the connection that does have a connection ID but
moves on top of a connection that doesn't, I don't think that is an
acceptable loss.

> - Breaking wireshark & co unless they can see the whole session;

Both of these are acceptable to me.  Unless you can describe a
middlebox use case that needs access to this information and can't
deal with the solution that I described.  Wireshark and co will need
to see the handshake if they want to decrypt and that's the only case
that is important.

>   on the parsing might have a performance impact.)

The second lookup only happens after a migration.  I neglected to
mention that successful use of a connection ID causes the 5-tuple to
be assigned to that connection; there's a trick there in that you need
to watch for reordering, but it saves the double lookup.

---

From: Nikos Mavrogiannopoulos <[email-masked]>
Date: Wed, 18 Oct 2017 10:13:03 +0200

On Wed, 2017-10-18 at 06:43 +0000, Fossati, Thomas (Nokia -
GB/Cambridge, UK) wrote:
> Hi Nikos,
> 
> On 13/10/2017, 07:21, "TLS on behalf of Nikos Mavrogiannopoulos" <tls
> [email-masked] on behalf of [email-masked]> wrote:

I had in mind scenarios of using these bytes to make the peer of talk
another protocol with an unsuspecting party, or using the peer to
attack a middle box which parses packets, e.g, by attempting buffer
overflows to it.

regards,
Nikos

---

From: Simon Bernard <[email-masked]>
Date: Wed, 18 Oct 2017 18:39:44 +0200

This makes me think about if this is feasible/desirable to use 
connection id to do load balancing.

I think about use cases where you have a cluster of server behind only 
one IP address. Often traffic will be load balanced by IP.
But with UDP and Nat environment, the IP can change.

Thx to CID, if client is redirected to the same server in the cluster, 
even if its IP has changed it will be able to communicate without new 
handshake.
But if its IP has changed there is little chance than load balancer will 
balance it on the same server and so new handshake is needed. (unless 
server share their connection state)

Any thought about that ?

---

From: Eric Rescorla <[email-masked]>
Date: Wed, 18 Oct 2017 09:58:57 -0700

On Wed, Oct 18, 2017 at 9:39 AM, Simon Bernard <[email-masked]>
wrote:

> This makes me think about if this is feasible/desirable to use connection
> id to do load balancing.
>
> I think about use cases where you have a cluster of server behind only one
> IP address. Often traffic will be load balanced by IP.

The usual procedure is for the server and load balancer to coordinate on
the CID algorithm.
A trivial version would be for the server to generate the connection ID as
<server-id> || <random>.

-Ekr

>>    connection = connection_ids.lookup(packet[c
>> onnection_id_offset:connection_id_offset+connection_id_length])
>> }
>> if (!connection) {

---

From: "Fossati, Thomas (Nokia - GB/Cambridge, UK)" <[email-masked]>
Date: Thu, 19 Oct 2017 14:21:48 +0000

Hi Martin,

sorry for taking so long to replay.

> On 18/10/2017, 09:08, "Martin Thomson" <[email-masked]>
> wrote:
> 

We seem to have a slightly different opinion on the meaning of trial and
error :-)  But more importantly, we seem to disagree on whether parsing
a binary header is orthogonal to context lookup (either via 5-tuple or
CID) or not.

> > Note that if A.1 and A.2's 5-tuples are swapped, the algorithm fails
> > to recognise A.1 as CID-enabled and sends it forward to the crypto
> > handler when it shouldn't.
> 

I'm not sure I agree with that.  CID should be the tie breaker exactly
in these situations.  When something like that happens, if your
implementation supports CID it should win/survive over one that doesn't.

> > And the already discussed limitations:i

I think you mean "I do think that is an acceptable loss", or "I don't
think that is an unacceptable loss", right?
 
> to see the handshake if they want to decrypt and that's the only case

For diagnostics, it'd be pretty useful if one could filter a capture by
CID and follow *that* session among lots of others.  Irrespective of
what's in the encrypted payloads (which one can probably get from the
endpoint, if needed).  This is one use case that seems very useful to me
and doesn't require wireshark to keep state.  I'm not saying that there
are no work-arounds: we know how to make do with pcap filters.  But I'd
prefer to design something that is simple and cheap to implement and use
in the first place, if possible.

What I'm asking for is a codepoint and an explicit length for the CID,
i.e., a total +1 byte per 1.2 record on the wire.  I'm not sure the
tiny saving we get with the current proposal justifies the increase in
complexity.

> The second lookup only happens after a migration.

In the IoT use cases, re-binding during a sleep cycle is the common
pattern, so the second lookup is going to be fairly common.

> I neglected to mention that successful use of a connection ID causes
> the 5-tuple to be assigned to that connection; there's a trick there
> in that you need to watch for reordering, but it saves the double
> lookup.

The thing that makes me slightly nervous is that we are talking about
doing trial & errors (at least in my definition of the term) and other
implementation tricks to achieve the very trivial task of parsing a
binary header.  This is what makes red flags pop up and makes me
think that we can do better.

Cheers

---

From: Stephen Farrell <[email-masked]>
Date: Sun, 22 Oct 2017 16:23:37 +0100

(Sorry for the slow response...)

Two things below...

> That's actually a design that people consider quite often and has been

So, if the WG want to allow for such designs, then I think that'd
be better explicitly stated as some level of requirement, e.g. to
say that some aspect of the scheme needs to allow some cids to be
an encrypted form of something else. (I do think allowing for such
is quite reasonable.)

> conn-ids from the peer but as long as you have one you can change

I think the design I outlined does differ somewhat from the draft.
In the draft the new connection ID has to be sent explicitly, but
in this design it can be inferred, which saves bandwidth. I'm not
claiming that's a mega-win, but I do think it might be needed for
some of the device-sends-one-message-per-day scenarios if those
are also using e.g. some lpwan radio technology.

Maybe the thing we could agree at this stage is that the cid scheme
has to be usable in that one-message-per-day scenario and needs to
provide some way that such messages aren't easily linkable based on
cids. (Which is useful if/when the 5-tuples don't provide linkage.)
Personally I do think a hash-chain based scheme may be needed to
meet that requirement, but I may well be wrong of course, as that
happens quite a lot:-)

Cheers,
S.

---

From: Eric Rescorla <[email-masked]>
Date: Sun, 22 Oct 2017 08:41:36 -0700

> an encrypted form of something else. (I do think allowing for such

I'd be fine with adding that sort of text.

> I think the design I outlined does differ somewhat from the draft.

I didn't say that it didn't differ. I said I didn't think it had better
linkability
properties.

> in this design it can be inferred, which saves bandwidth.

That's not obviously true, because the CIDs in your case need to
be larger to avoid collision problems.

> cids.

I think that's a requirement in some cases but not others. It might be
best to settle for the others.

(Which is useful if/when the 5-tuples don't provide linkage.)
> meet that requirement, but I may well be wrong of course, as that

That's clearly not true in the case where messages are symmetrical, as
each side can provide a new connection ID with each message it sends.
In fact, we considered just such a design for QUIC before concluding
it was impractical.

And note that in the case where you are actually sending one un-acked
message per day, then it's actually quite easy to have significant packet
loss in which case you run into the scaling problems I mentioned in my
previous message.

Again, I really would invite you to try to produce a fully worked out
proposal,
as its precisely the exercise of trying to do so that led us to this
design. As
none of the options are really ideal, it's quite easy to find deficiencies
in
any particular design, especially when the alternative is something that
is at the napkin stage, and so has deficiencies which are yet to be
determined.

-Ekr

---

From: Stephen Farrell <[email-masked]>
Date: Sun, 22 Oct 2017 16:50:13 +0100

> best to settle for the others.

Sorry, I'm not sure what you mean there. Are you saying that you think
the above requirement can't be met by a generally usable scheme?

I agree that not all scenarios need to meet the req posited above.

I'd worry that if DTLS1.3 can't meet the above requirement then folks
will invent something that does, which may be worse than using DTLS
in a bunch of cases. OTOH, one could equally, and maybe fairly, argue
that DTLS really doesn't scale down quite that far, which'd I guess
argue that there's a need for some other security protocol for those
situations.

S.

PS: I fully accept your point that purely napkin-based schemes aren't
good enough and if those're the only kind of hash-chain based proposals
seen, then the WG oughtn't go for one of those.

---

From: Eric Rescorla <[email-masked]>
Date: Sun, 22 Oct 2017 09:04:53 -0700

> argue that there's a need for some other security protocol for those

It's not a matter of DTLS versus non-DTLS. I am unaware of any method
of providing conn-IDs that simultaneously meets the requirements of:

- Unlinkability
- Being able to survive multiple conn-ID changes in one round-trip
  (which is implicit in both the one-packet per day and the unknown
  address changes scenarios)
- Low bandwidth
- Good receiver-side scaling (both state and computational)

This is a generic problem, not one limited to DTLS. And as I said earlier,
to the extent to which we either need specific schemes that meet different
subsets of these requirements or we come up with a better generic scheme,
the extension-based approach accommodates it.

We've seen others, and they fail the receiver-side scaling test, IMO

-Ekr

---

From: Stephen Farrell <[email-masked]>
Date: Sun, 22 Oct 2017 18:28:58 +0100

On 22/10/17 17:04, Eric Rescorla wrote:
> It's not a matter of DTLS versus non-DTLS. 

Not sure tbh, ISTM there's a bunch of challenges in trying to
use the kind of lpwan technologies being developed with DTLS,
with cid just being one of those. But time will tell I guess,
and that's a different discussion.

> I am unaware of any method

Fair enough - I can buy that the last above suffers when one tries
to satisfy all the rest. Maybe that means a WG draft ought have an
applicability statement section that captures the scenarios where
that particular cid extension is suitable.

I'll be sad though if the end result is to sacrifice unlinkability
which I fear will be the likely outcome in practice.

> the extension-based approach accommodates it.

Again, maybe some applicability text as per the above would make
it clearer that the draft is describing one (though hopefully the
most commonly useful) scheme and that others may be needed in
other situations.

Cheers,
S.

PS: In case it helps, with the additions discussed earlier and
above, and with the understanding that exploring other cid schemes
for cases where this one isn't fully satisfactory isn't ruled
out, I think this draft would be a fine starting point for a WG
document.