# Java Fix the PKIX Path Building Failed SSL Error

> Import the server's SSL certificate into the Java TrustStore with keytool, or configure a custom TrustStore, to resolve PKIX path building failed exceptions

**URL:** https://sentry.io/answers/how-to-solve-pkix-path-building-failed-error-in-java/

---

## The Problem

I encounter the `PKIX path building failed` error when trying to connect to a server using HTTPS:

```java
import java.io.IOException;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;

public class Main {
    public static void main(String[] args) {
        try {
            URL url = new URL("https://expired-rsa-ev.ssl.com/");
            HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
            System.out.println("Response Code: " + connection.getResponseCode());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
```

Trying to connect to the URL in the code above throws the following exception:

```
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 sun.security.ssl.Alert.createSSLException(Alert.java:131)
    at sun.security.ssl.TransportContext.fatal(TransportContext.java:324)
    at sun.security.ssl.TransportContext.fatal(TransportContext.java:267)
    at sun.security.ssl.TransportContext.fatal(TransportContext.java:262)
    at sun.security.ssl.CertificateMessage$T13CertificateConsumer.checkServerCerts(CertificateMessage.java:1325)
    at sun.security.ssl.CertificateMessage$T13CertificateConsumer.onConsumeCertificate(CertificateMessage.java:1200)
    at sun.security.ssl.CertificateMessage$T13CertificateConsumer.consume(CertificateMessage.java:1143)
    at sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:392)
    at sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:444)
    at sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:422)
    at sun.security.ssl.TransportContext.dispatch(TransportContext.java:182)
    at sun.security.ssl.SSLTransport.decode(SSLTransport.java:152)
    at sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1198)
    at sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1107)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:398)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:370)
    at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:567)
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:162)
    at Main.main(Main.java:9)
```

## The Solution

This error occurs when Java cannot verify the SSL certificate of the server you are trying to connect to. This is usually because the certificate isn't trusted by the Java TrustStore. You can resolve this issue by importing the SSL certificate into the default Java TrustStore or your own custom TrustStore. Alternatively, you can disable SSL certificate validation. This last option is not recommended, as it compromises security.

### Importing the Server Certificate into Java TrustStore

The most common solution is to import the server's SSL certificate into your Java TrustStore.

1. Open your browser and export the server's certificate in `.cer` format.
2. Use the `keytool` command to import the certificate into the Java TrustStore:

    ```
    keytool -import -alias server_cert -file server.cer -keystore cacerts
    ```

    - The default location of the `cacerts` TrustStore is usually `JAVA_HOME/lib/security/cacerts`.
    - The default password for the TrustStore is `changeit`.

### Specifying a Custom TrustStore

If you don't want to modify the default TrustStore, you can create a custom TrustStore for your application.

First, create a TrustStore and import the certificate:

```
keytool -import -alias server_cert -file server.cer -keystore customTrustStore.jks
```

Then specify the custom TrustStore when running your Java application:

```
java -Djavax.net.ssl.trustStore=customTrustStore.jks -Djavax.net.ssl.trustStorePassword=your_password YourApplication
```

### Disabling Certificate Validation

For development purposes, you can disable SSL certificate validation. However, this is not recommended for production environments as it compromises security.

The following example demonstrates how to disable certificate validation by creating a method to trust all certificates:

```java
/**
 * Configures SSL to trust all certificates and bypass hostname verification.
 * This allows the application to connect to servers with untrusted or self-signed certificates.
 * WARNING: This approach is insecure for production use.
 */
private static void configureTrustAllSSL() throws Exception {
    TrustManager[] trustAllCerts = new TrustManager[]{
        new X509TrustManager() {
            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
            @Override
            public void checkClientTrusted(X509Certificate[] certs, String authType) {
                // Do nothing - trust all clients
            }
            @Override
            public void checkServerTrusted(X509Certificate[] certs, String authType) {
                // Do nothing - trust all servers
            }
        }
    };

    SSLContext sc = SSLContext.getInstance("TLS");
    sc.init(null, trustAllCerts, new java.security.SecureRandom());
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

    HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true);
}
```

You can call this method before making the HTTPS connection. This will bypass SSL certificate validation and allow you to connect to servers with untrusted or self-signed certificates.

```java
public static void main(String[] args) {
        try {
            // Configure SSL to trust all certificates
            configureTrustAllSSL();

            // URL of the page with an expired or untrusted certificate
            URL url = new URL("https://expired-rsa-ev.ssl.com/"); // Replace with your URL
            String pageContent = fetchContentFromURL(url);

            // Print out the content of the page
            System.out.println(pageContent);
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
```

The output will display html page content representing a successful connection:

```html
<!DOCTYPE html>
    <html lang="en">  
    <head>    
        <meta charset="utf-8">    
        <link rel="icon" href="favicon-32x32.png"   sizes="32x32" />    
        <link rel="icon" href="favicon-192x192.png" sizes="192x192" />    
        <link rel="apple-touch-icon" href="favicon-180x180.png" />    
        <title>SSL.com - Test Website</title>  
    </head>  
    <body>    
        <h1>SSL.com - Test Website</h1>    
        <p>This is a test website authenticated by <a href="https://www.ssl.com" target="_blank">SSL.com.</a></p>  
    </body>
</html>
```

Here's the full example code:

```java
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.security.cert.X509Certificate;
import javax.net.ssl.*;

public class SSLBypassExample {

    public static void main(String[] args) {
        try {
            // Configure SSL to trust all certificates
            configureTrustAllSSL();

            // URL of the page with an expired or untrusted certificate
            URL url = new URL("https://expired-rsa-ev.ssl.com/"); // Replace with your URL
            String pageContent = fetchContentFromURL(url);

            // Print the content of the page
            System.out.println(pageContent);
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Configures SSL to trust all certificates and bypass hostname verification.
     * This allows the application to connect to servers with untrusted or self-signed certificates.
     * WARNING: This approach is insecure for production use.
     */
    private static void configureTrustAllSSL() throws Exception {
        TrustManager[] trustAllCerts = new TrustManager[]{
            new X509TrustManager() {
                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
                @Override
                public void checkClientTrusted(X509Certificate[] certs, String authType) {
                    // Do nothing - trust all clients
                }
                @Override
                public void checkServerTrusted(X509Certificate[] certs, String authType) {
                    // Do nothing - trust all servers
                }
            }
        };

        SSLContext sc = SSLContext.getInstance("TLS");
        sc.init(null, trustAllCerts, new java.security.SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

        HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true);
    }

    /**
     * Fetches the content from the specified URL as a String.
     * 
     * @param url The URL to fetch content from.
     * @return The content of the page as a String.
     * @throws Exception If an error occurs while reading from the URL.
     */
    private static String fetchContentFromURL(URL url) throws Exception {
        StringBuilder content = new StringBuilder();
        
        // Open HTTPS connection and read content
        HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
        try (BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
            String inputLine;
            while ((inputLine = in.readLine()) != null) {
                content.append(inputLine);
            }
        }
        
        return content.toString();
    }
}
```

**Warning:** This should only be used in development or testing environments where security is not a concern.

---

*Source: [sentry.io/answers/how-to-solve-pkix-path-building-failed-error-in-java/](https://sentry.io/answers/how-to-solve-pkix-path-building-failed-error-in-java/)*
