Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save cdongieux/08a96321e25d81f80fd32c68e7e430b8 to your computer and use it in GitHub Desktop.
Save cdongieux/08a96321e25d81f80fd32c68e7e430b8 to your computer and use it in GitHub Desktop.
OkHttpClient for Android API 19 (maybe 21?) devices having issues with SSL certificates
private fun createOkHttpClient(): OkHttpClient {
return OkHttp.Builder().apply {
createSocketFactoryForKitKatOrLollipop()?.let { socketFactory ->
sslSocketFactory(socketFactory)
}
}
}
private fun createSocketFactoryForKitKatOrLollipop(): SSLSocketFactory? {
/**
* Typical stacktrace:
javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
at com.google.android.gms.org.conscrypt.ConscryptFileDescriptorSocket.startHandshake(:com.google.android.gms@[email protected] (000700-316502805):25)
at com.google.android.gms.org.conscrypt.KitKatPlatformOpenSSLSocketImplAdapter.startHandshake(:com.google.android.gms@[email protected] (000700-316502805):0)
at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.java:320)
at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.java:284)
at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:169)
at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:258)
at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:135)
at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:114)
at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:127)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
...
Caused by: java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:282)
at com.android.org.conscrypt.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:202)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.google.android.gms.org.conscrypt.Platform.checkTrusted(:com.google.android.gms@[email protected] (000700-316502805):2)
at com.google.android.gms.org.conscrypt.Platform.checkServerTrusted(:com.google.android.gms@[email protected] (000700-316502805):3)
at com.google.android.gms.org.conscrypt.ConscryptFileDescriptorSocket.verifyCertificateChain(:com.google.android.gms@[email protected] (000700-316502805):6)
at com.google.android.gms.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
at com.google.android.gms.org.conscrypt.NativeSsl.doHandshake(:com.google.android.gms@[email protected] (000700-316502805):6)
at com.google.android.gms.org.conscrypt.ConscryptFileDescriptorSocket.startHandshake(:com.google.android.gms@[email protected] (000700-316502805):16)
...
Caused by: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
*/
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
return null
}
// From: https://developer.android.com/training/articles/security-ssl#UnknownCa
// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
val cf: CertificateFactory = CertificateFactory.getInstance("X.509")
val caInput: InputStream = DiamondApplication.getInstance().applicationContext.resources.openRawResource(R.raw.ca)
val ca: X509Certificate = caInput.use {
cf.generateCertificate(it) as X509Certificate
}
// Create a KeyStore containing our trusted CAs
val keyStoreType = KeyStore.getDefaultType()
val keyStore = KeyStore.getInstance(keyStoreType).apply {
load(null, null)
setCertificateEntry(ca.subjectX500Principal.name, ca)
}
// Create a TrustManager that trusts the CAs inputStream our KeyStore
val tmfAlgorithm: String = TrustManagerFactory.getDefaultAlgorithm()
val tmf: TrustManagerFactory = TrustManagerFactory.getInstance(tmfAlgorithm).apply {
init(keyStore)
}
// Create an SSLContext that uses our TrustManager
val context: SSLContext = SSLContext.getInstance("TLS").apply {
init(null, tmf.trustManagers, null)
}
return context.socketFactory
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment