TLS Session Resumption is not working

I’m trying to use the TLS Session Resumption feature in TLS 1.2 and 1.3. I first tested this on iOS, but it didn’t work as expected. To investigate via packet capture, I ran the same code on macOS and saw the same issue.

Using URLSession to establish a WebSocket connection, I captured packets in Wireshark to check if Session Resumption was working. The behavior differed from what I expected:

  • 1st TLS handshake – Client Hello does not contain the session_ticket extension (required for session resumption per the TLS spec).
  • 2nd TLS handshake – Client Hello does not contain a pre_shared_key.

Test apps: https://github.com/sf-jed-kyung/tls-session-resumption-test

Test environment: Xcode 16.3, macOS 15.6, OpenSSL 3.5.1

This repo contains:

  • tls-urlsession-macos – WebSocket via URLSession (shows missing extensions).
  • tls-openssl-macos – Manual TLS handshake via OpenSSL (shows both session_ticket and pre_shared_key).
    • To run this, adjust Header Search Paths and Library Search Paths for your local OpenSSL install.

URLSession – 1st Client Hello

Transport Layer Security
    TLSv1.3 Record Layer: Handshake Protocol: Client Hello
        Content Type: Handshake (22)
        Version: TLS 1.0 (0x0301)
        Length: 512
        Handshake Protocol: Client Hello
            Handshake Type: Client Hello (1)
            Length: 508
            Version: TLS 1.2 (0x0303)
            Random: 0502b10cf04223658...
            Session ID Length: 32
            Session ID: e3b276b14f2deaced...
            Cipher Suites Length: 42
            Cipher Suites (21 suites)
            Compression Methods Length: 1
            Compression Methods (1 method)
            Extensions Length: 393
            ...
            Extension: server_name (len=26) name=echo.websocket.events
            Extension: extended_master_secret (len=0)
            Extension: renegotiation_info (len=1)
            Extension: supported_groups (len=12)
            Extension: ec_point_formats (len=2)
            Extension: application_layer_protocol_negotiation (len=11)
            Extension: status_request (len=5)
            Extension: signature_algorithms (len=22)
            Extension: signed_certificate_timestamp (len=0)
            Extension: key_share (len=43) x25519
            Extension: psk_key_exchange_modes (len=2)
            Extension: supported_versions (len=7) TLS 1.3, TLS 1.2
            Extension: compress_certificate (len=3)
            ...

URLSession – 2nd Client Hello

Transport Layer Security
    TLSv1.3 Record Layer: Handshake Protocol: Client Hello
        Content Type: Handshake (22)
        Version: TLS 1.0 (0x0301)
        Length: 512
        Handshake Protocol: Client Hello
            Handshake Type: Client Hello (1)
            Length: 508
            Version: TLS 1.2 (0x0303)
            Random: 1e485f35ad66c8598...
            Session ID Length: 32
            Session ID: 99d02000c7ed403a5...
            Cipher Suites Length: 42
            Cipher Suites (21 suites)
            Compression Methods Length: 1
            Compression Methods (1 method)
            Extensions Length: 393
            ...
            Extension: server_name (len=26) name=echo.websocket.events
            Extension: extended_master_secret (len=0)
            Extension: renegotiation_info (len=1)
            Extension: supported_groups (len=12)
            Extension: ec_point_formats (len=2)
            Extension: application_layer_protocol_negotiation (len=11)
            Extension: status_request (len=5)
            Extension: signature_algorithms (len=22)
            Extension: signed_certificate_timestamp (len=0)
            Extension: key_share (len=43) x25519
            Extension: psk_key_exchange_modes (len=2)
            Extension: supported_versions (len=7) TLS 1.3, TLS 1.2
            Extension: compress_certificate (len=3)
            ...

OpenSSL – 1st Client Hello

