Subject: Re: [TLS] TLS1.3 + PSK with multiple identities

From: David Woodhouse <[email-masked]>
Date: Mon, 19 Sep 2016 10:49:50 +0100

On Mon, 2016-09-19 at 10:29 +0200, Nikos Mavrogiannopoulos wrote:
> On Mon, 2016-08-08 at 11:28 +0300, Ilari Liusvaara wrote:
> > More compact and makes the option where server sends some bad option
> > more clear.

Note that if we really want to be more compact, we might also observe
that there is a redundant length field in the extension as sent by the
client:
           case client_hello:
               PskIdentity identities<6..2^16-1>;

Each extension has at least four bytes on the wire — the extension_type
itself, and the length field of the extension_data in a uint16.

If I am interpreting the spec correctly, then the data for the
PreSharedKeyIdentity extension in the ClientHello then follows that
with another uint16, which is *always* a value two lower than the one
which immediately precedes it.

e.g.

  0x00 0x29      // ExtensionType extension_type == 41
  0x00 0x14      // opaque extension_data<0..2^16-1>
    // This length field is entirely redundant:
    0x00 0x12      // PskIdentity identities<6..2^16-1>
                     // First identity:
      0x00 0x00      // PskKeyExchangeMode, PskAuthenticationMode
      0x00 0x04      // opaque identity<0..2^16-1>
        0x44 0x61 0x76 0x65 // "Dave"
                     // Second identity:
      0x00 0x00      // PskKeyExchangeMode, PskAuthenticationMode
      0x00 0x06      // opaque identity<0..2^16-1)>
        0x43 0x68 0x6c 0x6f 0xc3 0xab // "Chloë"
 
Do we care that the '0x00 0x12' bytes on my third line above are
entirely redundant on the wire? Or have I interpreted it wrong?

I also find it interesting to note that the total permitted length of a
single PskIdentity (65539 bytes) is such that you might not be able to
fit even *one* of them into the PreSharedKeyIdentity extension at all,
let alone multiple such.

> > > 2. Why does the client send multiple identities? In TLS-SRP a single
> > > identity is sent, and the same in the existing TLS-PSK rfc. How is this
> > > envisioned to be used? A client sends: I'm probably one of Bob, Nikos,
> > > George, take a look on that list and tell me who I really am? In that
> > > case why not allow the server, to reply with a username outside that
> > > list (i.e., assign a new one to be used at the next session - see point
> > > 1).
> > You already need multiple if you try to "resume"[1] DHE-PSK session
> > (since "resumption" shares the PSK space).
> 
> That's very awkward. That way the protocol mandates code like:
> 
> if (!id_in_resumption_db()) {
>     if (!valid_ticket())
>       if (!try_find_user_in_psk_userfile())
>         proceed_with_random_psk(); /* hide the fact that username
> doesn't exist in db */
> }
> 
> which is not really sane code. Not only that, but servers who would
> like to prevent valid username testing in their PSK key file as above,
> would be forced to make resumption attempts with unknown or long-
> expired tickets fail.
> 
> A protocol must have clarity on the data sent on the wire and their
> purpose. Cross protocol attacks work by exploiting data which may be
> interpreted in multiple ways and such generic purpose identifiers seem
> to be like a good candidate for that.
> 
> I think at minimum identities known to the protocol (e.g., resumption)
> should be distinguishable from PSK usernames. The draft leaves that to
> the server implementor to do, but I do think such identifiers should be
> tagged at the protocol level since it affects all implementations.
> 
> > 
> > 3. The maximum size of the username is 2^16. Isn't that excessive
> > > 
> > > for a
> > > user name or a user identifier? Why not set 2^8? That would fit a
> > > uuid
> > > or anything similarly large.
> > If one wants to do the equivalent of tickets in TLS 1.2, one needs
> > pretty large usernames.
> 
> I find that, as another unfortunate side-effect of combining unrelated
> protocol fields.

Oh, it's more fun than that. RFC4279 §5.1 currently says that the PSK
identity MUST be a UTF-8 character string. Libraries such as OpenSSL
and GnuTLS already handle identities as NUL-terminated strings.

The current TLSv1.3 draft appears to relax that requirement without any
form of explicit compatibility note about it — I'd expect to see *some*
mention in the 'Major Differences from TLS 1.2" section.

Perhaps one way to resolve much of this is to put the traditional PSK
identities into one PreSharedKeyExtension and maintain the UTF-8
requirement there, and to put the "identity" used for session
resumption into a different extension. Perhaps allowing the latter to
appear multiple times in a ClientHello and for their contents to be
concatenated, which partly addresses the problem of their total size.

