Skip to content

Commit 29c9728

Browse files
authored
[3.8] gh-114572: Fix locking in cert_store_stats and get_ca_certs (#118442)
(cherry picked from commit 732c7d5)
1 parent 895f7e2 commit 29c9728

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
@@ -168,6 +168,10 @@ extern const SSL_METHOD *TLSv1_2_method(void);
168168
# define PY_OPENSSL_1_1_API 1
169169
#endif
170170

171+
#if (OPENSSL_VERSION_NUMBER >= 0x30300000L) && !defined(LIBRESSL_VERSION_NUMBER)
172+
# define OPENSSL_VERSION_3_3 1
173+
#endif
174+
171175
/* SNI support (client- and server-side) appeared in OpenSSL 1.0.0 and 0.9.8f
172176
* This includes the SSL_set_SSL_CTX() function.
173177
*/
@@ -212,6 +216,16 @@ extern const SSL_METHOD *TLSv1_2_method(void);
212216
#define HAVE_OPENSSL_CRYPTO_LOCK
213217
#endif
214218

219+
/* OpenSSL 1.1+ allows locking X509_STORE, 1.0.2 doesn't. */
220+
#ifdef OPENSSL_VERSION_1_1
221+
#define HAVE_OPENSSL_X509_STORE_LOCK
222+
#endif
223+
224+
/* OpenSSL 3.3 added the X509_STORE_get1_objects API */
225+
#ifdef OPENSSL_VERSION_3_3
226+
#define HAVE_OPENSSL_X509_STORE_GET1_OBJECTS 1
227+
#endif
228+
215229
#if defined(OPENSSL_VERSION_1_1) && !defined(OPENSSL_NO_SSL2)
216230
#define OPENSSL_NO_SSL2
217231
#endif
@@ -4678,6 +4692,54 @@ set_sni_callback(PySSLContext *self, PyObject *arg, void *c)
46784692
#endif
46794693
}
46804694

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

47094771
store = SSL_CTX_get_cert_store(self->ctx);
4772+
#if HAVE_OPENSSL_X509_STORE_GET1_OBJECTS
4773+
objs = X509_STORE_get1_objects(store);
4774+
if (objs == NULL) {
4775+
PyErr_SetString(PyExc_MemoryError, "failed to query cert store");
4776+
return NULL;
4777+
}
4778+
#else
47104779
objs = X509_STORE_get0_objects(store);
4780+
#endif
47114781
for (i = 0; i < sk_X509_OBJECT_num(objs); i++) {
47124782
obj = sk_X509_OBJECT_value(objs, i);
47134783
switch (X509_OBJECT_get_type(obj)) {
@@ -4721,12 +4791,13 @@ _ssl__SSLContext_cert_store_stats_impl(PySSLContext *self)
47214791
crl++;
47224792
break;
47234793
default:
4724-
/* Ignore X509_LU_FAIL, X509_LU_RETRY, X509_LU_PKEY.
4725-
* As far as I can tell they are internal states and never
4726-
* stored in a cert store */
4794+
/* Ignore unrecognized types. */
47274795
break;
47284796
}
47294797
}
4798+
#if HAVE_OPENSSL_X509_STORE_GET1_OBJECTS
4799+
sk_X509_OBJECT_pop_free(objs, X509_OBJECT_free);
4800+
#endif
47304801
return Py_BuildValue("{sisisi}", "x509", x509, "crl", crl,
47314802
"x509_ca", ca);
47324803
}
@@ -4758,7 +4829,15 @@ _ssl__SSLContext_get_ca_certs_impl(PySSLContext *self, int binary_form)
47584829
}
47594830

47604831
store = SSL_CTX_get_cert_store(self->ctx);
4832+
#if HAVE_OPENSSL_X509_STORE_GET1_OBJECTS
4833+
objs = X509_STORE_get1_objects(store);
4834+
if (objs == NULL) {
4835+
PyErr_SetString(PyExc_MemoryError, "failed to query cert store");
4836+
return NULL;
4837+
}
4838+
#else
47614839
objs = X509_STORE_get0_objects(store);
4840+
#endif
47624841
for (i = 0; i < sk_X509_OBJECT_num(objs); i++) {
47634842
X509_OBJECT *obj;
47644843
X509 *cert;
@@ -4786,9 +4865,15 @@ _ssl__SSLContext_get_ca_certs_impl(PySSLContext *self, int binary_form)
47864865
}
47874866
Py_CLEAR(ci);
47884867
}
4868+
#if HAVE_OPENSSL_X509_STORE_GET1_OBJECTS
4869+
sk_X509_OBJECT_pop_free(objs, X509_OBJECT_free);
4870+
#endif
47894871
return rlist;
47904872

47914873
error:
4874+
#if HAVE_OPENSSL_X509_STORE_GET1_OBJECTS
4875+
sk_X509_OBJECT_pop_free(objs, X509_OBJECT_free);
4876+
#endif
47924877
Py_XDECREF(ci);
47934878
Py_XDECREF(rlist);
47944879
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