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

37,502

Solution 1

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

    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);

Solution 2

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

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();
    }
}
Share:
37,502
nialloc
Author by

nialloc

Updated on July 22, 2022

Comments

  • nialloc
    nialloc almost 2 years

    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.

    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?

    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)
    
  • Darren Hague
    Darren Hague over 12 years
    You can write it anywhere you like, because it's making a static call on the SSLContext class itself. So long as you call it in the same classloader context and before the first HttpClient call then you should be good to go.
  • ptikobj
    ptikobj about 10 years
    Just to be sure: changing the TrustManager of an SSLContext as described above is not a persistent action, right? So it needs to be done each time the application is started.
  • Tim Holt
    Tim Holt over 6 years
    For reference, I had to import the following to use this... import javax.net.ssl.SSLContext; import javax.net.ssl.X509TrustManager; import java.security.cert.X509Certificate; import javax.net.ssl.TrustManager; import java.security.cert.CertificateException;