From 0ee9683987396f6c02016a7f455c57968a3db339 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Tue, 9 May 2023 09:49:01 +0100 Subject: [PATCH 01/82] Move mbedtls_ct_base64_(enc|dec)_char into base64.c Signed-off-by: Dave Rodgman --- include/mbedtls/base64.h | 29 ++++++++++++++++++++++ library/base64.c | 33 +++++++++++++++++++++++++ library/constant_time.c | 36 ---------------------------- library/constant_time_internal.h | 41 ++++++++++---------------------- 4 files changed, 74 insertions(+), 65 deletions(-) diff --git a/include/mbedtls/base64.h b/include/mbedtls/base64.h index 635be713d8..e82c270eab 100644 --- a/include/mbedtls/base64.h +++ b/include/mbedtls/base64.h @@ -87,6 +87,35 @@ int mbedtls_base64_self_test(int verbose); #endif /* MBEDTLS_SELF_TEST */ +#if defined(MBEDTLS_TEST_HOOKS) + +/** Given a value in the range 0..63, return the corresponding Base64 digit. + * + * The implementation assumes that letters are consecutive (e.g. ASCII + * but not EBCDIC). + * + * \param value A value in the range 0..63. + * + * \return A base64 digit converted from \p value. + */ +unsigned char mbedtls_ct_base64_enc_char(unsigned char value); + +/** Given a Base64 digit, return its value. + * + * If c is not a Base64 digit ('A'..'Z', 'a'..'z', '0'..'9', '+' or '/'), + * return -1. + * + * The implementation assumes that letters are consecutive (e.g. ASCII + * but not EBCDIC). + * + * \param c A base64 digit. + * + * \return The value of the base64 digit \p c. + */ +signed char mbedtls_ct_base64_dec_value(unsigned char c); + +#endif /* MBEDTLS_TEST_HOOKS */ + #ifdef __cplusplus } #endif diff --git a/library/base64.c b/library/base64.c index 3eb9e7cc55..3f13fdab06 100644 --- a/library/base64.c +++ b/library/base64.c @@ -33,6 +33,39 @@ #include "mbedtls/platform.h" #endif /* MBEDTLS_SELF_TEST */ +MBEDTLS_STATIC_TESTABLE +unsigned char mbedtls_ct_base64_enc_char(unsigned char value) +{ + unsigned char digit = 0; + /* For each range of values, if value is in that range, mask digit with + * the corresponding value. Since value can only be in a single range, + * only at most one masking will change digit. */ + digit |= mbedtls_ct_uchar_mask_of_range(0, 25, value) & ('A' + value); + digit |= mbedtls_ct_uchar_mask_of_range(26, 51, value) & ('a' + value - 26); + digit |= mbedtls_ct_uchar_mask_of_range(52, 61, value) & ('0' + value - 52); + digit |= mbedtls_ct_uchar_mask_of_range(62, 62, value) & '+'; + digit |= mbedtls_ct_uchar_mask_of_range(63, 63, value) & '/'; + return digit; +} + +MBEDTLS_STATIC_TESTABLE +signed char mbedtls_ct_base64_dec_value(unsigned char c) +{ + unsigned char val = 0; + /* For each range of digits, if c is in that range, mask val with + * the corresponding value. Since c can only be in a single range, + * only at most one masking will change val. Set val to one plus + * the desired value so that it stays 0 if c is in none of the ranges. */ + val |= mbedtls_ct_uchar_mask_of_range('A', 'Z', c) & (c - 'A' + 0 + 1); + val |= mbedtls_ct_uchar_mask_of_range('a', 'z', c) & (c - 'a' + 26 + 1); + val |= mbedtls_ct_uchar_mask_of_range('0', '9', c) & (c - '0' + 52 + 1); + val |= mbedtls_ct_uchar_mask_of_range('+', '+', c) & (c - '+' + 62 + 1); + val |= mbedtls_ct_uchar_mask_of_range('/', '/', c) & (c - '/' + 63 + 1); + /* At this point, val is 0 if c is an invalid digit and v+1 if c is + * a digit with the value v. */ + return val - 1; +} + /* * Encode a buffer into base64 format */ diff --git a/library/constant_time.c b/library/constant_time.c index c823b78894..1f6c2ca020 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -212,7 +212,6 @@ size_t mbedtls_ct_size_mask_ge(size_t x, * * Constant flow with respect to c. */ -MBEDTLS_STATIC_TESTABLE unsigned char mbedtls_ct_uchar_mask_of_range(unsigned char low, unsigned char high, unsigned char c) @@ -344,41 +343,6 @@ void mbedtls_ct_mpi_uint_cond_assign(size_t n, #endif /* MBEDTLS_BIGNUM_C */ -#if defined(MBEDTLS_BASE64_C) - -unsigned char mbedtls_ct_base64_enc_char(unsigned char value) -{ - unsigned char digit = 0; - /* For each range of values, if value is in that range, mask digit with - * the corresponding value. Since value can only be in a single range, - * only at most one masking will change digit. */ - digit |= mbedtls_ct_uchar_mask_of_range(0, 25, value) & ('A' + value); - digit |= mbedtls_ct_uchar_mask_of_range(26, 51, value) & ('a' + value - 26); - digit |= mbedtls_ct_uchar_mask_of_range(52, 61, value) & ('0' + value - 52); - digit |= mbedtls_ct_uchar_mask_of_range(62, 62, value) & '+'; - digit |= mbedtls_ct_uchar_mask_of_range(63, 63, value) & '/'; - return digit; -} - -signed char mbedtls_ct_base64_dec_value(unsigned char c) -{ - unsigned char val = 0; - /* For each range of digits, if c is in that range, mask val with - * the corresponding value. Since c can only be in a single range, - * only at most one masking will change val. Set val to one plus - * the desired value so that it stays 0 if c is in none of the ranges. */ - val |= mbedtls_ct_uchar_mask_of_range('A', 'Z', c) & (c - 'A' + 0 + 1); - val |= mbedtls_ct_uchar_mask_of_range('a', 'z', c) & (c - 'a' + 26 + 1); - val |= mbedtls_ct_uchar_mask_of_range('0', '9', c) & (c - '0' + 52 + 1); - val |= mbedtls_ct_uchar_mask_of_range('+', '+', c) & (c - '+' + 62 + 1); - val |= mbedtls_ct_uchar_mask_of_range('/', '/', c) & (c - '/' + 63 + 1); - /* At this point, val is 0 if c is an invalid digit and v+1 if c is - * a digit with the value v. */ - return val - 1; -} - -#endif /* MBEDTLS_BASE64_C */ - #if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) /** Shift some data towards the left inside a buffer. diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h index c4a32c7f02..4ca3925260 100644 --- a/library/constant_time_internal.h +++ b/library/constant_time_internal.h @@ -185,35 +185,6 @@ void mbedtls_ct_mpi_uint_cond_assign(size_t n, #endif /* MBEDTLS_BIGNUM_C */ -#if defined(MBEDTLS_BASE64_C) - -/** Given a value in the range 0..63, return the corresponding Base64 digit. - * - * The implementation assumes that letters are consecutive (e.g. ASCII - * but not EBCDIC). - * - * \param value A value in the range 0..63. - * - * \return A base64 digit converted from \p value. - */ -unsigned char mbedtls_ct_base64_enc_char(unsigned char value); - -/** Given a Base64 digit, return its value. - * - * If c is not a Base64 digit ('A'..'Z', 'a'..'z', '0'..'9', '+' or '/'), - * return -1. - * - * The implementation assumes that letters are consecutive (e.g. ASCII - * but not EBCDIC). - * - * \param c A base64 digit. - * - * \return The value of the base64 digit \p c. - */ -signed char mbedtls_ct_base64_dec_value(unsigned char c); - -#endif /* MBEDTLS_BASE64_C */ - #if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC) /** Conditional memcpy without branches. @@ -360,4 +331,16 @@ int mbedtls_ct_rsaes_pkcs1_v15_unpadding(unsigned char *input, #endif /* MBEDTLS_PKCS1_V15 && MBEDTLS_RSA_C && ! MBEDTLS_RSA_ALT */ +#if defined(MBEDTLS_BASE64_C) + +/* Return 0xff if low <= c <= high, 0 otherwise. + * + * Constant flow with respect to c. + */ +unsigned char mbedtls_ct_uchar_mask_of_range(unsigned char low, + unsigned char high, + unsigned char c); + +#endif /* MBEDTLS_BASE64_C */ + #endif /* MBEDTLS_CONSTANT_TIME_INTERNAL_H */ From 8c94e219f9e4a017af84b6aaa777cd12c19010d9 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Tue, 9 May 2023 10:39:03 +0100 Subject: [PATCH 02/82] Evolve mbedtls_ct_uchar_in_range_if interface Signed-off-by: Dave Rodgman --- library/base64.c | 20 ++++++++++---------- library/constant_time_internal.h | 24 +++++++++++++++++++----- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/library/base64.c b/library/base64.c index 3f13fdab06..2b623b9bc0 100644 --- a/library/base64.c +++ b/library/base64.c @@ -40,11 +40,11 @@ unsigned char mbedtls_ct_base64_enc_char(unsigned char value) /* For each range of values, if value is in that range, mask digit with * the corresponding value. Since value can only be in a single range, * only at most one masking will change digit. */ - digit |= mbedtls_ct_uchar_mask_of_range(0, 25, value) & ('A' + value); - digit |= mbedtls_ct_uchar_mask_of_range(26, 51, value) & ('a' + value - 26); - digit |= mbedtls_ct_uchar_mask_of_range(52, 61, value) & ('0' + value - 52); - digit |= mbedtls_ct_uchar_mask_of_range(62, 62, value) & '+'; - digit |= mbedtls_ct_uchar_mask_of_range(63, 63, value) & '/'; + digit |= mbedtls_ct_uchar_in_range_if(0, 25, value, 'A' + value); + digit |= mbedtls_ct_uchar_in_range_if(26, 51, value, 'a' + value - 26); + digit |= mbedtls_ct_uchar_in_range_if(52, 61, value, '0' + value - 52); + digit |= mbedtls_ct_uchar_in_range_if(62, 62, value, '+'); + digit |= mbedtls_ct_uchar_in_range_if(63, 63, value, '/'); return digit; } @@ -56,11 +56,11 @@ signed char mbedtls_ct_base64_dec_value(unsigned char c) * the corresponding value. Since c can only be in a single range, * only at most one masking will change val. Set val to one plus * the desired value so that it stays 0 if c is in none of the ranges. */ - val |= mbedtls_ct_uchar_mask_of_range('A', 'Z', c) & (c - 'A' + 0 + 1); - val |= mbedtls_ct_uchar_mask_of_range('a', 'z', c) & (c - 'a' + 26 + 1); - val |= mbedtls_ct_uchar_mask_of_range('0', '9', c) & (c - '0' + 52 + 1); - val |= mbedtls_ct_uchar_mask_of_range('+', '+', c) & (c - '+' + 62 + 1); - val |= mbedtls_ct_uchar_mask_of_range('/', '/', c) & (c - '/' + 63 + 1); + val |= mbedtls_ct_uchar_in_range_if('A', 'Z', c, c - 'A' + 0 + 1); + val |= mbedtls_ct_uchar_in_range_if('a', 'z', c, c - 'a' + 26 + 1); + val |= mbedtls_ct_uchar_in_range_if('0', '9', c, c - '0' + 52 + 1); + val |= mbedtls_ct_uchar_in_range_if('+', '+', c, c - '+' + 62 + 1); + val |= mbedtls_ct_uchar_in_range_if('/', '/', c, c - '/' + 63 + 1); /* At this point, val is 0 if c is an invalid digit and v+1 if c is * a digit with the value v. */ return val - 1; diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h index 4ca3925260..dde6a0bfc6 100644 --- a/library/constant_time_internal.h +++ b/library/constant_time_internal.h @@ -333,13 +333,27 @@ int mbedtls_ct_rsaes_pkcs1_v15_unpadding(unsigned char *input, #if defined(MBEDTLS_BASE64_C) -/* Return 0xff if low <= c <= high, 0 otherwise. +/** Constant-flow char selection * - * Constant flow with respect to c. + * \param low Bottom of range + * \param high Top of range + * \param c Value to compare to range + * \param t Value to return, if in range + * + * \return \p t if \p low <= \p c <= \p high, 0 otherwise. */ -unsigned char mbedtls_ct_uchar_mask_of_range(unsigned char low, - unsigned char high, - unsigned char c); +static inline unsigned char mbedtls_ct_uchar_in_range_if(unsigned char low, + unsigned char high, + unsigned char c, + unsigned char t) +{ + /* low_mask is: 0 if low <= c, 0x...ff if low > c */ + unsigned low_mask = ((unsigned) c - low) >> 8; + /* high_mask is: 0 if c <= high, 0x...ff if c > high */ + unsigned high_mask = ((unsigned) high - c) >> 8; + return (unsigned char) + mbedtls_ct_uint_if(~mbedtls_ct_mpi_uint_mask(low_mask | high_mask), t, 0); +} #endif /* MBEDTLS_BASE64_C */ From 2801f7fa8dcf9790b21f154712d8413570b409e0 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Tue, 9 May 2023 11:00:07 +0100 Subject: [PATCH 03/82] Move mbedtls_ct_hmac into ssl_msg.c Signed-off-by: Dave Rodgman --- library/constant_time.c | 221 ------------------------------ library/constant_time_internal.h | 57 -------- library/ssl_misc.h | 60 ++++++++ library/ssl_msg.c | 228 +++++++++++++++++++++++++++++++ 4 files changed, 288 insertions(+), 278 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index 1f6c2ca020..a786d380bd 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -431,227 +431,6 @@ void mbedtls_ct_memcpy_offset(unsigned char *dest, } } -#if defined(MBEDTLS_USE_PSA_CRYPTO) - -#if defined(PSA_WANT_ALG_SHA_384) -#define MAX_HASH_BLOCK_LENGTH PSA_HASH_BLOCK_LENGTH(PSA_ALG_SHA_384) -#elif defined(PSA_WANT_ALG_SHA_256) -#define MAX_HASH_BLOCK_LENGTH PSA_HASH_BLOCK_LENGTH(PSA_ALG_SHA_256) -#else /* See check_config.h */ -#define MAX_HASH_BLOCK_LENGTH PSA_HASH_BLOCK_LENGTH(PSA_ALG_SHA_1) -#endif - -int mbedtls_ct_hmac(mbedtls_svc_key_id_t key, - psa_algorithm_t mac_alg, - 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 psa_hash_clone() - * extension 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). - * - * We'll first compute ikey/okey, then 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. - */ - psa_algorithm_t hash_alg = PSA_ALG_HMAC_GET_HASH(mac_alg); - const size_t block_size = PSA_HASH_BLOCK_LENGTH(hash_alg); - unsigned char key_buf[MAX_HASH_BLOCK_LENGTH]; - const size_t hash_size = PSA_HASH_LENGTH(hash_alg); - psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT; - size_t hash_length; - - unsigned char aux_out[PSA_HASH_MAX_SIZE]; - psa_hash_operation_t aux_operation = PSA_HASH_OPERATION_INIT; - size_t offset; - psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; - - size_t mac_key_length; - size_t i; - -#define PSA_CHK(func_call) \ - do { \ - status = (func_call); \ - if (status != PSA_SUCCESS) \ - goto cleanup; \ - } while (0) - - /* Export MAC key - * We assume key length is always exactly the output size - * which is never more than the block size, thus we use block_size - * as the key buffer size. - */ - PSA_CHK(psa_export_key(key, key_buf, block_size, &mac_key_length)); - - /* Calculate ikey */ - for (i = 0; i < mac_key_length; i++) { - key_buf[i] = (unsigned char) (key_buf[i] ^ 0x36); - } - for (; i < block_size; ++i) { - key_buf[i] = 0x36; - } - - PSA_CHK(psa_hash_setup(&operation, hash_alg)); - - /* Now compute inner_hash = HASH(ikey + msg) */ - PSA_CHK(psa_hash_update(&operation, key_buf, block_size)); - PSA_CHK(psa_hash_update(&operation, add_data, add_data_len)); - PSA_CHK(psa_hash_update(&operation, data, min_data_len)); - - /* Fill the hash buffer in advance with something that is - * not a valid hash (barring an attack on the hash and - * deliberately-crafted input), in case the caller doesn't - * check the return status properly. */ - memset(output, '!', hash_size); - - /* For each possible length, compute the hash up to that point */ - for (offset = min_data_len; offset <= max_data_len; offset++) { - PSA_CHK(psa_hash_clone(&operation, &aux_operation)); - PSA_CHK(psa_hash_finish(&aux_operation, aux_out, - PSA_HASH_MAX_SIZE, &hash_length)); - /* Keep only the correct inner_hash in the output buffer */ - mbedtls_ct_memcpy_if_eq(output, aux_out, hash_size, - offset, data_len_secret); - - if (offset < max_data_len) { - PSA_CHK(psa_hash_update(&operation, data + offset, 1)); - } - } - - /* Abort current operation to prepare for final operation */ - PSA_CHK(psa_hash_abort(&operation)); - - /* Calculate okey */ - for (i = 0; i < mac_key_length; i++) { - key_buf[i] = (unsigned char) ((key_buf[i] ^ 0x36) ^ 0x5C); - } - for (; i < block_size; ++i) { - key_buf[i] = 0x5C; - } - - /* Now compute HASH(okey + inner_hash) */ - PSA_CHK(psa_hash_setup(&operation, hash_alg)); - PSA_CHK(psa_hash_update(&operation, key_buf, block_size)); - PSA_CHK(psa_hash_update(&operation, output, hash_size)); - PSA_CHK(psa_hash_finish(&operation, output, hash_size, &hash_length)); - -#undef PSA_CHK - -cleanup: - mbedtls_platform_zeroize(key_buf, MAX_HASH_BLOCK_LENGTH); - mbedtls_platform_zeroize(aux_out, PSA_HASH_MAX_SIZE); - - psa_hash_abort(&operation); - psa_hash_abort(&aux_operation); - return PSA_TO_MBEDTLS_ERR(status); -} - -#undef MAX_HASH_BLOCK_LENGTH - -#else -int mbedtls_ct_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.2 only supports 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)); - - /* Fill the hash buffer in advance with something that is - * not a valid hash (barring an attack on the hash and - * deliberately-crafted input), in case the caller doesn't - * check the return status properly. */ - memset(output, '!', hash_size); - - /* 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_ct_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_USE_PSA_CRYPTO */ - #endif /* MBEDTLS_SSL_SOME_SUITES_USE_MAC */ #if defined(MBEDTLS_BIGNUM_C) diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h index dde6a0bfc6..d8a0fc7b38 100644 --- a/library/constant_time_internal.h +++ b/library/constant_time_internal.h @@ -236,63 +236,6 @@ void mbedtls_ct_memcpy_offset(unsigned char *dest, size_t offset_max, size_t len); -/** 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 first part of the message whose HMAC is being - * calculated. 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 buffer containing the second part of the - * message. 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 the second part of the - * message, read from \p data. - * \param max_data_len The maximal length of the second part of the - * message, read from \p data. - * \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. - */ -#if defined(MBEDTLS_USE_PSA_CRYPTO) -int mbedtls_ct_hmac(mbedtls_svc_key_id_t key, - psa_algorithm_t alg, - 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); -#else -int mbedtls_ct_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_USE_PSA_CRYPTO */ - #endif /* MBEDTLS_SSL_SOME_SUITES_USE_MAC */ #if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) diff --git a/library/ssl_misc.h b/library/ssl_misc.h index 17149c59e6..eb11f7b254 100644 --- a/library/ssl_misc.h +++ b/library/ssl_misc.h @@ -2788,4 +2788,64 @@ static inline void mbedtls_ssl_session_clear_ticket_flags( int mbedtls_ssl_tls13_finalize_client_hello(mbedtls_ssl_context *ssl); #endif +#if defined(MBEDTLS_TEST_HOOKS) && defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC) + +/** 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 first part of the message whose HMAC is being + * calculated. 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 buffer containing the second part of the + * message. 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 the second part of the + * message, read from \p data. + * \param max_data_len The maximal length of the second part of the + * message, read from \p data. + * \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. + */ +#if defined(MBEDTLS_USE_PSA_CRYPTO) +int mbedtls_ct_hmac(mbedtls_svc_key_id_t key, + psa_algorithm_t mac_alg, + 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); +#else +int mbedtls_ct_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 /* defined(MBEDTLS_USE_PSA_CRYPTO) */ +#endif /* MBEDTLS_TEST_HOOKS && defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC) */ + #endif /* ssl_misc.h */ diff --git a/library/ssl_msg.c b/library/ssl_msg.c index 18c19f93ef..69706cf532 100644 --- a/library/ssl_msg.c +++ b/library/ssl_msg.c @@ -54,6 +54,234 @@ psa_generic_status_to_mbedtls) #endif +#if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC) + +#if defined(MBEDTLS_USE_PSA_CRYPTO) + +#if defined(PSA_WANT_ALG_SHA_384) +#define MAX_HASH_BLOCK_LENGTH PSA_HASH_BLOCK_LENGTH(PSA_ALG_SHA_384) +#elif defined(PSA_WANT_ALG_SHA_256) +#define MAX_HASH_BLOCK_LENGTH PSA_HASH_BLOCK_LENGTH(PSA_ALG_SHA_256) +#else /* See check_config.h */ +#define MAX_HASH_BLOCK_LENGTH PSA_HASH_BLOCK_LENGTH(PSA_ALG_SHA_1) +#endif + +MBEDTLS_STATIC_TESTABLE +int mbedtls_ct_hmac(mbedtls_svc_key_id_t key, + psa_algorithm_t mac_alg, + 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 psa_hash_clone() + * extension 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). + * + * We'll first compute ikey/okey, then 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. + */ + psa_algorithm_t hash_alg = PSA_ALG_HMAC_GET_HASH(mac_alg); + const size_t block_size = PSA_HASH_BLOCK_LENGTH(hash_alg); + unsigned char key_buf[MAX_HASH_BLOCK_LENGTH]; + const size_t hash_size = PSA_HASH_LENGTH(hash_alg); + psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT; + size_t hash_length; + + unsigned char aux_out[PSA_HASH_MAX_SIZE]; + psa_hash_operation_t aux_operation = PSA_HASH_OPERATION_INIT; + size_t offset; + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + size_t mac_key_length; + size_t i; + +#define PSA_CHK(func_call) \ + do { \ + status = (func_call); \ + if (status != PSA_SUCCESS) \ + goto cleanup; \ + } while (0) + + /* Export MAC key + * We assume key length is always exactly the output size + * which is never more than the block size, thus we use block_size + * as the key buffer size. + */ + PSA_CHK(psa_export_key(key, key_buf, block_size, &mac_key_length)); + + /* Calculate ikey */ + for (i = 0; i < mac_key_length; i++) { + key_buf[i] = (unsigned char) (key_buf[i] ^ 0x36); + } + for (; i < block_size; ++i) { + key_buf[i] = 0x36; + } + + PSA_CHK(psa_hash_setup(&operation, hash_alg)); + + /* Now compute inner_hash = HASH(ikey + msg) */ + PSA_CHK(psa_hash_update(&operation, key_buf, block_size)); + PSA_CHK(psa_hash_update(&operation, add_data, add_data_len)); + PSA_CHK(psa_hash_update(&operation, data, min_data_len)); + + /* Fill the hash buffer in advance with something that is + * not a valid hash (barring an attack on the hash and + * deliberately-crafted input), in case the caller doesn't + * check the return status properly. */ + memset(output, '!', hash_size); + + /* For each possible length, compute the hash up to that point */ + for (offset = min_data_len; offset <= max_data_len; offset++) { + PSA_CHK(psa_hash_clone(&operation, &aux_operation)); + PSA_CHK(psa_hash_finish(&aux_operation, aux_out, + PSA_HASH_MAX_SIZE, &hash_length)); + /* Keep only the correct inner_hash in the output buffer */ + mbedtls_ct_memcpy_if_eq(output, aux_out, hash_size, + offset, data_len_secret); + + if (offset < max_data_len) { + PSA_CHK(psa_hash_update(&operation, data + offset, 1)); + } + } + + /* Abort current operation to prepare for final operation */ + PSA_CHK(psa_hash_abort(&operation)); + + /* Calculate okey */ + for (i = 0; i < mac_key_length; i++) { + key_buf[i] = (unsigned char) ((key_buf[i] ^ 0x36) ^ 0x5C); + } + for (; i < block_size; ++i) { + key_buf[i] = 0x5C; + } + + /* Now compute HASH(okey + inner_hash) */ + PSA_CHK(psa_hash_setup(&operation, hash_alg)); + PSA_CHK(psa_hash_update(&operation, key_buf, block_size)); + PSA_CHK(psa_hash_update(&operation, output, hash_size)); + PSA_CHK(psa_hash_finish(&operation, output, hash_size, &hash_length)); + +#undef PSA_CHK + +cleanup: + mbedtls_platform_zeroize(key_buf, MAX_HASH_BLOCK_LENGTH); + mbedtls_platform_zeroize(aux_out, PSA_HASH_MAX_SIZE); + + psa_hash_abort(&operation); + psa_hash_abort(&aux_operation); + return PSA_TO_MBEDTLS_ERR(status); +} + +#undef MAX_HASH_BLOCK_LENGTH + +#else +MBEDTLS_STATIC_TESTABLE +int mbedtls_ct_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.2 only supports 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)); + + /* Fill the hash buffer in advance with something that is + * not a valid hash (barring an attack on the hash and + * deliberately-crafted input), in case the caller doesn't + * check the return status properly. */ + memset(output, '!', hash_size); + + /* 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_ct_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_USE_PSA_CRYPTO */ + +#endif /* MBEDTLS_SSL_SOME_SUITES_USE_MAC */ + static uint32_t ssl_get_hs_total_len(mbedtls_ssl_context const *ssl); /* From 0afe0018713de498eaaf6b7de3f6ee325db8e186 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Tue, 9 May 2023 11:09:52 +0100 Subject: [PATCH 04/82] Expose mbedtls_ct_size_gt and mbedtls_ct_mem_move_to_left in ct interface Signed-off-by: Dave Rodgman --- library/constant_time.c | 32 ++------------------------- library/constant_time_internal.h | 38 ++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 30 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index a786d380bd..093ae28726 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -253,19 +253,7 @@ unsigned mbedtls_ct_size_bool_eq(size_t x, #if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) -/** Constant-flow "greater than" comparison: - * return x > y - * - * This is equivalent to \p x > \p y, but is likely to be compiled - * to code using bitwise operation rather than a branch. - * - * \param x The first value to analyze. - * \param y The second value to analyze. - * - * \return 1 if \p x greater than \p y, otherwise 0. - */ -static unsigned mbedtls_ct_size_gt(size_t x, - size_t y) +unsigned mbedtls_ct_size_gt(size_t x, size_t y) { /* Return the sign bit (1 for negative) of (y - x). */ return (y - x) >> (sizeof(size_t) * 8 - 1); @@ -345,23 +333,7 @@ void mbedtls_ct_mpi_uint_cond_assign(size_t n, #if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) -/** Shift some data towards the left inside a buffer. - * - * `mbedtls_ct_mem_move_to_left(start, total, offset)` is functionally - * equivalent to - * ``` - * memmove(start, start + offset, total - offset); - * memset(start + offset, 0, total - offset); - * ``` - * but it strives to use a memory access pattern (and thus total timing) - * that does not depend on \p offset. This timing independence comes at - * the expense of performance. - * - * \param start Pointer to the start of the buffer. - * \param total Total size of the buffer. - * \param offset Offset from which to copy \p total - \p offset bytes. - */ -static void mbedtls_ct_mem_move_to_left(void *start, +void mbedtls_ct_mem_move_to_left(void *start, size_t total, size_t offset) { diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h index d8a0fc7b38..84ca96233f 100644 --- a/library/constant_time_internal.h +++ b/library/constant_time_internal.h @@ -300,4 +300,42 @@ static inline unsigned char mbedtls_ct_uchar_in_range_if(unsigned char low, #endif /* MBEDTLS_BASE64_C */ + +#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) + +/** Constant-flow "greater than" comparison: + * return x > y + * + * This is equivalent to \p x > \p y, but is likely to be compiled + * to code using bitwise operation rather than a branch. + * + * \param x The first value to analyze. + * \param y The second value to analyze. + * + * \return 1 if \p x greater than \p y, otherwise 0. + */ +unsigned mbedtls_ct_size_gt(size_t x, size_t y); + +/** Shift some data towards the left inside a buffer. + * + * `mbedtls_ct_mem_move_to_left(start, total, offset)` is functionally + * equivalent to + * ``` + * memmove(start, start + offset, total - offset); + * memset(start + offset, 0, total - offset); + * ``` + * but it strives to use a memory access pattern (and thus total timing) + * that does not depend on \p offset. This timing independence comes at + * the expense of performance. + * + * \param start Pointer to the start of the buffer. + * \param total Total size of the buffer. + * \param offset Offset from which to copy \p total - \p offset bytes. + */ +void mbedtls_ct_mem_move_to_left(void *start, + size_t total, + size_t offset); + +#endif /* defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) */ + #endif /* MBEDTLS_CONSTANT_TIME_INTERNAL_H */ From 19e8cd06febe82340cf6b74fd4f467ab098f6fd1 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Tue, 9 May 2023 11:10:21 +0100 Subject: [PATCH 05/82] Move mbedtls_ct_rsaes_pkcs1_v15_unpadding into rsa.c Signed-off-by: Dave Rodgman --- library/constant_time.c | 135 +------------------------- library/constant_time_internal.h | 40 +------- library/rsa.c | 158 +++++++++++++++++++++++++++++++ 3 files changed, 162 insertions(+), 171 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index 093ae28726..16d7a1fc41 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -334,8 +334,8 @@ void mbedtls_ct_mpi_uint_cond_assign(size_t n, #if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) void mbedtls_ct_mem_move_to_left(void *start, - size_t total, - size_t offset) + size_t total, + size_t offset) { volatile unsigned char *buf = start; size_t i, n; @@ -590,134 +590,3 @@ int mbedtls_mpi_lt_mpi_ct(const mbedtls_mpi *X, } #endif /* MBEDTLS_BIGNUM_C */ - -#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) - -int mbedtls_ct_rsaes_pkcs1_v15_unpadding(unsigned char *input, - size_t ilen, - unsigned char *output, - size_t output_max_len, - size_t *olen) -{ - int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; - size_t i, plaintext_max_size; - - /* The following variables take sensitive values: their value must - * not leak into the observable behavior of the function other than - * the designated outputs (output, olen, return value). Otherwise - * this would open the execution of the function to - * side-channel-based variants of the Bleichenbacher padding oracle - * attack. Potential side channels include overall timing, memory - * access patterns (especially visible to an adversary who has access - * to a shared memory cache), and branches (especially visible to - * an adversary who has access to a shared code cache or to a shared - * branch predictor). */ - size_t pad_count = 0; - unsigned bad = 0; - unsigned char pad_done = 0; - size_t plaintext_size = 0; - unsigned output_too_large; - - plaintext_max_size = (output_max_len > ilen - 11) ? ilen - 11 - : output_max_len; - - /* Check and get padding length in constant time and constant - * memory trace. The first byte must be 0. */ - bad |= input[0]; - - - /* Decode EME-PKCS1-v1_5 padding: 0x00 || 0x02 || PS || 0x00 - * where PS must be at least 8 nonzero bytes. */ - bad |= input[1] ^ MBEDTLS_RSA_CRYPT; - - /* Read the whole buffer. Set pad_done to nonzero if we find - * the 0x00 byte and remember the padding length in pad_count. */ - for (i = 2; i < ilen; i++) { - pad_done |= ((input[i] | (unsigned char) -input[i]) >> 7) ^ 1; - pad_count += ((pad_done | (unsigned char) -pad_done) >> 7) ^ 1; - } - - - /* If pad_done is still zero, there's no data, only unfinished padding. */ - bad |= mbedtls_ct_uint_if(pad_done, 0, 1); - - /* There must be at least 8 bytes of padding. */ - bad |= mbedtls_ct_size_gt(8, pad_count); - - /* If the padding is valid, set plaintext_size to the number of - * remaining bytes after stripping the padding. If the padding - * is invalid, avoid leaking this fact through the size of the - * output: use the maximum message size that fits in the output - * buffer. Do it without branches to avoid leaking the padding - * validity through timing. RSA keys are small enough that all the - * size_t values involved fit in unsigned int. */ - plaintext_size = mbedtls_ct_uint_if( - bad, (unsigned) plaintext_max_size, - (unsigned) (ilen - pad_count - 3)); - - /* Set output_too_large to 0 if the plaintext fits in the output - * buffer and to 1 otherwise. */ - output_too_large = mbedtls_ct_size_gt(plaintext_size, - plaintext_max_size); - - /* Set ret without branches to avoid timing attacks. Return: - * - INVALID_PADDING if the padding is bad (bad != 0). - * - OUTPUT_TOO_LARGE if the padding is good but the decrypted - * plaintext does not fit in the output buffer. - * - 0 if the padding is correct. */ - ret = -(int) mbedtls_ct_uint_if( - bad, -MBEDTLS_ERR_RSA_INVALID_PADDING, - mbedtls_ct_uint_if(output_too_large, - -MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE, - 0)); - - /* If the padding is bad or the plaintext is too large, zero the - * data that we're about to copy to the output buffer. - * We need to copy the same amount of data - * from the same buffer whether the padding is good or not to - * avoid leaking the padding validity through overall timing or - * through memory or cache access patterns. */ - bad = mbedtls_ct_uint_mask(bad | output_too_large); - for (i = 11; i < ilen; i++) { - input[i] &= ~bad; - } - - /* If the plaintext is too large, truncate it to the buffer size. - * Copy anyway to avoid revealing the length through timing, because - * revealing the length is as bad as revealing the padding validity - * for a Bleichenbacher attack. */ - plaintext_size = mbedtls_ct_uint_if(output_too_large, - (unsigned) plaintext_max_size, - (unsigned) plaintext_size); - - /* Move the plaintext to the leftmost position where it can start in - * the working buffer, i.e. make it start plaintext_max_size from - * the end of the buffer. Do this with a memory access trace that - * does not depend on the plaintext size. After this move, the - * starting location of the plaintext is no longer sensitive - * information. */ - mbedtls_ct_mem_move_to_left(input + ilen - plaintext_max_size, - plaintext_max_size, - plaintext_max_size - plaintext_size); - - /* Finally copy the decrypted plaintext plus trailing zeros into the output - * buffer. If output_max_len is 0, then output may be an invalid pointer - * and the result of memcpy() would be undefined; prevent undefined - * behavior making sure to depend only on output_max_len (the size of the - * user-provided output buffer), which is independent from plaintext - * length, validity of padding, success of the decryption, and other - * secrets. */ - if (output_max_len != 0) { - memcpy(output, input + ilen - plaintext_max_size, plaintext_max_size); - } - - /* Report the amount of data we copied to the output buffer. In case - * of errors (bad padding or output too large), the value of *olen - * when this function returns is not specified. Making it equivalent - * to the good case limits the risks of leaking the padding validity. */ - *olen = plaintext_size; - - return ret; -} - -#endif /* MBEDTLS_PKCS1_V15 && MBEDTLS_RSA_C && ! MBEDTLS_RSA_ALT */ diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h index 84ca96233f..bfeb8c55ec 100644 --- a/library/constant_time_internal.h +++ b/library/constant_time_internal.h @@ -238,42 +238,6 @@ void mbedtls_ct_memcpy_offset(unsigned char *dest, #endif /* MBEDTLS_SSL_SOME_SUITES_USE_MAC */ -#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) - -/** This function performs the unpadding part of a PKCS#1 v1.5 decryption - * operation (EME-PKCS1-v1_5 decoding). - * - * \note The return value from this function is a sensitive value - * (this is unusual). #MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE shouldn't happen - * in a well-written application, but 0 vs #MBEDTLS_ERR_RSA_INVALID_PADDING - * is often a situation that an attacker can provoke and leaking which - * one is the result is precisely the information the attacker wants. - * - * \param input The input buffer which is the payload inside PKCS#1v1.5 - * encryption padding, called the "encoded message EM" - * by the terminology. - * \param ilen The length of the payload in the \p input buffer. - * \param output The buffer for the payload, called "message M" by the - * PKCS#1 terminology. This must be a writable buffer of - * length \p output_max_len bytes. - * \param olen The address at which to store the length of - * the payload. This must not be \c NULL. - * \param output_max_len The length in bytes of the output buffer \p output. - * - * \return \c 0 on success. - * \return #MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE - * The output buffer is too small for the unpadded payload. - * \return #MBEDTLS_ERR_RSA_INVALID_PADDING - * The input doesn't contain properly formatted padding. - */ -int mbedtls_ct_rsaes_pkcs1_v15_unpadding(unsigned char *input, - size_t ilen, - unsigned char *output, - size_t output_max_len, - size_t *olen); - -#endif /* MBEDTLS_PKCS1_V15 && MBEDTLS_RSA_C && ! MBEDTLS_RSA_ALT */ - #if defined(MBEDTLS_BASE64_C) /** Constant-flow char selection @@ -333,8 +297,8 @@ unsigned mbedtls_ct_size_gt(size_t x, size_t y); * \param offset Offset from which to copy \p total - \p offset bytes. */ void mbedtls_ct_mem_move_to_left(void *start, - size_t total, - size_t offset); + size_t total, + size_t offset); #endif /* defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) */ diff --git a/library/rsa.c b/library/rsa.c index 87b3311899..e4a45b37c1 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -56,6 +56,164 @@ #include "mbedtls/platform.h" + +#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) + +/** This function performs the unpadding part of a PKCS#1 v1.5 decryption + * operation (EME-PKCS1-v1_5 decoding). + * + * \note The return value from this function is a sensitive value + * (this is unusual). #MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE shouldn't happen + * in a well-written application, but 0 vs #MBEDTLS_ERR_RSA_INVALID_PADDING + * is often a situation that an attacker can provoke and leaking which + * one is the result is precisely the information the attacker wants. + * + * \param input The input buffer which is the payload inside PKCS#1v1.5 + * encryption padding, called the "encoded message EM" + * by the terminology. + * \param ilen The length of the payload in the \p input buffer. + * \param output The buffer for the payload, called "message M" by the + * PKCS#1 terminology. This must be a writable buffer of + * length \p output_max_len bytes. + * \param olen The address at which to store the length of + * the payload. This must not be \c NULL. + * \param output_max_len The length in bytes of the output buffer \p output. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE + * The output buffer is too small for the unpadded payload. + * \return #MBEDTLS_ERR_RSA_INVALID_PADDING + * The input doesn't contain properly formatted padding. + */ +static int mbedtls_ct_rsaes_pkcs1_v15_unpadding(unsigned char *input, + size_t ilen, + unsigned char *output, + size_t output_max_len, + size_t *olen) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t i, plaintext_max_size; + + /* The following variables take sensitive values: their value must + * not leak into the observable behavior of the function other than + * the designated outputs (output, olen, return value). Otherwise + * this would open the execution of the function to + * side-channel-based variants of the Bleichenbacher padding oracle + * attack. Potential side channels include overall timing, memory + * access patterns (especially visible to an adversary who has access + * to a shared memory cache), and branches (especially visible to + * an adversary who has access to a shared code cache or to a shared + * branch predictor). */ + size_t pad_count = 0; + unsigned bad = 0; + unsigned char pad_done = 0; + size_t plaintext_size = 0; + unsigned output_too_large; + + plaintext_max_size = (output_max_len > ilen - 11) ? ilen - 11 + : output_max_len; + + /* Check and get padding length in constant time and constant + * memory trace. The first byte must be 0. */ + bad |= input[0]; + + + /* Decode EME-PKCS1-v1_5 padding: 0x00 || 0x02 || PS || 0x00 + * where PS must be at least 8 nonzero bytes. */ + bad |= input[1] ^ MBEDTLS_RSA_CRYPT; + + /* Read the whole buffer. Set pad_done to nonzero if we find + * the 0x00 byte and remember the padding length in pad_count. */ + for (i = 2; i < ilen; i++) { + pad_done |= ((input[i] | (unsigned char) -input[i]) >> 7) ^ 1; + pad_count += ((pad_done | (unsigned char) -pad_done) >> 7) ^ 1; + } + + + /* If pad_done is still zero, there's no data, only unfinished padding. */ + bad |= mbedtls_ct_uint_if(pad_done, 0, 1); + + /* There must be at least 8 bytes of padding. */ + bad |= mbedtls_ct_size_gt(8, pad_count); + + /* If the padding is valid, set plaintext_size to the number of + * remaining bytes after stripping the padding. If the padding + * is invalid, avoid leaking this fact through the size of the + * output: use the maximum message size that fits in the output + * buffer. Do it without branches to avoid leaking the padding + * validity through timing. RSA keys are small enough that all the + * size_t values involved fit in unsigned int. */ + plaintext_size = mbedtls_ct_uint_if( + bad, (unsigned) plaintext_max_size, + (unsigned) (ilen - pad_count - 3)); + + /* Set output_too_large to 0 if the plaintext fits in the output + * buffer and to 1 otherwise. */ + output_too_large = mbedtls_ct_size_gt(plaintext_size, + plaintext_max_size); + + /* Set ret without branches to avoid timing attacks. Return: + * - INVALID_PADDING if the padding is bad (bad != 0). + * - OUTPUT_TOO_LARGE if the padding is good but the decrypted + * plaintext does not fit in the output buffer. + * - 0 if the padding is correct. */ + ret = -(int) mbedtls_ct_uint_if( + bad, -MBEDTLS_ERR_RSA_INVALID_PADDING, + mbedtls_ct_uint_if(output_too_large, + -MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE, + 0)); + + /* If the padding is bad or the plaintext is too large, zero the + * data that we're about to copy to the output buffer. + * We need to copy the same amount of data + * from the same buffer whether the padding is good or not to + * avoid leaking the padding validity through overall timing or + * through memory or cache access patterns. */ + bad = mbedtls_ct_uint_mask(bad | output_too_large); + for (i = 11; i < ilen; i++) { + input[i] &= ~bad; + } + + /* If the plaintext is too large, truncate it to the buffer size. + * Copy anyway to avoid revealing the length through timing, because + * revealing the length is as bad as revealing the padding validity + * for a Bleichenbacher attack. */ + plaintext_size = mbedtls_ct_uint_if(output_too_large, + (unsigned) plaintext_max_size, + (unsigned) plaintext_size); + + /* Move the plaintext to the leftmost position where it can start in + * the working buffer, i.e. make it start plaintext_max_size from + * the end of the buffer. Do this with a memory access trace that + * does not depend on the plaintext size. After this move, the + * starting location of the plaintext is no longer sensitive + * information. */ + mbedtls_ct_mem_move_to_left(input + ilen - plaintext_max_size, + plaintext_max_size, + plaintext_max_size - plaintext_size); + + /* Finally copy the decrypted plaintext plus trailing zeros into the output + * buffer. If output_max_len is 0, then output may be an invalid pointer + * and the result of memcpy() would be undefined; prevent undefined + * behavior making sure to depend only on output_max_len (the size of the + * user-provided output buffer), which is independent from plaintext + * length, validity of padding, success of the decryption, and other + * secrets. */ + if (output_max_len != 0) { + memcpy(output, input + ilen - plaintext_max_size, plaintext_max_size); + } + + /* Report the amount of data we copied to the output buffer. In case + * of errors (bad padding or output too large), the value of *olen + * when this function returns is not specified. Making it equivalent + * to the good case limits the risks of leaking the padding validity. */ + *olen = plaintext_size; + + return ret; +} + +#endif /* MBEDTLS_PKCS1_V15 && MBEDTLS_RSA_C && ! MBEDTLS_RSA_ALT */ + #if !defined(MBEDTLS_RSA_ALT) int mbedtls_rsa_import(mbedtls_rsa_context *ctx, From 7d4f0198103e77b58701232b2141c8f99e07e7a7 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Tue, 9 May 2023 14:01:05 +0100 Subject: [PATCH 06/82] Move some bignum functions out of constant_time module Signed-off-by: Dave Rodgman --- library/bignum.c | 136 +++++++++++++++++++++++ library/bignum_core.c | 40 +++++++ library/bignum_core.h | 18 +++ library/constant_time.c | 185 ------------------------------- library/constant_time_internal.h | 18 --- 5 files changed, 194 insertions(+), 203 deletions(-) diff --git a/library/bignum.c b/library/bignum.c index 36effaf8da..b62f3f2c37 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -54,6 +54,142 @@ #define MPI_VALIDATE(cond) \ MBEDTLS_INTERNAL_VALIDATE(cond) +/* + * Compare signed values in constant time + */ +int mbedtls_mpi_lt_mpi_ct(const mbedtls_mpi *X, + const mbedtls_mpi *Y, + unsigned *ret) +{ + size_t i; + /* The value of any of these variables is either 0 or 1 at all times. */ + unsigned cond, done, X_is_negative, Y_is_negative; + + MPI_VALIDATE_RET(X != NULL); + MPI_VALIDATE_RET(Y != NULL); + MPI_VALIDATE_RET(ret != NULL); + + if (X->n != Y->n) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + /* + * Set sign_N to 1 if N >= 0, 0 if N < 0. + * We know that N->s == 1 if N >= 0 and N->s == -1 if N < 0. + */ + X_is_negative = (X->s & 2) >> 1; + Y_is_negative = (Y->s & 2) >> 1; + + /* + * If the signs are different, then the positive operand is the bigger. + * That is if X is negative (X_is_negative == 1), then X < Y is true and it + * is false if X is positive (X_is_negative == 0). + */ + cond = (X_is_negative ^ Y_is_negative); + *ret = cond & X_is_negative; + + /* + * This is a constant-time function. We might have the result, but we still + * need to go through the loop. Record if we have the result already. + */ + done = cond; + + for (i = X->n; i > 0; i--) { + /* + * If Y->p[i - 1] < X->p[i - 1] then X < Y is true if and only if both + * X and Y are negative. + * + * Again even if we can make a decision, we just mark the result and + * the fact that we are done and continue looping. + */ + cond = mbedtls_ct_mpi_uint_lt(Y->p[i - 1], X->p[i - 1]); + *ret |= cond & (1 - done) & X_is_negative; + done |= cond; + + /* + * If X->p[i - 1] < Y->p[i - 1] then X < Y is true if and only if both + * X and Y are positive. + * + * Again even if we can make a decision, we just mark the result and + * the fact that we are done and continue looping. + */ + cond = mbedtls_ct_mpi_uint_lt(X->p[i - 1], Y->p[i - 1]); + *ret |= cond & (1 - done) & (1 - X_is_negative); + done |= cond; + } + + return 0; +} + +/* + * Conditionally assign X = Y, without leaking information + * about whether the assignment was made or not. + * (Leaking information about the respective sizes of X and Y is ok however.) + */ +#if defined(_MSC_VER) && defined(_M_ARM64) && (_MSC_FULL_VER < 193131103) +/* + * MSVC miscompiles this function if it's inlined prior to Visual Studio 2022 version 17.1. See: + * https://developercommunity.visualstudio.com/t/c-compiler-miscompiles-part-of-mbedtls-library-on/1646989 + */ +__declspec(noinline) +#endif +int mbedtls_mpi_safe_cond_assign(mbedtls_mpi *X, + const mbedtls_mpi *Y, + unsigned char assign) +{ + int ret = 0; + MPI_VALIDATE_RET(X != NULL); + MPI_VALIDATE_RET(Y != NULL); + + /* all-bits 1 if assign is 1, all-bits 0 if assign is 0 */ + mbedtls_mpi_uint limb_mask = mbedtls_ct_mpi_uint_mask(assign); + + MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, Y->n)); + + X->s = (int) mbedtls_ct_uint_if(assign, Y->s, X->s); + + mbedtls_mpi_core_cond_assign(X->p, Y->p, Y->n, assign); + + for (size_t i = Y->n; i < X->n; i++) { + X->p[i] &= ~limb_mask; + } + +cleanup: + return ret; +} + +/* + * Conditionally swap X and Y, without leaking information + * about whether the swap was made or not. + * Here it is not ok to simply swap the pointers, which would lead to + * different memory access patterns when X and Y are used afterwards. + */ +int mbedtls_mpi_safe_cond_swap(mbedtls_mpi *X, + mbedtls_mpi *Y, + unsigned char swap) +{ + int ret = 0; + int s; + MPI_VALIDATE_RET(X != NULL); + MPI_VALIDATE_RET(Y != NULL); + + if (X == Y) { + return 0; + } + + MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, Y->n)); + MBEDTLS_MPI_CHK(mbedtls_mpi_grow(Y, X->n)); + + s = X->s; + X->s = (int) mbedtls_ct_uint_if(swap, Y->s, X->s); + Y->s = (int) mbedtls_ct_uint_if(swap, s, Y->s); + + mbedtls_mpi_core_cond_swap(X->p, Y->p, X->n, swap); + +cleanup: + return ret; +} + /* Implementation that should never be optimized out by the compiler */ static void mbedtls_mpi_zeroize(mbedtls_mpi_uint *v, size_t n) { diff --git a/library/bignum_core.c b/library/bignum_core.c index de57cfc04c..a51b3f404e 100644 --- a/library/bignum_core.c +++ b/library/bignum_core.c @@ -168,6 +168,46 @@ unsigned mbedtls_mpi_core_uint_le_mpi(mbedtls_mpi_uint min, return min_le_lsl | msll_nonzero; } +unsigned mbedtls_mpi_core_lt_ct(const mbedtls_mpi_uint *A, + const mbedtls_mpi_uint *B, + size_t limbs) +{ + unsigned ret, cond, done; + + /* The value of any of these variables is either 0 or 1 for the rest of + * their scope. */ + ret = cond = done = 0; + + for (size_t i = limbs; i > 0; i--) { + /* + * If B[i - 1] < A[i - 1] then A < B is false and the result must + * remain 0. + * + * Again even if we can make a decision, we just mark the result and + * the fact that we are done and continue looping. + */ + cond = mbedtls_ct_mpi_uint_lt(B[i - 1], A[i - 1]); + done |= cond; + + /* + * If A[i - 1] < B[i - 1] then A < B is true. + * + * Again even if we can make a decision, we just mark the result and + * the fact that we are done and continue looping. + */ + cond = mbedtls_ct_mpi_uint_lt(A[i - 1], B[i - 1]); + ret |= cond & (1 - done); + done |= cond; + } + + /* + * If all the limbs were equal, then the numbers are equal, A < B is false + * and leaving the result 0 is correct. + */ + + return ret; +} + void mbedtls_mpi_core_cond_assign(mbedtls_mpi_uint *X, const mbedtls_mpi_uint *A, size_t limbs, diff --git a/library/bignum_core.h b/library/bignum_core.h index 21a5a11c6a..1fc5375755 100644 --- a/library/bignum_core.h +++ b/library/bignum_core.h @@ -148,6 +148,24 @@ unsigned mbedtls_mpi_core_uint_le_mpi(mbedtls_mpi_uint min, const mbedtls_mpi_uint *A, size_t A_limbs); +/** + * \brief Check if one unsigned MPI is less than another in constant + * time. + * + * \param A The left-hand MPI. This must point to an array of limbs + * with the same allocated length as \p B. + * \param B The right-hand MPI. This must point to an array of limbs + * with the same allocated length as \p A. + * \param limbs The number of limbs in \p A and \p B. + * This must not be 0. + * + * \return The result of the comparison: + * \c 1 if \p A is less than \p B. + * \c 0 if \p A is greater than or equal to \p B. + */ +unsigned mbedtls_mpi_core_lt_ct(const mbedtls_mpi_uint *A, + const mbedtls_mpi_uint *B, + size_t limbs); /** * \brief Perform a safe conditional copy of an MPI which doesn't reveal * whether assignment was done or not. diff --git a/library/constant_time.c b/library/constant_time.c index 16d7a1fc41..135a6ece3f 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -405,188 +405,3 @@ void mbedtls_ct_memcpy_offset(unsigned char *dest, #endif /* MBEDTLS_SSL_SOME_SUITES_USE_MAC */ -#if defined(MBEDTLS_BIGNUM_C) - -#define MPI_VALIDATE_RET(cond) \ - MBEDTLS_INTERNAL_VALIDATE_RET(cond, MBEDTLS_ERR_MPI_BAD_INPUT_DATA) - -/* - * Conditionally assign X = Y, without leaking information - * about whether the assignment was made or not. - * (Leaking information about the respective sizes of X and Y is ok however.) - */ -#if defined(_MSC_VER) && defined(_M_ARM64) && (_MSC_FULL_VER < 193131103) -/* - * MSVC miscompiles this function if it's inlined prior to Visual Studio 2022 version 17.1. See: - * https://developercommunity.visualstudio.com/t/c-compiler-miscompiles-part-of-mbedtls-library-on/1646989 - */ -__declspec(noinline) -#endif -int mbedtls_mpi_safe_cond_assign(mbedtls_mpi *X, - const mbedtls_mpi *Y, - unsigned char assign) -{ - int ret = 0; - MPI_VALIDATE_RET(X != NULL); - MPI_VALIDATE_RET(Y != NULL); - - /* all-bits 1 if assign is 1, all-bits 0 if assign is 0 */ - mbedtls_mpi_uint limb_mask = mbedtls_ct_mpi_uint_mask(assign); - - MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, Y->n)); - - X->s = (int) mbedtls_ct_uint_if(assign, Y->s, X->s); - - mbedtls_mpi_core_cond_assign(X->p, Y->p, Y->n, assign); - - for (size_t i = Y->n; i < X->n; i++) { - X->p[i] &= ~limb_mask; - } - -cleanup: - return ret; -} - -/* - * Conditionally swap X and Y, without leaking information - * about whether the swap was made or not. - * Here it is not ok to simply swap the pointers, which would lead to - * different memory access patterns when X and Y are used afterwards. - */ -int mbedtls_mpi_safe_cond_swap(mbedtls_mpi *X, - mbedtls_mpi *Y, - unsigned char swap) -{ - int ret = 0; - int s; - MPI_VALIDATE_RET(X != NULL); - MPI_VALIDATE_RET(Y != NULL); - - if (X == Y) { - return 0; - } - - MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, Y->n)); - MBEDTLS_MPI_CHK(mbedtls_mpi_grow(Y, X->n)); - - s = X->s; - X->s = (int) mbedtls_ct_uint_if(swap, Y->s, X->s); - Y->s = (int) mbedtls_ct_uint_if(swap, s, Y->s); - - mbedtls_mpi_core_cond_swap(X->p, Y->p, X->n, swap); - -cleanup: - return ret; -} - -/* - * Compare unsigned values in constant time - */ -unsigned mbedtls_mpi_core_lt_ct(const mbedtls_mpi_uint *A, - const mbedtls_mpi_uint *B, - size_t limbs) -{ - unsigned ret, cond, done; - - /* The value of any of these variables is either 0 or 1 for the rest of - * their scope. */ - ret = cond = done = 0; - - for (size_t i = limbs; i > 0; i--) { - /* - * If B[i - 1] < A[i - 1] then A < B is false and the result must - * remain 0. - * - * Again even if we can make a decision, we just mark the result and - * the fact that we are done and continue looping. - */ - cond = mbedtls_ct_mpi_uint_lt(B[i - 1], A[i - 1]); - done |= cond; - - /* - * If A[i - 1] < B[i - 1] then A < B is true. - * - * Again even if we can make a decision, we just mark the result and - * the fact that we are done and continue looping. - */ - cond = mbedtls_ct_mpi_uint_lt(A[i - 1], B[i - 1]); - ret |= cond & (1 - done); - done |= cond; - } - - /* - * If all the limbs were equal, then the numbers are equal, A < B is false - * and leaving the result 0 is correct. - */ - - return ret; -} - -/* - * Compare signed values in constant time - */ -int mbedtls_mpi_lt_mpi_ct(const mbedtls_mpi *X, - const mbedtls_mpi *Y, - unsigned *ret) -{ - size_t i; - /* The value of any of these variables is either 0 or 1 at all times. */ - unsigned cond, done, X_is_negative, Y_is_negative; - - MPI_VALIDATE_RET(X != NULL); - MPI_VALIDATE_RET(Y != NULL); - MPI_VALIDATE_RET(ret != NULL); - - if (X->n != Y->n) { - return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; - } - - /* - * Set sign_N to 1 if N >= 0, 0 if N < 0. - * We know that N->s == 1 if N >= 0 and N->s == -1 if N < 0. - */ - X_is_negative = (X->s & 2) >> 1; - Y_is_negative = (Y->s & 2) >> 1; - - /* - * If the signs are different, then the positive operand is the bigger. - * That is if X is negative (X_is_negative == 1), then X < Y is true and it - * is false if X is positive (X_is_negative == 0). - */ - cond = (X_is_negative ^ Y_is_negative); - *ret = cond & X_is_negative; - - /* - * This is a constant-time function. We might have the result, but we still - * need to go through the loop. Record if we have the result already. - */ - done = cond; - - for (i = X->n; i > 0; i--) { - /* - * If Y->p[i - 1] < X->p[i - 1] then X < Y is true if and only if both - * X and Y are negative. - * - * Again even if we can make a decision, we just mark the result and - * the fact that we are done and continue looping. - */ - cond = mbedtls_ct_mpi_uint_lt(Y->p[i - 1], X->p[i - 1]); - *ret |= cond & (1 - done) & X_is_negative; - done |= cond; - - /* - * If X->p[i - 1] < Y->p[i - 1] then X < Y is true if and only if both - * X and Y are positive. - * - * Again even if we can make a decision, we just mark the result and - * the fact that we are done and continue looping. - */ - cond = mbedtls_ct_mpi_uint_lt(X->p[i - 1], Y->p[i - 1]); - *ret |= cond & (1 - done) & (1 - X_is_negative); - done |= cond; - } - - return 0; -} - -#endif /* MBEDTLS_BIGNUM_C */ diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h index bfeb8c55ec..e085478d69 100644 --- a/library/constant_time_internal.h +++ b/library/constant_time_internal.h @@ -129,24 +129,6 @@ unsigned mbedtls_ct_size_bool_eq(size_t x, unsigned mbedtls_ct_mpi_uint_lt(const mbedtls_mpi_uint x, const mbedtls_mpi_uint y); -/** - * \brief Check if one unsigned MPI is less than another in constant - * time. - * - * \param A The left-hand MPI. This must point to an array of limbs - * with the same allocated length as \p B. - * \param B The right-hand MPI. This must point to an array of limbs - * with the same allocated length as \p A. - * \param limbs The number of limbs in \p A and \p B. - * This must not be 0. - * - * \return The result of the comparison: - * \c 1 if \p A is less than \p B. - * \c 0 if \p A is greater than or equal to \p B. - */ -unsigned mbedtls_mpi_core_lt_ct(const mbedtls_mpi_uint *A, - const mbedtls_mpi_uint *B, - size_t limbs); #endif /* MBEDTLS_BIGNUM_C */ /** Choose between two integer values without branches. From 14bec1490f8bfdc6d7b4a6776d5604bb332c26bf Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Thu, 11 May 2023 16:19:27 +0100 Subject: [PATCH 07/82] tests Signed-off-by: Dave Rodgman --- tests/suites/test_suite_base64.function | 5 +- tests/suites/test_suite_bignum.function | 2 +- tests/suites/test_suite_bignum_core.function | 34 +- .../suites/test_suite_bignum_random.function | 8 +- tests/suites/test_suite_constant_time.data | 511 ++++++++++++++++-- .../suites/test_suite_constant_time.function | 256 ++++++++- .../test_suite_constant_time_hmac.function | 2 +- 7 files changed, 732 insertions(+), 86 deletions(-) diff --git a/tests/suites/test_suite_base64.function b/tests/suites/test_suite_base64.function index ce6bd42b7e..d9ac82cd05 100644 --- a/tests/suites/test_suite_base64.function +++ b/tests/suites/test_suite_base64.function @@ -1,7 +1,6 @@ /* BEGIN_HEADER */ #include "mbedtls/base64.h" #include "constant_time_internal.h" -#include "constant_time_invasive.h" #include #if defined(MBEDTLS_TEST_HOOKS) @@ -16,7 +15,7 @@ static const char base64_digits[] = * END_DEPENDENCIES */ -/* BEGIN_CASE depends_on:MBEDTLS_TEST_HOOKS */ +/* BEGIN_CASE */ void mask_of_range(int low_arg, int high_arg) { unsigned char low = low_arg, high = high_arg; @@ -24,7 +23,7 @@ void mask_of_range(int low_arg, int high_arg) for (c = 0; c <= 0xff; c++) { mbedtls_test_set_step(c); TEST_CF_SECRET(&c, sizeof(c)); - unsigned char m = mbedtls_ct_uchar_mask_of_range(low, high, c); + unsigned char m = mbedtls_ct_uchar_in_range_if(low, high, c, 0xff); TEST_CF_PUBLIC(&c, sizeof(c)); TEST_CF_PUBLIC(&m, sizeof(m)); if (low <= c && c <= high) { diff --git a/tests/suites/test_suite_bignum.function b/tests/suites/test_suite_bignum.function index 7f858e5543..caa7e0467e 100644 --- a/tests/suites/test_suite_bignum.function +++ b/tests/suites/test_suite_bignum.function @@ -438,7 +438,7 @@ void mpi_lt_mpi_ct(int size_X, char *input_X, TEST_ASSERT(mbedtls_mpi_lt_mpi_ct(&X, &Y, &ret) == input_err); if (input_err == 0) { - TEST_ASSERT(ret == input_uret); + TEST_EQUAL(ret, input_uret); } exit: diff --git a/tests/suites/test_suite_bignum_core.function b/tests/suites/test_suite_bignum_core.function index 81a3a45317..7ac03d0009 100644 --- a/tests/suites/test_suite_bignum_core.function +++ b/tests/suites/test_suite_bignum_core.function @@ -358,7 +358,7 @@ void mpi_core_lt_ct(char *input_X, char *input_Y, int exp_ret) TEST_CF_SECRET(Y, X_limbs * sizeof(mbedtls_mpi_uint)); ret = mbedtls_mpi_core_lt_ct(X, Y, X_limbs); - TEST_EQUAL(ret, exp_ret); + TEST_EQUAL(!!ret, exp_ret); exit: mbedtls_free(X); @@ -384,25 +384,25 @@ void mpi_core_uint_le_mpi(char *input_A) TEST_CF_SECRET(A, A_limbs * sizeof(*A)); - TEST_EQUAL(mbedtls_mpi_core_uint_le_mpi(0, A, A_limbs), 1); - TEST_EQUAL(mbedtls_mpi_core_uint_le_mpi(A[0], A, A_limbs), 1); + TEST_EQUAL(!!mbedtls_mpi_core_uint_le_mpi(0, A, A_limbs), 1); + TEST_EQUAL(!!mbedtls_mpi_core_uint_le_mpi(A[0], A, A_limbs), 1); if (is_large) { - TEST_EQUAL(mbedtls_mpi_core_uint_le_mpi(A[0] + 1, - A, A_limbs), 1); - TEST_EQUAL(mbedtls_mpi_core_uint_le_mpi((mbedtls_mpi_uint) (-1) >> 1, - A, A_limbs), 1); - TEST_EQUAL(mbedtls_mpi_core_uint_le_mpi((mbedtls_mpi_uint) (-1), - A, A_limbs), 1); + TEST_EQUAL(!!mbedtls_mpi_core_uint_le_mpi(A[0] + 1, + A, A_limbs), 1); + TEST_EQUAL(!!mbedtls_mpi_core_uint_le_mpi((mbedtls_mpi_uint) (-1) >> 1, + A, A_limbs), 1); + TEST_EQUAL(!!mbedtls_mpi_core_uint_le_mpi((mbedtls_mpi_uint) (-1), + A, A_limbs), 1); } else { - TEST_EQUAL(mbedtls_mpi_core_uint_le_mpi(A[0] + 1, - A, A_limbs), + TEST_EQUAL(!!mbedtls_mpi_core_uint_le_mpi(A[0] + 1, + A, A_limbs), A[0] + 1 <= A[0]); - TEST_EQUAL(mbedtls_mpi_core_uint_le_mpi((mbedtls_mpi_uint) (-1) >> 1, - A, A_limbs), + TEST_EQUAL(!!mbedtls_mpi_core_uint_le_mpi((mbedtls_mpi_uint) (-1) >> 1, + A, A_limbs), (mbedtls_mpi_uint) (-1) >> 1 <= A[0]); - TEST_EQUAL(mbedtls_mpi_core_uint_le_mpi((mbedtls_mpi_uint) (-1), - A, A_limbs), + TEST_EQUAL(!!mbedtls_mpi_core_uint_le_mpi((mbedtls_mpi_uint) (-1), + A, A_limbs), (mbedtls_mpi_uint) (-1) <= A[0]); } @@ -447,7 +447,7 @@ void mpi_core_cond_assign(char *input_X, TEST_CF_SECRET(X, bytes); TEST_CF_SECRET(Y, bytes); - mbedtls_mpi_core_cond_assign(X, Y, copy_limbs, 1); + mbedtls_mpi_core_cond_assign(X, Y, copy_limbs, mbedtls_ct_bool(1)); TEST_CF_PUBLIC(X, bytes); TEST_CF_PUBLIC(Y, bytes); @@ -515,7 +515,7 @@ void mpi_core_cond_swap(char *input_X, TEST_CF_SECRET(X, bytes); TEST_CF_SECRET(Y, bytes); - mbedtls_mpi_core_cond_swap(X, Y, copy_limbs, 1); + mbedtls_mpi_core_cond_swap(X, Y, copy_limbs, mbedtls_ct_bool(1)); TEST_CF_PUBLIC(X, bytes); TEST_CF_PUBLIC(Y, bytes); diff --git a/tests/suites/test_suite_bignum_random.function b/tests/suites/test_suite_bignum_random.function index e4db3d7acc..51ff4d8f79 100644 --- a/tests/suites/test_suite_bignum_random.function +++ b/tests/suites/test_suite_bignum_random.function @@ -134,7 +134,7 @@ void mpi_core_random_basic(int min, char *bound_bytes, int expected_ret) if (expected_ret == 0) { TEST_EQUAL(0, mbedtls_mpi_core_lt_ct(result, lower_bound, limbs)); - TEST_EQUAL(1, mbedtls_mpi_core_lt_ct(result, upper_bound, limbs)); + TEST_ASSERT(0 != mbedtls_mpi_core_lt_ct(result, upper_bound, limbs)); } exit: @@ -429,8 +429,7 @@ void mpi_mod_random_validation(int min, char *bound_hex, * size as the modulus, otherwise it's a mistake in the test data. */ TEST_EQUAL(result_limbs, N.limbs); /* Sanity check: check that the result is in range */ - TEST_EQUAL(mbedtls_mpi_core_lt_ct(result_digits, N.p, N.limbs), - 1); + TEST_ASSERT(0 != mbedtls_mpi_core_lt_ct(result_digits, N.p, N.limbs)); /* Check result >= min (changes result) */ TEST_EQUAL(mbedtls_mpi_core_sub_int(result_digits, result_digits, min, result_limbs), @@ -444,8 +443,7 @@ void mpi_mod_random_validation(int min, char *bound_hex, mbedtls_test_rnd_std_rand, NULL), expected_ret); if (expected_ret == 0) { - TEST_EQUAL(mbedtls_mpi_core_lt_ct(result_digits, N.p, N.limbs), - 1); + TEST_ASSERT(0 != mbedtls_mpi_core_lt_ct(result_digits, N.p, N.limbs)); TEST_EQUAL(mbedtls_mpi_core_sub_int(result_digits, result.p, min, result_limbs), 0); diff --git a/tests/suites/test_suite_constant_time.data b/tests/suites/test_suite_constant_time.data index 91a25faccb..f692176cda 100644 --- a/tests/suites/test_suite_constant_time.data +++ b/tests/suites/test_suite_constant_time.data @@ -1,14 +1,14 @@ # these are the numbers we'd get with an empty plaintext and truncated HMAC Constant-flow memcpy from offset: small -ssl_cf_memcpy_offset:0:5:10 +mbedtls_ct_memcpy_offset:0:5:10 # we could get this with 255-bytes plaintext and untruncated SHA-256 Constant-flow memcpy from offset: medium -ssl_cf_memcpy_offset:0:255:32 +mbedtls_ct_memcpy_offset:0:255:32 # we could get this with 255-bytes plaintext and untruncated SHA-384 Constant-flow memcpy from offset: large -ssl_cf_memcpy_offset:100:339:48 +mbedtls_ct_memcpy_offset:100:339:48 mbedtls_ct_memcmp NULL mbedtls_ct_memcmp_null @@ -91,47 +91,492 @@ mbedtls_ct_memcmp:-1:17:2 mbedtls_ct_memcmp len 17 offset 3 mbedtls_ct_memcmp:-1:17:3 -mbedtls_ct_memcpy_if_eq len 1 offset 0 -mbedtls_ct_memcpy_if_eq:1:1:0 +mbedtls_ct_memcpy_if len 1 offset 0 +mbedtls_ct_memcpy_if:1:1:0 -mbedtls_ct_memcpy_if_eq len 1 offset 1 -mbedtls_ct_memcpy_if_eq:1:1:1 +mbedtls_ct_memcpy_if len 1 offset 1 +mbedtls_ct_memcpy_if:1:1:1 -mbedtls_ct_memcpy_if_eq len 4 offset 0 -mbedtls_ct_memcpy_if_eq:1:1:0 +mbedtls_ct_memcpy_if len 4 offset 0 +mbedtls_ct_memcpy_if:1:1:0 -mbedtls_ct_memcpy_if_eq len 4 offset 1 -mbedtls_ct_memcpy_if_eq:1:1:1 +mbedtls_ct_memcpy_if len 4 offset 1 +mbedtls_ct_memcpy_if:1:1:1 -mbedtls_ct_memcpy_if_eq len 4 offset 2 -mbedtls_ct_memcpy_if_eq:1:1:2 +mbedtls_ct_memcpy_if len 4 offset 2 +mbedtls_ct_memcpy_if:1:1:2 -mbedtls_ct_memcpy_if_eq len 4 offset 3 -mbedtls_ct_memcpy_if_eq:1:1:3 +mbedtls_ct_memcpy_if len 4 offset 3 +mbedtls_ct_memcpy_if:1:1:3 -mbedtls_ct_memcpy_if_eq len 15 offset 0 -mbedtls_ct_memcpy_if_eq:1:15:0 +mbedtls_ct_memcpy_if len 15 offset 0 +mbedtls_ct_memcpy_if:1:15:0 -mbedtls_ct_memcpy_if_eq len 15 offset 1 -mbedtls_ct_memcpy_if_eq:1:15:1 +mbedtls_ct_memcpy_if len 15 offset 1 +mbedtls_ct_memcpy_if:1:15:1 -mbedtls_ct_memcpy_if_eq len 16 offset 0 -mbedtls_ct_memcpy_if_eq:1:16:0 +mbedtls_ct_memcpy_if len 16 offset 0 +mbedtls_ct_memcpy_if:1:16:0 -mbedtls_ct_memcpy_if_eq len 16 offset 1 -mbedtls_ct_memcpy_if_eq:1:16:1 +mbedtls_ct_memcpy_if len 16 offset 1 +mbedtls_ct_memcpy_if:1:16:1 -mbedtls_ct_memcpy_if_eq len 17 offset 0 -mbedtls_ct_memcpy_if_eq:1:17:0 +mbedtls_ct_memcpy_if len 17 offset 0 +mbedtls_ct_memcpy_if:1:17:0 -mbedtls_ct_memcpy_if_eq len 17 offset 1 -mbedtls_ct_memcpy_if_eq:1:17:1 +mbedtls_ct_memcpy_if len 17 offset 1 +mbedtls_ct_memcpy_if:1:17:1 -mbedtls_ct_memcpy_if_eq len 0 not eq -mbedtls_ct_memcpy_if_eq:0:17:0 +mbedtls_ct_memcpy_if len 0 not eq +mbedtls_ct_memcpy_if:0:17:0 -mbedtls_ct_memcpy_if_eq len 5 offset 1 not eq -mbedtls_ct_memcpy_if_eq:0:5:1 +mbedtls_ct_memcpy_if len 5 offset 1 not eq +mbedtls_ct_memcpy_if:0:5:1 + +mbedtls_ct_memcpy_if len 17 offset 3 not eq +mbedtls_ct_memcpy_if:0:17:3 + +mbedtls_ct_bool 0 +mbedtls_ct_bool:"0x0" + +mbedtls_ct_bool 1 +mbedtls_ct_bool:"0x1" + +mbedtls_ct_bool 4 +mbedtls_ct_bool:"0x4" + +mbedtls_ct_bool 0xfffffff +mbedtls_ct_bool:"0xfffffff" + +mbedtls_ct_bool 0x7fffffff +mbedtls_ct_bool:"0x7fffffff" + +mbedtls_ct_bool 0xfffffffe +mbedtls_ct_bool:"0xfffffffe" + +mbedtls_ct_bool 0xffffffff +mbedtls_ct_bool:"0xffffffff" + +mbedtls_ct_bool 0x0fffffffffffffff +mbedtls_ct_bool:"0x0fffffffffffffff" + +mbedtls_ct_bool 0x7fffffffffffffff +mbedtls_ct_bool:"0x7fffffffffffffff" + +mbedtls_ct_bool 0xffffffffffffffff +mbedtls_ct_bool:"0xffffffffffffffff" + +mbedtls_ct_bool_xxx 0x0 0x0 +mbedtls_ct_bool_xxx:"0x0":"0x0" + +mbedtls_ct_bool_xxx 0x0 0x1 +mbedtls_ct_bool_xxx:"0x0":"0x1" + +mbedtls_ct_bool_xxx 0x0 0x7fffffff +mbedtls_ct_bool_xxx:"0x0":"0x7fffffff" + +mbedtls_ct_bool_xxx 0x0 0xffffffff +mbedtls_ct_bool_xxx:"0x0":"0xffffffff" + +mbedtls_ct_bool_xxx 0x0 0x7fffffffffffffff +mbedtls_ct_bool_xxx:"0x0":"0x7fffffffffffffff" + +mbedtls_ct_bool_xxx 0x0 0xffffffffffffffff +mbedtls_ct_bool_xxx:"0x0":"0xffffffffffffffff" + +mbedtls_ct_bool_xxx 0x1 0x0 +mbedtls_ct_bool_xxx:"0x1":"0x0" + +mbedtls_ct_bool_xxx 0x1 0x1 +mbedtls_ct_bool_xxx:"0x1":"0x1" + +mbedtls_ct_bool_xxx 0x1 0x7fffffff +mbedtls_ct_bool_xxx:"0x1":"0x7fffffff" + +mbedtls_ct_bool_xxx 0x1 0xffffffff +mbedtls_ct_bool_xxx:"0x1":"0xffffffff" + +mbedtls_ct_bool_xxx 0x1 0x7fffffffffffffff +mbedtls_ct_bool_xxx:"0x1":"0x7fffffffffffffff" + +mbedtls_ct_bool_xxx 0x1 0xffffffffffffffff +mbedtls_ct_bool_xxx:"0x1":"0xffffffffffffffff" + +mbedtls_ct_bool_xxx 0x7fffffff 0x0 +mbedtls_ct_bool_xxx:"0x7fffffff":"0x0" + +mbedtls_ct_bool_xxx 0x7fffffff 0x1 +mbedtls_ct_bool_xxx:"0x7fffffff":"0x1" + +mbedtls_ct_bool_xxx 0x7fffffff 0x7fffffff +mbedtls_ct_bool_xxx:"0x7fffffff":"0x7fffffff" + +mbedtls_ct_bool_xxx 0x7fffffff 0xffffffff +mbedtls_ct_bool_xxx:"0x7fffffff":"0xffffffff" + +mbedtls_ct_bool_xxx 0x7fffffff 0x7fffffffffffffff +mbedtls_ct_bool_xxx:"0x7fffffff":"0x7fffffffffffffff" + +mbedtls_ct_bool_xxx 0x7fffffff 0xffffffffffffffff +mbedtls_ct_bool_xxx:"0x7fffffff":"0xffffffffffffffff" + +mbedtls_ct_bool_xxx 0xffffffff 0x0 +mbedtls_ct_bool_xxx:"0xffffffff":"0x0" + +mbedtls_ct_bool_xxx 0xffffffff 0x1 +mbedtls_ct_bool_xxx:"0xffffffff":"0x1" + +mbedtls_ct_bool_xxx 0xffffffff 0x7fffffff +mbedtls_ct_bool_xxx:"0xffffffff":"0x7fffffff" + +mbedtls_ct_bool_xxx 0xffffffff 0xffffffff +mbedtls_ct_bool_xxx:"0xffffffff":"0xffffffff" + +mbedtls_ct_bool_xxx 0xffffffff 0x7fffffffffffffff +mbedtls_ct_bool_xxx:"0xffffffff":"0x7fffffffffffffff" + +mbedtls_ct_bool_xxx 0xffffffff 0xffffffffffffffff +mbedtls_ct_bool_xxx:"0xffffffff":"0xffffffffffffffff" + +mbedtls_ct_bool_xxx 0x7fffffffffffffff 0x0 +mbedtls_ct_bool_xxx:"0x7fffffffffffffff":"0x0" + +mbedtls_ct_bool_xxx 0x7fffffffffffffff 0x1 +mbedtls_ct_bool_xxx:"0x7fffffffffffffff":"0x1" + +mbedtls_ct_bool_xxx 0x7fffffffffffffff 0x7fffffff +mbedtls_ct_bool_xxx:"0x7fffffffffffffff":"0x7fffffff" + +mbedtls_ct_bool_xxx 0x7fffffffffffffff 0xffffffff +mbedtls_ct_bool_xxx:"0x7fffffffffffffff":"0xffffffff" + +mbedtls_ct_bool_xxx 0x7fffffffffffffff 0x7fffffffffffffff +mbedtls_ct_bool_xxx:"0x7fffffffffffffff":"0x7fffffffffffffff" + +mbedtls_ct_bool_xxx 0x7fffffffffffffff 0xffffffffffffffff +mbedtls_ct_bool_xxx:"0x7fffffffffffffff":"0xffffffffffffffff" + +mbedtls_ct_bool_xxx 0xffffffffffffffff 0x0 +mbedtls_ct_bool_xxx:"0xffffffffffffffff":"0x0" + +mbedtls_ct_bool_xxx 0xffffffffffffffff 0x1 +mbedtls_ct_bool_xxx:"0xffffffffffffffff":"0x1" + +mbedtls_ct_bool_xxx 0xffffffffffffffff 0x7fffffff +mbedtls_ct_bool_xxx:"0xffffffffffffffff":"0x7fffffff" + +mbedtls_ct_bool_xxx 0xffffffffffffffff 0xffffffff +mbedtls_ct_bool_xxx:"0xffffffffffffffff":"0xffffffff" + +mbedtls_ct_bool_xxx 0xffffffffffffffff 0x7fffffffffffffff +mbedtls_ct_bool_xxx:"0xffffffffffffffff":"0x7fffffffffffffff" + +mbedtls_ct_bool_xxx 0xffffffffffffffff 0xffffffffffffffff +mbedtls_ct_bool_xxx:"0xffffffffffffffff":"0xffffffffffffffff" + +mbedtls_ct_bool_xxx 138 256 +mbedtls_ct_bool_xxx:"138":"256" + +mbedtls_ct_bool_xxx 256 138 +mbedtls_ct_bool_xxx:"256":"138" + +mbedtls_ct_bool_xxx 6 6 +mbedtls_ct_bool_xxx:"0x6":"0x6" + +mbedtls_ct_uchar_in_range_if 0 0 0 0 +mbedtls_ct_uchar_in_range_if:0:0:0:0 + +mbedtls_ct_uchar_in_range_if 0 100 2 2 +mbedtls_ct_uchar_in_range_if:0:100:2:2 + +mbedtls_ct_uchar_in_range_if 0 100 2 0 +mbedtls_ct_uchar_in_range_if:0:100:2:0 + +mbedtls_ct_uchar_in_range_if 0 100 200 2 +mbedtls_ct_uchar_in_range_if:0:100:200:2 + +mbedtls_ct_uchar_in_range_if 0 255 0 2 +mbedtls_ct_uchar_in_range_if:0:255:0:2 + +mbedtls_ct_uchar_in_range_if 0 255 100 2 +mbedtls_ct_uchar_in_range_if:0:255:100:2 + +mbedtls_ct_uchar_in_range_if 0 255 255 2 +mbedtls_ct_uchar_in_range_if:0:255:255:2 + +mbedtls_ct_uchar_in_range_if 255 255 255 255 +mbedtls_ct_uchar_in_range_if:255:255:255:255 + +mbedtls_ct_if 0x0 0x0 0x0 +mbedtls_ct_if:"0x0":"0x0":"0x0" + +mbedtls_ct_if 0x0 0x0 0x1 +mbedtls_ct_if:"0x0":"0x0":"0x1" + +mbedtls_ct_if 0x0 0x0 0x7fffffff +mbedtls_ct_if:"0x0":"0x0":"0x7fffffff" + +mbedtls_ct_if 0x0 0x0 0xffffffff +mbedtls_ct_if:"0x0":"0x0":"0xffffffff" + +mbedtls_ct_if 0x0 0x0 0x7fffffffffffffff +mbedtls_ct_if:"0x0":"0x0":"0x7fffffffffffffff" + +mbedtls_ct_if 0x0 0x0 0xffffffffffffffff +mbedtls_ct_if:"0x0":"0x0":"0xffffffffffffffff" + +mbedtls_ct_if 0x0 0x1 0x0 +mbedtls_ct_if:"0x0":"0x1":"0x0" + +mbedtls_ct_if 0x0 0x1 0x1 +mbedtls_ct_if:"0x0":"0x1":"0x1" + +mbedtls_ct_if 0x0 0x1 0x7fffffff +mbedtls_ct_if:"0x0":"0x1":"0x7fffffff" + +mbedtls_ct_if 0x0 0x1 0xffffffff +mbedtls_ct_if:"0x0":"0x1":"0xffffffff" + +mbedtls_ct_if 0x0 0x1 0x7fffffffffffffff +mbedtls_ct_if:"0x0":"0x1":"0x7fffffffffffffff" + +mbedtls_ct_if 0x0 0x1 0xffffffffffffffff +mbedtls_ct_if:"0x0":"0x1":"0xffffffffffffffff" + +mbedtls_ct_if 0x0 0x7fffffff 0x0 +mbedtls_ct_if:"0x0":"0x7fffffff":"0x0" + +mbedtls_ct_if 0x0 0x7fffffff 0x1 +mbedtls_ct_if:"0x0":"0x7fffffff":"0x1" + +mbedtls_ct_if 0x0 0x7fffffff 0x7fffffff +mbedtls_ct_if:"0x0":"0x7fffffff":"0x7fffffff" + +mbedtls_ct_if 0x0 0x7fffffff 0xffffffff +mbedtls_ct_if:"0x0":"0x7fffffff":"0xffffffff" + +mbedtls_ct_if 0x0 0x7fffffff 0x7fffffffffffffff +mbedtls_ct_if:"0x0":"0x7fffffff":"0x7fffffffffffffff" + +mbedtls_ct_if 0x0 0x7fffffff 0xffffffffffffffff +mbedtls_ct_if:"0x0":"0x7fffffff":"0xffffffffffffffff" + +mbedtls_ct_if 0x0 0xffffffff 0x0 +mbedtls_ct_if:"0x0":"0xffffffff":"0x0" + +mbedtls_ct_if 0x0 0xffffffff 0x1 +mbedtls_ct_if:"0x0":"0xffffffff":"0x1" + +mbedtls_ct_if 0x0 0xffffffff 0x7fffffff +mbedtls_ct_if:"0x0":"0xffffffff":"0x7fffffff" + +mbedtls_ct_if 0x0 0xffffffff 0xffffffff +mbedtls_ct_if:"0x0":"0xffffffff":"0xffffffff" + +mbedtls_ct_if 0x0 0xffffffff 0x7fffffffffffffff +mbedtls_ct_if:"0x0":"0xffffffff":"0x7fffffffffffffff" + +mbedtls_ct_if 0x0 0xffffffff 0xffffffffffffffff +mbedtls_ct_if:"0x0":"0xffffffff":"0xffffffffffffffff" + +mbedtls_ct_if 0x0 0x7fffffffffffffff 0x0 +mbedtls_ct_if:"0x0":"0x7fffffffffffffff":"0x0" + +mbedtls_ct_if 0x0 0x7fffffffffffffff 0x1 +mbedtls_ct_if:"0x0":"0x7fffffffffffffff":"0x1" + +mbedtls_ct_if 0x0 0x7fffffffffffffff 0x7fffffff +mbedtls_ct_if:"0x0":"0x7fffffffffffffff":"0x7fffffff" + +mbedtls_ct_if 0x0 0x7fffffffffffffff 0xffffffff +mbedtls_ct_if:"0x0":"0x7fffffffffffffff":"0xffffffff" + +mbedtls_ct_if 0x0 0x7fffffffffffffff 0x7fffffffffffffff +mbedtls_ct_if:"0x0":"0x7fffffffffffffff":"0x7fffffffffffffff" + +mbedtls_ct_if 0x0 0x7fffffffffffffff 0xffffffffffffffff +mbedtls_ct_if:"0x0":"0x7fffffffffffffff":"0xffffffffffffffff" + +mbedtls_ct_if 0x0 0xffffffffffffffff 0x0 +mbedtls_ct_if:"0x0":"0xffffffffffffffff":"0x0" + +mbedtls_ct_if 0x0 0xffffffffffffffff 0x1 +mbedtls_ct_if:"0x0":"0xffffffffffffffff":"0x1" + +mbedtls_ct_if 0x0 0xffffffffffffffff 0x7fffffff +mbedtls_ct_if:"0x0":"0xffffffffffffffff":"0x7fffffff" + +mbedtls_ct_if 0x0 0xffffffffffffffff 0xffffffff +mbedtls_ct_if:"0x0":"0xffffffffffffffff":"0xffffffff" + +mbedtls_ct_if 0x0 0xffffffffffffffff 0x7fffffffffffffff +mbedtls_ct_if:"0x0":"0xffffffffffffffff":"0x7fffffffffffffff" + +mbedtls_ct_if 0x0 0xffffffffffffffff 0xffffffffffffffff +mbedtls_ct_if:"0x0":"0xffffffffffffffff":"0xffffffffffffffff" + +mbedtls_ct_if 0xffffffffffffffff 0x0 0x0 +mbedtls_ct_if:"0xffffffffffffffff":"0x0":"0x0" + +mbedtls_ct_if 0xffffffffffffffff 0x0 0x1 +mbedtls_ct_if:"0xffffffffffffffff":"0x0":"0x1" + +mbedtls_ct_if 0xffffffffffffffff 0x0 0x7fffffff +mbedtls_ct_if:"0xffffffffffffffff":"0x0":"0x7fffffff" + +mbedtls_ct_if 0xffffffffffffffff 0x0 0xffffffff +mbedtls_ct_if:"0xffffffffffffffff":"0x0":"0xffffffff" + +mbedtls_ct_if 0xffffffffffffffff 0x0 0x7fffffffffffffff +mbedtls_ct_if:"0xffffffffffffffff":"0x0":"0x7fffffffffffffff" + +mbedtls_ct_if 0xffffffffffffffff 0x0 0xffffffffffffffff +mbedtls_ct_if:"0xffffffffffffffff":"0x0":"0xffffffffffffffff" + +mbedtls_ct_if 0xffffffffffffffff 0x1 0x0 +mbedtls_ct_if:"0xffffffffffffffff":"0x1":"0x0" + +mbedtls_ct_if 0xffffffffffffffff 0x1 0x1 +mbedtls_ct_if:"0xffffffffffffffff":"0x1":"0x1" + +mbedtls_ct_if 0xffffffffffffffff 0x1 0x7fffffff +mbedtls_ct_if:"0xffffffffffffffff":"0x1":"0x7fffffff" + +mbedtls_ct_if 0xffffffffffffffff 0x1 0xffffffff +mbedtls_ct_if:"0xffffffffffffffff":"0x1":"0xffffffff" + +mbedtls_ct_if 0xffffffffffffffff 0x1 0x7fffffffffffffff +mbedtls_ct_if:"0xffffffffffffffff":"0x1":"0x7fffffffffffffff" + +mbedtls_ct_if 0xffffffffffffffff 0x1 0xffffffffffffffff +mbedtls_ct_if:"0xffffffffffffffff":"0x1":"0xffffffffffffffff" + +mbedtls_ct_if 0xffffffffffffffff 0x7fffffff 0x0 +mbedtls_ct_if:"0xffffffffffffffff":"0x7fffffff":"0x0" + +mbedtls_ct_if 0xffffffffffffffff 0x7fffffff 0x1 +mbedtls_ct_if:"0xffffffffffffffff":"0x7fffffff":"0x1" + +mbedtls_ct_if 0xffffffffffffffff 0x7fffffff 0x7fffffff +mbedtls_ct_if:"0xffffffffffffffff":"0x7fffffff":"0x7fffffff" + +mbedtls_ct_if 0xffffffffffffffff 0x7fffffff 0xffffffff +mbedtls_ct_if:"0xffffffffffffffff":"0x7fffffff":"0xffffffff" + +mbedtls_ct_if 0xffffffffffffffff 0x7fffffff 0x7fffffffffffffff +mbedtls_ct_if:"0xffffffffffffffff":"0x7fffffff":"0x7fffffffffffffff" + +mbedtls_ct_if 0xffffffffffffffff 0x7fffffff 0xffffffffffffffff +mbedtls_ct_if:"0xffffffffffffffff":"0x7fffffff":"0xffffffffffffffff" + +mbedtls_ct_if 0xffffffffffffffff 0xffffffff 0x0 +mbedtls_ct_if:"0xffffffffffffffff":"0xffffffff":"0x0" + +mbedtls_ct_if 0xffffffffffffffff 0xffffffff 0x1 +mbedtls_ct_if:"0xffffffffffffffff":"0xffffffff":"0x1" + +mbedtls_ct_if 0xffffffffffffffff 0xffffffff 0x7fffffff +mbedtls_ct_if:"0xffffffffffffffff":"0xffffffff":"0x7fffffff" + +mbedtls_ct_if 0xffffffffffffffff 0xffffffff 0xffffffff +mbedtls_ct_if:"0xffffffffffffffff":"0xffffffff":"0xffffffff" + +mbedtls_ct_if 0xffffffffffffffff 0xffffffff 0x7fffffffffffffff +mbedtls_ct_if:"0xffffffffffffffff":"0xffffffff":"0x7fffffffffffffff" + +mbedtls_ct_if 0xffffffffffffffff 0xffffffff 0xffffffffffffffff +mbedtls_ct_if:"0xffffffffffffffff":"0xffffffff":"0xffffffffffffffff" + +mbedtls_ct_if 0xffffffffffffffff 0x7fffffffffffffff 0x0 +mbedtls_ct_if:"0xffffffffffffffff":"0x7fffffffffffffff":"0x0" + +mbedtls_ct_if 0xffffffffffffffff 0x7fffffffffffffff 0x1 +mbedtls_ct_if:"0xffffffffffffffff":"0x7fffffffffffffff":"0x1" + +mbedtls_ct_if 0xffffffffffffffff 0x7fffffffffffffff 0x7fffffff +mbedtls_ct_if:"0xffffffffffffffff":"0x7fffffffffffffff":"0x7fffffff" + +mbedtls_ct_if 0xffffffffffffffff 0x7fffffffffffffff 0xffffffff +mbedtls_ct_if:"0xffffffffffffffff":"0x7fffffffffffffff":"0xffffffff" + +mbedtls_ct_if 0xffffffffffffffff 0x7fffffffffffffff 0x7fffffffffffffff +mbedtls_ct_if:"0xffffffffffffffff":"0x7fffffffffffffff":"0x7fffffffffffffff" + +mbedtls_ct_if 0xffffffffffffffff 0x7fffffffffffffff 0xffffffffffffffff +mbedtls_ct_if:"0xffffffffffffffff":"0x7fffffffffffffff":"0xffffffffffffffff" + +mbedtls_ct_if 0xffffffffffffffff 0xffffffffffffffff 0x0 +mbedtls_ct_if:"0xffffffffffffffff":"0xffffffffffffffff":"0x0" + +mbedtls_ct_if 0xffffffffffffffff 0xffffffffffffffff 0x1 +mbedtls_ct_if:"0xffffffffffffffff":"0xffffffffffffffff":"0x1" + +mbedtls_ct_if 0xffffffffffffffff 0xffffffffffffffff 0x7fffffff +mbedtls_ct_if:"0xffffffffffffffff":"0xffffffffffffffff":"0x7fffffff" + +mbedtls_ct_if 0xffffffffffffffff 0xffffffffffffffff 0xffffffff +mbedtls_ct_if:"0xffffffffffffffff":"0xffffffffffffffff":"0xffffffff" + +mbedtls_ct_if 0xffffffffffffffff 0xffffffffffffffff 0x7fffffffffffffff +mbedtls_ct_if:"0xffffffffffffffff":"0xffffffffffffffff":"0x7fffffffffffffff" + +mbedtls_ct_if 0xffffffffffffffff 0xffffffffffffffff 0xffffffffffffffff +mbedtls_ct_if:"0xffffffffffffffff":"0xffffffffffffffff":"0xffffffffffffffff" + +mbedtls_ct_zeroize_if 0x0 0 +mbedtls_ct_zeroize_if:"0x0":0 + +mbedtls_ct_zeroize_if 0x0 1 +mbedtls_ct_zeroize_if:"0x0":1 + +mbedtls_ct_zeroize_if 0x0 1024 +mbedtls_ct_zeroize_if:"0x0":1024 + +mbedtls_ct_zeroize_if 0xffffffffffffffff 0 +mbedtls_ct_zeroize_if:"0xffffffffffffffff":0 + +mbedtls_ct_zeroize_if 0xffffffffffffffff 1 +mbedtls_ct_zeroize_if:"0xffffffffffffffff":1 + +mbedtls_ct_zeroize_if 0xffffffffffffffff 4 +mbedtls_ct_zeroize_if:"0xffffffffffffffff":4 + +mbedtls_ct_zeroize_if 0xffffffffffffffff 5 +mbedtls_ct_zeroize_if:"0xffffffffffffffff":5 + +mbedtls_ct_zeroize_if 0xffffffffffffffff 7 +mbedtls_ct_zeroize_if:"0xffffffffffffffff":7 + +mbedtls_ct_zeroize_if 0xffffffffffffffff 8 +mbedtls_ct_zeroize_if:"0xffffffffffffffff":8 + +mbedtls_ct_zeroize_if 0xffffffffffffffff 9 +mbedtls_ct_zeroize_if:"0xffffffffffffffff":9 + +mbedtls_ct_zeroize_if 0xffffffffffffffff 1024 +mbedtls_ct_zeroize_if:"0xffffffffffffffff":1024 + +mbedtls_ct_memmove_left 0 0 +mbedtls_ct_memmove_left:0:0 + +mbedtls_ct_memmove_left 1 0 +mbedtls_ct_memmove_left:1:0 + +mbedtls_ct_memmove_left 1 1 +mbedtls_ct_memmove_left:1:1 + +mbedtls_ct_memmove_left 16 0 +mbedtls_ct_memmove_left:16:0 + +mbedtls_ct_memmove_left 16 1 +mbedtls_ct_memmove_left:16:1 + +mbedtls_ct_memmove_left 16 4 +mbedtls_ct_memmove_left:16:4 + +mbedtls_ct_memmove_left 16 15 +mbedtls_ct_memmove_left:16:15 + +mbedtls_ct_memmove_left 16 16 +mbedtls_ct_memmove_left:16:16 -mbedtls_ct_memcpy_if_eq len 17 offset 3 not eq -mbedtls_ct_memcpy_if_eq:0:17:3 diff --git a/tests/suites/test_suite_constant_time.function b/tests/suites/test_suite_constant_time.function index a2bf3967f5..c9bdf7e344 100644 --- a/tests/suites/test_suite_constant_time.function +++ b/tests/suites/test_suite_constant_time.function @@ -8,9 +8,15 @@ * under MSan or Valgrind will detect a non-constant-time implementation. */ +#include + +#include +#include +#include + +#include #include #include -#include #include /* END_HEADER */ @@ -25,6 +31,143 @@ void mbedtls_ct_memcmp_null() } /* END_CASE */ +/* BEGIN_CASE */ +void mbedtls_ct_bool(char *input) +{ + mbedtls_ct_uint_t v = (mbedtls_ct_uint_t) strtoull(input, NULL, 16); + TEST_ASSERT(errno == 0); + + mbedtls_ct_condition_t expected = (v != 0) ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE; + TEST_CF_SECRET(&v, sizeof(v)); + TEST_EQUAL(mbedtls_ct_bool(v), expected); + TEST_CF_PUBLIC(&v, sizeof(v)); +} +/* END_CASE */ + +/* BEGIN_CASE */ +void mbedtls_ct_bool_xxx(char *x_str, char *y_str) +{ + mbedtls_ct_uint_t x = strtoull(x_str, NULL, 0); + mbedtls_ct_uint_t y = strtoull(y_str, NULL, 0); + + mbedtls_ct_uint_t x1 = x; + mbedtls_ct_uint_t y1 = y; + + TEST_CF_SECRET(&x, sizeof(x)); + TEST_CF_SECRET(&y, sizeof(y)); + + mbedtls_ct_condition_t expected = x1 ? MBEDTLS_CT_FALSE : MBEDTLS_CT_TRUE; + TEST_EQUAL(mbedtls_ct_bool_not(mbedtls_ct_bool(x)), expected); + + expected = x1 != y1 ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE; + TEST_EQUAL(mbedtls_ct_bool_ne(x, y), expected); + + expected = x1 == y1 ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE; + TEST_EQUAL(mbedtls_ct_bool_eq(x, y), expected); + + expected = x1 > y1 ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE; + TEST_EQUAL(mbedtls_ct_bool_gt(x, y), expected); + + expected = x1 < y1 ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE; + TEST_EQUAL(mbedtls_ct_bool_lt(x, y), expected); + + expected = x1 >= y1 ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE; + TEST_EQUAL(mbedtls_ct_bool_ge(x, y), expected); + + expected = x1 <= y1 ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE; + TEST_EQUAL(mbedtls_ct_bool_le(x, y), expected); + + expected = mbedtls_ct_bool(x) ^ mbedtls_ct_bool(y) ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE; + TEST_EQUAL(mbedtls_ct_bool_xor(mbedtls_ct_bool(x), mbedtls_ct_bool(y)), expected); + + expected = mbedtls_ct_bool(x) & mbedtls_ct_bool(y) ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE; + TEST_EQUAL(mbedtls_ct_bool_and(mbedtls_ct_bool(x), mbedtls_ct_bool(y)), expected); + + expected = mbedtls_ct_bool(x) | mbedtls_ct_bool(y) ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE; + TEST_EQUAL(mbedtls_ct_bool_or(mbedtls_ct_bool(x), mbedtls_ct_bool(y)), expected); + + TEST_CF_PUBLIC(&x, sizeof(x)); + TEST_CF_PUBLIC(&y, sizeof(y)); +} +/* END_CASE */ + +/* BEGIN_CASE depends_on:MBEDTLS_BASE64_C */ +void mbedtls_ct_uchar_in_range_if(int li, int hi, int xi, int ti) +{ + unsigned char l = li, h = hi, x = xi, t = ti; + unsigned char expected = (x >= l) && (x <= h) ? t : 0; + + TEST_CF_SECRET(&x, sizeof(x)); + TEST_CF_SECRET(&l, sizeof(l)); + TEST_CF_SECRET(&h, sizeof(h)); + TEST_CF_SECRET(&t, sizeof(t)); + + TEST_EQUAL(mbedtls_ct_uchar_in_range_if(l, h, x, t), expected); + + TEST_CF_PUBLIC(&x, sizeof(x)); + TEST_CF_PUBLIC(&l, sizeof(l)); + TEST_CF_PUBLIC(&h, sizeof(h)); + TEST_CF_PUBLIC(&t, sizeof(t)); +} +/* END_CASE */ + +/* BEGIN_CASE */ +void mbedtls_ct_if(char *c_str, char *t_str, char *f_str) +{ + mbedtls_ct_condition_t c = mbedtls_ct_bool(strtoull(c_str, NULL, 16)); + mbedtls_ct_uint_t t = (mbedtls_ct_uint_t) strtoull(t_str, NULL, 16); + mbedtls_ct_uint_t f = (mbedtls_ct_uint_t) strtoull(f_str, NULL, 16); + + mbedtls_ct_uint_t expected = c ? t : f; + mbedtls_ct_uint_t expected0 = c ? t : 0; + + TEST_CF_SECRET(&c, sizeof(c)); + TEST_CF_SECRET(&t, sizeof(t)); + TEST_CF_SECRET(&f, sizeof(f)); + + TEST_EQUAL(mbedtls_ct_if(c, t, f), expected); + TEST_EQUAL(mbedtls_ct_size_if(c, t, f), (size_t) expected); + TEST_EQUAL(mbedtls_ct_uint_if(c, t, f), (unsigned) expected); +#if defined(MBEDTLS_BIGNUM_C) + TEST_EQUAL(mbedtls_ct_mpi_uint_if(c, t, f), (mbedtls_mpi_uint) expected); +#endif + + TEST_EQUAL(mbedtls_ct_uint_if0(c, t), (unsigned) expected0); +#if defined(MBEDTLS_BIGNUM_C) + TEST_EQUAL(mbedtls_ct_mpi_uint_if0(c, t), (mbedtls_mpi_uint) expected0); +#endif + + TEST_CF_PUBLIC(&c, sizeof(c)); + TEST_CF_PUBLIC(&t, sizeof(t)); + TEST_CF_PUBLIC(&f, sizeof(f)); +} +/* END_CASE */ + +/* BEGIN_CASE depends_on:MBEDTLS_PKCS1_V15:MBEDTLS_RSA_C:!MBEDTLS_RSA_ALT */ +void mbedtls_ct_zeroize_if(char *c_str, int len) +{ + uint8_t *buf = NULL; + mbedtls_ct_condition_t c = mbedtls_ct_bool(strtoull(c_str, NULL, 16)); + + ASSERT_ALLOC(buf, len); + for (size_t i = 0; i < (size_t) len; i++) { + buf[i] = 1; + } + + TEST_CF_SECRET(&c, sizeof(c)); + TEST_CF_SECRET(buf, len); + mbedtls_ct_zeroize_if(c, buf, len); + TEST_CF_PUBLIC(&c, sizeof(c)); + TEST_CF_PUBLIC(buf, len); + + for (size_t i = 0; i < (size_t) len; i++) { + TEST_EQUAL(buf[i], c != 0 ? 0 : 1); + } +exit: + mbedtls_free(buf); +} +/* END_CASE */ + /* BEGIN_CASE */ void mbedtls_ct_memcmp(int same, int size, int offset) { @@ -32,9 +175,6 @@ void mbedtls_ct_memcmp(int same, int size, int offset) ASSERT_ALLOC(a, size + offset); ASSERT_ALLOC(b, size + offset); - TEST_CF_SECRET(a + offset, size); - TEST_CF_SECRET(b + offset, size); - /* Construct data that matches, if same == -1, otherwise * same gives the number of bytes (after the initial offset) * that will match; after that it will differ. @@ -49,9 +189,15 @@ void mbedtls_ct_memcmp(int same, int size, int offset) } int reference = memcmp(a + offset, b + offset, size); + + TEST_CF_SECRET(a, size + offset); + TEST_CF_SECRET(b, size + offset); + int actual = mbedtls_ct_memcmp(a + offset, b + offset, size); - TEST_CF_PUBLIC(a + offset, size); - TEST_CF_PUBLIC(b + offset, size); + + TEST_CF_PUBLIC(a, size + offset); + TEST_CF_PUBLIC(b, size + offset); + TEST_CF_PUBLIC(&actual, sizeof(actual)); if (same == -1 || same >= size) { TEST_ASSERT(reference == 0); @@ -66,30 +212,31 @@ exit: } /* END_CASE */ -/* BEGIN_CASE depends_on:MBEDTLS_SSL_SOME_SUITES_USE_MAC */ -void mbedtls_ct_memcpy_if_eq(int eq, int size, int offset) +/* BEGIN_CASE */ +void mbedtls_ct_memcpy_if(int eq, int size, int offset) { - uint8_t *src = NULL, *result = NULL, *expected = NULL; + uint8_t *src = NULL, *src2 = NULL, *result = NULL, *expected = NULL; ASSERT_ALLOC(src, size + offset); + ASSERT_ALLOC(src2, size + offset); ASSERT_ALLOC(result, size + offset); ASSERT_ALLOC(expected, size + offset); for (int i = 0; i < size + offset; i++) { - src[i] = 1; - result[i] = 0xff; + src[i] = 1; + result[i] = 0xff; expected[i] = eq ? 1 : 0xff; } - int one, secret_eq; - TEST_CF_SECRET(&one, sizeof(one)); - TEST_CF_SECRET(&secret_eq, sizeof(secret_eq)); - one = 1; - secret_eq = eq; + int secret_eq = eq; + TEST_CF_SECRET(&secret_eq, sizeof(secret_eq)); + TEST_CF_SECRET(src, size + offset); + TEST_CF_SECRET(result, size + offset); - mbedtls_ct_memcpy_if_eq(result + offset, src, size, secret_eq, one); + mbedtls_ct_memcpy_if(mbedtls_ct_bool(secret_eq), result + offset, src, NULL, size); - TEST_CF_PUBLIC(&one, sizeof(one)); TEST_CF_PUBLIC(&secret_eq, sizeof(secret_eq)); + TEST_CF_PUBLIC(src, size + offset); + TEST_CF_PUBLIC(result, size + offset); ASSERT_COMPARE(expected, size, result + offset, size); @@ -99,26 +246,80 @@ void mbedtls_ct_memcpy_if_eq(int eq, int size, int offset) expected[i] = eq ? 1 : 0xff; } - TEST_CF_SECRET(&one, sizeof(one)); - TEST_CF_SECRET(&secret_eq, sizeof(secret_eq)); - one = 1; - secret_eq = eq; + TEST_CF_SECRET(&secret_eq, sizeof(secret_eq)); + TEST_CF_SECRET(src, size + offset); + TEST_CF_SECRET(result, size + offset); - mbedtls_ct_memcpy_if_eq(result, src + offset, size, secret_eq, one); + mbedtls_ct_memcpy_if(mbedtls_ct_bool(secret_eq), result, src + offset, NULL, size); - TEST_CF_PUBLIC(&one, sizeof(one)); TEST_CF_PUBLIC(&secret_eq, sizeof(secret_eq)); + TEST_CF_PUBLIC(src, size + offset); + TEST_CF_PUBLIC(result, size + offset); + + ASSERT_COMPARE(expected, size, result, size); + + for (int i = 0; i < size + offset; i++) { + src[i] = 1; + src2[i] = 2; + result[i] = 0xff; + expected[i] = eq ? 1 : 2; + } + + TEST_CF_SECRET(&secret_eq, sizeof(secret_eq)); + TEST_CF_SECRET(src, size + offset); + TEST_CF_SECRET(src2, size + offset); + TEST_CF_SECRET(result, size + offset); + + mbedtls_ct_memcpy_if(mbedtls_ct_bool(secret_eq), result, src + offset, src2 + offset, size); + + TEST_CF_PUBLIC(&secret_eq, sizeof(secret_eq)); + TEST_CF_PUBLIC(src, size + offset); + TEST_CF_SECRET(src2, size + offset); + TEST_CF_PUBLIC(result, size + offset); ASSERT_COMPARE(expected, size, result, size); exit: mbedtls_free(src); + mbedtls_free(src2); mbedtls_free(result); mbedtls_free(expected); } /* END_CASE */ -/* BEGIN_CASE depends_on:MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC:MBEDTLS_TEST_HOOKS */ -void ssl_cf_memcpy_offset(int offset_min, int offset_max, int len) +/* BEGIN_CASE depends_on:MBEDTLS_PKCS1_V15:MBEDTLS_RSA_C:!MBEDTLS_RSA_ALT */ +void mbedtls_ct_memmove_left(int len, int offset) +{ + size_t l = (size_t) len; + size_t o = (size_t) offset; + + uint8_t *buf = NULL, *buf_expected = NULL; + ASSERT_ALLOC(buf, l); + ASSERT_ALLOC(buf_expected, l); + + for (size_t i = 0; i < l; i++) { + buf[i] = (uint8_t) i; + buf_expected[i] = buf[i]; + } + + TEST_CF_SECRET(&o, sizeof(o)); + TEST_CF_SECRET(buf, l); + mbedtls_ct_memmove_left(buf, l, o); + TEST_CF_PUBLIC(&o, sizeof(o)); + TEST_CF_PUBLIC(buf, l); + + if (l > 0) { + memmove(buf_expected, buf_expected + o, l - o); + memset(buf_expected + (l - o), 0, o); + TEST_ASSERT(memcmp(buf, buf_expected, l) == 0); + } +exit: + mbedtls_free(buf); + mbedtls_free(buf_expected); +} +/* END_CASE */ + +/* BEGIN_CASE depends_on:MBEDTLS_SSL_SOME_SUITES_USE_MAC */ +void mbedtls_ct_memcpy_offset(int offset_min, int offset_max, int len) { unsigned char *dst = NULL; unsigned char *src = NULL; @@ -135,9 +336,12 @@ void ssl_cf_memcpy_offset(int offset_min, int offset_max, int len) mbedtls_test_set_step((int) secret); TEST_CF_SECRET(&secret, sizeof(secret)); + TEST_CF_SECRET(src, len); + TEST_CF_SECRET(dst, len); mbedtls_ct_memcpy_offset(dst, src, secret, offset_min, offset_max, len); TEST_CF_PUBLIC(&secret, sizeof(secret)); + TEST_CF_PUBLIC(src, len); TEST_CF_PUBLIC(dst, len); ASSERT_COMPARE(dst, len, src + secret, len); diff --git a/tests/suites/test_suite_constant_time_hmac.function b/tests/suites/test_suite_constant_time_hmac.function index 985d482ebe..407d69338b 100644 --- a/tests/suites/test_suite_constant_time_hmac.function +++ b/tests/suites/test_suite_constant_time_hmac.function @@ -8,7 +8,7 @@ #include /* END_HEADER */ -/* BEGIN_CASE depends_on:MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC:MBEDTLS_TEST_HOOKS */ +/* BEGIN_CASE depends_on:MBEDTLS_SSL_SOME_SUITES_USE_MAC:MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC:MBEDTLS_TEST_HOOKS */ void ssl_cf_hmac(int hash) { /* From 40a41d046183b2e8361f147d4963e5468a38d791 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Wed, 17 May 2023 11:59:56 +0100 Subject: [PATCH 08/82] Introduce new CT interface (retain old interface) Signed-off-by: Dave Rodgman --- library/constant_time.c | 30 +- library/constant_time_impl.h | 276 ++++++++++++++++++ library/constant_time_internal.h | 475 +++++++++++++++++++++++++++++-- library/constant_time_invasive.h | 51 ---- 4 files changed, 734 insertions(+), 98 deletions(-) create mode 100644 library/constant_time_impl.h delete mode 100644 library/constant_time_invasive.h diff --git a/library/constant_time.c b/library/constant_time.c index 135a6ece3f..cc12c9c7c7 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -22,17 +22,14 @@ * might be translated to branches by some compilers on some platforms. */ +#include + #include "common.h" #include "constant_time_internal.h" #include "mbedtls/constant_time.h" #include "mbedtls/error.h" #include "mbedtls/platform_util.h" -#if defined(MBEDTLS_BIGNUM_C) -#include "mbedtls/bignum.h" -#include "bignum_core.h" -#endif - #if defined(MBEDTLS_SSL_TLS_C) #include "ssl_misc.h" #endif @@ -41,10 +38,6 @@ #include "mbedtls/rsa.h" #endif -#if defined(MBEDTLS_BASE64_C) -#include "constant_time_invasive.h" -#endif - #include #if defined(MBEDTLS_USE_PSA_CRYPTO) #define PSA_TO_MBEDTLS_ERR(status) PSA_TO_MBEDTLS_ERR_LIST(status, \ @@ -62,13 +55,11 @@ * Some of these definitions could be moved into alignment.h but for now they are * only used here. */ -#if defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS) && defined(MBEDTLS_HAVE_ASM) -#if defined(__arm__) || defined(__thumb__) || defined(__thumb2__) || defined(__aarch64__) -#define MBEDTLS_EFFICIENT_UNALIGNED_VOLATILE_ACCESS -#endif -#endif +#if defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS) && \ + (defined(MBEDTLS_CT_ARM_ASM) || defined(MBEDTLS_CT_AARCH64_ASM)) + +#define MBEDTLS_EFFICIENT_UNALIGNED_VOLATILE_ACCESS -#if defined(MBEDTLS_EFFICIENT_UNALIGNED_VOLATILE_ACCESS) static inline uint32_t mbedtls_get_unaligned_volatile_uint32(volatile const unsigned char *p) { /* This is UB, even where it's safe: @@ -76,14 +67,17 @@ static inline uint32_t mbedtls_get_unaligned_volatile_uint32(volatile const unsi * so instead the same thing is expressed in assembly below. */ uint32_t r; -#if defined(__arm__) || defined(__thumb__) || defined(__thumb2__) +#if defined(MBEDTLS_CT_ARM_ASM) asm volatile ("ldr %0, [%1]" : "=r" (r) : "r" (p) :); -#elif defined(__aarch64__) +#elif defined(MBEDTLS_CT_AARCH64_ASM) asm volatile ("ldr %w0, [%1]" : "=r" (r) : "r" (p) :); +#else +#error No assembly defined for mbedtls_get_unaligned_volatile_uint32 #endif return r; } -#endif /* MBEDTLS_EFFICIENT_UNALIGNED_VOLATILE_ACCESS */ +#endif /* defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS) && + (defined(MBEDTLS_CT_ARM_ASM) || defined(MBEDTLS_CT_AARCH64_ASM)) */ int mbedtls_ct_memcmp(const void *a, const void *b, diff --git a/library/constant_time_impl.h b/library/constant_time_impl.h new file mode 100644 index 0000000000..218a4a614f --- /dev/null +++ b/library/constant_time_impl.h @@ -0,0 +1,276 @@ +/** + * Constant-time functions + * + * For readability, the static inline definitions are here, and + * constant_time_internal.h has only the declarations. + * + * This results in duplicate declarations of the form: + * static inline void f() { ... } + * static inline void f(); + * when constant_time_internal.h is included. This appears to behave + * exactly as if the declaration-without-definition was not present. + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MBEDTLS_CONSTANT_TIME_IMPL_H +#define MBEDTLS_CONSTANT_TIME_IMPL_H + +#include + +#include "common.h" + +#if defined(MBEDTLS_BIGNUM_C) +#include "mbedtls/bignum.h" +#endif + + +/* Disable asm under Memsan because it confuses Memsan and generates false errors */ +#if defined(MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN) +#define MBEDTLS_CT_NO_ASM +#elif defined(__has_feature) +#if __has_feature(memory_sanitizer) +#define MBEDTLS_CT_NO_ASM +#endif +#endif + +/* armcc5 --gnu defines __GNUC__ but doesn't support GNU's extended asm */ +#if defined(MBEDTLS_HAVE_ASM) && defined(__GNUC__) && (!defined(__ARMCC_VERSION) || \ + __ARMCC_VERSION >= 6000000) && !defined(MBEDTLS_CT_NO_ASM) +#define MBEDTLS_CT_ASM +#if (defined(__arm__) || defined(__thumb__) || defined(__thumb2__)) +#define MBEDTLS_CT_ARM_ASM +#elif defined(__aarch64__) +#define MBEDTLS_CT_AARCH64_ASM +#endif +#endif + +#define MBEDTLS_CT_SIZE (sizeof(mbedtls_ct_uint_t) * 8) + + +/* ============================================================================ + * Core const-time primitives + */ + +/** Ensure that the compiler cannot know the value of x (i.e., cannot optimise + * based on its value) after this function is called. + * + * If we are not using assembly, this will be fairly inefficient, so its use + * should be minimised. + */ +static inline mbedtls_ct_uint_t mbedtls_ct_compiler_opaque(mbedtls_ct_uint_t x) +{ +#if defined(MBEDTLS_CT_ASM) + asm volatile ("" : [x] "+r" (x) :); + return x; +#else + volatile mbedtls_ct_uint_t result = x; + return result; +#endif +} + +/* Convert a number into a condition in constant time. */ +static inline mbedtls_ct_condition_t mbedtls_ct_bool(mbedtls_ct_uint_t x) +{ + /* + * Define mask-generation code that, as far as possible, will not use branches or conditional instructions. + * + * For some platforms / type sizes, we define assembly to assure this. + * + * Otherwise, we define a plain C fallback which (in May 2023) does not get optimised into + * conditional instructions or branches by trunk clang, gcc, or MSVC v19. + */ + const mbedtls_ct_uint_t xo = mbedtls_ct_compiler_opaque(x); +#if defined(_MSC_VER) + /* MSVC has a warning about unary minus on unsigned, but this is + * well-defined and precisely what we want to do here */ +#pragma warning( push ) +#pragma warning( disable : 4146 ) +#endif + return (mbedtls_ct_condition_t) (((mbedtls_ct_int_t) ((-xo) | -(xo >> 1))) >> + (MBEDTLS_CT_SIZE - 1)); +#if defined(_MSC_VER) +#pragma warning( pop ) +#endif +} + +static inline mbedtls_ct_uint_t mbedtls_ct_if(mbedtls_ct_condition_t condition, + mbedtls_ct_uint_t if1, + mbedtls_ct_uint_t if0) +{ + mbedtls_ct_condition_t not_mask = + (mbedtls_ct_condition_t) (~mbedtls_ct_compiler_opaque(condition)); + mbedtls_ct_condition_t mask = + (mbedtls_ct_condition_t) mbedtls_ct_compiler_opaque(condition); + return (mbedtls_ct_uint_t) ((mask & if1) | (not_mask & if0)); +} + +static inline mbedtls_ct_condition_t mbedtls_ct_bool_lt(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y) +{ + /* Ensure that the compiler cannot optimise the following operations over x and y, + * even if it knows the value of x and y. + */ + const mbedtls_ct_uint_t yo = mbedtls_ct_compiler_opaque(y); + /* + * Check if the most significant bits (MSB) of the operands are different. + * cond is true iff the MSBs differ. + */ + mbedtls_ct_condition_t cond = mbedtls_ct_bool((x ^ yo) >> (MBEDTLS_CT_SIZE - 1)); + + /* + * If the MSB are the same then the difference x-y will be negative (and + * have its MSB set to 1 during conversion to unsigned) if and only if x> (MBEDTLS_CT_SIZE - 1); + + // Convert to a condition (i.e., all bits set iff non-zero) + return mbedtls_ct_bool(ret); +} + +static inline mbedtls_ct_condition_t mbedtls_ct_bool_ne(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y) +{ + /* diff = 0 if x == y, non-zero otherwise */ + const mbedtls_ct_uint_t diff = mbedtls_ct_compiler_opaque(x) ^ y; + + /* all ones if x != y, 0 otherwise */ + return mbedtls_ct_bool(diff); +} + +static inline unsigned char mbedtls_ct_uchar_in_range_if(unsigned char low, + unsigned char high, + unsigned char c, + unsigned char t) +{ + const unsigned char co = (const unsigned char) mbedtls_ct_compiler_opaque(c); + const unsigned char to = (const unsigned char) mbedtls_ct_compiler_opaque(t); + + /* low_mask is: 0 if low <= c, 0x...ff if low > c */ + unsigned low_mask = ((unsigned) co - low) >> 8; + /* high_mask is: 0 if c <= high, 0x...ff if c > high */ + unsigned high_mask = ((unsigned) high - co) >> 8; + + return (unsigned char) (~(low_mask | high_mask)) & to; +} + + +/* ============================================================================ + * Everything below here is trivial wrapper functions + */ + +static inline mbedtls_ct_condition_t mbedtls_ct_bool_eq(mbedtls_ct_uint_t x, + mbedtls_ct_uint_t y) +{ + return ~mbedtls_ct_bool_ne(x, y); +} + +static inline size_t mbedtls_ct_size_if(mbedtls_ct_condition_t condition, + size_t if1, + size_t if0) +{ + return (size_t) mbedtls_ct_if(condition, (mbedtls_ct_uint_t) if1, (mbedtls_ct_uint_t) if0); +} + +static inline unsigned mbedtls_ct_uint_if_new(mbedtls_ct_condition_t condition, + unsigned if1, + unsigned if0) +{ + return (unsigned) mbedtls_ct_if(condition, (mbedtls_ct_uint_t) if1, (mbedtls_ct_uint_t) if0); +} + +#if defined(MBEDTLS_BIGNUM_C) + +static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if(mbedtls_ct_condition_t condition, \ + mbedtls_mpi_uint if1, \ + mbedtls_mpi_uint if0) +{ + return (mbedtls_mpi_uint) mbedtls_ct_if(condition, + (mbedtls_ct_uint_t) if1, + (mbedtls_ct_uint_t) if0); +} + +#endif + +static inline size_t mbedtls_ct_size_if0(mbedtls_ct_condition_t condition, size_t if1) +{ + return (size_t) (mbedtls_ct_compiler_opaque(condition) & if1); +} + +static inline unsigned mbedtls_ct_uint_if0(mbedtls_ct_condition_t condition, unsigned if1) +{ + return (unsigned) (mbedtls_ct_compiler_opaque(condition) & if1); +} + +#if defined(MBEDTLS_BIGNUM_C) + +static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if0(mbedtls_ct_condition_t condition, + mbedtls_mpi_uint if1) +{ + return (mbedtls_mpi_uint) (mbedtls_ct_compiler_opaque(condition) & if1); +} + +#endif /* MBEDTLS_BIGNUM_C */ + +static inline mbedtls_ct_condition_t mbedtls_ct_bool_gt(mbedtls_ct_uint_t x, + mbedtls_ct_uint_t y) +{ + return mbedtls_ct_bool_lt(y, x); +} + +static inline mbedtls_ct_condition_t mbedtls_ct_bool_ge(mbedtls_ct_uint_t x, + mbedtls_ct_uint_t y) +{ + return ~mbedtls_ct_bool_lt(x, y); +} + +static inline mbedtls_ct_condition_t mbedtls_ct_bool_le(mbedtls_ct_uint_t x, + mbedtls_ct_uint_t y) +{ + return ~mbedtls_ct_bool_gt(x, y); +} + +static inline mbedtls_ct_condition_t mbedtls_ct_bool_xor(mbedtls_ct_condition_t x, + mbedtls_ct_condition_t y) +{ + return (mbedtls_ct_condition_t) (mbedtls_ct_compiler_opaque(x) ^ mbedtls_ct_compiler_opaque(y)); +} + +static inline mbedtls_ct_condition_t mbedtls_ct_bool_and(mbedtls_ct_condition_t x, + mbedtls_ct_condition_t y) +{ + return (mbedtls_ct_condition_t) (mbedtls_ct_compiler_opaque(x) & mbedtls_ct_compiler_opaque(y)); +} + +static inline mbedtls_ct_condition_t mbedtls_ct_bool_or(mbedtls_ct_condition_t x, + mbedtls_ct_condition_t y) +{ + return (mbedtls_ct_condition_t) (mbedtls_ct_compiler_opaque(x) | mbedtls_ct_compiler_opaque(y)); +} + +static inline mbedtls_ct_condition_t mbedtls_ct_bool_not(mbedtls_ct_condition_t x) +{ + return (mbedtls_ct_condition_t) (~mbedtls_ct_compiler_opaque(x)); +} + +#endif /* MBEDTLS_CONSTANT_TIME_IMPL_H */ diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h index e085478d69..d1e3755d20 100644 --- a/library/constant_time_internal.h +++ b/library/constant_time_internal.h @@ -20,6 +20,9 @@ #ifndef MBEDTLS_CONSTANT_TIME_INTERNAL_H #define MBEDTLS_CONSTANT_TIME_INTERNAL_H +#include +#include + #include "common.h" #if defined(MBEDTLS_BIGNUM_C) @@ -30,8 +33,6 @@ #include "ssl_misc.h" #endif -#include - /** Turn a value into a mask: * - if \p value == 0, return the all-bits 0 mask, aka 0 @@ -220,33 +221,6 @@ void mbedtls_ct_memcpy_offset(unsigned char *dest, #endif /* MBEDTLS_SSL_SOME_SUITES_USE_MAC */ -#if defined(MBEDTLS_BASE64_C) - -/** Constant-flow char selection - * - * \param low Bottom of range - * \param high Top of range - * \param c Value to compare to range - * \param t Value to return, if in range - * - * \return \p t if \p low <= \p c <= \p high, 0 otherwise. - */ -static inline unsigned char mbedtls_ct_uchar_in_range_if(unsigned char low, - unsigned char high, - unsigned char c, - unsigned char t) -{ - /* low_mask is: 0 if low <= c, 0x...ff if low > c */ - unsigned low_mask = ((unsigned) c - low) >> 8; - /* high_mask is: 0 if c <= high, 0x...ff if c > high */ - unsigned high_mask = ((unsigned) high - c) >> 8; - return (unsigned char) - mbedtls_ct_uint_if(~mbedtls_ct_mpi_uint_mask(low_mask | high_mask), t, 0); -} - -#endif /* MBEDTLS_BASE64_C */ - - #if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) /** Constant-flow "greater than" comparison: @@ -284,4 +258,447 @@ void mbedtls_ct_mem_move_to_left(void *start, #endif /* defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) */ + + +/* The constant-time interface provides various operations that are likely + * to result in constant-time code that does not branch or use conditional + * instructions for secret data (for secret pointers, this also applies to + * the data pointed to). + * + * It has three main parts: + * + * - boolean operations (and a few non-boolean operations) + * These are all named mbedtls_ct_bool_, and operate over + * mbedtls_ct_condition_t. + * All arguments to these operations are considered secret. + * example: bool x = y | z => x = mbedtls_ct_bool_or(y, z) + * + * - conditional data selection + * These are all named mbedtls_ct__if and mbedtls_ct__if0 + * All arguments are considered secret. + * example: size_t a = x ? b : c => a = mbedtls_ct_size_if(x, b, c) + * example: unsigned a = x ? b : 0 => a = mbedtls_ct_uint_if0(x, b) + * + * - block memory operations + * Only some arguments are considered secret, as documented for each + * function. + * example: if (x) memcpy(...) => mbedtls_ct_memcpy_if(x, ...) + * + * mbedtls_ct_condition_t should be treated as opaque and only manipulated + * via the functions in this header. + * + * mbedtls_ct_uint_t is an unsigned integer type over which constant time + * operations may be performed via the functions in this header. It is as big + * as the larger of size_t and mbedtls_mpi_uint, i.e. it is safe to cast + * to/from "unsigned int", "size_t", and "mbedtls_mpi_uint" (and any other + * not-larger integer types). + * + * For Arm (32-bit, 64-bit and Thumb), assembly implementations are used + * to ensure that the generated code is constant time. For other architectures, + * a plain C fallback designed to yield constant-time code (this has been + * observed to be constant-time on latest gcc, clang and MSVC as of May 2023). + */ + +#if (SIZE_MAX > 0xffffffffffffffffULL) +/* Pointer size > 64-bit */ +typedef size_t mbedtls_ct_condition_t; +typedef size_t mbedtls_ct_uint_t; +typedef ptrdiff_t mbedtls_ct_int_t; +#define MBEDTLS_CT_TRUE ((mbedtls_ct_condition_t) SIZE_MAX) +#elif (SIZE_MAX > 0xffffffff) || defined(MBEDTLS_HAVE_INT64) +/* 32-bit < pointer size < 64-bit, or 64-bit MPI */ +typedef uint64_t mbedtls_ct_condition_t; +typedef uint64_t mbedtls_ct_uint_t; +typedef int64_t mbedtls_ct_int_t; +#define MBEDTLS_CT_TRUE ((mbedtls_ct_condition_t) UINT64_MAX) +#else +/* Pointer size < 32-bit, and no 64-bit MPIs */ +typedef uint32_t mbedtls_ct_condition_t; +typedef uint32_t mbedtls_ct_uint_t; +typedef int32_t mbedtls_ct_int_t; +#define MBEDTLS_CT_TRUE ((mbedtls_ct_condition_t) UINT32_MAX) +#endif +#define MBEDTLS_CT_FALSE ((mbedtls_ct_condition_t) 0) + +/* constant_time_impl.h contains all the static inline implementations, + * so that constant_time_internal.h is more readable. + */ +#include "constant_time_impl.h" + + +/* ============================================================================ + * Boolean operations + */ + +/** Convert a number into a mbedtls_ct_condition_t. + * + * \param x Number to convert. + * + * \return MBEDTLS_CT_TRUE if \p x != 0, or MBEDTLS_CT_FALSE if \p x == 0 + * + */ +static inline mbedtls_ct_condition_t mbedtls_ct_bool(mbedtls_ct_uint_t x); + +/** Boolean "not equal" operation. + * + * Functionally equivalent to: + * + * \p x != \p y + * + * \param x The first value to analyze. + * \param y The second value to analyze. + * + * \return MBEDTLS_CT_TRUE if \p x != \p y, otherwise MBEDTLS_CT_FALSE. + */ +static inline mbedtls_ct_condition_t mbedtls_ct_bool_ne(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y); + +/** Boolean "equals" operation. + * + * Functionally equivalent to: + * + * \p x == \p y + * + * \param x The first value to analyze. + * \param y The second value to analyze. + * + * \return MBEDTLS_CT_TRUE if \p x == \p y, otherwise MBEDTLS_CT_FALSE. + */ +static inline mbedtls_ct_condition_t mbedtls_ct_bool_eq(mbedtls_ct_uint_t x, + mbedtls_ct_uint_t y); + +/** Boolean "less than" operation. + * + * Functionally equivalent to: + * + * \p x < \p y + * + * \param x The first value to analyze. + * \param y The second value to analyze. + * + * \return MBEDTLS_CT_TRUE if \p x < \p y, otherwise MBEDTLS_CT_FALSE. + */ +static inline mbedtls_ct_condition_t mbedtls_ct_bool_lt(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y); + +/** Boolean "greater than" operation. + * + * Functionally equivalent to: + * + * \p x > \p y + * + * \param x The first value to analyze. + * \param y The second value to analyze. + * + * \return MBEDTLS_CT_TRUE if \p x > \p y, otherwise MBEDTLS_CT_FALSE. + */ +static inline mbedtls_ct_condition_t mbedtls_ct_bool_gt(mbedtls_ct_uint_t x, + mbedtls_ct_uint_t y); + +/** Boolean "greater or equal" operation. + * + * Functionally equivalent to: + * + * \p x >= \p y + * + * \param x The first value to analyze. + * \param y The second value to analyze. + * + * \return MBEDTLS_CT_TRUE if \p x >= \p y, + * otherwise MBEDTLS_CT_FALSE. + */ +static inline mbedtls_ct_condition_t mbedtls_ct_bool_ge(mbedtls_ct_uint_t x, + mbedtls_ct_uint_t y); + +/** Boolean "less than or equal" operation. + * + * Functionally equivalent to: + * + * \p x <= \p y + * + * \param x The first value to analyze. + * \param y The second value to analyze. + * + * \return MBEDTLS_CT_TRUE if \p x <= \p y, + * otherwise MBEDTLS_CT_FALSE. + */ +static inline mbedtls_ct_condition_t mbedtls_ct_bool_le(mbedtls_ct_uint_t x, + mbedtls_ct_uint_t y); + +/** Boolean "xor" operation. + * + * Functionally equivalent to: + * + * \p x ^ \p y + * + * \param x The first value to analyze. + * \param y The second value to analyze. + * + * \note This is more efficient than mbedtls_ct_bool_ne if both arguments are + * mbedtls_ct_condition_t. + * + * \return MBEDTLS_CT_TRUE if \p x ^ \p y, + * otherwise MBEDTLS_CT_FALSE. + */ +static inline mbedtls_ct_condition_t mbedtls_ct_bool_xor(mbedtls_ct_condition_t x, + mbedtls_ct_condition_t y); + +/** Boolean "and" operation. + * + * Functionally equivalent to: + * + * \p x && \p y + * + * \param x The first value to analyze. + * \param y The second value to analyze. + * + * \return MBEDTLS_CT_TRUE if \p x && \p y, + * otherwise MBEDTLS_CT_FALSE. + */ +static inline mbedtls_ct_condition_t mbedtls_ct_bool_and(mbedtls_ct_condition_t x, + mbedtls_ct_condition_t y); + +/** Boolean "or" operation. + * + * Functionally equivalent to: + * + * \p x || \p y + * + * \param x The first value to analyze. + * \param y The second value to analyze. + * + * \return MBEDTLS_CT_TRUE if \p x || \p y, + * otherwise MBEDTLS_CT_FALSE. + */ +static inline mbedtls_ct_condition_t mbedtls_ct_bool_or(mbedtls_ct_condition_t x, + mbedtls_ct_condition_t y); + +/** Boolean "not" operation. + * + * Functionally equivalent to: + * + * ! \p x + * + * \param x The value to invert + * + * \return MBEDTLS_CT_FALSE if \p x, otherwise MBEDTLS_CT_TRUE. + */ +static inline mbedtls_ct_condition_t mbedtls_ct_bool_not(mbedtls_ct_condition_t x); + + +/* ============================================================================ + * Data selection operations + */ + +/** Choose between two size_t values. + * + * Functionally equivalent to: + * + * condition ? if1 : if0. + * + * \param condition Condition to test. + * \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE. + * \param if0 Value to use if \p condition == MBEDTLS_CT_FALSE. + * + * \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise \c if0. + */ +static inline size_t mbedtls_ct_size_if(mbedtls_ct_condition_t condition, + size_t if1, + size_t if0); + +/** Choose between two unsigned values. + * + * Functionally equivalent to: + * + * condition ? if1 : if0. + * + * \param condition Condition to test. + * \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE. + * \param if0 Value to use if \p condition == MBEDTLS_CT_FALSE. + * + * \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise \c if0. + */ +static inline unsigned mbedtls_ct_uint_if_new(mbedtls_ct_condition_t condition, + unsigned if1, + unsigned if0); + +#if defined(MBEDTLS_BIGNUM_C) + +/** Choose between two mbedtls_mpi_uint values. + * + * Functionally equivalent to: + * + * condition ? if1 : if0. + * + * \param condition Condition to test. + * \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE. + * \param if0 Value to use if \p condition == MBEDTLS_CT_FALSE. + * + * \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise \c if0. + */ +static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if(mbedtls_ct_condition_t condition, \ + mbedtls_mpi_uint if1, \ + mbedtls_mpi_uint if0); + +#endif + +/** Choose between an unsigned value and 0. + * + * Functionally equivalent to: + * + * condition ? if1 : 0. + * + * Functionally equivalent tombedtls_ct_uint_if(condition, if1, 0) but + * results in smaller code size. + * + * \param condition Condition to test. + * \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE. + * + * \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise 0. + */ +static inline unsigned mbedtls_ct_uint_if0(mbedtls_ct_condition_t condition, unsigned if1); + +#if defined(MBEDTLS_BIGNUM_C) + +/** Choose between an mbedtls_mpi_uint value and 0. + * + * Functionally equivalent to: + * + * condition ? if1 : 0. + * + * Functionally equivalent tombedtls_ct_mpi_uint_if(condition, if1, 0) but + * results in smaller code size. + * + * \param condition Condition to test. + * \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE. + * + * \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise 0. + */ +static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if0(mbedtls_ct_condition_t condition, + mbedtls_mpi_uint if1); + +#endif + +/** Constant-flow char selection + * + * \param low Secret. Bottom of range + * \param high Secret. Top of range + * \param c Secret. Value to compare to range + * \param t Secret. Value to return, if in range + * + * \return \p t if \p low <= \p c <= \p high, 0 otherwise. + */ +static inline unsigned char mbedtls_ct_uchar_in_range_if(unsigned char low, + unsigned char high, + unsigned char c, + unsigned char t); + + +/* ============================================================================ + * Block memory operations + */ + +#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) + +/** Conditionally set a block of memory to zero. + * + * Regardless of the condition, every byte will be read once and written to + * once. + * + * \param condition Secret. Condition to test. + * \param buf Secret. Pointer to the start of the buffer. + * \param len Number of bytes to set to zero. + * + * \warning Unlike mbedtls_platform_zeroize, this does not have the same guarantees + * about not being optimised away if the memory is never read again. + */ +void mbedtls_ct_zeroize_if(mbedtls_ct_condition_t condition, void *buf, size_t len); + +/** Shift some data towards the left inside a buffer. + * + * Functionally equivalent to: + * + * memmove(start, start + offset, total - offset); + * memset(start + (total - offset), 0, offset); + * + * Timing independence comes at the expense of performance. + * + * \param start Secret. Pointer to the start of the buffer. + * \param total Total size of the buffer. + * \param offset Secret. Offset from which to copy \p total - \p offset bytes. + */ +void mbedtls_ct_memmove_left(void *start, + size_t total, + size_t offset); + +#endif /* defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) */ + +/** Conditional memcpy. + * + * Functionally equivalent to: + * + * if (condition) { + * memcpy(dest, src1, len); + * } else { + * if (src2 != NULL) + * memcpy(dest, src2, len); + * } + * + * It will always read len bytes from src1. + * If src2 != NULL, it will always read len bytes from src2. + * If src2 == NULL, it will instead read len bytes from dest (as if src2 == dest). + * + * \param condition The condition + * \param dest Secret. Destination pointer. + * \param src1 Secret. Pointer to copy from (if \p condition == MBEDTLS_CT_TRUE). Shouldn't overlap with \p dest. + * \param src2 Secret (contents only - may branch to test if src2 == NULL). + * Pointer to copy from (if \p condition == MBEDTLS_CT_FALSE and \p src2 is not NULL). Shouldn't overlap with \p dest. May be NULL. + * \param len Number of bytes to copy. + */ +void mbedtls_ct_memcpy_if(mbedtls_ct_condition_t condition, + unsigned char *dest, + const unsigned char *src1, + const unsigned char *src2, + size_t len + ); + +/** Copy data from a secret position. + * + * Functionally equivalent to: + * + * memcpy(dst, src + offset, len) + * + * This function copies \p len bytes from \p src_base + \p offset to \p + * dst, with a code flow and memory access pattern that does not depend on + * \p offset, but only on \p offset_min, \p offset_max and \p len. + * + * \note This function reads from \p dest, but the value that + * is read does not influence the result and this + * function's behavior is well-defined regardless of the + * contents of the buffers. This may result in false + * positives from static or dynamic analyzers, especially + * if \p dest is not initialized. + * + * \param dest Secret. The destination buffer. This must point to a writable + * buffer of at least \p len bytes. + * \param src Secret. The base of the source buffer. This must point to a + * readable buffer of at least \p offset_max + \p len + * bytes. Shouldn't overlap with \p dest. + * \param offset Secret. The offset in the source buffer from which to copy. + * This must be no less than \p offset_min and no greater + * than \p offset_max. + * \param offset_min The minimal value of \p offset. + * \param offset_max The maximal value of \p offset. + * \param len The number of bytes to copy. + */ +void mbedtls_ct_memcpy_offset(unsigned char *dest, + const unsigned char *src, + size_t offset, + size_t offset_min, + size_t offset_max, + size_t len); + +/* Documented in include/mbedtls/constant_time.h. a and b are secret. */ +int mbedtls_ct_memcmp(const void *a, + const void *b, + size_t n); + #endif /* MBEDTLS_CONSTANT_TIME_INTERNAL_H */ diff --git a/library/constant_time_invasive.h b/library/constant_time_invasive.h deleted file mode 100644 index c176b28ffd..0000000000 --- a/library/constant_time_invasive.h +++ /dev/null @@ -1,51 +0,0 @@ -/** - * \file constant_time_invasive.h - * - * \brief Constant-time module: interfaces for invasive testing only. - * - * The interfaces in this file are intended for testing purposes only. - * They SHOULD NOT be made available in library integrations except when - * building the library for testing. - */ -/* - * Copyright The Mbed TLS Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef MBEDTLS_CONSTANT_TIME_INVASIVE_H -#define MBEDTLS_CONSTANT_TIME_INVASIVE_H - -#include "common.h" - -#if defined(MBEDTLS_TEST_HOOKS) - -/** Turn a value into a mask: - * - if \p low <= \p c <= \p high, - * return the all-bits 1 mask, aka (unsigned) -1 - * - otherwise, return the all-bits 0 mask, aka 0 - * - * \param low The value to analyze. - * \param high The value to analyze. - * \param c The value to analyze. - * - * \return All-bits-one if \p low <= \p c <= \p high, otherwise zero. - */ -unsigned char mbedtls_ct_uchar_mask_of_range(unsigned char low, - unsigned char high, - unsigned char c); - -#endif /* MBEDTLS_TEST_HOOKS */ - -#endif /* MBEDTLS_CONSTANT_TIME_INVASIVE_H */ From 74e18ebf7784746358255c51916699be9004d9c1 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Wed, 17 May 2023 12:21:32 +0100 Subject: [PATCH 09/82] Improve const-timeness of mbedtls_ct_bool_lt Signed-off-by: Dave Rodgman --- library/constant_time_impl.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/constant_time_impl.h b/library/constant_time_impl.h index 218a4a614f..f4ad115b98 100644 --- a/library/constant_time_impl.h +++ b/library/constant_time_impl.h @@ -123,12 +123,13 @@ static inline mbedtls_ct_condition_t mbedtls_ct_bool_lt(mbedtls_ct_uint_t x, mbe /* Ensure that the compiler cannot optimise the following operations over x and y, * even if it knows the value of x and y. */ + const mbedtls_ct_uint_t xo = mbedtls_ct_compiler_opaque(x); const mbedtls_ct_uint_t yo = mbedtls_ct_compiler_opaque(y); /* * Check if the most significant bits (MSB) of the operands are different. * cond is true iff the MSBs differ. */ - mbedtls_ct_condition_t cond = mbedtls_ct_bool((x ^ yo) >> (MBEDTLS_CT_SIZE - 1)); + mbedtls_ct_condition_t cond = mbedtls_ct_bool((xo ^ yo) >> (MBEDTLS_CT_SIZE - 1)); /* * If the MSB are the same then the difference x-y will be negative (and @@ -140,7 +141,7 @@ static inline mbedtls_ct_condition_t mbedtls_ct_bool_lt(mbedtls_ct_uint_t x, mbe */ // Select either y, or x - y - mbedtls_ct_uint_t ret = mbedtls_ct_if(cond, yo, (mbedtls_ct_uint_t) (x - yo)); + mbedtls_ct_uint_t ret = mbedtls_ct_if(cond, yo, (mbedtls_ct_uint_t) (xo - yo)); // Extract only the MSB of ret ret = ret >> (MBEDTLS_CT_SIZE - 1); From 1c4eaa121f3da33ea76d22f059c71d2321d9291e Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Wed, 17 May 2023 12:22:59 +0100 Subject: [PATCH 10/82] Remove not-needed compiler_opaque in ct_if Signed-off-by: Dave Rodgman --- library/constant_time_impl.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/library/constant_time_impl.h b/library/constant_time_impl.h index f4ad115b98..149cf75068 100644 --- a/library/constant_time_impl.h +++ b/library/constant_time_impl.h @@ -111,11 +111,9 @@ static inline mbedtls_ct_uint_t mbedtls_ct_if(mbedtls_ct_condition_t condition, mbedtls_ct_uint_t if1, mbedtls_ct_uint_t if0) { - mbedtls_ct_condition_t not_mask = + mbedtls_ct_condition_t not_cond = (mbedtls_ct_condition_t) (~mbedtls_ct_compiler_opaque(condition)); - mbedtls_ct_condition_t mask = - (mbedtls_ct_condition_t) mbedtls_ct_compiler_opaque(condition); - return (mbedtls_ct_uint_t) ((mask & if1) | (not_mask & if0)); + return (mbedtls_ct_uint_t) ((condition & if1) | (not_cond & if0)); } static inline mbedtls_ct_condition_t mbedtls_ct_bool_lt(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y) From debf8679e035edda7c40aee8b02e0cdd383ec01a Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Wed, 17 May 2023 12:12:44 +0100 Subject: [PATCH 11/82] Add impl of mbedtls_ct_zeroize_if Signed-off-by: Dave Rodgman --- library/constant_time.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/library/constant_time.c b/library/constant_time.c index cc12c9c7c7..af385cd593 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -399,3 +399,22 @@ void mbedtls_ct_memcpy_offset(unsigned char *dest, #endif /* MBEDTLS_SSL_SOME_SUITES_USE_MAC */ +#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) + +void mbedtls_ct_zeroize_if(mbedtls_ct_condition_t condition, void *buf, size_t len) +{ + uint32_t mask = (uint32_t) ~condition; + uint8_t *p = (uint8_t *) buf; + size_t i = 0; +#if defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS) + for (; (i + 4) <= len; i += 4) { + mbedtls_put_unaligned_uint32((void *) (p + i), + mbedtls_get_unaligned_uint32((void *) (p + i)) & mask); + } +#endif + for (; i < len; i++) { + p[i] = p[i] & mask; + } +} + +#endif /* defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) */ From 6cee26db16bffee669dd1d748870045eb4d9321b Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Wed, 17 May 2023 12:16:29 +0100 Subject: [PATCH 12/82] Remove old interface for mem_move_to_left Signed-off-by: Dave Rodgman --- library/constant_time.c | 2 +- library/constant_time_internal.h | 20 -------------------- 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index af385cd593..32c0e5a20f 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -327,7 +327,7 @@ void mbedtls_ct_mpi_uint_cond_assign(size_t n, #if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) -void mbedtls_ct_mem_move_to_left(void *start, +void mbedtls_ct_memmove_left(void *start, size_t total, size_t offset) { diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h index d1e3755d20..5e0d9c45f7 100644 --- a/library/constant_time_internal.h +++ b/library/constant_time_internal.h @@ -236,26 +236,6 @@ void mbedtls_ct_memcpy_offset(unsigned char *dest, */ unsigned mbedtls_ct_size_gt(size_t x, size_t y); -/** Shift some data towards the left inside a buffer. - * - * `mbedtls_ct_mem_move_to_left(start, total, offset)` is functionally - * equivalent to - * ``` - * memmove(start, start + offset, total - offset); - * memset(start + offset, 0, total - offset); - * ``` - * but it strives to use a memory access pattern (and thus total timing) - * that does not depend on \p offset. This timing independence comes at - * the expense of performance. - * - * \param start Pointer to the start of the buffer. - * \param total Total size of the buffer. - * \param offset Offset from which to copy \p total - \p offset bytes. - */ -void mbedtls_ct_mem_move_to_left(void *start, - size_t total, - size_t offset); - #endif /* defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) */ From 15c142b58d5043ff4d2971ab95902f1c8202c35c Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Wed, 17 May 2023 12:20:11 +0100 Subject: [PATCH 13/82] Use new interface in mbedtls_ct_memmove_left Signed-off-by: Dave Rodgman --- library/constant_time.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index 32c0e5a20f..0b44587d52 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -327,26 +327,20 @@ void mbedtls_ct_mpi_uint_cond_assign(size_t n, #if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) -void mbedtls_ct_memmove_left(void *start, - size_t total, - size_t offset) +void mbedtls_ct_memmove_left(void *start, size_t total, size_t offset) { volatile unsigned char *buf = start; - size_t i, n; - if (total == 0) { - return; - } - for (i = 0; i < total; i++) { - unsigned no_op = mbedtls_ct_size_gt(total - offset, i); + for (size_t i = 0; i < total; i++) { + mbedtls_ct_condition_t no_op = mbedtls_ct_bool_gt(total - offset, i); /* The first `total - offset` passes are a no-op. The last * `offset` passes shift the data one byte to the left and * zero out the last byte. */ - for (n = 0; n < total - 1; n++) { + for (size_t n = 0; n < total - 1; n++) { unsigned char current = buf[n]; - unsigned char next = buf[n+1]; - buf[n] = mbedtls_ct_uint_if(no_op, current, next); + unsigned char next = buf[n+1]; + buf[n] = mbedtls_ct_uint_if_new(no_op, current, next); } - buf[total-1] = mbedtls_ct_uint_if(no_op, buf[total-1], 0); + buf[total-1] = mbedtls_ct_uint_if0(no_op, buf[total-1]); } } From 9f9c3b8c33a23ee93030fadfeb0fbedf1ef09f4c Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Wed, 17 May 2023 12:28:51 +0100 Subject: [PATCH 14/82] Use new CT interface in rsa.c Signed-off-by: Dave Rodgman --- library/rsa.c | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/library/rsa.c b/library/rsa.c index e4a45b37c1..9d67ef7d94 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -105,36 +105,37 @@ static int mbedtls_ct_rsaes_pkcs1_v15_unpadding(unsigned char *input, * an adversary who has access to a shared code cache or to a shared * branch predictor). */ size_t pad_count = 0; - unsigned bad = 0; - unsigned char pad_done = 0; + mbedtls_ct_condition_t bad; + mbedtls_ct_condition_t pad_done; size_t plaintext_size = 0; - unsigned output_too_large; + mbedtls_ct_condition_t output_too_large; plaintext_max_size = (output_max_len > ilen - 11) ? ilen - 11 : output_max_len; /* Check and get padding length in constant time and constant * memory trace. The first byte must be 0. */ - bad |= input[0]; + bad = mbedtls_ct_bool(input[0]); /* Decode EME-PKCS1-v1_5 padding: 0x00 || 0x02 || PS || 0x00 * where PS must be at least 8 nonzero bytes. */ - bad |= input[1] ^ MBEDTLS_RSA_CRYPT; + bad = mbedtls_ct_bool_or(bad, mbedtls_ct_bool_ne(input[1], MBEDTLS_RSA_CRYPT)); /* Read the whole buffer. Set pad_done to nonzero if we find * the 0x00 byte and remember the padding length in pad_count. */ + pad_done = MBEDTLS_CT_FALSE; for (i = 2; i < ilen; i++) { - pad_done |= ((input[i] | (unsigned char) -input[i]) >> 7) ^ 1; - pad_count += ((pad_done | (unsigned char) -pad_done) >> 7) ^ 1; + mbedtls_ct_condition_t found = mbedtls_ct_bool_eq(input[i], 0); + pad_done = mbedtls_ct_bool_or(pad_done, found); + pad_count += mbedtls_ct_uint_if0(mbedtls_ct_bool_not(pad_done), 1); } - /* If pad_done is still zero, there's no data, only unfinished padding. */ - bad |= mbedtls_ct_uint_if(pad_done, 0, 1); + bad = mbedtls_ct_bool_or(bad, mbedtls_ct_bool_not(pad_done)); /* There must be at least 8 bytes of padding. */ - bad |= mbedtls_ct_size_gt(8, pad_count); + bad = mbedtls_ct_bool_or(bad, mbedtls_ct_bool_gt(8, pad_count)); /* If the padding is valid, set plaintext_size to the number of * remaining bytes after stripping the padding. If the padding @@ -143,13 +144,13 @@ static int mbedtls_ct_rsaes_pkcs1_v15_unpadding(unsigned char *input, * buffer. Do it without branches to avoid leaking the padding * validity through timing. RSA keys are small enough that all the * size_t values involved fit in unsigned int. */ - plaintext_size = mbedtls_ct_uint_if( + plaintext_size = mbedtls_ct_uint_if_new( bad, (unsigned) plaintext_max_size, (unsigned) (ilen - pad_count - 3)); /* Set output_too_large to 0 if the plaintext fits in the output * buffer and to 1 otherwise. */ - output_too_large = mbedtls_ct_size_gt(plaintext_size, + output_too_large = mbedtls_ct_bool_gt(plaintext_size, plaintext_max_size); /* Set ret without branches to avoid timing attacks. Return: @@ -157,11 +158,13 @@ static int mbedtls_ct_rsaes_pkcs1_v15_unpadding(unsigned char *input, * - OUTPUT_TOO_LARGE if the padding is good but the decrypted * plaintext does not fit in the output buffer. * - 0 if the padding is correct. */ - ret = -(int) mbedtls_ct_uint_if( - bad, -MBEDTLS_ERR_RSA_INVALID_PADDING, - mbedtls_ct_uint_if(output_too_large, - -MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE, - 0)); + ret = -(int) mbedtls_ct_uint_if_new( + bad, + (unsigned) (-(MBEDTLS_ERR_RSA_INVALID_PADDING)), + mbedtls_ct_uint_if0( + output_too_large, + (unsigned) (-(MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE))) + ); /* If the padding is bad or the plaintext is too large, zero the * data that we're about to copy to the output buffer. @@ -169,16 +172,13 @@ static int mbedtls_ct_rsaes_pkcs1_v15_unpadding(unsigned char *input, * from the same buffer whether the padding is good or not to * avoid leaking the padding validity through overall timing or * through memory or cache access patterns. */ - bad = mbedtls_ct_uint_mask(bad | output_too_large); - for (i = 11; i < ilen; i++) { - input[i] &= ~bad; - } + mbedtls_ct_zeroize_if(mbedtls_ct_bool_or(bad, output_too_large), input + 11, ilen - 11); /* If the plaintext is too large, truncate it to the buffer size. * Copy anyway to avoid revealing the length through timing, because * revealing the length is as bad as revealing the padding validity * for a Bleichenbacher attack. */ - plaintext_size = mbedtls_ct_uint_if(output_too_large, + plaintext_size = mbedtls_ct_uint_if_new(output_too_large, (unsigned) plaintext_max_size, (unsigned) plaintext_size); @@ -188,9 +188,9 @@ static int mbedtls_ct_rsaes_pkcs1_v15_unpadding(unsigned char *input, * does not depend on the plaintext size. After this move, the * starting location of the plaintext is no longer sensitive * information. */ - mbedtls_ct_mem_move_to_left(input + ilen - plaintext_max_size, - plaintext_max_size, - plaintext_max_size - plaintext_size); + mbedtls_ct_memmove_left(input + ilen - plaintext_max_size, + plaintext_max_size, + plaintext_max_size - plaintext_size); /* Finally copy the decrypted plaintext plus trailing zeros into the output * buffer. If output_max_len is 0, then output may be an invalid pointer From 293eedd3ad48aa34a4d815127ade8d870087b6c9 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Wed, 17 May 2023 12:31:36 +0100 Subject: [PATCH 15/82] Use new CT interface in ssl_tls12_server.c Signed-off-by: Dave Rodgman --- library/ssl_tls12_server.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/library/ssl_tls12_server.c b/library/ssl_tls12_server.c index a377d805b9..c2f14f1266 100644 --- a/library/ssl_tls12_server.c +++ b/library/ssl_tls12_server.c @@ -3481,9 +3481,8 @@ static int ssl_parse_encrypted_pms(mbedtls_ssl_context *ssl, unsigned char *pms = ssl->handshake->premaster + pms_offset; unsigned char ver[2]; unsigned char fake_pms[48], peer_pms[48]; - unsigned char mask; - size_t i, peer_pmslen; - unsigned int diff; + size_t peer_pmslen; + mbedtls_ct_condition_t 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 @@ -3512,13 +3511,10 @@ static int ssl_parse_encrypted_pms(mbedtls_ssl_context *ssl, /* 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 */ - mask = mbedtls_ct_uint_mask(diff); + diff = mbedtls_ct_bool(ret); + diff = mbedtls_ct_bool_or(diff, mbedtls_ct_bool_ne(peer_pmslen, 48)); + diff = mbedtls_ct_bool_or(diff, mbedtls_ct_bool_ne(peer_pms[0], ver[0])); + diff = mbedtls_ct_bool_or(diff, mbedtls_ct_bool_ne(peer_pms[1], ver[1])); /* * Protection against Bleichenbacher's attack: invalid PKCS#1 v1.5 padding @@ -3537,7 +3533,7 @@ static int ssl_parse_encrypted_pms(mbedtls_ssl_context *ssl, } #if defined(MBEDTLS_SSL_DEBUG_ALL) - if (diff != 0) { + if (diff != MBEDTLS_CT_FALSE) { MBEDTLS_SSL_DEBUG_MSG(1, ("bad client key exchange message")); } #endif @@ -3551,9 +3547,7 @@ static int ssl_parse_encrypted_pms(mbedtls_ssl_context *ssl, /* 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]); - } + mbedtls_ct_memcpy_if(diff, pms, fake_pms, peer_pms, ssl->handshake->pmslen); return 0; } From 7fe6e6fb2bafbd4386316d1fc5a80a05a270c384 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Wed, 17 May 2023 12:34:56 +0100 Subject: [PATCH 16/82] Add impl of mbedtls_ct_memcpy_if Signed-off-by: Dave Rodgman --- library/constant_time.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/library/constant_time.c b/library/constant_time.c index 0b44587d52..e9da8e0a92 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -346,6 +346,35 @@ void mbedtls_ct_memmove_left(void *start, size_t total, size_t offset) #endif /* MBEDTLS_PKCS1_V15 && MBEDTLS_RSA_C && ! MBEDTLS_RSA_ALT */ +void mbedtls_ct_memcpy_if(mbedtls_ct_condition_t condition, + unsigned char *dest, + const unsigned char *src1, + const unsigned char *src2, + size_t len) +{ + const uint32_t mask = (uint32_t) condition; + const uint32_t not_mask = (uint32_t) ~mbedtls_ct_compiler_opaque(condition); + + /* If src2 is NULL and condition == 0, then this function has no effect. + * In this case, copy from dest back into dest. */ + if (src2 == NULL) { + src2 = dest; + } + + /* dest[i] = c1 == c2 ? src[i] : dest[i] */ + size_t i = 0; +#if defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS) + for (; (i + 4) <= len; i += 4) { + uint32_t a = mbedtls_get_unaligned_uint32(src1 + i) & mask; + uint32_t b = mbedtls_get_unaligned_uint32(src2 + i) & not_mask; + mbedtls_put_unaligned_uint32(dest + i, a | b); + } +#endif /* MBEDTLS_EFFICIENT_UNALIGNED_ACCESS */ + for (; i < len; i++) { + dest[i] = (src1[i] & mask) | (src2[i] & not_mask); + } +} + #if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC) void mbedtls_ct_memcpy_if_eq(unsigned char *dest, From a81373f80e82cca9f6e4b4cfe3f8a01a14d8e1f9 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Wed, 17 May 2023 12:36:01 +0100 Subject: [PATCH 17/82] Use new CT interface in ssl_msg.c Signed-off-by: Dave Rodgman --- library/ssl_msg.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/library/ssl_msg.c b/library/ssl_msg.c index 69706cf532..b5019ef1e8 100644 --- a/library/ssl_msg.c +++ b/library/ssl_msg.c @@ -148,8 +148,8 @@ int mbedtls_ct_hmac(mbedtls_svc_key_id_t key, PSA_CHK(psa_hash_finish(&aux_operation, aux_out, PSA_HASH_MAX_SIZE, &hash_length)); /* Keep only the correct inner_hash in the output buffer */ - mbedtls_ct_memcpy_if_eq(output, aux_out, hash_size, - offset, data_len_secret); + mbedtls_ct_memcpy_if(mbedtls_ct_bool_eq(offset, data_len_secret), + output, aux_out, NULL, hash_size); if (offset < max_data_len) { PSA_CHK(psa_hash_update(&operation, data + offset, 1)); @@ -251,8 +251,8 @@ int mbedtls_ct_hmac(mbedtls_md_context_t *ctx, 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_ct_memcpy_if_eq(output, aux_out, hash_size, - offset, data_len_secret); + mbedtls_ct_memcpy_if(mbedtls_ct_bool_eq(offset, data_len_secret), + output, aux_out, NULL, hash_size); if (offset < max_data_len) { MD_CHK(mbedtls_md_update(ctx, data + offset, 1)); @@ -1912,11 +1912,11 @@ hmac_failed_etm_enabled: padlen = data[rec->data_len - 1]; if (auth_done == 1) { - const size_t mask = mbedtls_ct_size_mask_ge( + const mbedtls_ct_condition_t ge = mbedtls_ct_bool_ge( rec->data_len, padlen + 1); - correct &= mask; - padlen &= mask; + correct = mbedtls_ct_size_if0(ge, correct); + padlen = mbedtls_ct_size_if0(ge, padlen); } else { #if defined(MBEDTLS_SSL_DEBUG_ALL) if (rec->data_len < transform->maclen + padlen + 1) { @@ -1928,12 +1928,11 @@ hmac_failed_etm_enabled: padlen + 1)); } #endif - - const size_t mask = mbedtls_ct_size_mask_ge( + const mbedtls_ct_condition_t ge = mbedtls_ct_bool_ge( rec->data_len, transform->maclen + padlen + 1); - correct &= mask; - padlen &= mask; + correct = mbedtls_ct_size_if0(ge, correct); + padlen = mbedtls_ct_size_if0(ge, padlen); } padlen++; @@ -1962,19 +1961,20 @@ hmac_failed_etm_enabled: /* pad_count += (idx >= padding_idx) && * (check[idx] == padlen - 1); */ - const size_t mask = mbedtls_ct_size_mask_ge(idx, padding_idx); - const size_t equal = mbedtls_ct_size_bool_eq(check[idx], - padlen - 1); - pad_count += mask & equal; + const mbedtls_ct_condition_t a = mbedtls_ct_bool_ge(idx, padding_idx); + size_t increment = mbedtls_ct_size_if0(a, 1); + const mbedtls_ct_condition_t b = mbedtls_ct_bool_eq(check[idx], padlen - 1); + increment = mbedtls_ct_size_if0(b, increment); + pad_count += increment; } - correct &= mbedtls_ct_size_bool_eq(pad_count, padlen); + correct = mbedtls_ct_size_if0(mbedtls_ct_bool_eq(pad_count, padlen), padlen); #if defined(MBEDTLS_SSL_DEBUG_ALL) if (padlen > 0 && correct == 0) { MBEDTLS_SSL_DEBUG_MSG(1, ("bad padding byte detected")); } #endif - padlen &= mbedtls_ct_size_mask(correct); + padlen = mbedtls_ct_size_if0(mbedtls_ct_bool(correct), padlen); #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ From cd2e38b90638a71eccbc1a242c1914f8ce6652a3 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Wed, 17 May 2023 13:31:55 +0100 Subject: [PATCH 18/82] Update mbedtls_mpi_safe_cond_(assign|swap) to use new CT interface Signed-off-by: Dave Rodgman --- library/bignum.c | 8 ++++++-- library/bignum_core.c | 16 +++++++--------- library/bignum_core.h | 22 ++++++---------------- library/bignum_mod_raw.c | 4 ++-- 4 files changed, 21 insertions(+), 29 deletions(-) diff --git a/library/bignum.c b/library/bignum.c index b62f3f2c37..76910b1e6f 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -141,6 +141,8 @@ int mbedtls_mpi_safe_cond_assign(mbedtls_mpi *X, MPI_VALIDATE_RET(X != NULL); MPI_VALIDATE_RET(Y != NULL); + mbedtls_ct_condition_t do_assign = mbedtls_ct_bool(assign); + /* all-bits 1 if assign is 1, all-bits 0 if assign is 0 */ mbedtls_mpi_uint limb_mask = mbedtls_ct_mpi_uint_mask(assign); @@ -148,7 +150,7 @@ int mbedtls_mpi_safe_cond_assign(mbedtls_mpi *X, X->s = (int) mbedtls_ct_uint_if(assign, Y->s, X->s); - mbedtls_mpi_core_cond_assign(X->p, Y->p, Y->n, assign); + mbedtls_mpi_core_cond_assign(X->p, Y->p, Y->n, do_assign); for (size_t i = Y->n; i < X->n; i++) { X->p[i] &= ~limb_mask; @@ -177,6 +179,8 @@ int mbedtls_mpi_safe_cond_swap(mbedtls_mpi *X, return 0; } + mbedtls_ct_condition_t do_swap = mbedtls_ct_bool(swap); + MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, Y->n)); MBEDTLS_MPI_CHK(mbedtls_mpi_grow(Y, X->n)); @@ -184,7 +188,7 @@ int mbedtls_mpi_safe_cond_swap(mbedtls_mpi *X, X->s = (int) mbedtls_ct_uint_if(swap, Y->s, X->s); Y->s = (int) mbedtls_ct_uint_if(swap, s, Y->s); - mbedtls_mpi_core_cond_swap(X->p, Y->p, X->n, swap); + mbedtls_mpi_core_cond_swap(X->p, Y->p, X->n, do_swap); cleanup: return ret; diff --git a/library/bignum_core.c b/library/bignum_core.c index a51b3f404e..75806cf24b 100644 --- a/library/bignum_core.c +++ b/library/bignum_core.c @@ -211,31 +211,29 @@ unsigned mbedtls_mpi_core_lt_ct(const mbedtls_mpi_uint *A, void mbedtls_mpi_core_cond_assign(mbedtls_mpi_uint *X, const mbedtls_mpi_uint *A, size_t limbs, - unsigned char assign) + mbedtls_ct_condition_t assign) { if (X == A) { return; } - mbedtls_ct_mpi_uint_cond_assign(limbs, X, A, assign); + mbedtls_ct_memcpy_if(assign, (unsigned char *) X, (unsigned char *) A, NULL, + limbs * sizeof(mbedtls_mpi_uint)); } void mbedtls_mpi_core_cond_swap(mbedtls_mpi_uint *X, mbedtls_mpi_uint *Y, size_t limbs, - unsigned char swap) + mbedtls_ct_condition_t swap) { if (X == Y) { return; } - /* all-bits 1 if swap is 1, all-bits 0 if swap is 0 */ - mbedtls_mpi_uint limb_mask = mbedtls_ct_mpi_uint_mask(swap); - for (size_t i = 0; i < limbs; i++) { mbedtls_mpi_uint tmp = X[i]; - X[i] = (X[i] & ~limb_mask) | (Y[i] & limb_mask); - Y[i] = (Y[i] & ~limb_mask) | (tmp & limb_mask); + X[i] = mbedtls_ct_mpi_uint_if(swap, Y[i], X[i]); + Y[i] = mbedtls_ct_mpi_uint_if(swap, tmp, Y[i]); } } @@ -637,7 +635,7 @@ void mbedtls_mpi_core_ct_uint_table_lookup(mbedtls_mpi_uint *dest, size_t index) { for (size_t i = 0; i < count; i++, table += limbs) { - unsigned char assign = mbedtls_ct_size_bool_eq(i, index); + mbedtls_ct_condition_t assign = mbedtls_ct_bool_eq(i, index); mbedtls_mpi_core_cond_assign(dest, table, limbs, assign); } } diff --git a/library/bignum_core.h b/library/bignum_core.h index 1fc5375755..5432c8009b 100644 --- a/library/bignum_core.h +++ b/library/bignum_core.h @@ -86,6 +86,8 @@ #include "mbedtls/bignum.h" #endif +#include "constant_time_internal.h" + #define ciL (sizeof(mbedtls_mpi_uint)) /** chars in limb */ #define biL (ciL << 3) /** bits in limb */ #define biH (ciL << 2) /** half limb size */ @@ -176,21 +178,15 @@ unsigned mbedtls_mpi_core_lt_ct(const mbedtls_mpi_uint *A, * \param[in] A The address of the source MPI. This must be initialized. * \param limbs The number of limbs of \p A. * \param assign The condition deciding whether to perform the - * assignment or not. Must be either 0 or 1: - * * \c 1: Perform the assignment `X = A`. - * * \c 0: Keep the original value of \p X. + * assignment or not. * * \note This function avoids leaking any information about whether * the assignment was done or not. - * - * \warning If \p assign is neither 0 nor 1, the result of this function - * is indeterminate, and the resulting value in \p X might be - * neither its original value nor the value in \p A. */ void mbedtls_mpi_core_cond_assign(mbedtls_mpi_uint *X, const mbedtls_mpi_uint *A, size_t limbs, - unsigned char assign); + mbedtls_ct_condition_t assign); /** * \brief Perform a safe conditional swap of two MPIs which doesn't reveal @@ -202,21 +198,15 @@ void mbedtls_mpi_core_cond_assign(mbedtls_mpi_uint *X, * This must be initialized. * \param limbs The number of limbs of \p X and \p Y. * \param swap The condition deciding whether to perform - * the swap or not. Must be either 0 or 1: - * * \c 1: Swap the values of \p X and \p Y. - * * \c 0: Keep the original values of \p X and \p Y. + * the swap or not. * * \note This function avoids leaking any information about whether * the swap was done or not. - * - * \warning If \p swap is neither 0 nor 1, the result of this function - * is indeterminate, and both \p X and \p Y might end up with - * values different to either of the original ones. */ void mbedtls_mpi_core_cond_swap(mbedtls_mpi_uint *X, mbedtls_mpi_uint *Y, size_t limbs, - unsigned char swap); + mbedtls_ct_condition_t swap); /** Import X from unsigned binary data, little-endian. * diff --git a/library/bignum_mod_raw.c b/library/bignum_mod_raw.c index 791921151d..ef8c2b33b3 100644 --- a/library/bignum_mod_raw.c +++ b/library/bignum_mod_raw.c @@ -40,7 +40,7 @@ void mbedtls_mpi_mod_raw_cond_assign(mbedtls_mpi_uint *X, const mbedtls_mpi_mod_modulus *N, unsigned char assign) { - mbedtls_mpi_core_cond_assign(X, A, N->limbs, assign); + mbedtls_mpi_core_cond_assign(X, A, N->limbs, mbedtls_ct_bool(assign)); } void mbedtls_mpi_mod_raw_cond_swap(mbedtls_mpi_uint *X, @@ -48,7 +48,7 @@ void mbedtls_mpi_mod_raw_cond_swap(mbedtls_mpi_uint *X, const mbedtls_mpi_mod_modulus *N, unsigned char swap) { - mbedtls_mpi_core_cond_swap(X, Y, N->limbs, swap); + mbedtls_mpi_core_cond_swap(X, Y, N->limbs, mbedtls_ct_bool(swap)); } int mbedtls_mpi_mod_raw_read(mbedtls_mpi_uint *X, From 589ccb8aaacb466efdf843de6c090133ef84471b Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Wed, 17 May 2023 13:55:01 +0100 Subject: [PATCH 19/82] Update mbedtls_mpi_safe_cond_(assign|swap) part 2 Signed-off-by: Dave Rodgman --- library/bignum.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/library/bignum.c b/library/bignum.c index 76910b1e6f..dd77bfc9fc 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -141,19 +141,17 @@ int mbedtls_mpi_safe_cond_assign(mbedtls_mpi *X, MPI_VALIDATE_RET(X != NULL); MPI_VALIDATE_RET(Y != NULL); - mbedtls_ct_condition_t do_assign = mbedtls_ct_bool(assign); - - /* all-bits 1 if assign is 1, all-bits 0 if assign is 0 */ - mbedtls_mpi_uint limb_mask = mbedtls_ct_mpi_uint_mask(assign); - MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, Y->n)); - X->s = (int) mbedtls_ct_uint_if(assign, Y->s, X->s); + mbedtls_ct_condition_t do_assign = mbedtls_ct_bool(assign); + + X->s = (int) mbedtls_ct_uint_if_new(do_assign, Y->s, X->s); mbedtls_mpi_core_cond_assign(X->p, Y->p, Y->n, do_assign); + mbedtls_ct_condition_t do_not_assign = mbedtls_ct_bool_not(do_assign); for (size_t i = Y->n; i < X->n; i++) { - X->p[i] &= ~limb_mask; + X->p[i] = mbedtls_ct_mpi_uint_if0(do_not_assign, X->p[i]); } cleanup: From 1a7a5626ec3bd8cb86d6e8c51725c72987a98a08 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Wed, 17 May 2023 13:47:56 +0100 Subject: [PATCH 20/82] Update mbedtls_mpi_lt_mpi_ct to new interface Signed-off-by: Dave Rodgman --- library/bignum.c | 51 +++++++++++++++++------------------------------- 1 file changed, 18 insertions(+), 33 deletions(-) diff --git a/library/bignum.c b/library/bignum.c index dd77bfc9fc..9e215d8e5f 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -61,9 +61,7 @@ int mbedtls_mpi_lt_mpi_ct(const mbedtls_mpi *X, const mbedtls_mpi *Y, unsigned *ret) { - size_t i; - /* The value of any of these variables is either 0 or 1 at all times. */ - unsigned cond, done, X_is_negative, Y_is_negative; + mbedtls_ct_condition_t cond, X_is_negative, Y_is_negative, result; MPI_VALIDATE_RET(X != NULL); MPI_VALIDATE_RET(Y != NULL); @@ -77,46 +75,33 @@ int mbedtls_mpi_lt_mpi_ct(const mbedtls_mpi *X, * Set sign_N to 1 if N >= 0, 0 if N < 0. * We know that N->s == 1 if N >= 0 and N->s == -1 if N < 0. */ - X_is_negative = (X->s & 2) >> 1; - Y_is_negative = (Y->s & 2) >> 1; + X_is_negative = mbedtls_ct_bool((X->s & 2) >> 1); + Y_is_negative = mbedtls_ct_bool((Y->s & 2) >> 1); /* * If the signs are different, then the positive operand is the bigger. * That is if X is negative (X_is_negative == 1), then X < Y is true and it * is false if X is positive (X_is_negative == 0). */ - cond = (X_is_negative ^ Y_is_negative); - *ret = cond & X_is_negative; + cond = mbedtls_ct_bool_xor(X_is_negative, Y_is_negative); // non-zero if different sign + result = mbedtls_ct_bool_and(cond, X_is_negative); - /* - * This is a constant-time function. We might have the result, but we still - * need to go through the loop. Record if we have the result already. + /* Assuming signs are the same, compare X and Y. We switch the comparison + * order if they are negative so that we get the right result, regardles of + * sign. + * + * Store in ret iff the signs are the same (i.e., iff cond == 0). If + * the signs differ, done has already been set. */ - done = cond; - for (i = X->n; i > 0; i--) { - /* - * If Y->p[i - 1] < X->p[i - 1] then X < Y is true if and only if both - * X and Y are negative. - * - * Again even if we can make a decision, we just mark the result and - * the fact that we are done and continue looping. - */ - cond = mbedtls_ct_mpi_uint_lt(Y->p[i - 1], X->p[i - 1]); - *ret |= cond & (1 - done) & X_is_negative; - done |= cond; + /* This is used to conditionally swap the pointers in const time */ + void * const p[2] = { X->p, Y->p }; + mbedtls_ct_condition_t lt = mbedtls_mpi_core_lt_ct( + p[X_is_negative & 1], p[(X_is_negative & 1) ^ 1], X->n); - /* - * If X->p[i - 1] < Y->p[i - 1] then X < Y is true if and only if both - * X and Y are positive. - * - * Again even if we can make a decision, we just mark the result and - * the fact that we are done and continue looping. - */ - cond = mbedtls_ct_mpi_uint_lt(X->p[i - 1], Y->p[i - 1]); - *ret |= cond & (1 - done) & (1 - X_is_negative); - done |= cond; - } + result = mbedtls_ct_bool_or(result, mbedtls_ct_bool_and(mbedtls_ct_bool_not(cond), lt)); + + *ret = mbedtls_ct_uint_if0(result, 1); return 0; } From ee54faf1cddc02a7656a85b7e18fadb2192e73a6 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Wed, 17 May 2023 13:56:33 +0100 Subject: [PATCH 21/82] Update mpi_select to use new CT interface Signed-off-by: Dave Rodgman --- library/bignum.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/library/bignum.c b/library/bignum.c index 9e215d8e5f..59b5f74184 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -1725,10 +1725,8 @@ static int mpi_select(mbedtls_mpi *R, const mbedtls_mpi *T, size_t T_size, size_ for (size_t i = 0; i < T_size; i++) { MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_assign(R, &T[i], - (unsigned char) mbedtls_ct_size_bool_eq(i, - idx))); + (unsigned char) mbedtls_ct_bool_eq(i, idx))); } - cleanup: return ret; } From fd7fab40738b9ea94be6b2fcab6dba2d0e601432 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Wed, 17 May 2023 14:00:39 +0100 Subject: [PATCH 22/82] Update mbedtls_mpi_core_uint_le_mpi to new CT interface Signed-off-by: Dave Rodgman --- library/bignum_core.c | 16 +++++++--------- library/bignum_core.h | 8 ++++---- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/library/bignum_core.c b/library/bignum_core.c index 75806cf24b..c9008a1d81 100644 --- a/library/bignum_core.c +++ b/library/bignum_core.c @@ -148,24 +148,22 @@ void mbedtls_mpi_core_bigendian_to_host(mbedtls_mpi_uint *A, /* Whether min <= A, in constant time. * A_limbs must be at least 1. */ -unsigned mbedtls_mpi_core_uint_le_mpi(mbedtls_mpi_uint min, - const mbedtls_mpi_uint *A, - size_t A_limbs) +mbedtls_ct_condition_t mbedtls_mpi_core_uint_le_mpi(mbedtls_mpi_uint min, + const mbedtls_mpi_uint *A, + size_t A_limbs) { /* min <= least significant limb? */ - unsigned min_le_lsl = 1 ^ mbedtls_ct_mpi_uint_lt(A[0], min); + mbedtls_ct_condition_t min_le_lsl = mbedtls_ct_bool_ge(A[0], min); /* limbs other than the least significant one are all zero? */ - mbedtls_mpi_uint msll_mask = 0; + mbedtls_ct_condition_t msll_mask = MBEDTLS_CT_FALSE; for (size_t i = 1; i < A_limbs; i++) { - msll_mask |= A[i]; + msll_mask = mbedtls_ct_bool_or(msll_mask, mbedtls_ct_bool(A[i])); } - /* The most significant limbs of A are not all zero iff msll_mask != 0. */ - unsigned msll_nonzero = mbedtls_ct_mpi_uint_mask(msll_mask) & 1; /* min <= A iff the lowest limb of A is >= min or the other limbs * are not all zero. */ - return min_le_lsl | msll_nonzero; + return mbedtls_ct_bool_or(msll_mask, min_le_lsl); } unsigned mbedtls_mpi_core_lt_ct(const mbedtls_mpi_uint *A, diff --git a/library/bignum_core.h b/library/bignum_core.h index 5432c8009b..e2d18e9b64 100644 --- a/library/bignum_core.h +++ b/library/bignum_core.h @@ -144,11 +144,11 @@ void mbedtls_mpi_core_bigendian_to_host(mbedtls_mpi_uint *A, * \param A_limbs The number of limbs of \p A. * This must be at least 1. * - * \return 1 if \p min is less than or equal to \p A, otherwise 0. + * \return MBEDTLS_CT_TRUE if \p min is less than or equal to \p A, otherwise MBEDTLS_CT_FALSE. */ -unsigned mbedtls_mpi_core_uint_le_mpi(mbedtls_mpi_uint min, - const mbedtls_mpi_uint *A, - size_t A_limbs); +mbedtls_ct_condition_t mbedtls_mpi_core_uint_le_mpi(mbedtls_mpi_uint min, + const mbedtls_mpi_uint *A, + size_t A_limbs); /** * \brief Check if one unsigned MPI is less than another in constant From 231a5166828a7ef8487d05d9b4e9783713e61b08 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Wed, 17 May 2023 15:13:14 +0100 Subject: [PATCH 23/82] Remove not-needed mbedtls_ct_mpi_uint_cond_assign Signed-off-by: Dave Rodgman --- library/bignum_core.c | 6 +++++- library/constant_time.c | 30 ------------------------------ library/constant_time_internal.h | 21 --------------------- 3 files changed, 5 insertions(+), 52 deletions(-) diff --git a/library/bignum_core.c b/library/bignum_core.c index c9008a1d81..a23862bee0 100644 --- a/library/bignum_core.c +++ b/library/bignum_core.c @@ -608,7 +608,11 @@ void mbedtls_mpi_core_montmul(mbedtls_mpi_uint *X, * So the correct return value is already in X if (carry ^ borrow) = 0, * but is in (the lower AN_limbs limbs of) T if (carry ^ borrow) = 1. */ - mbedtls_ct_mpi_uint_cond_assign(AN_limbs, X, T, (unsigned char) (carry ^ borrow)); + mbedtls_ct_memcpy_if(mbedtls_ct_bool(carry ^ borrow), + (unsigned char *) X, + (unsigned char *) T, + NULL, + AN_limbs * sizeof(mbedtls_mpi_uint)); } int mbedtls_mpi_core_get_mont_r2_unsafe(mbedtls_mpi *X, diff --git a/library/constant_time.c b/library/constant_time.c index e9da8e0a92..c5255851e1 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -295,36 +295,6 @@ unsigned mbedtls_ct_uint_if(unsigned condition, return (mask & if1) | (~mask & if0); } -#if defined(MBEDTLS_BIGNUM_C) - -void mbedtls_ct_mpi_uint_cond_assign(size_t n, - mbedtls_mpi_uint *dest, - const mbedtls_mpi_uint *src, - unsigned char condition) -{ - size_t i; - - /* MSVC has a warning about unary minus on unsigned integer types, - * 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 - - /* all-bits 1 if condition is 1, all-bits 0 if condition is 0 */ - const mbedtls_mpi_uint mask = -condition; - -#if defined(_MSC_VER) -#pragma warning( pop ) -#endif - - for (i = 0; i < n; i++) { - dest[i] = (src[i] & mask) | (dest[i] & ~mask); - } -} - -#endif /* MBEDTLS_BIGNUM_C */ - #if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) void mbedtls_ct_memmove_left(void *start, size_t total, size_t offset) diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h index 5e0d9c45f7..f2cb4871b1 100644 --- a/library/constant_time_internal.h +++ b/library/constant_time_internal.h @@ -147,27 +147,6 @@ unsigned mbedtls_ct_uint_if(unsigned condition, unsigned if1, unsigned if0); -#if defined(MBEDTLS_BIGNUM_C) - -/** Conditionally assign a value without branches. - * - * This is equivalent to `if ( condition ) dest = src`, but is likely - * to be compiled to code using bitwise operation rather than a branch. - * - * \param n \p dest and \p src must be arrays of limbs of size n. - * \param dest The MPI to conditionally assign to. This must point - * to an initialized MPI. - * \param src The MPI to be assigned from. This must point to an - * initialized MPI. - * \param condition Condition to test, must be 0 or 1. - */ -void mbedtls_ct_mpi_uint_cond_assign(size_t n, - mbedtls_mpi_uint *dest, - const mbedtls_mpi_uint *src, - unsigned char condition); - -#endif /* MBEDTLS_BIGNUM_C */ - #if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC) /** Conditional memcpy without branches. From 8ac9a1df24c9992cfda01bdbb3dac30f9012ec56 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Wed, 17 May 2023 15:16:22 +0100 Subject: [PATCH 24/82] Use new CT interface in mbedtls_mpi_core_lt_ct Signed-off-by: Dave Rodgman --- library/bignum_core.c | 22 +++++++++------------- library/bignum_core.h | 12 ++++++------ 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/library/bignum_core.c b/library/bignum_core.c index a23862bee0..7a77f07203 100644 --- a/library/bignum_core.c +++ b/library/bignum_core.c @@ -166,15 +166,11 @@ mbedtls_ct_condition_t mbedtls_mpi_core_uint_le_mpi(mbedtls_mpi_uint min, return mbedtls_ct_bool_or(msll_mask, min_le_lsl); } -unsigned mbedtls_mpi_core_lt_ct(const mbedtls_mpi_uint *A, - const mbedtls_mpi_uint *B, - size_t limbs) +mbedtls_ct_condition_t mbedtls_mpi_core_lt_ct(const mbedtls_mpi_uint *A, + const mbedtls_mpi_uint *B, + size_t limbs) { - unsigned ret, cond, done; - - /* The value of any of these variables is either 0 or 1 for the rest of - * their scope. */ - ret = cond = done = 0; + mbedtls_ct_condition_t ret = MBEDTLS_CT_FALSE, cond = MBEDTLS_CT_FALSE, done = MBEDTLS_CT_FALSE; for (size_t i = limbs; i > 0; i--) { /* @@ -184,8 +180,8 @@ unsigned mbedtls_mpi_core_lt_ct(const mbedtls_mpi_uint *A, * Again even if we can make a decision, we just mark the result and * the fact that we are done and continue looping. */ - cond = mbedtls_ct_mpi_uint_lt(B[i - 1], A[i - 1]); - done |= cond; + cond = mbedtls_ct_bool_lt(B[i - 1], A[i - 1]); + done = mbedtls_ct_bool_or(done, cond); /* * If A[i - 1] < B[i - 1] then A < B is true. @@ -193,9 +189,9 @@ unsigned mbedtls_mpi_core_lt_ct(const mbedtls_mpi_uint *A, * Again even if we can make a decision, we just mark the result and * the fact that we are done and continue looping. */ - cond = mbedtls_ct_mpi_uint_lt(A[i - 1], B[i - 1]); - ret |= cond & (1 - done); - done |= cond; + cond = mbedtls_ct_bool_lt(A[i - 1], B[i - 1]); + ret = mbedtls_ct_bool_or(ret, mbedtls_ct_bool_and(cond, mbedtls_ct_bool_not(done))); + done = mbedtls_ct_bool_or(done, cond); } /* diff --git a/library/bignum_core.h b/library/bignum_core.h index e2d18e9b64..64d51b92d1 100644 --- a/library/bignum_core.h +++ b/library/bignum_core.h @@ -161,13 +161,13 @@ mbedtls_ct_condition_t mbedtls_mpi_core_uint_le_mpi(mbedtls_mpi_uint min, * \param limbs The number of limbs in \p A and \p B. * This must not be 0. * - * \return The result of the comparison: - * \c 1 if \p A is less than \p B. - * \c 0 if \p A is greater than or equal to \p B. + * \return MBEDTLS_CT_TRUE if \p A is less than \p B. + * MBEDTLS_CT_FALSE if \p A is greater than or equal to \p B. */ -unsigned mbedtls_mpi_core_lt_ct(const mbedtls_mpi_uint *A, - const mbedtls_mpi_uint *B, - size_t limbs); +mbedtls_ct_condition_t mbedtls_mpi_core_lt_ct(const mbedtls_mpi_uint *A, + const mbedtls_mpi_uint *B, + size_t limbs); + /** * \brief Perform a safe conditional copy of an MPI which doesn't reveal * whether assignment was done or not. From b59b73e2bc82a0b970f388245de4bb9fd2e086b9 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Wed, 17 May 2023 15:17:12 +0100 Subject: [PATCH 25/82] Use new CT interface in mbedtls_mpi_core_add_if Signed-off-by: Dave Rodgman --- library/bignum_core.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/library/bignum_core.c b/library/bignum_core.c index 7a77f07203..308f5c76f4 100644 --- a/library/bignum_core.c +++ b/library/bignum_core.c @@ -458,11 +458,10 @@ mbedtls_mpi_uint mbedtls_mpi_core_add_if(mbedtls_mpi_uint *X, { mbedtls_mpi_uint c = 0; - /* all-bits 0 if cond is 0, all-bits 1 if cond is non-0 */ - const mbedtls_mpi_uint mask = mbedtls_ct_mpi_uint_mask(cond); + mbedtls_ct_condition_t do_add = mbedtls_ct_bool(cond); for (size_t i = 0; i < limbs; i++) { - mbedtls_mpi_uint add = mask & A[i]; + mbedtls_mpi_uint add = mbedtls_ct_mpi_uint_if0(do_add, A[i]); mbedtls_mpi_uint t = c + X[i]; c = (t < X[i]); t += add; From fd492ab1be4c04fa5eae726bf9af5e55967a2870 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Wed, 17 May 2023 15:17:29 +0100 Subject: [PATCH 26/82] Use new CT interface in mbedtls_mpi_core_random Signed-off-by: Dave Rodgman --- library/bignum_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/bignum_core.c b/library/bignum_core.c index 308f5c76f4..b41d046a54 100644 --- a/library/bignum_core.c +++ b/library/bignum_core.c @@ -672,7 +672,7 @@ int mbedtls_mpi_core_random(mbedtls_mpi_uint *X, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) { - unsigned ge_lower = 1, lt_upper = 0; + mbedtls_ct_condition_t ge_lower = MBEDTLS_CT_TRUE, lt_upper = MBEDTLS_CT_FALSE; size_t n_bits = mbedtls_mpi_core_bitlen(N, limbs); size_t n_bytes = (n_bits + 7) / 8; int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; @@ -717,7 +717,7 @@ int mbedtls_mpi_core_random(mbedtls_mpi_uint *X, ge_lower = mbedtls_mpi_core_uint_le_mpi(min, X, limbs); lt_upper = mbedtls_mpi_core_lt_ct(X, N, limbs); - } while (ge_lower == 0 || lt_upper == 0); + } while (mbedtls_ct_bool_and(ge_lower, lt_upper) == MBEDTLS_CT_FALSE); cleanup: return ret; From cf06acac3243a9d4300439f2e2deb24275ee4200 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Wed, 17 May 2023 15:21:37 +0100 Subject: [PATCH 27/82] Use new CT interface in mbedtls_mpi_safe_cond_swap Signed-off-by: Dave Rodgman --- library/bignum.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/bignum.c b/library/bignum.c index 59b5f74184..e8d91631eb 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -168,8 +168,8 @@ int mbedtls_mpi_safe_cond_swap(mbedtls_mpi *X, MBEDTLS_MPI_CHK(mbedtls_mpi_grow(Y, X->n)); s = X->s; - X->s = (int) mbedtls_ct_uint_if(swap, Y->s, X->s); - Y->s = (int) mbedtls_ct_uint_if(swap, s, Y->s); + X->s = (int) mbedtls_ct_uint_if_new(do_swap, Y->s, X->s); + Y->s = (int) mbedtls_ct_uint_if_new(do_swap, s, Y->s); mbedtls_mpi_core_cond_swap(X->p, Y->p, X->n, do_swap); From 199a2c5d39ba1a879431d5b92568a919c0699ed9 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Wed, 17 May 2023 15:46:23 +0100 Subject: [PATCH 28/82] Use new CT interface in mbedtls_ct_memcpy_offset Signed-off-by: Dave Rodgman --- library/constant_time.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index c5255851e1..76faeb6bcc 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -385,8 +385,8 @@ void mbedtls_ct_memcpy_offset(unsigned char *dest, size_t offsetval; for (offsetval = offset_min; offsetval <= offset_max; offsetval++) { - mbedtls_ct_memcpy_if_eq(dest, src + offsetval, len, - offsetval, offset); + mbedtls_ct_memcpy_if(mbedtls_ct_bool_eq(offsetval, offset), dest, src + offsetval, NULL, + len); } } From 2243137715db22ad7111da7f13b25fcabe80caf8 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Wed, 17 May 2023 15:35:07 +0100 Subject: [PATCH 29/82] Remove old interface Signed-off-by: Dave Rodgman --- library/constant_time.c | 210 ------------------------------- library/constant_time_internal.h | 190 ---------------------------- 2 files changed, 400 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index 76faeb6bcc..c86316b008 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -113,188 +113,6 @@ int mbedtls_ct_memcmp(const void *a, return (int) diff; } -unsigned mbedtls_ct_uint_mask(unsigned value) -{ - /* 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 - return -((value | -value) >> (sizeof(value) * 8 - 1)); -#if defined(_MSC_VER) -#pragma warning( pop ) -#endif -} - -#if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC) - -size_t mbedtls_ct_size_mask(size_t value) -{ - /* MSVC has a warning about unary minus on unsigned integer types, - * 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 - return -((value | -value) >> (sizeof(value) * 8 - 1)); -#if defined(_MSC_VER) -#pragma warning( pop ) -#endif -} - -#endif /* MBEDTLS_SSL_SOME_SUITES_USE_MAC */ - -#if defined(MBEDTLS_BIGNUM_C) - -mbedtls_mpi_uint mbedtls_ct_mpi_uint_mask(mbedtls_mpi_uint value) -{ - /* 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 - return -((value | -value) >> (sizeof(value) * 8 - 1)); -#if defined(_MSC_VER) -#pragma warning( pop ) -#endif -} - -#endif /* MBEDTLS_BIGNUM_C */ - -#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) - -/** Constant-flow mask generation for "less than" comparison: - * - if \p x < \p y, return all-bits 1, that is (size_t) -1 - * - otherwise, return all bits 0, that is 0 - * - * This function can be used to write constant-time code by replacing branches - * with bit operations using masks. - * - * \param x The first value to analyze. - * \param y The second value to analyze. - * - * \return All-bits-one if \p x is less than \p y, otherwise zero. - */ -static size_t mbedtls_ct_size_mask_lt(size_t x, - size_t y) -{ - /* This has the most significant bit set if and only if x < y */ - const size_t sub = x - y; - - /* sub1 = (x < y) ? 1 : 0 */ - const size_t sub1 = sub >> (sizeof(sub) * 8 - 1); - - /* mask = (x < y) ? 0xff... : 0x00... */ - const size_t mask = mbedtls_ct_size_mask(sub1); - - return mask; -} - -size_t mbedtls_ct_size_mask_ge(size_t x, - size_t y) -{ - return ~mbedtls_ct_size_mask_lt(x, y); -} - -#endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */ - -#if defined(MBEDTLS_BASE64_C) - -/* Return 0xff if low <= c <= high, 0 otherwise. - * - * Constant flow with respect to c. - */ -unsigned char mbedtls_ct_uchar_mask_of_range(unsigned char low, - unsigned char high, - unsigned char c) -{ - /* low_mask is: 0 if low <= c, 0x...ff if low > c */ - unsigned low_mask = ((unsigned) c - low) >> 8; - /* high_mask is: 0 if c <= high, 0x...ff if c > high */ - unsigned high_mask = ((unsigned) high - c) >> 8; - return ~(low_mask | high_mask) & 0xff; -} - -#endif /* MBEDTLS_BASE64_C */ - -unsigned mbedtls_ct_size_bool_eq(size_t x, - size_t y) -{ - /* diff = 0 if x == y, non-zero otherwise */ - const size_t diff = x ^ y; - - /* MSVC has a warning about unary minus on unsigned integer types, - * 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 - - /* diff_msb's most significant bit is equal to x != y */ - const size_t diff_msb = (diff | (size_t) -diff); - -#if defined(_MSC_VER) -#pragma warning( pop ) -#endif - - /* diff1 = (x != y) ? 1 : 0 */ - const unsigned diff1 = diff_msb >> (sizeof(diff_msb) * 8 - 1); - - return 1 ^ diff1; -} - -#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) - -unsigned mbedtls_ct_size_gt(size_t x, size_t y) -{ - /* Return the sign bit (1 for negative) of (y - x). */ - return (y - x) >> (sizeof(size_t) * 8 - 1); -} - -#endif /* MBEDTLS_PKCS1_V15 && MBEDTLS_RSA_C && ! MBEDTLS_RSA_ALT */ - -#if defined(MBEDTLS_BIGNUM_C) - -unsigned mbedtls_ct_mpi_uint_lt(const mbedtls_mpi_uint x, - const mbedtls_mpi_uint y) -{ - mbedtls_mpi_uint ret; - mbedtls_mpi_uint cond; - - /* - * Check if the most significant bits (MSB) of the operands are different. - */ - cond = (x ^ y); - /* - * If the MSB are the same then the difference x-y will be negative (and - * have its MSB set to 1 during conversion to unsigned) if and only if x> (sizeof(mbedtls_mpi_uint) * 8 - 1); - - return (unsigned) ret; -} - -#endif /* MBEDTLS_BIGNUM_C */ - -unsigned mbedtls_ct_uint_if(unsigned condition, - unsigned if1, - unsigned if0) -{ - unsigned mask = mbedtls_ct_uint_mask(condition); - return (mask & if1) | (~mask & if0); -} - #if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) void mbedtls_ct_memmove_left(void *start, size_t total, size_t offset) @@ -347,34 +165,6 @@ void mbedtls_ct_memcpy_if(mbedtls_ct_condition_t condition, #if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC) -void mbedtls_ct_memcpy_if_eq(unsigned char *dest, - const unsigned char *src, - size_t len, - size_t c1, - size_t c2) -{ - /* mask = c1 == c2 ? 0xff : 0x00 */ - const size_t equal = mbedtls_ct_size_bool_eq(c1, c2); - - /* dest[i] = c1 == c2 ? src[i] : dest[i] */ - size_t i = 0; -#if defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS) - const uint32_t mask32 = (uint32_t) mbedtls_ct_size_mask(equal); - const unsigned char mask = (unsigned char) mask32 & 0xff; - - for (; (i + 4) <= len; i += 4) { - uint32_t a = mbedtls_get_unaligned_uint32(src + i) & mask32; - uint32_t b = mbedtls_get_unaligned_uint32(dest + i) & ~mask32; - mbedtls_put_unaligned_uint32(dest + i, a | b); - } -#else - const unsigned char mask = (unsigned char) mbedtls_ct_size_mask(equal); -#endif /* MBEDTLS_EFFICIENT_UNALIGNED_ACCESS */ - for (; i < len; i++) { - dest[i] = (src[i] & mask) | (dest[i] & ~mask); - } -} - void mbedtls_ct_memcpy_offset(unsigned char *dest, const unsigned char *src, size_t offset, diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h index f2cb4871b1..362b822a41 100644 --- a/library/constant_time_internal.h +++ b/library/constant_time_internal.h @@ -29,196 +29,6 @@ #include "mbedtls/bignum.h" #endif -#if defined(MBEDTLS_SSL_TLS_C) -#include "ssl_misc.h" -#endif - - -/** Turn a value into a mask: - * - if \p value == 0, return the all-bits 0 mask, aka 0 - * - otherwise, return the all-bits 1 mask, aka (unsigned) -1 - * - * This function can be used to write constant-time code by replacing branches - * with bit operations using masks. - * - * \param value The value to analyze. - * - * \return Zero if \p value is zero, otherwise all-bits-one. - */ -unsigned mbedtls_ct_uint_mask(unsigned value); - -#if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC) - -/** Turn a value into a mask: - * - if \p value == 0, return the all-bits 0 mask, aka 0 - * - otherwise, return the all-bits 1 mask, aka (size_t) -1 - * - * This function can be used to write constant-time code by replacing branches - * with bit operations using masks. - * - * \param value The value to analyze. - * - * \return Zero if \p value is zero, otherwise all-bits-one. - */ -size_t mbedtls_ct_size_mask(size_t value); - -#endif /* MBEDTLS_SSL_SOME_SUITES_USE_MAC */ - -#if defined(MBEDTLS_BIGNUM_C) - -/** Turn a value into a mask: - * - if \p value == 0, return the all-bits 0 mask, aka 0 - * - otherwise, return the all-bits 1 mask, aka (mbedtls_mpi_uint) -1 - * - * This function can be used to write constant-time code by replacing branches - * with bit operations using masks. - * - * \param value The value to analyze. - * - * \return Zero if \p value is zero, otherwise all-bits-one. - */ -mbedtls_mpi_uint mbedtls_ct_mpi_uint_mask(mbedtls_mpi_uint value); - -#endif /* MBEDTLS_BIGNUM_C */ - -#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) - -/** Constant-flow mask generation for "greater or equal" comparison: - * - if \p x >= \p y, return all-bits 1, that is (size_t) -1 - * - otherwise, return all bits 0, that is 0 - * - * This function can be used to write constant-time code by replacing branches - * with bit operations using masks. - * - * \param x The first value to analyze. - * \param y The second value to analyze. - * - * \return All-bits-one if \p x is greater or equal than \p y, - * otherwise zero. - */ -size_t mbedtls_ct_size_mask_ge(size_t x, - size_t y); - -#endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */ - -/** Constant-flow boolean "equal" comparison: - * return x == y - * - * This is equivalent to \p x == \p y, but is likely to be compiled - * to code using bitwise operation rather than a branch. - * - * \param x The first value to analyze. - * \param y The second value to analyze. - * - * \return 1 if \p x equals to \p y, otherwise 0. - */ -unsigned mbedtls_ct_size_bool_eq(size_t x, - size_t y); - -#if defined(MBEDTLS_BIGNUM_C) - -/** Decide if an integer is less than the other, without branches. - * - * This is equivalent to \p x < \p y, but is likely to be compiled - * to code using bitwise operation rather than a branch. - * - * \param x The first value to analyze. - * \param y The second value to analyze. - * - * \return 1 if \p x is less than \p y, otherwise 0. - */ -unsigned mbedtls_ct_mpi_uint_lt(const mbedtls_mpi_uint x, - const mbedtls_mpi_uint y); - -#endif /* MBEDTLS_BIGNUM_C */ - -/** Choose between two integer values without branches. - * - * This is equivalent to `condition ? if1 : if0`, but is likely to be compiled - * to code using bitwise operation rather than a branch. - * - * \param condition Condition to test. - * \param if1 Value to use if \p condition is nonzero. - * \param if0 Value to use if \p condition is zero. - * - * \return \c if1 if \p condition is nonzero, otherwise \c if0. - */ -unsigned mbedtls_ct_uint_if(unsigned condition, - unsigned if1, - unsigned if0); - -#if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC) - -/** Conditional memcpy without branches. - * - * This is equivalent to `if ( c1 == c2 ) memcpy(dest, src, len)`, but is likely - * to be compiled to code using bitwise operation rather than a branch. - * - * \param dest The pointer to conditionally copy to. - * \param src The pointer to copy from. Shouldn't overlap with \p dest. - * \param len The number of bytes to copy. - * \param c1 The first value to analyze in the condition. - * \param c2 The second value to analyze in the condition. - */ -void mbedtls_ct_memcpy_if_eq(unsigned char *dest, - const unsigned char *src, - size_t len, - size_t c1, size_t c2); - -/** Copy data from a secret position with constant flow. - * - * This function copies \p len bytes from \p src_base + \p offset_secret to \p - * dst, with a code flow and memory access pattern that does not depend on \p - * offset_secret, but only on \p offset_min, \p offset_max and \p len. - * Functionally equivalent to `memcpy(dst, src + offset_secret, len)`. - * - * \note This function reads from \p dest, but the value that - * is read does not influence the result and this - * function's behavior is well-defined regardless of the - * contents of the buffers. This may result in false - * positives from static or dynamic analyzers, especially - * if \p dest is not initialized. - * - * \param dest The destination buffer. This must point to a writable - * buffer of at least \p len bytes. - * \param src The base of the source buffer. This must point to a - * readable buffer of at least \p offset_max + \p len - * bytes. Shouldn't overlap with \p dest. - * \param offset The offset in the source buffer from which to copy. - * This must be no less than \p offset_min and no greater - * than \p offset_max. - * \param offset_min The minimal value of \p offset. - * \param offset_max The maximal value of \p offset. - * \param len The number of bytes to copy. - */ -void mbedtls_ct_memcpy_offset(unsigned char *dest, - const unsigned char *src, - size_t offset, - size_t offset_min, - size_t offset_max, - size_t len); - -#endif /* MBEDTLS_SSL_SOME_SUITES_USE_MAC */ - -#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) - -/** Constant-flow "greater than" comparison: - * return x > y - * - * This is equivalent to \p x > \p y, but is likely to be compiled - * to code using bitwise operation rather than a branch. - * - * \param x The first value to analyze. - * \param y The second value to analyze. - * - * \return 1 if \p x greater than \p y, otherwise 0. - */ -unsigned mbedtls_ct_size_gt(size_t x, size_t y); - -#endif /* defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) */ - - - /* The constant-time interface provides various operations that are likely * to result in constant-time code that does not branch or use conditional * instructions for secret data (for secret pointers, this also applies to From 2b4486a01483a4163e12a53b8276d27c1d3fff24 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Wed, 17 May 2023 15:51:59 +0100 Subject: [PATCH 30/82] Rename mbedtls_ct_uint_if_new to mbedtls_ct_uint_if Signed-off-by: Dave Rodgman --- library/bignum.c | 6 +++--- library/constant_time.c | 2 +- library/constant_time_impl.h | 2 +- library/constant_time_internal.h | 2 +- library/rsa.c | 6 +++--- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/library/bignum.c b/library/bignum.c index e8d91631eb..30a30dd925 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -130,7 +130,7 @@ int mbedtls_mpi_safe_cond_assign(mbedtls_mpi *X, mbedtls_ct_condition_t do_assign = mbedtls_ct_bool(assign); - X->s = (int) mbedtls_ct_uint_if_new(do_assign, Y->s, X->s); + X->s = (int) mbedtls_ct_uint_if(do_assign, Y->s, X->s); mbedtls_mpi_core_cond_assign(X->p, Y->p, Y->n, do_assign); @@ -168,8 +168,8 @@ int mbedtls_mpi_safe_cond_swap(mbedtls_mpi *X, MBEDTLS_MPI_CHK(mbedtls_mpi_grow(Y, X->n)); s = X->s; - X->s = (int) mbedtls_ct_uint_if_new(do_swap, Y->s, X->s); - Y->s = (int) mbedtls_ct_uint_if_new(do_swap, s, Y->s); + X->s = (int) mbedtls_ct_uint_if(do_swap, Y->s, X->s); + Y->s = (int) mbedtls_ct_uint_if(do_swap, s, Y->s); mbedtls_mpi_core_cond_swap(X->p, Y->p, X->n, do_swap); diff --git a/library/constant_time.c b/library/constant_time.c index c86316b008..e11d88e6b8 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -126,7 +126,7 @@ void mbedtls_ct_memmove_left(void *start, size_t total, size_t offset) for (size_t n = 0; n < total - 1; n++) { unsigned char current = buf[n]; unsigned char next = buf[n+1]; - buf[n] = mbedtls_ct_uint_if_new(no_op, current, next); + buf[n] = mbedtls_ct_uint_if(no_op, current, next); } buf[total-1] = mbedtls_ct_uint_if0(no_op, buf[total-1]); } diff --git a/library/constant_time_impl.h b/library/constant_time_impl.h index 149cf75068..b73f92ee92 100644 --- a/library/constant_time_impl.h +++ b/library/constant_time_impl.h @@ -191,7 +191,7 @@ static inline size_t mbedtls_ct_size_if(mbedtls_ct_condition_t condition, return (size_t) mbedtls_ct_if(condition, (mbedtls_ct_uint_t) if1, (mbedtls_ct_uint_t) if0); } -static inline unsigned mbedtls_ct_uint_if_new(mbedtls_ct_condition_t condition, +static inline unsigned mbedtls_ct_uint_if(mbedtls_ct_condition_t condition, unsigned if1, unsigned if0) { diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h index 362b822a41..09de92f173 100644 --- a/library/constant_time_internal.h +++ b/library/constant_time_internal.h @@ -285,7 +285,7 @@ static inline size_t mbedtls_ct_size_if(mbedtls_ct_condition_t condition, * * \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise \c if0. */ -static inline unsigned mbedtls_ct_uint_if_new(mbedtls_ct_condition_t condition, +static inline unsigned mbedtls_ct_uint_if(mbedtls_ct_condition_t condition, unsigned if1, unsigned if0); diff --git a/library/rsa.c b/library/rsa.c index 9d67ef7d94..44ff3d2c0a 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -144,7 +144,7 @@ static int mbedtls_ct_rsaes_pkcs1_v15_unpadding(unsigned char *input, * buffer. Do it without branches to avoid leaking the padding * validity through timing. RSA keys are small enough that all the * size_t values involved fit in unsigned int. */ - plaintext_size = mbedtls_ct_uint_if_new( + plaintext_size = mbedtls_ct_uint_if( bad, (unsigned) plaintext_max_size, (unsigned) (ilen - pad_count - 3)); @@ -158,7 +158,7 @@ static int mbedtls_ct_rsaes_pkcs1_v15_unpadding(unsigned char *input, * - OUTPUT_TOO_LARGE if the padding is good but the decrypted * plaintext does not fit in the output buffer. * - 0 if the padding is correct. */ - ret = -(int) mbedtls_ct_uint_if_new( + ret = -(int) mbedtls_ct_uint_if( bad, (unsigned) (-(MBEDTLS_ERR_RSA_INVALID_PADDING)), mbedtls_ct_uint_if0( @@ -178,7 +178,7 @@ static int mbedtls_ct_rsaes_pkcs1_v15_unpadding(unsigned char *input, * Copy anyway to avoid revealing the length through timing, because * revealing the length is as bad as revealing the padding validity * for a Bleichenbacher attack. */ - plaintext_size = mbedtls_ct_uint_if_new(output_too_large, + plaintext_size = mbedtls_ct_uint_if(output_too_large, (unsigned) plaintext_max_size, (unsigned) plaintext_size); From 8f5e5c18d8bc75212b4b9f48178e393d9a30f0d2 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Tue, 16 May 2023 13:30:15 +0100 Subject: [PATCH 31/82] Make memmove_left more efficient Signed-off-by: Dave Rodgman --- library/constant_time.c | 39 +++++++++++++------ .../suites/test_suite_constant_time.function | 5 ++- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index e11d88e6b8..cf1f2b8c9d 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -117,18 +117,35 @@ int mbedtls_ct_memcmp(const void *a, void mbedtls_ct_memmove_left(void *start, size_t total, size_t offset) { - volatile unsigned char *buf = start; + /* Iterate over the array, reading each byte once and writing each byte once. */ for (size_t i = 0; i < total; i++) { - mbedtls_ct_condition_t no_op = mbedtls_ct_bool_gt(total - offset, i); - /* The first `total - offset` passes are a no-op. The last - * `offset` passes shift the data one byte to the left and - * zero out the last byte. */ - for (size_t n = 0; n < total - 1; n++) { - unsigned char current = buf[n]; - unsigned char next = buf[n+1]; - buf[n] = mbedtls_ct_uint_if(no_op, current, next); - } - buf[total-1] = mbedtls_ct_uint_if0(no_op, buf[total-1]); + /* Each iteration, read one byte, and write it to start[i]. + * + * The source address will either be the "true" source address, if it's in the range + * where data is getting moved, or (if the source address is off the end of the + * array), it will wrap back to the start. + * + * If the source address is out of range, mask it to zero. + */ + + // The address that we will read from + // TODO: if offset is marked as secret, this upsets Memsan. + size_t j = i + offset; + + // Is the address off the end of the array? + mbedtls_ct_condition_t not_dummy = mbedtls_ct_bool_lt(j, total); + + // Bring read address into range + j = j % total; + + // Read a byte + uint8_t b = ((uint8_t*)start)[j]; + + // Set it to zero if it's out of range + b = mbedtls_ct_uint_if0(not_dummy, b); + + // Write the byte to start[i] + ((uint8_t*)start)[i] = b; } } diff --git a/tests/suites/test_suite_constant_time.function b/tests/suites/test_suite_constant_time.function index c9bdf7e344..ba31c96d4c 100644 --- a/tests/suites/test_suite_constant_time.function +++ b/tests/suites/test_suite_constant_time.function @@ -301,10 +301,11 @@ void mbedtls_ct_memmove_left(int len, int offset) buf_expected[i] = buf[i]; } - TEST_CF_SECRET(&o, sizeof(o)); + //Note: Marking o as secret causes false positives from Memsan + //TEST_CF_SECRET(&o, sizeof(o)); TEST_CF_SECRET(buf, l); mbedtls_ct_memmove_left(buf, l, o); - TEST_CF_PUBLIC(&o, sizeof(o)); + //TEST_CF_PUBLIC(&o, sizeof(o)); TEST_CF_PUBLIC(buf, l); if (l > 0) { From fe76af20aa8ffd7c5dc05cd7b1a8ccaaab68055d Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Wed, 17 May 2023 17:45:17 +0100 Subject: [PATCH 32/82] Improve use of compiler_opaque Signed-off-by: Dave Rodgman --- library/constant_time_impl.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/library/constant_time_impl.h b/library/constant_time_impl.h index b73f92ee92..b4b3917cd7 100644 --- a/library/constant_time_impl.h +++ b/library/constant_time_impl.h @@ -151,7 +151,7 @@ static inline mbedtls_ct_condition_t mbedtls_ct_bool_lt(mbedtls_ct_uint_t x, mbe static inline mbedtls_ct_condition_t mbedtls_ct_bool_ne(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y) { /* diff = 0 if x == y, non-zero otherwise */ - const mbedtls_ct_uint_t diff = mbedtls_ct_compiler_opaque(x) ^ y; + const mbedtls_ct_uint_t diff = mbedtls_ct_compiler_opaque(x) ^ mbedtls_ct_compiler_opaque(y); /* all ones if x != y, 0 otherwise */ return mbedtls_ct_bool(diff); @@ -213,12 +213,12 @@ static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if(mbedtls_ct_condition_t con static inline size_t mbedtls_ct_size_if0(mbedtls_ct_condition_t condition, size_t if1) { - return (size_t) (mbedtls_ct_compiler_opaque(condition) & if1); + return (size_t) (condition & if1); } static inline unsigned mbedtls_ct_uint_if0(mbedtls_ct_condition_t condition, unsigned if1) { - return (unsigned) (mbedtls_ct_compiler_opaque(condition) & if1); + return (unsigned) (condition & if1); } #if defined(MBEDTLS_BIGNUM_C) @@ -226,7 +226,7 @@ static inline unsigned mbedtls_ct_uint_if0(mbedtls_ct_condition_t condition, uns static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if0(mbedtls_ct_condition_t condition, mbedtls_mpi_uint if1) { - return (mbedtls_mpi_uint) (mbedtls_ct_compiler_opaque(condition) & if1); + return (mbedtls_mpi_uint) (condition & if1); } #endif /* MBEDTLS_BIGNUM_C */ @@ -252,24 +252,24 @@ static inline mbedtls_ct_condition_t mbedtls_ct_bool_le(mbedtls_ct_uint_t x, static inline mbedtls_ct_condition_t mbedtls_ct_bool_xor(mbedtls_ct_condition_t x, mbedtls_ct_condition_t y) { - return (mbedtls_ct_condition_t) (mbedtls_ct_compiler_opaque(x) ^ mbedtls_ct_compiler_opaque(y)); + return (mbedtls_ct_condition_t) (x ^ y); } static inline mbedtls_ct_condition_t mbedtls_ct_bool_and(mbedtls_ct_condition_t x, mbedtls_ct_condition_t y) { - return (mbedtls_ct_condition_t) (mbedtls_ct_compiler_opaque(x) & mbedtls_ct_compiler_opaque(y)); + return (mbedtls_ct_condition_t) (x & y); } static inline mbedtls_ct_condition_t mbedtls_ct_bool_or(mbedtls_ct_condition_t x, mbedtls_ct_condition_t y) { - return (mbedtls_ct_condition_t) (mbedtls_ct_compiler_opaque(x) | mbedtls_ct_compiler_opaque(y)); + return (mbedtls_ct_condition_t) (x | y); } static inline mbedtls_ct_condition_t mbedtls_ct_bool_not(mbedtls_ct_condition_t x) { - return (mbedtls_ct_condition_t) (~mbedtls_ct_compiler_opaque(x)); + return (mbedtls_ct_condition_t) (~x); } #endif /* MBEDTLS_CONSTANT_TIME_IMPL_H */ From 585f7f776d06ea4fe1af56edd94baf751fb6cc62 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Wed, 17 May 2023 17:45:33 +0100 Subject: [PATCH 33/82] Whitespace etc Signed-off-by: Dave Rodgman --- library/constant_time.c | 8 ++++---- library/constant_time_impl.h | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index cf1f2b8c9d..e8ed086054 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -139,13 +139,13 @@ void mbedtls_ct_memmove_left(void *start, size_t total, size_t offset) j = j % total; // Read a byte - uint8_t b = ((uint8_t*)start)[j]; + uint8_t b = ((uint8_t *) start)[j]; // Set it to zero if it's out of range b = mbedtls_ct_uint_if0(not_dummy, b); // Write the byte to start[i] - ((uint8_t*)start)[i] = b; + ((uint8_t *) start)[i] = b; } } @@ -192,8 +192,8 @@ void mbedtls_ct_memcpy_offset(unsigned char *dest, size_t offsetval; for (offsetval = offset_min; offsetval <= offset_max; offsetval++) { - mbedtls_ct_memcpy_if(mbedtls_ct_bool_eq(offsetval, offset), dest, src + offsetval, NULL, - len); + mbedtls_ct_memcpy_if(mbedtls_ct_bool_eq(offsetval, offset), dest, src + offsetval, NULL, + len); } } diff --git a/library/constant_time_impl.h b/library/constant_time_impl.h index b4b3917cd7..44682c0497 100644 --- a/library/constant_time_impl.h +++ b/library/constant_time_impl.h @@ -178,12 +178,6 @@ static inline unsigned char mbedtls_ct_uchar_in_range_if(unsigned char low, * Everything below here is trivial wrapper functions */ -static inline mbedtls_ct_condition_t mbedtls_ct_bool_eq(mbedtls_ct_uint_t x, - mbedtls_ct_uint_t y) -{ - return ~mbedtls_ct_bool_ne(x, y); -} - static inline size_t mbedtls_ct_size_if(mbedtls_ct_condition_t condition, size_t if1, size_t if0) @@ -200,8 +194,8 @@ static inline unsigned mbedtls_ct_uint_if(mbedtls_ct_condition_t condition, #if defined(MBEDTLS_BIGNUM_C) -static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if(mbedtls_ct_condition_t condition, \ - mbedtls_mpi_uint if1, \ +static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if(mbedtls_ct_condition_t condition, + mbedtls_mpi_uint if1, mbedtls_mpi_uint if0) { return (mbedtls_mpi_uint) mbedtls_ct_if(condition, @@ -231,6 +225,12 @@ static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if0(mbedtls_ct_condition_t co #endif /* MBEDTLS_BIGNUM_C */ +static inline mbedtls_ct_condition_t mbedtls_ct_bool_eq(mbedtls_ct_uint_t x, + mbedtls_ct_uint_t y) +{ + return ~mbedtls_ct_bool_ne(x, y); +} + static inline mbedtls_ct_condition_t mbedtls_ct_bool_gt(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y) { From 1e8b6ac09c8076d5a8938612679b2357f4a088ac Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Thu, 18 May 2023 11:23:59 +0100 Subject: [PATCH 34/82] Improve tests for mbedtls_ct_uchar_in_range_if Remove tests from base64. Improve coverage in constant_time tests. Signed-off-by: Dave Rodgman --- tests/suites/test_suite_base64.data | 24 --- tests/suites/test_suite_base64.function | 20 --- tests/suites/test_suite_constant_time.data | 153 ++++++++++++++++-- .../suites/test_suite_constant_time.function | 27 ++-- 4 files changed, 151 insertions(+), 73 deletions(-) diff --git a/tests/suites/test_suite_base64.data b/tests/suites/test_suite_base64.data index 555666807d..3999e73bf9 100644 --- a/tests/suites/test_suite_base64.data +++ b/tests/suites/test_suite_base64.data @@ -1,27 +1,3 @@ -mask_of_range empty (1..0) -mask_of_range:1:0 - -mask_of_range empty (255..0) -mask_of_range:255:0 - -mask_of_range empty (42..7) -mask_of_range:42:7 - -mask_of_range 0..0 -mask_of_range:0:0 - -mask_of_range 42..42 -mask_of_range:42:42 - -mask_of_range 255..255 -mask_of_range:255:255 - -mask_of_range 0..255 -mask_of_range:0:255 - -mask_of_range 'A'..'Z' -mask_of_range:65:90 - enc_char (all digits) enc_chars: diff --git a/tests/suites/test_suite_base64.function b/tests/suites/test_suite_base64.function index d9ac82cd05..052d1d097b 100644 --- a/tests/suites/test_suite_base64.function +++ b/tests/suites/test_suite_base64.function @@ -15,26 +15,6 @@ static const char base64_digits[] = * END_DEPENDENCIES */ -/* BEGIN_CASE */ -void mask_of_range(int low_arg, int high_arg) -{ - unsigned char low = low_arg, high = high_arg; - unsigned c; - for (c = 0; c <= 0xff; c++) { - mbedtls_test_set_step(c); - TEST_CF_SECRET(&c, sizeof(c)); - unsigned char m = mbedtls_ct_uchar_in_range_if(low, high, c, 0xff); - TEST_CF_PUBLIC(&c, sizeof(c)); - TEST_CF_PUBLIC(&m, sizeof(m)); - if (low <= c && c <= high) { - TEST_EQUAL(m, 0xff); - } else { - TEST_EQUAL(m, 0); - } - } -} -/* END_CASE */ - /* BEGIN_CASE depends_on:MBEDTLS_TEST_HOOKS */ void enc_chars() { diff --git a/tests/suites/test_suite_constant_time.data b/tests/suites/test_suite_constant_time.data index f692176cda..1b0b964dad 100644 --- a/tests/suites/test_suite_constant_time.data +++ b/tests/suites/test_suite_constant_time.data @@ -283,29 +283,149 @@ mbedtls_ct_bool_xxx:"256":"138" mbedtls_ct_bool_xxx 6 6 mbedtls_ct_bool_xxx:"0x6":"0x6" -mbedtls_ct_uchar_in_range_if 0 0 0 0 -mbedtls_ct_uchar_in_range_if:0:0:0:0 +mbedtls_ct_uchar_in_range_if 0 0 0 +mbedtls_ct_uchar_in_range_if:0:0:0 -mbedtls_ct_uchar_in_range_if 0 100 2 2 -mbedtls_ct_uchar_in_range_if:0:100:2:2 +mbedtls_ct_uchar_in_range_if 0 0 100 +mbedtls_ct_uchar_in_range_if:0:0:100 -mbedtls_ct_uchar_in_range_if 0 100 2 0 -mbedtls_ct_uchar_in_range_if:0:100:2:0 +mbedtls_ct_uchar_in_range_if 0 0 255 +mbedtls_ct_uchar_in_range_if:0:0:255 -mbedtls_ct_uchar_in_range_if 0 100 200 2 -mbedtls_ct_uchar_in_range_if:0:100:200:2 +mbedtls_ct_uchar_in_range_if 0 65 0 +mbedtls_ct_uchar_in_range_if:0:65:0 -mbedtls_ct_uchar_in_range_if 0 255 0 2 -mbedtls_ct_uchar_in_range_if:0:255:0:2 +mbedtls_ct_uchar_in_range_if 0 65 100 +mbedtls_ct_uchar_in_range_if:0:65:100 -mbedtls_ct_uchar_in_range_if 0 255 100 2 -mbedtls_ct_uchar_in_range_if:0:255:100:2 +mbedtls_ct_uchar_in_range_if 0 65 255 +mbedtls_ct_uchar_in_range_if:0:65:255 -mbedtls_ct_uchar_in_range_if 0 255 255 2 -mbedtls_ct_uchar_in_range_if:0:255:255:2 +mbedtls_ct_uchar_in_range_if 0 90 0 +mbedtls_ct_uchar_in_range_if:0:90:0 -mbedtls_ct_uchar_in_range_if 255 255 255 255 -mbedtls_ct_uchar_in_range_if:255:255:255:255 +mbedtls_ct_uchar_in_range_if 0 90 100 +mbedtls_ct_uchar_in_range_if:0:90:100 + +mbedtls_ct_uchar_in_range_if 0 90 255 +mbedtls_ct_uchar_in_range_if:0:90:255 + +mbedtls_ct_uchar_in_range_if 0 255 0 +mbedtls_ct_uchar_in_range_if:0:255:0 + +mbedtls_ct_uchar_in_range_if 0 255 100 +mbedtls_ct_uchar_in_range_if:0:255:100 + +mbedtls_ct_uchar_in_range_if 0 255 255 +mbedtls_ct_uchar_in_range_if:0:255:255 + +mbedtls_ct_uchar_in_range_if 65 0 0 +mbedtls_ct_uchar_in_range_if:65:0:0 + +mbedtls_ct_uchar_in_range_if 65 0 100 +mbedtls_ct_uchar_in_range_if:65:0:100 + +mbedtls_ct_uchar_in_range_if 65 0 255 +mbedtls_ct_uchar_in_range_if:65:0:255 + +mbedtls_ct_uchar_in_range_if 65 65 0 +mbedtls_ct_uchar_in_range_if:65:65:0 + +mbedtls_ct_uchar_in_range_if 65 65 100 +mbedtls_ct_uchar_in_range_if:65:65:100 + +mbedtls_ct_uchar_in_range_if 65 65 255 +mbedtls_ct_uchar_in_range_if:65:65:255 + +mbedtls_ct_uchar_in_range_if 65 90 0 +mbedtls_ct_uchar_in_range_if:65:90:0 + +mbedtls_ct_uchar_in_range_if 65 90 100 +mbedtls_ct_uchar_in_range_if:65:90:100 + +mbedtls_ct_uchar_in_range_if 65 90 255 +mbedtls_ct_uchar_in_range_if:65:90:255 + +mbedtls_ct_uchar_in_range_if 65 255 0 +mbedtls_ct_uchar_in_range_if:65:255:0 + +mbedtls_ct_uchar_in_range_if 65 255 100 +mbedtls_ct_uchar_in_range_if:65:255:100 + +mbedtls_ct_uchar_in_range_if 65 255 255 +mbedtls_ct_uchar_in_range_if:65:255:255 + +mbedtls_ct_uchar_in_range_if 90 0 0 +mbedtls_ct_uchar_in_range_if:90:0:0 + +mbedtls_ct_uchar_in_range_if 90 0 100 +mbedtls_ct_uchar_in_range_if:90:0:100 + +mbedtls_ct_uchar_in_range_if 90 0 255 +mbedtls_ct_uchar_in_range_if:90:0:255 + +mbedtls_ct_uchar_in_range_if 90 65 0 +mbedtls_ct_uchar_in_range_if:90:65:0 + +mbedtls_ct_uchar_in_range_if 90 65 100 +mbedtls_ct_uchar_in_range_if:90:65:100 + +mbedtls_ct_uchar_in_range_if 90 65 255 +mbedtls_ct_uchar_in_range_if:90:65:255 + +mbedtls_ct_uchar_in_range_if 90 90 0 +mbedtls_ct_uchar_in_range_if:90:90:0 + +mbedtls_ct_uchar_in_range_if 90 90 100 +mbedtls_ct_uchar_in_range_if:90:90:100 + +mbedtls_ct_uchar_in_range_if 90 90 255 +mbedtls_ct_uchar_in_range_if:90:90:255 + +mbedtls_ct_uchar_in_range_if 90 255 0 +mbedtls_ct_uchar_in_range_if:90:255:0 + +mbedtls_ct_uchar_in_range_if 90 255 100 +mbedtls_ct_uchar_in_range_if:90:255:100 + +mbedtls_ct_uchar_in_range_if 90 255 255 +mbedtls_ct_uchar_in_range_if:90:255:255 + +mbedtls_ct_uchar_in_range_if 255 0 0 +mbedtls_ct_uchar_in_range_if:255:0:0 + +mbedtls_ct_uchar_in_range_if 255 0 100 +mbedtls_ct_uchar_in_range_if:255:0:100 + +mbedtls_ct_uchar_in_range_if 255 0 255 +mbedtls_ct_uchar_in_range_if:255:0:255 + +mbedtls_ct_uchar_in_range_if 255 65 0 +mbedtls_ct_uchar_in_range_if:255:65:0 + +mbedtls_ct_uchar_in_range_if 255 65 100 +mbedtls_ct_uchar_in_range_if:255:65:100 + +mbedtls_ct_uchar_in_range_if 255 65 255 +mbedtls_ct_uchar_in_range_if:255:65:255 + +mbedtls_ct_uchar_in_range_if 255 90 0 +mbedtls_ct_uchar_in_range_if:255:90:0 + +mbedtls_ct_uchar_in_range_if 255 90 100 +mbedtls_ct_uchar_in_range_if:255:90:100 + +mbedtls_ct_uchar_in_range_if 255 90 255 +mbedtls_ct_uchar_in_range_if:255:90:255 + +mbedtls_ct_uchar_in_range_if 255 255 0 +mbedtls_ct_uchar_in_range_if:255:255:0 + +mbedtls_ct_uchar_in_range_if 255 255 100 +mbedtls_ct_uchar_in_range_if:255:255:100 + +mbedtls_ct_uchar_in_range_if 255 255 255 +mbedtls_ct_uchar_in_range_if:255:255:255 mbedtls_ct_if 0x0 0x0 0x0 mbedtls_ct_if:"0x0":"0x0":"0x0" @@ -579,4 +699,3 @@ mbedtls_ct_memmove_left:16:15 mbedtls_ct_memmove_left 16 16 mbedtls_ct_memmove_left:16:16 - diff --git a/tests/suites/test_suite_constant_time.function b/tests/suites/test_suite_constant_time.function index ba31c96d4c..ac4dd7ab78 100644 --- a/tests/suites/test_suite_constant_time.function +++ b/tests/suites/test_suite_constant_time.function @@ -92,22 +92,25 @@ void mbedtls_ct_bool_xxx(char *x_str, char *y_str) /* END_CASE */ /* BEGIN_CASE depends_on:MBEDTLS_BASE64_C */ -void mbedtls_ct_uchar_in_range_if(int li, int hi, int xi, int ti) +void mbedtls_ct_uchar_in_range_if(int li, int hi, int ti) { - unsigned char l = li, h = hi, x = xi, t = ti; - unsigned char expected = (x >= l) && (x <= h) ? t : 0; + unsigned char l = li, h = hi, t = ti; - TEST_CF_SECRET(&x, sizeof(x)); - TEST_CF_SECRET(&l, sizeof(l)); - TEST_CF_SECRET(&h, sizeof(h)); - TEST_CF_SECRET(&t, sizeof(t)); + for (unsigned x = 0; x <= 255; x++) { + unsigned char expected = (x >= l) && (x <= h) ? t : 0; - TEST_EQUAL(mbedtls_ct_uchar_in_range_if(l, h, x, t), expected); + TEST_CF_SECRET(&x, sizeof(x)); + TEST_CF_SECRET(&l, sizeof(l)); + TEST_CF_SECRET(&h, sizeof(h)); + TEST_CF_SECRET(&t, sizeof(t)); - TEST_CF_PUBLIC(&x, sizeof(x)); - TEST_CF_PUBLIC(&l, sizeof(l)); - TEST_CF_PUBLIC(&h, sizeof(h)); - TEST_CF_PUBLIC(&t, sizeof(t)); + TEST_EQUAL(mbedtls_ct_uchar_in_range_if(l, h, (unsigned char) x, t), expected); + + TEST_CF_PUBLIC(&x, sizeof(x)); + TEST_CF_PUBLIC(&l, sizeof(l)); + TEST_CF_PUBLIC(&h, sizeof(h)); + TEST_CF_PUBLIC(&t, sizeof(t)); + } } /* END_CASE */ From 2c76484005c54d438734270d5616c5e87d3011e0 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Thu, 18 May 2023 13:28:21 +0100 Subject: [PATCH 35/82] Fix non-opaque use of mbedtls_ct_condition_t Signed-off-by: Dave Rodgman --- library/bignum.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/bignum.c b/library/bignum.c index 30a30dd925..8ad7258582 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -96,8 +96,8 @@ int mbedtls_mpi_lt_mpi_ct(const mbedtls_mpi *X, /* This is used to conditionally swap the pointers in const time */ void * const p[2] = { X->p, Y->p }; - mbedtls_ct_condition_t lt = mbedtls_mpi_core_lt_ct( - p[X_is_negative & 1], p[(X_is_negative & 1) ^ 1], X->n); + size_t i = mbedtls_ct_size_if0(X_is_negative, 1); + mbedtls_ct_condition_t lt = mbedtls_mpi_core_lt_ct(p[i], p[i ^ 1], X->n); result = mbedtls_ct_bool_or(result, mbedtls_ct_bool_and(mbedtls_ct_bool_not(cond), lt)); From 3108645d67e7bd0eae2877fa7f5018f520817c1e Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Thu, 18 May 2023 13:47:13 +0100 Subject: [PATCH 36/82] Document and test that memcpy_if may have src == dest Signed-off-by: Dave Rodgman --- library/constant_time_internal.h | 8 ++++--- .../suites/test_suite_constant_time.function | 24 +++++++++++++++++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h index 09de92f173..0cb3f2a346 100644 --- a/library/constant_time_internal.h +++ b/library/constant_time_internal.h @@ -417,9 +417,11 @@ void mbedtls_ct_memmove_left(void *start, * * \param condition The condition * \param dest Secret. Destination pointer. - * \param src1 Secret. Pointer to copy from (if \p condition == MBEDTLS_CT_TRUE). Shouldn't overlap with \p dest. + * \param src1 Secret. Pointer to copy from (if \p condition == MBEDTLS_CT_TRUE). + * This may be equal to \p dest, but may not overlap in other ways. * \param src2 Secret (contents only - may branch to test if src2 == NULL). - * Pointer to copy from (if \p condition == MBEDTLS_CT_FALSE and \p src2 is not NULL). Shouldn't overlap with \p dest. May be NULL. + * Pointer to copy from (if \p condition == MBEDTLS_CT_FALSE and \p src2 is not NULL). May be NULL. + * This may be equal to \p dest, but may not overlap it in other ways. It may overlap with \p src1. * \param len Number of bytes to copy. */ void mbedtls_ct_memcpy_if(mbedtls_ct_condition_t condition, @@ -450,7 +452,7 @@ void mbedtls_ct_memcpy_if(mbedtls_ct_condition_t condition, * buffer of at least \p len bytes. * \param src Secret. The base of the source buffer. This must point to a * readable buffer of at least \p offset_max + \p len - * bytes. Shouldn't overlap with \p dest. + * bytes. Shouldn't overlap with \p dest * \param offset Secret. The offset in the source buffer from which to copy. * This must be no less than \p offset_min and no greater * than \p offset_max. diff --git a/tests/suites/test_suite_constant_time.function b/tests/suites/test_suite_constant_time.function index ac4dd7ab78..2fafa948d6 100644 --- a/tests/suites/test_suite_constant_time.function +++ b/tests/suites/test_suite_constant_time.function @@ -224,6 +224,7 @@ void mbedtls_ct_memcpy_if(int eq, int size, int offset) ASSERT_ALLOC(result, size + offset); ASSERT_ALLOC(expected, size + offset); + /* Apply offset to result only */ for (int i = 0; i < size + offset; i++) { src[i] = 1; result[i] = 0xff; @@ -243,6 +244,8 @@ void mbedtls_ct_memcpy_if(int eq, int size, int offset) ASSERT_COMPARE(expected, size, result + offset, size); + + /* Apply offset to src only */ for (int i = 0; i < size + offset; i++) { src[i] = 1; result[i] = 0xff; @@ -261,6 +264,8 @@ void mbedtls_ct_memcpy_if(int eq, int size, int offset) ASSERT_COMPARE(expected, size, result, size); + + /* Apply offset to src and src2 */ for (int i = 0; i < size + offset; i++) { src[i] = 1; src2[i] = 2; @@ -281,6 +286,25 @@ void mbedtls_ct_memcpy_if(int eq, int size, int offset) TEST_CF_PUBLIC(result, size + offset); ASSERT_COMPARE(expected, size, result, size); + + + /* result == src == dest */ + for (int i = 0; i < size + offset; i++) { + src[i] = 2; + expected[i] = 2; + } + + TEST_CF_SECRET(&secret_eq, sizeof(secret_eq)); + TEST_CF_SECRET(src, size + offset); + TEST_CF_SECRET(result, size + offset); + + mbedtls_ct_memcpy_if(mbedtls_ct_bool(secret_eq), src + offset, src + offset, src + offset, size); + + TEST_CF_PUBLIC(&secret_eq, sizeof(secret_eq)); + TEST_CF_PUBLIC(src, size + offset); + TEST_CF_PUBLIC(result, size + offset); + + ASSERT_COMPARE(expected, size, src + offset, size); exit: mbedtls_free(src); mbedtls_free(src2); From 3b25c40f5296a284de45d402e050a3454de47fd9 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Thu, 18 May 2023 14:41:06 +0100 Subject: [PATCH 37/82] Fix RSA perf regression Signed-off-by: Dave Rodgman --- library/bignum_core.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/library/bignum_core.c b/library/bignum_core.c index b41d046a54..5e19590798 100644 --- a/library/bignum_core.c +++ b/library/bignum_core.c @@ -211,8 +211,14 @@ void mbedtls_mpi_core_cond_assign(mbedtls_mpi_uint *X, return; } - mbedtls_ct_memcpy_if(assign, (unsigned char *) X, (unsigned char *) A, NULL, - limbs * sizeof(mbedtls_mpi_uint)); + /* This function is very performance-sensitive for RSA. For this reason + * we have the loop below, instead of calling mbedtls_ct_memcpy_if + * (this is more optimal since here we don't have to handle the case where + * we copy awkwardly sized data). + */ + for (size_t i = 0; i < limbs; i++) { + X[i] = mbedtls_ct_mpi_uint_if(assign, A[i], X[i]); + } } void mbedtls_mpi_core_cond_swap(mbedtls_mpi_uint *X, From 1947088f91254b1d36cfcc18b21893e6572c963d Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Thu, 18 May 2023 15:17:21 +0100 Subject: [PATCH 38/82] Remove references to rsa.h and ssl_misc.h from constant_time.c Signed-off-by: Dave Rodgman --- library/constant_time.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index e8ed086054..90fbcf2d27 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -30,14 +30,6 @@ #include "mbedtls/error.h" #include "mbedtls/platform_util.h" -#if defined(MBEDTLS_SSL_TLS_C) -#include "ssl_misc.h" -#endif - -#if defined(MBEDTLS_RSA_C) -#include "mbedtls/rsa.h" -#endif - #include #if defined(MBEDTLS_USE_PSA_CRYPTO) #define PSA_TO_MBEDTLS_ERR(status) PSA_TO_MBEDTLS_ERR_LIST(status, \ @@ -180,8 +172,6 @@ void mbedtls_ct_memcpy_if(mbedtls_ct_condition_t condition, } } -#if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC) - void mbedtls_ct_memcpy_offset(unsigned char *dest, const unsigned char *src, size_t offset, @@ -197,8 +187,6 @@ void mbedtls_ct_memcpy_offset(unsigned char *dest, } } -#endif /* MBEDTLS_SSL_SOME_SUITES_USE_MAC */ - #if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) void mbedtls_ct_zeroize_if(mbedtls_ct_condition_t condition, void *buf, size_t len) From 0fec4395ac292d68b86644069c9f1ee2deb071ab Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Thu, 18 May 2023 15:24:36 +0100 Subject: [PATCH 39/82] Move base64 test interfaces into base64_internal.h Signed-off-by: Dave Rodgman --- include/mbedtls/base64.h | 29 ------------- library/base64.c | 1 + library/base64_internal.h | 57 +++++++++++++++++++++++++ tests/suites/test_suite_base64.function | 1 + 4 files changed, 59 insertions(+), 29 deletions(-) create mode 100644 library/base64_internal.h diff --git a/include/mbedtls/base64.h b/include/mbedtls/base64.h index e82c270eab..635be713d8 100644 --- a/include/mbedtls/base64.h +++ b/include/mbedtls/base64.h @@ -87,35 +87,6 @@ int mbedtls_base64_self_test(int verbose); #endif /* MBEDTLS_SELF_TEST */ -#if defined(MBEDTLS_TEST_HOOKS) - -/** Given a value in the range 0..63, return the corresponding Base64 digit. - * - * The implementation assumes that letters are consecutive (e.g. ASCII - * but not EBCDIC). - * - * \param value A value in the range 0..63. - * - * \return A base64 digit converted from \p value. - */ -unsigned char mbedtls_ct_base64_enc_char(unsigned char value); - -/** Given a Base64 digit, return its value. - * - * If c is not a Base64 digit ('A'..'Z', 'a'..'z', '0'..'9', '+' or '/'), - * return -1. - * - * The implementation assumes that letters are consecutive (e.g. ASCII - * but not EBCDIC). - * - * \param c A base64 digit. - * - * \return The value of the base64 digit \p c. - */ -signed char mbedtls_ct_base64_dec_value(unsigned char c); - -#endif /* MBEDTLS_TEST_HOOKS */ - #ifdef __cplusplus } #endif diff --git a/library/base64.c b/library/base64.c index 2b623b9bc0..fa22e53752 100644 --- a/library/base64.c +++ b/library/base64.c @@ -24,6 +24,7 @@ #if defined(MBEDTLS_BASE64_C) #include "mbedtls/base64.h" +#include "base64_internal.h" #include "constant_time_internal.h" #include diff --git a/library/base64_internal.h b/library/base64_internal.h new file mode 100644 index 0000000000..f9f56d78db --- /dev/null +++ b/library/base64_internal.h @@ -0,0 +1,57 @@ +/** + * \file base64_internal.h + * + * \brief RFC 1521 base64 encoding/decoding: interfaces for invasive testing + */ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MBEDTLS_BASE64_INTERNAL +#define MBEDTLS_BASE64_INTERNAL + +#include "common.h" + +#if defined(MBEDTLS_TEST_HOOKS) + +/** Given a value in the range 0..63, return the corresponding Base64 digit. + * + * The implementation assumes that letters are consecutive (e.g. ASCII + * but not EBCDIC). + * + * \param value A value in the range 0..63. + * + * \return A base64 digit converted from \p value. + */ +unsigned char mbedtls_ct_base64_enc_char(unsigned char value); + +/** Given a Base64 digit, return its value. + * + * If c is not a Base64 digit ('A'..'Z', 'a'..'z', '0'..'9', '+' or '/'), + * return -1. + * + * The implementation assumes that letters are consecutive (e.g. ASCII + * but not EBCDIC). + * + * \param c A base64 digit. + * + * \return The value of the base64 digit \p c. + */ +signed char mbedtls_ct_base64_dec_value(unsigned char c); + +#endif /* MBEDTLS_TEST_HOOKS */ + +#endif /* MBEDTLS_BASE64_INTERNAL */ diff --git a/tests/suites/test_suite_base64.function b/tests/suites/test_suite_base64.function index 052d1d097b..e351ad8a25 100644 --- a/tests/suites/test_suite_base64.function +++ b/tests/suites/test_suite_base64.function @@ -1,5 +1,6 @@ /* BEGIN_HEADER */ #include "mbedtls/base64.h" +#include "base64_internal.h" #include "constant_time_internal.h" #include From ec85b8546816cbbf73e171dcd370f51b3bb4010d Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Thu, 18 May 2023 20:41:02 +0100 Subject: [PATCH 40/82] code style Signed-off-by: Dave Rodgman --- tests/suites/test_suite_constant_time.function | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/suites/test_suite_constant_time.function b/tests/suites/test_suite_constant_time.function index 2fafa948d6..cce5b84353 100644 --- a/tests/suites/test_suite_constant_time.function +++ b/tests/suites/test_suite_constant_time.function @@ -298,7 +298,8 @@ void mbedtls_ct_memcpy_if(int eq, int size, int offset) TEST_CF_SECRET(src, size + offset); TEST_CF_SECRET(result, size + offset); - mbedtls_ct_memcpy_if(mbedtls_ct_bool(secret_eq), src + offset, src + offset, src + offset, size); + mbedtls_ct_memcpy_if(mbedtls_ct_bool(secret_eq), src + offset, src + offset, src + offset, + size); TEST_CF_PUBLIC(&secret_eq, sizeof(secret_eq)); TEST_CF_PUBLIC(src, size + offset); From 2894d007d32ac793ccabb998eb1cd05459a45f95 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Thu, 8 Jun 2023 17:52:21 +0100 Subject: [PATCH 41/82] Strengthen fall-back for mbedtls_ct_compiler_opaque Signed-off-by: Dave Rodgman --- library/constant_time_impl.h | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/library/constant_time_impl.h b/library/constant_time_impl.h index 44682c0497..c490d8229d 100644 --- a/library/constant_time_impl.h +++ b/library/constant_time_impl.h @@ -65,20 +65,29 @@ * Core const-time primitives */ -/** Ensure that the compiler cannot know the value of x (i.e., cannot optimise +/* Ensure that the compiler cannot know the value of x (i.e., cannot optimise * based on its value) after this function is called. * * If we are not using assembly, this will be fairly inefficient, so its use * should be minimised. */ + +#if !defined(MBEDTLS_CT_ASM) +/* +* Define an object with the value zero, such that the compiler cannot prove that it +* has the value zero (because it is volatile, it "may be modified in ways unknown to +* the implementation"). +*/ +static volatile mbedtls_ct_uint_t mbedtls_ct_zero = 0; +#endif + static inline mbedtls_ct_uint_t mbedtls_ct_compiler_opaque(mbedtls_ct_uint_t x) { #if defined(MBEDTLS_CT_ASM) asm volatile ("" : [x] "+r" (x) :); return x; #else - volatile mbedtls_ct_uint_t result = x; - return result; + return x ^ mbedtls_ct_zero; #endif } From 58c80f4d9208aa75aa5cb60585c1af176918d9e1 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Mon, 12 Jun 2023 18:19:46 +0100 Subject: [PATCH 42/82] Make mbedtls_ct_zero non-static Signed-off-by: Dave Rodgman --- library/constant_time.c | 9 +++++++++ library/constant_time_impl.h | 7 +------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index 90fbcf2d27..40a7f0dba1 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -37,6 +37,15 @@ psa_generic_status_to_mbedtls) #endif +#if !defined(MBEDTLS_CT_ASM) +/* +* Define an object with the value zero, such that the compiler cannot prove that it +* has the value zero (because it is volatile, it "may be modified in ways unknown to +* the implementation"). +*/ +volatile mbedtls_ct_uint_t mbedtls_ct_zero = 0; +#endif + /* * Define MBEDTLS_EFFICIENT_UNALIGNED_VOLATILE_ACCESS where assembly is present to * perform fast unaligned access to volatile data. diff --git a/library/constant_time_impl.h b/library/constant_time_impl.h index c490d8229d..91418e58ff 100644 --- a/library/constant_time_impl.h +++ b/library/constant_time_impl.h @@ -73,12 +73,7 @@ */ #if !defined(MBEDTLS_CT_ASM) -/* -* Define an object with the value zero, such that the compiler cannot prove that it -* has the value zero (because it is volatile, it "may be modified in ways unknown to -* the implementation"). -*/ -static volatile mbedtls_ct_uint_t mbedtls_ct_zero = 0; +extern volatile mbedtls_ct_uint_t mbedtls_ct_zero; #endif static inline mbedtls_ct_uint_t mbedtls_ct_compiler_opaque(mbedtls_ct_uint_t x) From 1ab0b48ac3a69275349fd9e6d77b0807d5eaebad Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Mon, 12 Jun 2023 18:22:18 +0100 Subject: [PATCH 43/82] Code style Signed-off-by: Dave Rodgman --- library/constant_time.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index 40a7f0dba1..68b9bdb3f3 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -39,10 +39,10 @@ #if !defined(MBEDTLS_CT_ASM) /* -* Define an object with the value zero, such that the compiler cannot prove that it -* has the value zero (because it is volatile, it "may be modified in ways unknown to -* the implementation"). -*/ + * Define an object with the value zero, such that the compiler cannot prove that it + * has the value zero (because it is volatile, it "may be modified in ways unknown to + * the implementation"). + */ volatile mbedtls_ct_uint_t mbedtls_ct_zero = 0; #endif From f27727b22e243a1a93f8b045d4e3be93501ad901 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Sat, 13 May 2023 12:12:02 +0100 Subject: [PATCH 44/82] Docs update Signed-off-by: Dave Rodgman --- library/constant_time_internal.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h index 0cb3f2a346..2320234d84 100644 --- a/library/constant_time_internal.h +++ b/library/constant_time_internal.h @@ -36,10 +36,10 @@ * * It has three main parts: * - * - boolean operations (and a few non-boolean operations) + * - boolean operations * These are all named mbedtls_ct_bool_, and operate over * mbedtls_ct_condition_t. - * All arguments to these operations are considered secret. + * All arguments are considered secret. * example: bool x = y | z => x = mbedtls_ct_bool_or(y, z) * * - conditional data selection @@ -62,10 +62,11 @@ * to/from "unsigned int", "size_t", and "mbedtls_mpi_uint" (and any other * not-larger integer types). * - * For Arm (32-bit, 64-bit and Thumb), assembly implementations are used - * to ensure that the generated code is constant time. For other architectures, - * a plain C fallback designed to yield constant-time code (this has been - * observed to be constant-time on latest gcc, clang and MSVC as of May 2023). + * For Arm (32-bit, 64-bit and Thumb), x86 and x86-64, assembly implementations + * are used to ensure that the generated code is constant time. For other + * architectures, a plain C fallback designed to yield constant-time code (this + * has been observed to be constant-time on latest gcc, clang and MSVC as of + * May 2023). */ #if (SIZE_MAX > 0xffffffffffffffffULL) From 855f72bb4c8fbacc2fa60017905318eb85c16c43 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Tue, 13 Jun 2023 10:36:06 +0100 Subject: [PATCH 45/82] Fix ecp test Signed-off-by: Dave Rodgman --- tests/suites/test_suite_ecp.function | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/suites/test_suite_ecp.function b/tests/suites/test_suite_ecp.function index bd0fcf2f18..1560299d55 100644 --- a/tests/suites/test_suite_ecp.function +++ b/tests/suites/test_suite_ecp.function @@ -1653,7 +1653,7 @@ void ecp_mod_random(int id, int ctype) TEST_EQUAL(0, mbedtls_mpi_mod_random(&rX, 1, &m, mbedtls_test_rnd_std_rand, NULL)); - TEST_ASSERT(mbedtls_mpi_core_lt_ct(rX.p, m.p, limbs) == 1); + TEST_ASSERT(mbedtls_mpi_core_lt_ct(rX.p, m.p, limbs) == MBEDTLS_CT_TRUE); exit: mbedtls_mpi_mod_modulus_free(&m); From c882adf0ca33fb4794ba823c0609249aa7abea7a Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Wed, 21 Jun 2023 07:37:56 +0100 Subject: [PATCH 46/82] Docs improvement Signed-off-by: Dave Rodgman --- library/constant_time_internal.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h index 2320234d84..9660758164 100644 --- a/library/constant_time_internal.h +++ b/library/constant_time_internal.h @@ -76,13 +76,13 @@ typedef size_t mbedtls_ct_uint_t; typedef ptrdiff_t mbedtls_ct_int_t; #define MBEDTLS_CT_TRUE ((mbedtls_ct_condition_t) SIZE_MAX) #elif (SIZE_MAX > 0xffffffff) || defined(MBEDTLS_HAVE_INT64) -/* 32-bit < pointer size < 64-bit, or 64-bit MPI */ +/* 32-bit < pointer size <= 64-bit, or 64-bit MPI */ typedef uint64_t mbedtls_ct_condition_t; typedef uint64_t mbedtls_ct_uint_t; typedef int64_t mbedtls_ct_int_t; #define MBEDTLS_CT_TRUE ((mbedtls_ct_condition_t) UINT64_MAX) #else -/* Pointer size < 32-bit, and no 64-bit MPIs */ +/* Pointer size <= 32-bit, and no 64-bit MPIs */ typedef uint32_t mbedtls_ct_condition_t; typedef uint32_t mbedtls_ct_uint_t; typedef int32_t mbedtls_ct_int_t; From a02b36886cdc97f7e1615380cddafcbe273616de Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Fri, 14 Jul 2023 13:43:39 +0100 Subject: [PATCH 47/82] Fix gcc warnings when -Wredundant-decls set Signed-off-by: Dave Rodgman --- include/mbedtls/constant_time.h | 8 ++++++++ library/constant_time_internal.h | 13 ++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/include/mbedtls/constant_time.h b/include/mbedtls/constant_time.h index 91a9e7fc33..2d33adc88c 100644 --- a/include/mbedtls/constant_time.h +++ b/include/mbedtls/constant_time.h @@ -23,6 +23,10 @@ #include +#ifdef __GNUC__ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wredundant-decls" +#endif /** Constant-time buffer comparison without branches. * @@ -43,4 +47,8 @@ int mbedtls_ct_memcmp(const void *a, const void *b, size_t n); +#ifdef __GNUC__ + #pragma GCC diagnostic pop +#endif + #endif /* MBEDTLS_CONSTANT_TIME_H */ diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h index 9660758164..f0fde6a71f 100644 --- a/library/constant_time_internal.h +++ b/library/constant_time_internal.h @@ -92,9 +92,16 @@ typedef int32_t mbedtls_ct_int_t; /* constant_time_impl.h contains all the static inline implementations, * so that constant_time_internal.h is more readable. + * + * gcc generates warnings about duplicate declarations, so disable this + * warning. */ -#include "constant_time_impl.h" +#ifdef __GNUC__ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wredundant-decls" +#endif +#include "constant_time_impl.h" /* ============================================================================ * Boolean operations @@ -473,4 +480,8 @@ int mbedtls_ct_memcmp(const void *a, const void *b, size_t n); +#ifdef __GNUC__ + #pragma GCC diagnostic pop +#endif + #endif /* MBEDTLS_CONSTANT_TIME_INTERNAL_H */ From fba559822f6438629f45ae878f6eb75e870677ee Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Fri, 14 Jul 2023 13:44:22 +0100 Subject: [PATCH 48/82] Ensure constant values not known to compiler Signed-off-by: Dave Rodgman --- library/constant_time_internal.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h index f0fde6a71f..79927c1f15 100644 --- a/library/constant_time_internal.h +++ b/library/constant_time_internal.h @@ -74,21 +74,21 @@ typedef size_t mbedtls_ct_condition_t; typedef size_t mbedtls_ct_uint_t; typedef ptrdiff_t mbedtls_ct_int_t; -#define MBEDTLS_CT_TRUE ((mbedtls_ct_condition_t) SIZE_MAX) +#define MBEDTLS_CT_TRUE ((mbedtls_ct_condition_t) mbedtls_ct_compiler_opaque(SIZE_MAX)) #elif (SIZE_MAX > 0xffffffff) || defined(MBEDTLS_HAVE_INT64) /* 32-bit < pointer size <= 64-bit, or 64-bit MPI */ typedef uint64_t mbedtls_ct_condition_t; typedef uint64_t mbedtls_ct_uint_t; typedef int64_t mbedtls_ct_int_t; -#define MBEDTLS_CT_TRUE ((mbedtls_ct_condition_t) UINT64_MAX) +#define MBEDTLS_CT_TRUE ((mbedtls_ct_condition_t) mbedtls_ct_compiler_opaque(UINT64_MAX)) #else /* Pointer size <= 32-bit, and no 64-bit MPIs */ typedef uint32_t mbedtls_ct_condition_t; typedef uint32_t mbedtls_ct_uint_t; typedef int32_t mbedtls_ct_int_t; -#define MBEDTLS_CT_TRUE ((mbedtls_ct_condition_t) UINT32_MAX) +#define MBEDTLS_CT_TRUE ((mbedtls_ct_condition_t) mbedtls_ct_compiler_opaque(UINT32_MAX)) #endif -#define MBEDTLS_CT_FALSE ((mbedtls_ct_condition_t) 0) +#define MBEDTLS_CT_FALSE ((mbedtls_ct_condition_t) mbedtls_ct_compiler_opaque(0)) /* constant_time_impl.h contains all the static inline implementations, * so that constant_time_internal.h is more readable. From 8de3482507400e39f0d38a335e40a60b81cf9e48 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Fri, 28 Jul 2023 15:10:00 +0100 Subject: [PATCH 49/82] Fix false-positive non-const-time errors in test Signed-off-by: Dave Rodgman --- tests/suites/test_suite_constant_time.function | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/suites/test_suite_constant_time.function b/tests/suites/test_suite_constant_time.function index cce5b84353..dbcc9f7597 100644 --- a/tests/suites/test_suite_constant_time.function +++ b/tests/suites/test_suite_constant_time.function @@ -77,13 +77,13 @@ void mbedtls_ct_bool_xxx(char *x_str, char *y_str) expected = x1 <= y1 ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE; TEST_EQUAL(mbedtls_ct_bool_le(x, y), expected); - expected = mbedtls_ct_bool(x) ^ mbedtls_ct_bool(y) ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE; + expected = mbedtls_ct_bool(x1) ^ mbedtls_ct_bool(y1) ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE; TEST_EQUAL(mbedtls_ct_bool_xor(mbedtls_ct_bool(x), mbedtls_ct_bool(y)), expected); - expected = mbedtls_ct_bool(x) & mbedtls_ct_bool(y) ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE; + expected = mbedtls_ct_bool(x1) & mbedtls_ct_bool(y1) ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE; TEST_EQUAL(mbedtls_ct_bool_and(mbedtls_ct_bool(x), mbedtls_ct_bool(y)), expected); - expected = mbedtls_ct_bool(x) | mbedtls_ct_bool(y) ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE; + expected = mbedtls_ct_bool(x1) | mbedtls_ct_bool(y1) ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE; TEST_EQUAL(mbedtls_ct_bool_or(mbedtls_ct_bool(x), mbedtls_ct_bool(y)), expected); TEST_CF_PUBLIC(&x, sizeof(x)); From fa5a4bbb02f625d43c2efdee853059afefc8110f Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Fri, 28 Jul 2023 16:13:52 +0100 Subject: [PATCH 50/82] Improve mbedtls_ct_memmove_left w.r.t. const-flow tests Signed-off-by: Dave Rodgman --- library/constant_time.c | 21 ++++++++++++++++--- .../suites/test_suite_constant_time.function | 5 ++--- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index f2cdddf961..6523ccf153 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -30,6 +30,8 @@ #include "mbedtls/error.h" #include "mbedtls/platform_util.h" +#include "../tests/include/test/constant_flow.h" + #include #if defined(MBEDTLS_USE_PSA_CRYPTO) && defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC) @@ -127,6 +129,20 @@ int mbedtls_ct_memcmp(const void *a, void mbedtls_ct_memmove_left(void *start, size_t total, size_t offset) { + /* In case of inlining, ensure that code generated is independent of the value of offset + * (e.g., if the compiler knows that offset == 0, it might be able to optimise this function + * to a no-op). */ + size_t hidden_offset = mbedtls_ct_compiler_opaque(offset); + + /* During this loop, j will take every value from [0..total) exactly once, + * regardless of the value of hidden_offset (it only changes the initial + * value for j). + * + * For this reason, when testing, it is safe to mark hidden_offset as non-secret. + * This prevents the const-flow checkers from generating a false-positive. + */ + TEST_CF_PUBLIC(&hidden_offset, sizeof(hidden_offset)); + /* Iterate over the array, reading each byte once and writing each byte once. */ for (size_t i = 0; i < total; i++) { /* Each iteration, read one byte, and write it to start[i]. @@ -138,9 +154,8 @@ void mbedtls_ct_memmove_left(void *start, size_t total, size_t offset) * If the source address is out of range, mask it to zero. */ - // The address that we will read from - // TODO: if offset is marked as secret, this upsets Memsan. - size_t j = i + offset; + // The offset that we will read from (if in range) + size_t j = i + hidden_offset; // Is the address off the end of the array? mbedtls_ct_condition_t not_dummy = mbedtls_ct_bool_lt(j, total); diff --git a/tests/suites/test_suite_constant_time.function b/tests/suites/test_suite_constant_time.function index dbcc9f7597..d8a1fccbe5 100644 --- a/tests/suites/test_suite_constant_time.function +++ b/tests/suites/test_suite_constant_time.function @@ -329,11 +329,10 @@ void mbedtls_ct_memmove_left(int len, int offset) buf_expected[i] = buf[i]; } - //Note: Marking o as secret causes false positives from Memsan - //TEST_CF_SECRET(&o, sizeof(o)); + TEST_CF_SECRET(&o, sizeof(o)); TEST_CF_SECRET(buf, l); mbedtls_ct_memmove_left(buf, l, o); - //TEST_CF_PUBLIC(&o, sizeof(o)); + TEST_CF_PUBLIC(&o, sizeof(o)); TEST_CF_PUBLIC(buf, l); if (l > 0) { From 08691679b51c3e8e985c3b29056bb85ebdf1e031 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Fri, 28 Jul 2023 16:17:57 +0100 Subject: [PATCH 51/82] Enable testing of asm under Memsan Signed-off-by: Dave Rodgman --- library/constant_time_impl.h | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/library/constant_time_impl.h b/library/constant_time_impl.h index 91418e58ff..f8f6bb194d 100644 --- a/library/constant_time_impl.h +++ b/library/constant_time_impl.h @@ -37,15 +37,7 @@ #include "mbedtls/bignum.h" #endif - -/* Disable asm under Memsan because it confuses Memsan and generates false errors */ -#if defined(MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN) -#define MBEDTLS_CT_NO_ASM -#elif defined(__has_feature) -#if __has_feature(memory_sanitizer) -#define MBEDTLS_CT_NO_ASM -#endif -#endif +#include "../tests/include/test/constant_flow.h" /* armcc5 --gnu defines __GNUC__ but doesn't support GNU's extended asm */ #if defined(MBEDTLS_HAVE_ASM) && defined(__GNUC__) && (!defined(__ARMCC_VERSION) || \ @@ -79,7 +71,19 @@ extern volatile mbedtls_ct_uint_t mbedtls_ct_zero; static inline mbedtls_ct_uint_t mbedtls_ct_compiler_opaque(mbedtls_ct_uint_t x) { #if defined(MBEDTLS_CT_ASM) + /* Prevent false positives from Memsan - otherwise it will report the asm as + * accessing secret data. */ + TEST_CF_PUBLIC(&x, sizeof(x)); + asm volatile ("" : [x] "+r" (x) :); + + /* Mark the return value as secret. This is needed so that code of the form: + * + * if (mbedtls_ct_compiler_opaque(secret)) { ... } + * + * will fail const-flow tests. + */ + TEST_CF_SECRET(&x, sizeof(x)); return x; #else return x ^ mbedtls_ct_zero; From d684d7342bf47252e1ab0deb42f8f13a9ddee3d2 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Fri, 28 Jul 2023 16:21:41 +0100 Subject: [PATCH 52/82] code style Signed-off-by: Dave Rodgman --- library/constant_time.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index 6523ccf153..8cdb53a1c6 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -135,13 +135,13 @@ void mbedtls_ct_memmove_left(void *start, size_t total, size_t offset) size_t hidden_offset = mbedtls_ct_compiler_opaque(offset); /* During this loop, j will take every value from [0..total) exactly once, - * regardless of the value of hidden_offset (it only changes the initial - * value for j). - * - * For this reason, when testing, it is safe to mark hidden_offset as non-secret. - * This prevents the const-flow checkers from generating a false-positive. - */ - TEST_CF_PUBLIC(&hidden_offset, sizeof(hidden_offset)); + * regardless of the value of hidden_offset (it only changes the initial + * value for j). + * + * For this reason, when testing, it is safe to mark hidden_offset as non-secret. + * This prevents the const-flow checkers from generating a false-positive. + */ + TEST_CF_PUBLIC(&hidden_offset, sizeof(hidden_offset)); /* Iterate over the array, reading each byte once and writing each byte once. */ for (size_t i = 0; i < total; i++) { From 983448ea6236b35bb165c305ebfd84fceda4eacb Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Fri, 28 Jul 2023 17:30:52 +0100 Subject: [PATCH 53/82] fix check for no-longer-used macro Signed-off-by: Dave Rodgman --- library/constant_time_impl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/constant_time_impl.h b/library/constant_time_impl.h index f8f6bb194d..c9e6a83ab1 100644 --- a/library/constant_time_impl.h +++ b/library/constant_time_impl.h @@ -41,7 +41,7 @@ /* armcc5 --gnu defines __GNUC__ but doesn't support GNU's extended asm */ #if defined(MBEDTLS_HAVE_ASM) && defined(__GNUC__) && (!defined(__ARMCC_VERSION) || \ - __ARMCC_VERSION >= 6000000) && !defined(MBEDTLS_CT_NO_ASM) + __ARMCC_VERSION >= 6000000) #define MBEDTLS_CT_ASM #if (defined(__arm__) || defined(__thumb__) || defined(__thumb2__)) #define MBEDTLS_CT_ARM_ASM From 2d28c46055b8006938df8f939d05e1f28e024064 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Fri, 28 Jul 2023 18:22:56 +0100 Subject: [PATCH 54/82] Fix asm Memsan workaround Signed-off-by: Dave Rodgman --- library/constant_time_impl.h | 7 ++++--- tests/include/test/constant_flow.h | 22 ++++++++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/library/constant_time_impl.h b/library/constant_time_impl.h index c9e6a83ab1..191769b192 100644 --- a/library/constant_time_impl.h +++ b/library/constant_time_impl.h @@ -73,17 +73,18 @@ static inline mbedtls_ct_uint_t mbedtls_ct_compiler_opaque(mbedtls_ct_uint_t x) #if defined(MBEDTLS_CT_ASM) /* Prevent false positives from Memsan - otherwise it will report the asm as * accessing secret data. */ - TEST_CF_PUBLIC(&x, sizeof(x)); + TEST_CF_SAVE_SECRET(x); asm volatile ("" : [x] "+r" (x) :); - /* Mark the return value as secret. This is needed so that code of the form: + /* Mark the return value as secret (if it was previously marked secret). + * This is needed so that code of the form: * * if (mbedtls_ct_compiler_opaque(secret)) { ... } * * will fail const-flow tests. */ - TEST_CF_SECRET(&x, sizeof(x)); + TEST_CF_RESTORE_SECRET(x); return x; #else return x ^ mbedtls_ct_zero; diff --git a/tests/include/test/constant_flow.h b/tests/include/test/constant_flow.h index f3d676e285..572835713f 100644 --- a/tests/include/test/constant_flow.h +++ b/tests/include/test/constant_flow.h @@ -32,14 +32,27 @@ * #define TEST_CF_SECRET(ptr, size) * #define TEST_CF_PUBLIC(ptr, size) * + * and + * + * #define TEST_CF_SAVE_SECRET(variable) + * #define TEST_CF_RESTORE_SECRET(variable) + * * that can be used in tests to mark a memory area as secret (no branch or * memory access should depend on it) or public (default, only needs to be * marked explicitly when it was derived from secret data). * + * The SAVE/RESTORE forms mark a variable as public, and subsequently restore its + * previous secret/not-secret state. This is used where library code is generating + * false positives and needs to temporarily disable Memsan checks for a particular + * variable, and then restore it's original state afterwards so it doesn't interfere + * with other checks. + * * Arguments: * - ptr: a pointer to the memory area to be marked * - size: the size in bytes of the memory area * + * - variable: a variable name + * * Implementation: * The basic idea is that of ctgrind : we can * re-use tools that were designed for checking use of uninitialized memory. @@ -63,6 +76,9 @@ #define TEST_CF_PUBLIC __msan_unpoison // void __msan_unpoison(const volatile void *a, size_t size); +#define TEST_CF_SAVE_SECRET(_x) int _test_cf_is_public_ ## _x = __msan_test_shadow(&(_x), sizeof(_x)) == -1; TEST_CF_PUBLIC(&(_x), sizeof(_x)); +#define TEST_CF_RESTORE_SECRET(_x) do { if (!_test_cf_is_public_ ## _x) TEST_CF_SECRET(&(_x), sizeof(_x)); } while(0) + #elif defined(MBEDTLS_TEST_CONSTANT_FLOW_VALGRIND) #include @@ -71,12 +87,18 @@ #define TEST_CF_PUBLIC VALGRIND_MAKE_MEM_DEFINED // VALGRIND_MAKE_MEM_DEFINED(_qzz_addr, _qzz_len) +#define TEST_CF_SAVE_SECRET(_x) +#define TEST_CF_RESTORE_SECRET(_x) + #else /* MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN || MBEDTLS_TEST_CONSTANT_FLOW_VALGRIND */ #define TEST_CF_SECRET(ptr, size) #define TEST_CF_PUBLIC(ptr, size) +#define TEST_CF_SAVE_SECRET(_x) +#define TEST_CF_RESTORE_SECRET(_x) + #endif /* MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN || MBEDTLS_TEST_CONSTANT_FLOW_VALGRIND */ From 2b174abd862160f8891eb416417c0baa7639fc67 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Fri, 28 Jul 2023 18:29:41 +0100 Subject: [PATCH 55/82] code style Signed-off-by: Dave Rodgman --- tests/include/test/constant_flow.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/include/test/constant_flow.h b/tests/include/test/constant_flow.h index 572835713f..ff464e617c 100644 --- a/tests/include/test/constant_flow.h +++ b/tests/include/test/constant_flow.h @@ -76,8 +76,11 @@ #define TEST_CF_PUBLIC __msan_unpoison // void __msan_unpoison(const volatile void *a, size_t size); -#define TEST_CF_SAVE_SECRET(_x) int _test_cf_is_public_ ## _x = __msan_test_shadow(&(_x), sizeof(_x)) == -1; TEST_CF_PUBLIC(&(_x), sizeof(_x)); -#define TEST_CF_RESTORE_SECRET(_x) do { if (!_test_cf_is_public_ ## _x) TEST_CF_SECRET(&(_x), sizeof(_x)); } while(0) +#define TEST_CF_SAVE_SECRET(_x) \ + int _test_cf_is_public_ ## _x = __msan_test_shadow(&(_x), sizeof(_x)) == -1; \ + TEST_CF_PUBLIC(&(_x), sizeof(_x)); +#define TEST_CF_RESTORE_SECRET(_x) \ + if (!_test_cf_is_public_ ## _x) TEST_CF_SECRET(&(_x), sizeof(_x)); #elif defined(MBEDTLS_TEST_CONSTANT_FLOW_VALGRIND) #include From fb1b851797bca8d445f37784a5c33eed4a311a2f Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Mon, 31 Jul 2023 12:27:05 +0100 Subject: [PATCH 56/82] Improve docs for mbedtls_mpi_core_cond_assign Signed-off-by: Dave Rodgman --- library/bignum_core.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/bignum_core.h b/library/bignum_core.h index 64d51b92d1..e5500f117a 100644 --- a/library/bignum_core.h +++ b/library/bignum_core.h @@ -178,7 +178,9 @@ mbedtls_ct_condition_t mbedtls_mpi_core_lt_ct(const mbedtls_mpi_uint *A, * \param[in] A The address of the source MPI. This must be initialized. * \param limbs The number of limbs of \p A. * \param assign The condition deciding whether to perform the - * assignment or not. + * assignment or not. Callers will need to use + * the constant time interface (e.g. `mbedtls_ct_bool()`) + * to construct this argument. * * \note This function avoids leaking any information about whether * the assignment was done or not. From 07f853713d60aa448a66fe8963c5ce0c1494e7c9 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Mon, 31 Jul 2023 12:27:49 +0100 Subject: [PATCH 57/82] Clarify comments in mbedtls_ct_memcpy_if Signed-off-by: Dave Rodgman --- library/constant_time.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index 8cdb53a1c6..c60ec84550 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -185,8 +185,11 @@ void mbedtls_ct_memcpy_if(mbedtls_ct_condition_t condition, const uint32_t mask = (uint32_t) condition; const uint32_t not_mask = (uint32_t) ~mbedtls_ct_compiler_opaque(condition); - /* If src2 is NULL and condition == 0, then this function has no effect. - * In this case, copy from dest back into dest. */ + /* If src2 is NULL, setup src2 so that we read from the destination address. + * + * This means that if src2 == NULL && condition is false, the result will be a + * no-op because we read from dest and write the same data back into dest. + */ if (src2 == NULL) { src2 = dest; } From 32d726033b6a3cd83c1c9b69b393266a386e33d5 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Mon, 31 Jul 2023 12:28:05 +0100 Subject: [PATCH 58/82] Improve comments in mbedtls_mpi_lt_mpi_ct Signed-off-by: Dave Rodgman --- library/bignum.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/library/bignum.c b/library/bignum.c index 8ad7258582..aa5f818c40 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -86,19 +86,21 @@ int mbedtls_mpi_lt_mpi_ct(const mbedtls_mpi *X, cond = mbedtls_ct_bool_xor(X_is_negative, Y_is_negative); // non-zero if different sign result = mbedtls_ct_bool_and(cond, X_is_negative); - /* Assuming signs are the same, compare X and Y. We switch the comparison + /* + * Assuming signs are the same, compare X and Y. We switch the comparison * order if they are negative so that we get the right result, regardles of * sign. - * - * Store in ret iff the signs are the same (i.e., iff cond == 0). If - * the signs differ, done has already been set. */ - /* This is used to conditionally swap the pointers in const time */ + /* This array is used to conditionally swap the pointers in const time */ void * const p[2] = { X->p, Y->p }; size_t i = mbedtls_ct_size_if0(X_is_negative, 1); mbedtls_ct_condition_t lt = mbedtls_mpi_core_lt_ct(p[i], p[i ^ 1], X->n); + /* + * Store in result iff the signs are the same (i.e., iff cond == false). If + * the signs differ, result has already been set, so we don't change it. + */ result = mbedtls_ct_bool_or(result, mbedtls_ct_bool_and(mbedtls_ct_bool_not(cond), lt)); *ret = mbedtls_ct_uint_if0(result, 1); From 93cec45af3de71894700b7824fae563939f46ebc Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Mon, 31 Jul 2023 12:30:26 +0100 Subject: [PATCH 59/82] Improve docs for mbedtls_ct_compiler_opaque Signed-off-by: Dave Rodgman --- library/constant_time_impl.h | 13 +++++++++++++ library/constant_time_internal.h | 5 +++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/library/constant_time_impl.h b/library/constant_time_impl.h index 191769b192..b2ef73f700 100644 --- a/library/constant_time_impl.h +++ b/library/constant_time_impl.h @@ -68,6 +68,19 @@ extern volatile mbedtls_ct_uint_t mbedtls_ct_zero; #endif +/** + * \brief Ensure that a value cannot be known at compile time. + * + * \param x The value to hide from the compiler. + * \return The same value that was passed in, such that the compiler + * cannot prove its value (even for calls of the form + * x = mbedtls_ct_compiler_opaque(1), x will be unknown). + * + * \note This is mainly used in constructing mbedtls_ct_condition_t + * values and performing operations over them, to ensure that + * there is no way for the compiler to ever know anything about + * the value of an mbedtls_ct_condition_t. + */ static inline mbedtls_ct_uint_t mbedtls_ct_compiler_opaque(mbedtls_ct_uint_t x) { #if defined(MBEDTLS_CT_ASM) diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h index 79927c1f15..c15eaeb4d7 100644 --- a/library/constant_time_internal.h +++ b/library/constant_time_internal.h @@ -53,8 +53,9 @@ * function. * example: if (x) memcpy(...) => mbedtls_ct_memcpy_if(x, ...) * - * mbedtls_ct_condition_t should be treated as opaque and only manipulated - * via the functions in this header. + * mbedtls_ct_condition_t must be treated as opaque and only created and + * manipulated via the functions in this header. The compiler should never + * be able to prove anything about its value at compile-time. * * mbedtls_ct_uint_t is an unsigned integer type over which constant time * operations may be performed via the functions in this header. It is as big From 741d423ef8fa705453ccbc4c9c3637240f85297f Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Mon, 31 Jul 2023 12:31:01 +0100 Subject: [PATCH 60/82] Clarify docs for mbedtls_ct_memcpy_if Signed-off-by: Dave Rodgman --- library/constant_time_internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h index c15eaeb4d7..959fbf9456 100644 --- a/library/constant_time_internal.h +++ b/library/constant_time_internal.h @@ -428,7 +428,7 @@ void mbedtls_ct_memmove_left(void *start, * \param dest Secret. Destination pointer. * \param src1 Secret. Pointer to copy from (if \p condition == MBEDTLS_CT_TRUE). * This may be equal to \p dest, but may not overlap in other ways. - * \param src2 Secret (contents only - may branch to test if src2 == NULL). + * \param src2 Secret (contents only - may branch to determine if this parameter is NULL). * Pointer to copy from (if \p condition == MBEDTLS_CT_FALSE and \p src2 is not NULL). May be NULL. * This may be equal to \p dest, but may not overlap it in other ways. It may overlap with \p src1. * \param len Number of bytes to copy. From 0172de8b3da60f7cb78fb5b701d216119630303b Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Mon, 31 Jul 2023 12:32:23 +0100 Subject: [PATCH 61/82] Fix docs grammar Signed-off-by: Dave Rodgman --- library/constant_time_internal.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h index 959fbf9456..5879e47bb8 100644 --- a/library/constant_time_internal.h +++ b/library/constant_time_internal.h @@ -65,9 +65,9 @@ * * For Arm (32-bit, 64-bit and Thumb), x86 and x86-64, assembly implementations * are used to ensure that the generated code is constant time. For other - * architectures, a plain C fallback designed to yield constant-time code (this - * has been observed to be constant-time on latest gcc, clang and MSVC as of - * May 2023). + * architectures, it uses a plain C fallback designed to yield constant-time code + * (this has been observed to be constant-time on latest gcc, clang and MSVC + * as of May 2023). */ #if (SIZE_MAX > 0xffffffffffffffffULL) From 9ee0e1f6fed0efb123bd75aefe7ced9f24484cd7 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Mon, 31 Jul 2023 12:33:36 +0100 Subject: [PATCH 62/82] Remove GCC redundant-decls workaround for mbedtls_ct_memcmp Signed-off-by: Dave Rodgman --- include/mbedtls/constant_time.h | 9 --------- library/constant_time_internal.h | 10 ++++++---- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/include/mbedtls/constant_time.h b/include/mbedtls/constant_time.h index 2d33adc88c..01d5d9d294 100644 --- a/include/mbedtls/constant_time.h +++ b/include/mbedtls/constant_time.h @@ -23,11 +23,6 @@ #include -#ifdef __GNUC__ - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wredundant-decls" -#endif - /** Constant-time buffer comparison without branches. * * This is equivalent to the standard memcmp function, but is likely to be @@ -47,8 +42,4 @@ int mbedtls_ct_memcmp(const void *a, const void *b, size_t n); -#ifdef __GNUC__ - #pragma GCC diagnostic pop -#endif - #endif /* MBEDTLS_CONSTANT_TIME_H */ diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h index 5879e47bb8..1411e14921 100644 --- a/library/constant_time_internal.h +++ b/library/constant_time_internal.h @@ -476,10 +476,12 @@ void mbedtls_ct_memcpy_offset(unsigned char *dest, size_t offset_max, size_t len); -/* Documented in include/mbedtls/constant_time.h. a and b are secret. */ -int mbedtls_ct_memcmp(const void *a, - const void *b, - size_t n); +/* Documented in include/mbedtls/constant_time.h. a and b are secret. + + int mbedtls_ct_memcmp(const void *a, + const void *b, + size_t n); + */ #ifdef __GNUC__ #pragma GCC diagnostic pop From ad9e5b9abe89216c90d70bf2676359bf6b989964 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Mon, 31 Jul 2023 12:33:47 +0100 Subject: [PATCH 63/82] Improve docs for mbedtls_ct_memcmp Signed-off-by: Dave Rodgman --- include/mbedtls/constant_time.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/include/mbedtls/constant_time.h b/include/mbedtls/constant_time.h index 01d5d9d294..49bb375d4e 100644 --- a/include/mbedtls/constant_time.h +++ b/include/mbedtls/constant_time.h @@ -26,16 +26,19 @@ /** Constant-time buffer comparison without branches. * * This is equivalent to the standard memcmp function, but is likely to be - * compiled to code using bitwise operation rather than a branch. + * compiled to code using bitwise operation rather than a branch, such that + * the time taken is constant w.r.t. the data pointed to by \p a and \p b, + * and w.r.t. whether \p a and \p b are equal or not. It is not constant-time + * w.r.t. \p n . * * This function can be used to write constant-time code by replacing branches * with bit operations using masks. * - * \param a Pointer to the first buffer. - * \param b Pointer to the second buffer. - * \param n The number of bytes to compare in the buffer. + * \param a Pointer to the first buffer, containing at least \p n bytes. May not be NULL. + * \param b Pointer to the second buffer, containing at least \p n bytes. May not be NULL. + * \param n The number of bytes to compare. * - * \return Zero if the content of the two buffer is the same, + * \return Zero if the contents of the two buffers are the same, * otherwise non-zero. */ int mbedtls_ct_memcmp(const void *a, From 04a334af550205cfed3990c1686270d5fad2ee6a Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Mon, 31 Jul 2023 12:35:26 +0100 Subject: [PATCH 64/82] Make const-time test not depend on internal knowledge of mbedtls_ct_condition_t Signed-off-by: Dave Rodgman --- tests/suites/test_suite_constant_time.function | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/suites/test_suite_constant_time.function b/tests/suites/test_suite_constant_time.function index d8a1fccbe5..bdd27f53dd 100644 --- a/tests/suites/test_suite_constant_time.function +++ b/tests/suites/test_suite_constant_time.function @@ -77,13 +77,13 @@ void mbedtls_ct_bool_xxx(char *x_str, char *y_str) expected = x1 <= y1 ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE; TEST_EQUAL(mbedtls_ct_bool_le(x, y), expected); - expected = mbedtls_ct_bool(x1) ^ mbedtls_ct_bool(y1) ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE; + expected = (!!x1) ^ (!!y1) ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE; TEST_EQUAL(mbedtls_ct_bool_xor(mbedtls_ct_bool(x), mbedtls_ct_bool(y)), expected); - expected = mbedtls_ct_bool(x1) & mbedtls_ct_bool(y1) ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE; + expected = (!!x1) && (!!y1) ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE; TEST_EQUAL(mbedtls_ct_bool_and(mbedtls_ct_bool(x), mbedtls_ct_bool(y)), expected); - expected = mbedtls_ct_bool(x1) | mbedtls_ct_bool(y1) ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE; + expected = (!!x1) || (!!y1) ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE; TEST_EQUAL(mbedtls_ct_bool_or(mbedtls_ct_bool(x), mbedtls_ct_bool(y)), expected); TEST_CF_PUBLIC(&x, sizeof(x)); From 1714a9b0ebbc8a6e6913c064a690484c1753923b Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Mon, 31 Jul 2023 12:37:01 +0100 Subject: [PATCH 65/82] Revert to old design for mbedtls_ct_memmove_left Signed-off-by: Dave Rodgman --- library/constant_time.c | 52 +++++++++-------------------------------- 1 file changed, 11 insertions(+), 41 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index c60ec84550..d4bd331d2e 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -129,48 +129,18 @@ int mbedtls_ct_memcmp(const void *a, void mbedtls_ct_memmove_left(void *start, size_t total, size_t offset) { - /* In case of inlining, ensure that code generated is independent of the value of offset - * (e.g., if the compiler knows that offset == 0, it might be able to optimise this function - * to a no-op). */ - size_t hidden_offset = mbedtls_ct_compiler_opaque(offset); - - /* During this loop, j will take every value from [0..total) exactly once, - * regardless of the value of hidden_offset (it only changes the initial - * value for j). - * - * For this reason, when testing, it is safe to mark hidden_offset as non-secret. - * This prevents the const-flow checkers from generating a false-positive. - */ - TEST_CF_PUBLIC(&hidden_offset, sizeof(hidden_offset)); - - /* Iterate over the array, reading each byte once and writing each byte once. */ + volatile unsigned char *buf = start; for (size_t i = 0; i < total; i++) { - /* Each iteration, read one byte, and write it to start[i]. - * - * The source address will either be the "true" source address, if it's in the range - * where data is getting moved, or (if the source address is off the end of the - * array), it will wrap back to the start. - * - * If the source address is out of range, mask it to zero. - */ - - // The offset that we will read from (if in range) - size_t j = i + hidden_offset; - - // Is the address off the end of the array? - mbedtls_ct_condition_t not_dummy = mbedtls_ct_bool_lt(j, total); - - // Bring read address into range - j = j % total; - - // Read a byte - uint8_t b = ((uint8_t *) start)[j]; - - // Set it to zero if it's out of range - b = mbedtls_ct_uint_if0(not_dummy, b); - - // Write the byte to start[i] - ((uint8_t *) start)[i] = b; + mbedtls_ct_condition_t no_op = mbedtls_ct_bool_gt(total - offset, i); + /* The first `total - offset` passes are a no-op. The last + * `offset` passes shift the data one byte to the left and + * zero out the last byte. */ + for (size_t n = 0; n < total - 1; n++) { + unsigned char current = buf[n]; + unsigned char next = buf[n+1]; + buf[n] = mbedtls_ct_uint_if(no_op, current, next); + } + buf[total-1] = mbedtls_ct_uint_if0(no_op, buf[total-1]); } } From fd78c34e23c95a49b0c0790b714aee7cd85335c9 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Mon, 31 Jul 2023 12:38:55 +0100 Subject: [PATCH 66/82] Move constant_flow.h into the main library Signed-off-by: Dave Rodgman --- {tests/include/test => library}/constant_flow.h | 0 library/constant_time.c | 2 +- library/constant_time_impl.h | 2 +- tests/src/helpers.c | 2 +- tests/suites/test_suite_base64.function | 2 +- tests/suites/test_suite_bignum.function | 2 +- tests/suites/test_suite_bignum_core.function | 2 +- tests/suites/test_suite_bignum_mod.function | 2 +- tests/suites/test_suite_bignum_mod_raw.function | 2 +- tests/suites/test_suite_constant_time.function | 2 +- tests/suites/test_suite_constant_time_hmac.function | 2 +- tests/suites/test_suite_ssl.function | 2 +- 12 files changed, 11 insertions(+), 11 deletions(-) rename {tests/include/test => library}/constant_flow.h (100%) diff --git a/tests/include/test/constant_flow.h b/library/constant_flow.h similarity index 100% rename from tests/include/test/constant_flow.h rename to library/constant_flow.h diff --git a/library/constant_time.c b/library/constant_time.c index d4bd331d2e..61fb094d91 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -30,7 +30,7 @@ #include "mbedtls/error.h" #include "mbedtls/platform_util.h" -#include "../tests/include/test/constant_flow.h" +#include "constant_flow.h" #include diff --git a/library/constant_time_impl.h b/library/constant_time_impl.h index b2ef73f700..1bb07b3e91 100644 --- a/library/constant_time_impl.h +++ b/library/constant_time_impl.h @@ -37,7 +37,7 @@ #include "mbedtls/bignum.h" #endif -#include "../tests/include/test/constant_flow.h" +#include "constant_flow.h" /* armcc5 --gnu defines __GNUC__ but doesn't support GNU's extended asm */ #if defined(MBEDTLS_HAVE_ASM) && defined(__GNUC__) && (!defined(__ARMCC_VERSION) || \ diff --git a/tests/src/helpers.c b/tests/src/helpers.c index 30fd362c01..1062560f20 100644 --- a/tests/src/helpers.c +++ b/tests/src/helpers.c @@ -15,7 +15,7 @@ * limitations under the License. */ -#include +#include "constant_flow.h" #include #include #include diff --git a/tests/suites/test_suite_base64.function b/tests/suites/test_suite_base64.function index e351ad8a25..acdfbea3c6 100644 --- a/tests/suites/test_suite_base64.function +++ b/tests/suites/test_suite_base64.function @@ -2,7 +2,7 @@ #include "mbedtls/base64.h" #include "base64_internal.h" #include "constant_time_internal.h" -#include +#include "constant_flow.h" #if defined(MBEDTLS_TEST_HOOKS) static const char base64_digits[] = diff --git a/tests/suites/test_suite_bignum.function b/tests/suites/test_suite_bignum.function index caa7e0467e..edb3695539 100644 --- a/tests/suites/test_suite_bignum.function +++ b/tests/suites/test_suite_bignum.function @@ -3,7 +3,7 @@ #include "mbedtls/entropy.h" #include "constant_time_internal.h" #include "bignum_core.h" -#include "test/constant_flow.h" +#include "constant_flow.h" #if MBEDTLS_MPI_MAX_BITS > 792 #define MPI_MAX_BITS_LARGER_THAN_792 diff --git a/tests/suites/test_suite_bignum_core.function b/tests/suites/test_suite_bignum_core.function index 7ac03d0009..32889203e2 100644 --- a/tests/suites/test_suite_bignum_core.function +++ b/tests/suites/test_suite_bignum_core.function @@ -3,7 +3,7 @@ #include "mbedtls/entropy.h" #include "bignum_core.h" #include "constant_time_internal.h" -#include "test/constant_flow.h" +#include "constant_flow.h" /** Verifies mbedtls_mpi_core_add(). * diff --git a/tests/suites/test_suite_bignum_mod.function b/tests/suites/test_suite_bignum_mod.function index 4edc0b90eb..f166079cf7 100644 --- a/tests/suites/test_suite_bignum_mod.function +++ b/tests/suites/test_suite_bignum_mod.function @@ -4,7 +4,7 @@ #include "bignum_mod.h" #include "bignum_mod_raw.h" #include "constant_time_internal.h" -#include "test/constant_flow.h" +#include "constant_flow.h" #define TEST_COMPARE_MPI_RESIDUES(a, b) \ ASSERT_COMPARE((a).p, (a).limbs * sizeof(mbedtls_mpi_uint), \ diff --git a/tests/suites/test_suite_bignum_mod_raw.function b/tests/suites/test_suite_bignum_mod_raw.function index b67ac51df1..db4c20f3b8 100644 --- a/tests/suites/test_suite_bignum_mod_raw.function +++ b/tests/suites/test_suite_bignum_mod_raw.function @@ -4,7 +4,7 @@ #include "bignum_core.h" #include "bignum_mod_raw.h" #include "constant_time_internal.h" -#include "test/constant_flow.h" +#include "constant_flow.h" #include "bignum_mod_raw_invasive.h" diff --git a/tests/suites/test_suite_constant_time.function b/tests/suites/test_suite_constant_time.function index bdd27f53dd..330dc6fd6d 100644 --- a/tests/suites/test_suite_constant_time.function +++ b/tests/suites/test_suite_constant_time.function @@ -18,7 +18,7 @@ #include #include -#include +#include "constant_flow.h" /* END_HEADER */ /* BEGIN_CASE */ diff --git a/tests/suites/test_suite_constant_time_hmac.function b/tests/suites/test_suite_constant_time_hmac.function index 902acfa2b0..b7cfb6686e 100644 --- a/tests/suites/test_suite_constant_time_hmac.function +++ b/tests/suites/test_suite_constant_time_hmac.function @@ -5,7 +5,7 @@ #include #include "md_psa.h" -#include +#include "constant_flow.h" /* END_HEADER */ /* BEGIN_CASE depends_on:MBEDTLS_SSL_SOME_SUITES_USE_MAC:MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC:MBEDTLS_TEST_HOOKS */ diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index a8c714f391..eadf715584 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -8,7 +8,7 @@ #include #include -#include +#include "constant_flow.h" #define SSL_MESSAGE_QUEUE_INIT { NULL, 0, 0, 0 } From d175d524330d4df2292bcbfa459562cb45558ee4 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Mon, 31 Jul 2023 14:03:08 +0100 Subject: [PATCH 67/82] Fix doxygen error Signed-off-by: Dave Rodgman --- library/constant_flow.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/constant_flow.h b/library/constant_flow.h index ff464e617c..9554cfc036 100644 --- a/library/constant_flow.h +++ b/library/constant_flow.h @@ -26,7 +26,7 @@ #include "mbedtls/build_info.h" -/* +/** * This file defines the two macros * * #define TEST_CF_SECRET(ptr, size) From 3d1bb9be06e3293742dc16bbd0703b0d2c1c2c80 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Mon, 31 Jul 2023 16:34:17 +0100 Subject: [PATCH 68/82] Revert "Fix doxygen error" This reverts commit d175d524330d4df2292bcbfa459562cb45558ee4. Signed-off-by: Dave Rodgman --- library/constant_flow.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/constant_flow.h b/library/constant_flow.h index 9554cfc036..ff464e617c 100644 --- a/library/constant_flow.h +++ b/library/constant_flow.h @@ -26,7 +26,7 @@ #include "mbedtls/build_info.h" -/** +/* * This file defines the two macros * * #define TEST_CF_SECRET(ptr, size) From 378280e57fd9862bb20df7b70bc7b4327101af23 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Mon, 31 Jul 2023 16:34:19 +0100 Subject: [PATCH 69/82] Revert "Move constant_flow.h into the main library" This reverts commit fd78c34e23c95a49b0c0790b714aee7cd85335c9. Signed-off-by: Dave Rodgman --- library/constant_time.c | 2 +- library/constant_time_impl.h | 2 +- {library => tests/include/test}/constant_flow.h | 0 tests/src/helpers.c | 2 +- tests/suites/test_suite_base64.function | 2 +- tests/suites/test_suite_bignum.function | 2 +- tests/suites/test_suite_bignum_core.function | 2 +- tests/suites/test_suite_bignum_mod.function | 2 +- tests/suites/test_suite_bignum_mod_raw.function | 2 +- tests/suites/test_suite_constant_time.function | 2 +- tests/suites/test_suite_constant_time_hmac.function | 2 +- tests/suites/test_suite_ssl.function | 2 +- 12 files changed, 11 insertions(+), 11 deletions(-) rename {library => tests/include/test}/constant_flow.h (100%) diff --git a/library/constant_time.c b/library/constant_time.c index 61fb094d91..d4bd331d2e 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -30,7 +30,7 @@ #include "mbedtls/error.h" #include "mbedtls/platform_util.h" -#include "constant_flow.h" +#include "../tests/include/test/constant_flow.h" #include diff --git a/library/constant_time_impl.h b/library/constant_time_impl.h index 1bb07b3e91..b2ef73f700 100644 --- a/library/constant_time_impl.h +++ b/library/constant_time_impl.h @@ -37,7 +37,7 @@ #include "mbedtls/bignum.h" #endif -#include "constant_flow.h" +#include "../tests/include/test/constant_flow.h" /* armcc5 --gnu defines __GNUC__ but doesn't support GNU's extended asm */ #if defined(MBEDTLS_HAVE_ASM) && defined(__GNUC__) && (!defined(__ARMCC_VERSION) || \ diff --git a/library/constant_flow.h b/tests/include/test/constant_flow.h similarity index 100% rename from library/constant_flow.h rename to tests/include/test/constant_flow.h diff --git a/tests/src/helpers.c b/tests/src/helpers.c index 1062560f20..30fd362c01 100644 --- a/tests/src/helpers.c +++ b/tests/src/helpers.c @@ -15,7 +15,7 @@ * limitations under the License. */ -#include "constant_flow.h" +#include #include #include #include diff --git a/tests/suites/test_suite_base64.function b/tests/suites/test_suite_base64.function index acdfbea3c6..e351ad8a25 100644 --- a/tests/suites/test_suite_base64.function +++ b/tests/suites/test_suite_base64.function @@ -2,7 +2,7 @@ #include "mbedtls/base64.h" #include "base64_internal.h" #include "constant_time_internal.h" -#include "constant_flow.h" +#include #if defined(MBEDTLS_TEST_HOOKS) static const char base64_digits[] = diff --git a/tests/suites/test_suite_bignum.function b/tests/suites/test_suite_bignum.function index edb3695539..caa7e0467e 100644 --- a/tests/suites/test_suite_bignum.function +++ b/tests/suites/test_suite_bignum.function @@ -3,7 +3,7 @@ #include "mbedtls/entropy.h" #include "constant_time_internal.h" #include "bignum_core.h" -#include "constant_flow.h" +#include "test/constant_flow.h" #if MBEDTLS_MPI_MAX_BITS > 792 #define MPI_MAX_BITS_LARGER_THAN_792 diff --git a/tests/suites/test_suite_bignum_core.function b/tests/suites/test_suite_bignum_core.function index 32889203e2..7ac03d0009 100644 --- a/tests/suites/test_suite_bignum_core.function +++ b/tests/suites/test_suite_bignum_core.function @@ -3,7 +3,7 @@ #include "mbedtls/entropy.h" #include "bignum_core.h" #include "constant_time_internal.h" -#include "constant_flow.h" +#include "test/constant_flow.h" /** Verifies mbedtls_mpi_core_add(). * diff --git a/tests/suites/test_suite_bignum_mod.function b/tests/suites/test_suite_bignum_mod.function index f166079cf7..4edc0b90eb 100644 --- a/tests/suites/test_suite_bignum_mod.function +++ b/tests/suites/test_suite_bignum_mod.function @@ -4,7 +4,7 @@ #include "bignum_mod.h" #include "bignum_mod_raw.h" #include "constant_time_internal.h" -#include "constant_flow.h" +#include "test/constant_flow.h" #define TEST_COMPARE_MPI_RESIDUES(a, b) \ ASSERT_COMPARE((a).p, (a).limbs * sizeof(mbedtls_mpi_uint), \ diff --git a/tests/suites/test_suite_bignum_mod_raw.function b/tests/suites/test_suite_bignum_mod_raw.function index db4c20f3b8..b67ac51df1 100644 --- a/tests/suites/test_suite_bignum_mod_raw.function +++ b/tests/suites/test_suite_bignum_mod_raw.function @@ -4,7 +4,7 @@ #include "bignum_core.h" #include "bignum_mod_raw.h" #include "constant_time_internal.h" -#include "constant_flow.h" +#include "test/constant_flow.h" #include "bignum_mod_raw_invasive.h" diff --git a/tests/suites/test_suite_constant_time.function b/tests/suites/test_suite_constant_time.function index 330dc6fd6d..bdd27f53dd 100644 --- a/tests/suites/test_suite_constant_time.function +++ b/tests/suites/test_suite_constant_time.function @@ -18,7 +18,7 @@ #include #include -#include "constant_flow.h" +#include /* END_HEADER */ /* BEGIN_CASE */ diff --git a/tests/suites/test_suite_constant_time_hmac.function b/tests/suites/test_suite_constant_time_hmac.function index b7cfb6686e..902acfa2b0 100644 --- a/tests/suites/test_suite_constant_time_hmac.function +++ b/tests/suites/test_suite_constant_time_hmac.function @@ -5,7 +5,7 @@ #include #include "md_psa.h" -#include "constant_flow.h" +#include /* END_HEADER */ /* BEGIN_CASE depends_on:MBEDTLS_SSL_SOME_SUITES_USE_MAC:MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC:MBEDTLS_TEST_HOOKS */ diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index eadf715584..a8c714f391 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -8,7 +8,7 @@ #include #include -#include "constant_flow.h" +#include #define SSL_MESSAGE_QUEUE_INIT { NULL, 0, 0, 0 } From 3d574da6fc0e7ddbb61fad2717d930586ed58bea Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Mon, 31 Jul 2023 16:54:00 +0100 Subject: [PATCH 70/82] Revert to not enabling asm under Memsan Signed-off-by: Dave Rodgman --- library/constant_time_impl.h | 24 +++++++++--------------- tests/include/test/constant_flow.h | 25 ------------------------- 2 files changed, 9 insertions(+), 40 deletions(-) diff --git a/library/constant_time_impl.h b/library/constant_time_impl.h index b2ef73f700..8570928070 100644 --- a/library/constant_time_impl.h +++ b/library/constant_time_impl.h @@ -37,11 +37,18 @@ #include "mbedtls/bignum.h" #endif -#include "../tests/include/test/constant_flow.h" +/* Disable asm under Memsan because it confuses Memsan and generates false errors */ +#if defined(MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN) +#define MBEDTLS_CT_NO_ASM +#elif defined(__has_feature) +#if __has_feature(memory_sanitizer) +#define MBEDTLS_CT_NO_ASM +#endif +#endif /* armcc5 --gnu defines __GNUC__ but doesn't support GNU's extended asm */ #if defined(MBEDTLS_HAVE_ASM) && defined(__GNUC__) && (!defined(__ARMCC_VERSION) || \ - __ARMCC_VERSION >= 6000000) + __ARMCC_VERSION >= 6000000) && !defined(MBEDTLS_CT_NO_ASM) #define MBEDTLS_CT_ASM #if (defined(__arm__) || defined(__thumb__) || defined(__thumb2__)) #define MBEDTLS_CT_ARM_ASM @@ -84,20 +91,7 @@ extern volatile mbedtls_ct_uint_t mbedtls_ct_zero; static inline mbedtls_ct_uint_t mbedtls_ct_compiler_opaque(mbedtls_ct_uint_t x) { #if defined(MBEDTLS_CT_ASM) - /* Prevent false positives from Memsan - otherwise it will report the asm as - * accessing secret data. */ - TEST_CF_SAVE_SECRET(x); - asm volatile ("" : [x] "+r" (x) :); - - /* Mark the return value as secret (if it was previously marked secret). - * This is needed so that code of the form: - * - * if (mbedtls_ct_compiler_opaque(secret)) { ... } - * - * will fail const-flow tests. - */ - TEST_CF_RESTORE_SECRET(x); return x; #else return x ^ mbedtls_ct_zero; diff --git a/tests/include/test/constant_flow.h b/tests/include/test/constant_flow.h index ff464e617c..f3d676e285 100644 --- a/tests/include/test/constant_flow.h +++ b/tests/include/test/constant_flow.h @@ -32,27 +32,14 @@ * #define TEST_CF_SECRET(ptr, size) * #define TEST_CF_PUBLIC(ptr, size) * - * and - * - * #define TEST_CF_SAVE_SECRET(variable) - * #define TEST_CF_RESTORE_SECRET(variable) - * * that can be used in tests to mark a memory area as secret (no branch or * memory access should depend on it) or public (default, only needs to be * marked explicitly when it was derived from secret data). * - * The SAVE/RESTORE forms mark a variable as public, and subsequently restore its - * previous secret/not-secret state. This is used where library code is generating - * false positives and needs to temporarily disable Memsan checks for a particular - * variable, and then restore it's original state afterwards so it doesn't interfere - * with other checks. - * * Arguments: * - ptr: a pointer to the memory area to be marked * - size: the size in bytes of the memory area * - * - variable: a variable name - * * Implementation: * The basic idea is that of ctgrind : we can * re-use tools that were designed for checking use of uninitialized memory. @@ -76,12 +63,6 @@ #define TEST_CF_PUBLIC __msan_unpoison // void __msan_unpoison(const volatile void *a, size_t size); -#define TEST_CF_SAVE_SECRET(_x) \ - int _test_cf_is_public_ ## _x = __msan_test_shadow(&(_x), sizeof(_x)) == -1; \ - TEST_CF_PUBLIC(&(_x), sizeof(_x)); -#define TEST_CF_RESTORE_SECRET(_x) \ - if (!_test_cf_is_public_ ## _x) TEST_CF_SECRET(&(_x), sizeof(_x)); - #elif defined(MBEDTLS_TEST_CONSTANT_FLOW_VALGRIND) #include @@ -90,18 +71,12 @@ #define TEST_CF_PUBLIC VALGRIND_MAKE_MEM_DEFINED // VALGRIND_MAKE_MEM_DEFINED(_qzz_addr, _qzz_len) -#define TEST_CF_SAVE_SECRET(_x) -#define TEST_CF_RESTORE_SECRET(_x) - #else /* MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN || MBEDTLS_TEST_CONSTANT_FLOW_VALGRIND */ #define TEST_CF_SECRET(ptr, size) #define TEST_CF_PUBLIC(ptr, size) -#define TEST_CF_SAVE_SECRET(_x) -#define TEST_CF_RESTORE_SECRET(_x) - #endif /* MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN || MBEDTLS_TEST_CONSTANT_FLOW_VALGRIND */ From 926d8da47ef3b688b9519891db1e327fb83007eb Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Mon, 31 Jul 2023 17:28:26 +0100 Subject: [PATCH 71/82] Fix test dependency Signed-off-by: Dave Rodgman --- tests/suites/test_suite_constant_time.function | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/suites/test_suite_constant_time.function b/tests/suites/test_suite_constant_time.function index bdd27f53dd..12ad686b9a 100644 --- a/tests/suites/test_suite_constant_time.function +++ b/tests/suites/test_suite_constant_time.function @@ -346,7 +346,7 @@ exit: } /* END_CASE */ -/* BEGIN_CASE depends_on:MBEDTLS_SSL_SOME_SUITES_USE_MAC */ +/* BEGIN_CASE */ void mbedtls_ct_memcpy_offset(int offset_min, int offset_max, int len) { unsigned char *dst = NULL; From 1f39f037bf5cb33420db8fc992b9504d85e2bc60 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Tue, 1 Aug 2023 09:19:16 +0100 Subject: [PATCH 72/82] Improve variable name in mbedtls_mpi_lt_mpi_ct Signed-off-by: Dave Rodgman --- library/bignum.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/library/bignum.c b/library/bignum.c index aa5f818c40..de652c3090 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -61,7 +61,7 @@ int mbedtls_mpi_lt_mpi_ct(const mbedtls_mpi *X, const mbedtls_mpi *Y, unsigned *ret) { - mbedtls_ct_condition_t cond, X_is_negative, Y_is_negative, result; + mbedtls_ct_condition_t different_sign, X_is_negative, Y_is_negative, result; MPI_VALIDATE_RET(X != NULL); MPI_VALIDATE_RET(Y != NULL); @@ -83,8 +83,8 @@ int mbedtls_mpi_lt_mpi_ct(const mbedtls_mpi *X, * That is if X is negative (X_is_negative == 1), then X < Y is true and it * is false if X is positive (X_is_negative == 0). */ - cond = mbedtls_ct_bool_xor(X_is_negative, Y_is_negative); // non-zero if different sign - result = mbedtls_ct_bool_and(cond, X_is_negative); + different_sign = mbedtls_ct_bool_xor(X_is_negative, Y_is_negative); // non-zero if different sign + result = mbedtls_ct_bool_and(different_sign, X_is_negative); /* * Assuming signs are the same, compare X and Y. We switch the comparison @@ -98,10 +98,11 @@ int mbedtls_mpi_lt_mpi_ct(const mbedtls_mpi *X, mbedtls_ct_condition_t lt = mbedtls_mpi_core_lt_ct(p[i], p[i ^ 1], X->n); /* - * Store in result iff the signs are the same (i.e., iff cond == false). If + * Store in result iff the signs are the same (i.e., iff different_sign == false). If * the signs differ, result has already been set, so we don't change it. */ - result = mbedtls_ct_bool_or(result, mbedtls_ct_bool_and(mbedtls_ct_bool_not(cond), lt)); + result = mbedtls_ct_bool_or(result, + mbedtls_ct_bool_and(mbedtls_ct_bool_not(different_sign), lt)); *ret = mbedtls_ct_uint_if0(result, 1); From 205295c57655f40d953b5903b337ff9fdc2654e4 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Tue, 1 Aug 2023 14:10:56 +0100 Subject: [PATCH 73/82] Tidy-up: move GCC warning fix to constant_time_impl.h Signed-off-by: Dave Rodgman --- library/constant_time_impl.h | 15 +++++++++++++++ library/constant_time_internal.h | 21 +++++---------------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/library/constant_time_impl.h b/library/constant_time_impl.h index 8570928070..1fa655d663 100644 --- a/library/constant_time_impl.h +++ b/library/constant_time_impl.h @@ -37,6 +37,17 @@ #include "mbedtls/bignum.h" #endif +/* constant_time_impl.h contains all the static inline implementations, + * so that constant_time_internal.h is more readable. + * + * gcc generates warnings about duplicate declarations, so disable this + * warning. + */ +#ifdef __GNUC__ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wredundant-decls" +#endif + /* Disable asm under Memsan because it confuses Memsan and generates false errors */ #if defined(MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN) #define MBEDTLS_CT_NO_ASM @@ -288,4 +299,8 @@ static inline mbedtls_ct_condition_t mbedtls_ct_bool_not(mbedtls_ct_condition_t return (mbedtls_ct_condition_t) (~x); } +#ifdef __GNUC__ + #pragma GCC diagnostic pop +#endif + #endif /* MBEDTLS_CONSTANT_TIME_IMPL_H */ diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h index 1411e14921..6d549f16ff 100644 --- a/library/constant_time_internal.h +++ b/library/constant_time_internal.h @@ -68,6 +68,9 @@ * architectures, it uses a plain C fallback designed to yield constant-time code * (this has been observed to be constant-time on latest gcc, clang and MSVC * as of May 2023). + * + * For readability, the static inline definitions are separated out into + * constant_time_impl.h. */ #if (SIZE_MAX > 0xffffffffffffffffULL) @@ -91,19 +94,6 @@ typedef int32_t mbedtls_ct_int_t; #endif #define MBEDTLS_CT_FALSE ((mbedtls_ct_condition_t) mbedtls_ct_compiler_opaque(0)) -/* constant_time_impl.h contains all the static inline implementations, - * so that constant_time_internal.h is more readable. - * - * gcc generates warnings about duplicate declarations, so disable this - * warning. - */ -#ifdef __GNUC__ - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wredundant-decls" -#endif - -#include "constant_time_impl.h" - /* ============================================================================ * Boolean operations */ @@ -483,8 +473,7 @@ void mbedtls_ct_memcpy_offset(unsigned char *dest, size_t n); */ -#ifdef __GNUC__ - #pragma GCC diagnostic pop -#endif +/* Include the implementation of static inline functions above. */ +#include "constant_time_impl.h" #endif /* MBEDTLS_CONSTANT_TIME_INTERNAL_H */ From 56e5d6887fa2f60f15a1bbd853360c94fe48500e Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Tue, 1 Aug 2023 15:04:11 +0100 Subject: [PATCH 74/82] Fix comment typo Co-authored-by: Tom Cosgrove Signed-off-by: Dave Rodgman --- include/mbedtls/constant_time.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mbedtls/constant_time.h b/include/mbedtls/constant_time.h index 49bb375d4e..ebecf35b09 100644 --- a/include/mbedtls/constant_time.h +++ b/include/mbedtls/constant_time.h @@ -26,7 +26,7 @@ /** Constant-time buffer comparison without branches. * * This is equivalent to the standard memcmp function, but is likely to be - * compiled to code using bitwise operation rather than a branch, such that + * compiled to code using bitwise operations rather than a branch, such that * the time taken is constant w.r.t. the data pointed to by \p a and \p b, * and w.r.t. whether \p a and \p b are equal or not. It is not constant-time * w.r.t. \p n . From 4dd89310e96817f6e6a67cbec99395db7074d1f6 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Mon, 7 Aug 2023 11:49:12 +0100 Subject: [PATCH 75/82] Update w.r.t. test macro name changes from #6253 Signed-off-by: Dave Rodgman --- tests/suites/test_suite_constant_time.function | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/suites/test_suite_constant_time.function b/tests/suites/test_suite_constant_time.function index bc3eb05103..7cf69937bd 100644 --- a/tests/suites/test_suite_constant_time.function +++ b/tests/suites/test_suite_constant_time.function @@ -152,7 +152,7 @@ void mbedtls_ct_zeroize_if(char *c_str, int len) uint8_t *buf = NULL; mbedtls_ct_condition_t c = mbedtls_ct_bool(strtoull(c_str, NULL, 16)); - ASSERT_ALLOC(buf, len); + TEST_CALLOC(buf, len); for (size_t i = 0; i < (size_t) len; i++) { buf[i] = 1; } @@ -321,8 +321,8 @@ void mbedtls_ct_memmove_left(int len, int offset) size_t o = (size_t) offset; uint8_t *buf = NULL, *buf_expected = NULL; - ASSERT_ALLOC(buf, l); - ASSERT_ALLOC(buf_expected, l); + TEST_CALLOC(buf, l); + TEST_CALLOC(buf_expected, l); for (size_t i = 0; i < l; i++) { buf[i] = (uint8_t) i; From b7825ceb3edcfed059ff8ccbff01d0086263b217 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Thu, 10 Aug 2023 11:58:18 +0100 Subject: [PATCH 76/82] Rename uint->bool operators to reflect input types Signed-off-by: Dave Rodgman --- library/bignum.c | 2 +- library/bignum_core.c | 8 ++++---- library/constant_time.c | 4 ++-- library/constant_time_impl.h | 20 +++++++++---------- library/constant_time_internal.h | 15 +++++++------- library/rsa.c | 8 ++++---- library/ssl_msg.c | 12 +++++------ library/ssl_tls12_server.c | 6 +++--- .../suites/test_suite_constant_time.function | 12 +++++------ 9 files changed, 44 insertions(+), 43 deletions(-) diff --git a/library/bignum.c b/library/bignum.c index 8a061dfbda..2a7786f4c0 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -1728,7 +1728,7 @@ static int mpi_select(mbedtls_mpi *R, const mbedtls_mpi *T, size_t T_size, size_ for (size_t i = 0; i < T_size; i++) { MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_assign(R, &T[i], - (unsigned char) mbedtls_ct_bool_eq(i, idx))); + (unsigned char) mbedtls_ct_uint_eq(i, idx))); } cleanup: return ret; diff --git a/library/bignum_core.c b/library/bignum_core.c index cae8905c6d..157ac078e2 100644 --- a/library/bignum_core.c +++ b/library/bignum_core.c @@ -149,7 +149,7 @@ mbedtls_ct_condition_t mbedtls_mpi_core_uint_le_mpi(mbedtls_mpi_uint min, size_t A_limbs) { /* min <= least significant limb? */ - mbedtls_ct_condition_t min_le_lsl = mbedtls_ct_bool_ge(A[0], min); + mbedtls_ct_condition_t min_le_lsl = mbedtls_ct_uint_ge(A[0], min); /* limbs other than the least significant one are all zero? */ mbedtls_ct_condition_t msll_mask = MBEDTLS_CT_FALSE; @@ -176,7 +176,7 @@ mbedtls_ct_condition_t mbedtls_mpi_core_lt_ct(const mbedtls_mpi_uint *A, * Again even if we can make a decision, we just mark the result and * the fact that we are done and continue looping. */ - cond = mbedtls_ct_bool_lt(B[i - 1], A[i - 1]); + cond = mbedtls_ct_uint_lt(B[i - 1], A[i - 1]); done = mbedtls_ct_bool_or(done, cond); /* @@ -185,7 +185,7 @@ mbedtls_ct_condition_t mbedtls_mpi_core_lt_ct(const mbedtls_mpi_uint *A, * Again even if we can make a decision, we just mark the result and * the fact that we are done and continue looping. */ - cond = mbedtls_ct_bool_lt(A[i - 1], B[i - 1]); + cond = mbedtls_ct_uint_lt(A[i - 1], B[i - 1]); ret = mbedtls_ct_bool_or(ret, mbedtls_ct_bool_and(cond, mbedtls_ct_bool_not(done))); done = mbedtls_ct_bool_or(done, cond); } @@ -634,7 +634,7 @@ void mbedtls_mpi_core_ct_uint_table_lookup(mbedtls_mpi_uint *dest, size_t index) { for (size_t i = 0; i < count; i++, table += limbs) { - mbedtls_ct_condition_t assign = mbedtls_ct_bool_eq(i, index); + mbedtls_ct_condition_t assign = mbedtls_ct_uint_eq(i, index); mbedtls_mpi_core_cond_assign(dest, table, limbs, assign); } } diff --git a/library/constant_time.c b/library/constant_time.c index d4bd331d2e..20e215a79b 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -131,7 +131,7 @@ void mbedtls_ct_memmove_left(void *start, size_t total, size_t offset) { volatile unsigned char *buf = start; for (size_t i = 0; i < total; i++) { - mbedtls_ct_condition_t no_op = mbedtls_ct_bool_gt(total - offset, i); + mbedtls_ct_condition_t no_op = mbedtls_ct_uint_gt(total - offset, i); /* The first `total - offset` passes are a no-op. The last * `offset` passes shift the data one byte to the left and * zero out the last byte. */ @@ -188,7 +188,7 @@ void mbedtls_ct_memcpy_offset(unsigned char *dest, size_t offsetval; for (offsetval = offset_min; offsetval <= offset_max; offsetval++) { - mbedtls_ct_memcpy_if(mbedtls_ct_bool_eq(offsetval, offset), dest, src + offsetval, NULL, + mbedtls_ct_memcpy_if(mbedtls_ct_uint_eq(offsetval, offset), dest, src + offsetval, NULL, len); } } diff --git a/library/constant_time_impl.h b/library/constant_time_impl.h index 1fa655d663..1660c12607 100644 --- a/library/constant_time_impl.h +++ b/library/constant_time_impl.h @@ -143,7 +143,7 @@ static inline mbedtls_ct_uint_t mbedtls_ct_if(mbedtls_ct_condition_t condition, return (mbedtls_ct_uint_t) ((condition & if1) | (not_cond & if0)); } -static inline mbedtls_ct_condition_t mbedtls_ct_bool_lt(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y) +static inline mbedtls_ct_condition_t mbedtls_ct_uint_lt(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y) { /* Ensure that the compiler cannot optimise the following operations over x and y, * even if it knows the value of x and y. @@ -175,7 +175,7 @@ static inline mbedtls_ct_condition_t mbedtls_ct_bool_lt(mbedtls_ct_uint_t x, mbe return mbedtls_ct_bool(ret); } -static inline mbedtls_ct_condition_t mbedtls_ct_bool_ne(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y) +static inline mbedtls_ct_condition_t mbedtls_ct_uint_ne(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y) { /* diff = 0 if x == y, non-zero otherwise */ const mbedtls_ct_uint_t diff = mbedtls_ct_compiler_opaque(x) ^ mbedtls_ct_compiler_opaque(y); @@ -252,28 +252,28 @@ static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if0(mbedtls_ct_condition_t co #endif /* MBEDTLS_BIGNUM_C */ -static inline mbedtls_ct_condition_t mbedtls_ct_bool_eq(mbedtls_ct_uint_t x, +static inline mbedtls_ct_condition_t mbedtls_ct_uint_eq(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y) { - return ~mbedtls_ct_bool_ne(x, y); + return ~mbedtls_ct_uint_ne(x, y); } -static inline mbedtls_ct_condition_t mbedtls_ct_bool_gt(mbedtls_ct_uint_t x, +static inline mbedtls_ct_condition_t mbedtls_ct_uint_gt(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y) { - return mbedtls_ct_bool_lt(y, x); + return mbedtls_ct_uint_lt(y, x); } -static inline mbedtls_ct_condition_t mbedtls_ct_bool_ge(mbedtls_ct_uint_t x, +static inline mbedtls_ct_condition_t mbedtls_ct_uint_ge(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y) { - return ~mbedtls_ct_bool_lt(x, y); + return ~mbedtls_ct_uint_lt(x, y); } -static inline mbedtls_ct_condition_t mbedtls_ct_bool_le(mbedtls_ct_uint_t x, +static inline mbedtls_ct_condition_t mbedtls_ct_uint_le(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y) { - return ~mbedtls_ct_bool_gt(x, y); + return ~mbedtls_ct_uint_gt(x, y); } static inline mbedtls_ct_condition_t mbedtls_ct_bool_xor(mbedtls_ct_condition_t x, diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h index 6d549f16ff..dc4c5f921d 100644 --- a/library/constant_time_internal.h +++ b/library/constant_time_internal.h @@ -37,10 +37,11 @@ * It has three main parts: * * - boolean operations - * These are all named mbedtls_ct_bool_, and operate over + * These are all named mbedtls_ct__, and operate over * mbedtls_ct_condition_t. * All arguments are considered secret. * example: bool x = y | z => x = mbedtls_ct_bool_or(y, z) + * example: bool x = y == z => x = mbedtls_ct_uint_eq(y, z) * * - conditional data selection * These are all named mbedtls_ct__if and mbedtls_ct__if0 @@ -118,7 +119,7 @@ static inline mbedtls_ct_condition_t mbedtls_ct_bool(mbedtls_ct_uint_t x); * * \return MBEDTLS_CT_TRUE if \p x != \p y, otherwise MBEDTLS_CT_FALSE. */ -static inline mbedtls_ct_condition_t mbedtls_ct_bool_ne(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y); +static inline mbedtls_ct_condition_t mbedtls_ct_uint_ne(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y); /** Boolean "equals" operation. * @@ -131,7 +132,7 @@ static inline mbedtls_ct_condition_t mbedtls_ct_bool_ne(mbedtls_ct_uint_t x, mbe * * \return MBEDTLS_CT_TRUE if \p x == \p y, otherwise MBEDTLS_CT_FALSE. */ -static inline mbedtls_ct_condition_t mbedtls_ct_bool_eq(mbedtls_ct_uint_t x, +static inline mbedtls_ct_condition_t mbedtls_ct_uint_eq(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y); /** Boolean "less than" operation. @@ -145,7 +146,7 @@ static inline mbedtls_ct_condition_t mbedtls_ct_bool_eq(mbedtls_ct_uint_t x, * * \return MBEDTLS_CT_TRUE if \p x < \p y, otherwise MBEDTLS_CT_FALSE. */ -static inline mbedtls_ct_condition_t mbedtls_ct_bool_lt(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y); +static inline mbedtls_ct_condition_t mbedtls_ct_uint_lt(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y); /** Boolean "greater than" operation. * @@ -158,7 +159,7 @@ static inline mbedtls_ct_condition_t mbedtls_ct_bool_lt(mbedtls_ct_uint_t x, mbe * * \return MBEDTLS_CT_TRUE if \p x > \p y, otherwise MBEDTLS_CT_FALSE. */ -static inline mbedtls_ct_condition_t mbedtls_ct_bool_gt(mbedtls_ct_uint_t x, +static inline mbedtls_ct_condition_t mbedtls_ct_uint_gt(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y); /** Boolean "greater or equal" operation. @@ -173,7 +174,7 @@ static inline mbedtls_ct_condition_t mbedtls_ct_bool_gt(mbedtls_ct_uint_t x, * \return MBEDTLS_CT_TRUE if \p x >= \p y, * otherwise MBEDTLS_CT_FALSE. */ -static inline mbedtls_ct_condition_t mbedtls_ct_bool_ge(mbedtls_ct_uint_t x, +static inline mbedtls_ct_condition_t mbedtls_ct_uint_ge(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y); /** Boolean "less than or equal" operation. @@ -188,7 +189,7 @@ static inline mbedtls_ct_condition_t mbedtls_ct_bool_ge(mbedtls_ct_uint_t x, * \return MBEDTLS_CT_TRUE if \p x <= \p y, * otherwise MBEDTLS_CT_FALSE. */ -static inline mbedtls_ct_condition_t mbedtls_ct_bool_le(mbedtls_ct_uint_t x, +static inline mbedtls_ct_condition_t mbedtls_ct_uint_le(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y); /** Boolean "xor" operation. diff --git a/library/rsa.c b/library/rsa.c index 182ab21dc5..65caf901bc 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -120,13 +120,13 @@ static int mbedtls_ct_rsaes_pkcs1_v15_unpadding(unsigned char *input, /* Decode EME-PKCS1-v1_5 padding: 0x00 || 0x02 || PS || 0x00 * where PS must be at least 8 nonzero bytes. */ - bad = mbedtls_ct_bool_or(bad, mbedtls_ct_bool_ne(input[1], MBEDTLS_RSA_CRYPT)); + bad = mbedtls_ct_bool_or(bad, mbedtls_ct_uint_ne(input[1], MBEDTLS_RSA_CRYPT)); /* Read the whole buffer. Set pad_done to nonzero if we find * the 0x00 byte and remember the padding length in pad_count. */ pad_done = MBEDTLS_CT_FALSE; for (i = 2; i < ilen; i++) { - mbedtls_ct_condition_t found = mbedtls_ct_bool_eq(input[i], 0); + mbedtls_ct_condition_t found = mbedtls_ct_uint_eq(input[i], 0); pad_done = mbedtls_ct_bool_or(pad_done, found); pad_count += mbedtls_ct_uint_if0(mbedtls_ct_bool_not(pad_done), 1); } @@ -135,7 +135,7 @@ static int mbedtls_ct_rsaes_pkcs1_v15_unpadding(unsigned char *input, bad = mbedtls_ct_bool_or(bad, mbedtls_ct_bool_not(pad_done)); /* There must be at least 8 bytes of padding. */ - bad = mbedtls_ct_bool_or(bad, mbedtls_ct_bool_gt(8, pad_count)); + bad = mbedtls_ct_bool_or(bad, mbedtls_ct_uint_gt(8, pad_count)); /* If the padding is valid, set plaintext_size to the number of * remaining bytes after stripping the padding. If the padding @@ -150,7 +150,7 @@ static int mbedtls_ct_rsaes_pkcs1_v15_unpadding(unsigned char *input, /* Set output_too_large to 0 if the plaintext fits in the output * buffer and to 1 otherwise. */ - output_too_large = mbedtls_ct_bool_gt(plaintext_size, + output_too_large = mbedtls_ct_uint_gt(plaintext_size, plaintext_max_size); /* Set ret without branches to avoid timing attacks. Return: diff --git a/library/ssl_msg.c b/library/ssl_msg.c index 72d5f32755..a72500256b 100644 --- a/library/ssl_msg.c +++ b/library/ssl_msg.c @@ -257,7 +257,7 @@ int mbedtls_ct_hmac(mbedtls_md_context_t *ctx, 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_ct_memcpy_if(mbedtls_ct_bool_eq(offset, data_len_secret), + mbedtls_ct_memcpy_if(mbedtls_ct_uint_eq(offset, data_len_secret), output, aux_out, NULL, hash_size); if (offset < max_data_len) { @@ -1918,7 +1918,7 @@ hmac_failed_etm_enabled: padlen = data[rec->data_len - 1]; if (auth_done == 1) { - const mbedtls_ct_condition_t ge = mbedtls_ct_bool_ge( + const mbedtls_ct_condition_t ge = mbedtls_ct_uint_ge( rec->data_len, padlen + 1); correct = mbedtls_ct_size_if0(ge, correct); @@ -1934,7 +1934,7 @@ hmac_failed_etm_enabled: padlen + 1)); } #endif - const mbedtls_ct_condition_t ge = mbedtls_ct_bool_ge( + const mbedtls_ct_condition_t ge = mbedtls_ct_uint_ge( rec->data_len, transform->maclen + padlen + 1); correct = mbedtls_ct_size_if0(ge, correct); @@ -1967,13 +1967,13 @@ hmac_failed_etm_enabled: /* pad_count += (idx >= padding_idx) && * (check[idx] == padlen - 1); */ - const mbedtls_ct_condition_t a = mbedtls_ct_bool_ge(idx, padding_idx); + const mbedtls_ct_condition_t a = mbedtls_ct_uint_ge(idx, padding_idx); size_t increment = mbedtls_ct_size_if0(a, 1); - const mbedtls_ct_condition_t b = mbedtls_ct_bool_eq(check[idx], padlen - 1); + const mbedtls_ct_condition_t b = mbedtls_ct_uint_eq(check[idx], padlen - 1); increment = mbedtls_ct_size_if0(b, increment); pad_count += increment; } - correct = mbedtls_ct_size_if0(mbedtls_ct_bool_eq(pad_count, padlen), padlen); + correct = mbedtls_ct_size_if0(mbedtls_ct_uint_eq(pad_count, padlen), padlen); #if defined(MBEDTLS_SSL_DEBUG_ALL) if (padlen > 0 && correct == 0) { diff --git a/library/ssl_tls12_server.c b/library/ssl_tls12_server.c index 8d0129b335..34ac0912a3 100644 --- a/library/ssl_tls12_server.c +++ b/library/ssl_tls12_server.c @@ -3537,9 +3537,9 @@ static int ssl_parse_encrypted_pms(mbedtls_ssl_context *ssl, * padding, to protect against timing-based Bleichenbacher-type * attacks. */ diff = mbedtls_ct_bool(ret); - diff = mbedtls_ct_bool_or(diff, mbedtls_ct_bool_ne(peer_pmslen, 48)); - diff = mbedtls_ct_bool_or(diff, mbedtls_ct_bool_ne(peer_pms[0], ver[0])); - diff = mbedtls_ct_bool_or(diff, mbedtls_ct_bool_ne(peer_pms[1], ver[1])); + diff = mbedtls_ct_bool_or(diff, mbedtls_ct_uint_ne(peer_pmslen, 48)); + diff = mbedtls_ct_bool_or(diff, mbedtls_ct_uint_ne(peer_pms[0], ver[0])); + diff = mbedtls_ct_bool_or(diff, mbedtls_ct_uint_ne(peer_pms[1], ver[1])); /* * Protection against Bleichenbacher's attack: invalid PKCS#1 v1.5 padding diff --git a/tests/suites/test_suite_constant_time.function b/tests/suites/test_suite_constant_time.function index 7cf69937bd..80cba79302 100644 --- a/tests/suites/test_suite_constant_time.function +++ b/tests/suites/test_suite_constant_time.function @@ -60,22 +60,22 @@ void mbedtls_ct_bool_xxx(char *x_str, char *y_str) TEST_EQUAL(mbedtls_ct_bool_not(mbedtls_ct_bool(x)), expected); expected = x1 != y1 ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE; - TEST_EQUAL(mbedtls_ct_bool_ne(x, y), expected); + TEST_EQUAL(mbedtls_ct_uint_ne(x, y), expected); expected = x1 == y1 ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE; - TEST_EQUAL(mbedtls_ct_bool_eq(x, y), expected); + TEST_EQUAL(mbedtls_ct_uint_eq(x, y), expected); expected = x1 > y1 ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE; - TEST_EQUAL(mbedtls_ct_bool_gt(x, y), expected); + TEST_EQUAL(mbedtls_ct_uint_gt(x, y), expected); expected = x1 < y1 ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE; - TEST_EQUAL(mbedtls_ct_bool_lt(x, y), expected); + TEST_EQUAL(mbedtls_ct_uint_lt(x, y), expected); expected = x1 >= y1 ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE; - TEST_EQUAL(mbedtls_ct_bool_ge(x, y), expected); + TEST_EQUAL(mbedtls_ct_uint_ge(x, y), expected); expected = x1 <= y1 ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE; - TEST_EQUAL(mbedtls_ct_bool_le(x, y), expected); + TEST_EQUAL(mbedtls_ct_uint_le(x, y), expected); expected = (!!x1) ^ (!!y1) ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE; TEST_EQUAL(mbedtls_ct_bool_xor(mbedtls_ct_bool(x), mbedtls_ct_bool(y)), expected); From 98ddc01a7c9b2d09e7874a696d3ac620a70c032f Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Thu, 10 Aug 2023 12:11:31 +0100 Subject: [PATCH 77/82] Rename ...if0 to ...else_0 Signed-off-by: Dave Rodgman --- library/bignum.c | 6 +++--- library/bignum_core.c | 2 +- library/constant_time.c | 2 +- library/constant_time_impl.h | 8 ++++---- library/constant_time_internal.h | 6 +++--- library/rsa.c | 4 ++-- library/ssl_msg.c | 16 ++++++++-------- tests/suites/test_suite_constant_time.function | 4 ++-- 8 files changed, 24 insertions(+), 24 deletions(-) diff --git a/library/bignum.c b/library/bignum.c index 2a7786f4c0..10bb4312ad 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -94,7 +94,7 @@ int mbedtls_mpi_lt_mpi_ct(const mbedtls_mpi *X, /* This array is used to conditionally swap the pointers in const time */ void * const p[2] = { X->p, Y->p }; - size_t i = mbedtls_ct_size_if0(X_is_negative, 1); + size_t i = mbedtls_ct_size_if_else_0(X_is_negative, 1); mbedtls_ct_condition_t lt = mbedtls_mpi_core_lt_ct(p[i], p[i ^ 1], X->n); /* @@ -104,7 +104,7 @@ int mbedtls_mpi_lt_mpi_ct(const mbedtls_mpi *X, result = mbedtls_ct_bool_or(result, mbedtls_ct_bool_and(mbedtls_ct_bool_not(different_sign), lt)); - *ret = mbedtls_ct_uint_if0(result, 1); + *ret = mbedtls_ct_uint_if_else_0(result, 1); return 0; } @@ -139,7 +139,7 @@ int mbedtls_mpi_safe_cond_assign(mbedtls_mpi *X, mbedtls_ct_condition_t do_not_assign = mbedtls_ct_bool_not(do_assign); for (size_t i = Y->n; i < X->n; i++) { - X->p[i] = mbedtls_ct_mpi_uint_if0(do_not_assign, X->p[i]); + X->p[i] = mbedtls_ct_mpi_uint_if_else_0(do_not_assign, X->p[i]); } cleanup: diff --git a/library/bignum_core.c b/library/bignum_core.c index 157ac078e2..a3c54036ff 100644 --- a/library/bignum_core.c +++ b/library/bignum_core.c @@ -463,7 +463,7 @@ mbedtls_mpi_uint mbedtls_mpi_core_add_if(mbedtls_mpi_uint *X, mbedtls_ct_condition_t do_add = mbedtls_ct_bool(cond); for (size_t i = 0; i < limbs; i++) { - mbedtls_mpi_uint add = mbedtls_ct_mpi_uint_if0(do_add, A[i]); + mbedtls_mpi_uint add = mbedtls_ct_mpi_uint_if_else_0(do_add, A[i]); mbedtls_mpi_uint t = c + X[i]; c = (t < X[i]); t += add; diff --git a/library/constant_time.c b/library/constant_time.c index 20e215a79b..86cc066b03 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -140,7 +140,7 @@ void mbedtls_ct_memmove_left(void *start, size_t total, size_t offset) unsigned char next = buf[n+1]; buf[n] = mbedtls_ct_uint_if(no_op, current, next); } - buf[total-1] = mbedtls_ct_uint_if0(no_op, buf[total-1]); + buf[total-1] = mbedtls_ct_uint_if_else_0(no_op, buf[total-1]); } } diff --git a/library/constant_time_impl.h b/library/constant_time_impl.h index 1660c12607..0c3cde99d1 100644 --- a/library/constant_time_impl.h +++ b/library/constant_time_impl.h @@ -232,20 +232,20 @@ static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if(mbedtls_ct_condition_t con #endif -static inline size_t mbedtls_ct_size_if0(mbedtls_ct_condition_t condition, size_t if1) +static inline size_t mbedtls_ct_size_if_else_0(mbedtls_ct_condition_t condition, size_t if1) { return (size_t) (condition & if1); } -static inline unsigned mbedtls_ct_uint_if0(mbedtls_ct_condition_t condition, unsigned if1) +static inline unsigned mbedtls_ct_uint_if_else_0(mbedtls_ct_condition_t condition, unsigned if1) { return (unsigned) (condition & if1); } #if defined(MBEDTLS_BIGNUM_C) -static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if0(mbedtls_ct_condition_t condition, - mbedtls_mpi_uint if1) +static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if_else_0(mbedtls_ct_condition_t condition, + mbedtls_mpi_uint if1) { return (mbedtls_mpi_uint) (condition & if1); } diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h index dc4c5f921d..664ee5af58 100644 --- a/library/constant_time_internal.h +++ b/library/constant_time_internal.h @@ -323,7 +323,7 @@ static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if(mbedtls_ct_condition_t con * * \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise 0. */ -static inline unsigned mbedtls_ct_uint_if0(mbedtls_ct_condition_t condition, unsigned if1); +static inline unsigned mbedtls_ct_uint_if_else_0(mbedtls_ct_condition_t condition, unsigned if1); #if defined(MBEDTLS_BIGNUM_C) @@ -341,8 +341,8 @@ static inline unsigned mbedtls_ct_uint_if0(mbedtls_ct_condition_t condition, uns * * \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise 0. */ -static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if0(mbedtls_ct_condition_t condition, - mbedtls_mpi_uint if1); +static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if_else_0(mbedtls_ct_condition_t condition, + mbedtls_mpi_uint if1); #endif diff --git a/library/rsa.c b/library/rsa.c index 65caf901bc..d0782f53c7 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -128,7 +128,7 @@ static int mbedtls_ct_rsaes_pkcs1_v15_unpadding(unsigned char *input, for (i = 2; i < ilen; i++) { mbedtls_ct_condition_t found = mbedtls_ct_uint_eq(input[i], 0); pad_done = mbedtls_ct_bool_or(pad_done, found); - pad_count += mbedtls_ct_uint_if0(mbedtls_ct_bool_not(pad_done), 1); + pad_count += mbedtls_ct_uint_if_else_0(mbedtls_ct_bool_not(pad_done), 1); } /* If pad_done is still zero, there's no data, only unfinished padding. */ @@ -161,7 +161,7 @@ static int mbedtls_ct_rsaes_pkcs1_v15_unpadding(unsigned char *input, ret = -(int) mbedtls_ct_uint_if( bad, (unsigned) (-(MBEDTLS_ERR_RSA_INVALID_PADDING)), - mbedtls_ct_uint_if0( + mbedtls_ct_uint_if_else_0( output_too_large, (unsigned) (-(MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE))) ); diff --git a/library/ssl_msg.c b/library/ssl_msg.c index a72500256b..1a9c17e291 100644 --- a/library/ssl_msg.c +++ b/library/ssl_msg.c @@ -1921,8 +1921,8 @@ hmac_failed_etm_enabled: const mbedtls_ct_condition_t ge = mbedtls_ct_uint_ge( rec->data_len, padlen + 1); - correct = mbedtls_ct_size_if0(ge, correct); - padlen = mbedtls_ct_size_if0(ge, padlen); + correct = mbedtls_ct_size_if_else_0(ge, correct); + padlen = mbedtls_ct_size_if_else_0(ge, padlen); } else { #if defined(MBEDTLS_SSL_DEBUG_ALL) if (rec->data_len < transform->maclen + padlen + 1) { @@ -1937,8 +1937,8 @@ hmac_failed_etm_enabled: const mbedtls_ct_condition_t ge = mbedtls_ct_uint_ge( rec->data_len, transform->maclen + padlen + 1); - correct = mbedtls_ct_size_if0(ge, correct); - padlen = mbedtls_ct_size_if0(ge, padlen); + correct = mbedtls_ct_size_if_else_0(ge, correct); + padlen = mbedtls_ct_size_if_else_0(ge, padlen); } padlen++; @@ -1968,19 +1968,19 @@ hmac_failed_etm_enabled: * (check[idx] == padlen - 1); */ const mbedtls_ct_condition_t a = mbedtls_ct_uint_ge(idx, padding_idx); - size_t increment = mbedtls_ct_size_if0(a, 1); + size_t increment = mbedtls_ct_size_if_else_0(a, 1); const mbedtls_ct_condition_t b = mbedtls_ct_uint_eq(check[idx], padlen - 1); - increment = mbedtls_ct_size_if0(b, increment); + increment = mbedtls_ct_size_if_else_0(b, increment); pad_count += increment; } - correct = mbedtls_ct_size_if0(mbedtls_ct_uint_eq(pad_count, padlen), padlen); + correct = mbedtls_ct_size_if_else_0(mbedtls_ct_uint_eq(pad_count, padlen), padlen); #if defined(MBEDTLS_SSL_DEBUG_ALL) if (padlen > 0 && correct == 0) { MBEDTLS_SSL_DEBUG_MSG(1, ("bad padding byte detected")); } #endif - padlen = mbedtls_ct_size_if0(mbedtls_ct_bool(correct), padlen); + padlen = mbedtls_ct_size_if_else_0(mbedtls_ct_bool(correct), padlen); #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ diff --git a/tests/suites/test_suite_constant_time.function b/tests/suites/test_suite_constant_time.function index 80cba79302..a8ba575cff 100644 --- a/tests/suites/test_suite_constant_time.function +++ b/tests/suites/test_suite_constant_time.function @@ -135,9 +135,9 @@ void mbedtls_ct_if(char *c_str, char *t_str, char *f_str) TEST_EQUAL(mbedtls_ct_mpi_uint_if(c, t, f), (mbedtls_mpi_uint) expected); #endif - TEST_EQUAL(mbedtls_ct_uint_if0(c, t), (unsigned) expected0); + TEST_EQUAL(mbedtls_ct_uint_if_else_0(c, t), (unsigned) expected0); #if defined(MBEDTLS_BIGNUM_C) - TEST_EQUAL(mbedtls_ct_mpi_uint_if0(c, t), (mbedtls_mpi_uint) expected0); + TEST_EQUAL(mbedtls_ct_mpi_uint_if_else_0(c, t), (mbedtls_mpi_uint) expected0); #endif TEST_CF_PUBLIC(&c, sizeof(c)); From 065f91246532340df88deae8f7620451ef9529bf Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Thu, 10 Aug 2023 12:11:58 +0100 Subject: [PATCH 78/82] Fix comment typo Signed-off-by: Dave Rodgman --- library/constant_time_internal.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h index 664ee5af58..23caa244e7 100644 --- a/library/constant_time_internal.h +++ b/library/constant_time_internal.h @@ -315,7 +315,7 @@ static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if(mbedtls_ct_condition_t con * * condition ? if1 : 0. * - * Functionally equivalent tombedtls_ct_uint_if(condition, if1, 0) but + * Functionally equivalent to mbedtls_ct_uint_if(condition, if1, 0) but * results in smaller code size. * * \param condition Condition to test. @@ -333,7 +333,7 @@ static inline unsigned mbedtls_ct_uint_if_else_0(mbedtls_ct_condition_t conditio * * condition ? if1 : 0. * - * Functionally equivalent tombedtls_ct_mpi_uint_if(condition, if1, 0) but + * Functionally equivalent to mbedtls_ct_mpi_uint_if(condition, if1, 0) but * results in smaller code size. * * \param condition Condition to test. From ac69b4548697d8bb01df958029b40b7905d19cd7 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Thu, 10 Aug 2023 12:13:27 +0100 Subject: [PATCH 79/82] Document and test mbedtls_ct_size_if_else_0 Signed-off-by: Dave Rodgman --- library/constant_time_internal.h | 16 ++++++++++++++++ tests/suites/test_suite_constant_time.function | 1 + 2 files changed, 17 insertions(+) diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h index 23caa244e7..b6c7ecb215 100644 --- a/library/constant_time_internal.h +++ b/library/constant_time_internal.h @@ -325,6 +325,22 @@ static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if(mbedtls_ct_condition_t con */ static inline unsigned mbedtls_ct_uint_if_else_0(mbedtls_ct_condition_t condition, unsigned if1); +/** Choose between an unsigned value and 0. + * + * Functionally equivalent to: + * + * condition ? if1 : 0. + * + * Functionally equivalent to mbedtls_ct_size_if(condition, if1, 0) but + * results in smaller code size. + * + * \param condition Condition to test. + * \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE. + * + * \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise 0. + */ +static inline size_t mbedtls_ct_size_if_else_0(mbedtls_ct_condition_t condition, size_t if1); + #if defined(MBEDTLS_BIGNUM_C) /** Choose between an mbedtls_mpi_uint value and 0. diff --git a/tests/suites/test_suite_constant_time.function b/tests/suites/test_suite_constant_time.function index a8ba575cff..0e2cfdc0cb 100644 --- a/tests/suites/test_suite_constant_time.function +++ b/tests/suites/test_suite_constant_time.function @@ -136,6 +136,7 @@ void mbedtls_ct_if(char *c_str, char *t_str, char *f_str) #endif TEST_EQUAL(mbedtls_ct_uint_if_else_0(c, t), (unsigned) expected0); + TEST_EQUAL(mbedtls_ct_size_if_else_0(c, (size_t) t), (size_t) expected0); #if defined(MBEDTLS_BIGNUM_C) TEST_EQUAL(mbedtls_ct_mpi_uint_if_else_0(c, t), (mbedtls_mpi_uint) expected0); #endif From 38b227c16beb91f930d0cf661a1075c36b3ba8aa Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Thu, 10 Aug 2023 12:18:27 +0100 Subject: [PATCH 80/82] Improve docs Signed-off-by: Dave Rodgman --- library/constant_time_internal.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h index b6c7ecb215..9f5b1305fd 100644 --- a/library/constant_time_internal.h +++ b/library/constant_time_internal.h @@ -37,8 +37,8 @@ * It has three main parts: * * - boolean operations - * These are all named mbedtls_ct__, and operate over - * mbedtls_ct_condition_t. + * These are all named mbedtls_ct__. + * They operate over and return mbedtls_ct_condition_t. * All arguments are considered secret. * example: bool x = y | z => x = mbedtls_ct_bool_or(y, z) * example: bool x = y == z => x = mbedtls_ct_uint_eq(y, z) From b364a22adf6a937f0593158822f38385ee2c7bd2 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Thu, 10 Aug 2023 12:25:25 +0100 Subject: [PATCH 81/82] Fix mbedtls_ct_size_if_else_0 docs Co-authored-by: Tom Cosgrove Signed-off-by: Dave Rodgman --- library/constant_time_internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h index 9f5b1305fd..647b664e80 100644 --- a/library/constant_time_internal.h +++ b/library/constant_time_internal.h @@ -325,7 +325,7 @@ static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if(mbedtls_ct_condition_t con */ static inline unsigned mbedtls_ct_uint_if_else_0(mbedtls_ct_condition_t condition, unsigned if1); -/** Choose between an unsigned value and 0. +/** Choose between a size_t value and 0. * * Functionally equivalent to: * From 48fb8a34485a659179655743356f7afcb65b45e6 Mon Sep 17 00:00:00 2001 From: Dave Rodgman Date: Thu, 10 Aug 2023 14:01:51 +0100 Subject: [PATCH 82/82] Fix some renames that were missed Signed-off-by: Dave Rodgman --- library/constant_time_internal.h | 6 +++--- library/ssl_msg.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h index 647b664e80..dabf720aa4 100644 --- a/library/constant_time_internal.h +++ b/library/constant_time_internal.h @@ -44,10 +44,10 @@ * example: bool x = y == z => x = mbedtls_ct_uint_eq(y, z) * * - conditional data selection - * These are all named mbedtls_ct__if and mbedtls_ct__if0 + * These are all named mbedtls_ct__if and mbedtls_ct__if_else_0 * All arguments are considered secret. * example: size_t a = x ? b : c => a = mbedtls_ct_size_if(x, b, c) - * example: unsigned a = x ? b : 0 => a = mbedtls_ct_uint_if0(x, b) + * example: unsigned a = x ? b : 0 => a = mbedtls_ct_uint__if_else_0(x, b) * * - block memory operations * Only some arguments are considered secret, as documented for each @@ -201,7 +201,7 @@ static inline mbedtls_ct_condition_t mbedtls_ct_uint_le(mbedtls_ct_uint_t x, * \param x The first value to analyze. * \param y The second value to analyze. * - * \note This is more efficient than mbedtls_ct_bool_ne if both arguments are + * \note This is more efficient than mbedtls_ct_uint_ne if both arguments are * mbedtls_ct_condition_t. * * \return MBEDTLS_CT_TRUE if \p x ^ \p y, diff --git a/library/ssl_msg.c b/library/ssl_msg.c index 1a9c17e291..c8ffc1ede2 100644 --- a/library/ssl_msg.c +++ b/library/ssl_msg.c @@ -154,7 +154,7 @@ int mbedtls_ct_hmac(mbedtls_svc_key_id_t key, PSA_CHK(psa_hash_finish(&aux_operation, aux_out, PSA_HASH_MAX_SIZE, &hash_length)); /* Keep only the correct inner_hash in the output buffer */ - mbedtls_ct_memcpy_if(mbedtls_ct_bool_eq(offset, data_len_secret), + mbedtls_ct_memcpy_if(mbedtls_ct_uint_eq(offset, data_len_secret), output, aux_out, NULL, hash_size); if (offset < max_data_len) {