SSL with Kotlin and Ktor

Alexey Soshin
ProAndroidDev
Published in
3 min readSep 17, 2020

--

Photo by Scott Webb on Unsplash

So, you develop some of your services with Kotlin and Ktor.

Normally, your Ktor services will sit safely behind a reverse proxy, that will handle all the basic security concerns, including SSL, for you.

And in your test environment, you would be running without SSL at all, simply bypassing all security. That’s usually the case.

But in my case, I had a particular HTTP client that I needed to test, that would only support HTTPS.

Unfortunately, the official documentation for Ktor is very confusing about self-signed certificates. For one, it only covers the case where you’re using applcation.conf to set up your server.

So, I decided to document here my findings on how to setup your own HTTPS test server with Ktor.

First, you’ll need additional dependency to support SSL.

In your build.gradle.kts add the following dependency:

val ktorVersion = "1.4.0"
dependencies {
...
testImplementation("io.ktor:ktor-network-tls-certificates:$ktorVersion")
}

Notice that I’m using testImplementation here, specifically so you won’t use this solution in your production code.

Now we can start the real work.

So, we want to start our Ktor server in HTTPS mode. For that we’ll need to define a keystore. You can do that from a command line, but I wanted to be able to do that programatically.

First, we’ll need two important variables that must be aligned: an alias for our certificate and a password for the keystore:

val alias = "certificateAlias"
val pass = "bcd"

Next, we’ll define our keystore. Keystore may contain multiple certificates that use different algorithms, but here I’ll be using only a single certificate:

val keystore = buildKeyStore {
certificate(alias) {
hash = HashAlgorithm.SHA256
sign = SignatureAlgorithm.ECDSA
keySizeInBits = 256
password = pass
}
// More certificates come here}

Next comes the definition of our server. This is were things start to get a bit more complicated:

val server = embeddedServer(Netty, applicationEngineEnvironment {
...
})

Notice that this is different from how we usually define our Ktor server:

val server = embeddedServer(Netty, 8080) {
...
}

Those two pieces of code may look similar, but the top block represents ApplicationEngineEnvironment, while the bottom block represents a Module. Those are distinctly different. And to set up SSL, we need to use ApplicationEngineEnvironment

Having ApplicationEngineEnvironment , we now can define sslConnector

applicationEngineEnvironment {
sslConnector(keystore,
alias,
{ "".toCharArray() },
{ pass.toCharArray() }) {
...
}
}

We’re using alias, password and keystore we’ve defined above.

Now, since we didn’t have a chance to define on which port our server starts, we may as well do so now:

sslConnector(...) {
port = 8443
keyStorePath = keyStore.asFile.absoluteFile
...
}

And, as you see, we also must define key store path as well here.

asFile is an extension property we’ve defined for simplicity:

private val KeyStore.asFile: File
get() {
val keyStoreFile = File("build/temp.jks")
this.saveToFile(keyStoreFile, pass)
return keyStoreFile
}

Now, if you invoke server.start() , you should see in you console:

Responding at https://0.0.0.0:8443

But wait, didn’t we forget something? It’s pretty pointless to have a server that doesn’t have any routes defined.

You may be tempted to do it as usual:

applicationEngineEnvironment {
sslConnector(...) {
...
}
routing {
...
}
}

But this won’t work. Remember that usually, we operate in a context of a Module, but here we’re in a context of ApplicationEngineEnvironment

So, we’ll need to declare a module first:

applicationEngineEnvironment {
sslConnector(...) {
...
}
module {
...
}
}

And now we can declare our routes as usual:

applicationEngineEnvironment {
sslConnector(...) {
...
}
module {
routes {
...
}
}
}

And that’s it. You can see the full example here:

Remember, you should use this only for testing purposes, and never in production.

--

--

Solutions Architect @Depop, author of “Kotlin Design Patterns and Best Practices” book and “Pragmatic System Design” course