diff --git a/libmproxy/proxy.py b/libmproxy/proxy.py index f3ea2ed29..8200c725c 100644 --- a/libmproxy/proxy.py +++ b/libmproxy/proxy.py @@ -22,9 +22,11 @@ class ProxyError(Exception): class Config: - def __init__(self, pemfile, ciphers = None): - self.pemfile = pemfile + def __init__(self, certfile = None, certpath = None, ciphers = None, cacert = None): + self.certfile = certfile + self.certpath = certpath self.ciphers = ciphers + self.cacert = cacert def read_chunked(fp): @@ -495,6 +497,23 @@ class ProxyHandler(SocketServer.StreamRequestHandler): if server: server.terminate() + def find_cert(self, host, port=443): + #return config.certpath + "/" + host + ":" + port + ".pem" + if config.certpath is not None: + cert = config.certpath + "/" + host + ".pem" + if not os.path.exists(cert) and config.cacert is not None: + utils.make_bogus_cert(cert, ca=config.cacert, commonName=host) + if os.path.exists(cert): + return cert + print >> sys.stderr, "WARNING: Certificate missing for %s:%d! (%s)\n" % (host, port, cert) + return config.certfile + + def find_key(self, host, port=443): + if config.cacert is not None: + return config.cacert + else: + return config.certfile + def read_request(self, client_conn): line = self.rfile.readline() if line == "\r\n" or line == "\n": # Possible leftover from previous message @@ -517,8 +536,8 @@ class ProxyHandler(SocketServer.StreamRequestHandler): self.wfile.flush() self.connection = ssl.wrap_socket( self.connection, - certfile = config.pemfile, - keyfile = config.pemfile, + certfile = self.find_cert(host,port), + keyfile = self.find_key(host,port), server_side = True, ssl_version = ssl.PROTOCOL_SSLv23, ciphers = config.ciphers, diff --git a/libmproxy/resources/bogus_template b/libmproxy/resources/bogus_template deleted file mode 100644 index afa7281c0..000000000 --- a/libmproxy/resources/bogus_template +++ /dev/null @@ -1,11 +0,0 @@ -[ req ] -prompt = no -distinguished_name = req_distinguished_name - -[ req_distinguished_name ] -C = NZ -ST = none -L = none -O = none -OU = none -emailAddress = none diff --git a/libmproxy/utils.py b/libmproxy/utils.py index 87fca5ce6..39279e049 100644 --- a/libmproxy/utils.py +++ b/libmproxy/utils.py @@ -14,7 +14,6 @@ # along with this program. If not, see . import re, os, subprocess, datetime, textwrap, errno - def format_timestamp(s): d = datetime.datetime.fromtimestamp(s) return d.strftime("%Y-%m-%d %H:%M:%S") @@ -314,32 +313,166 @@ class Data: data = Data(__name__) -def make_bogus_cert(path): +def make_openssl_conf(path, countryName=None, stateOrProvinceName=None, localityName=None, organizationName=None, organizationalUnitName=None, commonName=None, emailAddress=None, ca=False): + cnf = open(path, "w") + cnf.write("[ req ]\n") + cnf.write("prompt = no\n") + cnf.write("distinguished_name = req_distinguished_name\n") + if ca: + cnf.write("x509_extensions = v3_ca # The extentions to add to the self signed cert\n") + cnf.write("\n") + cnf.write("[ req_distinguished_name ]\n") + if countryName is not None: + cnf.write("countryName = %s\n" % (countryName) ) + cnf.write("stateOrProvinceName = %s\n" % (stateOrProvinceName) ) + cnf.write("localityName = %s\n" % (localityName) ) + cnf.write("organizationName = %s\n" % (organizationName) ) + cnf.write("organizationalUnitName = %s\n" % (organizationalUnitName) ) + cnf.write("commonName = %s\n" % (commonName) ) + cnf.write("emailAddress = %s\n" % (emailAddress) ) + cnf.write("\n") + cnf.write("[ v3_ca ]\n") + cnf.write("subjectKeyIdentifier=hash\n") + cnf.write("authorityKeyIdentifier=keyid:always,issuer\n") + if ca: + cnf.write("basicConstraints = critical,CA:true\n") + cnf.write("keyUsage = cRLSign, keyCertSign\n") + #cnf.write("nsCertType = sslCA, emailCA\n") + #cnf.write("subjectAltName=email:copy\n") + #cnf.write("issuerAltName=issuer:copy\n") + +def make_bogus_cert(certpath, countryName=None, stateOrProvinceName=None, localityName=None, organizationName="mitmproxy", organizationalUnitName=None, commonName="Dummy Certificate", emailAddress=None, ca=None, newca=False): # Generates a bogus certificate like so: # openssl req -config template -x509 -nodes -days 9999 -newkey rsa:1024 \ # -keyout cert.pem -out cert.pem + (path, ext) = os.path.splitext(certpath) d = os.path.dirname(path) if not os.path.exists(d): os.makedirs(d) - cmd = [ - "openssl", - "req", - "-config", data.path("resources/bogus_template"), - "-x509" , - "-nodes", - "-days", "9999", - "-newkey", "rsa:1024", - "-keyout", path, - "-out", path, - ] - subprocess.call( - cmd, - stderr=subprocess.PIPE, - stdout=subprocess.PIPE, - stdin=subprocess.PIPE - ) + cnf = open(path+".cnf", "w") + cnf.write("[ req ]\n") + cnf.write("prompt = no\n") + cnf.write("distinguished_name = req_distinguished_name\n") + if newca: + cnf.write("x509_extensions = v3_ca\n") + cnf.write("req_extensions = v3_ca_req\n") + else: + cnf.write("x509_extensions = v3_cert\n") + cnf.write("req_extensions = v3_cert_req\n") + cnf.write("\n") + cnf.write("[ req_distinguished_name ]\n") + if countryName is not None: + cnf.write("countryName = %s\n" % (countryName) ) + if stateOrProvinceName is not None: + cnf.write("stateOrProvinceName = %s\n" % (stateOrProvinceName) ) + if localityName is not None: + cnf.write("localityName = %s\n" % (localityName) ) + if organizationName is not None: + cnf.write("organizationName = %s\n" % (organizationName) ) + if organizationalUnitName is not None: + cnf.write("organizationalUnitName = %s\n" % (organizationalUnitName) ) + if commonName is not None: + cnf.write("commonName = %s\n" % (commonName) ) + if emailAddress is not None: + cnf.write("emailAddress = %s\n" % (emailAddress) ) + cnf.write("\n") + cnf.write("[ v3_ca ]\n") + cnf.write("subjectKeyIdentifier=hash\n") + cnf.write("authorityKeyIdentifier=keyid:always,issuer\n") + cnf.write("basicConstraints = critical,CA:true\n") + cnf.write("keyUsage = cRLSign, keyCertSign\n") + cnf.write("nsCertType = sslCA\n") + #cnf.write("subjectAltName=email:copy\n") + #cnf.write("issuerAltName=issuer:copy\n") + cnf.write("\n") + cnf.write("[ v3_ca_req ]\n") + cnf.write("basicConstraints = critical,CA:true\n") + cnf.write("keyUsage = cRLSign, keyCertSign\n") + cnf.write("nsCertType = sslCA\n") + #cnf.write("subjectAltName=email:copy\n") + cnf.write("\n") + cnf.write("[ v3_cert ]\n") + cnf.write("basicConstraints = CA:false\n") + cnf.write("keyUsage = nonRepudiation, digitalSignature, keyEncipherment\n") + cnf.write("nsCertType = server\n") + cnf.write("subjectKeyIdentifier=hash\n") + cnf.write("authorityKeyIdentifier=keyid:always,issuer\n") + cnf.write("\n") + cnf.write("[ v3_cert_req ]\n") + cnf.write("basicConstraints = CA:false\n") + cnf.write("keyUsage = nonRepudiation, digitalSignature, keyEncipherment\n") + cnf.write("nsCertType = server\n") + cnf.write("\n") + + cnf.close() + + if ca is None: + # Create a new selfsigned certificate + key + cmd = [ + "openssl", + "req", + "-new", + "-x509", + "-config", path+".cnf", + "-nodes", + "-days", "9999", + "-out", certpath, + "-newkey", "rsa:1024", + "-keyout", certpath, + ] + #print " ".join(cmd) + subprocess.call( + cmd, + stderr=subprocess.PIPE, + stdout=subprocess.PIPE, + stdin=subprocess.PIPE + ) + else: + # Create a dummy signed certificate. Uses same key as the signing CA + cmd = [ + "openssl", + "req", + "-new", + "-config", path+".cnf", + "-out", path+".req", + "-key", ca, + ] + #print " ".join(cmd) + subprocess.call( + cmd, + stderr=subprocess.PIPE, + stdout=subprocess.PIPE, + stdin=subprocess.PIPE + ) + cmd = [ + "openssl", + "x509", + "-req", + "-in", path+".req", + "-days", "9999", + "-out", certpath, + "-CA", ca, + "-CAcreateserial", + "-extfile", path+".cnf" + ] + if newca: + cmd.extend([ + "-extensions", "v3_ca", + ]) + else: + cmd.extend([ + "-extensions", "v3_cert", + ]) + + #print " ".join(cmd) + subprocess.call( + cmd, + stderr=subprocess.PIPE, + stdout=subprocess.PIPE, + stdin=subprocess.PIPE + ) def mkdir_p(path): try: diff --git a/mitmdump b/mitmdump index 26686afd0..11b715689 100755 --- a/mitmdump +++ b/mitmdump @@ -27,10 +27,20 @@ if __name__ == '__main__': version="%%prog %s"%VERSION, ) parser.add_option( - "-c", "--cert", action="store", - type = "str", dest="cert", default="~/.mitmproxy/cert.pem", + "--cert", action="store", + type = "str", dest="cert", default="~/.mitmproxy/default.pem", help = "SSL certificate file." ) + parser.add_option( + "-c", "--cacert", action="store", + type = "str", dest="cacert", default="~/.mitmproxy/ca.pem", + help = "SSL CA certificate file." + ) + parser.add_option( + "--certpath", action="store", + type = "str", dest="certpath", default="~/.mitmproxy/", + help = "SSL certificate store path." + ) parser.add_option( "--ciphers", action="store", type = "str", dest="ciphers", default=None, @@ -52,14 +62,17 @@ if __name__ == '__main__': if options.quiet: options.verbose = 0 - certpath = os.path.expanduser(options.cert) + options.cert = os.path.expanduser(options.cert) + options.certpath = os.path.expanduser(options.certpath) - if not os.path.exists(certpath): + if not os.path.exists(options.cert): print >> sys.stderr, "Creating bogus certificate at %s"%options.cert - utils.make_bogus_cert(certpath) + utils.make_bogus_cert(options.cert) proxy.config = proxy.Config( - certpath, + certfile = options.cert, + certpath = options.certpath, + cacert = options.cacert, ciphers = options.ciphers ) server = proxy.ProxyServer(options.port) diff --git a/mitmplayback b/mitmplayback index eb147cd93..9d4fe11a0 100755 --- a/mitmplayback +++ b/mitmplayback @@ -31,11 +31,23 @@ if __name__ == '__main__': ) parser.add_option( - "-c", "--cert", action="store", - type = "str", dest="cert", default="~/.mitmproxy/cert.pem", + "--cert", action="store", + type = "str", dest="cert", default="~/.mitmproxy/default.pem", help = "SSL certificate file." ) + parser.add_option( + "-c", "--cacert", action="store", + type = "str", dest="cacert", default="~/.mitmproxy/ca.pem", + help = "SSL CA certificate file." + ) + + parser.add_option( + "--certpath", action="store", + type = "str", dest="certpath", default=None, + help = "SSL certificate store path." + ) + parser.add_option( "--ciphers", action="store", type = "str", dest="ciphers", default=None, @@ -66,15 +78,27 @@ if __name__ == '__main__': if options.quiet: options.verbose = 0 - certpath = os.path.expanduser(options.cert) - options.cache = os.path.expanduser(options.cache) + if options.cert is not None: + options.cert = os.path.expanduser(options.cert) + if not os.path.exists(options.cert): + print >> sys.stderr, "Creating bogus certificate at %s"%options.cert + utils.make_bogus_cert(options.cert) + if options.cacert is not None: + options.cacert = os.path.expanduser(options.cacert) + if not os.path.exists(options.cacert): + print >> sys.stderr, "Creating bogus CA certificate at %s"%options.cacert + utils.make_bogus_cert(options.cacert, newca=True, commonName="Dummy CA") + if options.certpath is not None: + options.certpath = os.path.expanduser(options.certpath) + elif options.cacert is not None: + options.certpath = os.path.dirname(options.cacert) + if options.cache is not None: + options.cache = os.path.expanduser(options.cache) - if not os.path.exists(certpath): - print >> sys.stderr, "Creating bogus certificate at %s"%options.cert - utils.make_bogus_cert(certpath) - proxy.config = proxy.Config( - certpath, + certfile = options.cert, + certpath = options.certpath, + cacert = options.cacert, ciphers = options.ciphers ) server = proxy.ProxyServer(options.port) diff --git a/mitmproxy b/mitmproxy index e3ec9d9eb..cf746e38a 100755 --- a/mitmproxy +++ b/mitmproxy @@ -34,11 +34,23 @@ if __name__ == '__main__': ) parser.add_option( - "-c", "--cert", action="store", - type = "str", dest="cert", default="~/.mitmproxy/cert.pem", + "--cert", action="store", + type = "str", dest="cert", default="~/.mitmproxy/default.pem", help = "SSL certificate file." ) + parser.add_option( + "-c", "--cacert", action="store", + type = "str", dest="cacert", default="~/.mitmproxy/ca.pem", + help = "SSL CA certificate file." + ) + + parser.add_option( + "--certpath", action="store", + type = "str", dest="certpath", default="~/.mitmproxy/", + help = "SSL certificate store path." + ) + parser.add_option( "--ciphers", action="store", type = "str", dest="ciphers", default=None, @@ -96,14 +108,28 @@ if __name__ == '__main__': parser.add_option_group(group) options, args = parser.parse_args() - certpath = os.path.expanduser(options.cert) - - if not os.path.exists(certpath): - print >> sys.stderr, "Creating bogus certificate at %s"%options.cert - utils.make_bogus_cert(certpath) + + if options.cert is not None: + options.cert = os.path.expanduser(options.cert) + if not os.path.exists(options.cert): + print >> sys.stderr, "Creating bogus certificate at %s"%options.cert + utils.make_bogus_cert(options.cert) + if options.cacert is not None: + options.cacert = os.path.expanduser(options.cacert) + if not os.path.exists(options.cacert): + print >> sys.stderr, "Creating bogus CA certificate at %s"%options.cacert + utils.make_bogus_cert(options.cacert, newca=True, commonName="Dummy CA") + if options.certpath is not None: + options.certpath = os.path.expanduser(options.certpath) + elif options.cacert is not None: + options.certpath = os.path.dirname(options.cacert) + if options.cache is not None: + options.cache = os.path.expanduser(options.cache) proxy.config = proxy.Config( - certpath, + certfile = options.cert, + certpath = options.certpath, + cacert = options.cacert, ciphers = options.ciphers ) if options.cache is not None: diff --git a/mitmrecord b/mitmrecord index 11c7b6ca3..1f81633c5 100755 --- a/mitmrecord +++ b/mitmrecord @@ -30,11 +30,23 @@ if __name__ == '__main__': ) parser.add_option( - "-c", "--cert", action="store", - type = "str", dest="cert", default="~/.mitmproxy/cert.pem", + "--cert", action="store", + type = "str", dest="cert", default="~/.mitmproxy/default.pem", help = "SSL certificate file." ) + parser.add_option( + "-c", "--cacert", action="store", + type = "str", dest="cacert", default="~/.mitmproxy/ca.pem", + help = "SSL CA certificate file." + ) + + parser.add_option( + "--certpath", action="store", + type = "str", dest="certpath", default=None, + help = "SSL certificate store path." + ) + parser.add_option( "--ciphers", action="store", type = "str", dest="ciphers", default=None, @@ -71,15 +83,27 @@ if __name__ == '__main__': if options.quiet: options.verbose = 0 - certpath = os.path.expanduser(options.cert) - options.cache = os.path.expanduser(options.cache) - - if not os.path.exists(certpath): - print >> sys.stderr, "Creating bogus certificate at %s"%options.cert - utils.make_bogus_cert(certpath) + if options.cert is not None: + options.cert = os.path.expanduser(options.cert) + if not os.path.exists(options.cert): + print >> sys.stderr, "Creating bogus certificate at %s"%options.cert + utils.make_bogus_cert(options.cert) + if options.cacert is not None: + options.cacert = os.path.expanduser(options.cacert) + if not os.path.exists(options.cacert): + print >> sys.stderr, "Creating bogus CA certificate at %s"%options.cacert + utils.make_bogus_cert(options.cacert, newca=True, commonName="Dummy CA") + if options.certpath is not None: + options.certpath = os.path.expanduser(options.certpath) + elif options.cacert is not None: + options.certpath = os.path.dirname(options.cacert) + if options.cache is not None: + options.cache = os.path.expanduser(options.cache) proxy.config = proxy.Config( - certpath, + certfile = options.cert, + certpath = options.certpath, + cacert = options.cacert, ciphers = options.ciphers ) server = proxy.ProxyServer(options.port)