Skip to content

Commit 5f0ce44

Browse files
[3.14] gh-114905: Test that ssl._create_stdlib_context() rejects check_hostname with CERT_NONE (GH-155509) (GH-155671)
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 5a29b99 commit 5f0ce44

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
@@ -1744,6 +1744,35 @@ def test__create_stdlib_context(self):
17441744
self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
17451745
self._assert_context_options(ctx)
17461746

1747+
def test__create_stdlib_context_check_hostname(self):
1748+
# gh-114905: check_hostname cannot be combined with CERT_NONE,
1749+
# the default for cert_reqs.
1750+
msg = "Cannot set verify_mode to CERT_NONE when check_hostname"
1751+
with self.assertRaisesRegex(ValueError, msg):
1752+
ssl._create_stdlib_context(check_hostname=True)
1753+
with self.assertRaisesRegex(ValueError, msg):
1754+
ssl._create_stdlib_context(cert_reqs=ssl.CERT_NONE,
1755+
check_hostname=True)
1756+
1757+
# Accepted before 3.10 with a legacy protocol.
1758+
if has_tls_protocol('PROTOCOL_TLSv1_2'):
1759+
with warnings_helper.check_warnings():
1760+
with self.assertRaisesRegex(ValueError, msg):
1761+
ssl._create_stdlib_context(ssl.PROTOCOL_TLSv1_2,
1762+
cert_reqs=ssl.CERT_NONE,
1763+
check_hostname=True)
1764+
1765+
# cert_reqs=None leaves PROTOCOL_TLS_CLIENT's CERT_REQUIRED.
1766+
ctx = ssl._create_stdlib_context(cert_reqs=None, check_hostname=True)
1767+
self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
1768+
self.assertTrue(ctx.check_hostname)
1769+
1770+
# CERT_REQUIRED is covered by test__create_stdlib_context().
1771+
ctx = ssl._create_stdlib_context(cert_reqs=ssl.CERT_OPTIONAL,
1772+
check_hostname=True)
1773+
self.assertEqual(ctx.verify_mode, ssl.CERT_OPTIONAL)
1774+
self.assertTrue(ctx.check_hostname)
1775+
17471776
def test_check_hostname(self):
17481777
with warnings_helper.check_warnings():
17491778
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)

0 commit comments

Comments
 (0)