Okhttp: SSLHandshakeException on Android 5 (API 21)

Created on 5 Jan 2020  路  11Comments  路  Source: square/okhttp

I pushed a new version of my app to production and started to get bunch of complains from users.
Turns out with okhttp 4.3.0 there is SSLHandshakeException happening only on Android 5 for some reason. I'm getting this exception for all my requests including requests from 3th party SDKs. It's reproducible on API 21 Emulator.

javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
        at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:306)
        at com.android.okhttp.Connection.upgradeToTls(Connection.java:197)
        at com.android.okhttp.Connection.connect(Connection.java:151)
        at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:276)
        at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:211)
        at com.android.okhttp.internal.http.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:373)
        at com.android.okhttp.internal.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:323)
        at com.android.okhttp.internal.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:491)
        at com.android.okhttp.internal.http.DelegatingHttpsURLConnection.getResponseCode(DelegatingHttpsURLConnection.java:105)
        at com.android.okhttp.internal.http.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:25)
...
     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:318)
        at com.android.org.conscrypt.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:219)
        at com.android.org.conscrypt.Platform.checkServerTrusted(Platform.java:113)
        at com.android.org.conscrypt.OpenSSLSocketImpl.verifyCertificateChain(OpenSSLSocketImpl.java:525)
        at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
        at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:302)
        at com.android.okhttp.Connection.upgradeToTls(Connection.java:197)聽
        at com.android.okhttp.Connection.connect(Connection.java:151)聽
        at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:276)聽
        at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:211)聽
        at com.android.okhttp.internal.http.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:373)聽
        at com.android.okhttp.internal.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:323)聽
        at com.android.okhttp.internal.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:491)聽
        at com.android.okhttp.internal.http.DelegatingHttpsURLConnection.getResponseCode(DelegatingHttpsURLConnection.java:105)聽
        at com.android.okhttp.internal.http.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:25)聽
...
     Caused by: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
        at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:318)聽
        at com.android.org.conscrypt.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:219)聽
        at com.android.org.conscrypt.Platform.checkServerTrusted(Platform.java:113)聽
        at com.android.org.conscrypt.OpenSSLSocketImpl.verifyCertificateChain(OpenSSLSocketImpl.java:525)聽
        at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)聽
        at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:302)聽
        at com.android.okhttp.Connection.upgradeToTls(Connection.java:197)聽
        at com.android.okhttp.Connection.connect(Connection.java:151)聽
        at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:276)聽
        at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:211)聽
        at com.android.okhttp.internal.http.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:373)聽
        at com.android.okhttp.internal.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:323)聽
        at com.android.okhttp.internal.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:491)聽
        at com.android.okhttp.internal.http.DelegatingHttpsURLConnection.getResponseCode(DelegatingHttpsURLConnection.java:105)聽
        at com.android.okhttp.internal.http.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:25)聽
...
android bug

Most helpful comment

@swankjesse heads up another fix for 4.3.1

We lost this code in 4.3, which breaks some hosts on Android 5

      // This is SSLParameters.setServerNames() in API 24+.
      setHostname.invoke(sslSocket, hostname)

All 11 comments

Is there a URL to test against? What version did you upgrade from 4.2?

If you can make a failing test case with our Android test it would make this quicker to debug

https://github.com/square/okhttp/tree/master/android-test

Hi, I was using 4.2.2 before.
It happens with almost every HTTPS request I believe on API 21, maybe with some exception as github pages worked fine.

Will try to make a test now.

I just noticed that I get different types of exceptions for different websites. Eg I get SSLHandshakeException for my backend and from fabric SDK and I simply get ConnectException for some other websites.
Sorry I have to go out now, will make tests in a few hours if it's still needed, but it's easy to repro.
Eg try with this url: https://news.am/arm/news/552948.html
It works fine on 4.2.2, but I get java.net.ConnectException: Failed to connect to news.am/2606:4700:20::681a:85c:443 on 4.3

@minas90 That's enough. Thanks!

And to repro SSLHandshakeException use this url: https://docs.fabric.io/android/changelog.html

Two failing reproductions



  @Test
  fun testRequestFailing1() {
    assumeNetwork()

    client = client.newBuilder().connectionSpecs(listOf(ConnectionSpec.COMPATIBLE_TLS)).build()

    val request = Request.Builder().url("https://news.am/arm/news/552948.html").build()

    val response = client.newCall(request).execute()

    response.use {
      assertEquals(200, response.code)
    }
  }

  @Test
  fun testRequestFailing2() {
    assumeNetwork()

    client = client.newBuilder().connectionSpecs(listOf(ConnectionSpec.COMPATIBLE_TLS)).build()

    val request = Request.Builder().url("https://docs.fabric.io/android/changelog.html").build()

    val response = client.newCall(request).execute()

    response.use {
      assertEquals(200, response.code)
    }
  }

Reviewing git diff parent-4.2.2..parent-4.3.0

It's mostly relevant functional changes in http/2 settings, pings, and AndroidSocketAdapter. Starting with the latter.

@swankjesse heads up another fix for 4.3.1

We lost this code in 4.3, which breaks some hosts on Android 5

      // This is SSLParameters.setServerNames() in API 24+.
      setHostname.invoke(sslSocket, hostname)
Was this page helpful?
0 / 5 - 0 ratings