Repository: mitmproxy/mitmproxy

Issue:
clarify error message on SSLv3 failure
openssl SSLv3 support has been disabled on ubuntu 16.04 ([debian/patches/no-sslv3.patch](https://launchpad.net/ubuntu/+source/openssl/1.0.2g-1ubuntu1)),<br />and probably debian unstable + other distros.

`mitmproxy --ssl-version-server SSLv3 -R https://google.fr:443`

results in the following failure :

```
Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/libmproxy/proxy/server.py", line 120, in handle
    root_layer()
  File "/usr/lib/python2.7/dist-packages/libmproxy/proxy/modes/reverse_proxy.py", line 14, in __call__
    layer()
  File "/usr/lib/python2.7/dist-packages/libmproxy/protocol/tls.py", line 267, in __call__
    self._establish_tls_with_client_and_server()
  File "/usr/lib/python2.7/dist-packages/libmproxy/protocol/tls.py", line 392, in _establish_tls_with_client_and_server
    six.reraise(*sys.exc_info())
  File "/usr/lib/python2.7/dist-packages/libmproxy/protocol/tls.py", line 386, in _establish_tls_with_client_and_server
    self._establish_tls_with_server()
  File "/usr/lib/python2.7/dist-packages/libmproxy/protocol/tls.py", line 458, in _establish_tls_with_server
    alpn_protos=alpn,
  File "/usr/lib/python2.7/dist-packages/libmproxy/models/connections.py", line 183, in establish_ssl
    self.convert_to_ssl(cert=clientcert, sni=sni, **kwargs)
  File "/usr/lib/python2.7/dist-packages/netlib/tcp.py", line 605, in convert_to_ssl
    **sslctx_kwargs
  File "/usr/lib/python2.7/dist-packages/netlib/tcp.py", line 580, in create_ssl_context
    **sslctx_kwargs)
  File "/usr/lib/python2.7/dist-packages/netlib/tcp.py", line 488, in _create_ssl_context
    context = SSL.Context(method)
  File "/usr/local/lib/python2.7/dist-packages/OpenSSL/SSL.py", line 478, in __init__
    _raise_current_error()
  File "/usr/local/lib/python2.7/dist-packages/OpenSSL/_util.py", line 48, in exception_from_error_queue
    raise exception_type(errors)
Error: [('SSL routines', 'SSL_CTX_new', 'null ssl method passed')]

mitmproxy has crashed!
Please lodge a bug report at: https://github.com/mitmproxy/mitmproxy
```

It would be great to have a message such as "your libssl does not support SSLv3 (it was removed for security reasons)"

For those servers wo only support SSLv3 (hello [PDUs](https://en.wikipedia.org/wiki/Power_distribution_unit)), you can use TEMPORARILY a recompiled libssl with SSLv3 enabled :

```
cd $(mktemp -d)
sudo apt-get build-dep openssl
apt-get source openssl
dpkg-source -x openssl*.dsc
cd openssl*
patch -R -p1 < ./debian/patches/no-sslv3.patch
dpkg-buildpackage -rfakeroot -b
sudo chown root:root libssl.so.1.0.0
sudo chmod u=rw,go=r libssl.so.1.0.0
sudo cp libssl.so.1.0.0 /lib/x86_64-linux-gnu/libssl.so.1.0.0
```

(obviously you can keep your recomplied libssl.so.1.0.0 somewhere)

After use, restore the distro and SECURE libssl, launching :
`sudo apt-get install --reinstall libssl1.0.0`

Mitmproxy Version: any
Operating System: ubuntu 16.04



Discussion:
Thanks for the report! :smiley:
This issue should be easy to fix, so I'll leave it open if anyone wants to give it a shot. It should be enough to catch the exception and return a `netlib.exceptions.TlsException` with a descriptive error message linking to this issue instead.


Resolving patch:
diff --git a/mitmproxy/net/tcp.py b/mitmproxy/net/tcp.py
--- a/mitmproxy/net/tcp.py
+++ b/mitmproxy/net/tcp.py
@@ -70,6 +70,15 @@
     "TLSv1_2": (SSL.TLSv1_2_METHOD, SSL_BASIC_OPTIONS),
 }
 
+ssl_method_names = {
+    SSL.SSLv2_METHOD: "SSLv2",
+    SSL.SSLv3_METHOD: "SSLv3",
+    SSL.SSLv23_METHOD: "SSLv23",
+    SSL.TLSv1_METHOD: "TLSv1",
+    SSL.TLSv1_1_METHOD: "TLSv1.1",
+    SSL.TLSv1_2_METHOD: "TLSv1.2",
+}
+
 
 class SSLKeyLogger:
 
@@ -510,7 +519,17 @@ def _create_ssl_context(self,
         :param cipher_list: A textual OpenSSL cipher list, see https://www.openssl.org/docs/apps/ciphers.html
         :rtype : SSL.Context
         """
-        context = SSL.Context(method)
+        try:
+            context = SSL.Context(method)
+        except ValueError as e:
+            method_name = ssl_method_names.get(method, "unknown")
+            raise exceptions.TlsException(
+                "SSL method \"%s\" is most likely not supported "
+                "or disabled (for security reasons) in your libssl. "
+                "Please refer to https://github.com/mitmproxy/mitmproxy/issues/1101 "
+                "for more details." % method_name
+            )
+
         # Options (NO_SSLv2/3)
         if options is not None:
             context.set_options(options)


Test patch:
diff --git a/test/mitmproxy/net/test_tcp.py b/test/mitmproxy/net/test_tcp.py
--- a/test/mitmproxy/net/test_tcp.py
+++ b/test/mitmproxy/net/test_tcp.py
@@ -800,3 +800,18 @@ def test_create_logfun(self):
             tcp.SSLKeyLogger.create_logfun("test"),
             tcp.SSLKeyLogger)
         assert not tcp.SSLKeyLogger.create_logfun(False)
+
+
+class TestSSLInvalidMethod(tservers.ServerTestBase):
+    handler = EchoHandler
+    ssl = True
+
+    def test_invalid_ssl_method_should_fail(self):
+        fake_ssl_method = 100500
+        c = tcp.TCPClient(("127.0.0.1", self.port))
+        with c.connect():
+            tutils.raises(
+                exceptions.TlsException,
+                c.convert_to_ssl,
+                method=fake_ssl_method
+            )