Skip to content

Commit 732c7d5

Browse files
committed
[3.9] gh-114572: Fix locking in cert_store_stats and get_ca_certs
1 parent 40d77b9 commit 732c7d5

File tree

2 files changed

+92
-3
lines changed

2 files changed

+92
-3
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
:meth:`ssl.SSLContext.cert_store_stats` and
2+
:meth:`ssl.SSLContext.get_ca_certs` now correctly lock access to the
3+
certificate store, when the :class:`ssl.SSLContext` is shared across
4+
multiple threads.

Modules/_ssl.c

Lines changed: 88 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,10 @@ extern const SSL_METHOD *TLSv1_2_method(void);
166166
# define PY_OPENSSL_1_1_API 1
167167
#endif
168168

169+
#if (OPENSSL_VERSION_NUMBER >= 0x30300000L) && !defined(LIBRESSL_VERSION_NUMBER)
170+
# define OPENSSL_VERSION_3_3 1
171+
#endif
172+
169173
/* SNI support (client- and server-side) appeared in OpenSSL 1.0.0 and 0.9.8f
170174
* This includes the SSL_set_SSL_CTX() function.
171175
*/
@@ -210,6 +214,16 @@ extern const SSL_METHOD *TLSv1_2_method(void);
210214
#define HAVE_OPENSSL_CRYPTO_LOCK
211215
#endif
212216

217+
/* OpenSSL 1.1+ allows locking X509_STORE, 1.0.2 doesn't. */
218+
#ifdef OPENSSL_VERSION_1_1
219+
#define HAVE_OPENSSL_X509_STORE_LOCK
220+
#endif
221+
222+
/* OpenSSL 3.3 added the X509_STORE_get1_objects API */
223+
#ifdef OPENSSL_VERSION_3_3
224+
#define HAVE_OPENSSL_X509_STORE_GET1_OBJECTS 1
225+
#endif
226+
213227
#if defined(OPENSSL_VERSION_1_1) && !defined(OPENSSL_NO_SSL2)
214228
#define OPENSSL_NO_SSL2
215229
#endif
@@ -4675,6 +4689,54 @@ set_sni_callback(PySSLContext *self, PyObject *arg, void *c)
46754689
#endif
46764690
}
46774691

