使用SSLCertificateSocketFactory的Android HTTPS SNI支持 [英] Android HTTPS SNI support using SSLCertificateSocketFactory

查看:338
本文介绍了使用SSLCertificateSocketFactory的Android HTTPS SNI支持的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to add SNI support using SSLCertificateSocketFactory.setHostname, With wireshark i see the communication between client and SNI enabled server, The CLIENT HELLO goes to the server(with the correct hostname set), Server responds with Server Hello and sends certificate to client but after that client is not sending Certificate and communication/Handshake stops, via openssl command openssl s_client -connect theclient -servername thehostname -cert thecertificate everything goes smooth, Handshake occurs successfully ..

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

I am using sockets and on socket.startHandshake i get exception : IOException :javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

           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();

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

The solution of this IOexception SSLHANDSHAKEEXCEPTION on android developers is https://developer.android.com/training/articles/security-ssl.html#CommonProblems :

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

"Take a specific CA from an InputStream, uses it to create a KeyStore, which is then used to create and initialize a TrustManager. A TrustManager is what the system uses to validate certificates from the server and—by creating one from a KeyStore with one or more CAs—those will be the only CAs trusted by that TrustManager.

鉴于新的TrustManager,该示例初始化了一个新的SSLContext,该SSLContext提供了一个SSLSocketFactory,您可以使用该SSLSocketFactory覆盖HttpsURLConnection中的默认SSLSocketFactory.这样,连接将使用您的CA进行证书验证."

Given the new TrustManager, the example initializes a new SSLContext which provides an SSLSocketFactory you can use to override the default SSLSocketFactory from HttpsURLConnection. This way the connection will use your CAs for certificate validation."

现在sslcontext返回SSLSOCKETFACTORY,我想使用SSLCertificateSocketFactory(对于sethostname方法)该怎么办.. 我希望这个问题是明确的,如果不能让我知道或随时提出来更清楚

Now the sslcontext returns SSLSOCKETFACTORY, i want to use SSLCertificateSocketFactory (for sethostname method) What to do .. I hope the question is clear, if not let me know or feel free to make to more clear

推荐答案

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

You can use the NetCipher library to get a modern TLS config when using Android's HttpsURLConnection including SNI support. NetCipher configures the HttpsURLConnection instance to use the best supported TLS version, as well as the best suite of ciphers for that TLS version. First, add it to your build.gradle:

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

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

Or you can download the netcipher.jar and include it directly in your app. Then instead of calling:

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

呼叫此:

HttpsURLConnection connection = NetCipher.getHttpsURLConnection(sourceUrl);

如果要查看其在代码中的完成方式,请查看

If you want to see how its done in the code, look at TlsOnlySocketFactory

这篇关于使用SSLCertificateSocketFactory的Android HTTPS SNI支持的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