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

我有一个使用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 

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

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

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

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

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

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

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

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

如果这不起作用更新post更多信息(和完整的堆栈跟踪)。
您应该启用ssl debug info -Djavax.net.debug=ssl

这有没有解决?

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

  1. 我会把我的证书提交给服务器
  2. 服务器会立即响应握手失败。 (我甚至不会得到服务器Hello)。

最终我发现服务器需要比我在初始握手阶段提供的更强的加密/解密算法(即客户端和服务器无法就用于ssl通信的相互加密算法达成一致)。

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

此链接说明如何安装更新的策略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之后立即握手失败时,看起来客户端和服务器无法就某些事情达成一致(在很多情况下,它们是相互需要通信的加密算法)。

您很可能看到此错误,因为您的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 

堆栈跟踪来自您的客户端代码和您的客户端’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

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

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

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