mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
[3.12] gh-114572: Fix locking in cert_store_stats and get_ca_certs (GH-114573) (GH-115547)
gh-114572: Fix locking in cert_store_stats and get_ca_certs (GH-114573)
* gh-114572: Fix locking in cert_store_stats and get_ca_certs
cert_store_stats and get_ca_certs query the SSLContext's X509_STORE with
X509_STORE_get0_objects, but reading the result requires a lock. See
https://github.com/openssl/openssl/pull/23224 for details.
Instead, use X509_STORE_get1_objects, newly added in that PR.
X509_STORE_get1_objects does not exist in current OpenSSLs, but we can
polyfill it with X509_STORE_lock and X509_STORE_unlock.
* Work around const-correctness problem
* Add missing X509_STORE_get1_objects failure check
* Add blurb
(cherry picked from commit bce693111b
)
Co-authored-by: David Benjamin <davidben@google.com>
This commit is contained in:
parent
d4a1c8e628
commit
542f3272f5
2 changed files with 64 additions and 5 deletions
|
@ -0,0 +1,4 @@
|
||||||
|
:meth:`ssl.SSLContext.cert_store_stats` and
|
||||||
|
:meth:`ssl.SSLContext.get_ca_certs` now correctly lock access to the
|
||||||
|
certificate store, when the :class:`ssl.SSLContext` is shared across
|
||||||
|
multiple threads.
|
|
@ -4520,6 +4520,50 @@ set_sni_callback(PySSLContext *self, PyObject *arg, void *c)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if OPENSSL_VERSION_NUMBER < 0x30300000L
|
||||||
|
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
|
||||||
|
|
||||||
PyDoc_STRVAR(PySSLContext_sni_callback_doc,
|
PyDoc_STRVAR(PySSLContext_sni_callback_doc,
|
||||||
"Set a callback that will be called when a server name is provided by the SSL/TLS client in the SNI extension.\n\
|
"Set a callback that will be called when a server name is provided by the SSL/TLS client in the SNI extension.\n\
|
||||||
\n\
|
\n\
|
||||||
|
@ -4549,7 +4593,12 @@ _ssl__SSLContext_cert_store_stats_impl(PySSLContext *self)
|
||||||
int x509 = 0, crl = 0, ca = 0, i;
|
int x509 = 0, crl = 0, ca = 0, i;
|
||||||
|
|
||||||
store = SSL_CTX_get_cert_store(self->ctx);
|
store = SSL_CTX_get_cert_store(self->ctx);
|
||||||
objs = X509_STORE_get0_objects(store);
|
objs = X509_STORE_get1_objects(store);
|
||||||
|
if (objs == NULL) {
|
||||||
|
PyErr_SetString(PyExc_MemoryError, "failed to query cert store");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < sk_X509_OBJECT_num(objs); i++) {
|
for (i = 0; i < sk_X509_OBJECT_num(objs); i++) {
|
||||||
obj = sk_X509_OBJECT_value(objs, i);
|
obj = sk_X509_OBJECT_value(objs, i);
|
||||||
switch (X509_OBJECT_get_type(obj)) {
|
switch (X509_OBJECT_get_type(obj)) {
|
||||||
|
@ -4563,12 +4612,11 @@ _ssl__SSLContext_cert_store_stats_impl(PySSLContext *self)
|
||||||
crl++;
|
crl++;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* Ignore X509_LU_FAIL, X509_LU_RETRY, X509_LU_PKEY.
|
/* Ignore unrecognized types. */
|
||||||
* As far as I can tell they are internal states and never
|
|
||||||
* stored in a cert store */
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
sk_X509_OBJECT_pop_free(objs, X509_OBJECT_free);
|
||||||
return Py_BuildValue("{sisisi}", "x509", x509, "crl", crl,
|
return Py_BuildValue("{sisisi}", "x509", x509, "crl", crl,
|
||||||
"x509_ca", ca);
|
"x509_ca", ca);
|
||||||
}
|
}
|
||||||
|
@ -4600,7 +4648,12 @@ _ssl__SSLContext_get_ca_certs_impl(PySSLContext *self, int binary_form)
|
||||||
}
|
}
|
||||||
|
|
||||||
store = SSL_CTX_get_cert_store(self->ctx);
|
store = SSL_CTX_get_cert_store(self->ctx);
|
||||||
objs = X509_STORE_get0_objects(store);
|
objs = X509_STORE_get1_objects(store);
|
||||||
|
if (objs == NULL) {
|
||||||
|
PyErr_SetString(PyExc_MemoryError, "failed to query cert store");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < sk_X509_OBJECT_num(objs); i++) {
|
for (i = 0; i < sk_X509_OBJECT_num(objs); i++) {
|
||||||
X509_OBJECT *obj;
|
X509_OBJECT *obj;
|
||||||
X509 *cert;
|
X509 *cert;
|
||||||
|
@ -4628,9 +4681,11 @@ _ssl__SSLContext_get_ca_certs_impl(PySSLContext *self, int binary_form)
|
||||||
}
|
}
|
||||||
Py_CLEAR(ci);
|
Py_CLEAR(ci);
|
||||||
}
|
}
|
||||||
|
sk_X509_OBJECT_pop_free(objs, X509_OBJECT_free);
|
||||||
return rlist;
|
return rlist;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
sk_X509_OBJECT_pop_free(objs, X509_OBJECT_free);
|
||||||
Py_XDECREF(ci);
|
Py_XDECREF(ci);
|
||||||
Py_XDECREF(rlist);
|
Py_XDECREF(rlist);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue