2

I need to add a self-signed certificate on my app and for that, I set the Network security configuration. It works perfectly on API 31, but when I try it on API 21, the

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

error appear.

I saw in the Android documentation that

apps targeting Android 6.0 (API level 23) and lower also trust the user-added CA store by default

So even if the

android:networkSecurityConfig="@xml/network_security_config"

line in my manifest is used only for API level 24 and higher, I understand that it should work anyway in API level 23 and lower. (Or maybe I am wrong ?)

For information, my network_security_config.xml store in my res/xlm folder is like this :

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config>
    <domain includeSubdomains="true">my.server.ip</domain>
    <trust-anchors>
        <certificates src="@raw/my_pem_cert"/>
    </trust-anchors>
</domain-config>
</network-security-config>

And my my_pem_cert.pem store in res/raw folder looks like :

-----BEGIN CERTIFICATE-----
ekfozjoiejzfz...
-----END CERTIFICATE-----

Have you any idea why it doesn't work on API level 23 and lower then ?

user207421
  • 305,947
  • 44
  • 307
  • 483

1 Answers1

1

To help those who have the same issue, I didn't find why it doesn't work so I did the following to be able to comunicate with my server :

if ( android.os.Build.VERSION.SDK_INT <= android.os.Build.VERSION_CODES.M) {
    try {
        val caInput: InputStream = resources.openRawResource(R.raw.my_pem_cert)
        // Create a KeyStore containing our trusted CAs
        val keyStore = KeyStore.getInstance(KeyStore.getDefaultType())
        keyStore.load(null, null)
        keyStore.setCertificateEntry("ca", 
            try { 
     CertificateFactory.getInstance("X.509").generateCertificate(caInput)
            } finally {
                caInput.close()
            }
        )
        // Create a TrustManager that trusts the CAs in our KeyStore
        val tmf: TrustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
        tmf.init(keyStore)
        // Create an SSLContext that uses our TrustManager
        val sslContext: SSLContext = SSLContext.getInstance("TLS")
        sslContext.init(null, tmf.getTrustManagers(), null)
        Volley.newRequestQueue(context,HurlStack(null, sslContext.socketFactory)).add(temp)
    } catch (err : Exception) {
        FirebaseCrashlytics.recordException(err)
    }
} else {
    Volley.newRequestQueue(context).add(temp)
}

So in Android M (LVL 23) and lower, I create and use a custom SSL Socket Factory to execute my request. Else, I use the Network security configuration.