Подтвердить что ты не робот

Реализация X509TrustManager - передача части проверки существующего верификатора

Мне нужно игнорировать исключение для построения 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, прежде чем я его заменил.

то есть. это то, что я хочу сделать

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.

Как я могу это сделать?

4b9b3361

Ответ 1

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

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 явно.