https://github.com/python/cpython/commit/726e48565670e56affd3e6d461871ec20ee12694
commit: 726e48565670e56affd3e6d461871ec20ee12694
branch: main
author: Serhiy Storchaka <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2026-08-13T12:43:40+03:00
summary:
gh-114905: Test that ssl._create_stdlib_context() rejects check_hostname with
CERT_NONE (GH-155509)
With PROTOCOL_TLS_CLIENT, which became the default protocol in 3.10, this is
an error. With an explicitly specified legacy protocol it used to succeed,
silently raising verify_mode to CERT_REQUIRED and ignoring the requested
CERT_NONE.
No caller of ssl._create_stdlib_context() in the standard library passes
check_hostname, so no public API reaches it.
files:
M Lib/ssl.py
M Lib/test/test_ssl.py
diff --git a/Lib/ssl.py b/Lib/ssl.py
index db66c59c05cc54..dc957121728f28 100644
--- a/Lib/ssl.py
+++ b/Lib/ssl.py
@@ -754,6 +754,8 @@ def _create_unverified_context(protocol=None, *,
cert_reqs=CERT_NONE,
raise ValueError(purpose)
context = SSLContext(protocol)
+ # Setting verify_mode to CERT_NONE fails while check_hostname is
+ # enabled, so assign check_hostname first (gh-114905).
context.check_hostname = check_hostname
if cert_reqs is not None:
context.verify_mode = cert_reqs
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
index 6446f96eab42a4..2bba665d19343e 100644
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -1817,6 +1817,35 @@ def test__create_stdlib_context(self):
self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
self._assert_context_options(ctx)
+ def test__create_stdlib_context_check_hostname(self):
+ # gh-114905: check_hostname cannot be combined with CERT_NONE,
+ # the default for cert_reqs.
+ msg = "Cannot set verify_mode to CERT_NONE when check_hostname"
+ with self.assertRaisesRegex(ValueError, msg):
+ ssl._create_stdlib_context(check_hostname=True)
+ with self.assertRaisesRegex(ValueError, msg):
+ ssl._create_stdlib_context(cert_reqs=ssl.CERT_NONE,
+ check_hostname=True)
+
+ # Accepted before 3.10 with a legacy protocol.
+ if has_tls_protocol('PROTOCOL_TLSv1_2'):
+ with warnings_helper.check_warnings():
+ with self.assertRaisesRegex(ValueError, msg):
+ ssl._create_stdlib_context(ssl.PROTOCOL_TLSv1_2,
+ cert_reqs=ssl.CERT_NONE,
+ check_hostname=True)
+
+ # cert_reqs=None leaves PROTOCOL_TLS_CLIENT's CERT_REQUIRED.
+ ctx = ssl._create_stdlib_context(cert_reqs=None, check_hostname=True)
+ self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
+ self.assertTrue(ctx.check_hostname)
+
+ # CERT_REQUIRED is covered by test__create_stdlib_context().
+ ctx = ssl._create_stdlib_context(cert_reqs=ssl.CERT_OPTIONAL,
+ check_hostname=True)
+ self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
+ self.assertTrue(ctx.check_hostname)
+
def test_check_hostname(self):
with warnings_helper.check_warnings():
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]