Skip to content

Commit ad95c72

Browse files
authored
gh-106687: _ssl: use uint64_t for SSL options (#106700)
SSL_CTX_get_options() uses uint64_t for options: https://www.openssl.org/docs/man3.1/man3/SSL_CTX_get_options.html Fix this compiler warning on Windows with MSC: conversion from 'uint64_t' to 'long', possible loss of data
1 parent 036bb73 commit ad95c72

File tree

2 files changed

+78
-26
lines changed

2 files changed

+78
-26
lines changed

Lib/test/test_ssl.py

+24
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,15 @@ def test_constants(self):
339339
ssl.OP_NO_TLSv1_2
340340
self.assertEqual(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv23)
341341

342+
def test_options(self):
343+
# gh-106687: SSL options values are unsigned integer (uint64_t)
344+
for name in dir(ssl):
345+
if not name.startswith('OP_'):
346+
continue
347+
with self.subTest(option=name):
348+
value = getattr(ssl, name)
349+
self.assertGreaterEqual(value, 0, f"ssl.{name}")
350+
342351
def test_ssl_types(self):
343352
ssl_types = [
344353
_ssl._SSLContext,
@@ -951,6 +960,7 @@ def test_get_ciphers(self):
951960
)
952961

953962
def test_options(self):
963+
# Test default SSLContext options
954964
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
955965
# OP_ALL | OP_NO_SSLv2 | OP_NO_SSLv3 is the default value
956966
default = (ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3)
@@ -959,16 +969,30 @@ def test_options(self):
959969
OP_SINGLE_DH_USE | OP_SINGLE_ECDH_USE |
960970
OP_ENABLE_MIDDLEBOX_COMPAT)
961971
self.assertEqual(default, ctx.options)
972+
973+
# disallow TLSv1
962974
with warnings_helper.check_warnings():
963975
ctx.options |= ssl.OP_NO_TLSv1
964976
self.assertEqual(default | ssl.OP_NO_TLSv1, ctx.options)
977+
978+
# allow TLSv1
965979
with warnings_helper.check_warnings():
966980
ctx.options = (ctx.options & ~ssl.OP_NO_TLSv1)
967981
self.assertEqual(default, ctx.options)
982+
983+
# clear all options
968984
ctx.options = 0
969985
# Ubuntu has OP_NO_SSLv3 forced on by default
970986
self.assertEqual(0, ctx.options & ~ssl.OP_NO_SSLv3)
971987

988+
# invalid options
989+
with self.assertRaises(OverflowError):
990+
ctx.options = -1
991+
with self.assertRaises(OverflowError):
992+
ctx.options = 2 ** 100
993+
with self.assertRaises(TypeError):
994+
ctx.options = "abc"
995+
972996
def test_verify_mode_protocol(self):
973997
with warnings_helper.check_warnings():
974998
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)

Modules/_ssl.c

