Skip to content

Commit 726e485

Browse files
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.
1 parent 7586115 commit 726e485

2 files changed

Lines changed: 31 additions & 0 deletions

File tree

Lib/ssl.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -754,6 +754,8 @@ def _create_unverified_context(protocol=None, *, cert_reqs=CERT_NONE,
754754
raise ValueError(purpose)
755755

756756
context = SSLContext(protocol)
757+
# Setting verify_mode to CERT_NONE fails while check_hostname is
758+
# enabled, so assign check_hostname first (gh-114905).
757759
context.check_hostname = check_hostname
758760
if cert_reqs is not None:
759761
context.verify_mode = cert_reqs

Lib/test/test_ssl.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1817,6 +1817,35 @@ def test__create_stdlib_context(self):
18171817
self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
18181818
self._assert_context_options(ctx)
18191819

1820+
def test__create_stdlib_context_check_hostname(self):
1821+
# gh-114905: check_hostname cannot be combined with CERT_NONE,
1822+
# the default for cert_reqs.
1823+
msg = "Cannot set verify_mode to CERT_NONE when check_hostname"
1824+
with self.assertRaisesRegex(ValueError, msg):
1825+
ssl._create_stdlib_context(check_hostname=True)
1826+
with self.assertRaisesRegex(ValueError, msg):
1827+
ssl._create_stdlib_context(cert_reqs=ssl.CERT_NONE,
1828+
check_hostname=True)
1829+
1830+
# Accepted before 3.10 with a legacy protocol.
1831+
if has_tls_protocol('PROTOCOL_TLSv1_2'):
1832+
with warnings_helper.check_warnings():
1833+
with self.assertRaisesRegex(ValueError, msg):
1834+
ssl._create_stdlib_context(ssl.PROTOCOL_TLSv1_2,
1835+
cert_reqs=ssl.CERT_NONE,
1836+
check_hostname=True)
1837+
1838+
# cert_reqs=None leaves PROTOCOL_TLS_CLIENT's CERT_REQUIRED.
1839+
ctx = ssl._create_stdlib_context(cert_reqs=None, check_hostname=True)
1840+
self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1841+
self.assertTrue(ctx.check_hostname)
1842+
1843+
# CERT_REQUIRED is covered by test__create_stdlib_context().
1844+
ctx = ssl._create_stdlib_context(cert_reqs=ssl.CERT_OPTIONAL,
1845+
check_hostname=True)
1846+
self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
1847+
self.assertTrue(ctx.check_hostname)
1848+
18201849
def test_check_hostname(self):
18211850
with warnings_helper.check_warnings():
18221851
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)

0 commit comments

Comments
 (0)