c++ - 在 OpenSSL 1.1.0+ 中,我是否需要使用 CRYPTO 锁定函数来保证线程安全?

标签 c++ multithreading openssl thread-safety

此问题涉及 OpenSSL 1.1.0+。在代码示例中,我使用 std::string_view ,这意味着 C++17。这不是必需的,任何超过 C++11 的都可以,我只是太懒了,没有 const char* bufstd::size_t len code> 作为单独的变量。

#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 的方式线程安全吗?或者我需要使用加密锁吗? (文档对我来说不够清楚)。如果我确实需要使用加密锁,您能否提供一个关于如何操作的小示例?

在撰写本文时,我一直使用这些链接作为引用指南:
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

最佳答案

您不需要在 OpenSSL 1.1.0 及更高版本中设置线程锁。 OpenSSL 常见问题解答对此有这样的描述:

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.

只要您不跨多个线程共享 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 中,这些都不是必需的 - 它会自动启动和关闭。在某些情况下(但可能不需要),您可能需要在 thread_shutdown() 函数中调用 OPENSSL_thread_stop() 。请参阅:

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,如果无法验证对等证书,它将中止握手。

关于c++ - 在 OpenSSL 1.1.0+ 中,我是否需要使用 CRYPTO 锁定函数来保证线程安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58224138/

相关文章:

c++ - 哪个库包含 _is_c_termination_complete

c++ - 如何根据条件选择结构

android - 如何处理 facebook asyncrunner 更新 UI

c - Telnet session ,fork 与 thread

java - 从文件导入证书时 SSL 握手失败

c++ - 如何拦截64位进程中的API方法调用?

c++ - 使用友元函数迭代另一个类的私有(private)成员

java - 使用 Spring Hibernate 在 Java 中处理并发

linux - 加密/解密在两个不同的 openssl 版本之间不能很好地工作

python - SSL: SSLV3_ALERT_HANDSHAKE_FAILURE sslv3 警报握手失败 (_ssl.c:833)