As per the docs in Android for SSLSocket
and SSLContext
, TLS v1.1 and v1.2 protocols are supported in API level 16+, but are not enabled by default.
http://developer.android.com/reference/javax/net/ssl/SSLSocket.html
http://developer.android.com/reference/javax/net/ssl/SSLContext.html
How do I enable it on a device running Android 4.1 or later (but below 5.0)?
I have tried creating a custom SSLSocketFactory which enables all the supported protocols when Socket
's are created and later use my custom implementation as:
HttpsURLConnection.setDefaultSSLSocketFactory(new MySSLSocketFactory());
public class MySSLSocketFactory extends SSLSocketFactory {
private SSLContext sc;
private SSLSocketFactory ssf;
public MySSLSocketFactory() {
try {
sc = SSLContext.getInstance("TLS");
sc.init(null, null, null);
ssf = sc.getSocketFactory();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
}
@Override
public Socket createSocket(Socket s, String host, int port, boolean autoClose)
throws IOException {
SSLSocket ss = (SSLSocket) ssf.createSocket(s, host, port, autoClose);
ss.setEnabledProtocols(ss.getSupportedProtocols());
ss.setEnabledCipherSuites(ss.getSupportedCipherSuites());
return ss;
}
@Override
public String[] getDefaultCipherSuites() {
return ssf.getDefaultCipherSuites();
}
@Override
public String[] getSupportedCipherSuites() {
return ssf.getSupportedCipherSuites();
}
@Override
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
SSLSocket ss = (SSLSocket) ssf.createSocket(host, port);
ss.setEnabledProtocols(ss.getSupportedProtocols());
ss.setEnabledCipherSuites(ss.getSupportedCipherSuites());
return ss;
}
@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
SSLSocket ss = (SSLSocket) ssf.createSocket(host, port);
ss.setEnabledProtocols(ss.getSupportedProtocols());
ss.setEnabledCipherSuites(ss.getSupportedCipherSuites());
return ss;
}
@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort)
throws IOException, UnknownHostException {
SSLSocket ss = (SSLSocket) ssf.createSocket(host, port, localHost, localPort);
ss.setEnabledProtocols(ss.getSupportedProtocols());
ss.setEnabledCipherSuites(ss.getSupportedCipherSuites());
return ss;
}
@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress,
int localPort) throws IOException {
SSLSocket ss = (SSLSocket) ssf.createSocket(address, port, localAddress, localPort);
ss.setEnabledProtocols(ss.getSupportedProtocols());
ss.setEnabledCipherSuites(ss.getSupportedCipherSuites());
return ss;
}
}
But it still gives an exception while trying to establish a connection with a server on which Only TLS 1.2 is enabled.
Here is the exception I get:
03-09 09:21:38.427: W/System.err(2496): javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0xb7fa0620: Failure in SSL library, usually a protocol error
03-09 09:21:38.427: W/System.err(2496): error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:741 0xa90e6990:0x00000000)
TLS 1. In Android 10 and higher, TLS 1.3 is enabled by default for all TLS connections.
Click on: Start -> Control Panel -> Internet Options 2. Click on the Advanced tab 3. Scroll to the bottom and check the TLS version described in steps 3 and 4: 4. If Use SSL 2.0 is enabled, you must have TLS 1.2 enabled (checked) 5.
TLS 1.2 is supported on devices running Android 4.1. x or greater (API level 16).
2 ways to enable TLSv1.1 and TLSv1.2:
schemeRegistry.register(new Scheme("https", new TlsSniSocketFactory(), port));
I solved this issue following the indication provided in the article http://blog.dev-area.net/2015/08/13/android-4-1-enable-tls-1-1-and-tls-1-2/ with little changes.
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, null, null);
SSLSocketFactory noSSLv3Factory = null;
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
noSSLv3Factory = new TLSSocketFactory(sslContext.getSocketFactory());
} else {
noSSLv3Factory = sslContext.getSocketFactory();
}
connection.setSSLSocketFactory(noSSLv3Factory);
This is the code of the custom TLSSocketFactory:
public static class TLSSocketFactory extends SSLSocketFactory {
private SSLSocketFactory internalSSLSocketFactory;
public TLSSocketFactory(SSLSocketFactory delegate) throws KeyManagementException, NoSuchAlgorithmException {
internalSSLSocketFactory = delegate;
}
@Override
public String[] getDefaultCipherSuites() {
return internalSSLSocketFactory.getDefaultCipherSuites();
}
@Override
public String[] getSupportedCipherSuites() {
return internalSSLSocketFactory.getSupportedCipherSuites();
}
@Override
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(s, host, port, autoClose));
}
@Override
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
}
@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port, localHost, localPort));
}
@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
}
@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort));
}
/*
* Utility methods
*/
private static Socket enableTLSOnSocket(Socket socket) {
if (socket != null && (socket instanceof SSLSocket)
&& isTLSServerEnabled((SSLSocket) socket)) { // skip the fix if server doesn't provide there TLS version
((SSLSocket) socket).setEnabledProtocols(new String[]{TLS_v1_1, TLS_v1_2});
}
return socket;
}
private static boolean isTLSServerEnabled(SSLSocket sslSocket) {
System.out.println("__prova__ :: " + sslSocket.getSupportedProtocols().toString());
for (String protocol : sslSocket.getSupportedProtocols()) {
if (protocol.equals(TLS_v1_1) || protocol.equals(TLS_v1_2)) {
return true;
}
}
return false;
}
}
Edit: Thank's to ademar111190 for the kotlin implementation (link)
class TLSSocketFactory constructor(
private val internalSSLSocketFactory: SSLSocketFactory
) : SSLSocketFactory() {
private val protocols = arrayOf("TLSv1.2", "TLSv1.1")
override fun getDefaultCipherSuites(): Array<String> = internalSSLSocketFactory.defaultCipherSuites
override fun getSupportedCipherSuites(): Array<String> = internalSSLSocketFactory.supportedCipherSuites
override fun createSocket(s: Socket, host: String, port: Int, autoClose: Boolean) =
enableTLSOnSocket(internalSSLSocketFactory.createSocket(s, host, port, autoClose))
override fun createSocket(host: String, port: Int) =
enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port))
override fun createSocket(host: String, port: Int, localHost: InetAddress, localPort: Int) =
enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port, localHost, localPort))
override fun createSocket(host: InetAddress, port: Int) =
enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port))
override fun createSocket(address: InetAddress, port: Int, localAddress: InetAddress, localPort: Int) =
enableTLSOnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort))
private fun enableTLSOnSocket(socket: Socket?) = socket?.apply {
if (this is SSLSocket && isTLSServerEnabled(this)) {
enabledProtocols = protocols
}
}
private fun isTLSServerEnabled(sslSocket: SSLSocket) = sslSocket.supportedProtocols.any { it in protocols }
}
Add play-services-safetynet
library in android build.gradle
:
implementation 'com.google.android.gms:play-services-safetynet:+'
and add this code to your MainApplication.java
:
@Override
public void onCreate() {
super.onCreate();
upgradeSecurityProvider();
SoLoader.init(this, /* native exopackage */ false);
}
private void upgradeSecurityProvider() {
ProviderInstaller.installIfNeededAsync(this, new ProviderInstallListener() {
@Override
public void onProviderInstalled() {
}
@Override
public void onProviderInstallFailed(int errorCode, Intent recoveryIntent) {
// GooglePlayServicesUtil.showErrorNotification(errorCode, MainApplication.this);
GoogleApiAvailability.getInstance().showErrorNotification(MainApplication.this, errorCode);
}
});
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With