blob: 56d591d1b526398fb8ddda758bf3c925411566ca [file] [log] [blame]
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001From 170a614904febd14ff6cfd7a75c9bccc114b3948 Mon Sep 17 00:00:00 2001
2From: Christian Heimes <christian@python.org>
3Date: Tue, 14 Aug 2018 16:56:32 +0200
4Subject: [PATCH] bpo-32947: Fixes for TLS 1.3 and OpenSSL 1.1.1 (GH-8761)
5
6Backport of TLS 1.3 related fixes from 3.7.
7
8Misc fixes and workarounds for compatibility with OpenSSL 1.1.1 from git
9master and TLS 1.3 support. With OpenSSL 1.1.1, Python negotiates TLS 1.3 by
10default. Some test cases only apply to TLS 1.2.
11
12OpenSSL 1.1.1 has added a new option OP_ENABLE_MIDDLEBOX_COMPAT for TLS
131.3. The feature is enabled by default for maximum compatibility with
14broken middle boxes. Users should be able to disable the hack and CPython's test suite needs
15it to verify default options
16
17Signed-off-by: Christian Heimes <christian@python.org>
18
19Upstream-Status: Backport
20[https://github.com/python/cpython/commit/2a4ee8aa01d61b6a9c8e9c65c211e61bdb471826]
21
22Signed-off-by: Anuj Mittal <anuj.mittal@intel.com>
23---
24 Doc/library/ssl.rst | 9 ++++++
25 Lib/test/test_asyncio/test_events.py | 6 +++-
26 Lib/test/test_ssl.py | 29 +++++++++++++++----
27 .../2018-08-14-08-57-01.bpo-32947.mqStVW.rst | 2 ++
28 Modules/_ssl.c | 4 +++
29 5 files changed, 44 insertions(+), 6 deletions(-)
30 create mode 100644 Misc/NEWS.d/next/Library/2018-08-14-08-57-01.bpo-32947.mqStVW.rst
31
32diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst
33index 29c5e94cf6..f63a3deec5 100644
34--- a/Doc/library/ssl.rst
35+++ b/Doc/library/ssl.rst
36@@ -757,6 +757,15 @@ Constants
37
38 .. versionadded:: 3.3
39
40+.. data:: OP_ENABLE_MIDDLEBOX_COMPAT
41+
42+ Send dummy Change Cipher Spec (CCS) messages in TLS 1.3 handshake to make
43+ a TLS 1.3 connection look more like a TLS 1.2 connection.
44+
45+ This option is only available with OpenSSL 1.1.1 and later.
46+
47+ .. versionadded:: 3.6.7
48+
49 .. data:: OP_NO_COMPRESSION
50
51 Disable compression on the SSL channel. This is useful if the application
52diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py
53index 492a84a231..6f208474b9 100644
54--- a/Lib/test/test_asyncio/test_events.py
55+++ b/Lib/test/test_asyncio/test_events.py
56@@ -1169,7 +1169,11 @@ class EventLoopTestsMixin:
57 self.loop.run_until_complete(f_c)
58
59 # close connection
60- proto.transport.close()
61+ # transport may be None with TLS 1.3, because connection is
62+ # interrupted, server is unable to send session tickets, and
63+ # transport is closed.
64+ if proto.transport is not None:
65+ proto.transport.close()
66 server.close()
67
68 def test_legacy_create_server_ssl_match_failed(self):
69diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
70index 1acc12ec2d..a2e1d32a62 100644
71--- a/Lib/test/test_ssl.py
72+++ b/Lib/test/test_ssl.py
73@@ -78,6 +78,7 @@ OP_NO_COMPRESSION = getattr(ssl, "OP_NO_COMPRESSION", 0)
74 OP_SINGLE_DH_USE = getattr(ssl, "OP_SINGLE_DH_USE", 0)
75 OP_SINGLE_ECDH_USE = getattr(ssl, "OP_SINGLE_ECDH_USE", 0)
76 OP_CIPHER_SERVER_PREFERENCE = getattr(ssl, "OP_CIPHER_SERVER_PREFERENCE", 0)
77+OP_ENABLE_MIDDLEBOX_COMPAT = getattr(ssl, "OP_ENABLE_MIDDLEBOX_COMPAT", 0)
78
79
80 def handle_error(prefix):
81@@ -155,8 +156,8 @@ class BasicSocketTests(unittest.TestCase):
82 ssl.OP_NO_TLSv1
83 ssl.OP_NO_TLSv1_3
84 if ssl.OPENSSL_VERSION_INFO >= (1, 0, 1):
85- ssl.OP_NO_TLSv1_1
86- ssl.OP_NO_TLSv1_2
87+ ssl.OP_NO_TLSv1_1
88+ ssl.OP_NO_TLSv1_2
89
90 def test_str_for_enums(self):
91 # Make sure that the PROTOCOL_* constants have enum-like string
92@@ -854,7 +855,8 @@ class ContextTests(unittest.TestCase):
93 default = (ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3)
94 # SSLContext also enables these by default
95 default |= (OP_NO_COMPRESSION | OP_CIPHER_SERVER_PREFERENCE |
96- OP_SINGLE_DH_USE | OP_SINGLE_ECDH_USE)
97+ OP_SINGLE_DH_USE | OP_SINGLE_ECDH_USE |
98+ OP_ENABLE_MIDDLEBOX_COMPAT)
99 self.assertEqual(default, ctx.options)
100 ctx.options |= ssl.OP_NO_TLSv1
101 self.assertEqual(default | ssl.OP_NO_TLSv1, ctx.options)
102@@ -1860,11 +1862,26 @@ else:
103 self.sock, server_side=True)
104 self.server.selected_npn_protocols.append(self.sslconn.selected_npn_protocol())
105 self.server.selected_alpn_protocols.append(self.sslconn.selected_alpn_protocol())
106- except (ssl.SSLError, ConnectionResetError) as e:
107+ except (ConnectionResetError, BrokenPipeError) as e:
108 # We treat ConnectionResetError as though it were an
109 # SSLError - OpenSSL on Ubuntu abruptly closes the
110 # connection when asked to use an unsupported protocol.
111 #
112+ # BrokenPipeError is raised in TLS 1.3 mode, when OpenSSL
113+ # tries to send session tickets after handshake.
114+ # https://github.com/openssl/openssl/issues/6342
115+ self.server.conn_errors.append(str(e))
116+ if self.server.chatty:
117+ handle_error(
118+ "\n server: bad connection attempt from " + repr(
119+ self.addr) + ":\n")
120+ self.running = False
121+ self.close()
122+ return False
123+ except (ssl.SSLError, OSError) as e:
124+ # OSError may occur with wrong protocols, e.g. both
125+ # sides use PROTOCOL_TLS_SERVER.
126+ #
127 # XXX Various errors can have happened here, for example
128 # a mismatching protocol version, an invalid certificate,
129 # or a low-level bug. This should be made more discriminating.
130@@ -2974,7 +2991,7 @@ else:
131 # Block on the accept and wait on the connection to close.
132 evt.set()
133 remote, peer = server.accept()
134- remote.recv(1)
135+ remote.send(remote.recv(4))
136
137 t = threading.Thread(target=serve)
138 t.start()
139@@ -2982,6 +2999,8 @@ else:
140 evt.wait()
141 client = context.wrap_socket(socket.socket())
142 client.connect((host, port))
143+ client.send(b'data')
144+ client.recv()
145 client_addr = client.getsockname()
146 client.close()
147 t.join()
148diff --git a/Misc/NEWS.d/next/Library/2018-08-14-08-57-01.bpo-32947.mqStVW.rst b/Misc/NEWS.d/next/Library/2018-08-14-08-57-01.bpo-32947.mqStVW.rst
149new file mode 100644
150index 0000000000..28de360c36
151--- /dev/null
152+++ b/Misc/NEWS.d/next/Library/2018-08-14-08-57-01.bpo-32947.mqStVW.rst
153@@ -0,0 +1,2 @@
154+Add OP_ENABLE_MIDDLEBOX_COMPAT and test workaround for TLSv1.3 for future
155+compatibility with OpenSSL 1.1.1.
156diff --git a/Modules/_ssl.c b/Modules/_ssl.c
157index c71d89607c..eb123a87ba 100644
158--- a/Modules/_ssl.c
159+++ b/Modules/_ssl.c
160@@ -4858,6 +4858,10 @@ PyInit__ssl(void)
161 PyModule_AddIntConstant(m, "OP_NO_COMPRESSION",
162 SSL_OP_NO_COMPRESSION);
163 #endif
164+#ifdef SSL_OP_ENABLE_MIDDLEBOX_COMPAT
165+ PyModule_AddIntConstant(m, "OP_ENABLE_MIDDLEBOX_COMPAT",
166+ SSL_OP_ENABLE_MIDDLEBOX_COMPAT);
167+#endif
168
169 #if HAVE_SNI
170 r = Py_True;
171--
1722.17.1
173