1

i try to request a local service with https without certificate check. But i got this execption.

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

here is a part of code:

try {
            RestTemplate restTemplate = new RestTemplate();
            HttpsURLConnection.setDefaultHostnameVerifier(
                    (hostname, session) -> hostname.equals("IPADDRESS"));
            responseEntity = restTemplate.exchange(url, HttpMethod.POST, httpEntity, String.class);
        } catch (HttpClientErrorException e) {
            LOGGER.error(e.toString());
        }

what is wrong here?

Roman C
  • 49,761
  • 33
  • 66
  • 176
emoleumassi
  • 4,881
  • 13
  • 67
  • 93

2 Answers2

1

This problem is due to incomplete trust path for the server certificate: the server certificate is probably not trusted by the client.

Usually the fix is to import the server certificate into the client trust store. The default trustStore is in jre/lib/security/cacerts but is is a better practice to use your own keystore

You can create an SSLSocketFactory and add to your connection before connecting or apply to all connections using the static method

 HttpsURLConnection.setDefaultSSLSocketFactory(sslFactory);

This is an example to create the socket factory

/* Load the keyStore that includes the server cert as a "trusted" entry. */
KeyStore keyStore = ... 
TrustManagerFactory tmf = 
  TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keyStore);
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, tmf.getTrustManagers(), null);
sslFactory = ctx.getSocketFactory();

Example of loading the keyStore

KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(trustStore, trustStorePassword);
trustStore.close();

The trust store can also be configured using system properties

 System.setProperty("javax.net.ssl.trustStore", "pathtoyourjavakeystorefile");
 System.setProperty("javax.net.ssl.trustStorePassword", "password");

The simplest way to create the key store file is using the GUI tool Portecle. New KeyStore > Import Trusted certificates

You can import the root certificate of the chain if you want to 'trust' all certificates from root, or import only the server certificate. For a self-signed certificate, import it directly

pedrofb
  • 37,271
  • 5
  • 94
  • 142
  • 1
    I disagree. Modifying the installed JRE is never a good idea - therefore this not the usual fix! Create a Java KeyStore file, create a TrustManager and initialize it using that KeyStore that is the usual and correct fix... – Robert Jun 19 '16 at 16:10
  • And you don't have to import the entire certificate chain. Just the head of it will do. – user207421 Jun 19 '16 at 16:26
  • @Robert, you're right. The recommended way should be using your truststore instead of overwriting cacerts. I update the answer – pedrofb Jun 19 '16 at 18:50
  • @EJP, you can import the root certificate or the server certificate depending if you want to 'trust' all CA certificates or only the certificate of your server. Also I am going to include your comment in the answer – pedrofb Jun 20 '16 at 05:44
  • 1
    @EJP+pedrofb: A *self-signed* cert *is* a root so there is no difference in that case. For a 'real' chain -- one with multiple certs -- Java can use as trust anchor any cert you choose along that chain. There is also the option to use the default SSL factory with sysprops `javax.net.ssl.trustStore{,Password,Type}` as needed. See JSSE Reference Guide in the javadoc. – dave_thompson_085 Jun 20 '16 at 09:11
1

Hy,

i resolved it with this code part:

private void disableCertificateVerification() {
        TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return null;
            }

            @Override
            public void checkClientTrusted(java.security.cert.X509Certificate[] arg0, String arg1)                  throws CertificateException {
            }

            @Override
            public void checkServerTrusted(java.security.cert.X509Certificate[] arg0, String arg1)
                    throws CertificateException {
            }
        } };

        try {
            SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
            HttpsURLConnection.setDefaultHostnameVerifier(
                    (hostname, session) -> hostname.equals("IPADDRESS"));
        } catch (NoSuchAlgorithmException | KeyManagementException e) {
            LOGGER.error(e.toString());
        }
    }

and i called this function before i created the RestTemplate.

emoleumassi
  • 4,881
  • 13
  • 67
  • 93