Нужно ли использовать функции блокировки CRYPTO для обеспечения безопасности потоков в OpenSSL 1.1.0+? - PullRequest
4 голосов
/ 03 октября 2019

Этот вопрос касается 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, безопасен для потоков? Или мне нужно использовать CRYPTO замки? (документация не была достаточно ясна для меня). И если мне нужно использовать блокировки CRYPTO, не могли бы вы привести небольшой пример того, как это сделать?

Я использовал эти ссылки в качестве справочного руководства при написании этого:
Какчтобы правильно инициализировать OpenSSL
https://curl.haxx.se/libcurl/c/threadsafe.html
https://www.openssl.org/docs/man1.1.0/man3/CRYPTO_THREAD_run_once.html#DESCRIPTION

1 Ответ

3 голосов
/ 04 октября 2019

Вам не нужно устанавливать блокировки потоков в OpenSSL 1.1.0 и более поздних версиях. В FAQ по OpenSSL об этом сказано:

Является ли OpenSSL поточно-ориентированным?

Да, но с некоторыми ограничениями;Например, SSL-соединение не может использоваться одновременно несколькими потоками. Это справедливо для большинства объектов OpenSSL.

Для версии 1.1.0 и новее больше ничего делать не нужно.

Для более ранних версий, чем 1.1.0, это необходимо для вашего приложениянастроить функции обратного вызова потока. Для этого ваше приложение должно вызвать CRYPTO_set_locking_callback (3) и один из CRYPTO_THREADID_set ... API. Для получения дополнительной информации см. Справочную страницу по потокам 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, который прервет рукопожатие, если сертификат партнера не может быть проверен.

...