Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0f8b4cc1 authored by cketti's avatar cketti Committed by GitHub
Browse files

Merge pull request #1778 from philipwhiuk/newCiphers

Don't reorder TLS ciphers on newer Android versions
parents 9cd75bc6 059064c9
Loading
Loading
Loading
Loading
+42 −5
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@ import java.util.List;

import android.content.Context;
import android.net.SSLCertificateSocketFactory;
import android.os.Build;
import android.text.TextUtils;
import android.util.Log;

@@ -25,7 +26,11 @@ import static com.fsck.k9.mail.K9MailLib.LOG_TAG;


/**
 * Filter and reorder list of cipher suites and TLS versions.
 * Prior to API 21 (and notably from API 10 - 2.3.4) Android weakened it's cipher list
 * by ordering them badly such that RC4-MD5 was preferred. To work around this we 
 * remove the insecure ciphers and reorder them so the latest more secure ciphers are at the top.
 *
 * On more modern versions of Android we keep the system configuration.
 */
public class DefaultTrustedSocketFactory implements TrustedSocketFactory {
    protected static final String[] ENABLED_CIPHERS;
@@ -75,6 +80,11 @@ public class DefaultTrustedSocketFactory implements TrustedSocketFactory {
            "TLS_ECDH_ECDSA_WITH_RC4_128_SHA",
            "SSL_RSA_WITH_RC4_128_SHA",
            "SSL_RSA_WITH_RC4_128_MD5",
            "TLS_ECDH_RSA_WITH_NULL_SHA",
            "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA",
            "TLS_ECDH_anon_WITH_NULL_SHA",
            "TLS_ECDH_anon_WITH_RC4_128_SHA",
            "TLS_RSA_WITH_NULL_SHA256"
    };

    protected static final String[] ORDERED_KNOWN_PROTOCOLS = {
@@ -107,17 +117,28 @@ public class DefaultTrustedSocketFactory implements TrustedSocketFactory {
                    "protocols", e);
        }

        if (hasWeakSslImplementation()) {
            ENABLED_CIPHERS = (enabledCiphers == null) ? null :
                    reorder(enabledCiphers, ORDERED_KNOWN_CIPHERS, BLACKLISTED_CIPHERS);

            ENABLED_PROTOCOLS = (supportedProtocols == null) ? null :
                    reorder(supportedProtocols, ORDERED_KNOWN_PROTOCOLS, BLACKLISTED_PROTOCOLS);
        } else {
            ENABLED_CIPHERS = (enabledCiphers == null) ? null :
                    remove(enabledCiphers, BLACKLISTED_CIPHERS);
            ENABLED_PROTOCOLS = (supportedProtocols == null) ? null :
                    remove(supportedProtocols, BLACKLISTED_PROTOCOLS);
        }

    }

    public DefaultTrustedSocketFactory(Context context) {
        this.context = context;
    }

    private static boolean hasWeakSslImplementation() {
        return android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP;
    }

    protected static String[] reorder(String[] enabled, String[] known, String[] blacklisted) {
        List<String> unknown = new ArrayList<String>();
        Collections.addAll(unknown, enabled);
@@ -144,6 +165,20 @@ public class DefaultTrustedSocketFactory implements TrustedSocketFactory {
        return result.toArray(new String[result.size()]);
    }

    protected static String[] remove(String[] enabled, String[] blacklisted) {
        List<String> items = new ArrayList<String>();
        Collections.addAll(items, enabled);

        // Remove blacklisted items
        if (blacklisted != null) {
            for (String item : blacklisted) {
                items.remove(item);
            }
        }

        return items.toArray(new String[items.size()]);
    }

    private Context context;

    public Socket createSocket(Socket socket, String host, int port, String clientCertificateAlias)
@@ -166,7 +201,9 @@ public class DefaultTrustedSocketFactory implements TrustedSocketFactory {
        }

        SSLSocket sslSocket = (SSLSocket) trustedSocket;

        hardenSocket(sslSocket);

        setSniHost(socketFactory, sslSocket, host);

        return trustedSocket;