Tomcat 9 服务器:javax.net.ssl.SSLHandshakeException:空服务器证书链

Tomcat 9 server: javax.net.ssl.SSLHandshakeException: Empty server certificate chain

我正在尝试与安装在本地计算机上的 tomact 服务器建立 ssl 连接。 server.xml 包含以下条目:

<Connector
       protocol="org.apache.coyote.http11.Http11NioProtocol"
       port="8443" maxThreads="200"
       scheme="https" secure="true" SSLEnabled="true"
       sslImplementationName="localSSLImplementation keystoreFile="~/localhost.p12" 
       keystorePass="myPassword"
       keystoreType="PKCS12"
       
       truststoreFile="~/truststore.p12"
       truststorePass="changeit"
       truststoreType="PKCS12"
       truststoreProvider="SUN"
       clientAuth="required" sslProtocol="TLS"  sslEnabledProtocols="TLSv1.1,TLSv1.2"/>

我在 localhost.p12

上有一个自签名证书和私有-public 密钥对

我导出了此证书并将其导入到 truststore.p12 中,其中也包含从 JRE 的 cacerts 导入的条目。

现在,当设置 clientAuth="optional" 时,我可以无缝连接到 tomcat 服务器,但我可以在我的 eclipse 中看到 tomcat 的堆栈跟踪,如下所示:

javax.net.ssl|DEBUG|15|https-jsse-nio-8443-exec-6|2021-04-22 12:43:24.104 IST|Alert.java:238|Received alert message (
"Alert": {
  "level"      : "fatal",
  "description": "certificate_unknown"
}
)
javax.net.ssl|DEBUG|14|https-jsse-nio-8443-exec-5|2021-04-22 12:43:24.104 IST|Alert.java:238|Received alert message (
"Alert": {
  "level"      : "fatal",
  "description": "certificate_unknown"
}
)
javax.net.ssl|ERROR|15|https-jsse-nio-8443-exec-6|2021-04-22 12:43:24.106 IST|TransportContext.java:341|Fatal (CERTIFICATE_UNKNOWN): Received fatal alert: certificate_unknown (
"throwable" : {
  javax.net.ssl.SSLHandshakeException: Received fatal alert: certificate_unknown
    at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131)
    at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:117)
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:336)
    at java.base/sun.security.ssl.Alert$AlertConsumer.consume(Alert.java:293)
    at java.base/sun.security.ssl.TransportContext.dispatch(TransportContext.java:185)
    at java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:171)
    at java.base/sun.security.ssl.SSLEngineImpl.decode(SSLEngineImpl.java:681)
    at java.base/sun.security.ssl.SSLEngineImpl.readRecord(SSLEngineImpl.java:636)
    at java.base/sun.security.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:454)
    at java.base/sun.security.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:433)
    at java.base/javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:637)
    at org.apache.tomcat.util.net.SecureNioChannel.handshakeUnwrap(SecureNioChannel.java:511)
    at org.apache.tomcat.util.net.SecureNioChannel.handshake(SecureNioChannel.java:243)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1685)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.base/java.lang.Thread.run(Thread.java:829)}

)
javax.net.ssl|ERROR|14|https-jsse-nio-8443-exec-5|2021-04-22 12:43:24.106 IST|TransportContext.java:341|Fatal (CERTIFICATE_UNKNOWN): Received fatal alert: certificate_unknown (
"throwable" : {
  javax.net.ssl.SSLHandshakeException: Received fatal alert: certificate_unknown
    at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131)
    at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:117)
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:336)
    at java.base/sun.security.ssl.Alert$AlertConsumer.consume(Alert.java:293)
    at java.base/sun.security.ssl.TransportContext.dispatch(TransportContext.java:185)
    at java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:171)
    at java.base/sun.security.ssl.SSLEngineImpl.decode(SSLEngineImpl.java:681)
    at java.base/sun.security.ssl.SSLEngineImpl.readRecord(SSLEngineImpl.java:636)
    at java.base/sun.security.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:454)
    at java.base/sun.security.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:433)
    at java.base/javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:637)
    at org.apache.tomcat.util.net.SecureNioChannel.handshakeUnwrap(SecureNioChannel.java:511)
    at org.apache.tomcat.util.net.SecureNioChannel.handshake(SecureNioChannel.java:243)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1685)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.base/java.lang.Thread.run(Thread.java:829)}

)
javax.net.ssl|ALL|16|https-jsse-nio-8443-exec-7|2021-04-22 12:43:24.116 IST|X509Authentication.java:295|No X.509 cert selected for EC
javax.net.ssl|ALL|19|https-jsse-nio-8443-exec-10|2021-04-22 12:43:24.151 IST|X509Authentication.java:295|No X.509 cert selected for EC
javax.net.ssl|ALL|18|https-jsse-nio-8443-exec-9|2021-04-22 12:43:24.187 IST|SSLEngineImpl.java:752|Closing outbound of SSLEngine
javax.net.ssl|WARNING|18|https-jsse-nio-8443-exec-9|2021-04-22 12:43:24.188 IST|SSLEngineOutputRecord.java:168|outbound has closed, ignore outbound application data
javax.net.ssl|ALL|10|https-jsse-nio-8443-exec-1|2021-04-22 12:43:24.406 IST|SSLEngineImpl.java:752|Closing outbound of SSLEngine
javax.net.ssl|ALL|13|https-jsse-nio-8443-exec-4|2021-04-22 12:43:24.432 IST|SSLEngineImpl.java:752|Closing outbound of SSLEngine
javax.net.ssl|ALL|13|https-jsse-nio-8443-exec-4|2021-04-22 12:43:24.433 IST|SSLEngineImpl.java:752|Closing outbound of SSLEngine
javax.net.ssl|ALL|11|https-jsse-nio-8443-exec-2|2021-04-22 12:43:24.438 IST|SSLEngineImpl.java:752|Closing outbound of SSLEngine
javax.net.ssl|ALL|11|https-jsse-nio-8443-exec-2|2021-04-22 12:43:24.441 IST|SSLEngineImpl.java:752|Closing outbound of SSLEngine

