我是否需要在 OpenSSL 1.1.0+ 中使用加密锁定函数来实现线程安全?



这个问题与OpenSSL 1.1.0+有关。在代码示例中,我使用了std::string_view,这意味着C++17.这不是必需的,任何超过C++11的东西都很好,我只是懒得将const char* bufstd::size_t len作为单独的变量。

#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());
}

我有这四个函数(最后一个更像是一个伪函数(。startup在程序开始时运行,shutdown在程序结束时运行(两者都只运行一次(。thread_shutdown在每个线程的末尾运行(包括主线程中的前shutdown(。

run_per_thread函数是我如何将SSL与套接字一起使用的一个小例子。该函数可以在多个线程中运行,但是局部变量永远不会在线程之间的函数范围之外共享。

我目前在这里使用 OpenSSL 的方式线程安全吗?还是我需要使用加密锁?(文档对我来说不够清楚(。如果我确实需要使用加密锁,您能否提供一个有关如何操作的小示例?

在撰写本文时,我一直使用这些链接作为参考指南:
如何正确取消初始化OpenSSL
https://curl.haxx.se/libcurl/c/threadsafe.html
https://www.openssl.org/docs/man1.1.0/man3/CRYPTO_THREAD_run_once.html#DESCRIPTION

您无需在 OpenSSL 1.1.0 及更高版本中设置线程锁。OpenSSL FAQ对此进行了说明:

OpenSSL线程安全吗?

是的,但有一些限制;例如,SSL 连接不能 由多个线程同时使用。对于大多数人来说都是如此 OpenSSL 对象。

对于版本 1.1.0 及更高版本,您无需执行任何进一步操作。

对于 1.1.0 之前的早期版本,您的应用程序需要 以设置线程回调函数。为此,您的应用程序 必须调用CRYPTO_set_locking_callback(3(和其中一个 CRYPTO_THREADID_set...API's。请参阅 OpenSSL 线程手册页 详细信息和"关于多线程的说明"在 INSTALL 文件中 源分布。

只要您不跨多个线程共享SSL对象,那么您应该没问题。

关于以下示例代码的其他一些想法:

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();
}

您无需进行上述任何调用。这是您必须在OpenSSL 1.0.2中执行的晦涩的启动和关闭代码。这些在 OpenSSL 1.1.0 中都不是必需的 - 它会自动启动和关闭。在某些情况下,您可能唯一需要调用的是OPENSSL_thread_stop()thread_shutdown()函数(但可能不是(。看:

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;

没有必要使用SSL_OP_SINGLE_DH_USE.它在 OpenSSL 1.1.0 中不执行任何操作(仅在 1.0.2 或更早版本中需要(。

SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_NONE, nullptr);

请考虑改用SSL_VERIFY_PEER,如果无法验证对等证书,这将中止握手。

最新更新