[java] PKIX path building failed: unable to find valid certification path to requested target

I am calling some HTTPS web service which the following Client:

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.HttpURLConnection;
import java.net.URL;

import javax.net.ssl.HttpsURLConnection;

/**
 * Handles http and https connections. It sends XML request over http (or https)
 * to SOAP web service and receive the XML reply.
 * 
 * @author mhewedy
 * @date 30.10.2010
 */
public class HttpWSXmlClient
{
    private final String ws_url;
    private byte[] requestData;

    public HttpWSXmlClient(String wsUrl)
    {
        this.ws_url = wsUrl;
    }

    public void readRequest(String xmlRequestFilePath)
    {
        try
        {
            InputStream istream = new FileInputStream(xmlRequestFilePath);
            byte[] data = stream2Bytes(istream);
            istream.close();
            this.requestData = data;
        } catch (Exception e)
        {
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 
     * @param ps
     *            PrintStream object to send the debugging info to.
     * @return
     * @throws IOException
     */
    public byte[] sendAndRecieve(PrintStream ps) throws IOException
    {
        if (requestData == null)
            throw new RuntimeException(
                    "the request data didn't initialized yet.");
        if (ps != null)
            ps.println("Request:\n" + new String(requestData));
        URL url = new URL(ws_url);
        HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
        // or HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setDoOutput(true);
        connection.setRequestProperty("content-type", "text/xml");
        connection.connect();
        OutputStream os = connection.getOutputStream();
        os.write(requestData);
        InputStream is = connection.getInputStream();
        byte[] rply = stream2Bytes(is);
        if (ps != null)
            ps.println("Response:\n" + new String(rply));
        os.close();
        is.close();
        connection.disconnect();
        return rply;
    }

    public byte[] sendAndRecieve() throws IOException
    {
        return sendAndRecieve(null);
    }

    private byte[] stream2Bytes(InputStream istream) throws IOException
    {
        ByteArrayOutputStream outstream = new ByteArrayOutputStream();
        int c;
        while ((c = istream.read()) != -1)
        {
            if (c != 0x0A && c != 0x0D) // prevent new line character from being
            // written
            {
                if (c == 0x09)
                    c = 0x20; // prevent tab character from being written,
                // instead write single space char
                outstream.write(c);
            }
        }
        byte[] ret = outstream.toByteArray();
        outstream.close();
        return ret;
    }

}

Test:

public class Test
{
    private static final String WS_URL = "https://some_server/path/to/ws";

    public static void main(String[] args) throws Exception
    {
        HttpWSXmlClient client = new HttpWSXmlClient(WS_URL);
        client.readRequest("request.xml");
        client.sendAndRecieve(System.out);
    }
}

I got the following output:

Exception in thread "Main Thread" 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 com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1591)
    at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:187)
    at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:181)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1035)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:124)
    at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:516)
    at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:454)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:884)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1096)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1123)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1107)
    at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:415)
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:133)
    at com.se.swstest.HttpWSXmlClient.sendAndRecieve(HttpWSXmlClient.java:63)
    at com.se.swstest.Test.main(Test.java:11)
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:285)
    at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:191)
    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:1014)
    ... 12 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:280)
    ... 18 more

Do I need any certificate to be put at jdk/jre/lib/security??? Also, I have a xxx_IE.crt and xxx_FX.crt (for Firefox and IE respectively, and they don't work for the above Java client, so do I need a specific certificate for the Java client?

Thanks.

This question is related to java web-services certificate ssl-certificate

The answer is


For me, I had encountered this error when invoking a webservice call, make sure that the site has a valid ssl, i.e the logo on the side of the url is checked, otherwise need to add the certificate to trusted key store in your machine


I've run into this a few times and it was due to a certificate chain being incomplete. If you are using the standard java trust store, it may not have a certificate that is needed to complete the certificate chain which is required to validate the certificate of the SSL site you are connecting to.

I ran into this problem with some DigiCert certificates and had to manually add the intermediary cert myself.


If you do not need the SSL security then you might want to switch it off.

 /**
   * disable SSL
   */
  private void disableSslVerification() {
    try {
      // Create a trust manager that does not validate certificate chains
      TrustManager[] trustAllCerts = new TrustManager[] {
          new X509TrustManager() {
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
              return null;
            }

            public void checkClientTrusted(X509Certificate[] certs,
                String authType) {
            }

            public void checkServerTrusted(X509Certificate[] certs,
                String authType) {
            }
          } };

      // Install the all-trusting trust manager
      SSLContext sc = SSLContext.getInstance("SSL");
      sc.init(null, trustAllCerts, new java.security.SecureRandom());
      HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

      // Create all-trusting host name verifier
      HostnameVerifier allHostsValid = new HostnameVerifier() {
        public boolean verify(String hostname, SSLSession session) {
          return true;
        }
      };

      // Install the all-trusting host verifier
      HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
    } catch (NoSuchAlgorithmException e) {
      e.printStackTrace();
    } catch (KeyManagementException e) {
      e.printStackTrace();
    }
  }

You need to set certificate to hit this url. use below code to set keystore:

System.setProperty("javax.net.ssl.trustStore","clientTrustStore.key");

System.setProperty("javax.net.ssl.trustStorePassword","qwerty");

On Mac OS I had to open the server's self-signed certificate with system Keychain Access tool, import it, dobubleclick it and then select "Always trust" (even though I set the same in importer). Before that, of course I ran java key took with -importcert to import same file to cacert storage.


