エラーメッセージ
error:05800074:x509 certificate routines::key values mismatch
別の表記
- x509 certificate routines:ossl_x509_check_private_key:key values mismatch
- [X509: KEY_VALUES_MISMATCH] key values mismatch
- code: 'ERR_OSSL_X509_KEY_VALUES_MISMATCH'
nginx -t は「[emerg] SSL_CTX_use_PrivateKey(\"<key file>\") failed (SSL: error:05800074:x509 certificate routines::key values mismatch)」と報告します。openssl の CLI は関数名を付け加えます(「x509 certificate routines:ossl_x509_check_private_key:key values mismatch」)。Python は「[X509: KEY_VALUES_MISMATCH] key values mismatch」と出力し、Node.js は ERR_OSSL_X509_KEY_VALUES_MISMATCH というコードを設定します。OpenSSL 1.1.1 では 0B080074 というコードでした。
OpenSSL 3 — X509_R_KEY_VALUES_MISMATCH when loading a certificate with a private key (nginx, Node.js, Python, openssl s_server)
このエラーの意味
TLS サーバー(またはライブラリ)に、対応していない証明書と秘密鍵の組み合わせが渡されました。証明書に含まれる公開鍵が、その秘密鍵と対になる公開鍵ではありません。OpenSSL はこの組み合わせの読み込みを拒否するため、サーバーが起動しなかったり、コンテキストを作成できなかったりします。どちらのファイルも、単体では何の問題もありません。
発生する理由
証明書が新しい(または古い)鍵に対して発行されている
よくある更新時に新しい鍵と CSR を作成したのに設定がまだ古い鍵ファイルを指している場合や、新しい証明書を前年の鍵と組み合わせている場合です。
バンドルの先頭がリーフ証明書ではなく中間証明書になっている
よくあるサーバーは、鍵をファイル内の最初の証明書と比較します。中間証明書、リーフ証明書の順に並んだチェーンファイル(またはルートが先頭にあるもの)では、リーフ証明書と鍵が一致していてもこのエラーになります。
別のホストや環境のファイルが混在している
ときどきステージングと本番の間や、1 台のサーバーで扱う複数の名前の間で証明書をコピーしていると、証明書を別のホストの鍵と組み合わせてしまいがちです。
修正方法
- 1.
公開鍵を比較する
証明書から取り出した公開鍵と、秘密鍵から導出した公開鍵のハッシュ値を計算してください。ハッシュ値が同じなら、両者は対応しています。この方法は RSA、EC、Ed25519 のどの鍵でも同じように使えます。
bash # The two hashes must be identical openssl x509 -in server.pem -noout -pubkey | openssl sha256 openssl pkey -in server.key -pubout | openssl sha256 - 2.
バンドルの先頭にリーフ証明書を置く
バンドル内のサブジェクトを一覧表示してください。ホスト名に対応するリーフ証明書が最初に来て、その後に中間証明書が続かなければなりません。
bash # Servers match the key against the FIRST certificate of the file: make it the leaf openssl crl2pkcs7 -nocrl -certfile fullchain.pem | openssl pkcs7 -print_certs -noout | grep subject= cat api.example.com.crt intermediate.crt > fullchain.pem - 3.
複数の鍵から一致するものを探す
証明書の公開鍵のハッシュ値を、候補となる各鍵と比較してください。どれも一致しなければ鍵は失われているため、新しい鍵で証明書を再発行する必要があります。
bash # Which of several keys belongs to the certificate? cert=$(openssl x509 -in server.pem -noout -pubkey | openssl sha256) for k in /etc/ssl/private/*.key; do [ "$(openssl pkey -in "$k" -pubout 2>/dev/null | openssl sha256)" = "$cert" ] && echo "match: $k" done