1

(6 replies, posted in wolfSSL)

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

Hello,

For this one, we have applied a workaround, we stored the session pointer when a non-NULL was returned, and then used this stored pointer when NULL was returned.

I am not aware if the issue has been addressed on wolfSSL side, because the workaround was good enough for our use case.

Best regards,
Martin

Hello,

Just to update the status for anyone who would stumble upon this in the future.

This issue has been addressed by https://github.com/wolfSSL/wolfssl/pull/1785 and it can be marked as solved.

Best regards,
Martin

4

(6 replies, posted in wolfSSL)

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

5

(6 replies, posted in wolfSSL)

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

6

(6 replies, posted in wolfSSL)

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

Hi Kaleb,

The test client I attached to https://www.wolfssl.com/forums/post4061.html#p4061 can also be used for reproducing this issue, just replace runTests.sh with runTests2.sh attached here (now the OpenSSL server is not restarted after each connection, so that resumption can really happen).
Edit: I attached the whole archive with fixed test client here, see below.

When running
runTests2.sh ticket
I get

INFO: UseSessionTicket requested
INFO: going to attempt connection
Session ID not reused; Successful resume.
Connected to server.
wolfSSL_get_chain_count returned: 1
wolfSSL_get1_session returned 0x7fc7dfcfb868
sizeOfExportedSession is 1284
INFO: going to attempt connection
INFO: session for resumption set to ssl
Session ID reused; Successful resume.
Connected to server.
wolfSSL_get_chain_count returned: 1
wolfSSL_get1_session returned (nil)
sizeOfExportedSession is -173
INFO: going to attempt connection
INFO: session for resumption set to ssl
Session ID reused; Successful resume.
Connected to server.
wolfSSL_get_chain_count returned: 1
wolfSSL_get1_session returned (nil)
sizeOfExportedSession is -173
...

So it looks like that when I use the previously stored pointer to the session, the session gets resumed (confirmed by observing the traffic in Wireshark), but something gets broken, and wolfSSL_i2d_SSL_SESSION stops working.

Edit: The negative values returned by wolfSSL_i2d_SSL_SESSION were due to an error in my code, I was calling wolfSSL_i2d_SSL_SESSION on the returned NULL pointer instead of on the previously strored pointer. After fixing this, the correct value is returned.
I updated the attachment with the fixed code. To reproduce this " wolfSSL_get1_session returns NULL" issue, run demo2.

Best regards,
Martin

Hi Kaleb,

Find attached a simple demo client based on https://github.com/wolfSSL/wolfssl-exam … s-resume.c and the corresponding scripts for preparing wolfSSL and running the tests.
A simple README with instructions is also present in the archive.

The issue is reproduced with both session ID and ticket-based resumption.
It is also reproduced regardless of if SSL_VERIFY_PEER or SSL_VERIFY_NONE is set (these can be switched by sending 'p' or 'n' to the client's control socket).

Best regards,
Martin

Hi Kaleb,

I might be able to send you a simple test application and script tomorrow or next week.

Currently, I am not using anything special for the testing. Just

openssl s_server -status_verbose -key testKey.pem -cert testCert.pem -accept <port_number>

and restarting manually by Ctrl+C and launching again.
OpenSSL version is 1.1.0h-fips (Fedora 27).

I don't think that the issue depends on ciphersuites used (maybe except for some PSK), I tested with TLS_DHE_RSA_WITH_AES_128_CBC_SHA and with TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256.

Best regards,
Martin

Hi Kaleb,

I am working on an IoT device, and using TLS session resumption should help to reduce its data usage and energy consumption.

Yes, in step 6, wolfSSL_get1_session returns NULL. Since writing my original post, I checked again, and now I think that the workaround with using the session pointer stored previously is less risky than I originally thought.
Still, I think that wolfSSL_get1_session should not return NULL in such situation.

I don't think that the change made in https://github.com/wolfSSL/wolfssl/pull/851 is causing this behavior, because that change is in SendServerHello on the server side, and I am using openssl s_server as the test server and wolfSSL as client.

It could be related, though. RFC 5077, section 3.4 states

When presenting a ticket, the client MAY generate and include a Session ID in the TLS ClientHello.  If the server accepts the ticket and the Session ID is not empty, then it MUST respond with the same Session ID present in the ClientHello.

Maybe if the wolfSSL client sent its Session ID along with the ticket to the server and received the Session ID echoed by the server, wolfSSL_get1_session could start working. But I haven't checked if it wouldn't cause e.g. AddSession being called again, causing some other issues.

Best regards,
Martin

Hi,

I am using wolfSSL_get1_session and wolfSSL_set_session to enable TLS session resumption.

Each time when the server creates a new session instead of resuming the session (I trigger this by restarting my test openssl s_server, so that its session cache and ticket encryption key are dropped), the number of session's certificate chains increases. (The number which is returned by wolfSSL_get_chain_count(chain) when running on the chain obtained through wolfSSL_get_peer_chain(ssl) )
This happens for both session ID and ticket-based session resumption.

Is this expected behavior? And if so, are there any guidelines how to work with the certificate chains in such case, e.g. for the purpose of hostname validation?

Thanks,
Martin

Hi,

I am trying to use TLS session resumption with wolfSSL, but I encountered some issues when enabling RFC 5077 session tickets (wolfSSL_UseSessionTicket).

As shown in the cllient-tls-resume example (https://github.com/wolfSSL/wolfssl-exam … s-resume.c), I use wolfSSL_get1_session to get the session pointer (for now, I am relying on the internal session cache) before calling wolfSSL_shutdown on the ssl object.
Then, after creating a new ssl object with wolfSSL_new, I call wolfSSL_set_session to set the saved session to the ssl object.

This appears to work fine when I am not using ticket resumption. In such case, wolfSSL_get1_session always returns a non-NULL pointer, also for TLS connections which had been resumed from a previously saved session.

However, with ticket resumption enabled, wolfSSL_get1_session returns NULL for resumed sessions. That is:
1) no session saved, full handshake performed, ticket received from server. wolfSSL_get1_session returns a valid pointer
2) session resumed from the saved session, ticket sent to server, full handshake not performed, connection established. wolfSSL_get1_session returns NULL

It appears to be related to the session ID not really being used with RFC 5077 tickets (section 3.4) and wolfSSL using the session ID internally. Specifically, the NULL is returned because of the

    if (ssl->options.haveSessionId == 0)
        return NULL;

check in GetSession in https://raw.githubusercontent.com/wolfS … /src/ssl.c.

Am I doing something wrong, or is it a limitation of wolfSSL? And if it is a limitation of wolfSSL, are there any suggested workarounds?
I assume I could check for this condition, and if NULL is returned, use the previously stored pointer to resume the session next time. But in such case, I guess I would have to be quite careful about distinguishing this case from genuine errors when the session should be thrown away.

Thanks,
Martin