SSLContext.load_verify_locations(cadata=<DER>) fails with [ASN1: NOT_ENOUGH_DATA] when linked against OpenSSL 3.0.21+
还没有人认领这个 Issue。
- 主要语言
- Python
- 星标
- 77.2k
- 派生
- 35.9k
- PR 合并指标
- PR 指标待抓取
描述
Bug report
Bug description:
When CPython is linked against OpenSSL 3.0.21 (and likely any release carrying the CVE-2026-34180 ASN.1 hardening), SSLContext.load_verify_locations(cadata=) raises:
ssl.SSLError: [ASN1: NOT_ENOUGH_DATA] not enough data (_ssl.c:NNNN)
even for a single, perfectly valid DER certificate. On Windows this breaks ssl.create_default_context() outright, because SSLContext._load_windows_store_certs() loads the system trust store via cadata=. The practical effect is that all default-context HTTPS fails (e.g. importing aiohttp, which builds a default context at import time, crashes).
Reproducer (platform-independent)
import ssl
pem = ssl.get_server_certificate(("www.python.org", 443))
der = ssl.PEM_cert_to_DER_cert(pem)
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
ctx.load_verify_locations(cadata=der) # raises [ASN1: NOT_ENOUGH_DATA] on OpenSSL 3.0.21+
print("loaded OK")
OpenSSL 3.0.15 (and earlier): prints loaded OK.
OpenSSL 3.0.21: raises ssl.SSLError: [ASN1: NOT_ENOUGH_DATA].
The certificate itself is fine — calling d2i_X509 directly against the same libcrypto-3.dll parses it successfully; only the path through _ssl fails.
Root cause
In Modules/_ssl.c, _add_ca_certs() reads certs in a loop until d2i_X509_bio() returns NULL, then inspects the leftover error to distinguish a clean end-of-buffer from a real failure. It only accepts ASN1_R_HEADER_TOO_LONG as the benign EOF marker:
} else if ((filetype == SSL_FILETYPE_ASN1) &&
(ERR_GET_LIB(err) == ERR_LIB_ASN1) &&
(ERR_GET_REASON(err) == ASN1_R_HEADER_TOO_LONG)) {
/* EOF ASN1 file, not an error */
ERR_clear_error();
retval = 0;
}
OpenSSL 3.0.21 now reports end-of-buffer as ASN1_R_NOT_ENOUGH_DATA (reason 142) instead of ASN1_R_HEADER_TOO_LONG. That reason isn't whitelisted, so the function falls through to the generic error branch and raises, discarding the load. Confirmed by reading ERR_peek_last_error() after the final d2i_X509_bio() on a single-cert buffer: 0x0680008E = asn1 ... not enough data.
Proposed fix
Treat ASN1_R_NOT_ENOUGH_DATA as a clean EOF alongside ASN1_R_HEADER_TOO_LONG:
} else if ((filetype == SSL_FILETYPE_ASN1) &&
(ERR_GET_LIB(err) == ERR_LIB_ASN1) &&
((ERR_GET_REASON(err) == ASN1_R_HEADER_TOO_LONG) ||
(ERR_GET_REASON(err) == ASN1_R_NOT_ENOUGH_DATA))) {
/* EOF ASN1 buffer, not an error (OpenSSL 3.0.21+ reports the
end-of-data condition as ASN1_R_NOT_ENOUGH_DATA). */
ERR_clear_error();
retval = 0;
}
With this change, load_verify_locations(cadata=...) succeeds, the Windows store loads fully, and TLS verification works again.
Environment
CPython 3.11.15 (self-built, Windows x64, MSVC), linked against self-compiled OpenSSL 3.0.21.
Windows 11.
Also expected to affect any build/version of CPython linked against OpenSSL ≥ 3.0.21 (or whichever release introduced the reason-code change), on any platform, for the DER cadata path.
CPython versions tested on:
3.11
Operating systems tested on:
Windows
贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
调研方向
从 Modules/_ssl.c 中的 _add_ca_certs() 开始,重点查看 d2i_X509_bio() 循环以及对 ERR_peek_last_error() 的处理。使用提供的 ssl 示例重现 DER cadata 失败,然后验证单个证书能够成功加载,并确认在更新后的 EOF 处理下,Windows 默认上下文的信任存储加载能够正常工作。
由索引模型根据 Issue 内容生成。
评估
- 技术栈
- python
- 领域
- security
- Issue 类型
- 缺陷
- 难度
- 3/5
- 预计耗时
- 1-2 天
- 活跃度
- 活跃
- 描述清晰度
- 描述清楚
- 新手友好度
- 74/100