实施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 trueisServerTrusted实施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实例从已知的参考中比较链中的实际值。

此外,checkClientTrustedcheckServerTrusted不返回truefalse,但void方法,将默认默默成功的方法。如果您期望的证书有问题,请明确地输入CertificateException

+7

+1非常感谢评论_“//使用null在这里使用默认的信任存储库初始化TMF。这将是很好,如果这是在api文档;) – Dori

+0

您可以请解释并给我一个这个部分的例子:**你可以从一个已知的参考加载X509Certificate实例,并比较链中的实际值。 * – OnePunchMan

+0

@kaze,如果你想比较*确切*证书,你可以从你想要的任何来源加载一个X.509证书(例如通过CertificateFactory的PEM文件的密钥库),然后你可以比较链中呈现的内容(元素0)与参考实例。不确定'equals'是什么比较,但你当然可以在'X509Certificate'实例(字节数组比较,当然不是引用)上比较'getEncoded()'的结果。 – Bruno