Esempio n. 1
0
    def test_tls_start_client(self, tdata):
        ta = tlsconfig.TlsConfig()
        with taddons.context(ta) as tctx:
            ta.configure(["confdir"])
            tctx.configure(
                ta,
                certs=[
                    tdata.path(
                        "mitmproxy/net/data/verificationcerts/trusted-leaf.pem"
                    )
                ],
                ciphers_client="ECDHE-ECDSA-AES128-GCM-SHA256",
            )
            ctx = context.Context(
                connection.Client(("client", 1234), ("127.0.0.1", 8080),
                                  1605699329), tctx.options)

            tls_start = tls.TlsData(ctx.client, context=ctx)
            ta.tls_start_client(tls_start)
            tssl_server = tls_start.ssl_conn

            # assert that a preexisting ssl_conn is not overwritten
            ta.tls_start_client(tls_start)
            assert tssl_server is tls_start.ssl_conn

            tssl_client = test_tls.SSLTest()
            assert self.do_handshake(tssl_client, tssl_server)
            assert tssl_client.obj.getpeercert()["subjectAltName"] == ((
                "DNS", "example.mitmproxy.org"), )
Esempio n. 2
0
def tctx() -> context.Context:
    opts = options.Options()
    Proxyserver().load(opts)
    TermLog().load(opts)
    return context.Context(
        connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329),
        opts)
Esempio n. 3
0
    def test_alpn_selection(self):
        ta = tlsconfig.TlsConfig()
        with taddons.context(ta) as tctx:
            ctx = context.Context(
                connection.Client(("client", 1234), ("127.0.0.1", 8080),
                                  1605699329), tctx.options)
            ctx.server.address = ("example.mitmproxy.org", 443)
            tls_start = tls.TlsStartData(ctx.server, context=ctx)

            def assert_alpn(http2, client_offers, expected):
                tctx.configure(ta, http2=http2)
                ctx.client.alpn_offers = client_offers
                ctx.server.alpn_offers = None
                ta.tls_start(tls_start)
                assert ctx.server.alpn_offers == expected

            assert_alpn(True, tls.HTTP_ALPNS + (b"foo", ),
                        tls.HTTP_ALPNS + (b"foo", ))
            assert_alpn(False, tls.HTTP_ALPNS + (b"foo", ),
                        tls.HTTP1_ALPNS + (b"foo", ))
            assert_alpn(True, [], tls.HTTP_ALPNS)
            assert_alpn(False, [], tls.HTTP1_ALPNS)
            ctx.client.timestamp_tls_setup = time.time()
            # make sure that we don't upgrade h1 to h2,
            # see comment in tlsconfig.py
            assert_alpn(True, [], [])
Esempio n. 4
0
    def test_get_cert(self, tdata):
        """Test that we generate a certificate matching the connection's context."""
        ta = tlsconfig.TlsConfig()
        with taddons.context(ta) as tctx:
            ta.configure(["confdir"])

            ctx = context.Context(
                connection.Client(("client", 1234), ("127.0.0.1", 8080),
                                  1605699329), tctx.options)

            # Edge case first: We don't have _any_ idea about the server, so we just return "mitmproxy" as subject.
            entry = ta.get_cert(ctx)
            assert entry.cert.cn == "mitmproxy"

            # Here we have an existing server connection...
            ctx.server.address = ("server-address.example", 443)
            with open(
                    tdata.path(
                        "mitmproxy/net/data/verificationcerts/trusted-leaf.crt"
                    ), "rb") as f:
                ctx.server.certificate_list = [certs.Cert.from_pem(f.read())]
            entry = ta.get_cert(ctx)
            assert entry.cert.cn == "example.mitmproxy.org"
            assert entry.cert.altnames == [
                "example.mitmproxy.org", "server-address.example"
            ]

            # And now we also incorporate SNI.
            ctx.client.sni = "sni.example"
            entry = ta.get_cert(ctx)
            assert entry.cert.altnames == [
                "example.mitmproxy.org", "sni.example"
            ]
