This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author Maximilian Blochberger
Recipients Maximilian Blochberger, christian.heimes
Date 2017-01-31.07:19:42
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1485847183.69.0.499542154053.issue29394@psf.upfronthosting.co.za>
In-reply-to
Content
I have the following scenario: Client → Proxy → Target.

The following two scenarios are working perfectly fine:

1) Establishing a TLS-secured connection to the proxy and then tunnel traffic through that connection to the target. This results in the proxy being able to observe and manipulate the traffic in both directions. It protects against an adversary who has no control over the proxy, e.g. it prevents observers from learning that you are using a proxy (if the IP/port is not known) and from reading the actual traffic.

2) Establish a non-secured connection to the proxy and then tunnel TLS-secured traffic through that connection to the target. That prevents the proxy from being able to observe or manipulate the traffic. Although an observer could learn that you are using a proxy and what target you are connecting to.

Now what I tried was to establish a TLS-secured connection to the proxy and then to establish a TLS-secured tunnel to the target, effectively resulting in two layers of TLS in between the client and the proxy. This would protect from an observer learning that you are using a proxy and where you connect to (the proxy still knows) but preventing the proxy from observing and manipulating the actual traffic to the target.

This does not work in Python 3.6. The TLS-secured connection to the proxy is straight forward and can be easily done with ssl.SSLContext.wrap_socket(). The TCP connection between the proxy and the target can then be established by issuing an HTTP CONNECT request. The response can than be read without closing the connection as done in http.client.HTTPConnection._tunnel(). Now my idea was to call ssl.SSLContext.wrap_socket() again (with a different context for the target) and send traffic through that. Unfortunately the TLS handshake fails with the error message "unknown protocol". I looked into the actual traffic transmitted and realised that the handshake was performed in plain text – so effectively stripping the TLS layer that was established already – which results in the proxy server not knowing how to handle the traffic (as it is not TLS-secured) aborting the connection (and reporting a fatal TLS alert).

This leads to the conclusion that another call to ssl.SSLContext.wrap_socket() will override a previous call of the same function (different context object though). I think this is unexpected behaviour.

It might be easier to handle such scenarios if a tunnel would be a separate http.client.HTTP(S)Connection object, see issue #24964. This would also allow to handle ssl-specific calls such as ssl.SSLSocket.getpeercert() as each layer probably uses different certificates.
History
Date User Action Args
2017-01-31 07:19:43Maximilian Blochbergersetrecipients: + Maximilian Blochberger, christian.heimes
2017-01-31 07:19:43Maximilian Blochbergersetmessageid: <1485847183.69.0.499542154053.issue29394@psf.upfronthosting.co.za>
2017-01-31 07:19:43Maximilian Blochbergerlinkissue29394 messages
2017-01-31 07:19:42Maximilian Blochbergercreate