在 JVM 中注册多个密钥库 [英] Registering multiple keystores in JVM

查看:21
本文介绍了在 JVM 中注册多个密钥库的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个应用程序在同一个 java 虚拟机中运行,并且都使用不同的密钥库和信任库.

I have two applications running in the same java virtual machine, and both use different keystores and truststores.

一个可行的选择是使用单个密钥库并将所有其他密钥库导入共享密钥库(例如 keytool -import),但如果我可以为在同一个 jvm 中运行的不同应用程序使用单独的密钥库,这真的有助于我的需求.

A viable option would be use a single keystore and import all the other ones into the shared keystore (e.g. keytool -import), but it would really help my requirements if I could use separate keystores for separate applications running in the same jvm.

我可以将密钥库和信任库设置为 jvm 参数或系统属性,如下所示:

I could set the keystore and truststores to be used as jvm parameters or system properties as follows:

java -Djavax.net.ssl.keyStore=serverKeys 
-Djavax.net.ssl.keyStorePassword=password 
-Djavax.net.ssl.trustStore=serverTrust 
-Djavax.net.ssl.trustStorePassword=password SSLApplication

System.setProperty("javax.net.ssl.keyStore","serverKeys")

但这种方法的问题在于它指定了要在 JVM 级别使用的密钥库/信任库,因此在同一 JVM 中运行的所有应用程序都获得相同的密钥库/信任库.

But the problem with this approach is that it specifies the keystore/truststore to be used at a JVM level, thus all applications running in the same JVM gets the same keystore/truststore.

我还尝试创建自定义 SSLContext 并将其设置为默认值,但它也为在同一 JVM 中运行的所有应用程序设置了上下文.

I have also tried creating a custom SSLContext and setting it as the default, but it also sets the context for all applications running in the same JVM.

SSLContext context = SSLContext.getInstance("SSL");
context.init(kms, tms, null);
SSLContext.setDefault(context);

我希望能够在不修改单个应用程序代码的情况下使用不同的密钥库/信任库.

I want to be able use different keystores/truststores without modifying individual application codes.

除了 jre 中的默认密钥库/证书之外,还可以动态注册多个密钥库到 jvm 中的解决方案会很棒.

A solution that can dynamically register multiple key stores in addition to the default keystore/certs in jre into jvm would be great.

解决方案将以这种方式工作:

The solution will work in this way:

  • 当 JVM 启动时,它会加载所有默认的证书/密钥库来自 jre/certs 文件夹(未指定密钥库时的默认 java 行为).
  • 当应用程序 1 加载时,它会注册其密钥库,
  • 然后,当 App 2 加载时,它会注册其密钥库...

请告诉我您的想法或解决方案.提前致谢!

Please let me know your ideas or solutions. Thanks in advance!

推荐答案

在使用我从 ZZ Coder、sylvarking 和 Software Monkey 收到的代码后,我找到了一个有效的解决方案:

After playing with the code I have received from ZZ Coder, sylvarking and Software Monkey, I have found a solution that works:

首先,我编写了一个 X509KeyManager,它结合了自定义密钥库和默认密钥库.

First, I wrote a X509KeyManager that works combines a custom keystore and a default keystore.

class MultiKeyStoreManager implements X509KeyManager {
 private static final Logger logger = Logger.getLogger(MultiKeyStoreManager.class); 
 private final X509KeyManager jvmKeyManager;
 private final X509KeyManager customKeyManager;

 public MultiKeyStoreManager(X509KeyManager jvmKeyManager, X509KeyManager customKeyManager ) {
  this.jvmKeyManager = jvmKeyManager;
  this.customKeyManager = customKeyManager;  
 }

 @Override
 public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
  // try the first key manager
  String alias = customKeyManager.chooseClientAlias(keyType, issuers, socket);
  if( alias == null ) {
   alias = jvmKeyManager.chooseClientAlias(keyType, issuers, socket);
   logger.warn("Reverting to JVM CLIENT alias : " + alias);
  }

