OpenSSL: Import the callback/handshake logic from the MbedTLS backend

This commit is contained in:
Aaron Jones 2016-09-15 19:12:13 +00:00
parent 9114e3a2dc
commit 485b5b8084
No known key found for this signature in database
GPG key ID: EC6F86EE9CD840B5

View file

@ -52,13 +52,8 @@ struct ssl_connect
int timeout; int timeout;
}; };
static void rb_ssl_connect_realcb(rb_fde_t *, int, struct ssl_connect *);
static void rb_ssl_tryconn_timeout_cb(rb_fde_t *, void *);
static void rb_ssl_timeout(rb_fde_t *, void *);
static void rb_ssl_tryaccept(rb_fde_t *, void *);
static unsigned long rb_ssl_last_err(void);
static const char *rb_ssl_strerror(unsigned long); static const char *rb_ssl_strerror(unsigned long);
static void rb_ssl_connect_realcb(rb_fde_t *, int, struct ssl_connect *);
@ -105,172 +100,84 @@ rb_ssl_init_fd(rb_fde_t *const F, const rb_fd_tls_direction dir)
} }
static void static void
rb_ssl_accept_common(rb_fde_t *const new_F) rb_ssl_accept_common(rb_fde_t *const F, void *const data)
{ {
lrb_assert(F != NULL);
lrb_assert(F->accept != NULL);
lrb_assert(F->accept->callback != NULL);
lrb_assert(F->ssl != NULL);
(void) rb_ssl_last_err(); (void) rb_ssl_last_err();
int ssl_err = SSL_accept(SSL_P(new_F)); int ret = SSL_do_handshake(SSL_P(F));
int err = SSL_get_error(SSL_P(F), ret);
if(ssl_err <= 0) if(ret == 1)
{ {
switch((ssl_err = SSL_get_error(SSL_P(new_F), ssl_err))) F->handshake_count++;
{
case SSL_ERROR_SYSCALL: rb_settimeout(F, 0, NULL, NULL);
if(rb_ignore_errno(errno)) rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE, NULL, NULL);
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE: struct acceptdata *const ad = F->accept;
{ F->accept = NULL;
new_F->ssl_errno = rb_ssl_last_err(); ad->callback(F, RB_OK, (struct sockaddr *)&ad->S, ad->addrlen, ad->data);
rb_setselect(new_F, RB_SELECT_READ | RB_SELECT_WRITE, rb_free(ad);
rb_ssl_tryaccept, NULL);
return; return;
}
default:
new_F->ssl_errno = rb_ssl_last_err();
new_F->accept->callback(new_F, RB_ERROR_SSL, NULL, 0, new_F->accept->data);
return;
}
} }
else if(ret == -1 && err == SSL_ERROR_WANT_READ)
{ {
new_F->handshake_count++; rb_setselect(F, RB_SELECT_READ, rb_ssl_accept_common, NULL);
rb_ssl_tryaccept(new_F, NULL); return;
} }
} if(ret == -1 && err == SSL_ERROR_WANT_WRITE)
static void
rb_ssl_tryaccept(rb_fde_t *const F, void *const data)
{
lrb_assert(F->accept != NULL);
if(! SSL_is_init_finished(SSL_P(F)))
{ {
(void) rb_ssl_last_err(); rb_setselect(F, RB_SELECT_WRITE, rb_ssl_accept_common, NULL);
return;
int flags;
int ssl_err = SSL_accept(SSL_P(F));
if(ssl_err <= 0)
{
switch(ssl_err = SSL_get_error(SSL_P(F), ssl_err))
{
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
if(ssl_err == SSL_ERROR_WANT_WRITE)
flags = RB_SELECT_WRITE;
else
flags = RB_SELECT_READ;
F->ssl_errno = rb_ssl_last_err();
rb_setselect(F, flags, rb_ssl_tryaccept, NULL);
break;
case SSL_ERROR_SYSCALL:
F->accept->callback(F, RB_ERROR, NULL, 0, F->accept->data);
break;
default:
F->ssl_errno = rb_ssl_last_err();
F->accept->callback(F, RB_ERROR_SSL, NULL, 0, F->accept->data);
break;
}
return;
}
else
F->handshake_count++;
} }
rb_settimeout(F, 0, NULL, NULL); errno = EIO;
rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE, NULL, NULL); F->ssl_errno = (unsigned long) err;
F->accept->callback(F, RB_ERROR_SSL, NULL, 0, F->accept->data);
struct acceptdata *const ad = F->accept;
F->accept = NULL;
ad->callback(F, RB_OK, (struct sockaddr *)&ad->S, ad->addrlen, ad->data);
rb_free(ad);
} }
static void static void
rb_ssl_tryconn_cb(rb_fde_t *const F, void *const data) rb_ssl_tryconn_cb(rb_fde_t *const F, void *const data)
{
if(! SSL_is_init_finished(SSL_P(F)))
{
(void) rb_ssl_last_err();
struct ssl_connect *const sconn = data;
int ssl_err = SSL_connect(SSL_P(F));
if(ssl_err <= 0)
{
switch(ssl_err = SSL_get_error(SSL_P(F), ssl_err))
{
case SSL_ERROR_SYSCALL:
if(rb_ignore_errno(errno))
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
{
F->ssl_errno = rb_ssl_last_err();
rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE,
rb_ssl_tryconn_cb, sconn);
return;
}
default:
F->ssl_errno = rb_ssl_last_err();
rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn);
return;
}
}
else
{
F->handshake_count++;
rb_ssl_connect_realcb(F, RB_OK, sconn);
}
}
}
static void
rb_ssl_tryconn(rb_fde_t *const F, const int status, void *const data)
{ {
lrb_assert(F != NULL); lrb_assert(F != NULL);
lrb_assert(F->ssl != NULL);
struct ssl_connect *const sconn = data;
if(status != RB_OK)
{
rb_ssl_connect_realcb(F, status, sconn);
return;
}
F->type |= RB_FD_SSL;
rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn);
rb_ssl_init_fd(F, RB_FD_TLS_DIRECTION_OUT);
(void) rb_ssl_last_err(); (void) rb_ssl_last_err();
int ssl_err = SSL_connect(SSL_P(F)); int ret = SSL_do_handshake(SSL_P(F));
int err = SSL_get_error(SSL_P(F), ret);
if(ssl_err <= 0) if(ret == 1)
{
switch(ssl_err = SSL_get_error(SSL_P(F), ssl_err))
{
case SSL_ERROR_SYSCALL:
if(rb_ignore_errno(errno))
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
{
F->ssl_errno = rb_ssl_last_err();
rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE,
rb_ssl_tryconn_cb, sconn);
return;
}
default:
F->ssl_errno = rb_ssl_last_err();
rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn);
return;
}
}
else
{ {
F->handshake_count++; F->handshake_count++;
rb_ssl_connect_realcb(F, RB_OK, sconn);
rb_settimeout(F, 0, NULL, NULL);
rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE, NULL, NULL);
rb_ssl_connect_realcb(F, RB_OK, data);
return;
} }
if(ret == -1 && err == SSL_ERROR_WANT_READ)
{
rb_setselect(F, RB_SELECT_READ, rb_ssl_tryconn_cb, data);
return;
}
if(ret == -1 && err == SSL_ERROR_WANT_WRITE)
{
rb_setselect(F, RB_SELECT_WRITE, rb_ssl_tryconn_cb, data);
return;
}
errno = EIO;
F->ssl_errno = (unsigned long) err;
rb_ssl_connect_realcb(F, RB_ERROR_SSL, data);
} }
static const char * static const char *
@ -666,88 +573,6 @@ rb_ssl_write(rb_fde_t *const F, const void *const buf, const size_t count)
return rb_ssl_read_or_write(1, F, NULL, buf, count); return rb_ssl_read_or_write(1, F, NULL, buf, count);
} }
void
rb_ssl_start_accepted(rb_fde_t *const F, ACCB *const cb, void *const data, const int timeout)
{
F->type |= RB_FD_SSL;
F->accept = rb_malloc(sizeof(struct acceptdata));
F->accept->callback = cb;
F->accept->data = data;
F->accept->addrlen = 0;
(void) memset(&F->accept->S, 0x00, sizeof F->accept->S);
rb_settimeout(F, timeout, rb_ssl_timeout, NULL);
rb_ssl_init_fd(F, RB_FD_TLS_DIRECTION_IN);
rb_ssl_accept_common(F);
}
void
rb_ssl_accept_setup(rb_fde_t *const srv_F, rb_fde_t *const cli_F, struct sockaddr *const st, const int addrlen)
{
cli_F->type |= RB_FD_SSL;
cli_F->accept = rb_malloc(sizeof(struct acceptdata));
cli_F->accept->callback = srv_F->accept->callback;
cli_F->accept->data = srv_F->accept->data;
cli_F->accept->addrlen = addrlen;
(void) memset(&cli_F->accept->S, 0x00, sizeof cli_F->accept->S);
(void) memcpy(&cli_F->accept->S, st, addrlen);
rb_settimeout(cli_F, 10, rb_ssl_timeout, NULL);
rb_ssl_init_fd(cli_F, RB_FD_TLS_DIRECTION_IN);
rb_ssl_accept_common(cli_F);
}
void
rb_ssl_start_connected(rb_fde_t *const F, CNCB *const callback, void *const data, const int timeout)
{
if(F == NULL)
return;
struct ssl_connect *const sconn = rb_malloc(sizeof *sconn);
sconn->data = data;
sconn->callback = callback;
sconn->timeout = timeout;
F->connect = rb_malloc(sizeof(struct conndata));
F->connect->callback = callback;
F->connect->data = data;
F->type |= RB_FD_SSL;
rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn);
rb_ssl_init_fd(F, RB_FD_TLS_DIRECTION_OUT);
(void) rb_ssl_last_err();
int ssl_err = SSL_connect(SSL_P(F));
if(ssl_err <= 0)
{
switch((ssl_err = SSL_get_error(SSL_P(F), ssl_err)))
{
case SSL_ERROR_SYSCALL:
if(rb_ignore_errno(errno))
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
{
F->ssl_errno = rb_ssl_last_err();
rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE,
rb_ssl_tryconn_cb, sconn);
return;
}
default:
F->ssl_errno = rb_ssl_last_err();
rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn);
return;
}
}
else
{
rb_ssl_connect_realcb(F, RB_OK, sconn);
}
}
/* /*
@ -776,6 +601,26 @@ rb_ssl_tryconn_timeout_cb(rb_fde_t *const F, void *const data)
rb_ssl_connect_realcb(F, RB_ERR_TIMEOUT, data); rb_ssl_connect_realcb(F, RB_ERR_TIMEOUT, data);
} }
static void
rb_ssl_tryconn(rb_fde_t *const F, const int status, void *const data)
{
lrb_assert(F != NULL);
struct ssl_connect *const sconn = data;
if(status != RB_OK)
{
rb_ssl_connect_realcb(F, status, sconn);
return;
}
F->type |= RB_FD_SSL;
rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn);
rb_ssl_init_fd(F, RB_FD_TLS_DIRECTION_OUT);
rb_ssl_tryconn_cb(F, sconn);
}
/* /*
@ -800,6 +645,39 @@ rb_ssl_clear_handshake_count(rb_fde_t *const F)
F->handshake_count = 0; F->handshake_count = 0;
} }
void
rb_ssl_start_accepted(rb_fde_t *const F, ACCB *const cb, void *const data, const int timeout)
{
F->type |= RB_FD_SSL;
F->accept = rb_malloc(sizeof(struct acceptdata));
F->accept->callback = cb;
F->accept->data = data;
F->accept->addrlen = 0;
(void) memset(&F->accept->S, 0x00, sizeof F->accept->S);
rb_settimeout(F, timeout, rb_ssl_timeout, NULL);
rb_ssl_init_fd(F, RB_FD_TLS_DIRECTION_IN);
rb_ssl_accept_common(F, NULL);
}
void
rb_ssl_accept_setup(rb_fde_t *const srv_F, rb_fde_t *const cli_F, struct sockaddr *const st, const int addrlen)
{
cli_F->type |= RB_FD_SSL;
cli_F->accept = rb_malloc(sizeof(struct acceptdata));
cli_F->accept->callback = srv_F->accept->callback;
cli_F->accept->data = srv_F->accept->data;
cli_F->accept->addrlen = addrlen;
(void) memset(&cli_F->accept->S, 0x00, sizeof cli_F->accept->S);
(void) memcpy(&cli_F->accept->S, st, addrlen);
rb_settimeout(cli_F, 10, rb_ssl_timeout, NULL);
rb_ssl_init_fd(cli_F, RB_FD_TLS_DIRECTION_IN);
rb_ssl_accept_common(cli_F, NULL);
}
int int
rb_ssl_listen(rb_fde_t *const F, const int backlog, const int defer_accept) rb_ssl_listen(rb_fde_t *const F, const int backlog, const int defer_accept)
{ {
@ -825,4 +703,25 @@ rb_connect_tcp_ssl(rb_fde_t *const F, struct sockaddr *const dest, struct sockad
rb_connect_tcp(F, dest, clocal, socklen, rb_ssl_tryconn, sconn, timeout); rb_connect_tcp(F, dest, clocal, socklen, rb_ssl_tryconn, sconn, timeout);
} }
void
rb_ssl_start_connected(rb_fde_t *const F, CNCB *const callback, void *const data, const int timeout)
{
if(F == NULL)
return;
struct ssl_connect *const sconn = rb_malloc(sizeof *sconn);
sconn->data = data;
sconn->callback = callback;
sconn->timeout = timeout;
F->connect = rb_malloc(sizeof(struct conndata));
F->connect->callback = callback;
F->connect->data = data;
F->type |= RB_FD_SSL;
rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn);
rb_ssl_init_fd(F, RB_FD_TLS_DIRECTION_OUT);
rb_ssl_tryconn_cb(F, sconn);
}
#endif /* HAVE_OPESSL */ #endif /* HAVE_OPESSL */