Reputation: 5850
I'm using http.client.HTTPSConnection to generate an HTTPS connection to my server. I cannot use the original hostname to connect to the server since this is a test setup but I need to do a proper TLS handshake with the right hostname as SNI. How do I set the SNI for the client hello of the HTTPS connection?
Judging from ssl.SSLSocket.server_hostname, if I could access the underlying socket I should be able to set server_hostname on it to the value I want. HTTPSConnection
does indeed have a sock
member, but it is None
after construction.
In case more source code context is helpful, I'm working on the test proxy in proxy-verifier. See proxy_http1.py#L94
Upvotes: 4
Views: 2093
Reputation: 5850
Steffen Ullrich guided me to the answer. There is no direct support to pass two different host names a) to connect to and b) to send via SNI and verify the certificate against. However, http.client.HTTPSConnection
calls the ssl.SSLContext.wrap_socket function off of the SSLContext passed in. This code example leverages this with a simple wrapper:
hostname_connect = '192.168.1.3'
hostname_sni = 'www.example.com'
class WrapSSLContext(ssl.SSLContext):
def wrap_socket(self, *args, **kwargs):
kwargs['server_hostname'] = hostname_sni
return super().wrap_socket(*args, **kwargs)
context = WrapSSLContext(ssl.PROTOCOL_TLS_CLIENT)
context.load_default_certs()
connection = http.client.HTTPSConnection(hostname_connect, context=context)
Contexts created with ssl.PROTOCOL_TLS_CLIENT
have context.check_hostname
set by default. And thus, context.verify_mode = ssl.CERT_REQUIRED
as well.
Upvotes: 5