Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6a2ba94

Browse files
committed
Issue #21013: Enhance ssl.create_default_context() for server side contexts
Closes #21013 by modfying ssl.create_default_context() to: * Move the restricted ciphers to only apply when using ssl.Purpose.CLIENT_AUTH. The major difference between restricted and not is the lack of RC4 in the restricted. However there are servers that exist that only expose RC4 still. * Switches the default protocol to ssl.PROTOCOL_SSLv23 so that the context will select TLS1.1 or TLS1.2 if it is available. * Add ssl.OP_NO_SSLv3 by default to continue to block SSL3.0 sockets * Add ssl.OP_SINGLE_DH_USE and ssl.OP_SINGLE_ECDG_USE to improve the security of the perfect forward secrecy * Add ssl.OP_CIPHER_SERVER_PREFERENCE so that when used for a server side socket the context will prioritize our ciphers which have been carefully selected to maximize security and performance. * Documents the failure conditions when a SSL3.0 connection is required so that end users can more easily determine if they need to unset ssl.OP_NO_SSLv3.
1 parent 553e108 commit 6a2ba94

4 files changed

Lines changed: 70 additions & 16 deletions

File tree

Doc/library/ssl.rst

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -250,13 +250,13 @@ purposes.
250250
:const:`None`, this function can choose to trust the system's default
251251
CA certificates instead.
252252

253-
The settings in Python 3.4 are: :data:`PROTOCOL_TLSv1` with high encryption
254-
cipher suites without RC4 and without unauthenticated cipher suites.
255-
Passing :data:`~Purpose.SERVER_AUTH` as *purpose* sets
256-
:data:`~SSLContext.verify_mode` to :data:`CERT_REQUIRED` and either
257-
loads CA certificates (when at least one of *cafile*, *capath* or *cadata*
258-
is given) or uses :meth:`SSLContext.load_default_certs` to load default
259-
CA certificates.
253+
The settings in Python 3.4 are: :data:`PROTOCOL_SSLv23`, :data:`OP_NO_SSLv2`,
254+
and :data:`OP_NO_SSLv3` with high encryption cipher suites without RC4 and
255+
without unauthenticated cipher suites. Passing :data:`~Purpose.SERVER_AUTH`
256+
as *purpose* sets :data:`~SSLContext.verify_mode` to :data:`CERT_REQUIRED`
257+
and either loads CA certificates (when at least one of *cafile*, *capath* or
258+
*cadata* is given) or uses :meth:`SSLContext.load_default_certs` to load
259+
default CA certificates.
260260

261261
.. note::
262262
The protocol, options, cipher and other settings may change to more
@@ -266,6 +266,19 @@ purposes.
266266
If your application needs specific settings, you should create a
267267
:class:`SSLContext` and apply the settings yourself.
268268

269+
.. note::
270+
If you find that when certain older clients or servers attempt to connect
271+
with a :class:`SSLContext` created by this function that they get an
272+
error stating "Protocol or cipher suite mismatch", it may be that they
273+
only support SSL3.0 which this function excludes using the
274+
:data:`OP_NO_SSLv3`. SSL3.0 has problematic security due to a number of
275+
poor implementations and it's reliance on MD5 within the protocol. If you
276+
wish to continue to use this function but still allow SSL 3.0 connections
277+
you can re-enable them using::
278+
279+
ctx = ssl.create_default_context(Purpose.CLIENT_AUTH)
280+
ctx.options &= ~ssl.OP_NO_SSLv3
281+
269282
.. versionadded:: 3.4
270283

271284

Lib/ssl.py

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ def _import_symbols(prefix):
179179
'DH+RC4:RSA+RC4:!aNULL:!eNULL:!MD5'
180180
)
181181

