使用SSLCertificateSocketFactory支持Android HTTPS SNI

时间:2014-06-24 22:31:58

标签: android sockets ssl sni

我正在尝试使用SSLCertificateSocketFactory.setHostname添加SNI支持,通过wireshark我看到客户端和启用SNI的服务器之间的通信,CLIENT HELLO转到服务器(设置了正确的主机名),Server响应Server Hello并发送证书到客户端,但在客户端没有发送证书和通信/握手停止后,通过openssl命令openssl s_client -connect theclient -servername thehostname -cert thecertificate一切顺利,握手成功发生..

我正在使用socket和socket.startHandshake我得到异常:              IOException:javax.net.ssl.SSLHandshakeException:java.security.cert.CertPathValidatorException:找不到证书路径的信任锚。

           final SSLCertificateSocketFactory sslSocketFactory = (SSLCertificateSocketFactory) SSLCertificateSocketFactory.getDefault(0);

            socket = (SSLSocket) sslSocketFactory.createSocket(InetAddress.getByName("theserver"), 443);


            socket.setEnabledProtocols(socket.getSupportedProtocols());

            String[] cipherArray = socket.getEnabledCipherSuites();
            for(int i = 0; i<cipherArray.length; i++) {
                Log.e("","Available Cipher:"+cipherArray[i]);
            }
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                sslSocketFactory.setHostname(socket, "thehostname");
            } else {
                try {
                    java.lang.reflect.Method setHostnameMethod = socket.getClass().getMethod("setHostname", String.class);
                    setHostnameMethod.invoke(socket, "thehostname");
                } catch (Exception e) {
                    Log.w("", "SNI not useable", e);
                }
            }
            socket.setSoTimeout(20000);
            socket.setUseClientMode(true);
            Log.i(getClass().toString(), "Connected.");
            socket.startHandshake();
            SSLSession session = socket.getSession();
            boolean secured = session.isValid();

Android开发人员的这个IOexception SSLHANDSHAKEEXCEPTION的解决方案是https://developer.android.com/training/articles/security-ssl.html#CommonProblems

&#34;从InputStream获取特定CA,使用它创建KeyStore,然后用于创建和初始化TrustManager。 TrustManager是系统用于验证来自服务器的证书的方法,并且通过从具有一个或多个CA的KeyStore创建一个证书 - 那些将是该TrustManager信任的唯一CA.

给定新的TrustManager,该示例初始化一个新的SSLContext,它提供了一个SSLSocketFactory,可用于覆盖HttpsURLConnection中的默认SSLSocketFactory。这样,连接将使用您的CA进行证书验证。&#34;

现在sslcontext返回SSLSOCKETFACTORY,我想使用SSLCertificateSocketFactory(用于sethostname方法)怎么办.. 我希望这个问题很清楚,如果不是让我知道或随意做出更清楚的话

1 个答案:

答案 0 :(得分:2)

使用Android HttpsURLConnection(包括SNI支持)时,您可以使用NetCipher库来获取现代TLS配置。 NetCipher将HttpsURLConnection实例配置为使用支持最佳的TLS版本,以及该TLS版本的最佳密码套件。首先,将其添加到 build.gradle

compile 'info.guardianproject.netcipher:netcipher:2.0.0-alpha1'

或者您可以下载 netcipher.jar 并将其直接包含在您的应用中。然后而不是呼叫:

HttpURLConnection connection = (HttpURLConnection) sourceUrl.openConnection();

请致电:

HttpsURLConnection connection = NetCipher.getHttpsURLConnection(sourceUrl);

如果您想了解代码的完成情况,请查看TlsOnlySocketFactory