https://github.com/python/cpython/commit/8dde46eaa6baf5f027a7234845b20d50b509624e
commit: 8dde46eaa6baf5f027a7234845b20d50b509624e
branch: main
author: Brett Smith <[email protected]>
committer: StanFromIreland <[email protected]>
date: 2026-11-07T19:07:53Z
summary:

gh-161503: Check hostname in `ssl.get_server_certificate` with custom 
`ca_certs` (#161507)

files:
A Misc/NEWS.d/next/Security/2026-11-06-16-22-47.gh-issue-161503.FkIl87.rst
M Doc/library/ssl.rst
M Lib/ssl.py
M Lib/test/test_ssl.py

diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst
index d177abd48fa9cd4..020a8ab7301b6b7 100644
--- a/Doc/library/ssl.rst
+++ b/Doc/library/ssl.rst
@@ -432,7 +432,8 @@ Certificate handling
    same format as used for the *cafile* parameter in
    :meth:`SSLContext.load_verify_locations`.  The call will attempt to 
validate the
    server certificate against that set of root certificates, and will fail
-   if the validation attempt fails.  A timeout can be specified with the
+   if the validation attempt fails or the certificate hostname does not match
+   the server hostname.  A timeout can be specified with the
    ``timeout`` parameter.
 
    .. versionchanged:: 3.3
@@ -445,6 +446,11 @@ Certificate handling
    .. versionchanged:: 3.10
       The *timeout* parameter was added.
 
+   .. versionchanged:: next
+      The function now raises :exc:`SSLCertVerificationError` if *ca_certs* is
+      specified but the certificate hostname does not match the server
+      hostname.
+
 .. function:: DER_cert_to_PEM_cert(der_cert_bytes)
 
    Given a certificate as a DER-encoded blob of bytes, returns a PEM-encoded
diff --git a/Lib/ssl.py b/Lib/ssl.py
index df2eece13f2b138..49eec9cde0b6317 100644
--- a/Lib/ssl.py
+++ b/Lib/ssl.py
@@ -1638,7 +1638,8 @@ def get_server_certificate(addr, 
ssl_version=PROTOCOL_TLS_CLIENT,
                            ca_certs=None, timeout=_GLOBAL_DEFAULT_TIMEOUT):
     """Retrieve the certificate from the server at the specified address,
     and return it as a PEM-encoded string.
-    If 'ca_certs' is specified, validate the server cert against it.
+    If 'ca_certs' is specified, validate the server cert against it and
+    check that it matches the hostname.
     If 'ssl_version' is specified, use it in the connection attempt.
     If 'timeout' is specified, use it in the connection attempt.
     """
@@ -1650,6 +1651,7 @@ def get_server_certificate(addr, 
ssl_version=PROTOCOL_TLS_CLIENT,
         cert_reqs = CERT_NONE
     context = _create_stdlib_context(ssl_version,
                                      cert_reqs=cert_reqs,
+                                     check_hostname=ca_certs is not None,
                                      cafile=ca_certs)
     with create_connection(addr, timeout=timeout) as sock:
         with context.wrap_socket(sock, server_hostname=host) as sslsock:
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
index 5b4e4f080607726..b0e3cbaa548e8d5 100644
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -3112,6 +3112,10 @@ def test_get_server_certificate_fail(self):
         # independent test method
         _test_get_server_certificate_fail(self, *self.server_addr)
 
+    def test_get_server_certificate_fail_by_hostname(self):
+        _, port = self.server_addr
+        _test_get_server_certificate_fail(self, socket_helper.HOSTv4, port, 
SIGNING_CA)
+
     def test_get_server_certificate_timeout(self):
         def servername_cb(ssl_sock, server_name, initial_context):
             time.sleep(0.2)
@@ -3364,10 +3368,10 @@ def _test_get_server_certificate(test, host, port, 
cert=None):
     if support.verbose:
         sys.stdout.write("\nVerified certificate for %s:%s is\n%s\n" % (host, 
port ,pem))
 
-def _test_get_server_certificate_fail(test, host, port):
+def _test_get_server_certificate_fail(test, host, port, ca_certs=CERTFILE):
     with warnings_helper.check_no_resource_warning(test):
         try:
-            pem = ssl.get_server_certificate((host, port), ca_certs=CERTFILE)
+            pem = ssl.get_server_certificate((host, port), ca_certs=ca_certs)
         except ssl.SSLError as x:
             #should fail
             if support.verbose:
diff --git 
a/Misc/NEWS.d/next/Security/2026-11-06-16-22-47.gh-issue-161503.FkIl87.rst 
b/Misc/NEWS.d/next/Security/2026-11-06-16-22-47.gh-issue-161503.FkIl87.rst
new file mode 100644
index 000000000000000..308ba0c83f3efe4
--- /dev/null
+++ b/Misc/NEWS.d/next/Security/2026-11-06-16-22-47.gh-issue-161503.FkIl87.rst
@@ -0,0 +1,4 @@
+.. cve: CVE-2026-19552
+
+:func:`ssl.get_server_certificate` now verifies that the server hostname 
matches
+its certificate when the caller specifies *ca_certs*.

_______________________________________________
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]

Reply via email to