How would I get the hash of a public certificate's info to be able to perform SSL Pinning in my application?
I am using TrustKit in my iOS application and it is asking for me to set the hash that I am expecting. Where can I get this from?
How would I get the hash of a public certificate's info to be able to perform SSL Pinning in my application?
I am using TrustKit in my iOS application and it is asking for me to set the hash that I am expecting. Where can I get this from?
There is a really straight forward way of doing this. I spent some time scraping things together on this one to produce a very reusable solution. Unfortunately, I have only done this on OSX, but you should be able to follow along fairly easy if you're on another OS.
For this method you are going to need:
Install Homebrew
OpenSSL (
brew install openssl
in terminal after installing Homebrew)Create new .sh file and set contents to be:
openssl s_client -servername $1 -connect $1:443 | openssl x509 -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
Save file to disk
From terminal window, call
bash <new sh file directory> www.google.com
This should now return the hash that you require and leave you with a nice little reusable solution. You may have to press ctrl+c after the hash is returned.
It should leave you with something like the following:
Hope this helps someone out.
Thanks
Since this is a programming web-site, i wanted to explain how to calculate the public key hash for Public Key Pinning. This is important because the algorithm is completely undocumented. (It's not even documented by the canonical RFC 7469- Public Key Pinning Extension for HTTP!)
tl;dr:
Base64(SHA256(SubjectPublicKeyInfo))
A Certificate is not (just) a public key
The first important thing to realize is that a public key is just a number (e.g. 2,048 bit number for RSA). A certificate is a collection of a lot of additional information (subject names, hashes, digital signatures).
This means that:
A public-key pin contains a hash of the public key. It is not the hash of the certificate. This lets you renew certificates while keeping your same public key.
The Certificate structure
We need to extract the public key from a certificate, so we need to know its structure. The structure of a certificate is documented (horribly) in RFC 5280 - Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile
In programming terms, a Certificate is:
And it's the
SubjectPublicKeyInfo
inside thetbsCertificate
that contains what we're after:We need to take the SHA256 of the raw subjectPublicKeyInfo.
That value, base64 encoded, becomes the value we put in our web-server response headers:
For example:
But what do i actually hash?
As an example of calculating the PKP SHA256 hash, i am going to use the current certificate of Facebook.com. You can browse to Facebook, view the certificate, and save it in a base64 encoded DER PEM:
Facebook.cer (PEM DER ASN.1 encoded)
All the above is base64 encoded. Let's decode it into hex:
Facebook.cer (DER ASN.1 encoded)
The above binary is encoded in DER flavor of ASN.1. We can use the excellent javascript ASN.1 decoder to decode it for us:
Which is a lot
But the only part we care about is the SubjectPublicKeyInfo:
If you take just those bytes:
And run them through SHA256, you get:
You then base64 encode that, and you get:
That is the hash that you add to your HTTP response headers:
Cross-check
Our calculated values matches the PKP hash that SSL Labs returns:
You can also paste the original PEM (base64) encoded certificate into https://certpins.appspot.com/pin and confirm that it returns the same PKP hash:
Why SubjectPublicKeyInfo?
A public key is a number (or in the case of RSA a pair of numbers):
Over the years there are a number of ways of storing these two numbers:
SHH:
Xml
PKCS#1
PKCS#1 chose to use the DER flavor of ASN.1 encoding of the following structure:
Later when new public key encryption systems came along, they "borrowed" the RSAPublicKey structure, but prefixed it with an Algorithm ID:
Where AlgorithID for PKCS#1 RSAPublicKey is 1.2.840.113549.1.1.1, which comes from:
This format would then appear in base64 encoded files as:
This is the SubjectPublicKeyInfo that you get the sha256 hash of.
Inside every certificate is a SubjectPublicKeyInfo; even a Windows EFS certificate.
You can use OpenSSL to:
BEGIN PUBLIC KEY
filePeople need to stop treating OpenSSL as a magical crypto box. Too often, people just type in esoteric openssl commands to do something, rather than understanding what they're doing. Even the very RFC on Public Key Pinning doesn't bother to explain what it is, and just tells you to go to the all-knowing openssl. OpenSSL is not the be-all and end-off of encryption management.
If it is a public website, you can use SSL Labs server test which computes and displays the pin.
The Public Key Pinning page over at the Mozilla Developer Network also has commands for obtaining the pin from a key file, a certificate signing request, a certificate or a website (this is the one in @mylogon's answer).