Java 7(充当客户端)与在 Java 6 中工作的密钥库和信任库的 SSL 握手失败

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25241319/
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-10 23:58:08  来源:igfitidea点击:

Java 7 (acting as client) SSL handshake failure with keystore and truststore that worked in Java 6

javasslkeystorehandshaketruststore

提问by stupor-mundi

I'm doing a JBoss AS 5.1 to 7.4, and Java 6 to 7 migration, and get a handshake failure.

我正在执行 JBoss AS 5.1 到 7.4 和 Java 6 到 7 的迁移,并且握手失败。

The keystore and truststore are the ones we have been using successfully for ages with Java 6.

密钥库和信任库是我们在 Java 6 中成功使用多年的库。

I've written some tests to narrow the problem down, it's definitely not JBoss but rather Java 7.

我写了一些测试来缩小问题的范围,它绝对不是 JBoss,而是 Java 7。

With SSL logging turned on, I get this:

打开 SSL 日志记录后,我得到了这个:

17:44:30,041 INFO  [stdout] (http-/192.168.147.20:8080-120) %% Invalidated:  [Session-2, SSL_RSA_WITH_RC4_128_SHA]
17:44:30,041 INFO  [stdout] (http-/192.168.147.20:8080-120) http-/192.168.147.20:8080-120, SEND TLSv1 ALERT:  fatal, description = certificate_unknown
17:44:30,041 INFO  [stdout] (http-/192.168.147.20:8080-120) http-/192.168.147.20:8080-120, WRITE: TLSv1 Alert, length = 2
17:44:30,041 INFO  [stdout] (http-/192.168.147.20:8080-120) http-/192.168.147.20:8080-120, called closeSocket()
17:44:30,041 INFO  [stdout] (http-/192.168.147.20:8080-120) http-/192.168.147.20:8080-120, handling exception: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path validation failed: java.security.cert.CertPathValidatorException: Path does not chain with any of the trust anchors
17:44:30,041 INFO  [stdout] (http-/192.168.147.20:8080-120) http-/192.168.147.20:8080-120, called close()
17:44:30,042 INFO  [stdout] (http-/192.168.147.20:8080-120) http-/192.168.147.20:8080-120, called closeInternal(true)

There are some threads touching upon this (or a similar) problem, where people are suggesting to recreate certs or truststores with different params. I'd rather not go down this route, since I've recently without success tried to create more such keystores and truststores for different accounts of the same webservice.

有一些线程涉及这个(或类似的)问题,人们建议使用不同的参数重新创建证书或信任库。我宁愿不走这条路,因为我最近尝试为同一网络服务的不同帐户创建更多这样的密钥库和信任库,但没有成功。

Since we have been using these old (keystore and truststore) in production with Java 6, I'd like to keep them if at all possible.

由于我们一直在 Java 6 的生产中使用这些旧的(密钥库和信任库),如果可能的话,我想保留它们。

It appears the problem may be caused by Java 7 being more tight regarding the checking of truststore certificate chain?

看来问题可能是由于 Java 7 对信任库证书链的检查更加严格造成的?

Is it possible to set some flags to relax the checking, make it behave like Java 6?

是否可以设置一些标志来放松检查,使其表现得像 Java 6?

A thing I'm not 100% sure about is how to interpret the failure message: I think it's telling me that it's my machine (not the remove server), which isn't satisfied that the remote machine is safe. Is that correct?

我不是 100% 确定的是如何解释失败消息:我认为它告诉我这是我的机器(不是删除服务器),它不满意远程机器是安全的。那是对的吗?

Any help/ideas appreciated!

任何帮助/想法表示赞赏!

==========================================================

================================================== ========

As suggested, have added PEM (with chain), exported from firefox when accessing the WS URL, to the truststore. This doesn't make it handshake, but slightly changes the failure.

