Remove SslHelper. Don't use SecureRandom.

SslHelper has been removed, and its functionality has been transferred
into TrustedSocketFactory.  The added layer of indirection wasn't really
simplifying anything.  It's now easier to see what happens when
createSocket() is invoked.

A new instance of SecureRandom is no longer passed to SSLContext.init().
Instead, null is passed.

The (default) provider of the TLS SSLContext used is OpenSSLProvider,
which provides an SSLSocket instance of type OpenSSLSocketImpl.  The only
use of SecureRandom is in OpenSSLSocketImpl.startHandshake(), where it is
used to seed the OpenSSL PRNG with additional random data.  But if
SecureRandom is null, then /dev/urandom is used for seeding instead.

Meanwhile, the default provider for the SecureRandom service is
OpenSSLRandom, which uses the OpenSSL PRNG as its data source.  So we were
effectively seeding the OpenSSL PRNG with itself.  That's probably okay
(we trust that the OpenSSL PRNG was properly initialized with random data
before first use), but using /dev/urandom would seem like a better source
(or at least as good a source) for the additional seed data added with
each new connection.

Note that our PRNGFixes class replaces the default SecureRandom service
with one whose data source is /dev/urandom for certain vulnerable API
levels anyway.  (It also makes sure that the OpenSSL PRNG is properly
seeded before first use for certain vulnerable API levels.)
This commit is contained in:
Joe Steele 2014-08-21 16:16:19 -04:00
parent 5f0f4e9c21
commit 6f14294164
5 changed files with 42 additions and 103 deletions

View file

