2013-09-25 1 views
11

мне нужно игнорировать здание за исключением PKIX PathРеализация 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 

Я знаю, как сделать это, написав свой собственный класс реализации X509TrustManager, где я всегда return true от isServerTrusted ,

Однако я не хочу доверять всем серверам & всем клиентам.

  • Я хочу, чтобы все проверки по умолчанию выполнялись для клиентов, как это делается в настоящее время.
  • Для серверов я хочу игнорировать проверку сертификата сервера только для одного конкретного сертификата, но хочу продолжить и проверить его, как это делается в настоящее время (например, с использованием хранилища 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 проверки.

Как это сделать?

ответ

30

Вы можете разжиться существующего доверия по умолчанию менеджера и завернуть его в свой собственный, используя что-то вроде этого:

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 и Subject DN (что не трудно подделать) следующее:

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

Вы могли бы вместо того, чтобы загрузить экземпляр X509Certificate от известной ссылки и сравнить фактическое значение в цепочке.

Кроме того, checkClientTrusted и checkServerTrusted не методы, которые возвращают true или false, но void методы, которые будут преуспевать молча по умолчанию. Если что-то не так с сертификатом, который вы ожидаете, бросьте CertificateException явно.

+7

+1 большое спасибо за комментарий _ "// Использование null здесь инициализирует TMF с хранилищем доверия по умолчанию." _. Было бы неплохо, если бы это было в api docs;) – Dori

+0

Не могли бы вы объяснить и показать мне пример этой части: ** Вместо этого вы можете загрузить экземпляр X509Certificate из известной ссылки и сравнить фактическое значение в цепочке. * * – OnePunchMan

+0

@kaze, если вы хотите сравнить * точные * сертификаты, вы можете загрузить сертификат X.509 из любого источника, который вы хотите (например, хранилище файлов PEM через CertificateFactory), тогда вы можете сравнить то, что представлено в цепочке (элемент 0) с эталонным экземпляром.Не уверен, что сравнивать «equals», но вы можете, конечно, сравнивать результаты с 'getEncoded()' на обоих экземплярах X509Certificate' (сравнение байтовых массивов, конечно, не ссылок). – Bruno

Смежные вопросы