Abdul D.
—I encounter the PKIX path building failed
error when trying to connect to a server using HTTPS:
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)
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.
The most common solution is to import the server’s SSL certificate into your Java TrustStore.
Open your browser and export the server’s certificate in .cer
format.
Use the keytool
command to import the certificate into the Java TrustStore:
keytool -import -alias server_cert -file server.cer -keystore cacerts
cacerts
TrustStore is usually JAVA_HOME/lib/security/cacerts
.changeit
.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
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:
/** * 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("SSL"); 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.
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:
<!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:
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("SSL"); 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.
Tasty treats for web developers brought to you by Sentry. Get tips and tricks from Wes Bos and Scott Tolinski.
SEE EPISODESConsidered “not bad” by 4 million developers and more than 100,000 organizations worldwide, Sentry provides code-level observability to many of the world’s best-known companies like Disney, Peloton, Cloudflare, Eventbrite, Slack, Supercell, and Rockstar Games. Each month we process billions of exceptions from the most popular products on the internet.
Here’s a quick look at how Sentry handles your personal information (PII).
×We collect PII about people browsing our website, users of the Sentry service, prospective customers, and people who otherwise interact with us.
What if my PII is included in data sent to Sentry by a Sentry customer (e.g., someone using Sentry to monitor their app)? In this case you have to contact the Sentry customer (e.g., the maker of the app). We do not control the data that is sent to us through the Sentry service for the purposes of application monitoring.
Am I included?We may disclose your PII to the following type of recipients:
You may have the following rights related to your PII:
If you have any questions or concerns about your privacy at Sentry, please email us at compliance@sentry.io.
If you are a California resident, see our Supplemental notice.