Home > OS >  How to use custom root SSL certificate with system Android certificates?
How to use custom root SSL certificate with system Android certificates?

Time:12-16

I want to add custom certificate with system certificates. But I don't know which KeyStore contains the system certificates. Does anyone know how to use custom certificate and system certificates to get SSLContext?

The idea is: If custom certificate fail, then use and check with system certificates when make a request.

I use this code for adding custom certificate:

val cf: CertificateFactory = CertificateFactory.getInstance("X.509")
val ca = caInput.use { cf.generateCertificate(it) }
val keyStore: KeyStore = KeyStore.getInstance(KeyStore.getDefaultType()).apply {
    load(null, null)
    setCertificateEntry("ca", ca)
}
val tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm()
val tmf = TrustManagerFactory.getInstance(tmfAlgorithm)
tmf.init(keyStore)
val sslContext: SSLContext = SSLContext.getInstance("TLS")
sslContext.init(null, tmf.trustManagers, null)
return sslContext

As I understand the KeyStore.getDefaultType() not contains system certificates.

CodePudding user response:

I found a solution. May be it will be helpful for someone.

The first, the Android CA Key Store name is "AndroidCAStore". You can find all system CA at this store.

The second, you can get access to this store and load all CA to you custom store. If you will try to load your custom CA to system store then you get an exception.

private fun loadSystemCAToCustomKeyStore() {
    val systemCAKeyStore = KeyStore.getInstance("AndroidCAStore")
    systemCAKeyStore?.let {
        systemCAKeyStore.load(null, null)
        val keyAliases: Enumeration<String> = systemCAKeyStore.aliases()
        while (keyAliases.hasMoreElements()) {
            val alias: String = keyAliases.nextElement()
            val cert: Certificate = systemCAKeyStore.getCertificate(alias)
            try {
                if (!getCustomKeyStore().containsAlias(alias)) {
                    getCustomKeyStore().setCertificateEntry(alias, cert)
                }
            } catch (e: Exception) {
                throw IllegalAccessException("Can't load system CA to custom Key Store")
            }
        }
    }
}

private fun getCustomKeyStore(): KeyStore {
    if (customKeyStore == null) {
        customKeyStore = KeyStore.getInstance(KeyStore.getDefaultType()).apply {
            load(null, null)
        }
    }
    return customKeyStore!!
}

The third, you can load to custom KeyStore your own certificate and get SSLContext. And when you make requests to the network, all certificates (system and custom) from this store will be checked automatically.

fun fromInputStream(caInput: InputStream): SSLContext {
    val cf: CertificateFactory = CertificateFactory.getInstance("X.509")
    val ca = caInput.use { cf.generateCertificate(it) }
    getCustomKeyStore().setCertificateEntry("ca", ca)
    loadSystemCAToCustomKeyStore()
    val tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm()
    val tmf = TrustManagerFactory.getInstance(tmfAlgorithm)
    tmf.init(getCustomKeyStore())
    val sslContext: SSLContext = SSLContext.getInstance("TLS")
    sslContext.init(null, tmf.trustManagers, null)
    return sslContext
}

P.S. This has been tested on Android version 7.1.2.

  • Related