From 8f85f907e3d72b192b9b073e5505075635720282 Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Tue, 3 Jan 2012 22:46:48 +0100 Subject: [PATCH] Issue #13636: Weak ciphers are now disabled by default in the ssl module (except when SSLv2 is explicitly asked for). --- Lib/ssl.py | 12 ++++++++++-- Lib/test/test_ssl.py | 22 +++++++++++++++++++++- Misc/NEWS | 3 +++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/Lib/ssl.py b/Lib/ssl.py index ce9ebdf30a..8137231711 100644 --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -86,8 +86,9 @@ _PROTOCOL_NAMES = { } try: from _ssl import PROTOCOL_SSLv2 + _SSLv2_IF_EXISTS = PROTOCOL_SSLv2 except ImportError: - pass + _SSLv2_IF_EXISTS = None else: _PROTOCOL_NAMES[PROTOCOL_SSLv2] = "SSLv2" @@ -98,6 +99,10 @@ import base64 # for DER-to-PEM translation import traceback import errno +# Disable weak or insecure ciphers by default +# (OpenSSL's default setting is 'DEFAULT:!aNULL:!eNULL') +_DEFAULT_CIPHERS = 'DEFAULT:!aNULL:!eNULL:!LOW:!EXPORT:!SSLv2' + class CertificateError(ValueError): pass @@ -165,7 +170,10 @@ class SSLContext(_SSLContext): __slots__ = ('protocol',) def __new__(cls, protocol, *args, **kwargs): - return _SSLContext.__new__(cls, protocol) + self = _SSLContext.__new__(cls, protocol) + if protocol != _SSLv2_IF_EXISTS: + self.set_ciphers(_DEFAULT_CIPHERS) + return self def __init__(self, protocol): self.protocol = protocol diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index e9fbc8afeb..c6c26bcee3 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -762,10 +762,11 @@ else: try: self.sslconn = self.server.context.wrap_socket( self.sock, server_side=True) - except ssl.SSLError: + except ssl.SSLError as e: # XXX Various errors can have happened here, for example # a mismatching protocol version, an invalid certificate, # or a low-level bug. This should be made more discriminating. + self.server.conn_errors.append(e) if self.server.chatty: handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n") self.running = False @@ -878,12 +879,14 @@ else: self.port = support.bind_port(self.sock) self.flag = None self.active = False + self.conn_errors = [] threading.Thread.__init__(self) self.daemon = True def __enter__(self): self.start(threading.Event()) self.flag.wait() + return self def __exit__(self, *args): self.stop() @@ -1004,6 +1007,7 @@ else: def __enter__(self): self.start(threading.Event()) self.flag.wait() + return self def __exit__(self, *args): if support.verbose: @@ -1604,6 +1608,22 @@ else: t.join() server.close() + def test_default_ciphers(self): + context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) + try: + # Force a set of weak ciphers on our client context + context.set_ciphers("DES") + except ssl.SSLError: + self.skipTest("no DES cipher available") + with ThreadedEchoServer(CERTFILE, + ssl_version=ssl.PROTOCOL_SSLv23, + chatty=False) as server: + with socket.socket() as sock: + s = context.wrap_socket(sock) + with self.assertRaises((OSError, ssl.SSLError)): + s.connect((HOST, server.port)) + self.assertIn("no shared cipher", str(server.conn_errors[0])) + def test_main(verbose=False): if support.verbose: diff --git a/Misc/NEWS b/Misc/NEWS index da9e9de1b6..6e5b7f303a 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -97,6 +97,9 @@ Core and Builtins Library ------- +- Issue #13636: Weak ciphers are now disabled by default in the ssl module + (except when SSLv2 is explicitly asked for). + - Issue #12798: Updated the mimetypes documentation. - Issue #11006: Don't issue low level warning in subprocess when pipe2() fails. -- 2.40.0