1
0
mirror of https://github.com/moparisthebest/k-9 synced 2025-01-30 23:00:09 -05:00

Merge branch 'tls-hardening'

This commit is contained in:
cketti 2013-10-29 04:40:06 +01:00
commit a036e4d2f9
6 changed files with 128 additions and 27 deletions

View File

@ -2449,7 +2449,7 @@ public class ImapStore extends Store {
sslContext.init(null, new TrustManager[] { sslContext.init(null, new TrustManager[] {
TrustManagerFactory.get(mSettings.getHost(), secure) TrustManagerFactory.get(mSettings.getHost(), secure)
}, new SecureRandom()); }, new SecureRandom());
mSocket = sslContext.getSocketFactory().createSocket(); mSocket = TrustedSocketFactory.createSocket(sslContext);
} else { } else {
mSocket = new Socket(); mSocket = new Socket();
} }

View File

@ -330,7 +330,7 @@ public class Pop3Store extends Store {
sslContext.init(null, new TrustManager[] { sslContext.init(null, new TrustManager[] {
TrustManagerFactory.get(mHost, secure) TrustManagerFactory.get(mHost, secure)
}, new SecureRandom()); }, new SecureRandom());
mSocket = sslContext.getSocketFactory().createSocket(); mSocket = TrustedSocketFactory.createSocket(sslContext);
} else { } else {
mSocket = new Socket(); mSocket = new Socket();
} }

View File

@ -0,0 +1,96 @@
package com.fsck.k9.mail.store;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import java.io.IOException;
import java.net.Socket;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.*;
/**
* Filter and reorder list of cipher suites and TLS versions.
*
* <p>
* See: <a href="http://op-co.de/blog/posts/android_ssl_downgrade/">http://op-co.de/blog/posts/android_ssl_downgrade/</a>
* </p>
*/
public class TrustedSocketFactory {
protected static final String ENABLED_CIPHERS[];
protected static final String ENABLED_PROTOCOLS[];
static {
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 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) {
nsae.printStackTrace();
}
ENABLED_CIPHERS = supportedCiphers == null ? null :
filterBySupport(preferredCiphers, supportedCiphers);
ENABLED_PROTOCOLS = supportedProtocols == null ? null :
filterBySupport(preferredProtocols, supportedProtocols);
}
protected static String[] filterBySupport(String[] preferred, String[] supported) {
List<String> enabled = new ArrayList<String>();
Set<String> available = new HashSet<String>();
Collections.addAll(available, supported);
for (String item : preferred) {
if (available.contains(item)) enabled.add(item);
}
return enabled.toArray(new String[enabled.size()]);
}
public static Socket createSocket(SSLContext sslContext) throws IOException {
SSLSocket socket = (SSLSocket) sslContext.getSocketFactory().createSocket();
hardenSocket(socket);
return socket;
}
private static void hardenSocket(SSLSocket sock) {
if (ENABLED_CIPHERS != null) {
sock.setEnabledCipherSuites(ENABLED_CIPHERS);
}
if (ENABLED_PROTOCOLS != null) {
sock.setEnabledProtocols(ENABLED_PROTOCOLS);
}
}
}

View File

