Add dummy constant-flow HMAC function with tests

The dummy implementation is not constant-flow at all for now, it's just
here as a starting point and a support for developing the tests and putting
the infrastructure in place.

Depending on the implementation strategy, there might be various corner cases
depending on where the lengths fall relative to block boundaries. So it seems
safer to just test all possible lengths in a given range than to use only a
few randomly-chosen values.

Signed-off-by: Manuel Pégourié-Gonnard <manuel.pegourie-gonnard@arm.com>
This commit is contained in:
Manuel Pégourié-Gonnard 2020-07-28 10:19:45 +02:00
parent a60d0f2acb
commit fde750550d
4 changed files with 179 additions and 0 deletions

View File

@ -852,6 +852,50 @@ int mbedtls_ssl_get_key_exchange_md_tls1_2( mbedtls_ssl_context *ssl,
#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \
MBEDTLS_SSL_PROTO_TLS1_2 */
#if defined(MBEDTLS_SSL_SOME_SUITES_USE_CBC) && \
( defined(MBEDTLS_SSL_PROTO_TLS1) || \
defined(MBEDTLS_SSL_PROTO_TLS1_1) | \
defined(MBEDTLS_SSL_PROTO_TLS1_2) )
/** \brief Compute the HMAC of variable-length data with constant flow.
*
* This function computes the HMAC of the concatenation of \p add_data and \p
* data, and does with a code flow and memory access pattern that does not
* depend on \p data_len_secret, but only on \p min_data_len and \p
* max_data_len. In particular, this function always reads exactly \p
* max_data_len bytes from \p data.
*
* \param ctx The HMAC context. It must have keys configured
* with mbedtls_md_hmac_starts(). It is reset using
* mbedtls_md_hmac_reset() after the computation is
* complete to prepare for the next computation.
* \param add_data The additional data prepended to \p data. This
* must point to a readable buffer of \p add_data_len
* bytes.
* \param add_data_len The length of \p add_data in bytes.
* \param data The data appended to \p add_data. This must point
* to a readable buffer of \p max_data_len bytes.
* \param data_len_secret The length of the data to process in \p data.
* This must be no less than \p min_data_len and no
* greated than \p max_data_len.
* \param min_data_len The minimal length of \p data in bytes.
* \param max_data_len The maximal length of \p data in bytes.
* \param output The HMAC will be written here. This must point to
* a writeable buffer of sufficient size to hold the
* HMAC value.
*
* \retval 0
* Success.
* \retval MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED
* The hardware accelerator failed.
*/
int mbedtls_ssl_cf_hmac(
mbedtls_md_context_t *ctx,
const unsigned char *add_data, size_t add_data_len,
const unsigned char *data, size_t data_len_secret,
size_t min_data_len, size_t max_data_len,
unsigned char *output );
#endif /* MBEDTLS_SSL_SOME_SUITES_USE_CBC && TLS 1.0-1.2 */
#ifdef __cplusplus
}
#endif

View File

