mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
Issue #22641: In asyncio, the default SSL context for client connections is now created using ssl.create_default_context(), for stronger security.
This commit is contained in:
commit
94522ebe38
4 changed files with 60 additions and 17 deletions
|
@ -689,16 +689,17 @@ class _SelectorSslTransport(_SelectorTransport):
|
||||||
if not sslcontext:
|
if not sslcontext:
|
||||||
# Client side may pass ssl=True to use a default
|
# Client side may pass ssl=True to use a default
|
||||||
# context; in that case the sslcontext passed is None.
|
# context; in that case the sslcontext passed is None.
|
||||||
# The default is the same as used by urllib with
|
# The default is secure for client connections.
|
||||||
# cadefault=True.
|
if hasattr(ssl, 'create_default_context'):
|
||||||
if hasattr(ssl, '_create_stdlib_context'):
|
# Python 3.4+: use up-to-date strong settings.
|
||||||
sslcontext = ssl._create_stdlib_context(
|
sslcontext = ssl.create_default_context()
|
||||||
cert_reqs=ssl.CERT_REQUIRED,
|
if not server_hostname:
|
||||||
check_hostname=bool(server_hostname))
|
sslcontext.check_hostname = False
|
||||||
else:
|
else:
|
||||||
# Fallback for Python 3.3.
|
# Fallback for Python 3.3.
|
||||||
sslcontext = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
|
sslcontext = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
|
||||||
sslcontext.options |= ssl.OP_NO_SSLv2
|
sslcontext.options |= ssl.OP_NO_SSLv2
|
||||||
|
sslcontext.options |= ssl.OP_NO_SSLv3
|
||||||
sslcontext.set_default_verify_paths()
|
sslcontext.set_default_verify_paths()
|
||||||
sslcontext.verify_mode = ssl.CERT_REQUIRED
|
sslcontext.verify_mode = ssl.CERT_REQUIRED
|
||||||
|
|
||||||
|
|
|
@ -91,6 +91,13 @@ class SilentWSGIRequestHandler(WSGIRequestHandler):
|
||||||
|
|
||||||
class SilentWSGIServer(WSGIServer):
|
class SilentWSGIServer(WSGIServer):
|
||||||
|
|
||||||
|
request_timeout = 2
|
||||||
|
|
||||||
|
def get_request(self):
|
||||||
|
request, client_addr = super().get_request()
|
||||||
|
request.settimeout(self.request_timeout)
|
||||||
|
return request, client_addr
|
||||||
|
|
||||||
def handle_error(self, request, client_address):
|
def handle_error(self, request, client_address):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -138,7 +145,8 @@ def _run_test_server(*, address, use_ssl=False, server_cls, server_ssl_cls):
|
||||||
httpd = server_class(address, SilentWSGIRequestHandler)
|
httpd = server_class(address, SilentWSGIRequestHandler)
|
||||||
httpd.set_app(app)
|
httpd.set_app(app)
|
||||||
httpd.address = httpd.server_address
|
httpd.address = httpd.server_address
|
||||||
server_thread = threading.Thread(target=httpd.serve_forever)
|
server_thread = threading.Thread(
|
||||||
|
target=lambda: httpd.serve_forever(poll_interval=0.05))
|
||||||
server_thread.start()
|
server_thread.start()
|
||||||
try:
|
try:
|
||||||
yield httpd
|
yield httpd
|
||||||
|
@ -160,12 +168,15 @@ if hasattr(socket, 'AF_UNIX'):
|
||||||
|
|
||||||
class UnixWSGIServer(UnixHTTPServer, WSGIServer):
|
class UnixWSGIServer(UnixHTTPServer, WSGIServer):
|
||||||
|
|
||||||
|
request_timeout = 2
|
||||||
|
|
||||||
def server_bind(self):
|
def server_bind(self):
|
||||||
UnixHTTPServer.server_bind(self)
|
UnixHTTPServer.server_bind(self)
|
||||||
self.setup_environ()
|
self.setup_environ()
|
||||||
|
|
||||||
def get_request(self):
|
def get_request(self):
|
||||||
request, client_addr = super().get_request()
|
request, client_addr = super().get_request()
|
||||||
|
request.settimeout(self.request_timeout)
|
||||||
# Code in the stdlib expects that get_request
|
# Code in the stdlib expects that get_request
|
||||||
# will return a socket and a tuple (host, port).
|
# will return a socket and a tuple (host, port).
|
||||||
# However, this isn't true for UNIX sockets,
|
# However, this isn't true for UNIX sockets,
|
||||||
|
|
|
@ -606,15 +606,43 @@ class EventLoopTestsMixin:
|
||||||
self.assertGreater(pr.nbytes, 0)
|
self.assertGreater(pr.nbytes, 0)
|
||||||
tr.close()
|
tr.close()
|
||||||
|
|
||||||
|
def _dummy_ssl_create_context(self, purpose=ssl.Purpose.SERVER_AUTH, *,
|
||||||
|
cafile=None, capath=None, cadata=None):
|
||||||
|
"""
|
||||||
|
A ssl.create_default_context() replacement that doesn't enable
|
||||||
|
cert validation.
|
||||||
|
"""
|
||||||
|
self.assertEqual(purpose, ssl.Purpose.SERVER_AUTH)
|
||||||
|
return test_utils.dummy_ssl_context()
|
||||||
|
|
||||||
|
def _test_create_ssl_connection(self, httpd, create_connection,
|
||||||
|
check_sockname=True):
|
||||||
|
conn_fut = create_connection(ssl=test_utils.dummy_ssl_context())
|
||||||
|
self._basetest_create_ssl_connection(conn_fut, check_sockname)
|
||||||
|
|
||||||
|
# With ssl=True, ssl.create_default_context() should be called
|
||||||
|
with mock.patch('ssl.create_default_context',
|
||||||
|
side_effect=self._dummy_ssl_create_context) as m:
|
||||||
|
conn_fut = create_connection(ssl=True)
|
||||||
|
self._basetest_create_ssl_connection(conn_fut, check_sockname)
|
||||||
|
self.assertEqual(m.call_count, 1)
|
||||||
|
|
||||||
|
# With the real ssl.create_default_context(), certificate
|
||||||
|
# validation will fail
|
||||||
|
with self.assertRaises(ssl.SSLError) as cm:
|
||||||
|
conn_fut = create_connection(ssl=True)
|
||||||
|
self._basetest_create_ssl_connection(conn_fut, check_sockname)
|
||||||
|
|
||||||
|
self.assertEqual(cm.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
|
||||||
|
|
||||||
@unittest.skipIf(ssl is None, 'No ssl module')
|
@unittest.skipIf(ssl is None, 'No ssl module')
|
||||||
def test_create_ssl_connection(self):
|
def test_create_ssl_connection(self):
|
||||||
with test_utils.run_test_server(use_ssl=True) as httpd:
|
with test_utils.run_test_server(use_ssl=True) as httpd:
|
||||||
conn_fut = self.loop.create_connection(
|
create_connection = functools.partial(
|
||||||
|
self.loop.create_connection,
|
||||||
lambda: MyProto(loop=self.loop),
|
lambda: MyProto(loop=self.loop),
|
||||||
*httpd.address,
|
*httpd.address)
|
||||||
ssl=test_utils.dummy_ssl_context())
|
self._test_create_ssl_connection(httpd, create_connection)
|
||||||
|
|
||||||
self._basetest_create_ssl_connection(conn_fut)
|
|
||||||
|
|
||||||
@unittest.skipIf(ssl is None, 'No ssl module')
|
@unittest.skipIf(ssl is None, 'No ssl module')
|
||||||
@unittest.skipUnless(hasattr(socket, 'AF_UNIX'), 'No UNIX Sockets')
|
@unittest.skipUnless(hasattr(socket, 'AF_UNIX'), 'No UNIX Sockets')
|
||||||
|
@ -624,13 +652,13 @@ class EventLoopTestsMixin:
|
||||||
check_sockname = not osx_tiger()
|
check_sockname = not osx_tiger()
|
||||||
|
|
||||||
with test_utils.run_test_unix_server(use_ssl=True) as httpd:
|
with test_utils.run_test_unix_server(use_ssl=True) as httpd:
|
||||||
conn_fut = self.loop.create_unix_connection(
|
create_connection = functools.partial(
|
||||||
lambda: MyProto(loop=self.loop),
|
self.loop.create_unix_connection,
|
||||||
httpd.address,
|
lambda: MyProto(loop=self.loop), httpd.address,
|
||||||
ssl=test_utils.dummy_ssl_context(),
|
|
||||||
server_hostname='127.0.0.1')
|
server_hostname='127.0.0.1')
|
||||||
|
|
||||||
self._basetest_create_ssl_connection(conn_fut, check_sockname)
|
self._test_create_ssl_connection(httpd, create_connection,
|
||||||
|
check_sockname)
|
||||||
|
|
||||||
def test_create_connection_local_addr(self):
|
def test_create_connection_local_addr(self):
|
||||||
with test_utils.run_test_server() as httpd:
|
with test_utils.run_test_server() as httpd:
|
||||||
|
|
|
@ -175,6 +175,9 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #22641: In asyncio, the default SSL context for client connections
|
||||||
|
is now created using ssl.create_default_context(), for stronger security.
|
||||||
|
|
||||||
- Issue #21338: Add silent mode for compileall. quiet parameters of
|
- Issue #21338: Add silent mode for compileall. quiet parameters of
|
||||||
compile_{dir, file, path} functions now have a multilevel value. Also,
|
compile_{dir, file, path} functions now have a multilevel value. Also,
|
||||||
-q option of the CLI now have a multilevel value. Patch by Thomas Kluyver.
|
-q option of the CLI now have a multilevel value. Patch by Thomas Kluyver.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue