aboutsummaryrefslogtreecommitdiffstats
path: root/libmproxy/proxy.py
diff options
context:
space:
mode:
Diffstat (limited to 'libmproxy/proxy.py')
-rw-r--r--libmproxy/proxy.py103
1 files changed, 59 insertions, 44 deletions
diff --git a/libmproxy/proxy.py b/libmproxy/proxy.py
index b6480822..6dd37752 100644
--- a/libmproxy/proxy.py
+++ b/libmproxy/proxy.py
@@ -4,6 +4,10 @@ from netlib import tcp, http, certutils, http_auth
import utils, version, platform, controller, stateobject
TRANSPARENT_SSL_PORTS = [443, 8443]
+CONF_BASENAME = "mitmproxy"
+CONF_DIR = "~/.mitmproxy"
+CA_CERT_NAME = "mitmproxy-ca.pem"
+
class AddressPriority(object):
@@ -37,10 +41,12 @@ class Log:
class ProxyConfig:
- def __init__(self, certfile=None, cacert=None, clientcerts=None, no_upstream_cert=False, body_size_limit=None,
- reverse_proxy=None, forward_proxy=None, transparent_proxy=None, authenticator=None):
- self.certfile = certfile
- self.cacert = cacert
+ def __init__(self, confdir=CONF_DIR, clientcerts=None,
+ no_upstream_cert=False, body_size_limit=None, reverse_proxy=None,
+ forward_proxy=None, transparent_proxy=None, authenticator=None,
+ ciphers=None, certs=None
+ ):
+ self.ciphers = ciphers
self.clientcerts = clientcerts
self.no_upstream_cert = no_upstream_cert
self.body_size_limit = body_size_limit
@@ -48,7 +54,9 @@ class ProxyConfig:
self.forward_proxy = forward_proxy
self.transparent_proxy = transparent_proxy
self.authenticator = authenticator
- self.certstore = certutils.CertStore()
+ self.confdir = os.path.expanduser(confdir)
+ self.certstore = certutils.CertStore.from_store(self.confdir, CONF_BASENAME)
+
class ClientConnection(tcp.BaseHandler, stateobject.SimpleStateObject):
@@ -380,9 +388,12 @@ class ConnectionHandler:
if client:
if self.client_conn.ssl_established:
raise ProxyError(502, "SSL to Client already established.")
- dummycert = self.find_cert()
- self.client_conn.convert_to_ssl(dummycert, self.config.certfile or self.config.cacert,
- handle_sni=self.handle_sni)
+ cert, key = self.find_cert()
+ self.client_conn.convert_to_ssl(
+ cert, key,
+ handle_sni = self.handle_sni,
+ cipher_list = self.config.ciphers
+ )
def server_reconnect(self, no_ssl=False):
address = self.server_conn.address
@@ -410,22 +421,18 @@ class ConnectionHandler:
self.channel.tell("log", Log(msg))
def find_cert(self):
- if self.config.certfile:
- with open(self.config.certfile, "rb") as f:
- return certutils.SSLCert.from_pem(f.read())
- else:
- host = self.server_conn.address.host
- sans = []
- if not self.config.no_upstream_cert or not self.server_conn.ssl_established:
- upstream_cert = self.server_conn.cert
- if upstream_cert.cn:
- host = upstream_cert.cn.decode("utf8").encode("idna")
- sans = upstream_cert.altnames
-
- ret = self.config.certstore.get_cert(host, sans, self.config.cacert)
- if not ret:
- raise ProxyError(502, "Unable to generate dummy cert.")
- return ret
+ host = self.server_conn.address.host
+ sans = []
+ if not self.config.no_upstream_cert or not self.server_conn.ssl_established:
+ upstream_cert = self.server_conn.cert
+ if upstream_cert.cn:
+ host = upstream_cert.cn.decode("utf8").encode("idna")
+ sans = upstream_cert.altnames
+
+ ret = self.config.certstore.get_cert(host, sans)
+ if not ret:
+ raise ProxyError(502, "Unable to generate dummy cert.")
+ return ret
def handle_sni(self, connection):
"""
@@ -441,9 +448,9 @@ class ConnectionHandler:
self.server_reconnect() # reconnect to upstream server with SNI
# Now, change client context to reflect changed certificate:
new_context = SSL.Context(SSL.TLSv1_METHOD)
- new_context.use_privatekey_file(self.config.certfile or self.config.cacert)
- dummycert = self.find_cert()
- new_context.use_certificate(dummycert.x509)
+ cert, key = self.find_cert()
+ new_context.use_privatekey_file(key)
+ new_context.use_certificate(cert.X509)
connection.set_context(new_context)
# An unhandled exception in this method will core dump PyOpenSSL, so
# make dang sure it doesn't happen.
@@ -458,7 +465,6 @@ class ProxyServerError(Exception):
class ProxyServer(tcp.TCPServer):
allow_reuse_address = True
bound = True
-
def __init__(self, config, port, host='', server_version=version.NAMEVERSION):
"""
Raises ProxyServerError if there's a startup problem.
@@ -498,30 +504,29 @@ class DummyServer:
# Command-line utils
-def certificate_option_group(parser):
+def ssl_option_group(parser):
group = parser.add_argument_group("SSL")
group.add_argument(
- "--cert", action="store",
- type=str, dest="cert", default=None,
- help="User-created SSL certificate file."
+ "--cert", dest='certs', default=[], type=str,
+ metavar = "SPEC", action="append",
+ help='Add an SSL certificate. SPEC is of the form "[domain=]path". '\
+ 'The domain may include a wildcard, and is equal to "*" if not specified. '\
+ 'The file at path is a certificate in PEM format. If a private key is included in the PEM, '\
+ 'it is used, else the default key in the conf dir is used. Can be passed multiple times.'
)
group.add_argument(
"--client-certs", action="store",
type=str, dest="clientcerts", default=None,
help="Client certificate directory."
)
+ group.add_argument(
+ "--ciphers", action="store",
+ type=str, dest="ciphers", default=None,
+ help="SSL cipher specification."
+ )
def process_proxy_options(parser, options):
- if options.cert:
- options.cert = os.path.expanduser(options.cert)
- if not os.path.exists(options.cert):
- return parser.error("Manually created certificate does not exist: %s" % options.cert)
-
- cacert = os.path.join(options.confdir, "mitmproxy-ca.pem")
- cacert = os.path.expanduser(cacert)
- if not os.path.exists(cacert):
- certutils.dummy_ca(cacert)
body_size_limit = utils.parse_size(options.body_size_limit)
if options.reverse_proxy and options.transparent_proxy:
return parser.error("Can't set both reverse proxy and transparent proxy.")
@@ -574,14 +579,24 @@ def process_proxy_options(parser, options):
else:
authenticator = http_auth.NullProxyAuth(None)
+ certs = []
+ for i in options.certs:
+ parts = i.split("=", 1)
+ if len(parts) == 1:
+ parts = ["*", parts[0]]
+ parts[1] = os.path.expanduser(parts[1])
+ if not os.path.exists(parts[1]):
+ parser.error("Certificate file does not exist: %s"%parts[1])
+ certs.append(parts)
+
return ProxyConfig(
- certfile=options.cert,
- cacert=cacert,
clientcerts=options.clientcerts,
body_size_limit=body_size_limit,
no_upstream_cert=options.no_upstream_cert,
reverse_proxy=rp,
forward_proxy=fp,
transparent_proxy=trans,
- authenticator=authenticator
+ authenticator=authenticator,
+ ciphers=options.ciphers,
+ certs = certs,
)