@ -96,7 +96,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.net.ssl.SslHelper;
import com.fsck.k9.net.ssl.TrustedSocketFactory;
import com.jcraft.jzlib.JZlib;
import com.jcraft.jzlib.ZOutputStream;
@ -2435,7 +2435,7 @@ public class ImapStore extends Store {
mSettings.getPort());
if (connectionSecurity == ConnectionSecurity.SSL_TLS_REQUIRED) {
mSocket = SslHelper.createSslSocket(mSettings.getHost(),
mSocket = TrustedSocketFactory.createSocket(mSettings.getHost(),
mSettings.getPort(), mSettings.getClientCertificateAlias());
} else {
mSocket = new Socket();
@ -2485,8 +2485,8 @@ public class ImapStore extends Store {
// STARTTLS
executeSimpleCommand("STARTTLS");
mSocket = SslHelper.createStartTlsSocket(mSocket,
mSettings.getHost(), mSettings.getPort(), true,
mSocket = TrustedSocketFactory.createSocket(mSocket,
mSettings.getHost(), mSettings.getPort(),
mSettings.getClientCertificateAlias());
mSocket.setSoTimeout(Store.SOCKET_READ_TIMEOUT);
mIn = new PeekableInputStream(new BufferedInputStream(mSocket

View file

@ -12,7 +12,7 @@ import com.fsck.k9.mail.*;
import com.fsck.k9.mail.filter.Base64;
import com.fsck.k9.mail.filter.Hex;
import com.fsck.k9.mail.internet.MimeMessage;
import com.fsck.k9.net.ssl.SslHelper;
import com.fsck.k9.net.ssl.TrustedSocketFactory;
import javax.net.ssl.SSLException;
@ -314,7 +314,7 @@ public class Pop3Store extends Store {
try {
SocketAddress socketAddress = new InetSocketAddress(mHost, mPort);
if (mConnectionSecurity == ConnectionSecurity.SSL_TLS_REQUIRED) {
mSocket = SslHelper.createSslSocket(mHost, mPort, mClientCertificateAlias);
mSocket = TrustedSocketFactory.createSocket(mHost, mPort, mClientCertificateAlias);
} else {
mSocket = new Socket();
}
@ -336,7 +336,7 @@ public class Pop3Store extends Store {
if (mCapabilities.stls) {
executeSimpleCommand(STLS_COMMAND);
mSocket = SslHelper.createStartTlsSocket(mSocket, mHost, mPort, true,
mSocket = TrustedSocketFactory.createSocket(mSocket, mHost, mPort,
mClientCertificateAlias);
mSocket.setSoTimeout(Store.SOCKET_READ_TIMEOUT);
mIn = new BufferedInputStream(mSocket.getInputStream(), 1024);

View file

@ -15,7 +15,7 @@ import com.fsck.k9.mail.filter.PeekableInputStream;
import com.fsck.k9.mail.filter.SmtpDataStuffing;
import com.fsck.k9.mail.internet.MimeUtility;
import com.fsck.k9.mail.store.LocalStore.LocalMessage;
import com.fsck.k9.net.ssl.SslHelper;
import com.fsck.k9.net.ssl.TrustedSocketFactory;
import javax.net.ssl.SSLException;
@ -224,7 +224,7 @@ public class SmtpTransport extends Transport {
try {
SocketAddress socketAddress = new InetSocketAddress(addresses[i], mPort);
if (mConnectionSecurity == ConnectionSecurity.SSL_TLS_REQUIRED) {
mSocket = SslHelper.createSslSocket(mHost, mPort, mClientCertificateAlias);
mSocket = TrustedSocketFactory.createSocket(mHost, mPort, mClientCertificateAlias);
mSocket.connect(socketAddress, SOCKET_CONNECT_TIMEOUT);
secureConnection = true;
} else {
@ -278,7 +278,7 @@ public class SmtpTransport extends Transport {
if (extensions.containsKey("STARTTLS")) {
executeSimpleCommand("STARTTLS");
mSocket = SslHelper.createStartTlsSocket(mSocket, mHost, mPort, true,
mSocket = TrustedSocketFactory.createSocket(mSocket, mHost, mPort,
mClientCertificateAlias);
mIn = new PeekableInputStream(new BufferedInputStream(mSocket.getInputStream(),

View file

@ -1,81 +0,0 @@
package com.fsck.k9.net.ssl;
import java.io.IOException;
import java.net.Socket;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import android.util.Log;
import com.fsck.k9.K9;
import com.fsck.k9.mail.MessagingException;
/**
* Helper class to create SSL sockets with support for client certificate
* authentication
*/
public class SslHelper {
private static SSLContext createSslContext(String host, int port, String clientCertificateAlias)
throws NoSuchAlgorithmException, KeyManagementException, MessagingException {
if (K9.DEBUG)
Log.d(K9.LOG_TAG, "createSslContext: Client certificate alias: "
+ clientCertificateAlias);
KeyManager[] keyManagers;
if (clientCertificateAlias == null || clientCertificateAlias.isEmpty()) {
keyManagers = null;
} else {
keyManagers = new KeyManager[] { new KeyChainKeyManager(K9.app, clientCertificateAlias) };
}
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagers,
new TrustManager[] {
TrustManagerFactory.get(
host, port)
},
new SecureRandom());
return sslContext;
}
/**
* Create SSL socket
*
* @param host
* @param port
* @param clientCertificateAlias if not null, uses client certificate
* retrieved by this alias for authentication
*/
public static Socket createSslSocket(String host, int port, String clientCertificateAlias)
throws NoSuchAlgorithmException, KeyManagementException, IOException,
MessagingException {
SSLContext sslContext = createSslContext(host, port, clientCertificateAlias);
return TrustedSocketFactory.createSocket(sslContext);
}
/**
* Create socket for START_TLS. autoClose = true
*
* @param socket
* @param host
* @param port
* @param secure
* @param clientCertificateAlias if not null, uses client certificate
* retrieved by this alias for authentication
*/
public static Socket createStartTlsSocket(Socket socket, String host, int port, boolean secure,
String clientCertificateAlias) throws NoSuchAlgorithmException,
KeyManagementException, IOException, MessagingException {
SSLContext sslContext = createSslContext(host, port, clientCertificateAlias);
boolean autoClose = true;
return TrustedSocketFactory.createSocket(sslContext, socket, host, port, autoClose);
}
}

View file

@ -3,14 +3,21 @@ package com.fsck.k9.net.ssl;
import android.util.Log;
import com.fsck.k9.K9;
import com.fsck.k9.mail.MessagingException;
import javax.net.ssl.KeyManager;
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.Socket;
import java.security.SecureRandom;
import java.util.*;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
@ -71,7 +78,7 @@ public class TrustedSocketFactory {
try {
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, null, new SecureRandom());
sslContext.init(null, null, null);
SSLSocketFactory sf = sslContext.getSocketFactory();
SSLSocket sock = (SSLSocket) sf.createSocket();
enabledCiphers = sock.getEnabledCipherSuites();
@ -114,19 +121,32 @@ public class TrustedSocketFactory {
return result.toArray(new String[result.size()]);
}
public static Socket createSocket(SSLContext sslContext) throws IOException {
SSLSocket socket = (SSLSocket) sslContext.getSocketFactory().createSocket();
hardenSocket(socket);
public static Socket createSocket(String host, int port, String clientCertificateAlias)
throws IOException, MessagingException, KeyManagementException, NoSuchAlgorithmException {
return socket;
return createSocket(null, host, port, clientCertificateAlias);
}
public static Socket createSocket(SSLContext sslContext, Socket s, String host, int port,
boolean autoClose) throws IOException {
SSLSocket socket = (SSLSocket) sslContext.getSocketFactory().createSocket(s, host, port, autoClose);
hardenSocket(socket);
public static Socket createSocket(Socket socket, String host, int port, String clientCertificateAlias)
throws NoSuchAlgorithmException, KeyManagementException, MessagingException, IOException {
return socket;
TrustManager[] trustManagers = new TrustManager[] { TrustManagerFactory.get(host, port) };
KeyManager[] keyManagers = null;
if (clientCertificateAlias != null && !clientCertificateAlias.isEmpty()) {
keyManagers = new KeyManager[] { new KeyChainKeyManager(K9.app, clientCertificateAlias) };
}
SSLContext context = SSLContext.getInstance("TLS");
context.init(keyManagers, trustManagers, null);
SSLSocketFactory socketFactory = context.getSocketFactory();
Socket trustedSocket;
if (socket == null) {
trustedSocket = socketFactory.createSocket();
} else {
trustedSocket = socketFactory.createSocket(socket, host, port, true);
}
hardenSocket((SSLSocket) trustedSocket);
return trustedSocket;
}
private static void hardenSocket(SSLSocket sock) {