aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAldo Cortesi <aldo@corte.si>2015-06-30 10:51:46 +1200
committerAldo Cortesi <aldo@corte.si>2015-06-30 10:51:46 +1200
commit5ad6773e78404fc10f694ebf2f2d72d28df617a3 (patch)
treea22397901680338545ee69d614ed418e40528475
parentaebad44d550d917489c802d0d51e1002f87b4e3b (diff)
parentf0ad1f334ca57fdf57a3bfb190d314fc8d983475 (diff)
downloadmitmproxy-5ad6773e78404fc10f694ebf2f2d72d28df617a3.tar.gz
mitmproxy-5ad6773e78404fc10f694ebf2f2d72d28df617a3.tar.bz2
mitmproxy-5ad6773e78404fc10f694ebf2f2d72d28df617a3.zip
Merge pull request #661 from kyle-m/master
Enabling upstream server verification.
-rw-r--r--libmproxy/proxy/config.py32
-rw-r--r--libmproxy/proxy/server.py17
l---------test/data/trusted-cadir/8117bdb9.01
l---------test/data/trusted-cadir/9d45e6a9.01
-rw-r--r--test/data/trusted-cadir/trusted-ca.pem14
-rw-r--r--test/data/trusted-server.crt33
-rw-r--r--test/data/untrusted-server.crt32
-rw-r--r--test/test_proxy.py16
-rw-r--r--test/test_server.py60
9 files changed, 205 insertions, 1 deletions
diff --git a/libmproxy/proxy/config.py b/libmproxy/proxy/config.py
index a7a719cf..c5306b4a 100644
--- a/libmproxy/proxy/config.py
+++ b/libmproxy/proxy/config.py
@@ -52,6 +52,9 @@ class ProxyConfig:
ssl_version_server=tcp.SSL_DEFAULT_METHOD,
ssl_ports=TRANSPARENT_SSL_PORTS,
spoofed_ssl_port=None,
+ ssl_verify_upstream_cert=False,
+ ssl_upstream_trusted_cadir=None,
+ ssl_upstream_trusted_ca=None
):
self.host = host
self.port = port
@@ -100,6 +103,13 @@ class ProxyConfig:
self.openssl_method_server = ssl_version_server
else:
self.openssl_method_server = tcp.SSL_VERSIONS[ssl_version_server]
+
+ if ssl_verify_upstream_cert:
+ self.openssl_verification_mode_server = SSL.VERIFY_PEER
+ else:
+ self.openssl_verification_mode_server = SSL.VERIFY_NONE
+ self.openssl_trusted_cadir_server = ssl_upstream_trusted_cadir
+ self.openssl_trusted_ca_server = ssl_upstream_trusted_ca
self.openssl_options_client = tcp.SSL_DEFAULT_OPTIONS
self.openssl_options_server = tcp.SSL_DEFAULT_OPTIONS
@@ -203,7 +213,10 @@ def process_proxy_options(parser, options):
ssl_version_client=options.ssl_version_client,
ssl_version_server=options.ssl_version_server,
ssl_ports=ssl_ports,
- spoofed_ssl_port=spoofed_ssl_port
+ spoofed_ssl_port=spoofed_ssl_port,
+ ssl_verify_upstream_cert=options.ssl_verify_upstream_cert,
+ ssl_upstream_trusted_cadir=options.ssl_upstream_trusted_cadir,
+ ssl_upstream_trusted_ca=options.ssl_upstream_trusted_ca
)
@@ -243,6 +256,23 @@ def ssl_option_group(parser):
help="Don't connect to upstream server to look up certificate details."
)
group.add_argument(
+ "--verify-upstream-cert", default=False,
+ action="store_true", dest="ssl_verify_upstream_cert",
+ help="Verify upstream server SSL/TLS certificates and fail if invalid "
+ "or not present."
+ )
+ group.add_argument(
+ "--upstream-trusted-cadir", default=None, action="store",
+ dest="ssl_upstream_trusted_cadir",
+ help="Path to a directory of trusted CA certificates for upstream "
+ "server verification prepared using the c_rehash tool."
+ )
+ group.add_argument(
+ "--upstream-trusted-ca", default=None, action="store",
+ dest="ssl_upstream_trusted_ca",
+ help="Path to a PEM formatted trusted CA certificate."
+ )
+ group.add_argument(
"--ssl-port",
action="append",
type=int,
diff --git a/libmproxy/proxy/server.py b/libmproxy/proxy/server.py
index 051e8489..2711bd0e 100644
--- a/libmproxy/proxy/server.py
+++ b/libmproxy/proxy/server.py
@@ -235,8 +235,18 @@ class ConnectionHandler:
sni,
method=self.config.openssl_method_server,
options=self.config.openssl_options_server,
+ verify_options=self.config.openssl_verification_mode_server,
+ ca_path=self.config.openssl_trusted_cadir_server,
+ ca_pemfile=self.config.openssl_trusted_ca_server,
cipher_list=self.config.ciphers_server,
)
+ ssl_cert_err = self.server_conn.ssl_verification_error
+ if ssl_cert_err is not None:
+ self.log(
+ "SSL verification failed for upstream server at depth %s with error: %s" %
+ (ssl_cert_err['depth'], ssl_cert_err['errno']),
+ "error")
+ self.log("Ignoring server verification error, continuing with connection", "error")
except tcp.NetLibError as v:
e = ProxyError(502, repr(v))
# Workaround for https://github.com/mitmproxy/mitmproxy/issues/427
@@ -246,6 +256,13 @@ class ConnectionHandler:
if client and "handshake failure" in e.message:
self.server_conn.may_require_sni = e
else:
+ ssl_cert_err = self.server_conn.ssl_verification_error
+ if ssl_cert_err is not None:
+ self.log(
+ "SSL verification failed for upstream server at depth %s with error: %s" %
+ (ssl_cert_err['depth'], ssl_cert_err['errno']),
+ "error")
+ self.log("Aborting connection attempt", "error")
raise e
if client:
if self.client_conn.ssl_established:
diff --git a/test/data/trusted-cadir/8117bdb9.0 b/test/data/trusted-cadir/8117bdb9.0
new file mode 120000
index 00000000..91dcd797
--- /dev/null
+++ b/test/data/trusted-cadir/8117bdb9.0
@@ -0,0 +1 @@
+trusted-ca.pem \ No newline at end of file
diff --git a/test/data/trusted-cadir/9d45e6a9.0 b/test/data/trusted-cadir/9d45e6a9.0
new file mode 120000
index 00000000..91dcd797
--- /dev/null
+++ b/test/data/trusted-cadir/9d45e6a9.0
@@ -0,0 +1 @@
+trusted-ca.pem \ No newline at end of file
diff --git a/test/data/trusted-cadir/trusted-ca.pem b/test/data/trusted-cadir/trusted-ca.pem
new file mode 100644
index 00000000..ae78b546
--- /dev/null
+++ b/test/data/trusted-cadir/trusted-ca.pem
@@ -0,0 +1,14 @@
+-----BEGIN CERTIFICATE-----
+MIICJzCCAZACCQCo1BdopddN/TANBgkqhkiG9w0BAQUFADBXMQswCQYDVQQGEwJB
+VTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0
+cyBQdHkgTHRkMRAwDgYDVQQDEwdUUlVTVEVEMCAXDTE1MDYxOTE4MDEzMVoYDzIx
+MTUwNTI2MTgwMTMxWjBXMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0
+ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRAwDgYDVQQDEwdU
+UlVTVEVEMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC00Jf3KrBAmLQWl+Dz
+8Qrig8ActB94kv0/Lu03P/2DwOR8kH2h3w4OC3b3CFKX31h7hm/H1PPHq7cIX6IR
+fwrYCtBE77UbxklSlrwn06j6YSotz0/dwLEQEFDXWITJq7AyntaiafDHazbbXESN
+m/+I/YEl2wKemEHE//qWbeM9kwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAF0NREP3
+X+fTebzJGttzrFkDhGVFKRNyLXblXRVanlGOYF+q8grgZY2ufC/55gqf+ub6FRT5
+gKPhL4V2rqL8UAvCE7jq8ujpVfTB8kRAKC675W2DBZk2EJX9mjlr89t7qXGsI5nF
+onpfJ1UtiJshNoV7h/NFHeoag91kx628807n
+-----END CERTIFICATE-----
diff --git a/test/data/trusted-server.crt b/test/data/trusted-server.crt
new file mode 100644
index 00000000..76f8559a
--- /dev/null
+++ b/test/data/trusted-server.crt
@@ -0,0 +1,33 @@
+-----BEGIN CERTIFICATE-----
+MIIC8jCCAlugAwIBAgICEAcwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQVUx
+EzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMg
+UHR5IEx0ZDEQMA4GA1UEAxMHVFJVU1RFRDAgFw0xNTA2MjAwMTE4MjdaGA8yMTE1
+MDUyNzAxMTgyN1owfjELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUx
+ITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEUMBIGA1UECxMLSU5U
+RVJNIFVOSVQxITAfBgNVBAMTGE9SRyBXSVRIIElOVEVSTUVESUFURSBDQTCBnzAN
+BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtRPNKgh4WdYGmU2Ae6Tf2Mbd3oaRI/uY
+Qm6aKeYk1i7g41C0vVowNcD/qdNpGUNnai/Kak9anHOYyppNo7zHgf3EO8zQ4NTQ
+pkDKsdCqbUQcjGfhjWXKnOw+I5er4Rj+MwM1f5cbwb8bYHiSPmXaxzdL0/SNXGAA
+ys/UswgwkU8CAwEAAaOBozCBoDAMBgNVHRMEBTADAQH/MB0GA1UdDgQWBBTPkPQW
+DAPOIy8mipuEsZcP1694EDBxBgNVHSMEajBooVukWTBXMQswCQYDVQQGEwJBVTET
+MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ
+dHkgTHRkMRAwDgYDVQQDEwdUUlVTVEVEggkAqNQXaKXXTf0wDQYJKoZIhvcNAQEF
+BQADgYEApaPbwonY8l+zSxlY2Fw4WNKfl5nwcTW4fuv/0tZLzvsS6P4hTXxbYJNa
+k3hQ1qlrr8DiWJewF85hYvEI2F/7eqS5dhhPTEUFPpsjhbgiqnASvW+WKQIgoY2r
+aHgOXi7RNFtTcCgk0UZISWOY7ORLy8Xu6vKrLRjDhyfIbGlqnAs=
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQC1E80qCHhZ1gaZTYB7pN/Yxt3ehpEj+5hCbpop5iTWLuDjULS9
+WjA1wP+p02kZQ2dqL8pqT1qcc5jKmk2jvMeB/cQ7zNDg1NCmQMqx0KptRByMZ+GN
+Zcqc7D4jl6vhGP4zAzV/lxvBvxtgeJI+ZdrHN0vT9I1cYADKz9SzCDCRTwIDAQAB
+AoGAfKHocKnrzEmXuSSy7meI+vfF9kfA1ndxUSg3S+dwK0uQ1mTSQhI1ZIo2bnlo
+uU6/e0Lxm0KLJ2wZGjoifjSNTC8pcxIfAQY4kM9fqoUcXVSBVSS2kByTunhNSVZQ
+yQyc+UTq9g1zBnJsZAltn7/PaihU4heWgP/++lposuShqmECQQDaG+7l0qul1xak
+9kuZgc88BSTfn9iMK2zIQRcVKuidK4dT3QEp0wmWR5Ue8jq8lvTmVTGNGZbHcheh
+KhoZfLgLAkEA1IjwAw/8z02yV3lbc2QUjIl9m9lvjHBoE2sGuSfq/cZskLKrGat+
+CVj3spqVAg22tpQwVBuHiipBziWVnEtiTQJAB9FKfchQSLBt6lm9mfHyKJeSm8VR
+8Kw5yO+0URjpn4CI6DOasBIVXOKR8LsD6fCLNJpHHWSWZ+2p9SfaKaGzwwJBAM31
+Scld89qca4fzNZkT0goCrvOZeUy6HVE79Q72zPVSFSD/02kT1BaQ3bB5to5/5aD2
+6AKJjwZoPs7bgykrsD0CQBzU8U/8x2dNQnG0QeqaKQu5kKhZSZ9bsawvrCkxSl6b
+WAjl/Jehi5bbQ07zQo3cge6qeR38FCWVCHQ/5wNbc54=
+-----END RSA PRIVATE KEY-----
diff --git a/test/data/untrusted-server.crt b/test/data/untrusted-server.crt
new file mode 100644
index 00000000..62e58601
--- /dev/null
+++ b/test/data/untrusted-server.crt
@@ -0,0 +1,32 @@
+# untrusted-interm.crt, self-signed
+-----BEGIN CERTIFICATE-----
+MIICdTCCAd4CCQDRSKOnIMbTgDANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJB
+VTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0
+cyBQdHkgTHRkMRQwEgYDVQQLEwtJTlRFUk0gVU5JVDEhMB8GA1UEAxMYT1JHIFdJ
+VEggSU5URVJNRURJQVRFIENBMCAXDTE1MDYyMDAxMzY0M1oYDzIxMTUwNTI3MDEz
+NjQzWjB+MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UE
+ChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRQwEgYDVQQLEwtJTlRFUk0gVU5J
+VDEhMB8GA1UEAxMYT1JHIFdJVEggSU5URVJNRURJQVRFIENBMIGfMA0GCSqGSIb3
+DQEBAQUAA4GNADCBiQKBgQC1E80qCHhZ1gaZTYB7pN/Yxt3ehpEj+5hCbpop5iTW
+LuDjULS9WjA1wP+p02kZQ2dqL8pqT1qcc5jKmk2jvMeB/cQ7zNDg1NCmQMqx0Kpt
+RByMZ+GNZcqc7D4jl6vhGP4zAzV/lxvBvxtgeJI+ZdrHN0vT9I1cYADKz9SzCDCR
+TwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAGbObAMEajCz4kj7OP2/DB5SRy2+H/G3
+8Qvc43xlMMNQyYxsDuLOFL0UMRzoKgntrrm2nni8jND+tuMt+hv3ZlBcJlYJ6ynR
+sC1ITTC/1SwwwO0AFIyduUEIJYr/B3sgcVYPLcEfeDZgmEQc9Tnc01aEu3lx2+l9
+0JTSPL2L9LdA
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQC1E80qCHhZ1gaZTYB7pN/Yxt3ehpEj+5hCbpop5iTWLuDjULS9
+WjA1wP+p02kZQ2dqL8pqT1qcc5jKmk2jvMeB/cQ7zNDg1NCmQMqx0KptRByMZ+GN
+Zcqc7D4jl6vhGP4zAzV/lxvBvxtgeJI+ZdrHN0vT9I1cYADKz9SzCDCRTwIDAQAB
+AoGAfKHocKnrzEmXuSSy7meI+vfF9kfA1ndxUSg3S+dwK0uQ1mTSQhI1ZIo2bnlo
+uU6/e0Lxm0KLJ2wZGjoifjSNTC8pcxIfAQY4kM9fqoUcXVSBVSS2kByTunhNSVZQ
+yQyc+UTq9g1zBnJsZAltn7/PaihU4heWgP/++lposuShqmECQQDaG+7l0qul1xak
+9kuZgc88BSTfn9iMK2zIQRcVKuidK4dT3QEp0wmWR5Ue8jq8lvTmVTGNGZbHcheh
+KhoZfLgLAkEA1IjwAw/8z02yV3lbc2QUjIl9m9lvjHBoE2sGuSfq/cZskLKrGat+
+CVj3spqVAg22tpQwVBuHiipBziWVnEtiTQJAB9FKfchQSLBt6lm9mfHyKJeSm8VR
+8Kw5yO+0URjpn4CI6DOasBIVXOKR8LsD6fCLNJpHHWSWZ+2p9SfaKaGzwwJBAM31
+Scld89qca4fzNZkT0goCrvOZeUy6HVE79Q72zPVSFSD/02kT1BaQ3bB5to5/5aD2
+6AKJjwZoPs7bgykrsD0CQBzU8U/8x2dNQnG0QeqaKQu5kKhZSZ9bsawvrCkxSl6b
+WAjl/Jehi5bbQ07zQo3cge6qeR38FCWVCHQ/5wNbc54=
+-----END RSA PRIVATE KEY-----
diff --git a/test/test_proxy.py b/test/test_proxy.py
index d1e72f75..77051edd 100644
--- a/test/test_proxy.py
+++ b/test/test_proxy.py
@@ -9,6 +9,8 @@ from libpathod import test
from netlib import http, tcp
import mock
+from OpenSSL import SSL
+
def test_proxy_error():
p = ProxyError(111, "msg")
@@ -133,6 +135,20 @@ class TestProcessProxyOptions:
"--singleuser",
"test")
+ def test_verify_upstream_cert(self):
+ p = self.assert_noerr("--verify-upstream-cert")
+ assert p.openssl_verification_mode_server == SSL.VERIFY_PEER
+
+ def test_upstream_trusted_cadir(self):
+ expected_dir = "/path/to/a/ca/dir"
+ p = self.assert_noerr("--upstream-trusted-cadir", expected_dir)
+ assert p.openssl_trusted_cadir_server == expected_dir
+
+ def test_upstream_trusted_ca(self):
+ expected_file = "/path/to/a/cert/file"
+ p = self.assert_noerr("--upstream-trusted-ca", expected_file)
+ assert p.openssl_trusted_ca_server == expected_file
+
class TestProxyServer:
# binding to 0.0.0.0:1 works without special permissions on Windows
diff --git a/test/test_server.py b/test/test_server.py
index 8cf4095b..3726ec27 100644
--- a/test/test_server.py
+++ b/test/test_server.py
@@ -9,6 +9,7 @@ import tutils
import tservers
from libmproxy.protocol import KILL, Error
from libmproxy.protocol.http import CONTENT_MISSING
+from OpenSSL import SSL
"""
Note that the choice of response code in these tests matters more than you
@@ -348,6 +349,65 @@ class TestHTTPSCertfile(tservers.HTTPProxTest, CommonMixin):
assert self.pathod("304")
+class TestHTTPSUpstreamServerVerificationWTrustedCert(tservers.HTTPProxTest):
+ """
+ Test upstream server certificate verification with a trusted server cert.
+ """
+ ssl = True
+ ssloptions = pathod.SSLOptions(
+ cn = "trusted-cert",
+ certs = [
+ ("trusted-cert", tutils.test_data.path("data/trusted-server.crt"))
+ ])
+
+ def test_verification_w_cadir(self):
+ self.config.openssl_verification_mode_server = SSL.VERIFY_PEER
+ self.config.openssl_trusted_cadir_server = tutils.test_data.path(
+ "data/trusted-cadir/")
+
+ self.pathoc()
+
+ def test_verification_w_pemfile(self):
+ self.config.openssl_verification_mode_server = SSL.VERIFY_PEER
+ self.config.openssl_trusted_ca_server = tutils.test_data.path(
+ "data/trusted-cadir/trusted-ca.pem")
+
+ self.pathoc()
+
+
+class TestHTTPSUpstreamServerVerificationWBadCert(tservers.HTTPProxTest):
+ """
+ Test upstream server certificate verification with an untrusted server cert.
+ """
+ ssl = True
+ ssloptions = pathod.SSLOptions(
+ cn = "untrusted-cert",
+ certs = [
+ ("untrusted-cert", tutils.test_data.path("data/untrusted-server.crt"))
+ ])
+
+ def test_default_verification_w_bad_cert(self):
+ """Should use no verification."""
+ self.config.openssl_trusted_ca_server = tutils.test_data.path(
+ "data/trusted-cadir/trusted-ca.pem")
+
+ self.pathoc()
+
+ def test_no_verification_w_bad_cert(self):
+ self.config.openssl_verification_mode_server = SSL.VERIFY_NONE
+ self.config.openssl_trusted_ca_server = tutils.test_data.path(
+ "data/trusted-cadir/trusted-ca.pem")
+
+ self.pathoc()
+
+ def test_verification_w_bad_cert(self):
+ self.config.openssl_verification_mode_server = SSL.VERIFY_PEER
+ self.config.openssl_trusted_ca_server = tutils.test_data.path(
+ "data/trusted-cadir/trusted-ca.pem")
+
+ tutils.raises("SSL handshake error", self.pathoc)
+
+
class TestHTTPSNoCommonName(tservers.HTTPProxTest):
"""
Test what happens if we get a cert without common name back.