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
This commit is contained in:
Victor Stinner 2023-07-17 17:55:30 +02:00 committed by GitHub
parent 036bb73656
commit ad95c7253a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 78 additions and 26 deletions

View File

@ -339,6 +339,15 @@ class BasicSocketTests(unittest.TestCase):
ssl.OP_NO_TLSv1_2
self.assertEqual(ssl.PROTOCOL_TLS, ssl.PROTOCOL_SSLv23)
def test_options(self):
# gh-106687: SSL options values are unsigned integer (uint64_t)
for name in dir(ssl):
if not name.startswith('OP_'):
continue
with self.subTest(option=name):
value = getattr(ssl, name)
self.assertGreaterEqual(value, 0, f"ssl.{name}")
def test_ssl_types(self):
ssl_types = [
_ssl._SSLContext,
@ -951,6 +960,7 @@ class ContextTests(unittest.TestCase):
)
def test_options(self):
# Test default SSLContext options
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
# OP_ALL | OP_NO_SSLv2 | OP_NO_SSLv3 is the default value
default = (ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3)
@ -959,16 +969,30 @@ class ContextTests(unittest.TestCase):
OP_SINGLE_DH_USE | OP_SINGLE_ECDH_USE |
OP_ENABLE_MIDDLEBOX_COMPAT)
self.assertEqual(default, ctx.options)
# disallow TLSv1
with warnings_helper.check_warnings():
ctx.options |= ssl.OP_NO_TLSv1
self.assertEqual(default | ssl.OP_NO_TLSv1, ctx.options)
# allow TLSv1
with warnings_helper.check_warnings():
ctx.options = (ctx.options & ~ssl.OP_NO_TLSv1)
self.assertEqual(default, ctx.options)
# clear all options
ctx.options = 0
# Ubuntu has OP_NO_SSLv3 forced on by default
self.assertEqual(0, ctx.options & ~ssl.OP_NO_SSLv3)
# invalid options
with self.assertRaises(OverflowError):
ctx.options = -1
with self.assertRaises(OverflowError):
ctx.options = 2 ** 100
with self.assertRaises(TypeError):
ctx.options = "abc"
def test_verify_mode_protocol(self):
with warnings_helper.check_warnings():
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)

View File

