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

185,558

Solution 1

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

Solution 2

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.

Solution 3

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.

Solution 4

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.

Solution 5

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.

Share:
185,558

Related videos on Youtube

Muhammad Hewedy
Author by

Muhammad Hewedy

Updated on May 04, 2022

Comments

  • Muhammad Hewedy
    Muhammad Hewedy about 2 years

    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.

  • Alfredo Carrillo
    Alfredo Carrillo over 10 years
    I have a DigiCert too and I guess have the same problem you described. In my case I am not able to export from the browser the entire certificate chain to add all of them to the trust store. Could you share the way you did?
  • Casey
    Casey over 10 years
    What browser are you using? I believe I used Firefox to do it although I do not remember the exact method.
  • Alfredo Carrillo
    Alfredo Carrillo over 10 years
    I used IE before. Now I could export it with FireFox, added successfully to the trust store but still having the same exception. I will continue trying. Thanks anyway!
  • EpicPandaForce
    EpicPandaForce over 9 years
    This actually worked for me as I set the trust store to be my whatever.jks file, although I'm not sure why. But thank you.
  • entpnerd
    entpnerd about 8 years
    Note that the system's keystore is probably at: $JAVA_HOME/jre/lib/security/cacerts.
  • aholbreich
    aholbreich about 8 years
    Actually Webserver should send all the certificates in the chain. Is it a problem of Java Client implementation that cannot deal with that? Do you know details on that?
  • aswzen
    aswzen over 7 years
    worked well here..althought i don't even know what trustStore is :/
  • user207421
    user207421 over 7 years
    The truststore doesn't contain keys, so naming it .key is senseless.
  • Lucky
    Lucky over 7 years
    This doesn't answer the question. What do you mean by endorsed folder?
  • ozgur
    ozgur over 6 years
    Can someone tell what might be the real values of qwerty and clientTrustStore.key ?
  • dave_thompson_085
    dave_thompson_085 over 6 years
    Many modern servers use SNI; if so for s_client to get the correct cert(s) add -servername $host. In java7 up, -importcert can handle extraneous text in a PEM file so you don't need the sed; also in j7 up, keytool -printcert -sslserver $host[:$port] -rfc fetches the cert chain and prints in PEM (like s_client -showcerts without the extraneous text) which is easier if you don't have OpenSSL installed e.g. Windows.
  • Christopher Schultz
    Christopher Schultz about 6 years
    I have to point-out that setting the truststore for the whole JVM is a Really Bad Idea. It may hijack settings another component is expecting and, depending upon what you put into your trust store, may reduce the security of any code running within that JVM. It's must better to set the trust store (and related configuration) only for the connections you intend to make. You are using HttpsURLConnection, and you can set the trust managers on those connections without too much trouble.
  • golimar
    golimar about 6 years
    Is there a way to point the Java application to the .cer file instead of modifying the system's keystore?
  • golimar
    golimar about 6 years
    @ozgur trustStore could be "jssecacerts" or a .jks file stored on the server. Worked for me with the jssecacerts file generated with entpnerd's answer
  • entpnerd
    entpnerd about 6 years
    @golimar I don't believe so (see this Oracle page and this question). That being said, your question might be a worthwhile new question for the StackOverflow community.
  • golimar
    golimar about 6 years
    I think I have it working combining your answer (which generates jssecacerts file) file and @Vipin Kumar's answer (to point the application to that file)
  • Avec
    Avec over 2 years
    I use InstallCerts.java as mentioned but instead of updating JDK keystore wherever the application is deployed I bundle the keystore (file called jssecacerts) made from InstallCert.java together with the application. Just put it on the classpath. This way it will without need for updating the JDK.
  • Tom Ferguson
    Tom Ferguson about 2 years
    Your Windows command snippet is using sed so isn't going to work on Windows