[openssl-commits] [openssl] master update

Matt Caswell matt at openssl.org
Sun Jan 27 12:31:03 UTC 2019


The branch master has been updated
       via  9f5a87fd665cb597fa1c1f4eef882d2d2f833e61 (commit)
      from  61e033308b1c004bd808352fb1d786547dcdf62b (commit)


- Log -----------------------------------------------------------------
commit 9f5a87fd665cb597fa1c1f4eef882d2d2f833e61
Author: Ping Yu <ping.yu at intel.com>
Date:   Mon Nov 5 15:41:01 2018 -0500

    add an additional async notification communication method based on callback
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    Reviewed-by: Paul Yang <yang.yang at baishancloud.com>
    Signed-off-by: Ping Yu <ping.yu at intel.com>
    Signed-off-by: Steven Linsell <stevenx.linsell at intel.com>
    
    (Merged from https://github.com/openssl/openssl/pull/7573)

-----------------------------------------------------------------------

Summary of changes:
 crypto/async/async_locl.h           |  3 ++
 crypto/async/async_wait.c           | 35 ++++++++++++++
 doc/man3/ASYNC_WAIT_CTX_new.pod     | 73 ++++++++++++++++++++++++++--
 doc/man3/ASYNC_start_job.pod        | 36 +++++++-------
 doc/man3/SSL_set_async_callback.pod | 96 +++++++++++++++++++++++++++++++++++++
 engines/e_dasync.c                  | 14 ++++++
 include/openssl/async.h             | 14 ++++++
 include/openssl/ssl.h               |  9 ++++
 ssl/ssl_lib.c                       | 48 +++++++++++++++++++
 ssl/ssl_locl.h                      |  8 ++++
 test/asynctest.c                    | 38 +++++++++++++++
 util/libcrypto.num                  |  4 ++
 util/libssl.num                     |  5 ++
 util/private.num                    |  6 +++
 14 files changed, 369 insertions(+), 20 deletions(-)
 create mode 100644 doc/man3/SSL_set_async_callback.pod

diff --git a/crypto/async/async_locl.h b/crypto/async/async_locl.h
index 2325ce9..85dfcfa 100644
--- a/crypto/async/async_locl.h
+++ b/crypto/async/async_locl.h
@@ -59,6 +59,9 @@ struct async_wait_ctx_st {
     struct fd_lookup_st *fds;
     size_t numadd;
     size_t numdel;
+    ASYNC_callback_fn callback;
+    void *callback_arg;
+    int status;
 };
 
 DEFINE_STACK_OF(ASYNC_JOB)
diff --git a/crypto/async/async_wait.c b/crypto/async/async_wait.c
index 2553298..642b781 100644
--- a/crypto/async/async_wait.c
+++ b/crypto/async/async_wait.c
@@ -182,6 +182,41 @@ int ASYNC_WAIT_CTX_clear_fd(ASYNC_WAIT_CTX *ctx, const void *key)
     return 0;
 }
 
