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:
parent
a02b8a1b1e
commit
84211564bc
@ -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"
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user