我想在 Java 中通过 HTTPS 连接调用一些 Web 服务。证书颁发机构给了我一个 PKCS12 文件,但我得到了一个
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
这是我正在执行的代码:
System.setProperty("javax.net.ssl.keyStoreType", "JKS");
System.setProperty("javax.net.ssl.keyStore", "path/toto2.jks");
System.setProperty("javax.net.ssl.keyStorePassword", "pwd");
System.setProperty("javax.net.ssl.trustStoreType", "JKS");
System.setProperty("javax.net.ssl.trustStore", "path/toto2.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "pwd");
System.setProperty("proxySet","true") ;
System.setProperty("https.proxyHost", "XXX") ;
System.setProperty("https.proxyPort", "XXX") ;
我首先尝试提供 PKCS12 文件,然后是 JKS,但我遇到了同样的错误。
我尝试了另一种解决方案,使用 curl。所以我从 PKCS12 中提取了证书并且请求成功了。
以下是我用来从 P12 中提取不同文件的命令:
openssl pkcs12 -in file.p12 -nocerts -nodes -out clientcert.key
openssl pkcs12 -in file.p12 -clcerts -nokeys -out clientcert.cer
openssl pkcs12 -in file.p12 -cacerts -nokeys -chain -out cacerts.cer
我在 Java 中使用这些文件的方式有误吗?
最佳答案
PKCS12 通常包含私钥和证书(链)组合,用于验证您的系统,即客户端,这是通过 javax.net.ssl.keyStore*
属性。您应该指定类型 PKCS12,尽管某些 Java8 版本(仅!)在您指定 JKS 时可以读取 PKCS12。
它通常不会对服务器进行身份验证,这是 javax.net.ssl.trustStore*
的用途,所以不要在那里使用它。根据服务器的不同,您可能需要也可能不需要不同于 P12 的自定义信任库,也不同于 Java 的默认值。
使用浏览器或其他工具(如 curl
或 keytool -printcert -sslserver host[:port]
查看服务器使用的证书链
并确定它是否使用公共(public)根 CA,如 Verisign-now-Symantec-now-Digicert 或 GoDaddy,它们已经在 Java 的默认信任库中,或者是“私有(private)”CA 甚至是自签名证书,在这种情况下你应该要么将该证书添加到默认信任库,要么如果您不能或不想修改您的 JVM,请将该证书放入您用作信任库的 keystore 文件中。
PS:ValidatorException
导致 SSLHandshakeException
而不是相反。
关于java - 在 Java 中使用证书进行 HTTPS 请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50598468/