Skip to content

Commit e983252

Browse files
authored
bpo-43998: Default to TLS 1.2 and increase cipher suite security (GH-25778)
The ssl module now has more secure default settings. Ciphers without forward secrecy or SHA-1 MAC are disabled by default. Security level 2 prohibits weak RSA, DH, and ECC keys with less than 112 bits of security. :class:`~ssl.SSLContext` defaults to minimum protocol version TLS 1.2. Settings are based on Hynek Schlawack's research. ``` $ openssl version OpenSSL 1.1.1k FIPS 25 Mar 2021 $ openssl ciphers -v '@SECLEVEL=2:ECDH+AESGCM:ECDH+CHACHA20:ECDH+AES:DHE+AES:!aNULL:!eNULL:!aDSS:!SHA1:!AESCCM' TLS_AES_256_GCM_SHA384 TLSv1.3 Kx=any Au=any Enc=AESGCM(256) Mac=AEAD TLS_CHACHA20_POLY1305_SHA256 TLSv1.3 Kx=any Au=any Enc=CHACHA20/POLY1305(256) Mac=AEAD TLS_AES_128_GCM_SHA256 TLSv1.3 Kx=any Au=any Enc=AESGCM(128) Mac=AEAD TLS_AES_128_CCM_SHA256 TLSv1.3 Kx=any Au=any Enc=AESCCM(128) Mac=AEAD ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256) Mac=AEAD ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(128) Mac=AEAD ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(128) Mac=AEAD ECDHE-ECDSA-CHACHA20-POLY1305 TLSv1.2 Kx=ECDH Au=ECDSA Enc=CHACHA20/POLY1305(256) Mac=AEAD ECDHE-RSA-CHACHA20-POLY1305 TLSv1.2 Kx=ECDH Au=RSA Enc=CHACHA20/POLY1305(256) Mac=AEAD ECDHE-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA384 ECDHE-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA384 ECDHE-ECDSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(128) Mac=SHA256 ECDHE-RSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA256 DHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=DH Au=RSA Enc=AESGCM(256) Mac=AEAD DHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=DH Au=RSA Enc=AESGCM(128) Mac=AEAD DHE-RSA-AES256-SHA256 TLSv1.2 Kx=DH Au=RSA Enc=AES(256) Mac=SHA256 DHE-RSA-AES128-SHA256 TLSv1.2 Kx=DH Au=RSA Enc=AES(128) Mac=SHA256 ``` Signed-off-by: Christian Heimes <[email protected]>
1 parent 50c21ad commit e983252

File tree

8 files changed

+88
-18
lines changed

8 files changed

+88
-18
lines changed

Doc/library/ssl.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1509,6 +1509,14 @@ to speed up repeated connections from the same clients.
15091509
context class will either require :data:`PROTOCOL_TLS_CLIENT` or
15101510
:data:`PROTOCOL_TLS_SERVER` protocol in the future.
15111511

1512+
.. versionchanged:: 3.10
1513+
1514+
The default cipher suites now include only secure AES and ChaCha20
1515+
ciphers with forward secrecy and security level 2. RSA and DH keys with
1516+
less than 2048 bits and ECC keys with less than 224 bits are prohibited.
1517+
:data:`PROTOCOL_TLS`, :data:`PROTOCOL_TLS_CLIENT`, and
1518+
:data:`PROTOCOL_TLS_SERVER` use TLS 1.2 as minimum TLS version.
1519+
15121520

15131521
:class:`SSLContext` objects have the following methods and attributes:
15141522

Doc/using/configure.rst

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -441,12 +441,16 @@ Security Options
441441

442442
* ``python`` (default): use Python's preferred selection;
443443
* ``openssl``: leave OpenSSL's defaults untouched;
444-
* *STRING*: use a custom string, PROTOCOL_SSLv2 ignores the setting.
444+
* *STRING*: use a custom string
445445

446446
See the :mod:`ssl` module.
447447

448448
.. versionadded:: 3.7
449449

450+
.. versionchanged:: 3.10
451+
452+
The settings ``python`` and *STRING* also set TLS 1.2 as minimum
453+
protocol version.
450454

451455
macOS Options
452456
-------------

Doc/whatsnew/3.10.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1105,6 +1105,13 @@ Added option to create MPTCP sockets with ``IPPROTO_MPTCP``
11051105
ssl
11061106
---
11071107
1108+
The ssl module now has more secure default settings. Ciphers without forward
1109+
secrecy or SHA-1 MAC are disabled by default. Security level 2 prohibits
1110+
weak RSA, DH, and ECC keys with less than 112 bits of security.
1111+
:class:`~ssl.SSLContext` defaults to minimum protocol version TLS 1.2.
1112+
Settings are based on Hynek Schlawack's research.
1113+
(Contributed by Christian Heimes in :issue:`43998`.)
1114+
11081115
Add a *timeout* parameter to the :func:`ssl.get_server_certificate` function.
11091116
(Contributed by Zackery Spytz in :issue:`31870`.)
11101117

