0

我正在尝试重现Java 中提出的问题:为什么 SSL 握手会给出“无法生成 DH 密钥对”异常?.

我有一个日志显示此原因的异常:

Caused by: javax.net.ssl.SSLException: java.lang.RuntimeException: Could not generate DH keypair
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:208)
    at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1886)
    at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1844)
    at sun.security.ssl.SSLSocketImpl.handleException(SSLSocketImpl.java:1827)
    at sun.security.ssl.SSLSocketImpl.handleException(SSLSocketImpl.java:1753)
    at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:127)
    at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
    at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
    at org.apache.axis2.transport.http.AxisRequestEntity.writeRequest(AxisRequestEntity.java:94)
    ... 27 more
Caused by: java.lang.RuntimeException: Could not generate DH keypair
    at sun.security.ssl.DHCrypt.<init>(DHCrypt.java:136)
    at sun.security.ssl.ClientHandshaker.serverKeyExchange(ClientHandshaker.java:621)
    at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:205)
    at sun.security.ssl.Handshaker.processLoop(Handshaker.java:868)
    at sun.security.ssl.Handshaker.process_record(Handshaker.java:804)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1016)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312)
    at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:702)
    at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:122)
    ... 30 more
Caused by: java.security.InvalidAlgorithmParameterException: Prime size must be multiple of 64, and can only range from 512 to 1024 (inclusive)
    at com.sun.crypto.provider.DHKeyPairGenerator.initialize(DHKeyPairGenerator.java:120)
    at java.security.KeyPairGenerator$Delegate.initialize(KeyPairGenerator.java:658)
    at sun.security.ssl.DHCrypt.<init>(DHCrypt.java:127)
    ... 38 more

我正在使用 Axis2 调用 Web 服务。我在 jre/lib/security 中也有“Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files”(但正如在另一篇文章中提到的那样,这对他们不起作用)。

为了重现此问题,我尝试在具有类似环境(也使用 Axis2)的单独部署中托管 Web 服务。这有一个自定义 SSLServerSocketFactory,它正在创建和配置 SSLServerSocket。

使用 Wireshark(以及 javax.net.debug JVM 参数)我可以看到协商的密码套件是 TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA 但 ServerKeyExchange 中的 Prime DH 服务器参数只有 96 个字节(768 位)。

有什么方法可以将 SSLServerSocket 配置为在握手期间使用更大的素数?

我猜密钥是由 JRE 的 RSA 安全提供程序生成的。我是否需要添加自己的提供程序并将其添加到 jre/lib/security/java.security?

如果这是一个愚蠢的问题,我很抱歉,我一般是 DHE 和密码套件的新手。我只需要知道足以让服务器测试工作(我没有触及客户端实现)。

4

1 回答 1

0

因此,随着 EJP 朝着正确方向的推进,我最终设法准确地找到了确定强度(以及随后的 DH 参数)的位置。它确实在 JRE 中(特别是在 ServerHandshaker 中)。

将安全提供程序与具有强度限制的旧 JRE 一起使用(如原始帖子中所述)在这里不起作用。虽然使用其他安全提供程序可能会阻止此错误客户端,但在初始化 KeyPairGenerator 的实现之前已经确定了强度。

作为旁注,我没有费心升级 JRE 来重现这一点。我刚刚添加了带有调试信息的 BouncyCastle JCE 提供程序,在 org.bouncycastle.jcajce.provider.asymmetric.dh.KeyPairGeneratorSpi.initialize(int, SecureRandom) 方法中放置了一个断点并手动更改了强度。这对我的测试来说已经足够好了。

于 2015-04-08T00:59:41.500 回答