问题 1:- 我不知道是否应该发生这种情况,因为我在 truststoreFile

中指定了相同的证书

问题 2:- 如果我更改 clientAuth="required",这是我打算做的,我观察到跟踪堆栈跟踪以及 chrome 中的警告。

stackTrace:-

avax.net.ssl|ALL|11|https-jsse-nio-8443-exec-2|2021-04-22 12:48:16.627 IST|X509Authentication.java:295|No X.509 cert selected for EC
javax.net.ssl|ALL|10|https-jsse-nio-8443-exec-1|2021-04-22 12:48:16.627 IST|X509Authentication.java:295|No X.509 cert selected for EC
javax.net.ssl|DEBUG|14|https-jsse-nio-8443-exec-5|2021-04-22 12:48:16.660 IST|Alert.java:238|Received alert message (
"Alert": {
  "level"      : "fatal",
  "description": "certificate_unknown"
}
)
javax.net.ssl|DEBUG|15|https-jsse-nio-8443-exec-6|2021-04-22 12:48:16.660 IST|Alert.java:238|Received alert message (
"Alert": {
  "level"      : "fatal",
  "description": "certificate_unknown"
}
)
javax.net.ssl|ERROR|14|https-jsse-nio-8443-exec-5|2021-04-22 12:48:16.662 IST|TransportContext.java:341|Fatal (CERTIFICATE_UNKNOWN): Received fatal alert: certificate_unknown (
"throwable" : {
  javax.net.ssl.SSLHandshakeException: Received fatal alert: certificate_unknown
    at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131)
    at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:117)
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:336)
    at java.base/sun.security.ssl.Alert$AlertConsumer.consume(Alert.java:293)
    at java.base/sun.security.ssl.TransportContext.dispatch(TransportContext.java:185)
    at java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:171)
    at java.base/sun.security.ssl.SSLEngineImpl.decode(SSLEngineImpl.java:681)
    at java.base/sun.security.ssl.SSLEngineImpl.readRecord(SSLEngineImpl.java:636)
    at java.base/sun.security.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:454)
    at java.base/sun.security.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:433)
    at java.base/javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:637)
    at org.apache.tomcat.util.net.SecureNioChannel.handshakeUnwrap(SecureNioChannel.java:511)
    at org.apache.tomcat.util.net.SecureNioChannel.handshake(SecureNioChannel.java:243)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1685)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.base/java.lang.Thread.run(Thread.java:829)}

)
javax.net.ssl|ERROR|15|https-jsse-nio-8443-exec-6|2021-04-22 12:48:16.662 IST|TransportContext.java:341|Fatal (CERTIFICATE_UNKNOWN): Received fatal alert: certificate_unknown (
"throwable" : {
  javax.net.ssl.SSLHandshakeException: Received fatal alert: certificate_unknown
    at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131)
    at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:117)
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:336)
    at java.base/sun.security.ssl.Alert$AlertConsumer.consume(Alert.java:293)
    at java.base/sun.security.ssl.TransportContext.dispatch(TransportContext.java:185)
    at java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:171)
    at java.base/sun.security.ssl.SSLEngineImpl.decode(SSLEngineImpl.java:681)
    at java.base/sun.security.ssl.SSLEngineImpl.readRecord(SSLEngineImpl.java:636)
    at java.base/sun.security.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:454)
    at java.base/sun.security.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:433)
    at java.base/javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:637)
    at org.apache.tomcat.util.net.SecureNioChannel.handshakeUnwrap(SecureNioChannel.java:511)
    at org.apache.tomcat.util.net.SecureNioChannel.handshake(SecureNioChannel.java:243)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1685)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.base/java.lang.Thread.run(Thread.java:829)}

)
javax.net.ssl|ALL|16|https-jsse-nio-8443-exec-7|2021-04-22 12:48:16.669 IST|X509Authentication.java:295|No X.509 cert selected for EC
javax.net.ssl|ERROR|18|https-jsse-nio-8443-exec-9|2021-04-22 12:48:16.680 IST|TransportContext.java:341|Fatal (BAD_CERTIFICATE): Empty server certificate chain (
"throwable" : {
  javax.net.ssl.SSLHandshakeException: Empty server certificate chain
    at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131)
    at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:117)
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:336)
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:292)
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:283)
    at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.onCertificate(CertificateMessage.java:390)
    at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.consume(CertificateMessage.java:375)
    at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:392)
    at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:443)
    at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1074)
    at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1061)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask.run(SSLEngineImpl.java:1008)
    at org.apache.tomcat.util.net.SecureNioChannel.tasks(SecureNioChannel.java:455)
    at org.apache.tomcat.util.net.SecureNioChannel.handshakeUnwrap(SecureNioChannel.java:519)
    at org.apache.tomcat.util.net.SecureNioChannel.handshake(SecureNioChannel.java:243)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1685)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.base/java.lang.Thread.run(Thread.java:829)}

)
javax.net.ssl|WARNING|18|https-jsse-nio-8443-exec-9|2021-04-22 12:48:16.682 IST|SSLEngineOutputRecord.java:168|outbound has closed, ignore outbound application data

