Skip to content

Commit 201d02c

Browse files
abhinavsinghs-t-e-v-e-n-kpre-commit-ci[bot]
authored
Deprecate usage of ssl.wrap_socket in favour of SSLContext.wrap_socket (#1443)
* Remove use of ssl.wrap_socket ssl.wrap_socket() has been deprecated since Python 3.7, and isn't recommended for use, and further, has been removed in Python 3.12. ssl.SSLContext().wrap_socket() is the new path forward, so switch the one callsite and the two test cases to use it instead. * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Fix `SSLContext.wrap_socket` params and reusable `DEFAULT_SSL_CONTEXT_OPTIONS` * Fix test cases * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Fix e2e tests??? --------- Co-authored-by: Steve Kowalik <steven@wedontsleep.org> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 6ac5aed commit 201d02c

File tree

5 files changed

+38
-29
lines changed

5 files changed

+38
-29
lines changed

proxy/common/constants.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
:license: BSD, see LICENSE for more details.
1010
"""
1111
import os
12+
import ssl
1213
import sys
1314
import time
1415
import pathlib
@@ -156,6 +157,9 @@ def _env_threadless_compliant() -> bool:
156157
DEFAULT_SELECTOR_SELECT_TIMEOUT = 25 / 1000
157158
DEFAULT_WAIT_FOR_TASKS_TIMEOUT = 1 / 1000
158159
DEFAULT_INACTIVE_CONN_CLEANUP_TIMEOUT = 1 # in seconds
160+
DEFAULT_SSL_CONTEXT_OPTIONS = (
161+
ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 | ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1
162+
)
159163

160164
DEFAULT_DEVTOOLS_DOC_URL = 'http://proxy'
161165
DEFAULT_DEVTOOLS_FRAME_ID = secrets.token_hex(8)

proxy/common/utils.py

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
from .types import HostPort
2727
from .constants import (
2828
CRLF, COLON, HTTP_1_1, IS_WINDOWS, WHITESPACE, DEFAULT_TIMEOUT,
29-
DEFAULT_THREADLESS, PROXY_AGENT_HEADER_VALUE,
29+
DEFAULT_THREADLESS, PROXY_AGENT_HEADER_VALUE, DEFAULT_SSL_CONTEXT_OPTIONS,
3030
)
3131

3232

@@ -219,20 +219,11 @@ def wrap_socket(
219219
cafile: Optional[str] = None,
220220
) -> ssl.SSLSocket:
221221
"""Use this to upgrade server_side socket to TLS."""
222-
ctx = ssl.create_default_context(
223-
ssl.Purpose.CLIENT_AUTH,
224-
cafile=cafile,
225-
)
226-
ctx.options |= ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 | ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1
222+
ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH, cafile=cafile)
223+
ctx.options |= DEFAULT_SSL_CONTEXT_OPTIONS
227224
ctx.verify_mode = ssl.CERT_NONE
228-
ctx.load_cert_chain(
229-
certfile=certfile,
230-
keyfile=keyfile,
231-
)
232-
return ctx.wrap_socket(
233-
conn,
234-
server_side=True,
235-
)
225+
ctx.load_cert_chain(certfile=certfile, keyfile=keyfile)
226+
return ctx.wrap_socket(conn, server_side=True)
236227

237228

238229
def new_socket_connection(

proxy/core/connection/client.py

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@
99
:license: BSD, see LICENSE for more details.
1010
"""
1111
import ssl
12-
from typing import Optional
12+
from typing import Any, Dict, Optional
1313

1414
from .types import tcpConnectionTypes
1515
from .connection import TcpConnection, TcpConnectionUninitializedException
1616
from ...common.types import HostPort, TcpOrTlsSocket
17+
from ...common.constants import DEFAULT_SSL_CONTEXT_OPTIONS
1718

1819

1920
class TcpClientConnection(TcpConnection):
@@ -42,11 +43,19 @@ def connection(self) -> TcpOrTlsSocket:
4243
def wrap(self, keyfile: str, certfile: str) -> None:
4344
self.connection.setblocking(True)
4445
self.flush()
45-
self._conn = ssl.wrap_socket(
46-
self.connection,
47-
server_side=True,
48-
certfile=certfile,
49-
keyfile=keyfile,
50-
ssl_version=ssl.PROTOCOL_TLS,
46+
ctx = ssl.SSLContext(
47+
protocol=(
48+
ssl.PROTOCOL_TLS_CLIENT
49+
if self.tag == 'server'
50+
else ssl.PROTOCOL_TLS_SERVER
51+
),
5152
)
53+
ctx.options |= DEFAULT_SSL_CONTEXT_OPTIONS
54+
ctx.load_cert_chain(certfile=certfile, keyfile=keyfile)
55+
assert self.addr
56+
kwargs: Dict[str, Any] = {'server_side': True}
57+
if self.tag == 'server':
58+
assert self.addr
59+
kwargs['server_hostname'] = self.addr[0]
60+
self._conn = ctx.wrap_socket(self.connection, **kwargs)
5261
self.connection.setblocking(False)

tests/http/proxy/test_http_proxy_tls_interception.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,9 @@ async def test_e2e(self, mocker: MockerFixture) -> None:
6262
self.mock_ssl_context.return_value.wrap_socket.return_value = upstream_tls_sock
6363

6464
# Used for client wrapping
65-
self.mock_ssl_wrap = mocker.patch('ssl.wrap_socket')
65+
self.mock_ssl_wrap = mocker.patch('ssl.SSLContext')
6666
client_tls_sock = mock.MagicMock(spec=ssl.SSLSocket)
67-
self.mock_ssl_wrap.return_value = client_tls_sock
67+
self.mock_ssl_wrap.return_value.wrap_socket.return_value = client_tls_sock
6868

6969
plain_connection = mock.MagicMock(spec=socket.socket)
7070

@@ -251,13 +251,18 @@ async def asyncReturn(val: T) -> T:
251251
)
252252
assert self.flags.ca_cert_dir is not None
253253
self.mock_ssl_wrap.assert_called_with(
254-
self._conn,
255-
server_side=True,
254+
protocol=ssl.PROTOCOL_TLS_SERVER,
255+
)
256+
self.mock_ssl_wrap.return_value.load_cert_chain(
256257
keyfile=self.flags.ca_signing_key_file,
257258
certfile=HttpProxyPlugin.generated_cert_file_path(
258-
self.flags.ca_cert_dir, host,
259+
self.flags.ca_cert_dir,
260+
host,
259261
),
260-
ssl_version=ssl.PROTOCOL_TLS,
262+
)
263+
self.mock_ssl_wrap.return_value.wrap_socket.assert_called_with(
264+
self._conn,
265+
server_side=True,
261266
)
262267
self.assertEqual(self._conn.setblocking.call_count, 2)
263268
self.assertEqual(

tests/plugin/test_http_proxy_plugins_with_tls_interception.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def _setUp(self, request: Any, mocker: MockerFixture) -> None:
4646
'proxy.http.proxy.server.TcpServerConnection',
4747
)
4848
self.mock_ssl_context = mocker.patch('ssl.create_default_context')
49-
self.mock_ssl_wrap = mocker.patch('ssl.wrap_socket')
49+
self.mock_ssl_wrap = mocker.patch('ssl.SSLContext')
5050

5151
self.mock_sign_csr.return_value = True
5252
self.mock_gen_csr.return_value = True
@@ -82,7 +82,7 @@ def _setUp(self, request: Any, mocker: MockerFixture) -> None:
8282
self.server_ssl_connection = mocker.MagicMock(spec=ssl.SSLSocket)
8383
self.mock_ssl_context.return_value.wrap_socket.return_value = self.server_ssl_connection
8484
self.client_ssl_connection = mocker.MagicMock(spec=ssl.SSLSocket)
85-
self.mock_ssl_wrap.return_value = self.client_ssl_connection
85+
self.mock_ssl_wrap.return_value.wrap_socket.return_value = self.client_ssl_connection
8686

8787
def has_buffer() -> bool:
8888
return cast(bool, self.server.queue.called)

0 commit comments

Comments
 (0)