0

I'm using OpenSSL Bio interface with a blocking socket to create a TCP SSL connection.

After many successful send/reads...

BIO_write() succeeds. Immediately I progress to wait for the response but BIO_read() fails. I process the return value using OpenSSL enums but it maps to SSL_ERROR_NONE?

Given it's a blocking socket, is the only explanation the client MUST have closed the connection? It doesn't make much sense for the client to close the connection in this case. Are there any other possibilities, or ways to determine the exact reason?

This is how the code looks:

std::optional<Response> sendThenRecv()
{
    // .....

    if(BIO_write(bio_, write_buf, strlen(write_buf)) <= 0)
    {
        return std::nullopt;
    }

    const int res = BIO_read(bio_, read_buf, read_size);

    if(res <= 0)
    {
        LOG("BIO_read() failed. errno details: " << GetSSLError(res));
        return std::nullopt;
    }

    //.....
}

static inline std::string GetSSLError(const int reason)
{
    switch(reason)
    {
        case 0:
            return "SSL_ERROR_NONE";

        case 1:
            return "SSL_ERROR_SSL";

        case 2:
            return "SSL_ERROR_WANT_READ";

        case 3:
            return "SSL_ERROR_WANT_WRITE";

        case 4:
            return "SSL_ERROR_WANT_X509_LOOKUP";

        case 5:
            return "SSL_ERROR_SYSCALL: " + std::string(strerror(errno));

        case 6:
            return "SSL_ERROR_ZERO_RETURN";

        case 7:
            return "SSL_ERROR_WANT_CONNECT";

        case 8:
            return "SSL_ERROR_WANT_ACCEPT";

        case 9:
            return "SSL_ERROR_WANT_ASYNC";

        case 10:
            return "SSL_ERROR_WANT_ASYNC_JOB";

        case 11:
            return "SSL_ERROR_WANT_CLIENT_HELLO_CB";

        case 12:
            return "SSL_ERROR_WANT_RETRY_VERIFY";
        default:
            MY_ASSERT(false);
    }

    return std::to_string(reason);
}
rare77
  • 297
  • 6
  • 1
    Off-topic: do not map errors by yourself. You can fetch user friendly error discretion from OpenSSL library: https://stackoverflow.com/q/42106339/1387438 – Marek R May 23 '23 at 09:47
  • `BIO_read()` returning zero is not necessarily an indication of an error. See the *man* page. It could mean that the peer has disconnected, for example, or that you provided a zero length parameter. – user207421 May 23 '23 at 09:53
  • @user207421 I will add an assert on the zero length parameter. If we assume this was okay and `SSL_ERROR_NONE` is correct, is client disconnection the only possible reason? – rare77 May 23 '23 at 09:58
  • You should treat return values of 0 and -1 separately. As with `read()`, I would treat 0 as a disconnect and -1 as an error, but the *man* page is deplorably vague on the topic. – user207421 May 23 '23 at 10:14
  • 1
    [`BIO_read`](https://www.openssl.org/docs/man1.1.1/man3/BIO_read.html) doesn't return the error codes in `GetSSLError` – Alan Birtles May 23 '23 at 10:20
  • @AlanBirtles Should I still use the link from the first comment? – rare77 May 23 '23 at 15:26
  • I doubt it because you aren't getting an error, just no data – Alan Birtles May 23 '23 at 15:32
  • @AlanBirtles This is a blocking socket, why would it return if there was no data? Surely it would just block? – rare77 May 23 '23 at 21:07
  • There's an overhead to ssl, the socket may well have returned some data but there was no actual application payload – Alan Birtles May 23 '23 at 21:34

0 Answers0