Search code examples
javaspringssl-certificateresttemplate

Why am I getting a SunCertPathBuilderException when trying to consume data via REST API?


I try to consume a REST API via a Rest template. I add its certificate in my trust store but I have an Exception.

The cert DN is: *.domain.com and I try GET https://api.domain.com

the stack trace:

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:323)
    at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:217)
    at sun.security.validator.Validator.validate(Validator.java:218)
    at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:126)
    at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:209)
    at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:249)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1284)
    ... 56 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:174)
    at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:238)
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:318)
    ... 62 more

My service method

 HttpHeaders headers = new HttpHeaders();
        headers.add("Accept", "application/json");
        headers.add("Content-Type", "application/json");
        headers.add("authorization", "Bearer " + token);
        HttpEntity request = new HttpEntity(headers);
        ResponseEntity<String> response = restTemplate.exchange(
                https://api.domain.com,
                HttpMethod.GET,
                request,
                String.class,
                1
        );
        System.out.println(response.getStatusCode());

Have you some idea why this is happening?


Solution

  • Sounds like X509TrustManagerImpl has problems to accept the certificate. This can happen when the TLS certificate is not from a trusted source (e.g. self-signed or just not accepted by java trust store).

    I would try to execute your code with another (newer) JDK - e.g. Oracle or Amazon Coretto, where trust stores are maintained and up-to-date.

    When it works with other, newer JDK...

    If this works - TLS certificate seems to be valid. If you need to use your JDK (e.g. license issues) you could import certificate into your local trust store.

    When it also not works with other, newer JDK...

    If this does not work... Look at the certificate and check if it's really trustful... Maybe a security issue... e.g. man in the middle attack (or just a company proxy making odd things with certificates...)

    Or ... its just a self signed certificate, e.g. used on a test server. If you are really, really sure that you can trust a self signed certificate (e.g. when its your own test server), you can either import it into your trust store, or make a TRUST_ALL approach like done in : https://github.com/Daimler/sechub/blob/develop/sechub-adapter/src/main/java/com/daimler/sechub/adapter/support/TrustAllSupport.java

    But the correct way would be to just ensure certificates are trustful.