Make libssl async aware
[openssl.git] / ssl / ssl_lib.c
index c84ea15ed1e011fe8662b1bf5f5cf02e584de9ec..63a1a891f265ae81f07189a2dbdbbdb006604962 100644 (file)
 #ifndef OPENSSL_NO_ENGINE
 # include <openssl/engine.h>
 #endif
+#include <openssl/async.h>
 
-const char *SSL_version_str = OPENSSL_VERSION_TEXT;
+const char SSL_version_str[] = OPENSSL_VERSION_TEXT;
 
 SSL3_ENC_METHOD ssl3_undef_enc_method = {
     /*
@@ -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 */
@@ -215,9 +222,7 @@ int SSL_clear(SSL *s)
         return 0;
     }
 
-    s->type = 0;
-
-    s->state = SSL_ST_BEFORE | ((s->server) ? SSL_ST_ACCEPT : SSL_ST_CONNECT);
+    ossl_statem_clear(s);
 
     s->version = s->method->version;
     s->client_version = s->version;
@@ -232,7 +237,7 @@ int SSL_clear(SSL *s)
      * Check to see if we were changed into a different method, if so, revert
      * back if we are not doing session-id reuse.
      */
-    if (!s->in_handshake && (s->session == NULL)
+    if (!ossl_statem_get_in_handshake(s) && (s->session == NULL)
         && (s->method != s->ctx->method)) {
         s->method->ssl_free(s);
         s->method = s->ctx->method;
@@ -286,6 +291,7 @@ SSL *SSL_new(SSL_CTX *ctx)
     s->options = ctx->options;
     s->mode = ctx->mode;
     s->max_cert_list = ctx->max_cert_list;
+    s->references = 1;
 
     /*
      * Earlier library versions used to copy the pointer to the CERT, not
@@ -312,7 +318,7 @@ SSL *SSL_new(SSL_CTX *ctx)
     s->generate_session_id = ctx->generate_session_id;
 
     s->param = X509_VERIFY_PARAM_new();
-    if (!s->param)
+    if (s->param == NULL)
         goto err;
     X509_VERIFY_PARAM_inherit(s->param, ctx->param);
     s->quiet_shutdown = ctx->quiet_shutdown;
@@ -367,12 +373,14 @@ SSL *SSL_new(SSL_CTX *ctx)
 
     s->verify_result = X509_V_OK;
 
+    s->default_passwd_callback = ctx->default_passwd_callback;
+    s->default_passwd_callback_userdata = ctx->default_passwd_callback_userdata;
+
     s->method = ctx->method;
 
     if (!s->method->ssl_new(s))
         goto err;
 
-    s->references = 1;
     s->server = (ctx->method->ssl_accept == ssl_undefined_function) ? 0 : 1;
 
     if (!SSL_clear(s))
@@ -385,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);
@@ -858,7 +868,7 @@ int SSL_copy_session_id(SSL *t, const SSL *f)
     }
 
     /*
-     * what if we are setup as SSLv2 but want to talk SSLv3 or vice-versa
+     * what if we are setup for one protocol version but want to talk another
      */
     if (t->method != f->method) {
         t->method->ssl_free(t); /* cleanup current */
@@ -913,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)
@@ -936,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;
@@ -947,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)
@@ -963,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;
@@ -975,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)
@@ -992,7 +1134,7 @@ int SSL_shutdown(SSL *s)
         return -1;
     }
 
-    if ((s != NULL) && !SSL_in_init(s))
+    if (!SSL_in_init(s))
         return (s->method->ssl_shutdown(s));
     else
         return (1);
@@ -1078,10 +1220,11 @@ long SSL_ctrl(SSL *s, int cmd, long larg, void *parg)
                 return 0;
             *(unsigned char **)parg = s->s3->tmp.ciphers_raw;
             return (int)s->s3->tmp.ciphers_rawlen;
-        } else
-            return ssl_put_cipher_by_char(s, NULL, NULL);
+        } else {
+            return TLS_CIPHER_LEN;
+        }
     case SSL_CTRL_GET_EXTMS_SUPPORT:
-        if (!s->session || SSL_in_init(s) || s->in_handshake)
+        if (!s->session || SSL_in_init(s) || ossl_statem_get_in_handshake(s))
                return -1;
        if (s->session->flags & SSL_SESS_FLAG_EXTMS)
             return 1;
