10000 [3.12] gh-106687: _ssl: use uint64_t for SSL options (GH-106700) (#10… · python/cpython@497bfd5 · GitHub
[go: up one dir, main page]

Skip to content

Commit 497bfd5

Browse files
[3.12] gh-106687: _ssl: use uint64_t for SSL options (GH-106700) (#106827)
gh-106687: _ssl: use uint64_t for SSL options (GH-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 (cherry picked from commit ad95c72) Co-authored-by: Victor Stinner <vstinner@python.org>
1 parent 11b3d38 commit 497bfd5

File tree

2 files changed

+78
-26
lines changed

2 files changed

+78
-26
lines changed

Lib/test/test_ssl.py

Lines changed: 24 additions & 0 deletions
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

Lines changed: 54 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2996,7 +2996,7 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version)
29962996
/*[clinic end generated code: output=2cf0d7a0741b6bd1 input=8d58a805b95fc534]*/
29972997
{
29982998
PySSLContext *self;
2999-
long options;
2999+
uint64_t options;
30003000
const SSL_METHOD *method = NULL;
30013001
SSL_CTX *ctx = NULL;
30023002
X509_VERIFY_PARAM *params;
@@ -3594,20 +3594,32 @@ PyDoc_STRVAR(PySSLContext_security_level_doc, "The current security level");
35943594
static PyObject *
35953595
get_options(PySSLContext *self, void *c)
35963596
{
3597-
return PyLong_FromLong(SSL_CTX_get_options(self->ctx));
3597+
uint64_t options = SSL_CTX_get_options(self->ctx);
3598+
Py_BUILD_ASSERT(sizeof(unsigned long long) >= sizeof(options));
3599+
return PyLong_FromUnsignedLongLong(options);
35983600
}
35993601

36003602
static int
36013603
set_options(PySSLContext *self, PyObject *arg, void *c)
36023604
{
3603-
long new_opts, opts, set, clear;
3604-
long opt_no = (
3605+
PyObject *new_opts_obj;
3606+
unsigned long long new_opts_arg;
3607+
uint64_t new_opts, opts, clear, set;
3608+
uint64_t opt_no = (
36053609
SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 |
36063610
SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2 | SSL_OP_NO_TLSv1_3
36073611
);
36083612

3609-
if (!PyArg_Parse(arg, "l", &new_opts))
3613+
if (!PyArg_Parse(arg, "O!", &PyLong_Type, &new_opts_obj)) {
36103614
return -1;
3615+
}
3616+
new_opts_arg = PyLong_AsUnsignedLongLong(new_opts_obj);
3617+
if (new_opts_arg == (unsigned long long)-1 && PyErr_Occurred()) {
3618+
return -1;
3619+
}
3620+
Py_BUILD_ASSERT(sizeof(new_opts) >= sizeof(new_opts_arg));
3621+
new_opts = (uint64_t)new_opts_arg;
3622+
36113623
opts = SSL_CTX_get_options(self->ctx);
36123624
clear = opts & ~new_opts;
36133625
set = ~opts & new_opts;
@@ -3621,8 +3633,9 @@ set_options(PySSLContext *self, PyObject *arg, void *c)
36213633
if (clear) {
36223634
SSL_CTX_clear_options(self->ctx, clear);
36233635
}
3624-
if (set)
3636+
if (set) {
36253637
SSL_CTX_set_options(self->ctx, set);
3638+
}
36263639
return 0;
36273640
}
36283641

@@ -5731,10 +5744,24 @@ sslmodule_init_socketapi(PyObject *module)
57315744
return 0;
57325745
}
57335746

5747+
57345748
static int
5735-
sslmodule_init_constants(PyObject *m)
5749+
sslmodule_add_option(PyObject *m, const char *name, uint64_t value)
57365750
{
5751+
Py_BUILD_ASSERT(sizeof(unsigned long long) >= sizeof(value));
5752+
PyObject *obj = PyLong_FromUnsignedLongLong(value);
5753+
if (obj == NULL) {
5754+
return -1;
5755+
}
5756+
int res = PyModule_AddObjectRef(m, name, obj);
5757+
Py_DECREF(obj);
5758+
return res;
5759+
}
5760+
57375761

5762+
static int
5763+
sslmodule_init_constants(PyObject *m)
5764+
{
57385765
PyModule_AddStringConstant(m, "_DEFAULT_CIPHERS",
57395766
PY_SSL_DEFAULT_CIPHER_STRING);
57405767

@@ -5854,46 +5881,47 @@ sslmodule_init_constants(PyObject *m)
58545881
PyModule_AddIntConstant(m, "PROTOCOL_TLSv1_2",
58555882
PY_SSL_VERSION_TLS1_2);
58565883

5884+
#define ADD_OPTION(NAME, VALUE) if (sslmodule_add_option(m, NAME, (VALUE)) < 0) return -1
5885+
58575886
/* protocol options */
5858-
PyModule_AddIntConstant(m, "OP_ALL",
5859-
SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
5860-
PyModule_AddIntConstant(m, "OP_NO_SSLv2", SSL_OP_NO_SSLv2);
5861-
PyModule_AddIntConstant(m, "OP_NO_SSLv3", SSL_OP_NO_SSLv3);
5862-
PyModule_AddIntConstant(m, "OP_NO_TLSv1", SSL_OP_NO_TLSv1);
5863-
PyModule_AddIntConstant(m, "OP_NO_TLSv1_1", SSL_OP_NO_TLSv1_1);
5864-
PyModule_AddIntConstant(m, "OP_NO_TLSv1_2", SSL_OP_NO_TLSv1_2);
5887+
ADD_OPTION("OP_ALL", SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
5888+
ADD_OPTION("OP_NO_SSLv2", SSL_OP_NO_SSLv2);
5889+
ADD_OPTION("OP_NO_SSLv3", SSL_OP_NO_SSLv3);
5890+
ADD_OPTION("OP_NO_TLSv1", SSL_OP_NO_TLSv1);
5891+
ADD_OPTION("OP_NO_TLSv1_1", SSL_OP_NO_TLSv1_1);
5892+
ADD_OPTION("OP_NO_TLSv1_2", SSL_OP_NO_TLSv1_2);
58655893
#ifdef SSL_OP_NO_TLSv1_3
5866-
PyModule_AddIntConstant(m, "OP_NO_TLSv1_3", SSL_OP_NO_TLSv1_3);
5894+
ADD_OPTION("OP_NO_TLSv1_3", SSL_OP_NO_TLSv1_3);
58675895
#else
5868-
PyModule_AddIntConstant(m, "OP_NO_TLSv1_3", 0);
5896+
ADD_OPTION("OP_NO_TLSv1_3", 0);
58695897
#endif
5870-
PyModule_AddIntConstant(m, "OP_CIPHER_SERVER_PREFERENCE",
5898+
ADD_OPTION("OP_CIPHER_SERVER_PREFERENCE",
58715899
SSL_OP_CIPHER_SERVER_PREFERENCE);
5872-
PyModule_AddIntConstant(m, "OP_SINGLE_DH_USE", SSL_OP_SINGLE_DH_USE);
5873-
PyModule_AddIntConstant(m, "OP_NO_TICKET", SSL_OP_NO_TICKET);
5874-
PyModule_AddIntConstant(m, "OP_LEGACY_SERVER_CONNECT",
5900+
ADD_OPTION("OP_SINGLE_DH_USE", SSL_OP_SINGLE_DH_USE);
5901+
ADD_OPTION("OP_NO_TICKET", SSL_OP_NO_TICKET);
5902+
ADD_OPTION("OP_LEGACY_SERVER_CONNECT",
58755903
SSL_OP_LEGACY_SERVER_CONNECT);
58765904
#ifdef SSL_OP_SINGLE_ECDH_USE
5877-
PyModule_AddIntConstant(m, "OP_SINGLE_ECDH_USE", SSL_OP_SINGLE_ECDH_USE);
5905+
ADD_OPTION("OP_SINGLE_ECDH_USE", SSL_OP_SINGLE_ECDH_USE);
58785906
#endif
58795907
#ifdef SSL_OP_NO_COMPRESSION
5880-
PyModule_AddIntConstant(m, "OP_NO_COMPRESSION",
5908+
ADD_OPTION("OP_NO_COMPRESSION",
58815909
SSL_OP_NO_COMPRESSION);
58825910
#endif
58835911
#ifdef SSL_OP_ENABLE_MIDDLEBOX_COMPAT
5884-
PyModule_AddIntConstant(m, "OP_ENABLE_MIDDLEBOX_COMPAT",
5912+
ADD_OPTION("OP_ENABLE_MIDDLEBOX_COMPAT",
58855913
SSL_OP_ENABLE_MIDDLEBOX_COMPAT);
58865914
#endif
58875915
#ifdef SSL_OP_NO_RENEGOTIATION
5888-
PyModule_AddIntConstant(m, "OP_NO_RENEGOTIATION",
5916+
ADD_OPTION("OP_NO_RENEGOTIATION",
58895917
SSL_OP_NO_RENEGOTIATION);
58905918
#endif
58915919
#ifdef SSL_OP_IGNORE_UNEXPECTED_EOF
5892-
PyModule_AddIntConstant(m, "OP_IGNORE_UNEXPECTED_EOF",
5920+
ADD_OPTION("OP_IGNORE_UNEXPECTED_EOF",
58935921
SSL_OP_IGNORE_UNEXPECTED_EOF);
58945922
#endif
58955923
#ifdef SSL_OP_ENABLE_KTLS
5896-
PyModule_AddIntConstant(m, "OP_ENABLE_KTLS", SSL_OP_ENABLE_KTLS);
5924+
ADD_OPTION("OP_ENABLE_KTLS", SSL_OP_ENABLE_KTLS);
58975925
#endif
58985926

58995927
#ifdef X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT

0 commit comments

Comments
 (0)
0