エラーメッセージ
verify error:num=21:unable to verify the first certificate
別の表記
- Verify return code: 21 (unable to verify the first certificate)
openssl s_client は「verify error:num=21:…」および「Verify return code: 21 (…)」と出力します。Node.js は同じ状況を UNABLE_TO_VERIFY_LEAF_SIGNATURE(「unable to verify the first certificate」)として報告します。
OpenSSL CLI (openssl s_client) — X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE
このエラーの意味
OpenSSL のエラー 21(X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE)は、チェーンがサーバー自身の証明書 1 つだけで構成されていて、その発行者が見つからないため、リーフ証明書の署名さえ検証できないことを示します。s_client は通常、その直前に depth 0 についてエラー 20 を出力します。解決策はほぼ必ずサーバー側にあり、サーバーは中間証明書を送信しなければなりません。
発生する理由
サーバーにリーフ証明書だけが設定されている
よくあるfullchain.pem ではなく cert.pem を指定している場合、チェーンなしで証明書をロードバランサーに貼り付けた場合、発行元の CA なしで Java のキーストアにエントリをインポートした場合などが該当します。
チェーンは設定されているが送信されていない
ときどき一部のサーバーでは、チェーンを別のディレクティブやフィールドに指定する必要があります(古い Apache の SSLCertificateChainFile、クラウドのロードバランサーのチェーン入力欄など)。間違った場所に置いたバンドルは、何も通知されずに無視されます。
サーバーがリーフ証明書を発行していない中間証明書を送信している
ときどきCA が中間証明書を切り替えた後も古いチェーンファイルを使っていると、リーフ証明書の発行者ではない証明書が送信されます。OpenSSL はその証明書を使えません。
修正方法
- 1.
サーバーが送信しているものを確認する
証明書が 1 つだけで、その発行者(i:)が中間 CA であれば、この問題であることが確定します。
bash openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts </dev/null 2>/dev/null \ | grep -E '^ *[0-9]+ s:|^ *i:' - 2.
リーフ証明書と中間証明書を返す
リーフ証明書と、それを発行した中間証明書を順番に連結し、そのファイルをサーバーに設定してください。バンドルの内容を出力して、順序を確認してください。
bash # Build the file the server should use: leaf, then intermediates (issuer of each previous one) cat server.pem intermediate.pem > fullchain.pem openssl crl2pkcs7 -nocrl -certfile fullchain.pem | openssl pkcs7 -print_certs -noout # check the order - 3.
正しい中間証明書を見つける
リーフ証明書の Authority Information Access 拡張には、発行者の証明書の URL が記載されています。その証明書をダウンロードし、必要に応じて PEM に変換して、チェーンファイルに追加してください。
bash # Where to download the missing intermediate: the leaf's Authority Information Access URL openssl x509 -in server.pem -noout -ext authorityInfoAccess curl -sS -o intermediate.der http://ca.example.com/issuing-ca.crt openssl x509 -inform der -in intermediate.der -out intermediate.pem