1
0
mirror of https://github.com/etesync/android synced 2025-06-29 11:22:36 +00:00

Add SNI support for Android 4.2+ for new API again (fixes #205)

This commit is contained in:
rfc2822 2014-03-23 22:19:19 +01:00
parent a02b8a1b1e
commit 84211564bc
3 changed files with 37 additions and 29 deletions

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="at.bitfire.davdroid" package="at.bitfire.davdroid"
android:versionCode="31" android:versionCode="32"
android:versionName="0.5.10" android:installLocation="internalOnly"> android:versionName="0.5.10.1" android:installLocation="internalOnly">
<uses-sdk <uses-sdk
android:minSdkVersion="14" android:minSdkVersion="14"

View File

@ -12,6 +12,9 @@ package at.bitfire.davdroid.webdav;
import at.bitfire.davdroid.Constants; import at.bitfire.davdroid.Constants;
import ch.boye.httpclientandroidlib.client.config.RequestConfig; import ch.boye.httpclientandroidlib.client.config.RequestConfig;
import ch.boye.httpclientandroidlib.config.Registry;
import ch.boye.httpclientandroidlib.config.RegistryBuilder;
import ch.boye.httpclientandroidlib.conn.socket.ConnectionSocketFactory;
import ch.boye.httpclientandroidlib.impl.client.CloseableHttpClient; import ch.boye.httpclientandroidlib.impl.client.CloseableHttpClient;
import ch.boye.httpclientandroidlib.impl.client.HttpClients; import ch.boye.httpclientandroidlib.impl.client.HttpClients;
import ch.boye.httpclientandroidlib.impl.conn.ManagedHttpClientConnectionFactory; import ch.boye.httpclientandroidlib.impl.conn.ManagedHttpClientConnectionFactory;
@ -19,9 +22,14 @@ import ch.boye.httpclientandroidlib.impl.conn.PoolingHttpClientConnectionManager
public class DavHttpClient { public class DavHttpClient {
protected final static RequestConfig defaultRqConfig; private final static RequestConfig defaultRqConfig;
private final static Registry<ConnectionSocketFactory> socketFactoryRegistry;
static { static {
socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create()
.register("https", TlsSniSocketFactory.INSTANCE)
.build();
// use request defaults from AndroidHttpClient // use request defaults from AndroidHttpClient
defaultRqConfig = RequestConfig.copy(RequestConfig.DEFAULT) defaultRqConfig = RequestConfig.copy(RequestConfig.DEFAULT)
.setConnectTimeout(20*1000) .setConnectTimeout(20*1000)
@ -36,14 +44,14 @@ public class DavHttpClient {
public static CloseableHttpClient create() { public static CloseableHttpClient create() {
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
// limits per DavHttpClient (= per DavSyncAdapter extends AbstractThreadedSyncAdapter) // limits per DavHttpClient (= per DavSyncAdapter extends AbstractThreadedSyncAdapter)
connectionManager.setMaxTotal(2); // max. 2 connections in total connectionManager.setMaxTotal(2); // max. 2 connections in total
connectionManager.setDefaultMaxPerRoute(2); // max. 2 connections per host connectionManager.setDefaultMaxPerRoute(2); // max. 2 connections per host
return HttpClients.custom() return HttpClients.custom()
.useSystemProperties() .useSystemProperties()
.setSSLSocketFactory(TlsSniSocketFactory.INSTANCE)
.setConnectionManager(connectionManager) .setConnectionManager(connectionManager)
.setDefaultRequestConfig(defaultRqConfig) .setDefaultRequestConfig(defaultRqConfig)
.setUserAgent("DAVdroid/" + Constants.APP_VERSION) .setUserAgent("DAVdroid/" + Constants.APP_VERSION)

View File

@ -11,7 +11,6 @@
package at.bitfire.davdroid.webdav; package at.bitfire.davdroid.webdav;
import java.io.IOException; import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.Socket; import java.net.Socket;
import java.net.UnknownHostException; import java.net.UnknownHostException;
@ -21,58 +20,50 @@ import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocket;
import ch.boye.httpclientandroidlib.HttpHost;
import ch.boye.httpclientandroidlib.conn.socket.LayeredConnectionSocketFactory;
import ch.boye.httpclientandroidlib.conn.ssl.BrowserCompatHostnameVerifier;
import ch.boye.httpclientandroidlib.protocol.HttpContext;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.net.SSLCertificateSocketFactory; import android.net.SSLCertificateSocketFactory;
import android.os.Build; import android.os.Build;
import android.util.Log; import android.util.Log;
import ch.boye.httpclientandroidlib.HttpHost;
import ch.boye.httpclientandroidlib.conn.socket.LayeredConnectionSocketFactory;
import ch.boye.httpclientandroidlib.conn.ssl.BrowserCompatHostnameVerifier;
import ch.boye.httpclientandroidlib.protocol.HttpContext;
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public class TlsSniSocketFactory implements LayeredConnectionSocketFactory { public class TlsSniSocketFactory implements LayeredConnectionSocketFactory {
private static final String TAG = "davdroid.SNISocketFactory"; private static final String TAG = "davdroid.SNISocketFactory";
final static HostnameVerifier hostnameVerifier = new BrowserCompatHostnameVerifier();
final static TlsSniSocketFactory INSTANCE = new TlsSniSocketFactory(); final static TlsSniSocketFactory INSTANCE = new TlsSniSocketFactory();
private final static SSLCertificateSocketFactory sslSocketFactory = (SSLCertificateSocketFactory) SSLCertificateSocketFactory.getDefault(0);
private final static HostnameVerifier hostnameVerifier = new BrowserCompatHostnameVerifier();
// Plain TCP/IP (layer below TLS) // Plain TCP/IP (layer below TLS)
@Override @Override
public Socket createSocket(HttpContext context) throws IOException { public Socket createSocket(HttpContext context) throws IOException {
return null; return sslSocketFactory.createSocket();
} }
@Override @Override
public Socket connectSocket(int timeout, Socket socket, HttpHost host, InetSocketAddress remoteAddr, InetSocketAddress localAddr, HttpContext context) public Socket connectSocket(int timeout, Socket socket, HttpHost host, InetSocketAddress remoteAddr, InetSocketAddress localAddr, HttpContext context) throws IOException {
throws IOException { // we don't need the non-SSL socket
return null; socket.close();
}
// TLS layer
@Override
public Socket createLayeredSocket(Socket plainSocket, String host, int port, HttpContext context) throws IOException, UnknownHostException {
plainSocket.close();
// create and connect SSL socket, but don't do hostname/certificate verification yet // create and connect SSL socket, but don't do hostname/certificate verification yet
SSLCertificateSocketFactory sslSocketFactory = (SSLCertificateSocketFactory) SSLCertificateSocketFactory.getDefault(0); SSLSocket ssl = (SSLSocket)sslSocketFactory.createSocket(remoteAddr.getAddress(), host.getPort());
SSLSocket ssl = (SSLSocket)sslSocketFactory.createSocket(InetAddress.getByName(host), port);
// set up SNI before the handshake // set up SNI before the handshake
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
Log.d(TAG, "Setting SNI hostname"); Log.d(TAG, "Setting SNI hostname");
sslSocketFactory.setHostname(ssl, host); sslSocketFactory.setHostname(ssl, host.getHostName());
} else } else
Log.i(TAG, "No SNI support below Android 4.2!"); Log.i(TAG, "No SNI support below Android 4.2!");
// verify hostname and certificate // verify hostname and certificate
SSLSession session = ssl.getSession(); SSLSession session = ssl.getSession();
if (!hostnameVerifier.verify(host, session)) if (!hostnameVerifier.verify(host.getHostName(), session))
throw new SSLPeerUnverifiedException("Cannot verify hostname: " + host); throw new SSLPeerUnverifiedException("Cannot verify hostname: " + host);
Log.i(TAG, "Established " + session.getProtocol() + " connection with " + session.getPeerHost() + Log.i(TAG, "Established " + session.getProtocol() + " connection with " + session.getPeerHost() +
@ -80,4 +71,13 @@ public class TlsSniSocketFactory implements LayeredConnectionSocketFactory {
return ssl; return ssl;
} }
// TLS layer
@Override
public Socket createLayeredSocket(Socket plainSocket, String host, int port, HttpContext context) throws IOException, UnknownHostException {
Log.wtf(TAG, "createLayeredSocket should never be called");
return plainSocket;
}
} }