Проблема с SSL на Android 9 Google Pixel One

Я пытаюсь выполнить HTTPS-запросы к хосту 10.10.10.1 с хоста Android с 10.10.10.2 в сети без подключения к Интернету - только точка доступа Wi-Fi 2 и устройство Google Pixel One Android 9.

Я создал network_security_config.xml с моим самоподписанным сертификатом с CN = 10.10.10.1 и SAN = DNS: 10.10.10.1 PI: 10.10.10.1.

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

Я не получаю ошибку проверки и наблюдаю успешные запросы, поступающие на сервер - данные представляют собой HTTP-запрос, расшифровываются и отображаются в журнале сервера. Но сервер не может отправить данные обратно! Он отправляет, но по какой-то причине эти данные не принимаются телефоном Android - просто игнорируются.

Я вижу, что пакеты идут с сервера на телефон, и сервер неоднократно пытается выключить SSL-сокет до ошибки или успеха (я сделал такое поведение намеренно во время опроса) - вот дамп Wireshark из воздуха Wi-Fi:

Дамп Wireshark

Вот мой запрос от AsyncTask

   protected String doInBackground(String... params) {
        StringBuilder result = new StringBuilder();
        try {
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            InputStream caInput = new BufferedInputStream(MainActivity.this.getResources().openRawResource(R.raw.zone));

            Certificate ca = cf.generateCertificate(caInput);

            String keyStoreType = KeyStore.getDefaultType();
            KeyStore keyStore = KeyStore.getInstance(keyStoreType);
            keyStore.load(null, null);
            keyStore.setCertificateEntry("ca", ca);

            String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
            tmf.init(keyStore);

            SSLContext ctx = SSLContext.getInstance("TLS");
            ctx.init(null, tmf.getTrustManagers(), null);

            URL url = new URL("https://10.10.10.1/connect");
            HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
            conn.setSSLSocketFactory(ctx.getSocketFactory());

            conn.setRequestProperty("param1", params[0]);
            conn.setRequestProperty("param2", params[1]);
            conn.setRequestMethod("POST");

            conn.setDoOutput(true);
            conn.setDoInput(true);

            mInputStream = conn.getInputStream();
            byte[] buffer = new byte[1024];
            ByteArrayOutputStream _buf = new ByteArrayOutputStream();
            int l;
            BufferedInputStream bufin = new BufferedInputStream(mInputStream);
            while ((l = bufin.read(buffer,0,1024)) != -1) {
                _buf.write(buffer, 0, l);
                String rec = _buf.toString("UTF-8");
                Log.d("MAIN", "Read: " + rec);
                result.append(rec);
            }
            Log.d("MAIN", "Read finished: " + result.toString());

        } catch (Exception e) {
            e.printStackTrace();
        }
        return result.toString();
    }

Я подозреваю, что Android 9 Network Security каким-то образом блокирует трафик. Я попытался использовать SSLSockets, сменить порт с 443 на, например. 1234 - не повезло.

На самом деле мое приложение создается с помощью Qt, и сначала я использовал материал Qt, но мне не повезло - я сделал откат на Java-код Android в моем MainActivity, который я вызываю через JNI из кода Qt. Результат тот же, больше идей у ​​меня нет ...

Где копать?

UPD1

Когда самозаверяющий сертификат создается с SAN, содержащим только DNS:10.10.10.1 (без IP: 10.10.10.1), SSL не работает с предупреждениями:

W System.err: javax.net.ssl.SSLPeerUnverifiedException: Hostname 10.10.10.1 not verified:
W System.err:     certificate: sha1/gyr2GOhy5lA+ZAHEzh0E2SBEgx0=
W System.err:     DN: CN=10.10.10.1,O=Some ltd.,L=Knoxville,ST=TN,C=US
W System.err:     subjectAltNames: [10.10.10.1]
W System.err:   at com.android.okhttp.internal.io.RealConnection.connectTls(RealConnection.java:201)
W System.err:   at com.android.okhttp.internal.io.RealConnection.connectSocket(RealConnection.java:149)
W ...

И наоборот, с SAN IP: 10.10.10.1 (без DNS: 10.10.10.1) - работает, как и раньше - сеанс установлен, данные передаются на сервер и расшифровываются, но ответы от сервера к клиенту просто игнорируются клиентом.

UPD2

Я также пробовал использовать доменное имя some.device для устройства 10.10.10.1 и выдал сертификат с CN и SAN DNS = some.device. Это разрешено клиентом Android 9, данные отправляются успешно, но ответ все еще не принимается.

Похоже на ошибку Android.


person atlascoder    schedule 16.12.2018    source источник


Ответы (1)


После проведения дополнительных исследований: 1. Некоторые наборы устройств (сборок) Android, включая Pixel 1, не принимают сеанс TCP, который не был завершен взаимным [FIN, ACK], и полученные данные не доставляются на верхний уровень стека. Также данные могут быть не приняты, если поток TCP не был сплошным, с множеством повторных передач и изменением Seq. 2. В случае использования Qt - Конфигурация сетевой безопасности Android не влияет на связь. 3. Это не проблема, связанная с TLS.

person atlascoder    schedule 13.01.2019