Issue #19689: Add ssl.create_default_context() factory function. It creates
a new SSLContext object with secure default settings.
This commit is contained in:
parent
6b2ff98df4
commit
4c05b472dd
|
@ -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
|
||||
|
|
35
Lib/ssl.py
35
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
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue