エラーメッセージ
[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: CA cert does not include key usage extension
Python 3.13 以降にアップグレードした後に表示されます。それより前のバージョンは厳格フラグを設定しません。メッセージの後には「(_ssl.c:1082)」のようなソースの位置が続きます。openssl verify -x509_strict は、同じチェックを「error 92 at 1 depth lookup: CA cert does not include key usage extension」と報告します。
Python 3.13+ ssl module — VERIFY_X509_STRICT in create_default_context(), X509_V_ERR_CA_CERT_MISSING_KEY_USAGE (92)
このエラーの意味
Python 3.13 以降、ssl.create_default_context() は OpenSSL の厳格な X.509 チェック(VERIFY_X509_STRICT)を有効にします。そのうちの 1 つは、RFC 5280 が求めるとおり、すべての CA 証明書が、証明書への署名を許可する keyUsage 拡張を持つことを要求します。この CA 証明書には keyUsage がないため、Python 3.12 で動作していたチェーンが、CA を明示的に信頼していても拒否されるようになりました。
発生する理由
単純な openssl req -x509 で作成された CA
よくあるOpenSSL のデフォルト設定は、自己署名証明書に basicConstraints を追加しますが、keyUsage は追加しません。数え切れないほどのガイドがまさにこの方法でプライベート CA を作成しており、一部のテストフィクスチャや開発ツールも同様です。
クライアントが Python 3.13 以降に移行した
よくある証明書は変わっておらず、検証側が厳しくなっただけです。python:3.13+ に切り替えたコンテナーのベースイメージや CI ランナーでは、PKI に何も変更を加えなくてもこの問題が表面化します。
古い社内 PKI やアプライアンスの CA
ときどきアプライアンスが生成した CA 証明書や古い企業向けの CA 証明書の中には、keyUsage を省略しているものがあります。それらは、厳格なチェックを行わないクライアントでは引き続き動作します。
修正方法
- 1.
どの拡張が欠けているかを確認する
CA の basicConstraints と keyUsage を出力し、openssl verify -x509_strict を実行して、厳格モードでの失敗をすべてまとめて確認してください。
bash openssl x509 -in ca.pem -noout -ext basicConstraints,keyUsage # Same strict checks as Python 3.13+, without Python: openssl verify -x509_strict -CAfile ca.pem server.pem - 2.
keyUsage を付けて CA 証明書を再発行する
keyUsage = critical, keyCertSign, cRLSign(および critical の basicConstraints)を付けて、CA に署名し直してください。同じ鍵とサブジェクトを維持すれば、その CA がすでに発行した証明書は、引き続き新しい CA 証明書にチェーンがつながります。新しい CA ファイルをクライアントに配布してください。
bash # A CA certificate with the extensions RFC 5280 requires openssl req -x509 -new -key ca.key -days 3650 -subj "/CN=Example Private CA" \ -addext "basicConstraints=critical,CA:TRUE" \ -addext "keyUsage=critical,keyCertSign,cRLSign" \ -out ca.pem # Reusing the old key and subject keeps already issued certificates verifiable. - 3.
一時的な回避策:このコンテキストに限り VERIFY_X509_STRICT を解除する
フラグを解除すると、1 つのコンテキストに限って Python 3.12 の動作に戻ります。検証を無効にするのと同じではありませんが、RFC 5280 に違反する証明書を受け入れることになります。CA を修正したら、この設定を削除してください。
python # Temporary workaround while the CA is reissued: the chain, dates and host name # are still verified, only the RFC 5280 profile checks are relaxed. import ssl ctx = ssl.create_default_context(cafile="ca.pem") ctx.verify_flags &= ~ssl.VERIFY_X509_STRICT
関連するエラー
[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: Basic Constraints o…Python 3.13+ ssl module[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: Missing Authority K…Python 3.13+ ssl module[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local…Python ssl module (OpenSSL)