How to enable TLS 1.1+ in Android 4.1-4.4

english dev tls

What is TLS?

In short it’s a protocol that provides a secure connection between host and client. You can read more about that in Wiki.

In what cases it may be useful?

You can meet it in case of work with secure connection. The most primitive example is reading content into a string from website which works with TLS. It may be required when you are working with API.

How can I learn what type of connection uses site?

The most simple way is to go to the site using your home browser. If you will see a lock in the URL bar then site uses secure connection. Click at this lock and read about it. At the screenshot site vk.com uses TLS ver. 1.2.

TLS and Android versions

According to the Documentation TLS 1.1+ works initially only with Android 5.0 and higher (API 20+).

TLS and Android 2.3-4.4

Let’s write a very simple code for reading website into a string and run it on the device with a young Android on the board.

   public String readFromURL(String url) throws IOException {
        StringBuilder scanned = new StringBuilder();
        java.net.URL pageURL = new URL(url);
        HttpsURLConnection uc = (HttpsURLConnection) pageURL.openConnection();
        BufferedReader br = new BufferedReader(new InputStreamReader(uc.getInputStream(), "UTF-8"));

        String inputLine;
        while ((inputLine = br.readLine()) != null) {
            scanned.append(inputLine);
        }

        br.close();
        return scanned.toString();
    }

We’ve got an Exception SSLException: connection closed by peer.

Problem solution

The problem solution is very simple but it works only with Android version 4.1 and higher (API 16+). It’s because Android 4.1 and lower doesn’t know about existence of TLS 1.1+.

We will just create a new SSLSocketFactory where will connect needed protocols to the socket which are not enabled in Android 4.1-4.4 by default.

Create a class TLSSocketFactory with content:

import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

public class TLSSocketFactory extends SSLSocketFactory {

    private SSLSocketFactory mSSLSocketFactory;

    public TLSSocketFactory() throws KeyManagementException, NoSuchAlgorithmException {
        SSLContext context = SSLContext.getInstance("TLS");
        context.init(null, null, null);
        mSSLSocketFactory = context.getSocketFactory();
    }

    @Override
    public String[] getDefaultCipherSuites() {
        return mSSLSocketFactory.getDefaultCipherSuites();
    }

    @Override
    public String[] getSupportedCipherSuites() {
        return mSSLSocketFactory.getSupportedCipherSuites();
    }

    @Override
    public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
        return enableTLS(mSSLSocketFactory.createSocket(s, host, port, autoClose));
    }

    @Override
    public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
        return enableTLS(mSSLSocketFactory.createSocket(host, port));
    }

    @Override
    public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
        return enableTLS(mSSLSocketFactory.createSocket(host, port, localHost, localPort));
    }

    @Override
    public Socket createSocket(InetAddress host, int port) throws IOException {
        return enableTLS(mSSLSocketFactory.createSocket(host, port));
    }

    @Override
    public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
        return enableTLS(mSSLSocketFactory.createSocket(address, port, localAddress, localPort));
    }

    private Socket enableTLS(Socket socket) {
        if(socket != null && (socket instanceof SSLSocket)) {
            String[] protocols = new String[] {
                    "TLSv1.1",
                    "TLSv1.2"
            };
            ((SSLSocket) socket).setEnabledProtocols(protocols);
        }
        return socket;
    }
}

In enableTLS() method you should write specific protocols which you want to use with this connection.

Now let’s change readFromURL() method and plug in the new factory to our connection (HttpsURLConnection): uc.setSSLSocketFactory(new TLSSocketFactory());

Note: in this case connection will use ONLY protocols you’ve wrote. Don’t forget to point out it if you are going to use this connection with other protocols.

Here we go! Fully working code:

public String readFromURL(String url) throws IOException, NoSuchAlgorithmException, KeyManagementException {
    StringBuilder scanned = new StringBuilder();
    java.net.URL pageURL = new URL(url);
    HttpsURLConnection uc = (HttpsURLConnection) pageURL.openConnection();
    uc.setSSLSocketFactory(new TLSSocketFactory());
    BufferedReader br = new BufferedReader(new InputStreamReader(uc.getInputStream(), "UTF-8"));

    String inputLine;
    while ((inputLine = br.readLine()) != null) {
        scanned.append(inputLine);
    }

    br.close();
    return scanned.toString();
}

Previous Post