Checking Cloudflare SSL

My website for a while has used CloudFlare as its front-end.  It’s a rather nice setup and means my real server gets less of a hammering, which is a good thing.  A few months ago they enabled a feature called Universal SSL which I have also added to my site.  Around the same time, my SSL check scripts started failing for the website, the certificate had expired apparently many many days ago. Something wasn’t right.

The Problem

The problem was simply at first I’d get emails saying “The SSL certificate for enc.com.au “(CN: )” has expired!”.  I use a program called ssl-cert-check that would check all (web, smtp, imap) of my certificates. It’s very easy to forget to renew and this program runs daily and does a simple check.

Running the program on the command line gave some more information, but nothing (for me) that really helped:

$ /usr/bin/ssl-cert-check -s enc.com.au -p 443
Host Status Expires Days
----------------------------------------------- ------------ ------------ ----
unable to load certificate
140364897941136:error:0906D06C:PEM routines:PEM_read_bio:no start line:pem_lib.c:701:Expecting: TRUSTED CERTIFICATE
unable to load certificate
139905089558160:error:0906D06C:PEM routines:PEM_read_bio:no start line:pem_lib.c:701:Expecting: TRUSTED CERTIFICATE
unable to load certificate
140017829234320:error:0906D06C:PEM routines:PEM_read_bio:no start line:pem_lib.c:701:Expecting: TRUSTED CERTIFICATE
unable to load certificate
140567473276560:error:0906D06C:PEM routines:PEM_read_bio:no start line:pem_lib.c:701:Expecting: TRUSTED CERTIFICATE
enc.com.au:443 Expired -2457182

So, apparently, there was something wrong with the certificate. The problem was this was CloudFlare who seem to have a good idea on how to handle certificates and all my browsers were happy.

ssl-cert-check is a shell script that uses openssl to make the connection, so the next stop was to see what openssl had to say.

$ echo "" | /usr/bin/openssl s_client -connect enc.com.au:443 CONNECTED(00000003)
140115756086928:error:14077438:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert internal error:s23_clnt.c:769:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 7 bytes and written 345 bytes
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
---

No peer certificate available. That was the clue I was looking for.

Where’s my Certificate?

CloudFlare Universal SSL uses certificates that have multiple domains in the one certificate. The do this by having one canonical name which is something like sni(numbers).cloudflaressl.com and then multiple Subject Alternative Names (a bit like ServerAlias in apache configurations). This way a single server with a single certificate can serve multiple domains. The way that the client tells the server which website it is looking for is Server Name Indication (SNI). As part of the TLS handshaking the client tells the server “I want website www.enc.com.au”.

The thing is, by default, both openssl s_client and the check script do not use this feature. That was fail the SSL certificate checks were failing. The server was waiting for the client to ask what website it wanted.  Modern browsers do this automatically so it just works for them.

The Fix

For openssl on the command line, there is a flag -servername which does the trick nicely:

$ echo "" | /usr/bin/openssl s_client -connect enc.com.au:443 -servername enc.com.au 
CONNECTED(00000003)
depth=2 C = GB, ST = Greater Manchester, L = Salford, O = COMODO CA Limited, CN = COMODO ECC Certification Authority
verify error:num=20:unable to get local issuer certificate
---
(lots of good SSL type messages)

That was openssl happy now. We asked the server what website we were interested in with the -servername and got the certificate.

The fix for ssl-cert-check is even simpler.  Like a lot of things once you know the problem, the solution is not only easy to work out but someone has done it for you already.  There is a Debian bug report on this problem with a simple fix from Francois Marier.

Just edit the check script and change the line that has:

 TLSSERVERNAME="FALSE"

and change it to true.  Then the script is happy too:

$ ssl-cert-check -s enc.com.au -p https
Host Status Expires Days
----------------------------------------------- ------------ ------------ ----
enc.com.au:https Valid Sep 30 2015 114

All working and as expected!  This isn’t really a CloudFlare problem as such, it is just that’s the first place I had seen these sort of SNI certificates being used in something I administer (or more correctly something behind the something).

One thought on “Checking Cloudflare SSL

  1. Nice bit of debugging.

    I have to say, though, that Cloudflare is really horrible for Tor users (throws up huge numbers of almost unreadable CAPCHAs) so it’d be great if you’d reconsider using them.

Comments are closed.