@ -1,14 +1,9 @@
package com.fsck.k9.mail.transport; package com.fsck.k9.mail.store;
import com.fsck.k9.mail.store.TrustManagerFactory;
import org.apache.http.conn.ConnectTimeoutException; import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.scheme.LayeredSocketFactory; import org.apache.http.conn.scheme.LayeredSocketFactory;
import org.apache.http.params.HttpParams; import org.apache.http.params.HttpParams;
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.io.IOException;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.Socket; import java.net.Socket;
@ -17,24 +12,34 @@ import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom; import java.security.SecureRandom;
public class TrustedSocketFactory implements LayeredSocketFactory { 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 SSLSocketFactory mSocketFactory;
private org.apache.http.conn.ssl.SSLSocketFactory mSchemeSocketFactory; private org.apache.http.conn.ssl.SSLSocketFactory mSchemeSocketFactory;
public TrustedSocketFactory(String host, boolean secure) throws NoSuchAlgorithmException, KeyManagementException { public WebDavSocketFactory(String host, boolean secure) throws NoSuchAlgorithmException, KeyManagementException {
SSLContext sslContext = SSLContext.getInstance("TLS"); SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[] { sslContext.init(null, new TrustManager[] {
TrustManagerFactory.get(host, secure) TrustManagerFactory.get(host, secure)
}, new SecureRandom()); }, new SecureRandom());
mSocketFactory = sslContext.getSocketFactory(); mSocketFactory = sslContext.getSocketFactory();
mSchemeSocketFactory = org.apache.http.conn.ssl.SSLSocketFactory.getSocketFactory(); mSchemeSocketFactory = org.apache.http.conn.ssl.SSLSocketFactory.getSocketFactory();
mSchemeSocketFactory.setHostnameVerifier( mSchemeSocketFactory.setHostnameVerifier(
org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
} }
public Socket connectSocket(Socket sock, String host, int port, public Socket connectSocket(Socket sock, String host, int port,
InetAddress localAddress, int localPort, HttpParams params) InetAddress localAddress, int localPort, HttpParams params)
throws IOException, UnknownHostException, ConnectTimeoutException { throws IOException, UnknownHostException, ConnectTimeoutException {
return mSchemeSocketFactory.connectSocket(sock, host, port, localAddress, localPort, params); return mSchemeSocketFactory.connectSocket(sock, host, port, localAddress, localPort, params);
} }
@ -46,17 +51,17 @@ public class TrustedSocketFactory implements LayeredSocketFactory {
return mSchemeSocketFactory.isSecure(sock); return mSchemeSocketFactory.isSecure(sock);
} }
public Socket createSocket( public Socket createSocket(
final Socket socket, final Socket socket,
final String host, final String host,
final int port, final int port,
final boolean autoClose final boolean autoClose
) throws IOException, UnknownHostException { ) throws IOException, UnknownHostException {
SSLSocket sslSocket = (SSLSocket) mSocketFactory.createSocket( SSLSocket sslSocket = (SSLSocket) mSocketFactory.createSocket(
socket, socket,
host, host,
port, port,
autoClose autoClose
); );
//hostnameVerifier.verify(host, sslSocket); //hostnameVerifier.verify(host, sslSocket);
// verifyHostName() didn't blowup - good! // verifyHostName() didn't blowup - good!
return sslSocket; return sslSocket;

View File

@ -10,7 +10,6 @@ import com.fsck.k9.mail.*;
import com.fsck.k9.mail.filter.EOLConvertingOutputStream; import com.fsck.k9.mail.filter.EOLConvertingOutputStream;
import com.fsck.k9.mail.internet.MimeMessage; import com.fsck.k9.mail.internet.MimeMessage;
import com.fsck.k9.mail.transport.TrustedSocketFactory;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.http.*; import org.apache.http.*;
import org.apache.http.client.CookieStore; import org.apache.http.client.CookieStore;
@ -1080,7 +1079,7 @@ public class WebDavStore extends Store {
SchemeRegistry reg = mHttpClient.getConnectionManager().getSchemeRegistry(); SchemeRegistry reg = mHttpClient.getConnectionManager().getSchemeRegistry();
try { try {
Scheme s = new Scheme("https", new TrustedSocketFactory(mHost, mSecure), 443); Scheme s = new Scheme("https", new WebDavSocketFactory(mHost, mSecure), 443);
reg.register(s); reg.register(s);
} catch (NoSuchAlgorithmException nsa) { } catch (NoSuchAlgorithmException nsa) {
Log.e(K9.LOG_TAG, "NoSuchAlgorithmException in getHttpClient: " + nsa); Log.e(K9.LOG_TAG, "NoSuchAlgorithmException in getHttpClient: " + nsa);

View File

@ -14,6 +14,7 @@ import com.fsck.k9.mail.filter.SmtpDataStuffing;
import com.fsck.k9.mail.internet.MimeUtility; import com.fsck.k9.mail.internet.MimeUtility;
import com.fsck.k9.mail.store.TrustManagerFactory; import com.fsck.k9.mail.store.TrustManagerFactory;
import com.fsck.k9.mail.store.LocalStore.LocalMessage; import com.fsck.k9.mail.store.LocalStore.LocalMessage;
import com.fsck.k9.mail.store.TrustedSocketFactory;
import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException; import javax.net.ssl.SSLException;
@ -244,7 +245,7 @@ public class SmtpTransport extends Transport {
sslContext.init(null, new TrustManager[] { sslContext.init(null, new TrustManager[] {
TrustManagerFactory.get(mHost, secure) TrustManagerFactory.get(mHost, secure)
}, new SecureRandom()); }, new SecureRandom());
mSocket = sslContext.getSocketFactory().createSocket(); mSocket = TrustedSocketFactory.createSocket(sslContext);
mSocket.connect(socketAddress, SOCKET_CONNECT_TIMEOUT); mSocket.connect(socketAddress, SOCKET_CONNECT_TIMEOUT);
} else { } else {
mSocket = new Socket(); mSocket = new Socket();