Merge remote-tracking branch 'public/pr/1602' into development
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3538b80..0ade1d4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -117,8 +117,8 @@
     set(CMAKE_C_FLAGS_RELEASE     "-O2")
     set(CMAKE_C_FLAGS_DEBUG       "-O0 -g3")
     set(CMAKE_C_FLAGS_COVERAGE    "-O0 -g3 --coverage")
-    set(CMAKE_C_FLAGS_ASAN        "-Werror -fsanitize=address -fno-common -fsanitize=undefined -fno-sanitize-recover -O3")
-    set(CMAKE_C_FLAGS_ASANDBG     "-Werror -fsanitize=address -fno-common -fsanitize=undefined -fno-sanitize-recover -O1 -g3 -fno-omit-frame-pointer -fno-optimize-sibling-calls ")
+    set(CMAKE_C_FLAGS_ASAN        "-Werror -fsanitize=address -fno-common -fsanitize=undefined -fno-sanitize-recover=all -O3")
+    set(CMAKE_C_FLAGS_ASANDBG     "-Werror -fsanitize=address -fno-common -fsanitize=undefined -fno-sanitize-recover=all -O1 -g3 -fno-omit-frame-pointer -fno-optimize-sibling-calls ")
     set(CMAKE_C_FLAGS_MEMSAN      "-Werror -fsanitize=memory -O3")
     set(CMAKE_C_FLAGS_MEMSANDBG   "-Werror -fsanitize=memory -O1 -g3 -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize-memory-track-origins=2")
     set(CMAKE_C_FLAGS_CHECK       "-Werror -Os")
diff --git a/ChangeLog b/ChangeLog
index a8a255c..ddd5673 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -10,10 +10,15 @@
    * Add support for the CCM* block cipher mode as defined in IEEE Std. 802.15.4.
    * Add support for the XTS block cipher mode with AES (AES-XTS).
      Contributed by Aorimn in pull request #414.
+   * In TLS servers, support offloading private key operations to an external
+     cryptoprocessor. Private key operations can be asynchronous to allow
+     non-blocking operation of the TLS server stack.
 
 Bugfix
    * Fix the cert_write example to handle certificates signed with elliptic
      curves as well as RSA. Fixes #777 found by dbedev.
+   * Fix for redefinition of _WIN32_WINNT to avoid overriding a definition
+     used by user applications. Found and fixed by Fabio Alessandrelli.
 
 Changes
    * Changed CMake defaults for IAR to treat all compiler warnings as errors.
@@ -38,6 +43,7 @@
 Bugfix
    * Fix an issue with MicroBlaze support in bn_mul.h which was causing the
      build to fail. Found by zv-io. Fixes #1651.
+   * Fix braces in mbedtls_memory_buffer_alloc_status(). Found by sbranden, #552.
 
 Changes
    * Support TLS testing in out-of-source builds using cmake. Fixes #1193.
diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h
index be83e7f..307b90b 100644
--- a/include/mbedtls/config.h
+++ b/include/mbedtls/config.h
@@ -1149,6 +1149,17 @@
 #define MBEDTLS_SSL_ALL_ALERT_MESSAGES
 
 /**
+ * \def MBEDTLS_SSL_ASYNC_PRIVATE
+ *
+ * Enable asynchronous external private key operations in SSL. This allows
+ * you to configure an SSL connection to call an external cryptographic
+ * module to perform private key operations instead of performing the
+ * operation inside the library.
+ *
+ */
+#define MBEDTLS_SSL_ASYNC_PRIVATE
+
+/**
  * \def MBEDTLS_SSL_DEBUG_ALL
  *
  * Enable the debug messages in SSL module for all issues.
diff --git a/include/mbedtls/error.h b/include/mbedtls/error.h
index 2bde87a..13397a8 100644
--- a/include/mbedtls/error.h
+++ b/include/mbedtls/error.h
@@ -91,7 +91,7 @@
  * MD        5   5
  * HKDF      5   1 (Started from top)
  * CIPHER    6   8
- * SSL       6   17 (Started from top)
+ * SSL       6   22 (Started from top)
  * SSL       7   31
  *
  * Module dependent error code (5 bits 0x.00.-0x.F8.)
diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index 250031a..4513550 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -120,6 +120,7 @@
 #define MBEDTLS_ERR_SSL_NON_FATAL                         -0x6680  /**< The alert message received indicates a non-fatal error. */
 #define MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH               -0x6600  /**< Couldn't set the hash for verifying CertificateVerify */
 #define MBEDTLS_ERR_SSL_CONTINUE_PROCESSING               -0x6580  /**< Internal-only message signaling that further message-processing should be done */
+#define MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS                 -0x6500  /**< The asynchronous operation is not completed yet. */
 
 /*
  * Various constants
@@ -536,7 +537,6 @@
  */
 typedef int mbedtls_ssl_get_timer_t( void * ctx );
 
-
 /* Defined below */
 typedef struct mbedtls_ssl_session mbedtls_ssl_session;
 typedef struct mbedtls_ssl_context mbedtls_ssl_context;
@@ -553,6 +553,218 @@
 typedef struct mbedtls_ssl_flight_item mbedtls_ssl_flight_item;
 #endif
 
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+/**
+ * \brief           Callback type: start external signature operation.
+ *
+ *                  This callback is called during an SSL handshake to start
+ *                  a signature decryption operation using an
+ *                  external processor. The parameter \p cert contains
+ *                  the public key; it is up to the callback function to
+ *                  determine how to access the associated private key.
+ *
+ *                  This function typically sends or enqueues a request, and
+ *                  does not wait for the operation to complete. This allows
+ *                  the handshake step to be non-blocking.
+ *
+ *                  The parameters \p ssl and \p cert are guaranteed to remain
+ *                  valid throughout the handshake. On the other hand, this
+ *                  function must save the contents of \p hash if the value
+ *                  is needed for later processing, because the \p hash buffer
+ *                  is no longer valid after this function returns.
+ *
+ *                  This function may call mbedtls_ssl_set_async_operation_data()
+ *                  to store an operation context for later retrieval
+ *                  by the resume or cancel callback.
+ *
+ * \note            For RSA signatures, this function must produce output
+ *                  that is consistent with PKCS#1 v1.5 in the same way as
+ *                  mbedtls_rsa_pkcs1_sign(). Before the private key operation,
+ *                  apply the padding steps described in RFC 8017, section 9.2
+ *                  "EMSA-PKCS1-v1_5" as follows.
+ *                  - If \p md_alg is #MBEDTLS_MD_NONE, apply the PKCS#1 v1.5
+ *                    encoding, treating \p hash as the DigestInfo to be
+ *                    padded. In other words, apply EMSA-PKCS1-v1_5 starting
+ *                    from step 3, with `T = hash` and `tLen = hash_len`.
+ *                  - If `md_alg != MBEDTLS_MD_NONE`, apply the PKCS#1 v1.5
+ *                    encoding, treating \p hash as the hash to be encoded and
+ *                    padded. In other words, apply EMSA-PKCS1-v1_5 starting
+ *                    from step 2, with `digestAlgorithm` obtained by calling
+ *                    mbedtls_oid_get_oid_by_md() on \p md_alg.
+ *
+ * \note            For ECDSA signatures, the output format is the DER encoding
+ *                  `Ecdsa-Sig-Value` defined in
+ *                  [RFC 4492 section 5.4](https://tools.ietf.org/html/rfc4492#section-5.4).
+ *
+ * \param ssl             The SSL connection instance. It should not be
+ *                        modified other than via
+ *                        mbedtls_ssl_set_async_operation_data().
+ * \param cert            Certificate containing the public key.
+ *                        In simple cases, this is one of the pointers passed to
+ *                        mbedtls_ssl_conf_own_cert() when configuring the SSL
+ *                        connection. However, if other callbacks are used, this
+ *                        property may not hold. For example, if an SNI callback
+ *                        is registered with mbedtls_ssl_conf_sni(), then
+ *                        this callback determines what certificate is used.
+ * \param md_alg          Hash algorithm.
+ * \param hash            Buffer containing the hash. This buffer is
+ *                        no longer valid when the function returns.
+ * \param hash_len        Size of the \c hash buffer in bytes.
+ *
+ * \return          0 if the operation was started successfully and the SSL
+ *                  stack should call the resume callback immediately.
+ * \return          #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS if the operation
+ *                  was started successfully and the SSL stack should return
+ *                  immediately without calling the resume callback yet.
+ * \return          #MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH if the external
+ *                  processor does not support this key. The SSL stack will
+ *                  use the private key object instead.
+ * \return          Any other error indicates a fatal failure and is
+ *                  propagated up the call chain. The callback should
+ *                  use \c MBEDTLS_ERR_PK_xxx error codes, and <b>must not</b>
+ *                  use \c MBEDTLS_ERR_SSL_xxx error codes except as
+ *                  directed in the documentation of this callback.
+ */
+typedef int mbedtls_ssl_async_sign_t( mbedtls_ssl_context *ssl,
+                                      mbedtls_x509_crt *cert,
+                                      mbedtls_md_type_t md_alg,
+                                      const unsigned char *hash,
+                                      size_t hash_len );
+
+/**
+ * \brief           Callback type: start external decryption operation.
+ *
+ *                  This callback is called during an SSL handshake to start
+ *                  an RSA decryption operation using an
+ *                  external processor. The parameter \p cert contains
+ *                  the public key; it is up to the callback function to
+ *                  determine how to access the associated private key.
+ *
+ *                  This function typically sends or enqueues a request, and
+ *                  does not wait for the operation to complete. This allows
+ *                  the handshake step to be non-blocking.
+ *
+ *                  The parameters \p ssl and \p cert are guaranteed to remain
+ *                  valid throughout the handshake. On the other hand, this
+ *                  function must save the contents of \p input if the value
+ *                  is needed for later processing, because the \p input buffer
+ *                  is no longer valid after this function returns.
+ *
+ *                  This function may call mbedtls_ssl_set_async_operation_data()
+ *                  to store an operation context for later retrieval
+ *                  by the resume or cancel callback.
+ *
+ * \warning         RSA decryption as used in TLS is subject to a potential
+ *                  timing side channel attack first discovered by Bleichenbacher
+ *                  in 1998. This attack can be remotely exploitable
+ *                  in practice. To avoid this attack, you must ensure that
+ *                  if the callback performs an RSA decryption, the time it
+ *                  takes to execute and return the result does not depend
+ *                  on whether the RSA decryption succeeded or reported
+ *                  invalid padding.
+ *
+ * \param ssl             The SSL connection instance. It should not be
+ *                        modified other than via
+ *                        mbedtls_ssl_set_async_operation_data().
+ * \param cert            Certificate containing the public key.
+ *                        In simple cases, this is one of the pointers passed to
+ *                        mbedtls_ssl_conf_own_cert() when configuring the SSL
+ *                        connection. However, if other callbacks are used, this
+ *                        property may not hold. For example, if an SNI callback
+ *                        is registered with mbedtls_ssl_conf_sni(), then
+ *                        this callback determines what certificate is used.
+ * \param input           Buffer containing the input ciphertext. This buffer
+ *                        is no longer valid when the function returns.
+ * \param input_len       Size of the \p input buffer in bytes.
+ *
+ * \return          0 if the operation was started successfully and the SSL
+ *                  stack should call the resume callback immediately.
+ * \return          #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS if the operation
+ *                  was started successfully and the SSL stack should return
+ *                  immediately without calling the resume callback yet.
+ * \return          #MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH if the external
+ *                  processor does not support this key. The SSL stack will
+ *                  use the private key object instead.
+ * \return          Any other error indicates a fatal failure and is
+ *                  propagated up the call chain. The callback should
+ *                  use \c MBEDTLS_ERR_PK_xxx error codes, and <b>must not</b>
+ *                  use \c MBEDTLS_ERR_SSL_xxx error codes except as
+ *                  directed in the documentation of this callback.
+ */
+typedef int mbedtls_ssl_async_decrypt_t( mbedtls_ssl_context *ssl,
+                                         mbedtls_x509_crt *cert,
+                                         const unsigned char *input,
+                                         size_t input_len );
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
+
+/**
+ * \brief           Callback type: resume external operation.
+ *
+ *                  This callback is called during an SSL handshake to resume
+ *                  an external operation started by the
+ *                  ::mbedtls_ssl_async_sign_t or
+ *                  ::mbedtls_ssl_async_decrypt_t callback.
+ *
+ *                  This function typically checks the status of a pending
+ *                  request or causes the request queue to make progress, and
+ *                  does not wait for the operation to complete. This allows
+ *                  the handshake step to be non-blocking.
+ *
+ *                  This function may call mbedtls_ssl_get_async_operation_data()
+ *                  to retrieve an operation context set by the start callback.
+ *                  It may call mbedtls_ssl_set_async_operation_data() to modify
+ *                  this context.
+ *
+ *                  Note that when this function returns a status other than
+ *                  #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS, it must free any
+ *                  resources associated with the operation.
+ *
+ * \param ssl             The SSL connection instance. It should not be
+ *                        modified other than via
+ *                        mbedtls_ssl_set_async_operation_data().
+ * \param output          Buffer containing the output (signature or decrypted
+ *                        data) on success.
+ * \param output_len      On success, number of bytes written to \p output.
+ * \param output_size     Size of the \p output buffer in bytes.
+ *
+ * \return          0 if output of the operation is available in the
+ *                  \p output buffer.
+ * \return          #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS if the operation
+ *                  is still in progress. Subsequent requests for progress
+ *                  on the SSL connection will call the resume callback
+ *                  again.
+ * \return          Any other error means that the operation is aborted.
+ *                  The SSL handshake is aborted. The callback should
+ *                  use \c MBEDTLS_ERR_PK_xxx error codes, and <b>must not</b>
+ *                  use \c MBEDTLS_ERR_SSL_xxx error codes except as
+ *                  directed in the documentation of this callback.
+ */
+typedef int mbedtls_ssl_async_resume_t( mbedtls_ssl_context *ssl,
+                                        unsigned char *output,
+                                        size_t *output_len,
+                                        size_t output_size );
+
+/**
+ * \brief           Callback type: cancel external operation.
+ *
+ *                  This callback is called if an SSL connection is closed
+ *                  while an asynchronous operation is in progress. Note that
+ *                  this callback is not called if the
+ *                  ::mbedtls_ssl_async_resume_t callback has run and has
+ *                  returned a value other than
+ *                  #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS, since in that case
+ *                  the asynchronous operation has already completed.
+ *
+ *                  This function may call mbedtls_ssl_get_async_operation_data()
+ *                  to retrieve an operation context set by the start callback.
+ *
+ * \param ssl             The SSL connection instance. It should not be
+ *                        modified.
+ */
+typedef void mbedtls_ssl_async_cancel_t( mbedtls_ssl_context *ssl );
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+
 /*
  * This structure is used for storing current session data.
  */
