androidandroid-4.4-kitkattls1.2pci-compliancepci-dss

Android 4.1 to 4.4 KitKat - Enable TLS 1.2 for API


In trying to disable TLS 1.0, there are KitKat devices needing access to my API. I have tried overriding the default socket factory without success. I have tried converting to okhttp. Still not working. How do I get Android KitKat to connect to my API?


Solution

  • I had the same issue on pre-lollipop devices. As I'm using Retrofit, here is the solution for OkHttp.

    Tls12SocketFactory.java:

    public class Tls12SocketFactory extends SSLSocketFactory {
        private static final String[] TLS_V12_ONLY = {"TLSv1.2"};
    
        final SSLSocketFactory delegate;
    
        public Tls12SocketFactory(SSLSocketFactory base) {
            this.delegate = base;
        }
    
        @Override
        public String[] getDefaultCipherSuites() {
            return delegate.getDefaultCipherSuites();
        }
    
        @Override
        public String[] getSupportedCipherSuites() {
            return delegate.getSupportedCipherSuites();
        }
    
        @Override
        public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
            return patch(delegate.createSocket(s, host, port, autoClose));
        }
    
        @Override
        public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
            return patch(delegate.createSocket(host, port));
        }
    
        @Override
        public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
            return patch(delegate.createSocket(host, port, localHost, localPort));
        }
    
        @Override
        public Socket createSocket(InetAddress host, int port) throws IOException {
            return patch(delegate.createSocket(host, port));
        }
    
        @Override
        public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
            return patch(delegate.createSocket(address, port, localAddress, localPort));
        }
    
        private Socket patch(Socket s) {
            if (s instanceof SSLSocket) {
                ((SSLSocket) s).setEnabledProtocols(TLS_V12_ONLY);
            }
            return s;
        }
    }
    

    OkHttpUtils.java:

    public class OkHttpUtills {
    
        public static OkHttpClient createHttpClient() {
            HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
            logging.setLevel(HttpLoggingInterceptor.Level.BODY);
    
            OkHttpClient.Builder client = new OkHttpClient.Builder()
                    .followRedirects(true)
                    .followSslRedirects(true)
                    .addInterceptor(logging)
                    .cache(null)
                    .connectTimeout(15, TimeUnit.SECONDS)
                    .writeTimeout(15, TimeUnit.SECONDS)
                    .readTimeout(15, TimeUnit.SECONDS);
            return enableTls12OnPreLollipop(client).build();
        }
    
    
        /**
         * Enables TLSv1.2 protocol (which is disabled by default)
         * on pre-Lollipop devices, as well as on Lollipop, because some issues can take place on Samsung devices.
         *
         * @param client OKHtp client builder
         * @return
         */
        private static OkHttpClient.Builder enableTls12OnPreLollipop(OkHttpClient.Builder client) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP_MR1) {
                try {
                    SSLContext sc = SSLContext.getInstance("TLSv1.2");
                    sc.init(null, null, null);
                    client.sslSocketFactory(new Tls12SocketFactory(sc.getSocketFactory()));
    
                    ConnectionSpec cs = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
                            .tlsVersions(TlsVersion.TLS_1_2)
                            .build();
    
                    List<ConnectionSpec> specs = new ArrayList<>();
                    specs.add(cs);
                    specs.add(ConnectionSpec.COMPATIBLE_TLS);
                    specs.add(ConnectionSpec.CLEARTEXT);
    
                    client.connectionSpecs(specs);
                } catch (Exception exc) {
                    Log.e("OkHttpTLSCompat", "Error while setting TLS 1.2", exc);
                }
            }
            return client;
        }
    }
    

    Hope this could help you.