pjones123
pjones123

Reputation: 396

Install CA root certificate at runtime in JRE 1.8.0_51

I'm working with JRE 1.8.0_51 (I cannot change this), which does not include the root certificate for Let's Encrypt in lib/security/cacerts (it is added in 1.8.0_141)

I need to add the certificate at runtime, and I have found this code to do that:

        try {
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("X509");
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            InputStream keyStoreStream = getClass().getClassLoader().getResourceAsStream("j51_le_ca_cert.jks");
            keyStore.load(keyStoreStream, "changeit".toCharArray());
            trustManagerFactory.init(keyStore);
            TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, trustManagers, null);
            SSLContext.setDefault(sc);

        } catch (Exception e) {
            e.printStackTrace();
        }

This runs without throwing any error, but causes one of following things to happen:

Which of those two events happens varies, seemingly arbitrarily, based on the system and environment in which it is running.

How can I reliably install the certificate alongside the existing certificates?

Upvotes: 2

Views: 1732

Answers (1)

Hakan54
Hakan54

Reputation: 3889

Based on your question it looks like you have the following requirements:

  1. Not possible to upgrade Java, need to stay at v1.8.051
  2. Use the default jdk truststore (cacert)
  3. Add additional trusted certificate to the existing ones during runtime

I think this is possible. What you can do is create two separate TrustManagers and combined them as mentioned here: Registering multiple keystores in JVM. You just need to create a trustmanager from the default jdk truststore (cacert) and one for your own truststore containing the one with lets encrypt and merge that with a CompositeTrustManager as mentioned in that topic. This special TrustManager can be used to create a SSLContext.

I have extracted the code snippet into a library, so if you don mind to use an additional library you can try out the following snippet:

import nl.altindag.ssl.SSLFactory;

import javax.net.ssl.SSLContext;

public class App {

    public static void main(String[] args) {
        SSLFactory sslFactory = SSLFactory.builder()
                .withTrustMaterial("j51_le_ca_cert.jks", "changeit".toCharArray())
                .withDefaultTrustMaterial()
                .withSslContextAlgorithm("SSL")
                .build();

        SSLContext sslContext = sslFactory.getSslContext();
        SSLContext.setDefault(sslContext);
    }

}

You can add the library with the following snippet:

<dependency>
    <groupId>io.github.hakky54</groupId>
    <artifactId>sslcontext-kickstart</artifactId>
    <version>7.0.0</version>
</dependency>

See here for the full documentation and example usages: GitHub - SSLContext Kickstart

I think it is better to upgrade your JDK, but sometimes it is just not possible, so I hope this alternative solution will work for you.

Upvotes: 1

Related Questions