Skip to content

Commit

Permalink
bpo-43998: Default to TLS 1.2 and increase cipher suite security (pyt…
Browse files Browse the repository at this point in the history
…honGH-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 <christian@python.org>
  • Loading branch information
tiran authored and kreathon committed May 2, 2021
1 parent 43d191c commit 6c6561e
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 18 deletions.
8 changes: 8 additions & 0 deletions Doc/library/ssl.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1509,6 +1509,14 @@ to speed up repeated connections from the same clients.
context class will either require :data:`PROTOCOL_TLS_CLIENT` or
:data:`PROTOCOL_TLS_SERVER` protocol in the future.

.. versionchanged:: 3.10

The default cipher suites now include only secure AES and ChaCha20
ciphers with forward secrecy and security level 2. RSA and DH keys with
less than 2048 bits and ECC keys with less than 224 bits are prohibited.
:data:`PROTOCOL_TLS`, :data:`PROTOCOL_TLS_CLIENT`, and
:data:`PROTOCOL_TLS_SERVER` use TLS 1.2 as minimum TLS version.


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

Expand Down
6 changes: 5 additions & 1 deletion Doc/using/configure.rst
Original file line number Diff line number Diff line change
Expand Up @@ -441,12 +441,16 @@ Security Options

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

See the :mod:`ssl` module.

.. versionadded:: 3.7

.. versionchanged:: 3.10

The settings ``python`` and *STRING* also set TLS 1.2 as minimum
protocol version.

macOS Options
-------------
Expand Down
7 changes: 7 additions & 0 deletions Doc/whatsnew/3.10.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1105,6 +1105,13 @@ Added option to create MPTCP sockets with ``IPPROTO_MPTCP``
ssl
---
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.
(Contributed by Christian Heimes in :issue:`43998`.)
Add a *timeout* parameter to the :func:`ssl.get_server_certificate` function.
(Contributed by Zackery Spytz in :issue:`31870`.)
Expand Down
31 changes: 22 additions & 9 deletions Lib/test/test_nntplib.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ class SSLError(Exception):

class NetworkedNNTPTestsMixin:

ssl_context = None

def test_welcome(self):
welcome = self.server.getwelcome()
self.assertEqual(str, type(welcome))
Expand Down Expand Up @@ -273,18 +275,21 @@ def is_connected():
return False
return True

kwargs = dict(
timeout=support.INTERNET_TIMEOUT,
usenetrc=False
)
if self.ssl_context is not None:
kwargs["ssl_context"] = self.ssl_context

try:
server = self.NNTP_CLASS(self.NNTP_HOST,
timeout=support.INTERNET_TIMEOUT,
usenetrc=False)
server = self.NNTP_CLASS(self.NNTP_HOST, **kwargs)
with server:
self.assertTrue(is_connected())
self.assertTrue(server.help())
self.assertFalse(is_connected())

server = self.NNTP_CLASS(self.NNTP_HOST,
timeout=support.INTERNET_TIMEOUT,
usenetrc=False)
server = self.NNTP_CLASS(self.NNTP_HOST, **kwargs)
with server:
server.quit()
self.assertFalse(is_connected())
Expand Down Expand Up @@ -316,16 +321,21 @@ class NetworkedNNTPTests(NetworkedNNTPTestsMixin, unittest.TestCase):
@classmethod
def setUpClass(cls):
support.requires("network")
kwargs = dict(
timeout=support.INTERNET_TIMEOUT,
usenetrc=False
)
if cls.ssl_context is not None:
kwargs["ssl_context"] = cls.ssl_context
with socket_helper.transient_internet(cls.NNTP_HOST):
try:
cls.server = cls.NNTP_CLASS(cls.NNTP_HOST,
timeout=support.INTERNET_TIMEOUT,
usenetrc=False)
cls.server = cls.NNTP_CLASS(cls.NNTP_HOST, **kwargs)
except SSLError as ssl_err:
# matches "[SSL: DH_KEY_TOO_SMALL] dh key too small"
if re.search(r'(?i)KEY.TOO.SMALL', ssl_err.reason):
raise unittest.SkipTest(f"{cls} got {ssl_err} connecting "
f"to {cls.NNTP_HOST!r}")
print(cls.NNTP_HOST)
raise
except EOF_ERRORS:
raise unittest.SkipTest(f"{cls} got EOF error on connecting "
Expand Down Expand Up @@ -358,6 +368,9 @@ class NetworkedNNTP_SSLTests(NetworkedNNTPTests):
# Disabled as the connection will already be encrypted.
test_starttls = None

ssl_context = ssl._create_unverified_context()
ssl_context.set_ciphers("DEFAULT")
ssl_context.maximum_version = ssl.TLSVersion.TLSv1_2

#
# Non-networked tests using a local server (or something mocking it).
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
The :mod:`ssl` module sets more secure cipher suites defaults. Ciphers
without forward secrecy and with 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.
43 changes: 38 additions & 5 deletions Modules/_ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -152,15 +152,27 @@ extern const SSL_METHOD *TLSv1_2_method(void);
#ifndef PY_SSL_DEFAULT_CIPHER_STRING
#error "Py_SSL_DEFAULT_CIPHERS 0 needs Py_SSL_DEFAULT_CIPHER_STRING"
#endif
#ifndef PY_SSL_MIN_PROTOCOL
#define PY_SSL_MIN_PROTOCOL TLS1_2_VERSION
#endif
#elif PY_SSL_DEFAULT_CIPHERS == 1
/* Python custom selection of sensible cipher suites
* DEFAULT: OpenSSL's default cipher list. Since 1.0.2 the list is in sensible order.
* @SECLEVEL=2: security level 2 with 112 bits minimum security (e.g. 2048 bits RSA key)
* ECDH+*: enable ephemeral elliptic curve Diffie-Hellman
* DHE+*: fallback to ephemeral finite field Diffie-Hellman
* encryption order: AES AEAD (GCM), ChaCha AEAD, AES CBC
* !aNULL:!eNULL: really no NULL ciphers
* !MD5:!3DES:!DES:!RC4:!IDEA:!SEED: no weak or broken algorithms on old OpenSSL versions.
* !aDSS: no authentication with discrete logarithm DSA algorithm
* !SRP:!PSK: no secure remote password or pre-shared key authentication
* !SHA1: no weak SHA1 MAC
* !AESCCM: no CCM mode, it's uncommon and slow
*
* Based on Hynek's excellent blog post (update 2021-02-11)
* https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
*/
#define PY_SSL_DEFAULT_CIPHER_STRING "DEFAULT:!aNULL:!eNULL:!MD5:!3DES:!DES:!RC4:!IDEA:!SEED:!aDSS:!SRP:!PSK"
#define PY_SSL_DEFAULT_CIPHER_STRING "@SECLEVEL=2:ECDH+AESGCM:ECDH+CHACHA20:ECDH+AES:DHE+AES:!aNULL:!eNULL:!aDSS:!SHA1:!AESCCM"
#ifndef PY_SSL_MIN_PROTOCOL
#define PY_SSL_MIN_PROTOCOL TLS1_2_VERSION
#endif
#elif PY_SSL_DEFAULT_CIPHERS == 2
/* Ignored in SSLContext constructor, only used to as _ssl.DEFAULT_CIPHER_STRING */
#define PY_SSL_DEFAULT_CIPHER_STRING SSL_DEFAULT_CIPHER_LIST
Expand Down Expand Up @@ -3095,8 +3107,25 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version)
ERR_clear_error();
PyErr_SetString(get_state_ctx(self)->PySSLErrorObject,
"No cipher can be selected.");
return NULL;
goto error;
}
#ifdef PY_SSL_MIN_PROTOCOL
switch(proto_version) {
case PY_SSL_VERSION_TLS:
case PY_SSL_VERSION_TLS_CLIENT:
case PY_SSL_VERSION_TLS_SERVER:
result = SSL_CTX_set_min_proto_version(ctx, PY_SSL_MIN_PROTOCOL);
if (result == 0) {
PyErr_Format(PyExc_ValueError,
"Failed to set minimum protocol 0x%x",
PY_SSL_MIN_PROTOCOL);
goto error;
}
break;
default:
break;
}
#endif

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

return (PyObject *)self;
error:
Py_XDECREF(self);
ERR_clear_error();
return NULL;
}

static int
Expand Down
4 changes: 2 additions & 2 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -1604,8 +1604,8 @@ Optional Packages:
override default cipher suites string, python: use
Python's preferred selection (default), openssl:
leave OpenSSL's defaults untouched, STRING: use a
custom string, PROTOCOL_SSLv2 ignores the setting,
see Doc/library/ssl.rst
custom string, python and STRING also set TLS 1.2 as
minimum TLS version
--with-builtin-hashlib-hashes=md5,sha1,sha256,sha512,sha3,blake2
builtin hash modules, md5, sha1, sha256, sha512,
sha3 (with shake), blake2
Expand Down
2 changes: 1 addition & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -5836,7 +5836,7 @@ AC_ARG_WITH(ssl-default-suites,
python: use Python's preferred selection (default),
openssl: leave OpenSSL's defaults untouched,
STRING: use a custom string,
PROTOCOL_SSLv2 ignores the setting, see Doc/library/ssl.rst]),
python and STRING also set TLS 1.2 as minimum TLS version]),
[
AC_MSG_RESULT($withval)
case "$withval" in
Expand Down

0 comments on commit 6c6561e

Please sign in to comment.