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 <christian@python.org>
Co-authored-by: Mark Wright <gienah@gentoo.org>
This commit is contained in:
Christian Heimes 2020-06-01 08:58:14 +02:00 committed by GitHub
parent 2f172d8f15
commit a871f692b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 48 additions and 11 deletions

View File

@ -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``.

View File

@ -142,6 +142,24 @@ static void _PySSLFixErrno(void) {
# define PY_OPENSSL_1_1_API 1 # define PY_OPENSSL_1_1_API 1
#endif #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 */ /* LibreSSL 2.7.0 provides necessary OpenSSL 1.1.0 APIs */
#if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x2070000fL #if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x2070000fL
# define PY_OPENSSL_1_1_API 1 # define PY_OPENSSL_1_1_API 1
@ -201,6 +219,12 @@ static void _PySSLFixErrno(void) {
#define TLS_method SSLv23_method #define TLS_method SSLv23_method
#define TLS_client_method SSLv23_client_method #define TLS_client_method SSLv23_client_method
#define TLS_server_method SSLv23_server_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) 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; goto error;
} }
} else { } 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))) { ASN1_STRING_length(ip))) {
_setSSLError(NULL, 0, __FILE__, __LINE__); _setSSLError(NULL, 0, __FILE__, __LINE__);
goto error; goto error;
@ -1361,7 +1385,7 @@ _get_peer_alt_names (X509 *certificate) {
goto fail; goto fail;
} }
PyTuple_SET_ITEM(t, 0, v); 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)); ASN1_STRING_length(as));
if (v == NULL) { if (v == NULL) {
Py_DECREF(t); Py_DECREF(t);
@ -1657,7 +1681,7 @@ _decode_certificate(X509 *certificate) {
ASN1_INTEGER *serialNumber; ASN1_INTEGER *serialNumber;
char buf[2048]; char buf[2048];
int len, result; int len, result;
ASN1_TIME *notBefore, *notAfter; const ASN1_TIME *notBefore, *notAfter;
PyObject *pnotBefore, *pnotAfter; PyObject *pnotBefore, *pnotAfter;
retval = PyDict_New(); retval = PyDict_New();
@ -1719,7 +1743,7 @@ _decode_certificate(X509 *certificate) {
Py_DECREF(sn_obj); Py_DECREF(sn_obj);
(void) BIO_reset(biobuf); (void) BIO_reset(biobuf);
notBefore = X509_get_notBefore(certificate); notBefore = X509_get0_notBefore(certificate);
ASN1_TIME_print(biobuf, notBefore); ASN1_TIME_print(biobuf, notBefore);
len = BIO_gets(biobuf, buf, sizeof(buf)-1); len = BIO_gets(biobuf, buf, sizeof(buf)-1);
if (len < 0) { if (len < 0) {
@ -1736,7 +1760,7 @@ _decode_certificate(X509 *certificate) {
Py_DECREF(pnotBefore); Py_DECREF(pnotBefore);
(void) BIO_reset(biobuf); (void) BIO_reset(biobuf);
notAfter = X509_get_notAfter(certificate); notAfter = X509_get0_notAfter(certificate);
ASN1_TIME_print(biobuf, notAfter); ASN1_TIME_print(biobuf, notAfter);
len = BIO_gets(biobuf, buf, sizeof(buf)-1); len = BIO_gets(biobuf, buf, sizeof(buf)-1);
if (len < 0) { if (len < 0) {
@ -3079,17 +3103,23 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version)
ctx = SSL_CTX_new(SSLv3_method()); ctx = SSL_CTX_new(SSLv3_method());
break; break;
#endif #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: case PY_SSL_VERSION_TLS1:
ctx = SSL_CTX_new(TLSv1_method()); ctx = SSL_CTX_new(TLSv1_method());
break; break;
#endif #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: case PY_SSL_VERSION_TLS1_1:
ctx = SSL_CTX_new(TLSv1_1_method()); ctx = SSL_CTX_new(TLSv1_1_method());
break; break;
#endif #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: case PY_SSL_VERSION_TLS1_2:
ctx = SSL_CTX_new(TLSv1_2_method()); ctx = SSL_CTX_new(TLSv1_2_method());
break; 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 conservative and assume it wasn't fixed until release. We do this check
at runtime to avoid problems from the dynamic linker. at runtime to avoid problems from the dynamic linker.
See #25672 for more on this. */ See #25672 for more on this. */
libver = SSLeay(); libver = OpenSSL_version_num();
if (!(libver >= 0x10001000UL && libver < 0x1000108fUL) && if (!(libver >= 0x10001000UL && libver < 0x1000108fUL) &&
!(libver >= 0x10000000UL && libver < 0x100000dfUL)) { !(libver >= 0x10000000UL && libver < 0x100000dfUL)) {
SSL_CTX_set_mode(self->ctx, SSL_MODE_RELEASE_BUFFERS); SSL_CTX_set_mode(self->ctx, SSL_MODE_RELEASE_BUFFERS);
@ -5286,7 +5316,11 @@ PySSL_RAND(int len, int pseudo)
if (bytes == NULL) if (bytes == NULL)
return NULL; return NULL;
if (pseudo) { 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); ok = RAND_pseudo_bytes((unsigned char*)PyBytes_AS_STRING(bytes), len);
#endif
if (ok == 0 || ok == 1) if (ok == 0 || ok == 1)
return Py_BuildValue("NO", bytes, ok == 1 ? Py_True : Py_False); 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, /* SSLeay() gives us the version of the library linked against,
which could be different from the headers version. which could be different from the headers version.
*/ */
libver = SSLeay(); libver = OpenSSL_version_num();
r = PyLong_FromUnsignedLong(libver); r = PyLong_FromUnsignedLong(libver);
if (r == NULL) if (r == NULL)
return NULL; return NULL;
@ -6383,7 +6417,7 @@ PyInit__ssl(void)
r = Py_BuildValue("IIIII", major, minor, fix, patch, status); r = Py_BuildValue("IIIII", major, minor, fix, patch, status);
if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION_INFO", r)) if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION_INFO", r))
return NULL; 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)) if (r == NULL || PyModule_AddObject(m, "OPENSSL_VERSION", r))
return NULL; return NULL;

View File

@ -314,6 +314,7 @@ class AbstractBuilder(object):
"shared", "--debug", "shared", "--debug",
"--prefix={}".format(self.install_dir) "--prefix={}".format(self.install_dir)
] ]
# cmd.extend(["no-deprecated", "--api=1.1.0"])
env = os.environ.copy() env = os.environ.copy()
# set rpath # set rpath
env["LD_RUN_PATH"] = self.lib_dir env["LD_RUN_PATH"] = self.lib_dir