aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/main.yml16
-rw-r--r--.gitignore1
-rw-r--r--docs/src/content/addons-events.md16
-rw-r--r--docs/src/content/addons-scripting.md33
-rw-r--r--docs/src/content/concepts-commands.md10
-rw-r--r--docs/src/content/tools-mitmdump.md4
-rw-r--r--docs/src/content/tute-clientreplay.md2
-rw-r--r--docs/src/themes/mitmproxydocs/layouts/partials/header.html2
-rw-r--r--examples/addons/events-http-specific.py42
-rw-r--r--examples/addons/events-tcp-specific.py25
-rw-r--r--examples/addons/events-websocket-specific.py36
-rw-r--r--examples/addons/events.py93
-rw-r--r--examples/complex/nonblocking.py7
-rw-r--r--examples/complex/websocket_inject_message.py2
-rw-r--r--examples/simple/websocket_messages.py11
-rw-r--r--mitmproxy/__init__.py8
-rw-r--r--mitmproxy/addons/browser.py2
-rw-r--r--mitmproxy/addons/script.py13
-rw-r--r--mitmproxy/net/http/headers.py8
-rw-r--r--mitmproxy/net/http/http1/assemble.py11
-rw-r--r--mitmproxy/net/http/http1/read.py34
-rw-r--r--mitmproxy/net/tls.py78
-rw-r--r--mitmproxy/proxy/protocol/base.py4
-rw-r--r--mitmproxy/proxy/protocol/rawtcp.py11
-rw-r--r--mitmproxy/tools/web/master.py36
-rw-r--r--mitmproxy/tools/web/webaddons.py41
-rw-r--r--pathod/language/actions.py2
-rwxr-xr-xrelease/cibuild.py8
-rw-r--r--setup.py16
-rw-r--r--test/mitmproxy/addons/test_script.py11
-rw-r--r--test/mitmproxy/data/addonscripts/configure.py21
-rw-r--r--test/mitmproxy/data/servercert/9da13359.042
-rw-r--r--test/mitmproxy/data/servercert/self-signed.pem87
-rw-r--r--test/mitmproxy/data/servercert/trusted-leaf.pem85
-rw-r--r--test/mitmproxy/data/servercert/trusted-root.pem88
-rw-r--r--test/mitmproxy/net/data/verificationcerts/9da13359.042
-rw-r--r--test/mitmproxy/net/data/verificationcerts/generate.py54
-rw-r--r--test/mitmproxy/net/data/verificationcerts/self-signed.crt41
-rw-r--r--test/mitmproxy/net/data/verificationcerts/self-signed.key54
-rw-r--r--test/mitmproxy/net/data/verificationcerts/trusted-leaf.crt39
-rw-r--r--test/mitmproxy/net/data/verificationcerts/trusted-leaf.key54
-rw-r--r--test/mitmproxy/net/data/verificationcerts/trusted-root.crt42
-rw-r--r--test/mitmproxy/net/data/verificationcerts/trusted-root.key54
-rw-r--r--test/mitmproxy/net/data/verificationcerts/trusted-root.srl2
-rw-r--r--test/mitmproxy/net/http/http1/test_assemble.py12
-rw-r--r--test/mitmproxy/net/http/http1/test_read.py5
-rw-r--r--test/mitmproxy/net/http/test_headers.py2
-rw-r--r--test/mitmproxy/net/test_tcp.py35
-rw-r--r--test/mitmproxy/net/test_tls.py2
-rw-r--r--test/mitmproxy/test_connections.py4
-rw-r--r--tox.ini2
-rw-r--r--web/README.md2
52 files changed, 739 insertions, 613 deletions
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index b36d8c4f..59dad0ff 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -2,10 +2,6 @@ name: CI
on: [push, pull_request]
-# We currently use Python 3.7 for most things:
-# - zstandard currently doesn't have 3.8 wheels,
-# - we need to upgrade cryptography from version 2.4, which also doesn't have wheels
-
env:
# Codecov
CODECOV_TOKEN: "0409bdfd-57a4-477d-a8af-f6172ef431d3"
@@ -31,7 +27,7 @@ jobs:
steps:
- uses: actions/checkout@v1
- uses: actions/setup-python@v1
- - run: pip install mypy
+ - run: pip install mypy==0.770
- run: mypy .
test:
strategy:
@@ -44,9 +40,9 @@ jobs:
- uses: actions/checkout@v1
- uses: actions/setup-python@v1
with:
- python-version: '3.7'
+ python-version: '3.8'
- run: pip install tox
- - run: tox -e py37
+ - run: tox -e py38
# codecov's GitHub action only supports Linux. https://github.com/codecov/codecov-action/issues/7
# codecov's Python uploader has no github actions support yet. https://github.com/codecov/codecov-python/pull/214
- name: Extract branch name # https://stackoverflow.com/a/58035262/934719
@@ -77,7 +73,7 @@ jobs:
- uses: actions/checkout@v1
- uses: actions/setup-python@v1
with:
- python-version: '3.7'
+ python-version: '3.8'
- run: pip install tox
- run: tox -e cibuild -- build
- uses: actions/upload-artifact@master
@@ -142,7 +138,7 @@ jobs:
- uses: actions/checkout@v1
- uses: actions/setup-python@v1
with:
- python-version: '3.7'
+ python-version: '3.8'
- run: pip install tox
- run: |
wget https://github.com/gohugoio/hugo/releases/download/v0.65.3/hugo_extended_0.65.3_Linux-64bit.deb
@@ -187,7 +183,7 @@ jobs:
- uses: actions/checkout@v1
- uses: actions/setup-python@v1
with:
- python-version: '3.7'
+ python-version: '3.8'
# artifacts must be downloaded individually, see https://github.com/actions/download-artifact/issues/6
- uses: actions/download-artifact@master
with:
diff --git a/.gitignore b/.gitignore
index 6b514131..0d5943d5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,6 +17,7 @@ dist/
mitmproxy/contrib/kaitaistruct/*.ksy
.pytest_cache
__pycache__
+.hypothesis/
# UI
diff --git a/docs/src/content/addons-events.md b/docs/src/content/addons-events.md
index 489ea342..ddf0a99f 100644
--- a/docs/src/content/addons-events.md
+++ b/docs/src/content/addons-events.md
@@ -21,4 +21,18 @@ header with a count of the number of responses seen:
Below is an addon class that implements stubs for all events. We've added
annotations to illustrate the argument types for the various events.
-{{< example src="examples/addons/events.py" lang="py" >}} \ No newline at end of file
+### Generic Events
+
+{{< example src="examples/addons/events.py" lang="py" >}}
+
+### HTTP Events
+
+{{< example src="examples/addons/events-http-specific.py" lang="py" >}}
+
+### WebSocket Events
+
+{{< example src="examples/addons/events-websocket-specific.py" lang="py" >}}
+
+### TCP Events
+
+{{< example src="examples/addons/events-tcp-specific.py" lang="py" >}}
diff --git a/docs/src/content/addons-scripting.md b/docs/src/content/addons-scripting.md
index 6a18eaf4..c90a9037 100644
--- a/docs/src/content/addons-scripting.md
+++ b/docs/src/content/addons-scripting.md
@@ -5,7 +5,7 @@ menu:
weight: 5
---
-# Scripting
+# Scripting HTTP/1.1 and HTTP/2.0
Sometimes, we would like to write a quick script without going through the
trouble of creating a class. The addons mechanism has a shorthand that allows a
@@ -13,7 +13,6 @@ module as a whole to be treated as an addon object. This lets us place event
handler functions in the module scope. For instance, here is a complete script
that adds a header to every request.
-
{{< example src="examples/addons/scripting-headers.py" lang="py" >}}
@@ -22,11 +21,31 @@ an arbitrary response instead:
{{< example src="examples/simple/send_reply_from_proxy.py" lang="py" >}}
+All events around the HTTP protocol [can be found here]({{< relref "addons-events#http-events">}}).
-You can look at the [http][] module, or the [Request][], and
-[Response][] classes for other attributes that you can use when
+For HTTP-related objects, please look at the [http][] module, or the
+[Request][], and [Response][] classes for other attributes that you can use when
scripting.
-[http]: https://github.com/mitmproxy/mitmproxy/blob/master/mitmproxy/http.py
-[Request]: https://github.com/mitmproxy/mitmproxy/blob/master/mitmproxy/net/http/request.py
-[Response]: https://github.com/mitmproxy/mitmproxy/blob/master/mitmproxy/net/http/response.py
+# Scripting WebSocket
+
+The WebSocket protocol initially looks like a regular HTTP request, before the client and server agree to upgrade the connection to WebSocket. All scripting events for initial HTTP handshake, and also the dedicated WebSocket events [can be found here]({{< relref "addons-events#websocket-events">}}).
+
+{{< example src="examples/simple/websocket_messages.py" lang="py" >}}
+
+For WebSocket-related objects please look at the [websocket][] module to find
+all attributes that you can use when scripting.
+
+[websocket]: https://github.com/mitmproxy/mitmproxy/blob/master/mitmproxy/websocket.py
+
+
+# Scripting TCP
+
+All events around the TCP protocol [can be found here]({{< relref "addons-events#tcp-events">}}).
+
+{{< example src="examples/complex/tcp_message.py" lang="py" >}}
+
+For WebSocket-related objects please look at the [tcp][] module to find
+all attributes that you can use when scripting.
+
+[tcp]: https://github.com/mitmproxy/mitmproxy/blob/master/mitmproxy/tcp.py
diff --git a/docs/src/content/concepts-commands.md b/docs/src/content/concepts-commands.md
index 72f17252..46d76209 100644
--- a/docs/src/content/concepts-commands.md
+++ b/docs/src/content/concepts-commands.md
@@ -60,13 +60,3 @@ just replay flows for a specific domain:
{{< highlight none >}}
:replay.client "~d google.com"
{{< /highlight >}}
-
-
-
-
-
-
-
-
-
-
diff --git a/docs/src/content/tools-mitmdump.md b/docs/src/content/tools-mitmdump.md
index fb6a6c0c..dcc3bbf6 100644
--- a/docs/src/content/tools-mitmdump.md
+++ b/docs/src/content/tools-mitmdump.md
@@ -53,7 +53,7 @@ See the [client-side replay]({{< relref "overview-features#client-side-replay"
### Running a script
{{< highlight bash >}}
-mitmdump -s examples/add_header.py
+mitmdump -s examples/simple/add_header.py
{{< / highlight >}}
This runs the **add_header.py** example script, which simply adds a new
@@ -62,7 +62,7 @@ header to all responses.
### Scripted data transformation
{{< highlight bash >}}
-mitmdump -ns examples/add_header.py -r srcfile -w dstfile
+mitmdump -ns examples/simple/add_header.py -r srcfile -w dstfile
{{< / highlight >}}
This command loads flows from **srcfile**, transforms it according to
diff --git a/docs/src/content/tute-clientreplay.md b/docs/src/content/tute-clientreplay.md
index 275edfe6..048fd0a5 100644
--- a/docs/src/content/tute-clientreplay.md
+++ b/docs/src/content/tute-clientreplay.md
@@ -42,7 +42,7 @@ And that's it\! You now have a serialised version of the login process
in the file wireless-login, and you can replay it at any time like this:
{{< highlight bash >}}
-mitmdump -c wireless-login
+mitmdump -C wireless-login
{{< / highlight >}}
## Embellishments
diff --git a/docs/src/themes/mitmproxydocs/layouts/partials/header.html b/docs/src/themes/mitmproxydocs/layouts/partials/header.html
index 1dcf3a23..925631d6 100644
--- a/docs/src/themes/mitmproxydocs/layouts/partials/header.html
+++ b/docs/src/themes/mitmproxydocs/layouts/partials/header.html
@@ -20,6 +20,6 @@
{{ if .RSSLink -}}
<link href="{{ .RSSLink }}" rel="feed" type="application/rss+xml" title="{{ .Site.Title }}">
{{- end }}
- {{ .Hugo.Generator }}
+ {{ hugo.Generator }}
</head>
<body>
diff --git a/examples/addons/events-http-specific.py b/examples/addons/events-http-specific.py
new file mode 100644
index 00000000..37d9f91a
--- /dev/null
+++ b/examples/addons/events-http-specific.py
@@ -0,0 +1,42 @@
+import mitmproxy.http
+
+
+class Events:
+ # HTTP lifecycle
+ def http_connect(self, flow: mitmproxy.http.HTTPFlow):
+ """
+ An HTTP CONNECT request was received. Setting a non 2xx response on
+ the flow will return the response to the client abort the
+ connection. CONNECT requests and responses do not generate the usual
+ HTTP handler events. CONNECT requests are only valid in regular and
+ upstream proxy modes.
+ """
+
+ def requestheaders(self, flow: mitmproxy.http.HTTPFlow):
+ """
+ HTTP request headers were successfully read. At this point, the body
+ is empty.
+ """
+
+ def request(self, flow: mitmproxy.http.HTTPFlow):
+ """
+ The full HTTP request has been read.
+ """
+
+ def responseheaders(self, flow: mitmproxy.http.HTTPFlow):
+ """
+ HTTP response headers were successfully read. At this point, the body
+ is empty.
+ """
+
+ def response(self, flow: mitmproxy.http.HTTPFlow):
+ """
+ The full HTTP response has been read.
+ """
+
+ def error(self, flow: mitmproxy.http.HTTPFlow):
+ """
+ An HTTP error has occurred, e.g. invalid server responses, or
+ interrupted connections. This is distinct from a valid server HTTP
+ error response, which is simply a response with an HTTP error code.
+ """
diff --git a/examples/addons/events-tcp-specific.py b/examples/addons/events-tcp-specific.py
new file mode 100644
index 00000000..d150d0f9
--- /dev/null
+++ b/examples/addons/events-tcp-specific.py
@@ -0,0 +1,25 @@
+import mitmproxy.tcp
+
+
+class Events:
+ # TCP lifecycle
+ def tcp_start(self, flow: mitmproxy.tcp.TCPFlow):
+ """
+ A TCP connection has started.
+ """
+
+ def tcp_message(self, flow: mitmproxy.tcp.TCPFlow):
+ """
+ A TCP connection has received a message. The most recent message
+ will be flow.messages[-1]. The message is user-modifiable.
+ """
+
+ def tcp_error(self, flow: mitmproxy.tcp.TCPFlow):
+ """
+ A TCP error has occurred.
+ """
+
+ def tcp_end(self, flow: mitmproxy.tcp.TCPFlow):
+ """
+ A TCP connection has ended.
+ """
diff --git a/examples/addons/events-websocket-specific.py b/examples/addons/events-websocket-specific.py
new file mode 100644
index 00000000..60069fdb
--- /dev/null
+++ b/examples/addons/events-websocket-specific.py
@@ -0,0 +1,36 @@
+import mitmproxy.http
+import mitmproxy.websocket
+
+
+class Events:
+ # Websocket lifecycle
+ def websocket_handshake(self, flow: mitmproxy.http.HTTPFlow):
+ """
+ Called when a client wants to establish a WebSocket connection. The
+ WebSocket-specific headers can be manipulated to alter the
+ handshake. The flow object is guaranteed to have a non-None request
+ attribute.
+ """
+
+ def websocket_start(self, flow: mitmproxy.websocket.WebSocketFlow):
+ """
+ A websocket connection has commenced.
+ """
+
+ def websocket_message(self, flow: mitmproxy.websocket.WebSocketFlow):
+ """
+ Called when a WebSocket message is received from the client or
+ server. The most recent message will be flow.messages[-1]. The
+ message is user-modifiable. Currently there are two types of
+ messages, corresponding to the BINARY and TEXT frame types.
+ """
+
+ def websocket_error(self, flow: mitmproxy.websocket.WebSocketFlow):
+ """
+ A websocket connection has had an error.
+ """
+
+ def websocket_end(self, flow: mitmproxy.websocket.WebSocketFlow):
+ """
+ A websocket connection has ended.
+ """
diff --git a/examples/addons/events.py b/examples/addons/events.py
index f83c8f11..958e7d39 100644
--- a/examples/addons/events.py
+++ b/examples/addons/events.py
@@ -10,99 +10,6 @@ import mitmproxy.proxy.protocol
class Events:
- # HTTP lifecycle
- def http_connect(self, flow: mitmproxy.http.HTTPFlow):
- """
- An HTTP CONNECT request was received. Setting a non 2xx response on
- the flow will return the response to the client abort the
- connection. CONNECT requests and responses do not generate the usual
- HTTP handler events. CONNECT requests are only valid in regular and
- upstream proxy modes.
- """
-
- def requestheaders(self, flow: mitmproxy.http.HTTPFlow):
- """
- HTTP request headers were successfully read. At this point, the body
- is empty.
- """
-
- def request(self, flow: mitmproxy.http.HTTPFlow):
- """
- The full HTTP request has been read.
- """
-
- def responseheaders(self, flow: mitmproxy.http.HTTPFlow):
- """
- HTTP response headers were successfully read. At this point, the body
- is empty.
- """
-
- def response(self, flow: mitmproxy.http.HTTPFlow):
- """
- The full HTTP response has been read.
- """
-
- def error(self, flow: mitmproxy.http.HTTPFlow):
- """
- An HTTP error has occurred, e.g. invalid server responses, or
- interrupted connections. This is distinct from a valid server HTTP
- error response, which is simply a response with an HTTP error code.
- """
-
- # TCP lifecycle
- def tcp_start(self, flow: mitmproxy.tcp.TCPFlow):
- """
- A TCP connection has started.
- """
-
- def tcp_message(self, flow: mitmproxy.tcp.TCPFlow):
- """
- A TCP connection has received a message. The most recent message
- will be flow.messages[-1]. The message is user-modifiable.
- """
-
- def tcp_error(self, flow: mitmproxy.tcp.TCPFlow):
- """
- A TCP error has occurred.
- """
-
- def tcp_end(self, flow: mitmproxy.tcp.TCPFlow):
- """
- A TCP connection has ended.
- """
-
- # Websocket lifecycle
- def websocket_handshake(self, flow: mitmproxy.http.HTTPFlow):
- """
- Called when a client wants to establish a WebSocket connection. The
- WebSocket-specific headers can be manipulated to alter the
- handshake. The flow object is guaranteed to have a non-None request
- attribute.
- """
-
- def websocket_start(self, flow: mitmproxy.websocket.WebSocketFlow):
- """
- A websocket connection has commenced.
- """
-
- def websocket_message(self, flow: mitmproxy.websocket.WebSocketFlow):
- """
- Called when a WebSocket message is received from the client or
- server. The most recent message will be flow.messages[-1]. The
- message is user-modifiable. Currently there are two types of
- messages, corresponding to the BINARY and TEXT frame types.
- """
-
- def websocket_error(self, flow: mitmproxy.websocket.WebSocketFlow):
- """
- A websocket connection has had an error.
- """
-
- def websocket_end(self, flow: mitmproxy.websocket.WebSocketFlow):
- """
- A websocket connection has ended.
- """
-
# Network lifecycle
def clientconnect(self, layer: mitmproxy.proxy.protocol.Layer):
"""
diff --git a/examples/complex/nonblocking.py b/examples/complex/nonblocking.py
index 72c9c0ab..dd74aec0 100644
--- a/examples/complex/nonblocking.py
+++ b/examples/complex/nonblocking.py
@@ -1,12 +1,11 @@
import time
from mitmproxy.script import concurrent
-from mitmproxy import ctx
@concurrent # Remove this and see what happens
def request(flow):
- # You don't want to use mitmproxy.ctx from a different thread
- ctx.log.info("handle request: %s%s" % (flow.request.host, flow.request.path))
+ # This is ugly in mitmproxy's UI, but you don't want to use mitmproxy.ctx.log from a different thread.
+ print("handle request: %s%s" % (flow.request.host, flow.request.path))
time.sleep(5)
- ctx.log.info("start request: %s%s" % (flow.request.host, flow.request.path))
+ print("start request: %s%s" % (flow.request.host, flow.request.path))
diff --git a/examples/complex/websocket_inject_message.py b/examples/complex/websocket_inject_message.py
index e9c3ea0c..38be5555 100644
--- a/examples/complex/websocket_inject_message.py
+++ b/examples/complex/websocket_inject_message.py
@@ -13,7 +13,7 @@ class InjectWebSocketMessage:
i = 0
while not flow.ended and not flow.error:
await asyncio.sleep(5)
- flow.inject_message(flow.client_conn, 'This is the #{} an injected message!'.format(i))
+ flow.inject_message(flow.client_conn, 'This is the #{} injected message!'.format(i))
i += 1
def websocket_start(self, flow):
diff --git a/examples/simple/websocket_messages.py b/examples/simple/websocket_messages.py
index 719e7b10..071ea21f 100644
--- a/examples/simple/websocket_messages.py
+++ b/examples/simple/websocket_messages.py
@@ -6,8 +6,15 @@ def websocket_message(flow):
# get the latest message
message = flow.messages[-1]
- # simply print the content of the message
- ctx.log.info(message.content)
+ # was the message sent from the client or server?
+ if message.from_client:
+ ctx.log.info("Client sent a message: {}".format(message.content))
+ else:
+ ctx.log.info("Server sent a message: {}".format(message.content))
# manipulate the message content
message.content = re.sub(r'^Hello', 'HAPPY', message.content)
+
+ if 'FOOBAR' in message.content:
+ # kill the message and not send it to the other endpoint
+ message.kill()
diff --git a/mitmproxy/__init__.py b/mitmproxy/__init__.py
index e69de29b..e930cf1e 100644
--- a/mitmproxy/__init__.py
+++ b/mitmproxy/__init__.py
@@ -0,0 +1,8 @@
+import asyncio
+import sys
+
+if sys.platform == 'win32':
+ # workaround for
+ # https://github.com/tornadoweb/tornado/issues/2751
+ # https://www.tornadoweb.org/en/stable/index.html#installation
+ asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
diff --git a/mitmproxy/addons/browser.py b/mitmproxy/addons/browser.py
index e74b50db..5735698b 100644
--- a/mitmproxy/addons/browser.py
+++ b/mitmproxy/addons/browser.py
@@ -73,4 +73,4 @@ class Browser:
self.browser.kill()
self.tdir.cleanup()
self.browser = None
- self.tdir = None
+ self.tdir = None \ No newline at end of file
diff --git a/mitmproxy/addons/script.py b/mitmproxy/addons/script.py
index 3b2568c9..b3cb0999 100644
--- a/mitmproxy/addons/script.py
+++ b/mitmproxy/addons/script.py
@@ -105,11 +105,14 @@ class Script:
# We're already running, so we have to explicitly register and
# configure the addon
ctx.master.addons.invoke_addon(self.ns, "running")
- ctx.master.addons.invoke_addon(
- self.ns,
- "configure",
- ctx.options.keys()
- )
+ try:
+ ctx.master.addons.invoke_addon(
+ self.ns,
+ "configure",
+ ctx.options.keys()
+ )
+ except exceptions.OptionsError as e:
+ script_error_handler(self.fullpath, e, msg=str(e))
async def watcher(self):
last_mtime = 0
diff --git a/mitmproxy/net/http/headers.py b/mitmproxy/net/http/headers.py
index 8a58cbbc..baed7e06 100644
--- a/mitmproxy/net/http/headers.py
+++ b/mitmproxy/net/http/headers.py
@@ -162,8 +162,12 @@ class Headers(multidict.MultiDict):
pattern = re.compile(pattern, flags)
replacements = 0
flag_count = count > 0
+ count_reached = False
fields = []
for name, value in self.fields:
+ if count_reached:
+ fields.append((name, value))
+ continue
line, n = pattern.subn(repl, name + b": " + value, count=count)
try:
name, value = line.split(b": ", 1)
@@ -173,10 +177,12 @@ class Headers(multidict.MultiDict):
pass
else:
replacements += n
+ fields.append((name, value))
if flag_count:
count -= n
if count == 0:
- break
+ count_reached = True
+ continue
fields.append((name, value))
self.fields = tuple(fields)
return replacements
diff --git a/mitmproxy/net/http/http1/assemble.py b/mitmproxy/net/http/http1/assemble.py
index 8b7246f7..d30a74a1 100644
--- a/mitmproxy/net/http/http1/assemble.py
+++ b/mitmproxy/net/http/http1/assemble.py
@@ -1,4 +1,3 @@
-import mitmproxy.net.http.url
from mitmproxy import exceptions
@@ -78,15 +77,7 @@ def _assemble_request_headers(request_data):
Args:
request_data (mitmproxy.net.http.request.RequestData)
"""
- headers = request_data.headers
- if "host" not in headers and request_data.scheme and request_data.host and request_data.port:
- headers = headers.copy()
- headers["host"] = mitmproxy.net.http.url.hostport(
- request_data.scheme,
- request_data.host,
- request_data.port
- )
- return bytes(headers)
+ return bytes(request_data.headers)
def _assemble_response_line(response_data):
diff --git a/mitmproxy/net/http/http1/read.py b/mitmproxy/net/http/http1/read.py
index 294e8358..0fc03f1b 100644
--- a/mitmproxy/net/http/http1/read.py
+++ b/mitmproxy/net/http/http1/read.py
@@ -2,6 +2,8 @@ import time
import sys
import re
+import typing
+
from mitmproxy.net.http import request
from mitmproxy.net.http import response
from mitmproxy.net.http import headers
@@ -171,8 +173,15 @@ def connection_close(http_version, headers):
return http_version != "HTTP/1.1" and http_version != b"HTTP/1.1"
-def expected_http_body_size(request, response=None):
+def expected_http_body_size(
+ request: request.Request,
+ response: typing.Optional[response.Response] = None,
+ expect_continue_as_0: bool = True
+):
"""
+ Args:
+ - expect_continue_as_0: If true, incorrectly predict a body size of 0 for requests which are waiting
+ for a 100 Continue response.
Returns:
The expected body length:
- a positive integer, if the size is known in advance
@@ -186,24 +195,17 @@ def expected_http_body_size(request, response=None):
# http://tools.ietf.org/html/rfc7230#section-3.3
if not response:
headers = request.headers
- response_code = None
- is_request = True
- else:
- headers = response.headers
- response_code = response.status_code
- is_request = False
-
- if is_request:
- if headers.get("expect", "").lower() == "100-continue":
+ if expect_continue_as_0 and headers.get("expect", "").lower() == "100-continue":
return 0
else:
+ headers = response.headers
if request.method.upper() == "HEAD":
return 0
- if 100 <= response_code <= 199:
+ if 100 <= response.status_code <= 199:
return 0
- if response_code == 200 and request.method.upper() == "CONNECT":
+ if response.status_code == 200 and request.method.upper() == "CONNECT":
return 0
- if response_code in (204, 304):
+ if response.status_code in (204, 304):
return 0
if "chunked" in headers.get("transfer-encoding", "").lower():
@@ -218,9 +220,9 @@ def expected_http_body_size(request, response=None):
if size < 0:
raise ValueError()
return size
- except ValueError:
- raise exceptions.HttpSyntaxException("Unparseable Content Length")
- if is_request:
+ except ValueError as e:
+ raise exceptions.HttpSyntaxException("Unparseable Content Length") from e
+ if not response:
return 0
return -1
diff --git a/mitmproxy/net/tls.py b/mitmproxy/net/tls.py
index d68a008f..d8e943d3 100644
--- a/mitmproxy/net/tls.py
+++ b/mitmproxy/net/tls.py
@@ -7,14 +7,13 @@ import os
import struct
import threading
import typing
-from ssl import match_hostname, CertificateError
import certifi
from OpenSSL import SSL
from kaitaistruct import KaitaiStream
-import mitmproxy.options # noqa
-from mitmproxy import exceptions, certs
+import mitmproxy.options
+from mitmproxy import certs, exceptions
from mitmproxy.contrib.kaitaistruct import tls_client_hello
from mitmproxy.net import check
@@ -88,7 +87,18 @@ class MasterSecretLogger:
__name__ = "MasterSecretLogger"
def __call__(self, connection, where, ret):
- if where == SSL.SSL_CB_HANDSHAKE_DONE and ret == 1:
+ done_now = (
+ where == SSL.SSL_CB_HANDSHAKE_DONE and ret == 1
+ )
+ # this is a horrendous workaround for https://github.com/mitmproxy/mitmproxy/pull/3692#issuecomment-608454530:
+ # OpenSSL 1.1.1f decided to not make connection.master_key() fail in the SSL_CB_HANDSHAKE_DONE callback.
+ # To support various OpenSSL versions and still log master secrets, we now mark connections where this has
+ # happened and then try again on the next event. This is ugly and shouldn't be done, but eventually we
+ # replace this with context.set_keylog_callback anyways.
+ done_previously_but_not_logged_yet = (
+ hasattr(connection, "_still_needs_masterkey")
+ )
+ if done_now or done_previously_but_not_logged_yet:
with self.lock:
if not self.f:
d = os.path.dirname(self.filename)
@@ -96,10 +106,16 @@ class MasterSecretLogger:
os.makedirs(d)
self.f = open(self.filename, "ab")
self.f.write(b"\r\n")
- client_random = binascii.hexlify(connection.client_random())
- masterkey = binascii.hexlify(connection.master_key())
- self.f.write(b"CLIENT_RANDOM %s %s\r\n" % (client_random, masterkey))
- self.f.flush()
+ try:
+ client_random = binascii.hexlify(connection.client_random())
+ masterkey = binascii.hexlify(connection.master_key())
+ except (AssertionError, SSL.Error): # careful: exception type changes between pyOpenSSL versions
+ connection._still_needs_masterkey = True
+ else:
+ self.f.write(b"CLIENT_RANDOM %s %s\r\n" % (client_random, masterkey))
+ self.f.flush()
+ if hasattr(connection, "_still_needs_masterkey"):
+ delattr(connection, "_still_needs_masterkey")
def close(self):
with self.lock:
@@ -237,33 +253,11 @@ def create_client_context(
depth: int,
is_cert_verified: bool
) -> bool:
- if is_cert_verified and depth == 0:
- # Verify hostname of leaf certificate.
- cert = certs.Cert(x509)
- try:
- crt: typing.Dict[str, typing.Any] = dict(
- subjectAltName=[("DNS", x.decode("ascii", "strict")) for x in cert.altnames]
- )
- if cert.cn:
- crt["subject"] = [[["commonName", cert.cn.decode("ascii", "strict")]]]
- if sni:
- # SNI hostnames allow support of IDN by using ASCII-Compatible Encoding
- # Conversion algorithm is in RFC 3490 which is implemented by idna codec
- # https://docs.python.org/3/library/codecs.html#text-encodings
- # https://tools.ietf.org/html/rfc6066#section-3
- # https://tools.ietf.org/html/rfc4985#section-3
- hostname = sni.encode("idna").decode("ascii")
- else:
- hostname = "no-hostname"
- match_hostname(crt, hostname)
- except (ValueError, CertificateError) as e:
- conn.cert_error = exceptions.InvalidCertificateException(
- "Certificate verification error for {}: {}".format(
- sni or repr(address),
- str(e)
- )
- )
- is_cert_verified = False
+ if is_cert_verified and depth == 0 and not sni:
+ conn.cert_error = exceptions.InvalidCertificateException(
+ f"Certificate verification error for {address}: Cannot validate hostname, SNI missing."
+ )
+ is_cert_verified = False
elif is_cert_verified:
pass
else:
@@ -285,6 +279,20 @@ def create_client_context(
**sslctx_kwargs,
)
+ if sni:
+ # Manually enable hostname verification on the context object.
+ # https://wiki.openssl.org/index.php/Hostname_validation
+ param = SSL._lib.SSL_CTX_get0_param(context._context)
+ # Matching on the CN is disabled in both Chrome and Firefox, so we disable it, too.
+ # https://www.chromestatus.com/feature/4981025180483584
+ SSL._lib.X509_VERIFY_PARAM_set_hostflags(
+ param,
+ SSL._lib.X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS | SSL._lib.X509_CHECK_FLAG_NEVER_CHECK_SUBJECT
+ )
+ SSL._openssl_assert(
+ SSL._lib.X509_VERIFY_PARAM_set1_host(param, sni.encode("idna"), 0) == 1
+ )
+
# Client Certs
if cert:
try:
diff --git a/mitmproxy/proxy/protocol/base.py b/mitmproxy/proxy/protocol/base.py
index 2063f901..3bf03521 100644
--- a/mitmproxy/proxy/protocol/base.py
+++ b/mitmproxy/proxy/protocol/base.py
@@ -160,10 +160,10 @@ class ServerConnectionMixin:
"""
if not self.server_conn.address:
raise exceptions.ProtocolException("Cannot connect to server, no server address given.")
- self.log("serverconnect", "debug", [repr(self.server_conn.address)])
- self.channel.ask("serverconnect", self.server_conn)
try:
self.server_conn.connect()
+ self.log("serverconnect", "debug", [repr(self.server_conn.address)])
+ self.channel.ask("serverconnect", self.server_conn)
except exceptions.TcpException as e:
raise exceptions.ProtocolException(
"Server connection to {} failed: {}".format(
diff --git a/mitmproxy/proxy/protocol/rawtcp.py b/mitmproxy/proxy/protocol/rawtcp.py
index 0ec50594..00bba04c 100644
--- a/mitmproxy/proxy/protocol/rawtcp.py
+++ b/mitmproxy/proxy/protocol/rawtcp.py
@@ -29,13 +29,20 @@ class RawTCPLayer(base.Layer):
server = self.server_conn.connection
conns = [client, server]
+ # https://github.com/openssl/openssl/issues/6234
+ for conn in conns:
+ if isinstance(conn, SSL.Connection) and hasattr(SSL._lib, "SSL_clear_mode"):
+ SSL._lib.SSL_clear_mode(conn._ssl, SSL._lib.SSL_MODE_AUTO_RETRY)
+
try:
while not self.channel.should_exit.is_set():
r = mitmproxy.net.tcp.ssl_read_select(conns, 10)
for conn in r:
dst = server if conn == client else client
-
- size = conn.recv_into(buf, self.chunk_size)
+ try:
+ size = conn.recv_into(buf, self.chunk_size)
+ except (SSL.WantReadError, SSL.WantWriteError):
+ continue
if not size:
conns.remove(conn)
# Shutdown connection to the other peer
diff --git a/mitmproxy/tools/web/master.py b/mitmproxy/tools/web/master.py
index e2c60d94..17845106 100644
--- a/mitmproxy/tools/web/master.py
+++ b/mitmproxy/tools/web/master.py
@@ -1,5 +1,3 @@
-import webbrowser
-
import tornado.httpserver
import tornado.ioloop
from tornado.platform.asyncio import AsyncIOMainLoop
@@ -112,38 +110,4 @@ class WebMaster(master.Master):
self.log.info(
"Web server listening at {}".format(web_url),
)
- # FIXME: This should be in an addon hooked to the "running" event, not in master
- if self.options.web_open_browser:
- success = open_browser(web_url)
- if not success:
- self.log.info(
- "No web browser found. Please open a browser and point it to {}".format(web_url),
- )
self.run_loop(iol.start)
-
-
-def open_browser(url: str) -> bool:
- """
- Open a URL in a browser window.
- In contrast to webbrowser.open, we limit the list of suitable browsers.
- This gracefully degrades to a no-op on headless servers, where webbrowser.open
- would otherwise open lynx.
-
- Returns:
- True, if a browser has been opened
- False, if no suitable browser has been found.
- """
- browsers = (
- "windows-default", "macosx",
- "google-chrome", "chrome", "chromium", "chromium-browser",
- "firefox", "opera", "safari",
- )
- for browser in browsers:
- try:
- b = webbrowser.get(browser)
- except webbrowser.Error:
- pass
- else:
- b.open(url)
- return True
- return False
diff --git a/mitmproxy/tools/web/webaddons.py b/mitmproxy/tools/web/webaddons.py
index 6b52188c..ba3bdead 100644
--- a/mitmproxy/tools/web/webaddons.py
+++ b/mitmproxy/tools/web/webaddons.py
@@ -1,3 +1,8 @@
+import webbrowser
+
+from mitmproxy import ctx
+
+
class WebAddon:
def load(self, loader):
loader.add_option(
@@ -16,3 +21,39 @@ class WebAddon:
"web_iface", str, "127.0.0.1",
"Web UI interface."
)
+
+ def running(self):
+ if hasattr(ctx.options, "web_open_browser") and ctx.options.web_open_browser:
+ web_url = "http://{}:{}/".format(ctx.options.web_iface, ctx.options.web_port)
+ success = open_browser(web_url)
+ if not success:
+ ctx.log.info(
+ "No web browser found. Please open a browser and point it to {}".format(web_url),
+ )
+
+
+def open_browser(url: str) -> bool:
+ """
+ Open a URL in a browser window.
+ In contrast to webbrowser.open, we limit the list of suitable browsers.
+ This gracefully degrades to a no-op on headless servers, where webbrowser.open
+ would otherwise open lynx.
+
+ Returns:
+ True, if a browser has been opened
+ False, if no suitable browser has been found.
+ """
+ browsers = (
+ "windows-default", "macosx",
+ "google-chrome", "chrome", "chromium", "chromium-browser",
+ "firefox", "opera", "safari",
+ )
+ for browser in browsers:
+ try:
+ b = webbrowser.get(browser)
+ except webbrowser.Error:
+ pass
+ else:
+ b.open(url)
+ return True
+ return False
diff --git a/pathod/language/actions.py b/pathod/language/actions.py
index 3e48f40d..916cd0aa 100644
--- a/pathod/language/actions.py
+++ b/pathod/language/actions.py
@@ -6,7 +6,7 @@ import pyparsing as pp
from . import base
-@total_ordering
+@total_ordering # type: ignore
class _Action(base.Token):
"""
diff --git a/release/cibuild.py b/release/cibuild.py
index b2bad9a0..d070a4b9 100755
--- a/release/cibuild.py
+++ b/release/cibuild.py
@@ -454,10 +454,10 @@ def build_wininstaller(be: BuildEnviron): # pragma: no cover
return
click.echo("Building wininstaller package...")
- IB_VERSION = "19.10.0"
+ IB_VERSION = "20.3.0"
IB_DIR = pathlib.Path(be.release_dir) / "installbuilder"
IB_SETUP = IB_DIR / "setup" / f"{IB_VERSION}-installer.exe"
- IB_CLI = fr"C:\Program Files (x86)\BitRock InstallBuilder Enterprise {IB_VERSION}\bin\builder-cli.exe"
+ IB_CLI = fr"C:\Program Files (x86)\VMware InstallBuilder Enterprise {IB_VERSION}\bin\builder-cli.exe"
IB_LICENSE = IB_DIR / "license.xml"
if not os.path.isfile(IB_CLI):
@@ -470,11 +470,11 @@ def build_wininstaller(be: BuildEnviron): # pragma: no cover
click.secho(f"Downloading... {round(100 * done / total)}%")
urllib.request.urlretrieve(
- f"https://clients.bitrock.com/installbuilder/installbuilder-enterprise-{IB_VERSION}-windows-installer.exe",
+ f"https://installbuilder.com/installbuilder-enterprise-{IB_VERSION}-windows-installer.exe",
IB_SETUP.with_suffix(".tmp"),
reporthook=report
)
- shutil.move(IB_SETUP.with_suffix(".tmp"), IB_SETUP)
+ shutil.move(str(IB_SETUP.with_suffix(".tmp")), str(IB_SETUP))
click.echo("Install InstallBuilder...")
subprocess.run([str(IB_SETUP), "--mode", "unattended", "--unattendedmodeui", "none"], check=True)
diff --git a/setup.py b/setup.py
index c5edee18..a5795984 100644
--- a/setup.py
+++ b/setup.py
@@ -66,25 +66,25 @@ setup(
"Brotli>=1.0,<1.1",
"certifi>=2019.9.11", # no semver here - this should always be on the last release!
"click>=7.0,<8",
- "cryptography>=2.1.4,<2.5",
+ "cryptography>=2.9,<3.0",
"flask>=1.1.1,<1.2",
"h2>=3.2.0,<4",
"hyperframe>=5.1.0,<6",
"kaitaistruct>=0.7,<0.9",
- "ldap3>=2.6.1,<2.7",
+ "ldap3>=2.6.1,<2.8",
"passlib>=1.6.5, <1.8",
- "protobuf>=3.6.0, <3.11",
+ "protobuf>=3.6.0, <3.12",
"pyasn1>=0.3.1,<0.5",
- "pyOpenSSL==19.0.0",
+ "pyOpenSSL>=19.1.0,<19.2",
"pyparsing>=2.4.2,<2.5",
- "pyperclip>=1.6.0,<1.8",
+ "pyperclip>=1.6.0,<1.9",
"ruamel.yaml>=0.16,<0.17",
"sortedcontainers>=2.1.0,<2.2",
"tornado>=4.3,<7",
"urwid>=2.1.0,<2.2",
- "wsproto>=0.14.0,<0.15.0",
+ "wsproto>=0.14,<0.16",
"publicsuffix2>=2.20190812,<3",
- "zstandard>=0.11.0,<0.13.0",
+ "zstandard>=0.11,<0.14",
],
extras_require={
':sys_platform == "win32"': [
@@ -94,7 +94,7 @@ setup(
"asynctest>=0.12.0",
"flake8>=3.7.8,<3.8",
"Flask>=1.0,<1.2",
- "mypy>=0.740,<0.741",
+ "mypy>=0.740,<0.771",
"parver>=0.1,<2.0",
"pytest-asyncio>=0.10.0,<0.11",
"pytest-cov>=2.7.1,<3",
diff --git a/test/mitmproxy/addons/test_script.py b/test/mitmproxy/addons/test_script.py
index 05472d9a..61e19174 100644
--- a/test/mitmproxy/addons/test_script.py
+++ b/test/mitmproxy/addons/test_script.py
@@ -137,6 +137,17 @@ class TestScript:
assert await tctx.master.await_log("error.py")
@pytest.mark.asyncio
+ async def test_optionexceptions(self, tdata):
+ with taddons.context() as tctx:
+ sc = script.Script(
+ tdata.path("mitmproxy/data/addonscripts/configure.py"),
+ True,
+ )
+ tctx.master.addons.add(sc)
+ tctx.configure(sc)
+ assert await tctx.master.await_log("Options Error")
+
+ @pytest.mark.asyncio
async def test_addon(self, tdata):
with taddons.context() as tctx:
sc = script.Script(
diff --git a/test/mitmproxy/data/addonscripts/configure.py b/test/mitmproxy/data/addonscripts/configure.py
new file mode 100644
index 00000000..6f6ac06a
--- /dev/null
+++ b/test/mitmproxy/data/addonscripts/configure.py
@@ -0,0 +1,21 @@
+import typing
+
+from mitmproxy import exceptions
+
+
+class OptionAddon:
+ def load(self, loader):
+ loader.add_option(
+ name = "optionaddon",
+ typespec = typing.Optional[int],
+ default = None,
+ help = "Option Addon",
+ )
+
+ def configure(self, updates):
+ raise exceptions.OptionsError("Options Error")
+
+addons = [
+ OptionAddon()
+]
+
diff --git a/test/mitmproxy/data/servercert/9da13359.0 b/test/mitmproxy/data/servercert/9da13359.0
index 5868a304..88ed4145 100644
--- a/test/mitmproxy/data/servercert/9da13359.0
+++ b/test/mitmproxy/data/servercert/9da13359.0
@@ -1,21 +1,21 @@
------BEGIN CERTIFICATE-----
-MIIDXTCCAkWgAwIBAgIJALzkvKyFAwWYMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
-BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
-aWRnaXRzIFB0eSBMdGQwHhcNMTgwOTA3MDgyMjUxWhcNMzgwOTAyMDgyMjUxWjBF
-MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
-ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
-CgKCAQEAkvT4Y1ML8Gg4x5aFVygIW022tJsEyfuW4HsEvIarAGpFtUNkw0dOoAxv
-Gv71I0KAWOXxtc9DUjtq7ZXJcG+dBiheTYJ40lrYhHvUt7J37nrUF5v5trQzoE9I
-6WGtzTV8C8RI6F+M6GtwxgwRBgqkuXiK5ExPXAjGMMJZWtiEXHxGTNB6F4zy884m
-VjVtQi8jy+c5g21Awp3z5HrQLM210zwvgi7Rygk6/UM0AnmST4o32SqFSd+0MFUJ
-f3pH3xczfKmhU/TBoVEWRB1YzwixsJrzDOB8wOGnNKCsl45hYUJZZ8epVkyrvFZQ
-iMkwIqqBJbkU6H7fZBl68TJ8ascUCQIDAQABo1AwTjAdBgNVHQ4EFgQUkurgHlw1
-xMP2wrsrGPTk0ofxCyowHwYDVR0jBBgwFoAUkurgHlw1xMP2wrsrGPTk0ofxCyow
-DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAcdExVlSvH6aVExNiQO3k
-cMamj+78woDn9x563vwzaGP24KvOXk1B/IJp5kqu3ZsXS0I0Mz6xwXHAXeuxaj06
-cKgEpHKKgClLblXo2zWqo/3V1UFFpOVP/NhI3r21b+fPrS46rP0mw75haQCph8/8
-buQr0OeAYbElliY/ji+cJiCJB8A/D13fUMV/NUUfPW/UE6497jOmz+6PtZNAoOFx
-evrmDcbCzbJxacyLJX04rsrt6DO09jb/+5lFm5Aqr6ySKasrmheIGEisl4o9Zbuy
-5PvYgbOEmFgPATIiWGpBO/rqwDdsmgyYFl+YfFoW0akXUVhDb2e5iRDx6Rs0fmN/
-NA==
------END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDazCCAlOgAwIBAgIUTE2oFYATbkkytGOt0+CIAOPpaeEwDQYJKoZIhvcNAQEL
+BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
+GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xOTExMjMwMDA1MDlaFw0zOTEx
+MTgwMDA1MDlaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
+HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQDZ7fqv4iC6738OvOC/ONFmhOVmMNe2SrGtk+7KIv/M
+d7MJJKpIygwc99EfL3m6WFjvSQ8CABO9GnLIeoB6RzX5X904dPQzIekMkE27J4D5
+wzYWAmYsu9md//9rjadaA01zHvxtpc30AsToOrRa2Rv7Lwotvcop2bBCXXZMdgvD
+BpCuCOl3cQ346LZBmED41q77P7SgnI98gCPuyyMVAFTZE4NnFUloVERTcMMo5Vwv
+tXFT41B6FOqtyhZFY89W1SeNKlm+n8zu+/aUF5c9usxwvQzj79pzBFYS9xMZzbxl
+BmU91GbLFNU32O+wp0jX6c1MfluGvRjcHQpK+gHRRJdZAgMBAAGjUzBRMB0GA1Ud
+DgQWBBSTmtfFP/zQDiCbte3AG3vchjSekjAfBgNVHSMEGDAWgBSTmtfFP/zQDiCb
+te3AG3vchjSekjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQB6
+CnGmyJKVdD41Qs8QbyZ5VvrAkSq7DkL4CAIDy0pClOYjx51R16g4/dXPd8nuDjVB
+GbRuO/ZHlKeO+RAVbV4s74KeBmQ4uyuZMvuiJGCDtTgu+fbgp1l41vj21bkDnz/X
+0aVrwC4clh6O1/AFCY7cYygp22QJ0zGpIb9d0ly6QDMEocHJKasuQ8/0GPvv6wkY
+hwNub2ScsVFHPrFzzufZblBk3Ks0YZw+IsCMTY7QtGb1TZhGeX9xAydqNMnmIxNj
+XOE2FKx4ISQNFwf/U1LEAruO7PjbbsWx5FHr4oYV9TCLoERZFofwcGGM9o/cPc4P
+CH8fGvFYoU30PG+xX0Pc
+-----END CERTIFICATE-----
diff --git a/test/mitmproxy/data/servercert/self-signed.pem b/test/mitmproxy/data/servercert/self-signed.pem
index d35284bd..55145c52 100644
--- a/test/mitmproxy/data/servercert/self-signed.pem
+++ b/test/mitmproxy/data/servercert/self-signed.pem
@@ -1,46 +1,49 @@
-----BEGIN CERTIFICATE-----
-MIIDEzCCAfugAwIBAgIJAKzH8k6aKTP6MA0GCSqGSIb3DQEBCwUAMCAxHjAcBgNV
-BAMMFWV4YW1wbGUubWl0bXByb3h5Lm9yZzAeFw0xODA5MDcwODIyNTNaFw0zODA5
-MDIwODIyNTNaMCAxHjAcBgNVBAMMFWV4YW1wbGUubWl0bXByb3h5Lm9yZzCCASIw
-DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMOjJMp2o5eLQEmYJqMZzLBi61h9
-fsCVMvS8hgrH1Cg5q/RaLBLrZ8nILKmFZBapMUEFkUwQLB864tdTMaX7p+jNv3sM
-5LWEIYkTIbu6qV7QerKdubS1hpdFtQGRM1Q+C7H86FzF02DSKzNSmQc4fNed/lQM
-qo/jOm1xx4TZFR4j58BrmmoOfNP44IyrwXsPyXbMsukKixVEB3vQ2oyGDAyG6dYi
-VvM8PVL5yhX3BJ0D1Ky6hgGHJeirm0Cd8qqdSC/SWNdu1bGzg/xyUX5XFaHlIi7Y
-5YhD7ZDLvC76MeCWkfo4DaSB0CWmtG4l1TtHM2JqP8qf2l2LsABKs0q/a+UCAwEA
-AaNQME4wHQYDVR0OBBYEFIc9YAXgnGRhPTEcN/j+k/dxMdKqMB8GA1UdIwQYMBaA
-FIc9YAXgnGRhPTEcN/j+k/dxMdKqMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEL
-BQADggEBAD9qKci3Pr4/2WGx+sv8gOpKchC9eF2dXc5hA3xbDw7T6oRLUBAY8Pty
-JF7DHMovT+w7FPRYT8rSc190fbSwVRHAnEaqAzaxteImCp/qYgdBHOz39eG4c93W
-YrYvA1VdUDPcUnisEVWguDsKJGFg+G6pw+8Wkf/hCrJJkriTFogGvzg6ptdQatvE
-dpSkionfbuZKz+7lny6sCBGoMRIFBd22MHJsSQOyTb06Lwc5dpdF9c5vysPRzShJ
-5kkgIjGpTmWp+Ud8BAMQH8EDhJMkJ7iw1+07UQ9MUmXCp9Xgim6x1ri2/yoz9HeO
-83VCkD9YWufrzOrsXpo04rMYtoKo+lw=
+MIIDjTCCAnWgAwIBAgIUb0mIVHKB+bu2PGObggokU3Re7xMwDQYJKoZIhvcNAQEL
+BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
+GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xOTExMjMwMDA1MDlaFw0zOTEx
+MTgwMDA1MDlaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
+HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQDF6eqyZD2z83buUF4T+6AY0Zoe925a2AHOhGtHJMLo
+9AD7FF1Xi1iksEvxbOI6mreHtvYKzUpfNsA3DkFdSO91HMSkdvWcDcExpW62sNK9
+gQQrpcCx7DogOrFiGSIHI1LIy1y6YEJma3G71SgGbw7g1QF64dTX9+BzVQJsloT2
+H3ZxTi8Fb6APJq6d/Tp67GTM8U82vM+FjLKzfH7RMSEPvSyvWSibw3AZP6owFaxz
+DJtXpR7evOZbiZxqXmGOBl5OQPu9GdDA3Fyi9Drp7xa234loqd1a8PYyL8qWV/2G
+HM3IJOzG8Y5PUJhL8CkDbx4LJ9LfzeSuBnQPUf2ZNalZAgMBAAGjdTBzMB0GA1Ud
+DgQWBBQbkS0mAGPD4XjOv9GKzGMyR9ix3TAfBgNVHSMEGDAWgBQbkS0mAGPD4XjO
+v9GKzGMyR9ix3TAPBgNVHRMBAf8EBTADAQH/MCAGA1UdEQQZMBeCFWV4YW1wbGUu
+bWl0bXByb3h5Lm9yZzANBgkqhkiG9w0BAQsFAAOCAQEAqZ64xpu3qrTlCc555OoP
+GgobUFP3qv07d0/r48cOyYdAdlEHhvmDPlqWTB9e4ZYtWZMlocY9DpCywzKTa7F7
+Ad8BwS0a/No3wVdl1UEkIGYxuD//jbd77Mrpf5URvQco85o/bicn+H0GAOchYt1P
+jP1VShqsRv6WiTs5kn1/JwVoafddl1jBlMDmCqDv4loAZJYHzie0CqdjjSeorFfE
+8FG8OLwmEnmIW6VnanRH8coH9MBbZ+dRtCavS+Q8s0R77dJM1sCp5/4yKcr5D/PD
++dQN9f+iugLxDdBQjiRyadWX9/l4n/h8ezabZ4cNsiWbRXrp5VS0nGNmAK3XvPAu
+ow==
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
-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
+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
-----END RSA PRIVATE KEY-----
diff --git a/test/mitmproxy/data/servercert/trusted-leaf.pem b/test/mitmproxy/data/servercert/trusted-leaf.pem
index a2c25312..29bd38f7 100644
--- a/test/mitmproxy/data/servercert/trusted-leaf.pem
+++ b/test/mitmproxy/data/servercert/trusted-leaf.pem
@@ -1,45 +1,48 @@
-----BEGIN CERTIFICATE-----
-MIIC4TCCAckCCQCj6D9oVylb9zANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB
-VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
-cyBQdHkgTHRkMB4XDTE4MDkwNzA4MjI1MloXDTM4MDkwMjA4MjI1MlowIDEeMBwG
-A1UEAwwVZXhhbXBsZS5taXRtcHJveHkub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOC
-AQ8AMIIBCgKCAQEAqKzVdsRKgthv6V/dk3Tncy4ymbACs383nGutjulExvroNOCw
-b0y0e7unNGbtXxFQqSvA7eGaT1yRNfoMbXGSS+sn8A3gB6/s2A0Sw7KeSDdoaqEq
-F/LzRBed1YkxSyy0GXuTd7HXNIoFn/eF1tqxgViWdfyFD85qY4yJ+luofdm7IcPM
-ENPzV4nKzDh2PdJpQrEokWz2jM0zefC3IYnFHXY5bA3MnhE03/P0VxeEYkBdmEAt
-O1U2Bkw9SKCLy9zF13ks6/dDZ9LjMtRKI83gQS5z3S3bA45YxFuyeLWgVsJ2NYTa
-j9/8c4xwOjg9TpkCvcmZiPUYGddPHWoKqAAhBwIDAQABMA0GCSqGSIb3DQEBCwUA
-A4IBAQAf8cjxunN4Y7NUD2Z/SNOJ/s0uWJtTPV6m4FxSwwD0wfbsyirPchmattLc
-BabrQkeMMm8gMOrORfanXQwvLZvX0aDf96EgLSfHv8Iqeol5Byrgkn7UORXl20Jt
-8UNRURUZYtWxn08P8dlhxQUncPF/UxCesC8x0cihqv+YTB3TX1sni9mOqPCYY8yH
-E8kCW4zTJ0J9OQUHq9qdYQM/PGVm99+DWBItUeZAva8Rqj1FN3f9j1eWB+EjfYu7
-ztsTInpNWP4tIh6vIFtuaGr077cJawTe6YVyNxVqquI9+2fpSPkt7tCTIhbQ4AmM
-DeHzn+KjfKN8ooWqmcfmUZWaADe0
+MIIDajCCAlKgAwIBAgIJAKPoP2hXKVv4MA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
+BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
+aWRnaXRzIFB0eSBMdGQwHhcNMTkxMTIzMDAwNTA5WhcNMzkxMTE4MDAwNTA5WjBF
+MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
+ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEA4BZUGKkf52583Kps2SinCzRtGFaGIqtP1YfjaN1H21c08hEERRWf0GqW
+PIbZz0NRyqOVM0O+4A9cxKrdqDpALBNXdgB62Ven1NNE31ZjsbFgwbORPTiOQo+6
+Xsu+2KHQdqAGOXSqOdNSoZV/HqAKa41iweg6lUf3yrO/hpfnlXTFbuM/oYFARrr9
+YWY7qH5BEvcZBf4Sg3cWGjdbzYg8S6hnFBBkHPDMbS3xra7H8uru8aG9L70aiq0C
+3WsGf1/Qctz3cccB6BdnbiXji0QlP0miT+b52hEzDvNjdXvoObgbOZsUUcLrbz8q
+LqaQPj6TA2PYpKcxEdJLDcbN++tglQIDAQABo10wWzAfBgNVHSMEGDAWgBSTmtfF
+P/zQDiCbte3AG3vchjSekjAJBgNVHRMEAjAAMAsGA1UdDwQEAwIFoDAgBgNVHREE
+GTAXghVleGFtcGxlLm1pdG1wcm94eS5vcmcwDQYJKoZIhvcNAQELBQADggEBAMoK
+8+KTYF10dbQ8Hl3Fq4Iux7eutAPuKUXUz9dnCfDRhZukdl+gahRoNvkyMBdXOvvx
+R9Z2+Guo8NOYKgT1mJtS/c8IxTkjZj9doujJOVD2wTowSfoaT9z+/EJa+6Fp9+xd
+YVsO3E/2Vxai8PCNx8JTXr2axcnBDvpHPRXF21hOI8N94SPAcmLTZsdsTELjrGGa
+/BA0y+pCEwW6cY9mMHVAAvRoMoqfocBVI7nrYBaQfFoKuwxscxO679eEv+lbSjul
+z/VNdWfqrDhFFSzwRSVchapQ9q1EeTzv++wZRwI5bT0Ib6DFTJB3J5+9RihlFYfU
+GI17CI0D//DsFic7QJ0=
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
-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
+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
-----END RSA PRIVATE KEY-----
diff --git a/test/mitmproxy/data/servercert/trusted-root.pem b/test/mitmproxy/data/servercert/trusted-root.pem
index a53cb893..2248d9f3 100644
--- a/test/mitmproxy/data/servercert/trusted-root.pem
+++ b/test/mitmproxy/data/servercert/trusted-root.pem
@@ -1,48 +1,48 @@
-----BEGIN CERTIFICATE-----
-MIIDXTCCAkWgAwIBAgIJALzkvKyFAwWYMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
-BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
-aWRnaXRzIFB0eSBMdGQwHhcNMTgwOTA3MDgyMjUxWhcNMzgwOTAyMDgyMjUxWjBF
-MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
-ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
-CgKCAQEAkvT4Y1ML8Gg4x5aFVygIW022tJsEyfuW4HsEvIarAGpFtUNkw0dOoAxv
-Gv71I0KAWOXxtc9DUjtq7ZXJcG+dBiheTYJ40lrYhHvUt7J37nrUF5v5trQzoE9I
-6WGtzTV8C8RI6F+M6GtwxgwRBgqkuXiK5ExPXAjGMMJZWtiEXHxGTNB6F4zy884m
-VjVtQi8jy+c5g21Awp3z5HrQLM210zwvgi7Rygk6/UM0AnmST4o32SqFSd+0MFUJ
-f3pH3xczfKmhU/TBoVEWRB1YzwixsJrzDOB8wOGnNKCsl45hYUJZZ8epVkyrvFZQ
-iMkwIqqBJbkU6H7fZBl68TJ8ascUCQIDAQABo1AwTjAdBgNVHQ4EFgQUkurgHlw1
-xMP2wrsrGPTk0ofxCyowHwYDVR0jBBgwFoAUkurgHlw1xMP2wrsrGPTk0ofxCyow
-DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAcdExVlSvH6aVExNiQO3k
-cMamj+78woDn9x563vwzaGP24KvOXk1B/IJp5kqu3ZsXS0I0Mz6xwXHAXeuxaj06
-cKgEpHKKgClLblXo2zWqo/3V1UFFpOVP/NhI3r21b+fPrS46rP0mw75haQCph8/8
-buQr0OeAYbElliY/ji+cJiCJB8A/D13fUMV/NUUfPW/UE6497jOmz+6PtZNAoOFx
-evrmDcbCzbJxacyLJX04rsrt6DO09jb/+5lFm5Aqr6ySKasrmheIGEisl4o9Zbuy
-5PvYgbOEmFgPATIiWGpBO/rqwDdsmgyYFl+YfFoW0akXUVhDb2e5iRDx6Rs0fmN/
-NA==
+MIIDazCCAlOgAwIBAgIUTE2oFYATbkkytGOt0+CIAOPpaeEwDQYJKoZIhvcNAQEL
+BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
+GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xOTExMjMwMDA1MDlaFw0zOTEx
+MTgwMDA1MDlaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
+HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQDZ7fqv4iC6738OvOC/ONFmhOVmMNe2SrGtk+7KIv/M
+d7MJJKpIygwc99EfL3m6WFjvSQ8CABO9GnLIeoB6RzX5X904dPQzIekMkE27J4D5
+wzYWAmYsu9md//9rjadaA01zHvxtpc30AsToOrRa2Rv7Lwotvcop2bBCXXZMdgvD
+BpCuCOl3cQ346LZBmED41q77P7SgnI98gCPuyyMVAFTZE4NnFUloVERTcMMo5Vwv
+tXFT41B6FOqtyhZFY89W1SeNKlm+n8zu+/aUF5c9usxwvQzj79pzBFYS9xMZzbxl
+BmU91GbLFNU32O+wp0jX6c1MfluGvRjcHQpK+gHRRJdZAgMBAAGjUzBRMB0GA1Ud
+DgQWBBSTmtfFP/zQDiCbte3AG3vchjSekjAfBgNVHSMEGDAWgBSTmtfFP/zQDiCb
+te3AG3vchjSekjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQB6
+CnGmyJKVdD41Qs8QbyZ5VvrAkSq7DkL4CAIDy0pClOYjx51R16g4/dXPd8nuDjVB
+GbRuO/ZHlKeO+RAVbV4s74KeBmQ4uyuZMvuiJGCDtTgu+fbgp1l41vj21bkDnz/X
+0aVrwC4clh6O1/AFCY7cYygp22QJ0zGpIb9d0ly6QDMEocHJKasuQ8/0GPvv6wkY
+hwNub2ScsVFHPrFzzufZblBk3Ks0YZw+IsCMTY7QtGb1TZhGeX9xAydqNMnmIxNj
+XOE2FKx4ISQNFwf/U1LEAruO7PjbbsWx5FHr4oYV9TCLoERZFofwcGGM9o/cPc4P
+CH8fGvFYoU30PG+xX0Pc
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
-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
+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
-----END RSA PRIVATE KEY-----
diff --git a/test/mitmproxy/net/data/verificationcerts/9da13359.0 b/test/mitmproxy/net/data/verificationcerts/9da13359.0
index 5868a304..88ed4145 100644
--- a/test/mitmproxy/net/data/verificationcerts/9da13359.0
+++ b/test/mitmproxy/net/data/verificationcerts/9da13359.0
@@ -1,21 +1,21 @@
------BEGIN CERTIFICATE-----
-MIIDXTCCAkWgAwIBAgIJALzkvKyFAwWYMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
-BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
-aWRnaXRzIFB0eSBMdGQwHhcNMTgwOTA3MDgyMjUxWhcNMzgwOTAyMDgyMjUxWjBF
-MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
-ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
-CgKCAQEAkvT4Y1ML8Gg4x5aFVygIW022tJsEyfuW4HsEvIarAGpFtUNkw0dOoAxv
-Gv71I0KAWOXxtc9DUjtq7ZXJcG+dBiheTYJ40lrYhHvUt7J37nrUF5v5trQzoE9I
-6WGtzTV8C8RI6F+M6GtwxgwRBgqkuXiK5ExPXAjGMMJZWtiEXHxGTNB6F4zy884m
-VjVtQi8jy+c5g21Awp3z5HrQLM210zwvgi7Rygk6/UM0AnmST4o32SqFSd+0MFUJ
-f3pH3xczfKmhU/TBoVEWRB1YzwixsJrzDOB8wOGnNKCsl45hYUJZZ8epVkyrvFZQ
-iMkwIqqBJbkU6H7fZBl68TJ8ascUCQIDAQABo1AwTjAdBgNVHQ4EFgQUkurgHlw1
-xMP2wrsrGPTk0ofxCyowHwYDVR0jBBgwFoAUkurgHlw1xMP2wrsrGPTk0ofxCyow
-DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAcdExVlSvH6aVExNiQO3k
-cMamj+78woDn9x563vwzaGP24KvOXk1B/IJp5kqu3ZsXS0I0Mz6xwXHAXeuxaj06
-cKgEpHKKgClLblXo2zWqo/3V1UFFpOVP/NhI3r21b+fPrS46rP0mw75haQCph8/8
-buQr0OeAYbElliY/ji+cJiCJB8A/D13fUMV/NUUfPW/UE6497jOmz+6PtZNAoOFx
-evrmDcbCzbJxacyLJX04rsrt6DO09jb/+5lFm5Aqr6ySKasrmheIGEisl4o9Zbuy
-5PvYgbOEmFgPATIiWGpBO/rqwDdsmgyYFl+YfFoW0akXUVhDb2e5iRDx6Rs0fmN/
-NA==
------END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDazCCAlOgAwIBAgIUTE2oFYATbkkytGOt0+CIAOPpaeEwDQYJKoZIhvcNAQEL
+BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
+GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xOTExMjMwMDA1MDlaFw0zOTEx
+MTgwMDA1MDlaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
+HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQDZ7fqv4iC6738OvOC/ONFmhOVmMNe2SrGtk+7KIv/M
+d7MJJKpIygwc99EfL3m6WFjvSQ8CABO9GnLIeoB6RzX5X904dPQzIekMkE27J4D5
+wzYWAmYsu9md//9rjadaA01zHvxtpc30AsToOrRa2Rv7Lwotvcop2bBCXXZMdgvD
+BpCuCOl3cQ346LZBmED41q77P7SgnI98gCPuyyMVAFTZE4NnFUloVERTcMMo5Vwv
+tXFT41B6FOqtyhZFY89W1SeNKlm+n8zu+/aUF5c9usxwvQzj79pzBFYS9xMZzbxl
+BmU91GbLFNU32O+wp0jX6c1MfluGvRjcHQpK+gHRRJdZAgMBAAGjUzBRMB0GA1Ud
+DgQWBBSTmtfFP/zQDiCbte3AG3vchjSekjAfBgNVHSMEGDAWgBSTmtfFP/zQDiCb
+te3AG3vchjSekjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQB6
+CnGmyJKVdD41Qs8QbyZ5VvrAkSq7DkL4CAIDy0pClOYjx51R16g4/dXPd8nuDjVB
+GbRuO/ZHlKeO+RAVbV4s74KeBmQ4uyuZMvuiJGCDtTgu+fbgp1l41vj21bkDnz/X
+0aVrwC4clh6O1/AFCY7cYygp22QJ0zGpIb9d0ly6QDMEocHJKasuQ8/0GPvv6wkY
+hwNub2ScsVFHPrFzzufZblBk3Ks0YZw+IsCMTY7QtGb1TZhGeX9xAydqNMnmIxNj
+XOE2FKx4ISQNFwf/U1LEAruO7PjbbsWx5FHr4oYV9TCLoERZFofwcGGM9o/cPc4P
+CH8fGvFYoU30PG+xX0Pc
+-----END CERTIFICATE-----
diff --git a/test/mitmproxy/net/data/verificationcerts/generate.py b/test/mitmproxy/net/data/verificationcerts/generate.py
index 8439c9e6..1e09138d 100644
--- a/test/mitmproxy/net/data/verificationcerts/generate.py
+++ b/test/mitmproxy/net/data/verificationcerts/generate.py
@@ -5,10 +5,10 @@ import subprocess
import shlex
import os
import shutil
-
+import textwrap
ROOT_CA = "trusted-root"
-SUBJECT = "/CN=example.mitmproxy.org/"
+SUBJECT = "example.mitmproxy.org"
def do(args):
@@ -18,29 +18,39 @@ def do(args):
return output
-def genrsa(cert):
- do("openssl genrsa -out {cert}.key 2048".format(cert=cert))
+def genrsa(cert: str):
+ do(f"openssl genrsa -out {cert}.key 2048")
-def sign(cert):
- do("openssl x509 -req -in {cert}.csr "
- "-CA {root_ca}.crt "
- "-CAkey {root_ca}.key "
- "-CAcreateserial "
- "-days 7300 "
- "-out {cert}.crt".format(root_ca=ROOT_CA, cert=cert)
+def sign(cert: str, subject: str):
+ with open(f"openssl-{cert}.conf", "w") as f:
+ f.write(textwrap.dedent(f"""
+ authorityKeyIdentifier=keyid,issuer
+ basicConstraints=CA:FALSE
+ keyUsage = digitalSignature, keyEncipherment
+ subjectAltName = {subject}
+ """))
+ do(f"openssl x509 -req -in {cert}.csr "
+ f"-CA {ROOT_CA}.crt "
+ f"-CAkey {ROOT_CA}.key "
+ f"-CAcreateserial "
+ f"-days 7300 "
+ f"-sha256 "
+ f"-extfile \"openssl-{cert}.conf\" "
+ f"-out {cert}.crt"
)
+ os.remove(f"openssl-{cert}.conf")
-def mkcert(cert, args):
+def mkcert(cert, subject):
genrsa(cert)
- do("openssl req -new -nodes -batch "
- "-key {cert}.key "
- "{args} "
- "-out {cert}.csr".format(cert=cert, args=args)
+ do(f"openssl req -new -nodes -batch "
+ f"-key {cert}.key "
+ f"-addext \"subjectAltName = {subject}\" "
+ f"-out {cert}.csr"
)
- sign(cert)
- os.remove("{cert}.csr".format(cert=cert))
+ sign(cert, subject)
+ os.remove(f"{cert}.csr")
# create trusted root CA
@@ -54,13 +64,13 @@ h = do("openssl x509 -hash -noout -in trusted-root.crt").decode("ascii").strip()
shutil.copyfile("trusted-root.crt", "{}.0".format(h))
# create trusted leaf cert.
-mkcert("trusted-leaf", "-subj {}".format(SUBJECT))
+mkcert("trusted-leaf", f'DNS:{SUBJECT}')
# create self-signed cert
genrsa("self-signed")
do("openssl req -x509 -new -nodes -batch "
"-key self-signed.key "
- "-subj {} "
+ f'-addext "subjectAltName = DNS:{SUBJECT}" '
"-days 7300 "
- "-out self-signed.crt".format(SUBJECT)
- )
+ "-out self-signed.crt"
+ ) \ No newline at end of file
diff --git a/test/mitmproxy/net/data/verificationcerts/self-signed.crt b/test/mitmproxy/net/data/verificationcerts/self-signed.crt
index 6e234b8b..a02d9f32 100644
--- a/test/mitmproxy/net/data/verificationcerts/self-signed.crt
+++ b/test/mitmproxy/net/data/verificationcerts/self-signed.crt
@@ -1,19 +1,22 @@
------BEGIN CERTIFICATE-----
-MIIDEzCCAfugAwIBAgIJAKzH8k6aKTP6MA0GCSqGSIb3DQEBCwUAMCAxHjAcBgNV
-BAMMFWV4YW1wbGUubWl0bXByb3h5Lm9yZzAeFw0xODA5MDcwODIyNTNaFw0zODA5
-MDIwODIyNTNaMCAxHjAcBgNVBAMMFWV4YW1wbGUubWl0bXByb3h5Lm9yZzCCASIw
-DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMOjJMp2o5eLQEmYJqMZzLBi61h9
-fsCVMvS8hgrH1Cg5q/RaLBLrZ8nILKmFZBapMUEFkUwQLB864tdTMaX7p+jNv3sM
-5LWEIYkTIbu6qV7QerKdubS1hpdFtQGRM1Q+C7H86FzF02DSKzNSmQc4fNed/lQM
-qo/jOm1xx4TZFR4j58BrmmoOfNP44IyrwXsPyXbMsukKixVEB3vQ2oyGDAyG6dYi
-VvM8PVL5yhX3BJ0D1Ky6hgGHJeirm0Cd8qqdSC/SWNdu1bGzg/xyUX5XFaHlIi7Y
-5YhD7ZDLvC76MeCWkfo4DaSB0CWmtG4l1TtHM2JqP8qf2l2LsABKs0q/a+UCAwEA
-AaNQME4wHQYDVR0OBBYEFIc9YAXgnGRhPTEcN/j+k/dxMdKqMB8GA1UdIwQYMBaA
-FIc9YAXgnGRhPTEcN/j+k/dxMdKqMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEL
-BQADggEBAD9qKci3Pr4/2WGx+sv8gOpKchC9eF2dXc5hA3xbDw7T6oRLUBAY8Pty
-JF7DHMovT+w7FPRYT8rSc190fbSwVRHAnEaqAzaxteImCp/qYgdBHOz39eG4c93W
-YrYvA1VdUDPcUnisEVWguDsKJGFg+G6pw+8Wkf/hCrJJkriTFogGvzg6ptdQatvE
-dpSkionfbuZKz+7lny6sCBGoMRIFBd22MHJsSQOyTb06Lwc5dpdF9c5vysPRzShJ
-5kkgIjGpTmWp+Ud8BAMQH8EDhJMkJ7iw1+07UQ9MUmXCp9Xgim6x1ri2/yoz9HeO
-83VCkD9YWufrzOrsXpo04rMYtoKo+lw=
------END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDjTCCAnWgAwIBAgIUb0mIVHKB+bu2PGObggokU3Re7xMwDQYJKoZIhvcNAQEL
+BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
+GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xOTExMjMwMDA1MDlaFw0zOTEx
+MTgwMDA1MDlaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
+HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQDF6eqyZD2z83buUF4T+6AY0Zoe925a2AHOhGtHJMLo
+9AD7FF1Xi1iksEvxbOI6mreHtvYKzUpfNsA3DkFdSO91HMSkdvWcDcExpW62sNK9
+gQQrpcCx7DogOrFiGSIHI1LIy1y6YEJma3G71SgGbw7g1QF64dTX9+BzVQJsloT2
+H3ZxTi8Fb6APJq6d/Tp67GTM8U82vM+FjLKzfH7RMSEPvSyvWSibw3AZP6owFaxz
+DJtXpR7evOZbiZxqXmGOBl5OQPu9GdDA3Fyi9Drp7xa234loqd1a8PYyL8qWV/2G
+HM3IJOzG8Y5PUJhL8CkDbx4LJ9LfzeSuBnQPUf2ZNalZAgMBAAGjdTBzMB0GA1Ud
+DgQWBBQbkS0mAGPD4XjOv9GKzGMyR9ix3TAfBgNVHSMEGDAWgBQbkS0mAGPD4XjO
+v9GKzGMyR9ix3TAPBgNVHRMBAf8EBTADAQH/MCAGA1UdEQQZMBeCFWV4YW1wbGUu
+bWl0bXByb3h5Lm9yZzANBgkqhkiG9w0BAQsFAAOCAQEAqZ64xpu3qrTlCc555OoP
+GgobUFP3qv07d0/r48cOyYdAdlEHhvmDPlqWTB9e4ZYtWZMlocY9DpCywzKTa7F7
+Ad8BwS0a/No3wVdl1UEkIGYxuD//jbd77Mrpf5URvQco85o/bicn+H0GAOchYt1P
+jP1VShqsRv6WiTs5kn1/JwVoafddl1jBlMDmCqDv4loAZJYHzie0CqdjjSeorFfE
+8FG8OLwmEnmIW6VnanRH8coH9MBbZ+dRtCavS+Q8s0R77dJM1sCp5/4yKcr5D/PD
++dQN9f+iugLxDdBQjiRyadWX9/l4n/h8ezabZ4cNsiWbRXrp5VS0nGNmAK3XvPAu
+ow==
+-----END CERTIFICATE-----
diff --git a/test/mitmproxy/net/data/verificationcerts/self-signed.key b/test/mitmproxy/net/data/verificationcerts/self-signed.key
index 3546c3fb..b6da998f 100644
--- a/test/mitmproxy/net/data/verificationcerts/self-signed.key
+++ b/test/mitmproxy/net/data/verificationcerts/self-signed.key
@@ -1,27 +1,27 @@
------BEGIN RSA PRIVATE KEY-----
-MIIEpgIBAAKCAQEAw6Mkynajl4tASZgmoxnMsGLrWH1+wJUy9LyGCsfUKDmr9Fos
-EutnycgsqYVkFqkxQQWRTBAsHzri11Mxpfun6M2/ewzktYQhiRMhu7qpXtB6sp25
-tLWGl0W1AZEzVD4LsfzoXMXTYNIrM1KZBzh8153+VAyqj+M6bXHHhNkVHiPnwGua
-ag580/jgjKvBew/Jdsyy6QqLFUQHe9DajIYMDIbp1iJW8zw9UvnKFfcEnQPUrLqG
-AYcl6KubQJ3yqp1IL9JY127VsbOD/HJRflcVoeUiLtjliEPtkMu8Lvox4JaR+jgN
-pIHQJaa0biXVO0czYmo/yp/aXYuwAEqzSr9r5QIDAQABAoIBAQC1RpgymlffdgJt
-rvQuMRu/XQlhh3dJj3YV3BIAL0VguH+i/WLVbRdQm5D2y0kAzml7LGODrYCUt4W1
-q7rXaCYfy3Xf2QSbRQGl9/pL7xw9ZMQseYW38nPx+39LInYDWzKPDB9qx0uj7Vpm
-ReTSEf9r81PUIaBxj0V2X/VWHag5scBjXoflQLxyV6i1UvTuWyhYvX1Bbaj02MqV
-tGNMrjbj25Wx2za53VDonzNA6RMZzkWGMfzmkkGM6kjGzLEsveys+bYCt7Fs7slR
-4oby0bIUmN7iqLhqlEhS4weWW4iHlq17X7CZeQAE1XeVZBz1N4G8FLjND2eyqb2N
-RAcQqp3BAoGBAOiU3WTu/kSccteDRxR1gVRPqEgfoLDwyAb7ORVUWX4Ii/z/soMw
-xZ2MlYPLnp3Fyu/hKhJPC1LzkD4CGHCTJJ1NnUudtDxl2Zh1FZYGmv1hi1TID/cm
-G0+3XhlJgztS41+AzxTNMulV1yieT2HIRIoRpdSx1UIA72l42YqjrwUNAoGBANdV
-/Ib+3hAfFtSMMI1qZQXvlKEoDRbUOCYuBVkTK8oQJQH6MLDokHZ8sXBAqi9383b1
-XmhQBJZ//yMy0AqFa2QBlkK0Gizzhh7BLSjIT2LREf66B2cWzhgdhbSp6Nuk+3DK
-NfibxsFAPpW05HqtfxhbjrLfoE8VvTuMGQ8AaXw5AoGBAISo7IL2wrdV2TdN3Mwx
-ndv+N4kz6Q8jt6QrxUqCOy1lKJvdKPAlcIJFvr5W9RkeyXr7nmilB1uAK4UC4vfL
-JfZHX/HSeQx+N5f7KJ3TFLJz4eow1tJsvOVCPP0FbkH3LFO7/+HojSKEYN39NmAa
-v+VU3Zas/GvSZrxtPwASDvE9AoGBAJOBbluW6MzITx5H7dZhRFR9miWOxvCVbOUS
-b01mKX/f8UnadVIp7RONNQr88NdVZqxdRk9USOBDS6Vz4DjkzfySbbjBoJCcPIqC
-r4mZNXAuYRJJolqGr6SrTHTGUyFqcWcAzVnAc7TbakOoxz4V7NLlnOmA8FJcROUu
-gdfZ42hZAoGBANyL2IQ+L92iYVvqsz1zPBlvemevx8zP6GmlzvTcVexyDTIiLg6W
-BVil5zRDPJdDiFfBK18Qg1mJoE4SjLTg+yGww9ef37Zb9kZypy6pM6AbRWILZ1Gv
-7UsWUzk6rgcQpDdpJCUEt+AD3LQJTxxuoIhZePvC2GLkzsjZA7ZyB5+S
------END RSA PRIVATE KEY-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAxenqsmQ9s/N27lBeE/ugGNGaHvduWtgBzoRrRyTC6PQA+xRd
+V4tYpLBL8WziOpq3h7b2Cs1KXzbANw5BXUjvdRzEpHb1nA3BMaVutrDSvYEEK6XA
+sew6IDqxYhkiByNSyMtcumBCZmtxu9UoBm8O4NUBeuHU1/fgc1UCbJaE9h92cU4v
+BW+gDyaunf06euxkzPFPNrzPhYyys3x+0TEhD70sr1kom8NwGT+qMBWscwybV6Ue
+3rzmW4mcal5hjgZeTkD7vRnQwNxcovQ66e8Wtt+JaKndWvD2Mi/Kllf9hhzNyCTs
+xvGOT1CYS/ApA28eCyfS383krgZ0D1H9mTWpWQIDAQABAoIBAGl4H8+TZeJ5E18q
+ywfhJ08ym+x2tYOJ62SP4s+WApy8M62aC6g0pTeWj9IH0YOjobycPwBAqKqW9dYh
+Lao1zQ5fF1gB4R+ZoOQBIkAPeS7uCzfrbAYlOlCklpUNibm+FEbXQQI9fAUyqviL
+Pno3QvmD6fb/VDsHaMBthA40JIU4C3yUUcSooKKUC3XKmbRDg5/stKbVdi6co5AQ
+OMNFj4smts3rXtk5tKMBep4AgKKdClf4IuhpWEqZDxN6e+hZA7g1VOmOIE+hKEEO
+ODBkjHNgHIFbsr8GTlZ+GSkHBxMNVdHxntJTU5a2jPiTNTTnhqu2hcVdkyDwLb9x
+TGUCdyUCgYEA/ZPwI2KaT4Lj8b+6DCV4v3nZF8nLCtt1LiXxJWexdnr+3q/ZfNjN
+5sKVl9rIynz2zoJDVr1MI8yjO6OmV7GBW2wgJsSFwg0vnV/bs75KqPZWZXqy/mrp
+HnXd82XUweyyOpmBg4cCjmcnMTrdvCHvfgx7JafnUDqeXNwriWeC5Y8CgYEAx83d
+qHgAT2rlnCQYRmCOGb5fuyQ+pSM4p8h1AjueLrTNiWcqX57ct9eVWjymD+AgevFZ
+hZH9m6TI4nCb/5ukcvjQb4g1kyY3l7rZiiJ3kf/c22kVsVUagJGeiW6Ypnox4r1o
+oFXEwAw1qSGIqOIjYVB2DqvjUl3+UjWCl9SOnpcCgYEA0TSdWUQ/VTwCvW9VmjHM
+FgT8I5Ebj+CRI7qv4hFTqxE8dxKTl1nzPd/ptTgOkmhY4vU7gzN3vs1VGp4gXZcX
+xwpE2Fcol3lzgB4Wz4s+Y3mgu+ZoCFjB7ZyGugmYZ0nVnV0KKi5X4I6gGhCb4VwK
+D29SpjWJNHq4LpqC3MDmkGcCgYAxnKOKXmmtTpy+3ZONfhIqwEOjA0fu10UNHFA5
+grYvYMOcd5pk7dxeZdB2/JI7ZOqLvHv/F5YCXLNozo9ds7bsuW2AFDFBXX72VPYJ
+P6+y9/ZOINS7GKeg/wd/lo+e3r6eT2u4TDOzgBSe722wiZ5BXqpB0Fp8rEwm+5R2
+wNe89wKBgQC59SOa4EW3gfjLRaH6hEPcMEzjr0Dt5ilBgntYbI+DsCePwEX28hAK
+fd7A6XoCqjnwLpAmh0cmNRsYjtPCzg6TXUdrhfnR/3r7DHzvsxaC06BfkPZJ0+Fu
+rP3el/oKSPaDsZKjW6RA5oqlIF82o45MNl2oCG82LgVtu25e3HbJSA==
+-----END RSA PRIVATE KEY-----
diff --git a/test/mitmproxy/net/data/verificationcerts/trusted-leaf.crt b/test/mitmproxy/net/data/verificationcerts/trusted-leaf.crt
index 3ccae708..d71cbd07 100644
--- a/test/mitmproxy/net/data/verificationcerts/trusted-leaf.crt
+++ b/test/mitmproxy/net/data/verificationcerts/trusted-leaf.crt
@@ -1,18 +1,21 @@
------BEGIN CERTIFICATE-----
-MIIC4TCCAckCCQCj6D9oVylb9zANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB
-VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
-cyBQdHkgTHRkMB4XDTE4MDkwNzA4MjI1MloXDTM4MDkwMjA4MjI1MlowIDEeMBwG
-A1UEAwwVZXhhbXBsZS5taXRtcHJveHkub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOC
-AQ8AMIIBCgKCAQEAqKzVdsRKgthv6V/dk3Tncy4ymbACs383nGutjulExvroNOCw
-b0y0e7unNGbtXxFQqSvA7eGaT1yRNfoMbXGSS+sn8A3gB6/s2A0Sw7KeSDdoaqEq
-F/LzRBed1YkxSyy0GXuTd7HXNIoFn/eF1tqxgViWdfyFD85qY4yJ+luofdm7IcPM
-ENPzV4nKzDh2PdJpQrEokWz2jM0zefC3IYnFHXY5bA3MnhE03/P0VxeEYkBdmEAt
-O1U2Bkw9SKCLy9zF13ks6/dDZ9LjMtRKI83gQS5z3S3bA45YxFuyeLWgVsJ2NYTa
-j9/8c4xwOjg9TpkCvcmZiPUYGddPHWoKqAAhBwIDAQABMA0GCSqGSIb3DQEBCwUA
-A4IBAQAf8cjxunN4Y7NUD2Z/SNOJ/s0uWJtTPV6m4FxSwwD0wfbsyirPchmattLc
-BabrQkeMMm8gMOrORfanXQwvLZvX0aDf96EgLSfHv8Iqeol5Byrgkn7UORXl20Jt
-8UNRURUZYtWxn08P8dlhxQUncPF/UxCesC8x0cihqv+YTB3TX1sni9mOqPCYY8yH
-E8kCW4zTJ0J9OQUHq9qdYQM/PGVm99+DWBItUeZAva8Rqj1FN3f9j1eWB+EjfYu7
-ztsTInpNWP4tIh6vIFtuaGr077cJawTe6YVyNxVqquI9+2fpSPkt7tCTIhbQ4AmM
-DeHzn+KjfKN8ooWqmcfmUZWaADe0
------END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDajCCAlKgAwIBAgIJAKPoP2hXKVv4MA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
+BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
+aWRnaXRzIFB0eSBMdGQwHhcNMTkxMTIzMDAwNTA5WhcNMzkxMTE4MDAwNTA5WjBF
+MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
+ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEA4BZUGKkf52583Kps2SinCzRtGFaGIqtP1YfjaN1H21c08hEERRWf0GqW
+PIbZz0NRyqOVM0O+4A9cxKrdqDpALBNXdgB62Ven1NNE31ZjsbFgwbORPTiOQo+6
+Xsu+2KHQdqAGOXSqOdNSoZV/HqAKa41iweg6lUf3yrO/hpfnlXTFbuM/oYFARrr9
+YWY7qH5BEvcZBf4Sg3cWGjdbzYg8S6hnFBBkHPDMbS3xra7H8uru8aG9L70aiq0C
+3WsGf1/Qctz3cccB6BdnbiXji0QlP0miT+b52hEzDvNjdXvoObgbOZsUUcLrbz8q
+LqaQPj6TA2PYpKcxEdJLDcbN++tglQIDAQABo10wWzAfBgNVHSMEGDAWgBSTmtfF
+P/zQDiCbte3AG3vchjSekjAJBgNVHRMEAjAAMAsGA1UdDwQEAwIFoDAgBgNVHREE
+GTAXghVleGFtcGxlLm1pdG1wcm94eS5vcmcwDQYJKoZIhvcNAQELBQADggEBAMoK
+8+KTYF10dbQ8Hl3Fq4Iux7eutAPuKUXUz9dnCfDRhZukdl+gahRoNvkyMBdXOvvx
+R9Z2+Guo8NOYKgT1mJtS/c8IxTkjZj9doujJOVD2wTowSfoaT9z+/EJa+6Fp9+xd
+YVsO3E/2Vxai8PCNx8JTXr2axcnBDvpHPRXF21hOI8N94SPAcmLTZsdsTELjrGGa
+/BA0y+pCEwW6cY9mMHVAAvRoMoqfocBVI7nrYBaQfFoKuwxscxO679eEv+lbSjul
+z/VNdWfqrDhFFSzwRSVchapQ9q1EeTzv++wZRwI5bT0Ib6DFTJB3J5+9RihlFYfU
+GI17CI0D//DsFic7QJ0=
+-----END CERTIFICATE-----
diff --git a/test/mitmproxy/net/data/verificationcerts/trusted-leaf.key b/test/mitmproxy/net/data/verificationcerts/trusted-leaf.key
index 7db3186e..e62ee61f 100644
--- a/test/mitmproxy/net/data/verificationcerts/trusted-leaf.key
+++ b/test/mitmproxy/net/data/verificationcerts/trusted-leaf.key
@@ -1,27 +1,27 @@
------BEGIN RSA PRIVATE KEY-----
-MIIEogIBAAKCAQEAqKzVdsRKgthv6V/dk3Tncy4ymbACs383nGutjulExvroNOCw
-b0y0e7unNGbtXxFQqSvA7eGaT1yRNfoMbXGSS+sn8A3gB6/s2A0Sw7KeSDdoaqEq
-F/LzRBed1YkxSyy0GXuTd7HXNIoFn/eF1tqxgViWdfyFD85qY4yJ+luofdm7IcPM
-ENPzV4nKzDh2PdJpQrEokWz2jM0zefC3IYnFHXY5bA3MnhE03/P0VxeEYkBdmEAt
-O1U2Bkw9SKCLy9zF13ks6/dDZ9LjMtRKI83gQS5z3S3bA45YxFuyeLWgVsJ2NYTa
-j9/8c4xwOjg9TpkCvcmZiPUYGddPHWoKqAAhBwIDAQABAoIBABsUC/zSDEgvKOAl
-RLP8a3+hJfxoNjbMsIfK/YTYy/LJqud6PrjPbpYCjRgrgeXmKLXP0VwfAJ/G84Tf
-zIjxV5Qaf0HZaGKzimkwyBdkoGZlhry/fLt1hDolNHBoYuJ3nb4NiaIIiczkb3y7
-xt+0IhTqvNTaIh5ke83ZbPklJ8p0HAzw1q6+iRFZiZKH1iVRwJyIyK654wpNQ93W
-SqUKa3uAbqw+Bx9fzyEunANFwoBcZka9oSR9bTlhGB8HPHZFVYKgZvE4n9WOclKW
-E75pGG6vFYZkxBdqcjFNlPKKZRisDuey28teiHXThh1MvYxRdaMq4oxOE1J+n17k
-F2gQolECgYEA01j1FlExu45+U36n3tCCyS50dTtf0Qpi71c1s5DZyT+AAB2ZSGXm
-VBtKgVRNg/iWfHn5b/zHF30OtgIzcsrU66cWMwIXPUQigXh8Cteve7VMs03hce1w
-wsFwLoyvdWEam32YAymqRgN3H6JQim82IJJ3YlWrgEytBnvLkADCihkCgYEAzE/g
-8aoxDZJUwbvaZjLwuydmvc+aAwanVgqvtkca4x99oPhNQna6O0jXXAtJXMA3SHp5
-QYMDKh98BqCXyfXd+1Semc9pgAPz7l4j09WG7Zdap3xinTOkUsmTAz/2T967HIsP
-6qP7RUiwjmbUk8ZGcKsNjoxzPA4JURYimKB5qB8CgYBTjlnnJtaYpi8/Z1WK+7iZ
-PSqBpqWtCYQvx7TNdzkDHX3Hjewp+U9kdR2xn9i9kiw8riR1p+Q2XxTP1HLusU4Y
-lIhsRilV6XgS48V2q+sO55CZWvMEjbEE7mEhpjFAINHaI39T0Mcmwvv3n75j3K/z
-lLRqRiB1qtrFM3A5UHOZEQKBgBPQm2xUqTU7v+SaJ3BJ+HbuN1SpUbKBbrE1kB0J
-gF4Oq8x0yGltwloFkn1mytKoAbSRzDjCUAhBzXGHGbGImuLJLiiUqRK1T28Kyka9
-KrzYNP6RXa8JVyKAUjW6elT8sQDvq7eB99icWCM3bd53GFXNAR+WF4b3hYfLscdD
-qQjZAoGAB3ah068Qscb2Ef3+eufa+EvOfMDrNNvlEoZXRlhviTg3NEwjyqbxaCIy
-6Xg+rWvgJm9UE2RBOcCNeghkEabmL1+8DvmDiV1lt9oJtqULBirvalp2H3+9yiTk
-j5dnVcRF6cYvNFmwTr2WZFBGgq96d/Zmbx3o3MIqSBc8I6pLNzo=
------END RSA PRIVATE KEY-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEA4BZUGKkf52583Kps2SinCzRtGFaGIqtP1YfjaN1H21c08hEE
+RRWf0GqWPIbZz0NRyqOVM0O+4A9cxKrdqDpALBNXdgB62Ven1NNE31ZjsbFgwbOR
+PTiOQo+6Xsu+2KHQdqAGOXSqOdNSoZV/HqAKa41iweg6lUf3yrO/hpfnlXTFbuM/
+oYFARrr9YWY7qH5BEvcZBf4Sg3cWGjdbzYg8S6hnFBBkHPDMbS3xra7H8uru8aG9
+L70aiq0C3WsGf1/Qctz3cccB6BdnbiXji0QlP0miT+b52hEzDvNjdXvoObgbOZsU
+UcLrbz8qLqaQPj6TA2PYpKcxEdJLDcbN++tglQIDAQABAoIBAG5V8DB4TdI5T9ej
+Ppcqch2NQc5DBCbb7SI5l5qRogj5BoPOJykQ/bC0WqcQyvxHrGU3aIZma/yM8+OO
+Mjfb/q71ExJyKAsOIwAiyn2hXtMmgHq/vNrFFx7lACIe9ihafHd8UbRGom54g+41
+2vKsYJUWd7L8cqQAXJz9JmfSMeAfRBVVLyOpENSVT8gM/LgPokmZbg0wRJTA5oa3
+10f4Ax1HqXO3cQgKKnrvIU72gB7MQ9Y2G+P2eAmiAlzGr41N5sv7uFz0JrFHhqtC
+qc7QrGVVNtxanu0s/LWgfQ+LrKldTysX16j/j6J0tg7Pfuq9cMFPklU98dv2LF5J
+jMB8eQECgYEA84+Yy/IGVjUPVb3HjmCmWUoxt4Aqop/12/4+1cBNS6h58iLJpcWc
+FVh8m3UbuE7shimEg0fZ1rPPkqepKlDw8/sKXDni/khBASOAh2v1RhvOxNGjxDfn
+ZvcK+BG99kU8ZWQHpKmn8OGfYswL2Fvo67L9XFg/wDnk1QpJx7E1GVUCgYEA64gg
+G6qnsah1NKSW64BPVKi/Gby83l4oa1amjHqq/Unq6iuGB4/QhK4BzW0aOGI7RMTE
+SPh5NF5ZhfT3LWD/EnaMm6QxMTSsL9TDIg36WTVZTkbODFOJczg19EdTs1pa6OXW
+0NM6psLu6Nf/QmHJzyYxSZ83uqPOM305xgooKkECgYEAnA0XMySglr9sUd1EbJ7U
+NkVpUU8XAhdHKWrey4lofN83MsLDPCk+dha5z8jat94pgVQ8iPiSRBP1HNu7cVdm
+6ouf+bNFEvMsYxRiF2I+RmsuscA4E1JWOwxxxLtpYM6/gZ7znrbs2VNWEbD2retF
+cy69UltgjUMKsMzktMN/Z/kCgYAbzV285lAVMIVlSWhnNCYpICIur5C7zvGGehv+
+yRwV+fu42JphmiBLCR89WHuX3ECSxYdF9c6Y1+pJXbkvqhtx2nyOgrsry8PngX3n
+Ly82CI4aJ1F7MwEukJwN0b2XljrU8wyAae6qcKgy5AxFkbV4tlFrF1hEt8FHYqjH
+L7u+AQKBgBnN2vjOVagtlZjJadg5ueR7uKnfk7/TGMtZjNf89C1UZH3TqWnnj6p6
+rLLe4tnA3EebFtGeVWlmnw5k166HRBEd7KuebOCq3hkNlf71aHwhDJ0bIdDwo1g+
+FTpG2vqkqpuEb+2FzDjZT5EdPnj8tUGthREDXpXqsdjFb6+2Enjx
+-----END RSA PRIVATE KEY-----
diff --git a/test/mitmproxy/net/data/verificationcerts/trusted-root.crt b/test/mitmproxy/net/data/verificationcerts/trusted-root.crt
index 5868a304..88ed4145 100644
--- a/test/mitmproxy/net/data/verificationcerts/trusted-root.crt
+++ b/test/mitmproxy/net/data/verificationcerts/trusted-root.crt
@@ -1,21 +1,21 @@
------BEGIN CERTIFICATE-----
-MIIDXTCCAkWgAwIBAgIJALzkvKyFAwWYMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
-BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
-aWRnaXRzIFB0eSBMdGQwHhcNMTgwOTA3MDgyMjUxWhcNMzgwOTAyMDgyMjUxWjBF
-MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
-ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
-CgKCAQEAkvT4Y1ML8Gg4x5aFVygIW022tJsEyfuW4HsEvIarAGpFtUNkw0dOoAxv
-Gv71I0KAWOXxtc9DUjtq7ZXJcG+dBiheTYJ40lrYhHvUt7J37nrUF5v5trQzoE9I
-6WGtzTV8C8RI6F+M6GtwxgwRBgqkuXiK5ExPXAjGMMJZWtiEXHxGTNB6F4zy884m
-VjVtQi8jy+c5g21Awp3z5HrQLM210zwvgi7Rygk6/UM0AnmST4o32SqFSd+0MFUJ
-f3pH3xczfKmhU/TBoVEWRB1YzwixsJrzDOB8wOGnNKCsl45hYUJZZ8epVkyrvFZQ
-iMkwIqqBJbkU6H7fZBl68TJ8ascUCQIDAQABo1AwTjAdBgNVHQ4EFgQUkurgHlw1
-xMP2wrsrGPTk0ofxCyowHwYDVR0jBBgwFoAUkurgHlw1xMP2wrsrGPTk0ofxCyow
-DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAcdExVlSvH6aVExNiQO3k
-cMamj+78woDn9x563vwzaGP24KvOXk1B/IJp5kqu3ZsXS0I0Mz6xwXHAXeuxaj06
-cKgEpHKKgClLblXo2zWqo/3V1UFFpOVP/NhI3r21b+fPrS46rP0mw75haQCph8/8
-buQr0OeAYbElliY/ji+cJiCJB8A/D13fUMV/NUUfPW/UE6497jOmz+6PtZNAoOFx
-evrmDcbCzbJxacyLJX04rsrt6DO09jb/+5lFm5Aqr6ySKasrmheIGEisl4o9Zbuy
-5PvYgbOEmFgPATIiWGpBO/rqwDdsmgyYFl+YfFoW0akXUVhDb2e5iRDx6Rs0fmN/
-NA==
------END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDazCCAlOgAwIBAgIUTE2oFYATbkkytGOt0+CIAOPpaeEwDQYJKoZIhvcNAQEL
+BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
+GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xOTExMjMwMDA1MDlaFw0zOTEx
+MTgwMDA1MDlaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
+HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQDZ7fqv4iC6738OvOC/ONFmhOVmMNe2SrGtk+7KIv/M
+d7MJJKpIygwc99EfL3m6WFjvSQ8CABO9GnLIeoB6RzX5X904dPQzIekMkE27J4D5
+wzYWAmYsu9md//9rjadaA01zHvxtpc30AsToOrRa2Rv7Lwotvcop2bBCXXZMdgvD
+BpCuCOl3cQ346LZBmED41q77P7SgnI98gCPuyyMVAFTZE4NnFUloVERTcMMo5Vwv
+tXFT41B6FOqtyhZFY89W1SeNKlm+n8zu+/aUF5c9usxwvQzj79pzBFYS9xMZzbxl
+BmU91GbLFNU32O+wp0jX6c1MfluGvRjcHQpK+gHRRJdZAgMBAAGjUzBRMB0GA1Ud
+DgQWBBSTmtfFP/zQDiCbte3AG3vchjSekjAfBgNVHSMEGDAWgBSTmtfFP/zQDiCb
+te3AG3vchjSekjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQB6
+CnGmyJKVdD41Qs8QbyZ5VvrAkSq7DkL4CAIDy0pClOYjx51R16g4/dXPd8nuDjVB
+GbRuO/ZHlKeO+RAVbV4s74KeBmQ4uyuZMvuiJGCDtTgu+fbgp1l41vj21bkDnz/X
+0aVrwC4clh6O1/AFCY7cYygp22QJ0zGpIb9d0ly6QDMEocHJKasuQ8/0GPvv6wkY
+hwNub2ScsVFHPrFzzufZblBk3Ks0YZw+IsCMTY7QtGb1TZhGeX9xAydqNMnmIxNj
+XOE2FKx4ISQNFwf/U1LEAruO7PjbbsWx5FHr4oYV9TCLoERZFofwcGGM9o/cPc4P
+CH8fGvFYoU30PG+xX0Pc
+-----END CERTIFICATE-----
diff --git a/test/mitmproxy/net/data/verificationcerts/trusted-root.key b/test/mitmproxy/net/data/verificationcerts/trusted-root.key
index c690751f..11a4d5a6 100644
--- a/test/mitmproxy/net/data/verificationcerts/trusted-root.key
+++ b/test/mitmproxy/net/data/verificationcerts/trusted-root.key
@@ -1,27 +1,27 @@
------BEGIN RSA PRIVATE KEY-----
-MIIEpAIBAAKCAQEAkvT4Y1ML8Gg4x5aFVygIW022tJsEyfuW4HsEvIarAGpFtUNk
-w0dOoAxvGv71I0KAWOXxtc9DUjtq7ZXJcG+dBiheTYJ40lrYhHvUt7J37nrUF5v5
-trQzoE9I6WGtzTV8C8RI6F+M6GtwxgwRBgqkuXiK5ExPXAjGMMJZWtiEXHxGTNB6
-F4zy884mVjVtQi8jy+c5g21Awp3z5HrQLM210zwvgi7Rygk6/UM0AnmST4o32SqF
-Sd+0MFUJf3pH3xczfKmhU/TBoVEWRB1YzwixsJrzDOB8wOGnNKCsl45hYUJZZ8ep
-VkyrvFZQiMkwIqqBJbkU6H7fZBl68TJ8ascUCQIDAQABAoIBAC/1mopvs9nFaaJZ
-UTLccb26YwIWBT4VyWuBOk58dJoyFIXPdLb2MoaxCCF7S20yasiYYoW/Gm1fzsmy
-tIbpJgm4au5Iwj2EQF0cPJOmvtUpaMY7tQcXUDHlLhpcMmhiKBV+/Xw4krfXOHqp
-vXSHTLLq0Akpjkyu4F9RTfAD8U5tEbpPsCGcsSJEHxPgqDexITDwB/yuhvrKKUwY
-t8WQBWO5M8D6Z1HGTFovIa86eX4hUKKbNB8sE7yi1wGxbOloIOQESOcqiisP5GGN
-d6r5k9jBwZXlyh7GR+GNILF+n6ctdOFr6MQQEKvDzjh/IVYADen19909Ed7Wn0gR
-C0Ec2gECgYEAwruIv33GWxGFvQmAUtPaHyhkFOiIpTrmZGeaJe7uLvAF86wK9v35
-wN2fH69JczO1iEWuqDLZ4nEorx6UvjSFBGYTXT1dAnULJ1KHvkk6JjbXq1srTY42
-U2h33XfJiNgrXlj6v7tMhKD/nBsfyw8v4aHxxUkJl2HomPSv7C7EvhECgYEAwTFp
-sUwDXVeputWwBvDUXHgGaVks28QHXvYH7Q0WsbFjb6lZVH/FxLXvGs7aaZk8WuHQ
-JJcXmEkTs1QDMMWoOlZw9WJv5Zlopq31oYHp8dt2EuO/PQcYmXYEG7JIHJhx8mfL
-f3Y4ix/hnvnITTg7bRNpcxwGEqyg16kalP8PXnkCgYEAgml5cVTYLFEV0b21NMMw
-RsGUFPSN3qoNdZx0fYb/+GtCcSf8x+DbDDDfyiZn+EDfB/4ys+4qQR4rcuv2DVO6
-6XE68qyPx39/EryQr/z2dnUwBlAuNehRtZY3ABii3YR3tt28P/89hW0VAgSgTCtF
-k8QS2F7Lj5hAX38u+etwUyECgYBWjf7eckHnpgjjLi3JTki2jQfCVzOj2nW689ul
-NwH95o24T1U4aG6ArUpM5nQwb3j89sK8Qf1OOx9abr9nMIcoa+X76nhbk5mxY6rz
-CzN3Km4CFItvmihJSPiaOAva0+npQtuHZb37hvMcuKgnAJSPT+0kp1+JKlJ9jMPe
-EVAfcQKBgQCDxRNXxn4ILyH3kx8lrch7kD5fp/7KifDjAFFJ0DK2e2xsxLUToh2I
-PdMuzCUv4LL8kRsQ/+mUJY4YlOV9OKVAZbI/gPw9NnzBUBugz+wy0OG/nyS5k7G5
-MIzZm8yx3RieTNhwmw25NDLyGApHGQYsQ7DM/daA/wwdjFsyncxHSg==
------END RSA PRIVATE KEY-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEA2e36r+Iguu9/DrzgvzjRZoTlZjDXtkqxrZPuyiL/zHezCSSq
+SMoMHPfRHy95ulhY70kPAgATvRpyyHqAekc1+V/dOHT0MyHpDJBNuyeA+cM2FgJm
+LLvZnf//a42nWgNNcx78baXN9ALE6Dq0Wtkb+y8KLb3KKdmwQl12THYLwwaQrgjp
+d3EN+Oi2QZhA+Nau+z+0oJyPfIAj7ssjFQBU2RODZxVJaFREU3DDKOVcL7VxU+NQ
+ehTqrcoWRWPPVtUnjSpZvp/M7vv2lBeXPbrMcL0M4+/acwRWEvcTGc28ZQZlPdRm
+yxTVN9jvsKdI1+nNTH5bhr0Y3B0KSvoB0USXWQIDAQABAoIBAQCWWYbgHSPzlBOW
+eVyc0Hg3QGx7aisIStP2Kt9NeYP87oAISNFqUmq0+Yu+9iQHGbiRrVe7S45SopKa
+GVnWApcMKsUWlCl9tWFxF4VpH0HuDm2cFZ+kMR1b0ifHbf0NLsYaLEB+7Sr/s4Fh
+rk6LdsnFK5jcIdn9sX/W6WAaND69Ft45sMXuAKPeqwySm7t77nlIEp4lJy/F/rvS
+UUV77UVL/5GqC1HOP1kXXEJDxHtNrDPh0fF49Qo/6JPRmLIOia0yKUS5+8lKHh6V
+J7nWTucyvviKoYvdJHpi9w2+DTI7mT33Go1Ss4QgHihzcURTtfjsn7yOelS6z8XM
+YOxURwoZAoGBAPZpod0Zpjm9trf547reFPLfAJUiKDj1wYXnlpSFAzOf7pSXDrfW
+L5dc3c5x2DiBXUlBu03ZWo7wVOKv7d9ByTrvXEqT1/KTqmHoI6Mzy0rn9wU0FmL4
+ASPcpPMnNStOSmRfe9HITDVvgLYo2wQEu1MXf5rGs5HjTRpEGVdWRkRPAoGBAOJo
+pQ9uRtaLlCF3KXoRr8HCBKI64IWDki7pbbLTglOBbmptQLfE2GPc/FPBsQwR3KBX
+m18A2pc7CRUKzsDavb7SyXTqtP3NF/AguTjGXIv/45QD6A96SStaYR0ZXSA3/uhZ
+rAaSSXxaI3mDTc32pXoXJDp7K+CPc5w00I8u1/fXAoGAe1UPoPyPiGL+K0M1yngR
+gCZBwmMgQrIutHjfk2Kn4ZTw8wpQYY8grt/aXNP6Zv3I1TvDJgneG6EKu5NWueHR
+eGAJj4JEGbPzGaH5BFyOKeXEa6RQeCStXWe4X8OGBzDeZzKrZKqeCjjO8V2tkWtU
+3xfp1GwTwLdGBhmDnYUfEl0CgYEA1vzVF6T4gQtDGtADQ5V91je8nKvZvQ4lhoRD
+lVZAX7j8tvSNSrMRYypZM9Mtoi9n1524vGqcJpR5WFDN6NUM7iFMCMhCGupgO7Vn
+DCFXidzvJgLbna7Zwd/tbWtDQa/KTqmvrwHD49/X5a+n9tapZRiKXznMfUzaU87W
+589sZjsCgYBQvtZpNQRqTDNOSuIJGsloMNp1HG2Keoj/nBQ9idkw29rUqhae7ZAa
+Csk91ix+AMR8nzQSkpHWOk2+RjdVAQ7m87bnQM6mmAJTcipikDfFxNqOWt7JkM2h
+Ydk36LHBIBVLOeqMXrhCHvai3h6efUz7wjGhNxRJ2OGrzWFfLgVsqA==
+-----END RSA PRIVATE KEY-----
diff --git a/test/mitmproxy/net/data/verificationcerts/trusted-root.srl b/test/mitmproxy/net/data/verificationcerts/trusted-root.srl
index cf60e2a5..ee465f9d 100644
--- a/test/mitmproxy/net/data/verificationcerts/trusted-root.srl
+++ b/test/mitmproxy/net/data/verificationcerts/trusted-root.srl
@@ -1 +1 @@
-A3E83F6857295BF7
+A3E83F6857295BF8
diff --git a/test/mitmproxy/net/http/http1/test_assemble.py b/test/mitmproxy/net/http/http1/test_assemble.py
index ab177885..4b4ab414 100644
--- a/test/mitmproxy/net/http/http1/test_assemble.py
+++ b/test/mitmproxy/net/http/http1/test_assemble.py
@@ -15,7 +15,6 @@ def test_assemble_request():
b"GET /path HTTP/1.1\r\n"
b"header: qvalue\r\n"
b"content-length: 7\r\n"
- b"host: address:22\r\n"
b"\r\n"
b"content"
)
@@ -84,17 +83,6 @@ def test_assemble_request_headers():
assert b"Transfer-Encoding" in c
-def test_assemble_request_headers_host_header():
- r = treq()
- r.headers = Headers()
- c = _assemble_request_headers(r.data)
- assert b"host" in c
-
- r.host = None
- c = _assemble_request_headers(r.data)
- assert b"host" not in c
-
-
def test_assemble_response_headers():
# https://github.com/mitmproxy/mitmproxy/issues/186
r = tresp(content=b"")
diff --git a/test/mitmproxy/net/http/http1/test_read.py b/test/mitmproxy/net/http/http1/test_read.py
index 4084c360..127f75ba 100644
--- a/test/mitmproxy/net/http/http1/test_read.py
+++ b/test/mitmproxy/net/http/http1/test_read.py
@@ -163,6 +163,11 @@ def test_expected_http_body_size():
assert expected_http_body_size(
treq(headers=Headers(expect="100-continue", content_length="42"))
) == 0
+ # Expect: 100-continue
+ assert expected_http_body_size(
+ treq(headers=Headers(expect="100-continue", content_length="42")),
+ expect_continue_as_0=False
+ ) == 42
# http://tools.ietf.org/html/rfc7230#section-3.3
assert expected_http_body_size(
diff --git a/test/mitmproxy/net/http/test_headers.py b/test/mitmproxy/net/http/test_headers.py
index 8fc8b027..5f208dcb 100644
--- a/test/mitmproxy/net/http/test_headers.py
+++ b/test/mitmproxy/net/http/test_headers.py
@@ -88,6 +88,8 @@ class TestHeaders:
headers = Headers(Host="foobarfoo.com", Accept="foo/bar")
replacements = headers.replace("foo", "bar", count=1)
assert replacements == 1
+ assert headers["Host"] == "barbarfoo.com"
+ assert headers["Accept"] == "foo/bar"
def test_parse_content_type():
diff --git a/test/mitmproxy/net/test_tcp.py b/test/mitmproxy/net/test_tcp.py
index 22a306dc..ba9b7ebc 100644
--- a/test/mitmproxy/net/test_tcp.py
+++ b/test/mitmproxy/net/test_tcp.py
@@ -37,7 +37,7 @@ class ClientCipherListHandler(tcp.BaseHandler):
sni = None
def handle(self):
- self.wfile.write(str(self.connection.get_cipher_list()).encode())
+ self.wfile.write(f"{self.connection.get_cipher_list()}\n".encode())
self.wfile.flush()
@@ -219,7 +219,7 @@ class TestInvalidTrustFile(tservers.ServerTestBase):
c.convert_to_tls(
sni="example.mitmproxy.org",
verify=SSL.VERIFY_PEER,
- ca_pemfile=tdata.path("mitmproxy/net/data/verificationcerts/generate.py")
+ ca_pemfile=cdata.path("data/verificationcerts/generate.py")
)
@@ -265,7 +265,7 @@ class TestSSLUpstreamCertVerificationWBadServerCert(tservers.ServerTestBase):
c.convert_to_tls(
sni="example.mitmproxy.org",
verify=SSL.VERIFY_PEER,
- ca_pemfile=tdata.path("mitmproxy/net/data/verificationcerts/trusted-root.crt")
+ ca_pemfile=cdata.path("data/verificationcerts/trusted-root.crt")
)
assert c.ssl_verification_error
@@ -289,7 +289,7 @@ class TestSSLUpstreamCertVerificationWBadHostname(tservers.ServerTestBase):
with pytest.raises(exceptions.TlsException):
c.convert_to_tls(
verify=SSL.VERIFY_PEER,
- ca_pemfile=tdata.path("mitmproxy/net/data/verificationcerts/trusted-root.crt")
+ ca_pemfile=cdata.path("data/verificationcerts/trusted-root.crt")
)
def test_mode_none_should_pass_without_sni(self, tdata):
@@ -297,10 +297,10 @@ class TestSSLUpstreamCertVerificationWBadHostname(tservers.ServerTestBase):
with c.connect():
c.convert_to_tls(
verify=SSL.VERIFY_NONE,
- ca_path=tdata.path("mitmproxy/net/data/verificationcerts/")
+ ca_path=cdata.path("data/verificationcerts/")
)
- assert "'no-hostname' doesn't match" in str(c.ssl_verification_error)
+ assert "Cannot validate hostname, SNI missing." in str(c.ssl_verification_error)
def test_should_fail(self, tdata):
c = tcp.TCPClient(("127.0.0.1", self.port))
@@ -309,7 +309,7 @@ class TestSSLUpstreamCertVerificationWBadHostname(tservers.ServerTestBase):
c.convert_to_tls(
sni="mitmproxy.org",
verify=SSL.VERIFY_PEER,
- ca_pemfile=tdata.path("mitmproxy/net/data/verificationcerts/trusted-root.crt")
+ ca_pemfile=cdata.path("data/verificationcerts/trusted-root.crt")
)
assert c.ssl_verification_error
@@ -328,7 +328,7 @@ class TestSSLUpstreamCertVerificationWValidCertChain(tservers.ServerTestBase):
c.convert_to_tls(
sni="example.mitmproxy.org",
verify=SSL.VERIFY_PEER,
- ca_pemfile=tdata.path("mitmproxy/net/data/verificationcerts/trusted-root.crt")
+ ca_pemfile=cdata.path("data/verificationcerts/trusted-root.crt")
)
assert c.ssl_verification_error is None
@@ -344,7 +344,7 @@ class TestSSLUpstreamCertVerificationWValidCertChain(tservers.ServerTestBase):
c.convert_to_tls(
sni="example.mitmproxy.org",
verify=SSL.VERIFY_PEER,
- ca_path=tdata.path("mitmproxy/net/data/verificationcerts/")
+ ca_path=cdata.path("data/verificationcerts/")
)
assert c.ssl_verification_error is None
@@ -376,14 +376,14 @@ class TestSSLClientCert(tservers.ServerTestBase):
c = tcp.TCPClient(("127.0.0.1", self.port))
with c.connect():
c.convert_to_tls(
- cert=tdata.path("mitmproxy/net/data/clientcert/client.pem"))
+ cert=cdata.path("data/clientcert/client.pem"))
assert c.rfile.readline().strip() == b"1"
def test_clientcert_err(self, tdata):
c = tcp.TCPClient(("127.0.0.1", self.port))
with c.connect():
with pytest.raises(exceptions.TlsException):
- c.convert_to_tls(cert=tdata.path("mitmproxy/net/data/clientcert/make"))
+ c.convert_to_tls(cert=cdata.path("data/clientcert/make"))
class TestSNI(tservers.ServerTestBase):
@@ -421,16 +421,18 @@ class TestServerCipherList(tservers.ServerTestBase):
cipher_list='AES256-GCM-SHA384'
)
+ @pytest.mark.xfail
def test_echo(self):
+ # Not working for OpenSSL 1.1.1, see
+ # https://github.com/pyca/pyopenssl/blob/fc802df5c10f0d1cd9749c94887d652fa26db6fb/src/OpenSSL/SSL.py#L1192-L1196
c = tcp.TCPClient(("127.0.0.1", self.port))
with c.connect():
c.convert_to_tls(sni="foo.com")
- expected = b"['AES256-GCM-SHA384']"
- assert c.rfile.read(len(expected) + 2) == expected
+ expected = b"['TLS_AES_256_GCM_SHA384']"
+ assert c.rfile.readline() == expected
class TestServerCurrentCipher(tservers.ServerTestBase):
-
class handler(tcp.BaseHandler):
sni = None
@@ -442,7 +444,10 @@ class TestServerCurrentCipher(tservers.ServerTestBase):
cipher_list='AES256-GCM-SHA384'
)
+ @pytest.mark.xfail
def test_echo(self):
+ # Not working for OpenSSL 1.1.1, see
+ # https://github.com/pyca/pyopenssl/blob/fc802df5c10f0d1cd9749c94887d652fa26db6fb/src/OpenSSL/SSL.py#L1192-L1196
c = tcp.TCPClient(("127.0.0.1", self.port))
with c.connect():
c.convert_to_tls(sni="foo.com")
@@ -608,7 +613,7 @@ class TestDHParams(tservers.ServerTestBase):
def test_dhparams(self):
c = tcp.TCPClient(("127.0.0.1", self.port))
with c.connect():
- c.convert_to_tls()
+ c.convert_to_tls(method=SSL.TLSv1_2_METHOD)
ret = c.get_current_cipher()
assert ret[0] == "DHE-RSA-AES256-SHA"
diff --git a/test/mitmproxy/net/test_tls.py b/test/mitmproxy/net/test_tls.py
index c4e76bc6..e78564c7 100644
--- a/test/mitmproxy/net/test_tls.py
+++ b/test/mitmproxy/net/test_tls.py
@@ -43,7 +43,7 @@ class TestMasterSecretLogger(tservers.ServerTestBase):
tls.log_master_secret.close()
with open(logfile, "rb") as f:
- assert f.read().count(b"CLIENT_RANDOM") == 2
+ assert f.read().count(b"CLIENT_RANDOM") >= 2
tls.log_master_secret = _logfun
diff --git a/test/mitmproxy/test_connections.py b/test/mitmproxy/test_connections.py
index 7c371c1e..ae296631 100644
--- a/test/mitmproxy/test_connections.py
+++ b/test/mitmproxy/test_connections.py
@@ -199,6 +199,9 @@ class TestClientConnectionTLS:
s = socket.create_connection(address)
s = ctx.wrap_socket(s, server_hostname=sni)
s.send(b'foobar')
+ # we need to wait for the test to finish successfully before calling .close() on Windows.
+ # The workaround here is to signal completion by sending data the other way around.
+ s.recv(3)
s.close()
threading.Thread(target=client_run).start()
@@ -216,6 +219,7 @@ class TestClientConnectionTLS:
assert c.sni == sni
assert c.tls_established
assert c.rfile.read(6) == b'foobar'
+ c.wfile.send(b"foo")
c.finish()
sock.close()
diff --git a/tox.ini b/tox.ini
index 729d529a..73600759 100644
--- a/tox.ini
+++ b/tox.ini
@@ -41,7 +41,7 @@ passenv = CI_* GITHUB_* AWS_* TWINE_* DOCKER_*
deps =
-rrequirements.txt
pyinstaller==3.5
- twine==2.0.0
+ twine==3.1.1
awscli
commands =
mitmdump --version
diff --git a/web/README.md b/web/README.md
index ebdd1f2f..ae558bd6 100644
--- a/web/README.md
+++ b/web/README.md
@@ -1,5 +1,7 @@
# Quick Start
+**Be sure to follow the Development Setup instructions found in the README.md,
+and activate your virtualenv environment before proceeding.**
- Run `yarn` to install dependencies
- Run `yarn run gulp` to start live-compilation.