DAC
DAC

Reputation: 251

Need help running Spring restTemplate with cert files - unable to find valid certification path to requested target

I was looking for some help to solve the following problem where I am attempting to make a rest call from java via restTemplate with a jks. I looked all around and cannot figure out why this does not work.

So from my server I have a crt and key file with password. If I make the following curl call to the server everything works fine, it retrieves the info i need.

curl --key example.key --cert example.crt:certpassword --digest --user user:password https://myhost/user?id={url_encoded_id}

When I attempt to run this from java via Spring, I created jks files as follows:

keytool -import -file example.crt -alias exampleCA -keystore truststore.jks

openssl pkcs12 -export -in example.crt -inkey example.key -certfile example.crt -name "examplecert" -out keystore.p12

keytool -importkeystore -srckeystore keystore.p12 -srcstoretype pkcs12 -destkeystore keystore.jks -deststoretype JKS

I then wrote the following java code to use the jks:

HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Authorization", basicAuthValueForUser);
httpHeaders.setContentType(MediaType.APPLICATION_JSON);

String keystore = "<path>\\keystore.jks";
String truststore = "<path>\\truststore.jks";
String certPassPhrase = "certpassword";

SSLContext sslContext = SSLContextBuilder
        .create()
        .loadKeyMaterial(ResourceUtils.getFile(keystore), certPassPhrase.toCharArray(), certPassPhrase.toCharArray())
        .loadTrustMaterial(ResourceUtils.getFile(truststore), certPassPhrase.toCharArray())
        .build();

HttpClient client = HttpClients.custom()
        .setSSLContext(sslContext)
        .build();

HttpComponentsClientHttpRequestFactory factory =
        new HttpComponentsClientHttpRequestFactory(client);

RestTemplate restTemplate = new RestTemplate(factory);

ResponseEntity<String> exchange = restTemplate.exchange("https://myhost/user?id={url_encoded_id}",
        HttpMethod.GET, new HttpEntity<>("", httpHeaders), String.class);

When i attempt to run this I get the following error:

Exception in thread "main" org.springframework.web.client.ResourceAccessException: I/O error on GET request for "https://myhost/user": 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
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:666)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:613)
    at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:531)
    at eid.test.restTest.main(restTest.java:49)
Caused by: 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
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
    at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1959)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1514)
    at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216)
    at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1026)
    at sun.security.ssl.Handshaker.process_record(Handshaker.java:961)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1072)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1385)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1413)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1397)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:394)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:353)
    at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:141)
    at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:353)
    at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:380)
    at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236)
    at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
    at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
    at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
    at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:55)
    at org.springframework.http.client.HttpComponentsClientHttpRequest.executeInternal(HttpComponentsClientHttpRequest.java:89)
    at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48)
    at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:53)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:652)
    ... 3 more
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:397)
    at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:302)
    at sun.security.validator.Validator.validate(Validator.java:260)
    at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
    at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)
    at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1496)
    ... 26 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
    at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:392)
    ... 32 more

Any help would be appreciated!!

Upvotes: 2

Views: 8198

Answers (2)

Harish Vutukuri
Harish Vutukuri

Reputation: 1150

  1. Download Certificate(.cer) of the site from browser.
  2. Place the file in $JAVA_HOME\Java\jdk-11.0.3\lib\security
  3. Install the certificate with following command:
keytool -import -noprompt -trustcacerts -alias <alias_name> -file  <filename.cer> -keystore $JAVA_HOME\Java\jdk-11.0.3\lib\security\cacerts -storepass changeit

NOTE: replace <alias_name> and <filename.cer> as per your needs.

  1. Check if the certificate is installed from the List.
keytool -list -keystore $JAVA_HOME\jdk-11.0.3\lib\security\cacerts

Upvotes: 0

DAC
DAC

Reputation: 251

After some more testing and research, turns out my truststore was missing a cert that it needed to complete the chain.

I had to open a browser, go to https://myhost, download the cert (crt) file from the server and add it to my truststore.jks After this the error was cleared and i could make the call.

Upvotes: 1

Related Questions