Esempio n. 5
0
 def test_tls_clienthello(self):
     # only really testing for coverage here, there's no point in mirroring the individual conditions
     ta = tlsconfig.TlsConfig()
     with taddons.context(ta) as tctx:
         ctx = context.Context(connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
         ch = tls.ClientHelloData(ctx, None)  # type: ignore
         ta.tls_clienthello(ch)
         assert not ch.establish_server_tls_first
Esempio n. 6
0
def test_fuzz_h1_request(data):
    tctx = context.Context(connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), opts)

    layer = http.HttpLayer(tctx, HTTPMode.regular)
    for _ in layer.handle_event(Start()):
        pass
    for chunk in data:
        for _ in layer.handle_event(DataReceived(tctx.client, chunk)):
            pass
Esempio n. 7
0
async def test_block_global(block_global, block_private, should_be_killed,
                            address):
    ar = block.Block()
    with taddons.context(ar) as tctx:
        tctx.configure(ar,
                       block_global=block_global,
                       block_private=block_private)
        client = connection.Client(address, ("127.0.0.1", 8080), 1607699500)
        ar.client_connected(client)
        assert bool(client.error) == should_be_killed
Esempio n. 8
0
def h2_layer(opts):
    tctx = context.Context(connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), opts)
    tctx.client.alpn = b"h2"

    layer = http.HttpLayer(tctx, HTTPMode.regular)
    for _ in layer.handle_event(Start()):
        pass
    for _ in layer.handle_event(DataReceived(tctx.client, b'PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n')):
        pass
    return tctx, layer
Esempio n. 9
0
    def receive_handshake_data(
            self,
            data: bytes) -> layer.CommandGenerator[Tuple[bool, Optional[str]]]:
        if self.client_hello_parsed:
            return (yield from super().receive_handshake_data(data))
        self.recv_buffer.extend(data)
        try:
            client_hello = parse_client_hello(self.recv_buffer)
        except ValueError:
            return False, f"Cannot parse ClientHello: {self.recv_buffer.hex()}"

        if client_hello:
            self.client_hello_parsed = True
        else:
            return False, None

        self.conn.sni = client_hello.sni
        self.conn.alpn_offers = client_hello.alpn_protocols
        tls_clienthello = ClientHelloData(self.context, client_hello)
        yield TlsClienthelloHook(tls_clienthello)

        if tls_clienthello.ignore_connection:
            # we've figured out that we don't want to intercept this connection, so we assign fake connection objects
            # to all TLS layers. This makes the real connection contents just go through.
            self.conn = self.tunnel_connection = connection.Client(
                ("ignore-conn", 0), ("ignore-conn", 0), time.time())
            parent_layer = self.context.layers[self.context.layers.index(self)
                                               - 1]
            if isinstance(parent_layer, ServerTLSLayer):
                parent_layer.conn = parent_layer.tunnel_connection = connection.Server(
                    None)
            self.child_layer = tcp.TCPLayer(self.context, ignore=True)
            yield from self.event_to_child(
                events.DataReceived(self.context.client,
                                    bytes(self.recv_buffer)))
            self.recv_buffer.clear()
            return True, None
        if tls_clienthello.establish_server_tls_first and not self.context.server.tls_established:
            err = yield from self.start_server_tls()
            if err:
                yield commands.Log(
                    f"Unable to establish TLS connection with server ({err}). "
                    f"Trying to establish TLS with client anyway.")

        yield from self.start_tls()
        if not self.conn.connected:
            return False, "connection closed early"

        ret = yield from super().receive_handshake_data(bytes(
            self.recv_buffer))
        self.recv_buffer.clear()
        return ret
