52

The documentation in the N Developer Preview for their network security configuration offers these instructions:

Certificate pinning is done by providing a set of certificates by hash of the public key (SubjectPublicKeyInfo of the X.509 certificate). A certificate chain is then only valid if the certificate chain contains at least one of the pinned public keys.

The XML that they show is broken (missing a closing tag), but otherwise suggests that the hash is SHA256 and encoded base64:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config>
        <domain includeSubdomains="true">example.com</domain>
        <pin-set expiration="2018-01-01">
            <pin digest="SHA-256">7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=</pin>
            <!-- backup pin -->
            <pin digest="SHA-256">fwza0LRMXouZHRC8Ei+4PyuldPDcf3UKgO/04cDM1oE=</pin>
    </domain-config>
</network-security-config>

How do we create such a hash?

I tried the approach in this gist, but openssl x509 -inform der -pubkey -noout is not liking my CRT file. I cannot readily determine if the problem is in the CRT file, the instructions, my version of openssl, or something else.

Does anyone have a known good recipe for creating this hash?

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491

4 Answers4

115

openssl x509 -in cert.crt -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64

You may need to add -inform der to the first command if cert.crt is in DER form rather than in PEM form.

Alex Klyubin
  • 5,554
  • 2
  • 29
  • 24
  • 5
    I just want to add that the oneliner above is assuming `cert.crt` is in PEM format. If your have the DER format of the certificate, you can do `cat cert.der | openssl dgst -sha256 -binary | openssl enc -base64` without having to do a double conversion. – Devy Nov 09 '18 at 17:10
  • 1
    Perfect it works, in my case It was in DER format so as you suggested I added the -inform der. This is the command I used that generated the proper value: ```openssl x509 -inform DER -in TheCertificate.cer -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64``` – Gal Rom Apr 22 '20 at 10:24
  • 1
    Hi can you please let me know where i need to keep the certificate file for executing this command @GalRom – sanjeev kumar May 14 '20 at 22:44
16

For setting up Android network-security-config pinning for a host that is already live, I prefer gnutls-cli (GnuTLS Client). It outputs a host's certificate info in a form where the sha256 is readibly copy-pasteable as base64 encoded. For example:

$ gnutls-cli stackoverflow.com </dev/null
<...>
 - subject `CN=*.stackexchange.com,O=Stack Exchange\, Inc.,L=New York,ST=NY,C=US', issuer `CN=DigiCert SHA2 High Assurance Server CA,OU=www.digicert.com,O=DigiCert Inc,C=US', serial 0x0e11bbd70d54b710d0c6f540b6b52ca4, RSA key 2048 bits, signed using RSA-SHA256, activated `2016-05-21 00:00:00 UTC', expires `2019-08-14 12:00:00 UTC', pin-sha256="2zKehMv7KtnGBz1d2U0bFrAOKb1aWWlrG9a0BzrOvwA="
laalto
  • 150,114
  • 66
  • 286
  • 303
  • Thanks, was in fact way easier! If you want the pin just without the other (in this case) non-interesting mess: `gnutls-cli YOUR_PINNING_DOMAIN_HERE 2>/dev/null | grep -A 1 "Public Key PIN"` – Rafael T Apr 09 '19 at 15:34
  • 1
    is there any verisoning? i do not get the sha256 fingerprint. – Mike Aron Feb 27 '21 at 13:31
2

For anyone who needs to pin the entire certificate chain these are the steps I took, on a Windows 10 machine that luckily has Anaconda installed.

  1. Save the certificate file from Chrome or Edge. Choosing the option to save as (.P7B) and make sure check "Include all certificates.."

  2. Double click the file. This should launch windows certmgr.

  3. You should now see the cert chain entries once you click on Certificates

  4. Right click on each cert chain entry. Choose all tasks and export.

  5. Choose DER encoded (.CER)

  6. Repeat for each ( noting hierarchy)

  7. Start an Anaconda Prompt.

  8. Now run @Alex Klyubin / @Gal Rom (above) excellent commands for each file.

    openssl x509 -inform DER -in prod_root.cer -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64

  9. For each of the file produced. The output will the sha256 desired

Hope this helps someone. I was very stuck trying to extract the whole chain. I am sure there are better ways to do this but it has worked.

Isd Sava
  • 196
  • 1
  • 7
1

Use this to get base64 sha256 of online https url:

openssl s_client -connect google.com:443 < /dev/null 2>/dev/null | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
SaEEd
  • 41
  • 2