https://github.com/python/cpython/commit/5f0ce4461af2ee24fbc60f45f466ce8e348b9189 commit: 5f0ce4461af2ee24fbc60f45f466ce8e348b9189 branch: 3.14 author: Miss Islington (bot) <[email protected]> committer: serhiy-storchaka <[email protected]> date: 2026-08-13T10:12:43Z summary:
[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 726e48565670e56affd3e6d461871ec20ee12694) Co-authored-by: Serhiy Storchaka <[email protected]> files: M Lib/ssl.py M Lib/test/test_ssl.py diff --git a/Lib/ssl.py b/Lib/ssl.py index 8889aff92fa6c0..258ae1433eebf2 100644 --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -755,6 +755,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 91bfb408bb9965..d845a39b68e4d4 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -1744,6 +1744,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]
