Java 7 的 SSL 连接失败

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19228862/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 15:15:44  来源:igfitidea点击:

SSL connection failing for Java 7

javassl

提问by twizansk

I am attempting to create an SSL connection to a remote server using Java 7 and I'm receiving the following exception:

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

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)

When I rerun the code using Java 6, there is no exception. I have found references to this problem elsewhere on StackOverflow but my situation comes with a twist. The client code, which fails with Java 7 is

当我使用 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();
        }
    }
}

When I add the line

当我添加行时

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

after creating the socket, it works.

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

now, SSL_RSA_WITH_RC4_128_MD5exists in the original set of cipher suites so all I've done is add restrictions. Restricting the cipher suites is not a viable solution in the long run. Can anyone explain what is going on here?

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

The full debug log is:

完整的调试日志是:

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

Thanks.

谢谢。

回答by Henry

did you include the truststore when you execute the client?

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

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

回答by MattSenter

From a glance at your server configuration (https://www.ssllabs.com/ssltest/analyze.html?d=login.solon.com) compared to your list of available cipher suites in Java7, it appears you have only two accepted options for your cipher suite:

从您的服务器配置 ( 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

Now, TLS_DHE_RSA_WITH_AES_128_CBC_SHAis considered weak, but since your server declares no preference for order, it may be picking this and then failing the handshake. For Java6, it's entirely possible it just happens to be picking a stronger suite. The more options you give it, the more chances you have of giving it a chance to pick a weak cipher, so when you specify a single suite to use, it succeeds. (Although in looking at your server configuration, I'm not sure how you were getting SSL_RSA_WITH_RC4_128_MD5to succeed as it is apparently not supported.) On that train of thought, perhaps you should try limiting your cipher suites to only:

现在,TLS_DHE_RSA_WITH_AES_128_CBC_SHA被认为是弱的,但是由于您的服务器声明没有优先顺序,它可能会选择这个然后握手失败。对于 Java6,完全有可能只是碰巧选择了一个更强大的套件。您提供的选项越多,您选择弱密码的机会就越大,因此当您指定要使用的单个套件时,它就会成功。(虽然在查看您的服务器配置时,我不确定您是如何获得SSL_RSA_WITH_RC4_128_MD5成功的,因为它显然不受支持。)按照这种思路,也许您应该尝试将密码套件限制为:

TLS_RSA_WITH_AES_128_CBC_SHA

Or more specifically:

或者更具体地说:

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

回答by Deblina Das

It's Java 7's compatibility issue with keystores. Convert your keystore file into .p12 . It should work using that.

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

回答by Bruno

I have seen this sort of problem before when using an Ubuntu 12.04 server running a Java-based server using its OpenJDK package. (This may have been patched since, as I'm unable to reproduce the problem with the latest updates, but my configuration might be slightly different, I can't remember.)

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

This was essentially the problem described in this Ubuntu issue.

这本质上就是这个 Ubuntu问题中描述的问题

There was essentially an issue with the EC calculation on the server side, which prevented the connection to be established correctly.

服务器端的EC计算本质上存在问题,导致无法正确建立连接。

There is a difference in the preference order for the cipher suites between Java 6and Java 7(see both tables).

Java 6Java 7之间密码套件的优先顺序存在差异(请参阅两个表)。

Because TLS_RSA_WITH_AES_128_CBC_SHAis higher than any EC cipher suite in the preference order in Java 6 (and supported by both client and server), it will be chosen when you connect with a Java 6 client.

因为TLS_RSA_WITH_AES_128_CBC_SHA在 Java 6 中的首选项顺序中高于任何 EC 密码套件(并且客户端和服务器都支持),所以当您连接 Java 6 客户端时将选择它。

When you connect with a Java 7 client, some EC cipher suites (e.g. TLS_ECDHE_RSA_WITH_AES_128_CBC_SHAor TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) will be chosen and the server will start to proceed with this (you'd need to see the handshake debug log on the server side to confirm this). The server would then be done with the cipher suite selection process, but fail to go any further because of a subsequent bug when trying to use this cipher suite.

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

If you have some control over the server (and if it's indeed running a Java-based server), try to upgrade to the latest JRE packages. You can also try the fixes suggested in the Ubuntu issue (especially if it's not using PKCS#11) or to disable the ECDHE cipher suites in the server configuration.

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