mirror of
https://github.com/zhigang1992/mitmproxy.git
synced 2026-04-23 20:00:09 +08:00
Beef up client certificate handling substantially.
This commit is contained in:
@@ -256,11 +256,11 @@ class SSLCert:
|
||||
|
||||
@property
|
||||
def cn(self):
|
||||
cn = None
|
||||
c = None
|
||||
for i in self.subject:
|
||||
if i[0] == "CN":
|
||||
cn = i[1]
|
||||
return cn
|
||||
c = i[1]
|
||||
return c
|
||||
|
||||
@property
|
||||
def altnames(self):
|
||||
|
||||
@@ -173,10 +173,14 @@ class TCPClient:
|
||||
self.ssl_established = False
|
||||
|
||||
def convert_to_ssl(self, clientcert=None, sni=None, method=TLSv1_METHOD, options=None):
|
||||
"""
|
||||
clientcert: Path to a file containing both client cert and private key.
|
||||
"""
|
||||
context = SSL.Context(method)
|
||||
if not options is None:
|
||||
ctx.set_options(options)
|
||||
if clientcert:
|
||||
context.use_privatekey_file(clientcert)
|
||||
context.use_certificate_file(clientcert)
|
||||
self.connection = SSL.Connection(context, self.connection)
|
||||
self.ssl_established = True
|
||||
@@ -238,6 +242,7 @@ class BaseHandler:
|
||||
self.server = server
|
||||
self.finished = False
|
||||
self.ssl_established = False
|
||||
self.clientcert = None
|
||||
|
||||
def convert_to_ssl(self, cert, key, method=SSLv23_METHOD, options=None):
|
||||
"""
|
||||
@@ -246,13 +251,16 @@ class BaseHandler:
|
||||
ctx = SSL.Context(method)
|
||||
if not options is None:
|
||||
ctx.set_options(options)
|
||||
# SNI callback happens during do_handshake()
|
||||
ctx.set_tlsext_servername_callback(self.handle_sni)
|
||||
ctx.use_privatekey_file(key)
|
||||
ctx.use_certificate_file(cert)
|
||||
def ver(*args):
|
||||
self.clientcert = certutils.SSLCert(args[1])
|
||||
ctx.set_verify(SSL.VERIFY_PEER, ver)
|
||||
self.connection = SSL.Connection(ctx, self.connection)
|
||||
self.ssl_established = True
|
||||
self.connection.set_accept_state()
|
||||
# SNI callback happens during do_handshake()
|
||||
try:
|
||||
self.connection.do_handshake()
|
||||
except SSL.Error, v:
|
||||
|
||||
3
test/data/clientcert/.gitignore
vendored
Normal file
3
test/data/clientcert/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
client.crt
|
||||
client.key
|
||||
client.req
|
||||
5
test/data/clientcert/client.cnf
Normal file
5
test/data/clientcert/client.cnf
Normal file
@@ -0,0 +1,5 @@
|
||||
[ ssl_client ]
|
||||
basicConstraints = CA:FALSE
|
||||
nsCertType = client
|
||||
keyUsage = digitalSignature, keyEncipherment
|
||||
extendedKeyUsage = clientAuth
|
||||
42
test/data/clientcert/client.pem
Normal file
42
test/data/clientcert/client.pem
Normal file
@@ -0,0 +1,42 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEAzCpoRjSTfIN24kkNap/GYmP9zVWj0Gk8R5BB/PvvN0OB1Zk0
|
||||
EEYPsWCcuhEdK0ehiDZX030doF0DOncKKa6mop/d0x2o+ts42peDhZM6JNUrm6d+
|
||||
ZWQVtio33mpp77UMhR093vaA+ExDnmE26kBTVijJ1+fRAVDXG/cmQINEri91Kk/G
|
||||
3YJ5e45UrohGI5seBZ4vV0xbHtmczFRhYFlGOvYsoIe4Lvz/eFS2pIrTIpYQ2VM/
|
||||
SQQl+JFy+NlQRsWG2NrxtKOzMnnDE7YN4I3z5D5eZFo1EtwZ48LNCeSwrEOdfuzP
|
||||
G5q5qbs5KpE/x85H9umuRwSCIArbMwBYV8a8JwIDAQABAoIBAFE3FV/IDltbmHEP
|
||||
iky93hbJm+6QgKepFReKpRVTyqb7LaygUvueQyPWQMIriKTsy675nxo8DQr7tQsO
|
||||
y3YlSZgra/xNMikIB6e82c7K8DgyrDQw/rCqjZB3Xt4VCqsWJDLXnQMSn98lx0g7
|
||||
d7Lbf8soUpKWXqfdVpSDTi4fibSX6kshXyfSTpcz4AdoncEpViUfU1xkEEmZrjT8
|
||||
1GcCsDC41xdNmzCpqRuZX7DKSFRoB+0hUzsC1oiqM7FD5kixonRd4F5PbRXImIzt
|
||||
6YCsT2okxTA04jX7yByis7LlOLTlkmLtKQYuc3erOFvwx89s4vW+AeFei+GGNitn
|
||||
tHfSwbECgYEA7SzV+nN62hAERHlg8cEQT4TxnsWvbronYWcc/ev44eHSPDWL5tPi
|
||||
GHfSbW6YAq5Wa0I9jMWfXyhOYEC3MZTC5EEeLOB71qVrTwcy/sY66rOrcgjFI76Q
|
||||
5JFHQ4wy3SWU50KxE0oWJO9LIowprG+pW1vzqC3VF0T7q0FqESrY4LUCgYEA3F7Z
|
||||
80ndnCUlooJAb+Hfotv7peFf1o6+m1PTRcz1lLnVt5R5lXj86kn+tXEpYZo1RiGR
|
||||
2rE2N0seeznWCooakHcsBN7/qmFIhhooJNF7yW+JP2I4P2UV5+tJ+8bcs/voUkQD
|
||||
1x+rGOuMn8nvHBd2+Vharft8eGL2mgooPVI2XusCgYEAlMZpO3+w8pTVeHaDP2MR
|
||||
7i/AuQ3cbCLNjSX3Y7jgGCFllWspZRRIYXzYPNkA9b2SbBnTLjjRLgnEkFBIGgvs
|
||||
7O2EFjaCuDRvydUEQhjq4ErwIsopj7B8h0QyZcbOKTbn3uFQ3n68wVJx2Sv/ADHT
|
||||
FIHrp/WIE96r19Niy34LKXkCgYB2W59VsuOKnMz01l5DeR5C+0HSWxS9SReIl2IO
|
||||
yEFSKullWyJeLIgyUaGy0990430feKI8whcrZXYumuah7IDN/KOwzhCk8vEfzWao
|
||||
N7bzfqtJVrh9HA7C7DVlO+6H4JFrtcoWPZUIomJ549w/yz6EN3ckoMC+a/Ck1TW9
|
||||
ka1QFwKBgQCywG6TrZz0UmOjyLQZ+8Q4uvZklSW5NAKBkNnyuQ2kd5rzyYgMPE8C
|
||||
Er8T88fdVIKvkhDyHhwcI7n58xE5Gr7wkwsrk/Hbd9/ZB2GgAPY3cATskK1v1McU
|
||||
YeX38CU0fUS4aoy26hWQXkViB47IGQ3jWo3ZCtzIJl8DI9/RsBWTnw==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICYDCCAckCAQEwDQYJKoZIhvcNAQEFBQAwKDESMBAGA1UEAxMJbWl0bXByb3h5
|
||||
MRIwEAYDVQQKEwltaXRtcHJveHkwHhcNMTMwMTIwMDEwODEzWhcNMTUxMDE3MDEw
|
||||
ODEzWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UE
|
||||
ChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOC
|
||||
AQ8AMIIBCgKCAQEAzCpoRjSTfIN24kkNap/GYmP9zVWj0Gk8R5BB/PvvN0OB1Zk0
|
||||
EEYPsWCcuhEdK0ehiDZX030doF0DOncKKa6mop/d0x2o+ts42peDhZM6JNUrm6d+
|
||||
ZWQVtio33mpp77UMhR093vaA+ExDnmE26kBTVijJ1+fRAVDXG/cmQINEri91Kk/G
|
||||
3YJ5e45UrohGI5seBZ4vV0xbHtmczFRhYFlGOvYsoIe4Lvz/eFS2pIrTIpYQ2VM/
|
||||
SQQl+JFy+NlQRsWG2NrxtKOzMnnDE7YN4I3z5D5eZFo1EtwZ48LNCeSwrEOdfuzP
|
||||
G5q5qbs5KpE/x85H9umuRwSCIArbMwBYV8a8JwIDAQABMA0GCSqGSIb3DQEBBQUA
|
||||
A4GBAFvI+cd47B85PQ970n2dU/PlA2/Hb1ldrrXh2guR4hX6vYx/uuk5yRI/n0Rd
|
||||
KOXJ3czO0bd2Fpe3ZoNpkW0pOSDej/Q+58ScuJd0gWCT/Sh1eRk6ZdC0kusOuWoY
|
||||
bPOPMkG45LPgUMFOnZEsfJP6P5mZIxlbCvSMFC25nPHWlct7
|
||||
-----END CERTIFICATE-----
|
||||
8
test/data/clientcert/make
Executable file
8
test/data/clientcert/make
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/bin/sh
|
||||
|
||||
openssl genrsa -out client.key 2048
|
||||
openssl req -key client.key -new -out client.req
|
||||
openssl x509 -req -days 365 -in client.req -signkey client.key -out client.crt -extfile client.cnf -extensions ssl_client
|
||||
openssl x509 -req -days 1000 -in client.req -CA ~/.mitmproxy/mitmproxy-ca.pem -CAkey ~/.mitmproxy/mitmproxy-ca.pem -set_serial 00001 -out client.crt -extensions ssl_client
|
||||
cat client.key client.crt > client.pem
|
||||
openssl x509 -text -noout -in client.pem
|
||||
@@ -57,6 +57,16 @@ class EchoHandler(tcp.BaseHandler):
|
||||
self.wfile.flush()
|
||||
|
||||
|
||||
class CertHandler(tcp.BaseHandler):
|
||||
sni = None
|
||||
def handle_sni(self, connection):
|
||||
self.sni = connection.get_servername()
|
||||
|
||||
def handle(self):
|
||||
self.wfile.write("%s\n"%self.clientcert.serial)
|
||||
self.wfile.flush()
|
||||
|
||||
|
||||
class DisconnectHandler(tcp.BaseHandler):
|
||||
def handle(self):
|
||||
self.close()
|
||||
@@ -168,6 +178,18 @@ class TestSSLv3Only(ServerTestBase):
|
||||
tutils.raises(tcp.NetLibError, c.convert_to_ssl, sni="foo.com", method=tcp.TLSv1_METHOD)
|
||||
|
||||
|
||||
class TestSSLClientCert(ServerTestBase):
|
||||
@classmethod
|
||||
def makeserver(cls):
|
||||
return TServer(("127.0.0.1", 0), True, cls.q, CertHandler)
|
||||
|
||||
def test_clientcert(self):
|
||||
c = tcp.TCPClient("127.0.0.1", self.port)
|
||||
c.connect()
|
||||
c.convert_to_ssl(clientcert=tutils.test_data.path("data/clientcert/client.pem"))
|
||||
assert c.rfile.readline().strip() == "1"
|
||||
|
||||
|
||||
class TestSNI(ServerTestBase):
|
||||
@classmethod
|
||||
def makeserver(cls):
|
||||
|
||||
Reference in New Issue
Block a user