openssl 1.0.2j, как заставить сервер выбирать шифры ECDH*

У меня есть клиентский сервер, который использует opensl 1.0.2j, и использует ключ и сертификат RSA:4096 и хочу заставить сервер использовать только следующие шифры.

ECDHE-RSA-AES256-GCM-SHA384
ECDHE-RSA-AES256-SHA384
ECDH-RSA-AES128-GCM-SHA256
ECDH-RSA-AES128-SHA256
DHE-RSA-AES256-GCM-SHA384
DHE-RSA-AES256-SHA256
DHE-RSA-AES128-GCM-SHA256
DHE-RSA-AES128-SHA256

Мой код на стороне сервера будет выглядеть ниже.

method = SSLv23_server_method();
ctx = SSL_CTX_new(method);
SSL_CTX_set_cipher_list(ctx, "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDH-RSA-AES128-GCM-SHA256:ECDH-RSA-AES128-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-SHA256");
SSL_CTX_set_ecdh_auto(ctx, 1);
SSL_CTX_set_tmp_dh(ctx, dh);
SSL_CTX_set_tmp_ecdh(ctx, ecdh);
SSL_CTX_use_certificate_file(ctx, certFilePath, SSL_FILETYPE_PEM);
SSL_CTX_use_PrivateKey_file(ctx, privKeyPath, SSL_FILETYPE_PEM)
SSL_accept()

Мой код на стороне клиента будет выглядеть так, как показано ниже

method = SSLv23_server_method();
ctx = SSL_CTX_new(method);
SSL_CTX_set_cipher_list(ctx, "ECDH-RSA-AES128-GCM-SHA256:ECDH-RSA-AES128-SHA256:ECDH-ECDSA-AES128-GCM-SHA256:ECDH-ECDSA-AES128-SHA256");
SSL_CTX_set_ecdh_auto(ctx, 1);
SSL_CTX_set_tmp_dh(ctx, dh);
SSL_CTX_set_tmp_ecdh(ctx, ecdh);
SSL_CTX_use_certificate_file(ctx, certFilePath, SSL_FILETYPE_PEM);
SSL_CTX_use_PrivateKey_file(ctx, privKeyPath, SSL_FILETYPE_PEM)
SSL_connect()

Последний шаг ssl_accept() на сервере завершается неудачно с

err: 336027900 'error:140760FC:SSL routines:SSL23_GET_CLIENT_HELLO:unknown protocol'

Если я использую ECDHE*RSA* или же DHE*RSA* шифры на стороне клиента, все работает нормально.

Не могли бы вы дать мне знать, что мне не хватает?

Изменить: сертификат сервера (certFilePath) содержит открытый ключ RSA, а не открытый ключ ECDH.

1 ответ

Мета: ответ только до TLS1.2; 1.3 больше не имеет обмена ключами и аутентификации в ciphersuite.

Во-первых, нет смысла называть оба set_ecdh_auto а также set_tmp_ecdh - это взаимоисключающие. Также ваш сервер не запрашивает аутентификацию клиента, поэтому настройка самопроверки и ключа на клиенте бесполезна. OTOH ваш сервер использует самоподписанный сертификат, который, вероятно, отсутствует в хранилище доверенных сертификатов клиента по умолчанию, поэтому вам может потребоваться настроить хранилище доверенных сертификатов клиента (для этого есть несколько подходов).

Во-вторых, "статические" наборы шифров ECDH весьма отличаются от наборов ECDHE, так же как "статические" наборы DH отличаются от наборов DHE. Обе статические формы не получили широкого применения и очень мало используются, потому что они, как правило, не дают никакой выгоды; в частности, OpenSSL 1.1.0 и выше более не реализуют их, поэтому ваш код устареет примерно через год, если я правильно запомнил расписание.

Точнее, для комплектов DH-RSA требуется сертификат, содержащий ключ DH (который разрешает keyAgreement), а для TLS<=1.1 сертификат должен быть выдан СА с использованием ключа RSA; для 1.2 это последнее ограничение снято. Ни один публичный центр сертификации не выдаст сертификат для ключа DH, и даже сделать это самостоятельно непросто; см. https://security.stackexchange.com/questions/44251/openssl-generate-different-type-of-self-signed-certificate и (мой) https://crypto.stackexchange.com/questions/19452/static-dh-static-ecdh-certificate-using-openssl/.

Для комплектов ECDH-RSA аналогичным образом требуется сертификат, содержащий ключ ECC, который разрешает keyAgreement, и выдается RSA, если <=1.1; это несколько проще, потому что ключ (и CSR) для ECDH такой же, как для ECDSA, и должен отличаться только KeyUsage. Для вашего собственного и самозаверяющего случая это просто, просто сгенерируйте ключ ECC и сертификат (автоматически подписанный с ECDSA).

Но последнее, это не должно вызывать "неизвестный протокол"; это вызвало бы 'нет общего шифра' и handshake_failure. Код, который вы показали, не должен вызывать "неизвестный протокол", поэтому вам, вероятно, нужно сначала изучить и исправить это. Вы можете попробовать использовать командную строку s_client вместо этого особенно с его -debug или же -msg крючки, или -trace если вы собрали это в.

Другие вопросы по тегам