Issue #19689: Add ssl.create_default_context() factory function. It creates

a new SSLContext object with secure default settings.
This commit is contained in:
Christian Heimes 2013-11-23 15:58:30 +01:00
parent 6b2ff98df4
commit 4c05b472dd
4 changed files with 76 additions and 0 deletions

View File

@ -346,6 +346,24 @@ Certificate handling
.. versionchanged:: 3.3 .. versionchanged:: 3.3
This function is now IPv6-compatible. 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) .. function:: DER_cert_to_PEM_cert(DER_cert_bytes)
Given a certificate as a DER-encoded blob of bytes, returns a PEM-encoded Given a certificate as a DER-encoded blob of bytes, returns a PEM-encoded

View File

@ -165,6 +165,13 @@ def _import_symbols(prefix):
# (OpenSSL's default setting is 'DEFAULT:!aNULL:!eNULL') # (OpenSSL's default setting is 'DEFAULT:!aNULL:!eNULL')
_DEFAULT_CIPHERS = 'DEFAULT:!aNULL:!eNULL:!LOW:!EXPORT:!SSLv2' _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): class CertificateError(ValueError):
pass pass
@ -363,6 +370,34 @@ def load_default_certs(self, purpose=Purpose.SERVER_AUTH):
self.set_default_verify_paths() 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): class SSLSocket(socket):
"""This class implements a subtype of socket.socket that wraps """This class implements a subtype of socket.socket that wraps
the underlying OS socket in an SSL context when necessary, and the underlying OS socket in an SSL context when necessary, and

View File

@ -999,6 +999,26 @@ def test_load_default_certs(self):
self.assertRaises(TypeError, ctx.load_default_certs, None) self.assertRaises(TypeError, ctx.load_default_certs, None)
self.assertRaises(TypeError, ctx.load_default_certs, 'SERVER_AUTH') 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): class SSLErrorTests(unittest.TestCase):

View File

@ -68,6 +68,9 @@ Core and Builtins
Library 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 - Issue #19292: Add SSLContext.load_default_certs() to load default root CA
certificates from default stores or system stores. By default the method certificates from default stores or system stores. By default the method
loads CA certs for authentication of server certs. loads CA certs for authentication of server certs.