How-to guide · Inspect and check

How to check that a private key matches a certificate

In one sentence

You will have proved, without exposing the key, that a private key, its CSR and a certificate share one public key, or found the file that does not belong.

Task
Inspect and check
Platforms
  • Linux
  • macOS
  • Windows
  • Java
Who it is for
Level
Practitioner · 8 steps
On this page
  1. Before you start
  2. Steps
  3. 1. Hash the certificate’s public key
  4. 2. Hash the public key inside the private key
  5. 3. Hash the CSR’s public key (optional)
  6. 4. Compare
  7. 5. Find the right certificate in a folder
  8. 6. The older modulus method (RSA only)
  9. 7. On Windows
  10. 8. In a Java keystore
  11. Check it worked
  12. If something goes wrong
  13. Why this works
  14. Go deeper

Before you start

  • OpenSSL 1.1.1 or later (Linux, macOS with Homebrew, or Git Bash on Windows).
  • The files: the certificate, the private key and, if you have it, the CSR. If the key is encrypted, its pass phrase.
  • A safe place to work: the server that holds the key, or your own machine. Never paste a private key into a website, a chat or a ticket. Everything below runs locally.

Why check? A certificate is only useful with the key whose public half it contains. Mix-ups are common after a renewal, when several keys and CSRs lie in one folder, or when a CA reissues a certificate. The result is a server that refuses to start, often during a maintenance window.

Steps

A key pair shares one public key. The certificate and the CSR both contain that public key, and OpenSSL can derive it from the private key. So you compare public keys, never private ones. The method works the same for RSA, ECDSA and Ed25519 keys.

1. Hash the certificate’s public key

openssl x509 -in www.crt -noout -pubkey | openssl pkey -pubin -outform DER | openssl sha256
SHA2-256(stdin)= 563a06090f0794f4764bd0a5e78913b54e404d7d241f249dfb3e8469173de71e

-pubkey extracts the public key, openssl pkey -pubin -outform DER turns it into its binary form, and openssl sha256 gives a short value that is easy to compare.

2. Hash the public key inside the private key

openssl pkey -in www.key -pubout -outform DER | openssl sha256
SHA2-256(stdin)= 563a06090f0794f4764bd0a5e78913b54e404d7d241f249dfb3e8469173de71e

-pubout writes only the public half, so nothing secret is printed. If the key is encrypted (-----BEGIN ENCRYPTED PRIVATE KEY-----), OpenSSL asks for its pass phrase first.

3. Hash the CSR’s public key (optional)

openssl req -in www.csr -noout -pubkey | openssl pkey -pubin -outform DER | openssl sha256
SHA2-256(stdin)= 563a06090f0794f4764bd0a5e78913b54e404d7d241f249dfb3e8469173de71e

4. Compare

The three values are identical, so the key, the CSR and the certificate belong together. Here is the same check with another RSA key from the same folder:

openssl pkey -in other-rsa.key -pubout -outform DER | openssl sha256
SHA2-256(stdin)= e730a261ddfc48e58154dec4b4708ba6fbcbd8030be4ed22800222e9bc24cded

Different value, different key. There is no “partly matching”: either the public keys are identical or the files do not belong together.

5. Find the right certificate in a folder

When a CA sends several files, or a folder holds old and new certificates, test them all against one key:

want=$(openssl pkey -in www.key -pubout -outform DER | openssl sha256 -r | cut -d' ' -f1)
for f in *.crt; do
  have=$(openssl x509 -in "$f" -noout -pubkey | openssl pkey -pubin -outform DER | openssl sha256 -r | cut -d' ' -f1)
  [ "$have" = "$want" ] && echo "MATCH     $f" || echo "no match  $f"
done
no match  int.crt
no match  old.crt
no match  root.crt
MATCH     www.crt

6. The older modulus method (RSA only)

Many older guides compare the RSA modulus:

openssl x509 -in www.crt -noout -modulus | openssl sha256
openssl rsa -in www.key -noout -modulus | openssl sha256

It works for RSA, but not for EC keys, where OpenSSL prints Modulus=No modulus for this public key type. The public-key method above covers every key type.

7. On Windows

For a PFX file, certutil loads the key and tests it against each certificate inside:

certutil -dump www.pfx
================ Certificate 1 ================
...
Subject: CN=www.example.com, O=Example Shop, C=BE
...
  Provider = Microsoft Enhanced Cryptographic Provider v1.0
Encryption test passed

certutil asks for the PFX password. Encryption test passed means the key in the file works with that certificate’s public key. For a certificate already in the computer’s store, certutil -verifystore My <serial number> runs the same test against the linked key. In PowerShell, HasPrivateKey only tells you that a key is linked, not that it is the right one.

8. In a Java keystore

keytool checks the match itself when you import the CA’s reply into the alias that holds your key. A certificate for a different key is refused:

keytool -importcert -alias www -file www.crt -keystore keystore.p12
keytool error: java.lang.Exception: Public keys in reply and keystore don't match

If the import succeeds, keytool -list shows the alias as a PrivateKeyEntry with the certificate’s fingerprint. How to create a CSR with Java keytool covers the whole flow.

Check it worked

Load the pair the way a server would. openssl s_server refuses a key that does not match, just like nginx, Apache and most other OpenSSL-based servers:

openssl s_server -accept 127.0.0.1:8443 -cert www.crt -key other-rsa.key -www
error setting private key
...:x509 certificate routines:ossl_x509_check_private_key:key values mismatch:...

With the right key, it prints ACCEPT and waits for connections; stop it with Ctrl+C. You can also ask OpenSSL to check the key’s internal consistency with openssl pkey -in www.key -check -noout, which prints Key is valid.

If something goes wrong

  • The hashes differ: the certificate was issued for another key, usually from an older or newer CSR. Find the key that matches (step 5). If it is lost, create a new key and CSR (with OpenSSL, on Windows or with keytool) and ask the CA to reissue. A certificate cannot be edited to fit another key.
  • The same files give different hashes on two machines: you hashed PEM text. Use the DER form, as above.
  • Could not find private key of key from … (OpenSSL 3.2) or Could not read key from … (3.0): the file is not a private key, or the pass phrase was wrong (bad decrypt). A PFX needs converting first: How to convert PFX to PEM.
  • A server or library refuses the pair: OpenSSL reports key values mismatch when both keys are the same type, and Python reports [X509: KEY_VALUES_MISMATCH] key values mismatch. openssl pkcs12 -export says No cert in -in file 'www.crt' matches private key. All mean the same thing.
  • IIS shows the certificate but cannot use it: the request was completed on a different computer from the one that made the CSR, so the key is not there. See How to create a CSR on Windows.

Why this works

In public-key cryptography, the public key is derived from the private key, and a certificate is a CA’s signed statement that binds a name to one public key. If the public key in the certificate equals the one derived from your private key, the server can prove possession of the key that the certificate names, which is exactly what clients check in the TLS handshake. Key pairs explains the relationship, Asking for a certificate explains how the CSR carries the public key to the CA, and Anatomy of an X.509 certificate shows where it sits in the certificate.

Go deeper

Early edition. Checked against the standards; an independent expert review is in progress. Found a mistake? Tell us.

Last reviewed Edition 0.9