182-
# Restricted and more secure ciphers
182+
# Restricted and more secure ciphers for the server side
183183
# This list has been explicitly chosen to:
184184
# * Prefer cipher suites that offer perfect forward secrecy (DHE/ECDHE)
185185
# * Prefer ECDHE over DHE for better performance
@@ -188,7 +188,7 @@ def _import_symbols(prefix):
188188
# * Then Use 3DES as fallback which is secure but slow
189189
# * Disable NULL authentication, NULL encryption, MD5 MACs, DSS, and RC4 for
190190
# security reasons
191-
_RESTRICTED_CIPHERS = (
191+
_RESTRICTED_SERVER_CIPHERS = (
192192
'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:'
193193
'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES:!aNULL:'
194194
'!eNULL:!MD5:!DSS:!RC4'
@@ -404,17 +404,35 @@ def create_default_context(purpose=Purpose.SERVER_AUTH, *, cafile=None,
404404
"""
405405
if not isinstance(purpose, _ASN1Object):
406406
raise TypeError(purpose)
407-
context = SSLContext(PROTOCOL_TLSv1)
407+
408+
context = SSLContext(PROTOCOL_SSLv23)
409+
408410
# SSLv2 considered harmful.
409411
context.options |= OP_NO_SSLv2
412+
413+
# SSLv3 has problematic security and is only required for really old
414+
# clients such as IE6 on Windows XP
415+
context.options |= OP_NO_SSLv3
416+
410417
# disable compression to prevent CRIME attacks (OpenSSL 1.0+)
411418
context.options |= getattr(_ssl, "OP_NO_COMPRESSION", 0)
412-
# disallow ciphers with known vulnerabilities
413-
context.set_ciphers(_RESTRICTED_CIPHERS)
414-
# verify certs and host name in client mode
419+
415420
if purpose == Purpose.SERVER_AUTH:
421+
# verify certs and host name in client mode
416422
context.verify_mode = CERT_REQUIRED
417423
context.check_hostname = True
424+
elif purpose == Purpose.CLIENT_AUTH:
425+
# Prefer the server's ciphers by default so that we get stronger
426+
# encryption
427+
context.options |= getattr(_ssl, "OP_CIPHER_SERVER_PREFERENCE", 0)
428+
429+
# Use single use keys in order to improve forward secrecy
430+
context.options |= getattr(_ssl, "OP_SINGLE_DH_USE", 0)
431+
context.options |= getattr(_ssl, "OP_SINGLE_ECDH_USE", 0)
432+
433+
# disallow ciphers with known vulnerabilities
434+
context.set_ciphers(_RESTRICTED_SERVER_CIPHERS)
435+
418436
if cafile or capath or cadata:
419437
context.load_verify_locations(cafile, capath, cadata)
420438
elif context.verify_mode != CERT_NONE:

Lib/test/test_ssl.py

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1014,23 +1014,43 @@ def test_load_default_certs(self):
10141014

10151015
def test_create_default_context(self):
10161016
ctx = ssl.create_default_context()
1017-
self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1)
1017+
self.assertEqual(ctx.protocol, ssl.PROTOCOL_SSLv23)
10181018
self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
10191019
self.assertTrue(ctx.check_hostname)
10201020
self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2)
1021+
self.assertEqual(
1022+
ctx.options & getattr(ssl, "OP_NO_COMPRESSION", 0),
1023+
getattr(ssl, "OP_NO_COMPRESSION", 0),
1024+
)
10211025

10221026
with open(SIGNING_CA) as f:
10231027
cadata = f.read()
10241028
ctx = ssl.create_default_context(cafile=SIGNING_CA, capath=CAPATH,
10251029
cadata=cadata)
1026-
self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1)
1030+
self.assertEqual(ctx.protocol, ssl.PROTOCOL_SSLv23)
10271031
self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED)
10281032
self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2)
1033+
self.assertEqual(
1034+
ctx.options & getattr(ssl, "OP_NO_COMPRESSION", 0),
1035+
getattr(ssl, "OP_NO_COMPRESSION", 0),
1036+
)
10291037

10301038
ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
1031-
self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1)
1039+
self.assertEqual(ctx.protocol, ssl.PROTOCOL_SSLv23)
10321040
self.assertEqual(ctx.verify_mode, ssl.CERT_NONE)
10331041
self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2)
1042+
self.assertEqual(
1043+
ctx.options & getattr(ssl, "OP_NO_COMPRESSION", 0),
1044+
getattr(ssl, "OP_NO_COMPRESSION", 0),
1045+
)
1046+
self.assertEqual(
1047+
ctx.options & getattr(ssl, "OP_SINGLE_DH_USE", 0),
1048+
getattr(ssl, "OP_SINGLE_DH_USE", 0),
1049+
)
1050+
self.assertEqual(
1051+
ctx.options & getattr(ssl, "OP_SINGLE_ECDH_USE", 0),
1052+
getattr(ssl, "OP_SINGLE_ECDH_USE", 0),
1053+
)
10341054

10351055
def test__create_stdlib_context(self):
10361056
ctx = ssl._create_stdlib_context()

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ Core and Builtins
2424
Library
2525
-------
2626

27+
- Issue #21013: Enhance ssl.create_default_context() when used for server side
28+
sockets to provide better security by default.
29+
2730
- Issue #20633: Replace relative import by absolute import.
2831

2932
- Issue #20980: Stop wrapping exception when using ThreadPool.

0 commit comments

Comments
 (0)