Topic: TLS session cache thread safety

Hi,

The client application I am working on requires a different cache-handling model than what is expected in wolfSSL. Instead of having a single application-wide cache, I need to store the sessions per-server.
Originally, I was thinking about disabling the internal cache and using external cache (HAVE_EXT_CACHE). However, this would likely require to use a custom allocator, and/or I would probably need to be touching wolfSSL internals, at least for making a deep copy of WOLFSSL_SESSION.

Then I thought about still using the internal cache (but likely reducing its size), mainly to take care of the allocations, and keeping my per-server cache next to it. (Storing the sessions as byte buffers and using wolfSSL_i2d_SSL_SESSION and wolfSSL_d2i_SSL_SESSION for conversion.)

When examining these options, I ran into the question of the session cache being thread-safe. At the lowest level, it is protected by session_mutex, so the cache itself should remain consistent. However, I am not so sure about the sessions. E.g. when I use wolfSSL_get1_session, I obtain a pointer to a structure in the session cache, but I cannot see what is preventing the session structure in the cache from being updated (replaced with another session) while I am working with it.
Since the session cache can be updated e.g. after TLS handshake performed on unrelated WOLFSSL, I can't see an easy way of adding external locking without resorting to something like a global mutex.

Am I missing something, or is this a limitation of the session cache?

Thanks,
Martin

Share

Re: TLS session cache thread safety

Martin:

You aren't missing anything. The session cache is mutex protected for reads and writes. The contents of the session cache may change. We implement the cache as a statically allocated hash table and we recommend setting the length and width to minimize collisions in the hashing. The protocol is tolerant of having a hash table miss or an outdated cache entry as the session ID will not match, the server will perform a full handshake instead. The cache data also has an expiration date (about 5 minutes).

This was a trade off for avoiding memory allocations and speed. A general purpose server should have the memory for a large cache for many inbound connections; and embedded server probably won't be able to handle many inbound connections so can get away with a much smaller cache.

As for the 5 minute expiration time, we designed around having a client connect to the server many times in a short period. This saves time on doing only one public key operation for a bunch of connections over a short period of time. The trade off is that the public key operation will have to happen, each time, for new connections over long periods of time.

--John

Re: TLS session cache thread safety

Hi John,

Thank you for the explanation. I can see that doing it this way simplifies things, and that if reasonable settings are used, all should be working fine thanks to the cache miss/corruption tolerance.

However, now I ran into wolfSSL_i2d_SSL_SESSION which should mimic OpenSSL's i2d_SSL_SESSION (https://www.openssl.org/docs/man1.0.2/s … SSION.html), I assume.
According to the OpenSSL documentation, I would write something like this if I wanted to export the session into a buffer:

    unsigned char buffer[BUF_SIZE];
    unsigned char* buf = buffer;
    int sizeOfExportedSession = wolfSSL_i2d_SSL_SESSION(session, NULL);
    if (sizeOfExportedSession <= BUF_SIZE) {
        // what if session data got changed in the meantime and more than BUF_SIZE is to be written now?
        int sizeOfExportedSession2 = wolfSSL_i2d_SSL_SESSION(session, &buf);
        assert(sizeOfExportedSession == sizeOfExportedSession2); // will it always pass?
    }

As I indicate in the comments in the code snippet, I am worried about the race condition potentially leading to an out-of-bounds write.

Do you have any suggestions how to mitigate this on the user's side (if there really is this race condition)? Or would it require some change in wolfSSL, maybe adding some reference counting to the session cache?

Best regards,
Martin

Share

Re: TLS session cache thread safety

Martin:

I do think that the external cache is what you are looking for. It allocates the space needed to store the WOLFSSL_SESSION, copies the session information from the SSL session in process, not the old cache copy that might get written over. And then calls your own new_sess_cb with a pointer to the SESSION to put the pointer wherever you want. That data will not be overwritten by any new connections.

If you pass the pointer to the WOLFSSL_SESSION record from the external cache callback to wolfSSL_i2d_SSL_SESSION() there won't be a race condition issue.

--John

Re: TLS session cache thread safety

Hi John,

Thanks for confirming my fears :-)
I already considered using the external cache (with internal cache disabled), but at first, I dismissed this idea to avoid dealing with memory management (dynamic vs. static allocation etc.).

I yet have to see if I can make the race condition only a theoretical problem in my application, or if I will have to dive deeper into this...

Best regards,
Martin

Share

Re: TLS session cache thread safety

Did you come to a solution?

Re: TLS session cache thread safety

Hello,

In the end, I kept the internal cache in use to avoid dealing with the memory allocation issues.
And while the race condition is theoretically there, the nature of the application prevents it from manifesting itself in practice.

Therefore I consider this solved.

Best regards,
Martin

Share