# The certificate's public key as SubjectPublicKeyInfo PEM ("BEGIN PUBLIC KEY")openssl x509 -in cert.pem -noout -pubkey > pub.pemcat pub.pem # SHA-256 of the SPKI: the key's fingerprint, and (base64) the pin HPKP-style pinning usesopenssl pkey -pubin -in pub.pem -outform DER | openssl dgst -sha256 -copenssl pkey -pubin -in pub.pem -outform DER | openssl dgst -sha256 -binary | base64# Does key.pem belong to this certificate? Compare the public halves.if [ "$(openssl x509 -in cert.pem -noout -pubkey)" = "$(openssl pkey -in key.pem -pubout)" ]; then echo "key.pem matches cert.pem"fiHow it works
openssl x509 -noout -pubkeyprints the certificate's SubjectPublicKeyInfo — algorithm identifier plus key — as-----BEGIN PUBLIC KEY-----, the format every library imports.openssl pkey -pubin -outform DERturns it into DER; SHA-256 over those bytes is the key fingerprint (45:ca:a7:e3:…:7b:5fhere), and its base64 (Rcqn43J0…e18=) is the pin used by SPKI pinning (Android network security config, OkHttp, the former HPKP).- A private key belongs to a certificate when its public half is the same SPKI: compare
openssl pkey -in key.pem -puboutwith the certificate's-pubkeyoutput, as the second snippet does. - The certificate in the run is a P-256 leaf; the same commands work for RSA, Ed25519 and other keys.
Gotchas
openssl x509 -fingerprinthashes the whole certificate (CD:B1:A1:40…), not the key — it changes at every renewal, while the SPKI hash stays the same as long as the key does.- Without
-noout,openssl x509 -pubkeyprints the public key and then the certificate (2 PEM blocks in the run); scripts that save the output get both.