4692+
/* Shim of X509_STORE_get1_objects API from OpenSSL 3.3
4693+
* Only available with the X509_STORE_lock() API */
4694+
#if defined(HAVE_OPENSSL_X509_STORE_LOCK) && !defined(OPENSSL_VERSION_3_3)
4695+
#define HAVE_OPENSSL_X509_STORE_GET1_OBJECTS 1
4696+
4697+
static X509_OBJECT *x509_object_dup(const X509_OBJECT *obj)
4698+
{
4699+
int ok;
4700+
X509_OBJECT *ret = X509_OBJECT_new();
4701+
if (ret == NULL) {
4702+
return NULL;
4703+
}
4704+
switch (X509_OBJECT_get_type(obj)) {
4705+
case X509_LU_X509:
4706+
ok = X509_OBJECT_set1_X509(ret, X509_OBJECT_get0_X509(obj));
4707+
break;
4708+
case X509_LU_CRL:
4709+
/* X509_OBJECT_get0_X509_CRL was not const-correct prior to 3.0.*/
4710+
ok = X509_OBJECT_set1_X509_CRL(
4711+
ret, X509_OBJECT_get0_X509_CRL((X509_OBJECT *)obj));
4712+
break;
4713+
default:
4714+
/* We cannot duplicate unrecognized types in a polyfill, but it is
4715+
* safe to leave an empty object. The caller will ignore it. */
4716+
ok = 1;
4717+
break;
4718+
}
4719+
if (!ok) {
4720+
X509_OBJECT_free(ret);
4721+
return NULL;
4722+
}
4723+
return ret;
4724+
}
4725+
4726+
static STACK_OF(X509_OBJECT) *
4727+
X509_STORE_get1_objects(X509_STORE *store)
4728+
{
4729+
STACK_OF(X509_OBJECT) *ret;
4730+
if (!X509_STORE_lock(store)) {
4731+
return NULL;
4732+
}
4733+
ret = sk_X509_OBJECT_deep_copy(X509_STORE_get0_objects(store),
4734+
x509_object_dup, X509_OBJECT_free);
4735+
X509_STORE_unlock(store);
4736+
return ret;
4737+
}
4738+
#endif
4739+
46784740
PyDoc_STRVAR(PySSLContext_sni_callback_doc,
46794741
"Set a callback that will be called when a server name is provided by the SSL/TLS client in the SNI extension.\n\
46804742
\n\
@@ -4704,7 +4766,15 @@ _ssl__SSLContext_cert_store_stats_impl(PySSLContext *self)
47044766
int x509 = 0, crl = 0, ca = 0, i;
47054767

47064768
store = SSL_CTX_get_cert_store(self->ctx);
4769+
#if HAVE_OPENSSL_X509_STORE_GET1_OBJECTS
4770+
objs = X509_STORE_get1_objects(store);
4771+
if (objs == NULL) {
4772+
PyErr_SetString(PyExc_MemoryError, "failed to query cert store");
4773+
return NULL;
4774+
}
4775+
#else
47074776
objs = X509_STORE_get0_objects(store);
4777+
#endif
47084778
for (i = 0; i < sk_X509_OBJECT_num(objs); i++) {
47094779
obj = sk_X509_OBJECT_value(objs, i);
47104780
switch (X509_OBJECT_get_type(obj)) {
@@ -4718,12 +4788,13 @@ _ssl__SSLContext_cert_store_stats_impl(PySSLContext *self)
47184788
crl++;
47194789
break;
47204790
default:
4721-
/* Ignore X509_LU_FAIL, X509_LU_RETRY, X509_LU_PKEY.
4722-
* As far as I can tell they are internal states and never
4723-
* stored in a cert store */
4791+
/* Ignore unrecognized types. */
47244792
break;
47254793
}
47264794
}
4795+
#if HAVE_OPENSSL_X509_STORE_GET1_OBJECTS
4796+
sk_X509_OBJECT_pop_free(objs, X509_OBJECT_free);
4797+
#endif
47274798
return Py_BuildValue("{sisisi}", "x509", x509, "crl", crl,
47284799
"x509_ca", ca);
47294800
}
@@ -4755,7 +4826,15 @@ _ssl__SSLContext_get_ca_certs_impl(PySSLContext *self, int binary_form)
47554826
}
47564827

47574828
store = SSL_CTX_get_cert_store(self->ctx);
4829+
#if HAVE_OPENSSL_X509_STORE_GET1_OBJECTS
4830+
objs = X509_STORE_get1_objects(store);
4831+
if (objs == NULL) {
4832+
PyErr_SetString(PyExc_MemoryError, "failed to query cert store");
4833+
return NULL;
4834+
}
4835+
#else
47584836
objs = X509_STORE_get0_objects(store);
4837+
#endif
47594838
for (i = 0; i < sk_X509_OBJECT_num(objs); i++) {
47604839
X509_OBJECT *obj;
47614840
X509 *cert;
@@ -4783,9 +4862,15 @@ _ssl__SSLContext_get_ca_certs_impl(PySSLContext *self, int binary_form)
47834862
}
47844863
Py_CLEAR(ci);
47854864
}
4865+
#if HAVE_OPENSSL_X509_STORE_GET1_OBJECTS
4866+
sk_X509_OBJECT_pop_free(objs, X509_OBJECT_free);
4867+
#endif
47864868
return rlist;
47874869

47884870
error:
4871+
#if HAVE_OPENSSL_X509_STORE_GET1_OBJECTS
4872+
sk_X509_OBJECT_pop_free(objs, X509_OBJECT_free);
4873+
#endif
47894874
Py_XDECREF(ci);
47904875
Py_XDECREF(rlist);
47914876
return NULL;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy