4

I have a very simple httpd-setup with SSLSessionCache directive set so that sessions are available also after a graceful restart (in shared memory).

I then connect to the server with openssl s_client and the -sess_out parameter so i have a sessionfile.

Next step is to gracefully restart apache.

Then after that, connect again with openssl s_client this time using the sessionfile with the -sess_in parameter.

This works perfectly with TLSv1.2.

But with TLSv1.3 mod_ssl somehow falls back to a full handshake. SSL_session_reused() returns false. If i do exactly the same test, but don't gracefully restart between the requests, it works and SSL_session_reused() returns true.

We can see this also if we trace ssl messages:

without a graceful restart (correct behavior)

CLT0-0 send:
    Version: TLS 1.3 (772)
    Length: 512
    Content-Type: Handshake (22)
    Message-Type: ClientHello (1)
CLT0-0 receive:
    Version: TLS 1.3 (772)
    Length: 128
    Content-Type: Handshake (22)
    Message-Type: ServerHello (2)
    Server extension (43): supported versions
    Server extension (51): key share
    Server extension (41): pre shared key
CLT0-0 receive:
    Version: TLS 1.3 (772)
    Length: 6
    Content-Type: Handshake (22)
    Message-Type:  EncryptedExtensions (8)
CLT0-0 receive:
    Version: TLS 1.3 (772)
    Length: 52
    Content-Type: Handshake (22)
    Message-Type: Finished (20)
CLT0-0 send:
    Version: TLS 1.3 (772)
    Length: 1
    Content-Type: ChangeCipherSpec (20)
CLT0-0 send:
    Version: TLS 1.3 (772)
    Length: 52
    Content-Type: Handshake (22)
    Message-Type: Finished (20)

Here we see the client sends the "pre shared key" extension in his ClientHello. The Server responds then with his ServerHello which also contains the pre shared key extension and continues directly with the EncryptedExtensions and a Finish message. No Certificate and CertificateVerify message...

with a graceful restart (wrong behavior)

CLT0-0 send:
    Version: TLS 1.3 (772)
    Length: 512
    Content-Type: Handshake (22)
    Message-Type: ClientHello (1)
CLT0-0 receive:
    Version: TLS 1.3 (772)
    Length: 122
    Content-Type: Handshake (22)
    Message-Type: ServerHello (2)
    Server extension (43): supported versions
    Server extension (51): key share
CLT0-0 receive:
    Version: TLS 1.3 (772)
    Length: 6
    Content-Type: Handshake (22)
    Message-Type:  EncryptedExtensions (8)
CLT0-0 receive:
    Version: TLS 1.3 (772)
    Length: 1738
    Content-Type: Handshake (22)
    Message-Type: Certificate (11)
CLT0-0 receive:
    Version: TLS 1.3 (772)
    Length: 264
    Content-Type: Handshake (22)
    Message-Type: CertificateVerify (15)
CLT0-0 receive:
    Version: TLS 1.3 (772)
    Length: 52
    Content-Type: Handshake (22)
    Message-Type: Finished (20)
CLT0-0 send:
    Version: TLS 1.3 (772)
    Length: 1
    Content-Type: ChangeCipherSpec (20)
CLT0-0 send:
    Version: TLS 1.3 (772)
    Length: 52
    Content-Type: Handshake (22)
    Message-Type: Finished (20)

The client sends the same. But the Server responds then with his ServerHello which does NOT contain the "pre shared key" extension. Then a Certificate and CertificateVerify message as in the initial 1st handshake...

Also i see strange behavior related to the OpenSSL callbacks that mod_ssl registers:

mod_ssl registers all callbacks for adding, removing and getting a session (https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_sess_set_get_cb.html). The ssl-options, so that openssl doesn't use its internal cache are correctly set as well. But now with TLSv1.3 i never ever fall into the "get session"-callback, but always into the "new session" callback, even in the scenarion where i leave the graceful restart and SSL_session_reused returns true. I've had a look at the openssl code and indeed, in TLSv1.3 this callback never gets invoked. so i wonder if this might be a cause of incorrect behavior...

I think this is a very common use-case ("Allow to resume ssl-sessions after graceful restart") and should work with TLSv1.3 as it does with 1.2.

Any help is much appreciated!


UPDATE

This seems to be related to the SSLSessionTickets directive. With "SSLSessionTickets off" resumption works. If SessionTickets are enabled it doesn't work.


USP-dos
  • 83
  • 1
  • 9
  • "I think this is a very common use-case " The "cache" here primarily refers to making the sessions available across multiple httpd processes, not so much to allow resumption of handshakes _across_ a graceful restart. – covener Feb 06 '20 at 12:25
  • of course the cache is for that, but: 1. it works perfectly and always with TLS1.2, so why not with TLS1.3? this should be the same, independent from the protocol in my opinion.. 2. the code defenitly skips killing and re-initialising the cache, so where is the session gone? – USP-dos Feb 07 '20 at 09:19
  • Did you find the solution? SSLSessionTickets off is not the right approach as it disabled RFC 5077 tickets. I am facing the same issue https://stackoverflow.com/questions/69190143/reuse-openssl-session-ssl-session-reused-always-returns-zero – Jim Sep 15 '21 at 11:42
  • @Jim note that this question is explicitly about tls1.3. and there a lot of things changed, so the SSLSessionTickets off doesn't really turn off session tickets (because tls1.3 only knows tickets), but change openssl's internal behavior to "stateful" mode: read more about it [here](https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_options.html) (section SSL_OP_NO_TICKET) and in the [rfc](https://datatracker.ietf.org/doc/html/rfc8446#section-1.2) . so for me this solved the problem with the cache because this need that stateful mode.. – USP-dos Sep 16 '21 at 16:01

0 Answers0