2017-01-30 32 views
3

我有一个现有应用程序,它使用org.restlet.engine.ssl.DefaultSslContextFactory和启动服务器时加载的密钥库文件。 我有另一个应用程序创建的证书必须在服务器运行时动态添加 到密钥库文件。要执行此操作, 我在代码中创建了证书和私钥,然后将它写入 到目录中。该目录由bash脚本监视,用于检查新文件,如果出现该文件,它将被导入到现有密钥库文件中。Java DefaultSslContextFactory密钥库动态更新

但是当试图使用新导入的证书访问服务器时,握手失败。只有在重新启动服务器时,访问才能成功完成,我假设这意味着添加的证书不会被服务器重新加载。

是否有方法使用密钥库文件中的新条目更新正在运行的应用程序?

+0

你看过这个答案吗? http://stackoverflow.com/questions/859111/how-can-i-use-different-certificates-on-specific-connections – Tom

回答

0

将新证书导入密钥库不会刷新当前的SSLConext,因为没有任何信息告诉JVM密钥库已更改。

要做到这一点,你必须告诉你的应用程序一个新的证书被添加到你的密钥库中,而不是重新加载密钥库 - 据我所知它应该是不可能的 - ,可能的方式是什么是您可以将新证书添加到您当前的SSLContext See here

为了实现这一目标,你提供一个bean知道新的证书 - 也许是在叫你注入的SSL连接实例您的bash脚本 - 该组件。

这也是有趣的,如果你使用分割微服务架构应用程序,委托给一个模块的事实,处理证书和重新加载它(使用适当的配置LB)作为密钥库进行更新。

+0

我不明白你最后一段的意思!? bash脚本本身运行,所以我会在哪里注入实例? – wasp256

+0

进入你的Java代码,这取决于你的代码刷新内存证书链 –

+0

这听起来像一个非常肮脏的破解... – wasp256

0

由于这似乎是一项相当不可能完成的任务,因此我决定采取一种解决方法。我使用nginx作为应用程序前面的代理。 Nginx能够使用多个CA根证书执行客户端身份验证,这正是我所需要的。应用程序和nginx之间的连接可以简单地通过HTTP完成,因为它们驻留在同一个主机上(只是不同的端口)。

0

丑陋的黑客攻击警报

我下面的作品。我覆盖DefaultSSLContextFactory,存储每个创建的SSLContext并再次调用它的init方法。

要调用重装我只需拨打UglyHackSSLContextFactory.reloadKeyStore()

package test; 

import java.io.FileInputStream; 
import java.io.IOException; 
import java.security.KeyManagementException; 
import java.security.KeyStore; 
import java.security.KeyStoreException; 
import java.security.NoSuchAlgorithmException; 
import java.security.NoSuchProviderException; 
import java.security.SecureRandom; 
import java.security.UnrecoverableKeyException; 
import java.security.cert.CertificateException; 
import java.util.ArrayList; 

import javax.net.ssl.SSLContext; 

import org.restlet.engine.ssl.DefaultSslContextFactory; 

public class UglyHackSSLContextFactory extends DefaultSslContextFactory { 

    private SSLContext _context = null; 
    public static ArrayList<UglyHackSSLContextFactory> instances = new ArrayList<UglyHackSSLContextFactory>(); 

    // we need all used SSLContextFactories later, so store them 
    public UglyHackSSLContextFactory() { 
     instances.add(this); 
    } 

    // create a new context once and store it. 
    @Override 
    public SSLContext createSslContext() throws Exception { 
     if (this._context == null) { 
      this._context = super.createSslContext(); 
     } 
     return this._context; 
    } 

    // re-init all _context instances 
    public static void reload() throws KeyManagementException, UnrecoverableKeyException, 
      KeyStoreException, NoSuchProviderException, NoSuchAlgorithmException, 
      CertificateException, IOException { 
     for (final UglyHackSSLContextFactory f : instances) { 
      f.reinit(); 
     } 
    } 

    // this is mostly copied from 
    // org.restlet.engine.ssl.DefaultSslContextFactory 
    private void reinit() throws KeyManagementException, KeyStoreException, 
      NoSuchProviderException, NoSuchAlgorithmException, CertificateException, IOException, 
      UnrecoverableKeyException { 

     javax.net.ssl.KeyManagerFactory kmf = null; 

     if ((getKeyStorePath() != null) || (getKeyStoreProvider() != null) 
       || (getKeyStoreType() != null)) { 
      // Loads the key store. 
      final KeyStore keyStore = (getKeyStoreProvider() != null) ? KeyStore.getInstance(
        (getKeyStoreType() != null) ? getKeyStoreType() : KeyStore.getDefaultType(), 
        getKeyStoreProvider()) : KeyStore 
        .getInstance((getKeyStoreType() != null) ? getKeyStoreType() : KeyStore 
          .getDefaultType()); 
      FileInputStream keyStoreInputStream = null; 

      try { 
       keyStoreInputStream = ((getKeyStorePath() != null) && (!"NONE" 
         .equals(getKeyStorePath()))) ? new FileInputStream(getKeyStorePath()) 
         : null; 
       keyStore.load(keyStoreInputStream, getKeyStorePassword()); 
      } finally { 
       if (keyStoreInputStream != null) { 
        keyStoreInputStream.close(); 
       } 
      } 

      // Creates the key-manager factory. 
      kmf = javax.net.ssl.KeyManagerFactory.getInstance(getKeyManagerAlgorithm()); 
      kmf.init(keyStore, getKeyStoreKeyPassword()); 
     } 

     javax.net.ssl.TrustManagerFactory tmf = null; 

     if ((getTrustStorePath() != null) || (getTrustStoreProvider() != null) 
       || (getTrustStoreType() != null)) { 
      // Loads the trust store. 
      final KeyStore trustStore = (getTrustStoreProvider() != null) ? KeyStore 
        .getInstance(
          (getTrustStoreType() != null) ? getTrustStoreType() : KeyStore 
            .getDefaultType(), getTrustStoreProvider()) : KeyStore 
        .getInstance((getTrustStoreType() != null) ? getTrustStoreType() : KeyStore 
          .getDefaultType()); 
      FileInputStream trustStoreInputStream = null; 

      try { 
       trustStoreInputStream = ((getTrustStorePath() != null) && (!"NONE" 
         .equals(getTrustStorePath()))) ? new FileInputStream(getTrustStorePath()) 
         : null; 
       trustStore.load(trustStoreInputStream, getTrustStorePassword()); 
      } finally { 
       if (trustStoreInputStream != null) { 
        trustStoreInputStream.close(); 
       } 
      } 

      // Creates the trust-manager factory. 
      tmf = javax.net.ssl.TrustManagerFactory.getInstance(getTrustManagerAlgorithm()); 
      tmf.init(trustStore); 
     } 

     SecureRandom sr = null; 

     if (getSecureRandomAlgorithm() != null) { 
      sr = SecureRandom.getInstance(getSecureRandomAlgorithm()); 
     } 

     this._context.init(kmf != null ? kmf.getKeyManagers() : null, 
       tmf != null ? tmf.getTrustManagers() : null, sr); 

    } 

} 

希望这有助于!