From a2105f5a5f3c1404328cbbda5d7ae269ee82aa8b Mon Sep 17 00:00:00 2001 From: Eric Lundby Date: Wed, 10 Jun 2026 19:37:33 -0600 Subject: [PATCH 1/3] Backport 100373 --- recipe/meta.yaml | 2 + ...-DER-EOF-detection-for-openssl-3.5.7.patch | 68 +++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 recipe/patches/0028-Fix-ssl-DER-EOF-detection-for-openssl-3.5.7.patch diff --git a/recipe/meta.yaml b/recipe/meta.yaml index 99a85fa9f..6a0a72f9e 100644 --- a/recipe/meta.yaml +++ b/recipe/meta.yaml @@ -89,6 +89,8 @@ source: - patches/0026-Use-OpenSSL-1_1-instead-of-3.patch {% endif %} - patches/0027-Unvendor-expat.patch + # https://github.com/python/cpython/pull/100373 (OpenSSL 3.5.7 Windows cert-store fix) + - patches/0028-Fix-ssl-DER-EOF-detection-for-openssl-3.5.7.patch build: number: {{ build_number }} diff --git a/recipe/patches/0028-Fix-ssl-DER-EOF-detection-for-openssl-3.5.7.patch b/recipe/patches/0028-Fix-ssl-DER-EOF-detection-for-openssl-3.5.7.patch new file mode 100644 index 000000000..2633f6994 --- /dev/null +++ b/recipe/patches/0028-Fix-ssl-DER-EOF-detection-for-openssl-3.5.7.patch @@ -0,0 +1,68 @@ +From 863a0a7badf3919c4a710df67e98dbf5db0a2690 Mon Sep 17 00:00:00 2001 +From: David Benjamin +Date: Tue, 20 Dec 2022 10:36:19 -0500 +Subject: [PATCH 28/28] Fix ssl DER EOF detection for openssl 3.5.7 + +In PEM, we need to parse until error and then suppress +PEM_R_NO_START_LINE, because PEM allows arbitrary leading and trailing +data. DER, however, does not. Parsing until error and suppressing +ASN1_R_HEADER_TOO_LONG doesn't quite work because that error also +covers some cases that should be rejected. + +Instead, check BIO_eof early and stop the loop that way. + +Backported for OpenSSL 3.5.7 compatibility on Windows (openssl 3.5.7 +returns ASN1_R_NOT_ENOUGH_DATA at DER EOF instead of ASN1_R_HEADER_TOO_LONG). +--- + Lib/test/test_ssl.py | 2 ++ + Modules/_ssl.c | 10 ++++++---- + 2 files changed, 8 insertions(+), 4 deletions(-) + +diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py +index d4eb2d2e81..f251dff95c 100644 +--- a/Lib/test/test_ssl.py ++++ b/Lib/test/test_ssl.py +@@ -1546,6 +1546,8 @@ class ContextTests(unittest.TestCase): + "not enough data: cadata does not contain a certificate" + ): + ctx.load_verify_locations(cadata=b"broken") ++ with self.assertRaises(ssl.SSLError): ++ ctx.load_verify_locations(cadata=cacert_der + b"A") + + @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows") + def test_load_dh_params(self): +diff --git a/Modules/_ssl.c b/Modules/_ssl.c +index 8f03a846ae..c740decd66 100644 +--- a/Modules/_ssl.c ++++ b/Modules/_ssl.c +@@ -3968,7 +3968,7 @@ _add_ca_certs(PySSLContext *self, const void *data, Py_ssize_t len, + { + BIO *biobuf = NULL; + X509_STORE *store; +- int retval = -1, err, loaded = 0; ++ int retval = -1, err, loaded = 0, was_bio_eof = 0; + + assert(filetype == SSL_FILETYPE_ASN1 || filetype == SSL_FILETYPE_PEM); + +@@ -3996,6 +3996,10 @@ _add_ca_certs(PySSLContext *self, const void *data, Py_ssize_t len, + int r; + + if (filetype == SSL_FILETYPE_ASN1) { ++ if (BIO_eof(biobuf)) { ++ was_bio_eof = 1; ++ break; ++ } + cert = d2i_X509_bio(biobuf, NULL); + } else { + cert = PEM_read_bio_X509(biobuf, NULL, +@@ -4031,9 +4035,7 @@ _add_ca_certs(PySSLContext *self, const void *data, Py_ssize_t len, + } + _setSSLError(get_state_ctx(self), msg, 0, __FILE__, __LINE__); + retval = -1; +- } else if ((filetype == SSL_FILETYPE_ASN1) && +- (ERR_GET_LIB(err) == ERR_LIB_ASN1) && +- (ERR_GET_REASON(err) == ASN1_R_HEADER_TOO_LONG)) { ++ } else if ((filetype == SSL_FILETYPE_ASN1) && was_bio_eof) { + /* EOF ASN1 file, not an error */ + ERR_clear_error(); + retval = 0; From 34e0ed80eed866d621d1f470079ce7fec17c019f Mon Sep 17 00:00:00 2001 From: Eric Lundby Date: Wed, 10 Jun 2026 19:40:31 -0600 Subject: [PATCH 2/3] Bump build number, add simple test --- recipe/meta.yaml | 2 +- recipe/run_test.py | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/recipe/meta.yaml b/recipe/meta.yaml index 6a0a72f9e..2b37fdb39 100644 --- a/recipe/meta.yaml +++ b/recipe/meta.yaml @@ -4,7 +4,7 @@ {% set ver2 = '.'.join(version.split('.')[0:2]) %} {% set ver2nd = ''.join(version.split('.')[0:2]) %} {% set ver3nd = ''.join(version.split('.')[0:3]) %} -{% set build_number = "0" %} +{% set build_number = "1" %} {% set channel_targets = ('abc', 'def') %} # this is just for the initial build, to break dependencies with python -> pip -> libpython-static {% set bootstrap = "false" %} diff --git a/recipe/run_test.py b/recipe/run_test.py index b3140a17f..05be899a7 100644 --- a/recipe/run_test.py +++ b/recipe/run_test.py @@ -101,3 +101,9 @@ print('OPENSSL_VERSION:', ssl.OPENSSL_VERSION) CONDA_OPENSSL_VERSION = os.getenv("openssl") assert CONDA_OPENSSL_VERSION in ssl.OPENSSL_VERSION + +# xref https://github.com/conda-forge/openssl-feedstock/issues/237 +pem = ssl.get_server_certificate(("pypi.org", 443)) +der = ssl.PEM_cert_to_DER_cert(pem) +ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) +ctx.load_verify_locations(cadata=der) \ No newline at end of file From 6ee1a263dade9b4b3555c67e8a91a0f8f54d66f4 Mon Sep 17 00:00:00 2001 From: Eric Lundby Date: Thu, 11 Jun 2026 08:47:35 -0600 Subject: [PATCH 3/3] Use local cert instead of external request. --- recipe/meta.yaml | 1 + recipe/run_test.py | 3 ++- recipe/test-cert.pem | 19 +++++++++++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 recipe/test-cert.pem diff --git a/recipe/meta.yaml b/recipe/meta.yaml index 4ec683aaa..f07dd0534 100644 --- a/recipe/meta.yaml +++ b/recipe/meta.yaml @@ -236,6 +236,7 @@ outputs: - tests/cython/* - tests/prefix-replacement/* - run_test.py + - test-cert.pem commands: - echo on # [win] - set # [win] diff --git a/recipe/run_test.py b/recipe/run_test.py index f6854823c..764376832 100644 --- a/recipe/run_test.py +++ b/recipe/run_test.py @@ -101,7 +101,8 @@ assert CONDA_OPENSSL_VERSION in ssl.OPENSSL_VERSION # xref https://github.com/conda-forge/openssl-feedstock/issues/237 -pem = ssl.get_server_certificate(("pypi.org", 443)) +from pathlib import Path +pem = Path(__file__).with_name("test-cert.pem").read_text() der = ssl.PEM_cert_to_DER_cert(pem) ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) ctx.load_verify_locations(cadata=der) \ No newline at end of file diff --git a/recipe/test-cert.pem b/recipe/test-cert.pem new file mode 100644 index 000000000..2db63fd81 --- /dev/null +++ b/recipe/test-cert.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDKTCCAhGgAwIBAgIUbmuRNVmcGqJIEKm2YojxPMGv7OkwDQYJKoZIhvcNAQEL +BQAwJDEiMCAGA1UEAwwZcHl0aG9uLWZlZWRzdG9jay1zc2wtdGVzdDAeFw0yNjA2 +MTExNDQwMDJaFw0zNjA2MDgxNDQwMDJaMCQxIjAgBgNVBAMMGXB5dGhvbi1mZWVk +c3RvY2stc3NsLXRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCu +d7c1PE1tTme8XuK+8DlKILUR3FluP6O4R2EbAej2zPSwtcLjyf7T2KCh/HJPlU8F ++QNq4UXoyAalNe0QImcdAb9oaBBwQWtZCNqQ9vKKF8mg/UTEskRwcWrbFl4ZUhAP +k3xjTBflr16WbrPcffLQsTs6cwDhYRJ/1xHaX0Q0cSWqmpkbysdgLcixmKhl80HJ +unIUxO7speyf6yGS8IFymGPPt3b5DPaDgdLnvi5CQ+SRLxICPSec8SysAR+6e2tu +sDHQOm8YjDvHb5Ujbbogq1XogTca7BeaDVxd/z/FJDRVO9qfWBGaRQ9UeZ+peAgC +wfLG1zMgq21J2tEYiK7bAgMBAAGjUzBRMB0GA1UdDgQWBBS6aBjsrBctsIr+wygb +XyCTepLDXTAfBgNVHSMEGDAWgBS6aBjsrBctsIr+wygbXyCTepLDXTAPBgNVHRMB +Af8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQA/goYzC7BEwVdfJ5ordI8YhzWH +V3DOcsbAympVsWF6Ra8qa6TXEEHhsYyIwB50aw62ccWZoyIexc+Lx3H/NmjrPHXo +YD+341ORMjZTBsk/MHlf5ex0s+m9MJVNh2IfCanBc6k9kDYZNRd4YF2hdJTsqoxV +QByMLRRfrzg2VZHdEk3whGXD9C/36NML22oTRwWefAmV+jyJyjMgis4cjnaZVxpn +iT3joMkOreswCvo4O2tAlEfR81MvNu80GajckTtMMq7VWxf2t8OdLdoXLUJrY27Y +pDp5BoTJ+52YJP6kz2gIanevw4Z2XE6otP2VX6Anaydf4fiJSMVJDTl3eXB/ +-----END CERTIFICATE-----