From 4fc807cedd9a481db9e0fc1633d8c169f53f4a8e Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 20 Feb 2011 12:12:55 +1300 Subject: Clean up certificate generation. - Use templates for config files. We can re-introduce customization of the certificate attributes when we need them. - Split CA and cert generation into separate functions. - Generation methods provide an error return when generation fails. - When the user explicitly specifies a certificate, we don't generate it, but fail if it doesn't exist. --- libmproxy/utils.py | 225 +++++++++++++++++++++-------------------------------- 1 file changed, 88 insertions(+), 137 deletions(-) (limited to 'libmproxy/utils.py') diff --git a/libmproxy/utils.py b/libmproxy/utils.py index c9be7483..51a8e871 100644 --- a/libmproxy/utils.py +++ b/libmproxy/utils.py @@ -12,7 +12,7 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import re, os, subprocess, datetime, textwrap, errno +import re, os, subprocess, datetime, textwrap, errno, sys import optparse def format_timestamp(s): @@ -314,167 +314,118 @@ class Data: data = Data(__name__) -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) +def dummy_ca(path): + """ + Creates a dummy CA, and writes it to path. + + This function also creates the necessary directories if they don't exist. + + Returns True if operation succeeded, False if not. + """ d = os.path.dirname(path) if not os.path.exists(d): os.makedirs(d) - - 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") + cmd = [ + "openssl", + "req", + "-new", + "-x509", + "-config", data.path("resources/ca.cnf"), + "-nodes", + "-days", "9999", + "-out", path, + "-newkey", "rsa:1024", + "-keyout", path, + ] + ret = subprocess.call( + cmd, + stderr=subprocess.PIPE, + stdout=subprocess.PIPE, + stdin=subprocess.PIPE + ) + if ret: + return False 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 + return True + + +def dummy_cert(certdir, ca, commonname): + """ + certdir: Certificate directory. + ca: Path to the certificate authority file, or None. + commonname: Common name for the generated certificate. + + Returns True if operation succeeded, False if not. + """ + confpath = os.path.join(certdir, commonname + ".cnf") + reqpath = os.path.join(certdir, commonname + ".req") + certpath = os.path.join(certdir, commonname + ".pem") + + template = open(data.path("resources/cert.cnf")).read() + f = open(confpath, "w").write(template%(dict(commonname=commonname))) + + if ca: + # Create a dummy signed certificate. Uses same key as the signing CA cmd = [ "openssl", "req", "-new", - "-x509", - "-config", path+".cnf", - "-nodes", - "-days", "9999", - "-out", certpath, - "-newkey", "rsa:1024", - "-keyout", certpath, + "-config", confpath, + "-out", reqpath, + "-key", ca, ] - #print " ".join(cmd) - subprocess.call( + ret = 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 + if ret: + return False cmd = [ "openssl", - "req", - "-new", - "-config", path+".cnf", - "-out", path+".req", - "-key", ca, + "x509", + "-req", + "-in", reqpath, + "-days", "9999", + "-out", certpath, + "-CA", ca, + "-CAcreateserial", + "-extfile", confpath, + "-extensions", "v3_cert", ] - #print " ".join(cmd) - subprocess.call( + ret = subprocess.call( cmd, stderr=subprocess.PIPE, stdout=subprocess.PIPE, stdin=subprocess.PIPE ) + if ret: + return False + else: + # Create a new selfsigned certificate + key cmd = [ "openssl", - "x509", - "-req", - "-in", path+".req", + "req", + "-new", + "-x509", + "-config", confpath, + "-nodes", "-days", "9999", "-out", certpath, - "-CA", ca, - "-CAcreateserial", - "-extfile", path+".cnf" + "-newkey", "rsa:1024", + "-keyout", certpath, ] - if newca: - cmd.extend([ - "-extensions", "v3_ca", - ]) - else: - cmd.extend([ - "-extensions", "v3_cert", - ]) - - #print " ".join(cmd) - subprocess.call( + ret = subprocess.call( cmd, stderr=subprocess.PIPE, stdout=subprocess.PIPE, stdin=subprocess.PIPE ) - + if ret: + return False + return True + def mkdir_p(path): try: @@ -490,11 +441,11 @@ def certificate_option_group(parser): group = optparse.OptionGroup(parser, "SSL") group.add_option( "--cert", action="store", - type = "str", dest="cert", default="~/.mitmproxy/default.pem", + type = "str", dest="cert", default=None, help = "SSL certificate file." ) group.add_option( - "-c", "--cacert", action="store", + "--cacert", action="store", type = "str", dest="cacert", default="~/.mitmproxy/ca.pem", help = "SSL CA certificate file." ) @@ -510,17 +461,17 @@ def certificate_option_group(parser): ) parser.add_option_group(group) -def process_certificate_option_group(options): + +def process_certificate_option_group(parser, options): 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) + parser.error("Manually created certificate does not exist: %s"%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") + print >> sys.stderr, "Creating dummy CA certificate at %s"%options.cacert + dummy_ca(options.cacert) if options.certpath is not None: options.certpath = os.path.expanduser(options.certpath) elif options.cacert is not None: -- cgit v1.2.3