Skip to content

Instantly share code, notes, and snippets.

@VitaliyBelyaev
Last active June 4, 2020 10:34
Show Gist options
  • Save VitaliyBelyaev/15b539a1a0cbf8dd176e4f4d3df4fb2b to your computer and use it in GitHub Desktop.
Save VitaliyBelyaev/15b539a1a0cbf8dd176e4f4d3df4fb2b to your computer and use it in GitHub Desktop.
This class is patched Okhttp client to use only TLS 1.2
import android.os.Build
import okhttp3.ConnectionSpec
import okhttp3.OkHttpClient
import okhttp3.TlsVersion
import java.io.IOException
import java.net.InetAddress
import java.net.Socket
import java.net.UnknownHostException
import java.security.KeyStore
import javax.net.ssl.SSLContext
import javax.net.ssl.SSLSocket
import javax.net.ssl.SSLSocketFactory
import javax.net.ssl.TrustManagerFactory
import javax.net.ssl.X509TrustManager
/**
* Implementation of [SSLSocketFactory] that adds [TlsVersion.TLS_1_2] as an enabled protocol for every [SSLSocket]
* created by [delegate].
*
* [See this discussion for more details.](https://github.com/square/okhttp/issues/2372#issuecomment-244807676)
*
* @see SSLSocket
* @see SSLSocketFactory
*/
class Tls12SocketFactory(private val delegate: SSLSocketFactory) : SSLSocketFactory() {
companion object {
/**
* @return [X509TrustManager] from [TrustManagerFactory]
*
* @throws [NoSuchElementException] if not found. According to the Android docs for [TrustManagerFactory], this
* should never happen because PKIX is the only supported algorithm
*/
private val trustManager by lazy {
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
.apply { init(null as KeyStore?) }
.trustManagers
.first { it is X509TrustManager } as X509TrustManager
}
@JvmStatic
@Suppress("TooGenericExceptionCaught")
fun OkHttpClient.Builder.enableTls12() = apply {
try {
val tlsSocketFactory = SSLContext.getInstance(TlsVersion.TLS_1_2.javaName)
.apply { init(null, arrayOf(trustManager), null) }
.socketFactory
.let(::Tls12SocketFactory)
sslSocketFactory(tlsSocketFactory, trustManager)
val tls12ConnectionSpec = ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.tlsVersions(TlsVersion.TLS_1_2)
.build()
connectionSpecs(
listOf(
tls12ConnectionSpec,
ConnectionSpec.COMPATIBLE_TLS,
ConnectionSpec.CLEARTEXT
)
)
} catch (e: Exception) {
CrashReporter.logException(e, "Error while setting TLS 1.2 compatibility")
}
}
}
/**
* Forcefully adds [TlsVersion.TLS_1_2] as an enabled protocol if called on an [SSLSocket]
*
* @return the (potentially modified) [Socket]
*/
private fun Socket.patchForTls12(): Socket {
if (this is SSLSocket) {
enabledProtocols = arrayOf(TlsVersion.TLS_1_2.javaName)
}
return this
}
override fun getDefaultCipherSuites(): Array<String> = delegate.defaultCipherSuites
override fun getSupportedCipherSuites(): Array<String> = delegate.supportedCipherSuites
@Throws(IOException::class)
override fun createSocket(
s: Socket,
host: String,
port: Int,
autoClose: Boolean
): Socket? = delegate
.createSocket(s, host, port, autoClose)
.patchForTls12()
@Throws(IOException::class, UnknownHostException::class)
override fun createSocket(
host: String,
port: Int
): Socket? = delegate
.createSocket(host, port)
.patchForTls12()
@Throws(IOException::class, UnknownHostException::class)
override fun createSocket(
host: String,
port: Int,
localHost: InetAddress,
localPort: Int
): Socket? = delegate
.createSocket(host, port, localHost, localPort)
.patchForTls12()
@Throws(IOException::class)
override fun createSocket(
host: InetAddress,
port: Int
): Socket? = delegate
.createSocket(host, port)
.patchForTls12()
@Throws(IOException::class)
override fun createSocket(
address: InetAddress,
port: Int,
localAddress: InetAddress,
localPort: Int
): Socket? = delegate
.createSocket(address, port, localAddress, localPort)
.patchForTls12()
}

This class is patched Okhttp client to use only TLS 1.2.

It based on this code square/okhttp#2372 (comment).

This version don't check Andoid API level and patches Okttp client to use only TLS 1.2 on all Andoid API levels, because somtimes Android tryies to connect server with no TLS 1.2 despite that TLS 1.2 is default from API level 21.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment