我有一台服务器在Dropwizard上运行(即为其web服务器运行Jetty)。我正在尝试为它设置SSL。
我有一个由CA(特别是Comodo,通过Namecheap)签署的证书。我安装了根证书和中间证书,然后安装了我自己的证书(使用Comodo支持上的说明。尽管如此,当我第一次尝试连接到我的服务器时(它启动良好),我得到了一个错误:sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
(当然堆栈跟踪要长得多,但这是根本原因。)
我尝试过搜索这个错误,人们总是说它只应该发生在自签名证书上,而我的不是。尽管如此,我还是尝试下载InstallCert.java程序,该程序似乎源于Sun博客上的一篇文章(现已删除)。具体来说,我是从这个页面上获得学位的。
经过几次(失败)尝试通过命令行使其工作(这是另一次的讨论),我最终使其正常运行。现在我从程序中得到的输出是:
Loading KeyStore C:Program FilesJavajdk1.8.0_05jrelibsecuritycacerts...
Opening connection to localhost:8443...
Starting SSL handshake...
Exception in thread "main" java.net.SocketTimeoutException: Read timed out
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:150)
at java.net.SocketInputStream.read(SocketInputStream.java:121)
at sun.security.ssl.InputRecord.readFully(InputRecord.java:465)
at sun.security.ssl.InputRecord.read(InputRecord.java:503)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:954)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1343)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1371)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1355)
at com.aw.ad.util.InstallCert.main(InstallCert.java:98)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
Process finished with exit code 1
同时,如果我用我的网站打开窗口,它会再次传递unable to find valid certification path to requested target
错误并崩溃(因此导致超时)。本质上,在我看来,InstallCerts(它应该可以解决我的SSL问题)由于SSL问题而导致我的服务器崩溃。
如果我尝试使用类似openssl s_client -connect localhost:8443 -showcerts
的东西(这是我在某个地方看到的一个建议,将结果保存到.pem文件中并安装它),同样的事情也会发生。
这个问题有解决办法吗?我是不是遗漏了一些显而易见的东西?
您可能缺少从Comodo根CA到站点证书的整个证书链。检查您在Dropwizard中配置的密钥库,看看您是否拥有所有密钥库。最简单的方法是查找证书的颁发者,您需要具有相同主题的证书,然后查找证书的发布者,依此类推。为了确保安全,请尝试将证书的颁发机构密钥标识符证书扩展与颁发者和颁发者的颁发者的密钥指纹(密钥标识符)链接起来。如果您提供
keytool -list -keystore <your keystore> -rfc
我也许能帮你更多。。。
稍后添加:
我已经设法准确地再现了你的问题。TL;DR;添加:
validateCerts: true
trustStorePath: lyonesgamer.com.keystore
enableCRLDP: true
我创建了一个包含链的密钥库(单个条目、3个证书、ca、从属ca和最终实体证书),以及另一个仅包含两个ca证书作为受信任条目的密钥库。然后我配置了keyStorePath
、keyStorePassword
、trustStorePath
和validateCerts: true
。
这导致:java.security.cert.CertificateException: Unable to validate certificate: unable to find valid certification path to requested target
添加-Djava.security.debug=certpath
后,我注意到吊销检查失败,事实上这是证书链失败的根本原因:
certpath: SunCertPathBuilder.depthFirstSearchForward(): validation failed:
java.security.cert.CertPathValidatorException: Could not determine revocation status
然后我记得,如果您不为CertPath API启用CRL分发点扩展使用,您需要自己指定CRL。幸运的是,Dropwizard有一个启用CRLDP:enableCRLDP: true
的选项。启用后,应用程序成功启动。
或者,您可以将CRL保存在一个文件中,并将crlPath
指向它。
经过这么长时间,我一直在追逐一个兔子洞。事实证明,问题是我(相当天真)在自己的电脑上测试这个。Dropwizard的验证发现了一个错误,因为证书只对我的域有效,而我的个人计算机不是该域的成员。因此它崩溃了,因为它无法验证。
我通过在Dropwizard配置文件中关闭validateCerts发现了这一点(我本以为我已经关闭了它,但显然没有)。Dropwizard启动良好,允许我连接。当我这样做的时候,Firefox给了我一个不受信任的连接错误,点击详细信息给了我更有用的信息:
localhost:8443 uses an invalid security certificate.
The certificate is only valid for the following names: lyonesgamer.com, www.lyonesgamer.com
(Error code: ssl_error_bad_cert_domain)
谢谢你,佐兰,非常感谢你的帮助。恐怕大部分都是徒劳的。