diff --git a/recipe/meta.yaml b/recipe/meta.yaml index 087d7769b..f07dd0534 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" %} @@ -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 }} @@ -234,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/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; diff --git a/recipe/run_test.py b/recipe/run_test.py index 668bd030b..764376832 100644 --- a/recipe/run_test.py +++ b/recipe/run_test.py @@ -99,3 +99,10 @@ 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 +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-----