Java code that ignores an Invalid SSL Certificate

It seems that you are getting an error message that says:

Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target


This error means that your Java application is trying to connect to a server that has a certificate that is not trusted by your Java trust store. The Java trust store is a file that contains the certificates of the Certificate Authorities (CAs) that your Java application trusts. If the server’s certificate is not issued by one of these CAs, or if the certificate chain is broken or invalid, your Java application will not be able to verify the identity and authenticity of the server, and will throw this exception.


There are two possible ways to fix this error:

Java trust store

The recommended way is to import the server’s certificate into your Java trust store, so that your Java application can trust the server.

You will need to know the location of your Java trust store, which is usually in the JRE_HOME/lib/security/cacerts file, and the password to access it, which is usually changeit.

You will also need to obtain the server’s certificate, either by downloading it from the server’s website or by using a tool like openssl to extract it from the server’s response.

How to add certificate to cacert

keytool -import -trustcacerts -file YOUR_FILE_NAME -alias YOUR_ALIAS_NAME -keystore cacerts_file_PATH

For example, to add a certificate named “mycert.cer” to the cacerts file, you would use the following command:

keytool -import -alias mycert -file mycert.cer -keystore C:\Program Files\Java\jdk1.8\jre\lib\security\cacerts

You can also specify the -trustcacerts option to indicate that the certificate should be trusted, and the -noprompt option to avoid confirmation prompts.

-trustcacerts

How To List All Certificates in the JDK cacerts File

The JDK cacerts file is a file that contains the certificates of the trusted Certificate Authorities (CAs) that are used by Java applications to verify the identity and authenticity of servers. The cacerts file is usually located in the JRE_HOME/lib/security directory, and it can be accessed and modified by using the keytool command.

Open a terminal and navigate to the JRE_HOME/lib/security directory.

keytool -list -v -keystore /path/to/cacerts

Enter the password for the cacerts file, which is usually changeit.

changeit

You will see a list of certificates with their alias, type, and fingerprint.

To ignore the server’s certificate

The alternative way is to ignore the server’s certificate and accept any certificate presented by the server. This is not recommended, as it exposes your Java application to security risks, such as man-in-the-middle attacks, where a malicious third party can intercept and modify your communication with the server.

However, if you are sure that the server is trustworthy and you are only connecting to it for testing purposes, you can use this option.

You will need to modify your Java code to use a custom TrustManager that does not validate the server’s certificate

public String youFunctionName(String targetURL, String param1, String param2) throws Exception {

        // 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(
                            java.security.cert.X509Certificate[] certs, String authType) {
                    }
                    public void checkServerTrusted(
                            java.security.cert.X509Certificate[] certs, String authType) {
                    }
                }
        };

// Install the all-trusting trust manager
        try {
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        } catch (Exception e) {
            e.printStackTrace();
        }
        StringBuilder response = new StringBuilder();
// Now you can access an https URL without having the certificate verified
        try {
            URL url = new URL(targetURL);
            HttpsURLConnection myURLConnection = (HttpsURLConnection)url.openConnection();
            myURLConnection.setRequestMethod("POST");
            myURLConnection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
            myURLConnection.setUseCaches(false);
            myURLConnection.setDoInput(true);
            myURLConnection.setDoOutput(true);

            // Do something with the connection

//Create json body 
// option1
            JSONObject json = new JSONObject();
            json.put("param1Name", param1);
            json.put("param2Name", param2); 

//Create json body 
// option2
//String jsonInputString = "{"param1Name": param1, "param2Name": param2}";

            String jsonInputString = json.toJSONString();
//Create the Request Body
            try(OutputStream os = myURLConnection.getOutputStream()) {
                byte[] input = jsonInputString.getBytes("utf-8");
                os.write(input, 0, input.length);
            }

//Read the Response From Input Stream
            try(BufferedReader br = new BufferedReader(
                    new InputStreamReader(myURLConnection.getInputStream(), "utf-8"))) {

                String responseLine = null;
                while ((responseLine = br.readLine()) != null) {
                    response.append(responseLine.trim());
                }
                System.out.println(response.toString());

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return response.toString();

    }

Adding header for HttpURLConnection

You can try the below code. The code bellow is for POST, and you can modify it for GET

URL myURL = new URL(serviceURL);
HttpURLConnection myURLConnection = (HttpURLConnection)myURL.openConnection();

String userCredentials = "username:password";
String basicAuth = "Basic " + new String(Base64.getEncoder().encode(userCredentials.getBytes()));

myURLConnection.setRequestProperty ("Authorization", basicAuth);
myURLConnection.setRequestMethod("POST");
myURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
myURLConnection.setRequestProperty("Content-Length", "" + postData.getBytes().length);
myURLConnection.setRequestProperty("Content-Language", "en-US");
myURLConnection.setUseCaches(false);
myURLConnection.setDoInput(true);
myURLConnection.setDoOutput(true);

However, this approach is not secure, as it completely ignores all invalid certificates and exposes you to potential man-in-the-middle attacks. A better way is to use a custom HostnameVerifier that checks the hostname against the certificate’s subject alternative names, as explained in this web page

Problems with Let’s Encrypt certificates

One thing I found out while testing this, was that some of hava version 1.8.0___ won’t correctly handle Let’s Encrypt certificates:

This is because Let’s Encrypt certificates are not present in the Java installation. Upgrading to version 1.8.0_141 resolves this (for Oracle versions >= 8U101 or >= 7U111).

I hope this helps you resolve the error and connect to the server successfully