+int ASYNC_WAIT_CTX_set_callback(ASYNC_WAIT_CTX *ctx,
+                                ASYNC_callback_fn callback,
+                                void *callback_arg)
+{
+      if (ctx == NULL)
+          return 0;
+
+      ctx->callback = callback;
+      ctx->callback_arg = callback_arg;
+      return 1;
+}
+
+int ASYNC_WAIT_CTX_get_callback(ASYNC_WAIT_CTX *ctx,
+                                ASYNC_callback_fn *callback,
+                                void **callback_arg)
+{
+      if (ctx->callback == NULL)
+          return 0;
+
+      *callback = ctx->callback;
+      *callback_arg = ctx->callback_arg;
+      return 1;
+}
+
+int ASYNC_WAIT_CTX_set_status(ASYNC_WAIT_CTX *ctx, int status)
+{
+      ctx->status = status;
+      return 1;
+}
+
+int ASYNC_WAIT_CTX_get_status(ASYNC_WAIT_CTX *ctx)
+{
+      return ctx->status;
+}
+
 void async_wait_ctx_reset_counts(ASYNC_WAIT_CTX *ctx)
 {
     struct fd_lookup_st *curr, *prev = NULL;
diff --git a/doc/man3/ASYNC_WAIT_CTX_new.pod b/doc/man3/ASYNC_WAIT_CTX_new.pod
index eeb2777..9076be8 100644
--- a/doc/man3/ASYNC_WAIT_CTX_new.pod
+++ b/doc/man3/ASYNC_WAIT_CTX_new.pod
@@ -4,13 +4,22 @@
 
 ASYNC_WAIT_CTX_new, ASYNC_WAIT_CTX_free, ASYNC_WAIT_CTX_set_wait_fd,
 ASYNC_WAIT_CTX_get_fd, ASYNC_WAIT_CTX_get_all_fds,
-ASYNC_WAIT_CTX_get_changed_fds, ASYNC_WAIT_CTX_clear_fd - functions to manage
-waiting for asynchronous jobs to complete
+ASYNC_WAIT_CTX_get_changed_fds, ASYNC_WAIT_CTX_clear_fd,
+ASYNC_WAIT_CTX_set_callback, ASYNC_WAIT_CTX_get_callback,
+ASYNC_WAIT_CTX_set_status, ASYNC_WAIT_CTX_get_status, ASYNC_callback_fn,
+ASYNC_STATUS_UNSUPPORTED, ASYNC_STATUS_ERR, ASYNC_STATUS_OK,
+ASYNC_STATUS_EAGAIN
+- functions to manage waiting for asynchronous jobs to complete
 
 =head1 SYNOPSIS
 
  #include <openssl/async.h>
 
+ #define ASYNC_STATUS_UNSUPPORTED    0
+ #define ASYNC_STATUS_ERR            1
+ #define ASYNC_STATUS_OK             2
+ #define ASYNC_STATUS_EAGAIN         3
+ typedef int (*ASYNC_callback_fn)(void *arg);
  ASYNC_WAIT_CTX *ASYNC_WAIT_CTX_new(void);
  void ASYNC_WAIT_CTX_free(ASYNC_WAIT_CTX *ctx);
  int ASYNC_WAIT_CTX_set_wait_fd(ASYNC_WAIT_CTX *ctx, const void *key,
@@ -26,6 +35,14 @@ waiting for asynchronous jobs to complete
                                     size_t *numaddfds, OSSL_ASYNC_FD *delfd,
                                     size_t *numdelfds);
  int ASYNC_WAIT_CTX_clear_fd(ASYNC_WAIT_CTX *ctx, const void *key);
+ int ASYNC_WAIT_CTX_set_callback(ASYNC_WAIT_CTX *ctx,
+                                 ASYNC_callback_fn callback,
+                                 void *callback_arg);
+ int ASYNC_WAIT_CTX_get_callback(ASYNC_WAIT_CTX *ctx,
+                                 ASYNC_callback_fn *callback,
+                                 void **callback_arg);
+ int ASYNC_WAIT_CTX_set_status(ASYNC_WAIT_CTX *ctx, int status);
+ int ASYNC_WAIT_CTX_get_status(ASYNC_WAIT_CTX *ctx);
 
 
 =head1 DESCRIPTION
@@ -103,14 +120,58 @@ code that the job should be resumed by making the wait file descriptor
 "readable". Once resumed the engine should clear the wake signal on the wait
 file descriptor.
 
+As well as a file descriptor, user code may also be notified via a callback. The
+callback and data pointers are stored within the ASYNC_WAIT_CTX along with an
+additional status field that can be used for the notification of retries from an
+engine. This additional method can be used when the user thinks that a file
+descriptor is too costly in terms of CPU cycles or in some context where a file
+descriptor is not appropriate.
+
+ASYNC_WAIT_CTX_set_callback() sets the callback and the callback argument. The
+callback will be called to notify user code when an engine completes a
+cryptography operation. It is a requirement that the callback function is small
+and non-blocking as it will be run in the context of a polling mechanism or an
+interrupt.
+
+ASYNC_WAIT_CTX_get_callback() returns the callback set in the ASYNC_WAIT_CTX
+structure.
+
+ASYNC_WAIT_CTX_set_status() allows an engine to set the current engine status.
+The possible status values are the following:
+ASYNC_STATUS_UNSUPPORTED: The engine does not support the callback mechanism.
+This is the default value. The engine must call ASYNC_WAIT_CTX_set_status() to
+set the status to some value other than ASYNC_STATUS_UNSUPPORTED if it intends
+to enable the callback mechanism.
+ASYNC_STATUS_ERR: The engine has a fatal problem with this request. The user
+code should clean up this session.
+ASYNC_STATUS_OK: The request has been successfully submitted.
+ASYNC_STATUS_EAGAIN: The engine has some problem which will be recovered soon,
+such as a buffer is full, so user code should resume the job.
+
+ASYNC_WAIT_CTX_get_status() allows user code to obtain the current status value.
+If the status is any value other than ASYNC_STATUS_OK then the user code should
+not expect to receive a callback from the engine even if one has been set.
+
+An example of the usage of the callback method might be the following. User
+code would initiate cryptographic operations, and the engine code would dispatch
+this operation to hardware, and if the dispatch is successful, then the engine
+code would call ASYNC_pause_job() to return control to the user code. After
+that, user code can perform other tasks. When the hardware completes the
+operation, normally it is detected by a polling function or an interrupt, as the
+user code set a callback by calling ASYNC_WAIT_CTX_set_callback() previously,
+then the registered callback will be called.
+
 =head1 RETURN VALUES
 
 ASYNC_WAIT_CTX_new() returns a pointer to the newly allocated ASYNC_WAIT_CTX or
 NULL on error.
 
 ASYNC_WAIT_CTX_set_wait_fd, ASYNC_WAIT_CTX_get_fd, ASYNC_WAIT_CTX_get_all_fds,
-ASYNC_WAIT_CTX_get_changed_fds and ASYNC_WAIT_CTX_clear_fd all return 1 on
-success or 0 on error.
+ASYNC_WAIT_CTX_get_changed_fds, ASYNC_WAIT_CTX_clear_fd,
+ASYNC_WAIT_CTX_set_callback, ASYNC_WAIT_CTX_get_callback and
+ASYNC_WAIT_CTX_set_status all return 1 on success or 0 on error.
+ASYNC_WAIT_CTX_get_status() returs the engine status.
+
 
 =head1 NOTES
 
@@ -132,6 +193,10 @@ ASYNC_WAIT_CTX_get_fd(), ASYNC_WAIT_CTX_get_all_fds(),
 ASYNC_WAIT_CTX_get_changed_fds() and ASYNC_WAIT_CTX_clear_fd()
 were added in OpenSSL 1.1.0.
 
+ASYNC_WAIT_CTX_set_callback(), ASYNC_WAIT_CTX_get_callback(),
+ASYNC_WAIT_CTX_set_status(), and ASYNC_WAIT_CTX_get_status()
+were added in OpenSSL 3.0.0.
+
 =head1 COPYRIGHT
 
 Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
diff --git a/doc/man3/ASYNC_start_job.pod b/doc/man3/ASYNC_start_job.pod
index 95694b6..5ac368d 100644
--- a/doc/man3/ASYNC_start_job.pod
+++ b/doc/man3/ASYNC_start_job.pod
@@ -107,22 +107,26 @@ ASYNC_pause_job() is called whilst not within the context of a job then no
 action is taken and ASYNC_pause_job() returns immediately.
 
 ASYNC_get_wait_ctx() can be used to get a pointer to the ASYNC_WAIT_CTX
-for the B<job>. ASYNC_WAIT_CTXs can have a "wait" file descriptor associated
-with them. Applications can wait for the file descriptor to be ready for "read"
-using a system function call such as select or poll (being ready for "read"
-indicates that the job should be resumed). If no file descriptor is made
-available then an application will have to periodically "poll" the job by
-attempting to restart it to see if it is ready to continue.
-
-An example of typical usage might be an async capable engine. User code would
-initiate cryptographic operations. The engine would initiate those operations
-asynchronously and then call L<ASYNC_WAIT_CTX_set_wait_fd(3)> followed by
-ASYNC_pause_job() to return control to the user code. The user code can then
-perform other tasks or wait for the job to be ready by calling "select" or other
-similar function on the wait file descriptor. The engine can signal to the user
-code that the job should be resumed by making the wait file descriptor
-"readable". Once resumed the engine should clear the wake signal on the wait
-file descriptor.
+for the B<job>. ASYNC_WAIT_CTXs contain two different ways to notify
+applications that a job is ready to be resumed. One is a "wait" file
+descriptor, and the other is a "callback" mechanism.
+
+The "wait" file descriptor associated with ASYNC_WAIT_CTX is used for
+applications to wait for the file descriptor to be ready for "read" using a
+system function call such as select or poll (being ready for "read" indicates
+that the job should be resumed). If no file descriptor is made available then
+an application will have to periodically "poll" the job by attempting to restart
+it to see if it is ready to continue.
+
+ASYNC_WAIT_CTXs also have a "callback" mechanism to notify applications. The
+callback is set by an application, and it will be automatically called when an
+engine completes a cryptography operation, so that the application can resume
+the paused work flow without polling. An engine could be written to look whether
+the callback has been set. If it has then it would use the callback mechanism
+in preference to the file descriptor notifications. If a callback is not set
+then the engine may use file descriptor based notifications. Please note that
+not all engines may support the callback mechanism, so the callback may not be
+used even if it has been set. See ASYNC_WAIT_CTX_new() for more details.
 
 The ASYNC_block_pause() function will prevent the currently active job from
 pausing. The block will remain in place until a subsequent call to
diff --git a/doc/man3/SSL_set_async_callback.pod b/doc/man3/SSL_set_async_callback.pod
new file mode 100644
index 0000000..5e7f61e
--- /dev/null
+++ b/doc/man3/SSL_set_async_callback.pod
@@ -0,0 +1,96 @@
+=pod
+
+=head1 NAME
+
+SSL_CTX_set_async_callback,
+SSL_CTX_set_async_callback_arg,
+SSL_set_async_callback,
+SSL_set_async_callback_arg,
+SSL_get_async_status,
+SSL_async_callback_fn
+- manage asynchronous operations
+
+=head1 SYNOPSIS
+
+=for comment multiple includes
+
+ #include <openssl/ssl.h>
+
+ typedef int (*SSL_async_callback_fn)(SSL *s, void *arg);
+ int SSL_CTX_set_async_callback(SSL_CTX *ctx, SSL_async_callback_fn callback);
+ int SSL_CTX_set_async_callback_arg(SSL_CTX *ctx, void *arg);
+ int SSL_set_async_callback(SSL *s, SSL_async_callback_fn callback);
+ int SSL_set_async_callback_arg(SSL *s, void *arg);
+ int SSL_get_async_status(SSL *s, int *status);
+
+=head1 DESCRIPTION
+
+SSL_CTX_set_async_callback() sets an asynchronous callback function. All SSL
+objects generated based on this SSL_CTX will get this callback. If an engine
+supports the callback mechanism, it will be automatically called if
+SSL_MODE_ASYNC has been set and an asynchronous capable engine completes a
+cryptography operation to notify the application to resume the paused work flow.
+
+SSL_CTX_set_async_callback_arg() sets the callback argument.
+
+SSL_set_async_callback() allows an application to set a callback in an
+asynchronous SSL object, so that when an engine completes a cryptography
+operation, the callback will be called to notify the application to resume the
+paused work flow.
+
+SSL_set_async_callback_arg() sets an argument for the SSL object when the above
+callback is called.
+
+SSL_get_async_status() returns the engine status. This function facilitates the
+communication from the engine to the application. During an SSL session,
+cryptographic operations are dispatched to an engine. The engine status is very
+useful for an application to know if the operation has been successfully
+dispatched. If the engine does not support this additional callback method,
+"ASYNC_STATUS_UNSUPPORTED" will be returned. See ASYNC_WAIT_CTX_set_status() for
+a description of all of the status values.
+
+An example of the above functions would be the following.
+1. Application sets the async callback and callback data on an SSL connection
+by calling SSL_set_async_callback().
+2. Application sets SSL_MODE_ASYNC and makes an asynchronous SSL call
+3. OpenSSL submits the asynchronous request to the engine. If a retry occurs at
+this point then the status within the ASYNC_WAIT_CTX would be set and the async
+callback function would be called (goto Step 7).
+4. The OpenSSL engine pauses the current job and returns, so that the
+application can continue processing other connections.
+5. At a future point in time (probably via a polling mechanism or via an
+interrupt) the engine will become aware that the asynchronous request has
+finished processing.
+6. The engine will call the application's callback passing the callback data as
+a parameter.
+7. The callback function should then run. Note: it is a requirement that the
+callback function is small and non-blocking as it will be run in the context of
+a polling mechanism or an interrupt.
+8. It is the application's responsibility via the callback function to schedule
+recalling the OpenSSL asynchronous function and to continue processing.
+9. The callback function has the option to check the status returned via
+SSL_get_async_status() to determine whether a retry happened instead of the
+request being submitted, allowing different processing if required.
+
+=head1 RETURN VALUES
+
+SSL_CTX_set_async_callback(), SSL_set_async_callback(),
+SSL_CTX_set_async_callback_arg(), SSL_CTX_set_async_callback_arg() and
+SSL_get_async_status() return 1 on success or 0 on error.
+
+=head1 HISTORY
+
+SSL_CTX_set_async_callback(), SSL_CTX_set_async_callback_arg(),
+SSL_set_async_callback(), SSL_set_async_callback_arg() and
+SSL_get_async_status() were first added to OpenSSL 3.0.0.
+
+=head1 COPYRIGHT
+
+Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the OpenSSL license (the "License").  You may not use
+this file except in compliance with the License.  You can obtain a copy
+in the file LICENSE in the source distribution or at
+L<https://www.openssl.org/source/license.html>.
+
+=cut
diff --git a/engines/e_dasync.c b/engines/e_dasync.c
index 2e12411..3d80610 100644
--- a/engines/e_dasync.c
+++ b/engines/e_dasync.c
@@ -403,6 +403,8 @@ static void wait_cleanup(ASYNC_WAIT_CTX *ctx, const void *key,
 static void dummy_pause_job(void) {
     ASYNC_JOB *job;
     ASYNC_WAIT_CTX *waitctx;
+    ASYNC_callback_fn callback;
+    void * callback_arg;
     OSSL_ASYNC_FD pipefds[2] = {0, 0};
     OSSL_ASYNC_FD *writefd;
 #if defined(ASYNC_WIN)
@@ -417,6 +419,18 @@ static void dummy_pause_job(void) {
 
     waitctx = ASYNC_get_wait_ctx(job);
 
+    if (ASYNC_WAIT_CTX_get_callback(waitctx, &callback, &callback_arg) && callback != NULL) {
+        /*
+         * In the Dummy async engine we are cheating. We call the callback that the job
+         * is complete before the call to ASYNC_pause_job(). A real
+         * async engine would only call the callback when the job was actually complete
+         */
+        (*callback)(callback_arg);
+        ASYNC_pause_job();
+        return;
+    }
+
+
     if (ASYNC_WAIT_CTX_get_fd(waitctx, engine_dasync_id, &pipefds[0],
                               (void **)&writefd)) {
         pipefds[1] = *writefd;
diff --git a/include/openssl/async.h b/include/openssl/async.h
index 71aef3b..910c144 100644
--- a/include/openssl/async.h
+++ b/include/openssl/async.h
@@ -31,12 +31,18 @@ extern "C" {
 
 typedef struct async_job_st ASYNC_JOB;
 typedef struct async_wait_ctx_st ASYNC_WAIT_CTX;
+typedef int (*ASYNC_callback_fn)(void *arg);
 
 #define ASYNC_ERR      0
 #define ASYNC_NO_JOBS  1
 #define ASYNC_PAUSE    2
 #define ASYNC_FINISH   3
 
+#define ASYNC_STATUS_UNSUPPORTED    0
+#define ASYNC_STATUS_ERR            1
+#define ASYNC_STATUS_OK             2
+#define ASYNC_STATUS_EAGAIN         3
+
 int ASYNC_init_thread(size_t max_size, size_t init_size);
 void ASYNC_cleanup_thread(void);
 
@@ -52,6 +58,14 @@ int ASYNC_WAIT_CTX_get_fd(ASYNC_WAIT_CTX *ctx, const void *key,
                         OSSL_ASYNC_FD *fd, void **custom_data);
 int ASYNC_WAIT_CTX_get_all_fds(ASYNC_WAIT_CTX *ctx, OSSL_ASYNC_FD *fd,
                                size_t *numfds);
+int ASYNC_WAIT_CTX_get_callback(ASYNC_WAIT_CTX *ctx,
+                                ASYNC_callback_fn *callback,
+                                void **callback_arg);
+int ASYNC_WAIT_CTX_set_callback(ASYNC_WAIT_CTX *ctx,
+                                ASYNC_callback_fn callback,
+                                void *callback_arg);
+int ASYNC_WAIT_CTX_set_status(ASYNC_WAIT_CTX *ctx, int status);
+int ASYNC_WAIT_CTX_get_status(ASYNC_WAIT_CTX *ctx);
 int ASYNC_WAIT_CTX_get_changed_fds(ASYNC_WAIT_CTX *ctx, OSSL_ASYNC_FD *addfd,
                                    size_t *numaddfds, OSSL_ASYNC_FD *delfd,
                                    size_t *numdelfds);
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index ea41dd0..c7a8304 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -293,6 +293,9 @@ typedef int (*SSL_custom_ext_parse_cb_ex)(SSL *s, unsigned int ext_type,
 /* Typedef for verification callback */
 typedef int (*SSL_verify_cb)(int preverify_ok, X509_STORE_CTX *x509_ctx);
 
+/* Typedef for SSL async callback */
+typedef int (*SSL_async_callback_fn)(SSL *s, void *arg);
+
 /*
  * Some values are reserved until OpenSSL 1.2.0 because they were previously
  * included in SSL_OP_ALL in a 1.1.x release.
@@ -1815,6 +1818,12 @@ __owur int SSL_get_all_async_fds(SSL *s, OSSL_ASYNC_FD *fds, size_t *numfds);
 __owur int SSL_get_changed_async_fds(SSL *s, OSSL_ASYNC_FD *addfd,
                                      size_t *numaddfds, OSSL_ASYNC_FD *delfd,
                                      size_t *numdelfds);
+__owur int SSL_CTX_set_async_callback(SSL_CTX *ctx, SSL_async_callback_fn callback);
+__owur int SSL_CTX_set_async_callback_arg(SSL_CTX *ctx, void *arg);
+__owur int SSL_set_async_callback(SSL *s, SSL_async_callback_fn callback);
+__owur int SSL_set_async_callback_arg(SSL *s, void *arg);
+__owur int SSL_get_async_status(SSL *s, int *status);
+
 # endif
 __owur int SSL_accept(SSL *ssl);
 __owur int SSL_stateless(SSL *s);
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index ba606e3..6d6060a 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -831,6 +831,9 @@ SSL *SSL_new(SSL_CTX *ctx)
     s->psk_find_session_cb = ctx->psk_find_session_cb;
     s->psk_use_session_cb = ctx->psk_use_session_cb;
 
+    s->async_cb = ctx->async_cb;
+    s->async_cb_arg = ctx->async_cb_arg;
+
     s->job = NULL;
 
 #ifndef OPENSSL_NO_CT
@@ -1652,6 +1655,40 @@ int SSL_get_changed_async_fds(SSL *s, OSSL_ASYNC_FD *addfd, size_t *numaddfds,
                                           numdelfds);
 }
 
+int SSL_CTX_set_async_callback(SSL_CTX *ctx, SSL_async_callback_fn callback)
+{
+    ctx->async_cb = callback;
+    return 1;
+}
+
+int SSL_CTX_set_async_callback_arg(SSL_CTX *ctx, void *arg)
+{
+    ctx->async_cb_arg = arg;
+    return 1;
+}
+
+int SSL_set_async_callback(SSL *s, SSL_async_callback_fn callback)
+{
+    s->async_cb = callback;
+    return 1;
+}
+
+int SSL_set_async_callback_arg(SSL *s, void *arg)
+{
+    s->async_cb_arg = arg;
+    return 1;
+}
+
+int SSL_get_async_status(SSL *s, int *status)
+{
+    ASYNC_WAIT_CTX *ctx = s->waitctx;
+
+    if (ctx == NULL)
+        return 0;
+    *status = ASYNC_WAIT_CTX_get_status(ctx);
+    return 1;
+}
+
 int SSL_accept(SSL *s)
 {
     if (s->handshake_func == NULL) {
@@ -1677,6 +1714,13 @@ long SSL_get_default_timeout(const SSL *s)
     return s->method->get_timeout();
 }
 
+static int ssl_async_wait_ctx_cb(void *arg)
+{
+    SSL *s = (SSL *)arg;
+
+    return s->async_cb(s, s->async_cb_arg);
+}
+
 static int ssl_start_async_job(SSL *s, struct ssl_async_args *args,
                                int (*func) (void *))
 {
@@ -1685,6 +1729,10 @@ static int ssl_start_async_job(SSL *s, struct ssl_async_args *args,
         s->waitctx = ASYNC_WAIT_CTX_new();
         if (s->waitctx == NULL)
             return -1;
+        if (s->async_cb != NULL
+            && !ASYNC_WAIT_CTX_set_callback
+                 (s->waitctx, ssl_async_wait_ctx_cb, s))
+            return -1;
     }
     switch (ASYNC_start_job(&s->job, s->waitctx, &ret, func, args,
                             sizeof(struct ssl_async_args))) {
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 2d68691..bd0d421 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -1076,6 +1076,10 @@ struct ssl_ctx_st {
 
     /* Do we advertise Post-handshake auth support? */
     int pha_enabled;
+
+    /* Callback for SSL async handling */
+    SSL_async_callback_fn async_cb;
+    void *async_cb_arg;
 };
 
 struct ssl_st {
@@ -1471,6 +1475,10 @@ struct ssl_st {
     /* Callback to determine if early_data is acceptable or not */
     SSL_allow_early_data_cb_fn allow_early_data_cb;
     void *allow_early_data_cb_data;
+
+    /* Callback for SSL async handling */
+    SSL_async_callback_fn async_cb;
+    void *async_cb_arg;
 };
 
 /*
diff --git a/test/asynctest.c b/test/asynctest.c
index 3c08974..3ce190f 100644
--- a/test/asynctest.c
+++ b/test/asynctest.c
@@ -123,6 +123,43 @@ static int test_ASYNC_init_thread(void)
     return 1;
 }
 
+static int test_callback(void *arg)
+{
+    printf("callback test pass\n");
+    return 1;
+}
+
+static int test_ASYNC_callback_status(void)
+{
+    ASYNC_WAIT_CTX *waitctx = NULL;
+    int set_arg = 100;
+    ASYNC_callback_fn get_callback;
+    void *get_arg;
+    int set_status = 1;
+
+    if (       !ASYNC_init_thread(1, 0)
+            || (waitctx = ASYNC_WAIT_CTX_new()) == NULL
+            || ASYNC_WAIT_CTX_set_callback(waitctx, test_callback, (void*)&set_arg)
+               != 1
+            || ASYNC_WAIT_CTX_get_callback(waitctx, &get_callback, &get_arg)
+               != 1
+            || test_callback != get_callback
+            || get_arg != (void*)&set_arg
+            || (*get_callback)(get_arg) != 1
+            || ASYNC_WAIT_CTX_set_status(waitctx, set_status) != 1
+            || set_status != ASYNC_WAIT_CTX_get_status(waitctx)) {
+        fprintf(stderr, "test_ASYNC_callback_status() failed\n");
+        ASYNC_WAIT_CTX_free(waitctx);
+        ASYNC_cleanup_thread();
+        return 0;
+    }
+
+    ASYNC_WAIT_CTX_free(waitctx);
+    ASYNC_cleanup_thread();
+    return 1;
+
+}
+
 static int test_ASYNC_start_job(void)
 {
     ASYNC_JOB *job = NULL;
@@ -279,6 +316,7 @@ int main(int argc, char **argv)
         CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
 
         if (       !test_ASYNC_init_thread()
+                || !test_ASYNC_callback_status()
                 || !test_ASYNC_start_job()
                 || !test_ASYNC_get_current_job()
                 || !test_ASYNC_WAIT_CTX_get_all_fds()
diff --git a/util/libcrypto.num b/util/libcrypto.num
index b8b1980..e7d2ed7 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -4622,3 +4622,7 @@ CRYPTO_siv128_cleanup                   4577	3_0_0	EXIST::FUNCTION:SIV
 CRYPTO_siv128_speed                     4578	3_0_0	EXIST::FUNCTION:SIV
 OPENSSL_INIT_set_config_filename        4579	3_0_0	EXIST::FUNCTION:STDIO
 OPENSSL_INIT_set_config_file_flags      4580	3_0_0	EXIST::FUNCTION:STDIO
+ASYNC_WAIT_CTX_get_callback             4581	3_0_0	EXIST::FUNCTION:
+ASYNC_WAIT_CTX_set_callback             4582	3_0_0	EXIST::FUNCTION:
+ASYNC_WAIT_CTX_set_status               4583	3_0_0	EXIST::FUNCTION:
+ASYNC_WAIT_CTX_get_status               4584	3_0_0	EXIST::FUNCTION:
diff --git a/util/libssl.num b/util/libssl.num
index 6bc6688..d59ccf9 100644
--- a/util/libssl.num
+++ b/util/libssl.num
@@ -498,3 +498,8 @@ SSL_CTX_get_recv_max_early_data         498	3_0_0	EXIST::FUNCTION:
 SSL_CTX_set_recv_max_early_data         499	3_0_0	EXIST::FUNCTION:
 SSL_CTX_set_post_handshake_auth         500	3_0_0	EXIST::FUNCTION:
 SSL_get_signature_type_nid              501	3_0_0	EXIST::FUNCTION:
+SSL_CTX_set_async_callback              502	3_0_0	EXIST::FUNCTION:
+SSL_CTX_set_async_callback_arg          503	3_0_0	EXIST::FUNCTION:
+SSL_set_async_callback                  504	3_0_0	EXIST::FUNCTION:
+SSL_set_async_callback_arg              505	3_0_0	EXIST::FUNCTION:
+SSL_get_async_status                    506	3_0_0	EXIST::FUNCTION:
diff --git a/util/private.num b/util/private.num
index 09ab417..7a7c73f 100644
--- a/util/private.num
+++ b/util/private.num
@@ -90,6 +90,8 @@ custom_ext_free_cb                      datatype
 custom_ext_parse_cb                     datatype
 pem_password_cb                         datatype
 ssl_ct_validation_cb                    datatype
+ASYNC_callback_fn                       datatype
+SSL_async_callback_fn                   datatype
 #
 BIO_append_filename                     define
 BIO_destroy_bio_pair                    define
@@ -475,3 +477,7 @@ X509_STORE_set_verify_func              define
 EVP_PKEY_CTX_set1_id                    define
 EVP_PKEY_CTX_get1_id                    define
 EVP_PKEY_CTX_get1_id_len                define
+ASYNC_STATUS_EAGAIN                     define
+ASYNC_STATUS_OK                         define
+ASYNC_STATUS_ERR                        define
+ASYNC_STATUS_UNSUPPORTED                define


More information about the openssl-commits mailing list