Server and Client Certificates in HTTPS for Apache Client in Java

7 Jan 2012

I was working on a client to access a RESTful (representation state transfer AKA http) web service. Maybe that’s just the buzzword of choice these days, but the system seems to conform to Wikipedia’s list of REST architecture constraints. I’m reusing version 4.1.2 libraries provided by the Apache HttpComponents project. All straightforward so far, right?

Two complicating factors made this a bit interesting. First, the server requires access via HTTPS, and for that it uses a self-signed server certificate. This requirement can be met in a couple of ways: either the HttpClient can be told to trust all servers no matter what, or the server certificate can be cached locally for comparison. Apache offers example code to demonstrate caching a self-signed certificate so that was no significant problem.

The second requirement, presenting a user certificate to the server, was a bit tricker. I found example code at the Apache site, but it was for version 3 and no longer works in v4. Stackoverflow offered pieces of code but not the full solution. A blog post by Tim Sawyer was extremely helpful in pointing out that this scenario requires both a *keystore* and a *truststore*, but I still struggled to get the keystore and truststore files set up appropriately. I find the Java keytool fairly inscrutable but that’s prolly because I’m not a crypto person. And just to make it fun, the javadoc for the critical constructor in the SSLSocketFactory class is utterly free of any description, and the parameter names are barely helpful.

I had to save the server’s certificate in a Java keystore file. Because this file holds the server info, the proper term is a *truststore*, which is the term used in the Apache HttpClient javadoc. The keystore must show that it has a “trustedCertEntry.” This is the incantation I used to build a server truststore file in Java Keystore (“JKS”) format using the keytool command that comes with Java; after keytool shows the details you have to tell it to trust the certificate:

I had to save the client’s private key in a Java keystore file, and it must appear in that keystore as a “PrivateKeyEntry” (not a certificate entry). The client key was available in a PKCS12 (“.p12”) format and that was critical. I learned from googling that keytool can read a PKCS12 file and import its contents appropriately. This is the incantation I used to build a client keystore file in JKS format using the keytool command; again you have to approve import of the data:

Along the way I hit various stumbling blocks of course.

  1. Initially I supplied the wrong server certificate, and I hit this exception:

At least once I gave the wrong password for a keystore and this exception is what happens:

While I knew that the private key is protected by a password, I didn’t quite grasp that this protection is preserved when it’s imported into the destination keystore, which of course is protected by a different password. So I supplied the correct password to load the keystore, but not the right password to decrypt the private key within the keystore. That yielded the following exception.

When I botched the user private key certificate by supplying a keystore file with the wrong content, I hit this exception:

I used Java version 1.6.0_20, and apparently this VM has an SSL implementation that blocks SSL renegotation, which presented itself as this exception:

I frankly don’t understand all the ramifications of this, but again googling yielded the answer. Supposedly other versions don’t have this problem but I have not yet tested them. Launching the program with this additional VM argument turns this off. But note that his only appears *if some other problem is also present*; it’s not necessary when all the keystores and passwords are correct.

Putting all the pieces together yields the following demonstration code. It traps all the exceptions that I hit and tries to give helpful messages :). Forgive me for assuming UTF-8 encoding for the server response! Please drop me a line if it helps you.



Homeowner in northern New Jersey.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store