Click here to Skip to main content
15,883,901 members
Articles / Programming Languages / Java
Tip/Trick

Adding CAs at Runtime in Java

Rate me:
Please Sign up or sign in to vote.
0.00/5 (No votes)
9 Jul 2016MIT3 min read 17.9K   1  
CompositeJKS allows you to load a custom Java KeyStore into the SSL Context without replacing the system CA list.

Many companies host their own internal Certificate Authority (CA). These services issues X.509 certificates, e.g. for use in HTTPS connections. In order for web browsers and programmatic clients to trust connections to servers using such internal certificates, the appropriate root certificate needs to be imported into a "trusted root certificates" list.

The precise location and format of this list depends on the operating system, programming language and tool in use. For example, Internet Explorer and Google Chrome use the Windows certificate store when running on Windows while Mozilla Firefox uses its own private certificate store regardless of the operating system it is running on.

Here, I would like to illustrate the particular challenges that arise when consuming internally-signed web-services in Java clients. Like Mozilla Firefox, Java uses its own certificate store rather than relying on an operating system implementation. On Debian-based Linux distributions, this file is usually located at /etc/ssl/certs/java/cacerts. On Windows, the file can be found at path like C:\Program Files\Java\jre1.8.0_77\lib\security\cacerts.

These files use the Java KeyStore file format and can be modified using the keytool command-line tool. To add your own CA to the list of trusted roots, you can run:

keytool -import -trustcacerts -file yourca.pem -alias yourca 
-keystore [Location of the certificate store as described above]

When prompted for a password, use the default password set by Java: changeit

Changing this password is neither required nor recommended, since this particular Java KeyStore file only contains public keys of CAs and therefore stores no private data that required protection.

Unfortunately, there are a few problems with modifying this global KeyStore. On Windows, installation of new Java versions will replace the modified file with the default again. On both Windows and Linux, this modification requires administrative privileges. These issues motivate the need for a way to apply application-specific modifications to the list of trusted CAs.

The Java system property javax.net.ssl.trustStore can be used to specify an alternate path to load the cacerts file. You can create your own local copy of the default file and apply modifications to it using keytool. Then, you can launch your application like this:

java -Djavax.net.ssl.trustStore=/path/to/my/cacerts -jar myapp.jar

If the application in question is a web-service running in Tomcat, you can instead add this line to /etc/default/tomcat8:

JAVA_OPTS="${JAVA_OPTS} -Djavax.net.ssl.trustStore=/path/to/my/cacerts"

Another possibility is to set the Java system property within the startup code of the application itself using:

Java
System.setProperty("javax.net.ssl.trustStore", "/path/to/my/cacerts");

Note that this last option requires the KeyStore to be a real file on-disk and not a file embedded within a JAR.

All of the aforementioned options have one major drawback: By effectively forking the upstream default cacerts file, your application does not get any future updates to "public" CAs. Similarly, application-specific KeyStores will not include any customizations administrators make to the global KeyStore.

We have developed a small Java library to help with this: CompositeJKS allows you to load a custom Java KeyStore into the SSL Context without replacing the system CA list. The system and the custom KeyStores are merged into a composite view.

To use this library, add the following to your Maven pom.xml:

XML
<dependency>
  <groupId>com.oneandone</groupId>
  <artifactId>composite-jks</artifactId>
  <version>1.0</version>
</dependency>

You can then use a call like:

Java
SslContextUtils.mergeWithSystem("/path/to/my/cacerts");

CompositeJKS also supports loading JKS files embedded in the JAR. Place your file in src/main/resources/ to let Maven embed it and then use a call like:

Java
SslContextUtils.mergeWithSystem(getClass().getClassLoader().getResourceAsStream("cacerts")));
This article was originally posted at https://github.com/1and1/CompositeJKS

License

This article, along with any associated source code and files, is licensed under The MIT License


Written By
Software Developer
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
-- There are no messages in this forum --