接收SSLHandshakeException:handshake_failure,尽管我的客户端忽略所有证书

时间:2012-03-22 18:35:28

标签: java ssl jboss7.x

我有一个使用SSL / TLS连接到Web服务器的Java程序,并通过该连接发送各种HTTP请求。服务器是localhost并使用自签名证书,但我的代码使用自定义TrustManagers,并忽略无效证书。它一直运作到现在。

服务器上的唯一区别是它曾用于运行jboss 6并且现在正在运行jboss 7.我不确定这是配置问题,还是我的代码是否有问题,但我得到了如果我尝试使用其他基于Java的程序(如WebScarab或ZAP)进行连接,则会出现相同的错误。

无论如何,我可以对我的代码做些什么来解决这个问题?这是完整的错误:

Received fatal alert: handshake_failure
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
        at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source)
        at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source)
        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.recvAlert(Unknown Source)
        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(Unknown Source)
        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(Unknown Source)
        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(Unknown Source)
        at sun.net.www.protocol.https.HttpsClient.afterConnect(Unknown Source)
        at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source)
        at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(Unknown Source)

以下是失败前的调试消息:

main, WRITE: TLSv1 Handshake, length = 75
main, WRITE: SSLv2 client hello message, length = 101
main, READ: TLSv1 Alert, length = 2
main, RECV TLSv1 ALERT: fatal, handshake_failure

7 个答案:

答案 0 :(得分:25)

所以我发现了问题。 Java中可能存在错误,但客户端似乎启动了TLSv1握手,但随后发送了SSLv2客户端问候消息,此时服务器拒绝连接。

即使您使用TLS实例创建SSLContext,也会发生这种情况:

SSLContext sslContext = SSLContext.getInstance("TLS");

解决方案是在进行任何连接尝试之前设置系统属性:

System.setProperty("https.protocols", "TLSv1");

可能有其他解决方案,但这个对我有用。

答案 1 :(得分:4)

您提供的信息与您的堆栈跟踪信息非常少 我在这里猜一猜 我怀疑在新服务器中,协议是TLSv1,而您的客户端尝试连接SSLv3(或更少),因此握手失败。

将您的客户更改为使用更高版本的TLS 或
使您的网络服务器也支持SSLv3。我知道如何在Tomcat中执行此操作,而不是在JBoss中执行此操作。

如果这不起作用,请使用更多信息更新帖子(以及完整的堆栈跟踪) 您应该启用ssl调试信息-Djavax.net.debug=ssl

答案 2 :(得分:4)

这是否曾经解决过?

我遇到了完全相同的问题,基本上我在clientHello之后立即收到握手异常。所以事件链是

  1. 我会将证书提交给服务器
  2. 服务器会立即响应握手失败。 (我甚至不会得到服务器Hello)。
  3. 最终我发现服务器需要比我在初始握手阶段提供的更强的加密/解密算法(即客户端和服务器无法就用于ssl通信的相互加密算法达成一致)。 / p>

    我需要安装Unlimited Java JCE(Java加密扩展策略)。有关使用此功能的出口规则,因此如果您将代码发送到海外可能会产生影响..这就是解决我问题的方法。

    此链接说明如何安装更新的策略 http://suhothayan.blogspot.com/2012/05/how-to-install-java-cryptography.html

    这也是一个很好的链接,帮助我准确理解发生了什么 https://support.f5.com/kb/en-us/solutions/public/15000/200/sol15292.html#id

    这可能是也可能不是问题,但是当客户端Hello之后握手立即失败时,看起来客户端和服务器无法就某些内容达成一致(在很多情况下,它们是相互需要的加密算法)通信)。

答案 3 :(得分:0)

您很可能看到此错误,因为您的JBoss 7实例无法访问您的JBoss 6可访问的密钥库。

我建议的是以下内容。

您的自签名服务器证书必须导入信任库

keytool -import -alias gridserver -file server.crt -storepass $YOUR_PASSWORD_HERE -keystore server.keystore

将以下属性添加到run.conf

-Djavax.net.ssl.keyStoreType=pkcs12
-Djavax.net.ssl.trustStoreType=jks
-Djavax.net.ssl.keyStore=clientcertificate.p12
-Djavax.net.ssl.trustStore=server.keystore
-Djavax.net.debug=ssl # very verbose debug. Turn this off after everything looks good.
-Djavax.net.ssl.keyStorePassword=$YOUR_PASSWORD_HERE
-Djavax.net.ssl.trustStorePassword=$YOUR_PASSWORD_HERE

答案 4 :(得分:0)

堆栈跟踪来自您的客户端代码和您的客户端'Received [a]致命警报'。换句话说,SSL错误发生在Jboss中,而不是您的客户端。

因此,您的客户端自定义TrustManagers与它无关。我的猜测是,您的新Jboss 7配置为需要客户端证书,而您的客户端不提供任何证书。

要调试SSL连接,请使用openssl并尝试以下操作:

openssl s_client -connect jboss.server.com:443

或者它是SSLV3服务器

openssl s_client -connect jboss.server.com:443 -ssl3

这应该会打印很多有趣的信息。

答案 5 :(得分:0)

我认为这与Java 7 bug有关。没有更多细节,很难确定。

答案 6 :(得分:0)

对我而言,解决方案是:System.setProperty("https.protocols", "TLSv1.1,TLSv1.2");