79

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,561
  • 8
  • 43
  • 58
  • 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
  • 15
    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

56

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
  • 879
  • 1
  • 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
  • Thanks this worked for me... – Sudhakar Kummarasetty Oct 26 '21 at 11:44
55

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,313
  • 1
  • 18
  • 27
20

Set validateTLSCertificates property to false for your JSoup command.

Jsoup.connect("https://google.com/").validateTLSCertificates(false).get();
Synesso
  • 36,000
  • 33
  • 126
  • 200
Zahid Hasan
  • 211
  • 2
  • 4
6

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

slim
  • 2,497
  • 1
  • 24
  • 37
  • 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,319
  • 1
  • 12
  • 21
5

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
  • 585
  • 6
  • 7
2

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

Smart Coder
  • 931
  • 8
  • 15
1

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
  • 14,280
  • 7
  • 86
  • 100
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,365
  • 2
  • 12
  • 28
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
  • 63
  • 1
  • 1
  • 9