Urllib3 & MITMProxy: sslv3 alert handshake failure

1.7k views Asked by At

My client is on urllib3 HTTPSConnectionPool. I've installed a SSL version 1 certificate to the server and it works fine on request. Certificate for my server

On next instance of HTTPSConnectionPool, I've used a proxy to intercept. The problem is that client exits with following traceback:

Traceback (most recent call last):
  File "/home/user/Documents/project/cert-pinning/lib/python3.8/site-packages/urllib3/connectionpool.py", line 667, in urlopen
    self._prepare_proxy(conn)
  File "/home/user/Documents/project/cert-pinning/lib/python3.8/site-packages/urllib3/connectionpool.py", line 932, in _prepare_proxy
    conn.connect()
  File "/home/user/Documents/project/cert-pinning/lib/python3.8/site-packages/urllib3/connection.py", line 362, in connect
    self.sock = ssl_wrap_socket(
  File "/home/user/Documents/project/cert-pinning/lib/python3.8/site-packages/urllib3/util/ssl_.py", line 384, in ssl_wrap_socket
    return context.wrap_socket(sock, server_hostname=server_hostname)
  File "/usr/lib/python3.8/ssl.py", line 500, in wrap_socket
    return self.sslsocket_class._create(
  File "/usr/lib/python3.8/ssl.py", line 1040, in _create
    self.do_handshake()
  File "/usr/lib/python3.8/ssl.py", line 1309, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1123)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "client2.py", line 76, in <module>
    r = pool_with_proxy.urlopen('GET', '/')
  File "/home/user/Documents/project/cert-pinning/lib/python3.8/site-packages/urllib3/connectionpool.py", line 754, in urlopen
    return self.urlopen(
  File "/home/user/Documents/project/cert-pinning/lib/python3.8/site-packages/urllib3/connectionpool.py", line 754, in urlopen
    return self.urlopen(
  File "/home/user/Documents/project/cert-pinning/lib/python3.8/site-packages/urllib3/connectionpool.py", line 754, in urlopen
    return self.urlopen(
  File "/home/user/Documents/project/cert-pinning/lib/python3.8/site-packages/urllib3/connectionpool.py", line 726, in urlopen
    retries = retries.increment(
  File "/home/user/Documents/project/cert-pinning/lib/python3.8/site-packages/urllib3/util/retry.py", line 439, in increment
    raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: TestHTTPSConnectionPool(host='https://cod-avatar.com', port=8000): Max retries exceeded with url: / (Caused by SSLError(SSLError(1, '[SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1123)')))

I am pretty sure its due to the Version 3 certificate of HTTPS_PROXY.

HTTPS Proxy Certificate

I want to know. How do I enable Version 3 certificate for my urllib3 client.

UPDATE:

My certificates are all self-signed. When I start the mitmproxy without defining my ca-certs. It gives Bad Gateway which is obvious as it wont trust my certificates.

Certificate verification error for cod****.com: unable to get local issuer certificate (errno: 20, depth: 0)

But when I define my ca-certs while starting mitmproxy

mitmweb --cacerts cod*****.com=new-cacert.pem

The previous stack trace occurs

Trying with curl:

curl -X GET "https://cod*****.com:8000" --cacert new/new-cacert.pem --proxy 127.0.0.1:6666

also gives following response, but works fine without proxy

curl: (35) error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure

1

There are 1 answers

5
Steffen Ullrich On

The version of the certificate has nothing to do with the error you see. The certificate version is about using X509v1 vs. X509v3 certificates and you should better use the latter. The error instead is about the TLS protocol version. Both X509v1 and X509v3 certificates can be used with different TLS protocol versions, so both "versions" are unrelated to the other.

And the error message is likely not really abut the TLS protocol version either. My guess is instead that you simply try to access a plain HTTP site with HTTPS. An indicator for this is the use of port 8000 which is commonly associated with plain HTTP.

When sending a HTTPS request to a plain HTTP server one will usually get a plain HTTP response back complaining about an invalid HTTP request (invalid since HTTPS instead of plain HTTP was used). This plain HTTP response will be interpreted as TLS though by the client and a specific byte sequence in the response will be interpreted as TLS protocol version - even though it wasn't meant to be interpreted this way. This then causes the error message you see.