Payments are experiencing issues due to temporary restrictions in Russia. If your payment does not go through, please submit a support request.Our support team is available 24/7 — we are always here to help with hosting and server issues.We are now accepting requests for dedicated server rental and colocation services in our data center.Reminder: we recommend enabling backups for additional data protection.A new VPS/VDS lineup with NVMe storage and improved performance is now available.Maintenance work on some servers has been completed. All services are operating normally.
Article6 min readViews0

How to check that a TLS certificate matches its private key

Before reloading, extract the public key from both the certificate and the private key, compare their SHA-256 hashes, and handle read errors separately. Tested with OpenSSL 3.0.13: a matching pair, a different pair, and a damaged file.

Comments 0

A certificate, a metal key, and a server rack before a configuration check
In this article

If a new TLS certificate and private key belong to different pairs, the web server cannot use them together in one configuration. Before reloading, extract the public key from the certificate and from the private key, output both in DER format, and compare their SHA-256 hashes. Matching hashes mean the pair matches. If they differ, do not apply the change: determine the reason for the difference first.

Matching DER representations of the public key confirm that the pair matches, but do not verify the site name, validity period, trust chain, or which certificate the server is already presenting. Different DER representations do not yet prove that the keys differ: the parameter encoding must also be checked. This check does not replace the other stages of TLS acceptance testing.

Prerequisites

  • Linux with OpenSSL 3.x and GNU Coreutils; the commands were tested with OpenSSL 3.0.13.

  • A certificate in the PEM file cert.pem and a private key in private-key.pem. DER or PKCS#12 files require different input options.

  • Read access to the required files only. Do not copy the private key to a shared directory or publish its contents.

  • The check takes place before any configuration change and requires no reload, restart, or network request.

First, make sure both files can be read

Start with the certificate. This command displays the subject, issuer, and dates without changing the file:

openssl x509 -in cert.pem -noout -subject -issuer -dates

Stop if OpenSSL reports that it cannot read the certificate. Check the format, path, and permissions first. Do not hash empty output after an error.

Check the private key structure separately:

openssl pkey -in private-key.pem -check -noout

For an encrypted key, OpenSSL will prompt for a password. Do not put the secret directly in the command for convenience: it may end up in shell history, the process list, or an automation log.

Extract the same object from both files

The openssl x509 command can output the certificate’s public key, while openssl pkey outputs the public part of the private key. DER removes differences in PEM text formatting, allowing the two SHA-256 hashes to be compared. However, DER does not normalize every parameter encoding: for example, the same EC key encoded with a named curve and with explicit parameters can produce different hashes. If the hashes differ, investigate the pair and parameter encoding first; do not reissue the certificate blindly.

Hash of the public key extracted from the certificate:

openssl x509 -in cert.pem -pubkey -noout \ | openssl pkey -pubin -outform DER \ | sha256sum

Hash of the public part extracted from the private key:

openssl pkey -in private-key.pem -pubout -outform DER \ | sha256sum

For the matching pair tested, both commands returned the same SHA-256 hash and exit status 0. With a different valid key, both commands also completed without errors, but the hashes differed. A successful command exit status alone therefore does not prove that the pair matches.

Observation

Conclusion

Action

Both pipelines exited with status 0 and the hashes match

The certificate matches the key

Proceed to the service configuration check

Both pipelines exited with status 0 and the hashes differ

A match has not been confirmed by the DER comparison

Do not apply the change; check the pair and parameter encoding. Select another key or reissue the certificate only after investigating

At least one pipeline exited with a nonzero status

A file could not be parsed or a command failed

Correct the path, format, permissions, or password; do not compare the hashes

A script with pipefail makes comparison safer

When copying commands manually, it is easy to miss an error in the first command of a pipeline. In the training test without pipefail, the damaged certificate reached sha256sum as empty input. This produced the well-known hash of empty data: an apparently ordinary hash string, even though the certificate had not been read.

