From 00942c1431c551e0bded111271be9b69f5261d91 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Mon, 27 Feb 2012 15:05:45 +1300 Subject: Add upstream certificate lookup. This initiates a connection to the server to obtain certificate information to generate interception certificates. At the moment, the information used is the Common Name, and the list of Subject Alternative Names. --- libmproxy/utils.py | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 69 insertions(+), 4 deletions(-) (limited to 'libmproxy/utils.py') diff --git a/libmproxy/utils.py b/libmproxy/utils.py index 16540434..3381ad33 100644 --- a/libmproxy/utils.py +++ b/libmproxy/utils.py @@ -12,8 +12,8 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import re, os, subprocess, datetime, urlparse, string, urllib -import time, functools, cgi, textwrap, hashlib +import re, os, subprocess, datetime, urlparse, string, urllib, socket +import time, functools, cgi, textwrap, hashlib, ssl, tempfile import json CERT_SLEEP_TIME = 1 @@ -276,7 +276,7 @@ def dummy_ca(path): return True -def dummy_cert(certdir, ca, commonname): +def dummy_cert(certdir, ca, commonname, sans): """ certdir: Certificate directory. ca: Path to the certificate authority file, or None. @@ -293,8 +293,14 @@ def dummy_cert(certdir, ca, commonname): reqpath = os.path.join(certdir, namehash + ".req") template = open(pkg_data.path("resources/cert.cnf")).read() + + ss = [] + for i, v in enumerate(sans): + ss.append("DNS.%s = %s"%(i, v)) + ss = "\n".join(ss) + f = open(confpath, "w") - f.write(template%(dict(commonname=commonname))) + f.write(template%(dict(commonname=commonname, sans=ss))) f.close() if ca: @@ -483,3 +489,62 @@ def parse_size(s): return int(s) * mult except ValueError: raise ValueError("Invalid size specification: %s"%s) + + +def get_remote_cn(host, port): + addr = socket.gethostbyname(host) + s = ssl.get_server_certificate((addr, port)) + f = tempfile.NamedTemporaryFile() + f.write(s) + f.flush() + p = subprocess.Popen( + [ + "openssl", + "x509", + "-in", f.name, + "-text", + "-noout" + ], + stdout = subprocess.PIPE + ) + out, _ = p.communicate() + return parse_text_cert(out) + + +CNRE = re.compile( + r""" + Subject:.*CN=(\S*) + """, + re.VERBOSE|re.MULTILINE +) +SANRE = re.compile( + r""" + X509v3\ Subject\ Alternative\ Name:\s* + (.*)$ + """, + re.VERBOSE|re.MULTILINE +) + + +def parse_text_cert(txt): + """ + Returns a (common name, [subject alternative names]) tuple. + """ + r = re.search(CNRE, txt) + if r: + cn = r.group(1) + else: + return None + + r = re.search(SANRE, txt) + san = [] + if r: + for i in r.group(1).split(","): + i = i.strip() + k, v = i.split(":") + if k == "DNS": + san.append(v) + else: + san = [] + return (cn, san) + -- cgit v1.2.3 From 2ba8296843fc83256e3e13a23529a915d73a2e2d Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Mon, 27 Feb 2012 15:21:05 +1300 Subject: Better certificate parsing. --- libmproxy/utils.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'libmproxy/utils.py') diff --git a/libmproxy/utils.py b/libmproxy/utils.py index 3381ad33..57a9e983 100644 --- a/libmproxy/utils.py +++ b/libmproxy/utils.py @@ -513,7 +513,7 @@ def get_remote_cn(host, port): CNRE = re.compile( r""" - Subject:.*CN=(\S*) + Subject:.*CN=([^ \t\n\r\f\v/]*) """, re.VERBOSE|re.MULTILINE ) @@ -524,8 +524,6 @@ SANRE = re.compile( """, re.VERBOSE|re.MULTILINE ) - - def parse_text_cert(txt): """ Returns a (common name, [subject alternative names]) tuple. -- cgit v1.2.3 From 2c73e8f816c1965bc5092f4e7e7c57478293ade6 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Mon, 27 Feb 2012 15:36:19 +1300 Subject: Fix problems with SANs and certificate generation. --- libmproxy/utils.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'libmproxy/utils.py') diff --git a/libmproxy/utils.py b/libmproxy/utils.py index 57a9e983..474f7844 100644 --- a/libmproxy/utils.py +++ b/libmproxy/utils.py @@ -300,7 +300,15 @@ def dummy_cert(certdir, ca, commonname, sans): ss = "\n".join(ss) f = open(confpath, "w") - f.write(template%(dict(commonname=commonname, sans=ss))) + f.write( + template%( + dict( + commonname=commonname, + sans=ss, + altnames="subjectAltName = @alt_names" if ss else "" + ) + ) + ) f.close() if ca: -- cgit v1.2.3 From 764724748bf27466594be9755914ff25d52a66c5 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Mon, 27 Feb 2012 15:59:29 +1300 Subject: Fix cert generation harder. --- libmproxy/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'libmproxy/utils.py') diff --git a/libmproxy/utils.py b/libmproxy/utils.py index 474f7844..8e2097eb 100644 --- a/libmproxy/utils.py +++ b/libmproxy/utils.py @@ -296,7 +296,7 @@ def dummy_cert(certdir, ca, commonname, sans): ss = [] for i, v in enumerate(sans): - ss.append("DNS.%s = %s"%(i, v)) + ss.append("DNS.%s = %s"%(i+1, v)) ss = "\n".join(ss) f = open(confpath, "w") @@ -338,7 +338,7 @@ def dummy_cert(certdir, ca, commonname, sans): "-CA", ca, "-CAcreateserial", "-extfile", confpath, - "-extensions", "v3_cert", + "-extensions", "v3_cert_req", ] ret = subprocess.call( cmd, -- cgit v1.2.3