Find HTTPS certificates issued from a private key

Sat, 2018-03-24 20:42

I was having a great tea (not coffee, that's important) yesterday, casually scrolling Twitter, passing over dozens of tweets from people who deleted their Facebook accounts (#deletefacebook), and came across this: Statement In Regard To DigiCert® Revocation & Symantec® Distrust.

The Fiasco

I hope you remember the whole Trustico fiasco, that Trustico (a TLS certificate reseller) made DigiCert (the new owner of Symantec certificate authority) revoke ~23k certificates. To get a certificate from a CA or a reseller, you don't have to send the private key. However, Trustico had a tool that generated the private keys for customers and stored them. They still offered certificates over a regular CSR as well, and from what Trustico claims, they stored the private keys in a "cold storage".

Let me quote one point in Trustico's statement that I almost spilled my tea over and wanted to write this quick post:

As the only party other than Trustico® with access to the serial numbers for each certificate, only DigiCert® was able to undertake a match of the keys provided to issued certificates (by reference to serial numbers). Trustico® believes there were no security concerns for customers in what it did. Providing the private key and serial number would have been a security concern; the provision of one but not the other did not present a risk;

All other points of that post aside, I'd like to point out that this is not true. In fact, it's as easy as 1-2-3!

How to find certificates relating to a given private key

Every HTTPS certificate contains the public key that browser can use to establish a secure connection with the server. This public key can be easily derived from the private key. Once we have the public key, we can find certificates with a matching public key.

We use OpenSSL, because it's widely available. Refer to your relevant documentation if you want to do this in a different language

1. Get the public key

openssl rsa -in private-key.pem -outform DER -pubout -out public-key.der

We feed in (-in private-key.pem) private-key.pem file as the private key and take out the public key (-pubout) in DER format (-outform DER), and write it to a new file named public-key.der (-out public-key.der).

If you have a ECC key, replace the rsa command above with ec, for example openssl rsa -in private-key.pem -outform DER -pubout -out public-key.der.

2. Calculate the SPKI hash

In each HTTPS certificate, there is an x509v3 field called Subject Public Key Info. This field is simply the hash of the public key in DER format. Because we extracted the DER-formatted public key from the private key in above step, we can now calculate the SHA256 hash:

openssl dgst -sha256 public-key.der

You should see an output like this:

SHA256(public-key.der)= cd9bc7600534c1a352680859e47548dd59a604cd2e4380e4df58352d47c6be56

If we can find all certificates with a matching SPKI hash as same as above, we can find all certificates and their serial numbers.

3. Meet our savior, Certificate Transparency

Certificate Transparency is somewhat new project from Google, that enforces all Certificate Authorities to log every public certificate they issue to a log that they cannot modify later. Once this information is fed into a log, there is no way to update it, and tools like crt.sh and Censys make this information publicly available to search.

In the example above, the hash (cd9bc7600534c1a352680859e47548dd59a604cd2e4380e4df58352d47c6be56) is from a test domain I use, and I have requested a few certificates from Let's Encrypt using the same private key (which produced the same SPKI hash). Lets Encrypt promptly logged the certificates they issued for me, and you can easily look them up from crt.sh results and Censys results.

Was it hard?

Gifs are from giphy.com of Petra from Jane the Virgin.