@@ -669,6 +881,16 @@
     mbedtls_x509_crl *ca_crl;       /*!< trusted CAs CRLs                   */
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+    mbedtls_ssl_async_sign_t *f_async_sign_start; /*!< start asynchronous signature operation */
+    mbedtls_ssl_async_decrypt_t *f_async_decrypt_start; /*!< start asynchronous decryption operation */
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
+    mbedtls_ssl_async_resume_t *f_async_resume; /*!< resume asynchronous operation */
+    mbedtls_ssl_async_cancel_t *f_async_cancel; /*!< cancel asynchronous operation */
+    void *p_async_config_data; /*!< Configuration data set by mbedtls_ssl_conf_async_private_cb(). */
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+
 #if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED)
     const int *sig_hashes;          /*!< allowed signature hashes           */
 #endif
@@ -1307,6 +1529,85 @@
         void *p_export_keys );
 #endif /* MBEDTLS_SSL_EXPORT_KEYS */
 
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+/**
+ * \brief           Configure asynchronous private key operation callbacks.
+ *
+ * \param conf              SSL configuration context
+ * \param f_async_sign      Callback to start a signature operation. See
+ *                          the description of ::mbedtls_ssl_async_sign_t
+ *                          for more information. This may be \c NULL if the
+ *                          external processor does not support any signature
+ *                          operation; in this case the private key object
+ *                          associated with the certificate will be used.
+ * \param f_async_decrypt   Callback to start a decryption operation. See
+ *                          the description of ::mbedtls_ssl_async_decrypt_t
+ *                          for more information. This may be \c NULL if the
+ *                          external processor does not support any decryption
+ *                          operation; in this case the private key object
+ *                          associated with the certificate will be used.
+ * \param f_async_resume    Callback to resume an asynchronous operation. See
+ *                          the description of ::mbedtls_ssl_async_resume_t
+ *                          for more information. This may not be \c NULL unless
+ *                          \p f_async_sign and \p f_async_decrypt are both
+ *                          \c NULL.
+ * \param f_async_cancel    Callback to cancel an asynchronous operation. See
+ *                          the description of ::mbedtls_ssl_async_cancel_t
+ *                          for more information. This may be \c NULL if
+ *                          no cleanup is needed.
+ * \param config_data       A pointer to configuration data which can be
+ *                          retrieved with
+ *                          mbedtls_ssl_conf_get_async_config_data(). The
+ *                          library stores this value without dereferencing it.
+ */
+void mbedtls_ssl_conf_async_private_cb( mbedtls_ssl_config *conf,
+                                        mbedtls_ssl_async_sign_t *f_async_sign,
+                                        mbedtls_ssl_async_decrypt_t *f_async_decrypt,
+                                        mbedtls_ssl_async_resume_t *f_async_resume,
+                                        mbedtls_ssl_async_cancel_t *f_async_cancel,
+                                        void *config_data );
+
+/**
+ * \brief           Retrieve the configuration data set by
+ *                  mbedtls_ssl_conf_async_private_cb().
+ *
+ * \param conf      SSL configuration context
+ * \return          The configuration data set by
+ *                  mbedtls_ssl_conf_async_private_cb().
+ */
+void *mbedtls_ssl_conf_get_async_config_data( const mbedtls_ssl_config *conf );
+
+/**
+ * \brief           Retrieve the asynchronous operation user context.
+ *
+ * \note            This function may only be called while a handshake
+ *                  is in progress.
+ *
+ * \param ssl       The SSL context to access.
+ *
+ * \return          The asynchronous operation user context that was last
+ *                  set during the current handshake. If
+ *                  mbedtls_ssl_set_async_operation_data() has not yet been
+ *                  called during the current handshake, this function returns
+ *                  \c NULL.
+ */
+void *mbedtls_ssl_get_async_operation_data( const mbedtls_ssl_context *ssl );
+
+/**
+ * \brief           Retrieve the asynchronous operation user context.
+ *
+ * \note            This function may only be called while a handshake
+ *                  is in progress.
+ *
+ * \param ssl       The SSL context to access.
+ * \param ctx       The new value of the asynchronous operation user context.
+ *                  Call mbedtls_ssl_get_async_operation_data() later during the
+ *                  same handshake to retrieve this value.
+ */
+void mbedtls_ssl_set_async_operation_data( mbedtls_ssl_context *ssl,
+                                 void *ctx );
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+
 /**
  * \brief          Callback type: generate a cookie
  *
diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h
index 2b5a616..f48fe90 100644
--- a/include/mbedtls/ssl_internal.h
+++ b/include/mbedtls/ssl_internal.h
@@ -243,6 +243,7 @@
     mbedtls_x509_crl *sni_ca_crl;       /*!< trusted CAs CRLs from SNI      */
 #endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
+
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
     unsigned int out_msg_seq;           /*!<  Outgoing handshake sequence number */
     unsigned int in_msg_seq;            /*!<  Incoming handshake sequence number */
@@ -307,6 +308,19 @@
 #if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET)
     int extended_ms;                    /*!< use Extended Master Secret? */
 #endif
+
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+    unsigned int async_in_progress : 1; /*!< an asynchronous operation is in progress */
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+    /** Asynchronous operation context. This field is meant for use by the
+     * asynchronous operation callbacks (mbedtls_ssl_config::f_async_sign_start,
+     * mbedtls_ssl_config::f_async_decrypt_start,
+     * mbedtls_ssl_config::f_async_resume, mbedtls_ssl_config::f_async_cancel).
+     * The library does not use it internally. */
+    void *user_async_ctx;
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
 };
 
 /*
@@ -410,9 +424,9 @@
  * \brief           Free referenced items in an SSL handshake context and clear
  *                  memory
  *
- * \param handshake SSL handshake context
+ * \param ssl       SSL context
  */
-void mbedtls_ssl_handshake_free( mbedtls_ssl_handshake_params *handshake );
+void mbedtls_ssl_handshake_free( mbedtls_ssl_context *ssl );
 
 int mbedtls_ssl_handshake_client_step( mbedtls_ssl_context *ssl );
 int mbedtls_ssl_handshake_server_step( mbedtls_ssl_context *ssl );
@@ -652,9 +666,9 @@
 #if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \
     defined(MBEDTLS_SSL_PROTO_TLS1_2)
 int mbedtls_ssl_get_key_exchange_md_tls1_2( mbedtls_ssl_context *ssl,
-                                        unsigned char *output,
-                                        unsigned char *data, size_t data_len,
-                                        mbedtls_md_type_t md_alg );
+                                            unsigned char *hash, size_t *hashlen,
+                                            unsigned char *data, size_t data_len,
+                                            mbedtls_md_type_t md_alg );
 #endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \
           MBEDTLS_SSL_PROTO_TLS1_2 */
 
diff --git a/library/aes.c b/library/aes.c
index 5cd96ec..5a6b803 100644
--- a/library/aes.c
+++ b/library/aes.c
@@ -1710,7 +1710,8 @@
 #if defined(MBEDTLS_CIPHER_MODE_CBC)
     unsigned char prv[16];
 #endif
-#if defined(MBEDTLS_CIPHER_MODE_CTR) || defined(MBEDTLS_CIPHER_MODE_CFB)
+#if defined(MBEDTLS_CIPHER_MODE_CTR) || defined(MBEDTLS_CIPHER_MODE_CFB) || \
+    defined(MBEDTLS_CIPHER_MODE_OFB)
     size_t offset;
 #endif
 #if defined(MBEDTLS_CIPHER_MODE_CTR)
diff --git a/library/entropy_poll.c b/library/entropy_poll.c
index 67900c4..fd96258 100644
--- a/library/entropy_poll.c
+++ b/library/entropy_poll.c
@@ -25,13 +25,14 @@
 #include MBEDTLS_CONFIG_FILE
 #endif
 
+#include <string.h>
+
 #if defined(MBEDTLS_ENTROPY_C)
 
 #include "mbedtls/entropy.h"
 #include "mbedtls/entropy_poll.h"
 
 #if defined(MBEDTLS_TIMING_C)
-#include <string.h>
 #include "mbedtls/timing.h"
 #endif
 #if defined(MBEDTLS_HAVEGE_C)
diff --git a/library/error.c b/library/error.c
index 5b57c7c..2a85d27 100644
--- a/library/error.c
+++ b/library/error.c
@@ -501,6 +501,8 @@
             mbedtls_snprintf( buf, buflen, "SSL - Couldn't set the hash for verifying CertificateVerify" );
         if( use_ret == -(MBEDTLS_ERR_SSL_CONTINUE_PROCESSING) )
             mbedtls_snprintf( buf, buflen, "SSL - Internal-only message signaling that further message-processing should be done" );
+        if( use_ret == -(MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS) )
+            mbedtls_snprintf( buf, buflen, "SSL - The asynchronous operation is not completed yet" );
 #endif /* MBEDTLS_SSL_TLS_C */
 
 #if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C)
diff --git a/library/memory_buffer_alloc.c b/library/memory_buffer_alloc.c
index ceaeda1..51ea7c4 100644
--- a/library/memory_buffer_alloc.c
+++ b/library/memory_buffer_alloc.c
@@ -518,7 +518,9 @@
                       heap.alloc_count, heap.free_count );
 
     if( heap.first->next == NULL )
+    {
         mbedtls_fprintf( stderr, "All memory de-allocated in stack buffer\n" );
+    }
     else
     {
         mbedtls_fprintf( stderr, "Memory currently allocated:\n" );
diff --git a/library/net_sockets.c b/library/net_sockets.c
index 7b4a423..202da01 100644
--- a/library/net_sockets.c
+++ b/library/net_sockets.c
@@ -47,11 +47,12 @@
 
 #define IS_EINTR( ret ) ( ( ret ) == WSAEINTR )
 
-#ifdef _WIN32_WINNT
+#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0501)
 #undef _WIN32_WINNT
-#endif
 /* Enables getaddrinfo() & Co */
 #define _WIN32_WINNT 0x0501
+#endif
+
 #include <ws2tcpip.h>
 
 #include <winsock2.h>
diff --git a/library/ssl_cli.c b/library/ssl_cli.c
index 7455e99..e537f9d 100644
--- a/library/ssl_cli.c
+++ b/library/ssl_cli.c
@@ -2544,10 +2544,9 @@
     defined(MBEDTLS_SSL_PROTO_TLS1_2)
         if( md_alg != MBEDTLS_MD_NONE )
         {
-            /* Info from md_alg will be used instead */
-            hashlen = 0;
-            ret = mbedtls_ssl_get_key_exchange_md_tls1_2( ssl, hash, params,
-                                                          params_len, md_alg );
+            ret = mbedtls_ssl_get_key_exchange_md_tls1_2( ssl, hash, &hashlen,
+                                                          params, params_len,
+                                                          md_alg );
             if( ret != 0 )
                 return( ret );
         }
@@ -2559,8 +2558,7 @@
             return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
         }
 
-        MBEDTLS_SSL_DEBUG_BUF( 3, "parameters hash", hash, hashlen != 0 ? hashlen :
-            (unsigned int) ( mbedtls_md_get_size( mbedtls_md_info_from_type( md_alg ) ) ) );
+        MBEDTLS_SSL_DEBUG_BUF( 3, "parameters hash", hash, hashlen );
 
         if( ssl->session_negotiate->peer_cert == NULL )
         {
diff --git a/library/ssl_srv.c b/library/ssl_srv.c
index 09b7a3f..eb19f58 100644
--- a/library/ssl_srv.c
+++ b/library/ssl_srv.c
@@ -709,7 +709,7 @@
         MBEDTLS_SSL_DEBUG_CRT( 3, "candidate certificate chain, certificate",
                           cur->cert );
 
-        if( ! mbedtls_pk_can_do( cur->key, pk_alg ) )
+        if( ! mbedtls_pk_can_do( &cur->cert->pk, pk_alg ) )
         {
             MBEDTLS_SSL_DEBUG_MSG( 3, ( "certificate mismatch: key type" ) );
             continue;
@@ -733,7 +733,7 @@
 
 #if defined(MBEDTLS_ECDSA_C)
         if( pk_alg == MBEDTLS_PK_ECDSA &&
-            ssl_check_key_curve( cur->key, ssl->handshake->curves ) != 0 )
+            ssl_check_key_curve( &cur->cert->pk, ssl->handshake->curves ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_MSG( 3, ( "certificate mismatch: elliptic curve" ) );
             continue;
@@ -2828,54 +2828,56 @@
 #endif /* MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) ||
           MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */
 
-static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl )
+#if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) && \
+    defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+static int ssl_resume_server_key_exchange( mbedtls_ssl_context *ssl,
+                                           size_t *signature_len )
 {
-    int ret;
-    size_t n = 0;
+    /* Append the signature to ssl->out_msg, leaving 2 bytes for the
+     * signature length which will be added in ssl_write_server_key_exchange
+     * after the call to ssl_prepare_server_key_exchange.
+     * ssl_write_server_key_exchange also takes care of incrementing
+     * ssl->out_msglen. */
+    unsigned char *sig_start = ssl->out_msg + ssl->out_msglen + 2;
+    size_t sig_max_len = ( ssl->out_buf + MBEDTLS_SSL_MAX_CONTENT_LEN
+                           - sig_start );
+    int ret = ssl->conf->f_async_resume( ssl,
+                                         sig_start, signature_len, sig_max_len );
+    if( ret != MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS )
+    {
+        ssl->handshake->async_in_progress = 0;
+        mbedtls_ssl_set_async_operation_data( ssl, NULL );
+    }
+    MBEDTLS_SSL_DEBUG_RET( 2, "ssl_resume_server_key_exchange", ret );
+    return( ret );
+}
+#endif /* defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) &&
+          defined(MBEDTLS_SSL_ASYNC_PRIVATE) */
+
+/* Prepare the ServerKeyExchange message, up to and including
+ * calculating the signature if any, but excluding formatting the
+ * signature and sending the message. */
+static int ssl_prepare_server_key_exchange( mbedtls_ssl_context *ssl,
+                                            size_t *signature_len )
+{
     const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
                             ssl->transform_negotiate->ciphersuite_info;
-
 #if defined(MBEDTLS_KEY_EXCHANGE__SOME_PFS__ENABLED)
-    unsigned char *p = ssl->out_msg + 4;
-    size_t len;
 #if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED)
-    unsigned char *dig_signed = p;
-    size_t dig_signed_len = 0;
+    unsigned char *dig_signed = NULL;
 #endif /* MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED */
 #endif /* MBEDTLS_KEY_EXCHANGE__SOME_PFS__ENABLED */
 
-    MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write server key exchange" ) );
+    (void) ciphersuite_info; /* unused in some configurations */
+#if !defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED)
+    (void) signature_len;
+#endif /* MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED */
+
+    ssl->out_msglen = 4; /* header (type:1, length:3) to be written later */
 
     /*
      *
-     * Part 1: Extract static ECDH parameters and abort
-     *         if ServerKeyExchange not needed.
-     *
-     */
-
-    /* For suites involving ECDH, extract DH parameters
-     * from certificate at this point. */
-#if defined(MBEDTLS_KEY_EXCHANGE__SOME__ECDH_ENABLED)
-    if( mbedtls_ssl_ciphersuite_uses_ecdh( ciphersuite_info ) )
-    {
-        ssl_get_ecdh_params_from_cert( ssl );
-    }
-#endif /* MBEDTLS_KEY_EXCHANGE__SOME__ECDH_ENABLED */
-
-    /* Key exchanges not involving ephemeral keys don't use
-     * ServerKeyExchange, so end here. */
-#if defined(MBEDTLS_KEY_EXCHANGE__SOME_NON_PFS__ENABLED)
-    if( mbedtls_ssl_ciphersuite_no_pfs( ciphersuite_info ) )
-    {
-        MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write server key exchange" ) );
-        ssl->state++;
-        return( 0 );
-    }
-#endif /* MBEDTLS_KEY_EXCHANGE__NON_PFS__ENABLED */
-
-    /*
-     *
-     * Part 2: Provide key exchange parameters for chosen ciphersuite.
+     * Part 1: Provide key exchange parameters for chosen ciphersuite.
      *
      */
 
@@ -2885,18 +2887,21 @@
 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
     if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE )
     {
-        const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN;
+        int ret;
+        size_t len;
 
-        ret = mbedtls_ecjpake_write_round_two( &ssl->handshake->ecjpake_ctx,
-                p, end - p, &len, ssl->conf->f_rng, ssl->conf->p_rng );
+        ret = mbedtls_ecjpake_write_round_two(
+            &ssl->handshake->ecjpake_ctx,
+            ssl->out_msg + ssl->out_msglen,
+            MBEDTLS_SSL_MAX_CONTENT_LEN - ssl->out_msglen, &len,
+            ssl->conf->f_rng, ssl->conf->p_rng );
         if( ret != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_write_round_two", ret );
             return( ret );
         }
 
-        p += len;
-        n += len;
+        ssl->out_msglen += len;
     }
 #endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
 
@@ -2910,10 +2915,8 @@
     if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ||
         ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK )
     {
-        *(p++) = 0x00;
-        *(p++) = 0x00;
-
-        n += 2;
+        ssl->out_msg[ssl->out_msglen++] = 0x00;
+        ssl->out_msg[ssl->out_msglen++] = 0x00;
     }
 #endif /* MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED ||
           MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */
@@ -2924,6 +2927,9 @@
 #if defined(MBEDTLS_KEY_EXCHANGE__SOME__DHE_ENABLED)
     if( mbedtls_ssl_ciphersuite_uses_dhe( ciphersuite_info ) )
     {
+        int ret;
+        size_t len;
+
         if( ssl->conf->dhm_P.p == NULL || ssl->conf->dhm_G.p == NULL )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "no DH parameters set" ) );
@@ -2947,21 +2953,21 @@
             return( ret );
         }
 
