Java 7的SSL连接失败

我正在尝试使用Java 7创建到远程服务器的SSL连接,并且我收到以下exception:

javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:946) 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) at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221) at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:291) at sun.nio.cs.StreamEncoder.implFlush(StreamEncoder.java:295) at sun.nio.cs.StreamEncoder.flush(StreamEncoder.java:141) at java.io.OutputStreamWriter.flush(OutputStreamWriter.java:229) at java.io.BufferedWriter.flush(BufferedWriter.java:254) at ssl7.Client.main(Client.java:22) Caused by: java.io.EOFException: SSL peer shut down incorrectly at sun.security.ssl.InputRecord.read(InputRecord.java:482) at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:927) 

当我使用Java 6重新运行代码时,没有例外。 我在StackOverflow的其他地方找到了对这个问题的引用,但我的情况有一个转折。 使用Java 7失败的客户端代码是

 public class Client { public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException { try { SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault(); SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket("login.solon.com", 443); OutputStream outputstream = sslsocket.getOutputStream(); OutputStreamWriter outputstreamwriter = new OutputStreamWriter(outputstream); BufferedWriter bufferedwriter = new BufferedWriter(outputstreamwriter); bufferedwriter.write("hello\n"); bufferedwriter.flush(); } catch (Exception exception) { exception.printStackTrace(); } } } 

当我添加该行

 sslsocket.setEnabledCipherSuites(new String[] {"SSL_RSA_WITH_RC4_128_MD5"}); 

创建套接字后,它可以工作。

现在, SSL_RSA_WITH_RC4_128_MD5存在于原始的密码套件集中,所以我所做的就是添加限制。 从长远来看,限制密码套件不是一个可行的解决方案。 谁能解释一下这里发生了什么?

完整的调试日志是:

 keyStore is : keyStore type is : jks keyStore provider is : init keystore init keymanager of type SunX509 trustStore is: C:\Temp\keystore\clientkeystore trustStore type is : jks trustStore provider is : init truststore adding as trusted cert: Subject: CN=W, OU=D, O=S, L=H, ST=I, C=IL Issuer: CN=W, OU=D, O=S, L=H, ST=I, C=IL Algorithm: DSA; Serial number: 0x4a6e05b7 Valid from Mon Oct 07 10:22:54 EEST 2013 until Sun Jan 05 09:22:54 EET 2014 adding as trusted cert: Subject: CN=login.solon.com, OU=Domain Validated, OU=Thawte SSL123 certificate, OU=Go to https://www.thawte.com/repository/index.html Issuer: CN=Thawte DV SSL CA, OU=Domain Validated SSL, O="Thawte, Inc.", C=US Algorithm: RSA; Serial number: 0x3012ec22473f20aa2cdc4bf7fe2d22f4 Valid from Wed Feb 13 02:00:00 EET 2013 until Thu Apr 14 02:59:59 EEST 2016 adding as trusted cert: Subject: CN=W, OU=D, O=S, L=H, ST=I, C=IL Issuer: CN=W, OU=D, O=S, L=H, ST=I, C=IL Algorithm: RSA; Serial number: 0x5864235a Valid from Mon Oct 07 10:28:06 EEST 2013 until Sun Jan 05 09:28:06 EET 2014 trigger seeding of SecureRandom done seeding SecureRandom 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: true Allow legacy hello messages: true Is initial handshake: true Is secure renegotiation: false %% No cached client session *** ClientHello, TLSv1 RandomCookie: GMT: 1381093608 bytes = { 221, 239, 107, 239, 150, 213, 224, 210, 101, 229, 42, 58, 92, 9, 151, 0, 128, 105, 0, 55, 53, 224, 90, 111, 130, 175, 61, 121 } 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] *** [write] MD5 and SHA1 hashes: len = 149 0000: 01 00 00 91 03 01 52 52 D1 E8 DD EF 6B EF 96 D5 ......RR....k... 0010: E0 D2 65 E5 2A 3A 5C 09 97 00 80 69 00 37 35 E0 ..e.*:\....i.75. 0020: 5A 6F 82 AF 3D 79 00 00 2A C0 09 C0 13 00 2F C0 Zo..=y..*...../. 0030: 04 C0 0E 00 33 00 32 C0 07 C0 11 00 05 C0 02 C0 ....3.2......... 0040: 0C C0 08 C0 12 00 0A C0 03 C0 0D 00 16 00 13 00 ................ 0050: 04 00 FF 01 00 00 3E 00 0A 00 34 00 32 00 17 00 ......>...4.2... 0060: 01 00 03 00 13 00 15 00 06 00 07 00 09 00 0A 00 ................ 0070: 18 00 0B 00 0C 00 19 00 0D 00 0E 00 0F 00 10 00 ................ 0080: 11 00 02 00 12 00 04 00 05 00 14 00 08 00 16 00 ................ 0090: 0B 00 02 01 00 ..... main, WRITE: TLSv1 Handshake, length = 149 [Raw write]: length = 154 0000: 16 03 01 00 95 01 00 00 91 03 01 52 52 D1 E8 DD ...........RR... 0010: EF 6B EF 96 D5 E0 D2 65 E5 2A 3A 5C 09 97 00 80 .k.....e.*:\.... 0020: 69 00 37 35 E0 5A 6F 82 AF 3D 79 00 00 2A C0 09 i.75.Zo..=y..*.. 0030: C0 13 00 2F C0 04 C0 0E 00 33 00 32 C0 07 C0 11 .../.....3.2.... 0040: 00 05 C0 02 C0 0C C0 08 C0 12 00 0A C0 03 C0 0D ................ 0050: 00 16 00 13 00 04 00 FF 01 00 00 3E 00 0A 00 34 ...........>...4 0060: 00 32 00 17 00 01 00 03 00 13 00 15 00 06 00 07 .2.............. 0070: 00 09 00 0A 00 18 00 0B 00 0C 00 19 00 0D 00 0E ................ 0080: 00 0F 00 10 00 11 00 02 00 12 00 04 00 05 00 14 ................ 0090: 00 08 00 16 00 0B 00 02 01 00 .......... 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 [Raw write]: length = 7 0000: 15 03 01 00 02 02 28 ......( main, called closeSocket() javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:946) 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) at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221) at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:291) at sun.nio.cs.StreamEncoder.implFlush(StreamEncoder.java:295) at sun.nio.cs.StreamEncoder.flush(StreamEncoder.java:141) at java.io.OutputStreamWriter.flush(OutputStreamWriter.java:229) at java.io.BufferedWriter.flush(BufferedWriter.java:254) at ssl7.Client.main(Client.java:22) Caused by: java.io.EOFException: SSL peer shut down incorrectly at sun.security.ssl.InputRecord.read(InputRecord.java:482) at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:927) ... 10 more 

