SSLHandshakeException 但仅限于 Android 12?

SSLHandshakeException but only on Android 12?

我有一个已发布多年的应用程序。它工作得很好,但现在它开始抛出 SLLHandshakeExceptions 但仅适用于 Android 12.

我找不到任何官方文档是否在 Android 12 中发生了一些变化,我必须实施才能使事情正常进行,所以我只是一无所知。

这是日志:

Caused by java.security.cert.CertificateException: Unacceptable certificate: CN=R3, O=Let's Encrypt, C=US
       at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:609)
       at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:505)
       at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:425)
       at com.android.org.conscrypt.TrustManagerImpl.getTrustedChainForServer(TrustManagerImpl.java:353)
       at android.security.net.config.NetworkSecurityTrustManager.checkServerTrusted(NetworkSecurityTrustManager.java:94)
       at android.security.net.config.RootTrustManager.checkServerTrusted(RootTrustManager.java:90)
       at com.android.org.conscrypt.ConscryptEngineSocket.checkServerTrusted(ConscryptEngineSocket.java:163)
       at com.android.org.conscrypt.Platform.checkServerTrusted(Platform.java:255)
       at com.android.org.conscrypt.ConscryptEngine.verifyCertificateChain(ConscryptEngine.java:1638)
       at com.android.org.conscrypt.NativeCrypto.ENGINE_SSL_read_direct(NativeCrypto.java)
       at com.android.org.conscrypt.NativeSsl.readDirectByteBuffer(NativeSsl.java:569)
       at com.android.org.conscrypt.ConscryptEngine.readPlaintextDataDirect(ConscryptEngine.java:1095)
       at com.android.org.conscrypt.ConscryptEngine.readPlaintextData(ConscryptEngine.java:1079)
       at com.android.org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:876)
       at com.android.org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:747)
       at com.android.org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:712)
       at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.processDataFromSocket(ConscryptEngineSocket.java:858)
       at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.access0(ConscryptEngineSocket.java:731)
       at com.android.org.conscrypt.ConscryptEngineSocket.doHandshake(ConscryptEngineSocket.java:241)
       at com.android.org.conscrypt.ConscryptEngineSocket.startHandshake(ConscryptEngineSocket.java:220)
       at com.squareup.okhttp.Connection.connectTls(Connection.java:235)
       at com.squareup.okhttp.Connection.connectSocket(Connection.java:199)
       at com.squareup.okhttp.Connection.connect(Connection.java:172)
       at com.squareup.okhttp.Connection.connectAndSetOwner(Connection.java:367)
       at com.squareup.okhttp.OkHttpClient.connectAndSetOwner(OkHttpClient.java:128)
       at com.squareup.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:328)
       at com.squareup.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:245)
       at com.squareup.okhttp.Call.getResponse(Call.java:267)
       at com.squareup.okhttp.Call$ApplicationInterceptorChain.proceed(Call.java:224)
       at com.squareup.okhttp.Call.getResponseWithInterceptorChain(Call.java:195)
       at com.squareup.okhttp.Call.execute(Call.java:79)
       at com.kwindoo.application.network.newapilib.lib.BaseNetworkTask.doInBackground(BaseNetworkTask.java:325)
       at com.kwindoo.application.network.newapilib.lib.BaseNetworkTask.doInBackground(BaseNetworkTask.java:38)
       at android.os.AsyncTask.call(AsyncTask.java:394)
       at java.util.concurrent.FutureTask.run(FutureTask.java:266)
       at android.os.AsyncTask$SerialExecutor.run(AsyncTask.java:305)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
       at java.lang.Thread.run(Thread.java:920)

我还有第二个异常,即 CertExpiredException。所以这只是服务器端修复?

