Skip to content

bpo-36076: Add SNI support to ssl.get_server_certificate. #16820

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Lib/ssl.py
Original file line number Diff line number Diff line change
Expand Up @@ -1475,7 +1475,7 @@ def get_server_certificate(addr, ssl_version=PROTOCOL_TLS, ca_certs=None):
cert_reqs=cert_reqs,
cafile=ca_certs)
with create_connection(addr) as sock:
with context.wrap_socket(sock) as sslsock:
with context.wrap_socket(sock, server_hostname=host) as sslsock:
dercert = sslsock.getpeercert(True)
return DER_cert_to_PEM_cert(dercert)

Expand Down
26 changes: 25 additions & 1 deletion Lib/test/test_ssl.py
Original file line number Diff line number Diff line change
Expand Up @@ -1962,7 +1962,9 @@ class SimpleBackgroundTests(unittest.TestCase):
"""Tests that connect to a simple server running in the background"""

def setUp(self):
server = ThreadedEchoServer(SIGNED_CERTFILE)
self.server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
self.server_context.load_cert_chain(SIGNED_CERTFILE)
server = ThreadedEchoServer(context=self.server_context)
self.server_addr = (HOST, server.port)
server.__enter__()
self.addCleanup(server.__exit__, None, None, None)
Expand Down Expand Up @@ -2143,6 +2145,28 @@ def test_non_blocking_handshake(self):
def test_get_server_certificate(self):
_test_get_server_certificate(self, *self.server_addr, cert=SIGNING_CA)

@needs_sni
def test_get_server_certificate_sni(self):
host, port = self.server_addr
server_names = []

# We store servername_cb arguments to make sure they match the host
def servername_cb(ssl_sock, server_name, initial_context):
server_names.append(server_name)
self.server_context.set_servername_callback(servername_cb)

pem = ssl.get_server_certificate((host, port))
if not pem:
self.fail("No server certificate on %s:%s!" % (host, port))

pem = ssl.get_server_certificate((host, port), ca_certs=SIGNING_CA)
if not pem:
self.fail("No server certificate on %s:%s!" % (host, port))
if support.verbose:
sys.stdout.write("\nVerified certificate for %s:%s is\n%s\n" % (host, port, pem))

self.assertEqual(server_names, [host, host])

def test_get_server_certificate_fail(self):
# Connection failure crashes ThreadedEchoServer, so run this in an
# independent test method
Expand Down
1 change: 1 addition & 0 deletions Misc/ACKS
Original file line number Diff line number Diff line change
Expand Up @@ -1803,6 +1803,7 @@ Michael Urman
Hector Urtubia
Elizabeth Uselton
Lukas Vacek
Juho Vähä-Herttua
Ville Vainio
Yann Vaginay
Andi Vajda
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added SNI support to :func:`ssl.get_server_certificate`.