aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaximilian Hils <git@maximilianhils.com>2018-01-13 00:43:07 +0100
committerMaximilian Hils <git@maximilianhils.com>2018-01-13 01:49:20 +0100
commitd9e3fcf5ef0c82cba8a28b31f45b01b6c549b203 (patch)
tree5acb1dea238100935ead56a221c8bac30d92cadd
parent96a5ed9dff60c245cc74c98e87caf37942cf0ee2 (diff)
downloadmitmproxy-d9e3fcf5ef0c82cba8a28b31f45b01b6c549b203.tar.gz
mitmproxy-d9e3fcf5ef0c82cba8a28b31f45b01b6c549b203.tar.bz2
mitmproxy-d9e3fcf5ef0c82cba8a28b31f45b01b6c549b203.zip
store ClientHello extensions with client connection
-rw-r--r--mitmproxy/connections.py17
-rw-r--r--mitmproxy/io/compat.py11
-rw-r--r--mitmproxy/test/tflow.py1
-rw-r--r--mitmproxy/tools/web/app.py2
-rw-r--r--mitmproxy/version.py2
-rw-r--r--test/mitmproxy/net/test_tls.py2
-rw-r--r--test/mitmproxy/proxy/test_server.py3
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