Skip to content

Commit

Permalink
Patched our Python sources for CVE-2024-0397.
Browse files Browse the repository at this point in the history
  • Loading branch information
dumol committed Aug 15, 2024
1 parent 4a3120a commit 0a58cdb
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 5 deletions.
93 changes: 91 additions & 2 deletions src/python/Python-2.7.18/Modules/_ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)) {
Expand All @@ -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);
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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

5 changes: 2 additions & 3 deletions src/python/README
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 0a58cdb

Please sign in to comment.