サーバーに設定する秘密鍵と証明書が、ペアとして正しいか確認したいときは、それぞれから公開鍵を取り出して比較する。
$ diff <(openssl pkey -in server.key -pubout) <(openssl x509 -in server.crt -noout -pubkey) && echo MATCH
MATCH
秘密鍵と証明書の公開鍵が一致すれば、MATCHと表示される。一致しない場合は、diffが差分を出力して、MATCHは表示されない。
<(...)はプロセス置換で、bashやzshで使える。実行例はUbuntu 24.04のOpenSSL 3.0.13のもの。
公開鍵のハッシュ値で比較する
プロセス置換が使えない環境や、比較結果をログに残したい場合は、公開鍵のハッシュ値を比較する。
$ openssl pkey -in server.key -pubout | openssl dgst -sha256
SHA2-256(stdin)= 146e1e183da1299e3d7853b03e191eafd68244ddeaa8319d2b3f717783ec1e9f
$ openssl x509 -in server.crt -noout -pubkey | openssl dgst -sha256
SHA2-256(stdin)= 146e1e183da1299e3d7853b03e191eafd68244ddeaa8319d2b3f717783ec1e9f
ハッシュ値が同じであれば、対応している。ハッシュ値が異なる場合は、別の鍵から作られた証明書である。
$ openssl pkey -in other.key -pubout | openssl dgst -sha256
SHA2-256(stdin)= c1178968f53100d192cb9be7dcae135451536fb458c611a4f221516e091b811b
ハッシュ値は、公開鍵をPEM形式で出力した結果に対して計算している。公開鍵のハッシュ値は秘密情報ではないため、ログに残してもよい。
参考: 【openssl】ファイルのハッシュ値を計算する (dgst)
何を比較しているか
秘密鍵のファイルには、公開鍵を計算するために必要な情報が含まれている。openssl pkey -puboutは、秘密鍵から公開鍵を取り出す。証明書には公開鍵が含まれており、openssl x509 -pubkeyで取り出せる。
graph LR
K[秘密鍵] -->|pkey -pubout| P1[公開鍵]
C[証明書] -->|x509 -pubkey| P2[公開鍵]
P1 --- M{一致するか}
P2 --- M
秘密鍵とCSR、証明書とCSRの対応も、同じ方法で確認できる。CSRの公開鍵はopenssl req -noout -pubkeyで取り出す。
$ openssl req -in server.csr -noout -pubkey | openssl dgst -sha256
SHA2-256(stdin)= 146e1e183da1299e3d7853b03e191eafd68244ddeaa8319d2b3f717783ec1e9f
参考: 【openssl】秘密鍵から公開鍵を取り出す (pkey)
鍵の種類によらず使える
openssl pkeyとopenssl x509 -pubkeyは、鍵の種類を問わない。RSAだけでなく、ECDSAやEd25519の鍵でも同じ方法で比較できる。
$ openssl pkey -in ec.key -pubout | md5sum
f8d30a23db9ed4463ae717e58607825f -
$ openssl x509 -in ec.crt -noout -pubkey | md5sum
f8d30a23db9ed4463ae717e58607825f -
パスフレーズ付きの秘密鍵を比較する
パスフレーズで保護された秘密鍵は、-passinでパスフレーズを渡す。
$ openssl pkey -in server-enc.key -passin env:KEY_PW -pubout | openssl dgst -sha256
-passinを省略すると、対話的に入力を求められる。
証明書と秘密鍵を1つのファイルにまとめている場合
server.pemのように、証明書と秘密鍵を1つのファイルにまとめている場合も、同じファイルを両方のコマンドに渡せる。
$ openssl x509 -in combined.pem -noout -pubkey | openssl dgst -sha256
$ openssl pkey -in combined.pem -pubout | openssl dgst -sha256
複数の証明書を連結したファイルに対してopenssl x509を実行すると、先頭の1枚だけを処理する。サーバー証明書が先頭にあることを確認する。
署名で確認する
公開鍵の比較のほかに、秘密鍵で署名した結果を、証明書の公開鍵で検証する方法もある。
$ echo test > t.txt
$ openssl dgst -sha256 -sign server.key -out t.sig t.txt
$ openssl x509 -in server.crt -noout -pubkey > server.pub
$ openssl dgst -sha256 -verify server.pub -signature t.sig t.txt
Verified OK
対応していない証明書の公開鍵で検証すると、Verification failureになる。
$ openssl dgst -sha256 -verify other.pub -signature t.sig t.txt
Verification failure
署名を使う方法は手順が多い。確認だけが目的であれば、公開鍵の比較を使う。
RSAではmodulusを比較する方法もある
古い記事では、RSAのmodulus(公開鍵の一部)を比較する方法がよく紹介されている。
$ openssl x509 -in server.crt -noout -modulus | openssl md5
$ openssl rsa -in server.key -noout -modulus | openssl md5
$ openssl req -in server.csr -noout -modulus | openssl md5
3つのハッシュ値が一致すれば対応している。ただし、modulusはRSAの鍵にしかないため、ECDSAやEd25519の証明書では使えない。
$ openssl x509 -in ec.crt -noout -modulus
Modulus=No modulus for this public key type
また、modulusはRSAの公開鍵の一部でしかなく、公開指数などは比較できない。公開鍵全体を比較できるpkey -puboutのほうが確実である。
サーバーの起動時に検出される
openssl s_serverなどは、起動時に証明書と秘密鍵の対応を検証して、一致しない場合はエラーで終了する。
$ openssl s_server -accept 4433 -cert a.crt -key b.key -www
error setting private key
...error:05800074:x509 certificate routines:X509_check_private_key:key values mismatch...
Webサーバーの設定を変更する前に、公開鍵の比較で確認しておくと、設定後の起動失敗を避けられる。
バージョンによる違い
OpenSSL 3.6でも、ここまでの例は同じように動く。
macOS標準の/usr/bin/openssl(LibreSSL 3.3.6)でも、pkey -puboutとx509 -pubkeyの比較は動作する。modulusによる比較も使える。Ed25519の証明書は、LibreSSL 3.3.6が対応していないため、公開鍵を取り出せない。
