88

I got the following exception when try to post a request to a http server:

Here is the code I used

URL url = new URL(
        "https://www.abc.com");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();

conn.setRequestMethod("GET");

conn.setDoOutput(true);

DataOutputStream wr = new DataOutputStream(conn.getOutputStream());
// wr.writeBytes(params);
wr.flush();
wr.close();

BufferedReader br = new BufferedReader(new InputStreamReader(
        conn.getInputStream()));
String line = null;
while ((line = br.readLine()) != null) {
    System.out.println(line);
}

Here is the 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
    at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1731)
    at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:241)
    at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:235)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1206)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:136)
    at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:593)
    at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:529)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:925)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1170)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1197)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1181)
    at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434)
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166)
    at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1014)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:230)
    at com.amazon.mzang.tools.httpchecker.CategoryYank.getPV(CategoryYank.java:32)
    at com.amazon.mzang.tools.httpchecker.CategoryYank.main(CategoryYank.java:18)
Caused by: 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.validator.PKIXValidator.doBuild(PKIXValidator.java:323)
    at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:217)
    at sun.security.validator.Validator.validate(Validator.java:218)
    at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:126)
    at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:209)
    at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:249)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1185)
    ... 13 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:174)
    at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:238)
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:318)
    ... 19 more

The server is not owned by me. Is there a way to ignore this exception?

DeepNightTwo
  • 4,809
  • 8
  • 46
  • 60
  • 5
    Don't *ignore* this exception. Import the certificate (after some manual verification) in your trust store. Ignoring certificate errors makes the connection vulnerable to potential MITM attacks. – Bruno Nov 29 '12 at 14:35
  • 21
    There are times when trust is not important to the client but https has been used by the server none the less. – Gus Feb 23 '14 at 21:22
  • I get this error only sometimes - with the same server. Trying it again a second later the request goes through. The server is botcompany.de and has a LetsEncrypt certificate. How can this be explained? Never had this issue with a Comodo certificate. No idea if the certificate is the reason. Server is running NanoHTTPD. – Stefan Reich Jan 03 '20 at 12:05
  • Does this answer your question? [Resolving javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed Error?](https://stackoverflow.com/questions/9619030/resolving-javax-net-ssl-sslhandshakeexception-sun-security-validator-validatore) – rogerdpack Feb 22 '21 at 16:26

10 Answers10

59

I have used the below code to override the SSL checking in my project and it worked for me.

package com.beingjavaguys.testftp;

import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.net.URLConnection;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.cert.X509Certificate;

/**
 * Fix for 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
 */
public class ConnectToHttpsUrl {
    public static void main(String[] args) throws Exception {
        /* Start of Fix */
        TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
            public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; }
            public void checkClientTrusted(X509Certificate[] certs, String authType) { }
            public void checkServerTrusted(X509Certificate[] certs, String authType) { }

        } };

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

        // Create all-trusting host name verifier
        HostnameVerifier allHostsValid = new HostnameVerifier() {
            public boolean verify(String hostname, SSLSession session) { return true; }
        };
        // Install the all-trusting host verifier
        HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
        /* End of the fix*/

        URL url = new URL("https://nameofthesecuredurl.com");
        URLConnection con = url.openConnection();
        Reader reader = new InputStreamReader(con.getInputStream());
        while (true) {
            int ch = reader.read();
            if (ch == -1) 
                break;
            System.out.print((char) ch);
        }
    }
}
Kishore Kumar
  • 909
  • 2
  • 10
  • 15
  • Doesn't obey the contract. – user207421 Mar 16 '16 at 02:21
  • In your call to `sc.init()`, the third argument may be `null`. (A default value will be supplied.) – kevinarpe May 24 '17 at 09:09
  • 1
    Thanks, this fix will ignore all invalid certificates. Which is very useful when the certificate is auto-renewed every 3 months, such as the Let's Encrypt certicates, and you can't really manually install the certificate in the java trust store every 3 months ... – fnicollet Jul 05 '17 at 10:04
  • This works only for HTTP, right? But not SMTP. I tested this with SMTP, didn't do anything (still got the same cert errors ... until I added the cert to the keystore, eventually). – KajMagnus May 29 '18 at 08:56
  • @fnicollet: You are not supposed to install every single leaf certificate which change all the time (you don’t do that with your browser!), you are supposed to install only the root CA certificate of Let’s Encrypt (which is valid for many years). – Mormegil Aug 11 '22 at 09:26
