Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set the SNI via http.client.HTTPSConnection

Tags:

python

ssl

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

like image 995
firebush Avatar asked Oct 28 '25 06:10

firebush


1 Answers

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.

like image 98
firebush Avatar answered Oct 29 '25 20:10

firebush



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!