Попытка установить 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