按照建议,已将 PEM(带链)添加到信任库,该 PEM(带链)在访问 WS URL 时从 Firefox 导出。这不会使它握手,但会稍微改变失败。

***
%% Invalidated:  [Session-1, SSL_RSA_WITH_RC4_128_SHA]
main, SEND TLSv1 ALERT:  fatal, description = certificate_unknown
main, WRITE: TLSv1 Alert, length = 2
[Raw write]: length = 7
0000: 15 03 01 00 02 02 2E                               .......
main, called closeSocket()
main, handling exception: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
    at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1884)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:276)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:270)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1341)
    at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:153)
    at sun.security.ssl.Handshaker.processLoop(Handshaker.java:868)
    at sun.security.ssl.Handshaker.process_record(Handshaker.java:804)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1016)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1339)

==============================================================

================================================== ============

Also, as suggested in other threads, I've written another test that uses a TrustManager that does not validate certificate chains, and ran this with my original truststore.

此外,正如其他线程中所建议的那样,我编写了另一个使用不验证证书链的 TrustManager 的测试,并使用我原来的信任库运行它。

This test is able to connect, and thus shows that my machine's validating of the remote machine is the only problem, and that my keystore is fine.

该测试能够连接,因此表明我的机器对远程机器的验证是唯一的问题,并且我的密钥库很好。

However, I can't use this approach for our actual webservice client, since that uses the Sun RPC lib, and connecting happens somewhere deep inside their code, so I can't touch it.

但是,我不能将这种方法用于我们实际的 web 服务客户端,因为它使用 Sun RPC 库,并且连接发生在他们代码深处的某个地方,所以我无法触及它。

采纳答案by dave_thompson_085

First, yes, the exception says the Java SSL module in your machine doesn't trust the proof of identity (certificate) received from the server.

首先,是的,异常表明您机器中的 Java SSL 模块不信任从服务器收到的身明(证书)。

Yes, Java 7 does stricter checking. There may be more, but the one I'm sure of is that it doesn't allow the validity period of a child cert to end after the parent/CA cert (or begin before, but in practice that doesn't happen). See PKIX Path does not chain with any of the trust anchors error in Windows Environmentwhich says it is a bug and will be fixed.

是的,Java 7 进行了更严格的检查。可能还有更多,但我确定的是,它不允许子证书的有效期在父/CA 证书之后结束(或在此之前开始,但实际上不会发生)。请参阅PKIX 路径不与 Windows 环境中的任何信任锚错误链接,该错误表示这是一个错误,将被修复。

To check: if the server is a webserver, you could access any (harmless) page with a browser and use that to look at the cert chain. Otherwise, run openssl s_client -connect $host:443 -showcertsand once it connects enter EOF (Unix ^D, Windows ^Z), then put each ----BEGIN CERT...to -----END CERT...block in a different file and run openssl x509 -noout -subject -issuer -startdate -enddateon each in order.

要检查:如果服务器是网络服务器,您可以使用浏览器访问任何(无害的)页面并使用它来查看证书链。否则,运行openssl s_client -connect $host:443 -showcerts,一旦连接输入EOF(Unix的^ d时,Windows ^ Z),然后把每----BEGIN CERT...-----END CERT...一个不同的文件块,并运行openssl x509 -noout -subject -issuer -startdate -enddate在每个秩序。

To fix: if this is the problem, there doesn't seem to be any way to turn it off directly, except by turning off all cert checking (and thus losing some of the security of SSL), but adding the server entity cert to your truststore should work because then Java doesn't verify the chain. (You don't need to remove what's already there, just use an alias that isn't already in use.) Good luck.

修复:如果这是问题,似乎没有任何方法可以直接关闭它,除非关闭所有证书检查(从而失去 SSL 的一些安全性),但将服务器实体证书添加到您的信任库应该可以工作,因为 Java 不会验证链。(您无需删除已经存在的内容,只需使用尚未使用的别名即可。)祝您好运。