Is there no way the PSK identities for session resumption could be made
smaller? Of the data which RFC5077 suggests that we put into a session
ticket (and thus the PSK identity), is there *none* of it which could
be sent later in a ClientKeyExchange packet? Does the server need *all*
of it, for every session being offered for resumption by the client, in
the ClientHello?

My final comment on the PSK identities for now... I see the TLSv1.3
draft now contains a PskKeyExchangeMode which is absent from the
(once-)corresponding draft-jay-tls-psk-identity-extension. It's not
entirely obvious to me how this interacts with the selected cipher
suite, which itself may or may not use (EC)DHE.

Is it permitted, and what is the meaning, to request a cipher suite of
(e.g.) TLS_PSK_WITH_AES_256_CBC_SHA and set PskKeyExchangeMode in the
identity to 'psk_dhe_ke'? Or conversely, to use the cipher suite
TLS_DHE_PSK_WITH_AES_256_CBC_SHA with PskKeyExchangeMode set to
'psk_ke'?

This seems redundant to me at first glance (unless some combinations
really do mean that you end up doing DHE *twice*) and could probably do
with some clarification.

Or is the intent that when requesting offering both DHE and non-DHE
cipher suites, the client should offer *two* identities, one with each
possible value of PskKeyExchangeMode? In which case do we want a third
value for PskKeyExchangeMode which indicates that a given identity may
be used in either mode?

-- 
David Woodhouse                            Open Source Technology Centre
[email-masked]                              Intel Corporation

---

From: Eric Rescorla <[email-masked]>
Date: Mon, 19 Sep 2016 04:41:06 -0700

> entirely redundant on the wire? Or have I interpreted it wrong?

Not enough to fix it, this is just the way TLS rolls.

> be sent later in a ClientKeyExchange packet?

No. Also, there isn't a CKE record in TLS 1.3. All information needed to
derive
the key needs to be in the CH.

> really do mean that you end up doing DHE *twice*) and could probably do

TLS 1.3 cipher suites do not convey key exchange mode, just AED and KDF. See
https://tlswg.github.io/tls13-spec/#cryptographic-negotiation for an
overview of
negotiation.

-Ekr

---

From: David Woodhouse <[email-masked]>
Date: Mon, 19 Sep 2016 13:26:42 +0100

> Not enough to fix it, this is just the way TLS rolls.

An interesting contrast to Nikos's observation that using the index in
the response is "used nowhere else in TLS" — which he could have
phrased using similar words. But I suppose in that case you're saving a
*lot* more than two bytes in the ServerHello, so it makes sense to
deviate from "the way TLS rolls" :)
 
> No. Also, there isn't a CKE record in TLS 1.3. All information needed to derive

Well, that was kind of my point. Information needed to derive the *key*
needs to be in the ClientHello.

But if it's auxiliary information which isn't actually *needed* to
derive the key or to select which {identity to use,session to resume},
then perhaps the client could be required to supply it afterwards.
And then the client only needs to supply one copy of it for the
identity which the server actually selected, not one for *each*
identity which was being offered by the client.

But OK, if none of the information included by RFC5077 is in that
category then we really do need to cope with PSK identity fields which
can theoretically *each* be larger than the amount you can fit into a
single TLS extension...

I share Nikos's concern about using the PSK identity for two completely
different types of identifiers — especially given that one type has
historically been defined as UTF-8 text, while the other is binary.

The reason I care about this right now is that we're looking at using
PSK to bootstrap a DTLS connection in the context of an SSL VPN,
currently using DTLS 1.2 and draft-jay-tls-psk-identity-extension. And
the binary nature of 'session resumption' PSK identities will have an
effect on the crypto library APIs used to manage that — which as I
said, currently assume that they can use NUL-terminated strings.

So it would be useful to have some clarity on the UTF-8 requirement
from RFC4279, and whether it's being completely abandoned with TLS 1.3.

> https://tlswg.github.io/tls13-spec/#cryptographic-negotiation for an overview of
> negotiation.

Ah, thanks. That makes more sense now.

-- 
dwmw2

---

From: Eric Rescorla <[email-masked]>
Date: Mon, 19 Sep 2016 05:46:09 -0700

> deviate from "the way TLS rolls" :)

Yes.

> then perhaps the client could be required to supply it afterwards.

You need the complete ticket to make sensible decisions.

> identity which was being offered by the client.

We're most likely going to allow only on PSK anyway.

