我们正在使用HttpClient 4.4与一些外部服务器(server1.company.com,server2.company.com,server3.company.com)进行通信。他们最近添加了一个额外的环境(server4.company.com),该环境使用与另一个相同的证书3.有问题的证书将前3个服务器列为“证书主题备用名称”,但未提及server4。
我可以告诉keytool证书对其他SAN有效吗?或者有没有其他方法告诉HttpClient“信任”这个额外域名的证书?还有其他选择,还是我必须回到company.com并要求他们获得新证书?
答案 0 :(得分:1)
证书验证有两个方面(一般而言):
(如果您需要类比,可能会感兴趣this question, about libcurl。)
根据您的说法,该特定证书对其他主机名称是可信且有效的。因此,它将通过PKI验证(TrustStrategy
实现的内容)。
您需要的是为主机名验证方面构建一个特殊情况,仅针对该特定证书。
我不记得如何在Apache HTTP Client 4.4中使用它,但您应该使用自己的验证程序而不是DefaultHostnameVerifier
。
要实施的方法是verify(String hostYouAreAfter, SSLSession sessionYouActuallyGet)
和verify(String hostYouAreAfter, X509Certificate certYouActuallyGet)
。
您可以按照这些方式提供自己的实现:
public verify(String hostYouAreAfter, X509Certificate certYouActuallyGet) {
if (certYouActuallyGet.equals(referenceCertificate)) {
if ("server4.company.com".equalsIgnoreCase(hostYouAreAfter)) {
// All good, don't fail and throw an exception.
} else {
super.verify(hostYouAreAfter, certYouActuallyGet);
}
} else {
super.verify(hostYouAreAfter, certYouActuallyGet);
}
}
您可以对verify(String,SSLSession)
执行相同的操作,并从X509Certificate
的对等链(位置0)获取SSLSession
。逻辑是一样的,但你需要返回true / false而不是抛出异常。
在这里,我假设您已从具有该特定证书的引用位置加载referenceCertificate
。例如,您可以从已知密钥库加载它,或者从应用程序中配置的参考PEM文件加载CertificateFactory
。
TrustStrategy
与isTrusted(final X509Certificate[] chain, final String authType)
实施return "nice guy".equalsIgnoreCase(issuerDN.getName());
有两个主要区别:
String
的第一个HostnameVerifier.verify(...)
参数,该参数是您打算连接的主机名。至少你可以将它用于与你获得的证书进行比较,这是TrustStrategy
无法获得的。答案 1 :(得分:0)
可以使用自定义TrustStrategy
SSLContext sslcontext = SSLContexts.custom()
.loadTrustMaterial(new TrustStrategy() {
@Override
public boolean isTrusted(final X509Certificate[] chain, final String authType)
throws CertificateException {
X509Certificate x509Certificate = chain[0];
Principal issuerDN = x509Certificate.getIssuerDN();
return "nice guy".equalsIgnoreCase(issuerDN.getName());
}
}).build();
CloseableHttpClient client = HttpClients.custom()
.setSslcontext(sslcontext)
.build();