Ok, TLS!

Jerry M.
techbrews
Published in
4 min readMar 7, 2021

We are paranoid. Paranoid about security and always trying to strike a fine balance between security and usability. One of the simplest forms of security, which anyone can adopt while building APIs, is to expose them over a secure channel. HTTPS to be precise. In HTTPS, the “S” stands for secure and uses TLS or Transport Layer Security to encrypt the transmissions.

This is why you will find that all the APIs exposed by appveen data.stack are secure by default. We do not have an insecure mode. HTTPS is by default. The min. TLS versions that we support is 1.2 and the max version is 1.3

So it came as a surprise when one of our clients raised a support ticket claiming that, in their on-premise deployment, we were strictly using TLSv1.3 and there was no option to connect via TLSv1.2.

How do we establish TLSv1.2 and v1.3 support?

And how do we establish that we DO NOT support TLSv1.1?

The answer, cURL!

cURL has an option to specify which version of TLS you want to use.

  • --tlsv1.X — to specify the minimum supported version of TLS and,
  • --tls-max 1.X — to specify the max. supported version.

cURL installed via package managers might not yet support TLSv1.3. As it is in my case. So for my tests, I used the latest cURL docker image.

Let’s test it out against the cloud environment.

Test for TLSv1.1

docker run --rm curlimages/curl:7.75.0 -I https://cloud.appveen.com -v --tlsv1.1 --tls-max 1.1

Output:

* Connected to cloud.appveen.com (34.126.94.16) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
* CApath: none
} [5 bytes data]
* TLSv1.1 (OUT), TLS handshake, Client hello (1):
} [143 bytes data]
* TLSv1.1 (IN), TLS alert, protocol version (582):
{ [2 bytes data]
* error:1409442E:SSL routines:ssl3_read_bytes:tlsv1 alert protocol version
* Closing connection 0

So TLSv1.1 failed.

Test for TLS1.2

docker run --rm curlimages/curl:7.75.0 -I https://cloud.appveen.com -v --tlsv1.2 --tls-max 1.2

Output:

* Connected to cloud.appveen.com (34.126.94.16) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /cacert.pem
* CApath: none
} [5 bytes data]
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
} [233 bytes data]
* TLSv1.2 (IN), TLS handshake, Server hello (2):
{ [112 bytes data]
* TLSv1.2 (IN), TLS handshake, Certificate (11):
{ [2465 bytes data]
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
{ [300 bytes data]
* TLSv1.2 (IN), TLS handshake, Server finished (14):
{ [4 bytes data]
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
} [37 bytes data]
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
} [1 bytes data]
* TLSv1.2 (OUT), TLS handshake, Finished (20):
} [16 bytes data]
* TLSv1.2 (IN), TLS handshake, Finished (20):
{ [16 bytes data]
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
....

TLSv1.2 is a supported.

Test for TLSv1.3

Command:

docker run --rm curlimages/curl:7.75.0 -I https://cloud.appveen.com -v --tlsv1.3 --tls-max 1.3

Output:

* Connected to cloud.appveen.com (34.126.94.16) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /cacert.pem
* CApath: none
} [5 bytes data]
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
} [512 bytes data]
* TLSv1.3 (IN), TLS handshake, Server hello (2):
{ [122 bytes data]
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
{ [25 bytes data]
* TLSv1.3 (IN), TLS handshake, Certificate (11):
{ [2470 bytes data]
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
{ [264 bytes data]
* TLSv1.3 (IN), TLS handshake, Finished (20):
{ [52 bytes data]
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
} [1 bytes data]
* TLSv1.3 (OUT), TLS handshake, Finished (20):
} [52 bytes data]
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
...

TLS 1.3 is also a supported.

Version selection

But what about version selection, the property of SSL where the client and server will pick the highest supported TLS version available for them?

For this. we can slightly modify the command as,

docker run --rm curlimages/curl:7.75.0 -I https://cloud.appveen.com -v --tlsv1.2 --tls-max 1.3

We specify that the min. version we want to use is TLSv1.2, but we support upto TLSv1.3. This gives the output,

* Connected to cloud.appveen.com (34.126.94.16) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /cacert.pem
* CApath: none
} [5 bytes data]
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
} [512 bytes data]
* TLSv1.3 (IN), TLS handshake, Server hello (2):
{ [122 bytes data]
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
{ [25 bytes data]
* TLSv1.3 (IN), TLS handshake, Certificate (11):
{ [2470 bytes data]
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
{ [264 bytes data]
* TLSv1.3 (IN), TLS handshake, Finished (20):
{ [52 bytes data]
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
} [1 bytes data]
* TLSv1.3 (OUT), TLS handshake, Finished (20):
} [52 bytes data]
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384

But the output has TLSv1.3. How can we be sure that the client presented both options and the server selected 1.3? We look at the packets.

Fire up Wireshark, and capture the packets for this particular connection. Here’s the Client Hello,

Client Hello

This shows that the client sent both TLSv1.2 and TLSv1.3. Let’s look at the Server Hello,

Server Hello

The server picked 1.3!

TLS is a fascinating protocol. The handshake process, the way it negotiates an asymmetric/public-key algorithm to switch to a symmetric key for encrypting data etc. There’s a level of geekiness attached to it (and a bit of paranoia).

--

--

Jerry M.
techbrews

Manages technology @ appveen. Technology enthusiast. Admirer of algorithms. Husband, dad and beer lover. Views are my own or could have been coerced by my wife.