Реализация X509TrustManager

В настоящее время я пытаюсь передать данные через Интернет через SSL/TLS в Java, и я хочу, чтобы обе стороны аутентифицировались. Я сам реализовал KeyManager, чтобы загрузить пару ключей и представить другой стороне соответствующий сертификат.

Теперь я пытаюсь проверить сертификат и делаю это, внедряя свой собственный TrustManager (обе стороны владеют сертификатом другой стороны, все подписано самостоятельно). Однако getAcceptedIssuers не работает так, как я хочу, потому что даже когда я не возвращаю ни одного, соединение все равно устанавливается без проблем.

Почему в сертификате отказано?

protected static class SelectingTrustManager implements X509TrustManager{
    final X509TrustManager delegate;

    private String[] trustedAliases;
    private final KeyStore keystore;

    public SelectingTrustManager(X509TrustManager delegate, KeyStore keystore, String[] trustedAliases) {
        this.trustedAliases = trustedAliases;
        this.keystore = keystore;
        this.delegate = delegate;
    }

    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException{
        delegate.checkClientTrusted(chain, authType);
    }

    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException{
        delegate.checkServerTrusted(chain, authType);
    }

    public X509Certificate[] getAcceptedIssuers(){
        return new X509Certificate[0];
    }

}

1 ответ

Решение

Вам не ясно, является ли ваш код клиентским или серверным, поэтому я отвечаю на оба вопроса, хотя в значительной степени это имеет значение только для сервера.

Хотя Javadoc не является конкретным, X509TM.getAcceptedIssuers НЕ используется, чтобы решить, доверять ли полученному сертификату или цепочке; это делается исключительно checkServerTrusted в клиенте или checkClientTrusted на сервере.

Значение getAcceptedIssuers используется и влияет только на две вещи:

  • на сервере (только), если включена авторизация клиента (путем вызова needClientAuth(true) или же wantClientAuth(true)), имена субъектов из его элементов используются для создания списка CA на сервере. CertificateRequest сообщение Это не обязательно должно совпадать со списком CA, которые будут использоваться в качестве якорей доверия для цепочки сертификатов клиента, если таковой получен; на самом деле, менеджер доверия на самом деле не обязан использовать список якорей доверия или даже остальную часть стандартного алгоритма проверки - хотя, если ваш "делегат" является стандартом X509[Extended]TrustManager который использует стандарт CertPathValidator это делает. Однако, если вы скажете клиенту (-ам) использовать сертификат (ы) из определенных центров сертификации, а затем не примете действительные цепочки сертификатов из этих центров сертификации, у вас, скорее всего, будут несчастные клиенты, которые могут прийти после того, как вы различные тяжелые, острые и / или другие неприятные предметы.

    В конкретном случае отсутствия "CA" (массива нулевой длины, как у вас) клиент может отправить сертификат от любого CA, который он выберет, и сервер примет его в зависимости только от checkClientTrusted,

    Для полноты заметки, RFC определяют расширение для клиента, чтобы указать, какие CA он хочет использовать для сертификата сервера, но я не знаю какой-либо реализации, которая поддерживает это расширение, а Java/JSSE определенно нет, поэтому на практике у сервера либо есть только один сертификат (на алгоритм), либо он выбирается на основе SNI (и ничего больше), и если этот сертификат не слишком надежен для клиента.

  • если у вас есть действующие ограничения алгоритма (и в настоящее время вы обычно делаете это по умолчанию, даже если вы не устанавливаете их явно), они не применяются к последнему сертификату в цепочке (предполагаемой привязке), если он входит в число сертификатов, возвращаемых getAcceptedIssuers, которые предположительно являются (фактическими) якорями. Другими словами, если сертификат является якорем доверия, предположительно, пользователь решил доверять ему, даже если он может использовать алгоритмы, которые не соответствуют современным стандартам (например, MD5 или RSA меньше 1024).

    Независимо от того, поставил ли сертификат сертификат в доверенное хранилище или иным образом сделал его якорем, он правильно оценил свою безопасность - это другой вопрос, на который Java не пытается ответить. Даже Stackexchange, возможно, не сможет этого сделать, хотя я уверен, что здесь будут люди, которые будут рады попробовать. (Я не беру на себя обязательства, буду ли я одним из них.)

Другие вопросы по тегам