Java:為什麼SSL握手給出'無法生成DH密鑰對'異常?



9 Answers

“Java密碼學擴展(JCE)無限強度管轄權策略文件”答案不適用於我,但BouncyCastle的JCE提供者建議做到了。

以下是我在Mac OSC 10.7.5上使用Java 1.6.0_65-b14-462的步驟

1)下載這些罐子:

2)將這些罐子移動到$ JAVA_HOME / lib / ext

3)編輯$ JAVA_HOME / lib / security / java.security,如下所示:security.provider.1 = org.bouncycastle.jce.provider.BouncyCastleProvider

使用JRE重新啟動應用並嘗試一下

Question

當我與某些IRC服務器建立SSL連接時(但不是其他服務器的首選加密方法),我得到以下異常:

Caused by: java.lang.RuntimeException: Could not generate DH keypair
    at com.sun.net.ssl.internal.ssl.DHCrypt.<init>(DHCrypt.java:106)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverKeyExchange(ClientHandshaker.java:556)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:183)
    at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:593)
    at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:529)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:893)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1138)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1165)
    ... 3 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(DashoA13*..)
    at java.security.KeyPairGenerator$Delegate.initialize(KeyPairGenerator.java:627)
    at com.sun.net.ssl.internal.ssl.DHCrypt.<init>(DHCrypt.java:100)
    ... 10 more

一個演示這個問題的服務器的例子是aperture.esper.net:6697(這是一個IRC服務器)。 kornbluth.freenode.net:6697沒有證明問題的服務器的一個例子。 [毫不奇怪,每個網絡上的所有服務器共享相同的行為。]

我的代碼(如前所述,在連接到某些SSL服務器時工作正常)是:

    SSLContext sslContext = SSLContext.getInstance("SSL");
    sslContext.init(null, trustAllCerts, new SecureRandom());
    s = (SSLSocket)sslContext.getSocketFactory().createSocket();
    s.connect(new InetSocketAddress(host, port), timeout);
    s.setSoTimeout(0);
    ((SSLSocket)s).startHandshake();

這是最後一個引發異常的開始。 是的,有一些魔術與'trustAllCerts'進行; 該代碼強制SSL系統不驗證證書。 (所以......不是證書問題。)

很明顯,有一種可能性是esper的服務器配置錯誤,但我搜索了但沒有找到任何其他人提及esper的SSL端口有問題的人,並且'​​openssl'連接了它(見下文)。 所以我想知道這是否是Java默認SSL支持的限制,或者其他什麼。 有什麼建議麼?

以下是使用命令行中的'openssl'連接到aperture.esper.net 6697時發生的情況:

~ $ openssl s_client -connect aperture.esper.net:6697
CONNECTED(00000003)
depth=0 /C=GB/ST=England/L=London/O=EsperNet/OU=aperture.esper.net/CN=*.esper.net/emailAddress=support@esper.net
verify error:num=18:self signed certificate
verify return:1
depth=0 /C=GB/ST=England/L=London/O=EsperNet/OU=aperture.esper.net/CN=*.esper.net/emailAddress=support@esper.net
verify return:1
---
Certificate chain
 0 s:/C=GB/ST=England/L=London/O=EsperNet/OU=aperture.esper.net/CN=*.esper.net/emailAddress=support@esper.net
   i:/C=GB/ST=England/L=London/O=EsperNet/OU=aperture.esper.net/CN=*.esper.net/emailAddress=support@esper.net
---
Server certificate
-----BEGIN CERTIFICATE-----
[There was a certificate here, but I deleted it to save space]
-----END CERTIFICATE-----
subject=/C=GB/ST=England/L=London/O=EsperNet/OU=aperture.esper.net/CN=*.esper.net/emailAddress=support@esper.net
issuer=/C=GB/ST=England/L=London/O=EsperNet/OU=aperture.esper.net/CN=*.esper.net/emailAddress=support@esper.net
---
No client certificate CA names sent
---
SSL handshake has read 2178 bytes and written 468 bytes
---
New, TLSv1/SSLv3, Cipher is DHE-RSA-AES256-SHA
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
    Protocol  : TLSv1
    Cipher    : DHE-RSA-AES256-SHA
    Session-ID: 51F1D40A1B044700365D3BD1C61ABC745FB0C347A334E1410946DCB5EFE37AFD
    Session-ID-ctx: 
    Master-Key: DF8194F6A60B073E049C87284856B5561476315145B55E35811028C4D97F77696F676DB019BB6E271E9965F289A99083
    Key-Arg   : None
    Start Time: 1311801833
    Timeout   : 300 (sec)
    Verify return code: 18 (self signed certificate)
---

如上所述,畢竟,它連接成功,這比我的Java應用程序所說的要多。

如果它是相關的,我使用OS X 10.6.8,Java版本1.6.0_26。




如果服務器支持不包含DH的密碼,則可以強制客戶端選擇該密碼並避免DH錯誤。 如:

String pickedCipher[] ={"TLS_RSA_WITH_AES_256_CBC_SHA"};
sslsocket.setEnabledCipherSuites(pickedCipher);

