听起来您面临与此问题类似的问题,因为使用信任管理器null
参数SSLContext.init(...)
恢复为默认信任管理器,而密钥管理器则没有。
话虽如此,使用默认系统属性初始化 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);
(更具体地说,这个实用程序类getKeyStoreDefaultLoader()
也可能很有趣。)
编辑:(根据您的附加评论)
恐怕当您只想自定义一半的SSLContext
. 您在 Oracle JSSE 文档中链接到的部分说:“如果由 javax.net.ssl.keyStore 系统属性和适当的 javax.net.ssl.keyStorePassword 系统属性指定密钥库,则由默认 SSLContext 创建的 KeyManager将是用于管理指定密钥库的 KeyManager 实现。 ” 这在这里并不适用,因为您使用的是 custom SSLContext
,而不是默认的(即使您正在自定义其中的一部分)。
无论如何,Oracle JSSE 参考指南和 IBM JSSE 参考指南在这个主题上有所不同。(我不确定其中有多少是“标准”,以及原则上是否应该与另一个兼容,但显然情况并非如此。)
两个“创建SSLContext
对象”部分几乎相同,但它们不同。
Oracle JSSE 参考指南说:
如果 KeyManager[] 参数为 null,则将为该上下文定义一个空的 KeyManager。
IBM JSSE 参考指南说:
如果 KeyManager[] 参数为空,将在已安装的安全提供程序中搜索 KeyManagerFactory 的最高优先级实现,从中获取适当的 KeyManager。
不幸的是,如果您希望在具有不同规范的实现之间具有相同的行为,您将不得不编写一些代码,即使这实际上是在复制其中一个实现已经做的事情。