How to trust all SSL certificates with KMM and Ktor

Alistair and Nick looking at a screen together

How to configure Ktor in a Kotlin Multiplatform Mobile project to trust all SSL certificates

Warning - Trusting all certificates is dangerous. It means you cannot trust that the server is who you think it is.

Why

Often API test environments are not signed with a certificate authority backed certificate. This is to save time and avoid expiring certificates. By default, mobile applications will not allow communication with such servers.

When developing mobile applications it can be necessary to communicate with such APIs. Again I stress this can be dangerous and precautions should be taken. For example, by using isolated devices which cannot access any real data.



Project Setup

For this post, I am assuming a standard/template Kotlin Multiplatform Mobile (KMM) setup using Kotlin 1.8.0 and Ktor 2.2.3. I have a compileSdk of 33 and minSdk of 29 for Android. I have an iOS deployment target of 15.0. I am using Ktor engines OkHttp for Android and Darwin for iOS.

Here's an example of the shared/build.gradle.kts for reference



Client Configuration

First, we need to configure our HttpClient. We need to enable some common configuration and then platform specific too. Here is an approach you can take to achieve that:

commonMain/kotlin/com/example/client/HttpClient.kt

androidMain/kotlin/com/example/client/AndroidHttpClient.kt

iosMain/kotlin/com/example/client/IosHttpClient.kt



Android Trust All

For Android to trust all certificates we need to provide a custom implementation of an X509TrustManager. In this implementation, we will make every certificate check a no-op.

androidMain/kotlin/com/example/client/AllCertsTrustManager.kt

Then to use this custom trust manager:

androidMain/kotlin/com/example/client/AndroidHttpClient.kt

You will likely want to limit this configuration to only test environments. How you might do that is out of the scope of this post. But you could consider setting different base URLs for each environment. Then you can use that to determine whether this configuration should be applied.



iOS Trust All

To allow us to loosen the server trust evaluation we must first set a property in our Info.plist

iosApp/iosApp/Info.plist

You can read more about NSExceptionAllowsInsecureHTTPLoads here. Note that we must specify the domains which we wish to loosen.

Now we can write a custom implementation of a ChallengeHandler.

iosMain/kotlin/com/example/client/TrustAllChallengeHandler.kt

In this ChallengeHandler we copy the server's certificates. We then set them as anchor certificates. This means when we evaluate the trust with the server it should pass.

Then to use this custom ChallengeHandler:

iosMain/kotlin/com/example/client/IosHttpClient.kt

Again, you will likely want to limit this configuration to only test environments.



Summary

We discussed why you might want to override the certificate trust evaluation. We explored implementing trust all certificate configurations with Ktor in a KMM project. We leveraged expect / actual to provide platform-specific configurations.

Please take caution with this approach. Don't use this in production.




Looking for something else?

Search over 400 blog posts from our team

Want to hear more?

Subscribe to our monthly digest of blogs to stay in the loop and come with us on our journey to make things better!