--- Python-2.7.18/Modules/_hashopenssl.c +++ Python-2.7.18/Modules/_hashopenssl.c @@ -100,7 +100,13 @@ _setException(PyObject *exc) { unsigned long errcode; - const char *lib, *func, *reason; + const char *lib, *reason; +/* ERR_func_error_string() is OSSL_DEPRECATEDIN_3_0; the function-code field + * has been 0 since OpenSSL 3.0 so the string is always NULL anyway. + * Omit it entirely on OpenSSL >= 3.0. */ +#if OPENSSL_VERSION_NUMBER < 0x30000000L + const char *func; +#endif errcode = ERR_peek_last_error(); if (!errcode) { @@ -110,9 +116,12 @@ ERR_clear_error(); lib = ERR_lib_error_string(errcode); +#if OPENSSL_VERSION_NUMBER < 0x30000000L func = ERR_func_error_string(errcode); +#endif reason = ERR_reason_error_string(errcode); +#if OPENSSL_VERSION_NUMBER < 0x30000000L if (lib && func) { PyErr_Format(exc, "[%s: %s] %s", lib, func, reason); } @@ -122,6 +131,14 @@ else { PyErr_SetString(exc, reason); } +#else + if (lib) { + PyErr_Format(exc, "[%s] %s", lib, reason); + } + else { + PyErr_SetString(exc, reason ? reason : "unknown reason"); + } +#endif return NULL; } /* LCOV_EXCL_STOP */ --- Python-2.7.18/Modules/_ssl.c +++ Python-2.7.18/Modules/_ssl.c @@ -110,6 +110,21 @@ # define PY_OPENSSL_1_1_API 1 #endif +/* OpenSSL 4.0 removed the version-specific SSL/TLS method functions. + * TLS_method() with SSL_CTX_set_min/max_proto_version() is the replacement. + * PY_OPENSSL_1_1_API is already set for OpenSSL >= 1.1.0, which is the same + * boundary at which these functions disappeared. + */ +#if defined(PY_OPENSSL_1_1_API) +# define PY_OPENSSL_NO_VERSIONED_TLS_METHODS 1 +#endif + +/* ASN1_STRING_data() was removed in OpenSSL 4.0; use the read-only variant. + * Cast away const to preserve the existing char * call-site types. */ +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) +# define ASN1_STRING_data(x) ((unsigned char *)ASN1_STRING_get0_data(x)) +#endif + /* 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 @@ -595,8 +610,12 @@ self->handshake_done = 0; Py_INCREF(sslctx); - /* Make sure the SSL error state is initialized */ + /* Make sure the SSL error state is initialized. + * ERR_get_state() was removed in OpenSSL 4.0; thread-local error state + * is managed automatically since OpenSSL 1.1.0. */ +#ifndef PY_OPENSSL_1_1_API (void) ERR_get_state(); +#endif ERR_clear_error(); PySSL_BEGIN_ALLOW_THREADS @@ -960,18 +979,18 @@ goto fail; } - p = X509_EXTENSION_get_data(ext)->data; + p = ASN1_STRING_get0_data(X509_EXTENSION_get_data(ext)); if (method->it) names = (GENERAL_NAMES*) (ASN1_item_d2i(NULL, &p, - X509_EXTENSION_get_data(ext)->length, + ASN1_STRING_length(X509_EXTENSION_get_data(ext)), ASN1_ITEM_ptr(method->it))); else names = (GENERAL_NAMES*) (method->d2i(NULL, &p, - X509_EXTENSION_get_data(ext)->length)); + ASN1_STRING_length(X509_EXTENSION_get_data(ext)))); for(j = 0; j < sk_GENERAL_NAME_num(names); j++) { /* get a rendering of each name in the set of names */ @@ -1177,8 +1196,8 @@ continue; } uri = ad->location->d.uniformResourceIdentifier; - ostr = PyUnicode_FromStringAndSize((char *)uri->data, - uri->length); + ostr = PyUnicode_FromStringAndSize((char *)ASN1_STRING_get0_data(uri), + ASN1_STRING_length(uri)); if (ostr == NULL) { goto fail; } @@ -1244,8 +1263,8 @@ continue; } uri = gn->d.uniformResourceIdentifier; - ouri = PyUnicode_FromStringAndSize((char *)uri->data, - uri->length); + ouri = PyUnicode_FromStringAndSize((char *)ASN1_STRING_get0_data(uri), + ASN1_STRING_length(uri)); if (ouri == NULL) goto done; @@ -2193,6 +2212,7 @@ return NULL; PySSL_BEGIN_ALLOW_THREADS +#ifndef PY_OPENSSL_NO_VERSIONED_TLS_METHODS if (proto_version == PY_SSL_VERSION_TLS1) ctx = SSL_CTX_new(TLSv1_method()); #if HAVE_TLSv1_2 @@ -2213,6 +2233,34 @@ ctx = SSL_CTX_new(TLS_method()); else proto_version = -1; +#else /* PY_OPENSSL_NO_VERSIONED_TLS_METHODS */ + /* OpenSSL >= 1.1.0: version-pinned method functions are gone. + * Use TLS_method() and constrain the version range instead. */ + ctx = SSL_CTX_new(TLS_method()); + if (ctx != NULL) { + switch (proto_version) { + case PY_SSL_VERSION_TLS: + break; + case PY_SSL_VERSION_TLS1: + SSL_CTX_set_min_proto_version(ctx, TLS1_VERSION); + SSL_CTX_set_max_proto_version(ctx, TLS1_VERSION); + break; +#if HAVE_TLSv1_2 + case PY_SSL_VERSION_TLS1_1: + SSL_CTX_set_min_proto_version(ctx, TLS1_1_VERSION); + SSL_CTX_set_max_proto_version(ctx, TLS1_1_VERSION); + break; + case PY_SSL_VERSION_TLS1_2: + SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION); + SSL_CTX_set_max_proto_version(ctx, TLS1_2_VERSION); + break; +#endif + default: + proto_version = -1; + break; + } + } +#endif /* PY_OPENSSL_NO_VERSIONED_TLS_METHODS */ PySSL_END_ALLOW_THREADS if (proto_version == -1) { @@ -3087,7 +3135,15 @@ load_dh_params(PySSLContext *self, PyObject *filepath) { BIO *bio; +/* PEM_read_bio_DHparams() is absent from OpenSSL 4.1.0 pem.h. + * On OpenSSL >= 3.0 use PEM_read_bio_Parameters() (returns EVP_PKEY *) + * paired with SSL_CTX_set0_tmp_dh_pkey(). The old DH * path is kept for + * OpenSSL < 3.0 where the EVP_PKEY API is not available. */ +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY *dh; +#else DH *dh; +#endif PyObject *filepath_bytes = NULL; if (PyString_Check(filepath)) { @@ -3113,7 +3169,11 @@ } errno = 0; PySSL_BEGIN_ALLOW_THREADS +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + dh = PEM_read_bio_Parameters(bio, NULL); +#else dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); +#endif BIO_free(bio); Py_DECREF(filepath_bytes); PySSL_END_ALLOW_THREADS @@ -3127,9 +3187,18 @@ } return NULL; } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + if (SSL_CTX_set0_tmp_dh_pkey(self->ctx, dh) == 0) { + _setSSLError(NULL, 0, __FILE__, __LINE__); + EVP_PKEY_free(dh); + return NULL; + } + /* SSL_CTX_set0_tmp_dh_pkey takes ownership on success; do not free dh */ +#else if (SSL_CTX_set_tmp_dh(self->ctx, dh) == 0) _setSSLError(NULL, 0, __FILE__, __LINE__); DH_free(dh); +#endif Py_RETURN_NONE; }