Text Displayed in chrome:- 当我尝试连接到 https://localhost:8443

This site can’t provide a secure connectionlocalhost didn’t accept your login certificate, or one may not have been provided.
Try contacting the system admin.
ERR_BAD_SSL_CLIENT_AUTH_CERT

如果我尝试通过 ssl 客户端建立连接,我会看到以下错误:

SSL handshake has read 16672 bytes and written 388 bytes
Verification error: self signed certificate

============================================= =========================== Editing this post

Dave 的评论部分确实帮助我解决了我的第二个问题,在这种情况下,我将自签名证书添加到 chrome。

但是对于第一个问题,我仍然能够在 tomcat 服务器的日志堆栈跟踪中看到与我发布的第一个堆栈跟踪完全相似的堆栈跟踪。所以现在我的查询是因为我在服务器的信任库中导入了相同的根,该根已签署了我的客户端证书。那么,为什么每当我建立从客户端到服务器的连接时,我都会在堆栈跟踪中看到 javax.net.ssl.SSLHandshakeException: Received fatal alert: certificate_unknown

参考 Dave 的评论。我刚刚发现我看到的堆栈跟踪 certificate_unknown 是因为客户端不信任我的服务器证书,这是一个自签名证书。 所以这很正常,因为我的浏览器不信任本地证书。如果它是由授权的 CA 签名的,那么问题就解决了。