From c37149dec7dbc2ff2bccfa643792080c3c86ce18 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Wed, 25 Oct 2017 15:55:49 +0200 Subject: 8757 fixes session cookie handling by implementing okHttpClient and custom cookiejar, enables TLS 1.2 on old devices, restricts allowed cipher suites on new devices in order to harden tls based communication --- .../leap/bitmaskclient/TLSCompatSocketFactory.java | 133 +++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 app/src/main/java/se/leap/bitmaskclient/TLSCompatSocketFactory.java (limited to 'app/src/main/java/se/leap/bitmaskclient/TLSCompatSocketFactory.java') diff --git a/app/src/main/java/se/leap/bitmaskclient/TLSCompatSocketFactory.java b/app/src/main/java/se/leap/bitmaskclient/TLSCompatSocketFactory.java new file mode 100644 index 00000000..fdad6ba9 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/TLSCompatSocketFactory.java @@ -0,0 +1,133 @@ +package se.leap.bitmaskclient; + +import android.util.Log; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.cert.CertificateException; +import java.util.Arrays; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; + +import okhttp3.OkHttpClient; + +/** + * Created by cyberta on 24.10.17. + * This class ensures that modern TLS algorithms will also be used on old devices (Android 4.1 - Android 4.4.4) in order to avoid + * attacks like POODLE. + */ + +public class TLSCompatSocketFactory extends SSLSocketFactory { + + private static final String TAG = TLSCompatSocketFactory.class.getName(); + private SSLSocketFactory internalSSLSocketFactory; + private SSLContext sslContext; + private TrustManager trustManager; + + public TLSCompatSocketFactory(String trustedCaCert) throws KeyManagementException, NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException, NoSuchProviderException { + + initTrustManager(trustedCaCert); + internalSSLSocketFactory = sslContext.getSocketFactory(); + + } + + public void initSSLSocketFactory(OkHttpClient.Builder builder) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, KeyManagementException, IllegalStateException { + builder.sslSocketFactory(this, (X509TrustManager) trustManager); + } + + + private void initTrustManager(String trustedCaCert) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException, IllegalStateException, KeyManagementException, NoSuchProviderException { + java.security.cert.Certificate provider_certificate = ConfigHelper.parseX509CertificateFromString(trustedCaCert); + + // Create a KeyStore containing our trusted CAs + String defaultType = KeyStore.getDefaultType(); + KeyStore keyStore = KeyStore.getInstance(defaultType); + keyStore.load(null, null); + keyStore.setCertificateEntry("provider_ca_certificate", provider_certificate); + + // Create a TrustManager that trusts the CAs in our KeyStore + String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); + TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm); + tmf.init(keyStore); + + // Check if there's only 1 X509Trustmanager -> from okttp3 source code example + TrustManager[] trustManagers = tmf.getTrustManagers(); + if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) { + throw new IllegalStateException("Unexpected default trust managers:" + + Arrays.toString(trustManagers)); + } + + trustManager = trustManagers[0]; + + // Create an SSLContext that uses our TrustManager + sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, tmf.getTrustManagers(), null); + + } + + + @Override + public String[] getDefaultCipherSuites() { + return internalSSLSocketFactory.getDefaultCipherSuites(); + } + + @Override + public String[] getSupportedCipherSuites() { + return internalSSLSocketFactory.getSupportedCipherSuites(); + } + + @Override + public Socket createSocket() throws IOException { + return enableTLSOnSocket(internalSSLSocketFactory.createSocket()); + } + + @Override + public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException { + return enableTLSOnSocket(internalSSLSocketFactory.createSocket(s, host, port, autoClose)); + } + + @Override + public Socket createSocket(String host, int port) throws IOException, UnknownHostException { + return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port)); + } + + @Override + public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException { + return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port, localHost, localPort)); + } + + @Override + public Socket createSocket(InetAddress host, int port) throws IOException { + return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port)); + } + + @Override + public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { + return enableTLSOnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort)); + } + + private Socket enableTLSOnSocket(Socket socket) { + if(socket != null && (socket instanceof SSLSocket)) { + ((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.2"}); + ((SSLSocket)socket).setEnabledCipherSuites(getSupportedCipherSuites()); + } + return socket; + + + } + + + +} -- cgit v1.2.3 From 68bc106ee872b13830dfa5fa9794f7cecb306d8e Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 28 Oct 2017 20:41:05 +0200 Subject: #8757 refactores ProviderAPI for insecure flavor, fixes tests, renames confusing constants, updates robotium --- .../leap/bitmaskclient/TLSCompatSocketFactory.java | 60 +++++++++++++++------- 1 file changed, 42 insertions(+), 18 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient/TLSCompatSocketFactory.java') diff --git a/app/src/main/java/se/leap/bitmaskclient/TLSCompatSocketFactory.java b/app/src/main/java/se/leap/bitmaskclient/TLSCompatSocketFactory.java index fdad6ba9..76d38447 100644 --- a/app/src/main/java/se/leap/bitmaskclient/TLSCompatSocketFactory.java +++ b/app/src/main/java/se/leap/bitmaskclient/TLSCompatSocketFactory.java @@ -1,6 +1,6 @@ package se.leap.bitmaskclient; -import android.util.Log; +import android.text.TextUtils; import java.io.IOException; import java.net.InetAddress; @@ -33,14 +33,14 @@ public class TLSCompatSocketFactory extends SSLSocketFactory { private static final String TAG = TLSCompatSocketFactory.class.getName(); private SSLSocketFactory internalSSLSocketFactory; - private SSLContext sslContext; private TrustManager trustManager; public TLSCompatSocketFactory(String trustedCaCert) throws KeyManagementException, NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException, NoSuchProviderException { + initForSelfSignedCAs(trustedCaCert); + } - initTrustManager(trustedCaCert); - internalSSLSocketFactory = sslContext.getSocketFactory(); - + public TLSCompatSocketFactory() throws CertificateException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException, NoSuchProviderException, IOException { + initForCommercialCAs(); } public void initSSLSocketFactory(OkHttpClient.Builder builder) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, KeyManagementException, IllegalStateException { @@ -48,14 +48,15 @@ public class TLSCompatSocketFactory extends SSLSocketFactory { } - private void initTrustManager(String trustedCaCert) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException, IllegalStateException, KeyManagementException, NoSuchProviderException { - java.security.cert.Certificate provider_certificate = ConfigHelper.parseX509CertificateFromString(trustedCaCert); - + private void initForSelfSignedCAs(String trustedSelfSignedCaCert) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException, IllegalStateException, KeyManagementException, NoSuchProviderException { // Create a KeyStore containing our trusted CAs String defaultType = KeyStore.getDefaultType(); KeyStore keyStore = KeyStore.getInstance(defaultType); keyStore.load(null, null); - keyStore.setCertificateEntry("provider_ca_certificate", provider_certificate); + if (!TextUtils.isEmpty(trustedSelfSignedCaCert)) { + java.security.cert.Certificate provider_certificate = ConfigHelper.parseX509CertificateFromString(trustedSelfSignedCaCert); + keyStore.setCertificateEntry("provider_ca_certificate", provider_certificate); + } // Create a TrustManager that trusts the CAs in our KeyStore String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); @@ -72,9 +73,32 @@ public class TLSCompatSocketFactory extends SSLSocketFactory { trustManager = trustManagers[0]; // Create an SSLContext that uses our TrustManager - sslContext = SSLContext.getInstance("TLS"); + SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, tmf.getTrustManagers(), null); + internalSSLSocketFactory = sslContext.getSocketFactory(); + + } + + + private void initForCommercialCAs() throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException { + + // Create a TrustManager that trusts the CAs in our KeyStore + String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); + TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm); + tmf.init((KeyStore) null); + + // Check if there's only 1 X509Trustmanager -> from okttp3 source code example + TrustManager[] trustManagers = tmf.getTrustManagers(); + if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) { + throw new IllegalStateException("Unexpected default trust managers:" + + Arrays.toString(trustManagers)); + } + + trustManager = trustManagers[0]; + SSLContext context = SSLContext.getInstance("TLS"); + context.init(null, null, null); + internalSSLSocketFactory = context.getSocketFactory(); } @@ -89,39 +113,39 @@ public class TLSCompatSocketFactory extends SSLSocketFactory { } @Override - public Socket createSocket() throws IOException { + public Socket createSocket() throws IOException, IllegalArgumentException { return enableTLSOnSocket(internalSSLSocketFactory.createSocket()); } @Override - public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException { + public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException, IllegalArgumentException { return enableTLSOnSocket(internalSSLSocketFactory.createSocket(s, host, port, autoClose)); } @Override - public Socket createSocket(String host, int port) throws IOException, UnknownHostException { + public Socket createSocket(String host, int port) throws IOException, UnknownHostException, IllegalArgumentException { return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port)); } @Override - public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException { + public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException, IllegalArgumentException { return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port, localHost, localPort)); } @Override - public Socket createSocket(InetAddress host, int port) throws IOException { + public Socket createSocket(InetAddress host, int port) throws IOException, IllegalArgumentException { return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port)); } @Override - public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { + public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException, IllegalArgumentException { return enableTLSOnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort)); } - private Socket enableTLSOnSocket(Socket socket) { + private Socket enableTLSOnSocket(Socket socket) throws IllegalArgumentException { if(socket != null && (socket instanceof SSLSocket)) { ((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.2"}); - ((SSLSocket)socket).setEnabledCipherSuites(getSupportedCipherSuites()); + //TODO: add a android version check as soon as a new Android API or bcjsse supports TLSv1.3 } return socket; -- cgit v1.2.3