Java 7(作为客户端)使用在Java 6中工作的密钥库和信任库时SSL握手失败

14

我正在进行JBoss AS 5.1到7.4以及Java 6到7的迁移,但出现了握手失败的问题。

密钥库和信任库是我们长期以来一直使用的Java 6版本成功的那些。

我编写了一些测试来缩小问题范围,问题肯定不在于JBoss而是Java 7。

启用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)

有一些讨论这个(或类似)问题的线程,人们建议使用不同的参数重新创建证书或信任存储库。我不想走这条路,因为我最近曾尝试为相同的webservice的不同帐户创建更多的密钥库和信任存储库,但没有成功。

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

看起来问题可能是由于Java 7在检查信任存储库证书链方面更加严格引起的?

是否可以设置一些标志放松检查,使其像Java 6一样运行?

我不确定如何解释失败消息:我认为它告诉我,不满足远程机器是安全的条件是我的计算机而不是远程服务器。这正确吗?

任何帮助/想法都将不胜感激!

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

按照建议,已将PEM(带有链)添加到信任存储库中,从Firefox访问WS URL时导出。这并没有让它握手成功,但稍微改变了失败情况。

***
%% 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)

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

同时,如其他帖子中所建议的那样,我编写了另一个测试程序,使用了不验证证书链的TrustManager,并使用了我的原始信任库运行了该测试。

这个测试程序能够连接成功,从而表明我的机器对远程机器的验证是唯一的问题,而我的密钥库是正常的。

然而,我无法在我们实际的Web服务客户端中使用这种方法,因为它使用Sun RPC lib,连接操作发生在其代码的深处,所以我无法接触它。

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


请编辑您的问题,包括 openssl s_client -connect <server>:<port> 的输出。 - jww
1个回答

13

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

是的,Java 7执行更严格的检查。可能还有其他情况,但我肯定其中一个是它不允许子证书的有效期在父/CA证书之后结束(或在其之前开始,但实际上这种情况不会发生)。请参见PKIX路径不与Windows环境中任何信任锚点错误链接,该错误被视为bug,并将得到修复。

检查方法:如果服务器是web服务器,则可以使用浏览器访问任何(无害的)页面,并使用该页面查看证书链。否则,请运行openssl s_client -connect $host:443 -showcerts,并一旦连接输入EOF(Unix ^D,Windows ^Z),然后将每个----BEGIN CERT...-----END CERT...块放入不同的文件中,并按顺序运行openssl x509 -noout -subject -issuer -startdate -enddate

解决方法:如果问题出在此处,除了关闭所有证书检查(从而失去SSL的某些安全性)外,似乎没有直接关闭它的方法,但将服务器实体证书添加到信任存储库应该有效,因为此时Java不会验证链条。(您无需删除已经存在的内容,只需使用尚未使用的别名即可。)祝你好运。


当我在Firefox中访问Web服务URL时,在“页面信息”、“网站身份验证”中,我可以查看该站点的证书并导出它。这是你指的“服务器实体证书”吗?Firefox允许我将其导出为X.509 PEM、带链的X.509 PEM、X.509 DER、X.509 PKCS#7、带链的X.509 PKCS#7。这些选项在转换后会产生相同的结果吗,还是重要避免特定格式以避免信息丢失?导出“带链”是否重要,或者应该不带链? - stupor-mundi
关于链接中建议的一些检查细节是一个 bug,并且在 Java 8 中已经修复,我已经从 Ubuntu 的 webup8 ppa 下载了最新的 Java 8,并且得到了与 Java 7 中显示的完全相同的失败。 - stupor-mundi
@stupor 是的,浏览器首先显示的证书(如果您切换到完整链路,则在底部)是服务器证书,如果您直接信任它,Java将避免该错误。 keytool 可以读取 X.509PEM 或 X.509DER。 在其他情况下,keytool 还可以读取 PKCS#7 链,但是您不需要在此处使用链,因为 trustedCert 条目仅使用单个证书。 #23775155 表示“预计发布日期为 2014 年 10 月”,而 8u20 绝对还没有发布; Oracle 在 7 月份发布了 8u11(安全性)。 - dave_thompson_085
当我第一次尝试将服务器实体证书添加到信任存储时,似乎没有帮助。然而,在此期间,WS操作员不情愿地向我们提供了更多信息,包括关键事实,即他们在不同子域上备有多个Web服务副本,并由不同的证书支持。几周前,当我尝试这些建议时,它们失败了,因为我混合了子域。现在我再次尝试,将实体证书添加到信任存储解决了问题!谢谢Dave! - stupor-mundi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接