听起来你遇到类似于
this question的问题,因为在SSLContext.init(…)中使用null for trustmanager参数会恢复为默认的信任管理器,而对于keymanager则不会.
这就是说,使用默认系统属性初始化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文档中链接到的部分说:“如果密钥库由javax.net.ssl.keyStore系统属性和适当的javax.net.ssl.keyStorePassword系统属性指定,则由默认SSLContext创建的KeyManager将是用于管理指定密钥库的KeyManager实现.“
这不适用于此,因为您使用的是自定义SSLContext,而不是默认的SSLContext(即使您正在自定义其中的一部分).
无论如何,Oracle JSSE参考指南和IBM JSSE参考指南在这个主题上有所不同. (我不确定这有多少意味着“标准”,原则上是否应该与另一方相符,但事实显然并非如此.)
“创建SSLContext对象”部分几乎完全相同,但它们是不同的.
If the KeyManager[] parameter is null, then an empty KeyManager will
be defined for this context.
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.
遗憾的是,如果您希望在具有不同规范的实现中具有相同的行为,则必须编写一些代码,即使这有效地复制了其中一个实现已经执行的操作.