5

I am writing a routine to access a remote server. This server I am connecting to requires mutual authentication so I have to provide a keystore, and while I'm at it I'd like to put a proper truststore in place as well.

I can find plenty of tutorials on how to create a keystore with keytool and multiple ways to get an Apache HTTP client to recognize it, but not where to store it in a Tomcat environment so that the application can find it. Somehow putting it in the application's war file seems like a bad idea to me.

Again, this is not to permit Tomcat to handle inbound https connections - I have a reverse proxy set up by our admin team for that. I'm creating outgoing https connections that require mutual authentication, i.e., both accepting a self-signed destination server certificate, and providing my server's self-signed client certificate.

Where do you store the actual keystore and truststore files in a Tomcat environment for use by a web application?

Matt Thompson
  • 773
  • 1
  • 10
  • 26
  • What exactly do you mean by a 'proper truststore' that isn't already met by the one supplied with Java? – user207421 Nov 06 '14 at 02:17
  • That's off topic, but the service I am connecting to provides a self-signed certificate which is not acceptable to the cacert default. I currently "accept all" but they've turned on mutual and now I have to provide my own client self-signed as well, so if I have to add the plumbing for keystore then I should use the opportunity to add the truststore support as well. First I need to know where to put the darned things. – Matt Thompson Nov 06 '14 at 02:22
  • As far I know ,the keystore file can be anywhere in the directory path which the server has access to read.In server.xml of tomcat you need to specify the directory path in Connector port 8443 in the attribute Keystorefile. – Amar Nov 06 '14 at 03:26
  • @Amz The keystore used for a client TLS certificate has nothing to do with Tomcat's `` configuration. This is not a Tomcat configuration problem. – Christopher Schultz Nov 06 '14 at 04:09

2 Answers2

5

You can put your keystore wherever you want, as long as you know how to tell httpclient where to load the keystore.

That, of course, is the trick.

Using Apache httpclient for https

Buried in all that mess of code in the accepted answer is the key (ha!) to using httpclient with your own custom keystore. It's unfortunate that httpclient doesn't have a simple API like "here's the path to my keystore file, now use it" or "here are the bytes for my keystore, use those" (if you wanted to load the keystore from the ClassLoader or whatever), but that seems to be the case.

The honest truth is that using keystores and truststores in Java is messy business, and there's usually no way around it. Having written a client-cert-capable HTTP client myself using nothing other than HttpsURLConnection and then also adding raw-socket components to that, I know how painful it is.

The code in the above-linked article is fairly straightforward if a bit verbose. Unfortunately, you're going to need to make it a lot messier for production-quality code because you've got to do error-checking, etc. for every step of the process to make sure your service doesn't fall-over when you are trying to set up the various stores and make your connection.

Christopher Schultz
  • 20,221
  • 9
  • 60
  • 77
  • Please see my post, which is basically a comment to your answer. +1 to your answer otherwise. – ok2c Nov 06 '14 at 09:59
1

This is basically a comment to Christopher Schultz's answer, but since it involves some code snippets please excuse my putting it here

It's unfortunate that httpclient doesn't have a simple API like "here's the path to my keystore file, now use it" or "here are the bytes for my keystore, use those" (if you wanted to load the keystore from the ClassLoader or whatever), but that seems to be the case

This is how one can configure Apache HttpClient 4.3 to use a specific trust store for SSL context initialization.

SSLContext sslContext = SSLContexts.custom()
        .loadTrustMaterial(trustStore)
        .build();
CloseableHttpClient client = HttpClients.custom()
        .setSslcontext(sslContext)
        .build();

One can load trust material from a resource like that

URL resource = getClass().getResource("/com/mycompany/mystuff/my.truststore");
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
InputStream inputStream = resource.openStream();
try {
    trustStore.load(inputStream, null /*usually not password protected*/);
} finally {
    inputStream.close();
}
yoozer8
  • 7,361
  • 7
  • 58
  • 93
ok2c
  • 26,450
  • 5
  • 63
  • 71
  • Thanks for the updated code snippets. If the `HttpClient` folks didn't hide their Javadoc, I might have been able to search for any applicable methods (or, in this case, builders) that existed. :( – Christopher Schultz Nov 06 '14 at 13:04