实施X509TrustManager-将部分验证传递给现有验证者

问题描述 投票:15回答:2

我需要忽略PKIX路径构建异常

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

[我知道如何通过编写自己的实现X509TrustManager的类来做到这一点,在这里我总是return true中的isServerTrusted

但是,我不想信任所有服务器和所有客户端。

  • 我希望像目前一样为客户端完成所有默认验证。
  • 对于服务器,我只想忽略一个特定证书的服务器证书验证,但想像现在一样进行验证(例如,使用cacerts存储)。

我如何实现这样的目标-即,在我替换X509TrustFactory对象之前,将部分验证传递给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验证。

我该怎么做?

java security ssl x509certificate pki
2个回答
41
投票
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的

any证书通过(这很难伪造):

if(chain[0].getIssuerDN().getName().equals("MyTrustedServer") && chain[0].getSubjectDN().getName().equals("MyTrustedServer")) return true;

您可以改为从已知引用中加载X509Certificate实例,并比较链中的实际值。
此外,checkClientTrustedcheckServerTrusted不是返回truefalse的方法,而是void方法,默认情况下将无提示成功。如果您期望的证书有问题,请明确抛出CertificateException

1
投票
any证书,您可以根据特定的证书创建信任管理器。从.p12.jks密钥库或.crt文件中加载证书(您可以通过单击挂锁并选择证书,在Chrome中将浏览器中的证书复制到文件中)。该代码比实现自己的X509TrustManager短:

private static SSLSocketFactory createSSLSocketFactory(File crtFile) throws GeneralSecurityException, IOException { SSLContext sslContext = SSLContext.getInstance("SSL"); // Create a new trust store, use getDefaultType for .jks files or "pkcs12" for .p12 files KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); // You can supply a FileInputStream to a .jks or .p12 file and the keystore password as an alternative to loading the crt file trustStore.load(null, null); // Read the certificate from disk X509Certificate result; try (InputStream input = new FileInputStream(crtFile)) { result = (X509Certificate) CertificateFactory.getInstance("X509").generateCertificate(input); } // Add it to the trust store trustStore.setCertificateEntry(crtFile.getName(), result); // Convert the trust store to trust managers TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(trustStore); TrustManager[] trustManagers = tmf.getTrustManagers(); sslContext.init(null, trustManagers, null); return sslContext.getSocketFactory(); } 您可以通过调用HttpsURLConnection.setSSLSocketFactory(createSSLSocketFactory(crtFile))来使用它(尽管您可能想一次初始化套接字工厂并重用它)。

© www.soinside.com 2019 - 2024. All rights reserved.