+54-26
Original file line numberDiff line numberDiff line change
@@ -3025,7 +3025,7 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version)
30253025
/*[clinic end generated code: output=2cf0d7a0741b6bd1 input=8d58a805b95fc534]*/
30263026
{
30273027
PySSLContext *self;
3028-
long options;
3028+
uint64_t options;
30293029
const SSL_METHOD *method = NULL;
30303030
SSL_CTX *ctx = NULL;
30313031
X509_VERIFY_PARAM *params;
@@ -3618,20 +3618,32 @@ PyDoc_STRVAR(PySSLContext_security_level_doc, "The current security level");
36183618
static PyObject *
36193619
get_options(PySSLContext *self, void *c)
36203620
{
3621-
return PyLong_FromLong(SSL_CTX_get_options(self->ctx));
3621+
uint64_t options = SSL_CTX_get_options(self->ctx);
3622+
Py_BUILD_ASSERT(sizeof(unsigned long long) >= sizeof(options));
3623+
return PyLong_FromUnsignedLongLong(options);
36223624
}
36233625

36243626
static int
36253627
set_options(PySSLContext *self, PyObject *arg, void *c)
36263628
{
3627-
long new_opts, opts, set, clear;
3628-
long opt_no = (
3629+
PyObject *new_opts_obj;
3630+
unsigned long long new_opts_arg;
3631+
uint64_t new_opts, opts, clear, set;
3632+
uint64_t opt_no = (
36293633
SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 |
36303634
SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2 | SSL_OP_NO_TLSv1_3
36313635
);
36323636

3633-
if (!PyArg_Parse(arg, "l", &new_opts))
3637+
if (!PyArg_Parse(arg, "O!", &PyLong_Type, &new_opts_obj)) {
36343638
return -1;
3639+
}
3640+
new_opts_arg = PyLong_AsUnsignedLongLong(new_opts_obj);
3641+
if (new_opts_arg == (unsigned long long)-1 && PyErr_Occurred()) {
3642+
return -1;
3643+
}
3644+
Py_BUILD_ASSERT(sizeof(new_opts) >= sizeof(new_opts_arg));
3645+
new_opts = (uint64_t)new_opts_arg;
3646+
36353647
opts = SSL_CTX_get_options(self->ctx);
36363648
clear = opts & ~new_opts;
36373649
set = ~opts & new_opts;
@@ -3645,8 +3657,9 @@ set_options(PySSLContext *self, PyObject *arg, void *c)
36453657
if (clear) {
36463658
SSL_CTX_clear_options(self->ctx, clear);
36473659
}
3648-
if (set)
3660+
if (set) {
36493661
SSL_CTX_set_options(self->ctx, set);
3662+
}
36503663
return 0;
36513664
}
36523665

@@ -5754,10 +5767,24 @@ sslmodule_init_socketapi(PyObject *module)
57545767
return 0;
57555768
}
57565769

5770+
57575771
static int
5758-
sslmodule_init_constants(PyObject *m)
5772+
sslmodule_add_option(PyObject *m, const char *name, uint64_t value)
57595773
{
5774+
Py_BUILD_ASSERT(sizeof(unsigned long long) >= sizeof(value));
5775+
PyObject *obj = PyLong_FromUnsignedLongLong(value);
5776+
if (obj == NULL) {
5777+
return -1;
5778+
}
5779+
int res = PyModule_AddObjectRef(m, name, obj);
5780+
Py_DECREF(obj);
5781+
return res;
5782+
}
5783+
57605784

5785+
static int
5786+
sslmodule_init_constants(PyObject *m)
5787+
{
57615788
PyModule_AddStringConstant(m, "_DEFAULT_CIPHERS",
57625789
PY_SSL_DEFAULT_CIPHER_STRING);
57635790

@@ -5877,46 +5904,47 @@ sslmodule_init_constants(PyObject *m)
58775904
PyModule_AddIntConstant(m, "PROTOCOL_TLSv1_2",
58785905
PY_SSL_VERSION_TLS1_2);
58795906

5907+
#define ADD_OPTION(NAME, VALUE) if (sslmodule_add_option(m, NAME, (VALUE)) < 0) return -1
5908+
58805909
/* protocol options */
5881-
PyModule_AddIntConstant(m, "OP_ALL",
5882-
SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
5883-
PyModule_AddIntConstant(m, "OP_NO_SSLv2", SSL_OP_NO_SSLv2);
5884-
PyModule_AddIntConstant(m, "OP_NO_SSLv3", SSL_OP_NO_SSLv3);
5885-
PyModule_AddIntConstant(m, "OP_NO_TLSv1", SSL_OP_NO_TLSv1);
5886-
PyModule_AddIntConstant(m, "OP_NO_TLSv1_1", SSL_OP_NO_TLSv1_1);
5887-
PyModule_AddIntConstant(m, "OP_NO_TLSv1_2", SSL_OP_NO_TLSv1_2);
5910+
ADD_OPTION("OP_ALL", SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
5911+
ADD_OPTION("OP_NO_SSLv2", SSL_OP_NO_SSLv2);
5912+
ADD_OPTION("OP_NO_SSLv3", SSL_OP_NO_SSLv3);
5913+
ADD_OPTION("OP_NO_TLSv1", SSL_OP_NO_TLSv1);
5914+
ADD_OPTION("OP_NO_TLSv1_1", SSL_OP_NO_TLSv1_1);
5915+
ADD_OPTION("OP_NO_TLSv1_2", SSL_OP_NO_TLSv1_2);
58885916
#ifdef SSL_OP_NO_TLSv1_3
5889-
PyModule_AddIntConstant(m, "OP_NO_TLSv1_3", SSL_OP_NO_TLSv1_3);
5917+
ADD_OPTION("OP_NO_TLSv1_3", SSL_OP_NO_TLSv1_3);
58905918
#else
5891-
PyModule_AddIntConstant(m, "OP_NO_TLSv1_3", 0);
5919+
ADD_OPTION("OP_NO_TLSv1_3", 0);
58925920
#endif
5893-
PyModule_AddIntConstant(m, "OP_CIPHER_SERVER_PREFERENCE",
5921+
ADD_OPTION("OP_CIPHER_SERVER_PREFERENCE",
58945922
SSL_OP_CIPHER_SERVER_PREFERENCE);
5895-
PyModule_AddIntConstant(m, "OP_SINGLE_DH_USE", SSL_OP_SINGLE_DH_USE);
5896-
PyModule_AddIntConstant(m, "OP_NO_TICKET", SSL_OP_NO_TICKET);
5897-
PyModule_AddIntConstant(m, "OP_LEGACY_SERVER_CONNECT",
5923+
ADD_OPTION("OP_SINGLE_DH_USE", SSL_OP_SINGLE_DH_USE);
5924+
ADD_OPTION("OP_NO_TICKET", SSL_OP_NO_TICKET);
5925+
ADD_OPTION("OP_LEGACY_SERVER_CONNECT",
58985926
SSL_OP_LEGACY_SERVER_CONNECT);
58995927
#ifdef SSL_OP_SINGLE_ECDH_USE
5900-
PyModule_AddIntConstant(m, "OP_SINGLE_ECDH_USE", SSL_OP_SINGLE_ECDH_USE);
5928+
ADD_OPTION("OP_SINGLE_ECDH_USE", SSL_OP_SINGLE_ECDH_USE);
59015929
#endif
59025930
#ifdef SSL_OP_NO_COMPRESSION
5903-
PyModule_AddIntConstant(m, "OP_NO_COMPRESSION",
5931+
ADD_OPTION("OP_NO_COMPRESSION",
59045932
SSL_OP_NO_COMPRESSION);
59055933
#endif
59065934
#ifdef SSL_OP_ENABLE_MIDDLEBOX_COMPAT
5907-
PyModule_AddIntConstant(m, "OP_ENABLE_MIDDLEBOX_COMPAT",
5935+
ADD_OPTION("OP_ENABLE_MIDDLEBOX_COMPAT",
59085936
SSL_OP_ENABLE_MIDDLEBOX_COMPAT);
59095937
#endif
59105938
#ifdef SSL_OP_NO_RENEGOTIATION
5911-
PyModule_AddIntConstant(m, "OP_NO_RENEGOTIATION",
5939+
ADD_OPTION("OP_NO_RENEGOTIATION",
59125940
SSL_OP_NO_RENEGOTIATION);
59135941
#endif
59145942
#ifdef SSL_OP_IGNORE_UNEXPECTED_EOF
5915-
PyModule_AddIntConstant(m, "OP_IGNORE_UNEXPECTED_EOF",
5943+
ADD_OPTION("OP_IGNORE_UNEXPECTED_EOF",
59165944
SSL_OP_IGNORE_UNEXPECTED_EOF);
59175945
#endif
59185946
#ifdef SSL_OP_ENABLE_KTLS
5919-
PyModule_AddIntConstant(m, "OP_ENABLE_KTLS", SSL_OP_ENABLE_KTLS);
5947+
ADD_OPTION("OP_ENABLE_KTLS", SSL_OP_ENABLE_KTLS);
59205948
#endif
59215949

59225950
#ifdef X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT

0 commit comments

Comments
 (0)