-        if( ( ret = mbedtls_dhm_make_params( &ssl->handshake->dhm_ctx,
-                        (int) mbedtls_mpi_size( &ssl->handshake->dhm_ctx.P ),
-                        p, &len, ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 )
+        if( ( ret = mbedtls_dhm_make_params(
+                  &ssl->handshake->dhm_ctx,
+                  (int) mbedtls_mpi_size( &ssl->handshake->dhm_ctx.P ),
+                  ssl->out_msg + ssl->out_msglen, &len,
+                  ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_dhm_make_params", ret );
             return( ret );
         }
 
 #if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED)
-        dig_signed = p;
-        dig_signed_len = len;
+        dig_signed = ssl->out_msg + ssl->out_msglen;
 #endif
 
-        p += len;
-        n += len;
+        ssl->out_msglen += len;
 
         MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: X ", &ssl->handshake->dhm_ctx.X  );
         MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: P ", &ssl->handshake->dhm_ctx.P  );
@@ -2986,6 +2992,8 @@
          */
         const mbedtls_ecp_curve_info **curve = NULL;
         const mbedtls_ecp_group_id *gid;
+        int ret;
+        size_t len;
 
         /* Match our preference list against the offered curves */
         for( gid = ssl->conf->curve_list; *gid != MBEDTLS_ECP_DP_NONE; gid++ )
@@ -3009,21 +3017,21 @@
             return( ret );
         }
 
-        if( ( ret = mbedtls_ecdh_make_params( &ssl->handshake->ecdh_ctx, &len,
-                                      p, MBEDTLS_SSL_MAX_CONTENT_LEN - n,
-                                      ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 )
+        if( ( ret = mbedtls_ecdh_make_params(
+                  &ssl->handshake->ecdh_ctx, &len,
+                  ssl->out_msg + ssl->out_msglen,
+                  MBEDTLS_SSL_MAX_CONTENT_LEN - ssl->out_msglen,
+                  ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_make_params", ret );
             return( ret );
         }
 
 #if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED)
-        dig_signed     = p;
-        dig_signed_len = len;
+        dig_signed = ssl->out_msg + ssl->out_msglen;
 #endif
 
-        p += len;
-        n += len;
+        ssl->out_msglen += len;
 
         MBEDTLS_SSL_DEBUG_ECP( 3, "ECDH: Q ", &ssl->handshake->ecdh_ctx.Q );
     }
@@ -3031,19 +3039,20 @@
 
     /*
      *
-     * Part 3: For key exchanges involving the server signing the
+     * Part 2: For key exchanges involving the server signing the
      *         exchange parameters, compute and add the signature here.
      *
      */
 #if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED)
     if( mbedtls_ssl_ciphersuite_uses_server_signature( ciphersuite_info ) )
     {
-        size_t signature_len = 0;
-        unsigned int hashlen = 0;
-        unsigned char hash[64];
+        size_t dig_signed_len = ssl->out_msg + ssl->out_msglen - dig_signed;
+        size_t hashlen = 0;
+        unsigned char hash[MBEDTLS_MD_MAX_SIZE];
+        int ret;
 
         /*
-         * 3.1: Choose hash algorithm:
+         * 2.1: Choose hash algorithm:
          * A: For TLS 1.2, obey signature-hash-algorithm extension
          *    to choose appropriate hash.
          * B: For SSL3, TLS1.0, TLS1.1 and ECDHE_ECDSA, use SHA1
@@ -3090,7 +3099,7 @@
         MBEDTLS_SSL_DEBUG_MSG( 3, ( "pick hash algorithm %d for signing", md_alg ) );
 
         /*
-         * 3.2: Compute the hash to be signed
+         * 2.2: Compute the hash to be signed
          */
 #if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \
     defined(MBEDTLS_SSL_PROTO_TLS1_1)
@@ -3110,9 +3119,7 @@
     defined(MBEDTLS_SSL_PROTO_TLS1_2)
         if( md_alg != MBEDTLS_MD_NONE )
         {
-            /* Info from md_alg will be used instead */
-            hashlen = 0;
-            ret = mbedtls_ssl_get_key_exchange_md_tls1_2( ssl, hash,
+            ret = mbedtls_ssl_get_key_exchange_md_tls1_2( ssl, hash, &hashlen,
                                                           dig_signed,
                                                           dig_signed_len,
                                                           md_alg );
@@ -3127,18 +3134,11 @@
             return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
         }
 
-        MBEDTLS_SSL_DEBUG_BUF( 3, "parameters hash", hash, hashlen != 0 ? hashlen :
-            (unsigned int) ( mbedtls_md_get_size( mbedtls_md_info_from_type( md_alg ) ) ) );
+        MBEDTLS_SSL_DEBUG_BUF( 3, "parameters hash", hash, hashlen );
 
         /*
-         * 3.3: Compute and add the signature
+         * 2.3: Compute and add the signature
          */
-        if( mbedtls_ssl_own_key( ssl ) == NULL )
-        {
-            MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no private key" ) );
-            return( MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED );
-        }
-
 #if defined(MBEDTLS_SSL_PROTO_TLS1_2)
         if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 )
         {
@@ -3158,33 +3158,150 @@
              *
              */
 
-            *(p++) = mbedtls_ssl_hash_from_md_alg( md_alg );
-            *(p++) = mbedtls_ssl_sig_from_pk_alg( sig_alg );
-
-            n += 2;
+            ssl->out_msg[ssl->out_msglen++] =
+                mbedtls_ssl_hash_from_md_alg( md_alg );
+            ssl->out_msg[ssl->out_msglen++] =
+                mbedtls_ssl_sig_from_pk_alg( sig_alg );
         }
 #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
 
-        if( ( ret = mbedtls_pk_sign( mbedtls_ssl_own_key( ssl ), md_alg, hash, hashlen,
-                        p + 2 , &signature_len, ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 )
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+        if( ssl->conf->f_async_sign_start != NULL )
+        {
+            ret = ssl->conf->f_async_sign_start( ssl,
+                                                 mbedtls_ssl_own_cert( ssl ),
+                                                 md_alg, hash, hashlen );
+            switch( ret )
+            {
+            case MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH:
+                /* act as if f_async_sign was null */
+                break;
+            case 0:
+                ssl->handshake->async_in_progress = 1;
+                return( ssl_resume_server_key_exchange( ssl, signature_len ) );
+            case MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS:
+                ssl->handshake->async_in_progress = 1;
+                return( MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS );
+            default:
+                MBEDTLS_SSL_DEBUG_RET( 1, "f_async_sign_start", ret );
+                return( ret );
+            }
+        }
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+
+        if( mbedtls_ssl_own_key( ssl ) == NULL )
+        {
+            MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no private key" ) );
+            return( MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED );
+        }
+
+        /* Append the signature to ssl->out_msg, leaving 2 bytes for the
+         * signature length which will be added in ssl_write_server_key_exchange
+         * after the call to ssl_prepare_server_key_exchange.
+         * ssl_write_server_key_exchange also takes care of incrementing
+         * ssl->out_msglen. */
+        if( ( ret = mbedtls_pk_sign( mbedtls_ssl_own_key( ssl ),
+                                     md_alg, hash, hashlen,
+                                     ssl->out_msg + ssl->out_msglen + 2,
+                                     signature_len,
+                                     ssl->conf->f_rng,
+                                     ssl->conf->p_rng ) ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_sign", ret );
             return( ret );
         }
-
-        *(p++) = (unsigned char)( signature_len >> 8 );
-        *(p++) = (unsigned char)( signature_len      );
-        n += 2;
-
-        MBEDTLS_SSL_DEBUG_BUF( 3, "my signature", p, signature_len );
-
-        n += signature_len;
     }
 #endif /* MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED */
 
-    /* Done with actual work; add header and send. */
+    return( 0 );
+}
 
-    ssl->out_msglen  = 4 + n;
+/* Prepare the ServerKeyExchange message and send it. For ciphersuites
+ * that do not include a ServerKeyExchange message, do nothing. Either
+ * way, if successful, move on to the next step in the SSL state
+ * machine. */
+static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl )
+{
+    int ret;
+    size_t signature_len = 0;
+#if defined(MBEDTLS_KEY_EXCHANGE__SOME_NON_PFS__ENABLED)
+    const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
+                            ssl->transform_negotiate->ciphersuite_info;
+#endif /* MBEDTLS_KEY_EXCHANGE__SOME_NON_PFS__ENABLED */
+
+    MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write server key exchange" ) );
+
+#if defined(MBEDTLS_KEY_EXCHANGE__SOME_NON_PFS__ENABLED)
+    /* Extract static ECDH parameters and abort if ServerKeyExchange
+     * is not needed. */
+    if( mbedtls_ssl_ciphersuite_no_pfs( ciphersuite_info ) )
+    {
+        /* For suites involving ECDH, extract DH parameters
+         * from certificate at this point. */
+#if defined(MBEDTLS_KEY_EXCHANGE__SOME__ECDH_ENABLED)
+        if( mbedtls_ssl_ciphersuite_uses_ecdh( ciphersuite_info ) )
+        {
+            ssl_get_ecdh_params_from_cert( ssl );
+        }
+#endif /* MBEDTLS_KEY_EXCHANGE__SOME__ECDH_ENABLED */
+
+        /* Key exchanges not involving ephemeral keys don't use
+         * ServerKeyExchange, so end here. */
+        MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write server key exchange" ) );
+        ssl->state++;
+        return( 0 );
+    }
+#endif /* MBEDTLS_KEY_EXCHANGE__SOME_NON_PFS__ENABLED */
+
+#if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) && \
+    defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+    /* If we have already prepared the message and there is an ongoing
+     * signature operation, resume signing. */
+    if( ssl->handshake->async_in_progress != 0 )
+    {
+        MBEDTLS_SSL_DEBUG_MSG( 2, ( "resuming signature operation" ) );
+        ret = ssl_resume_server_key_exchange( ssl, &signature_len );
+    }
+    else
+#endif /* defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) &&
+          defined(MBEDTLS_SSL_ASYNC_PRIVATE) */
+    {
+        /* ServerKeyExchange is needed. Prepare the message. */
+        ret = ssl_prepare_server_key_exchange( ssl, &signature_len );
+    }
+
+    if( ret != 0 )
+    {
+        /* If we're starting to write a new message, set ssl->out_msglen
+         * to 0. But if we're resuming after an asynchronous message,
+         * out_msglen is the amount of data written so far and mst be
+         * preserved. */
+        if( ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS )
+            MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server key exchange (pending)" ) );
+        else
+            ssl->out_msglen = 0;
+        return( ret );
+    }
+
+    /* If there is a signature, write its length.
+     * ssl_prepare_server_key_exchange already wrote the signature
+     * itself at its proper place in the output buffer. */
+#if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED)
+    if( signature_len != 0 )
+    {
+        ssl->out_msg[ssl->out_msglen++] = (unsigned char)( signature_len >> 8 );
+        ssl->out_msg[ssl->out_msglen++] = (unsigned char)( signature_len      );
+
+        MBEDTLS_SSL_DEBUG_BUF( 3, "my signature",
+                               ssl->out_msg + ssl->out_msglen,
+                               signature_len );
+
+        /* Skip over the already-written signature */
+        ssl->out_msglen += signature_len;
+    }
+#endif /* MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED */
+
+    /* Add header and send. */
     ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE;
     ssl->out_msg[0]  = MBEDTLS_SSL_HS_SERVER_KEY_EXCHANGE;
 
@@ -3197,7 +3314,6 @@
     }
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server key exchange" ) );
-
     return( 0 );
 }
 
@@ -3272,28 +3388,50 @@
 
 #if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) ||                           \
     defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED)
-static int ssl_parse_encrypted_pms( mbedtls_ssl_context *ssl,
-                                    const unsigned char *p,
-                                    const unsigned char *end,
-                                    size_t pms_offset )
+
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+static int ssl_resume_decrypt_pms( mbedtls_ssl_context *ssl,
+                                   unsigned char *peer_pms,
+                                   size_t *peer_pmslen,
+                                   size_t peer_pmssize )
+{
+    int ret = ssl->conf->f_async_resume( ssl,
+                                         peer_pms, peer_pmslen, peer_pmssize );
+    if( ret != MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS )
+    {
+        ssl->handshake->async_in_progress = 0;
+        mbedtls_ssl_set_async_operation_data( ssl, NULL );
+    }
+    MBEDTLS_SSL_DEBUG_RET( 2, "ssl_decrypt_encrypted_pms", ret );
+    return( ret );
+}
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+
+static int ssl_decrypt_encrypted_pms( mbedtls_ssl_context *ssl,
+                                      const unsigned char *p,
+                                      const unsigned char *end,
+                                      unsigned char *peer_pms,
+                                      size_t *peer_pmslen,
+                                      size_t peer_pmssize )
 {
     int ret;
-    size_t len = mbedtls_pk_get_len( mbedtls_ssl_own_key( ssl ) );
-    unsigned char *pms = ssl->handshake->premaster + pms_offset;
-    unsigned char ver[2];
-    unsigned char fake_pms[48], peer_pms[48];
-    unsigned char mask;
-    size_t i, peer_pmslen;
-    unsigned int diff;
+    mbedtls_pk_context *private_key = mbedtls_ssl_own_key( ssl );
+    mbedtls_pk_context *public_key = &mbedtls_ssl_own_cert( ssl )->pk;
+    size_t len = mbedtls_pk_get_len( public_key );
 
-    if( ! mbedtls_pk_can_do( mbedtls_ssl_own_key( ssl ), MBEDTLS_PK_RSA ) )
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+    /* If we have already started decoding the message and there is an ongoing
+     * decryption operation, resume signing. */
+    if( ssl->handshake->async_in_progress != 0 )
     {
-        MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no RSA private key" ) );
-        return( MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED );
+        MBEDTLS_SSL_DEBUG_MSG( 2, ( "resuming decryption operation" ) );
+        return( ssl_resume_decrypt_pms( ssl,
+                                        peer_pms, peer_pmslen, peer_pmssize ) );
     }
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
 
     /*
-     * Decrypt the premaster using own private RSA key
+     * Prepare to decrypt the premaster using own private RSA key
      */
 #if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \
     defined(MBEDTLS_SSL_PROTO_TLS1_2)
@@ -3314,30 +3452,120 @@
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE );
     }
 
+    /*
+     * Decrypt the premaster secret
+     */
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+    if( ssl->conf->f_async_decrypt_start != NULL )
+    {
+        ret = ssl->conf->f_async_decrypt_start( ssl,
+                                                mbedtls_ssl_own_cert( ssl ),
+                                                p, len );
+        switch( ret )
+        {
+        case MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH:
+            /* act as if f_async_decrypt_start was null */
+            break;
+        case 0:
+            ssl->handshake->async_in_progress = 1;
+            return( ssl_resume_decrypt_pms( ssl,
+                                            peer_pms,
+                                            peer_pmslen,
+                                            peer_pmssize ) );
+        case MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS:
+            ssl->handshake->async_in_progress = 1;
+            return( MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS );
+        default:
+            MBEDTLS_SSL_DEBUG_RET( 1, "f_async_decrypt_start", ret );
+            return( ret );
+        }
+    }
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+
+    if( ! mbedtls_pk_can_do( private_key, MBEDTLS_PK_RSA ) )
+    {
+        MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no RSA private key" ) );
+        return( MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED );
+    }
+
+    ret = mbedtls_pk_decrypt( private_key, p, len,
+                              peer_pms, peer_pmslen, peer_pmssize,
+                              ssl->conf->f_rng, ssl->conf->p_rng );
+    return( ret );
+}
+
+static int ssl_parse_encrypted_pms( mbedtls_ssl_context *ssl,
+                                    const unsigned char *p,
+                                    const unsigned char *end,
+                                    size_t pms_offset )
+{
+    int ret;
+    unsigned char *pms = ssl->handshake->premaster + pms_offset;
+    unsigned char ver[2];
+    unsigned char fake_pms[48], peer_pms[48];
+    unsigned char mask;
+    size_t i, peer_pmslen;
+    unsigned int diff;
+
+    /* In case of a failure in decryption, the decryption may write less than
+     * 2 bytes of output, but we always read the first two bytes. It doesn't
+     * matter in the end because diff will be nonzero in that case due to
+     * peer_pmslen being less than 48, and we only care whether diff is 0.
+     * But do initialize peer_pms for robustness anyway. This also makes
+     * memory analyzers happy (don't access uninitialized memory, even
+     * if it's an unsigned char). */
+    peer_pms[0] = peer_pms[1] = ~0;
+
+    ret = ssl_decrypt_encrypted_pms( ssl, p, end,
+                                     peer_pms,
+                                     &peer_pmslen,
+                                     sizeof( peer_pms ) );
+
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+    if ( ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS )
+        return( ret );
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+
     mbedtls_ssl_write_version( ssl->handshake->max_major_ver,
-                       ssl->handshake->max_minor_ver,
-                       ssl->conf->transport, ver );
+                               ssl->handshake->max_minor_ver,
+                               ssl->conf->transport, ver );
+
+    /* Avoid data-dependent branches while checking for invalid
+     * padding, to protect against timing-based Bleichenbacher-type
+     * attacks. */
+    diff  = (unsigned int) ret;
+    diff |= peer_pmslen ^ 48;
+    diff |= peer_pms[0] ^ ver[0];
+    diff |= peer_pms[1] ^ ver[1];
+
+    /* mask = diff ? 0xff : 0x00 using bit operations to avoid branches */
+    /* MSVC has a warning about unary minus on unsigned, but this is
+     * well-defined and precisely what we want to do here */
+#if defined(_MSC_VER)
+#pragma warning( push )
+#pragma warning( disable : 4146 )
+#endif
+    mask = - ( ( diff | - diff ) >> ( sizeof( unsigned int ) * 8 - 1 ) );
+#if defined(_MSC_VER)
+#pragma warning( pop )
+#endif
 
     /*
      * Protection against Bleichenbacher's attack: invalid PKCS#1 v1.5 padding
      * must not cause the connection to end immediately; instead, send a
      * bad_record_mac later in the handshake.
-     * Also, avoid data-dependant branches here to protect against
-     * timing-based variants.
+     * To protect against timing-based variants of the attack, we must
+     * not have any branch that depends on whether the decryption was
+     * successful. In particular, always generate the fake premaster secret,
+     * regardless of whether it will ultimately influence the output or not.
      */
     ret = ssl->conf->f_rng( ssl->conf->p_rng, fake_pms, sizeof( fake_pms ) );
     if( ret != 0 )
+    {
+        /* It's ok to abort on an RNG failure, since this does not reveal
+         * anything about the RSA decryption. */
         return( ret );
-
-    ret = mbedtls_pk_decrypt( mbedtls_ssl_own_key( ssl ), p, len,
-                      peer_pms, &peer_pmslen,
-                      sizeof( peer_pms ),
-                      ssl->conf->f_rng, ssl->conf->p_rng );
-
-    diff  = (unsigned int) ret;
-    diff |= peer_pmslen ^ 48;
-    diff |= peer_pms[0] ^ ver[0];
-    diff |= peer_pms[1] ^ ver[1];
+    }
 
 #if defined(MBEDTLS_SSL_DEBUG_ALL)
     if( diff != 0 )
@@ -3352,18 +3580,8 @@
     }
     ssl->handshake->pmslen = 48;
 
-    /* mask = diff ? 0xff : 0x00 using bit operations to avoid branches */
-    /* MSVC has a warning about unary minus on unsigned, but this is
-     * well-defined and precisely what we want to do here */
-#if defined(_MSC_VER)
-#pragma warning( push )
-#pragma warning( disable : 4146 )
-#endif
-    mask = - ( ( diff | - diff ) >> ( sizeof( unsigned int ) * 8 - 1 ) );
-#if defined(_MSC_VER)
-#pragma warning( pop )
-#endif
-
+    /* Set pms to either the true or the fake PMS, without
+     * data-dependent branches. */
     for( i = 0; i < ssl->handshake->pmslen; i++ )
         pms[i] = ( mask & fake_pms[i] ) | ( (~mask) & peer_pms[i] );
 
@@ -3445,6 +3663,20 @@
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse client key exchange" ) );
 
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) && \
+    ( defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) || \
+      defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) )
+    if( ( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ||
+          ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA ) &&
+        ( ssl->handshake->async_in_progress != 0 ) )
+    {
+        /* We've already read a record and there is an asynchronous
+         * operation in progress to decrypt it. So skip reading the
+         * record. */
+        MBEDTLS_SSL_DEBUG_MSG( 3, ( "will resume decryption of previously-read record" ) );
+    }
+    else
+#endif
     if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 )
     {
         MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret );
