aboutsummaryrefslogtreecommitdiffstats
path: root/libmproxy/utils.py
diff options
context:
space:
mode:
authorAldo Cortesi <aldo@nullcube.com>2012-02-27 15:05:45 +1300
committerAldo Cortesi <aldo@nullcube.com>2012-02-27 15:05:45 +1300
commit00942c1431c551e0bded111271be9b69f5261d91 (patch)
treec03a1bd9c18ae941446bbdb24dcfa01b3890287a /libmproxy/utils.py
parent4a2964985c3ca9e044134857175bde895372a898 (diff)
downloadmitmproxy-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.py73
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)
+