8000 bpo-29136: Add TLS 1.3 cipher suites and OP_NO_TLSv1_3 (#1363) · python/cpython@cb5b68a · GitHub
[go: up one dir, main page]

Skip to content

Commit cb5b68a

Browse files
authored
bpo-29136: Add TLS 1.3 cipher suites and OP_NO_TLSv1_3 (#1363)
* bpo-29136: Add TLS 1.3 support TLS 1.3 introduces a new, distinct set of cipher suites. The TLS 1.3 cipher suites don't overlap with cipher suites from TLS 1.2 and earlier. Since Python sets its own set of permitted ciphers, TLS 1.3 handshake will fail as soon as OpenSSL 1.1.1 is released. Let's enable the common AES-GCM and ChaCha20 suites. Additionally the flag OP_NO_TLSv1_3 is added. It defaults to 0 (no op) with OpenSSL prior to 1.1.1. This allows applications to opt-out from TLS 1.3 now. Signed-off-by: Christian Heimes <christian@python.org>
1 parent 9020ac7 commit cb5b68a

File tree

5 files changed

+79
-3
lines changed

5 files changed

+79
-3
lines changed

Doc/library/ssl.rst

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,11 +193,11 @@ instead.
193193
.. table::
194194

195195
======================== ============ ============ ============= ========= =========== ===========
196-
*client* / **server** **SSLv2** **SSLv3** **TLS** **TLSv1** **TLSv1.1** **TLSv1.2**
196+
*client* / **server** **SSLv2** **SSLv3** **TLS** [3]_ **TLSv1** **TLSv1.1** **TLSv1.2**
197197
------------------------ ------------ ------------ ------------- --------- ----------- -----------
198198
*SSLv2* yes no no [1]_ no no no
199199
*SSLv3* no yes no [2]_ no no no
200-
*TLS* (*SSLv23*) no [1]_ no [2]_ yes yes yes yes
200+
*TLS* (*SSLv23*) [3]_ no [1]_ no [2]_ yes yes yes yes
201201
*TLSv1* no no yes yes no no
202202
*TLSv1.1* no no yes no yes no
203203
*TLSv1.2* no no yes no no yes
@@ -206,6 +206,9 @@ instead.
206206
.. rubric:: Footnotes
207207
.. [1] :class:`SSLContext` disables SSLv2 with :data:`OP_NO_SSLv2` by default.
208208
.. [2] :class:`SSLContext` disables SSLv3 with :data:`OP_NO_SSLv3` by default.
209+
.. [3] TLS 1.3 protocol will be available with :data:`PROTOCOL_TLS` in
210+
OpenSSL >= 1.1.1. There is no dedicated PROTOCOL constant for just
211+
TLS 1.3.
209212
210213
.. note::
211214

@@ -294,6 +297,11 @@ purposes.
294297

295298
3DES was dropped from the default cipher string.
296299

300+
.. versionchanged:: 3.7
301+
302+
TLS 1.3 cipher suites TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384,
303+
and TLS_CHACHA20_POLY1305_SHA256 were added to the default cipher string.
304+
297305

298306
Random generation
299307
^^^^^^^^^^^^^^^^^
@@ -764,6 +772,16 @@ Constants
764772

765773
.. versionadded:: 3.4
766774

775+
.. data:: OP_NO_TLSv1_3
776+
777+
Prevents a TLSv1.3 connection. This option is only applicable in conjunction
778+
with :const:`PROTOCOL_TLS`. It prevents the peers from choosing TLSv1.3 as
779+
the protocol version. TLS 1.3 is available with OpenSSL 1.1.1 or later.
780+
When Python has been compiled against an older version of OpenSSL, the
781+
flag defaults to *0*.
782+
783+
.. versionadded:: 3.7
784+
767785
.. data:: OP_CIPHER_SERVER_PREFERENCE
768786

769787
Use the server's cipher ordering preference, rather than the client's.
@@ -838,6 +856,12 @@ Constants
838856

839857
.. versionadded:: 3.3
840858

859+
.. data:: HAS_TLSv1_3
860+
861+
Whether the OpenSSL library has built-in support for the TLS 1.3 protocol.
862+
863+
.. versionadded:: 3.7
864+
841865
.. data:: CHANNEL_BINDING_TYPES
842866

843867
List of supported TLS channel binding types. Strings in this list

Lib/ssl.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@
115115
pass
116116

117117

118-
from _ssl import HAS_SNI, HAS_ECDH, HAS_NPN, HAS_ALPN
118+
from _ssl import HAS_SNI, HAS_ECDH, HAS_NPN, HAS_ALPN, HAS_TLSv1_3
119119
from _ssl import _OPENSSL_API_VERSION
120120

121121

@@ -178,6 +178,7 @@
178178
# (OpenSSL's default setting is 'DEFAULT:!aNULL:!eNULL')
179179
# Enable a better set of ciphers by default
180180
# This list has been explicitly chosen to:
181+
# * TLS 1.3 ChaCha20 and AES-GCM cipher suites
181182
# * Prefer cipher suites that offer perfect forward secrecy (DHE/ECDHE)
182183
# * Prefer ECDHE over DHE for better performance
183184
# * Prefer AEAD over CBC for better performance and security
@@ -189,13 +190,16 @@
189190
# * Disable NULL authentication, NULL encryption, 3DES and MD5 MACs
190191
# for security reasons
191192
_DEFAULT_CIPHERS = (
193+
'TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:'
194+
'TLS13-AES-128-GCM-SHA256:'
192195
'ECDH+AESGCM:ECDH+CHACHA20:DH+AESGCM:DH+CHACHA20:ECDH+AES256:DH+AES256:'
193196
'ECDH+AES128:DH+AES:ECDH+HIGH:DH+HIGH:RSA+AESGCM:RSA+AES:RSA+HIGH:'
194197
'!aNULL:!eNULL:!MD5:!3DES'
195198
)
196199

197200
# Restricted and more secure ciphers for the server side
198201
# This list has been explicitly chosen to:
202+
# * TLS 1.3 ChaCha20 and AES-GCM cipher suites
199203
# * Prefer cipher suites that offer perfect forward secrecy (DHE/ECDHE)
200204
# * Prefer ECDHE over DHE for better performance
201205
# * Prefer AEAD over CBC for better performance and security
@@ -206,6 +210,8 @@
206210
# * Disable NULL authentication, NULL encryption, MD5 MACs, DSS, RC4, and
207211
# 3DES for security reasons
208212
_RESTRICTED_SERVER_CIPHERS = (
213+
'TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:'
214+
'TLS13-AES-128-GCM-SHA256:'
209215
'ECDH+AESGCM:ECDH+CHACHA20:DH+AESGCM:DH+CHACHA20:ECDH+AES256:DH+AES256:'
210216
'ECDH+AES128:DH+AES:ECDH+HIGH:DH+HIGH:RSA+AESGCM:RSA+AES:RSA+HIGH:'
211217
'!aNULL:!eNULL:!MD5:!DSS:!RC4:!3DES'

Lib/test/test_ssl.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,13 @@ def test_constants(self):
170170
ssl.OP_NO_COMPRESSION
171171
self.assertIn(ssl.HAS_SNI, {True, False})
172172
self.assertIn(ssl.HAS_ECDH, {True, False})
173+
ssl.OP_NO_SSLv2
174+
ssl.OP_NO_SSLv3
175+
ssl.OP_NO_TLSv1
176+
ssl.OP_NO_TLSv1_3
177+
if ssl.OPENSSL_VERSION_INFO >= (1, 0, 1):
178+
ssl.OP_NO_TLSv1_1
179+
ssl.OP_NO_TLSv1_2
173180

174181
def test_str_for_enums(self):
175182
# Make sure that the PROTOCOL_* constants have enum-like string
@@ -3098,12 +3105,33 @@ def test_version_basic(self):
30983105
self.assertEqual(s.version(), 'TLSv1')
30993106
self.assertIs(s.version(), None)
31003107

3108+
@unittest.skipUnless(ssl.HAS_TLSv1_3,
3109+
"test requires TLSv1.3 enabled OpenSSL")
3110+
def test_tls1_3(self):
3111+
context = ssl.SSLContext(ssl.PROTOCOL_TLS)
3112+
context.load_cert_chain(CERTFILE)
3113+
# disable all but TLS 1.3
3114+
context.options |= (
3115+
ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1 | ssl.OP_NO_TLSv1_2
3116+
)
3117+
with ThreadedEchoServer(context=context) as server:
3118+
with context.wrap_socket(socket.socket()) as s:
3119+
s.connect((HOST, server.port))
3120+
self.assertIn(s.cipher()[0], [
3121+
'TLS13-AES-256-GCM-SHA384',
3122+
'TLS13-CHACHA20-POLY1305-SHA256',
3123+
'TLS13-AES-128-GCM-SHA256',
3124+
])
3125+
31013126
@unittest.skipUnless(ssl.HAS_ECDH, "test requires ECDH-enabled OpenSSL")
31023127
def test_default_ecdh_curve(self):
31033128
# Issue #21015: elliptic curve-based Diffie Hellman key exchange
31043129
# should be enabled by default on SSL contexts.
31053130
context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
31063131
context.load_cert_chain(CERTFILE)
3132+
# TLSv1.3 defaults to PFS key agreement and no longer has KEA in
3133+
# cipher name.
3134+
context.options |= ssl.OP_NO_TLSv1_3
31073135
# Prior to OpenSSL 1.0.0, ECDH ciphers have to be enabled
31083136
# explicitly using the 'ECCdraft' cipher alias. Otherwise,
31093137
# our default cipher list should prefer ECDH-based ciphers
@@ -3532,6 +3560,10 @@ def test_session_handling(self):
35323560
context2.load_verify_locations(CERTFILE)
35333561
context2.load_cert_chain(CERTFILE)
35343562

3563+
# TODO: session reuse does not work with TLS 1.3
3564+
context.options |= ssl.OP_NO_TLSv1_3
3565+
context2.options |= ssl.OP_NO_TLSv1_3
3566+
35353567
server = ThreadedEchoServer(context=context, chatty=False)
35363568
with server:
35373569
with context.wrap_socket(socket.socket()) as s:
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add TLS 1.3 cipher suites and OP_NO_TLSv1_3.

Modules/_ssl.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5349,6 +5349,11 @@ PyInit__ssl(void)
53495349
#if HAVE_TLSv1_2
53505350
PyModule_AddIntConstant(m, "OP_NO_TLSv1_1", SSL_OP_NO_TLSv1_1);
53515351
PyModule_AddIntConstant(m, "OP_NO_TLSv1_2", SSL_OP_NO_TLSv1_2);
5352+
#endif
5353+
#ifdef SSL_OP_NO_TLSv1_3
5354+
PyModule_AddIntConstant(m, "OP_NO_TLSv1_3", SSL_OP_NO_TLSv1_3);
5355+
#else
5356+
PyModule_AddIntConstant(m, "OP_NO_TLSv1_3", 0);
53525357
#endif
53535358
PyModule_AddIntConstant(m, "OP_CIPHER_SERVER_PREFERENCE",
53545359
SSL_OP_CIPHER_SERVER_PREFERENCE);
@@ -5398,6 +5403,14 @@ PyInit__ssl(void)
53985403
Py_INCREF(r);
53995404
PyModule_AddObject(m, "HAS_ALPN", r);
54005405

5406+
#if defined(TLS1_3_VERSION) && !defined(OPENSSL_NO_TLS1_3)
5407+
r = Py_True;
5408+
#else
5409+
r = Py_False;
5410+
#endif
5411+
Py_INCREF(r);
5412+
PyModule_AddObject(m, "HAS_TLSv1_3", r);
5413+
54015414
/* Mappings for error codes */
54025415
err_codes_to_names = PyDict_New();
54035416
err_names_to_codes = PyDict_New();

0 commit comments

Comments
 (0)
0