@@ -3557,6 +3789,19 @@
 #if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED)
     if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK )
     {
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+        if ( ssl->handshake->async_in_progress != 0 )
+        {
+            /* There is an asynchronous operation in progress to
+             * decrypt the encrypted premaster secret, so skip
+             * directly to resuming this operation. */
+            MBEDTLS_SSL_DEBUG_MSG( 3, ( "PSK identity already parsed" ) );
+            /* Update p to skip the PSK identity. ssl_parse_encrypted_pms
+             * won't actually use it, but maintain p anyway for robustness. */
+            p += ssl->conf->psk_identity_len + 2;
+        }
+        else
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
         if( ( ret = ssl_parse_client_psk_identity( ssl, &p, end ) ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_client_psk_identity" ), ret );
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index e8e0cd8..e5119fc 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -5202,7 +5202,7 @@
     /*
      * Free our handshake params
      */
-    mbedtls_ssl_handshake_free( ssl->handshake );
+    mbedtls_ssl_handshake_free( ssl );
     mbedtls_free( ssl->handshake );
     ssl->handshake = NULL;
 
@@ -5557,7 +5557,7 @@
     if( ssl->session_negotiate )
         mbedtls_ssl_session_free( ssl->session_negotiate );
     if( ssl->handshake )
-        mbedtls_ssl_handshake_free( ssl->handshake );
+        mbedtls_ssl_handshake_free( ssl );
 
     /*
      * Either the pointers are now NULL or cleared properly and can be freed.
@@ -6480,6 +6480,43 @@
 }
 #endif
 
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+void mbedtls_ssl_conf_async_private_cb(
+    mbedtls_ssl_config *conf,
+    mbedtls_ssl_async_sign_t *f_async_sign,
+    mbedtls_ssl_async_decrypt_t *f_async_decrypt,
+    mbedtls_ssl_async_resume_t *f_async_resume,
+    mbedtls_ssl_async_cancel_t *f_async_cancel,
+    void *async_config_data )
+{
+    conf->f_async_sign_start = f_async_sign;
+    conf->f_async_decrypt_start = f_async_decrypt;
+    conf->f_async_resume = f_async_resume;
+    conf->f_async_cancel = f_async_cancel;
+    conf->p_async_config_data = async_config_data;
+}
+
+void *mbedtls_ssl_conf_get_async_config_data( const mbedtls_ssl_config *conf )
+{
+    return( conf->p_async_config_data );
+}
+
+void *mbedtls_ssl_get_async_operation_data( const mbedtls_ssl_context *ssl )
+{
+    if( ssl->handshake == NULL )
+        return( NULL );
+    else
+        return( ssl->handshake->user_async_ctx );
+}
+
+void mbedtls_ssl_set_async_operation_data( mbedtls_ssl_context *ssl,
+                                 void *ctx )
+{
+    if( ssl->handshake != NULL )
+        ssl->handshake->user_async_ctx = ctx;
+}
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+
 /*
  * SSL get accessors
  */
@@ -7387,11 +7424,21 @@
 }
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
-void mbedtls_ssl_handshake_free( mbedtls_ssl_handshake_params *handshake )
+void mbedtls_ssl_handshake_free( mbedtls_ssl_context *ssl )
 {
+    mbedtls_ssl_handshake_params *handshake = ssl->handshake;
+
     if( handshake == NULL )
         return;
 
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+    if( ssl->conf->f_async_cancel != NULL && handshake->async_in_progress != 0 )
+    {
+        ssl->conf->f_async_cancel( ssl );
+        handshake->async_in_progress = 0;
+    }
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+
 #if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \
     defined(MBEDTLS_SSL_PROTO_TLS1_1)
     mbedtls_md5_free(    &handshake->fin_md5  );
@@ -7522,7 +7569,7 @@
 
     if( ssl->handshake )
     {
-        mbedtls_ssl_handshake_free( ssl->handshake );
+        mbedtls_ssl_handshake_free( ssl );
         mbedtls_ssl_transform_free( ssl->transform_negotiate );
         mbedtls_ssl_session_free( ssl->session_negotiate );
 
@@ -8289,13 +8336,14 @@
 #if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \
     defined(MBEDTLS_SSL_PROTO_TLS1_2)
 int mbedtls_ssl_get_key_exchange_md_tls1_2( mbedtls_ssl_context *ssl,
-                                       unsigned char *output,
-                                       unsigned char *data, size_t data_len,
-                                       mbedtls_md_type_t md_alg )
+                                            unsigned char *hash, size_t *hashlen,
+                                            unsigned char *data, size_t data_len,
+                                            mbedtls_md_type_t md_alg )
 {
     int ret = 0;
     mbedtls_md_context_t ctx;
     const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( md_alg );
+    *hashlen = mbedtls_md_get_size( md_info );
 
     mbedtls_md_init( &ctx );
 
@@ -8326,7 +8374,7 @@
         MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_md_update", ret );
         goto exit;
     }
-    if( ( ret = mbedtls_md_finish( &ctx, output ) ) != 0 )
+    if( ( ret = mbedtls_md_finish( &ctx, hash ) ) != 0 )
     {
         MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_md_finish", ret );
         goto exit;
diff --git a/library/version_features.c b/library/version_features.c
index 08f14e7..bea2b13 100644
--- a/library/version_features.c
+++ b/library/version_features.c
@@ -411,6 +411,9 @@
 #if defined(MBEDTLS_SSL_ALL_ALERT_MESSAGES)
     "MBEDTLS_SSL_ALL_ALERT_MESSAGES",
 #endif /* MBEDTLS_SSL_ALL_ALERT_MESSAGES */
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+    "MBEDTLS_SSL_ASYNC_PRIVATE",
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
 #if defined(MBEDTLS_SSL_DEBUG_ALL)
     "MBEDTLS_SSL_DEBUG_ALL",
 #endif /* MBEDTLS_SSL_DEBUG_ALL */
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index 6bfb210..81041c4 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -109,6 +109,10 @@
 #define DFL_KEY_FILE            ""
 #define DFL_CRT_FILE2           ""
 #define DFL_KEY_FILE2           ""
+#define DFL_ASYNC_OPERATIONS    "-"
+#define DFL_ASYNC_PRIVATE_DELAY1 ( -1 )
+#define DFL_ASYNC_PRIVATE_DELAY2 ( -1 )
+#define DFL_ASYNC_PRIVATE_ERROR  ( 0 )
 #define DFL_PSK                 ""
 #define DFL_PSK_IDENTITY        "Client_identity"
 #define DFL_ECJPAKE_PW          NULL
@@ -196,6 +200,18 @@
 #define USAGE_IO ""
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+#define USAGE_SSL_ASYNC \
+    "    async_operations=%%c...   d=decrypt, s=sign (default: -=off)\n" \
+    "    async_private_delay1=%%d  Asynchronous delay for key_file or preloaded key\n" \
+    "    async_private_delay2=%%d  Asynchronous delay for key_file2 and sni\n" \
+    "                              default: -1 (not asynchronous)\n" \
+    "    async_private_error=%%d   Async callback error injection (default=0=none,\n" \
+    "                              1=start, 2=cancel, 3=resume, negative=first time only)"
+#else
+#define USAGE_SSL_ASYNC ""
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+
 #if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED)
 #define USAGE_PSK                                                   \
     "    psk=%%s              default: \"\" (in hex, without 0x)\n" \
@@ -346,6 +362,7 @@
     "    cert_req_ca_list=%%d default: 1 (send ca list)\n"  \
     "                        options: 1 (send ca list), 0 (don't send)\n" \
     USAGE_IO                                                \
+    USAGE_SSL_ASYNC                                         \
     USAGE_SNI                                               \
     "\n"                                                    \
     USAGE_PSK                                               \
@@ -410,6 +427,10 @@
     const char *key_file;       /* the file with the server key             */
     const char *crt_file2;      /* the file with the 2nd server certificate */
     const char *key_file2;      /* the file with the 2nd server key         */
+    const char *async_operations; /* supported SSL asynchronous operations  */
+    int async_private_delay1;   /* number of times f_async_resume needs to be called for key 1, or -1 for no async */
+    int async_private_delay2;   /* number of times f_async_resume needs to be called for key 2, or -1 for no async */
+    int async_private_error;    /* inject error in async private callback */
     const char *psk;            /* the pre-shared key                       */
     const char *psk_identity;   /* the pre-shared key identity              */
     char *psk_list;             /* list of PSK id/key pairs for callback    */
@@ -841,6 +862,243 @@
 };
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
+/** Return true if \p ret is a status code indicating that there is an
+ * operation in progress on an SSL connection, and false if it indicates
+ * success or a fatal error.
+ *
+ * The possible operations in progress are:
+ *
+ * - A read, when the SSL input buffer does not contain a full message.
+ * - A write, when the SSL output buffer contains some data that has not
+ *   been sent over the network yet.
+ * - An asynchronous callback that has not completed yet. */
+static int mbedtls_status_is_ssl_in_progress( int ret )
+{
+    return( ret == MBEDTLS_ERR_SSL_WANT_READ ||
+            ret == MBEDTLS_ERR_SSL_WANT_WRITE ||
+            ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS );
+}
+
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+typedef struct
+{
+    mbedtls_x509_crt *cert; /*!< Certificate corresponding to the key */
+    mbedtls_pk_context *pk; /*!< Private key */
+    unsigned delay; /*!< Number of resume steps to go through */
+    unsigned pk_owned : 1; /*!< Whether to free the pk object on exit */
+} ssl_async_key_slot_t;
+
+typedef enum {
+    SSL_ASYNC_INJECT_ERROR_NONE = 0, /*!< Let the callbacks succeed */
+    SSL_ASYNC_INJECT_ERROR_START, /*!< Inject error during start */
+    SSL_ASYNC_INJECT_ERROR_CANCEL, /*!< Close the connection after async start */
+    SSL_ASYNC_INJECT_ERROR_RESUME, /*!< Inject error during resume */
+#define SSL_ASYNC_INJECT_ERROR_MAX SSL_ASYNC_INJECT_ERROR_RESUME
+} ssl_async_inject_error_t;
+
+typedef struct
+{
+    ssl_async_key_slot_t slots[4]; /* key, key2, sni1, sni2 */
+    size_t slots_used;
+    ssl_async_inject_error_t inject_error;
+    int (*f_rng)(void *, unsigned char *, size_t);
+    void *p_rng;
+} ssl_async_key_context_t;
+
+int ssl_async_set_key( ssl_async_key_context_t *ctx,
+                       mbedtls_x509_crt *cert,
+                       mbedtls_pk_context *pk,
+                       int pk_take_ownership,
+                       unsigned delay )
+{
+    if( ctx->slots_used >= sizeof( ctx->slots ) / sizeof( *ctx->slots ) )
+        return( -1 );
+    ctx->slots[ctx->slots_used].cert = cert;
+    ctx->slots[ctx->slots_used].pk = pk;
+    ctx->slots[ctx->slots_used].delay = delay;
+    ctx->slots[ctx->slots_used].pk_owned = pk_take_ownership;
+    ++ctx->slots_used;
+    return( 0 );
+}
+
+#define SSL_ASYNC_INPUT_MAX_SIZE 512
+
+typedef enum
+{
+    ASYNC_OP_SIGN,
+    ASYNC_OP_DECRYPT,
+} ssl_async_operation_type_t;
+/* Note that the enum above and the array below need to be kept in sync!
+ * `ssl_async_operation_names[op]` is the name of op for each value `op`
+ * of type `ssl_async_operation_type_t`. */
+static const char *const ssl_async_operation_names[] =
+{
+    "sign",
+    "decrypt",
+};
+
+typedef struct
+{
+    unsigned slot;
+    ssl_async_operation_type_t operation_type;
+    mbedtls_md_type_t md_alg;
+    unsigned char input[SSL_ASYNC_INPUT_MAX_SIZE];
+    size_t input_len;
+    unsigned remaining_delay;
+} ssl_async_operation_context_t;
+
+static int ssl_async_start( mbedtls_ssl_context *ssl,
+                            mbedtls_x509_crt *cert,
+                            ssl_async_operation_type_t op_type,
+                            mbedtls_md_type_t md_alg,
+                            const unsigned char *input,
+                            size_t input_len )
+{
+    ssl_async_key_context_t *config_data =
+        mbedtls_ssl_conf_get_async_config_data( ssl->conf );
+    unsigned slot;
+    ssl_async_operation_context_t *ctx = NULL;
+    const char *op_name = ssl_async_operation_names[op_type];
+
+    {
+        char dn[100];
+        mbedtls_x509_dn_gets( dn, sizeof( dn ), &cert->subject );
+        mbedtls_printf( "Async %s callback: looking for DN=%s\n", op_name, dn );
+    }
+
+    /* Look for a private key that matches the public key in cert.
+     * Since this test code has the private key inside Mbed TLS,
+     * we call mbedtls_pk_check_pair to match a private key with the
+     * public key. */
+    for( slot = 0; slot < config_data->slots_used; slot++ )
+    {
+        if( mbedtls_pk_check_pair( &cert->pk,
+                                   config_data->slots[slot].pk ) == 0 )
+            break;
+    }
+    if( slot == config_data->slots_used )
+    {
+        mbedtls_printf( "Async %s callback: no key matches this certificate.\n",
+                        op_name );
+        return( MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH );
+    }
+    mbedtls_printf( "Async %s callback: using key slot %u, delay=%u.\n",
+                    op_name, slot, config_data->slots[slot].delay );
+
+    if( config_data->inject_error == SSL_ASYNC_INJECT_ERROR_START )
+    {
+        mbedtls_printf( "Async %s callback: injected error\n", op_name );
+        return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE );
+    }
+
+    if( input_len > SSL_ASYNC_INPUT_MAX_SIZE )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+    ctx = mbedtls_calloc( 1, sizeof( *ctx ) );
+    if( ctx == NULL )
+        return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
+    ctx->slot = slot;
+    ctx->operation_type = op_type;
+    ctx->md_alg = md_alg;
+    memcpy( ctx->input, input, input_len );
+    ctx->input_len = input_len;
+    ctx->remaining_delay = config_data->slots[slot].delay;
+    mbedtls_ssl_set_async_operation_data( ssl, ctx );
+
+    if( ctx->remaining_delay == 0 )
+        return( 0 );
+    else
+        return( MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS );
+}
+
+static int ssl_async_sign( mbedtls_ssl_context *ssl,
+                           mbedtls_x509_crt *cert,
+                           mbedtls_md_type_t md_alg,
+                           const unsigned char *hash,
+                           size_t hash_len )
+{
+    return( ssl_async_start( ssl, cert,
+                             ASYNC_OP_SIGN, md_alg,
+                             hash, hash_len ) );
+}
+
+static int ssl_async_decrypt( mbedtls_ssl_context *ssl,
+                              mbedtls_x509_crt *cert,
+                              const unsigned char *input,
+                              size_t input_len )
+{
+    return( ssl_async_start( ssl, cert,
+                             ASYNC_OP_DECRYPT, MBEDTLS_MD_NONE,
+                             input, input_len ) );
+}
+
+static int ssl_async_resume( mbedtls_ssl_context *ssl,
+                             unsigned char *output,
+                             size_t *output_len,
+                             size_t output_size )
+{
+    ssl_async_operation_context_t *ctx = mbedtls_ssl_get_async_operation_data( ssl );
+    ssl_async_key_context_t *config_data =
+        mbedtls_ssl_conf_get_async_config_data( ssl->conf );
+    ssl_async_key_slot_t *key_slot = &config_data->slots[ctx->slot];
+    int ret;
+    const char *op_name;
+
+    if( ctx->remaining_delay > 0 )
+    {
+        --ctx->remaining_delay;
+        mbedtls_printf( "Async resume (slot %u): call %u more times.\n",
+                        ctx->slot, ctx->remaining_delay );
+        return( MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS );
+    }
+
+    switch( ctx->operation_type )
+    {
+        case ASYNC_OP_DECRYPT:
+            ret = mbedtls_pk_decrypt( key_slot->pk,
+                                      ctx->input, ctx->input_len,
+                                      output, output_len, output_size,
+                                      config_data->f_rng, config_data->p_rng );
+            break;
+        case ASYNC_OP_SIGN:
+            ret = mbedtls_pk_sign( key_slot->pk,
+                                   ctx->md_alg,
+                                   ctx->input, ctx->input_len,
+                                   output, output_len,
+                                   config_data->f_rng, config_data->p_rng );
+            break;
+        default:
+            mbedtls_printf( "Async resume (slot %u): unknown operation type %ld. This shouldn't happen.\n",
+                            ctx->slot, (long) ctx->operation_type );
+            mbedtls_free( ctx );
+            return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE );
+            break;
+    }
+
+    op_name = ssl_async_operation_names[ctx->operation_type];
+
+    if( config_data->inject_error == SSL_ASYNC_INJECT_ERROR_RESUME )
+    {
+        mbedtls_printf( "Async resume callback: %s done but injected error\n",
+                        op_name );
+        mbedtls_free( ctx );
+        return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE );
+    }
+
+    mbedtls_printf( "Async resume (slot %u): %s done, status=%d.\n",
+                    ctx->slot, op_name, ret );
+    mbedtls_free( ctx );
+    return( ret );
+}
+
+static void ssl_async_cancel( mbedtls_ssl_context *ssl )
+{
+    ssl_async_operation_context_t *ctx = mbedtls_ssl_get_async_operation_data( ssl );
+    mbedtls_printf( "Async cancel callback.\n" );
+    mbedtls_free( ctx );
+}
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+
 /*
  * Wait for an event from the underlying transport or the timer
  * (Used in event-driven IO mode).
@@ -929,7 +1187,10 @@
     mbedtls_x509_crt srvcert2;
     mbedtls_pk_context pkey2;
     int key_cert_init = 0, key_cert_init2 = 0;
-#endif
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+    ssl_async_key_context_t ssl_async_keys;
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
 #if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_FS_IO)
     mbedtls_dhm_context dhm;
 #endif
@@ -975,6 +1236,9 @@
     mbedtls_pk_init( &pkey );
     mbedtls_x509_crt_init( &srvcert2 );
     mbedtls_pk_init( &pkey2 );
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+    memset( &ssl_async_keys, 0, sizeof( ssl_async_keys ) );
+#endif
 #endif
 #if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_FS_IO)
     mbedtls_dhm_init( &dhm );
@@ -1032,6 +1296,10 @@
     opt.key_file            = DFL_KEY_FILE;
     opt.crt_file2           = DFL_CRT_FILE2;
     opt.key_file2           = DFL_KEY_FILE2;
+    opt.async_operations    = DFL_ASYNC_OPERATIONS;
+    opt.async_private_delay1 = DFL_ASYNC_PRIVATE_DELAY1;
+    opt.async_private_delay2 = DFL_ASYNC_PRIVATE_DELAY2;
+    opt.async_private_error = DFL_ASYNC_PRIVATE_ERROR;
     opt.psk                 = DFL_PSK;
     opt.psk_identity        = DFL_PSK_IDENTITY;
     opt.psk_list            = DFL_PSK_LIST;
@@ -1124,6 +1392,25 @@
             opt.key_file2 = q;
         else if( strcmp( p, "dhm_file" ) == 0 )
             opt.dhm_file = q;
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+        else if( strcmp( p, "async_operations" ) == 0 )
+            opt.async_operations = q;
+        else if( strcmp( p, "async_private_delay1" ) == 0 )
+            opt.async_private_delay1 = atoi( q );
+        else if( strcmp( p, "async_private_delay2" ) == 0 )
+            opt.async_private_delay2 = atoi( q );
+        else if( strcmp( p, "async_private_error" ) == 0 )
+        {
+            int n = atoi( q );
+            if( n < -SSL_ASYNC_INJECT_ERROR_MAX ||
+                n > SSL_ASYNC_INJECT_ERROR_MAX )
+            {
+                ret = 2;
+                goto usage;
+            }
+            opt.async_private_error = n;
+        }
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
         else if( strcmp( p, "psk" ) == 0 )
             opt.psk = q;
         else if( strcmp( p, "psk_identity" ) == 0 )
@@ -2018,22 +2305,109 @@
         mbedtls_ssl_conf_ca_chain( &conf, &cacert, NULL );
     }
     if( key_cert_init )
-        if( ( ret = mbedtls_ssl_conf_own_cert( &conf, &srvcert, &pkey ) ) != 0 )
+    {
+        mbedtls_pk_context *pk = &pkey;
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+        if( opt.async_private_delay1 >= 0 )
+        {
+            ret = ssl_async_set_key( &ssl_async_keys, &srvcert, pk, 0,
+                                     opt.async_private_delay1 );
+            if( ret < 0 )
+            {
+                mbedtls_printf( "  Test error: ssl_async_set_key failed (%d)\n",
+                                ret );
+                goto exit;
+            }
+            pk = NULL;
+        }
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+        if( ( ret = mbedtls_ssl_conf_own_cert( &conf, &srvcert, pk ) ) != 0 )
         {
             mbedtls_printf( " failed\n  ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret );
             goto exit;
         }
+    }
     if( key_cert_init2 )
-        if( ( ret = mbedtls_ssl_conf_own_cert( &conf, &srvcert2, &pkey2 ) ) != 0 )
+    {
+        mbedtls_pk_context *pk = &pkey2;
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+        if( opt.async_private_delay2 >= 0 )
+        {
+            ret = ssl_async_set_key( &ssl_async_keys, &srvcert2, pk, 0,
+                                     opt.async_private_delay2 );
+            if( ret < 0 )
+            {
+                mbedtls_printf( "  Test error: ssl_async_set_key failed (%d)\n",
+                                ret );
+                goto exit;
+            }
+            pk = NULL;
+        }
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+        if( ( ret = mbedtls_ssl_conf_own_cert( &conf, &srvcert2, pk ) ) != 0 )
         {
             mbedtls_printf( " failed\n  ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret );
             goto exit;
         }
-#endif
+    }
+
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+    if( opt.async_operations[0] != '-' )
+    {
+        mbedtls_ssl_async_sign_t *sign = NULL;
+        mbedtls_ssl_async_decrypt_t *decrypt = NULL;
+        const char *r;
+        for( r = opt.async_operations; *r; r++ )
+        {
+            switch( *r )
+            {
+            case 'd':
+                decrypt = ssl_async_decrypt;
+                break;
+            case 's':
+                sign = ssl_async_sign;
+                break;
+            }
+        }
+        ssl_async_keys.inject_error = ( opt.async_private_error < 0 ?
+                                        - opt.async_private_error :
+                                        opt.async_private_error );
+        ssl_async_keys.f_rng = mbedtls_ctr_drbg_random;
+        ssl_async_keys.p_rng = &ctr_drbg;
+        mbedtls_ssl_conf_async_private_cb( &conf,
+                                           sign,
+                                           decrypt,
+                                           ssl_async_resume,
+                                           ssl_async_cancel,
+                                           &ssl_async_keys );
+    }
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
 
 #if defined(SNI_OPTION)
     if( opt.sni != NULL )
+    {
         mbedtls_ssl_conf_sni( &conf, sni_callback, sni_info );
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+        if( opt.async_private_delay2 >= 0 )
+        {
+            sni_entry *cur;
+            for( cur = sni_info; cur != NULL; cur = cur->next )
+            {
+                ret = ssl_async_set_key( &ssl_async_keys,
+                                         cur->cert, cur->key, 1,
+                                         opt.async_private_delay2 );
+                if( ret < 0 )
+                {
+                    mbedtls_printf( "  Test error: ssl_async_set_key failed (%d)\n",
+                                    ret );
+                    goto exit;
+                }
+                cur->key = NULL;
+            }
+        }
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+    }
 #endif
 
 #if defined(MBEDTLS_ECP_C)
@@ -2205,8 +2579,16 @@
 
     while( ( ret = mbedtls_ssl_handshake( &ssl ) ) != 0 )
     {
-        if( ret != MBEDTLS_ERR_SSL_WANT_READ &&
-            ret != MBEDTLS_ERR_SSL_WANT_WRITE )
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+        if( ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS &&
+            ssl_async_keys.inject_error == SSL_ASYNC_INJECT_ERROR_CANCEL )
+        {
+            mbedtls_printf( " cancelling on injected error\n" );
+            break;
+        }
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+
+        if( ! mbedtls_status_is_ssl_in_progress( ret ) )
             break;
 
         /* For event-driven IO, wait for socket to become available */
