Лог сертификат SSL программно - PullRequest
0 голосов
/ 10 сентября 2018

У меня есть два устройства, которые не могут подключиться к моей конечной точке TLS v1.2.Все остальные, в том числе браузеры, устройства PostMan и iOS, могут это сделать.

Устройства работают под управлением Android 5 и 7 (так что должно не быть проблемой с поддержкой TLS v1.2),

Примечание. Это не самозаверяющий сертификат.Подписано Amazon.

Непосредственными мыслями были:

  1. Фрагментация Android - возможно, устройства (один из них - Kindle Fire 7) не включают правильные сертификаты вОПЕРАЦИОННЫЕ СИСТЕМЫ.Это будет не первый случай, когда производитель устройства принимает странное решение, нарушающее функциональность.

  2. Доступ к API осуществляется через прокси, и на самом деле равен a Man-In-The-Middle, правильно обнаруживаемый.


Исправление (1) означает пакетирование нашего сертификата и приводит к обычным проблемам, когда срок действия нашего сертификата истекает.

Я бы предпочел, чтобы пользователь установил отладочную сборку, которая подтверждает, является ли (1) или (2) проблемой.Такая сборка будет проверять SSL-сертификат, предоставленный сервером / прокси-сервером, и регистрировать его обратно.


Веб-фреймворки:

  • Retrofit v2.3.0
  • OkHttp v3.9.1

Вопрос:

Как проверить информацию SSL-сертификата, которую устройство видит при попадании в мою конечную точку?


Обновление за комментарий от @ SangeetSuresh :

Оказывается, есть 2 разных исключения.

Планшет Kindle Fire 7 "(KFAUWI, OS 5.1.1) выбрасывает тот, который я начал исследовать, и на котором сосредоточен этот вопрос. То есть базовый сбой SSL.

java.security.cert.CertPathValidatorException: 
    Trust anchor for certification path not found.
       at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:331)
       at com.android.org.conscrypt.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:232)
       at com.android.org.conscrypt.Platform.checkServerTrusted(Platform.java:114)

Устройство LG (LG-SP200, OS 7.1.2) имеет соединение, закрытое одноранговым узлом, который должен быть решен в рамках нового вопроса, если он не решен здесь:

javax.net.ssl.SSLHandshakeException: 
    Connection closed by peer
       at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(NativeCrypto.java)
       at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:360)
       at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.java:299)

1 Ответ

0 голосов
/ 10 сентября 2018

Робби Корнелиссен предоставил базовый ответ в комментарии со ссылкой на OkHttp Response:

информация должна быть доступна с response.handshake().peerCertificates().

Простой Interceptor был реализован для проверки сертификатов при действительном рукопожатии:

private static class SslCertificateLogger implements Interceptor {

    public static final String TAG = "SSL";

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        Response response;
        try {
            response = chain.proceed(request);
        } catch (Exception e) {
            Log.d(TAG, "<-- HTTP FAILED: " + e);
            throw e;
        }

        Handshake handshake = response.handshake();
        if (handshake == null) {
            Log.d(TAG, "no handshake");
            return response;
        }


        Log.d(TAG, "handshake success");
        List<Certificate> certificates = handshake.peerCertificates();
        if (certificates == null) {
            Log.d(TAG, "no peer certificates");
            return response;
        }

        String s;
        for (Certificate certificate : certificates) {
            s = certificate.toString();
            Log.d(TAG, s);
        }

        return response;
    }
}

Это добавляется к OkHttpClient как обычно:

OkHttpClient.Builder builder = new OkHttpClient.Builder()
        .addInterceptor(new SslCertificateLogger())
        .build();

Аналогичное решение было предложено Сангит Суреш , который ссылается на объект Retrofit Response:

response?.raw()?.handshake() Я думаю, это поможет вам

Здесь важной информацией является тот факт, что Retrofit предоставляет доступ к необработанному ответу OkHttp таким образом.

Это не будет использоваться в Interceptor, а скорее на более высоком уровне, в фактическом коде обработки Retrofit, после получения Retrofit Response<> от API.

Преобразование его решения Kotlin обратно в Java может привести к примерно так:

okhttp3.Response raw = httpResponse.raw();
if (raw != null) {
    Handshake handshake = raw.handshake();
    if (handshake != null) {
        List<Certificate> certificates = handshake.peerCertificates();
        if (certificates != null) {
            for (Certificate certificate : certificates) {
                Log.d(TAG, certificate.toString());
            }
        }
    }
}

Оба решения работают нормально, при условии, что handshake() не равно нулю, т. Е. При успешном рукопожатии.

Учитывая, что это расследование неудачных рукопожатий, потребовался еще один шаг, чтобы "доверять всем сертификатам" (только для отладочных сборок NB!).

Это было задокументировано много раз - вот одна из таких версий:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...