Esempio n. 10
0
    def test_tls_start_server_verify_ok(self, tdata):
        ta = tlsconfig.TlsConfig()
        with taddons.context(ta) as tctx:
            ctx = context.Context(connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
            ctx.server.address = ("example.mitmproxy.org", 443)
            tctx.configure(ta, ssl_verify_upstream_trusted_ca=tdata.path(
                "mitmproxy/net/data/verificationcerts/trusted-root.crt"))

            tls_start = tls.TlsStartData(ctx.server, context=ctx)
            ta.tls_start_server(tls_start)
            tssl_client = tls_start.ssl_conn
            tssl_server = test_tls.SSLTest(server_side=True)
            assert self.do_handshake(tssl_client, tssl_server)
Esempio n. 11
0
    def create(self, method: str, url: str) -> None:
        try:
            req = http.Request.make(method.upper(), url)
        except ValueError as e:
            raise exceptions.CommandError("Invalid URL: %s" % e)

        c = connection.Client(("", 0), ("", 0), req.timestamp_start - 0.0001)
        s = connection.Server((req.host, req.port))

        f = http.HTTPFlow(c, s)
        f.request = req
        f.request.headers["Host"] = req.host
        self.add([f])
Esempio n. 12
0
    def test_tls_start_server_verify_failed(self):
        ta = tlsconfig.TlsConfig()
        with taddons.context(ta) as tctx:
            ctx = context.Context(connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
            ctx.client.alpn_offers = [b"h2"]
            ctx.client.cipher_list = ["TLS_AES_256_GCM_SHA384", "ECDHE-RSA-AES128-SHA"]
            ctx.server.address = ("example.mitmproxy.org", 443)

            tls_start = tls.TlsData(ctx.server, context=ctx)
            ta.tls_start_server(tls_start)
            tssl_client = tls_start.ssl_conn
            tssl_server = test_tls.SSLTest(server_side=True)
            with pytest.raises(SSL.Error, match="certificate verify failed"):
                assert self.do_handshake(tssl_client, tssl_server)
Esempio n. 13
0
def _h2_response(chunks):
    tctx = context.Context(connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), opts)
    playbook = Playbook(http.HttpLayer(tctx, HTTPMode.regular), hooks=False)
    server = Placeholder(connection.Server)
    assert (
            playbook
            >> DataReceived(tctx.client, b"GET http://example.com/ HTTP/1.1\r\nHost: example.com\r\n\r\n")
            << OpenConnection(server)
            >> reply(None, side_effect=make_h2)
            << SendData(server, Placeholder())
    )
    for chunk in chunks:
        for _ in playbook.layer.handle_event(events.DataReceived(server(), chunk)):
            pass
Esempio n. 14
0
    def test_no_h2_proxy(self, tdata):
        """Do not negotiate h2 on the client<->proxy connection in secure web proxy mode,
        https://github.com/mitmproxy/mitmproxy/issues/4689"""

        ta = tlsconfig.TlsConfig()
        with taddons.context(ta) as tctx:
            tctx.configure(ta, certs=[tdata.path("mitmproxy/net/data/verificationcerts/trusted-leaf.pem")])

            ctx = context.Context(connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), tctx.options)
            # mock up something that looks like a secure web proxy.
            ctx.layers = [
                modes.HttpProxy(ctx),
                123
            ]
            tls_start = tls.TlsData(ctx.client, context=ctx)
            ta.tls_start_client(tls_start)
            assert tls_start.ssl_conn.get_app_data()["client_alpn"] == b"http/1.1"
Esempio n. 15
0
    def test_create_proxy_server_ssl_conn_insecure(self):
        ta = tlsconfig.TlsConfig()
        with taddons.context(ta) as tctx:
            ctx = context.Context(
                connection.Client(("client", 1234), ("127.0.0.1", 8080),
                                  1605699329), tctx.options)
            ctx.server.address = ("example.mitmproxy.org", 443)

            tctx.configure(ta,
                           ssl_verify_upstream_trusted_ca=None,
                           ssl_insecure=True,
                           http2=False,
                           ciphers_server="ALL")
            tls_start = tls.TlsStartData(ctx.server, context=ctx)
            ta.tls_start(tls_start)
            tssl_client = tls_start.ssl_conn
            tssl_server = test_tls.SSLTest(server_side=True)
            assert self.do_handshake(tssl_client, tssl_server)
Esempio n. 16
0
def tctx():
    context.Context(
        connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329),
        tctx.options)
