Skip to content

Commit

Permalink
openssl 3.0.0 / 1.1.1.e introduced a behavior change. When the peer s…
Browse files Browse the repository at this point in the history
…imply closes the connection without notifying its client, a specific error is now generated by SSL. With this commit, ACE_SSL handles this error gracefully.

Also, this patch includes some minor code cleanup such as more consistent error handling in the same file.
  • Loading branch information
Erik Sohns committed Oct 2, 2023
1 parent de47fd5 commit 5534ea9
Showing 1 changed file with 43 additions and 7 deletions.
50 changes: 43 additions & 7 deletions ACE/ace/SSL/SSL_SOCK_Stream.inl
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
// -*- C++ -*-
#include "openssl/err.h"
#include "openssl/ssl.h"

#include "ace/OS_NS_errno.h"
#include "ace/Truncate.h"

Expand Down Expand Up @@ -146,25 +149,25 @@ ACE_SSL_SOCK_Stream::recv_i (void *buf,
}

int const status = ::SSL_get_error (this->ssl_, bytes_read);
int substat = 0;
switch (status)
{
case SSL_ERROR_NONE:
break;

case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
{
if (timeout == 0)
{
errno = EWOULDBLOCK;
bytes_read = -1;
break;
}
substat = ACE::handle_ready (handle,
timeout,
status == SSL_ERROR_WANT_READ,
status == SSL_ERROR_WANT_WRITE,
false);
int substat = ACE::handle_ready (handle,
timeout,
status == SSL_ERROR_WANT_READ,
status == SSL_ERROR_WANT_WRITE,
false);
if (substat == 1) // Now ready to proceed
{
retry = true;
Expand All @@ -174,6 +177,7 @@ ACE_SSL_SOCK_Stream::recv_i (void *buf,
if (substat == 0)
errno = ETIME;
break;
}

case SSL_ERROR_ZERO_RETURN:
bytes_read = 0;
Expand All @@ -184,26 +188,48 @@ ACE_SSL_SOCK_Stream::recv_i (void *buf,

break;

#if OPENSSL_VERSION_NUMBER >= 0x30000000L /*OpenSSL 3.0.0*/ || \
OPENSSL_VERSION_NUMBER == 0x1010105fL /*OpenSSL 1.1.1e*/
// handle SSL_ERROR_SSL|SSL_R_UNEXPECTED_EOF_WHILE_READING the same as
// SSL_ERROR_SYSCALL (i.e. the previous behavior, see also:
// https://github.com/openssl/openssl/issues/18866
// https://www.openssl.org/docs/man1.1.1/man3/SSL_get_error.html)
case SSL_ERROR_SSL:
if (ERR_GET_REASON (::ERR_peek_last_error ()) != SSL_R_UNEXPECTED_EOF_WHILE_READING)
goto default_; // --> handle as default error
ACE_FALLTHROUGH

#endif // OPENSSL_VERSION_NUMBER >= 0x30000000L || OPENSSL_VERSION_NUMBER == 0x1010105fL
case SSL_ERROR_SYSCALL:
if (bytes_read == 0)
// An EOF occurred but the SSL "close_notify" message was not
// sent. This is a protocol error, but we ignore it.
break;

ACE_SSL_Context::report_error ();

// On some platforms (e.g. MS Windows) OpenSSL does not store
// the last error in errno so explicitly do so.
ACE_OS::set_errno_to_last_error ();

break;

default:
#if OPENSSL_VERSION_NUMBER >= 0x30000000L /*OpenSSL 3.0.0*/ || \
OPENSSL_VERSION_NUMBER == 0x1010105fL /*OpenSSL 1.1.1e*/
default_:
#endif // OPENSSL_VERSION_NUMBER >= 0x30000000L || OPENSSL_VERSION_NUMBER == 0x1010105fL
// Reset errno to prevent previous values (e.g. EWOULDBLOCK)
// from being associated with a fatal SSL error.
bytes_read = -1;
errno = 0;

ACE_SSL_Context::report_error ();

// On some platforms (e.g. MS Windows) OpenSSL does not store
// the last error in errno so explicitly do so.
ACE_OS::set_errno_to_last_error ();

break;
}
} while (retry);
Expand Down Expand Up @@ -317,9 +343,14 @@ ACE_SSL_SOCK_Stream::close ()
// connection, not 0.
int const status = ::SSL_shutdown (this->ssl_);

switch (::SSL_get_error (this->ssl_, status))
int const status_2 = ::SSL_get_error (this->ssl_, status);
switch (status_2)
{
case SSL_ERROR_NONE:
#if OPENSSL_VERSION_NUMBER >= 0x30000000L /*OpenSSL 3.0.0*/ || \
OPENSSL_VERSION_NUMBER == 0x1010105fL /*OpenSSL 1.1.1e*/
case SSL_ERROR_SSL: // Ignore this error condition.
#endif // OPENSSL_VERSION_NUMBER >= 0x30000000L || OPENSSL_VERSION_NUMBER == 0x1010105fL
case SSL_ERROR_SYSCALL: // Ignore this error condition.

// Reset the SSL object to allow another connection to be made
Expand All @@ -338,6 +369,11 @@ ACE_SSL_SOCK_Stream::close ()
default:
ACE_SSL_Context::report_error ();

// On some platforms (e.g. MS Windows) OpenSSL does not store
// the last error in errno so explicitly do so.
ACE_OS::set_errno_to_last_error ();

this->set_handle (ACE_INVALID_HANDLE);
ACE_Errno_Guard error (errno); // Save/restore errno
(void) this->stream_.close ();

Expand Down

0 comments on commit 5534ea9

Please sign in to comment.