Java 为什么我找不到 SSL 握手的信任库?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1725863/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 21:55:17  来源:igfitidea点击:

Why can't I find the truststore for an SSL handshake?

javaspringtomcatrestssl

提问by nialloc

I'm using the Spring RESTTemplate on the client side to make calls to a REST endpoint. The client in this case is a Spring app and Tomcat is the servlet container.

我在客户端使用 Spring RESTTemplate 来调用 REST 端点。本例中的客户端是 Spring 应用程序,Tomcat 是 servlet 容器。

I'm running into issues making a connection to an HTTPS endpoint. I am receiving an error which indicates it cannot find a valid path to the truststore. Where can I specify this? Is this done at the container level or the application config (Spring) level?

我在连接到 HTTPS 端点时遇到问题。我收到一个错误,表明它找不到信任库的有效路径。我在哪里可以指定这个?这是在容器级别还是应用程序配置(Spring)级别完成的?

Stack trace:

堆栈跟踪:

org.springframework.web.client.ResourceAccessException: I/O error:
sun.security.validator.ValidatorException: PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException:
unable to find valid certification path to requested target;
nested exception is javax.net.ssl.SSLHandshakeException:
sun.security.validator.ValidatorException:
PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException:
unable to find valid certification path to requested target
org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:330)
org.springframework.web.client.RestTemplate.execute(RestTemplate.java:292)
org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:227)

采纳答案by Kevin

You need to properly configure the SSLContext which is done external to the RESTTemplate. This should get you started:

您需要正确配置在 RESTTemplate 外部完成的 SSLContext。这应该让你开始:

    String keystoreType = "JKS";
    InputStream keystoreLocation = null;
    char [] keystorePassword = null;
    char [] keyPassword = null;

    KeyStore keystore = KeyStore.getInstance(keystoreType);
    keystore.load(keystoreLocation, keystorePassword);
    KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
    kmfactory.init(keystore, keyPassword);

    InputStream truststoreLocation = null;
    char [] truststorePassword = null;
    String truststoreType = "JKS";

    KeyStore truststore = KeyStore.getInstance(truststoreType);
    truststore.load(truststoreLocation, truststorePassword);
    TrustManagerFactory tmfactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());

    KeyManager [] keymanagers = kmfactory.getKeyManagers();
    TrustManager [] trustmanagers =  tmfactory.getTrustManagers();

    SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(keymanagers, trustmanagers, new SecureRandom());
    SSLContext.setDefault(sslContext);

回答by Darren Hague

More specifically, calling this method will do the trick, so that any subsequent HttpClient calls will not care about SSL certificate validity:

更具体地说,调用此方法将起到作用,因此任何后续的 HttpClient 调用都不会关心 SSL 证书的有效性:

public static void trustSelfSignedSSL() {
    try {
        SSLContext ctx = SSLContext.getInstance("TLS");
        X509TrustManager tm = new X509TrustManager() {

            public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException {
            }

            public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException {
            }

            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };
        ctx.init(null, new TrustManager[]{tm}, null);
        SSLContext.setDefault(ctx);
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}