エラーメッセージ
verify error:num=20:unable to get local issuer certificate
別の表記
- Verify return code: 20 (unable to get local issuer certificate)
- error 20 at 0 depth lookup: unable to get local issuer certificate
s_client はハンドシェイク中に「verify error:num=20:…」を、最後のサマリーに「Verify return code: 20 (…)」を出力し、openssl verify は「error 20 at <depth> depth lookup: …」と出力します。デフォルトでは、s_client は検証エラーの後も処理を続けます。失敗させるには -verify_return_error を追加してください。
OpenSSL CLI (openssl s_client / openssl verify) — X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY
このエラーの意味
OpenSSL のエラー 20(X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY)は、OpenSSL がチェーンの構築中に、発行者が見つからない証明書に行き当たったことを示します。発行者は、サーバーが送信した証明書の中にも、トラストストアの中にもありませんでした。直前に出力される depth の行が、発行者が見つからない証明書を示しています。curl の (60)、Python の CERTIFICATE_VERIFY_FAILED、Node.js の UNABLE_TO_GET_ISSUER_CERT_LOCALLY の背後にあるのも、これと同じコードです。
発生する理由
チェーンがストアにないルートで終わっている
よくあるプライベートなルートや社内のルート(または自身の中間証明書だけを送信する、TLS を検査するプロキシ)が該当します。最も大きい depth の行に、手元に発行者がない中間証明書が示されています。
サーバーが中間証明書を送信していない
よくあるdepth=0 だけが表示され、その発行者が中間 CA になっています。OpenSSL は不足している中間証明書をダウンロードしないため、サーバーが送信しなければなりません。
テストでトラストストアが使われていなかった
ときどき証明書単体で実行した openssl verify や、ca-certificates のないイメージ内の s_client には、チェーンを完成させるためのルートがありません。公開サイトであっても同様です。
修正方法
- 1.
depth の行を確認する
depth 0 はサーバーの証明書で、それより大きい数字はサーバーが送信した中間証明書です。エラーの直前にある最後の depth の行が、発行者が見つからない証明書です。
bash echo | openssl s_client -connect api.example.com:443 -servername api.example.com 2>&1 | grep -E '^depth|verify' # depth=1 CN=Example Corp Issuing CA <- the highest certificate received # verify error:num=20:... <- its issuer is not in the trust store - 2.
想定されるルートでテストする
正しいルートを -CAfile に指定すると(失敗を致命的なエラーにするには -verify_return_error も付けます)、そのルートでチェーンが完成するかどうかがわかります。「Verify return code: 0 (ok)」と表示されれば完成しています。
bash # Verify against a specific root (exit code and "Verify return code: 0 (ok)" confirm it) echo | openssl s_client -connect api.example.com:443 -servername api.example.com \ -CAfile corp-root-ca.pem -verify_return_error 2>&1 | grep 'Verify return code' - 3.
証明書ファイルをオフラインで検証する
openssl verify には、ルートを -CAfile として、中間証明書を -untrusted として渡してください。リーフ証明書だけでは検証できません。
bash # Offline: root as trust anchor, intermediate(s) as untrusted helpers openssl verify -CAfile corp-root-ca.pem -untrusted intermediate.pem server.pem - 4.
ルートをシステムのストアにインストールする
チェーンが正当な理由で社内のルートで終わっている場合は、そのルートをディストリビューションのストアに追加してください。そうすれば、そのマシン上の OpenSSL ベースのツールがルートを信頼するようになります。
bash sudo cp corp-root-ca.pem /usr/local/share/ca-certificates/corp-root-ca.crt sudo update-ca-certificates # openssl reads /etc/ssl/certs by default on Debian/Ubuntu
関連するエラー
verify error:num=21:unable to verify the first certificateOpenSSL CLI (openssl s_client)verify error:num=19:self-signed certificate in certificate chainOpenSSL CLI (openssl s_client / openssl verify)curl: (60) SSL certificate problem: unable to get local issuer certificatecurl (OpenSSL backend)[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local…Python ssl module (OpenSSL)