From 11ae4ed4bf1fc3bcacc6d9b92cb7f173b828983a Mon Sep 17 00:00:00 2001 From: Julius Goryavsky Date: Tue, 31 Jan 2023 09:25:06 +0100 Subject: MDEV-30452: ssl error: unexpected EOF while reading This commit contains a correction for a new behaviour was introduced in OpenSSL 3.x when a peer does not send close_notify before closing the connection - previously it was reported as an SSL_ERROR_SYSCALL error with a errno == 0, but now it is reported as SSL_ERROR_SSL with a special reason code. --- libmariadb | 2 +- vio/viossl.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++--- vio/viosslfactories.c | 29 ----------------------------- 3 files changed, 47 insertions(+), 33 deletions(-) diff --git a/libmariadb b/libmariadb index 12bd1d5511f..38ab85463c0 160000 --- a/libmariadb +++ b/libmariadb @@ -1 +1 @@ -Subproject commit 12bd1d5511fc2ff766ff6256c71b79a95739533f +Subproject commit 38ab85463c0088ba638ad333d0e0a068ff2a2c80 diff --git a/vio/viossl.c b/vio/viossl.c index 94c4bcb46cf..f9ad897dccf 100644 --- a/vio/viossl.c +++ b/vio/viossl.c @@ -32,7 +32,7 @@ @param ssl_error The result code of the failed TLS/SSL I/O operation. */ -static void ssl_set_sys_error(int ssl_error) +static void ssl_set_sys_error(int ssl_error, unsigned long err) { int error= 0; @@ -52,6 +52,25 @@ static void ssl_set_sys_error(int ssl_error) error= SOCKET_EWOULDBLOCK; break; case SSL_ERROR_SSL: +#ifdef SSL_R_UNEXPECTED_EOF_WHILE_READING + /* + Correction for a new behaviour was introduced in OpenSSL 3.x + when a peer does not send close_notify before closing the + connection - previously it was reported as an SSL_ERROR_SYSCALL + error with a errno == 0, but now it is reported as + SSL_ERROR_SSL with a special reason code: + */ + if (ERR_GET_REASON(err) == SSL_R_UNEXPECTED_EOF_WHILE_READING) + { + /* This is not really an fatal error - reset the error code to zero: */ +#ifdef _WIN32 + WSASetLastError(0); +#else + errno= 0; +#endif + break; + } +#endif /* Protocol error. */ #ifdef EPROTO error= EPROTO; @@ -96,13 +115,14 @@ static my_bool ssl_should_retry(Vio *vio, int ret, enum enum_vio_io_event *event SSL *ssl= vio->ssl_arg; my_bool should_retry= TRUE; + unsigned long err = ERR_peek_error(); + #if defined(ERR_LIB_X509) && defined(X509_R_CERT_ALREADY_IN_HASH_TABLE) /* Ignore error X509_R_CERT_ALREADY_IN_HASH_TABLE. This is a workaround for an OpenSSL bug in an older (< 1.1.1) OpenSSL version. */ - unsigned long err = ERR_peek_error(); if (ERR_GET_LIB(err) == ERR_LIB_X509 && ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) { @@ -129,7 +149,7 @@ static my_bool ssl_should_retry(Vio *vio, int ret, enum enum_vio_io_event *event default: should_retry= FALSE; *should_wait= FALSE; - ssl_set_sys_error(ssl_error); + ssl_set_sys_error(ssl_error, err); ERR_clear_error(); break; } @@ -233,8 +253,31 @@ int vio_ssl_close(Vio *vio) */ break; default: /* Shutdown failed */ +#ifdef SSL_R_UNEXPECTED_EOF_WHILE_READING + { + unsigned long err= ERR_peek_last_error(); + int ssl_error= SSL_get_error(ssl, r); + /* + Correction for a new behaviour was introduced in OpenSSL 3.x + when a peer does not send close_notify before closing the + connection - previously it was reported as an SSL_ERROR_SYSCALL + error with a errno == 0, but now it is reported as + SSL_ERROR_SSL with a special reason code: + */ + if (ssl_error == SSL_ERROR_SSL && + (ERR_GET_REASON(err) == SSL_R_UNEXPECTED_EOF_WHILE_READING || + ERR_GET_REASON(err) == SSL_R_SHUTDOWN_WHILE_IN_INIT)) + { + ERR_clear_error(); + break; + } + DBUG_PRINT("vio_error", ("SSL_shutdown() failed, error: %d", + ssl_error)); + } +#else DBUG_PRINT("vio_error", ("SSL_shutdown() failed, error: %d", SSL_get_error(ssl, r))); +#endif break; } } diff --git a/vio/viosslfactories.c b/vio/viosslfactories.c index 289c28d4cf4..9200d8c3ac4 100644 --- a/vio/viosslfactories.c +++ b/vio/viosslfactories.c @@ -233,30 +233,6 @@ new_VioSSLFd(const char *key_file, const char *cert_file, long ssl_ctx_options; DBUG_ENTER("new_VioSSLFd"); - /* - If some optional parameters indicate empty strings, then - for compatibility with SSL libraries, replace them with NULL, - otherwise these libraries will try to open files with an empty - name, etc., and they will return an error code instead performing - the necessary operations: - */ - if (ca_file && !ca_file[0]) - { - ca_file = NULL; - } - if (ca_path && !ca_path[0]) - { - ca_path = NULL; - } - if (crl_file && !crl_file[0]) - { - crl_file = NULL; - } - if (crl_path && !crl_path[0]) - { - crl_path = NULL; - } - DBUG_PRINT("enter", ("key_file: '%s' cert_file: '%s' ca_file: '%s' ca_path: '%s' " "cipher: '%s' crl_file: '%s' crl_path: '%s'", @@ -406,11 +382,6 @@ new_VioSSLConnectorFd(const char *key_file, const char *cert_file, struct st_VioSSLFd *ssl_fd; int verify= SSL_VERIFY_PEER; - if (ca_file && ! ca_file[0]) ca_file = NULL; - if (ca_path && ! ca_path[0]) ca_path = NULL; - if (crl_file && ! crl_file[0]) crl_file = NULL; - if (crl_path && ! crl_path[0]) crl_path = NULL; - /* If some optional parameters indicate empty strings, then for compatibility with SSL libraries, replace them with NULL, -- cgit v1.2.1