尝试使用自签名证书和新颖的网络安全配置方法以及cwac-netsecurity库建立SSLSession以实现向后兼容性,但适用于除7.0以外的所有其他版本的android(我已经尝试过)。
我有一个连接到设备的Android应用程序,以提供该设备的UI。该连接在设备侧使用TLSv1 SSLSocket和自签名服务器证书。在Nougat之前,我将服务器证书嵌入为BKS密钥存储区,并在运行时加载以创建自定义TrustManager,以初始化SSL上下文并创建套接字。这在Android 7+上不再起作用。在对SO(Cannot connect via SSL using self signed certificate on Android 7 and above)提出其他一些问题之后,我能够使用网络安全配置方法在Android 8设备(https://developer.android.com/training/articles/security-config#ConfigCustom)上建立SSLSocket连接。为了向后兼容,我使用了CommonsWare(https://github.com/commonsguy/cwac-netsecurity)中的cwac-netsecurity库。我构建了一个小型测试应用程序,并且正在针对openssl s_server进行测试。我写的东西可以从运行4.4、6.0和8.0的android设备成功建立SSLSession。但是由于某种原因,它在运行7.0的android设备上不这样做。这是显示测试的代码片段。任何帮助将不胜感激。
Android应用中的测试代码
{
// 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