Technical Q&A QA1727

TLS Session Cache

Q:  I'm using NSURLConnection to access two HTTPS URLs on the same server. I want to use a unique client identity for each connection. When I access the first URL I get an authentication challenge that allows me to supply the correct client identity, but when I then access the second URL I don't get any authentication challenges. How can I get an authentication challenge for this second connection?

A: When you access a URL via HTTPS, you're actually using HTTP over TLS (Transport Layer Security, the evolution of SSL, the Secure Sockets Layer). You don't get a second challenge because the second connection reuses the TLS session established by the first. To understand this problem, you need to understand something about TLS itself, and how it is implemented on OS X and iOS.

Opening a TLS session is computationally expensive (because it involves working with large asymmetric keys), so TLS has a mechanism to avoid doing this work for each connection. A TLS connection can either establish a new session or it can attempt to resume an existing session, where resuming an existing session is much cheaper than starting a new one. A TLS client can therefore boost performance by maintaining a cache of existing sessions and reusing them when it's appropriate.

The core TLS code on both OS X and iOS, Secure Transport, maintains such a cache. This TLS session cache is implemented independently in each process. In most circumstances the TLS session cache works transparently to speed up TLS connections, but in some cases it can cause problems. In this case, your second connection has reused the TLS session of the first connection, and thus you don't have an opportunity to supply a new client identity for the second connection.

Because caching can occur at various levels within the NSURLConnection stack, before trying to work around a TLS session cache problem it's a good idea to confirm that this is actually the root cause. You can do this by exploiting the fact that TLS session cache entries persist for about 10 minutes. Thus, if the problem still occurs when the second connection follows the first connection by 9 minutes, but goes away if the delay is 11 minutes, chances are that the TLS session cache is to blame.

Inside the NSURLConnection Framework, there's no direct way to flush the TLS session cache (other than to terminate the process itself), nor is there a way to tell NSURLConnection not to use it (r. 8957312) . The only reasonable workaround is to change your connection in such a way that the second connection doesn't hit (in the sense of a "cache hit") the cache entry created by the first connection. To do this you need to understand the TLS session cache key format used by NSURLConnection or, more accurately, the CFSocketStream that underlies NSURLConnection.

If you cannot switch to NSURLSession, please see below.

In the absence of a proxy, the TLS session cache key contains the destination IP address, the destination port, and the destination DNS name, for example, {131.39.46.209:47873}devforums.apple.com. Consequently, altering the IP address, the port, or the DNS name will cause a TLS session cache miss, and allow your second connection to receive the TLS authentication challenges. While it's unlikely that you'll be able to alter the IP address component of the TLS session cache key, the port and DNS name components are potential workaround candidates. For example:



Document Revision History


DateNotes
2015-08-19

Added Note to redirect users to NSURLSession and updated expository content.

2011-02-10

New document that describes how the TLS session cache affects HTTPS connections that need different TLS parameters.