Move mbedtls_cf_hmac function to the constant-time module
Signed-off-by: Gabor Mezei <gabor.mezei@arm.com>
diff --git a/library/constant_time.c b/library/constant_time.c
index d48d646..c5fce5b 100644
--- a/library/constant_time.c
+++ b/library/constant_time.c
@@ -19,11 +19,16 @@
#include "common.h"
#include "constant_time.h"
+#include "mbedtls/error.h"
#if defined(MBEDTLS_BIGNUM_C)
#include "mbedtls/bignum.h"
#endif
+#if defined(MBEDTLS_SSL_TLS_C)
+#include "mbedtls/ssl_internal.h"
+#endif
+
/* constant-time buffer comparison */
int mbedtls_ssl_safer_memcmp( const void *a, const void *b, size_t n )
@@ -439,3 +444,95 @@
offset, offset_secret );
}
}
+
+#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC)
+
+/*
+ * Compute HMAC of variable-length data with constant flow.
+ *
+ * Only works with MD-5, SHA-1, SHA-256 and SHA-384.
+ * (Otherwise, computation of block_size needs to be adapted.)
+ */
+int mbedtls_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 )
+{
+ /*
+ * This function breaks the HMAC abstraction and uses the md_clone()
+ * extension to the MD API in order to get constant-flow behaviour.
+ *
+ * HMAC(msg) is defined as HASH(okey + HASH(ikey + msg)) where + means
+ * concatenation, and okey/ikey are the XOR of the key with some fixed bit
+ * patterns (see RFC 2104, sec. 2), which are stored in ctx->hmac_ctx.
+ *
+ * We'll first compute inner_hash = HASH(ikey + msg) by hashing up to
+ * minlen, then cloning the context, and for each byte up to maxlen
+ * finishing up the hash computation, keeping only the correct result.
+ *
+ * Then we only need to compute HASH(okey + inner_hash) and we're done.
+ */
+ const mbedtls_md_type_t md_alg = mbedtls_md_get_type( ctx->md_info );
+ /* TLS 1.0-1.2 only support SHA-384, SHA-256, SHA-1, MD-5,
+ * all of which have the same block size except SHA-384. */
+ const size_t block_size = md_alg == MBEDTLS_MD_SHA384 ? 128 : 64;
+ const unsigned char * const ikey = ctx->hmac_ctx;
+ const unsigned char * const okey = ikey + block_size;
+ const size_t hash_size = mbedtls_md_get_size( ctx->md_info );
+
+ unsigned char aux_out[MBEDTLS_MD_MAX_SIZE];
+ mbedtls_md_context_t aux;
+ size_t offset;
+ int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+
+ mbedtls_md_init( &aux );
+
+#define MD_CHK( func_call ) \
+ do { \
+ ret = (func_call); \
+ if( ret != 0 ) \
+ goto cleanup; \
+ } while( 0 )
+
+ MD_CHK( mbedtls_md_setup( &aux, ctx->md_info, 0 ) );
+
+ /* After hmac_start() of hmac_reset(), ikey has already been hashed,
+ * so we can start directly with the message */
+ MD_CHK( mbedtls_md_update( ctx, add_data, add_data_len ) );
+ MD_CHK( mbedtls_md_update( ctx, data, min_data_len ) );
+
+ /* For each possible length, compute the hash up to that point */
+ for( offset = min_data_len; offset <= max_data_len; offset++ )
+ {
+ MD_CHK( mbedtls_md_clone( &aux, ctx ) );
+ MD_CHK( mbedtls_md_finish( &aux, aux_out ) );
+ /* Keep only the correct inner_hash in the output buffer */
+ mbedtls_cf_memcpy_if_eq( output, aux_out, hash_size,
+ offset, data_len_secret );
+
+ if( offset < max_data_len )
+ MD_CHK( mbedtls_md_update( ctx, data + offset, 1 ) );
+ }
+
+ /* The context needs to finish() before it starts() again */
+ MD_CHK( mbedtls_md_finish( ctx, aux_out ) );
+
+ /* Now compute HASH(okey + inner_hash) */
+ MD_CHK( mbedtls_md_starts( ctx ) );
+ MD_CHK( mbedtls_md_update( ctx, okey, block_size ) );
+ MD_CHK( mbedtls_md_update( ctx, output, hash_size ) );
+ MD_CHK( mbedtls_md_finish( ctx, output ) );
+
+ /* Done, get ready for next time */
+ MD_CHK( mbedtls_md_hmac_reset( ctx ) );
+
+#undef MD_CHK
+
+cleanup:
+ mbedtls_md_free( &aux );
+ return( ret );
+}
+
+#endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */
diff --git a/library/constant_time.h b/library/constant_time.h
index 060aca3..a8d142b 100644
--- a/library/constant_time.h
+++ b/library/constant_time.h
@@ -23,6 +23,10 @@
#include "mbedtls/bignum.h"
#endif
+#if defined(MBEDTLS_SSL_TLS_C)
+#include "mbedtls/ssl_internal.h"
+#endif
+
#include <stddef.h>
int mbedtls_ssl_safer_memcmp( const void *a, const void *b, size_t n );
@@ -98,3 +102,47 @@
size_t offset_secret,
size_t offset_min, size_t offset_max,
size_t len );
+
+#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC)
+
+/** 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() and use one of the
+ * following hashes: SHA-384, SHA-256, SHA-1 or MD-5.
+ * 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
+ * greater 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 writable buffer of sufficient size to hold the
+ * HMAC value.
+ *
+ * \retval 0 on 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_TLS_CBC */
diff --git a/library/ssl_msg.c b/library/ssl_msg.c
index fe73130..d80421c 100644
--- a/library/ssl_msg.c
+++ b/library/ssl_msg.c
@@ -1044,97 +1044,6 @@
return( 0 );
}
-#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC)
-
-/*
- * Compute HMAC of variable-length data with constant flow.
- *
- * Only works with MD-5, SHA-1, SHA-256 and SHA-384.
- * (Otherwise, computation of block_size needs to be adapted.)
- */
-MBEDTLS_STATIC_TESTABLE int mbedtls_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 )
-{
- /*
- * This function breaks the HMAC abstraction and uses the md_clone()
- * extension to the MD API in order to get constant-flow behaviour.
- *
- * HMAC(msg) is defined as HASH(okey + HASH(ikey + msg)) where + means
- * concatenation, and okey/ikey are the XOR of the key with some fixed bit
- * patterns (see RFC 2104, sec. 2), which are stored in ctx->hmac_ctx.
- *
- * We'll first compute inner_hash = HASH(ikey + msg) by hashing up to
- * minlen, then cloning the context, and for each byte up to maxlen
- * finishing up the hash computation, keeping only the correct result.
- *
- * Then we only need to compute HASH(okey + inner_hash) and we're done.
- */
- const mbedtls_md_type_t md_alg = mbedtls_md_get_type( ctx->md_info );
- /* TLS 1.0-1.2 only support SHA-384, SHA-256, SHA-1, MD-5,
- * all of which have the same block size except SHA-384. */
- const size_t block_size = md_alg == MBEDTLS_MD_SHA384 ? 128 : 64;
- const unsigned char * const ikey = ctx->hmac_ctx;
- const unsigned char * const okey = ikey + block_size;
- const size_t hash_size = mbedtls_md_get_size( ctx->md_info );
-
- unsigned char aux_out[MBEDTLS_MD_MAX_SIZE];
- mbedtls_md_context_t aux;
- size_t offset;
- int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
-
- mbedtls_md_init( &aux );
-
-#define MD_CHK( func_call ) \
- do { \
- ret = (func_call); \
- if( ret != 0 ) \
- goto cleanup; \
- } while( 0 )
-
- MD_CHK( mbedtls_md_setup( &aux, ctx->md_info, 0 ) );
-
- /* After hmac_start() of hmac_reset(), ikey has already been hashed,
- * so we can start directly with the message */
- MD_CHK( mbedtls_md_update( ctx, add_data, add_data_len ) );
- MD_CHK( mbedtls_md_update( ctx, data, min_data_len ) );
-
- /* For each possible length, compute the hash up to that point */
- for( offset = min_data_len; offset <= max_data_len; offset++ )
- {
- MD_CHK( mbedtls_md_clone( &aux, ctx ) );
- MD_CHK( mbedtls_md_finish( &aux, aux_out ) );
- /* Keep only the correct inner_hash in the output buffer */
- mbedtls_cf_memcpy_if_eq( output, aux_out, hash_size,
- offset, data_len_secret );
-
- if( offset < max_data_len )
- MD_CHK( mbedtls_md_update( ctx, data + offset, 1 ) );
- }
-
- /* The context needs to finish() before it starts() again */
- MD_CHK( mbedtls_md_finish( ctx, aux_out ) );
-
- /* Now compute HASH(okey + inner_hash) */
- MD_CHK( mbedtls_md_starts( ctx ) );
- MD_CHK( mbedtls_md_update( ctx, okey, block_size ) );
- MD_CHK( mbedtls_md_update( ctx, output, hash_size ) );
- MD_CHK( mbedtls_md_finish( ctx, output ) );
-
- /* Done, get ready for next time */
- MD_CHK( mbedtls_md_hmac_reset( ctx ) );
-
-#undef MD_CHK
-
-cleanup:
- mbedtls_md_free( &aux );
- return( ret );
-}
-#endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */
-
int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl,
mbedtls_ssl_transform *transform,
mbedtls_record *rec )