https://kotlinlang.org logo
#ktor
Title
# ktor
v

Václav Beneš

08/03/2021, 9:00 PM
Hi I d like to add ssl certificates to ktor client. Is it possible add them to default engine or should i use okhttps. Does ktor load ssl from system ? Thx
a

Aleksei Tirman [JB]

08/04/2021, 8:36 AM
Unfortunately, there is no common SSL configuration for all engines but you can customize it via specific config of an engine. Here are the examples for a few engines:
Copy code
HttpClient(Apache) {
    engine {
        // sslContext = SSLContexts.custom().build()
    }
}

HttpClient(OkHttp) {
    engine {
        config {
            // sslSocketFactory(...)
        }
    }
}

HttpClient(CIO) {
    engine {
        https {
            // trustManager = ...
            // cipherSuites = listOf(suite)
        }
    }
}
👀 1
v

Václav Beneš

08/26/2021, 8:03 AM
@Aleksei Tirman [JB] Hi , it seems like i was not successful. My setup is more specific communication from
ktor
client (teamcity build) goes through proxy server to api. I found this topic https://youtrack.jetbrains.com/issue/KTOR-411 . There I am using
addKeyStore
with added
keystore,jks
created from
build-proxy-ca.crt
. Error
Copy code
<blockquote id="error">
      <p><b>Failed to establish a secure connection to 108.128.82.18</b></p>
      </blockquote>
      
      <div id="sysmsg">
      <p>The system returned:</p>
      <blockquote id="data">
      <pre>(71) Protocol error (TLS code: SQUID_X509_V_ERR_DOMAIN_MISMATCH)</pre>
      <p>Certificate does not match domainname: /CN=*.<http://browserstack.com|browserstack.com></p>
      </blockquote>
      </div>
      
      <p>This proxy and the remote host failed to negotiate a mutually acceptable security settings for handling your request. It is possible that the remote host does not support secure connections, or the proxy is not satisfied with the host security credentials.</p>
      
      <p>Your cache administrator is <a href="mailto:root?subject=CacheErrorInfo%20-%20ERR_SECURE_CONNECT_FAIL&body=CacheHost%3A%20build-proxy-01.brq2.re.ida.avast.com%0D%0AErrPage%3A%20ERR_SECURE_CONNECT_FAIL%0D%0AErr%3A%20(71)%20Protocol%20error%0D%0ATimeStamp%3A%20Wed,%2025%20Aug%202021%2022%3A06%3A17%20GMT%0D%0A%0D%0AClientIP%3A%2010.84.36.245%0D%0AServerIP%3A%20api-cloud.browserstack.com%0D%0A%0D%0AHTTP%20Request%3A%0D%0ACONNECT%20%20HTTP%2F1.1%0AProxy-Connection%3A%20Keep-Alive%0D%0AHost%3A%20api-cloud.browserstack.com%3A443%0D%0A%0D%0A%0D%0A">root</a>.</p>
      <br>
      </div>
      
      <hr>
      <div id="footer">
      <p>Generated Wed, 25 Aug 2021 22:06:17 GMT by <http://build-proxy-01.brq2.re.ida.avast.com|build-proxy-01.brq2.re.ida.avast.com> (squid/4.11)</p>
      <!-- ERR_SECURE_CONNECT_FAIL -->
      </div>
      </body></html>
      "
00:06:18       io.ktor.client.features.ServerResponseException: Server error(<https://api-cloud.browserstack.com/app-automate/espresso/v2/test-suites>: 503 Service Unavailable. Text: "<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "<http://www.w3.org/TR/html4/strict.dtd>">
      <html><head>
      <meta type="copyright" content="Copyright (C) 1996-2020 The Squid Software Foundation and contributors">
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
      <title>ERROR: The requested URL could not be retrieved</title>
      <style type="text/css"><!--
Code
Copy code
val proxyHost = System.getenv("HTTP_PROXY_HOST")
val proxyPort = System.getenv("HTTP_PROXY_PORT")

open class KtorBaseClient(basePath: String) {

    val proxyBuilder: ProxyConfig?
        get() {
            println("PROXY: $proxyHost:$proxyPort")
            if (proxyHost != null && proxyPort != null) {
                return ProxyBuilder.http(Url("http://$proxyHost:$proxyPort"))
            }
            return null
        }

    private val json = Json {
        encodeDefaults = true
        ignoreUnknownKeys = true
    }

    val client = HttpClient(CIO) {

        engine {
            proxy = proxyBuilder

            val ks = KeyStore.getInstance(KeyStore.getDefaultType())

            val file = try {
                FileOutputStream(javaClass.getResource("/keystore.jks").file)
            } catch (e: FileNotFoundException) {
                println(e)
            }
            ks.load(null, "password".toCharArray())
            ks.store(file as OutputStream, "password".toCharArray())

            https {
                addKeyStore(ks, "password".toCharArray() as CharArray?)
                serverName = proxyHost
            }
        }
I tried ignore certificates with and it works. I cant find a way how to load proxy certificates.
Copy code
val client = HttpClient(OkHttp) {

        engine {
            proxy = proxyBuilder
            config {
                val tm: X509TrustManager = object : X509TrustManager {
                    override fun getAcceptedIssuers(): Array<X509Certificate?> {
                        return arrayOfNulls(0)
                    }

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

                    @Throws(CertificateException::class)
                    override fun checkServerTrusted(
                        certs: Array<X509Certificate?>?,
                        authType: String?
                    ) {
                    }
                }
                val trustAllCerts = arrayOf(tm)
                val sslContext = SSLContext.getInstance("SSL")
                sslContext.init(null, trustAllCerts, SecureRandom())
                val sslSocketFactory: SSLSocketFactory = sslContext.socketFactory
                sslSocketFactory(
                    sslSocketFactory, tm
                )

                val hostnameVerifier = HostnameVerifier { _, _ ->
                    true
                }
                hostnameVerifier(hostnameVerifier)
            }
        }
a

Aleksei Tirman [JB]

08/27/2021, 6:05 AM
In principle, you can load certificates for a proxy server the same way you do for a destination server. I am trying to write an example using a local Squid proxy server but I cannot make it work yet.
625 Views