Merge branch 'master' into docs-tutorials

This commit is contained in:
Maximilian Hils 2020-09-07 18:29:38 +02:00 committed by GitHub
commit bfa6467e4c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 77 additions and 11 deletions

View File

@ -13,6 +13,7 @@ Unreleased: mitmproxy next
* Add ASGI support for embedded apps (@mhils) * Add ASGI support for embedded apps (@mhils)
* Updated raw exports to not remove headers (@wchasekelley) * Updated raw exports to not remove headers (@wchasekelley)
* Fix file unlinking before external viewer finishes loading (@wchasekelley) * Fix file unlinking before external viewer finishes loading (@wchasekelley)
* Add --cert-passphrase command line argument (@mirosyn)
* Add interactive tutorials to the documentation (@mplattner) * Add interactive tutorials to the documentation (@mplattner)
* --- TODO: add new PRs above this line --- * --- TODO: add new PRs above this line ---

View File

@ -196,7 +196,7 @@ class CertStore:
return dh return dh
@classmethod @classmethod
def from_store(cls, path, basename, key_size): def from_store(cls, path, basename, key_size, passphrase: typing.Optional[bytes] = None):
ca_path = os.path.join(path, basename + "-ca.pem") ca_path = os.path.join(path, basename + "-ca.pem")
if not os.path.exists(ca_path): if not os.path.exists(ca_path):
key, ca = cls.create_store(path, basename, key_size) key, ca = cls.create_store(path, basename, key_size)
@ -208,7 +208,8 @@ class CertStore:
raw) raw)
key = OpenSSL.crypto.load_privatekey( key = OpenSSL.crypto.load_privatekey(
OpenSSL.crypto.FILETYPE_PEM, OpenSSL.crypto.FILETYPE_PEM,
raw) raw,
passphrase)
dh_path = os.path.join(path, basename + "-dhparam.pem") dh_path = os.path.join(path, basename + "-dhparam.pem")
dh = cls.load_dhparam(dh_path) dh = cls.load_dhparam(dh_path)
return cls(key, ca, ca_path, dh) return cls(key, ca, ca_path, dh)
@ -280,7 +281,7 @@ class CertStore:
return key, ca return key, ca
def add_cert_file(self, spec: str, path: str) -> None: def add_cert_file(self, spec: str, path: str, passphrase: typing.Optional[bytes] = None) -> None:
with open(path, "rb") as f: with open(path, "rb") as f:
raw = f.read() raw = f.read()
cert = Cert( cert = Cert(
@ -290,7 +291,8 @@ class CertStore:
try: try:
privatekey = OpenSSL.crypto.load_privatekey( privatekey = OpenSSL.crypto.load_privatekey(
OpenSSL.crypto.FILETYPE_PEM, OpenSSL.crypto.FILETYPE_PEM,
raw) raw,
passphrase)
except Exception: except Exception:
privatekey = self.default_privatekey privatekey = self.default_privatekey
self.add_cert( self.add_cert(

View File

@ -47,6 +47,10 @@ class Options(optmanager.OptManager):
certificate as the first entry. certificate as the first entry.
""" """
) )
self.add_option(
"cert_passphrase", Optional[str], None,
"Passphrase for decrypting the private key provided in the --cert option."
)
self.add_option( self.add_option(
"ciphers_client", Optional[str], None, "ciphers_client", Optional[str], None,
"Set supported ciphers for client connections using OpenSSL syntax." "Set supported ciphers for client connections using OpenSSL syntax."

View File

@ -62,10 +62,12 @@ class ProxyConfig:
os.path.dirname(certstore_path) os.path.dirname(certstore_path)
) )
key_size = options.key_size key_size = options.key_size
passphrase = options.cert_passphrase.encode("utf-8") if options.cert_passphrase else None
self.certstore = certs.CertStore.from_store( self.certstore = certs.CertStore.from_store(
certstore_path, certstore_path,
moptions.CONF_BASENAME, moptions.CONF_BASENAME,
key_size key_size,
passphrase
) )
for c in options.certs: for c in options.certs:
@ -79,7 +81,7 @@ class ProxyConfig:
"Certificate file does not exist: %s" % cert "Certificate file does not exist: %s" % cert
) )
try: try:
self.certstore.add_cert_file(parts[0], cert) self.certstore.add_cert_file(parts[0], cert, passphrase)
except crypto.Error: except crypto.Error:
raise exceptions.OptionsError( raise exceptions.OptionsError(
"Invalid certificate format: %s" % cert "Invalid certificate format: %s" % cert

View File

@ -67,6 +67,7 @@ def common_options(parser, opts):
# Proxy SSL options # Proxy SSL options
group = parser.add_argument_group("SSL") group = parser.add_argument_group("SSL")
opts.make_parser(group, "certs", metavar="SPEC") opts.make_parser(group, "certs", metavar="SPEC")
opts.make_parser(group, "cert_passphrase", metavar="PASS")
opts.make_parser(group, "ssl_insecure", short="k") opts.make_parser(group, "ssl_insecure", short="k")
opts.make_parser(group, "key_size", metavar="KEY_SIZE") opts.make_parser(group, "key_size", metavar="KEY_SIZE")

View File

@ -0,0 +1,51 @@
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIFHDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQI9fSurwMcOA4CAggA
MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECKALBF48zvQnBIIEyKDIy72IMJoZ
4q7LsG0dCSa8oGI/CtAnC9YqRlDj+paWoGKDUkzxnMloUbJkpQlTEYRHXp0xKtdP
IcCjWFqWeQjsaJUlwILNLiliVpbyW/0PLmNQmRSfvLhlZ77rRk08DyLU0mcW2zRX
DuKHuxGhdlmte7EKsNf8czch9hDXqrCLqxlzr86K0pwT40W1r32TgQdX68edluoj
acggWuEzeTTKy1BKkVtlCq63dflgRfSo0as+dYX38wxzC6O6hxKpax277ijoJZHc
QsXxi/zREa+gtVOq9D6Vz5E+MmmIIAzVrXsFe1Uj4wYb3XUSO6WnJ9GlrixqWeu3
9lkOZOEKyyDgIY+twn06kyZBspKnXvQMMPjeiSSeaqI9LA0qpvRsxuWCxyTJ2YZI
s+xab8j5g5RKOmrt1bGtLl66tcrGNP9jYC5pjMNl6fz3c8+oxC0Bun4q+yOA9QzG
4GaiA834x+9wtsEBSjlMB5AMwYH+1ODo6Q+VUAWH1qBvCm/gQT2mvSgcrz6bcGJI
gimfzl/IbqVuVkWl7yFqNN/renE47pvy34Dbymb0FBK/5Gb1FImno3CcAkCuaEJ1
sWdx2Ej0Ezit8v1iJN2q29xlD7MrxB0uPvklUPRlD9RVcDJ15GwBPA8ugN/Fjj50
2BiMJ2/uqBoEnAjMyStINArS5PWL6gthIXenVJ4w0wegBciCsGo4G7UFQ0z/w2Je
7NJ8TjwKdTYJdAfgO5Rr8u6j0ybn72T/+QJfjugNLufRx4sakvPZR90/AFb2YX+L
kgCVS3ySOfom9p5JcxdnI8omelBIi1Qa9xwPKMPaV6oYkqBVjmcDDZocC6qN15PD
jCrgGryV3Fsn5OLYTB+EQDLNqmo+qd1O0pNY2THwD/DGGlx6VhmeQnWdt534g5lo
clQOmLXEeUWIb2u5PanakqNpY5mBQcOJ88/RS+oGAjTGU0e3I1zLb6EN/Ftndjv1
sfEh+HMwHxIWxdnJb6z6m73XJr4z30VGN8e+f1lC8c9SJ9aTQ/9vH3bsaXLW6GFY
DBisBg2/+vMwRSG9PkYrp1p6rGAhwbaofnZE5zApT7PFEX2RVNPU7lgXn84ycRHw
gZ89Mpa9zShL4T1PS8BrKwS7AH/se7ofKW/s8Z9SgngTWj0Efd4hZmn/EenVHBWf
kjAkvKIgGE8FJF1QlmU5dHDFhRiUGXIaB1rYAcwwuwB06fxRqEL3pU6jkHSru3ry
sYaY/cfpd5D5PT+FlxkzAPH1iiC3knXpcotWpJ2iQshsw9ifwg/vVJB0n20+Rxeu
XTgwiT+X5mJNAQUCj6aExWUg+D5gPnJPwFmzAWBGKWrvwI+vI6zIv4MJywzU+Ei8
1lU5rezPovAbGSTwUBPDydhORua0P8tVT8KPMmPJhza6IORTPpzdEOCXCOH17CWg
VWKjYvEul8CdNh4O3CJDU4lN8yn6RXCBPK4NKDea17GCIEBgnOnpFny+jdfNT+Ce
9aNh8ah61vbPag9EM2okmBlbnpkhUO+x8K8prZHZE7qRgUbmn1cJwIP6pNN/263q
S2uKZMnoaT65BaQh9wpgSvWmDup3/lGG/C2+m0k087QBVHMSfpTK9WcZ94BbzoeR
S9rWCU2k/woEUOv3hssY5w==
-----END ENCRYPTED PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIDdTCCAl2gAwIBAgIURm3Wk48Uc3RtqZ0FFxCaE33TvjcwDQYJKoZIhvcNAQEL
BQAwSTELMAkGA1UEBhMCVVMxDTALBgNVBAgMBENhbGkxDTALBgNVBAcMBHRlc3Qx
DTALBgNVBAoMBHRlc3QxDTALBgNVBAMMBHRlc3QwIBcNMjAwODI4MTIyNDU4WhgP
MjI5NDA2MTIxMjI0NThaMEkxCzAJBgNVBAYTAlVTMQ0wCwYDVQQIDARDYWxpMQ0w
CwYDVQQHDAR0ZXN0MQ0wCwYDVQQKDAR0ZXN0MQ0wCwYDVQQDDAR0ZXN0MIIBIjAN
BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvyrgqfiwRh2EcPYk/GFMgF2k8yJq
4mkQcjpWlowp/fL99W/c33ySEtV/LyMJ6LtPAIKN4SambUFcx97pEgJi9YEDLRGW
aN9jznss5AAe03uXN2gizpq9LmdPxr/vmH1DnqdI5MKwa8g9phpe9tT6ik3f2qkm
1V9Ka38GlkHbB+w743ytz20jM6ifTtrX0SuDqDbAppandv5Ix3CHdlllRS/MKNEw
LAs7LVkct0UNTp+soTIhGcASmbf24dvJnO+Msfuqw60mHJpoUP/xDcRGcXnjsgAZ
zAi0UXlV9QiItQeOKxLBHIlMSAEd9oEejPCi6uN+zjKb3De7LUD2Vxu7iwIDAQAB
o1MwUTAdBgNVHQ4EFgQU6tvbiSgA6pujKJBSFw/j+QRZOiwwHwYDVR0jBBgwFoAU
6tvbiSgA6pujKJBSFw/j+QRZOiwwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B
AQsFAAOCAQEAgVa/jUdGqElv3EzxzSqtYkGxmeY5m2aLPKgsUl2zOPWwgyE1Synu
TuFS+B5pyTT1KZ6IDwRQ+hA9jOnEopNK33lVelz7XBuw7485qVidG4o6QH1uo/J9
GlxjM5SCY6yQ4frCI8lCY6+LA0NbI05qtVNTS1zgdOBnC/IOlMFpp0oDaf5FZHxc
Ci1I/g32ES3rvKiAGBY2m6hy138GzYpZTXnKS03MaTfUCFfsOvqq/z2KBCeCd4mH
VDO7adjhw4I7EYYXjmly2um6NaqyXtT6/AARY3JuQgFoW7W3XBV6TCsYmsGSeUTH
JrhnGnHiNi06IuBwOXYZDID+orBMr9NDKw==
-----END CERTIFICATE-----

View File

@ -204,3 +204,9 @@ class TestCert:
x = certs.Cert('') x = certs.Cert('')
x.set_state(a) x.set_state(a)
assert x == c assert x == c
def test_from_store_with_passphrase(self, tdata, tmpdir):
ca = certs.CertStore.from_store(str(tmpdir), "mitmproxy", 2048, "password")
ca.add_cert_file("*", tdata.path("mitmproxy/data/mitmproxy.pem"), "password")
assert ca.get_cert(b"foo", [])

View File

@ -42,11 +42,10 @@ class TestProcessProxyOptions:
assert self.p() assert self.p()
def test_certs(self, tdata): def test_certs(self, tdata):
self.assert_noerr( with pytest.raises(Exception, match="ambiguous option"):
"--cert", self.assert_noerr(
tdata.path("mitmproxy/data/testkey.pem")) "--cert",
with pytest.raises(Exception, match="does not exist"): tdata.path("mitmproxy/data/testkey.pem"))
self.p("--cert", "nonexistent")
class TestProxyServer: class TestProxyServer: