Skip to content

Commit

Permalink
Enable TLS 1.2 on pre-lollipop devices (#116)
Browse files Browse the repository at this point in the history
* enable tls 1.2 on pre-lollipop

* update doc
  • Loading branch information
sarahsnow1 committed May 31, 2017
1 parent c168ee6 commit dbe64d2
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 1 deletion.
63 changes: 63 additions & 0 deletions library/src/main/java/com/mapzen/http/Tls12OkHttpClientFactory.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.mapzen.http

import android.os.Build
import okhttp3.ConnectionSpec
import okhttp3.TlsVersion
import android.util.Log
import okhttp3.OkHttpClient
import java.security.KeyStore
import java.util.ArrayList
import java.util.Arrays
import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManagerFactory
import javax.net.ssl.X509TrustManager


/**
* Enables TLS 1.2 for [OkHttpClient.Builder].
*/
class Tls12OkHttpClientFactory {

/**
* Enables TLS 1.2 support for pre-lollipop on given [OkHttpClient.Builder].
* @param client Client to enable TLS on.
* *
* @return TLS enabled client.
*/
companion object {
fun enableTls12OnPreLollipop(client: OkHttpClient.Builder): OkHttpClient.Builder {
if (Build.VERSION.SDK_INT in 16..21) {
try {
val sc = SSLContext.getInstance("TLSv1.2")
sc.init(null, null, null)

val trustManagerFactory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm())
trustManagerFactory.init(null as KeyStore?)
val trustManagers = trustManagerFactory.getTrustManagers()
if (trustManagers.size != 1 || trustManagers[0] !is X509TrustManager) {
throw IllegalStateException(
"Unexpected default trust managers:" + Arrays.toString(trustManagers))
}
val trustManager = trustManagers[0] as X509TrustManager
client.sslSocketFactory(Tls12SocketFactory(sc.getSocketFactory()), trustManager)

val cs = ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.tlsVersions(TlsVersion.TLS_1_2)
.build()

val specs = ArrayList<ConnectionSpec>()
specs.add(cs)
specs.add(ConnectionSpec.COMPATIBLE_TLS)
specs.add(ConnectionSpec.CLEARTEXT)

client.connectionSpecs(specs)
} catch (exc: Exception) {
Log.e("OkHttpTLSCompat", "Error while setting TLS 1.2", exc)
}

}
return client
}
}
}
74 changes: 74 additions & 0 deletions library/src/main/java/com/mapzen/http/Tls12SocketFactory.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.mapzen.http

import java.io.IOException
import java.net.InetAddress
import java.net.Socket

import javax.net.ssl.SSLSocket
import javax.net.ssl.SSLSocketFactory

/**
* From https://github.com/square/okhttp/issues/2372.
* Enables TLS v1.2 when creating SSLSockets.
*
*
* For some reason, android supports TLS v1.2 from API 16, but enables it by
* default only from API 20.
* @link https://developer.android.com/reference/javax/net/ssl/SSLSocket.html
* *
* @see SSLSocketFactory
*/
class Tls12SocketFactory
/**
* Public constructor.
* @param base
*/
(internal val delegate: SSLSocketFactory) : SSLSocketFactory() {

override fun getDefaultCipherSuites(): Array<String> {
return delegate.defaultCipherSuites
}

override fun getSupportedCipherSuites(): Array<String> {
return delegate.supportedCipherSuites
}

@Throws(IOException::class)
override fun createSocket(s: Socket, host: String, port: Int, autoClose: Boolean): Socket {
return patch(delegate.createSocket(s, host, port, autoClose))
}

@Throws(IOException::class)
override fun createSocket(host: String, port: Int): Socket {
return patch(delegate.createSocket(host, port))
}

@Throws(IOException::class)
override fun createSocket(host: String, port: Int, localHost: InetAddress,
localPort: Int): Socket {
return patch(delegate.createSocket(host, port, localHost, localPort))
}

@Throws(IOException::class)
override fun createSocket(host: InetAddress, port: Int): Socket {
return patch(delegate.createSocket(host, port))
}

@Throws(IOException::class)
override fun createSocket(address: InetAddress, port: Int, localAddress: InetAddress,
localPort: Int): Socket {
return patch(delegate.createSocket(address, port, localAddress, localPort))
}

private fun patch(s: Socket): Socket {
if (s is SSLSocket) {
s.enabledProtocols = TLS_V12_ONLY
}
return s
}

companion object {
private val TLS_V12_ONLY = arrayOf("TLSv1.2")
}
}
6 changes: 5 additions & 1 deletion library/src/main/java/com/mapzen/valhalla/HttpHandler.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.mapzen.valhalla;

import com.mapzen.http.Tls12OkHttpClientFactory;

import java.io.IOException;

import okhttp3.Interceptor;
Expand Down Expand Up @@ -50,7 +52,9 @@ public HttpHandler(String endpoint, HttpLoggingInterceptor.Level logLevel) {
}

protected void configure(String endpoint, HttpLoggingInterceptor.Level logLevel) {
final OkHttpClient client = new OkHttpClient.Builder()
final OkHttpClient.Builder builder = Tls12OkHttpClientFactory.Companion.
enableTls12OnPreLollipop(new OkHttpClient.Builder());
final OkHttpClient client = builder
.addNetworkInterceptor(requestInterceptor)
.addNetworkInterceptor(new HttpLoggingInterceptor().setLevel(logLevel))
.build();
Expand Down

0 comments on commit dbe64d2

Please sign in to comment.