mirror of
https://github.com/mitmproxy/mitmproxy.git
synced 2024-11-26 23:00:40 +00:00
Warn if TLS version is unsupported by OpenSSL (#7139)
* warn if TLS version is unsupported by OpenSSL fix #7138 * [autofix.ci] apply automated fixes * coverage++ --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
36df8c8fac
commit
f2500dd0ae
@ -20,6 +20,9 @@
|
||||
([#7073](https://github.com/mitmproxy/mitmproxy/pull/7073), @mhils)
|
||||
- Fix a bug where fragmented QUIC client hellos were not handled properly.
|
||||
([#7067](https://github.com/mitmproxy/mitmproxy/pull/7067), @errorxyz)
|
||||
- Emit a warning when users configure a TLS version that is not supported by the
|
||||
current OpenSSL build.
|
||||
([#7139](https://github.com/mitmproxy/mitmproxy/pull/7139), @mhils)
|
||||
- Fix a bug where mitmproxy would crash when receiving `STOP_SENDING` QUIC frames.
|
||||
([#7119](https://github.com/mitmproxy/mitmproxy/pull/7119), @mhils)
|
||||
- mitmproxy now officially supports Python 3.13.
|
||||
|
@ -24,6 +24,8 @@ from mitmproxy.proxy.layers import modes
|
||||
from mitmproxy.proxy.layers import quic
|
||||
from mitmproxy.proxy.layers import tls as proxy_tls
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# We manually need to specify this, otherwise OpenSSL may select a non-HTTP2 cipher by default.
|
||||
# https://ssl-config.mozilla.org/#config=old
|
||||
|
||||
@ -441,7 +443,7 @@ class TlsConfig:
|
||||
else None,
|
||||
)
|
||||
if self.certstore.default_ca.has_expired():
|
||||
logging.warning(
|
||||
logger.warning(
|
||||
"The mitmproxy certificate authority has expired!\n"
|
||||
"Please delete all CA-related files in your ~/.mitmproxy folder.\n"
|
||||
"The CA will be regenerated automatically after restarting mitmproxy.\n"
|
||||
@ -484,6 +486,34 @@ class TlsConfig:
|
||||
f"Invalid ECDH curve: {ecdh_curve!r}"
|
||||
) from e
|
||||
|
||||
if "tls_version_client_min" in updated:
|
||||
self._warn_unsupported_version("tls_version_client_min", True)
|
||||
if "tls_version_client_max" in updated:
|
||||
self._warn_unsupported_version("tls_version_client_max", False)
|
||||
if "tls_version_server_min" in updated:
|
||||
self._warn_unsupported_version("tls_version_server_min", True)
|
||||
if "tls_version_server_max" in updated:
|
||||
self._warn_unsupported_version("tls_version_server_max", False)
|
||||
|
||||
def _warn_unsupported_version(self, attribute: str, warn_unbound: bool):
|
||||
val = net_tls.Version[getattr(ctx.options, attribute)]
|
||||
supported_versions = [
|
||||
v for v in net_tls.Version if net_tls.is_supported_version(v)
|
||||
]
|
||||
supported_versions_str = ", ".join(v.name for v in supported_versions)
|
||||
|
||||
if val is net_tls.Version.UNBOUNDED:
|
||||
if warn_unbound:
|
||||
logger.info(
|
||||
f"{attribute} has been set to {val.name}. Note that your "
|
||||
f"OpenSSL build only supports the following TLS versions: {supported_versions_str}"
|
||||
)
|
||||
elif val not in supported_versions:
|
||||
logger.warning(
|
||||
f"{attribute} has been set to {val.name}, which is not supported by the current OpenSSL build. "
|
||||
f"The current build only supports the following versions: {supported_versions_str}"
|
||||
)
|
||||
|
||||
def get_cert(self, conn_context: context.Context) -> certs.CertStoreEntry:
|
||||
"""
|
||||
This function determines the Common Name (CN), Subject Alternative Names (SANs) and Organization Name
|
||||
|
@ -3,6 +3,7 @@ import threading
|
||||
from collections.abc import Callable
|
||||
from collections.abc import Iterable
|
||||
from enum import Enum
|
||||
from functools import cache
|
||||
from functools import lru_cache
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
@ -58,6 +59,22 @@ DEFAULT_MAX_VERSION = Version.UNBOUNDED
|
||||
DEFAULT_OPTIONS = SSL.OP_CIPHER_SERVER_PREFERENCE | SSL.OP_NO_COMPRESSION
|
||||
|
||||
|
||||
@cache
|
||||
def is_supported_version(version: Version):
|
||||
client_ctx = SSL.Context(SSL.TLS_CLIENT_METHOD)
|
||||
client_ctx.set_min_proto_version(version.value)
|
||||
client_ctx.set_max_proto_version(version.value)
|
||||
client_conn = SSL.Connection(client_ctx)
|
||||
client_conn.set_connect_state()
|
||||
|
||||
try:
|
||||
client_conn.recv(4096)
|
||||
except SSL.WantReadError:
|
||||
return True
|
||||
except SSL.Error:
|
||||
return False
|
||||
|
||||
|
||||
class MasterSecretLogger:
|
||||
def __init__(self, filename: Path):
|
||||
self.filename = filename.expanduser()
|
||||
|
@ -1,4 +1,5 @@
|
||||
import ipaddress
|
||||
import logging
|
||||
import ssl
|
||||
import time
|
||||
from pathlib import Path
|
||||
@ -107,6 +108,29 @@ class TestTlsConfig:
|
||||
)
|
||||
assert ta.certstore.certs
|
||||
|
||||
def test_configure_tls_version(self, caplog):
|
||||
caplog.set_level(logging.INFO)
|
||||
ta = tlsconfig.TlsConfig()
|
||||
with taddons.context(ta) as tctx:
|
||||
for attr in [
|
||||
"tls_version_client_min",
|
||||
"tls_version_client_max",
|
||||
"tls_version_server_min",
|
||||
"tls_version_server_max",
|
||||
]:
|
||||
caplog.clear()
|
||||
tctx.configure(ta, **{attr: "SSL3"})
|
||||
assert (
|
||||
f"{attr} has been set to SSL3, "
|
||||
"which is not supported by the current OpenSSL build."
|
||||
) in caplog.text
|
||||
caplog.clear()
|
||||
tctx.configure(ta, tls_version_client_min="UNBOUNDED")
|
||||
assert (
|
||||
"tls_version_client_min has been set to UNBOUNDED. "
|
||||
"Note that your OpenSSL build only supports the following TLS versions"
|
||||
) in caplog.text
|
||||
|
||||
def test_get_cert(self, tdata):
|
||||
"""Test that we generate a certificate matching the connection's context."""
|
||||
ta = tlsconfig.TlsConfig()
|
||||
|
@ -1,5 +1,6 @@
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from OpenSSL import crypto
|
||||
from OpenSSL import SSL
|
||||
|
||||
@ -7,6 +8,13 @@ from mitmproxy import certs
|
||||
from mitmproxy.net import tls
|
||||
|
||||
|
||||
@pytest.mark.parametrize("version", [tls.Version.UNBOUNDED, tls.Version.SSL3])
|
||||
def test_supported(version):
|
||||
# wild assumption: test environments should not do SSLv3 by default.
|
||||
expected_support = version is tls.Version.UNBOUNDED
|
||||
assert tls.is_supported_version(version) == expected_support
|
||||
|
||||
|
||||
def test_make_master_secret_logger():
|
||||
assert tls.make_master_secret_logger(None) is None
|
||||
assert isinstance(tls.make_master_secret_logger("filepath"), tls.MasterSecretLogger)
|
||||
|
Loading…
Reference in New Issue
Block a user