【发布时间】:2018-12-28 17:57:51
【问题描述】:
我们有一个调用第三方的 Java 小程序(在 tomcat 下运行)。其中之一使用客户端证书进行身份验证。这在 Java 8 下工作,但我们最近将系统升级到 Java 11,但它不再可用。错误是
不支持的握手消息:server_hello_done
(这很奇怪,因为我认为 server_hello_done 是握手的有效部分)
我们在升级后确实遇到了 java 密钥库的问题。该服务失败,说它不是有效的 PCKS12 流。使用 keytool 列出内容有效,但有警告
警告:
JKS 密钥库使用专有格式。建议使用“keytool -importkeystore -srckeystore /path/to/keystore -destkeystore /path/to/keystore -deststoretype pkcs12”迁移到行业标准格式 PKCS12
我们使用了建议的命令,它现在可以正常打开密钥库,但我们收到握手错误。
回溯到我们代码的堆栈跟踪是:
Unsupported handshake message: server_hello_done
javax.net.ssl.SSLProtocolException: Unsupported handshake message: server_hello_done
at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:126)
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:321)
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:264)
at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:446)
at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:421)
at java.base/sun.security.ssl.TransportContext.dispatch(TransportContext.java:178)
at java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:164)
at java.base/sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1152)
at java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1063)
at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:402)
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:396)
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:355)
at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:142)
at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:359)
at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:381)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:237)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:185)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:111)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108)
我们使用的是 apache http 客户端 (org.apache.http.impl.client.CloseableHttpClient)。堆栈跟踪中的下一行只是在我们的代码中调用client.execute()。
还包括
Caused by: java.lang.UnsupportedOperationException: Not supported yet.
at java.base/sun.security.ssl.HandshakeHash$CloneableHash.archived(HandshakeHash.java:616)
at java.base/sun.security.ssl.HandshakeHash$T12HandshakeHash.archived(HandshakeHash.java:546)
at java.base/sun.security.ssl.HandshakeHash.archived(HandshakeHash.java:188)
at java.base/sun.security.ssl.CertificateVerify$T12CertificateVerifyMessage.<init>(CertificateVerify.java:581)
at java.base/sun.security.ssl.CertificateVerify$T12CertificateVerifyProducer.produce(CertificateVerify.java:740)
at java.base/sun.security.ssl.SSLHandshake.produce(SSLHandshake.java:436)
at java.base/sun.security.ssl.ServerHelloDone$ServerHelloDoneConsumer.consume(ServerHelloDone.java:173)
at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:392)
at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:444)
第三方确认他们在日志中看到“没有共享密码”,但表示他们支持广泛的密码(“SSL3、TLS 1.0、1.1 或 1.2。密码被标记为 HIGH:MEDIUM: !aNULL:!eNULL:@STRENGTH")。我认为我们支持除了 SSL3 之外的大部分内容。据我所知,我们在 java 11 中有默认设置。尝试暂时激活 SSLv3 但无法连接(尽管因为尝试我无法从那台机器连接(超时)即使在恢复后,所以这可能没什么好说的 - 我尝试从测试机器而不是生产机器那个)。
有什么想法吗?我是否在正确的路线上继续查看密码或者我缺少什么?
【问题讨论】:
-
TLS 1.3,刚刚在 8 月完成并由 Java 11 实现,不再使用 server_hello_done。但是,这似乎是一个 1.2 连接(与“第三方”所说的一致),并且从堆栈跟踪来看,问题不是 SHD,而是几个步骤后,计算客户端身份验证签名(使异常消息有点误导)。从密码字符串格式来看,服务器是 OpenSSL 或像 Libre 这样的分叉,我无法使用 Java 11.0.1 (Oracle Win64) 复制到 OpenSSL 1.0.2(d) 或 1.1.0(-)(都是 ShiningLight)。 ...
-
... 不要使用 SSL3,它已经被严重破坏了好几年(并且是协议或版本而不是密码 [套件])。您可能尝试 TLS1.1 或 1.0 而不是 1.2;他们使用稍微不同的客户端身份验证签名算法,至少在问题附近。更改密码无济于事;这根本不会影响握手的这一部分,如果“他们没有看到共享密码”,他们正在寻找错误的东西。但我怀疑这是一个 Java 错误,我没有设置调试 11,抱歉。
-
是的,我不打算使用 SSLv3,我只是在绝望中尝试激活它 :) 使用 openssl 命令行客户端谈论了很多关于 SSL3 的内容,但最终得到了 TLS1.2 连接