我们如何在Android上的HttpClient 4.4+中启用SNI?

问题描述:

我想解决在现代版本的Android上使用主要HTTP堆栈的SNI的食谱。这包括Apache独立的HttpClient库(不是版本,它已经销毁到Android本身,它已经不复存在了)。我们如何在Android上的HttpClient 4.4+中启用SNI?

看来最近的HttpClient版本不支持SNI开箱即用。当我使用'cz.msebera.android:httpclient:4.4.1.1'神器,我得到:

javax.net.ssl.SSLPeerUnverifiedException: Host name '...' does not match the certificate subject provided by the peer (CN=...) 
at cz.msebera.android.httpclient.conn.ssl.SSLConnectionSocketFactory.verifyHostname(SSLConnectionSocketFactory.java:466) 
at cz.msebera.android.httpclient.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:395) 

(与...删节主机名)

This HttpClient issue有一些代码,声称解决这一问题。但是,目前尚不清楚如何使用它。 This Stack Overflow answer有助于实现。然而,这反过来与一个等效的异常崩溃:

javax.net.ssl.SSLPeerUnverifiedException: Host name '' does not match the certificate subject provided by the peer (CN=...) 
at cz.msebera.android.httpclient.conn.ssl.SSLConnectionSocketFactory.verifyHostname(SSLConnectionSocketFactory.java:466) 
at cz.msebera.android.httpclient.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:395) 

这并不让我感到意外。建议的解决方法(用空字符串替换真实的主机名)让我觉得很奇怪。

This Stack Overflow question-and-answer基本上说“使用Java 1.7”,这不是Android的可行选项。

那么,有没有人制定了一个配方,以启用与Android兼容的HttpClient 4.4+环境的SNI?

尝试使用SSLConnectionSocketFactory的这个版本,而不是Marek Sebera的HttpClient fork。它包含这个Andriod特定位的代码。上次我使用官方的Apache端口HttpClient 4.3测试SNI时,它工作得很好。

// Android specific code to enable SNI 
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 
    if (Log.isLoggable(TAG, Log.DEBUG)) { 
     Log.d(TAG, "Enabling SNI for " + target); 
    } 
    try { 
     Method method = sslsock.getClass().getMethod("setHostname", String.class); 
     method.invoke(sslsock, target); 
    } catch (Exception ex) { 
     if (Log.isLoggable(TAG, Log.DEBUG)) { 
      Log.d(TAG, "SNI configuration failed", ex); 
     } 
    } 
} 
// End of Android specific code 
+0

谢谢!不幸的是,这是从4.3开始的,它取决于不存在的东西。然而,这*表明我可以在哪里介绍'setHostname'反射破解,我正在使用'HttpURLConnection'成功地使用(任何反射破解代表“成功”)。我已经有一个自定义的'createLayeredSocket()'''SSLConnectionSocketFactory'的自定义子类。我不会链接到超类实现,而是尝试克隆那些代码并在反射黑客中混合。 – CommonsWare

+0

我清除了克隆['SSLConnectionSocketFactory'的4.4.1版](http://svn.apache.org/repos/asf/httpcomponents/httpclient/tags/4.4.1/httpclient/src/main/java/org /apache/http/conn/ssl/SSLConnectionSocketFactory.java)并将您的答案中的代码引入'createLayeredSocket()'中,该链接位于与链接到的'4.3.5.1'版本相同的位置(在'prepareSocket()'之后) ,在'startHandshake()'之前)。这似乎工作。我的目标是最终把这个卷入图书馆。再次感谢! – CommonsWare

+0

我很高兴,帮助。请考虑向Marek报告此问题,并要求他将修补程序整合到他的叉子中。 – oleg