diff options
| author | Anuj Mittal <anuj.mittal@intel.com> | 2018-09-12 18:16:04 +0800 |
|---|---|---|
| committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2018-09-13 07:42:28 +0100 |
| commit | 3c32b1525ad5ce3ec82542846369547efc62f25a (patch) | |
| tree | 1665ff7eea6638f7da98ef803f1c4f4e03150e82 /meta/recipes-devtools/python/python3 | |
| parent | 55f36a4045b44e644887bc4316d6d3aae5d12e22 (diff) | |
| download | poky-3c32b1525ad5ce3ec82542846369547efc62f25a.tar.gz | |
python3{,-native}: backport openssl 1.1.1 compatibility changes
Backport changes from 3.7/3.6 to fix failing python3 ssl test suite.
Fixes [YOCTO #12919]
(From OE-Core rev: 6c123468b546931de005cf136d98bca6b893b37b)
Signed-off-by: Anuj Mittal <anuj.mittal@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta/recipes-devtools/python/python3')
5 files changed, 857 insertions, 0 deletions
diff --git a/meta/recipes-devtools/python/python3/0001-Issue-28043-SSLContext-has-improved-default-settings.patch b/meta/recipes-devtools/python/python3/0001-Issue-28043-SSLContext-has-improved-default-settings.patch new file mode 100644 index 0000000000..321b4afa12 --- /dev/null +++ b/meta/recipes-devtools/python/python3/0001-Issue-28043-SSLContext-has-improved-default-settings.patch | |||
| @@ -0,0 +1,272 @@ | |||
| 1 | From 758e7463c104f71b810c8588166747eeab6148d7 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Christian Heimes <christian@python.org> | ||
| 3 | Date: Sat, 10 Sep 2016 22:43:48 +0200 | ||
| 4 | Subject: [PATCH 1/4] Issue 28043: SSLContext has improved default settings | ||
| 5 | |||
| 6 | The options OP_NO_COMPRESSION, OP_CIPHER_SERVER_PREFERENCE, OP_SINGLE_DH_USE, OP_SINGLE_ECDH_USE, OP_NO_SSLv2 (except for PROTOCOL_SSLv2), and OP_NO_SSLv3 (except for PROTOCOL_SSLv3) are set by default. The initial cipher suite list contains only HIGH ciphers, no NULL ciphers and MD5 ciphers (except for PROTOCOL_SSLv2). | ||
| 7 | |||
| 8 | Upstream-Status: Backport | ||
| 9 | [https://github.com/python/cpython/commit/358cfd426ccc0fcd6a7940d306602138e76420ae] | ||
| 10 | |||
| 11 | Signed-off-by: Anuj Mittal <anuj.mittal@intel.com> | ||
| 12 | --- | ||
| 13 | Doc/library/ssl.rst | 9 ++++++- | ||
| 14 | Lib/ssl.py | 30 +++++---------------- | ||
| 15 | Lib/test/test_ssl.py | 62 +++++++++++++++++++++++--------------------- | ||
| 16 | Modules/_ssl.c | 31 ++++++++++++++++++++++ | ||
| 17 | 4 files changed, 78 insertions(+), 54 deletions(-) | ||
| 18 | |||
| 19 | diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst | ||
| 20 | index a2f008346b..14f2d68217 100644 | ||
| 21 | --- a/Doc/library/ssl.rst | ||
| 22 | +++ b/Doc/library/ssl.rst | ||
| 23 | @@ -1151,7 +1151,14 @@ to speed up repeated connections from the same clients. | ||
| 24 | |||
| 25 | .. versionchanged:: 3.5.3 | ||
| 26 | |||
| 27 | - :data:`PROTOCOL_TLS` is the default value. | ||
| 28 | + The context is created with secure default values. The options | ||
| 29 | + :data:`OP_NO_COMPRESSION`, :data:`OP_CIPHER_SERVER_PREFERENCE`, | ||
| 30 | + :data:`OP_SINGLE_DH_USE`, :data:`OP_SINGLE_ECDH_USE`, | ||
| 31 | + :data:`OP_NO_SSLv2` (except for :data:`PROTOCOL_SSLv2`), | ||
| 32 | + and :data:`OP_NO_SSLv3` (except for :data:`PROTOCOL_SSLv3`) are | ||
| 33 | + set by default. The initial cipher suite list contains only ``HIGH`` | ||
| 34 | + ciphers, no ``NULL`` ciphers and no ``MD5`` ciphers (except for | ||
| 35 | + :data:`PROTOCOL_SSLv2`). | ||
| 36 | |||
| 37 | |||
| 38 | :class:`SSLContext` objects have the following methods and attributes: | ||
| 39 | diff --git a/Lib/ssl.py b/Lib/ssl.py | ||
| 40 | index e1913904f3..4d302a78fa 100644 | ||
| 41 | --- a/Lib/ssl.py | ||
| 42 | +++ b/Lib/ssl.py | ||
| 43 | @@ -446,32 +446,16 @@ def create_default_context(purpose=Purpose.SERVER_AUTH, *, cafile=None, | ||
| 44 | if not isinstance(purpose, _ASN1Object): | ||
| 45 | raise TypeError(purpose) | ||
| 46 | |||
| 47 | + # SSLContext sets OP_NO_SSLv2, OP_NO_SSLv3, OP_NO_COMPRESSION, | ||
| 48 | + # OP_CIPHER_SERVER_PREFERENCE, OP_SINGLE_DH_USE and OP_SINGLE_ECDH_USE | ||
| 49 | + # by default. | ||
| 50 | context = SSLContext(PROTOCOL_TLS) | ||
| 51 | |||
| 52 | - # SSLv2 considered harmful. | ||
| 53 | - context.options |= OP_NO_SSLv2 | ||
| 54 | - | ||
| 55 | - # SSLv3 has problematic security and is only required for really old | ||
| 56 | - # clients such as IE6 on Windows XP | ||
| 57 | - context.options |= OP_NO_SSLv3 | ||
| 58 | - | ||
| 59 | - # disable compression to prevent CRIME attacks (OpenSSL 1.0+) | ||
| 60 | - context.options |= getattr(_ssl, "OP_NO_COMPRESSION", 0) | ||
| 61 | - | ||
| 62 | if purpose == Purpose.SERVER_AUTH: | ||
| 63 | # verify certs and host name in client mode | ||
| 64 | context.verify_mode = CERT_REQUIRED | ||
| 65 | context.check_hostname = True | ||
| 66 | elif purpose == Purpose.CLIENT_AUTH: | ||
| 67 | - # Prefer the server's ciphers by default so that we get stronger | ||
| 68 | - # encryption | ||
| 69 | - context.options |= getattr(_ssl, "OP_CIPHER_SERVER_PREFERENCE", 0) | ||
| 70 | - | ||
| 71 | - # Use single use keys in order to improve forward secrecy | ||
| 72 | - context.options |= getattr(_ssl, "OP_SINGLE_DH_USE", 0) | ||
| 73 | - context.options |= getattr(_ssl, "OP_SINGLE_ECDH_USE", 0) | ||
| 74 | - | ||
| 75 | - # disallow ciphers with known vulnerabilities | ||
| 76 | context.set_ciphers(_RESTRICTED_SERVER_CIPHERS) | ||
| 77 | |||
| 78 | if cafile or capath or cadata: | ||
| 79 | @@ -497,12 +481,10 @@ def _create_unverified_context(protocol=PROTOCOL_TLS, *, cert_reqs=None, | ||
| 80 | if not isinstance(purpose, _ASN1Object): | ||
| 81 | raise TypeError(purpose) | ||
| 82 | |||
| 83 | + # SSLContext sets OP_NO_SSLv2, OP_NO_SSLv3, OP_NO_COMPRESSION, | ||
| 84 | + # OP_CIPHER_SERVER_PREFERENCE, OP_SINGLE_DH_USE and OP_SINGLE_ECDH_USE | ||
| 85 | + # by default. | ||
| 86 | context = SSLContext(protocol) | ||
| 87 | - # SSLv2 considered harmful. | ||
| 88 | - context.options |= OP_NO_SSLv2 | ||
| 89 | - # SSLv3 has problematic security and is only required for really old | ||
| 90 | - # clients such as IE6 on Windows XP | ||
| 91 | - context.options |= OP_NO_SSLv3 | ||
| 92 | |||
| 93 | if cert_reqs is not None: | ||
| 94 | context.verify_mode = cert_reqs | ||
| 95 | diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py | ||
| 96 | index ffb7314f57..f91af7bd05 100644 | ||
| 97 | --- a/Lib/test/test_ssl.py | ||
| 98 | +++ b/Lib/test/test_ssl.py | ||
| 99 | @@ -73,6 +73,12 @@ NULLBYTECERT = data_file("nullbytecert.pem") | ||
| 100 | DHFILE = data_file("dh1024.pem") | ||
| 101 | BYTES_DHFILE = os.fsencode(DHFILE) | ||
| 102 | |||
| 103 | +# Not defined in all versions of OpenSSL | ||
| 104 | +OP_NO_COMPRESSION = getattr(ssl, "OP_NO_COMPRESSION", 0) | ||
| 105 | +OP_SINGLE_DH_USE = getattr(ssl, "OP_SINGLE_DH_USE", 0) | ||
| 106 | +OP_SINGLE_ECDH_USE = getattr(ssl, "OP_SINGLE_ECDH_USE", 0) | ||
| 107 | +OP_CIPHER_SERVER_PREFERENCE = getattr(ssl, "OP_CIPHER_SERVER_PREFERENCE", 0) | ||
| 108 | + | ||
| 109 | |||
| 110 | def handle_error(prefix): | ||
| 111 | exc_format = ' '.join(traceback.format_exception(*sys.exc_info())) | ||
| 112 | @@ -839,8 +845,9 @@ class ContextTests(unittest.TestCase): | ||
| 113 | ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) | ||
| 114 | # OP_ALL | OP_NO_SSLv2 | OP_NO_SSLv3 is the default value | ||
| 115 | default = (ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3) | ||
| 116 | - if not IS_LIBRESSL and ssl.OPENSSL_VERSION_INFO >= (1, 1, 0): | ||
| 117 | - default |= ssl.OP_NO_COMPRESSION | ||
| 118 | + # SSLContext also enables these by default | ||
| 119 | + default |= (OP_NO_COMPRESSION | OP_CIPHER_SERVER_PREFERENCE | | ||
| 120 | + OP_SINGLE_DH_USE | OP_SINGLE_ECDH_USE) | ||
| 121 | self.assertEqual(default, ctx.options) | ||
| 122 | ctx.options |= ssl.OP_NO_TLSv1 | ||
| 123 | self.assertEqual(default | ssl.OP_NO_TLSv1, ctx.options) | ||
| 124 | @@ -1205,16 +1212,29 @@ class ContextTests(unittest.TestCase): | ||
| 125 | stats["x509"] += 1 | ||
| 126 | self.assertEqual(ctx.cert_store_stats(), stats) | ||
| 127 | |||
| 128 | + def _assert_context_options(self, ctx): | ||
| 129 | + self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2) | ||
| 130 | + if OP_NO_COMPRESSION != 0: | ||
| 131 | + self.assertEqual(ctx.options & OP_NO_COMPRESSION, | ||
| 132 | + OP_NO_COMPRESSION) | ||
| 133 | + if OP_SINGLE_DH_USE != 0: | ||
| 134 | + self.assertEqual(ctx.options & OP_SINGLE_DH_USE, | ||
| 135 | + OP_SINGLE_DH_USE) | ||
| 136 | + if OP_SINGLE_ECDH_USE != 0: | ||
| 137 | + self.assertEqual(ctx.options & OP_SINGLE_ECDH_USE, | ||
| 138 | + OP_SINGLE_ECDH_USE) | ||
| 139 | + if OP_CIPHER_SERVER_PREFERENCE != 0: | ||
| 140 | + self.assertEqual(ctx.options & OP_CIPHER_SERVER_PREFERENCE, | ||
| 141 | + OP_CIPHER_SERVER_PREFERENCE) | ||
| 142 | + | ||
| 143 | def test_create_default_context(self): | ||
| 144 | ctx = ssl.create_default_context() | ||
| 145 | + | ||
| 146 | self.assertEqual(ctx.protocol, ssl.PROTOCOL_SSLv23) | ||
| 147 | self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED) | ||
| 148 | self.assertTrue(ctx.check_hostname) | ||
| 149 | - self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2) | ||
| 150 | - self.assertEqual( | ||
| 151 | - ctx.options & getattr(ssl, "OP_NO_COMPRESSION", 0), | ||
| 152 | - getattr(ssl, "OP_NO_COMPRESSION", 0), | ||
| 153 | - ) | ||
| 154 | + self._assert_context_options(ctx) | ||
| 155 | + | ||
| 156 | |||
| 157 | with open(SIGNING_CA) as f: | ||
| 158 | cadata = f.read() | ||
| 159 | @@ -1222,40 +1242,24 @@ class ContextTests(unittest.TestCase): | ||
| 160 | cadata=cadata) | ||
| 161 | self.assertEqual(ctx.protocol, ssl.PROTOCOL_SSLv23) | ||
| 162 | self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED) | ||
| 163 | - self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2) | ||
| 164 | - self.assertEqual( | ||
| 165 | - ctx.options & getattr(ssl, "OP_NO_COMPRESSION", 0), | ||
| 166 | - getattr(ssl, "OP_NO_COMPRESSION", 0), | ||
| 167 | - ) | ||
| 168 | + self._assert_context_options(ctx) | ||
| 169 | |||
| 170 | ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) | ||
| 171 | self.assertEqual(ctx.protocol, ssl.PROTOCOL_SSLv23) | ||
| 172 | self.assertEqual(ctx.verify_mode, ssl.CERT_NONE) | ||
| 173 | - self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2) | ||
| 174 | - self.assertEqual( | ||
| 175 | - ctx.options & getattr(ssl, "OP_NO_COMPRESSION", 0), | ||
| 176 | - getattr(ssl, "OP_NO_COMPRESSION", 0), | ||
| 177 | - ) | ||
| 178 | - self.assertEqual( | ||
| 179 | - ctx.options & getattr(ssl, "OP_SINGLE_DH_USE", 0), | ||
| 180 | - getattr(ssl, "OP_SINGLE_DH_USE", 0), | ||
| 181 | - ) | ||
| 182 | - self.assertEqual( | ||
| 183 | - ctx.options & getattr(ssl, "OP_SINGLE_ECDH_USE", 0), | ||
| 184 | - getattr(ssl, "OP_SINGLE_ECDH_USE", 0), | ||
| 185 | - ) | ||
| 186 | + self._assert_context_options(ctx) | ||
| 187 | |||
| 188 | def test__create_stdlib_context(self): | ||
| 189 | ctx = ssl._create_stdlib_context() | ||
| 190 | self.assertEqual(ctx.protocol, ssl.PROTOCOL_SSLv23) | ||
| 191 | self.assertEqual(ctx.verify_mode, ssl.CERT_NONE) | ||
| 192 | self.assertFalse(ctx.check_hostname) | ||
| 193 | - self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2) | ||
| 194 | + self._assert_context_options(ctx) | ||
| 195 | |||
| 196 | ctx = ssl._create_stdlib_context(ssl.PROTOCOL_TLSv1) | ||
| 197 | self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1) | ||
| 198 | self.assertEqual(ctx.verify_mode, ssl.CERT_NONE) | ||
| 199 | - self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2) | ||
| 200 | + self._assert_context_options(ctx) | ||
| 201 | |||
| 202 | ctx = ssl._create_stdlib_context(ssl.PROTOCOL_TLSv1, | ||
| 203 | cert_reqs=ssl.CERT_REQUIRED, | ||
| 204 | @@ -1263,12 +1267,12 @@ class ContextTests(unittest.TestCase): | ||
| 205 | self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1) | ||
| 206 | self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED) | ||
| 207 | self.assertTrue(ctx.check_hostname) | ||
| 208 | - self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2) | ||
| 209 | + self._assert_context_options(ctx) | ||
| 210 | |||
| 211 | ctx = ssl._create_stdlib_context(purpose=ssl.Purpose.CLIENT_AUTH) | ||
| 212 | self.assertEqual(ctx.protocol, ssl.PROTOCOL_SSLv23) | ||
| 213 | self.assertEqual(ctx.verify_mode, ssl.CERT_NONE) | ||
| 214 | - self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2) | ||
| 215 | + self._assert_context_options(ctx) | ||
| 216 | |||
| 217 | def test_check_hostname(self): | ||
| 218 | ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) | ||
| 219 | diff --git a/Modules/_ssl.c b/Modules/_ssl.c | ||
| 220 | index 86482677ae..0d5c121d2c 100644 | ||
| 221 | --- a/Modules/_ssl.c | ||
| 222 | +++ b/Modules/_ssl.c | ||
| 223 | @@ -2330,6 +2330,7 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version) | ||
| 224 | PySSLContext *self; | ||
| 225 | long options; | ||
| 226 | SSL_CTX *ctx = NULL; | ||
| 227 | + int result; | ||
| 228 | #if defined(SSL_MODE_RELEASE_BUFFERS) | ||
| 229 | unsigned long libver; | ||
| 230 | #endif | ||
| 231 | @@ -2393,8 +2394,38 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version) | ||
| 232 | options |= SSL_OP_NO_SSLv2; | ||
| 233 | if (proto_version != PY_SSL_VERSION_SSL3) | ||
| 234 | options |= SSL_OP_NO_SSLv3; | ||
| 235 | + /* Minimal security flags for server and client side context. | ||
| 236 | + * Client sockets ignore server-side parameters. */ | ||
| 237 | +#ifdef SSL_OP_NO_COMPRESSION | ||
| 238 | + options |= SSL_OP_NO_COMPRESSION; | ||
| 239 | +#endif | ||
| 240 | +#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE | ||
| 241 | + options |= SSL_OP_CIPHER_SERVER_PREFERENCE; | ||
| 242 | +#endif | ||
| 243 | +#ifdef SSL_OP_SINGLE_DH_USE | ||
| 244 | + options |= SSL_OP_SINGLE_DH_USE; | ||
| 245 | +#endif | ||
| 246 | +#ifdef SSL_OP_SINGLE_ECDH_USE | ||
| 247 | + options |= SSL_OP_SINGLE_ECDH_USE; | ||
| 248 | +#endif | ||
| 249 | SSL_CTX_set_options(self->ctx, options); | ||
| 250 | |||
| 251 | + /* A bare minimum cipher list without completly broken cipher suites. | ||
| 252 | + * It's far from perfect but gives users a better head start. */ | ||
| 253 | + if (proto_version != PY_SSL_VERSION_SSL2) { | ||
| 254 | + result = SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL:!eNULL:!MD5"); | ||
| 255 | + } else { | ||
| 256 | + /* SSLv2 needs MD5 */ | ||
| 257 | + result = SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL:!eNULL"); | ||
| 258 | + } | ||
| 259 | + if (result == 0) { | ||
| 260 | + Py_DECREF(self); | ||
| 261 | + ERR_clear_error(); | ||
| 262 | + PyErr_SetString(PySSLErrorObject, | ||
| 263 | + "No cipher can be selected."); | ||
| 264 | + return NULL; | ||
| 265 | + } | ||
| 266 | + | ||
| 267 | #if defined(SSL_MODE_RELEASE_BUFFERS) | ||
| 268 | /* Set SSL_MODE_RELEASE_BUFFERS. This potentially greatly reduces memory | ||
| 269 | usage for no cost at all. However, don't do this for OpenSSL versions | ||
| 270 | -- | ||
| 271 | 2.17.1 | ||
| 272 | |||
diff --git a/meta/recipes-devtools/python/python3/0002-bpo-29136-Add-TLS-1.3-cipher-suites-and-OP_NO_TLSv1_.patch b/meta/recipes-devtools/python/python3/0002-bpo-29136-Add-TLS-1.3-cipher-suites-and-OP_NO_TLSv1_.patch new file mode 100644 index 0000000000..cb744deec8 --- /dev/null +++ b/meta/recipes-devtools/python/python3/0002-bpo-29136-Add-TLS-1.3-cipher-suites-and-OP_NO_TLSv1_.patch | |||
| @@ -0,0 +1,234 @@ | |||
| 1 | From 46c719ec4f79d6830c55ab7f5a03d826eabd0bd5 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Christian Heimes <christian@python.org> | ||
| 3 | Date: Thu, 7 Sep 2017 20:23:52 -0700 | ||
| 4 | Subject: [PATCH 2/4] bpo-29136: Add TLS 1.3 cipher suites and OP_NO_TLSv1_3 | ||
| 5 | (GH-1363) (#3444) | ||
| 6 | |||
| 7 | * bpo-29136: Add TLS 1.3 support | ||
| 8 | |||
| 9 | TLS 1.3 introduces a new, distinct set of cipher suites. The TLS 1.3 | ||
| 10 | cipher suites don't overlap with cipher suites from TLS 1.2 and earlier. | ||
| 11 | Since Python sets its own set of permitted ciphers, TLS 1.3 handshake | ||
| 12 | will fail as soon as OpenSSL 1.1.1 is released. Let's enable the common | ||
| 13 | AES-GCM and ChaCha20 suites. | ||
| 14 | |||
| 15 | Additionally the flag OP_NO_TLSv1_3 is added. It defaults to 0 (no op) with | ||
| 16 | OpenSSL prior to 1.1.1. This allows applications to opt-out from TLS 1.3 | ||
| 17 | now. | ||
| 18 | |||
| 19 | Signed-off-by: Christian Heimes <christian@python.org>. | ||
| 20 | (cherry picked from commit cb5b68abdeb1b1d56c581d5b4d647018703d61e3) | ||
| 21 | |||
| 22 | Upstream-Status: Backport | ||
| 23 | [https://github.com/python/cpython/commit/cb5b68abdeb1b1d56c581d5b4d647018703d61e3] | ||
| 24 | |||
| 25 | Signed-off-by: Anuj Mittal <anuj.mittal@intel.com> | ||
| 26 | --- | ||
| 27 | Doc/library/ssl.rst | 21 ++++++++++++++ | ||
| 28 | Lib/ssl.py | 14 +++++++++ | ||
| 29 | Lib/test/test_ssl.py | 29 ++++++++++++++++++- | ||
| 30 | .../2017-09-04-16-39-49.bpo-29136.vSn1oR.rst | 1 + | ||
| 31 | Modules/_ssl.c | 13 +++++++++ | ||
| 32 | 5 files changed, 77 insertions(+), 1 deletion(-) | ||
| 33 | create mode 100644 Misc/NEWS.d/next/Library/2017-09-04-16-39-49.bpo-29136.vSn1oR.rst | ||
| 34 | |||
| 35 | diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst | ||
| 36 | index 14f2d68217..29c5e94cf6 100644 | ||
| 37 | --- a/Doc/library/ssl.rst | ||
| 38 | +++ b/Doc/library/ssl.rst | ||
| 39 | @@ -285,6 +285,11 @@ purposes. | ||
| 40 | |||
| 41 | 3DES was dropped from the default cipher string. | ||
| 42 | |||
| 43 | + .. versionchanged:: 3.7 | ||
| 44 | + | ||
| 45 | + TLS 1.3 cipher suites TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384, | ||
| 46 | + and TLS_CHACHA20_POLY1305_SHA256 were added to the default cipher string. | ||
| 47 | + | ||
| 48 | |||
| 49 | Random generation | ||
| 50 | ^^^^^^^^^^^^^^^^^ | ||
| 51 | @@ -719,6 +724,16 @@ Constants | ||
| 52 | |||
| 53 | .. versionadded:: 3.4 | ||
| 54 | |||
| 55 | +.. data:: OP_NO_TLSv1_3 | ||
| 56 | + | ||
| 57 | + Prevents a TLSv1.3 connection. This option is only applicable in conjunction | ||
| 58 | + with :const:`PROTOCOL_TLS`. It prevents the peers from choosing TLSv1.3 as | ||
| 59 | + the protocol version. TLS 1.3 is available with OpenSSL 1.1.1 or later. | ||
| 60 | + When Python has been compiled against an older version of OpenSSL, the | ||
| 61 | + flag defaults to *0*. | ||
| 62 | + | ||
| 63 | + .. versionadded:: 3.7 | ||
| 64 | + | ||
| 65 | .. data:: OP_CIPHER_SERVER_PREFERENCE | ||
| 66 | |||
| 67 | Use the server's cipher ordering preference, rather than the client's. | ||
| 68 | @@ -783,6 +798,12 @@ Constants | ||
| 69 | |||
| 70 | .. versionadded:: 3.3 | ||
| 71 | |||
| 72 | +.. data:: HAS_TLSv1_3 | ||
| 73 | + | ||
| 74 | + Whether the OpenSSL library has built-in support for the TLS 1.3 protocol. | ||
| 75 | + | ||
| 76 | + .. versionadded:: 3.7 | ||
| 77 | + | ||
| 78 | .. data:: CHANNEL_BINDING_TYPES | ||
| 79 | |||
| 80 | List of supported TLS channel binding types. Strings in this list | ||
| 81 | diff --git a/Lib/ssl.py b/Lib/ssl.py | ||
| 82 | index 4d302a78fa..ac2c0cbaf3 100644 | ||
| 83 | --- a/Lib/ssl.py | ||
| 84 | +++ b/Lib/ssl.py | ||
| 85 | @@ -122,6 +122,14 @@ _import_symbols('OP_') | ||
| 86 | _import_symbols('ALERT_DESCRIPTION_') | ||
| 87 | _import_symbols('SSL_ERROR_') | ||
| 88 | _import_symbols('VERIFY_') | ||
| 89 | +from _ssl import HAS_SNI, HAS_ECDH, HAS_NPN, HAS_ALPN, HAS_TLSv1_3 | ||
| 90 | +from _ssl import _OPENSSL_API_VERSION | ||
| 91 | + | ||
| 92 | + | ||
| 93 | +_IntEnum._convert( | ||
| 94 | + '_SSLMethod', __name__, | ||
| 95 | + lambda name: name.startswith('PROTOCOL_') and name != 'PROTOCOL_SSLv23', | ||
| 96 | + source=_ssl) | ||
| 97 | |||
| 98 | from _ssl import HAS_SNI, HAS_ECDH, HAS_NPN, HAS_ALPN | ||
| 99 | |||
| 100 | @@ -162,6 +170,7 @@ else: | ||
| 101 | # (OpenSSL's default setting is 'DEFAULT:!aNULL:!eNULL') | ||
| 102 | # Enable a better set of ciphers by default | ||
| 103 | # This list has been explicitly chosen to: | ||
| 104 | +# * TLS 1.3 ChaCha20 and AES-GCM cipher suites | ||
| 105 | # * Prefer cipher suites that offer perfect forward secrecy (DHE/ECDHE) | ||
| 106 | # * Prefer ECDHE over DHE for better performance | ||
| 107 | # * Prefer AEAD over CBC for better performance and security | ||
| 108 | @@ -173,6 +182,8 @@ else: | ||
| 109 | # * Disable NULL authentication, NULL encryption, 3DES and MD5 MACs | ||
| 110 | # for security reasons | ||
| 111 | _DEFAULT_CIPHERS = ( | ||
| 112 | + 'TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:' | ||
| 113 | + 'TLS13-AES-128-GCM-SHA256:' | ||
| 114 | 'ECDH+AESGCM:ECDH+CHACHA20:DH+AESGCM:DH+CHACHA20:ECDH+AES256:DH+AES256:' | ||
| 115 | 'ECDH+AES128:DH+AES:ECDH+HIGH:DH+HIGH:RSA+AESGCM:RSA+AES:RSA+HIGH:' | ||
| 116 | '!aNULL:!eNULL:!MD5:!3DES' | ||
| 117 | @@ -180,6 +191,7 @@ _DEFAULT_CIPHERS = ( | ||
| 118 | |||
| 119 | # Restricted and more secure ciphers for the server side | ||
| 120 | # This list has been explicitly chosen to: | ||
| 121 | +# * TLS 1.3 ChaCha20 and AES-GCM cipher suites | ||
| 122 | # * Prefer cipher suites that offer perfect forward secrecy (DHE/ECDHE) | ||
| 123 | # * Prefer ECDHE over DHE for better performance | ||
| 124 | # * Prefer AEAD over CBC for better performance and security | ||
| 125 | @@ -190,6 +202,8 @@ _DEFAULT_CIPHERS = ( | ||
| 126 | # * Disable NULL authentication, NULL encryption, MD5 MACs, DSS, RC4, and | ||
| 127 | # 3DES for security reasons | ||
| 128 | _RESTRICTED_SERVER_CIPHERS = ( | ||
| 129 | + 'TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:' | ||
| 130 | + 'TLS13-AES-128-GCM-SHA256:' | ||
| 131 | 'ECDH+AESGCM:ECDH+CHACHA20:DH+AESGCM:DH+CHACHA20:ECDH+AES256:DH+AES256:' | ||
| 132 | 'ECDH+AES128:DH+AES:ECDH+HIGH:DH+HIGH:RSA+AESGCM:RSA+AES:RSA+HIGH:' | ||
| 133 | '!aNULL:!eNULL:!MD5:!DSS:!RC4:!3DES' | ||
| 134 | diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py | ||
| 135 | index f91af7bd05..1acc12ec2d 100644 | ||
| 136 | --- a/Lib/test/test_ssl.py | ||
| 137 | +++ b/Lib/test/test_ssl.py | ||
| 138 | @@ -150,6 +150,13 @@ class BasicSocketTests(unittest.TestCase): | ||
| 139 | ssl.OP_NO_COMPRESSION | ||
| 140 | self.assertIn(ssl.HAS_SNI, {True, False}) | ||
| 141 | self.assertIn(ssl.HAS_ECDH, {True, False}) | ||
| 142 | + ssl.OP_NO_SSLv2 | ||
| 143 | + ssl.OP_NO_SSLv3 | ||
| 144 | + ssl.OP_NO_TLSv1 | ||
| 145 | + ssl.OP_NO_TLSv1_3 | ||
| 146 | + if ssl.OPENSSL_VERSION_INFO >= (1, 0, 1): | ||
| 147 | + ssl.OP_NO_TLSv1_1 | ||
| 148 | + ssl.OP_NO_TLSv1_2 | ||
| 149 | |||
| 150 | def test_str_for_enums(self): | ||
| 151 | # Make sure that the PROTOCOL_* constants have enum-like string | ||
| 152 | @@ -3028,12 +3035,33 @@ else: | ||
| 153 | self.assertEqual(s.version(), 'TLSv1') | ||
| 154 | self.assertIs(s.version(), None) | ||
| 155 | |||
| 156 | + @unittest.skipUnless(ssl.HAS_TLSv1_3, | ||
| 157 | + "test requires TLSv1.3 enabled OpenSSL") | ||
| 158 | + def test_tls1_3(self): | ||
| 159 | + context = ssl.SSLContext(ssl.PROTOCOL_TLS) | ||
| 160 | + context.load_cert_chain(CERTFILE) | ||
| 161 | + # disable all but TLS 1.3 | ||
| 162 | + context.options |= ( | ||
| 163 | + ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1 | ssl.OP_NO_TLSv1_2 | ||
| 164 | + ) | ||
| 165 | + with ThreadedEchoServer(context=context) as server: | ||
| 166 | + with context.wrap_socket(socket.socket()) as s: | ||
| 167 | + s.connect((HOST, server.port)) | ||
| 168 | + self.assertIn(s.cipher()[0], [ | ||
| 169 | + 'TLS13-AES-256-GCM-SHA384', | ||
| 170 | + 'TLS13-CHACHA20-POLY1305-SHA256', | ||
| 171 | + 'TLS13-AES-128-GCM-SHA256', | ||
| 172 | + ]) | ||
| 173 | + | ||
| 174 | @unittest.skipUnless(ssl.HAS_ECDH, "test requires ECDH-enabled OpenSSL") | ||
| 175 | def test_default_ecdh_curve(self): | ||
| 176 | # Issue #21015: elliptic curve-based Diffie Hellman key exchange | ||
| 177 | # should be enabled by default on SSL contexts. | ||
| 178 | context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) | ||
| 179 | context.load_cert_chain(CERTFILE) | ||
| 180 | + # TLSv1.3 defaults to PFS key agreement and no longer has KEA in | ||
| 181 | + # cipher name. | ||
| 182 | + context.options |= ssl.OP_NO_TLSv1_3 | ||
| 183 | # Prior to OpenSSL 1.0.0, ECDH ciphers have to be enabled | ||
| 184 | # explicitly using the 'ECCdraft' cipher alias. Otherwise, | ||
| 185 | # our default cipher list should prefer ECDH-based ciphers | ||
| 186 | @@ -3394,7 +3422,6 @@ else: | ||
| 187 | s.sendfile(file) | ||
| 188 | self.assertEqual(s.recv(1024), TEST_DATA) | ||
| 189 | |||
| 190 | - | ||
| 191 | def test_main(verbose=False): | ||
| 192 | if support.verbose: | ||
| 193 | import warnings | ||
| 194 | diff --git a/Misc/NEWS.d/next/Library/2017-09-04-16-39-49.bpo-29136.vSn1oR.rst b/Misc/NEWS.d/next/Library/2017-09-04-16-39-49.bpo-29136.vSn1oR.rst | ||
| 195 | new file mode 100644 | ||
| 196 | index 0000000000..e76997ef83 | ||
| 197 | --- /dev/null | ||
| 198 | +++ b/Misc/NEWS.d/next/Library/2017-09-04-16-39-49.bpo-29136.vSn1oR.rst | ||
| 199 | @@ -0,0 +1 @@ | ||
| 200 | +Add TLS 1.3 cipher suites and OP_NO_TLSv1_3. | ||
| 201 | diff --git a/Modules/_ssl.c b/Modules/_ssl.c | ||
| 202 | index 0d5c121d2c..c71d89607c 100644 | ||
| 203 | --- a/Modules/_ssl.c | ||
| 204 | +++ b/Modules/_ssl.c | ||
| 205 | @@ -4842,6 +4842,11 @@ PyInit__ssl(void) | ||
| 206 | #if HAVE_TLSv1_2 | ||
| 207 | PyModule_AddIntConstant(m, "OP_NO_TLSv1_1", SSL_OP_NO_TLSv1_1); | ||
| 208 | PyModule_AddIntConstant(m, "OP_NO_TLSv1_2", SSL_OP_NO_TLSv1_2); | ||
| 209 | +#endif | ||
| 210 | +#ifdef SSL_OP_NO_TLSv1_3 | ||
| 211 | + PyModule_AddIntConstant(m, "OP_NO_TLSv1_3", SSL_OP_NO_TLSv1_3); | ||
| 212 | +#else | ||
| 213 | + PyModule_AddIntConstant(m, "OP_NO_TLSv1_3", 0); | ||
| 214 | #endif | ||
| 215 | PyModule_AddIntConstant(m, "OP_CIPHER_SERVER_PREFERENCE", | ||
| 216 | SSL_OP_CIPHER_SERVER_PREFERENCE); | ||
| 217 | @@ -4890,6 +4895,14 @@ PyInit__ssl(void) | ||
| 218 | Py_INCREF(r); | ||
| 219 | PyModule_AddObject(m, "HAS_ALPN", r); | ||
| 220 | |||
| 221 | +#if defined(TLS1_3_VERSION) && !defined(OPENSSL_NO_TLS1_3) | ||
| 222 | + r = Py_True; | ||
| 223 | +#else | ||
| 224 | + r = Py_False; | ||
| 225 | +#endif | ||
| 226 | + Py_INCREF(r); | ||
| 227 | + PyModule_AddObject(m, "HAS_TLSv1_3", r); | ||
| 228 | + | ||
| 229 | /* Mappings for error codes */ | ||
| 230 | err_codes_to_names = PyDict_New(); | ||
| 231 | err_names_to_codes = PyDict_New(); | ||
| 232 | -- | ||
| 233 | 2.17.1 | ||
| 234 | |||
diff --git a/meta/recipes-devtools/python/python3/0003-bpo-32947-Fixes-for-TLS-1.3-and-OpenSSL-1.1.1-GH-876.patch b/meta/recipes-devtools/python/python3/0003-bpo-32947-Fixes-for-TLS-1.3-and-OpenSSL-1.1.1-GH-876.patch new file mode 100644 index 0000000000..56d591d1b5 --- /dev/null +++ b/meta/recipes-devtools/python/python3/0003-bpo-32947-Fixes-for-TLS-1.3-and-OpenSSL-1.1.1-GH-876.patch | |||
| @@ -0,0 +1,173 @@ | |||
| 1 | From 170a614904febd14ff6cfd7a75c9bccc114b3948 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Christian Heimes <christian@python.org> | ||
| 3 | Date: Tue, 14 Aug 2018 16:56:32 +0200 | ||
| 4 | Subject: [PATCH] bpo-32947: Fixes for TLS 1.3 and OpenSSL 1.1.1 (GH-8761) | ||
| 5 | |||
| 6 | Backport of TLS 1.3 related fixes from 3.7. | ||
| 7 | |||
| 8 | Misc fixes and workarounds for compatibility with OpenSSL 1.1.1 from git | ||
| 9 | master and TLS 1.3 support. With OpenSSL 1.1.1, Python negotiates TLS 1.3 by | ||
| 10 | default. Some test cases only apply to TLS 1.2. | ||
| 11 | |||
| 12 | OpenSSL 1.1.1 has added a new option OP_ENABLE_MIDDLEBOX_COMPAT for TLS | ||
| 13 | 1.3. The feature is enabled by default for maximum compatibility with | ||
| 14 | broken middle boxes. Users should be able to disable the hack and CPython's test suite needs | ||
| 15 | it to verify default options | ||
| 16 | |||
| 17 | Signed-off-by: Christian Heimes <christian@python.org> | ||
| 18 | |||
| 19 | Upstream-Status: Backport | ||
| 20 | [https://github.com/python/cpython/commit/2a4ee8aa01d61b6a9c8e9c65c211e61bdb471826] | ||
| 21 | |||
| 22 | Signed-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 | |||
| 32 | diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst | ||
| 33 | index 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 | ||
| 52 | diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py | ||
| 53 | index 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): | ||
| 69 | diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py | ||
| 70 | index 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() | ||
| 148 | 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 | ||
| 149 | new file mode 100644 | ||
| 150 | index 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. | ||
| 156 | diff --git a/Modules/_ssl.c b/Modules/_ssl.c | ||
| 157 | index 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 | -- | ||
| 172 | 2.17.1 | ||
| 173 | |||
diff --git a/meta/recipes-devtools/python/python3/0004-bpo-33570-TLS-1.3-ciphers-for-OpenSSL-1.1.1-GH-6976.patch b/meta/recipes-devtools/python/python3/0004-bpo-33570-TLS-1.3-ciphers-for-OpenSSL-1.1.1-GH-6976.patch new file mode 100644 index 0000000000..b97d5501e1 --- /dev/null +++ b/meta/recipes-devtools/python/python3/0004-bpo-33570-TLS-1.3-ciphers-for-OpenSSL-1.1.1-GH-6976.patch | |||
| @@ -0,0 +1,110 @@ | |||
| 1 | From 0c9354362bfa5f90fbea8ff8237a1f1f5dba686f Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Christian Heimes <christian@python.org> | ||
| 3 | Date: Wed, 12 Sep 2018 15:20:31 +0800 | ||
| 4 | Subject: [PATCH] bpo-33570: TLS 1.3 ciphers for OpenSSL 1.1.1 (GH-6976) | ||
| 5 | |||
| 6 | Change TLS 1.3 cipher suite settings for compatibility with OpenSSL | ||
| 7 | 1.1.1-pre6 and newer. OpenSSL 1.1.1 will have TLS 1.3 cipers enabled by | ||
| 8 | default. | ||
| 9 | |||
| 10 | Also update multissltests and Travis config to test with latest OpenSSL. | ||
| 11 | |||
| 12 | Signed-off-by: Christian Heimes <christian@python.org> | ||
| 13 | (cherry picked from commit e8eb6cb7920ded66abc5d284319a8539bdc2bae3) | ||
| 14 | |||
| 15 | Co-authored-by: Christian Heimes <christian@python.org | ||
| 16 | |||
| 17 | Upstream-Status: Backport | ||
| 18 | [https://github.com/python/cpython/commit/3e630c541b35c96bfe5619165255e559f577ee71] | ||
| 19 | |||
| 20 | Tweaked patch to not take changes for multissltests and Travis config. | ||
| 21 | |||
| 22 | Signed-off-by: Anuj Mittal <anuj.mittal@intel.com> | ||
| 23 | --- | ||
| 24 | Lib/test/test_ssl.py | 51 ++++++++++++++++++++++---------------------- | ||
| 25 | 1 file changed, 26 insertions(+), 25 deletions(-) | ||
| 26 | |||
| 27 | diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py | ||
| 28 | index a2e1d32a62..c484ead5ff 100644 | ||
| 29 | --- a/Lib/test/test_ssl.py | ||
| 30 | +++ b/Lib/test/test_ssl.py | ||
| 31 | @@ -3024,17 +3024,21 @@ else: | ||
| 32 | sock.do_handshake() | ||
| 33 | self.assertEqual(cm.exception.errno, errno.ENOTCONN) | ||
| 34 | |||
| 35 | - def test_default_ciphers(self): | ||
| 36 | - context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) | ||
| 37 | - try: | ||
| 38 | - # Force a set of weak ciphers on our client context | ||
| 39 | - context.set_ciphers("DES") | ||
| 40 | - except ssl.SSLError: | ||
| 41 | - self.skipTest("no DES cipher available") | ||
| 42 | - with ThreadedEchoServer(CERTFILE, | ||
| 43 | - ssl_version=ssl.PROTOCOL_SSLv23, | ||
| 44 | - chatty=False) as server: | ||
| 45 | - with context.wrap_socket(socket.socket()) as s: | ||
| 46 | + def test_no_shared_ciphers(self): | ||
| 47 | + server_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) | ||
| 48 | + server_context.load_cert_chain(SIGNED_CERTFILE) | ||
| 49 | + client_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) | ||
| 50 | + client_context.verify_mode = ssl.CERT_REQUIRED | ||
| 51 | + client_context.check_hostname = True | ||
| 52 | + | ||
| 53 | + client_context.set_ciphers("AES128") | ||
| 54 | + server_context.set_ciphers("AES256") | ||
| 55 | + # OpenSSL enables all TLS 1.3 ciphers, enforce TLS 1.2 for test | ||
| 56 | + client_context.options |= ssl.OP_NO_TLSv1_3 | ||
| 57 | + with ThreadedEchoServer(context=server_context) as server: | ||
| 58 | + with client_context.wrap_socket( | ||
| 59 | + socket.socket(), | ||
| 60 | + server_hostname="localhost") as s: | ||
| 61 | with self.assertRaises(OSError): | ||
| 62 | s.connect((HOST, server.port)) | ||
| 63 | self.assertIn("no shared cipher", str(server.conn_errors[0])) | ||
| 64 | @@ -3067,9 +3071,9 @@ else: | ||
| 65 | with context.wrap_socket(socket.socket()) as s: | ||
| 66 | s.connect((HOST, server.port)) | ||
| 67 | self.assertIn(s.cipher()[0], [ | ||
| 68 | - 'TLS13-AES-256-GCM-SHA384', | ||
| 69 | - 'TLS13-CHACHA20-POLY1305-SHA256', | ||
| 70 | - 'TLS13-AES-128-GCM-SHA256', | ||
| 71 | + 'TLS_AES_256_GCM_SHA384', | ||
| 72 | + 'TLS_CHACHA20_POLY1305_SHA256', | ||
| 73 | + 'TLS_AES_128_GCM_SHA256', | ||
| 74 | ]) | ||
| 75 | |||
| 76 | @unittest.skipUnless(ssl.HAS_ECDH, "test requires ECDH-enabled OpenSSL") | ||
| 77 | @@ -3391,22 +3395,19 @@ else: | ||
| 78 | client_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) | ||
| 79 | client_context.verify_mode = ssl.CERT_REQUIRED | ||
| 80 | client_context.load_verify_locations(SIGNING_CA) | ||
| 81 | - if ssl.OPENSSL_VERSION_INFO >= (1, 0, 2): | ||
| 82 | - client_context.set_ciphers("AES128:AES256") | ||
| 83 | - server_context.set_ciphers("AES256") | ||
| 84 | - alg1 = "AES256" | ||
| 85 | - alg2 = "AES-256" | ||
| 86 | - else: | ||
| 87 | - client_context.set_ciphers("AES:3DES") | ||
| 88 | - server_context.set_ciphers("3DES") | ||
| 89 | - alg1 = "3DES" | ||
| 90 | - alg2 = "DES-CBC3" | ||
| 91 | + client_context.set_ciphers("AES128:AES256") | ||
| 92 | + server_context.set_ciphers("AES256") | ||
| 93 | + expected_algs = [ | ||
| 94 | + "AES256", "AES-256", | ||
| 95 | + # TLS 1.3 ciphers are always enabled | ||
| 96 | + "TLS_CHACHA20", "TLS_AES", | ||
| 97 | + ] | ||
| 98 | |||
| 99 | stats = server_params_test(client_context, server_context) | ||
| 100 | ciphers = stats['server_shared_ciphers'][0] | ||
| 101 | self.assertGreater(len(ciphers), 0) | ||
| 102 | for name, tls_version, bits in ciphers: | ||
| 103 | - if not alg1 in name.split("-") and alg2 not in name: | ||
| 104 | + if not any (alg in name for alg in expected_algs): | ||
| 105 | self.fail(name) | ||
| 106 | |||
| 107 | def test_read_write_after_close_raises_valuerror(self): | ||
| 108 | -- | ||
| 109 | 2.17.1 | ||
| 110 | |||
diff --git a/meta/recipes-devtools/python/python3/0005-bpo-30714-ALPN-changes-for-OpenSSL-1.1.0f-2305.patch b/meta/recipes-devtools/python/python3/0005-bpo-30714-ALPN-changes-for-OpenSSL-1.1.0f-2305.patch new file mode 100644 index 0000000000..d609847204 --- /dev/null +++ b/meta/recipes-devtools/python/python3/0005-bpo-30714-ALPN-changes-for-OpenSSL-1.1.0f-2305.patch | |||
| @@ -0,0 +1,68 @@ | |||
| 1 | From 7b40cb7293cb14e5c7c8ed123efaf9acb33edae2 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Christian Heimes <christian@python.org> | ||
| 3 | Date: Tue, 15 Aug 2017 10:33:43 +0200 | ||
| 4 | Subject: [PATCH] bpo-30714: ALPN changes for OpenSSL 1.1.0f (#2305) | ||
| 5 | |||
| 6 | OpenSSL 1.1.0 to 1.1.0e aborted the handshake when server and client | ||
| 7 | could not agree on a protocol using ALPN. OpenSSL 1.1.0f changed that. | ||
| 8 | The most recent version now behaves like OpenSSL 1.0.2 again. The ALPN | ||
| 9 | callback can pretend to not been set. | ||
| 10 | |||
| 11 | See https://github.com/openssl/openssl/pull/3158 for more details | ||
| 12 | |||
| 13 | Signed-off-by: Christian Heimes <christian@python.org> | ||
| 14 | |||
| 15 | Upstream-Status: Backport | ||
| 16 | [https://github.com/python/cpython/commit/7b40cb7293cb14e5c7c8ed123efaf9acb33edae2] | ||
| 17 | |||
| 18 | Signed-off-by: Anuj Mittal <anuj.mittal@intel.com> | ||
| 19 | --- | ||
| 20 | Doc/library/ssl.rst | 5 +++-- | ||
| 21 | Lib/test/test_ssl.py | 5 +++-- | ||
| 22 | .../next/Tests/2017-07-25-15-27-44.bpo-30715.Sp7bTF.rst | 2 ++ | ||
| 23 | 3 files changed, 8 insertions(+), 4 deletions(-) | ||
| 24 | create mode 100644 Misc/NEWS.d/next/Tests/2017-07-25-15-27-44.bpo-30715.Sp7bTF.rst | ||
| 25 | |||
| 26 | diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst | ||
| 27 | index 729a239a1b..0a09e7e9d4 100644 | ||
| 28 | --- a/Doc/library/ssl.rst | ||
| 29 | +++ b/Doc/library/ssl.rst | ||
| 30 | @@ -1447,8 +1447,9 @@ to speed up repeated connections from the same clients. | ||
| 31 | This method will raise :exc:`NotImplementedError` if :data:`HAS_ALPN` is | ||
| 32 | False. | ||
| 33 | |||
| 34 | - OpenSSL 1.1.0+ will abort the handshake and raise :exc:`SSLError` when | ||
| 35 | - both sides support ALPN but cannot agree on a protocol. | ||
| 36 | + OpenSSL 1.1.0 to 1.1.0e will abort the handshake and raise :exc:`SSLError` | ||
| 37 | + when both sides support ALPN but cannot agree on a protocol. 1.1.0f+ | ||
| 38 | + behaves like 1.0.2, :meth:`SSLSocket.selected_alpn_protocol` returns None. | ||
| 39 | |||
| 40 | .. versionadded:: 3.5 | ||
| 41 | |||
| 42 | diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py | ||
| 43 | index d960d82065..104b7f377a 100644 | ||
| 44 | --- a/Lib/test/test_ssl.py | ||
| 45 | +++ b/Lib/test/test_ssl.py | ||
| 46 | @@ -3268,8 +3268,9 @@ if _have_threads: | ||
| 47 | except ssl.SSLError as e: | ||
| 48 | stats = e | ||
| 49 | |||
| 50 | - if expected is None and IS_OPENSSL_1_1: | ||
| 51 | - # OpenSSL 1.1.0 raises handshake error | ||
| 52 | + if (expected is None and IS_OPENSSL_1_1 | ||
| 53 | + and ssl.OPENSSL_VERSION_INFO < (1, 1, 0, 6)): | ||
| 54 | + # OpenSSL 1.1.0 to 1.1.0e raises handshake error | ||
| 55 | self.assertIsInstance(stats, ssl.SSLError) | ||
| 56 | else: | ||
| 57 | msg = "failed trying %s (s) and %s (c).\n" \ | ||
| 58 | diff --git a/Misc/NEWS.d/next/Tests/2017-07-25-15-27-44.bpo-30715.Sp7bTF.rst b/Misc/NEWS.d/next/Tests/2017-07-25-15-27-44.bpo-30715.Sp7bTF.rst | ||
| 59 | new file mode 100644 | ||
| 60 | index 0000000000..88394e585c | ||
| 61 | --- /dev/null | ||
| 62 | +++ b/Misc/NEWS.d/next/Tests/2017-07-25-15-27-44.bpo-30715.Sp7bTF.rst | ||
| 63 | @@ -0,0 +1,2 @@ | ||
| 64 | +Address ALPN callback changes for OpenSSL 1.1.0f. The latest version behaves | ||
| 65 | +like OpenSSL 1.0.2 and no longer aborts handshake. | ||
| 66 | -- | ||
| 67 | 2.17.1 | ||
| 68 | |||
