SSLContext.load_verify_locations(cadata=<DER>) fails with [ASN1: NOT_ENOUGH_DATA] when linked against OpenSSL 3.0.21+
Chưa có ai nhận issue này.
- Ngôn ngữ chính
- Python
- Star
- 77.2k
- Fork
- 35.9k
- Chỉ số merge pull request
- Chỉ số pull request đang chờ
Mô tả
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
Hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Hướng nghiên cứu
Bắt đầu trong Modules/_ssl.c tại _add_ca_certs(), đặc biệt là vòng lặp d2i_X509_bio() và cách xử lý ERR_peek_last_error(). Tái hiện lỗi cadata DER bằng ví dụ ssl được cung cấp, sau đó xác minh rằng chứng chỉ đơn lẻ được tải thành công và việc tải kho tin cậy của ngữ cảnh mặc định trên Windows hoạt động với cách xử lý EOF đã được cập nhật.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Đánh giá
- Công nghệ
- python
- Lĩnh vực
- security
- Loại issue
- Lỗi
- Độ khó
- 3/5
- Thời gian dự kiến
- 1-2 ngày
- Mức độ hoạt động
- Sôi nổi
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức phù hợp với người mới
- 74/100