Caused by java.security.cert.CertificateExpiredException: Certificate expired at Wed Sep 29 12:21:40 PDT 2021 (compared to Thu Mar 31 07:13:28 PDT 2022)
       at com.android.org.conscrypt.OpenSSLX509Certificate.checkValidity(OpenSSLX509Certificate.java:269)
       at com.android.org.conscrypt.OpenSSLX509Certificate.checkValidity(OpenSSLX509Certificate.java:255)
       at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:605)
       at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:505)
       at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:425)
       at com.android.org.conscrypt.TrustManagerImpl.getTrustedChainForServer(TrustManagerImpl.java:353)
       at android.security.net.config.NetworkSecurityTrustManager.checkServerTrusted(NetworkSecurityTrustManager.java:94)
       at android.security.net.config.RootTrustManager.checkServerTrusted(RootTrustManager.java:90)
       at com.android.org.conscrypt.ConscryptEngineSocket.checkServerTrusted(ConscryptEngineSocket.java:163)
       at com.android.org.conscrypt.Platform.checkServerTrusted(Platform.java:255)
       at com.android.org.conscrypt.ConscryptEngine.verifyCertificateChain(ConscryptEngine.java:1638)
       at com.android.org.conscrypt.NativeCrypto.ENGINE_SSL_read_direct(NativeCrypto.java)
       at com.android.org.conscrypt.NativeSsl.readDirectByteBuffer(NativeSsl.java:569)
       at com.android.org.conscrypt.ConscryptEngine.readPlaintextDataDirect(ConscryptEngine.java:1095)
       at com.android.org.conscrypt.ConscryptEngine.readPlaintextData(ConscryptEngine.java:1079)
       at com.android.org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:876)
       at com.android.org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:747)
       at com.android.org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:712)
       at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.processDataFromSocket(ConscryptEngineSocket.java:858)
       at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.access0(ConscryptEngineSocket.java:731)
       at com.android.org.conscrypt.ConscryptEngineSocket.doHandshake(ConscryptEngineSocket.java:241)
       at com.android.org.conscrypt.ConscryptEngineSocket.startHandshake(ConscryptEngineSocket.java:220)
       at com.squareup.okhttp.Connection.connectTls(Connection.java:235)
       at com.squareup.okhttp.Connection.connectSocket(Connection.java:199)
       at com.squareup.okhttp.Connection.connect(Connection.java:172)
       at com.squareup.okhttp.Connection.connectAndSetOwner(Connection.java:367)
       at com.squareup.okhttp.OkHttpClient.connectAndSetOwner(OkHttpClient.java:128)
       at com.squareup.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:328)
       at com.squareup.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:245)
       at com.squareup.okhttp.Call.getResponse(Call.java:267)
       at com.squareup.okhttp.Call$ApplicationInterceptorChain.proceed(Call.java:224)
       at com.squareup.okhttp.Call.getResponseWithInterceptorChain(Call.java:195)
       at com.squareup.okhttp.Call.execute(Call.java:79)
       at com.kwindoo.application.network.newapilib.lib.BaseNetworkTask.doInBackground(BaseNetworkTask.java:325)
       at com.kwindoo.application.network.newapilib.lib.BaseNetworkTask.doInBackground(BaseNetworkTask.java:38)
       at android.os.AsyncTask.call(AsyncTask.java:394)
       at java.util.concurrent.FutureTask.run(FutureTask.java:266)
       at android.os.AsyncTask$SerialExecutor.run(AsyncTask.java:305)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
       at java.lang.Thread.run(Thread.java:920)

我将以下库用于我的网络层:

  implementation 'com.squareup.okio:okio:2.8.0'
  implementation 'com.squareup.okhttp:okhttp:2.5.0'

有什么建议吗?

第二个例外的到期日期是 let's encrypt 之前使用的 R3 中间签名证书的到期日期:https://docs.certifytheweb.com/docs/kb/kb-202109-letsencrypt/

此后被新的根证书取代,Android 12 与新的根证书兼容。

可能是库的问题,您使用的okhttp版本已经过时:https://square.github.io/okhttp/

您可以尝试迁移到最新版本:

implementation("com.squareup.okhttp3:okhttp:4.9.3")

这是一个 known issue,因为 Let's Encrypt 签署的某些证书​​不受信任。

这是一个 server-side 问题,请更新证书。

如果您愿意,可以跳过证书检查

创建以下 kotlin class

object RetrofitClientInstance {

    fun unSafeOkHttpClient(): OkHttpClient.Builder {
        val okHttpClient = OkHttpClient.Builder()
        try {
            // Create a trust manager that does not validate certificate chains
            val trustAllCerts: Array<TrustManager> = arrayOf(object : X509TrustManager {
                override fun checkClientTrusted(
                    chain: Array<out X509Certificate>?,
                    authType: String?
                ) {
                }

                override fun checkServerTrusted(
                    chain: Array<out X509Certificate>?,
                    authType: String?
                ) {
                }

                override fun getAcceptedIssuers(): Array<X509Certificate> {
                    return arrayOf()
                }
            })

            // Install the all-trusting trust manager
            val sslContext = SSLContext.getInstance("SSL")
            sslContext.init(null, trustAllCerts, SecureRandom())

            // Create an ssl socket factory with our all-trusting manager
            val sslSocketFactory = sslContext.socketFactory
            if (trustAllCerts.isNotEmpty() && trustAllCerts.first() is X509TrustManager) {
                okHttpClient.sslSocketFactory(
                    sslSocketFactory,
                    trustAllCerts.first() as X509TrustManager
                )
                okHttpClient.hostnameVerifier { _, _ -> true }
            }

            return okHttpClient
        } catch (e: Exception) {
            return okHttpClient
        }
    }
}

你可以在 kotlin 中使用它

Retrofit.Builder()
        .client(RetrofitClientInstance.unSafeOkHttpClient().build())

并在 java

Retrofit.Builder()
.client(RetrofitClientInstance.INSTANCE.unSafeOkHttpClient().build())