I also faced this type of issue.I am using tomcat server then i put endorsed folder in tomcat then its start working.And also i replaced JDK1.6 with 1.7 then also its working.Finally i learn SSL then I resolved this type of issues.First you need to download the certificates from that servie provider server.then you are handshake is successfull. 1.Try to put endorsed folder in your server Next way 2.use jdk1.7

Next 3.Try to download valid certificates using SSL


Java 8 Solution: I just had this problem and solved it by adding the remote site's certificate to my Java keystore. My solution was based on the solution at the myshittycode blog, which was based on a previous solution in mykong's blog. These blog article solutions boil down to downloading a program called InstallCert, which is a Java class you can run from the command line to obtain the certificate. You then proceed to install the certificate in Java's keystore.

The InstallCert Readme worked perfectly for me. You just need to run the following commands:

  1. javac InstallCert.java
  2. java InstallCert [host]:[port] (Enter the given list number of the certificate you want to add in the list when you run the command - likely just 1)
  3. keytool -exportcert -alias [host]-1 -keystore jssecacerts -storepass changeit -file [host].cer
  4. sudo keytool -importcert -alias [host] -keystore [path to system keystore] -storepass changeit -file [host].cer

See the referenced README file for an example if need be.


Here is the solution that I used for installing a site's public cert into the systems keystore for use.

Download the certificate with the following command:

unix, linux, mac

openssl s_client -connect [host]:[port|443] < /dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > [host].crt

windows

openssl s_client -connect [host]:[port|443] < NUL | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > [host].crt

That will create a crt that can be used to import into a keystore.

Install the new certificate with the command:

keytool -import -alias "[host]" -keystore [path to keystore] -file [host].crt

This will allow you to import the new cert from the site that is causing the exception.


This error can also happen if the server only sends its leaf certificate and does not send all the chain certificates needed to build the trust chain to the root CA. Unfortunately this is a common misconfiguration of servers.

Most browsers work around this problem if they already know the missing chain certificate from earlier visits or maybe download the missing certificate if the leaf certificate contains a URL for CA issuers in Authority Information Access (AIA). But this behavior is usually restricted to desktop browsers and other tools simply fail because they cannot build the trust chain.

You can make the JRE to automatically download the intermediate certificate by setting com.sun.security.enableAIAcaIssuers to true

To verify if the server is sending all the chain certificates you can enter the host in the following SSL certificate validation tool https://www.digicert.com/help/


I had hit this when I was trying to initiate a SOAP request from Java code. What worked for me was:

  1. Get the Server certificate by hitting the URL in browser: http://docs.bvstools.com/home/ssl-documentation/exporting-certificate-authorities-cas-from-a-website This link has all the steps to get the server certificate

  2. Once you have the server certificate with you follow http://java.globinch.com/enterprise-java/security/pkix-path-building-failed-validation-sun-security-validatorexception/#Valid-Certification-Path-to-Requested-Target .

Copying the text from the link, in case this link dies:

All you need to do to fix this error is to add the server certificate to your trusted Java key store. First You need to download the document from the server.

Once you have the certificate in your hard drive you can import it to the Java trust store. To import the certificate to the trusted Java key store, you can use the java ‘keytool‘ tool. On command prompt navigate to JRE bin folder, in my case the path is : C:\Program Files\Java\jdk1.7.0_75\jre\bin . Then use keytool command as follows to import the certificate to JRE.

keytool -import -alias _alias_name_ -keystore ..\lib\security\cacerts -file _path_to_cer_file

It will ask for a password. By default the password is “changeit”. If the password is different you may not be able to import the certificate.


Examples related to java

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How much should a function trust another function How to implement a simple scenario the OO way Two constructors How do I get some variable from another class in Java? this in equals method How to split a string in two and store it in a field How to do perspective fixing? String index out of range: 4 My eclipse won't open, i download the bundle pack it keeps saying error log

Examples related to web-services

How do I POST XML data to a webservice with Postman? How to send json data in POST request using C# org.springframework.web.client.HttpClientErrorException: 400 Bad Request How to call a REST web service API from JavaScript? The request was rejected because no multipart boundary was found in springboot Generating Request/Response XML from a WSDL How to send a POST request using volley with string body? How to send post request to the below post method using postman rest client How to pass a JSON array as a parameter in URL Postman Chrome: What is the difference between form-data, x-www-form-urlencoded and raw

Examples related to certificate

Distribution certificate / private key not installed When you use 'badidea' or 'thisisunsafe' to bypass a Chrome certificate/HSTS error, does it only apply for the current site? Cannot install signed apk to device manually, got error "App not installed" Using client certificate in Curl command Convert .cer certificate to .jks SSL cert "err_cert_authority_invalid" on mobile chrome only Android Studio - Unable to find valid certification path to requested target SSL: error:0B080074:x509 certificate routines:X509_check_private_key:key values mismatch Verify a certificate chain using openssl verify Import Certificate to Trusted Root but not to Personal [Command Line]

Examples related to ssl-certificate

How to install OpenSSL in windows 10? Scraping: SSL: CERTIFICATE_VERIFY_FAILED error for http://en.wikipedia.org Not able to install Python packages [SSL: TLSV1_ALERT_PROTOCOL_VERSION] Letsencrypt add domain to existing certificate javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure bypass invalid SSL certificate in .net core How to add Certificate Authority file in CentOS 7 How to use a client certificate to authenticate and authorize in a Web API This certificate has an invalid issuer Apple Push Services iOS9 getting error “an SSL error has occurred and a secure connection to the server cannot be made”