实施X509TrustManager - 通过对验证的一部分,以现有的检验
问题描述:
我需要忽略PKIX路径建设例外实施X509TrustManager - 通过对验证的一部分,以现有的检验
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException:
PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderExc
ption: unable to find valid certification path to requested target
我知道如何写我自己的类,我总是return true
从isServerTrusted
实施X509TrustManager
做到这一点。
但是,我不想相信所有客户端的所有服务器&。
- 我想要为客户完成所有默认验证,就像当前所做的那样。
- 对于服务器,我只想忽略服务器证书验证,但只想为某个特定的证书进行验证,但要按照当前的步骤进行验证(例如,使用cacerts存储区)。
如何能够做到这样的事情 - 即通过对验证,无论是X509TrustFactory对象之前,我取代了它的一部分。
即这就是我想要做的
public boolean isServerTrusted(X509Certificate[] chain)
{
if(chain[0].getIssuerDN().getName().equals("MyTrustedServer") && chain[0].getSubjectDN().getName().equals("MyTrustedServer"))
return true;
// else I want to do whatever verification is normally done
}
我也不想打扰现有isClientTrusted
验证。
我该怎么做?
答
你可以得到现有的默认信任管理器的保持和使用这样的包装在自己:
TrustManagerFactory tmf = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
// Using null here initialises the TMF with the default trust store.
tmf.init((KeyStore) null);
// Get hold of the default trust manager
X509TrustManager x509Tm = null;
for (TrustManager tm : tmf.getTrustManagers()) {
if (tm instanceof X509TrustManager) {
x509Tm = (X509TrustManager) tm;
break;
}
}
// Wrap it in your own class.
final X509TrustManager finalTm = x509Tm;
X509TrustManager customTm = new X509TrustManager() {
@Override
public X509Certificate[] getAcceptedIssuers() {
return finalTm.getAcceptedIssuers();
}
@Override
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
finalTm.checkServerTrusted(chain, authType);
}
@Override
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
finalTm.checkClientTrusted(chain, authType);
}
};
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[] { customTm }, null);
// You don't have to set this as the default context,
// it depends on the library you're using.
SSLContext.setDefault(sslContext);
然后,您可以实现自己的逻辑周围finalTm.checkServerTrusted(chain, authType);
。
但是,您应该确保您为要忽略的特定证书制定例外。
你在做什么在下面通过让任何证书与这些发行者DN和主题DN(这是不是很难伪造):
if(chain[0].getIssuerDN().getName().equals("MyTrustedServer") && chain[0].getSubjectDN().getName().equals("MyTrustedServer"))
return true;
你可以改为装载X509Certificate
实例从已知的参考中比较链中的实际值。
此外,checkClientTrusted
和checkServerTrusted
不返回true
或false
,但void
方法,将默认默默成功的方法。如果您期望的证书有问题,请明确地输入CertificateException
。
+1非常感谢评论_“//使用null在这里使用默认的信任存储库初始化TMF。这将是很好,如果这是在api文档;) – Dori
您可以请解释并给我一个这个部分的例子:**你可以从一个已知的参考加载X509Certificate实例,并比较链中的实际值。 * – OnePunchMan
@kaze,如果你想比较*确切*证书,你可以从你想要的任何来源加载一个X.509证书(例如通过CertificateFactory的PEM文件的密钥库),然后你可以比较链中呈现的内容(元素0)与参考实例。不确定'equals'是什么比较,但你当然可以在'X509Certificate'实例(字节数组比较,当然不是引用)上比较'getEncoded()'的结果。 – Bruno