56

If you want to ignore the certificate all together then take a look at the answer here: Ignore self-signed ssl cert using Jersey Client

Although this will make your app vulnerable to man-in-the-middle attacks.

Or, try adding the cert to your java store as a trusted cert. This site may be helpful. http://blog.icodejava.com/tag/get-public-key-of-ssl-certificate-in-java/

Here's another thread showing how to add a cert to your store. Java SSL connect, add server cert to keystore programmatically

The key is:

KeyStore.Entry newEntry = new KeyStore.TrustedCertificateEntry(someCert);
ks.setEntry("someAlias", newEntry, null);
Community
  • 1
  • 1
km1
  • 2,383
  • 1
  • 22
  • 27
20

Set validateTLSCertificates property to false for your JSoup command.

Jsoup.connect("https://google.com/").validateTLSCertificates(false).get();
Synesso
  • 37,610
  • 35
  • 136
  • 207
Zahid Hasan
  • 211
  • 2
  • 4
10

If the issue is a missing intermediate certificate, you can enable Oracle JRE to automatically download the missing intermediate certificate as explained in this answer.

Just set the Java system property -Dcom.sun.security.enableAIAcaIssuers=true

For this to work the server's certificate must provide the URI to the intermediate certificate (the certificate's issuer). As far as I can tell, this is what browsers do as well and should be just as secure - I'm not a security expert though.

Edit: If I recall correctly, this seems to work at least with Java 8 and is documented here for Java 9.

Ben Romberg
  • 705
  • 8
  • 8
7

FWIW, on Ubuntu 10.04.2 LTS installing the ca-certificates-java and the ca-certificates packages fixed this problem for me.

slim
  • 2,545
  • 1
  • 24
  • 38
  • 1
    Omg after 6 hours fighting with my old Ubuntu 10.04 VM, this fixed that pesky error. This release is so old I had to modify sources.list as those package returned 404 https://askubuntu.com/questions/805523/apt-get-update-for-ubuntu-10-04 – jpp1jpp1 Jun 14 '17 at 20:36
6

I got the same error while executing the below spring-boot + RestAssured simple test.

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import static com.jayway.restassured.RestAssured.when;
import static org.apache.http.HttpStatus.SC_OK;

@RunWith(SpringJUnit4ClassRunner.class)
public class GeneratorTest {

@Test
public void generatorEndPoint() {
    when().get("https://bal-bla-bla-bla.com/generators")
            .then().statusCode(SC_OK);
    }
}

The simple fix in my case is to add 'useRelaxedHTTPSValidations()'

RestAssured.useRelaxedHTTPSValidation();

Then the test looks like

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import static com.jayway.restassured.RestAssured.when;
import static org.apache.http.HttpStatus.SC_OK;

@RunWith(SpringJUnit4ClassRunner.class)
public class GeneratorTest {

@Before
public void setUp() {
   RestAssured.useRelaxedHTTPSValidation();
}


@Test
public void generatorEndPoint() {
    when().get("https://bal-bla-bla-bla.com/generators")
            .then().statusCode(SC_OK);
    }
}
Praveen
  • 1,387
  • 1
  • 12
  • 22
3

If you're using CloudFoundry then you'd have to explicitly push the jar along with the keystore having the certificate.

Smart Coder
  • 1,435
  • 19
  • 19
0

I also faced this issue. I was having JDK 1.8.0_121. I upgraded JDK to 1.8.0_181 and it worked like a charm.

Osanda Deshan
  • 1,473
  • 3
  • 14
  • 30
0

I also came across the same issue. I was trying to build the project with a clean install goal. I simply changed it to clean package -o in the run configuration. Then I re-built the project and it worked for me.

Kirby
  • 15,127
  • 10
  • 89
  • 104
0

I also have the same problem on Apache Tomcat/7.0.67 and Java JVM Version: 1.8.0_66-b18. Just upgrading to JRE 1.8.0_241 it seems the issue was solved.

espajava
  • 73
  • 1
  • 1
  • 9