mirror of
https://github.com/internetarchive/warcprox.git
synced 2025-01-18 13:22:09 +01:00
i don't think we really need the CA, just use same cert for everything, cert won't verify anyway so host doesn't have to match
This commit is contained in:
parent
5b26a02549
commit
92e5d79ea7
121
src/warcprox/proxy.py
Normal file → Executable file
121
src/warcprox/proxy.py
Normal file → Executable file
@ -18,9 +18,8 @@ from ssl import wrap_socket
|
|||||||
from socket import socket
|
from socket import socket
|
||||||
from sys import argv
|
from sys import argv
|
||||||
|
|
||||||
from OpenSSL.crypto import (X509Extension, X509, dump_privatekey, dump_certificate, load_certificate, load_privatekey,
|
import OpenSSL.crypto
|
||||||
PKey, TYPE_RSA, X509Req)
|
import OpenSSL.SSL
|
||||||
from OpenSSL.SSL import FILETYPE_PEM
|
|
||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
import ssl
|
import ssl
|
||||||
@ -32,6 +31,7 @@ from datetime import datetime
|
|||||||
import time
|
import time
|
||||||
import Queue
|
import Queue
|
||||||
import threading
|
import threading
|
||||||
|
import os.path
|
||||||
|
|
||||||
__author__ = 'Nadeem Douba'
|
__author__ = 'Nadeem Douba'
|
||||||
__copyright__ = 'Copyright 2012, PyMiProxy Project'
|
__copyright__ = 'Copyright 2012, PyMiProxy Project'
|
||||||
@ -44,7 +44,6 @@ __email__ = 'ndouba@gmail.com'
|
|||||||
__status__ = 'Development'
|
__status__ = 'Development'
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'CertificateAuthority',
|
|
||||||
'ProxyHandler',
|
'ProxyHandler',
|
||||||
'RequestInterceptorPlugin',
|
'RequestInterceptorPlugin',
|
||||||
'ResponseInterceptorPlugin',
|
'ResponseInterceptorPlugin',
|
||||||
@ -54,91 +53,6 @@ __all__ = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class CertificateAuthority(object):
|
|
||||||
|
|
||||||
def __init__(self, ca_file='ca.pem', cache_dir=gettempdir()):
|
|
||||||
self.ca_file = ca_file
|
|
||||||
self.cache_dir = cache_dir
|
|
||||||
self._serial = self._get_serial()
|
|
||||||
if not path.exists(ca_file):
|
|
||||||
self._generate_ca()
|
|
||||||
else:
|
|
||||||
self._read_ca(ca_file)
|
|
||||||
|
|
||||||
def _get_serial(self):
|
|
||||||
s = 1
|
|
||||||
for c in filter(lambda x: x.startswith('.pymp_'), listdir(self.cache_dir)):
|
|
||||||
c = load_certificate(FILETYPE_PEM, open(path.sep.join([self.cache_dir, c])).read())
|
|
||||||
sc = c.get_serial_number()
|
|
||||||
if sc > s:
|
|
||||||
s = sc
|
|
||||||
del c
|
|
||||||
return s
|
|
||||||
|
|
||||||
def _generate_ca(self):
|
|
||||||
# Generate key
|
|
||||||
self.key = PKey()
|
|
||||||
self.key.generate_key(TYPE_RSA, 2048)
|
|
||||||
|
|
||||||
# Generate certificate
|
|
||||||
self.cert = X509()
|
|
||||||
self.cert.set_version(3)
|
|
||||||
self.cert.set_serial_number(1)
|
|
||||||
self.cert.get_subject().CN = 'ca.mitm.com'
|
|
||||||
self.cert.gmtime_adj_notBefore(0)
|
|
||||||
self.cert.gmtime_adj_notAfter(315360000)
|
|
||||||
self.cert.set_issuer(self.cert.get_subject())
|
|
||||||
self.cert.set_pubkey(self.key)
|
|
||||||
self.cert.add_extensions([
|
|
||||||
X509Extension("basicConstraints", True, "CA:TRUE, pathlen:0"),
|
|
||||||
X509Extension("keyUsage", True, "keyCertSign, cRLSign"),
|
|
||||||
X509Extension("subjectKeyIdentifier", False, "hash", subject=self.cert),
|
|
||||||
])
|
|
||||||
self.cert.sign(self.key, "sha1")
|
|
||||||
|
|
||||||
with open(self.ca_file, 'wb+') as f:
|
|
||||||
f.write(dump_privatekey(FILETYPE_PEM, self.key))
|
|
||||||
f.write(dump_certificate(FILETYPE_PEM, self.cert))
|
|
||||||
|
|
||||||
def _read_ca(self, file):
|
|
||||||
self.cert = load_certificate(FILETYPE_PEM, open(file).read())
|
|
||||||
self.key = load_privatekey(FILETYPE_PEM, open(file).read())
|
|
||||||
|
|
||||||
def __getitem__(self, cn):
|
|
||||||
cnp = path.sep.join([self.cache_dir, '.pymp_%s.pem' % cn])
|
|
||||||
if not path.exists(cnp):
|
|
||||||
# create certificate
|
|
||||||
key = PKey()
|
|
||||||
key.generate_key(TYPE_RSA, 2048)
|
|
||||||
|
|
||||||
# Generate CSR
|
|
||||||
req = X509Req()
|
|
||||||
req.get_subject().CN = cn
|
|
||||||
req.set_pubkey(key)
|
|
||||||
req.sign(key, 'sha1')
|
|
||||||
|
|
||||||
# Sign CSR
|
|
||||||
cert = X509()
|
|
||||||
cert.set_subject(req.get_subject())
|
|
||||||
cert.set_serial_number(self.serial)
|
|
||||||
cert.gmtime_adj_notBefore(0)
|
|
||||||
cert.gmtime_adj_notAfter(31536000)
|
|
||||||
cert.set_issuer(self.cert.get_subject())
|
|
||||||
cert.set_pubkey(req.get_pubkey())
|
|
||||||
cert.sign(self.key, 'sha1')
|
|
||||||
|
|
||||||
with open(cnp, 'wb+') as f:
|
|
||||||
f.write(dump_privatekey(FILETYPE_PEM, key))
|
|
||||||
f.write(dump_certificate(FILETYPE_PEM, cert))
|
|
||||||
|
|
||||||
return cnp
|
|
||||||
|
|
||||||
@property
|
|
||||||
def serial(self):
|
|
||||||
self._serial += 1
|
|
||||||
return self._serial
|
|
||||||
|
|
||||||
|
|
||||||
class UnsupportedSchemeException(Exception):
|
class UnsupportedSchemeException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -182,7 +96,7 @@ class ProxyHandler(BaseHTTPRequestHandler):
|
|||||||
|
|
||||||
|
|
||||||
def _transition_to_ssl(self):
|
def _transition_to_ssl(self):
|
||||||
self.request = wrap_socket(self.request, server_side=True, certfile=self.server.ca[self.path.split(':')[0]])
|
self.request = wrap_socket(self.request, server_side=True, certfile=self.server.certfile)
|
||||||
|
|
||||||
|
|
||||||
def do_CONNECT(self):
|
def do_CONNECT(self):
|
||||||
@ -293,11 +207,34 @@ class InvalidInterceptorPluginException(Exception):
|
|||||||
|
|
||||||
class MitmProxy(HTTPServer):
|
class MitmProxy(HTTPServer):
|
||||||
|
|
||||||
def __init__(self, server_address=('', 8080), RequestHandlerClass=ProxyHandler, bind_and_activate=True, ca_file='ca.pem'):
|
def __init__(self, server_address=('', 8080), RequestHandlerClass=ProxyHandler, bind_and_activate=True, certfile='warcprox.pem'):
|
||||||
HTTPServer.__init__(self, server_address, RequestHandlerClass, bind_and_activate)
|
HTTPServer.__init__(self, server_address, RequestHandlerClass, bind_and_activate)
|
||||||
self.ca = CertificateAuthority(ca_file)
|
|
||||||
self._res_plugins = []
|
self._res_plugins = []
|
||||||
self._req_plugins = []
|
self._req_plugins = []
|
||||||
|
self.certfile = certfile
|
||||||
|
|
||||||
|
if not os.path.exists(certfile):
|
||||||
|
self._generate_cert(certfile)
|
||||||
|
|
||||||
|
|
||||||
|
def _generate_cert(self, certfile):
|
||||||
|
key = OpenSSL.crypto.PKey()
|
||||||
|
key.generate_key(OpenSSL.crypto.TYPE_RSA, 2048)
|
||||||
|
|
||||||
|
cert = OpenSSL.crypto.X509()
|
||||||
|
cert.set_version(3)
|
||||||
|
cert.set_serial_number(1)
|
||||||
|
cert.get_subject().CN = 'warcprox man-in-the-middle archiving http/s proxy'
|
||||||
|
cert.gmtime_adj_notBefore(0) # now
|
||||||
|
cert.gmtime_adj_notAfter(100*365*24*60*60) # 100 yrs in future
|
||||||
|
cert.set_issuer(cert.get_subject())
|
||||||
|
cert.set_pubkey(key)
|
||||||
|
cert.sign(key, "sha1")
|
||||||
|
|
||||||
|
with open(certfile, 'wb+') as f:
|
||||||
|
f.write(OpenSSL.crypto.dump_privatekey(OpenSSL.SSL.FILETYPE_PEM, key))
|
||||||
|
f.write(OpenSSL.crypto.dump_certificate(OpenSSL.SSL.FILETYPE_PEM, cert))
|
||||||
|
|
||||||
|
|
||||||
def register_interceptor(self, interceptor_class):
|
def register_interceptor(self, interceptor_class):
|
||||||
if not issubclass(interceptor_class, InterceptorPlugin):
|
if not issubclass(interceptor_class, InterceptorPlugin):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user