From d84ce6ddb996e0e17c3de974bf67cb2f1d42b668 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20Veres-Szentkir=C3=A1lyi?= Date: Tue, 15 Oct 2013 10:16:42 +0200 Subject: [PATCH 1/6] Hardened TLS cipher suites and versions As Georg Lukas wrote in his blog post about how Android handles TLS handshake (http://op-co.de/blog/posts/android_ssl_downgrade/), an explicit order of cipher suites and TLS versions must be supplied to avoid having the weak (presumably broken) RC4 cipher at the top of the preference list. This commit adds the list included in the blog post to every TLS socket creation, including IMAP, POP3 and SMTP, see Wireshark screenshots done during testing at http://vsza.hu/k9mail-tls-hardening/ --- src/com/fsck/k9/mail/store/ImapStore.java | 3 ++ src/com/fsck/k9/mail/store/Pop3Store.java | 3 ++ .../fsck/k9/mail/transport/SmtpTransport.java | 2 ++ .../mail/transport/TrustedSocketFactory.java | 28 +++++++++++++++++++ 4 files changed, 36 insertions(+) diff --git a/src/com/fsck/k9/mail/store/ImapStore.java b/src/com/fsck/k9/mail/store/ImapStore.java index e2bbfa0f1..8334db923 100644 --- a/src/com/fsck/k9/mail/store/ImapStore.java +++ b/src/com/fsck/k9/mail/store/ImapStore.java @@ -50,6 +50,7 @@ import java.util.zip.InflaterInputStream; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLException; +import javax.net.ssl.SSLSocket; import javax.net.ssl.TrustManager; import org.apache.commons.io.IOUtils; @@ -96,6 +97,7 @@ import com.fsck.k9.mail.store.ImapResponseParser.ImapList; import com.fsck.k9.mail.store.ImapResponseParser.ImapResponse; import com.fsck.k9.mail.store.imap.ImapUtility; import com.fsck.k9.mail.transport.imap.ImapSettings; +import com.fsck.k9.mail.transport.TrustedSocketFactory; import com.jcraft.jzlib.JZlib; import com.jcraft.jzlib.ZOutputStream; @@ -2450,6 +2452,7 @@ public class ImapStore extends Store { TrustManagerFactory.get(mSettings.getHost(), secure) }, new SecureRandom()); mSocket = sslContext.getSocketFactory().createSocket(); + TrustedSocketFactory.hardenSocket((SSLSocket)mSocket); } else { mSocket = new Socket(); } diff --git a/src/com/fsck/k9/mail/store/Pop3Store.java b/src/com/fsck/k9/mail/store/Pop3Store.java index 7cac7b48e..ff7e1a3ba 100644 --- a/src/com/fsck/k9/mail/store/Pop3Store.java +++ b/src/com/fsck/k9/mail/store/Pop3Store.java @@ -7,12 +7,14 @@ import com.fsck.k9.Account; import com.fsck.k9.K9; import com.fsck.k9.controller.MessageRetrievalListener; import com.fsck.k9.helper.Utility; +import com.fsck.k9.mail.transport.TrustedSocketFactory; import com.fsck.k9.mail.*; import com.fsck.k9.mail.internet.MimeMessage; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLException; +import javax.net.ssl.SSLSocket; import javax.net.ssl.TrustManager; import java.io.*; import java.net.*; @@ -331,6 +333,7 @@ public class Pop3Store extends Store { TrustManagerFactory.get(mHost, secure) }, new SecureRandom()); mSocket = sslContext.getSocketFactory().createSocket(); + TrustedSocketFactory.hardenSocket((SSLSocket)mSocket); } else { mSocket = new Socket(); } diff --git a/src/com/fsck/k9/mail/transport/SmtpTransport.java b/src/com/fsck/k9/mail/transport/SmtpTransport.java index 30ad91b4d..1b4c57d25 100644 --- a/src/com/fsck/k9/mail/transport/SmtpTransport.java +++ b/src/com/fsck/k9/mail/transport/SmtpTransport.java @@ -17,6 +17,7 @@ import com.fsck.k9.mail.store.LocalStore.LocalMessage; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLException; +import javax.net.ssl.SSLSocket; import javax.net.ssl.TrustManager; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; @@ -245,6 +246,7 @@ public class SmtpTransport extends Transport { TrustManagerFactory.get(mHost, secure) }, new SecureRandom()); mSocket = sslContext.getSocketFactory().createSocket(); + TrustedSocketFactory.hardenSocket((SSLSocket)mSocket); mSocket.connect(socketAddress, SOCKET_CONNECT_TIMEOUT); } else { mSocket = new Socket(); diff --git a/src/com/fsck/k9/mail/transport/TrustedSocketFactory.java b/src/com/fsck/k9/mail/transport/TrustedSocketFactory.java index fa23f079b..264874fb9 100644 --- a/src/com/fsck/k9/mail/transport/TrustedSocketFactory.java +++ b/src/com/fsck/k9/mail/transport/TrustedSocketFactory.java @@ -21,6 +21,27 @@ public class TrustedSocketFactory implements LayeredSocketFactory { private SSLSocketFactory mSocketFactory; private org.apache.http.conn.ssl.SSLSocketFactory mSchemeSocketFactory; + protected static final String ENABLED_CIPHERS[] = { + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", + "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", + "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", + "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_RSA_WITH_RC4_128_SHA", + "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", + "TLS_RSA_WITH_AES_128_CBC_SHA", + "TLS_RSA_WITH_AES_256_CBC_SHA", + "SSL_RSA_WITH_3DES_EDE_CBC_SHA", + "SSL_RSA_WITH_RC4_128_SHA", + "SSL_RSA_WITH_RC4_128_MD5", + }; + + protected static final String ENABLED_PROTOCOLS[] = { + "TLSv1.2", "TLSv1.1", "TLSv1" + }; + public TrustedSocketFactory(String host, boolean secure) throws NoSuchAlgorithmException, KeyManagementException { SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, new TrustManager[] { @@ -45,6 +66,12 @@ public class TrustedSocketFactory implements LayeredSocketFactory { public boolean isSecure(Socket sock) throws IllegalArgumentException { return mSchemeSocketFactory.isSecure(sock); } + + public static void hardenSocket(SSLSocket sock) { + sock.setEnabledCipherSuites(ENABLED_CIPHERS); + sock.setEnabledProtocols(ENABLED_PROTOCOLS); + } + public Socket createSocket( final Socket socket, final String host, @@ -59,6 +86,7 @@ public class TrustedSocketFactory implements LayeredSocketFactory { ); //hostnameVerifier.verify(host, sslSocket); // verifyHostName() didn't blowup - good! + hardenSocket(sslSocket); return sslSocket; } } From dbc47c7297b677636c7a242e386372f7f8236093 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20Veres-Szentkir=C3=A1lyi?= Date: Sun, 20 Oct 2013 10:22:53 +0200 Subject: [PATCH 2/6] filter enabled cipher suites by availability --- .../mail/transport/TrustedSocketFactory.java | 62 ++++++++++++++----- 1 file changed, 45 insertions(+), 17 deletions(-) diff --git a/src/com/fsck/k9/mail/transport/TrustedSocketFactory.java b/src/com/fsck/k9/mail/transport/TrustedSocketFactory.java index 264874fb9..9a4d3d585 100644 --- a/src/com/fsck/k9/mail/transport/TrustedSocketFactory.java +++ b/src/com/fsck/k9/mail/transport/TrustedSocketFactory.java @@ -16,27 +16,53 @@ import java.net.UnknownHostException; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; +import java.util.*; public class TrustedSocketFactory implements LayeredSocketFactory { private SSLSocketFactory mSocketFactory; private org.apache.http.conn.ssl.SSLSocketFactory mSchemeSocketFactory; - protected static final String ENABLED_CIPHERS[] = { - "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", - "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", - "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", - "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", - "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", - "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", - "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", - "TLS_ECDHE_RSA_WITH_RC4_128_SHA", - "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", - "TLS_RSA_WITH_AES_128_CBC_SHA", - "TLS_RSA_WITH_AES_256_CBC_SHA", - "SSL_RSA_WITH_3DES_EDE_CBC_SHA", - "SSL_RSA_WITH_RC4_128_SHA", - "SSL_RSA_WITH_RC4_128_MD5", - }; + protected static final String ENABLED_CIPHERS[]; + + static { + List enabledCiphers = new ArrayList(); + try { + String preferredCiphers[] = { + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", + "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", + "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", + "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_RSA_WITH_RC4_128_SHA", + "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", + "TLS_RSA_WITH_AES_128_CBC_SHA", + "TLS_RSA_WITH_AES_256_CBC_SHA", + "SSL_RSA_WITH_3DES_EDE_CBC_SHA", + "SSL_RSA_WITH_RC4_128_SHA", + "SSL_RSA_WITH_RC4_128_MD5", + }; + + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, null, new SecureRandom()); + SSLSocketFactory sf = sslContext.getSocketFactory(); + Set supportedCiphers = new HashSet(); + Collections.addAll(supportedCiphers, sf.getSupportedCipherSuites()); + + for (String preferredCipher : preferredCiphers) { + if (supportedCiphers.contains(preferredCipher)) { + enabledCiphers.add(preferredCipher); + } + } + } catch (KeyManagementException kme) { + kme.printStackTrace(); + } catch (NoSuchAlgorithmException nsae) { + nsae.printStackTrace(); + } + ENABLED_CIPHERS = enabledCiphers.isEmpty() ? null : + enabledCiphers.toArray(new String[enabledCiphers.size()]); + } protected static final String ENABLED_PROTOCOLS[] = { "TLSv1.2", "TLSv1.1", "TLSv1" @@ -68,7 +94,9 @@ public class TrustedSocketFactory implements LayeredSocketFactory { } public static void hardenSocket(SSLSocket sock) { - sock.setEnabledCipherSuites(ENABLED_CIPHERS); + if (ENABLED_CIPHERS != null) { + sock.setEnabledCipherSuites(ENABLED_CIPHERS); + } sock.setEnabledProtocols(ENABLED_PROTOCOLS); } From 77d43fb7bdb79c86fd7e6e41abc953c5b3a8c961 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20Veres-Szentkir=C3=A1lyi?= Date: Sun, 20 Oct 2013 10:30:33 +0200 Subject: [PATCH 3/6] extracted method filterBySupport --- .../mail/transport/TrustedSocketFactory.java | 62 ++++++++++--------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/src/com/fsck/k9/mail/transport/TrustedSocketFactory.java b/src/com/fsck/k9/mail/transport/TrustedSocketFactory.java index 9a4d3d585..f9ad359f9 100644 --- a/src/com/fsck/k9/mail/transport/TrustedSocketFactory.java +++ b/src/com/fsck/k9/mail/transport/TrustedSocketFactory.java @@ -25,43 +25,49 @@ public class TrustedSocketFactory implements LayeredSocketFactory { protected static final String ENABLED_CIPHERS[]; static { - List enabledCiphers = new ArrayList(); - try { - String preferredCiphers[] = { - "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", - "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", - "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", - "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", - "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", - "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", - "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", - "TLS_ECDHE_RSA_WITH_RC4_128_SHA", - "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", - "TLS_RSA_WITH_AES_128_CBC_SHA", - "TLS_RSA_WITH_AES_256_CBC_SHA", - "SSL_RSA_WITH_3DES_EDE_CBC_SHA", - "SSL_RSA_WITH_RC4_128_SHA", - "SSL_RSA_WITH_RC4_128_MD5", - }; + String preferredCiphers[] = { + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", + "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", + "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", + "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_RSA_WITH_RC4_128_SHA", + "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", + "TLS_RSA_WITH_AES_128_CBC_SHA", + "TLS_RSA_WITH_AES_256_CBC_SHA", + "SSL_RSA_WITH_3DES_EDE_CBC_SHA", + "SSL_RSA_WITH_RC4_128_SHA", + "SSL_RSA_WITH_RC4_128_MD5", + }; + String[] supportedCiphers = null; + + try { SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, null, new SecureRandom()); SSLSocketFactory sf = sslContext.getSocketFactory(); - Set supportedCiphers = new HashSet(); - Collections.addAll(supportedCiphers, sf.getSupportedCipherSuites()); - - for (String preferredCipher : preferredCiphers) { - if (supportedCiphers.contains(preferredCipher)) { - enabledCiphers.add(preferredCipher); - } - } + supportedCiphers = sf.getSupportedCipherSuites(); } catch (KeyManagementException kme) { kme.printStackTrace(); } catch (NoSuchAlgorithmException nsae) { nsae.printStackTrace(); } - ENABLED_CIPHERS = enabledCiphers.isEmpty() ? null : - enabledCiphers.toArray(new String[enabledCiphers.size()]); + + ENABLED_CIPHERS = supportedCiphers == null ? null : + filterBySupport(preferredCiphers, supportedCiphers); + } + + protected static String[] filterBySupport(String[] preferred, String[] supported) { + List enabled = new ArrayList(); + Set available = new HashSet(); + Collections.addAll(available, supported); + + for (String item : preferred) { + if (available.contains(item)) enabled.add(item); + } + return enabled.toArray(new String[enabled.size()]); } protected static final String ENABLED_PROTOCOLS[] = { From 105d3b3c4e26f326117d22d876eb088089fb6fe1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20Veres-Szentkir=C3=A1lyi?= Date: Sun, 20 Oct 2013 10:40:16 +0200 Subject: [PATCH 4/6] filter TLS protocol versions by support as well --- .../mail/transport/TrustedSocketFactory.java | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/com/fsck/k9/mail/transport/TrustedSocketFactory.java b/src/com/fsck/k9/mail/transport/TrustedSocketFactory.java index f9ad359f9..aa73edf8d 100644 --- a/src/com/fsck/k9/mail/transport/TrustedSocketFactory.java +++ b/src/com/fsck/k9/mail/transport/TrustedSocketFactory.java @@ -23,6 +23,7 @@ public class TrustedSocketFactory implements LayeredSocketFactory { private org.apache.http.conn.ssl.SSLSocketFactory mSchemeSocketFactory; protected static final String ENABLED_CIPHERS[]; + protected static final String ENABLED_PROTOCOLS[]; static { String preferredCiphers[] = { @@ -41,14 +42,22 @@ public class TrustedSocketFactory implements LayeredSocketFactory { "SSL_RSA_WITH_RC4_128_SHA", "SSL_RSA_WITH_RC4_128_MD5", }; + String preferredProtocols[] = { + "TLSv1.2", "TLSv1.1", "TLSv1" + }; String[] supportedCiphers = null; + String[] supportedProtocols = null; try { SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, null, new SecureRandom()); SSLSocketFactory sf = sslContext.getSocketFactory(); supportedCiphers = sf.getSupportedCipherSuites(); + SSLSocket sock = (SSLSocket)sf.createSocket(); + supportedProtocols = sock.getSupportedProtocols(); + } catch (IOException ioe) { + ioe.printStackTrace(); } catch (KeyManagementException kme) { kme.printStackTrace(); } catch (NoSuchAlgorithmException nsae) { @@ -57,6 +66,8 @@ public class TrustedSocketFactory implements LayeredSocketFactory { ENABLED_CIPHERS = supportedCiphers == null ? null : filterBySupport(preferredCiphers, supportedCiphers); + ENABLED_PROTOCOLS = supportedProtocols == null ? null : + filterBySupport(preferredProtocols, supportedProtocols); } protected static String[] filterBySupport(String[] preferred, String[] supported) { @@ -70,10 +81,6 @@ public class TrustedSocketFactory implements LayeredSocketFactory { return enabled.toArray(new String[enabled.size()]); } - protected static final String ENABLED_PROTOCOLS[] = { - "TLSv1.2", "TLSv1.1", "TLSv1" - }; - public TrustedSocketFactory(String host, boolean secure) throws NoSuchAlgorithmException, KeyManagementException { SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, new TrustManager[] { @@ -103,7 +110,9 @@ public class TrustedSocketFactory implements LayeredSocketFactory { if (ENABLED_CIPHERS != null) { sock.setEnabledCipherSuites(ENABLED_CIPHERS); } - sock.setEnabledProtocols(ENABLED_PROTOCOLS); + if (ENABLED_PROTOCOLS != null) { + sock.setEnabledProtocols(ENABLED_PROTOCOLS); + } } public Socket createSocket( From 8f45d76b5cecba3f76478c49094346c4ce913a8e Mon Sep 17 00:00:00 2001 From: cketti Date: Tue, 29 Oct 2013 03:42:37 +0100 Subject: [PATCH 5/6] Extract WebDavSocketFactory --- .../k9/mail/store/WebDavSocketFactory.java | 69 +++++++++++++++++++ src/com/fsck/k9/mail/store/WebDavStore.java | 3 +- 2 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 src/com/fsck/k9/mail/store/WebDavSocketFactory.java diff --git a/src/com/fsck/k9/mail/store/WebDavSocketFactory.java b/src/com/fsck/k9/mail/store/WebDavSocketFactory.java new file mode 100644 index 000000000..2d4f959ed --- /dev/null +++ b/src/com/fsck/k9/mail/store/WebDavSocketFactory.java @@ -0,0 +1,69 @@ +package com.fsck.k9.mail.store; + +import org.apache.http.conn.ConnectTimeoutException; +import org.apache.http.conn.scheme.LayeredSocketFactory; +import org.apache.http.params.HttpParams; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; + + +/* + * TODO: find out what's going on here and document it. + * Using two socket factories looks suspicious. + */ +public class WebDavSocketFactory implements LayeredSocketFactory { + private SSLSocketFactory mSocketFactory; + private org.apache.http.conn.ssl.SSLSocketFactory mSchemeSocketFactory; + + public WebDavSocketFactory(String host, boolean secure) throws NoSuchAlgorithmException, KeyManagementException { + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, new TrustManager[] { + TrustManagerFactory.get(host, secure) + }, new SecureRandom()); + mSocketFactory = sslContext.getSocketFactory(); + mSchemeSocketFactory = org.apache.http.conn.ssl.SSLSocketFactory.getSocketFactory(); + mSchemeSocketFactory.setHostnameVerifier( + org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); + } + + public Socket connectSocket(Socket sock, String host, int port, + InetAddress localAddress, int localPort, HttpParams params) + throws IOException, UnknownHostException, ConnectTimeoutException { + return mSchemeSocketFactory.connectSocket(sock, host, port, localAddress, localPort, params); + } + + public Socket createSocket() throws IOException { + return mSocketFactory.createSocket(); + } + + public boolean isSecure(Socket sock) throws IllegalArgumentException { + return mSchemeSocketFactory.isSecure(sock); + } + public Socket createSocket( + final Socket socket, + final String host, + final int port, + final boolean autoClose + ) throws IOException, UnknownHostException { + SSLSocket sslSocket = (SSLSocket) mSocketFactory.createSocket( + socket, + host, + port, + autoClose + ); + //hostnameVerifier.verify(host, sslSocket); + // verifyHostName() didn't blowup - good! + return sslSocket; + } +} diff --git a/src/com/fsck/k9/mail/store/WebDavStore.java b/src/com/fsck/k9/mail/store/WebDavStore.java index 6d4b69d3f..b3f8d5f24 100644 --- a/src/com/fsck/k9/mail/store/WebDavStore.java +++ b/src/com/fsck/k9/mail/store/WebDavStore.java @@ -10,7 +10,6 @@ import com.fsck.k9.mail.*; import com.fsck.k9.mail.filter.EOLConvertingOutputStream; import com.fsck.k9.mail.internet.MimeMessage; -import com.fsck.k9.mail.transport.TrustedSocketFactory; import org.apache.commons.io.IOUtils; import org.apache.http.*; import org.apache.http.client.CookieStore; @@ -1080,7 +1079,7 @@ public class WebDavStore extends Store { SchemeRegistry reg = mHttpClient.getConnectionManager().getSchemeRegistry(); try { - Scheme s = new Scheme("https", new TrustedSocketFactory(mHost, mSecure), 443); + Scheme s = new Scheme("https", new WebDavSocketFactory(mHost, mSecure), 443); reg.register(s); } catch (NoSuchAlgorithmException nsa) { Log.e(K9.LOG_TAG, "NoSuchAlgorithmException in getHttpClient: " + nsa); From a97705ffa96de522c19614bb8628626923c15683 Mon Sep 17 00:00:00 2001 From: cketti Date: Tue, 29 Oct 2013 04:01:12 +0100 Subject: [PATCH 6/6] Refactor TrustedSocketFactory --- src/com/fsck/k9/mail/store/ImapStore.java | 5 +- src/com/fsck/k9/mail/store/Pop3Store.java | 5 +- .../TrustedSocketFactory.java | 71 +++++-------------- .../fsck/k9/mail/transport/SmtpTransport.java | 5 +- 4 files changed, 20 insertions(+), 66 deletions(-) rename src/com/fsck/k9/mail/{transport => store}/TrustedSocketFactory.java (53%) diff --git a/src/com/fsck/k9/mail/store/ImapStore.java b/src/com/fsck/k9/mail/store/ImapStore.java index 8334db923..f4eac81ae 100644 --- a/src/com/fsck/k9/mail/store/ImapStore.java +++ b/src/com/fsck/k9/mail/store/ImapStore.java @@ -50,7 +50,6 @@ import java.util.zip.InflaterInputStream; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLException; -import javax.net.ssl.SSLSocket; import javax.net.ssl.TrustManager; import org.apache.commons.io.IOUtils; @@ -97,7 +96,6 @@ import com.fsck.k9.mail.store.ImapResponseParser.ImapList; import com.fsck.k9.mail.store.ImapResponseParser.ImapResponse; import com.fsck.k9.mail.store.imap.ImapUtility; import com.fsck.k9.mail.transport.imap.ImapSettings; -import com.fsck.k9.mail.transport.TrustedSocketFactory; import com.jcraft.jzlib.JZlib; import com.jcraft.jzlib.ZOutputStream; @@ -2451,8 +2449,7 @@ public class ImapStore extends Store { sslContext.init(null, new TrustManager[] { TrustManagerFactory.get(mSettings.getHost(), secure) }, new SecureRandom()); - mSocket = sslContext.getSocketFactory().createSocket(); - TrustedSocketFactory.hardenSocket((SSLSocket)mSocket); + mSocket = TrustedSocketFactory.createSocket(sslContext); } else { mSocket = new Socket(); } diff --git a/src/com/fsck/k9/mail/store/Pop3Store.java b/src/com/fsck/k9/mail/store/Pop3Store.java index ff7e1a3ba..1621c1527 100644 --- a/src/com/fsck/k9/mail/store/Pop3Store.java +++ b/src/com/fsck/k9/mail/store/Pop3Store.java @@ -7,14 +7,12 @@ import com.fsck.k9.Account; import com.fsck.k9.K9; import com.fsck.k9.controller.MessageRetrievalListener; import com.fsck.k9.helper.Utility; -import com.fsck.k9.mail.transport.TrustedSocketFactory; import com.fsck.k9.mail.*; import com.fsck.k9.mail.internet.MimeMessage; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLException; -import javax.net.ssl.SSLSocket; import javax.net.ssl.TrustManager; import java.io.*; import java.net.*; @@ -332,8 +330,7 @@ public class Pop3Store extends Store { sslContext.init(null, new TrustManager[] { TrustManagerFactory.get(mHost, secure) }, new SecureRandom()); - mSocket = sslContext.getSocketFactory().createSocket(); - TrustedSocketFactory.hardenSocket((SSLSocket)mSocket); + mSocket = TrustedSocketFactory.createSocket(sslContext); } else { mSocket = new Socket(); } diff --git a/src/com/fsck/k9/mail/transport/TrustedSocketFactory.java b/src/com/fsck/k9/mail/store/TrustedSocketFactory.java similarity index 53% rename from src/com/fsck/k9/mail/transport/TrustedSocketFactory.java rename to src/com/fsck/k9/mail/store/TrustedSocketFactory.java index aa73edf8d..5268c01ee 100644 --- a/src/com/fsck/k9/mail/transport/TrustedSocketFactory.java +++ b/src/com/fsck/k9/mail/store/TrustedSocketFactory.java @@ -1,28 +1,25 @@ -package com.fsck.k9.mail.transport; - -import com.fsck.k9.mail.store.TrustManagerFactory; -import org.apache.http.conn.ConnectTimeoutException; -import org.apache.http.conn.scheme.LayeredSocketFactory; -import org.apache.http.params.HttpParams; +package com.fsck.k9.mail.store; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManager; import java.io.IOException; -import java.net.InetAddress; import java.net.Socket; -import java.net.UnknownHostException; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.*; -public class TrustedSocketFactory implements LayeredSocketFactory { - private SSLSocketFactory mSocketFactory; - private org.apache.http.conn.ssl.SSLSocketFactory mSchemeSocketFactory; - protected static final String ENABLED_CIPHERS[]; +/** + * Filter and reorder list of cipher suites and TLS versions. + * + *

+ * See: http://op-co.de/blog/posts/android_ssl_downgrade/ + *

+ */ +public class TrustedSocketFactory { + protected static final String ENABLED_CIPHERS[]; protected static final String ENABLED_PROTOCOLS[]; static { @@ -81,32 +78,14 @@ public class TrustedSocketFactory implements LayeredSocketFactory { return enabled.toArray(new String[enabled.size()]); } - public TrustedSocketFactory(String host, boolean secure) throws NoSuchAlgorithmException, KeyManagementException { - SSLContext sslContext = SSLContext.getInstance("TLS"); - sslContext.init(null, new TrustManager[] { - TrustManagerFactory.get(host, secure) - }, new SecureRandom()); - mSocketFactory = sslContext.getSocketFactory(); - mSchemeSocketFactory = org.apache.http.conn.ssl.SSLSocketFactory.getSocketFactory(); - mSchemeSocketFactory.setHostnameVerifier( - org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); + public static Socket createSocket(SSLContext sslContext) throws IOException { + SSLSocket socket = (SSLSocket) sslContext.getSocketFactory().createSocket(); + hardenSocket(socket); + + return socket; } - public Socket connectSocket(Socket sock, String host, int port, - InetAddress localAddress, int localPort, HttpParams params) - throws IOException, UnknownHostException, ConnectTimeoutException { - return mSchemeSocketFactory.connectSocket(sock, host, port, localAddress, localPort, params); - } - - public Socket createSocket() throws IOException { - return mSocketFactory.createSocket(); - } - - public boolean isSecure(Socket sock) throws IllegalArgumentException { - return mSchemeSocketFactory.isSecure(sock); - } - - public static void hardenSocket(SSLSocket sock) { + private static void hardenSocket(SSLSocket sock) { if (ENABLED_CIPHERS != null) { sock.setEnabledCipherSuites(ENABLED_CIPHERS); } @@ -114,22 +93,4 @@ public class TrustedSocketFactory implements LayeredSocketFactory { sock.setEnabledProtocols(ENABLED_PROTOCOLS); } } - - public Socket createSocket( - final Socket socket, - final String host, - final int port, - final boolean autoClose - ) throws IOException, UnknownHostException { - SSLSocket sslSocket = (SSLSocket) mSocketFactory.createSocket( - socket, - host, - port, - autoClose - ); - //hostnameVerifier.verify(host, sslSocket); - // verifyHostName() didn't blowup - good! - hardenSocket(sslSocket); - return sslSocket; - } } diff --git a/src/com/fsck/k9/mail/transport/SmtpTransport.java b/src/com/fsck/k9/mail/transport/SmtpTransport.java index 1b4c57d25..4e71d3ee8 100644 --- a/src/com/fsck/k9/mail/transport/SmtpTransport.java +++ b/src/com/fsck/k9/mail/transport/SmtpTransport.java @@ -14,10 +14,10 @@ import com.fsck.k9.mail.filter.SmtpDataStuffing; import com.fsck.k9.mail.internet.MimeUtility; import com.fsck.k9.mail.store.TrustManagerFactory; import com.fsck.k9.mail.store.LocalStore.LocalMessage; +import com.fsck.k9.mail.store.TrustedSocketFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLException; -import javax.net.ssl.SSLSocket; import javax.net.ssl.TrustManager; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; @@ -245,8 +245,7 @@ public class SmtpTransport extends Transport { sslContext.init(null, new TrustManager[] { TrustManagerFactory.get(mHost, secure) }, new SecureRandom()); - mSocket = sslContext.getSocketFactory().createSocket(); - TrustedSocketFactory.hardenSocket((SSLSocket)mSocket); + mSocket = TrustedSocketFactory.createSocket(sslContext); mSocket.connect(socketAddress, SOCKET_CONNECT_TIMEOUT); } else { mSocket = new Socket();