Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I add a new certificate to the keystore without restarting the JVM?

I'd like to import a new certificate into the keystore without restarting a running service. Is that possible?

Alternatively, is it possible to specify a certificate to use that's not in the keystore for a specific URL connection?

like image 670
Chung Wu Avatar asked Oct 19 '10 01:10

Chung Wu


People also ask

Do I need to restart after adding certificates?

You would only need to restart the Server if you manually generate the SSL certificate due to exception conditions such as changes in hostname or host IP in your etc/hosts.

How do I add a certificate to my JVM default trust store?

Import the certificate file into the JVM truststore using the following keytool command: $ keytool -importcert -alias [alias_of_certificate_entry] -file [path_to_certificate_file] -trustcacerts -keystore /path/to/truststore -storetype [storetype]


1 Answers

Turns out you can specify specific certificates to use for specific URL fetches; essentially, you need to create your own TrustManager and swap it in, like so:

public String fetchFromUrl(String urlString) throws IOException {
  URL url = new URL(urlString);
  URLConnection conn = url.openConnection();

  if (conn instanceof HttpsURLConnection && shouldSubstituteCert(url)) {
    HttpsURLConnection sslConn = (HttpsURLConnection) conn;
    try {
      SSLContext context = SSLContext.getInstance("SSL");
      context.init(null, new TrustManager[] {new MyTrustManager()}, null);
      sslConn.setSSLSocketFactory(context.getSocketFactory());
    } catch (Exception e) {
      e.printStackTrace();
      throw new IOException("Error creating custom keystore", e);
    }
  }

  return readAll(conn.getInputStream());
}

private static class MyTrustManager implements X509TrustManager {
  private final X509TrustManager trustManager;
  public MyTrustManager() throws 
      KeyStoreException, NoSuchAlgorithmException, 
      CertificateException, IOException {

    // Load a KeyStore with only our certificate
    KeyStore store = KeyStore.getInstance(KeyStore.getDefaultType());
    store.load(null, null);
    Certificate cert = loadPemCert();
    store.setCertificateEntry("me.com", cert);

    // create a TrustManager using our KeyStore
    TrustManagerFactory factory = TrustManagerFactory.getInstance(
        TrustManagerFactory.getDefaultAlgorithm());
    factory.init(store);
    this.trustManager = getX509TrustManager(factory.getTrustManagers());
  }

  public void checkClientTrusted(X509Certificate[] chain, String authType)
      throws CertificateException {
    trustManager.checkClientTrusted(chain, authType);
  }

  public void checkServerTrusted(X509Certificate[] chain, String authType)
      throws CertificateException {
    trustManager.checkServerTrusted(chain, authType);
  }

  public X509Certificate[] getAcceptedIssuers() {
    return trustManager.getAcceptedIssuers();
  }

  private static X509TrustManager getX509TrustManager(TrustManager[] managers) {
    for (TrustManager tm : managers) {
      if (tm instanceof X509TrustManager) {
        return (X509TrustManager) tm;
      }
    }
    return null;
  }

  private Certificate loadPemCert() 
      throws CertificateException, IOException {
    InputStream stream = 
      this.getClass().getClassLoader().getResourceAsStream("cert.pem");

    CertificateFactory factory = CertificateFactory.getInstance("X.509");
    return factory.generateCertificate(stream);
  }
}
like image 200
Chung Wu Avatar answered Sep 29 '22 22:09

Chung Wu