summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/ssl.py13
-rw-r--r--Lib/test/test_ssl.py22
-rw-r--r--Misc/NEWS3
3 files changed, 35 insertions, 3 deletions
diff --git a/Lib/ssl.py b/Lib/ssl.py
index b56a8c8..0282ee9 100644
--- a/Lib/ssl.py
+++ b/Lib/ssl.py
@@ -98,8 +98,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"
@@ -115,6 +116,11 @@ if _ssl.HAS_TLS_UNIQUE:
else:
CHANNEL_BINDING_TYPES = []
+# 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
@@ -181,7 +187,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 a4bcdd0..86d1cd8 100644
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -878,10 +878,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
@@ -999,12 +1000,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()
@@ -1124,6 +1127,7 @@ else:
def __enter__(self):
self.start(threading.Event())
self.flag.wait()
+ return self
def __exit__(self, *args):
if support.verbose:
@@ -1739,6 +1743,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]))
+
@unittest.skipUnless("tls-unique" in ssl.CHANNEL_BINDING_TYPES,
"'tls-unique' channel binding not available")
def test_tls_unique_channel_binding(self):
diff --git a/Misc/NEWS b/Misc/NEWS
index 827aa4e..2df62e5 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -422,6 +422,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 #12715: Add an optional symlinks argument to shutil functions
(copyfile, copymode, copystat, copy, copy2). When that parameter is
true, symlinks aren't dereferenced and the operation instead acts on the