Esempio n. 17
0
def _test_cancel(stream_req, stream_resp, draw):
    """
    Test that we don't raise an exception if someone disconnects.
    """
    tctx = context.Context(connection.Client(("client", 1234), ("127.0.0.1", 8080), 1605699329), opts)
    playbook, cff = start_h2_client(tctx)
    flow = Placeholder(HTTPFlow)
    server = Placeholder(Server)

    def maybe_stream(flow: HTTPFlow):
        if stream_req:
            flow.request.stream = True
        if stream_resp and flow.response:
            flow.response.stream = True

    hook_req_headers = http.HttpRequestHeadersHook(flow)
    hook_req = http.HttpRequestHook(flow)
    hook_resp_headers = http.HttpResponseHeadersHook(flow)
    hook_resp = http.HttpResponseHook(flow)
    hook_error = http.HttpErrorHook(flow)
    openconn = OpenConnection(server)
    send_upstream = SendData(server, Placeholder(bytes))

    data_req = DataReceived(tctx.client, cff.build_headers_frame(example_request_headers).serialize())
    data_reqbody = DataReceived(tctx.client, cff.build_data_frame(b"foo", flags=["END_STREAM"]).serialize())
    data_resp = DataReceived(server, cff.build_headers_frame(example_response_headers).serialize())
    data_respbody = DataReceived(server, cff.build_data_frame(b"bar", flags=["END_STREAM"]).serialize())

    client_disc = ConnectionClosed(tctx.client)
    client_rst = DataReceived(tctx.client, cff.build_rst_stream_frame(1).serialize())
    server_disc = ConnectionClosed(server)
    server_rst = DataReceived(server, cff.build_rst_stream_frame(1).serialize())

    evts: Dict[str, Tuple[Any, Any, Any]] = {}
    # precondition, but-not-after-this
    evts["data_req"] = data_req, None, client_disc
    evts["data_reqbody"] = data_reqbody, data_req, client_disc
    evts["reply_hook_req_headers"] = reply(to=hook_req_headers, side_effect=maybe_stream), hook_req_headers, None
    evts["reply_hook_req"] = reply(to=hook_req), hook_req, None
    evts["reply_openconn"] = reply(None, to=openconn, side_effect=make_h2), openconn, None
    evts["data_resp"] = data_resp, send_upstream, server_disc
    evts["data_respbody"] = data_respbody, data_resp, server_disc
    evts["reply_hook_resp_headers"] = reply(to=hook_resp_headers, side_effect=maybe_stream), hook_resp_headers, None
    evts["reply_hook_resp"] = reply(to=hook_resp), hook_resp, None
    evts["reply_hook_error"] = reply(to=hook_error), hook_error, None

    evts["err_client_disc"] = client_disc, None, None
    evts["err_client_rst"] = client_rst, None, client_disc
    evts["err_server_disc"] = server_disc, send_upstream, None
    evts["err_server_rst"] = server_rst, send_upstream, server_disc

    def eq_maybe(a, b):
        # _eq helpfully raises a TypeError when placeholder types don't match
        # that is useful in (test) development, but may happen legitimately when fuzzing here.
        try:
            return _eq(a, b)
        except TypeError:
            return False

    while evts:
        candidates = []
        for name, (evt, precon, negprecon) in evts.items():
            precondition_ok = (
                    precon is None or any(eq_maybe(x, precon) for x in playbook.actual)
            )
            neg_precondition_ok = (
                    negprecon is None or not any(eq_maybe(x, negprecon) for x in playbook.actual)
            )
            if precondition_ok and neg_precondition_ok:
                # crude hack to increase fuzzing efficiency: make it more likely that we progress.
                for i in range(1 if name.startswith("err_") else 3):
                    candidates.append((name, evt))
        if not candidates:
            break

        name, evt = draw(candidates)
        del evts[name]
        try:
            assert playbook >> evt
        except AssertionError:
            if any(
                    isinstance(x, _TracebackInPlaybook)
                    for x in playbook.actual
            ):
                raise
            else:
                # add commands that the server issued.
                playbook.expected.extend(playbook.actual[len(playbook.expected):])