本文へスキップ
ecdsa.com
Python 3.13+ ssl modulePython の cryptography

エラーメッセージ

[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 を明示的に信頼していても拒否されるようになりました。

発生する理由

修正方法

  1. 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. 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. 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

関連するエラー

署名エラーデータベースをすべて見る