如何在Java(JSSE)中使用默认的KeyStore时提供特定的TrustStore [英] How do I provide a specific TrustStore while using the default KeyStore in Java (JSSE)

查看:178
本文介绍了如何在Java(JSSE)中使用默认的KeyStore时提供特定的TrustStore的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

JSSE允许用户通过指定javax.net.ssl。*参数来提供默认信任存储和密钥存储。我想为我的应用程序提供一个非默认的TrustManager,同时允许用户像往常一样指定KeyManager,但似乎没有任何方法可以实现这一点。

JSSE allows users to provide default trust stores and key stores by specifying javax.net.ssl.* parameters. I would like to provide a non-default TrustManager for my application, while allowing the user to specify the KeyManager as usual, but there doesn't seem to be any way to achieve this.

http://docs.oracle.com/javase/7/docs/technotes/guides/security/jsse/JSSERefGuide.html#CustomizingStores

假设在unix机器上我想允许用户使用pkcs12密钥库进行身份验证,而在OS XI上则希望允许用户使用系统密钥链。在OS X上,应用程序可能会按如下方式启动:

Suppose on unix machines I want to allow the user to use a pkcs12 key store for authentication, while on OS X I want allow the user to use the system keychain. On OS X the application might be started as follows:

java -Djavax.net.ssl.keyStore=NONE -Djavax.net.ssl.keyStoreType=KeychainStore \
     -Djavax.net.ssl.keyStorePassword=- -jar MyApplication.jar

这样可以正常工作:当应用程序访问需要相互身份验证的https服务器(客户端证书身份验证)时,系统将提示用户允许访问其钥匙串。

This will work fine: when the application accesses an https server that requires mutual authentication (client certificate authentication) then the user will be prompted to allow access to their keychain.

现在假设我想将自签名证书颁发机构与我的应用程序捆绑在一起。我可以通过构造一个TrustManagerFactory并传入一个包含我的证书的KeyStore来覆盖默认的信任管理器( javadoc )。但是,要使用此非默认信任管理器,我需要创建并初始化SSLContext。这里存在问题。

Now suppose I want to bundle a self-signed certificate authority with my application. I can override the default trust manager by constructing a TrustManagerFactory and passing in a KeyStore containing my certificate (javadoc). However, to use this non-default trust manager I need to create and initialise an SSLContext. Here-in lies the problem.

通过调用 init(..)并传递KeyManager和TrustManager。但是,使用javax.net.ssl。*参数创建KeyManager的逻辑嵌入在默认SSLContexts的实现中 - 我找不到使用默认行为获取KeyManager或KeyManagerFactory的方法,同时还指定了非默认的TrustManager或TrustManagerFactory。因此,似乎不可能使用例如适当的操作系统特定的钥匙串实现,同时还提供用于验证远程服务器的根证书。

SSLContexts are initialised by calling init(..) and passing both a KeyManager and a TrustManager. However, logic for creating a KeyManager using the javax.net.ssl.* parameters is embedded in the implementation of the default SSLContexts -- I can't find a way to obtain a KeyManager or a KeyManagerFactory using the default behaviour while also specifying a non-default TrustManager or TrustManagerFactory. Thus, it seems that it is not possible to use, for example, the appropriate operating-system specific keychain implementation while also providing a root certificate for authenticating remote servers.

推荐答案

听起来你在使用这个问题时遇到了类似的问题对于中的trustmanager参数, null SSLContext.init(...)恢复为默认信任管理器,而不是对于keymanager来说。

It sounds like you're facing a similar problem to this question, in that using null for the trustmanager parameter in SSLContext.init(...) reverts to the default trust manager, whereas it doesn't for the keymanager.

这就是说,使用默认系统属性初始化KeyManager并不困难。这样的东西应该可以工作(代码直接写在这个答案中,所以你可能需要修改一些小东西):

This being said, it's not that hard to initialise a KeyManager using the default system properties. Something like this should work (code written directly in this answer, so you might need to fix a few little things):

String provider = System.getProperty("javax.net.ssl.keyStoreProvider");
String keystoreType = System.getProperty("javax.net.ssl.keyStoreType", KeyStore.getDefaultType());
KeyStore ks = null;
if (provider != null) {
    ks = KeyStore.getInstance(keystoreType, provider);
} else {
    ks = KeyStore.getInstance(keystoreType);
}
InputStream ksis = null;
String keystorePath = System.getProperty("javax.net.ssl.keyStore");
String keystorePassword = System.getProperty("javax.net.ssl.keyStorePassword");
if (keystorePath != null && !"NONE".equals(keystorePath)) {
    ksis = new FileInputStream(keystorePath);
}
try {
    ks.load(ksis, keystorePassword.toCharArray());
} finally {
     if (ksis != null) { ksis.close(); }
}

KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, keystorePassword.toCharArray());
// Note that there is no property for the key password itself, which may be different.
// We're using the keystore password too.

SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), ..., null);

此实用程序类也可能有用,更具体地说是 getKeyStoreDefaultLoader()。)

(This utility class may also be of interest, more specifically getKeyStoreDefaultLoader().)

编辑:(关注您的附加评论)

(Following your additional comment)

当你想只定制 SSLContext 。您在Oracle JSSE文档中链接到的部分说,如果密钥库由javax.net.ssl.keyStore系统属性和相应的javax.net.ssl.keyStorePassword系统属性指定,则KeyManager创建者默认的SSLContext将是用于管理指定密钥库的KeyManager实现。
这不适用于此,因为您使用的是自定义 SSLContext ,而不是默认的一个(即使你自定义它的一部分)。

I'm afraid there doesn't seem to be a default behaviour for both the Oracle and the IBM JSSE when you want to customise only half of the SSLContext. The section you link to in the Oracle JSSE documentation says, "If a keystore is specified by the javax.net.ssl.keyStore system property and an appropriate javax.net.ssl.keyStorePassword system property, then the KeyManager created by the default SSLContext will be a KeyManager implementation for managing the specified keystore." This wouldn't really apply here, since you're using a custom SSLContext, not the default one anyway (even if you're customising part of it).

无论如何,Oracle JSSE参考指南和IBM JSSE参考指南有所不同这个主题。 (我不确定这有多少意味着标准,原则上是否应该与另一方相符,但事实显然不是这样。)

Anyway, the Oracle JSSE reference guide and the IBM JSSE reference guide differ on this subject. (I'm not sure how much of this is meant to be "standard" and whether one should in principle be compliant with the other, but this is clearly not the case.)

创建 SSLContext 对象部分几乎相同,但它们不同。

Both "Creating an SSLContext Object" sections are almost identical, but they are different.

Oracle JSSE参考指南说:


如果KeyManager []参数为null,则为空KeyManager将为此上下文定义

If the KeyManager[] parameter is null, then an empty KeyManager will be defined for this context.

IBM JSSE参考指南说:


如果KeyManager []参数为空,则安装s ecurity
提供商将搜索KeyManagerFactory
的最高优先级实现,从中获得适当的KeyManager

If the KeyManager[] paramater is null, the installed security providers will be searched for the highest-priority implementation of the KeyManagerFactory, from which an appropriate KeyManager will be obtained.

不幸的是,如果你想在具有不同规范的实现中使用相同的行为,你将不得不编写一些代码,即使这有效地复制了其中一个实现已经完成的任务。

Unfortunately, if you want the same behaviour across implementations that have different specifications, you'll have to write a bit of code, even if that's effectively duplicating what one of the implementations already does.

这篇关于如何在Java(JSSE)中使用默认的KeyStore时提供特定的TrustStore的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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