TLS intercept self-signed servers using `--insecure-tls-interception` (#1446)
* Disable mandatory TLS verification with --insecure * Fix lint issues * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Fix type issues with `cert_der_to_dict` * Flake8 exception * Fix `cert_der_to_dict` where file may not be writter before it is gets used by `_test_decode_cert` * Silence lint issue due to pylint bug * Rename flag to `--insecure-tls-interception` * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Reuse `DEFAULT_SSL_CONTEXT_OPTIONS` * # noqa: WPS436 --------- Co-authored-by: d4x <d_4xfe@proton.me> Co-authored-by: d4xfe <168460626+d4xfe@users.noreply.github.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
39854e1d79
commit
50046d3f68
75
README.md
75
README.md
|
@ -71,6 +71,7 @@
|
|||
- [Plugin Ordering](#plugin-ordering)
|
||||
- [End-to-End Encryption](#end-to-end-encryption)
|
||||
- [TLS Interception](#tls-interception)
|
||||
- [Insecure TLS Interception](#insecure-tls-interception)
|
||||
- [TLS Interception With Docker](#tls-interception-with-docker)
|
||||
- [GROUT (NGROK Alternative)](#grout-ngrok-alternative)
|
||||
- [Grout Usage](#grout-usage)
|
||||
|
@ -1241,6 +1242,13 @@ cached file instead of plain text.
|
|||
Now use CA flags with other
|
||||
[plugin examples](#plugin-examples) to see them work with `https` traffic.
|
||||
|
||||
## Insecure TLS Interception
|
||||
|
||||
To intercept TLS traffic from a server using a self-signed certificate
|
||||
add the `--insecure-tls-interception` flag to disable mandatory TLS certificate validation.
|
||||
|
||||
NOTE: This flag disables certificate check for all servers.
|
||||
|
||||
## TLS Interception With Docker
|
||||
|
||||
Important notes about TLS Interception with Docker container:
|
||||
|
@ -2510,17 +2518,16 @@ To run standalone benchmark for `proxy.py`, use the following command from repo
|
|||
|
||||
```console
|
||||
❯ proxy -h
|
||||
usage: -m [-h] [--enable-proxy-protocol] [--threadless] [--threaded]
|
||||
[--num-workers NUM_WORKERS] [--enable-events] [--enable-conn-pool]
|
||||
[--key-file KEY_FILE] [--cert-file CERT_FILE]
|
||||
[--client-recvbuf-size CLIENT_RECVBUF_SIZE]
|
||||
[--server-recvbuf-size SERVER_RECVBUF_SIZE]
|
||||
[--max-sendbuf-size MAX_SENDBUF_SIZE] [--timeout TIMEOUT]
|
||||
[--tunnel-hostname TUNNEL_HOSTNAME] [--tunnel-port TUNNEL_PORT]
|
||||
usage: -m [-h] [--tunnel-hostname TUNNEL_HOSTNAME] [--tunnel-port TUNNEL_PORT]
|
||||
[--tunnel-username TUNNEL_USERNAME]
|
||||
[--tunnel-ssh-key TUNNEL_SSH_KEY]
|
||||
[--tunnel-ssh-key-passphrase TUNNEL_SSH_KEY_PASSPHRASE]
|
||||
[--tunnel-remote-port TUNNEL_REMOTE_PORT]
|
||||
[--tunnel-remote-port TUNNEL_REMOTE_PORT] [--threadless]
|
||||
[--threaded] [--num-workers NUM_WORKERS] [--enable-events]
|
||||
[--enable-proxy-protocol] [--enable-conn-pool] [--key-file KEY_FILE]
|
||||
[--cert-file CERT_FILE] [--client-recvbuf-size CLIENT_RECVBUF_SIZE]
|
||||
[--server-recvbuf-size SERVER_RECVBUF_SIZE]
|
||||
[--max-sendbuf-size MAX_SENDBUF_SIZE] [--timeout TIMEOUT]
|
||||
[--local-executor LOCAL_EXECUTOR] [--backlog BACKLOG]
|
||||
[--hostname HOSTNAME] [--hostnames HOSTNAMES [HOSTNAMES ...]]
|
||||
[--port PORT] [--ports PORTS [PORTS ...]] [--port-file PORT_FILE]
|
||||
|
@ -2533,9 +2540,9 @@ usage: -m [-h] [--enable-proxy-protocol] [--threadless] [--threaded]
|
|||
[--work-klass WORK_KLASS] [--pid-file PID_FILE] [--openssl OPENSSL]
|
||||
[--data-dir DATA_DIR] [--ssh-listener-klass SSH_LISTENER_KLASS]
|
||||
[--disable-http-proxy] [--disable-headers DISABLE_HEADERS]
|
||||
[--ca-key-file CA_KEY_FILE] [--ca-cert-dir CA_CERT_DIR]
|
||||
[--ca-cert-file CA_CERT_FILE] [--ca-file CA_FILE]
|
||||
[--ca-signing-key-file CA_SIGNING_KEY_FILE]
|
||||
[--ca-key-file CA_KEY_FILE] [--insecure-tls-interception]
|
||||
[--ca-cert-dir CA_CERT_DIR] [--ca-cert-file CA_CERT_FILE]
|
||||
[--ca-file CA_FILE] [--ca-signing-key-file CA_SIGNING_KEY_FILE]
|
||||
[--auth-plugin AUTH_PLUGIN] [--cache-requests]
|
||||
[--cache-by-content-type] [--cache-dir CACHE_DIR]
|
||||
[--proxy-pool PROXY_POOL] [--enable-web-server]
|
||||
|
@ -2549,13 +2556,25 @@ usage: -m [-h] [--enable-proxy-protocol] [--threadless] [--threaded]
|
|||
[--filtered-client-ips FILTERED_CLIENT_IPS]
|
||||
[--filtered-url-regex-config FILTERED_URL_REGEX_CONFIG]
|
||||
|
||||
proxy.py v2.4.4rc6.dev191+gef5a8922
|
||||
proxy.py v2.4.5
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
--enable-proxy-protocol
|
||||
Default: False. If used, will enable proxy protocol.
|
||||
Only version 1 is currently supported.
|
||||
--tunnel-hostname TUNNEL_HOSTNAME
|
||||
Default: None. Remote hostname or IP address to which
|
||||
SSH tunnel will be established.
|
||||
--tunnel-port TUNNEL_PORT
|
||||
Default: 22. SSH port of the remote host.
|
||||
--tunnel-username TUNNEL_USERNAME
|
||||
Default: None. Username to use for establishing SSH
|
||||
tunnel.
|
||||
--tunnel-ssh-key TUNNEL_SSH_KEY
|
||||
Default: None. Private key path in pem format
|
||||
--tunnel-ssh-key-passphrase TUNNEL_SSH_KEY_PASSPHRASE
|
||||
Default: None. Private key passphrase
|
||||
--tunnel-remote-port TUNNEL_REMOTE_PORT
|
||||
Default: 8899. Remote port which will be forwarded
|
||||
locally for proxy.
|
||||
--threadless Default: True. Enabled by default on Python 3.8+ (mac,
|
||||
linux). When disabled a new thread is spawned to
|
||||
handle each client connection.
|
||||
|
@ -2567,6 +2586,9 @@ options:
|
|||
--enable-events Default: False. Enables core to dispatch lifecycle
|
||||
events. Plugins can be used to subscribe for core
|
||||
events.
|
||||
--enable-proxy-protocol
|
||||
Default: False. If used, will enable proxy protocol.
|
||||
Only version 1 is currently supported.
|
||||
--enable-conn-pool Default: False. (WIP) Enable upstream connection
|
||||
pooling.
|
||||
--key-file KEY_FILE Default: None. Server key file to enable end-to-end
|
||||
|
@ -2588,21 +2610,6 @@ options:
|
|||
--timeout TIMEOUT Default: 10.0. Number of seconds after which an
|
||||
inactive connection must be dropped. Inactivity is
|
||||
defined by no data sent or received by the client.
|
||||
--tunnel-hostname TUNNEL_HOSTNAME
|
||||
Default: None. Remote hostname or IP address to which
|
||||
SSH tunnel will be established.
|
||||
--tunnel-port TUNNEL_PORT
|
||||
Default: 22. SSH port of the remote host.
|
||||
--tunnel-username TUNNEL_USERNAME
|
||||
Default: None. Username to use for establishing SSH
|
||||
tunnel.
|
||||
--tunnel-ssh-key TUNNEL_SSH_KEY
|
||||
Default: None. Private key path in pem format
|
||||
--tunnel-ssh-key-passphrase TUNNEL_SSH_KEY_PASSPHRASE
|
||||
Default: None. Private key passphrase
|
||||
--tunnel-remote-port TUNNEL_REMOTE_PORT
|
||||
Default: 8899. Remote port which will be forwarded
|
||||
locally for proxy.
|
||||
--local-executor LOCAL_EXECUTOR
|
||||
Default: 1. Enabled by default. Use 0 to disable. When
|
||||
enabled acceptors will make use of local (same
|
||||
|
@ -2668,6 +2675,8 @@ options:
|
|||
Default: None. CA key to use for signing dynamically
|
||||
generated HTTPS certificates. If used, must also pass
|
||||
--ca-cert-file and --ca-signing-key-file
|
||||
--insecure-tls-interception
|
||||
Default: False. Disables certificate verification
|
||||
--ca-cert-dir CA_CERT_DIR
|
||||
Default: ~/.proxy/certificates. Directory to store
|
||||
dynamically generated certificates. Also see --ca-key-
|
||||
|
@ -2676,9 +2685,9 @@ options:
|
|||
Default: None. Signing certificate to use for signing
|
||||
dynamically generated HTTPS certificates. If used,
|
||||
must also pass --ca-key-file and --ca-signing-key-file
|
||||
--ca-file CA_FILE Default: /Users/abhinavsingh/Dev/proxy.py/.venv31013/l
|
||||
ib/python3.10/site-packages/certifi/cacert.pem.
|
||||
Provide path to custom CA bundle for peer certificate
|
||||
--ca-file CA_FILE Default: /Users/abhinavsingh/Dev/proxy.py/.venv3118/li
|
||||
b/python3.11/site-packages/certifi/cacert.pem. Provide
|
||||
path to custom CA bundle for peer certificate
|
||||
verification
|
||||
--ca-signing-key-file CA_SIGNING_KEY_FILE
|
||||
Default: None. CA signing key to use for dynamic
|
||||
|
|
|
@ -91,6 +91,7 @@ DEFAULT_BASIC_AUTH = None
|
|||
DEFAULT_MAX_SEND_SIZE = 64 * 1024
|
||||
DEFAULT_BUFFER_SIZE = 128 * 1024
|
||||
DEFAULT_CA_CERT_DIR = None
|
||||
DEFAULT_INSECURE_TLS_INTERCEPTION = False
|
||||
DEFAULT_CA_CERT_FILE = None
|
||||
DEFAULT_CA_KEY_FILE = None
|
||||
DEFAULT_CA_SIGNING_KEY_FILE = None
|
||||
|
|
|
@ -12,17 +12,21 @@
|
|||
|
||||
utils
|
||||
"""
|
||||
import os
|
||||
import ssl
|
||||
import sys
|
||||
import socket
|
||||
import logging
|
||||
import argparse
|
||||
import tempfile
|
||||
import functools
|
||||
import ipaddress
|
||||
import contextlib
|
||||
from types import TracebackType
|
||||
from typing import Any, Dict, List, Type, Tuple, Callable, Optional
|
||||
|
||||
import _ssl # noqa: WPS436
|
||||
|
||||
from .types import HostPort
|
||||
from .constants import (
|
||||
CRLF, COLON, HTTP_1_1, IS_WINDOWS, WHITESPACE, DEFAULT_TIMEOUT,
|
||||
|
@ -36,6 +40,23 @@ if not IS_WINDOWS: # pragma: no cover
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def cert_der_to_dict(der: Optional[bytes]) -> Dict[str, Any]:
|
||||
"""Parse a DER formatted certificate to a python dict"""
|
||||
if not der:
|
||||
return {}
|
||||
with tempfile.NamedTemporaryFile(delete=False) as cert_file:
|
||||
pem = ssl.DER_cert_to_PEM_cert(der)
|
||||
cert_file.write(pem.encode())
|
||||
cert_file.flush()
|
||||
cert_file.seek(0)
|
||||
try:
|
||||
certificate = _ssl._test_decode_cert(cert_file.name)
|
||||
finally:
|
||||
cert_file.close()
|
||||
os.remove(cert_file.name)
|
||||
return certificate or {}
|
||||
|
||||
|
||||
def tls_interception_enabled(flags: argparse.Namespace) -> bool:
|
||||
return flags.ca_key_file is not None and \
|
||||
flags.ca_cert_dir is not None and \
|
||||
|
|
|
@ -15,6 +15,7 @@ from .types import tcpConnectionTypes
|
|||
from .connection import TcpConnection, TcpConnectionUninitializedException
|
||||
from ...common.types import HostPort, TcpOrTlsSocket
|
||||
from ...common.utils import new_socket_connection
|
||||
from ...common.constants import DEFAULT_SSL_CONTEXT_OPTIONS
|
||||
|
||||
|
||||
class TcpServerConnection(TcpConnection):
|
||||
|
@ -51,12 +52,12 @@ class TcpServerConnection(TcpConnection):
|
|||
# Ref https://github.com/PyCQA/pylint/issues/3691
|
||||
verify_mode: ssl.VerifyMode = ssl.VerifyMode.CERT_REQUIRED, # pylint: disable=E1101
|
||||
) -> None:
|
||||
ctx = ssl.create_default_context(
|
||||
ssl.Purpose.SERVER_AUTH,
|
||||
cafile=ca_file,
|
||||
ctx = ssl.create_default_context(ssl.Purpose.SERVER_AUTH, cafile=ca_file)
|
||||
ctx.options |= DEFAULT_SSL_CONTEXT_OPTIONS
|
||||
# pylint: disable=E1101
|
||||
ctx.check_hostname = (
|
||||
False if verify_mode == ssl.VerifyMode.CERT_NONE else hostname is not None
|
||||
)
|
||||
ctx.options |= ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 | ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1
|
||||
ctx.check_hostname = hostname is not None
|
||||
ctx.verify_mode = verify_mode
|
||||
self.connection.setblocking(True)
|
||||
self._conn = ctx.wrap_socket(
|
||||
|
|
|
@ -21,7 +21,7 @@ import socket
|
|||
import logging
|
||||
import threading
|
||||
import subprocess
|
||||
from typing import Any, Dict, List, Union, Optional, cast
|
||||
from typing import Any, Dict, List, Union, Optional
|
||||
|
||||
from .plugin import HttpProxyBasePlugin
|
||||
from ..parser import HttpParser, httpParserTypes, httpParserStates
|
||||
|
@ -35,7 +35,7 @@ from ...common.pki import gen_csr, sign_csr, gen_public_key
|
|||
from ...core.event import eventNames
|
||||
from ...common.flag import flags
|
||||
from ...common.types import Readables, Writables, Descriptors
|
||||
from ...common.utils import text_
|
||||
from ...common.utils import text_, cert_der_to_dict
|
||||
from ...core.connection import (
|
||||
TcpServerConnection, TcpConnectionUninitializedException,
|
||||
)
|
||||
|
@ -43,7 +43,8 @@ from ...common.constants import (
|
|||
COMMA, DEFAULT_CA_FILE, PLUGIN_PROXY_AUTH, DEFAULT_CA_CERT_DIR,
|
||||
DEFAULT_CA_KEY_FILE, DEFAULT_CA_CERT_FILE, DEFAULT_DISABLE_HEADERS,
|
||||
PROXY_AGENT_HEADER_VALUE, DEFAULT_DISABLE_HTTP_PROXY,
|
||||
DEFAULT_CA_SIGNING_KEY_FILE, DEFAULT_HTTP_PROXY_ACCESS_LOG_FORMAT,
|
||||
DEFAULT_CA_SIGNING_KEY_FILE, DEFAULT_INSECURE_TLS_INTERCEPTION,
|
||||
DEFAULT_HTTP_PROXY_ACCESS_LOG_FORMAT,
|
||||
DEFAULT_HTTPS_PROXY_ACCESS_LOG_FORMAT,
|
||||
)
|
||||
|
||||
|
@ -74,6 +75,13 @@ flags.add_argument(
|
|||
'HTTPS certificates. If used, must also pass --ca-cert-file and --ca-signing-key-file',
|
||||
)
|
||||
|
||||
flags.add_argument(
|
||||
'--insecure-tls-interception',
|
||||
action='store_true',
|
||||
default=DEFAULT_INSECURE_TLS_INTERCEPTION,
|
||||
help='Default: False. Disables certificate verification',
|
||||
)
|
||||
|
||||
flags.add_argument(
|
||||
'--ca-cert-dir',
|
||||
type=str,
|
||||
|
@ -760,10 +768,17 @@ class HttpProxyPlugin(HttpProtocolHandlerPlugin):
|
|||
assert isinstance(self.upstream.connection, socket.socket)
|
||||
do_close = False
|
||||
try:
|
||||
# pylint: disable=E1101
|
||||
verify_mode = (
|
||||
ssl.VerifyMode.CERT_NONE
|
||||
if self.flags.insecure_tls_interception
|
||||
else ssl.VerifyMode.CERT_REQUIRED
|
||||
)
|
||||
self.upstream.wrap(
|
||||
text_(self.request.host),
|
||||
self.flags.ca_file,
|
||||
as_non_blocking=True,
|
||||
verify_mode=verify_mode,
|
||||
)
|
||||
except ssl.SSLCertVerificationError: # Server raised certificate verification error
|
||||
# When --disable-interception-on-ssl-cert-verification-error flag is on,
|
||||
|
@ -802,7 +817,7 @@ class HttpProxyPlugin(HttpProtocolHandlerPlugin):
|
|||
try:
|
||||
# TODO: Perform async certificate generation
|
||||
generated_cert = self.generate_upstream_certificate(
|
||||
cast(Dict[str, Any], self.upstream.connection.getpeercert()),
|
||||
cert_der_to_dict(self.upstream.connection.getpeercert(True)),
|
||||
)
|
||||
self.client.wrap(self.flags.ca_signing_key_file, generated_cert)
|
||||
except subprocess.TimeoutExpired as e: # Popen communicate timeout
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
proxy.py
|
||||
~~~~~~~~
|
||||
⚡⚡⚡ Fast, Lightweight, Pluggable, TLS interception capable proxy server focused on
|
||||
Network monitoring, controls & Application development, testing, debugging.
|
||||
|
||||
:copyright: (c) 2013-present by Abhinav Singh and contributors.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
from typing import Any
|
||||
|
||||
|
||||
# pylint: disable=line-too-long
|
||||
test_cert_bytes = b"0\x82\x03\xa30\x82\x02\x8b\xa0\x03\x02\x01\x02\x02\x14PE\x01\x8c\xa6\xea\xd8#\xcf\x90\xb0D\xc7\x04\xde\x9b9Y\xf3 0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x0b\x05\x000a1\x0b0\t\x06\x03U\x04\x06\x13\x02as1\x0b0\t\x06\x03U\x04\x08\x0c\x02as1\x0b0\t\x06\x03U\x04\x07\x0c\x02as1\x0b0\t\x06\x03U\x04\n\x0c\x02as1\x0b0\t\x06\x03U\x04\x0b\x0c\x02as1\x0b0\t\x06\x03U\x04\x03\x0c\x02as1\x110\x0f\x06\t*\x86H\x86\xf7\r\x01\t\x01\x16\x02as0\x1e\x17\r240429125057Z\x17\r250429125057Z0a1\x0b0\t\x06\x03U\x04\x06\x13\x02as1\x0b0\t\x06\x03U\x04\x08\x0c\x02as1\x0b0\t\x06\x03U\x04\x07\x0c\x02as1\x0b0\t\x06\x03U\x04\n\x0c\x02as1\x0b0\t\x06\x03U\x04\x0b\x0c\x02as1\x0b0\t\x06\x03U\x04\x03\x0c\x02as1\x110\x0f\x06\t*\x86H\x86\xf7\r\x01\t\x01\x16\x02as0\x82\x01\"0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x01\x05\x00\x03\x82\x01\x0f\x000\x82\x01\n\x02\x82\x01\x01\x00\xee\xcbU\xe3\xc4]\x83\xb9\x9d\xb1(v0\x18\x18\xc3\x00\x96\xc0\x0f\xc29\x84\xe7/W\xc7\x0b\xec\xdf\x9d-\xec\xd9\x876\xe5m\xda\x96\xea\xb0\xc6\x00\x7f\xb6\x93;\xd6\x1bK`\xd4Hc<\xa0g\xe5Q[\xe3\xe1\xd1DD5\x9b\x12\xdf\xd0\xd0\xc6X\xc9\x98\xc9\xb1\x81\xf5\xa2\x12\xaa\xc1\xb0\x80\xe8)R\xa7\xed\xe3P6\x82\x05\xbcA4\x91\xbcs?\xc2\xf2\xfd-\xe65'};\xa7E\xb2yN\x0fiO7\x82-`CX\xdb\xe0\x9c\xd7\x8e\x00N\nAu\xac/\xb3o\xcaG;\xa4\x8d\xca\x92\xe3F\x96\xe5\xbd\x1dq\xf6\xa5\x9f\xc5@I=\xfc\x1cl\x81\xb3y\x93FaPa^\x08\x0f\x80t\xb8J\xfd\xb8]\xd52\xf5\x9bE\xe8J:\x08\x8c\x98m0\xba\x85\x1b\xb6\x97\xe5\xba4\xe3nU\xa5\xc7\xeb\xde_z\x1a(j\xa7\xeb\x8a\xb4\xe1'?\x91\x80MhG=y\xc7\xf1|\xcaJ@\xae\xc4'\xd6\xd6}L\xf4\x91NV`\x98\x80\xef%\xa2hq\x05s\x02\x03\x01\x00\x01\xa3S0Q0\x1d\x06\x03U\x1d\x0e\x04\x16\x04\x14\xc6\xa4,\xe5\xe3\x15j\x18\x15@Xw!\xdd\xbf\xc6\xe5\xf0vG0\x1f\x06\x03U\x1d#\x04\x180\x16\x80\x14\xc6\xa4,\xe5\xe3\x15j\x18\x15@Xw!\xdd\xbf\xc6\xe5\xf0vG0\x0f\x06\x03U\x1d\x13\x01\x01\xff\x04\x050\x03\x01\x01\xff0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x0b\x05\x00\x03\x82\x01\x01\x00\xacx\xeb\x02\x8a\xd3\x966\xb73\xfb\n\x1eb\ng\xda\x84\x18\x97P\xb4\x7f\x8a\xbd\x82\xf3\x1b\xe8k%\xcc\x0f\xbd\x7fB\xb9\x1df|-k\x01\xf3\x89\x08r\xb9\x93\xf5?Z\x16\xff\x0f\x97\x91b#\xef$I\x11\x9e\x16\xb2J\x97\xd1\x0e\xd6\xabD\xca@\xe7\xb3\xbe\x84S\x1e\xdb;\x9b\xc4\xf4\x18\xf4\x9a\x1b\xcej\xe0qmx\xe4N?K\n.p\xa8\xa6\xfa\xb0\xf7y\xe8\x0f\xbd\x0c216\xb0\xa1d\x1f\x7f3\xa1l?\xbe\x9a\x06\xed]\x1a\x00\xab\xb4e\x13:\x17\x1b\x88\x8e\xcaqp\"\x8f\xa6\xf7\x06J?`\xe0\xf7\xce\xf8K\x08\x15\x18\xa1\xc4\xb5\xd9hB\xb0\xc6\\\xae?\xa9\x83FL\x8cm\xd1\xad^\xf0\xa5:\x8e\x97\x07\xd2\xd0l\x0e\x9d\x01\xa00c)\xae\xd0@\xefr\xe7,\xb7[\xd3H\xfe1\xfb\xa9|\xd0\xac\xc6i\x98\xe5\xd5\xd1\xf2\x97<\xf9\xe1?=\x93\xfaM\x86\xa2\x9dy\xdeZj\x93&\xa6\x84d\x07a\xbf\xd6\xdde\xaa)\t\xd6\x0e\x99\x85K" # noqa: WPS342, E501
|
||||
|
||||
|
||||
def mock_cert(_: Any) -> Any:
|
||||
return test_cert_bytes
|
||||
|
||||
|
||||
cert_dict = {
|
||||
'subject': (
|
||||
(('countryName', 'as'),),
|
||||
(('stateOrProvinceName', 'as'),),
|
||||
(('localityName', 'as'),),
|
||||
(('organizationName', 'as'),),
|
||||
(('organizationalUnitName', 'as'),),
|
||||
(('commonName', 'as'),),
|
||||
(('emailAddress', 'as'),),
|
||||
),
|
||||
'issuer': (
|
||||
(('countryName', 'as'),),
|
||||
(('stateOrProvinceName', 'as'),),
|
||||
(('localityName', 'as'),),
|
||||
(('organizationName', 'as'),),
|
||||
(('organizationalUnitName', 'as'),),
|
||||
(('commonName', 'as'),),
|
||||
(('emailAddress', 'as'),),
|
||||
),
|
||||
'version': 3,
|
||||
'serialNumber': '5045018CA6EAD823CF90B044C704DE9B3959F320',
|
||||
'notBefore': 'Apr 29 12:50:57 2024 GMT',
|
||||
'notAfter': 'Apr 29 12:50:57 2025 GMT',
|
||||
}
|
|
@ -30,6 +30,7 @@ from proxy.http.responses import PROXY_TUNNEL_ESTABLISHED_RESPONSE_PKT
|
|||
from proxy.core.connection import TcpServerConnection
|
||||
from proxy.common.constants import DEFAULT_CA_FILE
|
||||
from ...test_assertions import Assertions
|
||||
from ...certificates.test_cert_data import mock_cert
|
||||
|
||||
|
||||
class TestHttpProxyTlsInterception(Assertions):
|
||||
|
@ -59,6 +60,7 @@ class TestHttpProxyTlsInterception(Assertions):
|
|||
# Used for server side wrapping
|
||||
self.mock_ssl_context = mocker.patch('ssl.create_default_context')
|
||||
upstream_tls_sock = mock.MagicMock(spec=ssl.SSLSocket)
|
||||
upstream_tls_sock.getpeercert = mock_cert
|
||||
self.mock_ssl_context.return_value.wrap_socket.return_value = upstream_tls_sock
|
||||
|
||||
# Used for client wrapping
|
||||
|
@ -75,8 +77,8 @@ class TestHttpProxyTlsInterception(Assertions):
|
|||
|
||||
# Do not mock the original wrap method
|
||||
self.mock_server_conn.return_value.wrap.side_effect = \
|
||||
lambda x, y, as_non_blocking: TcpServerConnection.wrap(
|
||||
self.mock_server_conn.return_value, x, y, as_non_blocking=as_non_blocking,
|
||||
lambda x, y, as_non_blocking, verify_mode: TcpServerConnection.wrap(
|
||||
self.mock_server_conn.return_value, x, y, as_non_blocking=as_non_blocking, verify_mode=verify_mode,
|
||||
)
|
||||
|
||||
type(self.mock_server_conn.return_value).connection = \
|
||||
|
|
|
@ -29,6 +29,7 @@ from proxy.http.responses import (
|
|||
from proxy.core.connection import TcpServerConnection
|
||||
from .utils import get_plugin_by_test_name
|
||||
from ..test_assertions import Assertions
|
||||
from ..certificates.test_cert_data import mock_cert
|
||||
|
||||
|
||||
class TestHttpProxyPluginExamplesWithTlsInterception(Assertions):
|
||||
|
@ -78,8 +79,8 @@ class TestHttpProxyPluginExamplesWithTlsInterception(Assertions):
|
|||
self.protocol_handler.initialize()
|
||||
|
||||
self.server = self.mock_server_conn.return_value
|
||||
|
||||
self.server_ssl_connection = mocker.MagicMock(spec=ssl.SSLSocket)
|
||||
self.server_ssl_connection.getpeercert = mock_cert
|
||||
self.mock_ssl_context.return_value.wrap_socket.return_value = self.server_ssl_connection
|
||||
self.client_ssl_connection = mocker.MagicMock(spec=ssl.SSLSocket)
|
||||
self.mock_ssl_wrap.return_value.wrap_socket.return_value = self.client_ssl_connection
|
||||
|
@ -97,8 +98,8 @@ class TestHttpProxyPluginExamplesWithTlsInterception(Assertions):
|
|||
|
||||
# Do not mock the original wrap method
|
||||
self.server.wrap.side_effect = \
|
||||
lambda x, y, as_non_blocking: TcpServerConnection.wrap(
|
||||
self.server, x, y, as_non_blocking=as_non_blocking,
|
||||
lambda x, y, as_non_blocking, verify_mode: TcpServerConnection.wrap(
|
||||
self.server, x, y, as_non_blocking=as_non_blocking, verify_mode=verify_mode,
|
||||
)
|
||||
|
||||
self.server.has_buffer.side_effect = has_buffer
|
||||
|
|
Loading…
Reference in New Issue