繁体   English   中英

使用trustStore时,HTTPS证书验证失败

[英]HTTPS certificate validation fails when using a trustStore

我收到以下错误

sun.security.validator.ValidatorException:PKIX路径构建失败:sun.security.provider.certpath.SunCertPathBuilderException:无法找到请求目标的有效证书路径

当连接谷歌地图地理编码API时。 我能够在一个简单的主程序中重现错误。 以下是使用此测试程序重现它的方法:

import javax.net.ssl.*;
import java.net.*;
import java.io.*;

public class Main {

    public static void main(String[] args) {
        try {
            String httpsURL = "https://maps.googleapis.com/maps/api/geocode/json?address=49+874%2Cla+plata%2Cbuenos+aires%2Cargentina&sensor=false&key=AIzaSyAJ1QS0C6KjiWajwxx4jUb_Jz0b8lBZyyE";
            URL myurl = new URL(httpsURL);
            HttpsURLConnection con = (HttpsURLConnection) myurl.openConnection();
            InputStream ins = con.getInputStream();
            InputStreamReader isr = new InputStreamReader(ins);
            BufferedReader in = new BufferedReader(isr);
            String inputLine;
            while ((inputLine = in.readLine()) != null) {
                System.out.println(inputLine);
            }
            in.close();
        } catch (IOException ex) {
            System.err.println(ex.getMessage());
        }
    }
}

保存为Main.java编译它

javac Main.java

运行

java Main

我得到了正常的结果(打印了json响应)。

但是,如果我从这里创建一个带有证书的TrustStore: https ://www.clic.gob.ar/我下载了SSL证书并将其保存为名为clic.gob.ar的X.509 PEM文件

创建一个名为keystorefede.jks的新TrustStore

keytool -import -file clic.gob.ar -alias clicCert -keystore keystorefede.jks

我给了它密码tompass。 我可以列出来

keytool -list -keystore keystorefede.jks -storepass tompass

TipodeAlmacéndeClaves:JKS ProveedordeAlmacéndeClaves:SUN

Sualmacéndeclaves contiene 1 entrada

cliccert,01/08/2014,trustedCertEntry,Huella Digital de Certificado(SHA1):15:3B:67:EE:51:C9:F2:CF:68:7C:24:51:A4:B6:6E:AE: EA:61:D5:B5

现在使用trustStore运行相同的程序

java -Djavax.net.ssl.trustStore=/home/fede/keystorefede.jks -Djavax.net.ssl.trustStorePassword=tompass Main sun.security.validator.ValidatorException:PKIX路径构建失败:sun.security.provider.certpath。 SunCertPathBuilderException:无法找到请求目标的有效证书路径

Java 8和Java 7都会发生这种情况。

java版“1.8.0_11”

Java(TM)SE运行时环境(版本1.8.0_11-b12)

Java HotSpot(TM)64位服务器VM(内置25.11-b03,混合模式)

该问题最初是在Tomcat内部运行的Web应用程序中发现的。 证书必须在Tomcat的命令行中的TrustStore中用于另一个请求; 信任商店没有谷歌相关的,只有一个证书。 如果我将Google的证书添加到信任存储区,那么问题就解决了,但这不是一个合适的解决方案。 Google不接受使用API​​密钥通过http进行地理编码请求。 -Djavax.net.ssl.trustStore覆盖所有根CA的Java知道吗?

实际上,javax.net.ssl.trustStore属性会使用您提供的JVM覆盖JVM的所有已知证书。

默认情况下,JVM附带一个trustStore,预先填充了相当多的众所周知的权限(Oracle JVM将其存储在JAVA_HOME / jre / lib / security / cacerts中)。

默认情况下,此keyStore将被JSSE(Java安全套接字扩展)用作默认值,以验证SSL握手。

javax.net.ssl.trustStore环境变量会覆盖此默认位置,这意味着其内容不再相关。

展望未来,您有几个解决方案:
一个是:你建立自己的JKS,包含你需要的一切。
其次是:您将证书添加到JVM的默认文件中。
第三是:你编码。

“手动”获取自己的SSL上下文?

底层HTTPURLConnection的套接字由SocketFactory实例构成。 当涉及HTTPS时,会发生的情况是您需要使用监视器初始化您自己的SSLSocketFactory,并且在连接之前将SocketFactory与HTTPURLConnection关联起来:请参阅http://docs.oracle.com/ JavaSE的/ 7 /文档/ API /的javax /净/ SSL / HttpsURLConnection.html#setSSLSocketFactory%28javax.net.ssl.SSLSocketFactory%29

这是这样的。 首先,您需要加载KeyStore(包含证书的JKS文件,用于缩短的异常处理):

InputStream keyStoreStream = ... // Wherever it is
KeyStore ks = KeyStore.getInstance("JKS"); // or "PKCS12" for pfx/p12
ks.load(is, password);

获得KeyStore实例后,您可以构建一个“TrustManager”,它将使用在Keystore中声明为受信任的任何证书作为有效的信任锚。

TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); // PKIX
tmf.init(yourKeyStore); // if you pass null, you get the JVM defaults
                        // which is CACerts file or javax.net.ssl.trustStore

您可以对SSL KeyManagerFactory执行相同的操作(如果使用双向SSL),则模式完全相同。 一旦有了TrustManagerFactory和KeyManagerFactory实例,就可以构建一个SSLSocketFactory。

  SSLContext sslCtx = SSLContext.getInstance("TLS");
  sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
  SSLSocketFactory sslSF = sslCtx.getSocketFactory();

此时,你可以做到

  URL url = new URL("https://test.com/test");
  URLConnection conn = url.openConnection();
  if(conn instanceof HttpsURLConnection) {
    ((HttpsURLConnection) conn).setSSLSocketFactory(sslSF);
  }
  conn.connect();

该应用程序找不到合适的信任库。 您可以通过以下方式定义它: System.setProperty("javax.net.ssl.trustStore", ".\\\\src\\\\truststore.jks"); System.setProperty("javax.net.ssl.trustStorePassword", "psw123"); System.setProperty("javax.net.ssl.trustStore", ".\\\\src\\\\truststore.jks"); System.setProperty("javax.net.ssl.trustStorePassword", "psw123");

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM