Subject: [Emu] Session tickets in TLS 1.3

From: Alan DeKok <[email-masked]>
Date: Fri, 5 Feb 2021 09:11:10 -0500

I've been rooting through the specs, TLS library implementations, and various other online things.  I think there are issues with session tickets and TLS 1.3.   These issues haven't been brought up in detail before (that I recall)

  Applications cannot control when the TLS layer sends session tickets.  So it's possible for a malicious client to get the ticket, and close the connection without sending a client cert.  Then, if the EAP server doesn't destroy the ticket, the client can reconnect.  This is partly also an issue in earlier versions of TLS.  But it's made worse in TLS 1.3.

 Sending early session tickets is in fact the default behaviour in OpenSSL.  EAP-TLS isn't the first one to notice this impedance mismatch between TLS 1.3 and applications.  There are long discussions here:

https://github.com/python-trio/trio/issues/819

https://github.com/openssl/openssl/issues/7948

 "AFAICT openssl's strategy for handling TLS 1.3 session tickets makes it impossible to reliably implement communication patterns where the server never sends application-level data"

 the solution the Python Trio group implemented is this:

"We did find and deploy a workaround for this that I think makes TLS 1.3 work correctly on all openssl versions, while still supporting session tickets. Instead of letting openssl do I/O directly, we use MemoryBIO, and manually copy data to/from the socket. After SSL_do_handshake completes, we check whether we're running in server mode, and whether we negotiated TLS v1.3. If so, then we capture the last volley of data that openssl asked us to send, and we don't send it – instead we stash it in an internal buffer, and send it the first time we have application data to write."

  Which seems problematic, at best.

 Further OpenSSL has this to say about session tickets:  https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_num_tickets.html

...
The default number of tickets is 2; the default number of tickets sent following a resumption handshake is 1 but this cannot be changed using these functions. The number of tickets following a resumption handshake can be reduced to 0 using custom session ticket callbacks (see SSL_CTX_set_session_ticket_cb(3)).

Tickets are also issued on receipt of a post-handshake certificate from the client following a request by the server using SSL_verify_client_post_handshake(3). These new tickets will be associated with the updated client identity (i.e. including their certificate and verification status). The number of tickets issued will normally be the same as was used for the initial handshake. If the initial handshake was a full handshake then SSL_set_num_tickets() can be called again prior to calling SSL_verify_client_post_handshake() to update the number of tickets that will be sent.
...

   The packet flows in Figure 2 of draft-14 shows only one exchange of session tickets, not 2.  So the question is: what actually happens here?

  https://tools.ietf.org/html/rfc8446#section-4.6.1 says:

   At any time after the server has received the client Finished
   message, it MAY send a NewSessionTicket message.

  Has OpenSSL turned this into a "must" ?

  8446 continues with:

   Note: Although the resumption master secret depends on the client's
   second flight, a server which does not request client authentication
   MAY compute the remainder of the transcript independently and then
   send a NewSessionTicket immediately upon sending its Finished rather
   than waiting for the client Finished.  

  However, EAP-TLS *is* requiring client authentication.  So the NewSessionTicket message MUST be sent only after the client Finished message is received.

  OpenSSL documentation further says:  https://www.openssl.org/docs/man1.1.1/man3/SSL_verify_client_post_handshake.html

...
When post-handshake authentication occurs, a refreshed NewSessionTicket message is sent to the client.
...

   I'm going to spend some time implementing various things and digging into the protocols / implementations / APIs in more detail.  The outcome should hopefully be clear answers as to who does what, when, and how.

  Alan DeKok.