Reputation: 396
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
Reputation: 3889
Based on your question it looks like you have the following requirements:
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