@@ -1225,25 +1368,21 @@ long SSL_CTX_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp) (void))
 
 int ssl_cipher_id_cmp(const SSL_CIPHER *a, const SSL_CIPHER *b)
 {
-    long l;
-
-    l = a->id - b->id;
-    if (l == 0L)
-        return (0);
-    else
-        return ((l > 0) ? 1 : -1);
+    if (a->id > b->id)
+        return 1;
+    if (a->id < b->id)
+        return -1;
+    return 0;
 }
 
 int ssl_cipher_ptr_id_cmp(const SSL_CIPHER *const *ap,
                           const SSL_CIPHER *const *bp)
 {
-    long l;
-
-    l = (*ap)->id - (*bp)->id;
-    if (l == 0L)
-        return (0);
-    else
-        return ((l > 0) ? 1 : -1);
+    if ((*ap)->id > (*bp)->id)
+        return 1;
+    if ((*ap)->id < (*bp)->id)
+        return -1;
+    return 0;
 }
 
 /** return a STACK of the ciphers available for the SSL and in order of
@@ -1362,7 +1501,6 @@ int SSL_set_cipher_list(SSL *s, const char *str)
     return 1;
 }
 
-/* works well for SSLv2, not so good for SSLv3 */
 char *SSL_get_shared_ciphers(const SSL *s, char *buf, int len)
 {
     char *p;
@@ -1553,7 +1691,7 @@ int SSL_CTX_set_alpn_protos(SSL_CTX *ctx, const unsigned char *protos,
 {
     OPENSSL_free(ctx->alpn_client_proto_list);
     ctx->alpn_client_proto_list = OPENSSL_malloc(protos_len);
-    if (!ctx->alpn_client_proto_list)
+    if (ctx->alpn_client_proto_list == NULL)
         return 1;
     memcpy(ctx->alpn_client_proto_list, protos, protos_len);
     ctx->alpn_client_proto_list_len = protos_len;
@@ -1571,7 +1709,7 @@ int SSL_set_alpn_protos(SSL *ssl, const unsigned char *protos,
 {
     OPENSSL_free(ssl->alpn_client_proto_list);
     ssl->alpn_client_proto_list = OPENSSL_malloc(protos_len);
-    if (!ssl->alpn_client_proto_list)
+    if (ssl->alpn_client_proto_list == NULL)
         return 1;
     memcpy(ssl->alpn_client_proto_list, protos, protos_len);
     ssl->alpn_client_proto_list_len = protos_len;
@@ -1714,7 +1852,7 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth)
     }
 
     ret->param = X509_VERIFY_PARAM_new();
-    if (!ret->param)
+    if (ret->param == NULL)
         goto err;
 
     if ((ret->md5 = EVP_get_digestbyname("ssl3-md5")) == NULL) {
@@ -1825,9 +1963,6 @@ void SSL_CTX_free(SSL_CTX *a)
 #ifndef OPENSSL_NO_SRTP
     sk_SRTP_PROTECTION_PROFILE_free(a->srtp_profiles);
 #endif
-#ifndef OPENSSL_NO_PSK
-    OPENSSL_free(a->psk_identity_hint);
-#endif
 #ifndef OPENSSL_NO_SRP
     SSL_CTX_SRP_CTX_free(a);
 #endif
@@ -1855,6 +1990,16 @@ void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *u)
     ctx->default_passwd_callback_userdata = u;
 }
 
+void SSL_set_default_passwd_cb(SSL *s, pem_password_cb *cb)
+{
+    s->default_passwd_callback = cb;
+}
+
+void SSL_set_default_passwd_cb_userdata(SSL *s, void *u)
+{
+    s->default_passwd_callback_userdata = u;
+}
+
 void SSL_CTX_set_cert_verify_callback(SSL_CTX *ctx,
                                       int (*cb) (X509_STORE_CTX *, void *),
                                       void *arg)
@@ -2369,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) &&
@@ -2399,7 +2547,7 @@ void SSL_set_accept_state(SSL *s)
 {
     s->server = 1;
     s->shutdown = 0;
-    s->state = SSL_ST_ACCEPT | SSL_ST_BEFORE;
+    ossl_statem_clear(s);
     s->handshake_func = s->method->ssl_accept;
     clear_ciphers(s);
 }
@@ -2408,7 +2556,7 @@ void SSL_set_connect_state(SSL *s)
 {
     s->server = 0;
     s->shutdown = 0;
-    s->state = SSL_ST_CONNECT | SSL_ST_BEFORE;
+    ossl_statem_clear(s);
     s->handshake_func = s->method->ssl_connect;
     clear_ciphers(s);
 }
@@ -2428,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);
 }
 
@@ -2470,7 +2616,6 @@ SSL *SSL_dup(SSL *s)
         return (NULL);
 
     ret->version = s->version;
-    ret->type = s->type;
     ret->method = s->method;
 
     if (s->session != NULL) {
@@ -2531,21 +2676,23 @@ SSL *SSL_dup(SSL *s)
             ret->wbio = ret->rbio;
     }
     ret->rwstate = s->rwstate;
-    ret->in_handshake = s->in_handshake;
     ret->handshake_func = s->handshake_func;
     ret->server = s->server;
     ret->renegotiate = s->renegotiate;
     ret->new_session = s->new_session;
     ret->quiet_shutdown = s->quiet_shutdown;
     ret->shutdown = s->shutdown;
-    ret->state = s->state;      /* SSL_dup does not really work at any state,
-                                 * though */
+    ret->statem = s->statem;      /* SSL_dup does not really work at any state,
+                                   * though */
     RECORD_LAYER_dup(&ret->rlayer, &s->rlayer);
     ret->init_num = 0;          /* would have to copy ret->init_buf,
                                  * ret->init_msg, ret->init_num,
                                  * ret->init_off */
     ret->hit = s->hit;
 