請記住,從長遠來看,指定一個確切的密碼很容易破損。




通過升級到JDK 8解決了該問題。




嘗試從Java下載站點下載“Java加密擴展(JCE)無限強化管轄策略文件”並替換JRE中的文件。

這對我有用,我甚至不需要使用BouncyCastle - 標準的Sun JCE能夠連接到服務器。

PS。 我在更改策略文件之前嘗試使用BouncyCastle時遇到了​​同樣的錯誤(ArrayIndexOutOfBoundsException:64),所以看起來我們的情況非常相似。




對我來說,下面的命令行解決了這個問題:

java -jar -Dhttps.protocols=TLSv1.2 -Ddeployment.security.TLSv1.2=true -Djavax.net.debug=ssl:handshake XXXXX.jar

我正在使用JDK 1.7.0_79




您可以動態安裝提供程序:

1)下載這些罐子:

  • bcprov-jdk15on-152.jar
  • bcprov-ext-jdk15on-152.jar

2)將jar複製到WEB-INF/lib (或你的類路徑)

3)動態添加提供者:

import org.bouncycastle.jce.provider.BouncyCastleProvider;

...

Security.addProvider(new BouncyCastleProvider());




上面的答案是正確的,但就解決方法而言,當我將其設置為首選提供程序時,我遇到了BouncyCastle實施方面的問題:

java.lang.ArrayIndexOutOfBoundsException: 64
    at com.sun.crypto.provider.TlsPrfGenerator.expand(DashoA13*..)

這也在我發現的一個論壇主題中討論過,它沒有提到解決方案。 http://www.javakb.com/Uwe/Forum.aspx/java-programmer/47512/TLS-problems

我發現了一種適用於我的案例的替代解決方案,儘管我對此並不滿意。 解決方案是設置它,以便Diffie-Hellman算法根本不可用。 然後,假設服務器支持另一種算法,它將在正常協商期間進行選擇。 顯然,這樣做的缺點是,如果某人以某種方式設法找到僅支持1024位或更少的Diffie-Hellman的服務器,那麼這實際上意味著它不能在以前工作的地方工作。

這裡是給出SSLSocket的代碼(在連接之前):

List<String> limited = new LinkedList<String>();
for(String suite : ((SSLSocket)s).getEnabledCipherSuites())
{
    if(!suite.contains("_DHE_"))
    {
        limited.add(suite);
    }
}
((SSLSocket)s).setEnabledCipherSuites(limited.toArray(
    new String[limited.size()]));

討厭。




我在Bamboo 5.7 + Gradle項目+ Apache中遇到了這個錯誤。 Gradle試圖通過SSL從我們的服務器獲得一些依賴關係。

解:

  1. 生成DH Param:

使用OpenSSL:

openssl dhparam 1024

示例輸出:

-----BEGIN DH PARAMETERS-----
MIGHfoGBALxpfMrDpImEuPlhopxYX4L2CFqQov+FomjKyHJrzj/EkTP0T3oAkjnS
oCGh6p07kwSLS8WCtYJn1GzItiZ05LoAzPs7T3ST2dWrEYFg/dldt+arifj6oWo+
vctDyDqIjlevUE+vyR9MF6B+Rfm4Zs8VGkxmsgXuz0gp/9lmftY7AgEC
-----END DH PARAMETERS-----
  1. 將輸出附加到證書文件(對於Apache- SSLCertificateFile參數)

  2. 重新啟動apache

  3. 重新啟動Bamboo

  4. 嘗試再次構建項目




我在運行JDK 6的CentOS服務器上遇到SSL錯誤。

我的計劃是安裝更高版本的JDK(JDK 7)與JDK 6共存,但事實證明,僅僅使用rpm -i來安裝更新的JDK是不夠的。

如下所示,JDK 7安裝只能通過rpm -U升級選項獲得成功。

1.下載JDK 7

wget -O /root/jdk-7u79-linux-x64.rpm --no-cookies --no-check-certificate --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F; o raclelicense=accept-securebackup-cookie" "http://download.oracle.com/otn-pub/java/jdk/7u79-b15/jdk-7u79-linux-x64.rpm"

2. RPM安裝失敗

rpm -ivh jdk-7u79-linux-x64.rpm
Preparing...                ########################################### [100%]
        file /etc/init.d/jexec from install of jdk-2000:1.7.0_79-fcs.x86_64 conflicts with file from package jdk-2000:1.6.0_43-fcs.x86_64

3. RPM升級成功

rpm -Uvh jdk-7u79-linux-x64.rpm
Preparing...                ########################################### [100%]
   1:jdk                    ########################################### [100%]
Unpacking JAR files...
        rt.jar...
        jsse.jar...
        charsets.jar...
        tools.jar...
        localedata.jar...
        jfxrt.jar...

4.確認新版本

java -version
java version "1.7.0_79"
Java(TM) SE Runtime Environment (build 1.7.0_79-b15)
Java HotSpot(TM) 64-Bit Server VM (build 24.79-b02, mixed mode)



如果您使用的是jdk1.7.0_04,請升級到jdk1.7.0_21。 該更新已修復此問題。




Related



Tags

java java   ssl