From 6e8cda91d92da72800d891b2fc2073ecbc134d98 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Sat, 16 May 2020 03:33:05 +0200 Subject: [PATCH] bpo-40457: Support OpenSSL without TLS 1.0/1.1 (GH-19862) OpenSSL can be build without support for TLS 1.0 and 1.1. The ssl module now correctly adheres to OPENSSL_NO_TLS1 and OPENSSL_NO_TLS1_1 flags. Also update multissltest to test with latest OpenSSL and LibreSSL releases. Signed-off-by: Christian Heimes Automerge-Triggered-By: @tiran --- .../2020-05-02-17-17-37.bpo-40457.EXReI1.rst | 1 + Modules/_ssl.c | 63 +++++++++---------- Tools/ssl/multissltests.py | 9 +-- 3 files changed, 34 insertions(+), 39 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-05-02-17-17-37.bpo-40457.EXReI1.rst diff --git a/Misc/NEWS.d/next/Library/2020-05-02-17-17-37.bpo-40457.EXReI1.rst b/Misc/NEWS.d/next/Library/2020-05-02-17-17-37.bpo-40457.EXReI1.rst new file mode 100644 index 00000000000..19b6dd685cd --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-05-02-17-17-37.bpo-40457.EXReI1.rst @@ -0,0 +1 @@ +The ssl module now support OpenSSL builds without TLS 1.0 and 1.1 methods. diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 987a9917877..5fe65a8a1d6 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -147,15 +147,6 @@ static void _PySSLFixErrno(void) { # define PY_OPENSSL_1_1_API 1 #endif -/* Openssl comes with TLSv1.1 and TLSv1.2 between 1.0.0h and 1.0.1 - http://www.openssl.org/news/changelog.html - */ -#if OPENSSL_VERSION_NUMBER >= 0x10001000L -# define HAVE_TLSv1_2 1 -#else -# define HAVE_TLSv1_2 0 -#endif - /* SNI support (client- and server-side) appeared in OpenSSL 1.0.0 and 0.9.8f * This includes the SSL_set_SSL_CTX() function. */ @@ -326,13 +317,9 @@ enum py_ssl_version { PY_SSL_VERSION_SSL2, PY_SSL_VERSION_SSL3=1, PY_SSL_VERSION_TLS, /* SSLv23 */ -#if HAVE_TLSv1_2 PY_SSL_VERSION_TLS1, PY_SSL_VERSION_TLS1_1, PY_SSL_VERSION_TLS1_2, -#else - PY_SSL_VERSION_TLS1, -#endif PY_SSL_VERSION_TLS_CLIENT=0x10, PY_SSL_VERSION_TLS_SERVER, }; @@ -3086,35 +3073,45 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version) #endif PySSL_BEGIN_ALLOW_THREADS - if (proto_version == PY_SSL_VERSION_TLS1) - ctx = SSL_CTX_new(TLSv1_method()); -#if HAVE_TLSv1_2 - else if (proto_version == PY_SSL_VERSION_TLS1_1) - ctx = SSL_CTX_new(TLSv1_1_method()); - else if (proto_version == PY_SSL_VERSION_TLS1_2) - ctx = SSL_CTX_new(TLSv1_2_method()); -#endif -#ifndef OPENSSL_NO_SSL3 - else if (proto_version == PY_SSL_VERSION_SSL3) + switch(proto_version) { +#if defined(SSL3_VERSION) && !defined(OPENSSL_NO_SSL3) + case PY_SSL_VERSION_SSL3: ctx = SSL_CTX_new(SSLv3_method()); + break; #endif -#ifndef OPENSSL_NO_SSL2 - else if (proto_version == PY_SSL_VERSION_SSL2) - ctx = SSL_CTX_new(SSLv2_method()); +#if defined(TLS1_VERSION) && !defined(OPENSSL_NO_TLS1) + case PY_SSL_VERSION_TLS1: + ctx = SSL_CTX_new(TLSv1_method()); + break; #endif - else if (proto_version == PY_SSL_VERSION_TLS) /* SSLv23 */ +#if defined(TLS1_1_VERSION) && !defined(OPENSSL_NO_TLS1_1) + case PY_SSL_VERSION_TLS1_1: + ctx = SSL_CTX_new(TLSv1_1_method()); + break; +#endif +#if defined(TLS1_2_VERSION) && !defined(OPENSSL_NO_TLS1_2) + case PY_SSL_VERSION_TLS1_2: + ctx = SSL_CTX_new(TLSv1_2_method()); + break; +#endif + case PY_SSL_VERSION_TLS: + /* SSLv23 */ ctx = SSL_CTX_new(TLS_method()); - else if (proto_version == PY_SSL_VERSION_TLS_CLIENT) + break; + case PY_SSL_VERSION_TLS_CLIENT: ctx = SSL_CTX_new(TLS_client_method()); - else if (proto_version == PY_SSL_VERSION_TLS_SERVER) + break; + case PY_SSL_VERSION_TLS_SERVER: ctx = SSL_CTX_new(TLS_server_method()); - else + break; + default: proto_version = -1; + } PySSL_END_ALLOW_THREADS if (proto_version == -1) { PyErr_SetString(PyExc_ValueError, - "invalid protocol version"); + "invalid or unsupported protocol version"); return NULL; } if (ctx == NULL) { @@ -6185,12 +6182,10 @@ PyInit__ssl(void) PY_SSL_VERSION_TLS_SERVER); PyModule_AddIntConstant(m, "PROTOCOL_TLSv1", PY_SSL_VERSION_TLS1); -#if HAVE_TLSv1_2 PyModule_AddIntConstant(m, "PROTOCOL_TLSv1_1", PY_SSL_VERSION_TLS1_1); PyModule_AddIntConstant(m, "PROTOCOL_TLSv1_2", PY_SSL_VERSION_TLS1_2); -#endif /* protocol options */ PyModule_AddIntConstant(m, "OP_ALL", @@ -6198,10 +6193,8 @@ PyInit__ssl(void) PyModule_AddIntConstant(m, "OP_NO_SSLv2", SSL_OP_NO_SSLv2); PyModule_AddIntConstant(m, "OP_NO_SSLv3", SSL_OP_NO_SSLv3); PyModule_AddIntConstant(m, "OP_NO_TLSv1", SSL_OP_NO_TLSv1); -#if HAVE_TLSv1_2 PyModule_AddIntConstant(m, "OP_NO_TLSv1_1", SSL_OP_NO_TLSv1_1); PyModule_AddIntConstant(m, "OP_NO_TLSv1_2", SSL_OP_NO_TLSv1_2); -#endif #ifdef SSL_OP_NO_TLSv1_3 PyModule_AddIntConstant(m, "OP_NO_TLSv1_3", SSL_OP_NO_TLSv1_3); #else diff --git a/Tools/ssl/multissltests.py b/Tools/ssl/multissltests.py index 0e37ec1bba9..12af98d12c4 100755 --- a/Tools/ssl/multissltests.py +++ b/Tools/ssl/multissltests.py @@ -43,20 +43,21 @@ import tarfile log = logging.getLogger("multissl") OPENSSL_OLD_VERSIONS = [ + "1.0.2u", + "1.1.0l", ] OPENSSL_RECENT_VERSIONS = [ - "1.0.2u", - "1.1.0l", "1.1.1g", # "3.0.0-alpha2" ] LIBRESSL_OLD_VERSIONS = [ + "2.9.2", ] LIBRESSL_RECENT_VERSIONS = [ - "2.9.2", + "3.1.0", ] # store files in ../multissl @@ -80,7 +81,7 @@ parser.add_argument( parser.add_argument( '--disable-ancient', action='store_true', - help="Don't test OpenSSL < 1.0.2 and LibreSSL < 2.5.3.", + help="Don't test OpenSSL and LibreSSL versions without upstream support", ) parser.add_argument( '--openssl',