HTTPURL connection in java 6/7

I have a java code with HTTPURL connection it keep saying the error as below and it states error in 47th line.

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|

It also shows error in line 47: OutputStream output = httpURLConnection.getOutputStream();

couldn't trace url responsecode, thou url is active to access.

here is the stack trace and javacode

https://gist.github.com/theakathir/c9138e3ea7470b698ec06a7db7dcdeab

Appreciate if someone could assist on this to resolve. Thanks

3 answers

  • answered 2017-06-17 18:20 Mayank Sharma

    You need to add the certificate to the keystore file of the used JVM located at %JAVA_HOME%\lib\security\cacerts.

    First you can check if your certificate is already in the keystore by running the following command: keytool -list -keystore "%JAVA_HOME%/jre/lib/security/cacerts" (you don't need to provide a password)

    If your certificate is missing you can get it by downloading it with your browser and add it to the keystore with the following command:

    keytool -import -noprompt -trustcacerts -alias -file -keystore -storepass

    Afer import you can run the first command again to check if your certificate was added.

  • answered 2017-06-17 18:20 Ravindra HV

    The server's domain certificate is usually signed by an intermediate certificate authority which in turn is signed by the root certificate authority. All common clients (browsers- chrome, mozilla, internet-explorer, safari, opera and the java-vm) have their own trust-store with the certificate authority already bundled during installation.

    The exceptions means that you are pointing to a server whose server certificate has not been signed by a certificate authority trusted by the jvm.

    In such cases you usually build your own trust-manager instead of modifying the jvm's default truststore (located at $JAVA_HOME\jre\lib\security\cacerts).

    Code snippet would look something like this :

    package com.example.so.tls;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.net.URL;
    import java.security.KeyManagementException;
    import java.security.KeyStore;
    import java.security.KeyStoreException;
    import java.security.NoSuchAlgorithmException;
    import java.security.cert.CertificateException;
    
    import javax.net.ssl.HttpsURLConnection;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLSocketFactory;
    import javax.net.ssl.TrustManagerFactory;
    
    
    /**
     * <p> https://stackoverflow.com/q/44607949/2862341 </p>
     * @author ravindra
     */
    public class TestCustomTruststore {
    
        public static void main(String[] args) {
    
            String pathToTruststore = "/path/to/customTruststore.jks"; // truststore has the server certificate loaded
            try {
                File file = new File(pathToTruststore);
                KeyStore trustStore = KeyStore.getInstance("jks");
                trustStore.load(new FileInputStream(file), null);
                TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("PKIX");
                trustManagerFactory.init(trustStore);
    
                SSLContext sslContext = SSLContext.getInstance("TLS");
                sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
    
                SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
    
                String urlStr = "https://example.com";
                URL url = new URL(urlStr);
                HttpsURLConnection httpsURLConnection = (HttpsURLConnection) url.openConnection();
                httpsURLConnection.setSSLSocketFactory(sslSocketFactory);
    
                httpsURLConnection.getInputStream();
    
            } catch (KeyStoreException e) {
                e.printStackTrace();
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (CertificateException e) {
                e.printStackTrace();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (KeyManagementException e) {
                e.printStackTrace();
            }
    
    
        }
    
    }
    

    PS: You'd need to use $JAVA_HOME\bin\keytool utility to create the keystore and load the certificate.

  • answered 2017-06-17 18:20 dave_thompson_085

    A middle alternative is to use your own truststore file (not JRE/lib/security/cacerts or even jssecacerts which is an official alternative) but instead of writing code to load this file and use it in an SSLSocketFactory you can have the default factory use your file by setting system properties javax.net.ssl.trustStore and javax.net.ssl.trustStorePassword . In many cases these can be set on the commandline to run your java program without any code change at all.

    Note that nearly all SSL/TLS certificates on the Internet today are not issued directly by a root CA (which is in the various browser, client, and JVM truststores) but using an intermediate CA cert also called a 'chain' cert because it is used to chain from the server/leaf cert to the root. Occasionally there are two chain certs, and in principle can be even more. Validation error might be caused not by your JVM lacking the root, but by the server failing to send the chain cert(s); you might not notice this error when accessing with a browser because browsers sometimes use other means of fetching the chain cert(s). In this case either examine the cert chain manually -- for java7 up you can use keytool -printcert -sslserver $host[:$port] and/or if you have openssl use openssl s_client -connect $host:$port -showcerts and then use openssl x509 on each PEM block in that output -- or use an automatic tester like https://www.ssllabs.com/ssltest/