Ошибка использования openssl с socat – SSL3_CHECK_CERT_AND_ALGORITHM: ключ dh слишком мал

Краткая версия вопроса

Если предположить наличие соответствующих файлов, почему не работает следующая последовательность команд?

socat tcp-listen:10001,fork exec:'/bin/cat' & socat openssl-listen:10002,fork,reuseaddr,cert=server.pem,cafile=client.crt tcp:localhost:10001 & socat tcp-listen:10003 openssl-connect:localhost:10002,cert=client.pem,cafile=server.crt & socat stdout tcp:localhost:10003 

Длинная версия вопроса

Я пытаюсь использовать socat с openssl как описано в следующих документах:

  • Пример подключения OpenSSL с использованием Socat
  • Защита трафика между двумя экземплярами Socat с использованием SSL

Для контекста я использую socat версии 1.7.2.4 + sigfix и OpenSSL версии 1.1.0f в Debian 9.

Прежде чем приступить к опробованию openssl , я сначала использую socat для проверки работоспособности. Я запускаю один экземпляр socat как «эхо-сервер», использую два промежуточных экземпляра socat (то есть второй и третий экземпляры) для создания туннеля, а затем четвертый экземпляр как «клиент» для отправки данных в исходный процесс через туннель , Вот пример команд, которые я выполнил:

 socat tcp-listen:10001,fork exec:'/bin/cat' & socat tcp-listen:10002,fork tcp:localhost:10001 & socat tcp-listen:10003,fork tcp:localhost:10002 & socat stdout tcp:localhost:10003 

Это работает как ожидалось – текст, введенный в терминал, возвращается на консоль. Пример сеанса выглядел примерно так:

 user@host:~$ socat tcp-listen:10001,fork exec:'/bin/cat' & [1] 1001 user@host:~$ socat tcp-listen:10002,fork tcp:localhost:10001 & [2] 1002 user@host:~$ socat tcp-listen:10003,fork tcp:localhost:10002 & [3] 1003 user@host:~$ socat stdout tcp:localhost:10003 hey hey 

Проверив свое здравомыслие, я приступил к процессу получения сертификата и ключа.

Сначала я сгенерировал ключ сервера и самозаверяющий сертификат:

 openssl genrsa -out server.key 2048 openssl req -new -key server.key -x509 -days 3653 -out server.crt cat server.key server.crt > server.pem chmod 600 server.key server.pem 

Затем я сгенерировал клиентский ключ и самозаверяющий сертификат:

 openssl genrsa -out client.key 2048 openssl req -new -key client.key -x509 -days 3653 -out client.crt cat client.key client.crt > client.pem chmod 600 client.key client.pem 

Наконец я попытался настроить тот же туннель, что и раньше, но с использованием шифрования OpenSSL:

 socat tcp-listen:10001,fork exec:'/bin/cat' & socat openssl-listen:10002,fork,reuseaddr,cert=server.pem,cafile=client.crt tcp:localhost:10001 & socat tcp-listen:10003 openssl-connect:localhost:10002,cert=client.pem,cafile=server.crt & socat stdout tcp:localhost:10003 

Это не похоже на работу, и после выполнения последней команды я получаю следующую ошибку:

 YYYY/mm/dd HH:MM:SS socat[pid1] E SSL_connect(): error:14082174:SSL routines:SSL3_CHECK_CERT_AND_ALGORITHM:dh key too small YYYY/mm/dd HH:MM:SS socat[pid2] E SSL_accept(): error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure 

Вот как выглядел пример сеанса:

 user@host:~$ socat tcp-listen:10001,fork exec:'/bin/cat' & [1] 1001 user@host:~$ socat openssl-listen:10002,fork,reuseaddr,cert=server.pem,cafile=client.crt tcp:localhost:10001 & [2] 1002 user@host:~$ socat tcp-listen:10003 openssl-connect:localhost:10002,cert=client.pem,cafile=server.crt & [3] 1003 user@host:~$ socat stdout tcp:localhost:10003 2018/08/22 23:43:30 socat[1005] E SSL_accept(): error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure 2018/08/22 23:43:30 socat[1003] E SSL_connect(): error:14082174:SSL routines:SSL3_CHECK_CERT_AND_ALGORITHM:dh key too small [3]+ Exit 1 socat tcp-listen:10003 openssl-connect:localhost:10002,cert=client.pem,cafile=server.crt 

Следуйте советам пользователя dave_thompson_085. Я попытался использовать команду openssl s_client следующим образом:

 openssl s_client -cipher 'DHE:!EXPORT:!LOW' -connect localhost:10002 

Это произвело ошибку, которая содержала следующее:

 socat[pid] E SSL_accept(): error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure error:141A318A:SSL routines:tls_process_ske_dhe:dh key too small:../ssl/statem/statem_clnt.c:1460: 

Во-первых, вы уверены, что socat использует OpenSSL 1.1.0? Исходный код (с сайта socat.org) 1.7.2.4 (выпущен в 2014 г.) не совместим с OpenSSL 1.1.0 (выпущен в 2016 г.), в котором внесены значительные изменения API. Проверьте ldd $(which socat) . Являются ли (оба) ваши socat и OpenSSL из стандартных репозиториев, других сборщиков / упаковщиков или собраны из исходного кода?

В любом случае, хотя «что нового» не говорит об этом, и если допустить, что патч «sig» не изменит его, источник 1.7.2.4 (upstream) по умолчанию использует 512-битные параметры DH. Это действительно слишком мало – его можно было сломать еще до Logjam, и он неприемлем для любого клиента libssl с версии 1.0.1n или 1.0.2b (обе версии 2015-06) (и любой версии 1.1.0, впервые выпущенной 2016-08) ,

AFAICS ваши альтернативы:

  • обновить socat как минимум до 1.7.3.0 (который в апстриме имеет 1024-битный); 3.1+ с 2048 битами еще лучше

  • сгенерируйте или получите откуда-нибудь параметры DH по крайней мере 1024 бит (2048 лучше для большинства клиентов, включая ваш, хотя у некоторых клиентов могут возникнуть проблемы, такие как устаревшие версии Java), и добавьте их в файл cert вашего сервера.

    Вы можете сгенерировать параметры DH с openssl dhparam $n >file где $n – 1024 или 2048. Если это слишком медленно, вы можете добавить -dsaparam .

  • То же самое, но поместите параметры в отдельный файл, настроенный на сервере. На dhparams= написано, что эта опция dhparams= но код говорит, что это dh= и тестирование подтверждает последнее.

  • сконфигурировать сервер или клиент или обоих в некоторой комбинации, чтобы они не договорились о шифре, который использует DHE; так как здесь виноват ваш сервер, лично я бы настроил только сервер. Снова на странице написано « cipher но реальность – это ciphers . Поскольку 1.7.2.4 не устанавливает параметры ‘tmp_ecdh’ и (AFAICT) не может использовать 1.1.0, он не будет поддерживать ECDHE, что означает, что без DHE ваши соединения не будут иметь Perfect Forward Secrecy. Если вы можете принять это ограничение, просто используйте команду ,ciphers='DEFAULT:!DHE' на сервере.

    (1.7.3.0 up, установите ‘tmp_ecdh’ и поддержите ECDHE, что позволило бы избежать проблемы здесь, даже если они не использовали DH-1024 по умолчанию или лучше, потому что комплекты ECDHE предпочтительнее, чем DHE, поэтому будет выбран ECDHE, а затем DHE параметры не используются и не имеют значения.)