这个问题与OpenSSL 1.1.0+有关。在代码示例中,我使用了std::string_view
,这意味着C++17
.这不是必需的,任何超过C++11
的东西都很好,我只是懒得将const char* buf
和std::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
,如果无法验证对等证书,这将中止握手。