谢谢。

在使用运行基于Java的服务器的Ubuntu 12.04服务器使用其OpenJDK包之前,我已经看到过这种问题。 (这可能已经修补了,因为我无法使用最新更新重现问题,但我的配置可能略有不同,我不记得了。)

这基本上是这个Ubuntu问题中描述的问题 。

服务器端的EC计算基本上存在问题,这阻止了正确建立连接。

Java 6和Java 7之间的密码套件的首选顺序有所不同(参见两个表)。

由于TLS_RSA_WITH_AES_128_CBC_SHA高于Java 6中的首选顺序中的任何EC密码套件(并且受客户端和服务器支持),因此在与Java 6客户端连接时将选择它。

当您连接Java 7客户端时,将选择一些EC密码套件(例如TLS_ECDHE_RSA_WITH_AES_128_CBC_SHATLS_ECDHE_RSA_WITH_AES_256_CBC_SHA ),服务器将开始继续执行此操作(您需要在服务器端查看握手调试日志以确认此情况) 。 然后,服务器将使用密码套件选择过程完成,但由于尝试使用此密码套件时存在后续错误,因此无法继续使用。

如果您对服务器有一定的控制权(如果它确实在运行基于Java的服务器),请尝试升级到最新的JRE包。 您还可以尝试Ubuntu问题中建议的修复(特别是如果它不使用PKCS#11)或禁用服务器配置中的ECDHE密码套件。

通过一瞥您的服务器配置( https://www.ssllabs.com/ssltest/analyze.html?d=login.solon.com )与Java7中可用的密码套件列表相比,您似乎只接受了两个密码套件密码套件的选项:

 TLS_RSA_WITH_AES_128_CBC_SHA TLS_DHE_RSA_WITH_AES_128_CBC_SHA 

现在, TLS_DHE_RSA_WITH_AES_128_CBC_SHA被认为是弱的,但由于您的服务器声明没有订单的偏好,它可能会选择此然后失败握手。 对于Java6来说,完全有可能恰好选择更强大的套件。 你给它的选项越多,你就有机会选择一个弱密码,所以当你指定一个单独的套件使用时,它就会成功。 (虽然在查看您的服务器配置时,我不确定您是如何获得SSL_RSA_WITH_RC4_128_MD5才能成功的,因为它显然不受支持。)在这一思路上,也许您应该尝试将密码套件限制为:

 TLS_RSA_WITH_AES_128_CBC_SHA 

或者更具体地说:

 sslsocket.setEnabledCipherSuites(new String[] {"TLS_RSA_WITH_AES_128_CBC_SHA"}); 

这是Java 7与密钥库的兼容性问题。 将密钥库文件转换为.p12。 它应该使用它。

你在执行客户端时是否包含了信任库?

 java -Djavax.net.ssl.trustStore=${resources}/localhost.truststore \ -Djavax.net.ssl.trustStorePassword=TRUSTSTORE_PASSWORD -jar client.jar com.acme.RunClient