From 81d4e899a4eee9e1f1a2d794dbe70a83b4a7be9a Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 27 Oct 2017 10:18:44 +0200 Subject: [PATCH 01/69] Don't rely on private key metadata in SSL In SSL, don't use mbedtls_pk_ec or mbedtls_pk_rsa on a private signature or decryption key (as opposed to a public key or a key used for DH/ECDH). Extract the data (it's the same data) from the public key object instead. This way the code works even if the private key is opaque or if there is no private key object at all. Specifically, with an EC key, when checking whether the curve in a server key matches the handshake parameters, rely only on the offered certificate and not on the metadata of the private key. --- library/ssl_srv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 37f415dd1..fd04e927a 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -731,7 +731,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; From fe1c0937d70a9970393afe7d77e1429cb6b07856 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 23 Nov 2017 13:35:02 +0100 Subject: [PATCH 02/69] ssl_write_server_key_exchange refactor: remove redundant variable n Remove redundant variable n, which counts in parallel to p. Having both adds the burden of keeping them in synch for no benefit. --- library/ssl_srv.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/library/ssl_srv.c b/library/ssl_srv.c index fd04e927a..70fe13d79 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -2829,12 +2829,11 @@ static int ssl_get_ecdh_params_from_cert( mbedtls_ssl_context *ssl ) static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) { 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; +#if defined(MBEDTLS_KEY_EXCHANGE__SOME_PFS__ENABLED) size_t len; #if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) unsigned char *dig_signed = p; @@ -2894,7 +2893,6 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) } p += len; - n += len; } #endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ @@ -2910,8 +2908,6 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) { *(p++) = 0x00; *(p++) = 0x00; - - n += 2; } #endif /* MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED || MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */ @@ -2958,7 +2954,6 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) #endif p += len; - n += 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 ); @@ -3006,9 +3001,10 @@ 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, + p, ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN - p, + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_make_params", ret ); return( ret ); @@ -3020,7 +3016,6 @@ curve_matching_done: #endif p += len; - n += len; MBEDTLS_SSL_DEBUG_ECP( 3, "ECDH: Q ", &ssl->handshake->ecdh_ctx.Q ); } @@ -3203,8 +3198,6 @@ curve_matching_done: *(p++) = mbedtls_ssl_hash_from_md_alg( md_alg ); *(p++) = mbedtls_ssl_sig_from_pk_alg( sig_alg ); - - n += 2; } #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ @@ -3217,17 +3210,16 @@ curve_matching_done: *(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; + p += signature_len; } #endif /* MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED */ /* Done with actual work; add header and send. */ - ssl->out_msglen = 4 + n; + ssl->out_msglen = p - ssl->out_msg; ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; ssl->out_msg[0] = MBEDTLS_SSL_HS_SERVER_KEY_EXCHANGE; From 59e83d96dbd337b02c2260729d1d0d4173e98852 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 5 Jan 2018 21:08:15 +0100 Subject: [PATCH 03/69] Add conf parameter to mbedtls_ssl_handshake_free This function is declared in ssl_internal.h, so this is not a public API change. This is in preparation for mbedtls_ssl_handshake_free needing to call methods from the config structure. --- include/mbedtls/ssl_internal.h | 4 +++- library/ssl_tls.c | 10 ++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h index 756360b18..f990243ee 100644 --- a/include/mbedtls/ssl_internal.h +++ b/include/mbedtls/ssl_internal.h @@ -385,9 +385,11 @@ void mbedtls_ssl_transform_free( mbedtls_ssl_transform *transform ); * \brief Free referenced items in an SSL handshake context and clear * memory * + * \param conf SSL configuration * \param handshake SSL handshake context */ -void mbedtls_ssl_handshake_free( mbedtls_ssl_handshake_params *handshake ); +void mbedtls_ssl_handshake_free( const mbedtls_ssl_config *conf, + mbedtls_ssl_handshake_params *handshake ); int mbedtls_ssl_handshake_client_step( mbedtls_ssl_context *ssl ); int mbedtls_ssl_handshake_server_step( mbedtls_ssl_context *ssl ); diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 2690e4673..9482723b3 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -5153,7 +5153,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->conf, ssl->handshake ); mbedtls_free( ssl->handshake ); ssl->handshake = NULL; @@ -5508,7 +5508,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->conf, ssl->handshake ); /* * Either the pointers are now NULL or cleared properly and can be freed. @@ -7263,10 +7263,12 @@ 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( const mbedtls_ssl_config *conf, + mbedtls_ssl_handshake_params *handshake ) { if( handshake == NULL ) return; + (void) conf; /*unused in some compile-time configurations*/ #if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ defined(MBEDTLS_SSL_PROTO_TLS1_1) @@ -7397,7 +7399,7 @@ void mbedtls_ssl_free( mbedtls_ssl_context *ssl ) if( ssl->handshake ) { - mbedtls_ssl_handshake_free( ssl->handshake ); + mbedtls_ssl_handshake_free( ssl->conf, ssl->handshake ); mbedtls_ssl_transform_free( ssl->transform_negotiate ); mbedtls_ssl_session_free( ssl->session_negotiate ); From 8bf79f6dc666efca9a7841935bef58508e584c1f Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 5 Jan 2018 21:11:53 +0100 Subject: [PATCH 04/69] SSL asynchronous private key operation callbacks: interface New compile-time option MBEDTLS_SSL_ASYNC_PRIVATE_C, enabling callbacks to replace private key operations. These callbacks allow the SSL stack to make an asynchronous call to an external cryptographic module instead of calling the cryptography layer inside the library. The call is asynchronous in that it may return the new status code MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS, in which case the SSL stack returns and can be later called where it left off. This commit introduces the configuration option. Later commits will implement the feature proper. --- include/mbedtls/config.h | 11 ++ include/mbedtls/error.h | 2 +- include/mbedtls/ssl.h | 199 +++++++++++++++++++++++++++++++++ include/mbedtls/ssl_internal.h | 4 + library/error.c | 2 + library/ssl_tls.c | 26 +++++ library/version_features.c | 3 + 7 files changed, 246 insertions(+), 1 deletion(-) diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h index 7c0681549..80a4fef32 100644 --- a/include/mbedtls/config.h +++ b/include/mbedtls/config.h @@ -2333,6 +2333,17 @@ */ #define MBEDTLS_SHA512_C +/** + * \def MBEDTLS_SSL_ASYNC_PRIVATE_C + * + * 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_C + /** * \def MBEDTLS_SSL_CACHE_C * diff --git a/include/mbedtls/error.h b/include/mbedtls/error.h index 4eb7b78eb..2fc9e46c1 100644 --- a/include/mbedtls/error.h +++ b/include/mbedtls/error.h @@ -79,7 +79,7 @@ * ECP 4 8 (Started from top) * MD 5 4 * CIPHER 6 6 - * SSL 6 17 (Started from top) + * SSL 6 21 (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 e98101e19..38538c7f1 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -109,6 +109,7 @@ #define MBEDTLS_ERR_SSL_UNEXPECTED_RECORD -0x6700 /**< Record header looks valid but is not expected. */ #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_ASYNC_IN_PROGRESS -0x6580 /**< Asynchronous operation is not completed yet */ /* * Various constants @@ -525,6 +526,160 @@ typedef void mbedtls_ssl_set_timer_t( void * ctx, */ typedef int mbedtls_ssl_get_timer_t( void * ctx ); +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) +#if defined(MBEDTLS_X509_CRT_PARSE_C) +/** + * \brief Callback type: start external signature operation + * + * Callback to start a signature operation using an + * external processor. The parameter \c cert contains + * the public key; it is up to the callback function to + * look up the associated private key or a handle to the + * private key. + * + * This function must start the signature operation. + * It is expected to be non-blocking, i.e. typically + * this function sends or enqueues a request and does + * not wait for the operation to complete. + * + * The parameters \c connection_ctx and \c cert are + * guaranteed to remain valid as long as the SSL + * configuration remains valid. On the other hand, this + * function must save the contents of \c hash, as the + * \c hash buffer is no longer valid when this function + * returns. + * + * \param connection_ctx Pointer to the connection context set in the + * SSL configuration + * \param p_operation_ctx On output, pointer to the operation context. + * This pointer will be passed later to the resume + * or detach function. The value is only used if + * an operation is started, i.e. if this callback + * returns 0 or \c MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS. + * \param cert Certificate containing the public key + * \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 SSL stack should call the resume callback + * immediately. The resume function may provide the + * or may itself return + * \c MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS. + * - \c MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS if the SSL stack + * should return immediately without calling the resume + * callback. + * - \c MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH if the external + * processor does not support this key. The SSL stack will + * use the associated private key object instead. + * - Any other error is propagated up the call chain. + */ +typedef int mbedtls_ssl_async_sign_t( void *connection_ctx, + void **p_operation_ctx, + 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 + * + * Callback to start a decryption operation using an + * external processor. The parameter \c cert contains + * the public key; it is up to the callback function to + * look up the associated private key or a handle to the + * private key. + * + * This function must start the decryption operation. + * It is expected to be non-blocking, i.e. typically + * this function sends or enqueues a request and does + * not wait for the operation to complete. + * + * The parameters \c connection_ctx and \c cert are + * guaranteed to remain valid as long as the SSL + * configuration remains valid. On the other hand, this + * function must save the contents of \c hash, as the + * \c hash buffer is no longer valid when this function + * returns. + * + * \param connection_ctx Pointer to the connection context set in the + * SSL configuration + * \param p_operation_ctx On output, pointer to the operation context. + * This pointer will be passed later to the resume + * or detach function. The value is only used if + * an operation is started, i.e. if this callback + * returns 0 or \c MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS. + * \param cert Certificate containing the public key + * \param input Buffer containing the input ciphertext. This buffer + * is no longer valid when the function returns. + * \param input_len Size of the \c input buffer in bytes + * + * \return - 0 if the SSL stack should call the resume callback + * immediately. The resume function may provide the + * or may itself return + * \c MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS. + * - \c MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS if the SSL stack + * should return immediately without calling the resume + * callback. + * - \c MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH if the external + * processor does not support this key. The SSL stack will + * use the associated private key object instead. + * - Any other error is propagated up the call chain. + */ +typedef int mbedtls_ssl_async_decrypt_t( void *connection_ctx, + void **p_operation_ctx, + mbedtls_x509_crt *cert, + const unsigned char *input, + size_t input_len ); +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +/** + * \brief Callback type: resume external operation + * + * Callback to resume an external operation + * started by the \c mbedtls_ssl_async_sign_t callback. + * + * \param connection_ctx Pointer to the connection context set in the + * SSL configuration + * \param operation_ctx Pointer to the operation context created by + * the start function. If this callback returns + * any value other than + * \c MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS, it should + * free all resources associated with this context. + * \param output Buffer containing the output on success + * \param output_len On success, number of bytes written to \c output + * \param output_size Size of the \c output buffer in bytes + * + * \return - 0 if output of the operation is available in the + * \c output buffer. + * - \c 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. + * - Any other error means that the operation is aborted. + * The SSL handshake is aborted. + */ +typedef int mbedtls_ssl_async_resume_t( void *connection_ctx, + void *operation_ctx, + unsigned char *output, + size_t *output_len, + size_t output_size ); + +/** + * \brief Callback type: cancel external operation + * + * Callback to cancel an external operation + * started by the \c mbedtls_ssl_async_sign_t callback. + * + * \param connection_ctx Pointer to the connection context set in the + * SSL configuration + * \param operation_ctx Pointer to the operation context created by + * the start function. The callback should free + * all resources associated with this context. + */ +typedef void mbedtls_ssl_async_cancel_t( void *connection_ctx, + void *operation_ctx ); +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ /* Defined below */ typedef struct mbedtls_ssl_session mbedtls_ssl_session; @@ -658,6 +813,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_C) +#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_connection_ctx; /*!< connection context for asynchronous operation callbacks */ +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ + #if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) const int *sig_hashes; /*!< allowed signature hashes */ #endif @@ -1291,6 +1456,40 @@ 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_C) +/** + * \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 \c mbedtls_ssl_async_sign_t + * for more information. This may be NULL if the + * external processor does no 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 \c mbedtls_ssl_async_decrypt_t + * for more information. This may be NULL if the + * external processor does no 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 \c mbedtls_ssl_async_resume_t + * for more information. + * \param f_async_cancel Callback to cancel an asynchronous operation. See + * the description of \c mbedtls_ssl_async_cancel_t + * for more information. + * \param connection_ctx Pointer to the connection context which will be + * passed to the callbacks + */ +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 *connection_ctx ); +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ + /** * \brief Callback type: generate a cookie * diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h index f990243ee..c141e8adc 100644 --- a/include/mbedtls/ssl_internal.h +++ b/include/mbedtls/ssl_internal.h @@ -218,6 +218,10 @@ 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_ASYNC_PRIVATE_C) + void *p_async_operation_ctx; /*!< asynchronous operation context */ +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_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 */ diff --git a/library/error.c b/library/error.c index 151ca4eae..490a04058 100644 --- a/library/error.c +++ b/library/error.c @@ -441,6 +441,8 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen ) mbedtls_snprintf( buf, buflen, "SSL - The alert message received indicates a non-fatal error" ); if( use_ret == -(MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH) ) mbedtls_snprintf( buf, buflen, "SSL - Couldn't set the hash for verifying CertificateVerify" ); + if( use_ret == -(MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS) ) + mbedtls_snprintf( buf, buflen, "SSL - 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_tls.c b/library/ssl_tls.c index 9482723b3..9626fa7a1 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -6399,6 +6399,23 @@ void mbedtls_ssl_conf_export_keys_cb( mbedtls_ssl_config *conf, } #endif +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) +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 *connection_ctx ) +{ + 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_connection_ctx = connection_ctx; +} +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ + /* * SSL get accessors */ @@ -7332,6 +7349,15 @@ void mbedtls_ssl_handshake_free( const mbedtls_ssl_config *conf, } #endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_SSL_SERVER_NAME_INDICATION */ +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) + if( conf->f_async_cancel != NULL && + handshake->p_async_operation_ctx != NULL ) + { + conf->f_async_cancel( conf->p_async_connection_ctx, + handshake->p_async_operation_ctx ); + } +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ + #if defined(MBEDTLS_SSL_PROTO_DTLS) mbedtls_free( handshake->verify_cookie ); mbedtls_free( handshake->hs_msg ); diff --git a/library/version_features.c b/library/version_features.c index 49bba11ef..7152e702b 100644 --- a/library/version_features.c +++ b/library/version_features.c @@ -615,6 +615,9 @@ static const char *features[] = { #if defined(MBEDTLS_SHA512_C) "MBEDTLS_SHA512_C", #endif /* MBEDTLS_SHA512_C */ +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) + "MBEDTLS_SSL_ASYNC_PRIVATE_C", +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ #if defined(MBEDTLS_SSL_CACHE_C) "MBEDTLS_SSL_CACHE_C", #endif /* MBEDTLS_SSL_CACHE_C */ From 9eb5e9a16ea7a5f639bb948ac6089457c5fcf6c2 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 5 Jan 2018 21:15:57 +0100 Subject: [PATCH 05/69] SSL asynchronous private key operation callbacks: test server New options in ssl_server2 to use the asynchronous private key operation feature. Features: resume delay to call resume more than once; error injection at each stage; renegotiation support. --- programs/ssl/ssl_server2.c | 259 +++++++++++++++++++++++++++++++++++-- 1 file changed, 248 insertions(+), 11 deletions(-) diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index 1285abcbd..d75338fe2 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -108,6 +108,9 @@ int main( void ) #define DFL_KEY_FILE "" #define DFL_CRT_FILE2 "" #define DFL_KEY_FILE2 "" +#define DFL_ASYNC_PRIVATE_DELAY1 ( -1 ) +#define DFL_ASYNC_PRIVATE_DELAY2 ( -1 ) +#define DFL_ASYNC_PRIVATE_ERROR ( -1 ) #define DFL_PSK "" #define DFL_PSK_IDENTITY "Client_identity" #define DFL_ECJPAKE_PW NULL @@ -195,6 +198,16 @@ int main( void ) #define USAGE_IO "" #endif /* MBEDTLS_X509_CRT_PARSE_C */ +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) +#define USAGE_SSL_ASYNC \ + " async_private_delay1=%%d Asynchronous delay for key_file or preloaded key\n" \ + " async_private_delay2=%%d Asynchronous delay for key_file2\n" \ + " default: -1 (not asynchronous)\n" \ + " async_private_error=%%d Async callback error injection (default=0=none, 1=start, 2=cancel, 3=resume, 4=pk)" +#else +#define USAGE_SSL_ASYNC "" +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ + #if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) #define USAGE_PSK \ " psk=%%s default: \"\" (in hex, without 0x)\n" \ @@ -343,6 +356,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 \ @@ -406,6 +420,9 @@ 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 */ + 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 */ @@ -837,6 +854,150 @@ static int ssl_sig_hashes_for_test[] = { }; #endif /* MBEDTLS_X509_CRT_PARSE_C */ +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) +typedef struct +{ + mbedtls_x509_crt *cert; + mbedtls_pk_context *pk; + unsigned delay; +} ssl_async_key_slot_t; + +typedef enum { + SSL_ASYNC_INJECT_ERROR_NONE = 0, + SSL_ASYNC_INJECT_ERROR_START, + SSL_ASYNC_INJECT_ERROR_CANCEL, + SSL_ASYNC_INJECT_ERROR_RESUME, + SSL_ASYNC_INJECT_ERROR_PK +#define SSL_ASYNC_INJECT_ERROR_MAX SSL_ASYNC_INJECT_ERROR_PK +} ssl_async_inject_error_t; + +typedef struct +{ + ssl_async_key_slot_t slots[2]; + 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; + +void ssl_async_set_key( ssl_async_key_context_t *ctx, + mbedtls_x509_crt *cert, + mbedtls_pk_context *pk, + unsigned delay ) +{ + ctx->slots[ctx->slots_used].cert = cert; + ctx->slots[ctx->slots_used].pk = pk; + ctx->slots[ctx->slots_used].delay = delay; + ++ctx->slots_used; +} + +typedef struct +{ + size_t slot; + mbedtls_md_type_t md_alg; + unsigned char hash[MBEDTLS_MD_MAX_SIZE]; + size_t hash_len; + unsigned delay; +} ssl_async_operation_context_t; + +int ssl_async_sign( void *connection_ctx_arg, + void **p_operation_ctx, + mbedtls_x509_crt *cert, + mbedtls_md_type_t md_alg, + const unsigned char *hash, + size_t hash_len ) +{ + ssl_async_key_context_t *key_ctx = connection_ctx_arg; + size_t slot; + ssl_async_operation_context_t *ctx = NULL; + { + char dn[100]; + mbedtls_x509_dn_gets( dn, sizeof( dn ), &cert->subject ); + mbedtls_printf( "Async sign callback: looking for DN=%s\n", dn ); + } + for( slot = 0; slot < key_ctx->slots_used; slot++ ) + { + if( key_ctx->slots[slot].cert == cert ) + break; + } + if( slot == key_ctx->slots_used ) + { + mbedtls_printf( "Async sign callback: no key matches this certificate.\n" ); + return( MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH ); + } + mbedtls_printf( "Async sign callback: using key slot %zd, delay=%u.\n", + slot, key_ctx->slots[slot].delay ); + if( key_ctx->inject_error == SSL_ASYNC_INJECT_ERROR_START ) + { + mbedtls_printf( "Async sign callback: injected error\n" ); + return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); + } + if( hash_len > MBEDTLS_MD_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->md_alg = md_alg; + memcpy( ctx->hash, hash, hash_len ); + ctx->hash_len = hash_len; + ctx->delay = key_ctx->slots[slot].delay; + *p_operation_ctx = ctx; + if( ctx->delay == 0 ) + return( 0 ); + else + return( MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ); +} + +int ssl_async_resume( void *connection_ctx_arg, + void *operation_ctx_arg, + unsigned char *output, + size_t *output_len, + size_t output_size ) +{ + ssl_async_operation_context_t *ctx = operation_ctx_arg; + ssl_async_key_context_t *connection_ctx = connection_ctx_arg; + ssl_async_key_slot_t *key_slot = &connection_ctx->slots[ctx->slot]; + int ret; + if( connection_ctx->inject_error == SSL_ASYNC_INJECT_ERROR_RESUME ) + { + mbedtls_printf( "Async resume callback: injected error\n" ); + return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); + } + if( ctx->delay > 0 ) + { + --ctx->delay; + mbedtls_printf( "Async resume (slot %zd): call %u more times.\n", + ctx->slot, ctx->delay ); + return( MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ); + } + (void) output_size; /* mbedtls_pk_size lacks this parameter */ + ret = mbedtls_pk_sign( key_slot->pk, + ctx->md_alg, + ctx->hash, ctx->hash_len, + output, output_len, + connection_ctx->f_rng, connection_ctx->p_rng ); + if( connection_ctx->inject_error == SSL_ASYNC_INJECT_ERROR_PK ) + { + mbedtls_printf( "Async resume callback: done but injected error\n" ); + return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); + } + mbedtls_printf( "Async resume (slot %zd): done, status=%d.\n", + ctx->slot, ret ); + mbedtls_free( ctx ); + return( ret ); +} + +void ssl_async_cancel( void *connection_ctx_arg, + void *operation_ctx_arg ) +{ + ssl_async_operation_context_t *ctx = operation_ctx_arg; + (void) connection_ctx_arg; + mbedtls_printf( "Async cancel callback.\n" ); + mbedtls_free( ctx ); +} +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ + int main( int argc, char *argv[] ) { int ret = 0, len, written, frags, exchanges_left; @@ -875,7 +1036,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_C) + ssl_async_key_context_t ssl_async_keys; +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ +#endif /* MBEDTLS_X509_CRT_PARSE_C */ #if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_FS_IO) mbedtls_dhm_context dhm; #endif @@ -977,6 +1141,9 @@ 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_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; @@ -1063,6 +1230,22 @@ 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_C) + 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 < 0 || n > SSL_ASYNC_INJECT_ERROR_MAX ) + { + ret = 2; + goto usage; + } + opt.async_private_error = n; + } +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ else if( strcmp( p, "psk" ) == 0 ) opt.psk = q; else if( strcmp( p, "psk_identity" ) == 0 ) @@ -1932,18 +2115,55 @@ 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_C) + if( opt.async_private_delay1 >= 0 ) + { + ssl_async_set_key( &ssl_async_keys, &srvcert, pk, + opt.async_private_delay1 ); + pk = NULL; + } +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ + 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_C) + if( opt.async_private_delay2 >= 0 ) + { + ssl_async_set_key( &ssl_async_keys, &srvcert2, pk, + opt.async_private_delay2 ); + pk = NULL; + } +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ + 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_C) + if( opt.async_private_delay1 >= 0 || opt.async_private_delay2 >= 0 ) + { + ssl_async_keys.inject_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, + ssl_async_sign, + NULL, + ssl_async_resume, + ssl_async_cancel, + &ssl_async_keys ); + } +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ +#endif /* MBEDTLS_X509_CRT_PARSE_C */ #if defined(SNI_OPTION) if( opt.sni != NULL ) @@ -2113,9 +2333,21 @@ handshake: mbedtls_printf( " . Performing the SSL/TLS handshake..." ); fflush( stdout ); - do ret = mbedtls_ssl_handshake( &ssl ); + do + { + ret = mbedtls_ssl_handshake( &ssl ); +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) + if( ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS && + opt.async_private_error == SSL_ASYNC_INJECT_ERROR_CANCEL ) + { + mbedtls_printf( " cancelling on injected error\n" ); + goto reset; + } +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ + } while( ret == MBEDTLS_ERR_SSL_WANT_READ || - ret == MBEDTLS_ERR_SSL_WANT_WRITE ); + ret == MBEDTLS_ERR_SSL_WANT_WRITE || + ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ); if( ret == MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED ) { @@ -2220,7 +2452,8 @@ data_exchange: ret = mbedtls_ssl_read( &ssl, buf, len ); if( ret == MBEDTLS_ERR_SSL_WANT_READ || - ret == MBEDTLS_ERR_SSL_WANT_WRITE ) + ret == MBEDTLS_ERR_SSL_WANT_WRITE || + ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ) continue; if( ret <= 0 ) @@ -2311,7 +2544,8 @@ data_exchange: do ret = mbedtls_ssl_read( &ssl, buf, len ); while( ret == MBEDTLS_ERR_SSL_WANT_READ || - ret == MBEDTLS_ERR_SSL_WANT_WRITE ); + ret == MBEDTLS_ERR_SSL_WANT_WRITE || + ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ); if( ret <= 0 ) { @@ -2347,7 +2581,8 @@ data_exchange: while( ( ret = mbedtls_ssl_renegotiate( &ssl ) ) != 0 ) { if( ret != MBEDTLS_ERR_SSL_WANT_READ && - ret != MBEDTLS_ERR_SSL_WANT_WRITE ) + ret != MBEDTLS_ERR_SSL_WANT_WRITE && + ret != MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ) { mbedtls_printf( " failed\n ! mbedtls_ssl_renegotiate returned %d\n\n", ret ); goto reset; @@ -2381,7 +2616,8 @@ data_exchange: } if( ret != MBEDTLS_ERR_SSL_WANT_READ && - ret != MBEDTLS_ERR_SSL_WANT_WRITE ) + ret != MBEDTLS_ERR_SSL_WANT_WRITE && + ret != MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ) { mbedtls_printf( " failed\n ! mbedtls_ssl_write returned %d\n\n", ret ); goto reset; @@ -2393,7 +2629,8 @@ data_exchange: { do ret = mbedtls_ssl_write( &ssl, buf, len ); while( ret == MBEDTLS_ERR_SSL_WANT_READ || - ret == MBEDTLS_ERR_SSL_WANT_WRITE ); + ret == MBEDTLS_ERR_SSL_WANT_WRITE || + ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ); if( ret < 0 ) { From e198df53a070da3e29707fd16c5736811a2b1415 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 5 Jan 2018 21:17:45 +0100 Subject: [PATCH 06/69] ssl_pick_cert: use the public key for can_do This is in preparation for support of external private key operations, where there is no private key object. --- library/ssl_srv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 70fe13d79..2034d75f3 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -707,7 +707,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; From e1efdf912f9f2d8a1ff9704454615de1dc1716fc Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 5 Jan 2018 21:18:37 +0100 Subject: [PATCH 07/69] ssl_write_server_key_exchange: don't hard-code max hash size --- library/ssl_srv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 2034d75f3..bc94ebb98 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -3032,7 +3032,7 @@ curve_matching_done: { size_t signature_len = 0; unsigned int hashlen = 0; - unsigned char hash[64]; + unsigned char hash[MBEDTLS_MD_MAX_SIZE]; /* * 3.1: Choose hash algorithm: From ebd652fe2dfc2c82d774bfd334398279d9027492 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 5 Jan 2018 21:18:59 +0100 Subject: [PATCH 08/69] ssl_write_server_key_exchange: calculate hashlen explicitly The pk layer can infer the hash length from the hash type. Calculate it explicitly here anyway because it's needed for debugging purposes, and it's needed for the upcoming feature allowing the signature operation to be offloaded to an external cryptographic processor, as the offloading code will need to know what length hash to copy. --- library/ssl_srv.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/library/ssl_srv.c b/library/ssl_srv.c index bc94ebb98..84c8e1e11 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -3135,8 +3135,7 @@ curve_matching_done: mbedtls_md_init( &ctx ); - /* Info from md_alg will be used instead */ - hashlen = 0; + hashlen = mbedtls_md_get_size( md_info ); /* * digitally-signed struct { @@ -3165,8 +3164,7 @@ 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 From 4bf9a28d1df0adf88456044684dd0f3c94a87b79 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 5 Jan 2018 21:20:50 +0100 Subject: [PATCH 09/69] SSL asynchronous signature: first implementation Implement SSL asynchronous private operation for the case of a signature operation in a server. This is a first implementation. It is functional, but the code is not clean, with heavy reliance on goto. --- include/mbedtls/ssl_internal.h | 1 + library/ssl_srv.c | 67 +++++++++++++++++++++++++++++++--- 2 files changed, 62 insertions(+), 6 deletions(-) diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h index c141e8adc..e4b767b7b 100644 --- a/include/mbedtls/ssl_internal.h +++ b/include/mbedtls/ssl_internal.h @@ -220,6 +220,7 @@ struct mbedtls_ssl_handshake_params #endif /* MBEDTLS_X509_CRT_PARSE_C */ #if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) void *p_async_operation_ctx; /*!< asynchronous operation context */ + unsigned char *out_async_start; /*!< pointer where the asynchronous operation must write in the output buffer */ #endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ #if defined(MBEDTLS_SSL_PROTO_DTLS) diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 84c8e1e11..ac9e6a55d 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -2843,6 +2843,17 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write server key exchange" ) ); +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) && \ + defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) + if( ssl->handshake->out_async_start != NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "resuming signature operation" ) ); + p = ssl->handshake->out_async_start; + goto async_resume; + } +#endif /* defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) && + defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) */ + /* * * Part 1: Extract static ECDH parameters and abort @@ -3169,12 +3180,6 @@ curve_matching_done: /* * 3.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 ) { @@ -3199,6 +3204,55 @@ curve_matching_done: } #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) + if( ssl->conf->f_async_sign_start != NULL ) + { + size_t sig_max_len = ( ssl->out_buf + MBEDTLS_SSL_MAX_CONTENT_LEN + - ( p + 2 ) ); + ret = ssl->conf->f_async_sign_start( + ssl->conf->p_async_connection_ctx, + &ssl->handshake->p_async_operation_ctx, + 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: + async_resume: + ret = ssl->conf->f_async_resume( + ssl->conf->p_async_connection_ctx, + ssl->handshake->p_async_operation_ctx, + p + 2, &signature_len, sig_max_len ); + if( ret != MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ) + { + ssl->handshake->p_async_operation_ctx = NULL; + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "f_async_resume", ret ); + return( ret ); + } + goto have_signature; + } + /* FALLTHROUGH */ + case MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS: + ssl->handshake->out_async_start = p; + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server key exchange (pending)" ) ); + return( MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ); + default: + MBEDTLS_SSL_DEBUG_RET( 1, "f_async_sign", ret ); + return( ret ); + } + } +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ + + if( mbedtls_ssl_own_key( ssl ) == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no private key" ) ); + return( MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED ); + } + 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 ) { @@ -3206,6 +3260,7 @@ curve_matching_done: return( ret ); } + have_signature: *(p++) = (unsigned char)( signature_len >> 8 ); *(p++) = (unsigned char)( signature_len ); From 3665f1db9db40b5ff0ea5a10d91a0e899f432e9d Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 5 Jan 2018 21:22:12 +0100 Subject: [PATCH 10/69] SSL asynchronous signature: test cases Add test cases for SSL asynchronous signature to ssl-opt.sh: * Delay=0,1 to test the sequences of calls to f_async_resume * Test fallback when the async callbacks don't support that key * Test error injection at each stage * Test renegotiation --- programs/ssl/ssl_server2.c | 2 +- tests/ssl-opt.sh | 121 +++++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+), 1 deletion(-) diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index d75338fe2..28f636751 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -110,7 +110,7 @@ int main( void ) #define DFL_KEY_FILE2 "" #define DFL_ASYNC_PRIVATE_DELAY1 ( -1 ) #define DFL_ASYNC_PRIVATE_DELAY2 ( -1 ) -#define DFL_ASYNC_PRIVATE_ERROR ( -1 ) +#define DFL_ASYNC_PRIVATE_ERROR ( 0 ) #define DFL_PSK "" #define DFL_PSK_IDENTITY "Client_identity" #define DFL_ECJPAKE_PW NULL diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index fa785a4f1..5f23cd1df 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -3636,6 +3636,127 @@ 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_C +run_test "SSL async private: delay=0" \ + "$P_SRV async_private_delay1=0 async_private_delay2=0" \ + "$P_CLI" \ + 0 \ + -s "Async sign callback: using key slot " \ + -s "Async resume (slot [0-9]): done, status=0" + +requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C +run_test "SSL async private: delay=1" \ + "$P_SRV 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]): done, status=0" + +# key1: ECDSA, key2: RSA; use key1 from slot 0 +requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C +run_test "SSL async private: slot 0 used with key1" \ + "$P_SRV key_file=data_files/server5.key crt_file=data_files/server5.crt \ + key_file2=data_files/server2.key crt_file2=data_files/server2.crt \ + async_private_delay1=1" \ + "$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): done, status=0" + +# key1: ECDSA, key2: RSA; use key2 from slot 0 +requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C +run_test "SSL async private: slot 0 used with key2" \ + "$P_SRV key_file=data_files/server5.key crt_file=data_files/server5.crt \ + key_file2=data_files/server2.key crt_file2=data_files/server2.crt \ + async_private_delay2=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 (slot 0): call 0 more times." \ + -s "Async resume (slot 0): done, status=0" + +# key1: ECDSA, key2: RSA; use key2 from slot 1 +requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C +run_test "SSL async private: slot 1 used" \ + "$P_SRV key_file=data_files/server5.key crt_file=data_files/server5.crt \ + key_file2=data_files/server2.key crt_file2=data_files/server2.crt \ + async_private_delay1=1 async_private_delay2=1" \ + "$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): done, status=0" + +# key1: ECDSA, key2: RSA; use key2 directly +requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C +run_test "SSL async private: fall back to transparent key" \ + "$P_SRV key_file=data_files/server5.key crt_file=data_files/server5.crt \ + key_file2=data_files/server2.key crt_file2=data_files/server2.crt \ + async_private_delay1=1" \ + "$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_C +run_test "SSL async private: error in start" \ + "$P_SRV 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 "! mbedtls_ssl_handshake returned" + +requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C +run_test "SSL async private: cancel after start" \ + "$P_SRV 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_C +run_test "SSL async private: error in resume" \ + "$P_SRV 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: injected error" \ + -s "! mbedtls_ssl_handshake returned" + +requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C +run_test "SSL async private: error in pk" \ + "$P_SRV async_private_delay1=1 async_private_delay2=1 async_private_error=4" \ + "$P_CLI" \ + 1 \ + -s "Async sign callback: using key slot " \ + -s "Async resume callback: done but injected error" \ + -s "! mbedtls_ssl_handshake returned" + +requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C +requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +run_test "SSL async private: renegotiation: client-initiated" \ + "$P_SRV 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]): done, status=0" + +requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C +requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +run_test "SSL async private: renegotiation: server-initiated" \ + "$P_SRV 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]): done, status=0" + # Tests for DTLS HelloVerifyRequest run_test "DTLS cookie: enabled" \ From 3ce9b900d262149518f2d3222f6a11c8542f629a Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Sat, 6 Jan 2018 01:34:21 +0100 Subject: [PATCH 11/69] ssl_write_server_key_exchange refactor: remove dig_signed_len Simplify the redundant varaible dig_signed_len away. This is in preparation for splitting ssl_write_server_key_exchange into several functions. --- library/ssl_srv.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/library/ssl_srv.c b/library/ssl_srv.c index ac9e6a55d..daebb9e94 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -2836,8 +2836,7 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) #if defined(MBEDTLS_KEY_EXCHANGE__SOME_PFS__ENABLED) 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 */ @@ -2961,7 +2960,6 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) #if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) dig_signed = p; - dig_signed_len = len; #endif p += len; @@ -3022,8 +3020,7 @@ curve_matching_done: } #if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) - dig_signed = p; - dig_signed_len = len; + dig_signed = p; #endif p += len; @@ -3041,6 +3038,7 @@ curve_matching_done: #if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) if( mbedtls_ssl_ciphersuite_uses_server_signature( ciphersuite_info ) ) { + size_t dig_signed_len = p - dig_signed; size_t signature_len = 0; unsigned int hashlen = 0; unsigned char hash[MBEDTLS_MD_MAX_SIZE]; From 184a3faa8ad1a5264dca11dd7a8a01e73295af8f Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Sat, 6 Jan 2018 01:46:17 +0100 Subject: [PATCH 12/69] ssl_write_server_key_exchange refactor: create ssl_prepare_server_key_exchange This is in the process of splitting ssl_write_server_key_exchange into several functions. --- library/ssl_srv.c | 87 +++++++++++++++++++++++++++-------------------- 1 file changed, 51 insertions(+), 36 deletions(-) diff --git a/library/ssl_srv.c b/library/ssl_srv.c index daebb9e94..d87663d99 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -2826,9 +2826,8 @@ 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 ) +static int ssl_prepare_server_key_exchange( mbedtls_ssl_context *ssl ) { - int ret; const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; @@ -2839,6 +2838,7 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) unsigned char *dig_signed = NULL; #endif /* MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED */ #endif /* MBEDTLS_KEY_EXCHANGE__SOME_PFS__ENABLED */ + (void) ciphersuite_info; /* unused in some configurations */ MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write server key exchange" ) ); @@ -2855,34 +2855,7 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) /* * - * 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. * */ @@ -2892,6 +2865,7 @@ 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 ) { + int ret; const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; ret = mbedtls_ecjpake_write_round_two( &ssl->handshake->ecjpake_ctx, @@ -2928,6 +2902,8 @@ 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; + if( ssl->conf->dhm_P.p == NULL || ssl->conf->dhm_G.p == NULL ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "no DH parameters set" ) ); @@ -2987,6 +2963,7 @@ 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; /* Match our preference list against the offered curves */ for( gid = ssl->conf->curve_list; *gid != MBEDTLS_ECP_DP_NONE; gid++ ) @@ -3031,7 +3008,7 @@ 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. * */ @@ -3042,9 +3019,10 @@ curve_matching_done: size_t signature_len = 0; unsigned int 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 @@ -3091,7 +3069,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) @@ -3176,7 +3154,7 @@ curve_matching_done: MBEDTLS_SSL_DEBUG_BUF( 3, "parameters hash", hash, hashlen ); /* - * 3.3: Compute and add the signature + * 2.3: Compute and add the signature */ #if defined(MBEDTLS_SSL_PROTO_TLS1_2) if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) @@ -3258,7 +3236,9 @@ curve_matching_done: return( ret ); } +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) have_signature: +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ *(p++) = (unsigned char)( signature_len >> 8 ); *(p++) = (unsigned char)( signature_len ); @@ -3268,9 +3248,44 @@ curve_matching_done: } #endif /* MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED */ - /* Done with actual work; add header and send. */ - ssl->out_msglen = p - ssl->out_msg; + return( 0 ); +} + +static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) +{ + int ret; + /* Extract static ECDH parameters and abort if ServerKeyExchange + * is not needed. */ +#if defined(MBEDTLS_KEY_EXCHANGE__SOME_NON_PFS__ENABLED) + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = + ssl->transform_negotiate->ciphersuite_info; + + 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__NON_PFS__ENABLED */ + + /* ServerKeyExchange is needed. Prepare the message. */ + ret = ssl_prepare_server_key_exchange( ssl ); + if( ret != 0 ) + return( ret ); + + /* Add header and send. */ ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; ssl->out_msg[0] = MBEDTLS_SSL_HS_SERVER_KEY_EXCHANGE; From 1004c19ed0a67c4bdbc4635dcd6814817360338e Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 8 Jan 2018 16:59:14 +0100 Subject: [PATCH 13/69] ssl_write_server_key_exchange refactor: don't use p in the signing phase This is in preparation of further splitting ssl_write_server_key_exchange into several functions. --- library/ssl_srv.c | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/library/ssl_srv.c b/library/ssl_srv.c index d87663d99..6c2059b62 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -3006,6 +3006,8 @@ curve_matching_done: } #endif /* MBEDTLS_KEY_EXCHANGE__SOME__ECDHE_ENABLED */ + ssl->out_msglen = p - ssl->out_msg; + /* * * Part 2: For key exchanges involving the server signing the @@ -3015,7 +3017,7 @@ curve_matching_done: #if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) if( mbedtls_ssl_ciphersuite_uses_server_signature( ciphersuite_info ) ) { - size_t dig_signed_len = p - dig_signed; + size_t dig_signed_len = ssl->out_msg + ssl->out_msglen - dig_signed; size_t signature_len = 0; unsigned int hashlen = 0; unsigned char hash[MBEDTLS_MD_MAX_SIZE]; @@ -3175,8 +3177,10 @@ curve_matching_done: * */ - *(p++) = mbedtls_ssl_hash_from_md_alg( md_alg ); - *(p++) = mbedtls_ssl_sig_from_pk_alg( sig_alg ); + 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 */ @@ -3184,7 +3188,7 @@ curve_matching_done: if( ssl->conf->f_async_sign_start != NULL ) { size_t sig_max_len = ( ssl->out_buf + MBEDTLS_SSL_MAX_CONTENT_LEN - - ( p + 2 ) ); + - ( ssl->out_msg + ssl->out_msglen + 2 ) ); ret = ssl->conf->f_async_sign_start( ssl->conf->p_async_connection_ctx, &ssl->handshake->p_async_operation_ctx, @@ -3200,7 +3204,8 @@ curve_matching_done: ret = ssl->conf->f_async_resume( ssl->conf->p_async_connection_ctx, ssl->handshake->p_async_operation_ctx, - p + 2, &signature_len, sig_max_len ); + ssl->out_msg + ssl->out_msglen + 2, + &signature_len, sig_max_len ); if( ret != MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ) { ssl->handshake->p_async_operation_ctx = NULL; @@ -3213,7 +3218,7 @@ curve_matching_done: } /* FALLTHROUGH */ case MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS: - ssl->handshake->out_async_start = p; + ssl->handshake->out_async_start = ssl->out_msg + ssl->out_msglen; MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server key exchange (pending)" ) ); return( MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ); default: @@ -3229,8 +3234,12 @@ curve_matching_done: return( MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED ); } - 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( ( 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 ); @@ -3239,22 +3248,24 @@ curve_matching_done: #if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) have_signature: #endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ - *(p++) = (unsigned char)( signature_len >> 8 ); - *(p++) = (unsigned char)( signature_len ); + 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", p, signature_len ); + MBEDTLS_SSL_DEBUG_BUF( 3, "my signature", + ssl->out_msg + ssl->out_msglen, + signature_len ); - p += signature_len; + ssl->out_msglen += signature_len; } #endif /* MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED */ - ssl->out_msglen = p - ssl->out_msg; return( 0 ); } static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) { int ret; + /* Extract static ECDH parameters and abort if ServerKeyExchange * is not needed. */ #if defined(MBEDTLS_KEY_EXCHANGE__SOME_NON_PFS__ENABLED) From 7ab013a08a729dab0c43dfa860c8218b94ca83eb Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 8 Jan 2018 17:04:16 +0100 Subject: [PATCH 14/69] ssl_write_server_key_exchange refactor: move signature_len out Move the writing of signature_len out of ssl_prepare_server_key_exchange. This simplifies the control flow (one less goto). --- library/ssl_srv.c | 50 +++++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 6c2059b62..daf87b96c 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -2826,7 +2826,8 @@ 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_prepare_server_key_exchange( mbedtls_ssl_context *ssl ) +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; @@ -2839,6 +2840,7 @@ static int ssl_prepare_server_key_exchange( mbedtls_ssl_context *ssl ) #endif /* MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED */ #endif /* MBEDTLS_KEY_EXCHANGE__SOME_PFS__ENABLED */ (void) ciphersuite_info; /* unused in some configurations */ + (void) signature_len; /* unused in some configurations */ MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write server key exchange" ) ); @@ -3018,7 +3020,6 @@ curve_matching_done: if( mbedtls_ssl_ciphersuite_uses_server_signature( ciphersuite_info ) ) { size_t dig_signed_len = ssl->out_msg + ssl->out_msglen - dig_signed; - size_t signature_len = 0; unsigned int hashlen = 0; unsigned char hash[MBEDTLS_MD_MAX_SIZE]; int ret; @@ -3205,16 +3206,12 @@ curve_matching_done: ssl->conf->p_async_connection_ctx, ssl->handshake->p_async_operation_ctx, ssl->out_msg + ssl->out_msglen + 2, - &signature_len, sig_max_len ); + signature_len, sig_max_len ); if( ret != MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ) { ssl->handshake->p_async_operation_ctx = NULL; - if( ret != 0 ) - { - MBEDTLS_SSL_DEBUG_RET( 1, "f_async_resume", ret ); - return( ret ); - } - goto have_signature; + MBEDTLS_SSL_DEBUG_RET( 1, "f_async_resume", ret ); + return( ret ); } /* FALLTHROUGH */ case MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS: @@ -3237,25 +3234,13 @@ curve_matching_done: if( ( ret = mbedtls_pk_sign( mbedtls_ssl_own_key( ssl ), md_alg, hash, hashlen, ssl->out_msg + ssl->out_msglen + 2, - &signature_len, + signature_len, ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_sign", ret ); return( ret ); } - -#if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) - have_signature: -#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ - 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 ); - - ssl->out_msglen += signature_len; } #endif /* MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED */ @@ -3265,6 +3250,7 @@ curve_matching_done: static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) { int ret; + size_t signature_len = 0; /* Extract static ECDH parameters and abort if ServerKeyExchange * is not needed. */ @@ -3292,10 +3278,28 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) #endif /* MBEDTLS_KEY_EXCHANGE__NON_PFS__ENABLED */ /* ServerKeyExchange is needed. Prepare the message. */ - ret = ssl_prepare_server_key_exchange( ssl ); + ret = ssl_prepare_server_key_exchange( ssl, &signature_len ); if( ret != 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; From ab50f83a93b07fb0bb82ecdfcf4d8565229e9173 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Sat, 6 Jan 2018 03:12:45 +0100 Subject: [PATCH 15/69] Improve documentation of async operation start callbacks --- include/mbedtls/ssl.h | 58 ++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 38538c7f1..d895f3acf 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -551,28 +551,29 @@ typedef int mbedtls_ssl_get_timer_t( void * ctx ); * * \param connection_ctx Pointer to the connection context set in the * SSL configuration - * \param p_operation_ctx On output, pointer to the operation context. - * This pointer will be passed later to the resume - * or detach function. The value is only used if - * an operation is started, i.e. if this callback - * returns 0 or \c MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS. + * \param p_operation_ctx On success, pointer to the operation context. + * This must be a non-null pointer. Success means + * that an operation was started, and the return + * status is 0 or \c MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS. + * This pointer will be passed to later calls to the + * resume or cancel function. If the callback fails, + * the value is ignored. * \param cert Certificate containing the public key * \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 SSL stack should call the resume callback - * immediately. The resume function may provide the - * or may itself return - * \c MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS. - * - \c MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS if the SSL stack - * should return immediately without calling the resume - * callback. + * \return - 0 if the operation was started successfully and the SSL + * stack should call the resume callback immediately. + * - \c 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. * - \c MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH if the external * processor does not support this key. The SSL stack will - * use the associated private key object instead. - * - Any other error is propagated up the call chain. + * use the private key object instead. + * - Any other error indicates a fatal failure and is + * propagated up the call chain. */ typedef int mbedtls_ssl_async_sign_t( void *connection_ctx, void **p_operation_ctx, @@ -604,27 +605,28 @@ typedef int mbedtls_ssl_async_sign_t( void *connection_ctx, * * \param connection_ctx Pointer to the connection context set in the * SSL configuration - * \param p_operation_ctx On output, pointer to the operation context. - * This pointer will be passed later to the resume - * or detach function. The value is only used if - * an operation is started, i.e. if this callback - * returns 0 or \c MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS. + * \param p_operation_ctx On success, pointer to the operation context. + * This must be a non-null pointer. Success means + * that an operation was started, and the return + * status is 0 or \c MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS. + * This pointer will be passed to later calls to the + * resume or cancel function. If the callback fails, + * the value is ignored. * \param cert Certificate containing the public key * \param input Buffer containing the input ciphertext. This buffer * is no longer valid when the function returns. * \param input_len Size of the \c input buffer in bytes * - * \return - 0 if the SSL stack should call the resume callback - * immediately. The resume function may provide the - * or may itself return - * \c MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS. - * - \c MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS if the SSL stack - * should return immediately without calling the resume - * callback. + * \return - 0 if the operation was started successfully and the SSL + * stack should call the resume callback immediately. + * - \c 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. * - \c MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH if the external * processor does not support this key. The SSL stack will - * use the associated private key object instead. - * - Any other error is propagated up the call chain. + * use the private key object instead. + * - Any other error indicates a fatal failure and is + * propagated up the call chain. */ typedef int mbedtls_ssl_async_decrypt_t( void *connection_ctx, void **p_operation_ctx, From d04d292b64865b1316d4c3117a2cc3104404e90c Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Sat, 6 Jan 2018 03:13:12 +0100 Subject: [PATCH 16/69] Get rid of useless handshake field out_async_start The location where the signature goes is now tracked via ssl->out_msglen, which makes ssl->handshake->out_async_start redundant. --- include/mbedtls/ssl_internal.h | 1 - library/ssl_srv.c | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h index e4b767b7b..c141e8adc 100644 --- a/include/mbedtls/ssl_internal.h +++ b/include/mbedtls/ssl_internal.h @@ -220,7 +220,6 @@ struct mbedtls_ssl_handshake_params #endif /* MBEDTLS_X509_CRT_PARSE_C */ #if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) void *p_async_operation_ctx; /*!< asynchronous operation context */ - unsigned char *out_async_start; /*!< pointer where the asynchronous operation must write in the output buffer */ #endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ #if defined(MBEDTLS_SSL_PROTO_DTLS) diff --git a/library/ssl_srv.c b/library/ssl_srv.c index daf87b96c..f6db3c715 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -2846,10 +2846,9 @@ static int ssl_prepare_server_key_exchange( mbedtls_ssl_context *ssl, #if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) && \ defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) - if( ssl->handshake->out_async_start != NULL ) + if( ssl->handshake->p_async_operation_ctx != NULL ) { MBEDTLS_SSL_DEBUG_MSG( 2, ( "resuming signature operation" ) ); - p = ssl->handshake->out_async_start; goto async_resume; } #endif /* defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) && @@ -3215,7 +3214,6 @@ curve_matching_done: } /* FALLTHROUGH */ case MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS: - ssl->handshake->out_async_start = ssl->out_msg + ssl->out_msglen; MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server key exchange (pending)" ) ); return( MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ); default: From ebd30ae205b3d76ffd7101006a46e38a8ba09eea Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Sat, 6 Jan 2018 03:34:20 +0100 Subject: [PATCH 17/69] ssl_write_server_key_exchange refactor: ssl_resume_server_key_exchange Continue clarifying the control flow. This gets rid of the last goto introduced by the initial code for asynchronous signature support. --- library/ssl_srv.c | 71 ++++++++++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 29 deletions(-) diff --git a/library/ssl_srv.c b/library/ssl_srv.c index f6db3c715..da6069d84 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -2826,6 +2826,27 @@ 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 */ +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) && \ + defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) +static int ssl_resume_server_key_exchange( mbedtls_ssl_context *ssl, + size_t *signature_len ) +{ + size_t sig_max_len = ( ssl->out_buf + MBEDTLS_SSL_MAX_CONTENT_LEN + - ( ssl->out_msg + ssl->out_msglen + 2 ) ); + int ret = ssl->conf->f_async_resume( ssl->conf->p_async_connection_ctx, + ssl->handshake->p_async_operation_ctx, + ssl->out_msg + ssl->out_msglen + 2, + signature_len, sig_max_len ); + MBEDTLS_SSL_DEBUG_RET( 3, "f_async_resume", ret ); + if( ret != MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ) + { + ssl->handshake->p_async_operation_ctx = NULL; + } + return( ret ); +} +#endif /* defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) && + defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) */ + static int ssl_prepare_server_key_exchange( mbedtls_ssl_context *ssl, size_t *signature_len ) { @@ -2844,16 +2865,6 @@ static int ssl_prepare_server_key_exchange( mbedtls_ssl_context *ssl, MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write server key exchange" ) ); -#if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) && \ - defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) - if( ssl->handshake->p_async_operation_ctx != NULL ) - { - MBEDTLS_SSL_DEBUG_MSG( 2, ( "resuming signature operation" ) ); - goto async_resume; - } -#endif /* defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) && - defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) */ - /* * * Part 1: Provide key exchange parameters for chosen ciphersuite. @@ -3187,8 +3198,6 @@ curve_matching_done: #if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) if( ssl->conf->f_async_sign_start != NULL ) { - size_t sig_max_len = ( ssl->out_buf + MBEDTLS_SSL_MAX_CONTENT_LEN - - ( ssl->out_msg + ssl->out_msglen + 2 ) ); ret = ssl->conf->f_async_sign_start( ssl->conf->p_async_connection_ctx, &ssl->handshake->p_async_operation_ctx, @@ -3200,19 +3209,7 @@ curve_matching_done: /* act as if f_async_sign was null */ break; case 0: - async_resume: - ret = ssl->conf->f_async_resume( - ssl->conf->p_async_connection_ctx, - ssl->handshake->p_async_operation_ctx, - ssl->out_msg + ssl->out_msglen + 2, - signature_len, sig_max_len ); - if( ret != MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ) - { - ssl->handshake->p_async_operation_ctx = NULL; - MBEDTLS_SSL_DEBUG_RET( 1, "f_async_resume", ret ); - return( ret ); - } - /* FALLTHROUGH */ + return( ssl_resume_server_key_exchange( ssl, signature_len ) ); case MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS: MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server key exchange (pending)" ) ); return( MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ); @@ -3275,10 +3272,26 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) } #endif /* MBEDTLS_KEY_EXCHANGE__NON_PFS__ENABLED */ - /* ServerKeyExchange is needed. Prepare the message. */ - ret = ssl_prepare_server_key_exchange( ssl, &signature_len ); - if( ret != 0 ) - return( ret ); + /* If we have already prepared the message and there is an ongoing + signature operation, resume signing. */ +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) && \ + defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) + if( ssl->handshake->p_async_operation_ctx != NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "resuming signature operation" ) ); + ret = ssl_resume_server_key_exchange( ssl, &signature_len ); + if( ret != 0 ) + return( ret ); + } + else +#endif /* defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) && + defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) */ + { + /* ServerKeyExchange is needed. Prepare the message. */ + ret = ssl_prepare_server_key_exchange( ssl, &signature_len ); + if( ret != 0 ) + return( ret ); + } /* If there is a signature, write its length. ssl_prepare_server_key_exchange already wrote the signature From d3eb0619a6858798e1220b42c43e0487002cb34d Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 8 Jan 2018 17:07:44 +0100 Subject: [PATCH 18/69] ssl_write_server_key_exchange refactor: minor cleanup Clean up some debug messages and improve some comments. --- library/ssl_srv.c | 44 ++++++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/library/ssl_srv.c b/library/ssl_srv.c index da6069d84..415eaf8c9 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -2837,25 +2837,26 @@ static int ssl_resume_server_key_exchange( mbedtls_ssl_context *ssl, ssl->handshake->p_async_operation_ctx, ssl->out_msg + ssl->out_msglen + 2, signature_len, sig_max_len ); - MBEDTLS_SSL_DEBUG_RET( 3, "f_async_resume", ret ); if( ret != MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ) { ssl->handshake->p_async_operation_ctx = 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_C) */ +/* 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; - unsigned char *p = ssl->out_msg + 4; #if defined(MBEDTLS_KEY_EXCHANGE__SOME_PFS__ENABLED) - size_t len; #if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) unsigned char *dig_signed = NULL; #endif /* MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED */ @@ -2863,8 +2864,6 @@ static int ssl_prepare_server_key_exchange( mbedtls_ssl_context *ssl, (void) ciphersuite_info; /* unused in some configurations */ (void) signature_len; /* unused in some configurations */ - MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write server key exchange" ) ); - /* * * Part 1: Provide key exchange parameters for chosen ciphersuite. @@ -2879,6 +2878,7 @@ static int ssl_prepare_server_key_exchange( mbedtls_ssl_context *ssl, { int ret; const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + 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 ); @@ -2915,6 +2915,7 @@ static int ssl_prepare_server_key_exchange( mbedtls_ssl_context *ssl, 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 ) { @@ -2976,6 +2977,7 @@ static int ssl_prepare_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++ ) @@ -3211,7 +3213,6 @@ curve_matching_done: case 0: return( ssl_resume_server_key_exchange( ssl, signature_len ) ); case MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS: - MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server key exchange (pending)" ) ); return( MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ); default: MBEDTLS_SSL_DEBUG_RET( 1, "f_async_sign", ret ); @@ -3242,17 +3243,24 @@ curve_matching_done: return( 0 ); } +/* 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; - - /* Extract static ECDH parameters and abort if ServerKeyExchange - * is not needed. */ #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__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 @@ -3272,16 +3280,14 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) } #endif /* MBEDTLS_KEY_EXCHANGE__NON_PFS__ENABLED */ - /* If we have already prepared the message and there is an ongoing - signature operation, resume signing. */ #if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) && \ defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) + /* If we have already prepared the message and there is an ongoing + signature operation, resume signing. */ if( ssl->handshake->p_async_operation_ctx != NULL ) { MBEDTLS_SSL_DEBUG_MSG( 2, ( "resuming signature operation" ) ); ret = ssl_resume_server_key_exchange( ssl, &signature_len ); - if( ret != 0 ) - return( ret ); } else #endif /* defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) && @@ -3289,8 +3295,15 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) { /* ServerKeyExchange is needed. Prepare the message. */ ret = ssl_prepare_server_key_exchange( ssl, &signature_len ); - if( ret != 0 ) - return( ret ); + } + + if( ret != 0 ) + { + 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. @@ -3324,7 +3337,6 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) } MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server key exchange" ) ); - return( 0 ); } From f9f15ae5a12c9595315a104549e95c59b7da931f Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 8 Jan 2018 17:13:01 +0100 Subject: [PATCH 19/69] ssl_write_server_key_exchange refactor: don't use p at all Use ssl->out_msglen as the cursor in ssl->out_msg throughout, rather than switching a between pointer and an offset. --- library/ssl_srv.c | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 415eaf8c9..56a266231 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -2855,15 +2855,17 @@ static int ssl_prepare_server_key_exchange( mbedtls_ssl_context *ssl, { const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; - unsigned char *p = ssl->out_msg + 4; #if defined(MBEDTLS_KEY_EXCHANGE__SOME_PFS__ENABLED) #if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) unsigned char *dig_signed = NULL; #endif /* MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED */ #endif /* MBEDTLS_KEY_EXCHANGE__SOME_PFS__ENABLED */ + (void) ciphersuite_info; /* unused in some configurations */ (void) signature_len; /* unused in some configurations */ + ssl->out_msglen = 4; /* header (type:1, length:3) to be written later */ + /* * * Part 1: Provide key exchange parameters for chosen ciphersuite. @@ -2877,18 +2879,20 @@ static int ssl_prepare_server_key_exchange( mbedtls_ssl_context *ssl, if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) { int ret; - const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; 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; + ssl->out_msglen += len; } #endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ @@ -2902,8 +2906,8 @@ static int ssl_prepare_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; + 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 */ @@ -2939,19 +2943,21 @@ static int ssl_prepare_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 = ssl->out_msg + ssl->out_msglen; #endif - p += 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 ); @@ -3003,7 +3009,8 @@ curve_matching_done: if( ( ret = mbedtls_ecdh_make_params( &ssl->handshake->ecdh_ctx, &len, - p, ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN - p, + 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 ); @@ -3011,17 +3018,15 @@ curve_matching_done: } #if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) - dig_signed = p; + dig_signed = ssl->out_msg + ssl->out_msglen; #endif - p += len; + ssl->out_msglen += len; MBEDTLS_SSL_DEBUG_ECP( 3, "ECDH: Q ", &ssl->handshake->ecdh_ctx.Q ); } #endif /* MBEDTLS_KEY_EXCHANGE__SOME__ECDHE_ENABLED */ - ssl->out_msglen = p - ssl->out_msg; - /* * * Part 2: For key exchanges involving the server signing the From 60ee4cadceeae56375a1543a592177e3722695d1 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 8 Jan 2018 11:28:05 +0100 Subject: [PATCH 20/69] SSL asynchronous signature: basic test of recovery after error Add test cases where the server goes through an async operation which fails, then the server makes a successful connection. --- programs/ssl/ssl_server2.c | 19 +++++++++++---- tests/ssl-opt.sh | 50 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 5 deletions(-) diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index 28f636751..2a4c833d9 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -203,7 +203,8 @@ int main( void ) " async_private_delay1=%%d Asynchronous delay for key_file or preloaded key\n" \ " async_private_delay2=%%d Asynchronous delay for key_file2\n" \ " default: -1 (not asynchronous)\n" \ - " async_private_error=%%d Async callback error injection (default=0=none, 1=start, 2=cancel, 3=resume, 4=pk)" + " async_private_error=%%d Async callback error injection (default=0=none,\n" \ + " 1=start, 2=cancel, 3=resume, 4=pk, negative=first time only)" #else #define USAGE_SSL_ASYNC "" #endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ @@ -1238,7 +1239,8 @@ int main( int argc, char *argv[] ) else if( strcmp( p, "async_private_error" ) == 0 ) { int n = atoi( q ); - if( n < 0 || n > SSL_ASYNC_INJECT_ERROR_MAX ) + if( n < -SSL_ASYNC_INJECT_ERROR_MAX || + n > SSL_ASYNC_INJECT_ERROR_MAX ) { ret = 2; goto usage; @@ -2152,7 +2154,9 @@ int main( int argc, char *argv[] ) #if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) if( opt.async_private_delay1 >= 0 || opt.async_private_delay2 >= 0 ) { - ssl_async_keys.inject_error = opt.async_private_error; + 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, @@ -2338,10 +2342,10 @@ handshake: ret = mbedtls_ssl_handshake( &ssl ); #if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) if( ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS && - opt.async_private_error == SSL_ASYNC_INJECT_ERROR_CANCEL ) + ssl_async_keys.inject_error == SSL_ASYNC_INJECT_ERROR_CANCEL ) { mbedtls_printf( " cancelling on injected error\n" ); - goto reset; + break; } #endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ } @@ -2371,6 +2375,11 @@ handshake: } #endif +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) + 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 */ diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index 5f23cd1df..1ec1a149a 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -3737,6 +3737,56 @@ run_test "SSL async private: error in pk" \ -s "Async resume callback: done but injected error" \ -s "! mbedtls_ssl_handshake returned" +requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C +run_test "SSL async private: cancel after start then operate correctly" \ + "$P_SRV 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_C +run_test "SSL async private: error in resume then operate correctly" \ + "$P_SRV 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_C +run_test "SSL async private: cancel after start then fall back to transparent key" \ + "$P_SRV key_file=data_files/server5.key crt_file=data_files/server5.crt \ + key_file2=data_files/server2.key crt_file2=data_files/server2.crt \ + async_private_delay1=1 async_private_error=-2" \ + "$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 "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_C +run_test "SSL async private: error in resume then fall back to transparent key" \ + "$P_SRV key_file=data_files/server5.key crt_file=data_files/server5.crt \ + key_file2=data_files/server2.key crt_file2=data_files/server2.crt \ + async_private_delay1=1 async_private_error=-3" \ + "$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_C requires_config_enabled MBEDTLS_SSL_RENEGOTIATION run_test "SSL async private: renegotiation: client-initiated" \ From 9d12b4c849a84cb1783bca04e78aa8ec804833a5 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 8 Jan 2018 13:17:27 +0100 Subject: [PATCH 21/69] SSL asynchronous signature: turn off by default --- include/mbedtls/config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h index 80a4fef32..6b7ecf2ca 100644 --- a/include/mbedtls/config.h +++ b/include/mbedtls/config.h @@ -2342,7 +2342,7 @@ * operation inside the library. * */ -#define MBEDTLS_SSL_ASYNC_PRIVATE_C +//#define MBEDTLS_SSL_ASYNC_PRIVATE_C /** * \def MBEDTLS_SSL_CACHE_C From dbb14e09f240867ed4048717bc6dd97db5ac69ac Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 8 Jan 2018 18:17:53 +0100 Subject: [PATCH 22/69] all.sh: run ssl-opt.sh on ECJPAKE, SSL async Run ssl-opt.sh in the "full" configuration on things that are not in the default configuration: SSL async private, ECJPAKE. --- tests/scripts/all.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh index 2ea31dbc2..f9eb990f3 100755 --- a/tests/scripts/all.sh +++ b/tests/scripts/all.sh @@ -541,8 +541,8 @@ make CFLAGS='-Werror -Wall -Wextra -std=c99 -pedantic' msg "test: main suites (full config)" # ~ 5s make CFLAGS='-Werror -Wall -Wextra' 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, SSL async (full config)" # ~ 1s +if_build_succeeded tests/ssl-opt.sh -f 'Default\|ECJPAKE\|SSL async private' 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' From e630aed5aef599cc661473877e6c2e6c7c1fbfbf Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 8 Jan 2018 18:28:00 +0100 Subject: [PATCH 23/69] SSL asynchronous signature: ChangeLog entry --- ChangeLog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ChangeLog b/ChangeLog index 2284f3427..8c7b6d8de 100644 --- a/ChangeLog +++ b/ChangeLog @@ -22,6 +22,10 @@ Features MBEDTLS_CMAC_ALT). Submitted by Steve Cooreman, Silicon Labs. * Add support for alternative implementations of GCM, selected by the configuration flag MBEDTLS_GCM_ALT. + * In TLS, support offloading private key operations to an external + cryptoprocessor. Private key operations can be asynchronous to allow + non-blocking operation of the TLS stack. + Currently restricted to signature only, server-side only. New deprecations * Deprecate usage of RSA primitives with non-matching key-type From d9bfcabcb918d7a6f1c933a1ef45f79251a3acb7 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 12 Jan 2018 13:49:37 +0100 Subject: [PATCH 24/69] SSL asynchronous signature: fix renegotiation tests Fixed typo in "SSL async private: renegotiation" tests that caused the renegotiation not to actually take place. --- tests/ssl-opt.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index 1ec1a149a..e3a3edd02 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -3790,7 +3790,7 @@ run_test "SSL async private: error in resume then fall back to transparent ke requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C requires_config_enabled MBEDTLS_SSL_RENEGOTIATION run_test "SSL async private: renegotiation: client-initiated" \ - "$P_SRV async_private_delay1=1 async_private_delay2=1 + "$P_SRV async_private_delay1=1 async_private_delay2=1 \ exchanges=2 renegotiation=1" \ "$P_CLI exchanges=2 renegotiation=1 renegotiate=1" \ 0 \ @@ -3800,7 +3800,7 @@ run_test "SSL async private: renegotiation: client-initiated" \ requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C requires_config_enabled MBEDTLS_SSL_RENEGOTIATION run_test "SSL async private: renegotiation: server-initiated" \ - "$P_SRV async_private_delay1=1 async_private_delay2=1 + "$P_SRV async_private_delay1=1 async_private_delay2=1 \ exchanges=2 renegotiation=1 renegotiate=1" \ "$P_CLI exchanges=2 renegotiation=1" \ 0 \ From 422ccabe2944574ec6475a6e359d7e24bbc13975 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 11 Jan 2018 18:29:01 +0100 Subject: [PATCH 25/69] ssl_parse_encrypted_pms refactor: prepare for remote private key Use the public key to extract metadata rather than the public key. Don't abort early if there is no private key. This is in preparation for allowing the private key operation to be offloaded to an external cryptographic module. --- library/ssl_srv.c | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 56a266231..c8578158a 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -3422,7 +3422,9 @@ static int ssl_parse_encrypted_pms( mbedtls_ssl_context *ssl, size_t pms_offset ) { int ret; - size_t len = mbedtls_pk_get_len( mbedtls_ssl_own_key( ssl ) ); + 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 ); unsigned char *pms = ssl->handshake->premaster + pms_offset; unsigned char ver[2]; unsigned char fake_pms[48], peer_pms[48]; @@ -3430,14 +3432,8 @@ static int ssl_parse_encrypted_pms( mbedtls_ssl_context *ssl, size_t i, peer_pmslen; unsigned int diff; - if( ! mbedtls_pk_can_do( mbedtls_ssl_own_key( ssl ), MBEDTLS_PK_RSA ) ) - { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no RSA private key" ) ); - return( MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED ); - } - /* - * 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) @@ -3466,18 +3462,31 @@ static int ssl_parse_encrypted_pms( mbedtls_ssl_context *ssl, * 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, always generate the fake + * premaster secret, so as to avoid data-dependant branches. */ ret = ssl->conf->f_rng( ssl->conf->p_rng, fake_pms, sizeof( fake_pms ) ); if( ret != 0 ) return( ret ); - ret = mbedtls_pk_decrypt( mbedtls_ssl_own_key( ssl ), p, len, + /* + * Decrypt the premaster secret + */ + 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, sizeof( peer_pms ), ssl->conf->f_rng, ssl->conf->p_rng ); + /* 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]; @@ -3508,6 +3517,8 @@ static int ssl_parse_encrypted_pms( mbedtls_ssl_context *ssl, #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] ); From bcd98a5306a6d2143c992f1169449c9a32b39642 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 11 Jan 2018 21:30:40 +0100 Subject: [PATCH 26/69] ssl_parse_encrypted_pms refactor: prepare, decrypt, return Reorganize ssl_parse_encrypted_pms so that it first prepares the ciphertext to decrypt, then decrypts it, then returns either the decrypted premaster secret or random data in an appropriate manner. This is in preparation for allowing the private key operation to be offloaded to an external cryptographic module which can operate asynchronously. The refactored code no longer calculates state before the decryption that needs to be saved until after the decryption, which allows the decryption to be started and later resumed. --- library/ssl_srv.c | 76 ++++++++++++++++++++++++++++++----------------- 1 file changed, 48 insertions(+), 28 deletions(-) diff --git a/library/ssl_srv.c b/library/ssl_srv.c index c8578158a..0c7e15d29 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -3416,21 +3416,17 @@ 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 ) +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; 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 ); - 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; /* * Prepare to decrypt the premaster using own private RSA key @@ -3454,21 +3450,6 @@ static int ssl_parse_encrypted_pms( mbedtls_ssl_context *ssl, return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); } - mbedtls_ssl_write_version( ssl->handshake->max_major_ver, - ssl->handshake->max_minor_ver, - ssl->conf->transport, ver ); - - /* - * 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. - * To protect against timing-based variants, always generate the fake - * premaster secret, so as to avoid data-dependant branches. - */ - ret = ssl->conf->f_rng( ssl->conf->p_rng, fake_pms, sizeof( fake_pms ) ); - if( ret != 0 ) - return( ret ); - /* * Decrypt the premaster secret */ @@ -3480,9 +3461,48 @@ static int ssl_parse_encrypted_pms( mbedtls_ssl_context *ssl, } ret = mbedtls_pk_decrypt( private_key, p, len, - peer_pms, &peer_pmslen, - sizeof( peer_pms ), - ssl->conf->f_rng, ssl->conf->p_rng ); + 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; + + ret = ssl_decrypt_encrypted_pms( ssl, p, end, + peer_pms, + &peer_pmslen, + sizeof( peer_pms ) ); + + /* + * 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. + * 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 */ + return( ret ); + } + + mbedtls_ssl_write_version( ssl->handshake->max_major_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 From 2c6078ed3b68d823381d8161f475e4e3a109e910 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 12 Jan 2018 13:46:43 +0100 Subject: [PATCH 27/69] SSL asynchronous decryption (server side) Support SSL asynchronous private operation for the case of a decryption operation on a server. --- library/ssl_srv.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 0c7e15d29..5c3aacf99 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -3416,6 +3416,25 @@ 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) + +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) +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->conf->p_async_connection_ctx, + ssl->handshake->p_async_operation_ctx, + peer_pms, peer_pmslen, peer_pmssize ); + if( ret != MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ) + { + ssl->handshake->p_async_operation_ctx = NULL; + } + MBEDTLS_SSL_DEBUG_RET( 2, "ssl_decrypt_encrypted_pms", ret ); + return( ret ); +} +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ + static int ssl_decrypt_encrypted_pms( mbedtls_ssl_context *ssl, const unsigned char *p, const unsigned char *end, @@ -3428,6 +3447,17 @@ static int ssl_decrypt_encrypted_pms( mbedtls_ssl_context *ssl, mbedtls_pk_context *public_key = &mbedtls_ssl_own_cert( ssl )->pk; size_t len = mbedtls_pk_get_len( public_key ); +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) + /* If we have already started decoding the message and there is an ongoing + decryption operation, resume signing. */ + if( ssl->handshake->p_async_operation_ctx != NULL ) + { + 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_C */ + /* * Prepare to decrypt the premaster using own private RSA key */ @@ -3453,6 +3483,33 @@ static int ssl_decrypt_encrypted_pms( mbedtls_ssl_context *ssl, /* * Decrypt the premaster secret */ +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) + if( ssl->conf->f_async_decrypt_start != NULL ) + { + ret = ssl->conf->f_async_decrypt_start( + ssl->conf->p_async_connection_ctx, + &ssl->handshake->p_async_operation_ctx, + 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: + return( ssl_resume_decrypt_pms( ssl, + peer_pms, + peer_pmslen, + peer_pmssize ) ); + case MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS: + return( MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ); + default: + MBEDTLS_SSL_DEBUG_RET( 1, "f_async_sign", ret ); + return( ret ); + } + } +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ + if( ! mbedtls_pk_can_do( private_key, MBEDTLS_PK_RSA ) ) { /* */ @@ -3484,6 +3541,11 @@ static int ssl_parse_encrypted_pms( mbedtls_ssl_context *ssl, &peer_pmslen, sizeof( peer_pms ) ); +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) + if ( ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ) + return( ret ); +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ + /* * Protection against Bleichenbacher's attack: invalid PKCS#1 v1.5 padding * must not cause the connection to end immediately; instead, send a @@ -3620,6 +3682,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_C) && \ + ( 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->p_async_operation_ctx != NULL ) ) + { + /* 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 ); @@ -3732,6 +3808,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_C) + if ( ssl->handshake->p_async_operation_ctx != NULL ) + { + /* 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_C */ if( ( ret = ssl_parse_client_psk_identity( ssl, &p, end ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_client_psk_identity" ), ret ); From fcca9d8cef06aebb411a6e4cc7218f51f36d10bb Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 12 Jan 2018 13:47:48 +0100 Subject: [PATCH 28/69] SSL asynchronous decryption (server side): tests Test SSL asynchronous private operation for the case of a decryption operation on a server. --- programs/ssl/ssl_server2.c | 130 ++++++++++++++++++------- tests/ssl-opt.sh | 192 +++++++++++++++++++++++++++++-------- 2 files changed, 247 insertions(+), 75 deletions(-) diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index 2a4c833d9..2f3908d97 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -108,6 +108,7 @@ 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 ) @@ -200,6 +201,7 @@ int main( void ) #if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) #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\n" \ " default: -1 (not asynchronous)\n" \ @@ -421,6 +423,7 @@ 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 */ @@ -892,21 +895,23 @@ void ssl_async_set_key( ssl_async_key_context_t *ctx, ++ctx->slots_used; } +#define SSL_ASYNC_INPUT_MAX_SIZE 512 typedef struct { size_t slot; mbedtls_md_type_t md_alg; - unsigned char hash[MBEDTLS_MD_MAX_SIZE]; - size_t hash_len; + unsigned char input[SSL_ASYNC_INPUT_MAX_SIZE]; + size_t input_len; unsigned delay; } ssl_async_operation_context_t; -int ssl_async_sign( void *connection_ctx_arg, - void **p_operation_ctx, - mbedtls_x509_crt *cert, - mbedtls_md_type_t md_alg, - const unsigned char *hash, - size_t hash_len ) +static int ssl_async_start( void *connection_ctx_arg, + void **p_operation_ctx, + mbedtls_x509_crt *cert, + const char *op_name, + mbedtls_md_type_t md_alg, + const unsigned char *input, + size_t input_len ) { ssl_async_key_context_t *key_ctx = connection_ctx_arg; size_t slot; @@ -914,7 +919,7 @@ int ssl_async_sign( void *connection_ctx_arg, { char dn[100]; mbedtls_x509_dn_gets( dn, sizeof( dn ), &cert->subject ); - mbedtls_printf( "Async sign callback: looking for DN=%s\n", dn ); + mbedtls_printf( "Async %s callback: looking for DN=%s\n", op_name, dn ); } for( slot = 0; slot < key_ctx->slots_used; slot++ ) { @@ -923,25 +928,26 @@ int ssl_async_sign( void *connection_ctx_arg, } if( slot == key_ctx->slots_used ) { - mbedtls_printf( "Async sign callback: no key matches this certificate.\n" ); + mbedtls_printf( "Async %s callback: no key matches this certificate.\n", + op_name ); return( MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH ); } - mbedtls_printf( "Async sign callback: using key slot %zd, delay=%u.\n", - slot, key_ctx->slots[slot].delay ); + mbedtls_printf( "Async %s callback: using key slot %zd, delay=%u.\n", + op_name, slot, key_ctx->slots[slot].delay ); if( key_ctx->inject_error == SSL_ASYNC_INJECT_ERROR_START ) { - mbedtls_printf( "Async sign callback: injected error\n" ); + mbedtls_printf( "Async %s callback: injected error\n", op_name ); return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); } - if( hash_len > MBEDTLS_MD_MAX_SIZE ) + 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->md_alg = md_alg; - memcpy( ctx->hash, hash, hash_len ); - ctx->hash_len = hash_len; + memcpy( ctx->input, input, input_len ); + ctx->input_len = input_len; ctx->delay = key_ctx->slots[slot].delay; *p_operation_ctx = ctx; if( ctx->delay == 0 ) @@ -950,16 +956,40 @@ int ssl_async_sign( void *connection_ctx_arg, return( MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ); } -int ssl_async_resume( void *connection_ctx_arg, - void *operation_ctx_arg, - unsigned char *output, - size_t *output_len, - size_t output_size ) +static int ssl_async_sign( void *connection_ctx_arg, + void **p_operation_ctx, + mbedtls_x509_crt *cert, + mbedtls_md_type_t md_alg, + const unsigned char *hash, + size_t hash_len ) +{ + return( ssl_async_start( connection_ctx_arg, p_operation_ctx, cert, + "sign", md_alg, + hash, hash_len ) ); +} + +static int ssl_async_decrypt( void *connection_ctx_arg, + void **p_operation_ctx, + mbedtls_x509_crt *cert, + const unsigned char *input, + size_t input_len ) +{ + return( ssl_async_start( connection_ctx_arg, p_operation_ctx, cert, + "decrypt", MBEDTLS_MD_NONE, + input, input_len ) ); +} + +static int ssl_async_resume( void *connection_ctx_arg, + void *operation_ctx_arg, + unsigned char *output, + size_t *output_len, + size_t output_size ) { ssl_async_operation_context_t *ctx = operation_ctx_arg; ssl_async_key_context_t *connection_ctx = connection_ctx_arg; ssl_async_key_slot_t *key_slot = &connection_ctx->slots[ctx->slot]; int ret; + const char *op_name; if( connection_ctx->inject_error == SSL_ASYNC_INJECT_ERROR_RESUME ) { mbedtls_printf( "Async resume callback: injected error\n" ); @@ -972,25 +1002,37 @@ int ssl_async_resume( void *connection_ctx_arg, ctx->slot, ctx->delay ); return( MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ); } - (void) output_size; /* mbedtls_pk_size lacks this parameter */ - ret = mbedtls_pk_sign( key_slot->pk, - ctx->md_alg, - ctx->hash, ctx->hash_len, - output, output_len, - connection_ctx->f_rng, connection_ctx->p_rng ); + if( ctx->md_alg == MBEDTLS_MD_NONE ) + { + op_name = "decrypt"; + ret = mbedtls_pk_decrypt( key_slot->pk, + ctx->input, ctx->input_len, + output, output_len, output_size, + connection_ctx->f_rng, connection_ctx->p_rng ); + } + else + { + op_name = "sign"; + ret = mbedtls_pk_sign( key_slot->pk, + ctx->md_alg, + ctx->input, ctx->input_len, + output, output_len, + connection_ctx->f_rng, connection_ctx->p_rng ); + } if( connection_ctx->inject_error == SSL_ASYNC_INJECT_ERROR_PK ) { - mbedtls_printf( "Async resume callback: done but injected error\n" ); + mbedtls_printf( "Async resume callback: %s done but injected error\n", + op_name ); return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); } - mbedtls_printf( "Async resume (slot %zd): done, status=%d.\n", - ctx->slot, ret ); + mbedtls_printf( "Async resume (slot %zd): %s done, status=%d.\n", + ctx->slot, op_name, ret ); mbedtls_free( ctx ); return( ret ); } -void ssl_async_cancel( void *connection_ctx_arg, - void *operation_ctx_arg ) +static void ssl_async_cancel( void *connection_ctx_arg, + void *operation_ctx_arg ) { ssl_async_operation_context_t *ctx = operation_ctx_arg; (void) connection_ctx_arg; @@ -1142,6 +1184,7 @@ 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; @@ -1232,6 +1275,8 @@ int main( int argc, char *argv[] ) else if( strcmp( p, "dhm_file" ) == 0 ) opt.dhm_file = q; #if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) + 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 ) @@ -2152,16 +2197,31 @@ int main( int argc, char *argv[] ) } #if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) - if( opt.async_private_delay1 >= 0 || opt.async_private_delay2 >= 0 ) + if( opt.async_operations[0] != '-' ) { + mbedtls_ssl_async_sign_t *sign = NULL; + mbedtls_ssl_async_decrypt_t *decrypt = NULL; + const char *p; + for( p = opt.async_operations; *p; p++ ) + { + switch( *p ) + { + 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, - ssl_async_sign, - NULL, + sign, + decrypt, ssl_async_resume, ssl_async_cancel, &ssl_async_keys ); diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index e3a3edd02..5579e4ab8 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -3639,71 +3639,145 @@ run_test "Large packet TLS 1.2 AEAD shorter tag" \ # Tests of asynchronous private key support in SSL requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C -run_test "SSL async private: delay=0" \ - "$P_SRV async_private_delay1=0 async_private_delay2=0" \ +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]): done, status=0" + -s "Async resume (slot [0-9]): sign done, status=0" requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C -run_test "SSL async private: delay=1" \ - "$P_SRV async_private_delay1=1 async_private_delay2=1" \ +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]): done, status=0" + -s "Async resume (slot [0-9]): sign done, status=0" + +requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C +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_C +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_C +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_C +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_C +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_C +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_C run_test "SSL async private: slot 0 used with key1" \ - "$P_SRV key_file=data_files/server5.key crt_file=data_files/server5.crt \ - key_file2=data_files/server2.key crt_file2=data_files/server2.crt \ - async_private_delay1=1" \ + "$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): done, status=0" + -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_C run_test "SSL async private: slot 0 used with key2" \ - "$P_SRV key_file=data_files/server5.key crt_file=data_files/server5.crt \ - key_file2=data_files/server2.key crt_file2=data_files/server2.crt \ - async_private_delay2=1" \ + "$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): done, status=0" + -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_C run_test "SSL async private: slot 1 used" \ - "$P_SRV key_file=data_files/server5.key crt_file=data_files/server5.crt \ - key_file2=data_files/server2.key crt_file2=data_files/server2.crt \ - async_private_delay1=1 async_private_delay2=1" \ + "$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): done, status=0" + -s "Async resume (slot 1): sign done, status=0" # key1: ECDSA, key2: RSA; use key2 directly requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C run_test "SSL async private: fall back to transparent key" \ - "$P_SRV key_file=data_files/server5.key crt_file=data_files/server5.crt \ - key_file2=data_files/server2.key crt_file2=data_files/server2.crt \ - async_private_delay1=1" \ + "$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_C run_test "SSL async private: error in start" \ - "$P_SRV async_private_delay1=1 async_private_delay2=1 async_private_error=1" \ + "$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" \ @@ -3712,7 +3786,9 @@ run_test "SSL async private: error in start" \ requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C run_test "SSL async private: cancel after start" \ - "$P_SRV async_private_delay1=1 async_private_delay2=1 async_private_error=2" \ + "$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 " \ @@ -3721,7 +3797,9 @@ run_test "SSL async private: cancel after start" \ requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C run_test "SSL async private: error in resume" \ - "$P_SRV async_private_delay1=1 async_private_delay2=1 async_private_error=3" \ + "$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 " \ @@ -3730,16 +3808,20 @@ run_test "SSL async private: error in resume" \ requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C run_test "SSL async private: error in pk" \ - "$P_SRV async_private_delay1=1 async_private_delay2=1 async_private_error=4" \ + "$P_SRV \ + async_operations=s async_private_delay1=1 async_private_delay2=1 \ + async_private_error=4" \ "$P_CLI" \ 1 \ -s "Async sign callback: using key slot " \ - -s "Async resume callback: done but injected error" \ + -s "Async resume callback: sign done but injected error" \ -s "! mbedtls_ssl_handshake returned" requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C run_test "SSL async private: cancel after start then operate correctly" \ - "$P_SRV async_private_delay1=1 async_private_delay2=1 async_private_error=-2" \ + "$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" \ @@ -3749,7 +3831,9 @@ run_test "SSL async private: cancel after start then operate correctly" \ requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C run_test "SSL async private: error in resume then operate correctly" \ - "$P_SRV async_private_delay1=1 async_private_delay2=1 async_private_error=-3" \ + "$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" \ @@ -3759,9 +3843,10 @@ run_test "SSL async private: error in resume then operate correctly" \ # key1: ECDSA, key2: RSA; use key1 through async, then key2 directly requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C run_test "SSL async private: cancel after start then fall back to transparent key" \ - "$P_SRV key_file=data_files/server5.key crt_file=data_files/server5.crt \ - key_file2=data_files/server2.key crt_file2=data_files/server2.crt \ - async_private_delay1=1 async_private_error=-2" \ + "$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" \ @@ -3775,9 +3860,10 @@ run_test "SSL async private: cancel after start then fall back to transparent # key1: ECDSA, key2: RSA; use key1 through async, then key2 directly requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C run_test "SSL async private: error in resume then fall back to transparent key" \ - "$P_SRV key_file=data_files/server5.key crt_file=data_files/server5.crt \ - key_file2=data_files/server2.key crt_file2=data_files/server2.crt \ - async_private_delay1=1 async_private_error=-3" \ + "$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" \ @@ -3789,23 +3875,49 @@ run_test "SSL async private: error in resume then fall back to transparent ke requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C requires_config_enabled MBEDTLS_SSL_RENEGOTIATION -run_test "SSL async private: renegotiation: client-initiated" \ - "$P_SRV async_private_delay1=1 async_private_delay2=1 \ +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]): done, status=0" + -s "Async resume (slot [0-9]): sign done, status=0" requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C requires_config_enabled MBEDTLS_SSL_RENEGOTIATION -run_test "SSL async private: renegotiation: server-initiated" \ - "$P_SRV async_private_delay1=1 async_private_delay2=1 \ +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]): done, status=0" + -s "Async resume (slot [0-9]): sign done, status=0" + +requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C +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_C +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 From 0329d72ad49603812cc5ffbfbff37ebcd85fe4d3 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 12 Jan 2018 13:52:00 +0100 Subject: [PATCH 29/69] SSL asynchronous decryption (server side): update ChangeLog --- ChangeLog | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8c7b6d8de..888ee2e8c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -22,10 +22,9 @@ Features MBEDTLS_CMAC_ALT). Submitted by Steve Cooreman, Silicon Labs. * Add support for alternative implementations of GCM, selected by the configuration flag MBEDTLS_GCM_ALT. - * In TLS, support offloading private key operations to an external + * 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 stack. - Currently restricted to signature only, server-side only. + non-blocking operation of the TLS server stack. New deprecations * Deprecate usage of RSA primitives with non-matching key-type From ca1d74290439ec9e2723a911657fd96aa320e219 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 24 Apr 2018 11:53:22 +0200 Subject: [PATCH 30/69] mbedtls_ssl_get_key_exchange_md_tls1_2: return hashlen In mbedtls_ssl_get_key_exchange_md_tls1_2, add an output parameter for the hash length. The code that calls this function can currently do without it, but it will need the hash length in the future, when adding support for a third-party callback to calculate the signature of the hash. --- include/mbedtls/ssl_internal.h | 6 +++--- library/ssl_cli.c | 10 ++++------ library/ssl_srv.c | 9 +++------ library/ssl_tls.c | 9 +++++---- 4 files changed, 15 insertions(+), 19 deletions(-) diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h index 60b431a0f..d4b1b19ee 100644 --- a/include/mbedtls/ssl_internal.h +++ b/include/mbedtls/ssl_internal.h @@ -646,9 +646,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/ssl_cli.c b/library/ssl_cli.c index 738014e9e..f952b0f88 100644 --- a/library/ssl_cli.c +++ b/library/ssl_cli.c @@ -2526,10 +2526,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 ); } @@ -2541,8 +2540,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 2c180f13f..618c81b9b 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -3045,7 +3045,7 @@ curve_matching_done: if( mbedtls_ssl_ciphersuite_uses_server_signature( ciphersuite_info ) ) { size_t signature_len = 0; - unsigned int hashlen = 0; + size_t hashlen = 0; unsigned char hash[64]; /* @@ -3116,9 +3116,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 ); @@ -3133,8 +3131,7 @@ 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 diff --git a/library/ssl_tls.c b/library/ssl_tls.c index e8063d2c1..28c234ad9 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -8310,13 +8310,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 ); @@ -8347,7 +8348,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; From 12ab5d4cfbd30b6b298c3d8c92fe162670aa0676 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 24 Apr 2018 12:32:04 +0200 Subject: [PATCH 31/69] Don't shadow the variable p --- programs/ssl/ssl_server2.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index 02f963337..86672e864 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -2287,10 +2287,10 @@ int main( int argc, char *argv[] ) { mbedtls_ssl_async_sign_t *sign = NULL; mbedtls_ssl_async_decrypt_t *decrypt = NULL; - const char *p; - for( p = opt.async_operations; *p; p++ ) + const char *r; + for( r = opt.async_operations; *r; r++ ) { - switch( *p ) + switch( *r ) { case 'd': decrypt = ssl_async_decrypt; From f112725487e16b7a1c9608ad5d71612da79c30d4 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 24 Apr 2018 13:05:39 +0200 Subject: [PATCH 32/69] Style and grammar fixes --- include/mbedtls/ssl.h | 4 ++-- library/ssl_srv.c | 4 ++-- library/ssl_tls.c | 2 +- programs/ssl/ssl_server2.c | 11 +++++++++++ 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 720c33877..582be2c79 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -1490,13 +1490,13 @@ void mbedtls_ssl_conf_export_keys_cb( mbedtls_ssl_config *conf, * \param f_async_sign Callback to start a signature operation. See * the description of \c mbedtls_ssl_async_sign_t * for more information. This may be NULL if the - * external processor does no support any signature + * 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 \c mbedtls_ssl_async_decrypt_t * for more information. This may be NULL if the - * external processor does no support any decryption + * 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 diff --git a/library/ssl_srv.c b/library/ssl_srv.c index fa858f8e9..f7bed5847 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -3221,7 +3221,7 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) #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__NON_PFS__ENABLED */ +#endif /* MBEDTLS_KEY_EXCHANGE__SOME_NON_PFS__ENABLED */ MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write server key exchange" ) ); @@ -3245,7 +3245,7 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) ssl->state++; return( 0 ); } -#endif /* MBEDTLS_KEY_EXCHANGE__NON_PFS__ENABLED */ +#endif /* MBEDTLS_KEY_EXCHANGE__SOME_NON_PFS__ENABLED */ #if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) && \ defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 8ad3494e4..256590ff7 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -7431,7 +7431,7 @@ void mbedtls_ssl_handshake_free( const mbedtls_ssl_config *conf, { if( handshake == NULL ) return; - (void) conf; /*unused in some compile-time configurations*/ + (void) conf; /* Unused in some compile-time configurations. */ #if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ defined(MBEDTLS_SSL_PROTO_TLS1_1) diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index 86672e864..9f05e7d4d 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -920,11 +920,13 @@ static int ssl_async_start( void *connection_ctx_arg, ssl_async_key_context_t *key_ctx = connection_ctx_arg; size_t slot; ssl_async_operation_context_t *ctx = NULL; + { 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 ); } + for( slot = 0; slot < key_ctx->slots_used; slot++ ) { if( key_ctx->slots[slot].cert == cert ) @@ -938,13 +940,16 @@ static int ssl_async_start( void *connection_ctx_arg, } mbedtls_printf( "Async %s callback: using key slot %zd, delay=%u.\n", op_name, slot, key_ctx->slots[slot].delay ); + if( key_ctx->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 ); @@ -954,6 +959,7 @@ static int ssl_async_start( void *connection_ctx_arg, ctx->input_len = input_len; ctx->delay = key_ctx->slots[slot].delay; *p_operation_ctx = ctx; + if( ctx->delay == 0 ) return( 0 ); else @@ -994,11 +1000,13 @@ static int ssl_async_resume( void *connection_ctx_arg, ssl_async_key_slot_t *key_slot = &connection_ctx->slots[ctx->slot]; int ret; const char *op_name; + if( connection_ctx->inject_error == SSL_ASYNC_INJECT_ERROR_RESUME ) { mbedtls_printf( "Async resume callback: injected error\n" ); return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); } + if( ctx->delay > 0 ) { --ctx->delay; @@ -1006,6 +1014,7 @@ static int ssl_async_resume( void *connection_ctx_arg, ctx->slot, ctx->delay ); return( MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ); } + if( ctx->md_alg == MBEDTLS_MD_NONE ) { op_name = "decrypt"; @@ -1023,12 +1032,14 @@ static int ssl_async_resume( void *connection_ctx_arg, output, output_len, connection_ctx->f_rng, connection_ctx->p_rng ); } + if( connection_ctx->inject_error == SSL_ASYNC_INJECT_ERROR_PK ) { mbedtls_printf( "Async resume callback: %s done but injected error\n", op_name ); return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); } + mbedtls_printf( "Async resume (slot %zd): %s done, status=%d.\n", ctx->slot, op_name, ret ); mbedtls_free( ctx ); From b74a1c73b107827b5a09d6f2d5550f4a3fde0dc3 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 24 Apr 2018 13:09:22 +0200 Subject: [PATCH 33/69] Rename MBEDTLS_SSL_ASYNC_PRIVATE_C to MBEDTLS_SSL_ASYNC_PRIVATE This is an optional feature, not a module of its own, so don't call it MBEDTLS_xxx_C and put it in the appropriate section of config.h. --- include/mbedtls/config.h | 22 ++++++++-------- include/mbedtls/ssl.h | 12 ++++----- include/mbedtls/ssl_internal.h | 4 +-- library/ssl_srv.c | 34 ++++++++++++------------ library/ssl_tls.c | 8 +++--- library/version_features.c | 6 ++--- programs/ssl/ssl_server2.c | 34 ++++++++++++------------ tests/ssl-opt.sh | 48 +++++++++++++++++----------------- 8 files changed, 84 insertions(+), 84 deletions(-) diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h index 4aec9ac64..b80667ab1 100644 --- a/include/mbedtls/config.h +++ b/include/mbedtls/config.h @@ -1128,6 +1128,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 * @@ -2472,17 +2483,6 @@ */ #define MBEDTLS_SHA512_C -/** - * \def MBEDTLS_SSL_ASYNC_PRIVATE_C - * - * 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_C - /** * \def MBEDTLS_SSL_CACHE_C * diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 582be2c79..be27b89ca 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -537,7 +537,7 @@ typedef void mbedtls_ssl_set_timer_t( void * ctx, */ typedef int mbedtls_ssl_get_timer_t( void * ctx ); -#if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) #if defined(MBEDTLS_X509_CRT_PARSE_C) /** * \brief Callback type: start external signature operation @@ -692,7 +692,7 @@ typedef int mbedtls_ssl_async_resume_t( void *connection_ctx, */ typedef void mbedtls_ssl_async_cancel_t( void *connection_ctx, void *operation_ctx ); -#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ /* Defined below */ typedef struct mbedtls_ssl_session mbedtls_ssl_session; @@ -826,7 +826,7 @@ struct mbedtls_ssl_config mbedtls_x509_crl *ca_crl; /*!< trusted CAs CRLs */ #endif /* MBEDTLS_X509_CRT_PARSE_C */ -#if defined(MBEDTLS_SSL_ASYNC_PRIVATE_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 */ @@ -834,7 +834,7 @@ struct mbedtls_ssl_config 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_connection_ctx; /*!< connection context for asynchronous operation callbacks */ -#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ #if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) const int *sig_hashes; /*!< allowed signature hashes */ @@ -1482,7 +1482,7 @@ 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_C) +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) /** * \brief Configure asynchronous private key operation callbacks. * @@ -1514,7 +1514,7 @@ void mbedtls_ssl_conf_async_private_cb( mbedtls_ssl_config *conf, mbedtls_ssl_async_resume_t *f_async_resume, mbedtls_ssl_async_cancel_t *f_async_cancel, void *connection_ctx ); -#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ +#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 6f36711a1..4c7205d70 100644 --- a/include/mbedtls/ssl_internal.h +++ b/include/mbedtls/ssl_internal.h @@ -243,9 +243,9 @@ 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_ASYNC_PRIVATE_C) +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) void *p_async_operation_ctx; /*!< asynchronous operation context */ -#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ #if defined(MBEDTLS_SSL_PROTO_DTLS) unsigned int out_msg_seq; /*!< Outgoing handshake sequence number */ diff --git a/library/ssl_srv.c b/library/ssl_srv.c index f7bed5847..de8056426 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -2835,7 +2835,7 @@ static int ssl_get_ecdh_params_from_cert( mbedtls_ssl_context *ssl ) MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */ #if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) && \ - defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) + defined(MBEDTLS_SSL_ASYNC_PRIVATE) static int ssl_resume_server_key_exchange( mbedtls_ssl_context *ssl, size_t *signature_len ) { @@ -2853,7 +2853,7 @@ static int ssl_resume_server_key_exchange( mbedtls_ssl_context *ssl, return( ret ); } #endif /* defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) && - defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) */ + defined(MBEDTLS_SSL_ASYNC_PRIVATE) */ /* Prepare the ServerKeyExchange message, up to and including calculating the signature if any, but excluding formatting the @@ -3164,7 +3164,7 @@ curve_matching_done: } #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ -#if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) if( ssl->conf->f_async_sign_start != NULL ) { ret = ssl->conf->f_async_sign_start( @@ -3186,7 +3186,7 @@ curve_matching_done: return( ret ); } } -#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ if( mbedtls_ssl_own_key( ssl ) == NULL ) { @@ -3248,7 +3248,7 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) #endif /* MBEDTLS_KEY_EXCHANGE__SOME_NON_PFS__ENABLED */ #if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) && \ - defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) + defined(MBEDTLS_SSL_ASYNC_PRIVATE) /* If we have already prepared the message and there is an ongoing signature operation, resume signing. */ if( ssl->handshake->p_async_operation_ctx != NULL ) @@ -3258,7 +3258,7 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) } else #endif /* defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) && - defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) */ + defined(MBEDTLS_SSL_ASYNC_PRIVATE) */ { /* ServerKeyExchange is needed. Prepare the message. */ ret = ssl_prepare_server_key_exchange( ssl, &signature_len ); @@ -3379,7 +3379,7 @@ 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) -#if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) static int ssl_resume_decrypt_pms( mbedtls_ssl_context *ssl, unsigned char *peer_pms, size_t *peer_pmslen, @@ -3395,7 +3395,7 @@ static int ssl_resume_decrypt_pms( mbedtls_ssl_context *ssl, MBEDTLS_SSL_DEBUG_RET( 2, "ssl_decrypt_encrypted_pms", ret ); return( ret ); } -#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ static int ssl_decrypt_encrypted_pms( mbedtls_ssl_context *ssl, const unsigned char *p, @@ -3409,7 +3409,7 @@ static int ssl_decrypt_encrypted_pms( mbedtls_ssl_context *ssl, mbedtls_pk_context *public_key = &mbedtls_ssl_own_cert( ssl )->pk; size_t len = mbedtls_pk_get_len( public_key ); -#if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) +#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->p_async_operation_ctx != NULL ) @@ -3418,7 +3418,7 @@ static int ssl_decrypt_encrypted_pms( mbedtls_ssl_context *ssl, return( ssl_resume_decrypt_pms( ssl, peer_pms, peer_pmslen, peer_pmssize ) ); } -#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ /* * Prepare to decrypt the premaster using own private RSA key @@ -3445,7 +3445,7 @@ static int ssl_decrypt_encrypted_pms( mbedtls_ssl_context *ssl, /* * Decrypt the premaster secret */ -#if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) if( ssl->conf->f_async_decrypt_start != NULL ) { ret = ssl->conf->f_async_decrypt_start( @@ -3470,7 +3470,7 @@ static int ssl_decrypt_encrypted_pms( mbedtls_ssl_context *ssl, return( ret ); } } -#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ if( ! mbedtls_pk_can_do( private_key, MBEDTLS_PK_RSA ) ) { @@ -3503,10 +3503,10 @@ static int ssl_parse_encrypted_pms( mbedtls_ssl_context *ssl, &peer_pmslen, sizeof( peer_pms ) ); -#if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) if ( ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ) return( ret ); -#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ /* * Protection against Bleichenbacher's attack: invalid PKCS#1 v1.5 padding @@ -3644,7 +3644,7 @@ 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_C) && \ +#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 || @@ -3770,7 +3770,7 @@ 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_C) +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) if ( ssl->handshake->p_async_operation_ctx != NULL ) { /* There is an asynchronous operation in progress to @@ -3782,7 +3782,7 @@ static int ssl_parse_client_key_exchange( mbedtls_ssl_context *ssl ) p += ssl->conf->psk_identity_len + 2; } else -#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ +#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 256590ff7..f5d332fa8 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -6478,7 +6478,7 @@ void mbedtls_ssl_conf_export_keys_cb( mbedtls_ssl_config *conf, } #endif -#if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) +#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, @@ -6493,7 +6493,7 @@ void mbedtls_ssl_conf_async_private_cb( conf->f_async_cancel = f_async_cancel; conf->p_async_connection_ctx = connection_ctx; } -#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ /* * SSL get accessors @@ -7495,14 +7495,14 @@ void mbedtls_ssl_handshake_free( const mbedtls_ssl_config *conf, } #endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_SSL_SERVER_NAME_INDICATION */ -#if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) if( conf->f_async_cancel != NULL && handshake->p_async_operation_ctx != NULL ) { conf->f_async_cancel( conf->p_async_connection_ctx, handshake->p_async_operation_ctx ); } -#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ #if defined(MBEDTLS_SSL_PROTO_DTLS) mbedtls_free( handshake->verify_cookie ); diff --git a/library/version_features.c b/library/version_features.c index c017c4151..659b96d17 100644 --- a/library/version_features.c +++ b/library/version_features.c @@ -402,6 +402,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 */ @@ -648,9 +651,6 @@ static const char *features[] = { #if defined(MBEDTLS_SHA512_C) "MBEDTLS_SHA512_C", #endif /* MBEDTLS_SHA512_C */ -#if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) - "MBEDTLS_SSL_ASYNC_PRIVATE_C", -#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ #if defined(MBEDTLS_SSL_CACHE_C) "MBEDTLS_SSL_CACHE_C", #endif /* MBEDTLS_SSL_CACHE_C */ diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index 9f05e7d4d..bf25d4e03 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -200,7 +200,7 @@ int main( void ) #define USAGE_IO "" #endif /* MBEDTLS_X509_CRT_PARSE_C */ -#if defined(MBEDTLS_SSL_ASYNC_PRIVATE_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" \ @@ -210,7 +210,7 @@ int main( void ) " 1=start, 2=cancel, 3=resume, 4=pk, negative=first time only)" #else #define USAGE_SSL_ASYNC "" -#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ #if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) #define USAGE_PSK \ @@ -862,7 +862,7 @@ static int ssl_sig_hashes_for_test[] = { }; #endif /* MBEDTLS_X509_CRT_PARSE_C */ -#if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) typedef struct { mbedtls_x509_crt *cert; @@ -1054,7 +1054,7 @@ static void ssl_async_cancel( void *connection_ctx_arg, mbedtls_printf( "Async cancel callback.\n" ); mbedtls_free( ctx ); } -#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ /* * Wait for an event from the underlying transport or the timer @@ -1144,9 +1144,9 @@ int main( int argc, char *argv[] ) mbedtls_x509_crt srvcert2; mbedtls_pk_context pkey2; int key_cert_init = 0, key_cert_init2 = 0; -#if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) ssl_async_key_context_t ssl_async_keys; -#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ #endif /* MBEDTLS_X509_CRT_PARSE_C */ #if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_FS_IO) mbedtls_dhm_context dhm; @@ -1346,7 +1346,7 @@ 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_C) +#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 ) @@ -1364,7 +1364,7 @@ int main( int argc, char *argv[] ) } opt.async_private_error = n; } -#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ else if( strcmp( p, "psk" ) == 0 ) opt.psk = q; else if( strcmp( p, "psk_identity" ) == 0 ) @@ -2261,14 +2261,14 @@ int main( int argc, char *argv[] ) if( key_cert_init ) { mbedtls_pk_context *pk = &pkey; -#if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) if( opt.async_private_delay1 >= 0 ) { ssl_async_set_key( &ssl_async_keys, &srvcert, pk, opt.async_private_delay1 ); pk = NULL; } -#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ +#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 ); @@ -2278,14 +2278,14 @@ int main( int argc, char *argv[] ) if( key_cert_init2 ) { mbedtls_pk_context *pk = &pkey2; -#if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) if( opt.async_private_delay2 >= 0 ) { ssl_async_set_key( &ssl_async_keys, &srvcert2, pk, opt.async_private_delay2 ); pk = NULL; } -#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ +#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 ); @@ -2293,7 +2293,7 @@ int main( int argc, char *argv[] ) } } -#if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) if( opt.async_operations[0] != '-' ) { mbedtls_ssl_async_sign_t *sign = NULL; @@ -2323,7 +2323,7 @@ int main( int argc, char *argv[] ) ssl_async_cancel, &ssl_async_keys ); } -#endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */ +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ #endif /* MBEDTLS_X509_CRT_PARSE_C */ #if defined(SNI_OPTION) @@ -2500,14 +2500,14 @@ handshake: while( ( ret = mbedtls_ssl_handshake( &ssl ) ) != 0 ) { -#if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) +#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_C */ +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE && @@ -2549,7 +2549,7 @@ handshake: } #endif -#if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C) +#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; diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index ee34a6c6b..c692fc9ae 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -4069,7 +4069,7 @@ run_test "Large packet TLS 1.2 AEAD shorter tag" \ # Tests of asynchronous private key support in SSL -requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C +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" \ @@ -4078,7 +4078,7 @@ run_test "SSL async private: sign, delay=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_C +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" \ @@ -4088,7 +4088,7 @@ run_test "SSL async private: sign, delay=1" \ -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_C +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" \ @@ -4097,7 +4097,7 @@ run_test "SSL async private: decrypt, delay=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_C +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" \ @@ -4107,7 +4107,7 @@ run_test "SSL async private: decrypt, delay=1" \ -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_C +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" \ @@ -4117,7 +4117,7 @@ run_test "SSL async private: decrypt RSA-PSK, delay=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_C +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" \ @@ -4128,7 +4128,7 @@ run_test "SSL async private: decrypt RSA-PSK, delay=1" \ -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_C +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" \ @@ -4141,7 +4141,7 @@ run_test "SSL async private: sign callback not present" \ -s "Async resume (slot [0-9]): decrypt done, status=0" \ -s "Successful connection" -requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C +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" \ @@ -4155,7 +4155,7 @@ run_test "SSL async private: decrypt callback not present" \ -s "Successful connection" # key1: ECDSA, key2: RSA; use key1 from slot 0 -requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C +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 \ @@ -4168,7 +4168,7 @@ run_test "SSL async private: slot 0 used with key1" \ -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_C +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 \ @@ -4181,7 +4181,7 @@ run_test "SSL async private: slot 0 used with key2" \ -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_C +requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE run_test "SSL async private: slot 1 used" \ "$P_SRV \ async_operations=s async_private_delay1=1 async_private_delay2=1\ @@ -4194,7 +4194,7 @@ run_test "SSL async private: slot 1 used" \ -s "Async resume (slot 1): sign done, status=0" # key1: ECDSA, key2: RSA; use key2 directly -requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C +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 \ @@ -4204,7 +4204,7 @@ run_test "SSL async private: fall back to transparent key" \ 0 \ -s "Async sign callback: no key matches this certificate." -requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C +requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE run_test "SSL async private: error in start" \ "$P_SRV \ async_operations=s async_private_delay1=1 async_private_delay2=1 \ @@ -4215,7 +4215,7 @@ run_test "SSL async private: error in start" \ -S "Async resume" \ -s "! mbedtls_ssl_handshake returned" -requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C +requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE run_test "SSL async private: cancel after start" \ "$P_SRV \ async_operations=s async_private_delay1=1 async_private_delay2=1 \ @@ -4226,7 +4226,7 @@ run_test "SSL async private: cancel after start" \ -S "Async resume" \ -s "Async cancel" -requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C +requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE run_test "SSL async private: error in resume" \ "$P_SRV \ async_operations=s async_private_delay1=1 async_private_delay2=1 \ @@ -4237,7 +4237,7 @@ run_test "SSL async private: error in resume" \ -s "Async resume callback: injected error" \ -s "! mbedtls_ssl_handshake returned" -requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C +requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE run_test "SSL async private: error in pk" \ "$P_SRV \ async_operations=s async_private_delay1=1 async_private_delay2=1 \ @@ -4248,7 +4248,7 @@ run_test "SSL async private: error in pk" \ -s "Async resume callback: sign done but injected error" \ -s "! mbedtls_ssl_handshake returned" -requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C +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 \ @@ -4260,7 +4260,7 @@ run_test "SSL async private: cancel after start then operate correctly" \ -s "Async resume" \ -s "Successful connection" -requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C +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 \ @@ -4272,7 +4272,7 @@ run_test "SSL async private: error in resume then operate correctly" \ -s "Successful connection" # key1: ECDSA, key2: RSA; use key1 through async, then key2 directly -requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C +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 \ @@ -4289,7 +4289,7 @@ run_test "SSL async private: cancel after start then fall back to transparent -s "Successful connection" # key1: ECDSA, key2: RSA; use key1 through async, then key2 directly -requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C +requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE run_test "SSL async private: error in resume then fall back to transparent key" \ "$P_SRV \ async_operations=s async_private_delay1=1 async_private_error=-3 \ @@ -4304,7 +4304,7 @@ run_test "SSL async private: error in resume then fall back to transparent ke -s "Async sign callback: no key matches this certificate." \ -s "Successful connection" -requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C +requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE requires_config_enabled MBEDTLS_SSL_RENEGOTIATION run_test "SSL async private: renegotiation: client-initiated; sign" \ "$P_SRV \ @@ -4315,7 +4315,7 @@ run_test "SSL async private: renegotiation: client-initiated; sign" \ -s "Async sign callback: using key slot " \ -s "Async resume (slot [0-9]): sign done, status=0" -requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C +requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE requires_config_enabled MBEDTLS_SSL_RENEGOTIATION run_test "SSL async private: renegotiation: server-initiated; sign" \ "$P_SRV \ @@ -4326,7 +4326,7 @@ run_test "SSL async private: renegotiation: server-initiated; sign" \ -s "Async sign callback: using key slot " \ -s "Async resume (slot [0-9]): sign done, status=0" -requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C +requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE requires_config_enabled MBEDTLS_SSL_RENEGOTIATION run_test "SSL async private: renegotiation: client-initiated; decrypt" \ "$P_SRV \ @@ -4338,7 +4338,7 @@ run_test "SSL async private: renegotiation: client-initiated; decrypt" \ -s "Async decrypt callback: using key slot " \ -s "Async resume (slot [0-9]): decrypt done, status=0" -requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE_C +requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE requires_config_enabled MBEDTLS_SSL_RENEGOTIATION run_test "SSL async private: renegotiation: server-initiated; decrypt" \ "$P_SRV \ From 2e333375708f01bed5db51a3d89613e2fdd30daf Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 24 Apr 2018 13:22:10 +0200 Subject: [PATCH 34/69] Fix invalid data being accepted in RSA-decryption-based ciphersuites In the refactoring of ssl_parse_encrypted_pms, I advertently broke the case when decryption signalled an error, with the variable ret getting overwritten before calculating diff. Move the calculation of diff immediately after getting the return code to make the connection more obvious. Also move the calculation of mask immediately after the calculation of diff, which doesn't change the behavior, because I find the code clearer that way. --- library/ssl_srv.c | 48 +++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/library/ssl_srv.c b/library/ssl_srv.c index de8056426..e1dc5a8e9 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -3508,6 +3508,30 @@ static int ssl_parse_encrypted_pms( mbedtls_ssl_context *ssl, 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 ); + + /* 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 @@ -3524,18 +3548,6 @@ static int ssl_parse_encrypted_pms( mbedtls_ssl_context *ssl, return( ret ); } - mbedtls_ssl_write_version( ssl->handshake->max_major_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]; - #if defined(MBEDTLS_SSL_DEBUG_ALL) if( diff != 0 ) MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); @@ -3549,18 +3561,6 @@ 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++ ) From 9b562d5c3671354d61193c285eaf5e50d62d64e4 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 25 Apr 2018 20:32:43 +0200 Subject: [PATCH 35/69] mbedtls_ssl_handshake_free: take the SSL context as argument Change the signature of mbedtls_ssl_handshake_free again. Now take the whole SSL context as argument and not just the configuration and the handshake substructure. This is in preparation for changing the asynchronous cancel callback to take the SSL context as an argument. --- include/mbedtls/ssl_internal.h | 6 ++---- library/ssl_tls.c | 18 +++++++++--------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h index 4c7205d70..334b5d852 100644 --- a/include/mbedtls/ssl_internal.h +++ b/include/mbedtls/ssl_internal.h @@ -414,11 +414,9 @@ void mbedtls_ssl_transform_free( mbedtls_ssl_transform *transform ); * \brief Free referenced items in an SSL handshake context and clear * memory * - * \param conf SSL configuration - * \param handshake SSL handshake context + * \param ssl SSL context */ -void mbedtls_ssl_handshake_free( const mbedtls_ssl_config *conf, - 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 ); diff --git a/library/ssl_tls.c b/library/ssl_tls.c index f5d332fa8..aa48b4538 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -5201,7 +5201,7 @@ static void ssl_handshake_wrapup_free_hs_transform( mbedtls_ssl_context *ssl ) /* * Free our handshake params */ - mbedtls_ssl_handshake_free( ssl->conf, ssl->handshake ); + mbedtls_ssl_handshake_free( ssl ); mbedtls_free( ssl->handshake ); ssl->handshake = NULL; @@ -5556,7 +5556,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->conf, ssl->handshake ); + mbedtls_ssl_handshake_free( ssl ); /* * Either the pointers are now NULL or cleared properly and can be freed. @@ -7426,12 +7426,12 @@ static void ssl_key_cert_free( mbedtls_ssl_key_cert *key_cert ) } #endif /* MBEDTLS_X509_CRT_PARSE_C */ -void mbedtls_ssl_handshake_free( const mbedtls_ssl_config *conf, - 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; - (void) conf; /* Unused in some compile-time configurations. */ #if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ defined(MBEDTLS_SSL_PROTO_TLS1_1) @@ -7496,11 +7496,11 @@ void mbedtls_ssl_handshake_free( const mbedtls_ssl_config *conf, #endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_SSL_SERVER_NAME_INDICATION */ #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) - if( conf->f_async_cancel != NULL && + if( ssl->conf->f_async_cancel != NULL && handshake->p_async_operation_ctx != NULL ) { - conf->f_async_cancel( conf->p_async_connection_ctx, - handshake->p_async_operation_ctx ); + ssl->conf->f_async_cancel( ssl->conf->p_async_connection_ctx, + handshake->p_async_operation_ctx ); } #endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ @@ -7571,7 +7571,7 @@ void mbedtls_ssl_free( mbedtls_ssl_context *ssl ) if( ssl->handshake ) { - mbedtls_ssl_handshake_free( ssl->conf, ssl->handshake ); + mbedtls_ssl_handshake_free( ssl ); mbedtls_ssl_transform_free( ssl->transform_negotiate ); mbedtls_ssl_session_free( ssl->session_negotiate ); From df13d5c7a6e0e4678075f948499530654ff65d5b Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 25 Apr 2018 20:39:48 +0200 Subject: [PATCH 36/69] Pass the SSL context to async callbacks When a handshake step starts an asynchronous operation, the application needs to know which SSL connection the operation is for, so that when the operation completes, the application can wake that connection up. Therefore the async start callbacks need to take the SSL context as an argument. It isn't enough to let them set a cookie in the SSL connection, the application needs to be able to find the right SSL connection later. Also pass the SSL context to the other callbacks for consistency. Add a new field to the handshake that the application can use to store a per-connection context. This new field replaces the former context (operation_ctx) that was created by the start function and passed to the resume function. Add a boolean flag to the handshake structure to track whether an asynchronous operation is in progress. This is more robust than relying on the application to set a non-null application context. --- include/mbedtls/ssl.h | 148 ++++++++++++++++++++------------- include/mbedtls/ssl_internal.h | 16 +++- library/ssl_srv.c | 46 +++++----- library/ssl_tls.c | 36 +++++--- programs/ssl/ssl_server2.c | 58 ++++++------- 5 files changed, 179 insertions(+), 125 deletions(-) diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index be27b89ca..2dac1da77 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -537,6 +537,22 @@ 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; +typedef struct mbedtls_ssl_config mbedtls_ssl_config; + +/* Defined in ssl_internal.h */ +typedef struct mbedtls_ssl_transform mbedtls_ssl_transform; +typedef struct mbedtls_ssl_handshake_params mbedtls_ssl_handshake_params; +typedef struct mbedtls_ssl_sig_hash_set_t mbedtls_ssl_sig_hash_set_t; +#if defined(MBEDTLS_X509_CRT_PARSE_C) +typedef struct mbedtls_ssl_key_cert mbedtls_ssl_key_cert; +#endif +#if defined(MBEDTLS_SSL_PROTO_DTLS) +typedef struct mbedtls_ssl_flight_item mbedtls_ssl_flight_item; +#endif + #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) #if defined(MBEDTLS_X509_CRT_PARSE_C) /** @@ -553,22 +569,20 @@ typedef int mbedtls_ssl_get_timer_t( void * ctx ); * this function sends or enqueues a request and does * not wait for the operation to complete. * - * The parameters \c connection_ctx and \c cert are + * The parameters \c ssl and \c cert are * guaranteed to remain valid as long as the SSL * configuration remains valid. On the other hand, this * function must save the contents of \c hash, as the * \c hash buffer is no longer valid when this function * returns. * - * \param connection_ctx Pointer to the connection context set in the - * SSL configuration - * \param p_operation_ctx On success, pointer to the operation context. - * This must be a non-null pointer. Success means - * that an operation was started, and the return - * status is 0 or \c MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS. - * This pointer will be passed to later calls to the - * resume or cancel function. If the callback fails, - * the value is ignored. + * This function may call mbedtls_ssl_async_set_data() to + * store an operation context for later retrieval + * by the resume callback. + * + * \param config_data The configuration data parameter passed to + * mbedtls_ssl_conf_async_private_cb(). + * \param ssl The SSL connection instance. * \param cert Certificate containing the public key * \param md_alg Hash algorithm * \param hash Buffer containing the hash. This buffer is @@ -586,8 +600,8 @@ typedef int mbedtls_ssl_get_timer_t( void * ctx ); * - Any other error indicates a fatal failure and is * propagated up the call chain. */ -typedef int mbedtls_ssl_async_sign_t( void *connection_ctx, - void **p_operation_ctx, +typedef int mbedtls_ssl_async_sign_t( void *config_data, + mbedtls_ssl_context *ssl, mbedtls_x509_crt *cert, mbedtls_md_type_t md_alg, const unsigned char *hash, @@ -607,22 +621,20 @@ typedef int mbedtls_ssl_async_sign_t( void *connection_ctx, * this function sends or enqueues a request and does * not wait for the operation to complete. * - * The parameters \c connection_ctx and \c cert are + * The parameters \c ssl and \c cert are * guaranteed to remain valid as long as the SSL * configuration remains valid. On the other hand, this * function must save the contents of \c hash, as the * \c hash buffer is no longer valid when this function * returns. * - * \param connection_ctx Pointer to the connection context set in the - * SSL configuration - * \param p_operation_ctx On success, pointer to the operation context. - * This must be a non-null pointer. Success means - * that an operation was started, and the return - * status is 0 or \c MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS. - * This pointer will be passed to later calls to the - * resume or cancel function. If the callback fails, - * the value is ignored. + * This function may call mbedtls_ssl_async_set_data() to + * store an operation context for later retrieval + * by the resume callback. + * + * \param config_data The configuration data parameter passed to + * mbedtls_ssl_conf_async_private_cb(). + * \param ssl The SSL connection instance. * \param cert Certificate containing the public key * \param input Buffer containing the input ciphertext. This buffer * is no longer valid when the function returns. @@ -639,8 +651,8 @@ typedef int mbedtls_ssl_async_sign_t( void *connection_ctx, * - Any other error indicates a fatal failure and is * propagated up the call chain. */ -typedef int mbedtls_ssl_async_decrypt_t( void *connection_ctx, - void **p_operation_ctx, +typedef int mbedtls_ssl_async_decrypt_t( void *config_data, + mbedtls_ssl_context *ssl, mbedtls_x509_crt *cert, const unsigned char *input, size_t input_len ); @@ -652,13 +664,14 @@ typedef int mbedtls_ssl_async_decrypt_t( void *connection_ctx, * Callback to resume an external operation * started by the \c mbedtls_ssl_async_sign_t callback. * - * \param connection_ctx Pointer to the connection context set in the - * SSL configuration - * \param operation_ctx Pointer to the operation context created by - * the start function. If this callback returns - * any value other than - * \c MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS, it should - * free all resources associated with this context. + * This function may call mbedtls_ssl_async_get_data() to + * retrieve an operation context set by the start callback. + * It may call mbedtls_ssl_async_set_data() to modify this + * context. + * + * \param config_data The configuration data parameter passed to + * mbedtls_ssl_conf_async_private_cb(). + * \param ssl The SSL connection instance. * \param output Buffer containing the output on success * \param output_len On success, number of bytes written to \c output * \param output_size Size of the \c output buffer in bytes @@ -672,8 +685,8 @@ typedef int mbedtls_ssl_async_decrypt_t( void *connection_ctx, * - Any other error means that the operation is aborted. * The SSL handshake is aborted. */ -typedef int mbedtls_ssl_async_resume_t( void *connection_ctx, - void *operation_ctx, +typedef int mbedtls_ssl_async_resume_t( void *config_data, + mbedtls_ssl_context *ssl, unsigned char *output, size_t *output_len, size_t output_size ); @@ -684,32 +697,17 @@ typedef int mbedtls_ssl_async_resume_t( void *connection_ctx, * Callback to cancel an external operation * started by the \c mbedtls_ssl_async_sign_t callback. * - * \param connection_ctx Pointer to the connection context set in the - * SSL configuration - * \param operation_ctx Pointer to the operation context created by - * the start function. The callback should free - * all resources associated with this context. + * This function may call mbedtls_ssl_async_get_data() to + * retrieve an operation context set by the start callback. + * + * \param config_data The configuration data parameter passed to + * mbedtls_ssl_conf_async_private_cb(). + * \param ssl The SSL connection instance. */ -typedef void mbedtls_ssl_async_cancel_t( void *connection_ctx, - void *operation_ctx ); +typedef void mbedtls_ssl_async_cancel_t( void *config_data, + mbedtls_ssl_context *ssl ); #endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ -/* Defined below */ -typedef struct mbedtls_ssl_session mbedtls_ssl_session; -typedef struct mbedtls_ssl_context mbedtls_ssl_context; -typedef struct mbedtls_ssl_config mbedtls_ssl_config; - -/* Defined in ssl_internal.h */ -typedef struct mbedtls_ssl_transform mbedtls_ssl_transform; -typedef struct mbedtls_ssl_handshake_params mbedtls_ssl_handshake_params; -typedef struct mbedtls_ssl_sig_hash_set_t mbedtls_ssl_sig_hash_set_t; -#if defined(MBEDTLS_X509_CRT_PARSE_C) -typedef struct mbedtls_ssl_key_cert mbedtls_ssl_key_cert; -#endif -#if defined(MBEDTLS_SSL_PROTO_DTLS) -typedef struct mbedtls_ssl_flight_item mbedtls_ssl_flight_item; -#endif - /* * This structure is used for storing current session data. */ @@ -833,7 +831,7 @@ struct mbedtls_ssl_config #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_connection_ctx; /*!< connection context for asynchronous operation callbacks */ + void *p_async_config_data; /*!< Configuration data set by mbedtls_ssl_conf_async_private_cb() and passed to the callbacks. */ #endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ #if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) @@ -1505,15 +1503,45 @@ void mbedtls_ssl_conf_export_keys_cb( mbedtls_ssl_config *conf, * \param f_async_cancel Callback to cancel an asynchronous operation. See * the description of \c mbedtls_ssl_async_cancel_t * for more information. - * \param connection_ctx Pointer to the connection context which will be - * passed to the callbacks + * \param config_data A pointer to configuration data which will be + * passed to the callbacks. The library stores and + * passes back 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 *connection_ctx ); + void *config_data ); + +/** + * \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_data() + * has not been called during the current handshake yet, + * this function returns \c NULL. + */ +void *mbedtls_ssl_async_get_data( 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_data() later during the same handshake + * to retrieve this value. + */ +void mbedtls_ssl_async_set_data( mbedtls_ssl_context *ssl, + void *ctx ); #endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ /** diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h index 334b5d852..506aff395 100644 --- a/include/mbedtls/ssl_internal.h +++ b/include/mbedtls/ssl_internal.h @@ -243,9 +243,6 @@ 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_ASYNC_PRIVATE) - void *p_async_operation_ctx; /*!< asynchronous operation context */ -#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ #if defined(MBEDTLS_SSL_PROTO_DTLS) unsigned int out_msg_seq; /*!< Outgoing handshake sequence number */ @@ -311,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) + 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 */ }; /* diff --git a/library/ssl_srv.c b/library/ssl_srv.c index e1dc5a8e9..8bd332cba 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -2841,13 +2841,13 @@ static int ssl_resume_server_key_exchange( mbedtls_ssl_context *ssl, { size_t sig_max_len = ( ssl->out_buf + MBEDTLS_SSL_MAX_CONTENT_LEN - ( ssl->out_msg + ssl->out_msglen + 2 ) ); - int ret = ssl->conf->f_async_resume( ssl->conf->p_async_connection_ctx, - ssl->handshake->p_async_operation_ctx, + int ret = ssl->conf->f_async_resume( ssl->conf->p_async_config_data, ssl, ssl->out_msg + ssl->out_msglen + 2, signature_len, sig_max_len ); if( ret != MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ) { - ssl->handshake->p_async_operation_ctx = NULL; + ssl->handshake->async_in_progress = 0; + mbedtls_ssl_async_set_data( ssl, NULL ); } MBEDTLS_SSL_DEBUG_RET( 2, "ssl_resume_server_key_exchange", ret ); return( ret ); @@ -3167,22 +3167,23 @@ curve_matching_done: #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) if( ssl->conf->f_async_sign_start != NULL ) { - ret = ssl->conf->f_async_sign_start( - ssl->conf->p_async_connection_ctx, - &ssl->handshake->p_async_operation_ctx, - mbedtls_ssl_own_cert( ssl ), - md_alg, hash, hashlen ); + ret = ssl->conf->f_async_sign_start( ssl->conf->p_async_config_data, + 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", ret ); + MBEDTLS_SSL_DEBUG_RET( 1, "f_async_sign_start", ret ); return( ret ); } } @@ -3251,7 +3252,7 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) defined(MBEDTLS_SSL_ASYNC_PRIVATE) /* If we have already prepared the message and there is an ongoing signature operation, resume signing. */ - if( ssl->handshake->p_async_operation_ctx != NULL ) + if( ssl->handshake->async_in_progress != 0 ) { MBEDTLS_SSL_DEBUG_MSG( 2, ( "resuming signature operation" ) ); ret = ssl_resume_server_key_exchange( ssl, &signature_len ); @@ -3385,12 +3386,12 @@ static int ssl_resume_decrypt_pms( mbedtls_ssl_context *ssl, size_t *peer_pmslen, size_t peer_pmssize ) { - int ret = ssl->conf->f_async_resume( ssl->conf->p_async_connection_ctx, - ssl->handshake->p_async_operation_ctx, + int ret = ssl->conf->f_async_resume( ssl->conf->p_async_config_data, ssl, peer_pms, peer_pmslen, peer_pmssize ); if( ret != MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ) { - ssl->handshake->p_async_operation_ctx = NULL; + ssl->handshake->async_in_progress = 0; + mbedtls_ssl_async_set_data( ssl, NULL ); } MBEDTLS_SSL_DEBUG_RET( 2, "ssl_decrypt_encrypted_pms", ret ); return( ret ); @@ -3412,7 +3413,7 @@ static int ssl_decrypt_encrypted_pms( mbedtls_ssl_context *ssl, #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->p_async_operation_ctx != NULL ) + if( ssl->handshake->async_in_progress != 0 ) { MBEDTLS_SSL_DEBUG_MSG( 2, ( "resuming decryption operation" ) ); return( ssl_resume_decrypt_pms( ssl, @@ -3448,25 +3449,26 @@ static int ssl_decrypt_encrypted_pms( mbedtls_ssl_context *ssl, #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) if( ssl->conf->f_async_decrypt_start != NULL ) { - ret = ssl->conf->f_async_decrypt_start( - ssl->conf->p_async_connection_ctx, - &ssl->handshake->p_async_operation_ctx, - mbedtls_ssl_own_cert( ssl ), - p, len ); + ret = ssl->conf->f_async_decrypt_start( ssl->conf->p_async_config_data, + 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_sign", ret ); + MBEDTLS_SSL_DEBUG_RET( 1, "f_async_decrypt_start", ret ); return( ret ); } } @@ -3649,7 +3651,7 @@ static int ssl_parse_client_key_exchange( mbedtls_ssl_context *ssl ) 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->p_async_operation_ctx != NULL ) ) + ( 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 @@ -3771,7 +3773,7 @@ static int ssl_parse_client_key_exchange( mbedtls_ssl_context *ssl ) if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ) { #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) - if ( ssl->handshake->p_async_operation_ctx != NULL ) + if ( ssl->handshake->async_in_progress != 0 ) { /* There is an asynchronous operation in progress to * decrypt the encrypted premaster secret, so skip diff --git a/library/ssl_tls.c b/library/ssl_tls.c index aa48b4538..2c6eef8ec 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -6485,13 +6485,28 @@ void mbedtls_ssl_conf_async_private_cb( 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 *connection_ctx ) + 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_connection_ctx = connection_ctx; + conf->p_async_config_data = async_config_data; +} + +void *mbedtls_ssl_async_get_data( mbedtls_ssl_context *ssl ) +{ + if( ssl->handshake == NULL ) + return( NULL ); + else + return( ssl->handshake->user_async_ctx ); +} + +void mbedtls_ssl_async_set_data( mbedtls_ssl_context *ssl, + void *ctx ) +{ + if( ssl->handshake != NULL ) + ssl->handshake->user_async_ctx = ctx; } #endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ @@ -7433,6 +7448,14 @@ void mbedtls_ssl_handshake_free( mbedtls_ssl_context *ssl ) 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->conf->p_async_config_data, 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 ); @@ -7495,15 +7518,6 @@ void mbedtls_ssl_handshake_free( mbedtls_ssl_context *ssl ) } #endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_SSL_SERVER_NAME_INDICATION */ -#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) - if( ssl->conf->f_async_cancel != NULL && - handshake->p_async_operation_ctx != NULL ) - { - ssl->conf->f_async_cancel( ssl->conf->p_async_connection_ctx, - handshake->p_async_operation_ctx ); - } -#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ - #if defined(MBEDTLS_SSL_PROTO_DTLS) mbedtls_free( handshake->verify_cookie ); mbedtls_free( handshake->hs_msg ); diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index bf25d4e03..9ff735ad8 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -909,15 +909,15 @@ typedef struct unsigned delay; } ssl_async_operation_context_t; -static int ssl_async_start( void *connection_ctx_arg, - void **p_operation_ctx, +static int ssl_async_start( void *config_data_arg, + mbedtls_ssl_context *ssl, mbedtls_x509_crt *cert, const char *op_name, mbedtls_md_type_t md_alg, const unsigned char *input, size_t input_len ) { - ssl_async_key_context_t *key_ctx = connection_ctx_arg; + ssl_async_key_context_t *config_data = config_data_arg; size_t slot; ssl_async_operation_context_t *ctx = NULL; @@ -927,21 +927,21 @@ static int ssl_async_start( void *connection_ctx_arg, mbedtls_printf( "Async %s callback: looking for DN=%s\n", op_name, dn ); } - for( slot = 0; slot < key_ctx->slots_used; slot++ ) + for( slot = 0; slot < config_data->slots_used; slot++ ) { - if( key_ctx->slots[slot].cert == cert ) + if( config_data->slots[slot].cert == cert ) break; } - if( slot == key_ctx->slots_used ) + 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 %zd, delay=%u.\n", - op_name, slot, key_ctx->slots[slot].delay ); + op_name, slot, config_data->slots[slot].delay ); - if( key_ctx->inject_error == SSL_ASYNC_INJECT_ERROR_START ) + 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 ); @@ -957,8 +957,8 @@ static int ssl_async_start( void *connection_ctx_arg, ctx->md_alg = md_alg; memcpy( ctx->input, input, input_len ); ctx->input_len = input_len; - ctx->delay = key_ctx->slots[slot].delay; - *p_operation_ctx = ctx; + ctx->delay = config_data->slots[slot].delay; + mbedtls_ssl_async_set_data( ssl, ctx ); if( ctx->delay == 0 ) return( 0 ); @@ -966,42 +966,42 @@ static int ssl_async_start( void *connection_ctx_arg, return( MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ); } -static int ssl_async_sign( void *connection_ctx_arg, - void **p_operation_ctx, +static int ssl_async_sign( void *config_data_arg, + 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( connection_ctx_arg, p_operation_ctx, cert, + return( ssl_async_start( config_data_arg, ssl, cert, "sign", md_alg, hash, hash_len ) ); } -static int ssl_async_decrypt( void *connection_ctx_arg, - void **p_operation_ctx, +static int ssl_async_decrypt( void *config_data_arg, + mbedtls_ssl_context *ssl, mbedtls_x509_crt *cert, const unsigned char *input, size_t input_len ) { - return( ssl_async_start( connection_ctx_arg, p_operation_ctx, cert, + return( ssl_async_start( config_data_arg, ssl, cert, "decrypt", MBEDTLS_MD_NONE, input, input_len ) ); } -static int ssl_async_resume( void *connection_ctx_arg, - void *operation_ctx_arg, +static int ssl_async_resume( void *config_data_arg, + mbedtls_ssl_context *ssl, unsigned char *output, size_t *output_len, size_t output_size ) { - ssl_async_operation_context_t *ctx = operation_ctx_arg; - ssl_async_key_context_t *connection_ctx = connection_ctx_arg; - ssl_async_key_slot_t *key_slot = &connection_ctx->slots[ctx->slot]; + ssl_async_operation_context_t *ctx = mbedtls_ssl_async_get_data( ssl ); + ssl_async_key_context_t *config_data = config_data_arg; + ssl_async_key_slot_t *key_slot = &config_data->slots[ctx->slot]; int ret; const char *op_name; - if( connection_ctx->inject_error == SSL_ASYNC_INJECT_ERROR_RESUME ) + if( config_data->inject_error == SSL_ASYNC_INJECT_ERROR_RESUME ) { mbedtls_printf( "Async resume callback: injected error\n" ); return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); @@ -1021,7 +1021,7 @@ static int ssl_async_resume( void *connection_ctx_arg, ret = mbedtls_pk_decrypt( key_slot->pk, ctx->input, ctx->input_len, output, output_len, output_size, - connection_ctx->f_rng, connection_ctx->p_rng ); + config_data->f_rng, config_data->p_rng ); } else { @@ -1030,10 +1030,10 @@ static int ssl_async_resume( void *connection_ctx_arg, ctx->md_alg, ctx->input, ctx->input_len, output, output_len, - connection_ctx->f_rng, connection_ctx->p_rng ); + config_data->f_rng, config_data->p_rng ); } - if( connection_ctx->inject_error == SSL_ASYNC_INJECT_ERROR_PK ) + if( config_data->inject_error == SSL_ASYNC_INJECT_ERROR_PK ) { mbedtls_printf( "Async resume callback: %s done but injected error\n", op_name ); @@ -1046,11 +1046,11 @@ static int ssl_async_resume( void *connection_ctx_arg, return( ret ); } -static void ssl_async_cancel( void *connection_ctx_arg, - void *operation_ctx_arg ) +static void ssl_async_cancel( void *config_data_arg, + mbedtls_ssl_context *ssl ) { - ssl_async_operation_context_t *ctx = operation_ctx_arg; - (void) connection_ctx_arg; + ssl_async_operation_context_t *ctx = mbedtls_ssl_async_get_data( ssl ); + (void) config_data_arg; mbedtls_printf( "Async cancel callback.\n" ); mbedtls_free( ctx ); } From 168dae85676c8dcda800e2e28c8e90e7ae3802ff Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 25 Apr 2018 23:35:42 +0200 Subject: [PATCH 37/69] Comment formatting and whitespace fixes --- library/ssl_srv.c | 21 ++++++++++----------- tests/ssl-opt.sh | 2 +- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 8bd332cba..92372310d 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -2856,8 +2856,8 @@ static int ssl_resume_server_key_exchange( mbedtls_ssl_context *ssl, 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. */ + * 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 ) { @@ -3212,9 +3212,9 @@ curve_matching_done: } /* 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 */ + * 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; @@ -3251,7 +3251,7 @@ 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) /* If we have already prepared the message and there is an ongoing - signature operation, resume signing. */ + * signature operation, resume signing. */ if( ssl->handshake->async_in_progress != 0 ) { MBEDTLS_SSL_DEBUG_MSG( 2, ( "resuming signature operation" ) ); @@ -3275,8 +3275,8 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) } /* 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. */ + * 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 ) { @@ -3412,7 +3412,7 @@ static int ssl_decrypt_encrypted_pms( mbedtls_ssl_context *ssl, #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) /* If we have already started decoding the message and there is an ongoing - decryption operation, resume signing. */ + * decryption operation, resume signing. */ if( ssl->handshake->async_in_progress != 0 ) { MBEDTLS_SSL_DEBUG_MSG( 2, ( "resuming decryption operation" ) ); @@ -3476,7 +3476,6 @@ static int ssl_decrypt_encrypted_pms( mbedtls_ssl_context *ssl, 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 ); } @@ -3655,7 +3654,7 @@ static int ssl_parse_client_key_exchange( mbedtls_ssl_context *ssl ) { /* We've already read a record and there is an asynchronous * operation in progress to decrypt it. So skip reading the - record. */ + * record. */ MBEDTLS_SSL_DEBUG_MSG( 3, ( "will resume decryption of previously-read record" ) ); } else diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index c692fc9ae..1a35aac41 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -4184,7 +4184,7 @@ run_test "SSL async private: slot 0 used with key2" \ requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE run_test "SSL async private: slot 1 used" \ "$P_SRV \ - async_operations=s async_private_delay1=1 async_private_delay2=1\ + 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" \ From ad28bf0e58b21d38d948e04cd71ba9c84927b02f Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 26 Apr 2018 00:19:16 +0200 Subject: [PATCH 38/69] Documentation improvements --- include/mbedtls/ssl.h | 97 +++++++++++++++++++++----------------- library/ssl_srv.c | 4 ++ programs/ssl/ssl_server2.c | 10 ++-- tests/ssl-opt.sh | 2 +- 4 files changed, 65 insertions(+), 48 deletions(-) diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 2dac1da77..9b17e610b 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -556,25 +556,24 @@ typedef struct mbedtls_ssl_flight_item mbedtls_ssl_flight_item; #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) #if defined(MBEDTLS_X509_CRT_PARSE_C) /** - * \brief Callback type: start external signature operation + * \brief Callback type: start external signature operation. * - * Callback to start a signature operation using an + * This callback is called during an SSL handshake to start + * a signature decryption operation using an * external processor. The parameter \c cert contains * the public key; it is up to the callback function to - * look up the associated private key or a handle to the - * private key. + * determine how to access the associated private key. * - * This function must start the signature operation. - * It is expected to be non-blocking, i.e. typically - * this function sends or enqueues a request and does - * not wait for the operation to complete. + * 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 \c ssl and \c cert are * guaranteed to remain valid as long as the SSL * configuration remains valid. On the other hand, this - * function must save the contents of \c hash, as the - * \c hash buffer is no longer valid when this function - * returns. + * function must save the contents of \c hash if the value + * is needed for later processing, because the \c hash buffer + * is no longer valid after this function returns. * * This function may call mbedtls_ssl_async_set_data() to * store an operation context for later retrieval @@ -582,12 +581,13 @@ typedef struct mbedtls_ssl_flight_item mbedtls_ssl_flight_item; * * \param config_data The configuration data parameter passed to * mbedtls_ssl_conf_async_private_cb(). - * \param ssl The SSL connection instance. - * \param cert Certificate containing the public key - * \param md_alg Hash algorithm + * \param ssl The SSL connection instance. It should not be + * modified other than via mbedtls_ssl_async_set_data(). + * \param cert Certificate containing the public key. + * \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 + * \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. @@ -608,25 +608,24 @@ typedef int mbedtls_ssl_async_sign_t( void *config_data, size_t hash_len ); /** - * \brief Callback type: start external decryption operation + * \brief Callback type: start external decryption operation. * - * Callback to start a decryption operation using an + * This callback is called during an SSL handshake to start + * an RSA decryption operation using an * external processor. The parameter \c cert contains * the public key; it is up to the callback function to - * look up the associated private key or a handle to the - * private key. + * determine how to access the associated private key. * - * This function must start the decryption operation. - * It is expected to be non-blocking, i.e. typically - * this function sends or enqueues a request and does - * not wait for the operation to complete. + * 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 \c ssl and \c cert are * guaranteed to remain valid as long as the SSL * configuration remains valid. On the other hand, this - * function must save the contents of \c hash, as the - * \c hash buffer is no longer valid when this function - * returns. + * function must save the contents of \c input if the value + * is needed for later processing, because the \c input buffer + * is no longer valid after this function returns. * * This function may call mbedtls_ssl_async_set_data() to * store an operation context for later retrieval @@ -634,11 +633,12 @@ typedef int mbedtls_ssl_async_sign_t( void *config_data, * * \param config_data The configuration data parameter passed to * mbedtls_ssl_conf_async_private_cb(). - * \param ssl The SSL connection instance. - * \param cert Certificate containing the public key + * \param ssl The SSL connection instance. It should not be + * modified other than via mbedtls_ssl_async_set_data(). + * \param cert Certificate containing the public key. * \param input Buffer containing the input ciphertext. This buffer * is no longer valid when the function returns. - * \param input_len Size of the \c input buffer in bytes + * \param input_len Size of the \c input buffer in bytes. * * \return - 0 if the operation was started successfully and the SSL * stack should call the resume callback immediately. @@ -659,10 +659,17 @@ typedef int mbedtls_ssl_async_decrypt_t( void *config_data, #endif /* MBEDTLS_X509_CRT_PARSE_C */ /** - * \brief Callback type: resume external operation + * \brief Callback type: resume external operation. * - * Callback to resume an external operation - * started by the \c mbedtls_ssl_async_sign_t callback. + * This callback is called during an SSL handshake to resume + * an external operation started by the + * \c mbedtls_ssl_async_sign_t or + * \c 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_async_get_data() to * retrieve an operation context set by the start callback. @@ -671,10 +678,12 @@ typedef int mbedtls_ssl_async_decrypt_t( void *config_data, * * \param config_data The configuration data parameter passed to * mbedtls_ssl_conf_async_private_cb(). - * \param ssl The SSL connection instance. - * \param output Buffer containing the output on success - * \param output_len On success, number of bytes written to \c output - * \param output_size Size of the \c output buffer in bytes + * \param ssl The SSL connection instance. It should not be + * modified other than via mbedtls_ssl_async_set_data(). + * \param output Buffer containing the output (signature or decrypted + * data) on success. + * \param output_len On success, number of bytes written to \c output. + * \param output_size Size of the \c output buffer in bytes. * * \return - 0 if output of the operation is available in the * \c output buffer. @@ -692,17 +701,18 @@ typedef int mbedtls_ssl_async_resume_t( void *config_data, size_t output_size ); /** - * \brief Callback type: cancel external operation + * \brief Callback type: cancel external operation. * - * Callback to cancel an external operation - * started by the \c mbedtls_ssl_async_sign_t callback. + * This callback is called if an SSL connection is closed + * while an asynchronous operation is in progress. * * This function may call mbedtls_ssl_async_get_data() to * retrieve an operation context set by the start callback. * * \param config_data The configuration data parameter passed to * mbedtls_ssl_conf_async_private_cb(). - * \param ssl The SSL connection instance. + * \param ssl The SSL connection instance. It should not be + * modified. */ typedef void mbedtls_ssl_async_cancel_t( void *config_data, mbedtls_ssl_context *ssl ); @@ -1499,10 +1509,13 @@ void mbedtls_ssl_conf_export_keys_cb( mbedtls_ssl_config *conf, * associated with the certificate will be used. * \param f_async_resume Callback to resume an asynchronous operation. See * the description of \c mbedtls_ssl_async_resume_t - * for more information. + * 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 \c mbedtls_ssl_async_cancel_t - * for more information. + * for more information. This may be \c NULL if + * no cleanup is needed. * \param config_data A pointer to configuration data which will be * passed to the callbacks. The library stores and * passes back this value without dereferencing it. diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 92372310d..c4f1adee8 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -3267,6 +3267,10 @@ static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) 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 diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index 9ff735ad8..7d9072e87 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -871,11 +871,11 @@ typedef struct } ssl_async_key_slot_t; typedef enum { - SSL_ASYNC_INJECT_ERROR_NONE = 0, - SSL_ASYNC_INJECT_ERROR_START, - SSL_ASYNC_INJECT_ERROR_CANCEL, - SSL_ASYNC_INJECT_ERROR_RESUME, - SSL_ASYNC_INJECT_ERROR_PK + 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 */ + SSL_ASYNC_INJECT_ERROR_PK /*!< Inject error during resume */ #define SSL_ASYNC_INJECT_ERROR_MAX SSL_ASYNC_INJECT_ERROR_PK } ssl_async_inject_error_t; diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index 1a35aac41..15503e2c5 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -4182,7 +4182,7 @@ run_test "SSL async private: slot 0 used with key2" \ # key1: ECDSA, key2: RSA; use key2 from slot 1 requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE -run_test "SSL async private: slot 1 used" \ +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 \ From 22e695fc5ada32346544664080852c0373c0cdb7 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 26 Apr 2018 00:22:50 +0200 Subject: [PATCH 39/69] Be more precise about when a variable is unused --- library/ssl_srv.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/ssl_srv.c b/library/ssl_srv.c index c4f1adee8..9c94fff7d 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -2870,7 +2870,9 @@ static int ssl_prepare_server_key_exchange( mbedtls_ssl_context *ssl, #endif /* MBEDTLS_KEY_EXCHANGE__SOME_PFS__ENABLED */ (void) ciphersuite_info; /* unused in some configurations */ - (void) signature_len; /* 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 */ From ceb541b7deffcfc920d72b584a2e460be255f665 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 26 Apr 2018 06:30:45 +0200 Subject: [PATCH 40/69] ssl_server2: rename delay in ssl_async_operation_context_t Rename to remaining_delay to convey that it is decremented over time. --- programs/ssl/ssl_server2.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index 7d9072e87..500ff042b 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -906,7 +906,7 @@ typedef struct mbedtls_md_type_t md_alg; unsigned char input[SSL_ASYNC_INPUT_MAX_SIZE]; size_t input_len; - unsigned delay; + unsigned remaining_delay; } ssl_async_operation_context_t; static int ssl_async_start( void *config_data_arg, @@ -957,10 +957,10 @@ static int ssl_async_start( void *config_data_arg, ctx->md_alg = md_alg; memcpy( ctx->input, input, input_len ); ctx->input_len = input_len; - ctx->delay = config_data->slots[slot].delay; + ctx->remaining_delay = config_data->slots[slot].delay; mbedtls_ssl_async_set_data( ssl, ctx ); - if( ctx->delay == 0 ) + if( ctx->remaining_delay == 0 ) return( 0 ); else return( MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ); @@ -1007,11 +1007,11 @@ static int ssl_async_resume( void *config_data_arg, return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); } - if( ctx->delay > 0 ) + if( ctx->remaining_delay > 0 ) { - --ctx->delay; + --ctx->remaining_delay; mbedtls_printf( "Async resume (slot %zd): call %u more times.\n", - ctx->slot, ctx->delay ); + ctx->slot, ctx->remaining_delay ); return( MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ); } From d3268834f376f6fdd5e58686ebb68d7e8e43d595 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 26 Apr 2018 06:23:59 +0200 Subject: [PATCH 41/69] Document what the SSL async sign callback needs to do with RSA Document how the SSL async sign callback must treat its md_alg and hash parameters when doing an RSA signature: sign-the-hash if md_alg is nonzero (TLS 1.2), and sign-the-digestinfo if md_alg is zero (TLS <= 1.1). In ssl_server2, don't use md_alg=MBEDTLS_MD_NONE to indicate that ssl_async_resume must perform an encryption, because md_alg is also MBEDTLS_MD_NONE in TLS <= 1.1. Add a test case to exercise this case (signature with MBEDTLS_MD_NONE). --- include/mbedtls/ssl.h | 15 +++++++++ programs/ssl/ssl_server2.c | 62 ++++++++++++++++++++++++++------------ tests/ssl-opt.sh | 12 ++++++++ 3 files changed, 70 insertions(+), 19 deletions(-) diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 9b17e610b..6460fd9bf 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -579,6 +579,21 @@ typedef struct mbedtls_ssl_flight_item mbedtls_ssl_flight_item; * store an operation context for later retrieval * by the resume 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 \p md_alg is #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. + * * \param config_data The configuration data parameter passed to * mbedtls_ssl_conf_async_private_cb(). * \param ssl The SSL connection instance. It should not be diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index 500ff042b..28d9e6f4c 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -900,9 +900,25 @@ void ssl_async_set_key( ssl_async_key_context_t *ctx, } #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 { size_t 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; @@ -912,7 +928,7 @@ typedef struct static int ssl_async_start( void *config_data_arg, mbedtls_ssl_context *ssl, mbedtls_x509_crt *cert, - const char *op_name, + ssl_async_operation_type_t op_type, mbedtls_md_type_t md_alg, const unsigned char *input, size_t input_len ) @@ -920,6 +936,7 @@ static int ssl_async_start( void *config_data_arg, ssl_async_key_context_t *config_data = config_data_arg; size_t slot; ssl_async_operation_context_t *ctx = NULL; + const char *op_name = ssl_async_operation_names[op_type]; { char dn[100]; @@ -954,6 +971,7 @@ static int ssl_async_start( void *config_data_arg, 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; @@ -974,7 +992,7 @@ static int ssl_async_sign( void *config_data_arg, size_t hash_len ) { return( ssl_async_start( config_data_arg, ssl, cert, - "sign", md_alg, + ASYNC_OP_SIGN, md_alg, hash, hash_len ) ); } @@ -985,7 +1003,7 @@ static int ssl_async_decrypt( void *config_data_arg, size_t input_len ) { return( ssl_async_start( config_data_arg, ssl, cert, - "decrypt", MBEDTLS_MD_NONE, + ASYNC_OP_DECRYPT, MBEDTLS_MD_NONE, input, input_len ) ); } @@ -999,7 +1017,7 @@ static int ssl_async_resume( void *config_data_arg, ssl_async_key_context_t *config_data = config_data_arg; ssl_async_key_slot_t *key_slot = &config_data->slots[ctx->slot]; int ret; - const char *op_name; + const char *op_name = NULL; if( config_data->inject_error == SSL_ASYNC_INJECT_ERROR_RESUME ) { @@ -1015,22 +1033,28 @@ static int ssl_async_resume( void *config_data_arg, return( MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ); } - if( ctx->md_alg == MBEDTLS_MD_NONE ) + switch( ctx->operation_type ) { - op_name = "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 ); - } - else - { - op_name = "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 ); + case ASYNC_OP_DECRYPT: + op_name = "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: + op_name = "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 %zd): unknown operation type %ld. This shouldn't happen.\n", + ctx->slot, (long) ctx->operation_type ); + return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); + break; } if( config_data->inject_error == SSL_ASYNC_INJECT_ERROR_PK ) diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index 15503e2c5..0f8af026a 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -4088,6 +4088,18 @@ run_test "SSL async private: sign, delay=1" \ -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: decrypt, delay=0" \ "$P_SRV \ From c912572a7f6886fc3e28723ca5f2644f3e76a878 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 26 Apr 2018 07:15:40 +0200 Subject: [PATCH 42/69] ssl_server2: merge redundant async_private_error=resume/pk Testing the case where the resume callback returns an error at the beginning and the case where it returns an error at the end is redundant. Keep the test after the output has been produced, to validate that the product does not use even a valid output if the return value is an error code. --- programs/ssl/ssl_server2.c | 13 +++---------- tests/ssl-opt.sh | 11 ----------- 2 files changed, 3 insertions(+), 21 deletions(-) diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index 28d9e6f4c..544ff3606 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -207,7 +207,7 @@ int main( void ) " async_private_delay2=%%d Asynchronous delay for key_file2\n" \ " default: -1 (not asynchronous)\n" \ " async_private_error=%%d Async callback error injection (default=0=none,\n" \ - " 1=start, 2=cancel, 3=resume, 4=pk, negative=first time only)" + " 1=start, 2=cancel, 3=resume, negative=first time only)" #else #define USAGE_SSL_ASYNC "" #endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ @@ -875,8 +875,7 @@ typedef enum { 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 */ - SSL_ASYNC_INJECT_ERROR_PK /*!< Inject error during resume */ -#define SSL_ASYNC_INJECT_ERROR_MAX SSL_ASYNC_INJECT_ERROR_PK +#define SSL_ASYNC_INJECT_ERROR_MAX SSL_ASYNC_INJECT_ERROR_RESUME } ssl_async_inject_error_t; typedef struct @@ -1019,12 +1018,6 @@ static int ssl_async_resume( void *config_data_arg, int ret; const char *op_name = NULL; - if( config_data->inject_error == SSL_ASYNC_INJECT_ERROR_RESUME ) - { - mbedtls_printf( "Async resume callback: injected error\n" ); - return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); - } - if( ctx->remaining_delay > 0 ) { --ctx->remaining_delay; @@ -1057,7 +1050,7 @@ static int ssl_async_resume( void *config_data_arg, break; } - if( config_data->inject_error == SSL_ASYNC_INJECT_ERROR_PK ) + if( config_data->inject_error == SSL_ASYNC_INJECT_ERROR_RESUME ) { mbedtls_printf( "Async resume callback: %s done but injected error\n", op_name ); diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index 0f8af026a..6261225b2 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -4246,17 +4246,6 @@ run_test "SSL async private: error in resume" \ "$P_CLI" \ 1 \ -s "Async sign callback: using key slot " \ - -s "Async resume callback: injected error" \ - -s "! mbedtls_ssl_handshake returned" - -requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE -run_test "SSL async private: error in pk" \ - "$P_SRV \ - async_operations=s async_private_delay1=1 async_private_delay2=1 \ - async_private_error=4" \ - "$P_CLI" \ - 1 \ - -s "Async sign callback: using key slot " \ -s "Async resume callback: sign done but injected error" \ -s "! mbedtls_ssl_handshake returned" From 2481a712ed37d2757474d8812226c4d310da0eb3 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 26 Apr 2018 07:28:44 +0200 Subject: [PATCH 43/69] Doxygen formatting improvements --- include/mbedtls/ssl.h | 94 +++++++++++++++++++++---------------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 6460fd9bf..60ce5d470 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -560,7 +560,7 @@ typedef struct mbedtls_ssl_flight_item mbedtls_ssl_flight_item; * * This callback is called during an SSL handshake to start * a signature decryption operation using an - * external processor. The parameter \c cert contains + * 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. * @@ -568,11 +568,11 @@ typedef struct mbedtls_ssl_flight_item mbedtls_ssl_flight_item; * does not wait for the operation to complete. This allows * the handshake step to be non-blocking. * - * The parameters \c ssl and \c cert are + * The parameters \p ssl and \p cert are * guaranteed to remain valid as long as the SSL * configuration remains valid. On the other hand, this - * function must save the contents of \c hash if the value - * is needed for later processing, because the \c hash buffer + * 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_async_set_data() to @@ -604,16 +604,16 @@ typedef struct mbedtls_ssl_flight_item mbedtls_ssl_flight_item; * 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. - * - \c 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. - * - \c 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. - * - Any other error indicates a fatal failure and is - * propagated up the call chain. + * \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. */ typedef int mbedtls_ssl_async_sign_t( void *config_data, mbedtls_ssl_context *ssl, @@ -627,7 +627,7 @@ typedef int mbedtls_ssl_async_sign_t( void *config_data, * * This callback is called during an SSL handshake to start * an RSA decryption operation using an - * external processor. The parameter \c cert contains + * 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. * @@ -635,11 +635,11 @@ typedef int mbedtls_ssl_async_sign_t( void *config_data, * does not wait for the operation to complete. This allows * the handshake step to be non-blocking. * - * The parameters \c ssl and \c cert are + * The parameters \p ssl and \p cert are * guaranteed to remain valid as long as the SSL * configuration remains valid. On the other hand, this - * function must save the contents of \c input if the value - * is needed for later processing, because the \c input buffer + * 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_async_set_data() to @@ -653,18 +653,18 @@ typedef int mbedtls_ssl_async_sign_t( void *config_data, * \param cert Certificate containing the public key. * \param input Buffer containing the input ciphertext. This buffer * is no longer valid when the function returns. - * \param input_len Size of the \c input buffer in bytes. + * \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. - * - \c 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. - * - \c 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. - * - Any other error indicates a fatal failure and is - * propagated up the call chain. + * \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. */ typedef int mbedtls_ssl_async_decrypt_t( void *config_data, mbedtls_ssl_context *ssl, @@ -678,8 +678,8 @@ typedef int mbedtls_ssl_async_decrypt_t( void *config_data, * * This callback is called during an SSL handshake to resume * an external operation started by the - * \c mbedtls_ssl_async_sign_t or - * \c mbedtls_ssl_async_decrypt_t callback. + * ::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 @@ -697,17 +697,17 @@ typedef int mbedtls_ssl_async_decrypt_t( void *config_data, * modified other than via mbedtls_ssl_async_set_data(). * \param output Buffer containing the output (signature or decrypted * data) on success. - * \param output_len On success, number of bytes written to \c output. - * \param output_size Size of the \c output buffer in bytes. + * \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 - * \c output buffer. - * - \c 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. - * - Any other error means that the operation is aborted. - * The SSL handshake is aborted. + * \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. */ typedef int mbedtls_ssl_async_resume_t( void *config_data, mbedtls_ssl_context *ssl, @@ -1511,24 +1511,24 @@ void mbedtls_ssl_conf_export_keys_cb( mbedtls_ssl_config *conf, * * \param conf SSL configuration context * \param f_async_sign Callback to start a signature operation. See - * the description of \c mbedtls_ssl_async_sign_t - * for more information. This may be NULL if the + * 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 \c mbedtls_ssl_async_decrypt_t - * for more information. This may be NULL if the + * 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 \c mbedtls_ssl_async_resume_t + * 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 \c mbedtls_ssl_async_cancel_t + * 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 will be From 0fd90dd713d34afb5e36e6219425c1911705ac2b Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 26 Apr 2018 07:41:09 +0200 Subject: [PATCH 44/69] ssl_prepare_server_key_exchange: clarify where the signature is written --- library/ssl_srv.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 9c94fff7d..10ded131e 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -2837,13 +2837,18 @@ static int ssl_get_ecdh_params_from_cert( 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 ) + 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 - - ( ssl->out_msg + ssl->out_msglen + 2 ) ); + - sig_start ); int ret = ssl->conf->f_async_resume( ssl->conf->p_async_config_data, ssl, - ssl->out_msg + ssl->out_msglen + 2, - signature_len, sig_max_len ); + sig_start, signature_len, sig_max_len ); if( ret != MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ) { ssl->handshake->async_in_progress = 0; @@ -3197,6 +3202,11 @@ curve_matching_done: 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, From a36ac4fe6894e4df9058e25285dc1902114c6bd7 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 26 Apr 2018 08:05:02 +0200 Subject: [PATCH 45/69] New wrapper mbedtls_status_is_ssl_in_progress(ret) Wrapper function to check whether a return status indicates that an SSL operation is in progress. --- programs/ssl/ssl_server2.c | 41 +++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index 544ff3606..f96040ea2 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -862,6 +862,23 @@ 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 { @@ -2526,9 +2543,7 @@ handshake: } #endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ - if( ret != MBEDTLS_ERR_SSL_WANT_READ && - ret != MBEDTLS_ERR_SSL_WANT_WRITE && - ret != MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ) + if( ! mbedtls_status_is_ssl_in_progress( ret ) ) break; /* For event-driven IO, wait for socket to become available */ @@ -2651,9 +2666,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 || - ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ) + if( mbedtls_status_is_ssl_in_progress( ret ) ) { if( opt.event == 1 /* level triggered IO */ ) { @@ -2784,9 +2797,7 @@ data_exchange: * returns `MBEDTLS_ERR_SSL_WANT_READ`, because the pending messages * might be discarded (e.g. because they are retransmissions). */ } - while( ret == MBEDTLS_ERR_SSL_WANT_READ || - ret == MBEDTLS_ERR_SSL_WANT_WRITE || - ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ); + while( mbedtls_status_is_ssl_in_progress( ret ) ); if( ret <= 0 ) { @@ -2821,9 +2832,7 @@ data_exchange: while( ( ret = mbedtls_ssl_renegotiate( &ssl ) ) != 0 ) { - if( ret != MBEDTLS_ERR_SSL_WANT_READ && - ret != MBEDTLS_ERR_SSL_WANT_WRITE && - ret != MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ) + if( ! mbedtls_status_is_ssl_in_progress( ret ) ) { mbedtls_printf( " failed\n ! mbedtls_ssl_renegotiate returned %d\n\n", ret ); goto reset; @@ -2866,9 +2875,7 @@ data_exchange: goto reset; } - if( ret != MBEDTLS_ERR_SSL_WANT_READ && - ret != MBEDTLS_ERR_SSL_WANT_WRITE && - ret != MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ) + if( ! mbedtls_status_is_ssl_in_progress( ret ) ) { mbedtls_printf( " failed\n ! mbedtls_ssl_write returned %d\n\n", ret ); goto reset; @@ -2892,9 +2899,7 @@ data_exchange: { ret = mbedtls_ssl_write( &ssl, buf, len ); - if( ret != MBEDTLS_ERR_SSL_WANT_READ && - ret != MBEDTLS_ERR_SSL_WANT_WRITE && - ret != MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ) + if( ! mbedtls_status_is_ssl_in_progress( ret ) ) break; /* For event-driven IO, wait for socket to become available */ From e14163886852d744adb317e1ffc107f742e360d6 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 26 Apr 2018 10:23:21 +0200 Subject: [PATCH 46/69] Finish writing an unfinished comment --- library/ssl_srv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 10ded131e..6819e7ac7 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -3561,7 +3561,8 @@ static int ssl_parse_encrypted_pms( mbedtls_ssl_context *ssl, 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 */ + /* It's ok to abort on an RNG failure, since this does not reveal + * anything about the RSA decryption. */ return( ret ); } From 8f97af7ea3ebe368b5359331f4f726add2640384 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 26 Apr 2018 11:46:10 +0200 Subject: [PATCH 47/69] Don't pass the async config data to async callbacks The config data is in the SSL config, so callbacks can retrieve it from there, with the new function mbedtls_ssl_conf_get_async_config_data. --- include/mbedtls/ssl.h | 41 +++++++++++++++++++------------------- library/ssl_srv.c | 10 ++++------ library/ssl_tls.c | 9 +++++++-- programs/ssl/ssl_server2.c | 26 ++++++++++-------------- 4 files changed, 42 insertions(+), 44 deletions(-) diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 60ce5d470..2e5a1b80d 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -594,8 +594,6 @@ typedef struct mbedtls_ssl_flight_item mbedtls_ssl_flight_item; * from step 2, with `digestAlgorithm` obtained by calling * mbedtls_oid_get_oid_by_md() on \p md_alg. * - * \param config_data The configuration data parameter passed to - * mbedtls_ssl_conf_async_private_cb(). * \param ssl The SSL connection instance. It should not be * modified other than via mbedtls_ssl_async_set_data(). * \param cert Certificate containing the public key. @@ -615,8 +613,7 @@ typedef struct mbedtls_ssl_flight_item mbedtls_ssl_flight_item; * \return Any other error indicates a fatal failure and is * propagated up the call chain. */ -typedef int mbedtls_ssl_async_sign_t( void *config_data, - mbedtls_ssl_context *ssl, +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, @@ -646,8 +643,6 @@ typedef int mbedtls_ssl_async_sign_t( void *config_data, * store an operation context for later retrieval * by the resume callback. * - * \param config_data The configuration data parameter passed to - * mbedtls_ssl_conf_async_private_cb(). * \param ssl The SSL connection instance. It should not be * modified other than via mbedtls_ssl_async_set_data(). * \param cert Certificate containing the public key. @@ -666,8 +661,7 @@ typedef int mbedtls_ssl_async_sign_t( void *config_data, * \return Any other error indicates a fatal failure and is * propagated up the call chain. */ -typedef int mbedtls_ssl_async_decrypt_t( void *config_data, - mbedtls_ssl_context *ssl, +typedef int mbedtls_ssl_async_decrypt_t( mbedtls_ssl_context *ssl, mbedtls_x509_crt *cert, const unsigned char *input, size_t input_len ); @@ -691,8 +685,6 @@ typedef int mbedtls_ssl_async_decrypt_t( void *config_data, * It may call mbedtls_ssl_async_set_data() to modify this * context. * - * \param config_data The configuration data parameter passed to - * mbedtls_ssl_conf_async_private_cb(). * \param ssl The SSL connection instance. It should not be * modified other than via mbedtls_ssl_async_set_data(). * \param output Buffer containing the output (signature or decrypted @@ -709,8 +701,7 @@ typedef int mbedtls_ssl_async_decrypt_t( void *config_data, * \return Any other error means that the operation is aborted. * The SSL handshake is aborted. */ -typedef int mbedtls_ssl_async_resume_t( void *config_data, - mbedtls_ssl_context *ssl, +typedef int mbedtls_ssl_async_resume_t( mbedtls_ssl_context *ssl, unsigned char *output, size_t *output_len, size_t output_size ); @@ -724,13 +715,10 @@ typedef int mbedtls_ssl_async_resume_t( void *config_data, * This function may call mbedtls_ssl_async_get_data() to * retrieve an operation context set by the start callback. * - * \param config_data The configuration data parameter passed to - * mbedtls_ssl_conf_async_private_cb(). * \param ssl The SSL connection instance. It should not be * modified. */ -typedef void mbedtls_ssl_async_cancel_t( void *config_data, - mbedtls_ssl_context *ssl ); +typedef void mbedtls_ssl_async_cancel_t( mbedtls_ssl_context *ssl ); #endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ /* @@ -856,7 +844,7 @@ struct mbedtls_ssl_config #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() and passed to the callbacks. */ + 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) @@ -1531,9 +1519,10 @@ void mbedtls_ssl_conf_export_keys_cb( mbedtls_ssl_config *conf, * 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 will be - * passed to the callbacks. The library stores and - * passes back this value without dereferencing it. + * \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, @@ -1542,6 +1531,16 @@ void mbedtls_ssl_conf_async_private_cb( mbedtls_ssl_config *conf, 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. * @@ -1555,7 +1554,7 @@ void mbedtls_ssl_conf_async_private_cb( mbedtls_ssl_config *conf, * has not been called during the current handshake yet, * this function returns \c NULL. */ -void *mbedtls_ssl_async_get_data( mbedtls_ssl_context *ssl ); +void *mbedtls_ssl_async_get_data( const mbedtls_ssl_context *ssl ); /** * \brief Retrieve the asynchronous operation user context. diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 6819e7ac7..5439f6d61 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -2847,7 +2847,7 @@ static int ssl_resume_server_key_exchange( mbedtls_ssl_context *ssl, 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->conf->p_async_config_data, ssl, + int ret = ssl->conf->f_async_resume( ssl, sig_start, signature_len, sig_max_len ); if( ret != MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ) { @@ -3174,8 +3174,7 @@ curve_matching_done: #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) if( ssl->conf->f_async_sign_start != NULL ) { - ret = ssl->conf->f_async_sign_start( ssl->conf->p_async_config_data, - ssl, + ret = ssl->conf->f_async_sign_start( ssl, mbedtls_ssl_own_cert( ssl ), md_alg, hash, hashlen ); switch( ret ) @@ -3402,7 +3401,7 @@ static int ssl_resume_decrypt_pms( mbedtls_ssl_context *ssl, size_t *peer_pmslen, size_t peer_pmssize ) { - int ret = ssl->conf->f_async_resume( ssl->conf->p_async_config_data, ssl, + int ret = ssl->conf->f_async_resume( ssl, peer_pms, peer_pmslen, peer_pmssize ); if( ret != MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ) { @@ -3465,8 +3464,7 @@ static int ssl_decrypt_encrypted_pms( mbedtls_ssl_context *ssl, #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) if( ssl->conf->f_async_decrypt_start != NULL ) { - ret = ssl->conf->f_async_decrypt_start( ssl->conf->p_async_config_data, - ssl, + ret = ssl->conf->f_async_decrypt_start( ssl, mbedtls_ssl_own_cert( ssl ), p, len ); switch( ret ) diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 2c6eef8ec..04f34587d 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -6494,7 +6494,12 @@ void mbedtls_ssl_conf_async_private_cb( conf->p_async_config_data = async_config_data; } -void *mbedtls_ssl_async_get_data( mbedtls_ssl_context *ssl ) +void *mbedtls_ssl_conf_get_async_config_data( const mbedtls_ssl_config *conf ) +{ + return( conf->p_async_config_data ); +} + +void *mbedtls_ssl_async_get_data( const mbedtls_ssl_context *ssl ) { if( ssl->handshake == NULL ) return( NULL ); @@ -7451,7 +7456,7 @@ void mbedtls_ssl_handshake_free( mbedtls_ssl_context *ssl ) #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) if( ssl->conf->f_async_cancel != NULL && handshake->async_in_progress != 0 ) { - ssl->conf->f_async_cancel( ssl->conf->p_async_config_data, ssl ); + ssl->conf->f_async_cancel( ssl ); handshake->async_in_progress = 0; } #endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index f96040ea2..272eecdc5 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -941,15 +941,15 @@ typedef struct unsigned remaining_delay; } ssl_async_operation_context_t; -static int ssl_async_start( void *config_data_arg, - mbedtls_ssl_context *ssl, +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 = config_data_arg; + ssl_async_key_context_t *config_data = + mbedtls_ssl_conf_get_async_config_data( ssl->conf ); size_t slot; ssl_async_operation_context_t *ctx = NULL; const char *op_name = ssl_async_operation_names[op_type]; @@ -1000,37 +1000,35 @@ static int ssl_async_start( void *config_data_arg, return( MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ); } -static int ssl_async_sign( void *config_data_arg, - mbedtls_ssl_context *ssl, +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( config_data_arg, ssl, cert, + return( ssl_async_start( ssl, cert, ASYNC_OP_SIGN, md_alg, hash, hash_len ) ); } -static int ssl_async_decrypt( void *config_data_arg, - mbedtls_ssl_context *ssl, +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( config_data_arg, ssl, cert, + return( ssl_async_start( ssl, cert, ASYNC_OP_DECRYPT, MBEDTLS_MD_NONE, input, input_len ) ); } -static int ssl_async_resume( void *config_data_arg, - mbedtls_ssl_context *ssl, +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_async_get_data( ssl ); - ssl_async_key_context_t *config_data = config_data_arg; + 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 = NULL; @@ -1080,11 +1078,9 @@ static int ssl_async_resume( void *config_data_arg, return( ret ); } -static void ssl_async_cancel( void *config_data_arg, - mbedtls_ssl_context *ssl ) +static void ssl_async_cancel( mbedtls_ssl_context *ssl ) { ssl_async_operation_context_t *ctx = mbedtls_ssl_async_get_data( ssl ); - (void) config_data_arg; mbedtls_printf( "Async cancel callback.\n" ); mbedtls_free( ctx ); } From ac5e8a32862f3e99eee830822d969e22e092d51a Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 26 Apr 2018 11:50:07 +0200 Subject: [PATCH 48/69] Document that callbacks must not return arbitrary SSL errors --- include/mbedtls/ssl.h | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 2e5a1b80d..84bc63ba5 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -611,7 +611,10 @@ typedef struct mbedtls_ssl_flight_item mbedtls_ssl_flight_item; * 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. + * 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 here. */ typedef int mbedtls_ssl_async_sign_t( mbedtls_ssl_context *ssl, mbedtls_x509_crt *cert, @@ -659,7 +662,10 @@ typedef int mbedtls_ssl_async_sign_t( mbedtls_ssl_context *ssl, * 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. + * 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 here. */ typedef int mbedtls_ssl_async_decrypt_t( mbedtls_ssl_context *ssl, mbedtls_x509_crt *cert, @@ -699,7 +705,10 @@ typedef int mbedtls_ssl_async_decrypt_t( mbedtls_ssl_context *ssl, * 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 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 here. */ typedef int mbedtls_ssl_async_resume_t( mbedtls_ssl_context *ssl, unsigned char *output, From 5ffe41c8f9e53ddde74e63d58bd05fb5e67abca0 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 26 Apr 2018 11:51:03 +0200 Subject: [PATCH 49/69] Turn on MBEDTLS_SSL_ASYNC_PRIVATE by default This is an ABI change in libmbedtls. --- include/mbedtls/config.h | 2 +- tests/scripts/all.sh | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h index b80667ab1..43ca74ee7 100644 --- a/include/mbedtls/config.h +++ b/include/mbedtls/config.h @@ -1137,7 +1137,7 @@ * operation inside the library. * */ -//#define MBEDTLS_SSL_ASYNC_PRIVATE +#define MBEDTLS_SSL_ASYNC_PRIVATE /** * \def MBEDTLS_SSL_DEBUG_ALL diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh index 0eda3788c..d61ba9869 100755 --- a/tests/scripts/all.sh +++ b/tests/scripts/all.sh @@ -557,8 +557,8 @@ make msg "test: main suites (full config)" # ~ 5s make test -msg "test: ssl-opt.sh default, ECJPAKE, SSL async (full config)" # ~ 1s -if_build_succeeded tests/ssl-opt.sh -f 'Default\|ECJPAKE\|SSL async private' +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' From 783007375f839a5fa0c78c6304923305ae6831db Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 26 Apr 2018 13:03:29 +0200 Subject: [PATCH 50/69] Change boolean bitfield to unsigned Reminder to self: 1 is not a valid value in a 1-bit bitfield. It's undefined behavior and gcc -ansi -pedantic helpfully complains about it. --- include/mbedtls/ssl_internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h index 506aff395..bbaf3564f 100644 --- a/include/mbedtls/ssl_internal.h +++ b/include/mbedtls/ssl_internal.h @@ -310,7 +310,7 @@ struct mbedtls_ssl_handshake_params #endif #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) - int async_in_progress : 1; /*!< an asynchronous operation is in progress */ + unsigned int async_in_progress : 1; /*!< an asynchronous operation is in progress */ #endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) From 5bea9f61b91d143904cdddc56d9d74aaf10855d7 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 26 Apr 2018 13:27:43 +0200 Subject: [PATCH 51/69] Don't use the printf format %zd We target C89 libc, so don't use %zd or %zu. Just use %u, and make slot numbers `unsigned` for simplicity. --- programs/ssl/ssl_server2.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index 272eecdc5..9a226e4e4 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -933,7 +933,7 @@ static const char *const ssl_async_operation_names[] = typedef struct { - size_t slot; + unsigned slot; ssl_async_operation_type_t operation_type; mbedtls_md_type_t md_alg; unsigned char input[SSL_ASYNC_INPUT_MAX_SIZE]; @@ -950,7 +950,7 @@ static int ssl_async_start( mbedtls_ssl_context *ssl, { ssl_async_key_context_t *config_data = mbedtls_ssl_conf_get_async_config_data( ssl->conf ); - size_t slot; + unsigned slot; ssl_async_operation_context_t *ctx = NULL; const char *op_name = ssl_async_operation_names[op_type]; @@ -971,7 +971,7 @@ static int ssl_async_start( mbedtls_ssl_context *ssl, op_name ); return( MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH ); } - mbedtls_printf( "Async %s callback: using key slot %zd, delay=%u.\n", + 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 ) @@ -1036,7 +1036,7 @@ static int ssl_async_resume( mbedtls_ssl_context *ssl, if( ctx->remaining_delay > 0 ) { --ctx->remaining_delay; - mbedtls_printf( "Async resume (slot %zd): call %u more times.\n", + mbedtls_printf( "Async resume (slot %u): call %u more times.\n", ctx->slot, ctx->remaining_delay ); return( MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ); } @@ -1059,7 +1059,7 @@ static int ssl_async_resume( mbedtls_ssl_context *ssl, config_data->f_rng, config_data->p_rng ); break; default: - mbedtls_printf( "Async resume (slot %zd): unknown operation type %ld. This shouldn't happen.\n", + mbedtls_printf( "Async resume (slot %u): unknown operation type %ld. This shouldn't happen.\n", ctx->slot, (long) ctx->operation_type ); return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); break; @@ -1072,7 +1072,7 @@ static int ssl_async_resume( mbedtls_ssl_context *ssl, return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); } - mbedtls_printf( "Async resume (slot %zd): %s done, status=%d.\n", + mbedtls_printf( "Async resume (slot %u): %s done, status=%d.\n", ctx->slot, op_name, ret ); mbedtls_free( ctx ); return( ret ); From 9de55fab562e8e37d42fd609576c32bc4d5d7299 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 26 Apr 2018 14:33:43 +0200 Subject: [PATCH 52/69] Fix uninitialized variable in ssl_server2 --- programs/ssl/ssl_server2.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index 9a226e4e4..bf50f1d50 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -1223,6 +1223,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 ); From 12d0cc1b8fbbeedc87afe6f5920eaef5b0ded643 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 26 Apr 2018 15:06:56 +0200 Subject: [PATCH 53/69] Add test case for SSL async resume after resume Add a test case for SSL asynchronous signature where f_async_resume is called twice. Verify that f_async_sign_start is only called once. This serves as a non-regression test for a bug where f_async_sign_start was only called once, which turned out to be due to a stale build artifacts with mismatched numerical values of MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS. --- tests/ssl-opt.sh | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index 6261225b2..bf7d914b2 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -4088,6 +4088,18 @@ run_test "SSL async private: sign, delay=1" \ -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 From 20deb01264721df975bfa7ff4c3fa1a72bf04fae Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 26 Apr 2018 17:57:37 +0200 Subject: [PATCH 54/69] Improve documentation of the async callback's crypto parameters --- include/mbedtls/ssl.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 84bc63ba5..097b86a3c 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -594,9 +594,16 @@ typedef struct mbedtls_ssl_flight_item mbedtls_ssl_flight_item; * 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_async_set_data(). * \param cert Certificate containing the public key. + * This is one of the pointers passed to + * mbedtls_ssl_conf_own_cert() when configuring the SSL + * connection. * \param md_alg Hash algorithm. * \param hash Buffer containing the hash. This buffer is * no longer valid when the function returns. @@ -646,9 +653,21 @@ typedef int mbedtls_ssl_async_sign_t( mbedtls_ssl_context *ssl, * store an operation context for later retrieval * by the resume 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_async_set_data(). * \param cert Certificate containing the public key. + * This is one of the pointers passed to + * mbedtls_ssl_conf_own_cert() when configuring the SSL + * connection. * \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. From 37289cdb9958efb6f175a1739b150e82e7cf2763 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 27 Apr 2018 11:50:14 +0200 Subject: [PATCH 55/69] SSL async tests: tighten a few log checks in some test cases --- tests/ssl-opt.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index bf7d914b2..cf2c16875 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -4237,6 +4237,7 @@ run_test "SSL async private: error in start" \ 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 @@ -4259,6 +4260,7 @@ run_test "SSL async private: error in resume" \ 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 @@ -4295,6 +4297,7 @@ run_test "SSL async private: cancel after start then fall back to transparent [ \$? -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" \ From deda75a09e6a2c828ec68820e6025a1a205b49fa Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 30 Apr 2018 10:02:45 +0200 Subject: [PATCH 56/69] Fix missing continuation indicator in ssl-opt.sh --- tests/ssl-opt.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index cf2c16875..597a5f1c1 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -4297,7 +4297,7 @@ run_test "SSL async private: cancel after start then fall back to transparent [ \$? -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 sign callback: using key slot 0" \ -S "Async resume" \ -s "Async cancel" \ -s "! mbedtls_ssl_handshake returned" \ From 0b53e24c6b74fdeaf4d40b8e9a85f98afc05fe67 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 30 Apr 2018 10:23:56 +0200 Subject: [PATCH 57/69] ssl_async_set_key: detect if ctx->slots overflows --- programs/ssl/ssl_server2.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index bf50f1d50..838f41d7c 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -904,15 +904,18 @@ typedef struct void *p_rng; } ssl_async_key_context_t; -void ssl_async_set_key( ssl_async_key_context_t *ctx, +int ssl_async_set_key( ssl_async_key_context_t *ctx, mbedtls_x509_crt *cert, mbedtls_pk_context *pk, 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_used; + return( 0 ); } #define SSL_ASYNC_INPUT_MAX_SIZE 512 @@ -2297,8 +2300,14 @@ int main( int argc, char *argv[] ) #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) if( opt.async_private_delay1 >= 0 ) { - ssl_async_set_key( &ssl_async_keys, &srvcert, pk, - opt.async_private_delay1 ); + ret = ssl_async_set_key( &ssl_async_keys, &srvcert, pk, + 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 */ @@ -2314,8 +2323,14 @@ int main( int argc, char *argv[] ) #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) if( opt.async_private_delay2 >= 0 ) { - ssl_async_set_key( &ssl_async_keys, &srvcert2, pk, - opt.async_private_delay2 ); + ret = ssl_async_set_key( &ssl_async_keys, &srvcert2, pk, + 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 */ From 807d74a062f79eb7196f56c967357ccaf9d663b4 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 30 Apr 2018 10:30:49 +0200 Subject: [PATCH 58/69] SSL async callback: cert is not always from mbedtls_ssl_conf_own_cert The certificate passed to async callbacks may not be the one set by mbedtls_ssl_conf_own_cert. For example, when using an SNI callback, it's whatever the callback is using. Document this, and add a test case (and code sample) with SNI. --- include/mbedtls/ssl.h | 14 ++++++++++---- programs/ssl/ssl_server2.c | 25 ++++++++++++++++++++++--- tests/ssl-opt.sh | 14 ++++++++++++++ 3 files changed, 46 insertions(+), 7 deletions(-) diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 097b86a3c..b199e2ea6 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -601,9 +601,12 @@ typedef struct mbedtls_ssl_flight_item mbedtls_ssl_flight_item; * \param ssl The SSL connection instance. It should not be * modified other than via mbedtls_ssl_async_set_data(). * \param cert Certificate containing the public key. - * This is one of the pointers passed to + * In simple cases, this is one of the pointers passed to * mbedtls_ssl_conf_own_cert() when configuring the SSL - * connection. + * 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. @@ -665,9 +668,12 @@ typedef int mbedtls_ssl_async_sign_t( mbedtls_ssl_context *ssl, * \param ssl The SSL connection instance. It should not be * modified other than via mbedtls_ssl_async_set_data(). * \param cert Certificate containing the public key. - * This is one of the pointers passed to + * In simple cases, this is one of the pointers passed to * mbedtls_ssl_conf_own_cert() when configuring the SSL - * connection. + * 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. diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index 838f41d7c..b1f2382cb 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -204,7 +204,7 @@ int main( void ) #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\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)" @@ -897,7 +897,7 @@ typedef enum { typedef struct { - ssl_async_key_slot_t slots[2]; + ssl_async_key_slot_t slots[3]; /* key, key2, sni */ size_t slots_used; ssl_async_inject_error_t inject_error; int (*f_rng)(void *, unsigned char *, size_t); @@ -965,7 +965,9 @@ static int ssl_async_start( mbedtls_ssl_context *ssl, for( slot = 0; slot < config_data->slots_used; slot++ ) { - if( config_data->slots[slot].cert == cert ) + if( memcmp( &config_data->slots[slot].cert->pk, + &cert->pk, + sizeof( cert->pk ) ) == 0 ) break; } if( slot == config_data->slots_used ) @@ -2376,7 +2378,24 @@ int main( int argc, char *argv[] ) #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 ) + { + ret = ssl_async_set_key( &ssl_async_keys, + sni_info->cert, sni_info->key, + opt.async_private_delay2 ); + if( ret < 0 ) + { + mbedtls_printf( " Test error: ssl_async_set_key failed (%d)\n", + ret ); + goto exit; + } + sni_info->key = NULL; + } +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ + } #endif #if defined(MBEDTLS_ECP_C) diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index 597a5f1c1..6afca2d12 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -4112,6 +4112,20 @@ run_test "SSL async private: sign, RSA, TLS 1.1" \ -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 \ From 6a8cb36c24c60b3734c46479350066b1e1361245 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 30 Apr 2018 11:54:14 +0200 Subject: [PATCH 59/69] Fix copypasta in the async callback documentation --- include/mbedtls/ssl.h | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index b199e2ea6..b7dc98b5b 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -568,9 +568,8 @@ typedef struct mbedtls_ssl_flight_item mbedtls_ssl_flight_item; * 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 as long as the SSL - * configuration remains valid. On the other hand, this + * 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. @@ -588,7 +587,7 @@ typedef struct mbedtls_ssl_flight_item mbedtls_ssl_flight_item; * 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 \p md_alg is #MBEDTLS_MD_NONE, apply the PKCS#1 v1.5 + * - 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 @@ -645,9 +644,8 @@ typedef int mbedtls_ssl_async_sign_t( mbedtls_ssl_context *ssl, * 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 as long as the SSL - * configuration remains valid. On the other hand, this + * 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. From 1febfef56122a79d5fa4f04412c2c14bce712a90 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 30 Apr 2018 11:54:39 +0200 Subject: [PATCH 60/69] Rename mbedtls_ssl_async_{get,set}_data for clarity Rename to mbedtls_ssl_get_async_operation_data and mbedtls_ssl_set_async_operation_data so that they're about "async operation data" and not about some not-obvious "data". --- include/mbedtls/ssl.h | 44 +++++++++++++++++++++----------------- library/ssl_srv.c | 4 ++-- library/ssl_tls.c | 4 ++-- programs/ssl/ssl_server2.c | 6 +++--- 4 files changed, 31 insertions(+), 27 deletions(-) diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index b7dc98b5b..ec9018a1f 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -574,8 +574,8 @@ typedef struct mbedtls_ssl_flight_item mbedtls_ssl_flight_item; * is needed for later processing, because the \p hash buffer * is no longer valid after this function returns. * - * This function may call mbedtls_ssl_async_set_data() to - * store an operation context for later retrieval + * This function may call mbedtls_ssl_set_async_operation_data() + * to store an operation context for later retrieval * by the resume callback. * * \note For RSA signatures, this function must produce output @@ -598,7 +598,8 @@ typedef struct mbedtls_ssl_flight_item mbedtls_ssl_flight_item; * [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_async_set_data(). + * 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 @@ -650,8 +651,8 @@ typedef int mbedtls_ssl_async_sign_t( mbedtls_ssl_context *ssl, * is needed for later processing, because the \p input buffer * is no longer valid after this function returns. * - * This function may call mbedtls_ssl_async_set_data() to - * store an operation context for later retrieval + * This function may call mbedtls_ssl_set_async_operation_data() + * to store an operation context for later retrieval * by the resume callback. * * \warning RSA decryption as used in TLS is subject to a potential @@ -664,7 +665,8 @@ typedef int mbedtls_ssl_async_sign_t( mbedtls_ssl_context *ssl, * invalid padding. * * \param ssl The SSL connection instance. It should not be - * modified other than via mbedtls_ssl_async_set_data(). + * 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 @@ -709,13 +711,14 @@ typedef int mbedtls_ssl_async_decrypt_t( mbedtls_ssl_context *ssl, * does not wait for the operation to complete. This allows * the handshake step to be non-blocking. * - * This function may call mbedtls_ssl_async_get_data() to - * retrieve an operation context set by the start callback. - * It may call mbedtls_ssl_async_set_data() to modify this - * context. + * 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. * * \param ssl The SSL connection instance. It should not be - * modified other than via mbedtls_ssl_async_set_data(). + * 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. @@ -744,8 +747,8 @@ typedef int mbedtls_ssl_async_resume_t( mbedtls_ssl_context *ssl, * This callback is called if an SSL connection is closed * while an asynchronous operation is in progress. * - * This function may call mbedtls_ssl_async_get_data() to - * retrieve an operation context set by the start callback. + * 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. @@ -1582,11 +1585,12 @@ void *mbedtls_ssl_conf_get_async_config_data( const mbedtls_ssl_config *conf ); * \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_data() - * has not been called during the current handshake yet, - * this function returns \c NULL. + * 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_async_get_data( const mbedtls_ssl_context *ssl ); +void *mbedtls_ssl_get_async_operation_data( const mbedtls_ssl_context *ssl ); /** * \brief Retrieve the asynchronous operation user context. @@ -1596,10 +1600,10 @@ void *mbedtls_ssl_async_get_data( const mbedtls_ssl_context *ssl ); * * \param ssl The SSL context to access. * \param ctx The new value of the asynchronous operation user context. - * Call mbedtls_ssl_get_data() later during the same handshake - * to retrieve this value. + * Call mbedtls_ssl_get_async_operation_data() later during the + * same handshake to retrieve this value. */ -void mbedtls_ssl_async_set_data( mbedtls_ssl_context *ssl, +void mbedtls_ssl_set_async_operation_data( mbedtls_ssl_context *ssl, void *ctx ); #endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 5439f6d61..2b25e091f 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -2852,7 +2852,7 @@ static int ssl_resume_server_key_exchange( mbedtls_ssl_context *ssl, if( ret != MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ) { ssl->handshake->async_in_progress = 0; - mbedtls_ssl_async_set_data( ssl, NULL ); + mbedtls_ssl_set_async_operation_data( ssl, NULL ); } MBEDTLS_SSL_DEBUG_RET( 2, "ssl_resume_server_key_exchange", ret ); return( ret ); @@ -3406,7 +3406,7 @@ static int ssl_resume_decrypt_pms( mbedtls_ssl_context *ssl, if( ret != MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ) { ssl->handshake->async_in_progress = 0; - mbedtls_ssl_async_set_data( ssl, NULL ); + mbedtls_ssl_set_async_operation_data( ssl, NULL ); } MBEDTLS_SSL_DEBUG_RET( 2, "ssl_decrypt_encrypted_pms", ret ); return( ret ); diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 04f34587d..3819b6f7f 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -6499,7 +6499,7 @@ void *mbedtls_ssl_conf_get_async_config_data( const mbedtls_ssl_config *conf ) return( conf->p_async_config_data ); } -void *mbedtls_ssl_async_get_data( const mbedtls_ssl_context *ssl ) +void *mbedtls_ssl_get_async_operation_data( const mbedtls_ssl_context *ssl ) { if( ssl->handshake == NULL ) return( NULL ); @@ -6507,7 +6507,7 @@ void *mbedtls_ssl_async_get_data( const mbedtls_ssl_context *ssl ) return( ssl->handshake->user_async_ctx ); } -void mbedtls_ssl_async_set_data( mbedtls_ssl_context *ssl, +void mbedtls_ssl_set_async_operation_data( mbedtls_ssl_context *ssl, void *ctx ) { if( ssl->handshake != NULL ) diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index b1f2382cb..876f8156c 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -997,7 +997,7 @@ static int ssl_async_start( mbedtls_ssl_context *ssl, memcpy( ctx->input, input, input_len ); ctx->input_len = input_len; ctx->remaining_delay = config_data->slots[slot].delay; - mbedtls_ssl_async_set_data( ssl, ctx ); + mbedtls_ssl_set_async_operation_data( ssl, ctx ); if( ctx->remaining_delay == 0 ) return( 0 ); @@ -1031,7 +1031,7 @@ static int ssl_async_resume( mbedtls_ssl_context *ssl, size_t *output_len, size_t output_size ) { - ssl_async_operation_context_t *ctx = mbedtls_ssl_async_get_data( ssl ); + 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]; @@ -1085,7 +1085,7 @@ static int ssl_async_resume( mbedtls_ssl_context *ssl, static void ssl_async_cancel( mbedtls_ssl_context *ssl ) { - ssl_async_operation_context_t *ctx = mbedtls_ssl_async_get_data( ssl ); + ssl_async_operation_context_t *ctx = mbedtls_ssl_get_async_operation_data( ssl ); mbedtls_printf( "Async cancel callback.\n" ); mbedtls_free( ctx ); } From 26d01bcb5cd48c437318aa12a5360591f0988ec5 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 30 Apr 2018 12:07:56 +0200 Subject: [PATCH 61/69] Async callback: use mbedtls_pk_check_pair to compare keys In the current test code, the object that is used as a public key in the certificate also contains a private key. However this is because of the way the stest code is built and does not demonstrate the API in a useful way. Use mbedtls_pk_check_pair, which is not what real-world code would do (since the private key would typically be in an external cryptoprocessor) but is a more representative placeholder. --- programs/ssl/ssl_server2.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index 876f8156c..d550b7c4c 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -963,11 +963,14 @@ static int ssl_async_start( mbedtls_ssl_context *ssl, 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( memcmp( &config_data->slots[slot].cert->pk, - &cert->pk, - sizeof( cert->pk ) ) == 0 ) + if( mbedtls_pk_check_pair( &cert->pk, + config_data->slots[slot].pk ) == 0 ) break; } if( slot == config_data->slots_used ) From ea5fab829c0940e8dcba8ece9e13ae142aab9781 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 30 Apr 2018 13:57:45 +0200 Subject: [PATCH 62/69] SSL async callbacks documentation: clarify resource cleanup Clarify when resume must clean up resources and when cancel is called. --- include/mbedtls/ssl.h | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index ec9018a1f..a839e84d8 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -576,7 +576,7 @@ typedef struct mbedtls_ssl_flight_item mbedtls_ssl_flight_item; * * This function may call mbedtls_ssl_set_async_operation_data() * to store an operation context for later retrieval - * by the resume callback. + * 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 @@ -653,7 +653,7 @@ typedef int mbedtls_ssl_async_sign_t( mbedtls_ssl_context *ssl, * * This function may call mbedtls_ssl_set_async_operation_data() * to store an operation context for later retrieval - * by the resume callback. + * 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 @@ -716,6 +716,10 @@ typedef int mbedtls_ssl_async_decrypt_t( mbedtls_ssl_context *ssl, * 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(). @@ -745,7 +749,12 @@ typedef int mbedtls_ssl_async_resume_t( mbedtls_ssl_context *ssl, * \brief Callback type: cancel external operation. * * This callback is called if an SSL connection is closed - * while an asynchronous operation is in progress. + * 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. From 9ceae8b4f6858a97ca694412d63e7e18b1016715 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 30 Apr 2018 16:37:03 +0200 Subject: [PATCH 63/69] Clarify "as directed here" in SSL async callback documentation --- include/mbedtls/ssl.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index a839e84d8..606d9c2f5 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -624,7 +624,7 @@ typedef struct mbedtls_ssl_flight_item mbedtls_ssl_flight_item; * 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 here. + * directed in the documentation of this callback. */ typedef int mbedtls_ssl_async_sign_t( mbedtls_ssl_context *ssl, mbedtls_x509_crt *cert, @@ -690,7 +690,7 @@ typedef int mbedtls_ssl_async_sign_t( mbedtls_ssl_context *ssl, * 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 here. + * directed in the documentation of this callback. */ typedef int mbedtls_ssl_async_decrypt_t( mbedtls_ssl_context *ssl, mbedtls_x509_crt *cert, @@ -738,7 +738,7 @@ typedef int mbedtls_ssl_async_decrypt_t( mbedtls_ssl_context *ssl, * 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 here. + * directed in the documentation of this callback. */ typedef int mbedtls_ssl_async_resume_t( mbedtls_ssl_context *ssl, unsigned char *output, From 276b9a650c1865b0b73fc4276547e97e686a0f8d Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 30 Apr 2018 16:37:23 +0200 Subject: [PATCH 64/69] ssl_server2: get op_name from context in ssl_async_resume as well --- programs/ssl/ssl_server2.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index d550b7c4c..ac3d1b1c7 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -1039,7 +1039,7 @@ static int ssl_async_resume( mbedtls_ssl_context *ssl, 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 = NULL; + const char *op_name; if( ctx->remaining_delay > 0 ) { @@ -1052,14 +1052,12 @@ static int ssl_async_resume( mbedtls_ssl_context *ssl, switch( ctx->operation_type ) { case ASYNC_OP_DECRYPT: - op_name = "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: - op_name = "sign"; ret = mbedtls_pk_sign( key_slot->pk, ctx->md_alg, ctx->input, ctx->input_len, @@ -1073,6 +1071,8 @@ static int ssl_async_resume( mbedtls_ssl_context *ssl, 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", From 3cde2fca53d2f80b90739c0ec8a73fb7a25d9b69 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 12 Jun 2018 14:17:39 +0200 Subject: [PATCH 65/69] ssl_async_resume: free the operation context on error --- programs/ssl/ssl_server2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index ac3d1b1c7..a7b019c7f 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -1077,6 +1077,7 @@ static int ssl_async_resume( mbedtls_ssl_context *ssl, { mbedtls_printf( "Async resume callback: %s done but injected error\n", op_name ); + mbedtls_free( ctx ); return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); } From 157f6d8f7432ceab02aeac4c8ae7f8aea4f3c0bd Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 13 Jun 2018 18:06:51 +0200 Subject: [PATCH 66/69] SNI + SSL async callback: make all keys async When testing async callbacks with SNI, make all the keys async, not just the first one. Otherwise the test is fragile with respect to whether a key is used directly or through the async callbacks. --- programs/ssl/ssl_server2.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index a7b019c7f..ae50b3d31 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -897,7 +897,7 @@ typedef enum { typedef struct { - ssl_async_key_slot_t slots[3]; /* key, key2, sni */ + 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); @@ -2387,16 +2387,20 @@ int main( int argc, char *argv[] ) #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) if( opt.async_private_delay2 >= 0 ) { - ret = ssl_async_set_key( &ssl_async_keys, - sni_info->cert, sni_info->key, - opt.async_private_delay2 ); - if( ret < 0 ) + sni_entry *cur; + for( cur = sni_info; cur != NULL; cur = cur->next ) { - mbedtls_printf( " Test error: ssl_async_set_key failed (%d)\n", - ret ); - goto exit; + ret = ssl_async_set_key( &ssl_async_keys, + cur->cert, cur->key, + opt.async_private_delay2 ); + if( ret < 0 ) + { + mbedtls_printf( " Test error: ssl_async_set_key failed (%d)\n", + ret ); + goto exit; + } + cur->key = NULL; } - sni_info->key = NULL; } #endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ } From 3f3ada8839821b6b61149086caa641974de43a1a Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 13 Jun 2018 18:09:28 +0200 Subject: [PATCH 67/69] Fix memory leak in ssl_server2 with SNI + async callback In ssl_server2, the private key objects are normally local variables of the main function. However this does not hold for private keys in the SNI configuration. When async callbacks are used, the test code transfers the ownership of the private keys to the async callbacks. Therefore the test code must free the SNI private keys through the async callbacks (but it must not free the straight private keys this way since they are not even heap-allocated). --- programs/ssl/ssl_server2.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index ae50b3d31..81041c44d 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -882,9 +882,10 @@ static int mbedtls_status_is_ssl_in_progress( int ret ) #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) typedef struct { - mbedtls_x509_crt *cert; - mbedtls_pk_context *pk; - unsigned delay; + 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 { @@ -905,15 +906,17 @@ typedef struct } ssl_async_key_context_t; int ssl_async_set_key( ssl_async_key_context_t *ctx, - mbedtls_x509_crt *cert, - mbedtls_pk_context *pk, - unsigned delay ) + 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 ); } @@ -1067,6 +1070,7 @@ static int ssl_async_resume( mbedtls_ssl_context *ssl, 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; } @@ -2306,7 +2310,7 @@ int main( int argc, char *argv[] ) #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) if( opt.async_private_delay1 >= 0 ) { - ret = ssl_async_set_key( &ssl_async_keys, &srvcert, pk, + ret = ssl_async_set_key( &ssl_async_keys, &srvcert, pk, 0, opt.async_private_delay1 ); if( ret < 0 ) { @@ -2329,7 +2333,7 @@ int main( int argc, char *argv[] ) #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) if( opt.async_private_delay2 >= 0 ) { - ret = ssl_async_set_key( &ssl_async_keys, &srvcert2, pk, + ret = ssl_async_set_key( &ssl_async_keys, &srvcert2, pk, 0, opt.async_private_delay2 ); if( ret < 0 ) { @@ -2391,7 +2395,7 @@ int main( int argc, char *argv[] ) for( cur = sni_info; cur != NULL; cur = cur->next ) { ret = ssl_async_set_key( &ssl_async_keys, - cur->cert, cur->key, + cur->cert, cur->key, 1, opt.async_private_delay2 ); if( ret < 0 ) { @@ -3018,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 From 725f1cb6bd5c6fe0efc9cb2b80ea1632290ef6a5 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 12 Jun 2018 15:06:40 +0200 Subject: [PATCH 68/69] SSL async tests: add a few test cases for error in decrypt The code paths in the library are different for decryption and for signature. Improve the test coverage by doing some error path tests for decryption in addition to signature. --- tests/ssl-opt.sh | 43 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index 6afca2d12..3ea56db8e 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -4243,7 +4243,7 @@ run_test "SSL async private: fall back to transparent key" \ -s "Async sign callback: no key matches this certificate." requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE -run_test "SSL async private: error in start" \ +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" \ @@ -4255,7 +4255,7 @@ run_test "SSL async private: error in start" \ -s "! mbedtls_ssl_handshake returned" requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE -run_test "SSL async private: cancel after start" \ +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" \ @@ -4266,7 +4266,7 @@ run_test "SSL async private: cancel after start" \ -s "Async cancel" requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE -run_test "SSL async private: error in resume" \ +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" \ @@ -4277,6 +4277,41 @@ run_test "SSL async private: error in resume" \ -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 \ @@ -4320,7 +4355,7 @@ run_test "SSL async private: cancel after start then fall back to transparent # key1: ECDSA, key2: RSA; use key1 through async, then key2 directly requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE -run_test "SSL async private: error in resume then fall back to transparent key" \ +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 \ From 0a8352b4c2b653e1fcafd18a0df91878034a29a5 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 13 Jun 2018 18:16:41 +0200 Subject: [PATCH 69/69] Fix harmless use of uninitialized memory in ssl_parse_encrypted_pms In ssl_parse_encrypted_pms, some operational failures from ssl_decrypt_encrypted_pms lead to diff being set to a value that depended on some uninitialized unsigned char and size_t values. This didn't affect the behavior of the program (assuming an implementation with no trap values for size_t) because all that matters is whether diff is 0, but Valgrind rightfully complained about the use of uninitialized memory. Behave nicely and initialize the offending memory. --- library/ssl_srv.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 2b25e091f..b49b9e1dd 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -3513,6 +3513,15 @@ static int ssl_parse_encrypted_pms( mbedtls_ssl_context *ssl, 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,