问题
I am trying to work out recipes for using SNI with major HTTP stacks on modern versions of Android. This includes Apache's separate HttpClient library (not the version baked into Android itself, which is dead and gone).
It appears that recent versions of HttpClient do not support SNI out of the box. When I use the 'cz.msebera.android:httpclient:4.4.1.1' artifact, I get:
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)
(host names redacted with ...)
This HttpClient issue has some code that purports to address this. However, it is not clear exactly how to use it. This Stack Overflow answer helps a bit with an implementation. However, that in turn crashes with an equivalent exception:
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 does not surprise me. The proposed workaround (replace the real host name with the empty string) struck me as rather odd.
This Stack Overflow question-and-answer basically say "use Java 1.7", which is not a viable option for Android.
So, has anyone worked out a recipe for enabling SNI with an Android-compatible HttpClient 4.4+ environment?
回答1:
Try using this version of SSLConnectionSocketFactory instead of the one shipped with Marek Sebera's fork of HttpClient. It contains this Andriod specific bit of code. Last time I tested SNI with the official Apache port of HttpClient 4.3 it worked just fine.
// 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
来源:https://stackoverflow.com/questions/35782882/how-do-we-enable-sni-in-httpclient-4-4-on-android