Subject: [TLS] Question regarding TLS 1.3 session resumption

From: <[email-masked]>
Date: Sun, 5 May 2019 13:11:27 +0200

Good afternoon all,

The RFC 8446 mentions key schedule, resumption_master_secret and new session
ticket and I am not quite sure if I understand the session resumption
behavior correctly.

My understanding is that both the client and server calculate all the
secrets of the key schedule therefore both the client and server know the
value of the resumption_master_secret, therefore both sides calculate,

PSK = HKDF-Expand-Label(resumption_master_secret,

                        "resumption", ticket_nonce, Hash.length)

and the server sends back to the client the PSK (unencrypted, which acts as
an input into the HKDF-Extract to calculate the 0-RTT encryption key) + new
session ticket (encrypted using the session ticket key). Upon resumption the
PSK is provided as an input into the key schedule together with new ECDHE
parameters to assure forward secrecy of the resumed session + the new
session ticket is sent to the server as a reminder it is a resumed session.

If the session ticket is opaque to the client then the client needs to store
session information of the initial session (cipher suite, key exchange,
etc..) + PSK and session ticket and the server needs to store only the
session encryption key to resume session. Correct?

My question is what key is encrypting the session ticket (is it a symmetric
key that is generated by the webserver/SSL library for each session? In my
Apache 2.4.39 and openssl 1.1.1b testing the TLS 1.3 resumption works
without specifying the SSLSessionTicketKeyFile directive) and what
information is stored in the ticket (is it cipher suite, key exchange?? The
full key schedule is executed anew for resumed session and new crypto.
material is generated so there is no need for the ticket to contain
master_secret or anything similar like in TLS 1.2, so what exactly does the
ticket contain?).

Thank you,

Lukáš Geyer

---

From: Ilari Liusvaara <[email-masked]>
Date: Sun, 5 May 2019 16:03:29 +0300

> session ticket is sent to the server as a reminder it is a resumed session.

The session ticket can also be a server-side database pointer. Which is
highly recommended if ticket allows 0-RTT.

And protocol allows skipping ECDHE, but that is of course a bad idea.

The reason why the ticket_nonce exists is to have all the tickets have
computationally independent keys, even if derived from the same
connection.

> session encryption key to resume session. Correct?

IIRC, one does need key exchange type of initial session. The information
that needs to be stored includes:

- The ticket itself
- Expiry time of authentication (can not be extended).
- Expiry time for ticket (as sent by server)
- Hash function used by initial session
- What key exchange modes are supported for this ticket (if multiple are
  supported).
- Cipher used by initial session (0-RTT only).
- Maximum 0-RTT size (0-RTT only).
- Ticket age masking value
- The PSK key data.

If client demands forward secrecy, one can leave supported kex modes
out and just discard all tickets that do not support PFS.

Note that if connection was resumed, the expiry time of authentication is
copied from the ticket that was used to create the session, there is no
way to extend it. Tickets that have expired either the ticket itself or
the authentication are deleted and must not be used.

> master_secret or anything similar like in TLS 1.2, so what exactly does the

The key (unless tickets are actually database pointers) should be 
symmetric key generated by the server and frequently automatically
rotated (with overlapping validity windows).

Of course, many implementations do not properly autorotate the key.

The ticket contains things like (assuming 0-RTT is not supported, like it
should not):

- The PSK key data
- Expiry time of the ticket.
- Ticket age masking value.
- Hash function used by initial session

If expiry time has passed, the attempt to use the ticket must be
rejected. Same if the calculated ticket age and the unmasked ticket age
disagree too much (but beware that there are pretty bad clocks out
there... The mechanism can not correct even first-order error)

And yes, the tickets do not contain anything like master_secret. The
TLS 1.2 session ticket mechanism is a security disaster (with many
small mistakes combining into one big problem).

-Ilari

---

From: "Martin Thomson" <[email-masked]>
Date: Sun, 05 May 2019 23:31:57 -0400

Ilari answered your question, but this jumped out:

On Sun, May 5, 2019, at 21:11, [email-masked] wrote:
> [...] both sides calculate,
>     PSK = [...]
> and the server sends back to the client the PSK (unencrypted [...])

The PSK never gets sent.  As you say, both sides can calculate the same value.

> My question is what key is encrypting the session ticket (is it a 
> symmetric key that is generated by the webserver/SSL library for each 
> session? 

If you want a bad design choice, NSS uses RSA encryption using a key from one of its certificates to encrypt a symmetric key that we use with CBC.  The symmetric key is used for all tickets once it is recovered, so the asymmetric encryption/decryption costs are paid just once when the system runs.

The ways in which this design is bad are lengthy enough that I won't bother to list them.  A better scheme would use a straight symmetric key with an AEAD, but there are historical deployment reasons for that design.