Вопрос SSL на Android 9 Google Pixel One
Я пытаюсь выполнить HTTPS-запросы к хосту 10.10.10.1 с хоста Android с 10.10.10.2 в сети без подключения к Интернету - только WiFi 2 peers AP и устройство Android 9 Google Pixel One.
Я создал 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 из эфира WiFi:
Вот мой запрос от 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.
1 ответ
После проведения дополнительного опроса: 1. Некоторый набор устройств Android (сборок), включая Pixel 1, не принимает сеанс TCP, который не был завершен по взаимному [FIN,ACK], и полученные данные не доставляются на верхний уровень стека. Кроме того, данные могут быть не приняты, если поток TCP не был сплошным, со многими повторными передачами и изменением Seq. 2. В случае использования Qt - Конфигурация безопасности сети Android не влияет на связь. 3. Это не связано с TLS.