浏览器接受的Java拒绝证书



我在Wildfly 9中配置有效证书(非自签名!)时遇到问题。我已经在Wildfly:中配置了HTTPS连接器

<https-listener name="https" socket-binding="https" security-realm="UndertowRealm" />

安全领域:

<security-realm name="UndertowRealm">
<server-identities>
<ssl>
<keystore path="domain.p12" relative-to="jboss.server.config.dir" keystore-password="password"
alias="appcert"  />
</ssl>
</server-identities>
</security-realm>

并使用以下命令生成密钥库:

openssl pkcs12-export-in-domain.crt-inkey domain.key-out domain.p12-name appcert-CAfile CAfile.crt-caname root

现在,当我在浏览器中打开应用程序时,一切都很好。浏览器将证书识别为有效证书,而不会像在自签名证书中那样提示异常。

然而,当我试图通过SSLPoke.java连接到同一个URL时,我会得到以下异常:

javax.net.ssl.ssl握手异常:sun.security.validator.ValidatorException:PKIX路径构建失败:sun.security.provider.certpath.SunCertPathBuilderException:无法找到到请求目标的有效证书路径在sun.security.ssl.Alerts.getSSLException(Alerts.java:192)在sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949)在sun.security.ssl.Handshaker.totalSE(Handshaker.java:302)在sun.security.ssl.Handshaker.totalSE(Handshaker.java:296)在sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1509)在sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216)在sun.security.ssl.Handshaker.processLoop(Handshaker.java:979)位于sun.security.ssl.Handshaker.process_record(Handshaker.java:914)位于sun.security.ssl.SSSLSocketImpl.readRecord(SSLSocketImpl.java:1062)在sun.security.ssl.SLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)位于sun.security.ssl.SSSLSocketImpl.writeRecord(SSLSocketImpl.java:747)位于sun.security.ssl.AppOutputStream.write(AppOutputStream.java:123)在sun.security.ssl.AppOutputStream.write(AppOutputStream.java:138)在SSLPoke.main(SSLPoke.java:26)由以下原因引起:sun.security.validator.ValidatorException:PKIX路径生成失败:sun.scurity.provider.certpath.SunCertPathBuilderException:无法找到到请求目标的有效证书路径在sun.security.validator.PKIXFalidator.doBuild(PKIXValidator.java:387)在sun.security.validator.PIXValidator.engineValidate(PKIXValidator.java:292)在sun.security.validator.validate(validator.java:260)在sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)位于sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)位于sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509CrustManagerImpl.java:124)位于sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1491)…还有9个由以下原因引起:sun.security.provider.certpath.SunCertPathBuilderException:无法找到到请求目标的有效证书路径位于sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuildr.java:141)位于sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuildr.java:126)位于java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)在sun.security.validator.PIXValidator.doBuild(PKIXValidator.java:382)…还有15个

如果我在客户端导入证书,这个错误就会消失,但我认为我不应该这样做,因为这是一个有效的证书。

测试代码如下:

导入java.io.InputStream;导入java.io.OutputStream;导入javax.net.ssl.SSLSocket;导入javax.net.ssl.ssl SocketFactory;/**建立到主机和端口的SSL连接,写入一个字节和*打印响应。看见*http://confluence.atlassian.com/display/JIRA/Connecting+到+SSL+服务*/公共类SSLPoke{public static void main(String[]args){if(args.length!=2){System.out.println("用法:"+SSLPoke.class.getName()+");系统出口(1);}尝试{SSLSocketFactory sslocketfactory=(SSLSocketFactory)SSLSocketFactory.getDefault();SSLSocket sslocket=(SSLSocket)sslocketfactory.createSocket(args[0],Integer.parseInt(args[1]));InputStream in=sslocket.getInputStream();OutputStream out=sslocket.getOutputStream();//编写一个测试字节以获得反应:)out.write(1);while(in.available()>0){System.out.print(in.read());}System.out.println("已成功连接");}catch(异常异常){exception.printStackTrace();}}}

为什么会发生这种情况,设置SSL证书的正确方法是什么?

这里的问题是,默认情况下,Java附带的根CA证书非常有限。与典型的浏览器相比,它"接受"的CA要少得多。解决这个问题的最简单方法是从Chrome或Firefox等浏览器导出一组CA证书,并使用keytool将它们导入Java的密钥库。

之所以会发生这种情况,是因为Java信任库不信任链中的任何证书。

最通用的解决方案是将top证书(链中的最后一个,最顶层的签名者)导入JRE的lib/security/cacerts文件。

最新更新