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
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With