1

My Java program uses GitHub's raw address to access a version file to get the latest version. This address is in the format https://raw.github.com/user/repository/branch/version_file

During testing stages, I had no problems using this with the following code:

currentVersion = new Version(plugin.getDescription().getVersion());

URL url = new URL("https://raw.github.com/zonedabone/CommandSigns/master/VERSION");
URLConnection connection = url.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
newestVersion = new Version(in.readLine());

if (currentVersion.compareTo(newestVersion) < 0)
    newAvailable = true;

However, some users have complained of the following error:

sun.security.validator.ValidatorException:
  PKIX path building failed:
    sun.security.provider.certpath.SunCertPathBuilderException:
      unable to find valid certification path to requested target

Java is complaining that it can't validate the SSL certificate. GitHub's certificate is verified by DigiCert, but apparently some Java builds won't identify this.

I have read there are two ways to overcome this: adding the certificate to the TrustStore and disabling the validation altogether.

The answers suggested on StackOverflow either make use of an allow-all TrustStore, which would be a really bad idea considering it's not within bounds of a 'test environment', or if they show how to add the certificate, they usually link to a broken web page.

Can somebody provide new information?

Chris Watts
  • 6,197
  • 7
  • 49
  • 98
  • This question has been asked and answered _countless_ times on SO and the web in general. Please do a Google search on "java self-signed certificate" and delete this question. – Jim Garrison Sep 13 '12 at 17:19
  • possible duplicate of [How do I accept a self-signed certificate with a Java HttpsURLConnection?](http://stackoverflow.com/questions/859111/how-do-i-accept-a-self-signed-certificate-with-a-java-httpsurlconnection) – Jim Garrison Sep 13 '12 at 17:21
  • @JimGarrison, true, unfortunately that google search will lead to a number of answers that suggest using a trust manager that trusts any cert... – Bruno Sep 13 '12 at 17:22
  • @Bruno Agreed, I've upvoted your answer. – Jim Garrison Sep 13 '12 at 17:29
  • 1
    @JimGarrison Might not be a duplicate. The question wasn't actually asking about a self-signed certificate, but one signed by DigiCert; and "DigiCert High Assurance EV Root CA" (with thumbprint 5f b7 ee 06 ...) is in Java's cacerts file, according to "keytool -list". So it should have worked, and something else is going wrong that isn't explained by the current answers. – gatkin Mar 27 '13 at 16:33

2 Answers2

4

First the theory... As the JSSE Reference Guide says:

IMPORTANT NOTE: The JDK ships with a limited number of trusted root certificates in the /lib/security/cacerts file. As documented in keytool, it is your responsibility to maintain (that is, add/remove) the certificates contained in this file if you use this file as a truststore.

Depending on the certificate configuration of the servers you contact, you may need to add additional root certificate(s). Obtain the needed specific root certificate(s) from the appropriate vendor.

Users should maintain the list of CA certificates themselves. A number of people won't know how to do it, unfortunately. They could use another JRE's cacerts file (more recent) into their own installation.

You could use a trust manager that trusts any certificate and use it specifically for that connection, but that's not a good idea, since it opens the connection to potential MITM attacks. There are enough examples of code for this insecure solution around.

The best solution, if you want to trust a specific certificate, is to load it correctly using a specific truststore, as described in this answer. You could even load this trust store from an InputStream from the classloader if you want to bundle it with your application.

Alternatively, where possible, you could use the OS trust store directly. On Windows, you can load the Windows-ROOT keystore as described in this article. On OSX, you can load a KeychainStore.

Community
  • 1
  • 1
Bruno
  • 119,590
  • 31
  • 270
  • 376
  • The first solution you suggested seems quite reasonable. I'm now away for a week so I'll have to let the other plugin developer to take a look at this before I accept it. The second answer wouldn't be possible as the plugin is non operating system dependent. – Chris Watts Sep 14 '12 at 07:53
-2

You can implement an HttpsUrlConnection with "all"-TrustManager

like http://bitsandcodes.blogspot.de/2010/08/create-trust-manager-that-trust-all-ssl.html

  • Are there any better examples? This one uses deprecated types such as SSLContext and uses JSSESocketFactory which cant be resolved in my IDE. – Chris Watts Sep 13 '12 at 16:14
  • Edit: the types aren't deprecated, I was just making the wrong imports. However, I still can't use JSSESocketFactory as I am not using org.apache. – Chris Watts Sep 13 '12 at 16:21
  • That `JSSESocketFactory` is specific to Axis, which has nothing to do with the question. In addition, it's a bad idea to trust all certificates blindly. – Bruno Sep 13 '12 at 17:16