> currently using DTLS 1.2 and draft-jay-tls-psk-identity-extension.

I recommend against this: I very much doubt that we are going to adopt this
draft in TLS.

> from RFC4279, and whether it's being completely abandoned with TLS 1.3.

It's being abandoned. PR welcome.

-Ekr

---

From: David Woodhouse <[email-masked]>
Date: Mon, 19 Sep 2016 15:07:53 +0100

> We're most likely going to allow only on PSK anyway.

You mean "only one", I assume?

What if my client authenticates with an actual pre-shared key, and I
also want to resume a session? As it stands, that means I really do
need to offer two PSK identities — one for the real identity, and one
for the session resumption attempt. Are you saying that won't be
permitted?

Or do we stop to stop conflating the two types of PSK-identity, so that
we can allow only one of each?

> I recommend against this: I very much doubt that we are going to adopt this

That is useful feedback; thank you. Although I'm slightly confused —
although the draft is out of date, I thought the point of it was to
simply document what you *are* adopting in TLS1.3, for use in TLS1.2.
Are you saying that the extension will never be retroactively 'blessed'
for TLS1.2 even when it's part of TLS1.3?

What we're trying to do is move away from the existing model, inherited
from Cisco AnyConnect, where the DTLS ciphersuite is negotiated out-of-
band along with a master secret, and then we 'resume' a DTLS session
that never really existed.

It took us a *long* time to gain support for DTLS1.2 and AEAD cipher
suites because of that, and it would be much better just to let DTLS
negotiate as $DEITY intended.

But the architecture of our server is such that it *really* wants to
know from the very first ClientHello packet which client it's talking
to, so that the packet can be dispatched to the correct worker
process. 

The first prototype of this continued to abuse the Session-ID to
identify the client — making it *look* like a session resume attempt
when in fact we weren't prepared to resume the session at all, and we
rely on the server *not* doing so.

I kind of threw my toys out of the pram at that — if we're going to
attempt to use the protocol properly, then I really do want to do it
*properly*. Hence the interest in draft-jay-tls-psk-identity-extension.

If that's not going to be viable, then I'm starting to wonder if we
should just wait for DTLS1.3. After all we *already* support the fun
parts of DTLS1.2, and AEAD ciphersuites, so there's no desperate rush
to start using proper negotiation.

-- 
dwmw2

---

From: Eric Rescorla <[email-masked]>
Date: Mon, 19 Sep 2016 07:55:29 -0700

Yes.

> for the session resumption attempt. Are you saying that won't be

I should start by saying that it's not entirely clear why this is useful.
Can you elaborate?

> we can allow only one of each?

That doesn't address the reasons for only allowing one, unfortunately. See
the thread on Finished stuffing.

> for TLS1.2 even when it's part of TLS1.3?

I can't speak for the motivations of the authors of this draft. It's not a
WG
item. However, I'm not generally in favor of backporting pieces of TLS 1.3
into 1.2
like this.

> to start using proper negotiation.

I would address this either by:

1. Registering a new extension which is used to indicate the right worker
process, but using existing TLS 1.2 PSK.
2. Wait for DTLS 1.3.

-Ekr

---

From: David Woodhouse <[email-masked]>
Date: Mon, 19 Sep 2016 16:37:45 +0100

> I should start by saying that it's not entirely clear why this is useful.

I should start by pointing out that I have no personal *need* for this;
it just seems strange and wrong to forbid it.

I assume you're not asking why one would use PSK in the first place, in
place of public keys? I think the introduction to RFC4279 fairly much
covers that and is still relevant.

So I interpret your question as asking why it's useful to *resume* a
session which was initiated with PSK?

Even though the cryptographic operations are basically the same —
there's none of the heavyweight asymmetric key operations, it's also
the case that resumed sessions may carry more application-specific
context than a newly-authenticated connection. 

Consider IMAP, as an example. It has a large amount of per-connection
state. This *could* be maintained even when the client disconnects —
you can imagine a mobile client which resumes an existing TLS session
and is *immediately* presented with all the status updates which have
occurred since it disconnected, without any need for re-building the
application-session state (or using any of the protocol extensions like
QRESYNC which help to reduce the connection startup time).

(Note: I'm not suggesting a *stateless* resume could do that.)

Perhaps I should turn your question round, and ask: if PSK is a first-
class citizen as a key exchange and authentication method, why *should*
we be forbidden from resuming sessions which started that way... just
because you've chosen to conflate PSK identities and session resumption
on the wire? :)

> > Or do we [need] to stop conflating the two types of PSK-identity, so that

