Certificates are now generated in a temporary per-session directory.

This means that certificates don't accumulate in the conf directory, users
don't have to clear certificates if the CA is regenerated, and the user can
specify a custom CA without invalid certificates being loaded inadvertently.
This commit is contained in:
Aldo Cortesi 2011-02-20 13:29:41 +13:00
parent c2ae8285f4
commit 7ddba22f51
7 changed files with 24 additions and 62 deletions

View File

@ -215,7 +215,7 @@ class State:
Add an error response to the state. Returns the matching flow, or
None if there isn't one.
"""
f = self.flow_map.get(err.flow.request)
f = self.flow_map.get(err.request) if err.request else None
if not f:
return None
f.error = err

View File

@ -6,6 +6,7 @@
Development started from Neil Schemenauer's munchy.py
"""
import sys, os, time, string, socket, urlparse, re, select, copy, base64
import shutil, tempfile
import optparse, SocketServer, ssl
import utils, controller
@ -21,11 +22,11 @@ class ProxyError(Exception):
class Config:
def __init__(self, certfile = None, certpath = None, ciphers = None, cacert = None):
def __init__(self, certfile = None, ciphers = None, cacert = None):
self.certfile = certfile
self.certpath = certpath
self.ciphers = ciphers
self.cacert = cacert
self.certdir = None
def read_chunked(fp):
@ -369,8 +370,8 @@ class ClientConnect(controller.Msg):
class Error(controller.Msg):
def __init__(self, flow, msg, timestamp=None):
self.flow, self.msg = flow, msg
def __init__(self, request, msg, timestamp=None):
self.request, self.msg = request, msg
self.timestamp = timestamp or time.time()
controller.Msg.__init__(self)
@ -509,7 +510,7 @@ class ProxyHandler(SocketServer.StreamRequestHandler):
self.finish()
def handle_request(self, cc):
server = None
server, request = None, None
try:
request = self.read_request(cc)
if request is None:
@ -538,7 +539,7 @@ class ProxyHandler(SocketServer.StreamRequestHandler):
except IOError:
pass
except ProxyError, e:
err = Error(cc, e.msg)
err = Error(request, e.msg)
err.send(self.mqueue)
cc.close = True
self.send_error(e.code, e.msg)
@ -549,7 +550,7 @@ class ProxyHandler(SocketServer.StreamRequestHandler):
if self.config.certfile:
return self.config.certfile
else:
ret = utils.dummy_cert(self.config.certpath, self.config.cacert, host)
ret = utils.dummy_cert(self.config.certdir, self.config.cacert, host)
if not ret:
raise ProxyError(400, "mitmproxy: Unable to generate dummy cert.")
return ret
@ -667,6 +668,8 @@ class ProxyServer(ServerBase):
self.config, self.port, self.address = config, port, address
ServerBase.__init__(self, (address, port), ProxyHandler)
self.masterq = None
self.certdir = tempfile.mkdtemp(prefix="mitmproxy")
config.certdir = self.certdir
def set_mqueue(self, q):
self.masterq = q
@ -675,6 +678,7 @@ class ProxyServer(ServerBase):
self.RequestHandlerClass(self.config, request, client_address, self, self.masterq)
def shutdown(self):
shutil.rmtree(self.certdir)
ServerBase.shutdown(self)
@ -691,11 +695,6 @@ def certificate_option_group(parser):
type = "str", dest="cacert", default="~/.mitmproxy/ca.pem",
help = "SSL CA certificate file. Generated if it doesn't exist."
)
group.add_option(
"--certpath", action="store",
type = "str", dest="certpath", default="~/.mitmproxy/",
help = "SSL certificate store path."
)
group.add_option(
"--ciphers", action="store",
type = "str", dest="ciphers", default=None,
@ -713,21 +712,11 @@ def process_certificate_option_group(parser, options):
if options.cacert:
options.cacert = os.path.expanduser(options.cacert)
if not os.path.exists(options.cacert):
dummy_ca(options.cacert)
if options.certpath:
options.certpath = os.path.expanduser(options.certpath)
elif options.cacert:
options.certpath = os.path.dirname(options.cacert)
utils.dummy_ca(options.cacert)
if getattr(options, "cache", None) is not None:
options.cache = os.path.expanduser(options.cache)
return Config(
certfile = options.cert,
certpath = options.certpath,
cacert = options.cacert,
ciphers = options.ciphers
)

View File

@ -54,16 +54,8 @@ if __name__ == '__main__':
if options.quiet:
options.verbose = 0
proxy.process_certificate_option_group(parser, options)
config = proxy.Config(
certfile = options.cert,
certpath = options.certpath,
cacert = options.cacert,
ciphers = options.ciphers
)
config = proxy.process_certificate_option_group(parser, options)
server = proxy.ProxyServer(config, options.port)
dumpopts = dump.Options(
verbosity = options.verbose,
wfile = options.wfile,

View File

@ -56,17 +56,11 @@ if __name__ == '__main__':
if options.quiet:
options.verbose = 0
proxy.process_certificate_option_group(parser, options)
if options.cache is not None:
options.cache = os.path.expanduser(options.cache)
config = proxy.Config(
certfile = options.cert,
certpath = options.certpath,
cacert = options.cacert,
ciphers = options.ciphers
)
config = proxy.process_certificate_option_group(parser, options)
server = proxy.ProxyServer(config, options.port)
m = playback.PlaybackMaster(server, options)
m.run()

View File

@ -85,22 +85,16 @@ if __name__ == '__main__':
options, args = parser.parse_args()
proxy.process_certificate_option_group(parser, options)
if options.cache is not None:
options.cache = os.path.expanduser(options.cache)
config = proxy.Config(
certfile = options.cert,
certpath = options.certpath,
cacert = options.cacert,
ciphers = options.ciphers
)
if options.cache is not None:
utils.mkdir_p(options.cache)
if os.path.exists(options.cache + "/index.txt"):
print >> sys.stderr, "ERROR: data already recorded in %s"%options.cache
sys.exit(1)
config = proxy.process_certificate_option_group(parser, options)
server = proxy.ProxyServer(config, options.port, options.addr)
m = console.ConsoleMaster(server, options)

View File

@ -61,14 +61,7 @@ if __name__ == '__main__':
if options.quiet:
options.verbose = 0
proxy.process_certificate_option_group(parser, options)
config = proxy.Config(
certfile = options.cert,
certpath = options.certpath,
cacert = options.cacert,
ciphers = options.ciphers
)
config = proxy.process_certificate_option_group(parser, options)
server = proxy.ProxyServer(config, options.port)
utils.mkdir_p(options.cache)
if os.path.exists(options.cache + "/index.txt"):

View File

@ -47,12 +47,12 @@ class uFlow(libpry.AutoTree):
assert f == flow.Flow.from_state(state)
f.response = None
f.error = proxy.Error(f, "error")
f.error = proxy.Error(f.request, "error")
state = f.get_state()
assert f == flow.Flow.from_state(state)
f2 = utils.tflow()
f2.error = proxy.Error(f, "e2")
f2.error = proxy.Error(f.request, "e2")
assert not f == f2
f.load_state(f2.get_state())
assert f == f2
@ -143,10 +143,10 @@ class uState(libpry.AutoTree):
c = flow.State()
req = utils.treq()
f = c.add_request(req)
e = proxy.Error(f, "message")
e = proxy.Error(f.request, "message")
assert c.add_error(e)
e = proxy.Error(utils.tflow(), "message")
e = proxy.Error(utils.tflow().request, "message")
assert not c.add_error(e)
def test_view(self):
@ -190,7 +190,7 @@ class uState(libpry.AutoTree):
def _add_error(self, state):
req = utils.treq()
f = state.add_request(req)
f.error = proxy.Error(f, "msg")
f.error = proxy.Error(f.request, "msg")
def test_kill_flow(self):
c = flow.State()
@ -269,7 +269,7 @@ class uFlowMaster(libpry.AutoTree):
dc = proxy.ClientDisconnect(req.client_conn)
fm.handle_clientdisconnect(dc)
err = proxy.Error(f, "msg")
err = proxy.Error(f.request, "msg")
fm.handle_error(err)