diff options
author | Bastiaan Bakker <bbakker@xebia.com> | 2020-06-11 15:13:09 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-06-11 17:13:09 +0400 |
commit | b8733538ef3a258ee76329c3900acb9456fae98e (patch) | |
tree | e42f184f81e8ef5cfdf609797563a3a0152cd3f7 | |
parent | 90cae5d12261da1da71effec099ae9817b270301 (diff) | |
download | urllib3-b8733538ef3a258ee76329c3900acb9456fae98e.tar.gz |
Feature/support env var sslkeylogfile (#1867)
-rw-r--r-- | CONTRIBUTORS.txt | 3 | ||||
-rw-r--r-- | docs/advanced-usage.rst | 15 | ||||
-rw-r--r-- | src/urllib3/util/ssl_.py | 7 | ||||
-rw-r--r-- | test/with_dummyserver/test_https.py | 25 |
4 files changed, 49 insertions, 1 deletions
diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index ef41e32b..68caa5de 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -300,5 +300,8 @@ In chronological order: * Chris Olufson <tycarac@gmail.com> * Fix for connection not being released on HTTP redirect and response not preloaded +* [Bastiaan Bakker] <https://github.com/bastiaanb> + * Support for logging session keys via environment variable ``SSLKEYLOGFILE`` (Python 3.8+) + * [Your name or handle] <[email or website]> * [Brief summary of your changes] diff --git a/docs/advanced-usage.rst b/docs/advanced-usage.rst index 5bcc93ad..e36287a0 100644 --- a/docs/advanced-usage.rst +++ b/docs/advanced-usage.rst @@ -128,7 +128,7 @@ you're contacting. When contacting a HTTP website through a HTTP or HTTPS proxy, the request will be forwarded with the `absolute URI -<https://tools.ietf.org/html/rfc7230#section-5.3.2>`_. +<https://tools.ietf.org/html/rfc7230#section-5.3.2>`_. When contacting a HTTPS website through a HTTP proxy, a TCP tunnel will be established with a HTTP CONNECT. Afterward a TLS connection will be established @@ -303,3 +303,16 @@ Here's an example using brotli encoding via the ``Accept-Encoding`` header:: >>> from urllib3 import PoolManager >>> http = PoolManager() >>> http.request('GET', 'https://www.google.com/', headers={'Accept-Encoding': 'br'}) + +Decrypting captured TLS sessions with Wireshark +----------------------------------------------- +Python 3.8 and higher support logging of TLS pre-master secrets. +With these secrets tools like `Wireshark <https://wireshark.org>`_ can decrypt captured +network traffic. + +To enable this simply define environment variable `SSLKEYLOGFILE`: + + export SSLKEYLOGFILE=/path/to/keylogfile.txt + +Then configure the key logfile in `Wireshark <https://wireshark.org>`_, see +`Wireshark TLS Decryption <https://wiki.wireshark.org/TLS#TLS_Decryption>`_ for instructions. diff --git a/src/urllib3/util/ssl_.py b/src/urllib3/util/ssl_.py index 3f45c525..3d89a56c 100644 --- a/src/urllib3/util/ssl_.py +++ b/src/urllib3/util/ssl_.py @@ -2,6 +2,7 @@ from __future__ import absolute_import import errno import warnings import hmac +import os import sys from binascii import hexlify, unhexlify @@ -293,6 +294,12 @@ def create_urllib3_context( # We do our own verification, including fingerprints and alternative # hostnames. So disable it here context.check_hostname = False + + # Enable logging of TLS session keys via defacto standard environment variable + # 'SSLKEYLOGFILE', if the feature is available (Python 3.8+). + if hasattr(context, "keylog_filename"): + context.keylog_filename = os.environ.get("SSLKEYLOGFILE") + return context diff --git a/test/with_dummyserver/test_https.py b/test/with_dummyserver/test_https.py index 897c8ab1..e0b2504b 100644 --- a/test/with_dummyserver/test_https.py +++ b/test/with_dummyserver/test_https.py @@ -698,6 +698,31 @@ class TestHTTPS(HTTPSDummyServerTestCase): finally: conn.close() + @pytest.mark.skipif( + not hasattr(ssl.SSLContext, "keylog_filename"), + reason="requires OpenSSL 1.1.1+", + ) + @pytest.mark.skipif(sys.version_info < (3, 8), reason="requires python 3.8+") + @pytest.mark.skipif( + sys.platform == "win32", + reason="does not work reliably in Appveyor test enviroment for not yet known reasons", + ) + def test_sslkeylogfile(self, tmpdir, monkeypatch): + keylog_file = tmpdir.join("keylogfile.txt") + monkeypatch.setenv("SSLKEYLOGFILE", str(keylog_file)) + with HTTPSConnectionPool( + self.host, self.port, ca_certs=DEFAULT_CA + ) as https_pool: + r = https_pool.request("GET", "/") + assert r.status == 200, r.data + assert keylog_file.check(file=1), "keylogfile '%s' should exist" % str( + keylog_file + ) + assert keylog_file.read().startswith("# TLS secrets log file"), ( + "keylogfile '%s' should start with '# TLS secrets log file'" + % str(keylog_file) + ) + @requiresTLSv1() class TestHTTPS_TLSv1(TestHTTPS): |