Make libssl async aware

The following entry points have been made async aware:
SSL_accept
SSL_read
SSL_write

Also added is a new mode - SSL_MODE_ASYNC. Calling the above functions with
the async mode enabled will initiate a new async job. If an async pause is
encountered whilst executing the job (such as for example if using SHA1/RSA
with the Dummy Async engine), then the above functions return with
SSL_WANT_ASYNC. Calling the functions again (with exactly the same args
as per non-blocking IO), will resume the job where it left off.

Reviewed-by: Rich Salz <rsalz@openssl.org>
This commit is contained in:
Matt Caswell
2015-02-13 23:28:49 +00:00
parent a14e9ff713
commit 07bbc92ccb
7 changed files with 840 additions and 667 deletions

View File

@@ -158,6 +158,7 @@
#ifndef OPENSSL_NO_ENGINE
# include <openssl/engine.h>
#endif
#include <openssl/async.h>
const char SSL_version_str[] = OPENSSL_VERSION_TEXT;
@@ -186,6 +187,12 @@ SSL3_ENC_METHOD ssl3_undef_enc_method = {
int use_context))ssl_undefined_function,
};
struct ssl_async_args {
SSL *s;
void *buf;
int num;
};
static void clear_ciphers(SSL *s)
{
/* clear the current cipher */
@@ -386,6 +393,8 @@ SSL *SSL_new(SSL_CTX *ctx)
s->psk_server_callback = ctx->psk_server_callback;
#endif
s->job = NULL;
return (s);
err:
SSL_free(s);
@@ -914,13 +923,55 @@ int SSL_check_private_key(const SSL *ssl)
ssl->cert->key->privatekey));
}
int SSL_waiting_for_async(SSL *s)
{
if(s->job) {
return ASYNC_job_is_waiting(s->job);
}
return 0;
}
static int ssl_accept_intern(void *vargs)
{
struct ssl_async_args *args;
SSL *s;
args = (struct ssl_async_args *)vargs;
s = args->s;
return s->method->ssl_accept(s);
}
int SSL_accept(SSL *s)
{
int ret;
struct ssl_async_args args;
if (s->handshake_func == 0)
/* Not properly initialized yet */
SSL_set_accept_state(s);
return (s->method->ssl_accept(s));
args.s = s;
if((s->mode & SSL_MODE_ASYNC) && !ASYNC_in_job()) {
switch(ASYNC_start_job(&s->job, &ret, ssl_accept_intern, &args,
sizeof(struct ssl_async_args))) {
case ASYNC_ERR:
SSLerr(SSL_F_SSL_ACCEPT, SSL_R_FAILED_TO_INIT_ASYNC);
return -1;
case ASYNC_PAUSE:
return -1;
case ASYNC_FINISH:
s->job = NULL;
return ret;
default:
SSLerr(SSL_F_SSL_ACCEPT, ERR_R_INTERNAL_ERROR);
/* Shouldn't happen */
return -1;
}
} else {
return s->method->ssl_accept(s);
}
}
int SSL_connect(SSL *s)
@@ -937,8 +988,27 @@ long SSL_get_default_timeout(const SSL *s)
return (s->method->get_timeout());
}
static int ssl_read_intern(void *vargs)
{
struct ssl_async_args *args;
SSL *s;
void *buf;
int num;
args = (struct ssl_async_args *)vargs;
s = args->s;
buf = args->buf;
num = args->num;
return s->method->ssl_read(s, buf, num);
}
int SSL_read(SSL *s, void *buf, int num)
{
int ret;
struct ssl_async_args args;
if (s->handshake_func == 0) {
SSLerr(SSL_F_SSL_READ, SSL_R_UNINITIALIZED);
return -1;
@@ -948,7 +1018,33 @@ int SSL_read(SSL *s, void *buf, int num)
s->rwstate = SSL_NOTHING;
return (0);
}
return (s->method->ssl_read(s, buf, num));
args.s = s;
args.buf = buf;
args.num = num;
if((s->mode & SSL_MODE_ASYNC) && !ASYNC_in_job()) {
switch(ASYNC_start_job(&s->job, &ret, ssl_read_intern, &args,
sizeof(struct ssl_async_args))) {
case ASYNC_ERR:
s->rwstate = SSL_NOTHING;
SSLerr(SSL_F_SSL_READ, SSL_R_FAILED_TO_INIT_ASYNC);
return -1;
case ASYNC_PAUSE:
s->rwstate = SSL_ASYNC_PAUSED;
return -1;
case ASYNC_FINISH:
s->job = NULL;
return ret;
default:
s->rwstate = SSL_NOTHING;
SSLerr(SSL_F_SSL_READ, ERR_R_INTERNAL_ERROR);
/* Shouldn't happen */
return -1;
}
} else {
return s->method->ssl_read(s, buf, num);
}
}
int SSL_peek(SSL *s, void *buf, int num)
@@ -964,8 +1060,27 @@ int SSL_peek(SSL *s, void *buf, int num)
return (s->method->ssl_peek(s, buf, num));
}
static int ssl_write_intern(void *vargs)
{
struct ssl_async_args *args;
SSL *s;
const void *buf;
int num;
args = (struct ssl_async_args *)vargs;
s = args->s;
buf = args->buf;
num = args->num;
return s->method->ssl_write(s, buf, num);
}
int SSL_write(SSL *s, const void *buf, int num)
{
int ret;
struct ssl_async_args args;
if (s->handshake_func == 0) {
SSLerr(SSL_F_SSL_WRITE, SSL_R_UNINITIALIZED);
return -1;
@@ -976,7 +1091,33 @@ int SSL_write(SSL *s, const void *buf, int num)
SSLerr(SSL_F_SSL_WRITE, SSL_R_PROTOCOL_IS_SHUTDOWN);
return (-1);
}
return (s->method->ssl_write(s, buf, num));
args.s = s;
args.buf = (void *) buf;
args.num = num;
if((s->mode & SSL_MODE_ASYNC) && !ASYNC_in_job()) {
switch(ASYNC_start_job(&s->job, &ret, ssl_write_intern, &args,
sizeof(struct ssl_async_args))) {
case ASYNC_ERR:
s->rwstate = SSL_NOTHING;
SSLerr(SSL_F_SSL_WRITE, SSL_R_FAILED_TO_INIT_ASYNC);
return -1;
case ASYNC_PAUSE:
s->rwstate = SSL_ASYNC_PAUSED;
return -1;
case ASYNC_FINISH:
s->job = NULL;
return ret;
default:
s->rwstate = SSL_NOTHING;
SSLerr(SSL_F_SSL_WRITE, ERR_R_INTERNAL_ERROR);
/* Shouldn't happen */
return -1;
}
} else {
return s->method->ssl_write(s, buf, num);
}
}
int SSL_shutdown(SSL *s)
@@ -2373,6 +2514,9 @@ int SSL_get_error(const SSL *s, int i)
if ((i < 0) && SSL_want_x509_lookup(s)) {
return (SSL_ERROR_WANT_X509_LOOKUP);
}
if ((i < 0) && SSL_want_async(s)) {
return SSL_ERROR_WANT_ASYNC;
}
if (i == 0) {
if ((s->shutdown & SSL_RECEIVED_SHUTDOWN) &&
@@ -2432,8 +2576,6 @@ int ssl_undefined_void_function(void)
int ssl_undefined_const_function(const SSL *s)
{
SSLerr(SSL_F_SSL_UNDEFINED_CONST_FUNCTION,
ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return (0);
}