summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorstratakis <cstratak@redhat.com>2019-02-15 17:27:44 (GMT)
committerVictor Stinner <vstinner@redhat.com>2019-02-15 17:27:44 (GMT)
commit2149a9ad7a9d39d7d680ec0fb602042c91057484 (patch)
treeb45e3f3f5c47752b44873be0b2782b88d4b5fa71
parent28eb87f4f558952f259fada7be1ab5b31b8a91ef (diff)
downloadcpython-2149a9ad7a9d39d7d680ec0fb602042c91057484.zip
cpython-2149a9ad7a9d39d7d680ec0fb602042c91057484.tar.gz
cpython-2149a9ad7a9d39d7d680ec0fb602042c91057484.tar.bz2
[2.7] bpo-32947: Fixes for TLS 1.3 and OpenSSL 1.1.1 (GH-8761) (GH-11876)
Backport of TLS 1.3 related fixes from 3.7. Misc fixes and workarounds for compatibility with OpenSSL 1.1.1 from git master and TLS 1.3 support. With OpenSSL 1.1.1, Python negotiates TLS 1.3 by default. Some test cases only apply to TLS 1.2. OpenSSL 1.1.1 has added a new option OP_ENABLE_MIDDLEBOX_COMPAT for TLS 1.3. The feature is enabled by default for maximum compatibility with broken middle boxes. Users should be able to disable the hack and CPython's test suite needs it to verify default options Signed-off-by: Christian Heimes <christian@python.org> (cherry picked from commit 2a4ee8aa01d61b6a9c8e9c65c211e61bdb471826)
-rw-r--r--Doc/library/ssl.rst9
-rw-r--r--Lib/test/test_ssl.py62
-rw-r--r--Misc/NEWS.d/next/Library/2018-08-14-08-57-01.bpo-32947.mqStVW.rst2
-rw-r--r--Modules/_ssl.c4
4 files changed, 58 insertions, 19 deletions
diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst
index 35c9548..8e90492 100644
--- a/Doc/library/ssl.rst
+++ b/Doc/library/ssl.rst
@@ -742,6 +742,15 @@ Constants
.. versionadded:: 2.7.9
+.. data:: OP_ENABLE_MIDDLEBOX_COMPAT
+
+ Send dummy Change Cipher Spec (CCS) messages in TLS 1.3 handshake to make
+ a TLS 1.3 connection look more like a TLS 1.2 connection.
+
+ This option is only available with OpenSSL 1.1.1 and later.
+
+ .. versionadded:: 2.7.16
+
.. data:: OP_NO_COMPRESSION
Disable compression on the SSL channel. This is useful if the application
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
index 01e5432..0eecc78 100644
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -82,6 +82,7 @@ OP_NO_COMPRESSION = getattr(ssl, "OP_NO_COMPRESSION", 0)
OP_SINGLE_DH_USE = getattr(ssl, "OP_SINGLE_DH_USE", 0)
OP_SINGLE_ECDH_USE = getattr(ssl, "OP_SINGLE_ECDH_USE", 0)
OP_CIPHER_SERVER_PREFERENCE = getattr(ssl, "OP_CIPHER_SERVER_PREFERENCE", 0)
+OP_ENABLE_MIDDLEBOX_COMPAT = getattr(ssl, "OP_ENABLE_MIDDLEBOX_COMPAT", 0)
def handle_error(prefix):
@@ -806,7 +807,8 @@ class ContextTests(unittest.TestCase):
default = (ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3)
# SSLContext also enables these by default
default |= (OP_NO_COMPRESSION | OP_CIPHER_SERVER_PREFERENCE |
- OP_SINGLE_DH_USE | OP_SINGLE_ECDH_USE)
+ OP_SINGLE_DH_USE | OP_SINGLE_ECDH_USE |
+ OP_ENABLE_MIDDLEBOX_COMPAT)
self.assertEqual(default, ctx.options)
ctx.options |= ssl.OP_NO_TLSv1
self.assertEqual(default | ssl.OP_NO_TLSv1, ctx.options)
@@ -1697,23 +1699,43 @@ else:
self.sock, server_side=True)
self.server.selected_npn_protocols.append(self.sslconn.selected_npn_protocol())
self.server.selected_alpn_protocols.append(self.sslconn.selected_alpn_protocol())
- except socket.error as e:
- # We treat ConnectionResetError as though it were an
- # SSLError - OpenSSL on Ubuntu abruptly closes the
- # connection when asked to use an unsupported protocol.
- #
- # XXX Various errors can have happened here, for example
- # a mismatching protocol version, an invalid certificate,
- # or a low-level bug. This should be made more discriminating.
- if not isinstance(e, ssl.SSLError) and e.errno != errno.ECONNRESET:
- raise
- self.server.conn_errors.append(e)
- if self.server.chatty:
- handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
- self.running = False
- self.server.stop()
- self.close()
- return False
+ except (ssl.SSLError, socket.error, OSError) as e:
+ if e.errno in (errno.ECONNRESET, errno.EPIPE, errno.ESHUTDOWN):
+ # Mimick Python 3:
+ #
+ # except (ConnectionResetError, BrokenPipeError):
+ #
+ # We treat ConnectionResetError as though it were an
+ # SSLError - OpenSSL on Ubuntu abruptly closes the
+ # connection when asked to use an unsupported protocol.
+ #
+ # BrokenPipeError is raised in TLS 1.3 mode, when OpenSSL
+ # tries to send session tickets after handshake.
+ # https://github.com/openssl/openssl/issues/6342
+ self.server.conn_errors.append(str(e))
+ if self.server.chatty:
+ handle_error(
+ "\n server: bad connection attempt from "
+ + repr(self.addr) + ":\n")
+ self.running = False
+ self.close()
+ return False
+ else:
+ # OSError may occur with wrong protocols, e.g. both
+ # sides use PROTOCOL_TLS_SERVER.
+ #
+ # XXX Various errors can have happened here, for example
+ # a mismatching protocol version, an invalid certificate,
+ # or a low-level bug. This should be made more discriminating.
+ if not isinstance(e, ssl.SSLError) and e.errno != errno.ECONNRESET:
+ raise
+ self.server.conn_errors.append(e)
+ if self.server.chatty:
+ handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
+ self.running = False
+ self.server.stop()
+ self.close()
+ return False
else:
if self.server.context.verify_mode == ssl.CERT_REQUIRED:
cert = self.sslconn.getpeercert()
@@ -2769,7 +2791,7 @@ else:
# Block on the accept and wait on the connection to close.
evt.set()
remote[0], peer[0] = server.accept()
- remote[0].recv(1)
+ remote[0].send(remote[0].recv(4))
t = threading.Thread(target=serve)
t.start()
@@ -2777,6 +2799,8 @@ else:
evt.wait()
client = context.wrap_socket(socket.socket())
client.connect((host, port))
+ client.send(b'data')
+ client.recv()
client_addr = client.getsockname()
client.close()
t.join()
diff --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
new file mode 100644
index 0000000..28de360
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2018-08-14-08-57-01.bpo-32947.mqStVW.rst
@@ -0,0 +1,2 @@
+Add OP_ENABLE_MIDDLEBOX_COMPAT and test workaround for TLSv1.3 for future
+compatibility with OpenSSL 1.1.1.
diff --git a/Modules/_ssl.c b/Modules/_ssl.c
index 80078aa..93b635c 100644
--- a/Modules/_ssl.c
+++ b/Modules/_ssl.c
@@ -4411,6 +4411,10 @@ init_ssl(void)
PyModule_AddIntConstant(m, "OP_NO_COMPRESSION",
SSL_OP_NO_COMPRESSION);
#endif
+#ifdef SSL_OP_ENABLE_MIDDLEBOX_COMPAT
+ PyModule_AddIntConstant(m, "OP_ENABLE_MIDDLEBOX_COMPAT",
+ SSL_OP_ENABLE_MIDDLEBOX_COMPAT);
+#endif
#if HAVE_SNI
r = Py_True;