Skip to content

Commit 427dfa6

Browse files
[3.13] gh-114905: Test that ssl._create_stdlib_context() rejects check_hostname with CERT_NONE (GH-155509) (GH-155670)
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. (cherry picked from commit 726e485) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
1 parent 35b1794 commit 427dfa6

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
@@ -755,6 +755,8 @@ def _create_unverified_context(protocol=None, *, cert_reqs=CERT_NONE,
755755
raise ValueError(purpose)
756756

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

Lib/test/test_ssl.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1715,6 +1715,35 @@ def test__create_stdlib_context(self):
17151715
self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
17161716
self._assert_context_options(ctx)
17171717

1718+
def test__create_stdlib_context_check_hostname(self):
1719+
# gh-114905: check_hostname cannot be combined with CERT_NONE,
1720+
# the default for cert_reqs.
1721+
msg = "Cannot set verify_mode to CERT_NONE when check_hostname"
1722+
with self.assertRaisesRegex(ValueError, msg):
1723+
ssl._create_stdlib_context(check_hostname=True)
1724+
with self.assertRaisesRegex(ValueError, msg):
1725+
ssl._create_stdlib_context(cert_reqs=ssl.CERT_NONE,
1726+
check_hostname=True)
1727+
1728+
# Accepted before 3.10 with a legacy protocol.
1729+
if has_tls_protocol('PROTOCOL_TLSv1_2'):
1730+
with warnings_helper.check_warnings():
1731+
with self.assertRaisesRegex(ValueError, msg):
1732+
ssl._create_stdlib_context(ssl.PROTOCOL_TLSv1_2,
1733+
cert_reqs=ssl.CERT_NONE,
1734+
check_hostname=True)
1735+
1736+
# cert_reqs=None leaves PROTOCOL_TLS_CLIENT's CERT_REQUIRED.
1737+
ctx = ssl._create_stdlib_context(cert_reqs=None, check_hostname=True)
1738+
self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1739+
self.assertTrue(ctx.check_hostname)
1740+
1741+
# CERT_REQUIRED is covered by test__create_stdlib_context().
1742+
ctx = ssl._create_stdlib_context(cert_reqs=ssl.CERT_OPTIONAL,
1743+
check_hostname=True)
1744+
self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
1745+
self.assertTrue(ctx.check_hostname)
1746+
17181747
def test_check_hostname(self):
17191748
with warnings_helper.check_warnings():
17201749
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)

0 commit comments

Comments
 (0)