Merge pull request #870 from bazzinotti/master

[docs/libmproxy/test] Support single client-side cert file
This commit is contained in:
Maximilian Hils 2015-12-29 17:51:11 +01:00
commit 7b093b46b6
7 changed files with 48 additions and 21 deletions

View File

@ -175,10 +175,21 @@ no such file exists, it will be generated automatically.
Using a client side certificate
-------------------------------
You can use a client certificate by passing the ``--client-certs DIRECTORY`` option to mitmproxy.
You can use a client certificate by passing the ``--client-certs DIRECTORY|FILE``
option to mitmproxy. Using a directory allows certs to be selected based on
hostname, while using a filename allows a single specific certificate to be used for
all SSL connections. Certificate files must be in the PEM format and should
contain both the unencrypted private key and the certificate.
Multiple certs by Hostname
^^^^^^^^^^^^^^^^^^^^^^^^^^
If you've specified a directory to ``--client-certs``, then the following
behavior will be taken:
If you visit example.org, mitmproxy looks for a file named ``example.org.pem`` in the specified
directory and uses this as the client cert. The certificate file needs to be in the PEM format and
should contain both the unencrypted private key and the certificate.
directory and uses this as the client cert.
.. _Certificate Pinning: http://security.stackexchange.com/questions/29988/what-is-certificate-pinning/

View File

@ -407,7 +407,7 @@ def proxy_ssl_options(parser):
group.add_argument(
"--client-certs", action="store",
type=str, dest="clientcerts", default=None,
help="Client certificate directory."
help="Client certificate file or directory."
)
group.add_argument(
"--no-upstream-cert", default=False,

View File

@ -174,11 +174,14 @@ class ServerConnection(tcp.TCPClient, stateobject.StateObject):
def establish_ssl(self, clientcerts, sni, **kwargs):
clientcert = None
if clientcerts:
path = os.path.join(
clientcerts,
self.address.host.encode("idna")) + ".pem"
if os.path.exists(path):
clientcert = path
if os.path.isfile(clientcerts):
clientcert = clientcerts
else:
path = os.path.join(
clientcerts,
self.address.host.encode("idna")) + ".pem"
if os.path.exists(path):
clientcert = path
self.convert_to_ssl(cert=clientcert, sni=sni, **kwargs)
self.sni = sni

View File

@ -133,10 +133,9 @@ def process_proxy_options(parser, options):
if options.clientcerts:
options.clientcerts = os.path.expanduser(options.clientcerts)
if not os.path.exists(options.clientcerts) or not os.path.isdir(options.clientcerts):
if not os.path.exists(options.clientcerts):
return parser.error(
"Client certificate directory does not exist or is not a directory: %s" %
options.clientcerts
"Client certificate path does not exist: %s" % options.clientcerts
)
if options.auth_nonanonymous or options.auth_singleuser or options.auth_htpasswd:

View File

@ -1,3 +1,4 @@
import os
import mock
from OpenSSL import SSL
@ -99,8 +100,11 @@ class TestProcessProxyOptions:
def test_client_certs(self):
with tutils.tmpdir() as cadir:
self.assert_noerr("--client-certs", cadir)
self.assert_noerr(
"--client-certs",
os.path.join(tutils.test_data.path("data/clientcert"), "client.pem"))
self.assert_err(
"directory does not exist",
"path does not exist",
"--client-certs",
"nonexistent")

View File

@ -1,3 +1,4 @@
import os
import socket
import time
from OpenSSL import SSL
@ -313,13 +314,24 @@ class TestHTTPAuth(tservers.HTTPProxTest):
class TestHTTPS(tservers.HTTPProxTest, CommonMixin, TcpMixin):
ssl = True
ssloptions = pathod.SSLOptions(request_client_cert=True)
clientcerts = True
def test_clientcert(self):
f = self.pathod("304")
assert f.status_code == 304
assert self.server.last_log()["request"]["clientcert"]["keyinfo"]
def test_clientcert_file(self):
try:
self.config.clientcerts = os.path.join(
tutils.test_data.path("data/clientcert"), "client.pem")
f = self.pathod("304")
assert f.status_code == 304
assert self.server.last_log()["request"]["clientcert"]["keyinfo"]
finally:
self.config.clientcerts = None
def test_clientcert_dir(self):
try:
self.config.clientcerts = tutils.test_data.path("data/clientcert")
f = self.pathod("304")
assert f.status_code == 304
assert self.server.last_log()["request"]["clientcert"]["keyinfo"]
finally:
self.config.clientcerts = None
def test_error_post_connect(self):
p = self.pathoc()
assert p.request("get:/:i0,'invalid\r\n\r\n'").status_code == 400

View File

@ -83,7 +83,6 @@ class ProxTestBase(object):
# Test Configuration
ssl = None
ssloptions = False
clientcerts = False
no_upstream_cert = False
authenticator = None
masterclass = TestMaster
@ -130,7 +129,6 @@ class ProxTestBase(object):
no_upstream_cert = cls.no_upstream_cert,
cadir = cls.cadir,
authenticator = cls.authenticator,
clientcerts = tutils.test_data.path("data/clientcert") if cls.clientcerts else None
)