How to avoid SSLHandshakeException while connecting to HTTPS urls

Have you got a javax.net.ssl.SSLHandshakeException while trying to connect to a URL which is SSL encrypted? You want to connect to a web page or a SOAP Web Service from your Java application but it is throwing the below exception:

Exception in thread "main" 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

The error says the connection could not be established due to a certificate validation error. You might be wondering why some urls are working while some not. To understand this you need to know what is SSL and how SSL works.

What is Secure Socket Layer?

SSL stands for Secure Socket Layer which is a protocol in which the data transfer between a Web Client(e.g. web browser) and a Web Server takes place in an encrypted format. Content encrypted by the server is decrypted by the client using a public-private key pair.

Key pairs contains a public key and a private key, content encrypted with one key can be decrypted with the other. All modern browsers includes a set of well known certificates issued by certificate authorities(CA), which makes the encryption-decryption possible for HTTPS sites.

Why Java throwing javax.net.ssl.SSLHandshakeException for some SSL sites?

As in browser, JRE also contains a trustsore where all trusted CA certificates are stored. This truststore is stored in a file named cacerts located at <JRE_HOME>/lib/security/. You can connect to all HTTPS sites which are having certificates trusted by Java truststore but a SSLHandshakeException is thrown for sites with untrusted certificates(including self signed certificates).

How to avoid SSLHandshakeException?

There are many ways to overcome SSLHandshakeException, some are given below:

  1. Adding certificate to Java trust store manually
  2. Adding certificate to Java trust store programmatically
  3. Use custom trust store
  4. Turn off certificate validation

Safest option is to add the certificate to Java trust store manually to avoid any security issues.

How to add SSL certificate to the Java Truststore?

It is a two step process, first download the certificate, then add the certificate to the truststore.

1. Downloading the certificate

First, open the url in your browser(steps may vary depends on the browser), then click on the lock icon on the navigation bar, then click on Certificate Information. Now go to Details tab, there you will see a Copy to File button. Clicking on this will give you a certificate export wizard where you need to select certificate format as DER encoded binary X.509. Give a file name say mycertificate.cer and save the file.

2. Adding certificate to the Java truststore

This is a simple step, go to <JRE_HOME>/bin and execute the below command:

keytool -import -alias alias -keystore ../lib/security/cacerts 
      -file mycertificate.cer
Enter the default keystore password 'changeit'(changeme on Mac) for the prompt 'Enter keystore password:'.

Then enter 'yes' for the prompt 'Trust this certificate? [no]:' and press enter key.

If everything goes well, you will get a message 'Certificate was added to keystore' which confirms your certificate is added to the Java truststore successfylly!

Connecting to a HTTPS site with URLConnection

Below program will now work without any SSL handshake exception:

 URL url = new URL("https://secure.skunkworks.net.au");
 URLConnection con = url.openConnection();
 con.connect();
  
 InputStream in = con.getInputStream();
 InputStreamReader inputstreamreader = new InputStreamReader(in);
 BufferedReader bufferedreader = new BufferedReader(inputstreamreader);

 String string = null;
 while ((string = bufferedreader.readLine()) != null) {
  System.out.println(string);
 } 

That's it, now you learnt how to connect to a SSL secured url from a Java application!

Those who want to connect to a mail server over SSL using Java Mail API, use the below property to authenticate over SSL:

 props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");

1 Comments

Did you enjoy this post? Why not leave a comment below and continue the conversation, or subscribe to our feed and get articles like this delivered automatically to your feed reader? Like our Facebook Page.

  1. Hi, Thanks for this article seems really helpful. But I have some doubts as
    I've installed jenkins on a VM (CentOS 8) and accessing from my local machine browser, from where should I download the certificate ?
    also how do run command from JRE_HOME ?

    ReplyDelete
Post a Comment
Previous Post Next Post