你没有发布任何代码,所以我不能确定你实际做了什么。不过,我假设你正在使用自定义的X509TrustManager
子类设置SSLContext
。这很好,但是你可以让你的自定义信任管理器实现同时链接到内置的信任管理器。你可以在设置信任管理器的同时实现这一点;以下代码应该能够正常工作:
private List<X509TrustManager> trustManagers = new ArrayList<X509TrustManager>();
public MyCustomTrustManager() {
TrustManagerFactory tmFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmFactory.init((KeyStore)null);
for (TrustManager tm : tmFactory.getTrustManagers()) {
if (tm instanceof X509TrustManager)
trustManagers.add((X509TrustManager)tm);
}
}
所以你的自定义信任管理器现在有了所有内置信任管理器的列表。在你重写的
checkServerTrusted()
中,你需要循环遍历内置信任管理器,并依次调用
checkServerTrusted()
检查每一个。如果它们都不信任证书,你可以应用自己的证书检查。如果通过了,你可以正常返回。如果没有通过,就像通常一样抛出。
编辑:添加以下内容关于如何执行主机名验证。
你还可以验证证书中的主机名是否与你期望的一致。你需要在你的自定义信任管理器的构造函数中传入有效的主机名并将其存储在类中。你的
checkServerTrusted()
方法将被传递一个
X509Certificate
数组。许多“链”将只包含一个证书,但其他链将会有好几个,这取决于cA如何签署你的证书。无论哪种方式,数组中的第一个证书应该是你想要比较的“你的”证书。
在使用信任管理器检查基本证书有效性之后,你将需要执行以下操作:
Principal subjectDN = chain[0].getSubjectDN();
String subjectCN = parseDN(subjectDN.getName(), "CN");
if (this.allowedCN.equals(subjectCN)) {
}
parseDN()
的实现由您完成。 subjectDN.getName()
将返回逗号分隔的键值对列表(由=
分隔),例如 C=US,ST=California,L=Mountain View,O=Google Inc,CN=www.google.com
。 您需要获取 CN(“通用名称”)值以进行主机名比较。 请注意,如果您有通配符证书,则会列出类似于 *.example.com
的内容,因此在这种情况下,您需要进行更复杂的匹配。