Lib/test/test_nntplib.py

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ class SSLError(Exception):
3737

3838
class NetworkedNNTPTestsMixin:
3939

40+
ssl_context = None
41+
4042
def test_welcome(self):
4143
welcome = self.server.getwelcome()
4244
self.assertEqual(str, type(welcome))
@@ -273,18 +275,21 @@ def is_connected():
273275
return False
274276
return True
275277

278+
kwargs = dict(
279+
timeout=support.INTERNET_TIMEOUT,
280+
usenetrc=False
281+
)
282+
if self.ssl_context is not None:
283+
kwargs["ssl_context"] = self.ssl_context
284+
276285
try:
277-
server = self.NNTP_CLASS(self.NNTP_HOST,
278-
timeout=support.INTERNET_TIMEOUT,
279-
usenetrc=False)
286+
server = self.NNTP_CLASS(self.NNTP_HOST, **kwargs)
280287
with server:
281288
self.assertTrue(is_connected())
282289
self.assertTrue(server.help())
283290
self.assertFalse(is_connected())
284291

285-
server = self.NNTP_CLASS(self.NNTP_HOST,
286-
timeout=support.INTERNET_TIMEOUT,
287-
usenetrc=False)
292+
server = self.NNTP_CLASS(self.NNTP_HOST, **kwargs)
288293
with server:
289294
server.quit()
290295
self.assertFalse(is_connected())
@@ -316,16 +321,21 @@ class NetworkedNNTPTests(NetworkedNNTPTestsMixin, unittest.TestCase):
316321
@classmethod
317322
def setUpClass(cls):
318323
support.requires("network")
324+
kwargs = dict(
325+
timeout=support.INTERNET_TIMEOUT,
326+
usenetrc=False
327+
)
328+
if cls.ssl_context is not None:
329+
kwargs["ssl_context"] = cls.ssl_context
319330
with socket_helper.transient_internet(cls.NNTP_HOST):
320331
try:
321-
cls.server = cls.NNTP_CLASS(cls.NNTP_HOST,
322-
timeout=support.INTERNET_TIMEOUT,
323-
usenetrc=False)
332+
cls.server = cls.NNTP_CLASS(cls.NNTP_HOST, **kwargs)
324333
except SSLError as ssl_err:
325334
# matches "[SSL: DH_KEY_TOO_SMALL] dh key too small"
326335
if re.search(r'(?i)KEY.TOO.SMALL', ssl_err.reason):
327336
raise unittest.SkipTest(f"{cls} got {ssl_err} connecting "
328337
f"to {cls.NNTP_HOST!r}")
338+
print(cls.NNTP_HOST)
329339
raise
330340
except EOF_ERRORS:
331341
raise unittest.SkipTest(f"{cls} got EOF error on connecting "
@@ -358,6 +368,9 @@ class NetworkedNNTP_SSLTests(NetworkedNNTPTests):
358368
# Disabled as the connection will already be encrypted.
359369
test_starttls = None
360370

371+
ssl_context = ssl._create_unverified_context()
372+
ssl_context.set_ciphers("DEFAULT")
373+
ssl_context.maximum_version = ssl.TLSVersion.TLSv1_2
361374

362375
#
363376
# Non-networked tests using a local server (or something mocking it).
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
The :mod:`ssl` module sets more secure cipher suites defaults. Ciphers
2+
without forward secrecy and with SHA-1 MAC are disabled by default. Security
3+
level 2 prohibits weak RSA, DH, and ECC keys with less than 112 bits of
4+
security. :class:`~ssl.SSLContext` defaults to minimum protocol version TLS
5+
1.2. Settings are based on Hynek Schlawack's research.

Modules/_ssl.c

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -152,15 +152,27 @@ extern const SSL_METHOD *TLSv1_2_method(void);
152152
#ifndef PY_SSL_DEFAULT_CIPHER_STRING
153153
#error "Py_SSL_DEFAULT_CIPHERS 0 needs Py_SSL_DEFAULT_CIPHER_STRING"
154154
#endif
155+
#ifndef PY_SSL_MIN_PROTOCOL
156+
#define PY_SSL_MIN_PROTOCOL TLS1_2_VERSION
157+
#endif
155158
#elif PY_SSL_DEFAULT_CIPHERS == 1
156159
/* Python custom selection of sensible cipher suites
157-
* DEFAULT: OpenSSL's default cipher list. Since 1.0.2 the list is in sensible order.
160+
* @SECLEVEL=2: security level 2 with 112 bits minimum security (e.g. 2048 bits RSA key)
161+
* ECDH+*: enable ephemeral elliptic curve Diffie-Hellman
162+
* DHE+*: fallback to ephemeral finite field Diffie-Hellman
163+
* encryption order: AES AEAD (GCM), ChaCha AEAD, AES CBC
158164
* !aNULL:!eNULL: really no NULL ciphers
159-
* !MD5:!3DES:!DES:!RC4:!IDEA:!SEED: no weak or broken algorithms on old OpenSSL versions.
160165
* !aDSS: no authentication with discrete logarithm DSA algorithm
161-
* !SRP:!PSK: no secure remote password or pre-shared key authentication
166+
* !SHA1: no weak SHA1 MAC
167+
* !AESCCM: no CCM mode, it's uncommon and slow
168+
*
169+
* Based on Hynek's excellent blog post (update 2021-02-11)
170+
* https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
162171
*/
163-
#define PY_SSL_DEFAULT_CIPHER_STRING "DEFAULT:!aNULL:!eNULL:!MD5:!3DES:!DES:!RC4:!IDEA:!SEED:!aDSS:!SRP:!PSK"
172+
#define PY_SSL_DEFAULT_CIPHER_STRING "@SECLEVEL=2:ECDH+AESGCM:ECDH+CHACHA20:ECDH+AES:DHE+AES:!aNULL:!eNULL:!aDSS:!SHA1:!AESCCM"
173+
#ifndef PY_SSL_MIN_PROTOCOL
174+
#define PY_SSL_MIN_PROTOCOL TLS1_2_VERSION
175+
#endif
164176
#elif PY_SSL_DEFAULT_CIPHERS == 2
165177
/* Ignored in SSLContext constructor, only used to as _ssl.DEFAULT_CIPHER_STRING */
166178
#define PY_SSL_DEFAULT_CIPHER_STRING SSL_DEFAULT_CIPHER_LIST
@@ -3095,8 +3107,25 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version)
30953107
ERR_clear_error();
30963108
PyErr_SetString(get_state_ctx(self)->PySSLErrorObject,
30973109
"No cipher can be selected.");
3098-
return NULL;
3110+
goto error;
30993111
}
3112+
#ifdef PY_SSL_MIN_PROTOCOL
3113+
switch(proto_version) {
3114+
case PY_SSL_VERSION_TLS:
3115+
case PY_SSL_VERSION_TLS_CLIENT:
3116+
case PY_SSL_VERSION_TLS_SERVER:
3117+
result = SSL_CTX_set_min_proto_version(ctx, PY_SSL_MIN_PROTOCOL);
3118+
if (result == 0) {
3119+
PyErr_Format(PyExc_ValueError,
3120+
"Failed to set minimum protocol 0x%x",
3121+
PY_SSL_MIN_PROTOCOL);
3122+
goto error;
3123+
}
3124+
break;
3125+
default:
3126+
break;
3127+
}
3128+
#endif
31003129

