github linkedin
Fun with Alexa skills and TLS
2020-03-11

I recently updated my Alexa skill, the “Mächtiger Aluhut” (mighty tinfoil hat), which provides you with your daily dose of conspiracy theories. The technical base for the skill is an embedded Jetty server, using the Alexa SDK with servlets.

I developed the skill (source code is here) and deployed it on my server. Then I opened up the Alexa ASK console (where you can test your skill) and tried to invoke it. Yeah, well, Alexa only told me “that the skill can’t be reached”, without further information.

So I fired up curl and executed a HTTP request against the skill. Works. Hmm.

Then I found a workaround in the Alexa console: you can copy the JSON which Alexa sends to the skill, switch to the tab “Manual JSON” and then paste that JSON. Then hit execute, and in the resulting JSON response you find a more detailed cause why the skill can’t be reached.

In my case it just said “Error executing TLS handshake”. Strange. Firefox works, Chrome works, curl works, but Alexa doesn’t.

The TLS connection isn’t terminated in Jetty - I decided to reverse proxy the skill with the nginx which is also serving my blog, using a Let’s Encrypt certificate.

This nginx uses a “tuned” TLS config (which disables crappy ciphers and the like), created by the Mozilla SSL Configuration Generator. I chose the “Intermediate” config, and I heard no complains about failing TLS connections so far.

Running nmap to show the supported ciphers yields this:

nmap --script ssl-enum-ciphers -p 443 www.mkammerer.de
Starting Nmap 7.80 ( https://nmap.org ) at 2020-02-29 15:35 CET
Nmap scan report for www.mkammerer.de (185.162.248.147)
Host is up (0.027s latency).
rDNS record for 185.162.248.147: v22019081128195184.nicesrv.de

PORT    STATE SERVICE
443/tcp open  https
| ssl-enum-ciphers: 
|   TLSv1.2: 
|     ciphers: 
|       TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 (dh 2048) - A
|       TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 (dh 2048) - A
|       TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (secp256r1) - A
|       TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (secp256r1) - A
|       TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (secp256r1) - A
|     compressors: 
|       NULL
|     cipher preference: client
|_  least strength: A

Okay, maybe switch to the “old” config in the Mozilla generator? Did that, now nmap shows this:

nmap --script ssl-enum-ciphers -p 443 tunnel.mkammerer.de
Starting Nmap 7.80 ( https://nmap.org ) at 2020-02-29 15:35 CET
Nmap scan report for tunnel.mkammerer.de (185.162.248.147)
Host is up (0.032s latency).
rDNS record for 185.162.248.147: v22019081128195184.nicesrv.de

PORT    STATE SERVICE
443/tcp open  https
| ssl-enum-ciphers: 
|   TLSv1.2: 
|     ciphers: 
|       TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (ecdh_x25519) - A
|       TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (ecdh_x25519) - A
|       TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (ecdh_x25519) - A
|       TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 (dh 2048) - A
|       TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 (dh 2048) - A
|       TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (dh 2048) - A
|       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (ecdh_x25519) - A
|       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (ecdh_x25519) - A
|       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (ecdh_x25519) - A
|       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (ecdh_x25519) - A
|       TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 (dh 2048) - A
|       TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 (dh 2048) - A
|       TLS_RSA_WITH_AES_128_GCM_SHA256 (rsa 2048) - A
|       TLS_RSA_WITH_AES_256_GCM_SHA384 (rsa 2048) - A
|       TLS_RSA_WITH_AES_128_CBC_SHA256 (rsa 2048) - A
|       TLS_RSA_WITH_AES_256_CBC_SHA256 (rsa 2048) - A
|       TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A
|     compressors: 
|       NULL
|     cipher preference: server
|_  least strength: A

Back to the Alexa console, test again, and it works!

What. Strange.

Running this code

URLConnection connection = new URL("https://www.mkammerer.de").openConnection();
try (InputStream stream = connection.getInputStream()) {
    System.out.println(new String(stream.readAllBytes(), StandardCharsets.UTF_8));
}

on a modern JVM

java --version
openjdk 11.0.6 2020-01-14
OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.6+10)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 11.0.6+10, mixed mode)

has absolutely no problems connecting to my server even with the “Intermediate” config, but for some reason this stuff won’t work with Alexa skills.

I didn’t bother to search further and single out the cipher which needs to be supported. I created a new virtual host which soley hosts my skill, enabled the old TLS config there, and left the www.mkammerer.de domain on the new config. Now everything works as expected, and hopefully Alexa updates their supported cipher suites.

If you have a german Alexa, feel free to test my skill!


Tags: java alexa

Back to posts