Java SSL connect,以编程方式将服务器证书添加到密钥库 [英] Java SSL connect, add server cert to keystore programmatically

查看:104
本文介绍了Java SSL connect,以编程方式将服务器证书添加到密钥库的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在将SSL客户端连接到我的SSL服务器。
当客户端由于客户端密钥存储区中不存在根证书而无法验证证书时,我需要选择将该证书添加到代码中的本地密钥存储区并继续。
有一些示例总是接受所有证书,但我希望用户验证证书并将其添加到本地密钥库而无需离开应用程序。

I am connecting an SSL client to my SSL server. When the client fails to verify a certificate due to the root not existing in the client's key store, I need the option to add that certificate to the local key store in code and continue. There are examples for always accepting all certificates, but I want the user to verify the cert and add it to local key store without leaving the application.

SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket("localhost", 23467);
try{
    sslsocket.startHandshake();
} catch (IOException e) {
    //here I want to get the peer's certificate, conditionally add to local key store, then reauthenticate successfully
}

有很多关于自定义SocketFactory,TrustManager,SSLContext等的东西,我真的不明白它们是如何组合在一起的将是我达到目标的最短路径。

There is a whole lot of stuff about custom SocketFactory, TrustManager, SSLContext, etc and I don't really understand how they all fit together or which would be the shortest path to my goal.

推荐答案

您可以使用 X509TrustManager

获取SSLContext

Obtain an SSLContext with

SSLContext ctx = SSLContext.getInstance("TLS");

然后使用您的自定义 X509TrustManager 进行初始化使用 SSLContext #init 。 SecureRandom和KeyManager []可能为null。后者仅在您执行客户端身份验证时才有用,如果在您的方案中只有服务器需要进行身份验证而您不需要进行身份验证。

Then initialize it with your custom X509TrustManager by using SSLContext#init. The SecureRandom and the KeyManager[] may be null. The latter is only useful if you perform client authentication, if in your scenario only the server needs to authenticate you don't need to set it.

从此SSLContext获取你的SSLSocketFactory使用 SSLContext# getSocketFactory 并按计划进行。

From this SSLContext, get your SSLSocketFactory using SSLContext#getSocketFactory and proceed as planned.

关于您的X509TrustManager实现,它可能如下所示:

As concerns your X509TrustManager implementation, it could look like this:

TrustManager tm = new X509TrustManager() {
    public void checkClientTrusted(X509Certificate[] chain,
                    String authType)
                    throws CertificateException {
        //do nothing, you're the client
    }

    public X509Certificate[] getAcceptedIssuers() {
        //also only relevant for servers
    }

    public void checkServerTrusted(X509Certificate[] chain,
                    String authType)
                    throws CertificateException {
        /* chain[chain.length -1] is the candidate for the
         * root certificate. 
         * Look it up to see whether it's in your list.
         * If not, ask the user for permission to add it.
         * If not granted, reject.
         * Validate the chain using CertPathValidator and 
         * your list of trusted roots.
         */
    }
};

编辑:

Ryan是对的,我忘了解释如何将新根添加到现有根。假设您当前的受信任根KeyStore派生自 cacerts (JDK附带的'Java default trust store',位于jre / lib / security下)。我假设您使用KeyStore #load(InputStream,char [])加载了该密钥库(它是JKS格式)。

Ryan was right, I forgot to explain how to add the new root to the existing ones. Let's assume your current KeyStore of trusted roots was derived from cacerts (the 'Java default trust store' that comes with your JDK, located under jre/lib/security). I assume you loaded that key store (it's in JKS format) with KeyStore#load(InputStream, char[]).

KeyStore ks = KeyStore.getInstance("JKS");
FileInputStream in = new FileInputStream("<path to cacerts"");
ks.load(in, "changeit".toCharArray);

<* c $ c> cacerts 的默认密码是changeit,如果你还没有,那就改变了。

The default password to cacerts is "changeit" if you haven't, well, changed it.

然后你可以使用 KeyStore#setEntry 。您可以省略ProtectionParameter (即null),KeyStore.Entry将是 TrustedCertificateEntry 将新root作为其构造函数的参数。

Then you may add addtional trusted roots using KeyStore#setEntry. You can omit the ProtectionParameter (i.e. null), the KeyStore.Entry would be a TrustedCertificateEntry that takes the new root as parameter to its constructor.

KeyStore.Entry newEntry = new KeyStore.TrustedCertificateEntry(newRoot);
ks.setEntry("someAlias", newEntry, null);

如果你想在某个时候坚持改变的信任存储,你可以用 KeyStore #store(OutputStream,char []

If you'd like to persist the altered trust store at some point, you may achieve this with KeyStore#store(OutputStream, char[].

这篇关于Java SSL connect,以编程方式将服务器证书添加到密钥库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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