6

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

我正在使用套接字,并且在 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();

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

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

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

现在 sslcontext 返回 SSLSOCKETFACTORY,我想使用 SSLCertificateSocketFactory (用于 sethostname 方法)做什么.. 我希望问题很清楚,如果不让我知道或随时让我更清楚

4

1 回答 1

2

使用包含 SNI 支持的 Android 时,您可以使用NetCipher库获取现代 TLS 配置。HttpsURLConnectionNetCipher 将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

于 2016-11-01T17:19:57.333 回答