@@ -2244,6 +2626,11 @@
         }
 #endif
 
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+        if( opt.async_private_error < 0 )
+            /* Injected error only the first time round, to test reset */
+            ssl_async_keys.inject_error = SSL_ASYNC_INJECT_ERROR_NONE;
+#endif
         goto reset;
     }
     else /* ret == 0 */
@@ -2324,8 +2711,7 @@
             memset( buf, 0, sizeof( buf ) );
             ret = mbedtls_ssl_read( &ssl, buf, len );
 
-            if( ret == MBEDTLS_ERR_SSL_WANT_READ ||
-                ret == MBEDTLS_ERR_SSL_WANT_WRITE )
+            if( mbedtls_status_is_ssl_in_progress( ret ) )
             {
                 if( opt.event == 1 /* level triggered IO */ )
                 {
@@ -2425,7 +2811,7 @@
         len = sizeof( buf ) - 1;
         memset( buf, 0, sizeof( buf ) );
 
-        while( 1 )
+        do
         {
             /* Without the call to `mbedtls_ssl_check_pending`, it might
              * happen that the client sends application data in the same
@@ -2455,10 +2841,8 @@
              * it can happen that the subsequent call to `mbedtls_ssl_read`
              * returns `MBEDTLS_ERR_SSL_WANT_READ`, because the pending messages
              * might be discarded (e.g. because they are retransmissions). */
-            if( ret != MBEDTLS_ERR_SSL_WANT_READ &&
-                ret != MBEDTLS_ERR_SSL_WANT_WRITE )
-                break;
         }
+        while( mbedtls_status_is_ssl_in_progress( ret ) );
 
         if( ret <= 0 )
         {
@@ -2493,8 +2877,7 @@
 
         while( ( ret = mbedtls_ssl_renegotiate( &ssl ) ) != 0 )
         {
-            if( ret != MBEDTLS_ERR_SSL_WANT_READ &&
-                ret != MBEDTLS_ERR_SSL_WANT_WRITE )
+            if( ! mbedtls_status_is_ssl_in_progress( ret ) )
             {
                 mbedtls_printf( " failed\n  ! mbedtls_ssl_renegotiate returned %d\n\n", ret );
                 goto reset;
@@ -2537,8 +2920,7 @@
                     goto reset;
                 }
 
-                if( ret != MBEDTLS_ERR_SSL_WANT_READ &&
-                    ret != MBEDTLS_ERR_SSL_WANT_WRITE )
+                if( ! mbedtls_status_is_ssl_in_progress( ret ) )
                 {
                     mbedtls_printf( " failed\n  ! mbedtls_ssl_write returned %d\n\n", ret );
                     goto reset;
@@ -2562,8 +2944,7 @@
         {
             ret = mbedtls_ssl_write( &ssl, buf, len );
 
-            if( ret != MBEDTLS_ERR_SSL_WANT_READ &&
-                ret != MBEDTLS_ERR_SSL_WANT_WRITE )
+            if( ! mbedtls_status_is_ssl_in_progress( ret ) )
                 break;
 
             /* For event-driven IO, wait for socket to become available */
@@ -2641,6 +3022,17 @@
     mbedtls_x509_crt_free( &srvcert2 );
     mbedtls_pk_free( &pkey2 );
 #endif
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+    for( i = 0; (size_t) i < ssl_async_keys.slots_used; i++ )
+    {
+        if( ssl_async_keys.slots[i].pk_owned )
+        {
+            mbedtls_pk_free( ssl_async_keys.slots[i].pk );
+            mbedtls_free( ssl_async_keys.slots[i].pk );
+            ssl_async_keys.slots[i].pk = NULL;
+        }
+    }
+#endif
 #if defined(SNI_OPTION)
     sni_free( sni_info );
 #endif
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index 4894ad9..43c27b4 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -531,8 +531,8 @@
 msg "test: main suites (full config)" # ~ 5s
 make test
 
-msg "test: ssl-opt.sh default (full config)" # ~ 1s
-if_build_succeeded tests/ssl-opt.sh -f Default
+msg "test: ssl-opt.sh default, ECJPAKE (full config)" # ~ 1s
+if_build_succeeded tests/ssl-opt.sh -f 'Default\|ECJPAKE'
 
 msg "test: compat.sh RC4, DES & NULL (full config)" # ~ 2 min
 if_build_succeeded env OPENSSL_CMD="$OPENSSL_LEGACY" GNUTLS_CLI="$GNUTLS_LEGACY_CLI" GNUTLS_SERV="$GNUTLS_LEGACY_SERV" tests/compat.sh -e '3DES\|DES-CBC3' -f 'NULL\|DES\|RC4\|ARCFOUR'
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index c4a10a2..9faeb67 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -2652,6 +2652,142 @@
             -S "! The certificate is not correctly signed by the trusted CA" \
             -s "The certificate has been revoked (is on a CRL)"
 
+# Tests for SNI and DTLS
+
+run_test    "SNI: DTLS, no SNI callback" \
+            "$P_SRV debug_level=3 dtls=1 \
+             crt_file=data_files/server5.crt key_file=data_files/server5.key" \
+            "$P_CLI server_name=localhost dtls=1" \
+            0 \
+            -S "parse ServerName extension" \
+            -c "issuer name *: C=NL, O=PolarSSL, CN=Polarssl Test EC CA" \
+            -c "subject name *: C=NL, O=PolarSSL, CN=localhost"
+
+run_test    "SNI: DTLS, matching cert 1" \
+            "$P_SRV debug_level=3 dtls=1 \
+             crt_file=data_files/server5.crt key_file=data_files/server5.key \
+             sni=localhost,data_files/server2.crt,data_files/server2.key,-,-,-,polarssl.example,data_files/server1-nospace.crt,data_files/server1.key,-,-,-" \
+            "$P_CLI server_name=localhost dtls=1" \
+            0 \
+            -s "parse ServerName extension" \
+            -c "issuer name *: C=NL, O=PolarSSL, CN=PolarSSL Test CA" \
+            -c "subject name *: C=NL, O=PolarSSL, CN=localhost"
+
+run_test    "SNI: DTLS, matching cert 2" \
+            "$P_SRV debug_level=3 dtls=1 \
+             crt_file=data_files/server5.crt key_file=data_files/server5.key \
+             sni=localhost,data_files/server2.crt,data_files/server2.key,-,-,-,polarssl.example,data_files/server1-nospace.crt,data_files/server1.key,-,-,-" \
+            "$P_CLI server_name=polarssl.example dtls=1" \
+            0 \
+            -s "parse ServerName extension" \
+            -c "issuer name *: C=NL, O=PolarSSL, CN=PolarSSL Test CA" \
+            -c "subject name *: C=NL, O=PolarSSL, CN=polarssl.example"
+
+run_test    "SNI: DTLS, no matching cert" \
+            "$P_SRV debug_level=3 dtls=1 \
+             crt_file=data_files/server5.crt key_file=data_files/server5.key \
+             sni=localhost,data_files/server2.crt,data_files/server2.key,-,-,-,polarssl.example,data_files/server1-nospace.crt,data_files/server1.key,-,-,-" \
+            "$P_CLI server_name=nonesuch.example dtls=1" \
+            1 \
+            -s "parse ServerName extension" \
+            -s "ssl_sni_wrapper() returned" \
+            -s "mbedtls_ssl_handshake returned" \
+            -c "mbedtls_ssl_handshake returned" \
+            -c "SSL - A fatal alert message was received from our peer"
+
+run_test    "SNI: DTLS, client auth no override: optional" \
+            "$P_SRV debug_level=3 auth_mode=optional dtls=1 \
+             crt_file=data_files/server5.crt key_file=data_files/server5.key \
+             sni=localhost,data_files/server2.crt,data_files/server2.key,-,-,-" \
+            "$P_CLI debug_level=3 server_name=localhost dtls=1" \
+            0 \
+            -S "skip write certificate request" \
+            -C "skip parse certificate request" \
+            -c "got a certificate request" \
+            -C "skip write certificate" \
+            -C "skip write certificate verify" \
+            -S "skip parse certificate verify"
+
+run_test    "SNI: DTLS, client auth override: none -> optional" \
+            "$P_SRV debug_level=3 auth_mode=none dtls=1 \
+             crt_file=data_files/server5.crt key_file=data_files/server5.key \
+             sni=localhost,data_files/server2.crt,data_files/server2.key,-,-,optional" \
+            "$P_CLI debug_level=3 server_name=localhost dtls=1" \
+            0 \
+            -S "skip write certificate request" \
+            -C "skip parse certificate request" \
+            -c "got a certificate request" \
+            -C "skip write certificate" \
+            -C "skip write certificate verify" \
+            -S "skip parse certificate verify"
+
+run_test    "SNI: DTLS, client auth override: optional -> none" \
+            "$P_SRV debug_level=3 auth_mode=optional dtls=1 \
+             crt_file=data_files/server5.crt key_file=data_files/server5.key \
+             sni=localhost,data_files/server2.crt,data_files/server2.key,-,-,none" \
+            "$P_CLI debug_level=3 server_name=localhost dtls=1" \
+            0 \
+            -s "skip write certificate request" \
+            -C "skip parse certificate request" \
+            -c "got no certificate request" \
+            -c "skip write certificate" \
+            -c "skip write certificate verify" \
+            -s "skip parse certificate verify"
+
+run_test    "SNI: DTLS, CA no override" \
+            "$P_SRV debug_level=3 auth_mode=optional dtls=1 \
+             crt_file=data_files/server5.crt key_file=data_files/server5.key \
+             ca_file=data_files/test-ca.crt \
+             sni=localhost,data_files/server2.crt,data_files/server2.key,-,-,required" \
+            "$P_CLI debug_level=3 server_name=localhost dtls=1 \
+             crt_file=data_files/server6.crt key_file=data_files/server6.key" \
+            1 \
+            -S "skip write certificate request" \
+            -C "skip parse certificate request" \
+            -c "got a certificate request" \
+            -C "skip write certificate" \
+            -C "skip write certificate verify" \
+            -S "skip parse certificate verify" \
+            -s "x509_verify_cert() returned" \
+            -s "! The certificate is not correctly signed by the trusted CA" \
+            -S "The certificate has been revoked (is on a CRL)"
+
+run_test    "SNI: DTLS, CA override" \
+            "$P_SRV debug_level=3 auth_mode=optional dtls=1 \
+             crt_file=data_files/server5.crt key_file=data_files/server5.key \
+             ca_file=data_files/test-ca.crt \
+             sni=localhost,data_files/server2.crt,data_files/server2.key,data_files/test-ca2.crt,-,required" \
+            "$P_CLI debug_level=3 server_name=localhost dtls=1 \
+             crt_file=data_files/server6.crt key_file=data_files/server6.key" \
+            0 \
+            -S "skip write certificate request" \
+            -C "skip parse certificate request" \
+            -c "got a certificate request" \
+            -C "skip write certificate" \
+            -C "skip write certificate verify" \
+            -S "skip parse certificate verify" \
+            -S "x509_verify_cert() returned" \
+            -S "! The certificate is not correctly signed by the trusted CA" \
+            -S "The certificate has been revoked (is on a CRL)"
+
+run_test    "SNI: DTLS, CA override with CRL" \
+            "$P_SRV debug_level=3 auth_mode=optional \
+             crt_file=data_files/server5.crt key_file=data_files/server5.key dtls=1 \
+             ca_file=data_files/test-ca.crt \
+             sni=localhost,data_files/server2.crt,data_files/server2.key,data_files/test-ca2.crt,data_files/crl-ec-sha256.pem,required" \
+            "$P_CLI debug_level=3 server_name=localhost dtls=1 \
+             crt_file=data_files/server6.crt key_file=data_files/server6.key" \
+            1 \
+            -S "skip write certificate request" \
+            -C "skip parse certificate request" \
+            -c "got a certificate request" \
+            -C "skip write certificate" \
+            -C "skip write certificate verify" \
+            -S "skip parse certificate verify" \
+            -s "x509_verify_cert() returned" \
+            -S "! The certificate is not correctly signed by the trusted CA" \
+            -s "The certificate has been revoked (is on a CRL)"
+
 # Tests for non-blocking I/O: exercise a variety of handshake flows
 
 run_test    "Non-blocking I/O: basic handshake" \
@@ -4067,6 +4203,354 @@
             -c "16384 bytes written in 1 fragments" \
             -s "Read from client: 16384 bytes read"
 
+# Tests of asynchronous private key support in SSL
+
+requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE
+run_test    "SSL async private: sign, delay=0" \
+            "$P_SRV \
+             async_operations=s async_private_delay1=0 async_private_delay2=0" \
+            "$P_CLI" \
+            0 \
+            -s "Async sign callback: using key slot " \
+            -s "Async resume (slot [0-9]): sign done, status=0"
+
+requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE
+run_test    "SSL async private: sign, delay=1" \
+            "$P_SRV \
+             async_operations=s async_private_delay1=1 async_private_delay2=1" \
+            "$P_CLI" \
+            0 \
+            -s "Async sign callback: using key slot " \
+            -s "Async resume (slot [0-9]): call 0 more times." \
+            -s "Async resume (slot [0-9]): sign done, status=0"
+
+requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE
+run_test    "SSL async private: sign, delay=2" \
+            "$P_SRV \
+             async_operations=s async_private_delay1=2 async_private_delay2=2" \
+            "$P_CLI" \
+            0 \
+            -s "Async sign callback: using key slot " \
+            -U "Async sign callback: using key slot " \
+            -s "Async resume (slot [0-9]): call 1 more times." \
+            -s "Async resume (slot [0-9]): call 0 more times." \
+            -s "Async resume (slot [0-9]): sign done, status=0"
+
+# Test that the async callback correctly signs the 36-byte hash of TLS 1.0/1.1
+# with RSA PKCS#1v1.5 as used in TLS 1.0/1.1.
+requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_1
+run_test    "SSL async private: sign, RSA, TLS 1.1" \
+            "$P_SRV key_file=data_files/server2.key crt_file=data_files/server2.crt \
+             async_operations=s async_private_delay1=0 async_private_delay2=0" \
+            "$P_CLI force_version=tls1_1" \
+            0 \
+            -s "Async sign callback: using key slot " \
+            -s "Async resume (slot [0-9]): sign done, status=0"
+
+requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE
+run_test    "SSL async private: sign, SNI" \
+            "$P_SRV debug_level=3 \
+             async_operations=s async_private_delay1=0 async_private_delay2=0 \
+             crt_file=data_files/server5.crt key_file=data_files/server5.key \
+             sni=localhost,data_files/server2.crt,data_files/server2.key,-,-,-,polarssl.example,data_files/server1-nospace.crt,data_files/server1.key,-,-,-" \
+            "$P_CLI server_name=polarssl.example" \
+            0 \
+            -s "Async sign callback: using key slot " \
+            -s "Async resume (slot [0-9]): sign done, status=0" \
+            -s "parse ServerName extension" \
+            -c "issuer name *: C=NL, O=PolarSSL, CN=PolarSSL Test CA" \
+            -c "subject name *: C=NL, O=PolarSSL, CN=polarssl.example"
+
+requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE
+run_test    "SSL async private: decrypt, delay=0" \
+            "$P_SRV \
+             async_operations=d async_private_delay1=0 async_private_delay2=0" \
+            "$P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA" \
+            0 \
+            -s "Async decrypt callback: using key slot " \
+            -s "Async resume (slot [0-9]): decrypt done, status=0"
+
+requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE
+run_test    "SSL async private: decrypt, delay=1" \
+            "$P_SRV \
+             async_operations=d async_private_delay1=1 async_private_delay2=1" \
+            "$P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA" \
+            0 \
+            -s "Async decrypt callback: using key slot " \
+            -s "Async resume (slot [0-9]): call 0 more times." \
+            -s "Async resume (slot [0-9]): decrypt done, status=0"
+
+requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE
+run_test    "SSL async private: decrypt RSA-PSK, delay=0" \
+            "$P_SRV psk=abc123 \
+             async_operations=d async_private_delay1=0 async_private_delay2=0" \
+            "$P_CLI psk=abc123 \
+             force_ciphersuite=TLS-RSA-PSK-WITH-AES-128-CBC-SHA256" \
+            0 \
+            -s "Async decrypt callback: using key slot " \
+            -s "Async resume (slot [0-9]): decrypt done, status=0"
+
+requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE
+run_test    "SSL async private: decrypt RSA-PSK, delay=1" \
+            "$P_SRV psk=abc123 \
+             async_operations=d async_private_delay1=1 async_private_delay2=1" \
+            "$P_CLI psk=abc123 \
+             force_ciphersuite=TLS-RSA-PSK-WITH-AES-128-CBC-SHA256" \
+            0 \
+            -s "Async decrypt callback: using key slot " \
+            -s "Async resume (slot [0-9]): call 0 more times." \
+            -s "Async resume (slot [0-9]): decrypt done, status=0"
+
+requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE
+run_test    "SSL async private: sign callback not present" \
+            "$P_SRV \
+             async_operations=d async_private_delay1=1 async_private_delay2=1" \
+            "$P_CLI; [ \$? -eq 1 ] &&
+             $P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA" \
+            0 \
+            -S "Async sign callback" \
+            -s "! mbedtls_ssl_handshake returned" \
+            -s "The own private key or pre-shared key is not set, but needed" \
+            -s "Async resume (slot [0-9]): decrypt done, status=0" \
+            -s "Successful connection"
+
+requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE
+run_test    "SSL async private: decrypt callback not present" \
+            "$P_SRV debug_level=1 \
+             async_operations=s async_private_delay1=1 async_private_delay2=1" \
+            "$P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA;
+             [ \$? -eq 1 ] && $P_CLI" \
+            0 \
+            -S "Async decrypt callback" \
+            -s "! mbedtls_ssl_handshake returned" \
+            -s "got no RSA private key" \
+            -s "Async resume (slot [0-9]): sign done, status=0" \
+            -s "Successful connection"
+
+# key1: ECDSA, key2: RSA; use key1 from slot 0
+requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE
+run_test    "SSL async private: slot 0 used with key1" \
+            "$P_SRV \
+             async_operations=s async_private_delay1=1 \
+             key_file=data_files/server5.key crt_file=data_files/server5.crt \
+             key_file2=data_files/server2.key crt_file2=data_files/server2.crt" \
+            "$P_CLI force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256" \
+            0 \
+            -s "Async sign callback: using key slot 0," \
+            -s "Async resume (slot 0): call 0 more times." \
+            -s "Async resume (slot 0): sign done, status=0"
+
+# key1: ECDSA, key2: RSA; use key2 from slot 0
+requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE
+run_test    "SSL async private: slot 0 used with key2" \
+            "$P_SRV \
+             async_operations=s async_private_delay2=1 \
+             key_file=data_files/server5.key crt_file=data_files/server5.crt \
+             key_file2=data_files/server2.key crt_file2=data_files/server2.crt" \
+            "$P_CLI force_ciphersuite=TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256" \
+            0 \
+            -s "Async sign callback: using key slot 0," \
+            -s "Async resume (slot 0): call 0 more times." \
+            -s "Async resume (slot 0): sign done, status=0"
+
+# key1: ECDSA, key2: RSA; use key2 from slot 1
+requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE
+run_test    "SSL async private: slot 1 used with key2" \
+            "$P_SRV \
+             async_operations=s async_private_delay1=1 async_private_delay2=1 \
+             key_file=data_files/server5.key crt_file=data_files/server5.crt \
+             key_file2=data_files/server2.key crt_file2=data_files/server2.crt" \
+            "$P_CLI force_ciphersuite=TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256" \
+            0 \
+            -s "Async sign callback: using key slot 1," \
+            -s "Async resume (slot 1): call 0 more times." \
+            -s "Async resume (slot 1): sign done, status=0"
+
+# key1: ECDSA, key2: RSA; use key2 directly
+requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE
+run_test    "SSL async private: fall back to transparent key" \
+            "$P_SRV \
+             async_operations=s async_private_delay1=1 \
+             key_file=data_files/server5.key crt_file=data_files/server5.crt \
+             key_file2=data_files/server2.key crt_file2=data_files/server2.crt " \
+            "$P_CLI force_ciphersuite=TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256" \
+            0 \
+            -s "Async sign callback: no key matches this certificate."
+
+requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE
+run_test    "SSL async private: sign, error in start" \
+            "$P_SRV \
+             async_operations=s async_private_delay1=1 async_private_delay2=1 \
+             async_private_error=1" \
+            "$P_CLI" \
+            1 \
+            -s "Async sign callback: injected error" \
+            -S "Async resume" \
+            -S "Async cancel" \
+            -s "! mbedtls_ssl_handshake returned"
+
+requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE
+run_test    "SSL async private: sign, cancel after start" \
+            "$P_SRV \
+             async_operations=s async_private_delay1=1 async_private_delay2=1 \
+             async_private_error=2" \
+            "$P_CLI" \
+            1 \
+            -s "Async sign callback: using key slot " \
+            -S "Async resume" \
+            -s "Async cancel"
+
+requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE
+run_test    "SSL async private: sign, error in resume" \
+            "$P_SRV \
+             async_operations=s async_private_delay1=1 async_private_delay2=1 \
+             async_private_error=3" \
+            "$P_CLI" \
+            1 \
+            -s "Async sign callback: using key slot " \
+            -s "Async resume callback: sign done but injected error" \
+            -S "Async cancel" \
+            -s "! mbedtls_ssl_handshake returned"
+
+requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE
+run_test    "SSL async private: decrypt, error in start" \
+            "$P_SRV \
+             async_operations=d async_private_delay1=1 async_private_delay2=1 \
+             async_private_error=1" \
+            "$P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA" \
+            1 \
+            -s "Async decrypt callback: injected error" \
+            -S "Async resume" \
+            -S "Async cancel" \
+            -s "! mbedtls_ssl_handshake returned"
+
+requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE
+run_test    "SSL async private: decrypt, cancel after start" \
+            "$P_SRV \
+             async_operations=d async_private_delay1=1 async_private_delay2=1 \
+             async_private_error=2" \
+            "$P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA" \
+            1 \
+            -s "Async decrypt callback: using key slot " \
+            -S "Async resume" \
+            -s "Async cancel"
+
+requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE
+run_test    "SSL async private: decrypt, error in resume" \
+            "$P_SRV \
+             async_operations=d async_private_delay1=1 async_private_delay2=1 \
+             async_private_error=3" \
+            "$P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA" \
+            1 \
+            -s "Async decrypt callback: using key slot " \
+            -s "Async resume callback: decrypt done but injected error" \
+            -S "Async cancel" \
+            -s "! mbedtls_ssl_handshake returned"
+
+requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE
+run_test    "SSL async private: cancel after start then operate correctly" \
+            "$P_SRV \
+             async_operations=s async_private_delay1=1 async_private_delay2=1 \
+             async_private_error=-2" \
+            "$P_CLI; [ \$? -eq 1 ] && $P_CLI" \
+            0 \
+            -s "Async cancel" \
+            -s "! mbedtls_ssl_handshake returned" \
+            -s "Async resume" \
+            -s "Successful connection"
+
+requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE
+run_test    "SSL async private: error in resume then operate correctly" \
+            "$P_SRV \
+             async_operations=s async_private_delay1=1 async_private_delay2=1 \
+             async_private_error=-3" \
+            "$P_CLI; [ \$? -eq 1 ] && $P_CLI" \
+            0 \
+            -s "! mbedtls_ssl_handshake returned" \
+            -s "Async resume" \
+            -s "Successful connection"
+
+# key1: ECDSA, key2: RSA; use key1 through async, then key2 directly
+requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE
+run_test    "SSL async private: cancel after start then fall back to transparent key" \
+            "$P_SRV \
+             async_operations=s async_private_delay1=1 async_private_error=-2 \
+             key_file=data_files/server5.key crt_file=data_files/server5.crt \
+             key_file2=data_files/server2.key crt_file2=data_files/server2.crt" \
+            "$P_CLI force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256;
+             [ \$? -eq 1 ] &&
+             $P_CLI force_ciphersuite=TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256" \
+            0 \
+            -s "Async sign callback: using key slot 0" \
+            -S "Async resume" \
+            -s "Async cancel" \
+            -s "! mbedtls_ssl_handshake returned" \
+            -s "Async sign callback: no key matches this certificate." \
+            -s "Successful connection"
+
+# key1: ECDSA, key2: RSA; use key1 through async, then key2 directly
+requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE
+run_test    "SSL async private: sign, error in resume then fall back to transparent key" \
+            "$P_SRV \
+             async_operations=s async_private_delay1=1 async_private_error=-3 \
+             key_file=data_files/server5.key crt_file=data_files/server5.crt \
+             key_file2=data_files/server2.key crt_file2=data_files/server2.crt" \
+            "$P_CLI force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256;
+             [ \$? -eq 1 ] &&
+             $P_CLI force_ciphersuite=TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256" \
+            0 \
+            -s "Async resume" \
+            -s "! mbedtls_ssl_handshake returned" \
+            -s "Async sign callback: no key matches this certificate." \
+            -s "Successful connection"
+
+requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE
+requires_config_enabled MBEDTLS_SSL_RENEGOTIATION
+run_test    "SSL async private: renegotiation: client-initiated; sign" \
+            "$P_SRV \
+             async_operations=s async_private_delay1=1 async_private_delay2=1 \
+             exchanges=2 renegotiation=1" \
+            "$P_CLI exchanges=2 renegotiation=1 renegotiate=1" \
+            0 \
+            -s "Async sign callback: using key slot " \
+            -s "Async resume (slot [0-9]): sign done, status=0"
+
+requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE
+requires_config_enabled MBEDTLS_SSL_RENEGOTIATION
+run_test    "SSL async private: renegotiation: server-initiated; sign" \
+            "$P_SRV \
+             async_operations=s async_private_delay1=1 async_private_delay2=1 \
+             exchanges=2 renegotiation=1 renegotiate=1" \
+            "$P_CLI exchanges=2 renegotiation=1" \
+            0 \
+            -s "Async sign callback: using key slot " \
+            -s "Async resume (slot [0-9]): sign done, status=0"
+
+requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE
+requires_config_enabled MBEDTLS_SSL_RENEGOTIATION
+run_test    "SSL async private: renegotiation: client-initiated; decrypt" \
+            "$P_SRV \
+             async_operations=d async_private_delay1=1 async_private_delay2=1 \
+             exchanges=2 renegotiation=1" \
+            "$P_CLI exchanges=2 renegotiation=1 renegotiate=1 \
+             force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA" \
+            0 \
+            -s "Async decrypt callback: using key slot " \
+            -s "Async resume (slot [0-9]): decrypt done, status=0"
+
+requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE
+requires_config_enabled MBEDTLS_SSL_RENEGOTIATION
+run_test    "SSL async private: renegotiation: server-initiated; decrypt" \
+            "$P_SRV \
+             async_operations=d async_private_delay1=1 async_private_delay2=1 \
+             exchanges=2 renegotiation=1 renegotiate=1" \
+            "$P_CLI exchanges=2 renegotiation=1 \
+             force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA" \
+            0 \
+            -s "Async decrypt callback: using key slot " \
+            -s "Async resume (slot [0-9]): decrypt done, status=0"
+
 # Tests for DTLS HelloVerifyRequest
 
 run_test    "DTLS cookie: enabled" \