How to solve javax.net.ssl.SSLHandshakeException

If you’re encountering the “handshake_failure through SSLHandshakeException” error, it means there is an issue with the SSL/TLS handshake between the client and server. This can be caused by a variety of reasons such as outdated SSL/TLS protocol version, missing SSL/TLS certificates, or incorrect SSL/TLS configurations.

To connect securely to a server, you first need to get the server’s public certificate. Save the certificate in a file and add it to your computer’s list of trusted certificates.

This list of trusted certificates is called the trust store and is located in a file called cacerts. You can find it in a folder named security in the Java installation directory.

To add the certificate to the trust store, you need to run a program called keytool with the certificate file, a meaningful name, and the path to the cacerts file.

keytool -import -file <the cert file> -alias <some meaningful name> -keystore <path to cacerts file>

Once you have completed these steps, you can communicate securely with the server provided that both JVMs (client/server) are using the following properties with the correct values:

java -Djavax.net.ssl.keyStore=path_to_keystore_file 
     -Djavax.net.ssl.keyStorePassword=password 
     -Djavax.net.ssl.trustStore=path_to_truststore_file 
     -Djavax.net.ssl.trustStorePassword=password MyClass

If you have followed the above steps and you are facing javax.net.ssl.SSLHandshakeException then you need to check for some possible causes.

Causes of the Issue

Here are some possible solutions to fix the issue javax.net.ssl.SSLHandshakeException:

  1. You need to update your SSL/TLS protocol version: Make sure that you’re using the latest SSL/TLS protocol version that is supported by your web server. Some older versions of SSL/TLS are no longer considered secure and may result in handshake failures. Consider upgrading to TLS 1.2 or TLS 1.3, which are currently the most secure versions.
  2. You need to install SSL/TLS certificates: Ensure that you have a valid SSL/TLS certificate installed on your web server. This certificate should be issued by a trusted certificate authority (CA) and should be valid for the domain name that you’re accessing. You can use online tools like SSL Checker to verify the validity of your SSL/TLS certificate.
  3. Wrong SSL/TLS configuration: Ensure that your SSL/TLS configuration is correct and matches the settings of your SSL/TLS certificate. If you’re using a self-signed certificate, make sure that you’ve installed it on your client device as well. If you’re unsure about your SSL/TLS configuration, you can use online tools like SSL Labs to diagnose any issues.
  4. Disable outdated SSL/TLS protocols: Disable outdated SSL/TLS protocols like SSLv3 or TLS 1.0/1.1 that are no longer considered secure. This will help prevent handshake failures and improve the security of your website. You can do this by modifying your web server configuration.
  5. Disable cipher suites with weak encryption: Disable cipher suites with weak encryption that are no longer considered secure. This will help prevent handshake failures and improve the security of your website. You can do this by modifying your web server configuration.

Troubleshooting and solution

When you set the system property javax.net.debug=ssl,handshake, it enables debug logging for SSL/TLS connections, including detailed information about the handshake process. This debug logging can help you determine whether a handshake failure is caused by the client or the server.:

 javax.net.debug=ssl,handshake

Another option is to use JInfo to see SSL/TLS Properties of the Java process

The jinfo command allows to view the system properties of the process. For example, if the PID of your process is 12345, you can use the following command to view the system properties:

jinfo -sysprops 12345

This will output a list of all system properties set for your Java process, including the value of javax.net.ssl.trustStore.

Look for the javax.net.ssl.trustStore property in the output and verify that it’s set to the expected value. For example, if you expect the trustStore to be set to /path/to/truststore, look for a line in the output that looks like this:

javax.net.ssl.trustStore=/path/to/truststore

By using the jinfo command to verify the runtime system properties, you can ensure that your Java application or server is using the correct SSL/TLS trustStore at runtime.

Finally, you can try to reproduce the SSLHandshakeException locally programmatically. This can be useful, for example, if your Client application uses unsupported Cipher suites. By enabling them in your code, you can determine if that is the root cause.

Here is a sample Java Class you can use to test SSL Connectivity:

import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;

public class SSLConnectivityTest {

    public static void main(String[] args) throws Exception {

        // Set the SSL socket factory
        SSLSocketFactory sslSocketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();

        // Set the SSL socket
        SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket("your.server.com", 443);

        // Enable all supported cipher suites
        String[] enabledCipherSuites = sslSocket.getSupportedCipherSuites();
        sslSocket.setEnabledCipherSuites(enabledCipherSuites);

        // Start the SSL handshake
        sslSocket.startHandshake();

        // Get the input and output streams of the SSL socket
        InputStream inputStream = sslSocket.getInputStream();
        OutputStream outputStream = sslSocket.getOutputStream();

        // Write data to the SSL socket
        outputStream.write("Hello, server!\n".getBytes());

        // Read data from the SSL socket
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        String line = reader.readLine();
        System.out.println("Server response: " + line);

        // Close the SSL socket
        sslSocket.close();
    }
}

Make sure you are running the above class with the KeyStore/TrustStore System Properties:

java -Djavax.net.ssl.keyStore=path_to_keystore_file -Djavax.net.ssl.keyStorePassword=password -Djavax.net.ssl.trustStore=path_to_truststore_file -Djavax.net.ssl.trustStorePassword=password SSLConnectivityTest

Using OpenSSL to rest a remote connection

Besides, you can also use openssl as Client to debug the remote connection to a secure Host. For example:

openssl s_client -debug -connect www.server.com:443

You can use the openssl tool to verify some use cases, such as if your Java Client is not sending the SNI (service Name Indication) extension to a SSL/TLS endpoint. You can add the SNI to the openssl tool to verify if this solves the issue as follows:

openssl s_client -debug -connect www.server.com:443 -servername www.server.com