Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do I need to use CRYPTO locking functions for thread safety in OpenSSL 1.1.0+?

This question concerns OpenSSL 1.1.0+. In the code example I use std::string_view which implies C++17. This is not required, anything over C++11 is fine, I was just too lazy to have const char* buf and std::size_t len as separate variables.

#include <string_view>

#include <openssl/err.h>
#include <openssl/ssl.h>

void startup()
{
    SSL_library_init();
    SSL_load_error_strings();
    OpenSSL_add_ssl_algorithms();
    ERR_load_crypto_strings();
}

void shutdown()
{
    ERR_free_strings();
    EVP_cleanup();
}

void thread_shutdown()
{
    CRYPTO_cleanup_all_ex_data();
}

void run_per_thread()
{
    // intial non SSL stuff
    int sockfd = get_connected_socket();
    std::string_view hostname = get_hostname();
    std::string_view buffer = get_buffer();
    // SSL context setup
    auto ssl_ctx = SSL_CTX_new(TLS_client_method());
    auto ssl_ctx_options = SSL_OP_SINGLE_DH_USE || SSL_OP_NO_SSLv3;
    SSL_CTX_set_options(ssl_ctx, ssl_ctx_options);
    SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_NONE, nullptr);
    // SSL client setup
    auto ssl_client = SSL_new(ssl_ctx);
    SSL_set_tlsext_host_name(ssl_client, hostname.data());
    // connect and write
    auto ssl_err = SSL_connect(ssl_client);
    auto result = SSL_write(ssl_client, buf.data(), buf.size());
}

I have these four functions (the last one is more of a pseudo function). startup is run at the beginning of the program and shutdown at the end (both only run once each). thread_shutdown is run at the end of every thread (including the before shutdown in the main thread).

The run_per_thread function is a small example of how I might use SSL with a socket. The function could be run in multiple threads, however the local variables are never shared outside the scope of the function between threads.

Is the way that I'm currently using OpenSSL here thread safe? Or do I need to use CRYPTO locks? (the documentation wasn't clear enough for me). And if I do need to use CRYPTO locks, could you please provide a small example on how to do it?

I have been using these links as a reference guide when writing this:
How to properly uninitialize OpenSSL
https://curl.haxx.se/libcurl/c/threadsafe.html
https://www.openssl.org/docs/man1.1.0/man3/CRYPTO_THREAD_run_once.html#DESCRIPTION

like image 956
doodspav Avatar asked Oct 03 '19 17:10

doodspav


People also ask

Is OpenSSL thread-safe?

Note that OpenSSL is not completely thread-safe, and unfortunately not all global resources have the necessary locks. Further, the thread-safety does not extend to things like multiple threads using the same SSL object at the same time.

What is thread-safe in CPP?

An object is thread-safe for reading from multiple threads. For example, given an object A, it is safe to read A from thread 1 and from thread 2 simultaneously. If an object is being written to by one thread, then all reads and writes to that object on the same or other threads must be protected.


1 Answers

You do not need to set up thread locks in OpenSSL 1.1.0 and later. The OpenSSL FAQ says this about it:

Is OpenSSL thread-safe?

Yes but with some limitations; for example, an SSL connection cannot be used concurrently by multiple threads. This is true for most OpenSSL objects.

For version 1.1.0 and later, there is nothing further you need do.

For earlier versions than 1.1.0, it is necessary for your application to set up the thread callback functions. To do this, your application must call CRYPTO_set_locking_callback(3) and one of the CRYPTO_THREADID_set... API's. See the OpenSSL threads manpage for details and "note on multi-threading" in the INSTALL file in the source distribution.

As long as you do not share your SSL objects across multiple threads then you should be fine.

Some other thoughts on your sample code below:

void startup()
{
    SSL_library_init();
    SSL_load_error_strings();
    OpenSSL_add_ssl_algorithms();
    ERR_load_crypto_strings();
}

void shutdown()
{
    ERR_free_strings();
    EVP_cleanup();
}

void thread_shutdown()
{
    CRYPTO_cleanup_all_ex_data();
}

You don't need to make any of the above calls. This is the arcane startup and shutdown code that you had to do in OpenSSL 1.0.2. None of this is necessary in OpenSSL 1.1.0 - it starts up and shutdown automatically. The only thing you might need to call is OPENSSL_thread_stop() in your thread_shutdown() function in certain circumstances (but probably not). See:

https://www.openssl.org/docs/man1.1.1/man3/OPENSSL_thread_stop.html

auto ssl_ctx_options = SSL_OP_SINGLE_DH_USE || SSL_OP_NO_SSLv3;

There is no need to use SSL_OP_SINGLE_DH_USE. It does nothing in OpenSSL 1.1.0 (its only required for 1.0.2 or before).

SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_NONE, nullptr);

Consider using SSL_VERIFY_PEER instead which will abort the handshake if the peer certificate cannot be verified.

like image 91
Matt Caswell Avatar answered Sep 22 '22 05:09

Matt Caswell