The minimal check below returns 0 when the SHA-256 hashes of the DER representations match, 1 when they differ, and 2 if the certificate or key cannot be parsed:

set -o pipefail cert_hash="$({ openssl x509 -in cert.pem -pubkey -noout | openssl pkey -pubin -outform DER | sha256sum | awk '{print $1}' })" || exit 2 key_hash="$({ openssl pkey -in private-key.pem -pubout -outform DER | sha256sum | awk '{print $1}' })" || exit 2 if [ "$cert_hash" = "$key_hash" ]; then printf 'MATCH sha256=%s\n' "$cert_hash" exit 0 fi printf 'MISMATCH cert_sha256=%s key_sha256=%s\n' \ "$cert_hash" "$key_hash" exit 1

Run this snippet in a shell that supports pipefail, such as Bash. For automation, retain only the result and exit statuses; the report does not need the contents of the private key.

Results of the reproducible test

Test environment: OpenSSL 3.0.13, Bash, and a temporary directory. I created two separate training RSA key pairs, issued a self-signed certificate valid for two days for each, and ran the scenario twice. No production certificates, keys, or domains were used.

Scenario

Observation

Exit status

cert-a.pem + key-a.pem

MATCH; the same SHA-256 hash

0

cert-a.pem + key-b.pem

MISMATCH; two different SHA-256 hashes

1

Damaged certificate + key-a.pem

OpenSSL could not read the certificate; no comparison was performed

2

openssl pkey -check for key-a.pem

Key is valid

0

Randomly generated keys produce new SHA-256 values on every run, so the relevant findings are whether the hashes match or differ and the exit status, rather than a particular hash string.

Three certificate and key check results: match — 0, mismatch — 1, read error — 2
OpenSSL 3.0.13 training test: a matching pair, a different valid pair, and a damaged certificate produce different results and exit statuses.

Do not confuse the site certificate with the chain

For this comparison, use the site certificate that should match the private key. If a file contains several certificates, explicitly confirm which one the command reads. An intermediate certificate belongs to a certification authority key and will naturally produce a different result.

Do not rearrange certificates in a production fullchain file at random. The order and configuration method depend on the web server and configuration format. Work on a copy first and check the final set of files with the service’s standard validation command.

Limits of this check

  • Matching public keys do not confirm that the certificate is still valid.

  • This check does not verify whether the certificate covers the required DNS name.

  • It does not build a chain to a trusted root certification authority.

  • It does not prove that Nginx, Apache, or the load balancer is already using these exact files.

  • A key in an HSM or external store may not be readable as an ordinary PEM file; follow the key provider’s interface requirements.

  • Do not address a nonzero exit status by weakening permissions or copying a secret to an accessible location without investigating the cause.

The certificate and key match, while the name, dates, chain, configuration, and live TLS connection require separate checks
Matching public keys confirm only that the two files form a pair; the other TLS properties must be checked separately.

What to check before and after applying the change

  1. Before the change: confirm that the pair matches, check the expected subject and dates, back up the current configuration, and confirm the exact file paths.

  2. Before reloading: run the standard configuration test for the specific service, using the same build that serves the site.

  3. After applying the change: check the TLS response from the intended virtual host, including the name, dates, and chain of the certificate actually presented.

  4. With multiple nodes: check each delivery path separately; one successful response does not describe the entire cluster.

For Nginx, first run a configuration check before applying the change. After the change, inspect the certificate presented by a real connection rather than the file on disk; the website SSL check can help with this.

Acceptance criteria

The pair is ready for the next stage when both files can be read individually, the script returns MATCH with exit status 0, the certificate details are as expected, the service configuration passes its own test, and a live connection presents the new certificate after a controlled change. If any step is unconfirmed, continue diagnosing: a reload cannot fix a mismatched pair.

Discussion 0

Share your experience and ask questions. Comments without links appear after editorial review.

No comments yet. Start the discussion.