@ -1805,6 +1805,32 @@ static int ssl_encrypt_buf( mbedtls_ssl_context *ssl )
return( 0 );
}
#if defined(MBEDTLS_SSL_SOME_SUITES_USE_CBC) && \
( defined(MBEDTLS_SSL_PROTO_TLS1) || \
defined(MBEDTLS_SSL_PROTO_TLS1_1) || \
defined(MBEDTLS_SSL_PROTO_TLS1_2) )
/*
* Compute HMAC of variable-length data with constant flow.
*/
int mbedtls_ssl_cf_hmac(
mbedtls_md_context_t *ctx,
const unsigned char *add_data, size_t add_data_len,
const unsigned char *data, size_t data_len_secret,
size_t min_data_len, size_t max_data_len,
unsigned char *output )
{
/* WORK IN PROGRESS - THIS IS NOT CONSTANT FLOW AT ALL */
(void) min_data_len;
(void) max_data_len;
mbedtls_md_hmac_update( ctx, add_data, add_data_len );
mbedtls_md_hmac_update( ctx, data, data_len_secret );
mbedtls_md_hmac_finish( ctx, output );
mbedtls_md_hmac_reset( ctx );
return( 0 );
}
#endif /* MBEDTLS_SSL_SOME_SUITES_USE_CBC && TLS 1.0-1.2 */
static int ssl_decrypt_buf( mbedtls_ssl_context *ssl )
{
mbedtls_cipher_mode_t mode;

View File

@ -57,3 +57,19 @@ ssl_dtls_replay:"abcd12340000abcd12340100":"abcd123400ff":0
SSL SET_HOSTNAME memory leak: call ssl_set_hostname twice
ssl_set_hostname_twice:"server0":"server1"
Constant-flow HMAC: MD5
depends_on:MBEDTLS_MD5_C
ssl_cf_hmac:MBEDTLS_MD_MD5
Constant-flow HMAC: SHA1
depends_on:MBEDTLS_SHA1_C
ssl_cf_hmac:MBEDTLS_MD_SHA1
Constant-flow HMAC: SHA256
depends_on:MBEDTLS_SHA256_C
ssl_cf_hmac:MBEDTLS_MD_SHA256
Constant-flow HMAC: SHA384
depends_on:MBEDTLS_SHA512_C:!MBEDTLS_SHA512_NO_SHA384
ssl_cf_hmac:MBEDTLS_MD_SHA384

View File

@ -52,3 +52,96 @@ void ssl_set_hostname_twice( char *hostname0, char *hostname1 )
mbedtls_ssl_free( &ssl );
}
/* END_CASE */
/* BEGIN_CASE depends_on:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_AES_C:MBEDTLS_SSL_PROTO_TLS1_2 */
void ssl_cf_hmac( int hash )
{
/*
* Test the function mbedtls_ssl_cf_hmac() against a reference
* implementation.
*
* Note: the dependency is actually on TLS 1.0-1.2 and (AES or ARIA or
* Camellia or DES), but since the test framework doesn't support
* alternation in dependencies, just depend on the most common.
*/
mbedtls_md_context_t ctx, ref_ctx;
const mbedtls_md_info_t *md_info;
size_t out_len, block_size;
size_t min_in_len, in_len, max_in_len, i;
/* TLS additional data is 13 bytes (hence the "lucky 13" name) */
unsigned char add_data[13];
unsigned char ref_out[MBEDTLS_MD_MAX_SIZE];
unsigned char *data = NULL;
unsigned char *out = NULL;
unsigned char rec_num = 0;
mbedtls_md_init( &ctx );
mbedtls_md_init( &ref_ctx );
md_info = mbedtls_md_info_from_type( hash );
TEST_ASSERT( md_info != NULL );
out_len = mbedtls_md_get_size( md_info );
TEST_ASSERT( out_len != 0 );
block_size = hash == MBEDTLS_MD_SHA384 ? 128 : 64;
/* Use allocated out buffer to catch overwrites */
out = mbedtls_calloc( 1, out_len );
TEST_ASSERT( out != NULL );
/* Set up contexts with the given hash and a dummy key */
TEST_ASSERT( 0 == mbedtls_md_setup( &ctx, md_info, 1 ) );
TEST_ASSERT( 0 == mbedtls_md_setup( &ref_ctx, md_info, 1 ) );
memset( ref_out, 42, sizeof( ref_out ) );
TEST_ASSERT( 0 == mbedtls_md_hmac_starts( &ctx, ref_out, out_len ) );
TEST_ASSERT( 0 == mbedtls_md_hmac_starts( &ref_ctx, ref_out, out_len ) );
memset( ref_out, 0, sizeof( ref_out ) );
/*
* Test all possible lengths up to a point. The difference between
* max_in_len and min_in_len is at most 255, and make sure they both vary
* by at least one block size.
*/
for( max_in_len = 0; max_in_len <= 255 + block_size; max_in_len++ )
{
/* Use allocated in buffer to catch overreads */
data = mbedtls_calloc( 1, max_in_len );
TEST_ASSERT( data != NULL || max_in_len == 0 );
min_in_len = max_in_len > 255 ? max_in_len - 255 : 0;
for( in_len = min_in_len; in_len <= max_in_len; in_len++ )
{
/* Set up dummy data and add_data */
rec_num++;
memset( add_data, rec_num, sizeof( add_data ) );
for( i = 0; i < in_len; i++ )
data[i] = ( i & 0xff ) ^ rec_num;
/* Get the function's result */
TEST_ASSERT( 0 == mbedtls_ssl_cf_hmac( &ctx, add_data, sizeof( add_data ),
data, in_len,
min_in_len, max_in_len,
out ) );
/* Compute the reference result */
TEST_ASSERT( 0 == mbedtls_md_hmac_update( &ref_ctx, add_data,
sizeof( add_data ) ) );
TEST_ASSERT( 0 == mbedtls_md_hmac_update( &ref_ctx, data, in_len ) );
TEST_ASSERT( 0 == mbedtls_md_hmac_finish( &ref_ctx, ref_out ) );
TEST_ASSERT( 0 == mbedtls_md_hmac_reset( &ref_ctx ) );
/* Compare */
TEST_ASSERT( 0 == memcmp( out, ref_out, out_len ) );
}
mbedtls_free( data );
data = NULL;
}
exit:
mbedtls_md_free( &ref_ctx );
mbedtls_md_free( &ctx );
mbedtls_free( data );
mbedtls_free( out );
}
/* END_CASE */