Java HTTPS to a server with a self-signed certificate

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.

One thought on “Java HTTPS to a server with a self-signed certificate”

  1. I was trying to import the public cert of selfsigned into existing java cacerts keystore (which is default used by the java), but it didn’t until I did above. My understanding is all it needs is to trust the cert that I did by importing.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.