0

Here is the example that doesn't work:

public class Temp {
  public static void main(String[] args) throws Exception {
    new URL("https://float.software").openConnection().getInputStream();
  }
}

Going to https://float.software/ in my browser works just fine. But java throws this 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 sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
    at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1937)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1478)
    at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:212)
    at sun.security.ssl.Handshaker.processLoop(Handshaker.java:957)
    at sun.security.ssl.Handshaker.process_record(Handshaker.java:892)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1050)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1363)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1391)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1375)
    at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:563)
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1512)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1440)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
    at fb.Temp.main(Temp.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(PKIXValidator.java:387)
    at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
    at sun.security.validator.Validator.validate(Validator.java:260)
    at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
    at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)
    at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1460)
    ... 13 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:145)
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:131)
    at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382)
    ... 19 more

When I've looked at other answers they all talk about installing certificates. I don't think I should have to install a certificate. This isn't self-signed. It uses a real certificate authority. Python downloads this URL just fine. So does chrome. Java doesn't.

EDIT: For those saying that Comodo is a newer authority not yet added to java, it was added as a root in Java 5. See http://forums.comodo.com/comodo-cleaning-essentials-killswitch-autoruns-cce/how-do-i-unblock-a-processexecutable-t17086.0.html

satnam
  • 10,719
  • 5
  • 32
  • 42

2 Answers2

4

If you look at the SSLLabs report for this domain you will see two possible certification path:

  • The first (shorter) one ends expects that the "COMODO RSA Certification Authority" is trusted by the client. Although this CA is valid since 2010 it got only recently (about half year) ago included in browser like Firefox, see https://bugzilla.mozilla.org/show_bug.cgi?id=1062589. You will not find this CA as trusted outside most browsers, i.e. in the trust stores shipped with Java or similar (Java does not use the systems trust store).
  • The other longer certification path expects a trusted root CA "AddTrust External CA Root ". This CA is included for years in browsers and OS and is probably also in the Java trust store. Unfortunately to verify this certification path an additional chain certificate is needed which is not provided by the server (marked as "Extra Download" in the SSLLabs report).

Since Java does not include the Root-CA from the first path it is not able to verify it. And it fails to verify the second path because of the missing chain certificate. This means the verification fails.

Python downloads this URL just fine. So does chrome.

Chrome has the newer root-CA. Also Chrome attempts to download missing chain certificates, while Java, Python etc do not.

Python only started recently to verify certificates by default, i.e. since 2.7.9+ and 3.4.3+. All previous (which means most installed) versions did not validate the certificates (except when using the requests library) so it just worked (typical problem: nobody notices that's insecure because it seems to work). See https://www.python.org/dev/peps/pep-0476/.

Steffen Ullrich
  • 114,247
  • 10
  • 131
  • 172
  • Seems like there are two solutions: 1. add comodo authority certificate to java 2. have java auto-download certs -- which do you think is easier? – satnam May 27 '15 at 19:24
  • The first is just adding a new trusted CA which is not hard. The other would be to change the certificate validation part of Java which is probably not what you want to do and I'm sure it will not be easy. – Steffen Ullrich May 27 '15 at 19:33
  • Is there an easy way of adding a trusted CA at runtime? I don't want to have to install the certificate on every linux server I deploy to. – satnam May 27 '15 at 20:06
  • I'm not familiar with Java in this regard but according to http://stackoverflow.com/questions/1650596/how-do-i-import-a-new-java-ca-cert-without-using-the-keytool-command-line-utilit it does not look simple . But I can say that with Perl it can be done within a single line :) – Steffen Ullrich May 27 '15 at 20:18
  • You could contact the site owner to see if they are willing to add the intermediate cert (the one with Fingerprint: f5ad0bcc1ad56cd150725b1c866c30ad92ef21b0) to the chain – Anand Bhat May 29 '15 at 01:39
1

You may have to update your cacerts file if you're using an old version of Java. float.software's SSL cert is signed by "COMODO RSA Certification Authority", which has only be valid since Feb 2014. It's possible your Java install is older than that.

Also, watch out on Python. Not all HTTPS implementations verify the remote certificate.

Alastair McCormack
  • 26,573
  • 8
  • 77
  • 100
  • You're right. I've just checked JDK 8 and it doesn't contain "COMODO RSA Certification Authority". You will have to add it to cacerts – Alastair McCormack May 27 '15 at 19:53
  • Is there a way to add it to cacerts at runtime? I don't want to have to install the certificate on every linux server I deploy to. – satnam May 27 '15 at 20:06