I am trying to run the following code in android
URLConnection l_connection = null;
// Create connection
uzip=new UnZipData(mContext);
When I got this error, it was because the protocols (TLS versions) and/or cipher suites supported by the server were not enabled on (and possibly not even supported by) the device. For API 16-19, TLSv1.1 and TLSv1.2 are supported but not enabled by default. Once I enabled them for these versions, I still got the error because these versions don't support any of the ciphers on our instance of AWS CloudFront.
Since it's not possible to add ciphers to Android, we had to switch our CloudFront version from TLSv1.2_2018 to TLSv1.1_2016 (which still supports TLSv1.2; it just doesn't require it), which has four of the ciphers supported by the earlier Android versions, two of which are still considered strong.
At that point, the error disappeared and the calls went through (with TLSv1.2) because there was at least one protocol and at least one cipher that the device and server shared.
Refer to the tables on this page to see which protocols and ciphers are supported by and enabled on which versions of Android.
Now was Android really trying to use SSLv3 as implied by the "sslv3 alert handshake failure" part of the error message? I doubt it; I suspect this is an old cobweb in the SSL library that hasn't been cleaned out but I can't say for sure.
In order to enable TLSv1.2 (and TLSv1.1), I was able to use a much simpler SSLSocketFactory
than the ones seen elsewhere (like NoSSLv3SocketFactory
). It simply makes sure that the enabled protocols include all the supported protocols and that the enabled ciphers include all the supported ciphers (the latter wasn't necessary for me but it could be for others) - see configure()
at the bottom. If you'd rather enable only the latest protocols, you can replace socket.supportedProtocols
with something like arrayOf("TLSv1.1", "TLSv1.2")
(likewise for the ciphers):
class TLSSocketFactory : SSLSocketFactory() {
private val socketFactory: SSLSocketFactory
init {
val sslContext = SSLContext.getInstance("TLS")
sslContext.init(null, null, null)
socketFactory = sslContext.socketFactory
}
override fun getDefaultCipherSuites(): Array {
return socketFactory.defaultCipherSuites
}
override fun getSupportedCipherSuites(): Array {
return socketFactory.supportedCipherSuites
}
override fun createSocket(s: Socket, host: String, port: Int, autoClose: Boolean): Socket {
return configure(socketFactory.createSocket(s, host, port, autoClose) as SSLSocket)
}
override fun createSocket(host: String, port: Int): Socket {
return configure(socketFactory.createSocket(host, port) as SSLSocket)
}
override fun createSocket(host: InetAddress, port: Int): Socket {
return configure(socketFactory.createSocket(host, port) as SSLSocket)
}
override fun createSocket(host: String, port: Int, localHost: InetAddress, localPort: Int): Socket {
return configure(socketFactory.createSocket(host, port, localHost, localPort) as SSLSocket)
}
override fun createSocket(address: InetAddress, port: Int, localAddress: InetAddress, localPort: Int): Socket {
return configure(socketFactory.createSocket(address, port, localAddress, localPort) as SSLSocket)
}
private fun configure(socket: SSLSocket): SSLSocket {
socket.enabledProtocols = socket.supportedProtocols
socket.enabledCipherSuites = socket.supportedCipherSuites
return socket
}
}