+    ret->default_passwd_callback = s->default_passwd_callback;
+    ret->default_passwd_callback_userdata = s->default_passwd_callback_userdata;
+
     X509_VERIFY_PARAM_inherit(ret->param, s->param);
 
     /* dup the cipher_list and cipher_list_by_id stacks */
@@ -2783,18 +2930,47 @@ SSL_CTX *SSL_set_SSL_CTX(SSL *ssl, SSL_CTX *ctx)
     return (ssl->ctx);
 }
 
-#ifndef OPENSSL_NO_STDIO
 int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx)
 {
     return (X509_STORE_set_default_paths(ctx->cert_store));
 }
 
+int SSL_CTX_set_default_verify_dir(SSL_CTX *ctx)
+{
+    X509_LOOKUP *lookup;
+
+    lookup = X509_STORE_add_lookup(ctx->cert_store, X509_LOOKUP_hash_dir());
+    if (lookup == NULL)
+        return 0;
+    X509_LOOKUP_add_dir(lookup, NULL, X509_FILETYPE_DEFAULT);
+
+    /* Clear any errors if the default directory does not exist */
+    ERR_clear_error();
+
+    return 1;
+}
+
+int SSL_CTX_set_default_verify_file(SSL_CTX *ctx)
+{
+    X509_LOOKUP *lookup;
+
+    lookup = X509_STORE_add_lookup(ctx->cert_store, X509_LOOKUP_file());
+    if (lookup == NULL)
+        return 0;
+
+    X509_LOOKUP_load_file(lookup, NULL, X509_FILETYPE_DEFAULT);
+
+    /* Clear any errors if the default file does not exist */
+    ERR_clear_error();
+
+    return 1;
+}
+
 int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile,
                                   const char *CApath)
 {
     return (X509_STORE_load_locations(ctx->cert_store, CAfile, CApath));
 }
-#endif
 
 void SSL_set_info_callback(SSL *ssl,
                            void (*cb) (const SSL *ssl, int type, int val))
@@ -2812,16 +2988,6 @@ void (*SSL_get_info_callback(const SSL *ssl)) (const SSL * /* ssl */ ,
     return ssl->info_callback;
 }
 
-int SSL_state(const SSL *ssl)
-{
-    return (ssl->state);
-}
-
-void SSL_set_state(SSL *ssl, int state)
-{
-    ssl->state = state;
-}
-
 void SSL_set_verify_result(SSL *ssl, long arg)
 {
     ssl->verify_result = arg;
@@ -3007,13 +3173,13 @@ int SSL_CTX_use_psk_identity_hint(SSL_CTX *ctx, const char *identity_hint)
                SSL_R_DATA_LENGTH_TOO_LONG);
         return 0;
     }
-    OPENSSL_free(ctx->psk_identity_hint);
+    OPENSSL_free(ctx->cert->psk_identity_hint);
     if (identity_hint != NULL) {
-        ctx->psk_identity_hint = BUF_strdup(identity_hint);
-        if (ctx->psk_identity_hint == NULL)
+        ctx->cert->psk_identity_hint = BUF_strdup(identity_hint);
+        if (ctx->cert->psk_identity_hint == NULL)
             return 0;
     } else
-        ctx->psk_identity_hint = NULL;
+        ctx->cert->psk_identity_hint = NULL;
     return 1;
 }
 
@@ -3022,20 +3188,17 @@ int SSL_use_psk_identity_hint(SSL *s, const char *identity_hint)
     if (s == NULL)
         return 0;
 
-    if (s->session == NULL)
-        return 1;               /* session not created yet, ignored */
-
     if (identity_hint != NULL && strlen(identity_hint) > PSK_MAX_IDENTITY_LEN) {
         SSLerr(SSL_F_SSL_USE_PSK_IDENTITY_HINT, SSL_R_DATA_LENGTH_TOO_LONG);
         return 0;
     }
-    OPENSSL_free(s->session->psk_identity_hint);
+    OPENSSL_free(s->cert->psk_identity_hint);
     if (identity_hint != NULL) {
-        s->session->psk_identity_hint = BUF_strdup(identity_hint);
-        if (s->session->psk_identity_hint == NULL)
+        s->cert->psk_identity_hint = BUF_strdup(identity_hint);
+        if (s->cert->psk_identity_hint == NULL)
             return 0;
     } else
-        s->session->psk_identity_hint = NULL;
+        s->cert->psk_identity_hint = NULL;
     return 1;
 }
 
@@ -3144,8 +3307,11 @@ EVP_MD_CTX *ssl_replace_hash(EVP_MD_CTX **hash, const EVP_MD *md)
 {
     ssl_clear_hash_ctx(hash);
     *hash = EVP_MD_CTX_create();
-    if (md)
-        EVP_DigestInit_ex(*hash, md, NULL);
+    if (*hash == NULL || (md && EVP_DigestInit_ex(*hash, md, NULL) <= 0)) {
+        EVP_MD_CTX_destroy(*hash);
+        *hash = NULL;
+        return NULL;
+    }
     return *hash;
 }