Не удается установить SSLSession с самозаверяющим сертификатом только на Nougat - PullRequest
1 голос
/ 11 апреля 2019

Попытка установить SSLS-сеанс с использованием самозаверяющего сертификата и нового метода настройки безопасности сети, а также библиотеки cwac-netsecurity для обратной совместимости работает на всех других версиях Android (которые я пробовал), кроме Android 7.0.

У меня есть приложение для Android, которое подключается к устройству для предоставления пользовательского интерфейса для этого устройства.Соединение использует SSLSocket TLSv1 и самозаверяющий сертификат сервера на стороне устройства.До Nougat у меня были серверные сертификаты, встроенные в хранилище ключей BKS и загружаемые во время выполнения, чтобы создать собственный TrustManager для инициализации контекста SSL и создания сокета.Это больше не работает под Android 7+.После некоторых других вопросов по SO ( Невозможно подключиться через SSL с использованием самозаверяющего сертификата на Android 7 и выше ), я смог использовать метод настройки безопасности сети для установки соединения SSLSocket на устройстве Android 8 (https://developer.android.com/training/articles/security-config#ConfigCustom). Для обратной совместимости я использую библиотеку cwac-netsecurity от CommonsWare (https://github.com/commonsguy/cwac-netsecurity). Я создал небольшое тестовое приложение и тестирую против openssl s_server. То, что я написал, успешно устанавливает SSLS-сессию на устройствах Androidпод управлением 4.4, 6.0 и 8.0. Однако по какой-то причине это не выполняется на устройстве Android под управлением 7.0. Вот фрагменты кода, показывающие тест. Любая помощь приветствуется.

Тестовый код в Androidapp

{
    // createSocketFactory
    SSLSocketFactory factory = (SSLSocketFactory)SSLSocketFactory.getDefault(); //null;
    TrustManagerBuilder tmb = new TrustManagerBuilder();
    tmb.withManifestConfig(MainActivity.this);
    tmb.withCertChainListener(
            new CertChainListener()
            {
                @Override
                public void onChain(X509Certificate[] chain, String domain)
                {
                    if (domain == null)
                    {
                        Log.d(TAG, "onChain: Certificate chain for request to unknown domain");
                    }
                    else
                    {
                        Log.d(TAG, "onChain: Certificate chain for request to: " + domain);
                    }

                    for (X509Certificate cert : chain)
                    {
                        Log.d(TAG, "onChain: Subject: " + cert.getSubjectX500Principal().getName());
                        Log.d(TAG, "onChain: Issuer: " + cert.getIssuerX500Principal().getName());
                    }
                }
            });
    CompositeTrustManager ctm = tmb.build();
    try
    {
        SSLContext sc = SSLContext.getInstance("TLSv1");
        sc.init(null, new TrustManager[] { ctm }, new SecureRandom());
        factory = sc.getSocketFactory();
    }
    catch (NoSuchAlgorithmException e)
    {
        Log.e(TAG, "createSocketFactory: failed to get SSLContext", e);
    }
    catch (KeyManagementException e)
    {
        Log.e(TAG, "createSocketFactory: failed to init SSLContext from CompositeTrustManager");
    }

    // createSslSocket
    SSLSocket socket = null;
    String addr = "172.31.106.60";
    int port = 50001;

    if (factory != null)
    {
        Log.d(TAG, "createSocketFactory - SUCCESS");
        try
        {
            socket = (SSLSocket)factory.createSocket(addr, port);
            Log.d(TAG, "createAltSocket - SUCCESS");

            socket.setEnabledProtocols(new String[] { "TLSv1" });
            socket.setEnabledCipherSuites(new String[] { "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA" });
            socket.setTcpNoDelay(true);
            socket.setKeepAlive(true);
        }
        catch (IOException e)
        {
            Log.e(TAG, "createSslSocket - Couldn't create SSLSocket", e);
            try
            {
                socket.close();
            }
            catch (IOException e1)
            {
                e1.printStackTrace();
            }
            finally
            {
                socket = null;
            }
        }
    }
    else
    {
        Log.d(TAG, "createSocketFactory - FAILED");
    }

    // testSslSocket
    if (socket != null && socket.isConnected())
    {
        SSLSession session = socket.getSession();
        if (session != null && session.isValid())
            Log.d(TAG, "testSslSocket: SESSION SUCCESS");
        else
            Log.d(TAG, "testSslSocket: SESSION FAILED");

        try
        {
            socket.close();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }
}

network_securiity_config.xml

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config>
        <trust-anchors>
            <certificates src="@raw/test_cert_chain"/>
            <certificates src="system"/>
        </trust-anchors>
    </base-config>
</network-security-config>

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.ssltesting">

    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:networkSecurityConfig="@xml/network_security_config">
        <meta-data
            android:name="android.security.net.config"
            android:resource="@xml/network_security_config" />

тестовый сервер

openssl s_server -tls1 -WWW -accept 50001 -cert test.crt -key mcv.key -state

Во всех рабочих случаях,SSLSession действителен в конце процедуры тестирования, и я получаю запись в журнале от CertChainListener.при запуске этого на моем устройстве Android 7.0 все тихо.Я не получаю журналов от CertChainListener, SSLSession недопустим, и я получаю следующее на стороне сервера:

Using default temp DH parameters
ACCEPT
SSL_accept:before/accept initialization
SSL3 alert write:fatal:handshake failure
SSL_accept:error in error
140386525526784:error:1408A0C1:SSL routines:ssl3_get_client_hello:no shared cipher:s3_srvr.c:1417:
ACCEPT
...