Sunday, March 16, 2014

Calling a secure HTTPS webservice from a Java client

Over the last decade, I have seen so many developers struggle with digital certificates when they have to call a secure webservice. A lot of confusion arises when a secure https webservice call is made from a servlet running in Tomcat. This is because the exception stack shows a SSLHandshake exception and then developers keep fiddling with the Tomcat connector configuration as stated here.

But when we make a connection to a secure server, what we need is to trust the digital certificate of the server. If the digital certificate of the server has been signed by a trusted root authority such as 'Verisign', 'eTrust', then our default Java Trust Store would automatically validate it. But if the server has a self-signed certificate, then we have to add the server's digital certificate to the trust store.

There are multiple ways of doing this. A long time ago, I had blogged about one option that entails setting the Java system properties. This can be done through code or by setting the Java properties of the JVM during startup. For e.g.


System.setProperty("javax.net.ssl.trustStore", trustFilename );
System.setProperty("javax.net.ssl.trustStorePassword", "changeit") ;



Different AppServers (WebSphere, Weblogic, etc.) may provide different ways to add certs to the trust store.

Another option is to create a cert-store (filename:jssecacerts) that contains the digital cert of the server and copy that cert-store file to the “$JAVA_HOME\jre\lib\security” folder. There is also a nifty program called InstallCert.java that downloads the certificate and creates the cert-store file. A good tutorial on the same is available here.
I have also created a mirror of InstallCert.java here. This program cam be run without any dependencies on external libraries and I have found it to be very handy.

So what is the difference between setting the TrustStore system property and adding the jssecacerts file?
Well, the documentation of JSSE should help our understanding here. The TrustManager performs the following steps to search for trusted certs:
1.  system property javax.net.ssl.trustStore
2.  $JAVA_HOME/lib/security/jssecacerts
3. $JAVA_HOME/lib/security/cacerts (shipped by default)

It's important to note that is the TrustManager finds the jssecacerts file, then it would not read cacerts file! Hence it may be a better option to add the server digital cert to the cacerts keystore file. To add a certificate to a keystore, there is a nice GUI program called portecle. Alternatively do it from the command prompt using the keytool command as stated here