Программный журнал SSL-сертификата

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

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

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

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

  1. Фрагментация Android - возможно, устройства (одно из них - Kindle Fire 7) не включают правильные сертификаты в ОС. Не было бы быть первым, когда производитель устройства принял странное решение это нарушает функциональность.

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


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

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


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

  • Модернизация 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)

TLS 1.2 поддерживается только Android 4.1 и выше. Кроме того, он отключен по умолчанию на устройствах с более ранней версией 5.0.

Christopher 10.09.2018 11:03

@Christopher отметил и уже проверил на моей стороне. OkHttp или Retrofit фактически позаботились об этом на старых устройствах. Сейчас выходят из строя только устройства Android 5 и 7.

Richard Le Mesurier 10.09.2018 11:07

Так что же ты можешь зацепить? Ответ OkHttp? В этом случае я думаю, что информацию можно получить на response.handshake().peerCertificates().

Robby Cornelissen 10.09.2018 11:12

Я понятия не имею. У вас может быть приложение для отладки, которое просто доверяет всем сертификатам и проверяет, что вы получаете.

Robby Cornelissen 10.09.2018 11:19

Вперед, продолжать. Поскольку у вас есть тестовый код, вы сможете составить лучший ответ, чем я.

Robby Cornelissen 10.09.2018 11:54

@RichardLeMesurier Вы добавили закрепление сертификатов для okhttp?

Sangeet Suresh 10.09.2018 12:23

@Sangeet Нет, я еще не видел. Это конечная точка, которую я использую рассчитывать на возможность работать (поскольку она работает почти на всех устройствах, iOS, Android, ПК). Я пытаюсь сфокусировать этот вопрос на как отлаживать то, что видит устройство - чтобы определить, потребуется ли закрепление для этих проблемных устройств или какой будет лучший маршрут вперед.

Richard Le Mesurier 10.09.2018 12:26

@RichardLeMesurier, вы получаете исключение квитирования SSL или тайм-аут?

Sangeet Suresh 10.09.2018 12:28

@RichardLeMesurier response?.raw()?.handshake() Думаю, это вам поможет

Sangeet Suresh 10.09.2018 12:33

@RichardLeMesurier Вы можете сделать одно: если устройство не доверяет вашему сертификату, вы можете добавить закрепление сертификата и проверить, работает ли он нормально или нет. Потому что, если вы добавите привязку сертификата, он будет проверять только этот сертификат.

Sangeet Suresh 10.09.2018 12:48
7
10
1 512
1

Ответы 1

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

the information should be available from 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() I think this will help you

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

Это будет использоваться не в Interceptor, а на более высоком уровне, в фактическом коде обработки модернизации, после получения 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() не равен нулю, т.е. когда рукопожатие прошло успешно.

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

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

Этот объект рукопожатия спас мне сегодня жизнь! Я искал перехватчик, чтобы проверить сертификаты с сервера и вау, теперь я спасен! Большое спасибо!

sunlover3 04.11.2019 18:02

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