2013-03-23 15 views
28

我看到从运行Java 6会失败,异常客户端的SSL连接:如何使Java 6与“SSL对等关闭不正确”的SSL连接失败,像Java 7一样成功?

Caused by: javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake 
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:882) 
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1188) 
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1215) 
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1199) 
    at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434) 
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166) 
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:133) 
    ... 35 more 
Caused by: java.io.EOFException: SSL peer shut down incorrectly 
    at com.sun.net.ssl.internal.ssl.InputRecord.read(InputRecord.java:462) 
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:863) 
    ... 41 more 

服务器是基于7 Tomcat的应用程序,在Java 7中,Linux上运行,并在Amazon EC2上,为了什么是值得的。

我发现了很多关于可能的casues的建议,包括意外连接到非SSL端口等。我相信我已经排除了所有这些,主要是因为运行Java 7时完全相同的客户端没有变化。 (在这两种情况下都是OS X)。

下面我包含Java 6的调试输出和Java 7的SSL连接过程。我对专家的问题是,这是否表明在Java 6中可以启用某些可能的密码或协议设置(可能是Java 7中的默认设置)以使其工作

的Java 6:

Allow unsafe renegotiation: false 
Allow legacy hello messages: true 
Is initial handshake: true 
Is secure renegotiation: false 
%% No cached client session 
*** ClientHello, TLSv1 
RandomCookie: GMT: 1363993281 bytes = { 77, 153, 100, 72, 45, 178, 253, 243, 195, 167, 17, 151, 39, 247, 148, 102, 213, 129, 39, 17, 26, 139, 157, 154, 63, 88, 41, 160 } 
Session ID: {} 
Cipher Suites: [SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_DES_CBC_SHA, SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV] 
Compression Methods: { 0 } 
*** 
main, WRITE: TLSv1 Handshake, length = 81 
main, WRITE: SSLv2 client hello message, length = 110 
main, received EOFException: error 
main, handling exception: javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake 
main, SEND TLSv1 ALERT: fatal, description = handshake_failure 
main, WRITE: TLSv1 Alert, length = 2 
main, called closeSocket() 

的Java 7:

Ignoring unavailable cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA 
Ignoring unavailable cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA 
Ignoring unavailable cipher suite: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA 
Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 
Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 
Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 
Ignoring unsupported cipher suite: TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 
Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 
Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 
Ignoring unsupported cipher suite: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 
Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA256 
Ignoring unavailable cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA 
Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 
Ignoring unavailable cipher suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA 
Ignoring unsupported cipher suite: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 
Ignoring unsupported cipher suite: TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 
Ignoring unavailable cipher suite: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA 
Ignoring unavailable cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA 
Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_128_CBC_SHA256 
Allow unsafe renegotiation: false 
Allow legacy hello messages: true 
Is initial handshake: true 
Is secure renegotiation: false 
main, setSoTimeout(0) called 
%% No cached client session 
*** ClientHello, TLSv1 
RandomCookie: GMT: 1363993435 bytes = { 131, 83, 80, 186, 215, 90, 171, 131, 231, 18, 184, 183, 249, 155, 197, 204, 73, 1, 74, 79, 32, 142, 236, 28, 111, 37, 58, 255 } 
Session ID: {} 
Cipher Suites: [TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA, SSL_RSA_WITH_RC4_128_SHA, TLS_ECDH_ECDSA_WITH_RC4_128_SHA, TLS_ECDH_RSA_WITH_RC4_128_SHA, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_RC4_128_MD5, TLS_EMPTY_RENEGOTIATION_INFO_SCSV] 
Compression Methods: { 0 } 
Extension elliptic_curves, curve names: {secp256r1, sect163k1, sect163r2, secp192r1, secp224r1, sect233k1, sect233r1, sect283k1, sect283r1, secp384r1, sect409k1, sect409r1, secp521r1, sect571k1, sect571r1, secp160k1, secp160r1, secp160r2, sect163r1, secp192k1, sect193r1, sect193r2, secp224k1, sect239k1, secp256k1} 
Extension ec_point_formats, formats: [uncompressed] 
Extension server_name, server_name: [host_name: ec2-xx-xx-xx-xx.compute-1.amazonaws.com] 
+0

服务器参数故障是否从客户端可见?作为正常SSL协商的一部分,我已经看到过这些类型的错误,即从用户的角度来看,它“起作用”。 – Taylor 2013-03-23 17:35:10

+0

对于Java 6,客户端hello会回退到SSLv2,而对于Java 7,它似乎是使用TLSv1进行的。我相信Java 6下的JSSE并没有正式支持SSL V2,但我需要研究 – 2013-03-23 17:42:05

+1

使用'openssl s_client -connect servername:443',你可以调试服务器支持的协议,并通过强制诸如'ssl2','' ssl2',勾选[this](http://www.openssl.org/docs/apps/s_client.html) – 2013-03-23 17:47:22

回答

18

布鲁诺的答案最终是正确的。这个系统属性最容易控制。这就是你如何能够控制工厂方法返回的内容。例如,设置为“TLSv1”。

+2

当您想要使用两个协议而不是一个时会导致问题。例如'SSLv3'和'TLSv1'。如果尝试连接SSLv3或TLSv1,此'-Dhttps.protocols = TLSv1,SSLv3'将导致异常。 – Dragon 2013-12-04 14:38:10

+1

@Dragon真的吗?什么例外?为什么? – EJP 2015-05-13 11:43:29

6

看来,在调试日志Java 6请求是在发送格式SSLv2。 110

作为默认在支持Java 7.
更改客户端使用SSLv3和上述避免这种互操作性此没有提及的SSLv2客户端问候消息,长度=:

主,WRITE的问题。在Java 7

寻找在JSSE供应商的差异,并从客户端的SSLSocket或HttpsURLConnection的启用的协议Java 6

+0

是的,这是很好的证据,事实上SSLv2似乎是问题所在。这种导致我的答案在这里,尽管@EJP是正确的,最好找到一种方法来明确地关闭SSLv2。 – 2013-03-24 05:55:04

4

删除“SSLv2ClientHello”。

+0

我认为这是完全正确的,但我不知道如何去做。我正在为该平台构建一个'SSLSocketFactory'。 'SSLContext.createSSLEngine()'生成一个'SSLEngine',它有方法来设置(不是删除,似乎)协议。但我不认为这有助于'SSLSocketFactory'。 'SSLContext'也只允许你请求一个协议,而不是禁用其他任何需要的(?)。如果你碰巧知道这是怎么回事,让我知道。 – 2013-03-24 05:54:01

+0

获取启用的协议,删除“SSLv2ClientHello”,并将它们设置为剩下的内容。 – EJP 2013-03-24 06:33:17

+0

虽然我不相信有这样的方法。至少我不能在'SSLContext'或'SSLSocketFactory'上看到它。 'SSLEngine'没有帮助我相信,因为框架将在以后自己做。将继续寻找。 – 2013-03-24 07:11:54

1

做这样的:

SSLSocket socket = (SSLSocket) sslFactory.createSocket(host, port); 
socket.setEnabledProtocols(new String[]{"SSLv3", "TLSv1"}); 
3

更新从-Dhttps.protocols =的SSLv3到-Dhttps.protocols =使用TLSv1,SSLv3的