Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OpenSSL and signals

Socket functions like send and receive can be interrupted by signals. Because of this some extra code is needed, e.g. to check for errno == EINTR. This is described on corresponding man pages.

I wonder how this works when OpenSSL functions are used, e.g. SSL_write, SSL_read. Their man pages do not say anything about signals. I also tried to google for this, but without luck. Do you know if OpenSSL handles signals internally, or some extra code is needed? If yes, how to check if function call was interrupted by signal?

Update:

Looks that OpenSSL does not handle retries. It only sets the "should retry" flag on BIO object. So I need to use something like this to detect if call was interrupted and retry is needed:

int result = SSL_write(ssl, buff, length);
if ((result < 0) && BIO_should_retry(SSL_get_wbio(ssl)))
    // need to retry

int result = SSL_read(ssl, buff, length);
if ((result < 0) && BIO_should_retry(SSL_get_rbio(ssl)))
    // need to retry
like image 755
Daniel Frużyński Avatar asked Jun 12 '14 15:06

Daniel Frużyński


1 Answers

As being a libray OpenSSL cannot make any assumptions on how signals are handled by the particular program using it. So it needs to handle the case of a system call being interupted on the reception of a signal.

A check whether it made sense to retry a failed read() is implemented inside OpenSSL.

Use BIO_should_retry() if BIO_read() (or BIO_write()) failed.

For an example read here: http://cvs.openssl.org/rlog?f=openssl/demos/bio/sconnect.c

The implementation's relevant code follows:

static int sock_read(BIO *b, char *out, int outl)
    {
    int ret=0;

    if (out != NULL)
            {
            clear_socket_error();
            ret=readsocket(b->num,out,outl);
            BIO_clear_retry_flags(b);
            if (ret <= 0)
                    {
                    if (BIO_sock_should_retry(ret))
                            BIO_set_retry_read(b);
                    }
            }
    return(ret);
    }

The relevant referred functions are here:

(get_last_socket_error() returns errno on most IXish platforms)

int BIO_sock_should_retry(int i)
    {
    int err;

    if ((i == 0) || (i == -1))
            {
            err=get_last_socket_error();

#if defined(OPENSSL_SYS_WINDOWS) && 0 /* more microsoft stupidity? perhaps not? Ben 4/1/99 */
            if ((i == -1) && (err == 0))
                    return(1);
#endif

            return(BIO_sock_non_fatal_error(err));
            }
    return(0);
    }


int BIO_sock_non_fatal_error(int err)
        {
        switch (err)
                {
#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_NETWARE)
# if defined(WSAEWOULDBLOCK)
        case WSAEWOULDBLOCK:
# endif

# if 0 /* This appears to always be an error */
#  if defined(WSAENOTCONN)
        case WSAENOTCONN:
#  endif
# endif
#endif

#ifdef EWOULDBLOCK
# ifdef WSAEWOULDBLOCK
#  if WSAEWOULDBLOCK != EWOULDBLOCK
        case EWOULDBLOCK:
#  endif
# else
        case EWOULDBLOCK:
# endif
#endif

#if defined(ENOTCONN)
        case ENOTCONN:
#endif

#ifdef EINTR
        case EINTR:
#endif

#ifdef EAGAIN
# if EWOULDBLOCK != EAGAIN
        case EAGAIN:
# endif
#endif

#ifdef EPROTO
        case EPROTO:
#endif

#ifdef EINPROGRESS
        case EINPROGRESS:
#endif

#ifdef EALREADY
        case EALREADY:
#endif
                return(1);
                /* break; */
        default:
                break;
                }
        return(0);
        }

For details see sock_read() to be inspected here: http://cvs.openssl.org/rlog?f=openssl/crypto/bio/bss_sock.c

(The sources quoted along with the indention used is from version 1.0.1e.)

like image 130
alk Avatar answered Nov 04 '22 20:11

alk