将 openssl 与 socat 一起使用时出错 - SSL3_CHECK_CERT_AND_ALGORITHM:dh 密钥太小

将 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

问题的长版本

我正在尝试按照以下文档所述使用socatwith :openssl

对于上下文,我在 Debian 9 上运行 socat 版本 1.7.2.4+sigfix 和 OpenSSL 版本 1.1.0f。

在继续尝试之前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

遵循用户的建议戴夫·汤普森_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:

答案1

首先,你确定索卡特正在使用 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(上游)源默认为 512 位 DH 参数。这确实太小了——甚至在 Logjam 之前就知道它是易碎的,并且对于 1.0.1n 或 1.0.2b 及以上版本(均于 2015-06 发布)的任何 libssl 客户端来说都是不可接受的(并且任何1.1.0,首次发布于 2016 年 8 月)。

AFAICS 您的选择是:

  • 将 socat 升级到至少 1.7.3.0(上游确实有 1024 位); 3.1+ 2048 位更好

  • 生成或从某处获取至少 1024 位的 DH 参数(对于大多数客户端(包括您的客户端)来说 2048 更好,尽管一些客户端可能会遇到问题(例如 Java 版本过时),并将它们添加到服务器的cert文件中。

    您可以使用 1024 或 2048 生成 DHopenssl dhparam $n >file参数$n如果这太慢你可以添加-dsaparam

  • 同上,但将参数放在服务器上配置的单独文件中。联机帮助页说这个选项是,dhparams=<file>但代码说它是,dh=并且测试证实了后者。

  • 配置服务器或客户端,或两者的某种组合,以便它们不同意使用 DHE 的密码套件;由于您的服务器是这里的错误服务器,因此我个人只会配置服务器。手册页再次说cipher但现实是ciphers。由于 1.7.2.4 没有设置“tmp_ecdh”参数,并且(AFAICT)它不能使用 1.1.0,因此它不支持 ECDHE,这意味着如果没有 DHE,您的连接将不具有完美的前向保密性。如果您可以接受该限制,那么,ciphers='DEFAULT:!DHE'在服务器上使用是一个简单的解决方案。

    (1.7.3.0 以上确实设置了“tmp_ecdh”并支持 ECDHE,即使它们没有默认 DH-1024 或更好,这也可以避免这里的问题,因为 ECDHE 套件优于 DHE,因此将选择 ECDHE,然后选择 DHE参数没有被使用并且无关紧要。)

相关内容