diff --git a/src/python/Python-2.7.18/Modules/_ssl.c b/src/python/Python-2.7.18/Modules/_ssl.c index 6df9f4779..e28f02d12 100644 --- a/src/python/Python-2.7.18/Modules/_ssl.c +++ b/src/python/Python-2.7.18/Modules/_ssl.c @@ -106,6 +106,10 @@ struct py_ssl_library_code { # define PY_OPENSSL_1_1_API 1 #endif +#if (OPENSSL_VERSION_NUMBER >= 0x30300000L) && !defined(LIBRESSL_VERSION_NUMBER) +# define OPENSSL_VERSION_3_3 1 +#endif + /* LibreSSL 2.7.0 provides necessary OpenSSL 1.1.0 APIs */ #if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x2070000fL # define PY_OPENSSL_1_1_API 1 @@ -161,6 +165,16 @@ struct py_ssl_library_code { #define HAVE_OPENSSL_CRYPTO_LOCK #endif +/* OpenSSL 1.1+ allows locking X509_STORE, 1.0.2 doesn't. */ +#ifdef OPENSSL_VERSION_1_1 +#define HAVE_OPENSSL_X509_STORE_LOCK +#endif + +/* OpenSSL 3.3 added the X509_STORE_get1_objects API */ +#ifdef OPENSSL_VERSION_3_3 +#define HAVE_OPENSSL_X509_STORE_GET1_OBJECTS 1 +#endif + #if defined(OPENSSL_VERSION_1_1) && !defined(OPENSSL_NO_SSL2) #define OPENSSL_NO_SSL2 #endif @@ -3504,7 +3518,15 @@ cert_store_stats(PySSLContext *self) int x509 = 0, crl = 0, ca = 0, i; store = SSL_CTX_get_cert_store(self->ctx); - objs = X509_STORE_get0_objects(store); + #if HAVE_OPENSSL_X509_STORE_GET1_OBJECTS + objs = X509_STORE_get1_objects(store); + if (objs == NULL) { + PyErr_SetString(PyExc_MemoryError, "failed to query cert store"); + return NULL; + } + #else + objs = X509_STORE_get0_objects(store); + #endif for (i = 0; i < sk_X509_OBJECT_num(objs); i++) { obj = sk_X509_OBJECT_value(objs, i); switch (X509_OBJECT_get_type(obj)) { @@ -3521,9 +3543,15 @@ cert_store_stats(PySSLContext *self) /* Ignore X509_LU_FAIL, X509_LU_RETRY, X509_LU_PKEY. * As far as I can tell they are internal states and never * stored in a cert store */ + /* Ignore enrecognized types */ break; } } + +#if HAVE_OPENSSL_X509_STORE_GET1_OBJECTS + sk_X509_OBJECT_pop_free(objs, X509_OBJECT_free); +#endif + return Py_BuildValue("{sisisi}", "x509", x509, "crl", crl, "x509_ca", ca); } @@ -3558,9 +3586,16 @@ get_ca_certs(PySSLContext *self, PyObject *args, PyObject *kwds) if ((rlist = PyList_New(0)) == NULL) { return NULL; } - store = SSL_CTX_get_cert_store(self->ctx); +#if HAVE_OPENSSL_X509_STORE_GET1_OBJECTS + objs = X509_STORE_get1_objects(store); + if (objs == NULL) { + PyErr_SetString(PyExc_MemoryError, "failed to query cert store"); + return NULL; + } +#else objs = X509_STORE_get0_objects(store); +#endif for (i = 0; i < sk_X509_OBJECT_num(objs); i++) { X509_OBJECT *obj; X509 *cert; @@ -3588,9 +3623,15 @@ get_ca_certs(PySSLContext *self, PyObject *args, PyObject *kwds) } Py_CLEAR(ci); } + #if HAVE_OPENSSL_X509_STORE_GET1_OBJECTS + sk_X509_OBJECT_pop_free(objs, X509_OBJECT_free); + #endif return rlist; error: +#if HAVE_OPENSSL_X509_STORE_GET1_OBJECTS + sk_X509_OBJECT_pop_free(objs, X509_OBJECT_free); +#endif Py_XDECREF(ci); Py_XDECREF(rlist); return NULL; @@ -4642,3 +4683,51 @@ init_ssl(void) return; } +/* Shim of X509_STORE_get1_objects API from OpenSSL 3.3 + * Only available with the X509_STORE_lock() API */ +#if defined(HAVE_OPENSSL_X509_STORE_LOCK) && !defined(OPENSSL_VERSION_3_3) +#define HAVE_OPENSSL_X509_STORE_GET1_OBJECTS 1 + +static X509_OBJECT *x509_object_dup(const X509_OBJECT *obj) +{ + int ok; + X509_OBJECT *ret = X509_OBJECT_new(); + if (ret == NULL) { + return NULL; + } + switch (X509_OBJECT_get_type(obj)) { + case X509_LU_X509: + ok = X509_OBJECT_set1_X509(ret, X509_OBJECT_get0_X509(obj)); + break; + case X509_LU_CRL: + /* X509_OBJECT_get0_X509_CRL was not const-correct prior to 3.0.*/ + ok = X509_OBJECT_set1_X509_CRL( + ret, X509_OBJECT_get0_X509_CRL((X509_OBJECT *)obj)); + break; + default: + /* We cannot duplicate unrecognized types in a polyfill, but it is + * safe to leave an empty object. The caller will ignore it. */ + ok = 1; + break; + } + if (!ok) { + X509_OBJECT_free(ret); + return NULL; + } + return ret; +} + +static STACK_OF(X509_OBJECT) * +X509_STORE_get1_objects(X509_STORE *store) +{ + STACK_OF(X509_OBJECT) *ret; + if (!X509_STORE_lock(store)) { + return NULL; + } + ret = sk_X509_OBJECT_deep_copy(X509_STORE_get0_objects(store), + x509_object_dup, X509_OBJECT_free); + X509_STORE_unlock(store); + return ret; +} +#endif + diff --git a/src/python/README b/src/python/README index a1670f31a..f3d5a7602 100644 --- a/src/python/README +++ b/src/python/README @@ -14,9 +14,8 @@ to apply to our Python sources tree, then issue something like: cd Python-2.7.18 patch -p1 < ~/Downloads/CVE-2020-10735.diff -Python sources are currently patched from upstream Active State branch at -https://github.com/ActiveState/cpython/commits/2.7.18.6_base/ up to & including -fixes from July 31, 2024. Last commit: 0f39e68197b735203b8c1b4988ff78ae61842864. +Python sources are currently patched from upstream Active State branch up to and +including fixes from Aug 9, 2024 for ActiveState Python version 2.7.18.10. Patches that can be applied on Windows as hot fixes (see below for more details) are saved as diff files in the current directory. They are also applied on