gpt4 book ai didi

java - 在 Java (JSSE) 中使用默认 KeyStore 时如何提供特定的 TrustStore

转载 作者:搜寻专家 更新时间:2023-10-31 19:56:25 25 4
gpt4 key购买 nike

概览

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

详情

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

假设在 unix 机器上我想允许用户使用 pkcs12 keystore 进行身份验证,而在 OS X 上我想允许用户使用系统钥匙串(keychain)。在 OS X 上,应用程序可能会按如下方式启动:

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

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

问题

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

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

最佳答案

听起来您遇到的问题与 this question 类似,因为在 SSLContext.init(...) 中对 trustmanager 参数使用 null 会恢复到默认的信任管理器,而 key 管理器则不会。

话虽如此,使用默认系统属性初始化 KeyManager 并不难。像这样的东西应该可以工作(代码直接写在这个答案中,所以你可能需要修复一些小问题):

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);

(This utility class 也可能令人感兴趣,更具体地说是 getKeyStoreDefaultLoader()。)

编辑:(根据您的补充评论)

当您只想自定义 SSLContext 的一半时,恐怕 Oracle 和 IBM JSSE 似乎都没有默认行为。您在 Oracle JSSE 文档中链接到的部分说,“如果 keystore 是由 javax.net.ssl.keyStore 系统属性和适当的 javax.net.ssl.keyStorePassword 系统属性指定的,则由创建的 KeyManager默认的 SSLContext 将是用于管理指定 keystore 的 KeyManager 实现。”这在这里并不适用,因为您使用的是自定义 SSLContext,而不是默认的(即使您正在自定义其中的一部分)。

无论如何,Oracle JSSE 引用指南和 IBM JSSE 引用指南在这个主题上有所不同。 (我不确定其中有多少是“标准”的,也不确定一个原则上是否应该与另一个兼容,但显然情况并非如此。)

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

Oracle JSSE Reference guide说:

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

IBM JSSE Reference guide说:

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.

不幸的是,如果您想要在具有不同规范的实现之间实现相同的行为,您将不得不编写一些代码,即使这实际上是在复制其中一个实现已经做的事情。

关于java - 在 Java (JSSE) 中使用默认 KeyStore 时如何提供特定的 TrustStore,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15269419/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com