您可以使用与上一个答案中提到的模式类似的模式(针对另一个问题)。
本质上,掌握默认的信任管理器,创建另一个使用您自己的信任库的信任管理器。将它们都包装在一个自定义的信任管理器实现中,该实现将调用都委派给两者(当一个失败时回退到另一个)。
TrustManagerFactory tmf = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init((KeyStore) null);
X509TrustManager defaultTm = null;
for (TrustManager tm : tmf.getTrustManagers()) {
if (tm instanceof X509TrustManager) {
defaultTm = (X509TrustManager) tm;
break;
}
}
FileInputStream myKeys = new FileInputStream("truststore.jks");
KeyStore myTrustStore = KeyStore.getInstance(KeyStore.getDefaultType());
myTrustStore.load(myKeys, "password".toCharArray());
myKeys.close();
tmf = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(myTrustStore);
X509TrustManager myTm = null;
for (TrustManager tm : tmf.getTrustManagers()) {
if (tm instanceof X509TrustManager) {
myTm = (X509TrustManager) tm;
break;
}
}
final X509TrustManager finalDefaultTm = defaultTm;
final X509TrustManager finalMyTm = myTm;
X509TrustManager customTm = new X509TrustManager() {
@Override
public X509Certificate[] getAcceptedIssuers() {
return finalDefaultTm.getAcceptedIssuers();
}
@Override
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
try {
finalMyTm.checkServerTrusted(chain, authType);
} catch (CertificateException e) {
finalDefaultTm.checkServerTrusted(chain, authType);
}
}
@Override
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
finalDefaultTm.checkClientTrusted(chain, authType);
}
};
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[] { customTm }, null);
SSLContext.setDefault(sslContext);
您不必将该上下文设置为默认上下文。如何使用它取决于您使用的客户端库(以及从中获取套接字工厂的位置)。
这就是说,原则上,无论如何,您始终必须根据需要更新信任库。Java 7 JSSE参考指南对此有一个“重要说明”,现在在同一指南的第8版中已降级为“重要说明” :
JDK在java-home / lib / security / cacerts文件中附带了数量有限的受信任的根证书。如keytool参考页中所述,如果您将此文件用作信任库,则有责任维护(即添加和删除)此文件中包含的证书。
根据您联系的服务器的证书配置,您可能需要添加其他根证书。从适当的供应商处获取所需的特定根证书。