<!-- https://pkizerotohero.com/guides/check-key-matches-certificate/ | Markdown mirror of the HTML page | PKI Zero to Hero, by Duyutech BV -->

> Check that a private key matches a certificate or CSR by comparing public-key hashes with OpenSSL, with Windows certutil and Java keytool checks too.

Source: https://pkizerotohero.com/guides/check-key-matches-certificate/ · Last reviewed: 2026-10-20

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](https://pkizerotohero.com/guides/#task-inspect)

Platforms

- Linux
- macOS
- Windows
- Java

Who it is for

- [IT ops](https://pkizerotohero.com/start/#itops)
- [Developer](https://pkizerotohero.com/start/#developer)
- [Expert](https://pkizerotohero.com/start/#expert)

Level

Practitioner · 8 steps

## 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](https://pkizerotohero.com/handbook/glossary/#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](https://pkizerotohero.com/handbook/glossary/#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

```bash
openssl x509 -in www.crt -noout -pubkey | openssl pkey -pubin -outform DER | openssl sha256
```

```text
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

```bash
openssl pkey -in www.key -pubout -outform DER | openssl sha256
```

```text
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)

```bash
openssl req -in www.csr -noout -pubkey | openssl pkey -pubin -outform DER | openssl sha256
```

```text
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:

```bash
openssl pkey -in other-rsa.key -pubout -outform DER | openssl sha256
```

```text
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.

Note

Why hash the DER form?

You can hash the PEM text instead (leave out `openssl pkey -pubin -outform DER`), and it works on one machine. But OpenSSL in Git Bash on Windows writes PEM with Windows line endings, so the same key gave `748be954…` on Linux and `fad63bad…` in Git Bash. The DER bytes are the same everywhere, which matters when you compare a value from a colleague’s machine.

### 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:

```bash
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
```

```text
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:

```bash
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:

```powershell
certutil -dump www.pfx
```

```text
================ 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:

```bash
keytool -importcert -alias www -file www.crt -keystore keystore.p12
```

```text
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](https://pkizerotohero.com/guides/create-csr-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:

```bash
openssl s_server -accept 127.0.0.1:8443 -cert www.crt -key other-rsa.key -www
```

```text
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](https://pkizerotohero.com/guides/create-csr-openssl/), [on Windows](https://pkizerotohero.com/guides/create-csr-windows/) or [with keytool](https://pkizerotohero.com/guides/create-csr-java-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](https://pkizerotohero.com/guides/convert-pfx-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](https://pkizerotohero.com/guides/create-csr-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](https://pkizerotohero.com/handbook/key-pairs/) explains the relationship, [Asking for a certificate](https://pkizerotohero.com/handbook/csr/) explains how the CSR carries the public key to the CA, and [Anatomy of an X.509 certificate](https://pkizerotohero.com/handbook/x509-certificates/) shows where it sits in the certificate.

## Go deeper

- [OpenSSL `pkey` manual](https://docs.openssl.org/master/man1/openssl-pkey/): `-pubout`, `-check` and output formats.
- [OpenSSL `x509` manual](https://docs.openssl.org/master/man1/openssl-x509/): `-pubkey` and `-modulus`.
- [RFC 5280, section 4.1.2.7](https://www.rfc-editor.org/rfc/rfc5280#section-4.1.2.7): the Subject Public Key Info field.
- [RFC 2986](https://www.rfc-editor.org/rfc/rfc2986): the PKCS #10 CSR format, which carries the same public key.
- [Microsoft Learn: certutil](https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/certutil): `-dump` and `-verifystore`.
- [Oracle: keytool](https://docs.oracle.com/en/java/javase/21/docs/specs/man/keytool.html): importing a certificate reply.

**Early edition.** Checked against the standards; an independent expert review is in progress. Found a mistake? [Tell us](https://pkizerotohero.com/contact/?topic=content-error&page=/guides/check-key-matches-certificate/).

Last reviewed 20 October 2026Edition 0.9

## Keep going

### Learn why it works

- [Chapter 3: Key pairs: public and private keys](https://pkizerotohero.com/handbook/key-pairs/)
- [Chapter 10: Asking for a certificate: key generation and the CSR](https://pkizerotohero.com/handbook/csr/)
- [Chapter 8: Anatomy of an X.509 certificate](https://pkizerotohero.com/handbook/x509-certificates/)

### Topics

- [Certificates](https://pkizerotohero.com/topics/certificates/)
- [Hashes and signatures](https://pkizerotohero.com/topics/signing/)

## More guides: Inspect and check

- [How to inspect a certificate with OpenSSL](https://pkizerotohero.com/guides/inspect-certificate-openssl/)
- [How to check the certificate chain a server sends](https://pkizerotohero.com/guides/check-remote-certificate-chain/)
