Search code examples
pythonsecuritysslopenssltls1.3

Python SSL Verify Alternative Domain


I intend to connect to the remote host example.com over TLS but I have to connect through a proxy IP address with DNS name example-proxy.com.

I don't have control over the SSL certificate and I cannot ask the admin at example.com to add example-proxy.com to its certificate's SAN.

Using example-prxoy.com would cause OpenSSL to error out because the host name does not match the name in the certificate. How can I split the host parameter into two: (1) domain name for the network connection and (2) domain name for the certificate verification.

I don't have the resources to modify the OpenSSL library but I can make changes to the Python libraries. According to this doc, I could have modified the match_hostname method to implement this feature but it is no longer available as of Python 3.7+.

Asks

  1. How can I use Python 3.7+ to specify both a host name and a certificate name?
  2. From the security standpoint, How could my implementation go wrong?

Solution

  • Just give a different hostname for TCP connection and TLS handshake, i.e. set server_hostname in wrap_socket. To modify the example from the official documentation for this:

    import socket
    import ssl
    
    tls_hostname = 'www.example.com'
    context = ssl.create_default_context()
    
    with socket.create_connection(('127.0.0.1',8443)) as sock:
        with context.wrap_socket(sock, server_hostname=tls_hostname) as ssock:
            print(ssock.version())
    

    This will connect to ('127.0.0.1',8443) but do the TLS handshake with www.example.com. Note that this will use tls_hostname for both SNI extension in the TLS handshake and for validating the certificate. But this seems to be what you need based on your question anyway: connect to IP:port but do TLS handshake and validation with a specific hostname.