remove BIO stuff completely, replace with callback

This commit is contained in:
Raoul Wols 2021-07-13 12:31:04 +02:00
parent 4d49b44283
commit faa491ce65
No known key found for this signature in database
GPG Key ID: 9FFE06A0F6AAA2DF
4 changed files with 72 additions and 69 deletions

View File

@ -169,10 +169,7 @@ private:
{
// get a human-readable error string
const SslErrorPrinter printer{error};
// ensure it is null-terminated
const std::string message{printer.data(), printer.size()};
const SslErrorPrinter message{error};
// report an error to user-space
_parent->onError(this, message.data());

View File

@ -17,75 +17,86 @@
*/
namespace AMQP {
/**
* Callback used for ERR_print_errors_cb
* @param str The string
* @param len The length
* @param ctx The context (this ptr)
* @return always 1 to signal to OpenSSL to continue
*/
int sslerrorprintercallback(const char *str, size_t len, void *ctx)
{
// cast to ourselves
auto *self = static_cast<SslErrorPrinter*>(ctx);
// if this is not the first line, add a newline character
if (!self->_message.empty()) self->_message.push_back('\n');
// store the message
self->_message.append(str, len);
// continue with the next message
return 1;
}
/**
* Constructor
* @param retval return value of SSL_get_error (must be a proper error)
* @throw std::bad_alloc if the BIO couldn't be allocated
*/
SslErrorPrinter::SslErrorPrinter(int retval) : _bio(nullptr, &::BIO_free)
SslErrorPrinter::SslErrorPrinter(int retval)
{
// check the return value of the SSL_get_error function, which has a very unfortunate name.
switch (retval)
{
// It can be a syscall error.
case SSL_ERROR_SYSCALL:
{
// The SSL_ERROR_SYSCALL with errno value of 0 indicates unexpected
// EOF from the peer. This will be properly reported as SSL_ERROR_SSL
// with reason code SSL_R_UNEXPECTED_EOF_WHILE_READING in the
// OpenSSL 3.0 release because it is truly a TLS protocol error to
// terminate the connection without a SSL_shutdown().
if (errno == 0) _strerror = "SSL_R_UNEXPECTED_EOF_WHILE_READING";
// It can be a syscall error.
case SSL_ERROR_SYSCALL:
// Otherwise we ask the OS for a description of the error.
else _strerror = ::strerror(errno);
// The SSL_ERROR_SYSCALL with errno value of 0 indicates unexpected
// EOF from the peer. This will be properly reported as SSL_ERROR_SSL
// with reason code SSL_R_UNEXPECTED_EOF_WHILE_READING in the
// OpenSSL 3.0 release because it is truly a TLS protocol error to
// terminate the connection without a SSL_shutdown().
if (errno == 0) _message = "SSL_R_UNEXPECTED_EOF_WHILE_READING";
// done
break;
}
// It can be an error in OpenSSL. In that case the error stack contains
// more information. The documentation notes: if this error occurs then
// no further I/O operations should be performed on the connection and
// SSL_shutdown() must not be called.
case SSL_ERROR_SSL:
{
// create a new bio
_bio = decltype(_bio)(::BIO_new(::BIO_s_mem()), &::BIO_free);
// Otherwise we ask the OS for a description of the error.
else _message = ::strerror(errno);
// check if it was allocated
if (!_bio) throw std::bad_alloc();
// done
break;
// invoke the convenience function to extract the whole error stack
::ERR_print_errors(_bio.get());
// It can be an error in OpenSSL. In that case the error stack contains
// more information. The documentation notes: if this error occurs then
// no further I/O operations should be performed on the connection and
// SSL_shutdown() must not be called.
case SSL_ERROR_SSL:
// get it from the bio
::BIO_get_mem_ptr(_bio.get(), &_bufmem);
// collect all error lines
::ERR_print_errors_cb(&sslerrorprintercallback, this);
// done
break;
}
default:
{
// we don't know what kind of error this is
_strerror = "unknown ssl error";
// done
break;
// done
break;
}
default:
// we don't know what kind of error this is
_message = "unknown ssl error";
// done
break;
}
}
/**
* data ptr
* data ptr (guaranteed null-terminated)
* @return const char *
*/
const char *SslErrorPrinter::data() const noexcept { return _strerror ? _strerror : _bufmem->data; }
const char *SslErrorPrinter::data() const noexcept { return _message.data(); }
/**
* length of the string
* @return size_t
*/
std::size_t SslErrorPrinter::size() const noexcept { return _strerror ? std::strlen(_strerror) : _bufmem->length; }
std::size_t SslErrorPrinter::size() const noexcept { return _message.size(); }
/**
* End of namespace AMQP

View File

@ -30,24 +30,6 @@ namespace AMQP {
*/
class SslErrorPrinter final
{
/**
* pointer to the BIO
* @var unique_ptr
*/
std::unique_ptr<::BIO, decltype(&::BIO_free)> _bio;
/**
* pointer to the (data, size) tuple
* @var ::BUF_MEM*
*/
::BUF_MEM *_bufmem = nullptr;
/**
* In case of a syscall error, the static string pointing to the error
* @var const char*
*/
const char *_strerror = nullptr;
public:
/**
* Constructor
@ -57,7 +39,7 @@ public:
SslErrorPrinter(int retval);
/**
* data ptr
* data ptr (guaranteed null-terminated)
* @return const char *
*/
const char *data() const noexcept;
@ -67,6 +49,22 @@ public:
* @return size_t
*/
std::size_t size() const noexcept;
private:
/**
* The error message
* @var std::string
*/
std::string _message;
/**
* Callback used for ERR_print_errors_cb
* @param str The string
* @param len The length
* @param ctx The context (this ptr)
* @return always 1 to signal to OpenSSL to continue
*/
friend int sslerrorprintercallback(const char *str, size_t len, void *ctx);
};
/**

View File

@ -87,10 +87,7 @@ private:
TcpState *reportError(const Monitor &monitor, int retval)
{
// extract a human-readable error string
const SslErrorPrinter printer{retval};
// ensure it's null-terminated
const std::string message{printer.data(), printer.size()};
const SslErrorPrinter message{retval};
// we have an error - report this to the user
_parent->onError(this, message.data());