无法仅在牛轧糖上使用自签名证书建立SSLSession

时间:2019-04-11 18:02:54

标签: android ssl android-7.0-nougat commonsware-cwac

尝试使用自签名证书和新颖的网络安全配置方法以及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

0 个答案:

没有答案