]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Issue #19689: Add ssl.create_default_context() factory function. It creates
authorChristian Heimes <christian@cheimes.de>
Sat, 23 Nov 2013 14:58:30 +0000 (15:58 +0100)
committerChristian Heimes <christian@cheimes.de>
Sat, 23 Nov 2013 14:58:30 +0000 (15:58 +0100)
a new SSLContext object with secure default settings.

Doc/library/ssl.rst
Lib/ssl.py
Lib/test/test_ssl.py
Misc/NEWS

index 94bdcef67b1ff7a7af5785b6c9a932a10867079f..73aa0a5a3274449591a98c3a5c5bc8cdfb06f0b1 100644 (file)
@@ -346,6 +346,24 @@ Certificate handling
    .. versionchanged:: 3.3
       This function is now IPv6-compatible.
 
+.. function:: create_default_context(purpose=Purpose.SERVER_AUTH, cafile=None, capath=None, cadata=None)
+
+   Create a :class:`SSLContext` with default settings.
+
+   The current settings are: :data:`PROTOCOL_TLSv1` with high encryption
+   cipher suites without RC4 and without unauthenticated cipher suites. The
+   *purpose* :data:`Purpose.SERVER_AUTH` sets verify_mode to
+   :data:`CERT_REQUIRED` and either loads CA certs (when at least one of
+   *cafile*, *capath* or *cadata* is given) or uses
+   :meth:`SSLContext.load_default_certs` to load default CA certs.
+
+   .. note::
+      The protocol, options, cipher and other settings may change to more
+      restrictive values anytime without prior deprecation. The values
+      represent a fair balance between maximum compatibility and security.
+
+   .. versionadded:: 3.4
+
 .. function:: DER_cert_to_PEM_cert(DER_cert_bytes)
 
    Given a certificate as a DER-encoded blob of bytes, returns a PEM-encoded
index e668dc181f0d526b6c9b5c7ffe752736cbcb0f4c..880a3d4af6795cc6ffaf07d5d7864c7d58ca467d 100644 (file)
@@ -165,6 +165,13 @@ else:
 # (OpenSSL's default setting is 'DEFAULT:!aNULL:!eNULL')
 _DEFAULT_CIPHERS = 'DEFAULT:!aNULL:!eNULL:!LOW:!EXPORT:!SSLv2'
 
+# restricted and more secure ciphers
+# HIGH: high encryption cipher suites with key length >= 128 bits (no MD5)
+# !aNULL: only authenticated cipher suites (no anonymous DH)
+# !RC4: no RC4 streaming cipher, RC4 is broken
+# !DSS: RSA is preferred over DSA
+_RESTRICTED_CIPHERS = 'HIGH:!aNULL:!RC4:!DSS'
+
 
 class CertificateError(ValueError):
     pass
@@ -363,6 +370,34 @@ class SSLContext(_SSLContext):
             self.set_default_verify_paths()
 
 
+def create_default_context(purpose=Purpose.SERVER_AUTH, *, cafile=None,
+                           capath=None, cadata=None):
+    """Create a SSLContext object with default settings.
+
+    NOTE: The protocol and settings may change anytime without prior
+          deprecation. The values represent a fair balance between maximum
+          compatibility and security.
+    """
+    if not isinstance(purpose, _ASN1Object):
+        raise TypeError(purpose)
+    context = SSLContext(PROTOCOL_TLSv1)
+    # SSLv2 considered harmful.
+    context.options |= OP_NO_SSLv2
+    # disallow ciphers with known vulnerabilities
+    context.set_ciphers(_RESTRICTED_CIPHERS)
+    # verify certs in client mode
+    if purpose == Purpose.SERVER_AUTH:
+        context.verify_mode = CERT_REQUIRED
+    if cafile or capath or cadata:
+        context.load_verify_locations(cafile, capath, cadata)
+    elif context.verify_mode != CERT_NONE:
+        # no explicit cafile, capath or cadata but the verify mode is
+        # CERT_OPTIONAL or CERT_REQUIRED. Let's try to load default system
+        # root CA certificates for the given purpose. This may fail silently.
+        context.load_default_certs(purpose)
+    return context
+
+
 class SSLSocket(socket):
     """This class implements a subtype of socket.socket that wraps
     the underlying OS socket in an SSL context when necessary, and
index 722d331f273ed4f352628c1da022495ae9eef3da..0b7ea477d68e996b6e5cf39c106b2d2f185347d5 100644 (file)
@@ -999,6 +999,26 @@ class ContextTests(unittest.TestCase):
         self.assertRaises(TypeError, ctx.load_default_certs, None)
         self.assertRaises(TypeError, ctx.load_default_certs, 'SERVER_AUTH')
 
+    def test_create_default_context(self):
+        ctx = ssl.create_default_context()
+        self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1)
+        self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
+        self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2)
+
+        with open(SIGNING_CA) as f:
+            cadata = f.read()
+        ctx = ssl.create_default_context(cafile=SIGNING_CA, capath=CAPATH,
+                                         cadata=cadata)
+        self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1)
+        self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
+        self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2)
+
+        ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
+        self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1)
+        self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
+        self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2)
+
+
 
 class SSLErrorTests(unittest.TestCase):
 
index ac04743df5384767eb2fbc4b0be4c0ab60267a4e..b7b9b3b1dd4d8cc81de0782aca7cb02e602a36df 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -68,6 +68,9 @@ Core and Builtins
 Library
 -------
 
+- Issue #19689: Add ssl.create_default_context() factory function. It creates
+  a new SSLContext object with secure default settings.
+
 - Issue #19292: Add SSLContext.load_default_certs() to load default root CA
   certificates from default stores or system stores. By default the method
   loads CA certs for authentication of server certs.