From a871f692b4a2e6c7d45579693e787edc0af1a02c Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Mon, 1 Jun 2020 08:58:14 +0200 Subject: [PATCH] bpo-30008: Fix OpenSSL no-deprecated compilation (GH-20397) Fix :mod:`ssl`` code to be compatible with OpenSSL 1.1.x builds that use ``no-deprecated`` and ``--api=1.1.0``. Note: Tests assume full OpenSSL API and fail with limited API. Signed-off-by: Christian Heimes Co-authored-by: Mark Wright --- .../2020-05-25-22-18-38.bpo-30008.CKC3td.rst | 2 + Modules/_ssl.c | 56 +++++++++++++++---- Tools/ssl/multissltests.py | 1 + 3 files changed, 48 insertions(+), 11 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-05-25-22-18-38.bpo-30008.CKC3td.rst diff --git a/Misc/NEWS.d/next/Library/2020-05-25-22-18-38.bpo-30008.CKC3td.rst b/Misc/NEWS.d/next/Library/2020-05-25-22-18-38.bpo-30008.CKC3td.rst new file mode 100644 index 00000000000000..c4cfa56ce02c58 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-05-25-22-18-38.bpo-30008.CKC3td.rst @@ -0,0 +1,2 @@ +Fix :mod:`ssl` code to be compatible with OpenSSL 1.1.x builds that use +``no-deprecated`` and ``--api=1.1.0``. diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 5fe65a8a1d6dff..5e82fe41a76ec2 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -142,6 +142,24 @@ static void _PySSLFixErrno(void) { # define PY_OPENSSL_1_1_API 1 #endif +/* OpenSSL API compat */ +#ifdef OPENSSL_API_COMPAT +#if OPENSSL_API_COMPAT >= 0x10100000L + +/* OpenSSL API 1.1.0+ does not include version methods */ +#ifndef OPENSSL_NO_TLS1_METHOD +#define OPENSSL_NO_TLS1_METHOD 1 +#endif +#ifndef OPENSSL_NO_TLS1_1_METHOD +#define OPENSSL_NO_TLS1_1_METHOD 1 +#endif +#ifndef OPENSSL_NO_TLS1_2_METHOD +#define OPENSSL_NO_TLS1_2_METHOD 1 +#endif + +#endif /* >= 1.1.0 compcat */ +#endif /* OPENSSL_API_COMPAT */ + /* LibreSSL 2.7.0 provides necessary OpenSSL 1.1.0 APIs */ #if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x2070000fL # define PY_OPENSSL_1_1_API 1 @@ -201,6 +219,12 @@ static void _PySSLFixErrno(void) { #define TLS_method SSLv23_method #define TLS_client_method SSLv23_client_method #define TLS_server_method SSLv23_server_method +#define ASN1_STRING_get0_data ASN1_STRING_data +#define X509_get0_notBefore X509_get_notBefore +#define X509_get0_notAfter X509_get_notAfter +#define OpenSSL_version_num SSLeay +#define OpenSSL_version SSLeay_version +#define OPENSSL_VERSION SSLEAY_VERSION static int X509_NAME_ENTRY_set(const X509_NAME_ENTRY *ne) { @@ -885,7 +909,7 @@ _ssl_configure_hostname(PySSLSocket *self, const char* server_hostname) goto error; } } else { - if (!X509_VERIFY_PARAM_set1_ip(param, ASN1_STRING_data(ip), + if (!X509_VERIFY_PARAM_set1_ip(param, ASN1_STRING_get0_data(ip), ASN1_STRING_length(ip))) { _setSSLError(NULL, 0, __FILE__, __LINE__); goto error; @@ -1361,7 +1385,7 @@ _get_peer_alt_names (X509 *certificate) { goto fail; } PyTuple_SET_ITEM(t, 0, v); - v = PyUnicode_FromStringAndSize((char *)ASN1_STRING_data(as), + v = PyUnicode_FromStringAndSize((char *)ASN1_STRING_get0_data(as), ASN1_STRING_length(as)); if (v == NULL) { Py_DECREF(t); @@ -1657,7 +1681,7 @@ _decode_certificate(X509 *certificate) { ASN1_INTEGER *serialNumber; char buf[2048]; int len, result; - ASN1_TIME *notBefore, *notAfter; + const ASN1_TIME *notBefore, *notAfter; PyObject *pnotBefore, *pnotAfter; retval = PyDict_New(); @@ -1719,7 +1743,7 @@ _decode_certificate(X509 *certificate) { Py_DECREF(sn_obj); (void) BIO_reset(biobuf); - notBefore = X509_get_notBefore(certificate); + notBefore = X509_get0_notBefore(certificate); ASN1_TIME_print(biobuf, notBefore); len = BIO_gets(biobuf, buf, sizeof(buf)-1); if (len < 0) { @@ -1736,7 +1760,7 @@ _decode_certificate(X509 *certificate) { Py_DECREF(pnotBefore); (void) BIO_reset(biobuf); - notAfter = X509_get_notAfter(certificate); + notAfter = X509_get0_notAfter(certificate); ASN1_TIME_print(biobuf, notAfter); len = BIO_gets(biobuf, buf, sizeof(buf)-1); if (len < 0) { @@ -3079,17 +3103,23 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version) ctx = SSL_CTX_new(SSLv3_method()); break; #endif -#if defined(TLS1_VERSION) && !defined(OPENSSL_NO_TLS1) +#if (defined(TLS1_VERSION) && \ + !defined(OPENSSL_NO_TLS1) && \ + !defined(OPENSSL_NO_TLS1_METHOD)) case PY_SSL_VERSION_TLS1: ctx = SSL_CTX_new(TLSv1_method()); break; #endif -#if defined(TLS1_1_VERSION) && !defined(OPENSSL_NO_TLS1_1) +#if (defined(TLS1_1_VERSION) && \ + !defined(OPENSSL_NO_TLS1_1) && \ + !defined(OPENSSL_NO_TLS1_1_METHOD)) 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) +#if (defined(TLS1_2_VERSION) && \ + !defined(OPENSSL_NO_TLS1_2) && \ + !defined(OPENSSL_NO_TLS1_2_METHOD)) case PY_SSL_VERSION_TLS1_2: ctx = SSL_CTX_new(TLSv1_2_method()); break; @@ -3207,7 +3237,7 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version) conservative and assume it wasn't fixed until release. We do this check at runtime to avoid problems from the dynamic linker. See #25672 for more on this. */ - libver = SSLeay(); + libver = OpenSSL_version_num(); if (!(libver >= 0x10001000UL && libver < 0x1000108fUL) && !(libver >= 0x10000000UL && libver < 0x100000dfUL)) { SSL_CTX_set_mode(self->ctx, SSL_MODE_RELEASE_BUFFERS); @@ -5286,7 +5316,11 @@ PySSL_RAND(int len, int pseudo) if (bytes == NULL) return NULL; if (pseudo) { +#ifdef PY_OPENSSL_1_1_API + ok = RAND_bytes((unsigned char*)PyBytes_AS_STRING(bytes), len); +#else ok = RAND_pseudo_bytes((unsigned char*)PyBytes_AS_STRING(bytes), len); +#endif if (ok == 0 || ok == 1) return Py_BuildValue("NO", bytes, ok == 1 ? Py_True : Py_False); } @@ -6373,7 +6407,7 @@ PyInit__ssl(void) /* SSLeay() gives us the version of the library linked against, which could be different from the headers version. */ - libver = SSLeay(); + libver = OpenSSL_version_num(); r = PyLong_FromUnsignedLong(libver); if (r == NULL) return NULL; @@ -6383,7 +6417,7 @@ PyInit__ssl(void) r = Py_BuildValue("IIIII", major, minor, fix, patch, status); if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION_INFO", r)) return NULL; - r = PyUnicode_FromString(SSLeay_version(SSLEAY_VERSION)); + r = PyUnicode_FromString(OpenSSL_version(OPENSSL_VERSION)); if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION", r)) return NULL; diff --git a/Tools/ssl/multissltests.py b/Tools/ssl/multissltests.py index 12af98d12c45db..3818165a836fb1 100755 --- a/Tools/ssl/multissltests.py +++ b/Tools/ssl/multissltests.py @@ -314,6 +314,7 @@ def _build_src(self): "shared", "--debug", "--prefix={}".format(self.install_dir) ] + # cmd.extend(["no-deprecated", "--api=1.1.0"]) env = os.environ.copy() # set rpath env["LD_RUN_PATH"] = self.lib_dir