31013130
/* Set SSL_MODE_RELEASE_BUFFERS. This potentially greatly reduces memory
31023131
usage for no cost at all. */
@@ -3119,6 +3148,10 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version)
31193148
#endif
31203149

31213150
return (PyObject *)self;
3151+
error:
3152+
Py_XDECREF(self);
3153+
ERR_clear_error();
3154+
return NULL;
31223155
}
31233156

31243157
static int

configure

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1604,8 +1604,8 @@ Optional Packages:
16041604
override default cipher suites string, python: use
16051605
Python's preferred selection (default), openssl:
16061606
leave OpenSSL's defaults untouched, STRING: use a
1607-
custom string, PROTOCOL_SSLv2 ignores the setting,
1608-
see Doc/library/ssl.rst
1607+
custom string, python and STRING also set TLS 1.2 as
1608+
minimum TLS version
16091609
--with-builtin-hashlib-hashes=md5,sha1,sha256,sha512,sha3,blake2
16101610
builtin hash modules, md5, sha1, sha256, sha512,
16111611
sha3 (with shake), blake2

configure.ac

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5836,7 +5836,7 @@ AC_ARG_WITH(ssl-default-suites,
58365836
python: use Python's preferred selection (default),
58375837
openssl: leave OpenSSL's defaults untouched,
58385838
STRING: use a custom string,
5839-
PROTOCOL_SSLv2 ignores the setting, see Doc/library/ssl.rst]),
5839+
python and STRING also set TLS 1.2 as minimum TLS version]),
58405840
[
58415841
AC_MSG_RESULT($withval)
58425842
case "$withval" in

0 commit comments

Comments
 (0)