Let's EncryptでSSLHandshakeException

環境

Pixel 4a(Android 11)

エラー

HTTP FAILED: javax.net.ssl.SSLHandshakeException: 
java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

状況

  • https通信時に上記エラー。
  • 通信はOkHttpを使用。
  • WebViewからの通信も同様のエラー。
  • 端末のChromeアプリから該当サーバーへの疎通は問題なし。

解決

Chain of Trust - Let's Encrypt から必要な証明書をダウンロードして raw ディレクトリに保存し、OkHttpやWebViewに追加する。

OkHttp

build.gradleに以下を追加

implementation "com.squareup.okhttp3:okhttp-tls:$okhttp_version"

okhttp/okhttp-tls at master · square/okhttp · GitHub

保存した証明書を追加する。

private fun buildOkHttp(): OkHttpClient {
    val x1Certificates = context.resources.openRawResource(R.raw.isrg_root_x1).reader()
        .use(InputStreamReader::readText).decodeCertificatePem()
    val x2Certificates = context.resources.openRawResource(R.raw.isrg_root_x2).reader()
        .use(InputStreamReader::readText).decodeCertificatePem()
    val r3Certificates = context.resources.openRawResource(R.raw.lets_encrypt_r3).reader()
        .use(InputStreamReader::readText).decodeCertificatePem()

    val certificates =
        HandshakeCertificates.Builder()
            .addTrustedCertificate(x1Certificates)
            .addTrustedCertificate(x2Certificates)
            .addTrustedCertificate(r3Certificates)
            .build()
    return OkHttpClient
        .Builder()
        .sslSocketFactory(certificates.sslSocketFactory(), certificates.trustManager)
        .build()
}

okhttp-tlsのサンプルはこちら
okhttp/CustomTrust.kt at master · square/okhttp · GitHub

WebView

xml/network_security_config.xml として以下のファイルを作成。

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true" >
        <trust-anchors>
            <certificates src="@raw/isrg_root_x1" />
            <certificates src="@raw/isrg_root_x2" />
            <certificates src="@raw/lets_encrypt_r3" />
            <certificates src="system" />
        </trust-anchors>
    </base-config>
</network-security-config>

AndroidManifest.xmlに以下の記述を追加

<manifest...>
  <application
      ...
      android:networkSecurityConfig="@xml/network_security_config"
      ...
  </application>
</manifest>

参考

stackoverflow.com

developer.android.com