@ -3025,7 +3025,7 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version)
/*[clinic end generated code: output=2cf0d7a0741b6bd1 input=8d58a805b95fc534]*/
{
PySSLContext *self;
long options;
uint64_t options;
const SSL_METHOD *method = NULL;
SSL_CTX *ctx = NULL;
X509_VERIFY_PARAM *params;
@ -3618,20 +3618,32 @@ PyDoc_STRVAR(PySSLContext_security_level_doc, "The current security level");
static PyObject *
get_options(PySSLContext *self, void *c)
{
return PyLong_FromLong(SSL_CTX_get_options(self->ctx));
uint64_t options = SSL_CTX_get_options(self->ctx);
Py_BUILD_ASSERT(sizeof(unsigned long long) >= sizeof(options));
return PyLong_FromUnsignedLongLong(options);
}
static int
set_options(PySSLContext *self, PyObject *arg, void *c)
{
long new_opts, opts, set, clear;
long opt_no = (
PyObject *new_opts_obj;
unsigned long long new_opts_arg;
uint64_t new_opts, opts, clear, set;
uint64_t opt_no = (
SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 |
SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2 | SSL_OP_NO_TLSv1_3
);
if (!PyArg_Parse(arg, "l", &new_opts))
if (!PyArg_Parse(arg, "O!", &PyLong_Type, &new_opts_obj)) {
return -1;
}
new_opts_arg = PyLong_AsUnsignedLongLong(new_opts_obj);
if (new_opts_arg == (unsigned long long)-1 && PyErr_Occurred()) {
return -1;
}
Py_BUILD_ASSERT(sizeof(new_opts) >= sizeof(new_opts_arg));
new_opts = (uint64_t)new_opts_arg;
opts = SSL_CTX_get_options(self->ctx);
clear = opts & ~new_opts;
set = ~opts & new_opts;
@ -3645,8 +3657,9 @@ set_options(PySSLContext *self, PyObject *arg, void *c)
if (clear) {
SSL_CTX_clear_options(self->ctx, clear);
}
if (set)
if (set) {
SSL_CTX_set_options(self->ctx, set);
}
return 0;
}
@ -5754,10 +5767,24 @@ sslmodule_init_socketapi(PyObject *module)
return 0;
}
static int
sslmodule_add_option(PyObject *m, const char *name, uint64_t value)
{
Py_BUILD_ASSERT(sizeof(unsigned long long) >= sizeof(value));
PyObject *obj = PyLong_FromUnsignedLongLong(value);
if (obj == NULL) {
return -1;
}
int res = PyModule_AddObjectRef(m, name, obj);
Py_DECREF(obj);
return res;
}
static int
sslmodule_init_constants(PyObject *m)
{
PyModule_AddStringConstant(m, "_DEFAULT_CIPHERS",
PY_SSL_DEFAULT_CIPHER_STRING);
@ -5877,46 +5904,47 @@ sslmodule_init_constants(PyObject *m)
PyModule_AddIntConstant(m, "PROTOCOL_TLSv1_2",
PY_SSL_VERSION_TLS1_2);
#define ADD_OPTION(NAME, VALUE) if (sslmodule_add_option(m, NAME, (VALUE)) < 0) return -1
/* protocol options */
PyModule_AddIntConstant(m, "OP_ALL",
SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
PyModule_AddIntConstant(m, "OP_NO_SSLv2", SSL_OP_NO_SSLv2);
PyModule_AddIntConstant(m, "OP_NO_SSLv3", SSL_OP_NO_SSLv3);
PyModule_AddIntConstant(m, "OP_NO_TLSv1", SSL_OP_NO_TLSv1);
PyModule_AddIntConstant(m, "OP_NO_TLSv1_1", SSL_OP_NO_TLSv1_1);
PyModule_AddIntConstant(m, "OP_NO_TLSv1_2", SSL_OP_NO_TLSv1_2);
ADD_OPTION("OP_ALL", SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
ADD_OPTION("OP_NO_SSLv2", SSL_OP_NO_SSLv2);
ADD_OPTION("OP_NO_SSLv3", SSL_OP_NO_SSLv3);
ADD_OPTION("OP_NO_TLSv1", SSL_OP_NO_TLSv1);
ADD_OPTION("OP_NO_TLSv1_1", SSL_OP_NO_TLSv1_1);
ADD_OPTION("OP_NO_TLSv1_2", SSL_OP_NO_TLSv1_2);
#ifdef SSL_OP_NO_TLSv1_3
PyModule_AddIntConstant(m, "OP_NO_TLSv1_3", SSL_OP_NO_TLSv1_3);
ADD_OPTION("OP_NO_TLSv1_3", SSL_OP_NO_TLSv1_3);
#else
PyModule_AddIntConstant(m, "OP_NO_TLSv1_3", 0);
ADD_OPTION("OP_NO_TLSv1_3", 0);
#endif
PyModule_AddIntConstant(m, "OP_CIPHER_SERVER_PREFERENCE",
ADD_OPTION("OP_CIPHER_SERVER_PREFERENCE",
SSL_OP_CIPHER_SERVER_PREFERENCE);
PyModule_AddIntConstant(m, "OP_SINGLE_DH_USE", SSL_OP_SINGLE_DH_USE);
PyModule_AddIntConstant(m, "OP_NO_TICKET", SSL_OP_NO_TICKET);
PyModule_AddIntConstant(m, "OP_LEGACY_SERVER_CONNECT",
ADD_OPTION("OP_SINGLE_DH_USE", SSL_OP_SINGLE_DH_USE);
ADD_OPTION("OP_NO_TICKET", SSL_OP_NO_TICKET);
ADD_OPTION("OP_LEGACY_SERVER_CONNECT",
SSL_OP_LEGACY_SERVER_CONNECT);
#ifdef SSL_OP_SINGLE_ECDH_USE
PyModule_AddIntConstant(m, "OP_SINGLE_ECDH_USE", SSL_OP_SINGLE_ECDH_USE);
ADD_OPTION("OP_SINGLE_ECDH_USE", SSL_OP_SINGLE_ECDH_USE);
#endif
#ifdef SSL_OP_NO_COMPRESSION
PyModule_AddIntConstant(m, "OP_NO_COMPRESSION",
ADD_OPTION("OP_NO_COMPRESSION",
SSL_OP_NO_COMPRESSION);
#endif
#ifdef SSL_OP_ENABLE_MIDDLEBOX_COMPAT
PyModule_AddIntConstant(m, "OP_ENABLE_MIDDLEBOX_COMPAT",
ADD_OPTION("OP_ENABLE_MIDDLEBOX_COMPAT",
SSL_OP_ENABLE_MIDDLEBOX_COMPAT);
#endif
#ifdef SSL_OP_NO_RENEGOTIATION
PyModule_AddIntConstant(m, "OP_NO_RENEGOTIATION",
ADD_OPTION("OP_NO_RENEGOTIATION",
SSL_OP_NO_RENEGOTIATION);
#endif
#ifdef SSL_OP_IGNORE_UNEXPECTED_EOF
PyModule_AddIntConstant(m, "OP_IGNORE_UNEXPECTED_EOF",
ADD_OPTION("OP_IGNORE_UNEXPECTED_EOF",
SSL_OP_IGNORE_UNEXPECTED_EOF);
#endif
#ifdef SSL_OP_ENABLE_KTLS
PyModule_AddIntConstant(m, "OP_ENABLE_KTLS", SSL_OP_ENABLE_KTLS);
ADD_OPTION("OP_ENABLE_KTLS", SSL_OP_ENABLE_KTLS);
#endif
#ifdef X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT