9

I am trying to connect to a service that has a self signed certificate from an internal testing environment that will only exist during prototyping. The Ktor client fails with

javax.net.ssl.SSLHandshakeException: PKIX path building failed:
 sun.security.provider.certpath.SunCertPathBuilderException:
 unable to find valid certification path to requested target

How can I disable certificate verification in this case?

3 Answers 3

13

Here's my solution for CIO engine.

val client = HttpClient(CIO) {
    engine {
        https {
            trustManager = object: X509TrustManager {
                override fun checkClientTrusted(p0: Array<out X509Certificate>?, p1: String?) { }

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

                override fun getAcceptedIssuers(): Array<X509Certificate>? = null
            }
        }
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

seems to be not working anymore with ktor 2.3.2
Works for me on 2.3.9
2

WARNING! do not use this in any production environment. I have done this for an isolated test environment where nothing is sensitive

Following the instructions from the first answer on Java: Overriding function to disable SSL certificate check (specifically: https://stackoverflow.com/a/19723687/2733184)

I found that I could add my own implementation of the TrustAll manager:

import java.security.cert.X509Certificate
import javax.net.ssl.X509TrustManager

class TrustAllX509TrustManager : X509TrustManager {
    override fun getAcceptedIssuers(): Array<X509Certificate?> = arrayOfNulls(0)

    override fun checkClientTrusted(certs: Array<X509Certificate?>?, authType: String?) {}

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

To add this to the Ktor client we need to configure the engine. I am using the Apache engine at the moment so you may need to change the setter to suit your chosen engine.

import io.ktor.client.*
import io.ktor.client.engine.apache.*
import java.security.SecureRandom
import javax.net.ssl.SSLContext

val client = HttpClient(Apache) {
    engine {
        sslContext = SSLContext.getInstance("TLS")
            .apply {
                init(null, arrayOf(TrustAllX509TrustManager()), SecureRandom())
            }
    }
    // install other features ....
}

I encourage anyone who finds how to do this for the other engines to add their own answer, or, if you add it as a comment, I will try to keep this answer updated

1 Comment

For HttpClient(Android), you do engine { sslManager = { httpsURLConnection -> httpsURLConnection.sslSocketFactory = SSLContext.getInstance("TLS").apply{}.socketFactory }
2

Here is the solution for Android engine:

Firstly, you should know that trusting all certificates and disabling SSL verification are dangerous practices. These are recommended only for testing environments.

class AllCertsTrustManager : X509TrustManager {

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

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

override fun getAcceptedIssuers(): Array<X509Certificate> = arrayOf()

}

To add this to Android engine configuration:

import io.ktor.client.HttpClient
import io.ktor.client.engine.android.Android
import io.ktor.serialization.kotlinx.json.json
import java.security.SecureRandom
import javax.net.ssl.HostnameVerifier
import javax.net.ssl.SSLContext


private val httpClient by lazy {
    HttpClient(Android) {
        engine {
            sslManager = { httpsURLConnection ->
                httpsURLConnection.hostnameVerifier = HostnameVerifier { _, _ -> true }
                httpsURLConnection.sslSocketFactory = SSLContext.getInstance("TLS")
                    .apply {
                        init(null, arrayOf(AllCertsTrustManager()), SecureRandom())
                    }.socketFactory
            }
        }
    }
}

1 Comment

For me, X509TrustManager was imported from javax.net.ssl.X509TrustManager but the X509Certificate from import java.security.cert.X509Certificate. I ran into some compilation problems initially because of those 2 namespaces (java and javax).

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.