diff --git a/ChangeLog b/ChangeLog
index 1e252d85d..ddd56732c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -10,6 +10,9 @@ Features
* 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
diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h
index e90893f8a..7f4107f9a 100644
--- a/include/mbedtls/config.h
+++ b/include/mbedtls/config.h
@@ -1148,6 +1148,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
*
diff --git a/include/mbedtls/error.h b/include/mbedtls/error.h
index 2bde87a6f..13397a83b 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 250031a6d..45135500f 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 void mbedtls_ssl_set_timer_t( void * ctx,
*/
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_key_cert mbedtls_ssl_key_cert;
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 must not
+ * 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 must not
+ * 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 must not
+ * 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 @@ struct mbedtls_ssl_config
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 mbedtls_ssl_conf_export_keys_cb( mbedtls_ssl_config *conf,
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 2b5a61637..f48fe9042 100644
--- a/include/mbedtls/ssl_internal.h
+++ b/include/mbedtls/ssl_internal.h
@@ -243,6 +243,7 @@ struct mbedtls_ssl_handshake_params
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 @@ struct mbedtls_ssl_handshake_params
#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 @@ void mbedtls_ssl_transform_free( mbedtls_ssl_transform *transform );
* \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 @@ int mbedtls_ssl_get_key_exchange_md_ssl_tls( mbedtls_ssl_context *ssl,
#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/error.c b/library/error.c
index 5b57c7c4d..2a85d27d7 100644
--- a/library/error.c
+++ b/library/error.c
@@ -501,6 +501,8 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen )
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/ssl_cli.c b/library/ssl_cli.c
index 7455e99d2..e537f9d2e 100644
--- a/library/ssl_cli.c
+++ b/library/ssl_cli.c
@@ -2544,10 +2544,9 @@ static int ssl_parse_server_key_exchange( mbedtls_ssl_context *ssl )
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 @@ static int ssl_parse_server_key_exchange( mbedtls_ssl_context *ssl )
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 09b7a3fed..eb19f58c0 100644
--- a/library/ssl_srv.c
+++ b/library/ssl_srv.c
@@ -709,7 +709,7 @@ static int ssl_pick_cert( mbedtls_ssl_context *ssl,
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 @@ static int ssl_pick_cert( mbedtls_ssl_context *ssl,
#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 @@ static int ssl_get_ecdh_params_from_cert( mbedtls_ssl_context *ssl )
#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 )
+{
+ /* 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 )
{
- int ret;
- size_t n = 0;
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 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl )
#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 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl )
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 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl )
#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 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl )
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 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl )
*/
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 @@ curve_matching_done:
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 @@ curve_matching_done:
/*
*
- * 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 @@ curve_matching_done:
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 @@ curve_matching_done:
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 @@ curve_matching_done:
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 @@ curve_matching_done:
*
*/
- *(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 @@ curve_matching_done:
}
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server key exchange" ) );
-
return( 0 );
}
@@ -3272,28 +3388,50 @@ static int ssl_parse_client_dh_public( mbedtls_ssl_context *ssl, unsigned char *
#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 @@ static int ssl_parse_encrypted_pms( mbedtls_ssl_context *ssl,
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 @@ static int ssl_parse_encrypted_pms( mbedtls_ssl_context *ssl,
}
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 @@ static int ssl_parse_client_key_exchange( mbedtls_ssl_context *ssl )
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 @@ static int ssl_parse_client_key_exchange( mbedtls_ssl_context *ssl )
#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 e8e0cd854..e5119fcda 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -5202,7 +5202,7 @@ static void ssl_handshake_wrapup_free_hs_transform( mbedtls_ssl_context *ssl )
/*
* 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 @@ static int ssl_handshake_init( mbedtls_ssl_context *ssl )
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 @@ void mbedtls_ssl_conf_export_keys_cb( mbedtls_ssl_config *conf,
}
#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 @@ static void ssl_key_cert_free( mbedtls_ssl_key_cert *key_cert )
}
#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 @@ void mbedtls_ssl_free( mbedtls_ssl_context *ssl )
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 @@ exit:
#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 @@ int mbedtls_ssl_get_key_exchange_md_tls1_2( mbedtls_ssl_context *ssl,
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 99fb1fe18..35d30355a 100644
--- a/library/version_features.c
+++ b/library/version_features.c
@@ -411,6 +411,9 @@ static const char *features[] = {
#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 6bfb210f2..81041c44d 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -109,6 +109,10 @@ int main( void )
#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 @@ int main( void )
#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 @@ int main( void )
" 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 @@ struct options
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 @@ static int ssl_sig_hashes_for_test[] = {
};
#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 @@ int main( int argc, char *argv[] )
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 @@ int main( int argc, char *argv[] )
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 @@ int main( int argc, char *argv[] )
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 @@ int main( int argc, char *argv[] )
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 @@ int main( int argc, char *argv[] )
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 @@ handshake:
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 @@ handshake:
}
#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 @@ data_exchange:
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 @@ data_exchange:
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 @@ data_exchange:
* 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 @@ data_exchange:
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 @@ data_exchange:
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 @@ data_exchange:
{
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 @@ exit:
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 4894ad9b5..43c27b4bd 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -531,8 +531,8 @@ make
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 c4a10a2fa..3ea56db8e 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -4067,6 +4067,354 @@ run_test "Large packet TLS 1.2 AEAD shorter tag" \
-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" \