summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Heimes <christian@cheimes.de>2013-11-23 14:58:30 (GMT)
committerChristian Heimes <christian@cheimes.de>2013-11-23 14:58:30 (GMT)
commit4c05b472ddd4634138b6abfa857ee37761d33185 (patch)
treeda4b06b3937c1f82f56ecd54e6a999af08e5f326
parent6b2ff98df45d3d1ca389f4ae07a2ef4e08257867 (diff)
downloadcpython-4c05b472ddd4634138b6abfa857ee37761d33185.zip
cpython-4c05b472ddd4634138b6abfa857ee37761d33185.tar.gz
cpython-4c05b472ddd4634138b6abfa857ee37761d33185.tar.bz2
Issue #19689: Add ssl.create_default_context() factory function. It creates
a new SSLContext object with secure default settings.
-rw-r--r--Doc/library/ssl.rst18
-rw-r--r--Lib/ssl.py35
-rw-r--r--Lib/test/test_ssl.py20
-rw-r--r--Misc/NEWS3
4 files changed, 76 insertions, 0 deletions
diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst
index 94bdcef..73aa0a5 100644
--- a/Doc/library/ssl.rst
+++ b/Doc/library/ssl.rst
@@ -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
diff --git a/Lib/ssl.py b/Lib/ssl.py
index e668dc1..880a3d4 100644
--- a/Lib/ssl.py
+++ b/Lib/ssl.py
@@ -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
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
index 722d331..0b7ea47 100644
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -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):
diff --git a/Misc/NEWS b/Misc/NEWS
index ac04743..b7b9b3b 100644
--- 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.