mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-22 07:08:10 +00:00
parent
4f925848d9
commit
81c911345b
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
* fix some responses not being decoded properly if the encoding was uppercase #4735 (@Mattwmaster58)
|
* fix some responses not being decoded properly if the encoding was uppercase #4735 (@Mattwmaster58)
|
||||||
* Expose TLS 1.0 as possible minimum version on older pyOpenSSL releases
|
* Expose TLS 1.0 as possible minimum version on older pyOpenSSL releases
|
||||||
|
* Improve error message on TLS version mismatch.
|
||||||
* Windows: Switch to Python's default asyncio event loop, which increases the number of sockets
|
* Windows: Switch to Python's default asyncio event loop, which increases the number of sockets
|
||||||
that can be processed simultaneously.
|
that can be processed simultaneously.
|
||||||
|
|
||||||
|
@ -34,15 +34,10 @@ class Context:
|
|||||||
return ret
|
return ret
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
layers = "\n ".join(repr(l) for l in self.layers)
|
|
||||||
if layers:
|
|
||||||
layers = f"[\n {layers}\n ]"
|
|
||||||
else:
|
|
||||||
layers = "[]"
|
|
||||||
return (
|
return (
|
||||||
f"Context(\n"
|
f"Context(\n"
|
||||||
f" {self.client!r},\n"
|
f" {self.client!r},\n"
|
||||||
f" {self.server!r},\n"
|
f" {self.server!r},\n"
|
||||||
f" layers={layers}\n"
|
f" layers=[{self.layers!r}]\n"
|
||||||
f")"
|
f")"
|
||||||
)
|
)
|
||||||
|
@ -213,8 +213,12 @@ class _TLSLayer(tunnel.TunnelLayer):
|
|||||||
err = last_err[2]
|
err = last_err[2]
|
||||||
elif last_err == ('SSL routines', 'ssl3_get_record', 'wrong version number') and data[:4].isascii():
|
elif last_err == ('SSL routines', 'ssl3_get_record', 'wrong version number') and data[:4].isascii():
|
||||||
err = f"The remote server does not speak TLS."
|
err = f"The remote server does not speak TLS."
|
||||||
else: # pragma: no cover
|
elif last_err == ('SSL routines', 'ssl3_read_bytes', 'tlsv1 alert protocol version'):
|
||||||
# TODO: Add test case once we find one.
|
err = (
|
||||||
|
f"The remote server and mitmproxy cannot agree on a TLS version to use. "
|
||||||
|
f"You may need to adjust mitmproxy's tls_version_server_min option."
|
||||||
|
)
|
||||||
|
else:
|
||||||
err = f"OpenSSL {e!r}"
|
err = f"OpenSSL {e!r}"
|
||||||
self.conn.error = err
|
self.conn.error = err
|
||||||
return False, err
|
return False, err
|
||||||
@ -428,6 +432,11 @@ class ClientTLSLayer(_TLSLayer):
|
|||||||
level: Literal["warn", "info"] = "warn"
|
level: Literal["warn", "info"] = "warn"
|
||||||
if err.startswith("Cannot parse ClientHello"):
|
if err.startswith("Cannot parse ClientHello"):
|
||||||
pass
|
pass
|
||||||
|
elif "('SSL routines', 'tls_early_post_process_client_hello', 'unsupported protocol')" in err:
|
||||||
|
err = (
|
||||||
|
f"Client and mitmproxy cannot agree on a TLS version to use. "
|
||||||
|
f"You may need to adjust mitmproxy's tls_version_client_min option."
|
||||||
|
)
|
||||||
elif "unknown ca" in err or "bad certificate" in err:
|
elif "unknown ca" in err or "bad certificate" in err:
|
||||||
err = f"The client does not trust the proxy's certificate for {dest} ({err})"
|
err = f"The client does not trust the proxy's certificate for {dest} ({err})"
|
||||||
elif err == "connection closed":
|
elif err == "connection closed":
|
||||||
|
@ -86,8 +86,13 @@ def test_parse_client_hello():
|
|||||||
class SSLTest:
|
class SSLTest:
|
||||||
"""Helper container for Python's builtin SSL object."""
|
"""Helper container for Python's builtin SSL object."""
|
||||||
|
|
||||||
def __init__(self, server_side: bool = False, alpn: typing.Optional[typing.List[str]] = None,
|
def __init__(
|
||||||
sni: typing.Optional[bytes] = b"example.mitmproxy.org"):
|
self,
|
||||||
|
server_side: bool = False,
|
||||||
|
alpn: typing.Optional[typing.List[str]] = None,
|
||||||
|
sni: typing.Optional[bytes] = b"example.mitmproxy.org",
|
||||||
|
max_ver: typing.Optional[ssl.TLSVersion] = None,
|
||||||
|
):
|
||||||
self.inc = ssl.MemoryBIO()
|
self.inc = ssl.MemoryBIO()
|
||||||
self.out = ssl.MemoryBIO()
|
self.out = ssl.MemoryBIO()
|
||||||
self.ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER if server_side else ssl.PROTOCOL_TLS_CLIENT)
|
self.ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER if server_side else ssl.PROTOCOL_TLS_CLIENT)
|
||||||
@ -104,6 +109,8 @@ class SSLTest:
|
|||||||
certfile=tlsdata.path("../../net/data/verificationcerts/trusted-leaf.crt"),
|
certfile=tlsdata.path("../../net/data/verificationcerts/trusted-leaf.crt"),
|
||||||
keyfile=tlsdata.path("../../net/data/verificationcerts/trusted-leaf.key"),
|
keyfile=tlsdata.path("../../net/data/verificationcerts/trusted-leaf.key"),
|
||||||
)
|
)
|
||||||
|
if max_ver:
|
||||||
|
self.ctx.maximum_version = max_ver
|
||||||
|
|
||||||
self.obj = self.ctx.wrap_bio(
|
self.obj = self.ctx.wrap_bio(
|
||||||
self.inc,
|
self.inc,
|
||||||
@ -162,7 +169,10 @@ def reply_tls_start_client(alpn: typing.Optional[bytes] = None, *args, **kwargs)
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def make_client_conn(tls_start: tls.TlsStartData) -> None:
|
def make_client_conn(tls_start: tls.TlsStartData) -> None:
|
||||||
|
# ssl_context = SSL.Context(Method.TLS_METHOD)
|
||||||
|
# ssl_context.set_min_proto_version(SSL.TLS1_3_VERSION)
|
||||||
ssl_context = SSL.Context(SSL.SSLv23_METHOD)
|
ssl_context = SSL.Context(SSL.SSLv23_METHOD)
|
||||||
|
ssl_context.set_options(SSL.OP_NO_SSLv3 | SSL.OP_NO_TLSv1 | SSL.OP_NO_TLSv1_1 | SSL.OP_NO_TLSv1_2)
|
||||||
ssl_context.use_privatekey_file(
|
ssl_context.use_privatekey_file(
|
||||||
tlsdata.path("../../net/data/verificationcerts/trusted-leaf.key")
|
tlsdata.path("../../net/data/verificationcerts/trusted-leaf.key")
|
||||||
)
|
)
|
||||||
@ -184,7 +194,10 @@ def reply_tls_start_server(alpn: typing.Optional[bytes] = None, *args, **kwargs)
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def make_server_conn(tls_start: tls.TlsStartData) -> None:
|
def make_server_conn(tls_start: tls.TlsStartData) -> None:
|
||||||
|
# ssl_context = SSL.Context(Method.TLS_METHOD)
|
||||||
|
# ssl_context.set_min_proto_version(SSL.TLS1_3_VERSION)
|
||||||
ssl_context = SSL.Context(SSL.SSLv23_METHOD)
|
ssl_context = SSL.Context(SSL.SSLv23_METHOD)
|
||||||
|
ssl_context.set_options(SSL.OP_NO_SSLv3 | SSL.OP_NO_TLSv1 | SSL.OP_NO_TLSv1_1 | SSL.OP_NO_TLSv1_2)
|
||||||
ssl_context.load_verify_locations(
|
ssl_context.load_verify_locations(
|
||||||
cafile=tlsdata.path("../../net/data/verificationcerts/trusted-root.crt")
|
cafile=tlsdata.path("../../net/data/verificationcerts/trusted-root.crt")
|
||||||
)
|
)
|
||||||
@ -337,6 +350,39 @@ class TestServerTLS:
|
|||||||
<< commands.CloseConnection(tctx.server)
|
<< commands.CloseConnection(tctx.server)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_unsupported_protocol(self, tctx: context.Context):
|
||||||
|
"""Test the scenario where the server only supports an outdated TLS version by default."""
|
||||||
|
playbook = tutils.Playbook(tls.ServerTLSLayer(tctx))
|
||||||
|
tctx.server.address = ("example.mitmproxy.org", 443)
|
||||||
|
tctx.server.state = ConnectionState.OPEN
|
||||||
|
tctx.server.sni = "example.mitmproxy.org"
|
||||||
|
|
||||||
|
# noinspection PyTypeChecker
|
||||||
|
tssl = SSLTest(server_side=True, max_ver=ssl.TLSVersion.TLSv1_2)
|
||||||
|
|
||||||
|
# send ClientHello
|
||||||
|
data = tutils.Placeholder(bytes)
|
||||||
|
assert (
|
||||||
|
playbook
|
||||||
|
<< tls.TlsStartServerHook(tutils.Placeholder())
|
||||||
|
>> reply_tls_start_server()
|
||||||
|
<< commands.SendData(tctx.server, data)
|
||||||
|
)
|
||||||
|
|
||||||
|
# receive ServerHello
|
||||||
|
tssl.bio_write(data())
|
||||||
|
with pytest.raises(ssl.SSLError):
|
||||||
|
tssl.do_handshake()
|
||||||
|
|
||||||
|
# send back error
|
||||||
|
assert (
|
||||||
|
playbook
|
||||||
|
>> events.DataReceived(tctx.server, tssl.bio_read())
|
||||||
|
<< commands.Log("Server TLS handshake failed. The remote server and mitmproxy cannot agree on a TLS version"
|
||||||
|
" to use. You may need to adjust mitmproxy's tls_version_server_min option.", "warn")
|
||||||
|
<< commands.CloseConnection(tctx.server)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def make_client_tls_layer(
|
def make_client_tls_layer(
|
||||||
tctx: context.Context,
|
tctx: context.Context,
|
||||||
@ -564,3 +610,20 @@ class TestClientTLS:
|
|||||||
"client does not trust the proxy's certificate.", "info")
|
"client does not trust the proxy's certificate.", "info")
|
||||||
<< commands.CloseConnection(tctx.client)
|
<< commands.CloseConnection(tctx.client)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_unsupported_protocol(self, tctx: context.Context):
|
||||||
|
"""Test the scenario where the client only supports an outdated TLS version by default."""
|
||||||
|
playbook, client_layer, tssl_client = make_client_tls_layer(tctx, max_ver=ssl.TLSVersion.TLSv1_2)
|
||||||
|
playbook.logs = True
|
||||||
|
|
||||||
|
assert (
|
||||||
|
playbook
|
||||||
|
>> events.DataReceived(tctx.client, tssl_client.bio_read())
|
||||||
|
<< tls.TlsClienthelloHook(tutils.Placeholder())
|
||||||
|
>> tutils.reply()
|
||||||
|
<< tls.TlsStartClientHook(tutils.Placeholder())
|
||||||
|
>> reply_tls_start_client()
|
||||||
|
<< commands.Log("Client TLS handshake failed. Client and mitmproxy cannot agree on a TLS version to "
|
||||||
|
"use. You may need to adjust mitmproxy's tls_version_client_min option.", "warn")
|
||||||
|
<< commands.CloseConnection(tctx.client)
|
||||||
|
)
|
||||||
|
@ -2,6 +2,7 @@ import collections.abc
|
|||||||
import difflib
|
import difflib
|
||||||
import itertools
|
import itertools
|
||||||
import re
|
import re
|
||||||
|
import textwrap
|
||||||
import traceback
|
import traceback
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
@ -65,6 +66,7 @@ def _fmt_entry(x: PlaybookEntry):
|
|||||||
x = str(x)
|
x = str(x)
|
||||||
x = re.sub('Placeholder:None', '<unset placeholder>', x, flags=re.IGNORECASE)
|
x = re.sub('Placeholder:None', '<unset placeholder>', x, flags=re.IGNORECASE)
|
||||||
x = re.sub('Placeholder:', '', x, flags=re.IGNORECASE)
|
x = re.sub('Placeholder:', '', x, flags=re.IGNORECASE)
|
||||||
|
x = textwrap.indent(x, " ")[5:]
|
||||||
return f"{arrow} {x}"
|
return f"{arrow} {x}"
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user