]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Issue #13636: Weak ciphers are now disabled by default in the ssl module
authorAntoine Pitrou <solipsis@pitrou.net>
Tue, 3 Jan 2012 21:49:08 +0000 (22:49 +0100)
committerAntoine Pitrou <solipsis@pitrou.net>
Tue, 3 Jan 2012 21:49:08 +0000 (22:49 +0100)
(except when SSLv2 is explicitly asked for).

1  2 
Lib/ssl.py
Lib/test/test_ssl.py
Misc/NEWS

diff --cc Lib/ssl.py
index b56a8c849afd5f953b3b06c15c0549efc399944a,813723171188488e0c2f74f1abb3dea011823c35..0282ee924a092e61af185b1c8c94ce15c1604797
@@@ -110,11 -99,11 +111,16 @@@ import base64        # for DER-to-PEM t
  import traceback
  import errno
  
 +if _ssl.HAS_TLS_UNIQUE:
 +    CHANNEL_BINDING_TYPES = ['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
  
index a4bcdd017ea94adc67cf0d508d69862445b2acda,c6c26bcee3af12536a568364566bc43d83d11726..86d1cd8df700dfee5bd8c28902055e1e35047ae1
                  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):
 +            """Test tls-unique channel binding."""
 +            if support.verbose:
 +                sys.stdout.write("\n")
 +
 +            server = ThreadedEchoServer(CERTFILE,
 +                                        certreqs=ssl.CERT_NONE,
 +                                        ssl_version=ssl.PROTOCOL_TLSv1,
 +                                        cacerts=CERTFILE,
 +                                        chatty=True,
 +                                        connectionchatty=False)
 +            with server:
 +                s = ssl.wrap_socket(socket.socket(),
 +                                    server_side=False,
 +                                    certfile=CERTFILE,
 +                                    ca_certs=CERTFILE,
 +                                    cert_reqs=ssl.CERT_NONE,
 +                                    ssl_version=ssl.PROTOCOL_TLSv1)
 +                s.connect((HOST, server.port))
 +                # get the data
 +                cb_data = s.get_channel_binding("tls-unique")
 +                if support.verbose:
 +                    sys.stdout.write(" got channel binding data: {0!r}\n"
 +                                     .format(cb_data))
 +
 +                # check if it is sane
 +                self.assertIsNotNone(cb_data)
 +                self.assertEqual(len(cb_data), 12) # True for TLSv1
 +
 +                # and compare with the peers version
 +                s.write(b"CB tls-unique\n")
 +                peer_data_repr = s.read().strip()
 +                self.assertEqual(peer_data_repr,
 +                                 repr(cb_data).encode("us-ascii"))
 +                s.close()
 +
 +                # now, again
 +                s = ssl.wrap_socket(socket.socket(),
 +                                    server_side=False,
 +                                    certfile=CERTFILE,
 +                                    ca_certs=CERTFILE,
 +                                    cert_reqs=ssl.CERT_NONE,
 +                                    ssl_version=ssl.PROTOCOL_TLSv1)
 +                s.connect((HOST, server.port))
 +                new_cb_data = s.get_channel_binding("tls-unique")
 +                if support.verbose:
 +                    sys.stdout.write(" got another channel binding data: {0!r}\n"
 +                                     .format(new_cb_data))
 +                # is it really unique
 +                self.assertNotEqual(cb_data, new_cb_data)
 +                self.assertIsNotNone(cb_data)
 +                self.assertEqual(len(cb_data), 12) # True for TLSv1
 +                s.write(b"CB tls-unique\n")
 +                peer_data_repr = s.read().strip()
 +                self.assertEqual(peer_data_repr,
 +                                 repr(new_cb_data).encode("us-ascii"))
 +                s.close()
 +
 +        def test_compression(self):
 +            context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
 +            context.load_cert_chain(CERTFILE)
 +            stats = server_params_test(context, context,
 +                                       chatty=True, connectionchatty=True)
 +            if support.verbose:
 +                sys.stdout.write(" got compression: {!r}\n".format(stats['compression']))
 +            self.assertIn(stats['compression'], { None, 'ZLIB', 'RLE' })
 +
 +        @unittest.skipUnless(hasattr(ssl, 'OP_NO_COMPRESSION'),
 +                             "ssl.OP_NO_COMPRESSION needed for this test")
 +        def test_compression_disabled(self):
 +            context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
 +            context.load_cert_chain(CERTFILE)
 +            context.options |= ssl.OP_NO_COMPRESSION
 +            stats = server_params_test(context, context,
 +                                       chatty=True, connectionchatty=True)
 +            self.assertIs(stats['compression'], None)
 +
 +        def test_dh_params(self):
 +            # Check we can get a connection with ephemeral Diffie-Hellman
 +            context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
 +            context.load_cert_chain(CERTFILE)
 +            context.load_dh_params(DHFILE)
 +            context.set_ciphers("kEDH")
 +            stats = server_params_test(context, context,
 +                                       chatty=True, connectionchatty=True)
 +            cipher = stats["cipher"][0]
 +            parts = cipher.split("-")
 +            if "ADH" not in parts and "EDH" not in parts and "DHE" not in parts:
 +                self.fail("Non-DH cipher: " + cipher[0])
 +
  
  def test_main(verbose=False):
      if support.verbose:
diff --cc Misc/NEWS
index 827aa4e32a9b3e80be883da903b71f39ba85f0fc,6e5b7f303aa25b4da468b9bc959c5a1d9c89e761..2df62e5c9a7ebb342182bac3b160e9bfdea4176f
+++ b/Misc/NEWS
@@@ -422,23 -97,13 +422,26 @@@ Core and Builtin
  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
 +  symlink itself (or creates one, if relevant).  Patch by Hynek Schlawack.
 +
 +- Add a flags parameter to select.epoll.
 +
  - Issue #12798: Updated the mimetypes documentation.
  
 +- Issue #13626: Add support for SSL Diffie-Hellman key exchange, through the
 +  SSLContext.load_dh_params() method and the ssl.OP_SINGLE_DH_USE option.
 +
  - Issue #11006: Don't issue low level warning in subprocess when pipe2() fails.
  
 +- Issue #13620: Support for Chrome browser in webbrowser.py Patch contributed
 +  by Arnaud Calmettes.
 +
  - Issue #11829: Fix code execution holes in inspect.getattr_static for
    metaclasses with metaclasses. Patch by Andreas Stührk.