Curl with TLSv1.3 and openSSL on macOS
This took me some time to figure out as I couldn’t find that much resources about it online. It all starts with me trying to be a good citizen of the web and use a modern configuration for my web server. Mozilla provides a configuration service where the “modern” one only support TLSv1.3. This is great, I think. Maybe not for everyone, right now, if you want to support old browsers, but for my use case it’s great. I enabled it on one of my sites to start with and tested it in Firefox and called it a day. A couple of weeks later I tried it with curl
on my macOS Mojave machine.
$ curl --tlsv1.3 https://bolmaster2.com
curl: (4) LibreSSL was built without TLS 1.3 support
Hm. I thought this should work. Here I’m using the pre-shipped curl
with macOS Mojave which is using LibreSSL 2.6.5. Check it by running:
$ curl --version
curl 7.54.0 (x86_64-apple-darwin18.0) libcurl/7.54.0 LibreSSL/2.6.5 zlib/1.2.11 nghttp2/1.24.1
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp smb smbs smtp smtps telnet tftp
Features: AsynchDNS IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz HTTP2 UnixSockets HTTPS-proxy
It turns out that LibreSSL doesn’t have support for TLSv1.3.
Building curl with openssl
So, I thought: why isn’t curl
using openssl? I’m using openssl on my dev machine, installed with homebrew, so I should just be able to use that. One thing that’s easy to miss here is that homebrew’s default openssl formula is using version 1.0.2
and openssl first started to support TLSv1.3 on version 1.1.1
. Homebrew has a separate formula for openssl 1.1.1
called [email protected].
So you need to use openssl 1.1.1
. That shouldn’t be a problem. Compiling curl with So when you read this, there’s probably not gonna be a problem. Then you should just be able to run:openssl 1.1.1
was a bit of a PITA because of curl
’s dependencies was also needed to be compiled with openssl 1.1.1
. Anyway, the homebrew maintainers are starting to move formulas to compile with [email protected]
.
brew install curl-openssl
UPDATE: The homebrew-core curl-openssl
formula now uses [email protected]
. All is needed to use TLSv1.3 with curl is the above command ✅
Now when you run:
/usr/local/opt/curl-openssl/bin/curl --version
it should yield something like this:
curl 7.65.3 (x86_64-apple-darwin18.7.0) libcurl/7.65.3 OpenSSL/1.1.1c zlib/1.2.11 brotli/1.0.7 c-ares/1.15.0 libidn2/2.2.0 libssh2/1.9.0 nghttp2/1.39.2 librtmp/2.3
Release-Date: 2019-07-19
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp scp sftp smb smbs smtp smtps telnet tftp
Features: AsynchDNS brotli GSS-API HTTP2 HTTPS-proxy IDN IPv6 Kerberos Largefile libz Metalink NTLM NTLM_WB SPNEGO SSL TLS-SRP UnixSockets
The important part is that is says OpenSSL/1.1.1c.
Add to PATH
To be able to reach the new version with curl
command you need to add it to your PATH
.
Depending on what shell you use this will look differently:
# Using bash
echo 'export PATH="/usr/local/opt/curl-openssl/bin/:$PATH"' >> ~/.bashrc
# Using zsh
echo 'export PATH="/usr/local/opt/curl-openssl/bin/:$PATH"' >> ~/.zshrc
Restart your terminal and now you should get the same output as before with:
curl --version
And finally TLSv1.3 should work 😅:
$ curl --tlsv1.3 -v https://bolmaster2.com
* Trying 2606:4700:3034::6812:3865:443...
* Connected to bolmaster2.com (2606:4700:3034::6812:3865) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /usr/local/etc/[email protected]/cert.pem
CApath: /usr/local/etc/[email protected]/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use h2
* Server certificate:
* subject: C=US; ST=CA; L=San Francisco; O=Cloudflare, Inc.; CN=sni.cloudflaressl.com
* start date: Oct 8 00:00:00 2019 GMT
* expire date: Oct 7 12:00:00 2020 GMT
* subjectAltName: host "bolmaster2.com" matched cert's "bolmaster2.com"
* issuer: C=US; ST=CA; L=San Francisco; O=CloudFlare, Inc.; CN=CloudFlare Inc ECC CA-2
* SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x7f8ac6801400)
> GET / HTTP/2
> Host: bolmaster2.com
> user-agent: curl/7.65.3
> accept: */*
>
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
* Connection state changed (MAX_CONCURRENT_STREAMS == 256)!
...