  return alias;

 }

 @Override
 public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
  // try the first key manager
  String alias = customKeyManager.chooseServerAlias(keyType, issuers, socket);
  if( alias == null ) {
   alias =  jvmKeyManager.chooseServerAlias(keyType, issuers, socket);
   logger.warn("Reverting to JVM Server alias : " + alias);
  } 
  return alias;
 }

 @Override
 public X509Certificate[] getCertificateChain(String alias) {
  X509Certificate[] chain = customKeyManager.getCertificateChain(alias);
  if( chain == null || chain.length == 0) {
   logger.warn("Reverting to JVM Chain : " + alias);
   return jvmKeyManager.getCertificateChain(alias);
  } else {
   return chain;
  }  
 }

 @Override
 public String[] getClientAliases(String keyType, Principal[] issuers) {
  String[] cAliases = customKeyManager.getClientAliases(keyType, issuers);
  String[] jAliases = jvmKeyManager.getClientAliases(keyType, issuers);
  logger.warn("Supported Client Aliases Custom: " + cAliases.length + " JVM : " + jAliases.length);
  return ArrayUtils.join(cAliases,jAliases);
 }

 @Override
 public PrivateKey getPrivateKey(String alias) {
  PrivateKey key = customKeyManager.getPrivateKey(alias);
  if( key == null ) {
   logger.warn("Reverting to JVM Key : " + alias);
   return jvmKeyManager.getPrivateKey(alias);
  } else {
   return key;
  }
 }

 @Override
 public String[] getServerAliases(String keyType, Principal[] issuers) {
  String[] cAliases = customKeyManager.getServerAliases(keyType, issuers);
  String[] jAliases = jvmKeyManager.getServerAliases(keyType, issuers);
  logger.warn("Supported Server Aliases Custom: " + cAliases.length + " JVM : " + jAliases.length);
  return ArrayUtils.join(cAliases,jAliases);
 }

}

然后,您可以在创建 SSL 上下文或 SocketFactory 时使用此密钥库管理器.代码需要一些重构和整理,但效果很好.

Then, you can use this keystore manager when creating an SSL Context or SocketFactory. The code needs some refactoring and tidying up but it works perfectly.

 /**
  * Returns an array of KeyManagers, set up to use the required keyStore.
  * This method does the bulk of the work of setting up the custom trust managers.
  * 
  * @param props 
  * 
  * @return an array of KeyManagers set up accordingly.
  */
 private static KeyManager[] getKeyManagers(Properties props) throws IOException, GeneralSecurityException {
  // First, get the default KeyManagerFactory.
  String alg = KeyManagerFactory.getDefaultAlgorithm();
  KeyManagerFactory kmFact = KeyManagerFactory.getInstance(alg);   
  // Next, set up the KeyStore to use. We need to load the file into
  // a KeyStore instance.
  FileInputStream fis = new FileInputStream(props.getProperty(SSL_KEYSTORE));
  logger.info("Loaded keystore");
  KeyStore ks = KeyStore.getInstance("jks");
  String keyStorePassword = props.getProperty(SSL_KEYSTORE_PASSWORD);
  ks.load(fis, keyStorePassword.toCharArray());
  fis.close();
  // Now we initialise the KeyManagerFactory with this KeyStore
  kmFact.init(ks, keyStorePassword.toCharArray());

  // default
  KeyManagerFactory dkmFact = KeyManagerFactory.getInstance(alg); 
  dkmFact.init(null,null);  

  // Get the first X509KeyManager in the list
  X509KeyManager customX509KeyManager = getX509KeyManager(alg, kmFact);
  X509KeyManager jvmX509KeyManager = getX509KeyManager(alg, dkmFact);

  KeyManager[] km = { new MultiKeyStoreManager(jvmX509KeyManager, customX509KeyManager) };   
  logger.debug("Number of key managers registered:" + km.length);  
  return km;
 }


 /**
  * Find a X509 Key Manager compatible with a particular algorithm
  * @param algorithm
  * @param kmFact
  * @return
  * @throws NoSuchAlgorithmException
  */
 private static X509KeyManager getX509KeyManager(String algorithm, KeyManagerFactory kmFact)
   throws NoSuchAlgorithmException {
  KeyManager[] keyManagers = kmFact.getKeyManagers();

  if (keyManagers == null || keyManagers.length == 0) {
   throw new NoSuchAlgorithmException("The default algorithm :" + algorithm + " produced no key managers");
  }

  X509KeyManager x509KeyManager = null;

  for (int i = 0; i < keyManagers.length; i++) {
   if (keyManagers[i] instanceof X509KeyManager) {
    x509KeyManager = (X509KeyManager) keyManagers[i];
    break;
   }
  }

  if (x509KeyManager == null) {
   throw new NoSuchAlgorithmException("The default algorithm :"+ algorithm + " did not produce a X509 Key manager");
  }
  return x509KeyManager;
 }




 private static void initialiseManager(Properties props) throws IOException, GeneralSecurityException { 
  // Next construct and initialise a SSLContext with the KeyStore and
  // the TrustStore. We use the default SecureRandom.
  SSLContext context = SSLContext.getInstance("SSL");
  context.init(getKeyManagers(props), getTrustManagers(props), null);
  SSLContext.setDefault(context);

 }

如果有人有任何问题或需要任何演示代码,请告诉我.

Let me know if anyone has any question or need any demonstration codes.

这篇关于在 JVM 中注册多个密钥库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