Skip to content

Commit a6a90ca

Browse files
miss-islingtondavidben
authored andcommitted
[3.10] pythongh-114572: Fix locking in cert_store_stats and get_ca_certs (pythonGH-114573) (python#115548)
pythongh-114572: Fix locking in cert_store_stats and get_ca_certs (pythonGH-114573) * pythongh-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 openssl/openssl#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 bce6931) Co-authored-by: David Benjamin <davidben@google.com>
1 parent 3ec9183 commit a6a90ca

1 file changed

Lines changed: 60 additions & 5 deletions

File tree

Modules/_ssl.c

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4712,6 +4712,50 @@ set_sni_callback(PySSLContext *self, PyObject *arg, void *c)
47124712
#endif
47134713
}
47144714

4715+
#if OPENSSL_VERSION_NUMBER < 0x30300000L
4716+
static X509_OBJECT *x509_object_dup(const X509_OBJECT *obj)
4717+
{
4718+
int ok;
4719+
X509_OBJECT *ret = X509_OBJECT_new();
4720+
if (ret == NULL) {
4721+
return NULL;
4722+
}
4723+
switch (X509_OBJECT_get_type(obj)) {
4724+
case X509_LU_X509:
4725+
ok = X509_OBJECT_set1_X509(ret, X509_OBJECT_get0_X509(obj));
4726+
break;
4727+
case X509_LU_CRL:
4728+
/* X509_OBJECT_get0_X509_CRL was not const-correct prior to 3.0.*/
4729+
ok = X509_OBJECT_set1_X509_CRL(
4730+
ret, X509_OBJECT_get0_X509_CRL((X509_OBJECT *)obj));
4731+
break;
4732+
default:
4733+
/* We cannot duplicate unrecognized types in a polyfill, but it is
4734+
* safe to leave an empty object. The caller will ignore it. */
4735+
ok = 1;
4736+
break;
4737+
}
4738+
if (!ok) {
4739+
X509_OBJECT_free(ret);
4740+
return NULL;
4741+
}
4742+
return ret;
4743+
}
4744+
4745+
static STACK_OF(X509_OBJECT) *
4746+
X509_STORE_get1_objects(X509_STORE *store)
4747+
{
4748+
STACK_OF(X509_OBJECT) *ret;
4749+
if (!X509_STORE_lock(store)) {
4750+
return NULL;
4751+
}
4752+
ret = sk_X509_OBJECT_deep_copy(X509_STORE_get0_objects(store),
4753+
x509_object_dup, X509_OBJECT_free);
4754+
X509_STORE_unlock(store);
4755+
return ret;
4756+
}
4757+
#endif
4758+
47154759
PyDoc_STRVAR(PySSLContext_sni_callback_doc,
47164760
"Set a callback that will be called when a server name is provided by the SSL/TLS client in the SNI extension.\n\
47174761
\n\
@@ -4741,7 +4785,12 @@ _ssl__SSLContext_cert_store_stats_impl(PySSLContext *self)
47414785
int x509 = 0, crl = 0, ca = 0, i;
47424786

47434787
store = SSL_CTX_get_cert_store(self->ctx);
4744-
objs = X509_STORE_get0_objects(store);
4788+
objs = X509_STORE_get1_objects(store);
4789+
if (objs == NULL) {
4790+
PyErr_SetString(PyExc_MemoryError, "failed to query cert store");
4791+
return NULL;
4792+
}
4793+
47454794
for (i = 0; i < sk_X509_OBJECT_num(objs); i++) {
47464795
obj = sk_X509_OBJECT_value(objs, i);
47474796
switch (X509_OBJECT_get_type(obj)) {
@@ -4755,12 +4804,11 @@ _ssl__SSLContext_cert_store_stats_impl(PySSLContext *self)
47554804
crl++;
47564805
break;
47574806
default:
4758-
/* Ignore X509_LU_FAIL, X509_LU_RETRY, X509_LU_PKEY.
4759-
* As far as I can tell they are internal states and never
4760-
* stored in a cert store */
4807+
/* Ignore unrecognized types. */
47614808
break;
47624809
}
47634810
}
4811+
sk_X509_OBJECT_pop_free(objs, X509_OBJECT_free);
47644812
return Py_BuildValue("{sisisi}", "x509", x509, "crl", crl,
47654813
"x509_ca", ca);
47664814
}
@@ -4792,7 +4840,12 @@ _ssl__SSLContext_get_ca_certs_impl(PySSLContext *self, int binary_form)
47924840
}
47934841

47944842
store = SSL_CTX_get_cert_store(self->ctx);
4795-
objs = X509_STORE_get0_objects(store);
4843+
objs = X509_STORE_get1_objects(store);
4844+
if (objs == NULL) {
4845+
PyErr_SetString(PyExc_MemoryError, "failed to query cert store");
4846+
goto error;
4847+
}
4848+
47964849
for (i = 0; i < sk_X509_OBJECT_num(objs); i++) {
47974850
X509_OBJECT *obj;
47984851
X509 *cert;
@@ -4820,9 +4873,11 @@ _ssl__SSLContext_get_ca_certs_impl(PySSLContext *self, int binary_form)
48204873
}
48214874
Py_CLEAR(ci);
48224875
}
4876+
sk_X509_OBJECT_pop_free(objs, X509_OBJECT_free);
48234877
return rlist;
48244878

48254879
error:
4880+
sk_X509_OBJECT_pop_free(objs, X509_OBJECT_free);
48264881
Py_XDECREF(ci);
48274882
Py_XDECREF(rlist);
48284883
return NULL;

0 commit comments

Comments
 (0)