diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst index 21077e0f4b42be..5e2032dbc94dce 100644 --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -920,6 +920,16 @@ Constants .. versionadded:: 3.10 +.. data:: OP_LEGACY_SERVER_CONNECT + + Allow legacy insecure renegotiation between OpenSSL and unpatched servers + only. + + This option is only available with OpenSSL 0.9.8m and later, and is disabled + in default context since OpenSSL 3.0.0. + + .. versionadded:: 3.11 + .. data:: HAS_ALPN Whether the OpenSSL library has built-in support for the *Application-Layer diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index d9e184365ce082..b53f092936d055 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -157,6 +157,7 @@ def data_file(*name): OP_CIPHER_SERVER_PREFERENCE = getattr(ssl, "OP_CIPHER_SERVER_PREFERENCE", 0) OP_ENABLE_MIDDLEBOX_COMPAT = getattr(ssl, "OP_ENABLE_MIDDLEBOX_COMPAT", 0) OP_IGNORE_UNEXPECTED_EOF = getattr(ssl, "OP_IGNORE_UNEXPECTED_EOF", 0) +OP_LEGACY_SERVER_CONNECT = getattr(ssl, "OP_LEGACY_SERVER_CONNECT", 0) # Ubuntu has patched OpenSSL and changed behavior of security level 2 # see https://bugs.python.org/issue41561#msg389003 @@ -1191,6 +1192,9 @@ def test_options(self): ctx.options = 0 # Ubuntu has OP_NO_SSLv3 forced on by default self.assertEqual(0, ctx.options & ~ssl.OP_NO_SSLv3) + # 0.9.8m or later + if ssl.OPENSSL_VERSION_INFO >= (0, 9, 8, 13, 15): + self.assertNotEqual(OP_LEGACY_SERVER_CONNECT, 0) def test_verify_mode_protocol(self): with warnings_helper.check_warnings(): @@ -1681,6 +1685,12 @@ def _assert_context_options(self, ctx): if OP_CIPHER_SERVER_PREFERENCE != 0: self.assertEqual(ctx.options & OP_CIPHER_SERVER_PREFERENCE, OP_CIPHER_SERVER_PREFERENCE) + if OP_LEGACY_SERVER_CONNECT != 0: + if IS_OPENSSL_3_0_0: + self.assertEqual(ctx.options & OP_LEGACY_SERVER_CONNECT, 0) + else: + self.assertEqual(ctx.options & OP_LEGACY_SERVER_CONNECT, + OP_LEGACY_SERVER_CONNECT) def test_create_default_context(self): ctx = ssl.create_default_context() @@ -4073,6 +4083,18 @@ def test_compression_disabled(self): sni_name=hostname) self.assertIs(stats['compression'], None) + @unittest.skipUnless(hasattr(ssl, 'OP_LEGACY_SERVER_CONNECT'), + "ssl.OP_LEGACY_SERVER_CONNECT needed for this test") + def test_legacy_server_connect(self): + client_context, server_context, hostname = testing_context() + if IS_OPENSSL_3_0_0: + client_context.options |= ssl.OP_LEGACY_SERVER_CONNECT + else: + client_context.options &= ~ssl.OP_LEGACY_SERVER_CONNECT + stats = server_params_test(client_context, server_context, + chatty=True, connectionchatty=True, + sni_name=hostname) + @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows") def test_dh_params(self): # Check we can get a connection with ephemeral Diffie-Hellman diff --git a/Misc/NEWS.d/next/Library/2021-08-18-05-14-36.bpo-44888.kpmYjl.rst b/Misc/NEWS.d/next/Library/2021-08-18-05-14-36.bpo-44888.kpmYjl.rst new file mode 100644 index 00000000000000..5c8164863b8192 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-08-18-05-14-36.bpo-44888.kpmYjl.rst @@ -0,0 +1 @@ +Add :data:`ssl.OP_LEGACY_SERVER_CONNECT` diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 84cc3697b07063..486ff1be79467c 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -5890,6 +5890,10 @@ sslmodule_init_constants(PyObject *m) PyModule_AddIntConstant(m, "OP_IGNORE_UNEXPECTED_EOF", SSL_OP_IGNORE_UNEXPECTED_EOF); #endif +#ifdef SSL_OP_LEGACY_SERVER_CONNECT + PyModule_AddIntConstant(m, "OP_LEGACY_SERVER_CONNECT", + SSL_OP_LEGACY_SERVER_CONNECT); +#endif #ifdef X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT PyModule_AddIntConstant(m, "HOSTFLAG_ALWAYS_CHECK_SUBJECT",