diff options
author | Maximilian Hils <git@maximilianhils.com> | 2018-01-13 00:43:07 +0100 |
---|---|---|
committer | Maximilian Hils <git@maximilianhils.com> | 2018-01-13 01:49:20 +0100 |
commit | d9e3fcf5ef0c82cba8a28b31f45b01b6c549b203 (patch) | |
tree | 5acb1dea238100935ead56a221c8bac30d92cadd | |
parent | 96a5ed9dff60c245cc74c98e87caf37942cf0ee2 (diff) | |
download | mitmproxy-d9e3fcf5ef0c82cba8a28b31f45b01b6c549b203.tar.gz mitmproxy-d9e3fcf5ef0c82cba8a28b31f45b01b6c549b203.tar.bz2 mitmproxy-d9e3fcf5ef0c82cba8a28b31f45b01b6c549b203.zip |
store ClientHello extensions with client connection
-rw-r--r-- | mitmproxy/connections.py | 17 | ||||
-rw-r--r-- | mitmproxy/io/compat.py | 11 | ||||
-rw-r--r-- | mitmproxy/test/tflow.py | 1 | ||||
-rw-r--r-- | mitmproxy/tools/web/app.py | 2 | ||||
-rw-r--r-- | mitmproxy/version.py | 2 | ||||
-rw-r--r-- | test/mitmproxy/net/test_tls.py | 2 | ||||
-rw-r--r-- | test/mitmproxy/proxy/test_server.py | 3 |
7 files changed, 28 insertions, 10 deletions
diff --git a/mitmproxy/connections.py b/mitmproxy/connections.py index d1869157..86565b7b 100644 --- a/mitmproxy/connections.py +++ b/mitmproxy/connections.py @@ -1,11 +1,13 @@ import time import os +import typing import uuid -from mitmproxy import stateobject +from mitmproxy import stateobject, exceptions from mitmproxy import certs from mitmproxy.net import tcp +from mitmproxy.net import tls from mitmproxy.utils import strutils @@ -26,6 +28,7 @@ class ClientConnection(tcp.BaseHandler, stateobject.StateObject): cipher_name: The current used cipher alpn_proto_negotiated: The negotiated application protocol tls_version: TLS version + tls_extensions: TLS ClientHello extensions """ def __init__(self, client_connection, address, server): @@ -51,6 +54,7 @@ class ClientConnection(tcp.BaseHandler, stateobject.StateObject): self.cipher_name = None self.alpn_proto_negotiated = None self.tls_version = None + self.tls_extensions = None def connected(self): return bool(self.connection) and not self.finished @@ -96,6 +100,7 @@ class ClientConnection(tcp.BaseHandler, stateobject.StateObject): cipher_name=str, alpn_proto_negotiated=bytes, tls_version=str, + tls_extensions=typing.List[typing.Tuple[int, bytes]], ) def send(self, message): @@ -125,9 +130,19 @@ class ClientConnection(tcp.BaseHandler, stateobject.StateObject): cipher_name=None, alpn_proto_negotiated=None, tls_version=None, + tls_extensions=None, )) def convert_to_tls(self, cert, *args, **kwargs): + # Unfortunately OpenSSL provides no way to expose all TLS extensions, so we do this dance + # here and use our Kaitai parser. + try: + client_hello = tls.ClientHello.from_file(self.rfile) + except exceptions.TlsProtocolException: # pragma: no cover + pass # if this fails, we don't want everything to go down. + else: + self.tls_extensions = client_hello.extensions + super().convert_to_tls(cert, *args, **kwargs) self.timestamp_tls_setup = time.time() self.mitmcert = cert diff --git a/mitmproxy/io/compat.py b/mitmproxy/io/compat.py index ecf852e7..51bd116b 100644 --- a/mitmproxy/io/compat.py +++ b/mitmproxy/io/compat.py @@ -166,11 +166,10 @@ def convert_5_6(data): return data -# def convert_6_7(data): -# data["version"] = 7 -# # Your changes here! -# # Make sure to also increment FLOW_FORMAT_VERSION. -# return data +def convert_6_7(data): + data["version"] = 7 + data["client_conn"]["tls_extensions"] = None + return data def _convert_dict_keys(o: Any) -> Any: @@ -226,7 +225,7 @@ converters = { (3, 0): convert_300_4, 4: convert_4_5, 5: convert_5_6, - # 6: convert_6_7, + 6: convert_6_7, } diff --git a/mitmproxy/test/tflow.py b/mitmproxy/test/tflow.py index 60ec0899..204c7526 100644 --- a/mitmproxy/test/tflow.py +++ b/mitmproxy/test/tflow.py @@ -165,6 +165,7 @@ def tclient_conn(): cipher_name="cipher", alpn_proto_negotiated=b"http/1.1", tls_version="TLSv1.2", + tls_extensions=[(0x00, bytes.fromhex("000e00000b6578616d"))], )) c.reply = controller.DummyReply() c.rfile = io.BytesIO() diff --git a/mitmproxy/tools/web/app.py b/mitmproxy/tools/web/app.py index 77695515..36c9d917 100644 --- a/mitmproxy/tools/web/app.py +++ b/mitmproxy/tools/web/app.py @@ -43,6 +43,8 @@ def flow_to_json(flow: mitmproxy.flow.Flow) -> dict: continue f[conn]["alpn_proto_negotiated"] = \ f[conn]["alpn_proto_negotiated"].decode(errors="backslashreplace") + # There are some bytes in here as well, let's skip it until we have them in the UI. + f["client_conn"].pop("tls_extensions", None) if flow.error: f["error"] = flow.error.get_state() diff --git a/mitmproxy/version.py b/mitmproxy/version.py index d932c067..c2cb3822 100644 --- a/mitmproxy/version.py +++ b/mitmproxy/version.py @@ -9,7 +9,7 @@ MITMPROXY = "mitmproxy " + VERSION # Serialization format version. This is displayed nowhere, it just needs to be incremented by one # for each change in the file format. -FLOW_FORMAT_VERSION = 6 +FLOW_FORMAT_VERSION = 7 def get_version(dev: bool = False, build: bool = False, refresh: bool = False) -> str: diff --git a/test/mitmproxy/net/test_tls.py b/test/mitmproxy/net/test_tls.py index c67b59cd..489bf89f 100644 --- a/test/mitmproxy/net/test_tls.py +++ b/test/mitmproxy/net/test_tls.py @@ -136,7 +136,7 @@ class TestClientHello: (10, b'\x00\x06\x00\x1d\x00\x17\x00\x18') ] - def test_from_conn(self): + def test_from_file(self): rfile = io.BufferedReader(io.BytesIO( FULL_CLIENT_HELLO_NO_EXTENSIONS )) diff --git a/test/mitmproxy/proxy/test_server.py b/test/mitmproxy/proxy/test_server.py index 56b7b4c9..8ec83d18 100644 --- a/test/mitmproxy/proxy/test_server.py +++ b/test/mitmproxy/proxy/test_server.py @@ -723,12 +723,13 @@ class TestProxy(tservers.HTTPProxyTest): class TestProxySSL(tservers.HTTPProxyTest): ssl = True - def test_request_ssl_setup_timestamp_presence(self): + def test_request_tls_attribute_presence(self): # tests that the ssl timestamp is present when ssl is used f = self.pathod("304:b@10k") assert f.status_code == 304 first_flow = self.master.state.flows[0] assert first_flow.server_conn.timestamp_tls_setup + assert first_flow.client_conn.tls_extensions def test_via(self): # tests that the ssl timestamp is present when ssl is used |