Transport Layer Security
    TLSv1.3 Record Layer: Handshake Protocol: Client Hello
        Content Type: Handshake (22)
        Version: TLS 1.0 (0x0301)
        Length: 1564
        Handshake Protocol: Client Hello
            Handshake Type: Client Hello (1)
            Length: 1560
            Version: TLS 1.2 (0x0303)
            Random: aec30b0aad542252...
            Session ID Length: 32
            Session ID: f7ee7178cab8716a625...
            Cipher Suites Length: 60
            Cipher Suites (30 suites)
            Compression Methods Length: 1
            Compression Methods (1 method)
            Extensions Length: 1427
            Extension: renegotiation_info (len=1)
            Extension: server_name (len=26) name=echo.websocket.events
            Extension: ec_point_formats (len=4)
            Extension: supported_groups (len=18)
            Extension: session_ticket (len=0)
            Extension: application_layer_protocol_negotiation (len=11)
            Extension: encrypt_then_mac (len=0)
            Extension: extended_master_secret (len=0)
            Extension: signature_algorithms (len=54)
            Extension: supported_versions (len=5) TLS 1.3, TLS 1.2
            Extension: psk_key_exchange_modes (len=2)
            Extension: key_share (len=1258) X25519MLKEM768, x25519

OpenSSL – 2nd Client Hello

Transport Layer Security
    TLSv1.3 Record Layer: Handshake Protocol: Client Hello
        Content Type: Handshake (22)
        Version: TLS 1.0 (0x0301)
        Length: 1716
        Handshake Protocol: Client Hello
            Handshake Type: Client Hello (1)
            Length: 1712
            Version: TLS 1.2 (0x0303)
            Random: 3fb3938a88166e4eb...
            Session ID Length: 32
            Session ID: 7f13e54a231c17ccff70...
            Cipher Suites Length: 60
            Cipher Suites (30 suites)
            Compression Methods Length: 1
            Compression Methods (1 method)
            Extensions Length: 1579
            Extension: renegotiation_info (len=1)
            Extension: server_name (len=26) name=echo.websocket.events
            Extension: ec_point_formats (len=4)
            Extension: supported_groups (len=18)
            Extension: session_ticket (len=0)
            Extension: application_layer_protocol_negotiation (len=11)
            Extension: encrypt_then_mac (len=0)
            Extension: extended_master_secret (len=0)
            Extension: signature_algorithms (len=54)
            Extension: supported_versions (len=5) TLS 1.3, TLS 1.2
            Extension: psk_key_exchange_modes (len=2)
            Extension: key_share (len=1258) X25519MLKEM768, x25519
            Extension: pre_shared_key (len=148)

Since the Client Hello is generated by the client, I believe the session_ticket should be included in the first handshake regardless of server support. However, URLSession omits it entirely.

Question: How can I enable TLS Session Resumption when using URLSession?

I wanted to post a quick reply just to let you know that this isn’t being ignored. I’ve been researching this in my (copious :-) free time over the last few days and, well, it’s more complex than it seems. I’m still working on it, and I’ll update this thread when I know more.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Oh, and I have at least some answers over in this thread.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I conducted a few experiments.

First, I started a local server with OpenSSL as follows:

openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 3 -nodes -subj "/CN=localhost"
openssl s_server -accept 8443 -cert cert.pem -key key.pem -tls1_3 -www -num_tickets 2 -keylogfile keylog.txt -msg -state

When I opened https://localhost:8443 in Google Chrome and captured the loopback interface with Wireshark, I saw ClientHello packets containing a pre_shared_key.

However, when I ran the same experiment with Safari, there was no ClientHello packet containing a pre_shared_key at all.

This led me to suspect that the network stack used by Safari may have stricter requirements for enabling TLS Session Resumption compared to Chrome, and that the same conditions might also apply to URLSession.

I found a post stating that TLS 1.3 on iOS or macOS did not support pre_shared_key.

https://developer.apple.com/forums/thread/688508

The post is from August 2021—does this still hold true today?

TLS Session Resumption is not working
 
 
Q