From 018c229ae40d93f0f0987a37a33256db57cdc62c Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Mon, 31 Dec 2012 09:15:56 +1300 Subject: Start solidifying proxy authentication - Add a unit test file - Remove some extraneous methods - Change the auth API to make the authenticate method take a header object. --- libmproxy/authentication.py | 39 ++++++++++++++++++++++----------------- libmproxy/proxy.py | 8 ++++++-- 2 files changed, 28 insertions(+), 19 deletions(-) (limited to 'libmproxy') diff --git a/libmproxy/authentication.py b/libmproxy/authentication.py index e5383f5a..c928ebbd 100644 --- a/libmproxy/authentication.py +++ b/libmproxy/authentication.py @@ -2,32 +2,35 @@ import binascii import contrib.md5crypt as md5crypt class NullProxyAuth(): - """ No proxy auth at all (returns empty challange headers) """ - def __init__(self, password_manager=None): + """ + No proxy auth at all (returns empty challange headers) + """ + def __init__(self, password_manager): self.password_manager = password_manager self.username = "" - def authenticate(self, auth_value): - """ Tests that the specified user is allowed to use the proxy (stub) """ + def authenticate(self, headers): + """ + Tests that the specified user is allowed to use the proxy (stub) + """ return True def auth_challenge_headers(self): - """ Returns a dictionary containing the headers require to challenge the user """ + """ + Returns a dictionary containing the headers require to challenge the user + """ return {} - def get_username(self): - return self.username - class BasicProxyAuth(NullProxyAuth): - def __init__(self, password_manager, realm="mitmproxy"): NullProxyAuth.__init__(self, password_manager) self.realm = "mitmproxy" - def authenticate(self, auth_value): - if (not auth_value) or (not auth_value[0]): - return False; + def authenticate(self, headers): + auth_value = headers.get('Proxy-Authorization', []) + if not auth_value: + return False try: scheme, username, password = self.parse_authorization_header(auth_value[0]) except: @@ -49,6 +52,7 @@ class BasicProxyAuth(NullProxyAuth): username, password = user.split(':') return scheme, username, password + class PasswordManager(): def __init__(self): pass @@ -56,8 +60,8 @@ class PasswordManager(): def test(self, username, password_token): return False -class PermissivePasswordManager(PasswordManager): +class PermissivePasswordManager(PasswordManager): def __init__(self): PasswordManager.__init__(self) @@ -66,16 +70,17 @@ class PermissivePasswordManager(PasswordManager): return True return False -class HtpasswdPasswordManager(PasswordManager): - """ Read usernames and passwords from a file created by Apache htpasswd""" +class HtpasswdPasswordManager(PasswordManager): + """ + Read usernames and passwords from a file created by Apache htpasswd + """ def __init__(self, filehandle): PasswordManager.__init__(self) entries = (line.strip().split(':') for line in filehandle) valid_entries = (entry for entry in entries if len(entry)==2) self.usernames = {username:token for username,token in valid_entries} - def test(self, username, password_token): if username not in self.usernames: return False @@ -84,8 +89,8 @@ class HtpasswdPasswordManager(PasswordManager): expected = md5crypt.md5crypt(password_token, salt, '$'+magic+'$') return expected==full_token -class SingleUserPasswordManager(PasswordManager): +class SingleUserPasswordManager(PasswordManager): def __init__(self, username, password): PasswordManager.__init__(self) self.username = username diff --git a/libmproxy/proxy.py b/libmproxy/proxy.py index b1ce310c..2c62a880 100644 --- a/libmproxy/proxy.py +++ b/libmproxy/proxy.py @@ -356,8 +356,12 @@ class ProxyHandler(tcp.BaseHandler): headers = http.read_headers(self.rfile) if headers is None: raise ProxyError(400, "Invalid headers") - if authenticate and self.config.authenticator and not self.config.authenticator.authenticate(headers.get('Proxy-Authorization', [])): - raise ProxyError(407, "Proxy Authentication Required", self.config.authenticator.auth_challenge_headers()) + if authenticate and self.config.authenticator and not self.config.authenticator.authenticate(headers): + raise ProxyError( + 407, + "Proxy Authentication Required", + self.config.authenticator.auth_challenge_headers() + ) return headers def send_response(self, response): -- cgit v1.2.3 From 3b84111493dee7c21c4dd6ba390fd70cb13a8674 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Mon, 31 Dec 2012 10:34:25 +1300 Subject: Test and robustify BasicProxyAuth.parse_auth_value - This is partly in preparation for moving the implementation to netlib - Also add an unparse_auth_value for testing (and use in pathod once the move is done) --- libmproxy/authentication.py | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) (limited to 'libmproxy') diff --git a/libmproxy/authentication.py b/libmproxy/authentication.py index c928ebbd..675f5dc5 100644 --- a/libmproxy/authentication.py +++ b/libmproxy/authentication.py @@ -32,8 +32,8 @@ class BasicProxyAuth(NullProxyAuth): if not auth_value: return False try: - scheme, username, password = self.parse_authorization_header(auth_value[0]) - except: + scheme, username, password = self.parse_auth_value(auth_value[0]) + except ValueError: return False if scheme.lower()!='basic': return False @@ -45,12 +45,23 @@ class BasicProxyAuth(NullProxyAuth): def auth_challenge_headers(self): return {'Proxy-Authenticate':'Basic realm="%s"'%self.realm} - def parse_authorization_header(self, auth_value): + def unparse_auth_value(self, scheme, username, password): + v = binascii.b2a_base64(username + ":" + password) + return scheme + " " + v + + def parse_auth_value(self, auth_value): words = auth_value.split() + if len(words) != 2: + raise ValueError("Invalid basic auth credential.") scheme = words[0] - user = binascii.a2b_base64(words[1]) - username, password = user.split(':') - return scheme, username, password + try: + user = binascii.a2b_base64(words[1]) + except binascii.Error: + raise ValueError("Invalid basic auth credential: user:password pair not valid base64: %s"%words[1]) + parts = user.split(':') + if len(parts) != 2: + raise ValueError("Invalid basic auth credential: decoded user:password pair not valid: %s"%user) + return scheme, parts[0], parts[1] class PasswordManager(): -- cgit v1.2.3 From 5347cb9c269acdbc2fc36f92e3545fcbb9de45a1 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Mon, 31 Dec 2012 10:56:44 +1300 Subject: More work on proxy auth - Strip auth header if auth succeeds, so it's not passed upstream - Actually use realm specification to BasicProxyAuth, and make it mandatory - Cleanups and unit tests --- libmproxy/authentication.py | 21 ++++++++++++++++----- libmproxy/proxy.py | 17 ++++++++++------- 2 files changed, 26 insertions(+), 12 deletions(-) (limited to 'libmproxy') diff --git a/libmproxy/authentication.py b/libmproxy/authentication.py index 675f5dc5..1f1f40ae 100644 --- a/libmproxy/authentication.py +++ b/libmproxy/authentication.py @@ -9,9 +9,15 @@ class NullProxyAuth(): self.password_manager = password_manager self.username = "" + def clean(self, headers): + """ + Clean up authentication headers, so they're not passed upstream. + """ + pass + def authenticate(self, headers): """ - Tests that the specified user is allowed to use the proxy (stub) + Tests that the user is allowed to use the proxy """ return True @@ -23,12 +29,17 @@ class NullProxyAuth(): class BasicProxyAuth(NullProxyAuth): - def __init__(self, password_manager, realm="mitmproxy"): + CHALLENGE_HEADER = 'Proxy-Authenticate' + AUTH_HEADER = 'Proxy-Authorization' + def __init__(self, password_manager, realm): NullProxyAuth.__init__(self, password_manager) - self.realm = "mitmproxy" + self.realm = realm + + def clean(self, headers): + del headers[self.AUTH_HEADER] def authenticate(self, headers): - auth_value = headers.get('Proxy-Authorization', []) + auth_value = headers.get(self.AUTH_HEADER, []) if not auth_value: return False try: @@ -43,7 +54,7 @@ class BasicProxyAuth(NullProxyAuth): return True def auth_challenge_headers(self): - return {'Proxy-Authenticate':'Basic realm="%s"'%self.realm} + return {self.CHALLENGE_HEADER:'Basic realm="%s"'%self.realm} def unparse_auth_value(self, scheme, username, password): v = binascii.b2a_base64(username + ":" + password) diff --git a/libmproxy/proxy.py b/libmproxy/proxy.py index 2c62a880..0cba4cbc 100644 --- a/libmproxy/proxy.py +++ b/libmproxy/proxy.py @@ -356,12 +356,15 @@ class ProxyHandler(tcp.BaseHandler): headers = http.read_headers(self.rfile) if headers is None: raise ProxyError(400, "Invalid headers") - if authenticate and self.config.authenticator and not self.config.authenticator.authenticate(headers): - raise ProxyError( - 407, - "Proxy Authentication Required", - self.config.authenticator.auth_challenge_headers() - ) + if authenticate and self.config.authenticator: + if self.config.authenticator.authenticate(headers): + self.config.authenticator.clean(headers) + else: + raise ProxyError( + 407, + "Proxy Authentication Required", + self.config.authenticator.auth_challenge_headers() + ) return headers def send_response(self, response): @@ -552,7 +555,7 @@ def process_proxy_options(parser, options): password_manager = authentication.HtpasswdPasswordManager(options.auth_htpasswd) # in the meanwhile, basic auth is the only true authentication scheme we support # so just use it - authenticator = authentication.BasicProxyAuth(password_manager) + authenticator = authentication.BasicProxyAuth(password_manager, "mitmproxy") else: authenticator = authentication.NullProxyAuth(None) -- cgit v1.2.3 From e2dc7ba09d54fb4fa4af796d5c37cd36174f8897 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Tue, 1 Jan 2013 11:13:56 +1300 Subject: First draft of OSX transparent proxy mode. --- libmproxy/platform/osx.py | 111 ++++++---------------------------------------- libmproxy/platform/pf.py | 16 +++++++ 2 files changed, 30 insertions(+), 97 deletions(-) create mode 100644 libmproxy/platform/pf.py (limited to 'libmproxy') diff --git a/libmproxy/platform/osx.py b/libmproxy/platform/osx.py index a66c03ed..d1c420e2 100644 --- a/libmproxy/platform/osx.py +++ b/libmproxy/platform/osx.py @@ -1,103 +1,20 @@ -import socket, ctypes - -# Python socket module does not have this constant -DIOCNATLOOK = 23 -PFDEV = "/dev/pf" - - -class PF_STATE_XPORT(ctypes.Union): - """ - union pf_state_xport { - u_int16_t port; - u_int16_t call_id; - u_int32_t spi; - }; - """ - _fields_ = [ - ("port", ctypes.c_uint), - ("call_id", ctypes.c_uint), - ("spi", ctypes.c_ulong), - ] - - -class PF_ADDR(ctypes.Union): - """ - struct pf_addr { - union { - struct in_addr v4; - struct in6_addr v6; - u_int8_t addr8[16]; - u_int16_t addr16[8]; - u_int32_t addr32[4]; - } pfa; - } - """ - _fields_ = [ - ("addr8", ctypes.c_byte * 2), - ("addr16", ctypes.c_byte * 4), - ("addr32", ctypes.c_byte * 8), - ] - - -class PFIOC_NATLOOK(ctypes.Structure): - """ - struct pfioc_natlook { - struct pf_addr saddr; - struct pf_addr daddr; - struct pf_addr rsaddr; - struct pf_addr rdaddr; - #ifndef NO_APPLE_EXTENSIONS - union pf_state_xport sxport; - union pf_state_xport dxport; - union pf_state_xport rsxport; - union pf_state_xport rdxport; - sa_family_t af; - u_int8_t proto; - u_int8_t proto_variant; - u_int8_t direction; - #else - u_int16_t sport; - u_int16_t dport; - u_int16_t rsport; - u_int16_t rdport; - sa_family_t af; - u_int8_t proto; - u_int8_t direction; - #endif - }; - """ - _fields_ = [ - ("saddr", PF_ADDR), - ("daddr", PF_ADDR), - ("rsaddr", PF_ADDR), - ("rdaddr", PF_ADDR), - - ("sxport", PF_STATE_XPORT), - ("dxport", PF_STATE_XPORT), - ("rsxport", PF_STATE_XPORT), - ("rdxport", PF_STATE_XPORT), - ("af", ctypes.c_uint), - ("proto", ctypes.c_ushort), - ("proto_variant", ctypes.c_ushort), - ("direction", ctypes.c_ushort), - ] +import subprocess +import pf +""" + Doing this the "right" way by using DIOCNATLOOK on the pf device turns out + to be a pain. Apple has made a number of modifications to the data + structures returned, and compiling userspace tools to test and work with + this turns out to be a pain in the ass. Parsing pfctl output is short, + simple, and works. +""" class Resolver: + STATECMD = ("sudo", "-n", "/sbin/pfctl", "-s", "state") def __init__(self): - self.pfdev = open(PFDEV, "r") + pass def original_addr(self, csock): - """ - The following sttruct defintions are plucked from the current XNU source, found here: - - http://www.opensource.apple.com/source/xnu/xnu-1699.26.8/bsd/net/pfvar.h - - - union pf_state_xport { - u_int16_t port; - u_int16_t call_id; - u_int32_t spi; - }; - """ - pass + peer = csock.getpeername() + stxt = subprocess.check_output(self.STATECMD, stderr=subprocess.STDOUT) + return pf.lookup(peer[0], peer[1], stxt) diff --git a/libmproxy/platform/pf.py b/libmproxy/platform/pf.py new file mode 100644 index 00000000..062d3311 --- /dev/null +++ b/libmproxy/platform/pf.py @@ -0,0 +1,16 @@ + +def lookup(address, port, s): + """ + Parse the pfctl state output s, to look up the destination host + matching the client (address, port). + + Returns an (address, port) tuple, or None. + """ + spec = "%s:%s"%(address, port) + for i in s.split("\n"): + if "ESTABLISHED:ESTABLISHED" in i and spec in i: + s = i.split() + if len(s) > 4: + s = s[4].split(":") + if len(s) == 2: + return s[0], int(s[1]) -- cgit v1.2.3 From e42136a6ef6f29a16cb2eb5f566be317ed7f3579 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Tue, 1 Jan 2013 11:24:11 +1300 Subject: Better error handling for transparent mode remote address resolution. --- libmproxy/platform/osx.py | 5 ++++- libmproxy/proxy.py | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'libmproxy') diff --git a/libmproxy/platform/osx.py b/libmproxy/platform/osx.py index d1c420e2..dda5d9af 100644 --- a/libmproxy/platform/osx.py +++ b/libmproxy/platform/osx.py @@ -16,5 +16,8 @@ class Resolver: def original_addr(self, csock): peer = csock.getpeername() - stxt = subprocess.check_output(self.STATECMD, stderr=subprocess.STDOUT) + try: + stxt = subprocess.check_output(self.STATECMD, stderr=subprocess.STDOUT) + except subprocess.CalledProcessError: + return None return pf.lookup(peer[0], peer[1], stxt) diff --git a/libmproxy/proxy.py b/libmproxy/proxy.py index 0cba4cbc..9abb9833 100644 --- a/libmproxy/proxy.py +++ b/libmproxy/proxy.py @@ -267,7 +267,10 @@ class ProxyHandler(tcp.BaseHandler): def read_request(self, client_conn): if self.config.transparent_proxy: - host, port = self.config.transparent_proxy["resolver"].original_addr(self.connection) + orig = self.config.transparent_proxy["resolver"].original_addr(self.connection) + if not orig: + raise ProxyError(502, "Transparent mode failure: could not resolve original destination.") + host, port = orig if not self.ssl_established and (port in self.config.transparent_proxy["sslports"]): scheme = "https" certfile = self.find_cert(host, port, None) -- cgit v1.2.3 From 7b3d3dc85e9618f4b16f2c81a37429ebdaf5ebf2 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Wed, 2 Jan 2013 14:02:41 +1300 Subject: Documentation, setup.py updates, styling. --- libmproxy/authentication.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'libmproxy') diff --git a/libmproxy/authentication.py b/libmproxy/authentication.py index 1f1f40ae..500ead6b 100644 --- a/libmproxy/authentication.py +++ b/libmproxy/authentication.py @@ -12,7 +12,7 @@ class NullProxyAuth(): def clean(self, headers): """ Clean up authentication headers, so they're not passed upstream. - """ + """ pass def authenticate(self, headers): @@ -33,7 +33,7 @@ class BasicProxyAuth(NullProxyAuth): AUTH_HEADER = 'Proxy-Authorization' def __init__(self, password_manager, realm): NullProxyAuth.__init__(self, password_manager) - self.realm = realm + self.realm = realm def clean(self, headers): del headers[self.AUTH_HEADER] -- cgit v1.2.3 From 09f664cdeafae1d9923fe5ce2c4ab3acc7757a61 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Wed, 2 Jan 2013 17:35:44 +1300 Subject: Refactor proxy auth a bit - Remove authentication scheme option. We only support basic at the moment - we'll add the option back when we diversify. - Add some meta variables to make printout nicer --- libmproxy/cmdline.py | 33 ++++++++------------------------- libmproxy/proxy.py | 17 ++++++----------- 2 files changed, 14 insertions(+), 36 deletions(-) (limited to 'libmproxy') diff --git a/libmproxy/cmdline.py b/libmproxy/cmdline.py index db1ebf0d..060e0073 100644 --- a/libmproxy/cmdline.py +++ b/libmproxy/cmdline.py @@ -338,46 +338,29 @@ def common_options(parser): group = parser.add_argument_group( "Proxy Authentication", """ - Specification of which users are allowed to access the proxy and the method used for authenticating them. - If authscheme is specified, one must specify a list of authorized users and their passwords. - In case that authscheme is not specified, or set to None, any list of authorized users will be ignored. - """.strip() - ) - - group.add_argument( - "--authscheme", type=str, - action="store", dest="authscheme", default=None, choices=["none", "basic"], - help=""" - Specify the scheme used by the proxy to identify users. - If not none, requires the specification of a list of authorized users. - This option is ignored if the proxy is in transparent or reverse mode. - """.strip() - + Specify which users are allowed to access the proxy and the method + used for authenticating them. These options are ignored if the + proxy is in transparent or reverse proxy mode. + """ ) - user_specification_group = group.add_mutually_exclusive_group() - - user_specification_group.add_argument( "--nonanonymous", action="store_true", dest="auth_nonanonymous", - help="Allow access to any user as long as a username is specified. Ignores the provided password." + help="Allow access to any user long as a credentials are specified." ) user_specification_group.add_argument( "--singleuser", action="store", dest="auth_singleuser", type=str, - help="Allows access to a single user as specified by the option value. Specify a username and password in the form username:password." + metavar="USER", + help="Allows access to a a single user, specified in the form username:password." ) - user_specification_group.add_argument( "--htpasswd", action="store", dest="auth_htpasswd", type=argparse.FileType('r'), + metavar="PATH", help="Allow access to users specified in an Apache htpasswd file." ) - - - - proxy.certificate_option_group(parser) diff --git a/libmproxy/proxy.py b/libmproxy/proxy.py index 9abb9833..22e7ff63 100644 --- a/libmproxy/proxy.py +++ b/libmproxy/proxy.py @@ -544,25 +544,20 @@ def process_proxy_options(parser, options): if not os.path.exists(options.certdir) or not os.path.isdir(options.certdir): parser.error("Dummy cert directory does not exist or is not a directory: %s"%options.certdir) - if options.authscheme and (options.authscheme!='none'): - if not (options.auth_nonanonymous or options.auth_singleuser or options.auth_htpasswd): - parser.error("Proxy authentication scheme is specified, but no allowed user list is given.") - if options.auth_singleuser and len(options.auth_singleuser.split(':'))!=2: - parser.error("Authorized user is not given in correct format username:password") - if options.auth_nonanonymous: - password_manager = authentication.PermissivePasswordManager() - elif options.auth_singleuser: + if (options.auth_nonanonymous or options.auth_singleuser or options.auth_htpasswd): + if options.auth_singleuser: + if len(options.auth_singleuser.split(':')) != 2: + parser.error("Please specify user in the format username:password") username, password = options.auth_singleuser.split(':') password_manager = authentication.SingleUserPasswordManager(username, password) + elif options.auth_nonanonymous: + password_manager = authentication.PermissivePasswordManager() elif options.auth_htpasswd: password_manager = authentication.HtpasswdPasswordManager(options.auth_htpasswd) - # in the meanwhile, basic auth is the only true authentication scheme we support - # so just use it authenticator = authentication.BasicProxyAuth(password_manager, "mitmproxy") else: authenticator = authentication.NullProxyAuth(None) - return ProxyConfig( certfile = options.cert, cacert = cacert, -- cgit v1.2.3 From 46ab6ed4912039e19c17cc4346bf562f2acdc8a9 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Fri, 4 Jan 2013 14:19:32 +1300 Subject: Minor cleanups of proxy request handling. --- libmproxy/proxy.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'libmproxy') diff --git a/libmproxy/proxy.py b/libmproxy/proxy.py index 22e7ff63..da47dc20 100644 --- a/libmproxy/proxy.py +++ b/libmproxy/proxy.py @@ -51,6 +51,7 @@ class ProxyConfig: self.transparent_proxy = transparent_proxy self.authenticator = authenticator + class RequestReplayThread(threading.Thread): def __init__(self, config, flow, masterq): self.config, self.flow, self.masterq = config, flow, masterq @@ -311,7 +312,7 @@ class ProxyHandler(tcp.BaseHandler): line = self.get_line(self.rfile) if line == "": return None - if line.startswith("CONNECT"): + if http.parse_init_connect(line): r = http.parse_init_connect(line) if not r: raise ProxyError(400, "Bad HTTP request line: %s"%repr(line)) @@ -332,14 +333,15 @@ class ProxyHandler(tcp.BaseHandler): raise ProxyError(400, str(v)) self.proxy_connect_state = (host, port, httpversion) line = self.rfile.readline(line) + if self.proxy_connect_state: - host, port, httpversion = self.proxy_connect_state r = http.parse_init_http(line) if not r: raise ProxyError(400, "Bad HTTP request line: %s"%repr(line)) method, path, httpversion = r headers = self.read_headers(authenticate=False) + host, port, _ = self.proxy_connect_state content = http.read_http_body_request( self.rfile, self.wfile, headers, httpversion, self.config.body_size_limit ) @@ -348,7 +350,7 @@ class ProxyHandler(tcp.BaseHandler): r = http.parse_init_proxy(line) if not r: raise ProxyError(400, "Bad HTTP request line: %s"%repr(line)) - method, scheme, host, port, path, httpversion = http.parse_init_proxy(line) + method, scheme, host, port, path, httpversion = r headers = self.read_headers(authenticate=True) content = http.read_http_body_request( self.rfile, self.wfile, headers, httpversion, self.config.body_size_limit -- cgit v1.2.3 From 9cfc785cd3092591a4b020dc03b890fb968bba3f Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sat, 5 Jan 2013 21:41:16 +1300 Subject: Unit test love - 100% for flow.py, dump.py --- libmproxy/flow.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'libmproxy') diff --git a/libmproxy/flow.py b/libmproxy/flow.py index 8e4c2117..a9d4e12d 100644 --- a/libmproxy/flow.py +++ b/libmproxy/flow.py @@ -1375,6 +1375,8 @@ class FlowMaster(controller.Master): self.kill_nonreplay = kill def stop_server_playback(self): + if self.server_playback.exit: + self.shutdown() self.server_playback = None def do_server_playback(self, flow): @@ -1408,10 +1410,6 @@ class FlowMaster(controller.Master): self.shutdown() self.client_playback.tick(self) - if self.server_playback: - if self.server_playback.exit and self.server_playback.count() == 0: - self.shutdown() - return controller.Master.tick(self, q) def duplicate_flow(self, f): -- cgit v1.2.3 From 891c441a6dc26b725999ca67bb16f649b92176b4 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 6 Jan 2013 01:16:08 +1300 Subject: Use new netlib certificate store implementation. --- libmproxy/proxy.py | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) (limited to 'libmproxy') diff --git a/libmproxy/proxy.py b/libmproxy/proxy.py index da47dc20..98bcb23d 100644 --- a/libmproxy/proxy.py +++ b/libmproxy/proxy.py @@ -43,7 +43,6 @@ class ProxyConfig: self.certfile = certfile self.cacert = cacert self.clientcerts = clientcerts - self.certdir = certdir self.cert_wait_time = cert_wait_time self.no_upstream_cert = no_upstream_cert self.body_size_limit = body_size_limit @@ -51,6 +50,7 @@ class ProxyConfig: self.transparent_proxy = transparent_proxy self.authenticator = authenticator + self.certstore = certutils.CertStore(certdir) class RequestReplayThread(threading.Thread): def __init__(self, config, flow, masterq): @@ -246,7 +246,9 @@ class ProxyHandler(tcp.BaseHandler): raise ProxyError(502, "Unable to get remote cert: %s"%str(v)) sans = cert.altnames host = cert.cn.decode("utf8").encode("idna") - ret = certutils.dummy_cert(self.config.certdir, self.config.cacert, host, sans) + ret = self.config.certstore.get_cert(host, sans, self.config.cacert) + # FIXME: Is this still necessary? Can we now set a proper + # commencement date, since we're using PyOpenSSL? time.sleep(self.config.cert_wait_time) if not ret: raise ProxyError(502, "mitmproxy: Unable to generate dummy cert.") @@ -414,13 +416,6 @@ class ProxyServer(tcp.TCPServer): except socket.error, v: raise ProxyServerError('Error starting proxy server: ' + v.strerror) self.masterq = None - if config.certdir: - self.certdir = config.certdir - self.remove_certdir = False - else: - self.certdir = tempfile.mkdtemp(prefix="mitmproxy") - config.certdir = self.certdir - self.remove_certdir = True self.apps = AppRegistry() def start_slave(self, klass, masterq): @@ -439,11 +434,7 @@ class ProxyServer(tcp.TCPServer): pass def handle_shutdown(self): - try: - if self.remove_certdir: - shutil.rmtree(self.certdir) - except OSError: - pass + self.config.certstore.cleanup() class AppRegistry: -- cgit v1.2.3 From 060e3198bca48f327984b2d1d73a5d4592866736 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 6 Jan 2013 01:18:47 +1300 Subject: Remove cert_wait_time flag. We now cater for this by generating certs with a commencement date an hour in the past in netlib. --- libmproxy/cmdline.py | 5 ----- libmproxy/proxy.py | 7 +------ 2 files changed, 1 insertion(+), 11 deletions(-) (limited to 'libmproxy') diff --git a/libmproxy/cmdline.py b/libmproxy/cmdline.py index 060e0073..de70bea8 100644 --- a/libmproxy/cmdline.py +++ b/libmproxy/cmdline.py @@ -248,11 +248,6 @@ def common_options(parser): help="Byte size limit of HTTP request and response bodies."\ " Understands k/m/g suffixes, i.e. 3m for 3 megabytes." ) - parser.add_argument( - "--cert-wait-time", type=float, - action="store", dest="cert_wait_time", default=0, - help="Wait for specified number of seconds after a new cert is generated. This can smooth over small discrepancies between the client and server times." - ) parser.add_argument( "--no-upstream-cert", default=False, diff --git a/libmproxy/proxy.py b/libmproxy/proxy.py index 98bcb23d..370eca9a 100644 --- a/libmproxy/proxy.py +++ b/libmproxy/proxy.py @@ -38,12 +38,11 @@ class Log(controller.Msg): class ProxyConfig: - def __init__(self, certfile = None, cacert = None, clientcerts = None, cert_wait_time=0, no_upstream_cert=False, body_size_limit = None, reverse_proxy=None, transparent_proxy=None, certdir = None, authenticator=None): + def __init__(self, certfile = None, cacert = None, clientcerts = None, no_upstream_cert=False, body_size_limit = None, reverse_proxy=None, transparent_proxy=None, certdir = None, authenticator=None): assert not (reverse_proxy and transparent_proxy) self.certfile = certfile self.cacert = cacert self.clientcerts = clientcerts - self.cert_wait_time = cert_wait_time self.no_upstream_cert = no_upstream_cert self.body_size_limit = body_size_limit self.reverse_proxy = reverse_proxy @@ -247,9 +246,6 @@ class ProxyHandler(tcp.BaseHandler): sans = cert.altnames host = cert.cn.decode("utf8").encode("idna") ret = self.config.certstore.get_cert(host, sans, self.config.cacert) - # FIXME: Is this still necessary? Can we now set a proper - # commencement date, since we're using PyOpenSSL? - time.sleep(self.config.cert_wait_time) if not ret: raise ProxyError(502, "mitmproxy: Unable to generate dummy cert.") return ret @@ -555,7 +551,6 @@ def process_proxy_options(parser, options): certfile = options.cert, cacert = cacert, clientcerts = options.clientcerts, - cert_wait_time = options.cert_wait_time, body_size_limit = body_size_limit, no_upstream_cert = options.no_upstream_cert, reverse_proxy = rp, -- cgit v1.2.3