2

I am trying to connect to a webpage to gather information, and I am using jsoup to parse the HTML. However, whenever I try to connect to the URL to download the source, I get an error saying something about the PKIX build path. I've looked around, and everything I've found says to add the website's CA Root certificate to my truststore, which I did, but the problem persists (The CA Root cert was already there). I am able to connect to the website through a web browser, but not through a URL class. Here is the most basic code I could write which would produce the error.

public class URLConnectStart {
    public static void main(String[] args) {
        try {
            URL u = new URL("https://ntst.umd.edu/soc/");
            u.openStream();     
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Here is the error

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.Alerts.getSSLException(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.fatal(Unknown Source)
    at sun.security.ssl.Handshaker.fatalSE(Unknown Source)
    at sun.security.ssl.Handshaker.fatalSE(Unknown Source)
    at sun.security.ssl.ClientHandshaker.serverCertificate(Unknown Source)
    at sun.security.ssl.ClientHandshaker.processMessage(Unknown Source)
    at sun.security.ssl.Handshaker.processLoop(Unknown Source)
    at sun.security.ssl.Handshaker.process_record(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
    at sun.net.www.protocol.https.HttpsClient.afterConnect(Unknown Source)
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(Unknown Source)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(Unknown Source)
    at java.net.URL.openStream(Unknown Source)
    at URLConnectStart.run(URLConnectStart.java:14)
    at URLConnectStart.main(URLConnectStart.java:8)
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(Unknown Source)
    at sun.security.validator.PKIXValidator.engineValidate(Unknown Source)
    at sun.security.validator.Validator.validate(Unknown Source)
    at sun.security.ssl.X509TrustManagerImpl.validate(Unknown Source)
    at sun.security.ssl.X509TrustManagerImpl.checkTrusted(Unknown Source)
    at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source)
    ... 16 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.provider.certpath.SunCertPathBuilder.build(Unknown Source)
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(Unknown Source)
    at java.security.cert.CertPathBuilder.build(Unknown Source)
    ... 22 more

Info from chrome regarding the website's cert

Info from chrome regarding the website's cert

Any help would be appreciated. This is not a critical application, so security is not all that important, but if I can maintain security I would rather do so. Regardless, all I want to be able to do is download the HTML for this website through code.

Thank you.

Jtvd78
  • 4,135
  • 5
  • 20
  • 21

2 Answers2

4

The website does not provide an intermediate certificate that is required to complete the certificate chain. Some user agents/ browsers have a functionality called AIA chasing where they download the necessary intermediates but the Java client isn't one of them.

SSL Labs resport showing incomplete certificate chain

If you are the site admin, the correct way to address this is to supply the intermediate certificate so that the complete chain is sent. Even if you are an end user, do consider contacting the website to fix this issue. Folks using the Android browsers will also be unable to access this site without accepting a security warning due to this issue.

In the meantime, if you'd like to address this in your client, you can download the missing intermediate cert and add it to your Java certificate store.

Anand Bhat
  • 5,591
  • 26
  • 30
  • 1
    This comment was very helpful in understanding the problem, but for some reason I couldn't get the problem to resolve. I was able to add the cert to the keystore, but when I run the program I still get the same error. Is there supposed to be more than 1 entry in the keystore, or do I need to add something to my code? – Jtvd78 Oct 22 '15 at 22:22
  • The certificate store should normally contain all root CA certificates that come bundled with the JDK/ JRE in addition to whatever else you may have added. My default cacert file (Java 1.8.0_66) had 93 certificates and after adding the intermediate to this store, I was able to connect to the URL with your code snippet. – Anand Bhat Oct 22 '15 at 23:33
  • Okay, I found out what I was doing wrong. I was creating a new cacerts in the bin folder instead of using the one in /lib/security. I am able to connect to the website, and I will be contacting the administrators about their certificate problem. Thank you for your help. – Jtvd78 Oct 23 '15 at 03:46
  • 1
    It seems you can activate automatic downloading for intermediate certificate (AIA) using JVM argument `-Dcom.sun.security.enableAIAcaIssuers=true`. See [here](https://security.stackexchange.com/questions/162592/why-do-i-need-to-add-intermediate-ca-certificates-to-jvms-cacerts-file#answer-168061) for more details – Nicolas Mauti Jun 02 '20 at 13:04
1

You can manually install certificates to java keystore.

  • Open chrome and give the URL. in the address bar
  • Click on the Secure with a lock icon.
  • Pop-up window with some option will appear.
  • Choose Certificate -> valid link just below that.
  • Click on the details tab and choose copy to file.
  • Give some name and save it.

First command to clear if any alias is present ( I prefer to run this from JAVA_HOME in windows so the path are relative to this. if you are running from out side please change the path accordingly.

  • keytool -delete -alias "c11" -keystore ../jre/lib/security/cacerts -storepass changeit -noprompt

Now we need to install the certificate

  • keytool -import -file "C:\Certificateert\c1.cer" -keystore ../jre/lib/security/cacerts -alias "c11" -storepass changeit -noprompt

Default password to keystore is changeit

If you have number of certificate add this commands to a text file each of that and save it as bat extension and put to JAVA_HOME\bin or any where you like. Make sure the path mentioned is relative.

if your jre is outside jdk , then provide the path to that.

  • keytool -import -file "C:\Certificate\c6.cer" -keystore "C:\Program Files\Java\jre1.8.0_181\lib\security\cacerts" -alias "c66" -storepass changeit -noprompt
Arundev
  • 1,388
  • 23
  • 22