Java HTTPS to a server with a self-signed certificate
December 07, 2015 [Java]Nothing is easy in Java, and nothing is more disproportionately non-easy than downloading something. If you add SSL to the equation, it becomes unfeasible for any human to navigate the twisted passages of the Java API, so here is a tiny fragment of map I have pieced together using the Internets.
Updated to link to my article about how to create a self-signed cert and trust store file.
If you have a server that you want to download something from, and you need to use SSL (i.e. your URL starts with "https://"), and it has a self-signed certificate, you will need to get hold of a "trust store" file (a .pkcs12 or .jks file) that tells Java it can trust your server. If you need to set this up yourself, try my article how to create a self-signed cert and trust store file.
Note that this will only work if the self-signed certificate has the correct Subject Alternative Name (the hostname of the server) embedded in it. The article linked above tells you how to achieve this.
Assuming you have somehow magicked up a trust store file (let's call it trust.pkcs12), and you know the password for it (let's assume it's 000000, as we set up in the linked article), we can continue.
Let's write a little program Get.java that fetches a URL and tells us whether we got an error with the SSL connection:
import java.net.URL; public class Get { public static void main( String[] args ) throws Exception { try { new URL( args[0] ).openConnection().getInputStream(); System.out.println( "Succeeded." ); } catch( javax.net.ssl.SSLHandshakeException e ) { System.out.println( "SSL exception." ); } } }
Compile this with:
javac Get.java
And run it with:
$ java Get https://google.com Succeeded.
This should succeed, because Java knows it can trust the benevolent Google deity, as we all do.
Now try it against your server with a self-signed (or otherwise untrusted) certificate and you should see an error:
$ java Get https://selfsigned.example.com SSL exception.
And now for the answer you were waiting for. You don't need to use keytool. Repeat: you don't need to use keytool. To run Java telling it to trust your server, just do this:
$ java \ -Djavax.net.ssl.trustStore=/path/to/trust.pkcs12 \ -Djavax.net.ssl.trustStorePassword=000000 \ Get https://selfsigned.example.com Succeeded.
That's it.
If it doesn't work, try:
$ java \ -Djavax.net.debug=SSL,trustmanager \ -Djavax.net.ssl.trustStore=/path/to/trust.pkcs12 \ -Djavax.net.ssl.trustStorePassword=000000 \ Get https://selfsigned.example.com
and you should see some debugging output that may help.
Another useful debugging command is:
openssl s_client -showcerts -connect selfsigned.example.com
Hope it helps.