1
0
mirror of https://github.com/etesync/android synced 2024-11-15 12:28:57 +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"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="at.bitfire.davdroid"
android:versionCode="31"
android:versionName="0.5.10" android:installLocation="internalOnly">
android:versionCode="32"
android:versionName="0.5.10.1" android:installLocation="internalOnly">
<uses-sdk
android:minSdkVersion="14"

View File

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

View File

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