错误信息
[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: Basic Constraints of CA cert not marked critical
只有启用了严格检查的客户端才会打印这条消息:默认启用严格检查的 Python 3.13 及更高版本,以及 openssl verify -x509_strict。Python 还会附加源代码位置,例如“(_ssl.c:1082)”。
Python 3.13+ ssl module — VERIFY_X509_STRICT in create_default_context(), X509_V_ERR_CA_BCONS_NOT_CRITICAL
含义
Python 3.13+ 使用 OpenSSL 的严格 X.509 模式进行验证,该模式强制执行 RFC 5280 的规定:CA 证书的 basicConstraints 扩展必须标记为关键(critical)。你的证书链中的 CA 带有 basicConstraints CA:TRUE,但没有 critical 标志,因此即使这个 CA 受信任,OpenSSL 也会拒绝这条证书链。
原因
创建 CA 时使用的配置模板没有“critical”
常见OpenSSL 配置中写成 basicConstraints = CA:TRUE(而不是 critical,CA:TRUE)的配置节,或者使用不合规模板的 CA 工具,都会生成这样的 CA 证书。
客户端升级到了 Python 3.13 或更高版本
常见更早的 Python 版本不设置 VERIFY_X509_STRICT,所以在升级之前,同一个 CA 一直能正常使用。
证书链中的某个中间 CA 有这个缺陷
偶见这项检查适用于路径中的每一张 CA 证书,包括由合规根证书签发的中间证书。
修复方法
- 1.
找出不合规的证书
输出证书链中每张 CA 证书的 basicConstraints;没有“critical”的那张必须重新签发。openssl verify -x509_strict 会显示所有严格模式下的问题。
bash openssl x509 -in ca.pem -noout -ext basicConstraints # X509v3 Basic Constraints: <- no "critical" here is the problem # CA:TRUE openssl verify -x509_strict -CAfile ca.pem server.pem - 2.
重新签发 CA,并把 basicConstraints 标记为关键扩展
重新签名 CA 证书,设置 basicConstraints = critical, CA:TRUE,并添加 keyUsage 扩展。保持密钥和主体不变,现有证书就仍能通过它验证。
bash 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 - 3.
临时规避方案:清除 VERIFY_X509_STRICT
在修复 CA 期间,为单个上下文恢复 3.13 之前的行为。证书链、有效期和主机名的验证仍然保持开启。
python # Temporary workaround until the CA is reissued (chain, dates and name are still checked) import ssl ctx = ssl.create_default_context(cafile="ca.pem") ctx.verify_flags &= ~ssl.VERIFY_X509_STRICT