Java DefaultSslContextFactory密钥库动态更新

时间:2017-01-30 20:36:01

标签: java keystore restlet

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

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

有没有办法用密钥库文件中的新条目更新正在运行的应用程序?

3 个答案:

答案 0 :(得分:0)

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

要做到这一点,你必须告诉你的应用程序一个新的证书被添加到你的密钥库中,而不是重新加载密钥库 - 尽管我知道它应该是不可能的 - 顺便说一句,可能的是您可以将新证书添加到当前的SSLContext See here

要实现这一点,您需要提供一个知道新证书的bean - 可以是调用您的bash脚本的组件 - 您注入了SSLContext实例。

如果您使用微服务架构拆分应用程序,将一个模块委托给一个模块处理证书并重新加载它(使用适当的配置LB),因为密钥库已更新,这也很有趣。

答案 1 :(得分:0)

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

答案 2 :(得分: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);

    }

}

希望这有帮助!