diff options
author | Aldo Cortesi <aldo@nullcube.com> | 2012-02-27 15:05:45 +1300 |
---|---|---|
committer | Aldo Cortesi <aldo@nullcube.com> | 2012-02-27 15:05:45 +1300 |
commit | 00942c1431c551e0bded111271be9b69f5261d91 (patch) | |
tree | c03a1bd9c18ae941446bbdb24dcfa01b3890287a /libmproxy/utils.py | |
parent | 4a2964985c3ca9e044134857175bde895372a898 (diff) | |
download | mitmproxy-00942c1431c551e0bded111271be9b69f5261d91.tar.gz mitmproxy-00942c1431c551e0bded111271be9b69f5261d91.tar.bz2 mitmproxy-00942c1431c551e0bded111271be9b69f5261d91.zip |
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.
Diffstat (limited to 'libmproxy/utils.py')
-rw-r--r-- | libmproxy/utils.py | 73 |
1 files changed, 69 insertions, 4 deletions
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 <http://www.gnu.org/licenses/>. -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) + |