diff options
| author | Maximilian Hils <git@maximilianhils.com> | 2017-01-23 21:22:38 +0100 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-01-23 21:22:38 +0100 | 
| commit | 2eaac31344da93fa8c8e2d245d81193aa65db346 (patch) | |
| tree | 98d2b794e107325e04944fec17a3fe30ccd69e95 | |
| parent | c512f095aefd83e0fc977fe14ba20e641452dc21 (diff) | |
| parent | 006eb39cc562ff3f8b741f9d022503081861827f (diff) | |
| download | mitmproxy-2eaac31344da93fa8c8e2d245d81193aa65db346.tar.gz mitmproxy-2eaac31344da93fa8c8e2d245d81193aa65db346.tar.bz2 mitmproxy-2eaac31344da93fa8c8e2d245d81193aa65db346.zip | |
Merge pull request #1945 from Kriechi/ca-expired
fix #939
| -rw-r--r-- | mitmproxy/addons/__init__.py | 28 | ||||
| -rw-r--r-- | mitmproxy/addons/check_alpn.py | 17 | ||||
| -rw-r--r-- | mitmproxy/addons/check_ca.py | 24 | ||||
| -rw-r--r-- | mitmproxy/addons/termlog.py | 4 | ||||
| -rw-r--r-- | mitmproxy/certs.py | 4 | ||||
| -rw-r--r-- | mitmproxy/tools/console/master.py | 12 | ||||
| -rw-r--r-- | mitmproxy/tools/dump.py | 18 | ||||
| -rw-r--r-- | test/mitmproxy/addons/test_check_alpn.py | 23 | ||||
| -rw-r--r-- | test/mitmproxy/addons/test_check_ca.py | 19 | ||||
| -rw-r--r-- | test/mitmproxy/test_tools_dump.py | 21 | ||||
| -rw-r--r-- | test/mitmproxy/test_web_master.py | 5 | 
11 files changed, 133 insertions, 42 deletions
| diff --git a/mitmproxy/addons/__init__.py b/mitmproxy/addons/__init__.py index 8a2f2974..2e1d1c67 100644 --- a/mitmproxy/addons/__init__.py +++ b/mitmproxy/addons/__init__.py @@ -1,35 +1,39 @@  from mitmproxy.addons import anticache  from mitmproxy.addons import anticomp +from mitmproxy.addons import check_alpn +from mitmproxy.addons import check_ca  from mitmproxy.addons import clientplayback -from mitmproxy.addons import streamfile +from mitmproxy.addons import disable_h2c_upgrade  from mitmproxy.addons import onboarding  from mitmproxy.addons import proxyauth  from mitmproxy.addons import replace  from mitmproxy.addons import script -from mitmproxy.addons import setheaders  from mitmproxy.addons import serverplayback +from mitmproxy.addons import setheaders  from mitmproxy.addons import stickyauth  from mitmproxy.addons import stickycookie  from mitmproxy.addons import streambodies +from mitmproxy.addons import streamfile  from mitmproxy.addons import upstream_auth -from mitmproxy.addons import disable_h2c_upgrade  def default_addons():      return [ -        onboarding.Onboarding(), -        proxyauth.ProxyAuth(),          anticache.AntiCache(),          anticomp.AntiComp(), +        check_alpn.CheckALPN(), +        check_ca.CheckCA(), +        clientplayback.ClientPlayback(), +        disable_h2c_upgrade.DisableH2CleartextUpgrade(), +        onboarding.Onboarding(), +        proxyauth.ProxyAuth(), +        replace.Replace(), +        script.ScriptLoader(), +        serverplayback.ServerPlayback(), +        setheaders.SetHeaders(),          stickyauth.StickyAuth(),          stickycookie.StickyCookie(), -        script.ScriptLoader(), -        streamfile.StreamFile(),          streambodies.StreamBodies(), -        replace.Replace(), -        setheaders.SetHeaders(), -        serverplayback.ServerPlayback(), -        clientplayback.ClientPlayback(), +        streamfile.StreamFile(),          upstream_auth.UpstreamAuth(), -        disable_h2c_upgrade.DisableH2CleartextUpgrade(),      ] diff --git a/mitmproxy/addons/check_alpn.py b/mitmproxy/addons/check_alpn.py new file mode 100644 index 00000000..c288d788 --- /dev/null +++ b/mitmproxy/addons/check_alpn.py @@ -0,0 +1,17 @@ +import mitmproxy +from mitmproxy.net import tcp + + +class CheckALPN: +    def __init__(self): +        self.failed = False + +    def configure(self, options, updated): +        self.failed = mitmproxy.ctx.master.options.http2 and not tcp.HAS_ALPN +        if self.failed: +            mitmproxy.ctx.master.add_log( +                "HTTP/2 is disabled because ALPN support missing!\n" +                "OpenSSL 1.0.2+ required to support HTTP/2 connections.\n" +                "Use --no-http2 to silence this warning.", +                "warn", +            ) diff --git a/mitmproxy/addons/check_ca.py b/mitmproxy/addons/check_ca.py new file mode 100644 index 00000000..a83ab8e1 --- /dev/null +++ b/mitmproxy/addons/check_ca.py @@ -0,0 +1,24 @@ +import mitmproxy + + +class CheckCA: +    def __init__(self): +        self.failed = False + +    def configure(self, options, updated): +        has_ca = ( +            mitmproxy.ctx.master.server and +            mitmproxy.ctx.master.server.config and +            mitmproxy.ctx.master.server.config.certstore and +            mitmproxy.ctx.master.server.config.certstore.default_ca +        ) +        if has_ca: +            self.failed = mitmproxy.ctx.master.server.config.certstore.default_ca.has_expired() +            if self.failed: +                mitmproxy.ctx.master.add_log( +                    "The mitmproxy certificate authority has expired!\n" +                    "Please delete all CA-related files in your ~/.mitmproxy folder.\n" +                    "The CA will be regenerated automatically after restarting mitmproxy.\n" +                    "Then make sure all your clients have the new CA installed.", +                    "warn", +                ) diff --git a/mitmproxy/addons/termlog.py b/mitmproxy/addons/termlog.py index b75f5f5a..f7739efe 100644 --- a/mitmproxy/addons/termlog.py +++ b/mitmproxy/addons/termlog.py @@ -5,9 +5,9 @@ from mitmproxy import log  class TermLog: -    def __init__(self, outfile=sys.stdout): +    def __init__(self, outfile=None):          self.options = None -        self.outfile = outfile +        self.outfile = outfile or sys.stdout      def configure(self, options, updated):          self.options = options diff --git a/mitmproxy/certs.py b/mitmproxy/certs.py index 4e4eb4d1..4b939c80 100644 --- a/mitmproxy/certs.py +++ b/mitmproxy/certs.py @@ -3,8 +3,8 @@ import ssl  import time  import datetime  import ipaddress -  import sys +  from pyasn1.type import univ, constraint, char, namedtype, tag  from pyasn1.codec.der.decoder import decode  from pyasn1.error import PyAsn1Error @@ -13,8 +13,8 @@ import OpenSSL  from mitmproxy.types import serializable  # Default expiry must not be too long: https://github.com/mitmproxy/mitmproxy/issues/815 -  DEFAULT_EXP = 94608000  # = 24 * 60 * 60 * 365 * 3 +  # Generated with "openssl dhparam". It's too slow to generate this on startup.  DEFAULT_DHPARAM = b"""  -----BEGIN DH PARAMETERS----- diff --git a/mitmproxy/tools/console/master.py b/mitmproxy/tools/console/master.py index 8afdce2c..10f8cbf5 100644 --- a/mitmproxy/tools/console/master.py +++ b/mitmproxy/tools/console/master.py @@ -33,8 +33,6 @@ from mitmproxy.tools.console import statusbar  from mitmproxy.tools.console import window  from mitmproxy.utils import strutils -from mitmproxy.net import tcp -  EVENTLOG_SIZE = 10000 @@ -272,16 +270,6 @@ class ConsoleMaster(master.Master):                  print("Could not load file: {}".format(ret), file=sys.stderr)                  sys.exit(1) -        self.loop.set_alarm_in(0.01, self.ticker) -        if self.options.http2 and not tcp.HAS_ALPN:  # pragma: no cover -            def http2err(*args, **kwargs): -                signals.status_message.send( -                    message = "HTTP/2 disabled - OpenSSL 1.0.2+ required." -                              " Use --no-http2 to silence this warning.", -                    expire=5 -                ) -            self.loop.set_alarm_in(0.01, http2err) -          self.loop.set_alarm_in(              0.0001,              lambda *args: self.view_flowlist() diff --git a/mitmproxy/tools/dump.py b/mitmproxy/tools/dump.py index 4e2844a1..e1e40fb0 100644 --- a/mitmproxy/tools/dump.py +++ b/mitmproxy/tools/dump.py @@ -6,7 +6,6 @@ from mitmproxy import addons  from mitmproxy import options  from mitmproxy import master  from mitmproxy.addons import dumper, termlog -from mitmproxy.net import tcp  class DumpError(Exception): @@ -30,7 +29,13 @@ class Options(options.Options):  class DumpMaster(master.Master): -    def __init__(self, options, server, with_termlog=True, with_dumper=True): +    def __init__( +            self, +            options: Options, +            server, +            with_termlog=True, +            with_dumper=True, +    ) -> None:          master.Master.__init__(self, options, server)          self.has_errored = False          if with_termlog: @@ -38,8 +43,6 @@ class DumpMaster(master.Master):          self.addons.add(*addons.default_addons())          if with_dumper:              self.addons.add(dumper.Dumper()) -        # This line is just for type hinting -        self.options = self.options  # type: Options          if not self.options.no_server:              self.add_log( @@ -47,13 +50,6 @@ class DumpMaster(master.Master):                  "info"              ) -        if self.server and self.options.http2 and not tcp.HAS_ALPN:  # pragma: no cover -            self.add_log( -                "ALPN support missing (OpenSSL 1.0.2+ required)!\n" -                "HTTP/2 is disabled. Use --no-http2 to silence this warning.", -                "error" -            ) -          if options.rfile:              try:                  self.load_flows_file(options.rfile) diff --git a/test/mitmproxy/addons/test_check_alpn.py b/test/mitmproxy/addons/test_check_alpn.py new file mode 100644 index 00000000..2dc0c835 --- /dev/null +++ b/test/mitmproxy/addons/test_check_alpn.py @@ -0,0 +1,23 @@ +from mitmproxy.addons import check_alpn +from mitmproxy.test import taddons +from ...conftest import requires_alpn + + +class TestCheckALPN: + +    @requires_alpn +    def test_check_alpn(self): +        msg = 'ALPN support missing' + +        with taddons.context() as tctx: +            a = check_alpn.CheckALPN() +            tctx.configure(a) +            assert not any(msg in m for l, m in tctx.master.event_log) + +    def test_check_no_alpn(self, disable_alpn): +        msg = 'ALPN support missing' + +        with taddons.context() as tctx: +            a = check_alpn.CheckALPN() +            tctx.configure(a) +            assert any(msg in m for l, m in tctx.master.event_log) diff --git a/test/mitmproxy/addons/test_check_ca.py b/test/mitmproxy/addons/test_check_ca.py new file mode 100644 index 00000000..fc64621c --- /dev/null +++ b/test/mitmproxy/addons/test_check_ca.py @@ -0,0 +1,19 @@ +import pytest +from unittest import mock + +from mitmproxy.addons import check_ca +from mitmproxy.test import taddons + + +class TestCheckCA: + +    @pytest.mark.parametrize('expired', [False, True]) +    def test_check_ca(self, expired): +        msg = 'The mitmproxy certificate authority has expired!' + +        with taddons.context() as tctx: +            tctx.master.server = mock.MagicMock() +            tctx.master.server.config.certstore.default_ca.has_expired = mock.MagicMock(return_value=expired) +            a = check_ca.CheckCA() +            tctx.configure(a) +            assert any(msg in m for l, m in tctx.master.event_log) is expired diff --git a/test/mitmproxy/test_tools_dump.py b/test/mitmproxy/test_tools_dump.py index 2e64d2d2..505f514b 100644 --- a/test/mitmproxy/test_tools_dump.py +++ b/test/mitmproxy/test_tools_dump.py @@ -1,10 +1,13 @@  import os +import pytest +from unittest import mock -from mitmproxy.tools import dump  from mitmproxy import proxy -from mitmproxy.test import tutils  from mitmproxy import log  from mitmproxy import controller +from mitmproxy.tools import dump + +from mitmproxy.test import tutils  from . import mastertest @@ -37,3 +40,17 @@ class TestDumpMaster(mastertest.MasterTest):          ent.reply = controller.DummyReply()          m.log(ent)          assert m.has_errored + +    @pytest.mark.parametrize("termlog", [False, True]) +    def test_addons_termlog(self, termlog): +        with mock.patch('sys.stdout'): +            o = dump.Options() +            m = dump.DumpMaster(o, proxy.DummyServer(), with_termlog=termlog) +            assert (m.addons.get('termlog') is not None) == termlog + +    @pytest.mark.parametrize("dumper", [False, True]) +    def test_addons_dumper(self, dumper): +        with mock.patch('sys.stdout'): +            o = dump.Options() +            m = dump.DumpMaster(o, proxy.DummyServer(), with_dumper=dumper) +            assert (m.addons.get('dumper') is not None) == dumper diff --git a/test/mitmproxy/test_web_master.py b/test/mitmproxy/test_web_master.py index 08dce8f3..3591284d 100644 --- a/test/mitmproxy/test_web_master.py +++ b/test/mitmproxy/test_web_master.py @@ -1,13 +1,16 @@  from mitmproxy.tools.web import master  from mitmproxy import proxy  from mitmproxy import options +from mitmproxy.proxy.config import ProxyConfig +  from . import mastertest  class TestWebMaster(mastertest.MasterTest):      def mkmaster(self, **opts):          o = options.Options(**opts) -        return master.WebMaster(o, proxy.DummyServer(o)) +        c = ProxyConfig(o) +        return master.WebMaster(o, proxy.DummyServer(c))      def test_basic(self):          m = self.mkmaster() | 