OK, I'll read up on that; thanks.

> process, but using existing TLS 1.2 PSK.

OK... except this basically *is* the PSK identity. So the new extension
we'd want to register, if we want to make it something that's useful in
the general case rather than an application-specific hack, *is*
basically draft-jay-tls-psk-identity-extension :)

If we do anything else, we might as well stick with some of the horrid
hacks we already have (like abusing the session-id and not actually
*resuming* that session).

> 2. Wait for DTLS 1.3.

It's certainly *tempting* to manually add chacha20 to our ever-growing
list and *then* wait for DTLS1.3 :)

-- 
dwmw2

---

From: Eric Rescorla <[email-masked]>
Date: Mon, 19 Sep 2016 09:53:57 -0700

On Mon, Sep 19, 2016 at 8:37 AM, David Woodhouse <[email-masked]>
wrote:

> it just seems strange and wrong to forbid it
>

Yes.

> (Note: I'm not suggesting a *stateless* resume could do that.)

This doesn't seem like the kind of behavior we want to encourage in
applications.

> class citizen as a key exchange and authentication method, why *should*

we be forbidden from resuming sessions which started that way...

Well, I'm not saying you can't do that. As I said, you can use HRR if the
resumption
fails.

just
> because you've chosen to conflate PSK identities and session resumption

As I said before, that's not the reason to restrict to a single identity.

> basically draft-jay-tls-psk-identity-extension :)

No, I don't think that's true. That extension also attempts to actually
negotiate the keys in that layer. I'm just talking about a hint.

-Ekr

---

From: David Woodhouse <[email-masked]>
Date: Mon, 19 Sep 2016 21:35:57 +0100

On Mon, 2016-09-19 at 09:53 -0700, Eric Rescorla wrote:
> Well, I'm not saying you can't do that. As I said, you can use HRR if the resumption
> fails.

I suppose that's an answer in the general case too, isn't it? If you
want to try multiple identities, you can just keep trying with HRR
until you find one that the server accepts.

In fact, it doesn't even need to be "keep trying until...".

You could still offer multiple PSK identities in the ClientHello, and
only offer a hello_finished MAC for the *first* (preferred) one. If the
server doesn't want that one, it can send a HRR with a
PreSharedKeyExtension that tells the client which one it *does* want.

You preserve the original behaviour of negotiating which PSK identity
to use, while also fixing the problem that limits you to just one.

 < ...context switching to my actual use case... >

> negotiate the keys in that layer. I'm just talking about a hint.

It's more than just a hint. It is saying precisely which client it is,
which has a 1:1 correspondence with which PSK it's using.

In theory it would work to use the existing identity in the
ClientKeyExchange in TLS1.2. However, in practice it becomes extremely
painful to do so because the ClientKeyExchange comes in too late.

It is purely a matter of software architecture — the initial incoming
UDP packets reach a dispatcher that needs to hand the connection off to
the appropriate worker process for that client.... and *really* wants
to make that decision based on the ClientHello alone.

If we *start* the handshake in the main dispatcher and get to the point
of seeing the ClientKeyExchange, we have to hand over the partially-
completed handshake (or keep going and then hand over a fully-completed 
handshake) to the appropriate worker. And in fact I don't even think
the dispatcher *has* the actual keys; only the identities so that it
knows where to dispatch connections to.

So I really do think that draft-jay-tls-psk-identity-extension was
*exactly* what I wanted. I don't care about *negotiating* the PSK
identity per se; I'm happy to support only one. It's purely about
*telling* the server, in the ClientHello, which identity I'm using.

I suppose I can just say 'screw it' and continue to abuse the
session-id for this without actually resuming a session :)

-- 
dwmw2

---

From: Eric Rescorla <[email-masked]>
Date: Mon, 19 Sep 2016 14:13:40 -0700

> which has a 1:1 correspondence with which PSK it's using.

Call it a promise, if you prefer. One that you fulfill with the CE.

> knows where to dispatch connections to.

See above. The key advantage of what I am proposing here is that it has
exactly the same cryptographic properties as current TLS-PSK, with the
indicator just serving as a routing-ID.

> *telling* the server, in the ClientHello, which identity I'm using.

See above.

-Ekr

---

From: Nikos Mavrogiannopoulos <[email-masked]>
Date: Wed, 21 Sep 2016 11:31:51 +0200

> indicator just serving as a routing-ID.

We've decided to take that approach. What we have currently is
described at:
https://tools.ietf.org/html/draft-mavrogiannopoulos-app-id-00

Comments are welcome.

regards,
Nikos