diff options
author | Christian Heimes <christian@cheimes.de> | 2013-11-23 14:58:30 (GMT) |
---|---|---|
committer | Christian Heimes <christian@cheimes.de> | 2013-11-23 14:58:30 (GMT) |
commit | 4c05b472ddd4634138b6abfa857ee37761d33185 (patch) | |
tree | da4b06b3937c1f82f56ecd54e6a999af08e5f326 | |
parent | 6b2ff98df45d3d1ca389f4ae07a2ef4e08257867 (diff) | |
download | cpython-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.rst | 18 | ||||
-rw-r--r-- | Lib/ssl.py | 35 | ||||
-rw-r--r-- | Lib/test/test_ssl.py | 20 | ||||
-rw-r--r-- | Misc/NEWS | 3 |
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 @@ -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): @@ -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. |