TLS 1.2 中的 DHE_RSA 公钥长度?

信息安全 tls
2021-08-30 18:18:56

概括:

当服务器在 DHE_RSA 服务器密钥交换消息中交出 127 字节的公钥时,TLS 客户端似乎无法协商,但在交出 128 字节的公钥时协商成功。公钥长度有什么问题,特别是服务器端的这种合法行为是什么?

血腥细节:

我有一个客户端(软件未知)在连接到我的 TLS 服务器(F5、TLS 1.2)时遇到间歇性故障。成功和失败的连接都取决于服务器 Hello 中的 Cipher Suite TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 (0x009f)。所有连接尝试都到达服务器 Hello Done 并且失败的连接在此之后立即由客户端进行 FIN。

查看数据包捕获,失败似乎都与服务器密钥交换握手中的“公钥长度”为 127 一致:

使用 127 字节 DHE_RSA 公钥捕获 Wireshark

另一方面,与该客户端的每次成功协商都在服务器密钥交换握手中涉及 128 的“公钥长度”:

使用 128 字节 DHE_RSA 公钥捕获 Wireshark

每当服务器发送 127 字节版本时,客户端都会以 FIN/ACK 而不是客户端密钥交换进行响应。我们得出的结论是客户端不能接受 127 字节的公钥长度。我已经阅读 了RFC 5246以了解我是否可以了解允许的内容并且它们没有帮助(至少对我来说!):

struct {
    opaque dh_p<1..2^16-1>;
    opaque dh_g<1..2^16-1>;
    opaque dh_Ys<1..2^16-1>;
} ServerDHParams;     /* Ephemeral DH parameters */

 struct {
     select (KeyExchangeAlgorithm) {
         case dhe_rsa:
             ServerDHParams params;
             digitally-signed struct {
                 opaque client_random[32];
                 opaque server_random[32];
                 ServerDHParams params;
              } signed_params;
    };
} ServerKeyExchange;

所以具体的问题是:

  1. DHE_RSA 服务器密钥交换中的公钥长度是怎么回事?具体来说,127 与 128 是否代表类似零截断以节省长度的东西,还是真的提供 127 字节的密钥?

  2. 更具体地说,127 是否是客户端应该能够处理的有效公钥长度,或者这是否代表需要解决的服务器问题?

澄清:

有问题的服务器是一个运行最新 (11.6) 软件的 F5 负载均衡器,因此在 TLS 出处方面它不仅是现成的,而且是现成的。这并不是说这不是问题,只是说这不像我在后端滚动我自己的 Lua-over-Django-with-third-Rails TLS 服务器:)

OpenSSL 的想法

我留下了一个脚本,openssl s_client用于在周末每分钟访问服务器,并捕获完整的数据包,以便我可以看到 OpenSSL 对这个特定服务器配置的看法。简单地说,对于 127 字节的 DHE“公钥”长度,OpenSSL 认为“服务器临时密钥”是 1024 位的。

这是 Wireshark 中显示的服务器密钥交换:

OpenSSL 触发的服务器密钥交换握手

这是该连接的 OpenSSL 输出:

$ tail -25 20151107234244.txt
---
No client certificate CA names sent
Server Temp Key: DH, 1024 bits
---
SSL handshake has read 2014 bytes and written 291 bytes
---
New, TLSv1/SSLv3, Cipher is DHE-RSA-AES256-GCM-SHA384
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : DHE-RSA-AES256-GCM-SHA384
    Session-ID: 8C48CAD47FC01AF350CF618E21AE9C7E8764BB7C7243D8D6204F95634523EF2F
    Session-ID-ctx:
    Master-Key: FB80D1070A3BB2435C2D4E50D6633DA3DE4FDCFA5C8A922E17EC6FB0EDC41E259F55DFC33345B51F9A90568B36CFBB7C
    Key-Arg   : None
    Krb5 Principal: None
    PSK identity: None
    PSK identity hint: None
    Start Time: 1446957764
    Timeout   : 300 (sec)
    Verify return code: 21 (unable to verify the first certificate)
---
$

那么它是 1024 位还是 1016 位?'p' 长度是否表示密钥强度而不是公钥长度(对于那些在 Wireshark 中跟随的人来说,ssl.handshake.ys_len)?Diffie-Hellman 的“服务器密钥交换”在哪里定义?有人找到了足够的文档来编写 Wireshark 解析器,如果我可以查看他们使用的文档,也许我会更好地了解这些领域的期望。

4个回答

在您的所有示例中,所有DH 密钥的大小都是“1024 位”。在 DH 中,有参数(模p,生成器g)、私钥x)和公钥y)。关系是y = g x mod p

“密钥长度”是素数p的大小。在所有情况下,p介于 2 1023和 2 1024之间,因此它是“1024 位整数”,这是 DH 密钥对的大小。现在,“公钥”本身就是介于 1 和p -1之间的整数y ;特别是,没有什么会迫使y大于 2 1023这不是问题“公钥长度”字段是编码值y的大小(以字节为单位) (采用大端无符号表示法)。取决于p的确切值,预计 1/256 到 1/128 的所有 DH 公钥将只需要 127 个字节进行编码。在您的最后一个示例中,值y被编码为 127 个字节,第一个是06,这意味着y在技​​术上是一个 1011 位整数;DH 密钥长度仍然是 1024 位,因为这是p的大小。

因此,“公钥长度”与“ y的编码长度”中的公钥长度相关,但与“告诉强大攻击者是否可以破解密钥的长度”不同。

显然,您设置中的某些系统(客户端,或客户端和服务器之间的某些路由器/防火墙 - 也许您在服务器上观察到的 FIN 不是由客户端本身发送的)被混淆并且无法区分这两个概念“公钥长度”。将您的 F5 配置为对 DH 使用更大的模数可能会解决该问题,并且无论如何都可以被认为是一个好主意(1024 位 DH 尚不可破解,但理论上您不希望使用 1024 位 DH将接受使用 1024 位 RSA)。

我只是想总结一下这个问题的现状:

  • 一位 F5 工程师向 Microsoft 提交了关于此问题的错误,可在此处找到。似乎 MS 已经接受了它并正在研究解决方案,所以它似乎真的是一个 SCHANNEL 问题。
  • 目前唯一的解决方案似乎是禁用 DHE 密码。

注意——OpenSSL 1.1.0 有一个我提交的更改以解决这个问题(请参阅此处的 PR ),并且截至 2016 年 12 月 14 日,它也已合并到 1.0.2 分支中,因此它将在任何未来的 1.0.2 中发布。如果需要,也可以将其向后移植到 1.0.1。

公钥的长度取决于素数字段的值。我猜想密钥大小确实小于 128 字节/1024 位。这意味着服务器上的软件有问题。

原则上,任何大小的素数都可以用于 Diffie-Hellman;最后,该值将用作数字。然而,使用 127 字节/1016 位密钥确实存在一些问题:

  • 并非所有软件都能够处理任何特定的密钥大小,例如有时软件需要 8 个字节的倍数;
  • 1024 位对于 DH 来说已经是一个非常小的尺寸,现在您希望使用更大的尺寸,例如 2048 位。

但是,我会首先联系对服务器进行编程的组织。即使 1016 位密钥大小不是直接问题,它也可能表明存在更严重的问题。