summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBastiaan Bakker <bbakker@xebia.com>2020-06-11 15:13:09 +0200
committerGitHub <noreply@github.com>2020-06-11 17:13:09 +0400
commitb8733538ef3a258ee76329c3900acb9456fae98e (patch)
treee42f184f81e8ef5cfdf609797563a3a0152cd3f7
parent90cae5d12261da1da71effec099ae9817b270301 (diff)
downloadurllib3-b8733538ef3a258ee76329c3900acb9456fae98e.tar.gz
Feature/support env var sslkeylogfile (#1867)
-rw-r--r--CONTRIBUTORS.txt3
-rw-r--r--docs/advanced-usage.rst15
-rw-r--r--src/urllib3/util/ssl_.py7
-rw-r--r--test/with_dummyserver/test_https.py25
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):