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:
parent
5f0f4e9c21
commit
6f14294164
5 changed files with 42 additions and 103 deletions
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue