From 9055972227af78ee9872465072af6b86ecb98330 Mon Sep 17 00:00:00 2001 From: gabor-mezei-arm Date: Mon, 12 Jul 2021 16:31:22 +0200 Subject: [PATCH 01/53] Add a new file for constant-time functions Signed-off-by: Gabor Mezei --- library/CMakeLists.txt | 1 + library/Makefile | 1 + library/constant_time.c | 20 ++++++++++++++++++++ 3 files changed, 22 insertions(+) create mode 100644 library/constant_time.c diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index a69e73330..0cafd8881 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -26,6 +26,7 @@ set(src_crypto chachapoly.c cipher.c cipher_wrap.c + constant_time.c cmac.c ctr_drbg.c des.c diff --git a/library/Makefile b/library/Makefile index 2ee361583..1abafe3fe 100644 --- a/library/Makefile +++ b/library/Makefile @@ -84,6 +84,7 @@ OBJS_CRYPTO= \ cipher.o \ cipher_wrap.o \ cmac.o \ + constant_time.o \ ctr_drbg.o \ des.o \ dhm.o \ diff --git a/library/constant_time.c b/library/constant_time.c new file mode 100644 index 000000000..9f0229bd5 --- /dev/null +++ b/library/constant_time.c @@ -0,0 +1,20 @@ +/** + * Constant-time functions + * + * 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. + */ + +#include "common.h" From e41e3e8a8b4baf0f4c6d42d0e202f9c62b8add48 Mon Sep 17 00:00:00 2001 From: gabor-mezei-arm Date: Tue, 28 Sep 2021 16:14:47 +0200 Subject: [PATCH 02/53] Rename function to have suitable name Signed-off-by: Gabor Mezei --- library/bignum.c | 30 ++++++------ library/rsa.c | 65 +++++++++++++------------- library/ssl_invasive.h | 12 ++--- library/ssl_msg.c | 68 ++++++++++++++-------------- tests/suites/test_suite_ssl.function | 14 +++--- 5 files changed, 96 insertions(+), 93 deletions(-) diff --git a/library/bignum.c b/library/bignum.c index 364332664..d15bc1a96 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -280,7 +280,7 @@ void mbedtls_mpi_swap( mbedtls_mpi *X, mbedtls_mpi *Y ) * * \return The selected sign value. */ -static int mpi_safe_cond_select_sign( int a, int b, unsigned char second ) +static int mbedtls_cf_cond_select_sign( int a, int b, unsigned char second ) { /* In order to avoid questions about what we can reasonnably assume about * the representations of signed integers, move everything to unsigned @@ -304,10 +304,10 @@ static int mpi_safe_cond_select_sign( int a, int b, unsigned char second ) * dest and src must be arrays of limbs of size n. * assign must be 0 or 1. */ -static void mpi_safe_cond_assign( size_t n, - mbedtls_mpi_uint *dest, - const mbedtls_mpi_uint *src, - unsigned char assign ) +void mbedtls_cf_mpi_uint_cond_assign( size_t n, + mbedtls_mpi_uint *dest, + const mbedtls_mpi_uint *src, + unsigned char assign ) { size_t i; @@ -360,9 +360,9 @@ int mbedtls_mpi_safe_cond_assign( mbedtls_mpi *X, const mbedtls_mpi *Y, unsigned MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) ); - X->s = mpi_safe_cond_select_sign( X->s, Y->s, assign ); + X->s = mbedtls_cf_cond_select_sign( X->s, Y->s, assign ); - mpi_safe_cond_assign( Y->n, X->p, Y->p, assign ); + mbedtls_cf_mpi_uint_cond_assign( Y->n, X->p, Y->p, assign ); for( i = Y->n; i < X->n; i++ ) X->p[i] &= ~limb_mask; @@ -409,8 +409,8 @@ int mbedtls_mpi_safe_cond_swap( mbedtls_mpi *X, mbedtls_mpi *Y, unsigned char sw MBEDTLS_MPI_CHK( mbedtls_mpi_grow( Y, X->n ) ); s = X->s; - X->s = mpi_safe_cond_select_sign( X->s, Y->s, swap ); - Y->s = mpi_safe_cond_select_sign( Y->s, s, swap ); + X->s = mbedtls_cf_cond_select_sign( X->s, Y->s, swap ); + Y->s = mbedtls_cf_cond_select_sign( Y->s, s, swap ); for( i = 0; i < X->n; i++ ) @@ -1253,7 +1253,7 @@ int mbedtls_mpi_cmp_mpi( const mbedtls_mpi *X, const mbedtls_mpi *Y ) * * \return 1 if \p x is less than \p y, 0 otherwise */ -static unsigned ct_lt_mpi_uint( const mbedtls_mpi_uint x, +static unsigned mbedtls_cf_mpi_uint_lt( const mbedtls_mpi_uint x, const mbedtls_mpi_uint y ) { mbedtls_mpi_uint ret; @@ -1328,7 +1328,7 @@ int mbedtls_mpi_lt_mpi_ct( const mbedtls_mpi *X, const mbedtls_mpi *Y, * Again even if we can make a decision, we just mark the result and * the fact that we are done and continue looping. */ - cond = ct_lt_mpi_uint( Y->p[i - 1], X->p[i - 1] ); + cond = mbedtls_cf_mpi_uint_lt( Y->p[i - 1], X->p[i - 1] ); *ret |= cond & ( 1 - done ) & X_is_negative; done |= cond; @@ -1339,7 +1339,7 @@ int mbedtls_mpi_lt_mpi_ct( const mbedtls_mpi *X, const mbedtls_mpi *Y, * Again even if we can make a decision, we just mark the result and * the fact that we are done and continue looping. */ - cond = ct_lt_mpi_uint( X->p[i - 1], Y->p[i - 1] ); + cond = mbedtls_cf_mpi_uint_lt( X->p[i - 1], Y->p[i - 1] ); *ret |= cond & ( 1 - done ) & ( 1 - X_is_negative ); done |= cond; } @@ -2207,7 +2207,7 @@ static void mpi_montmul( mbedtls_mpi *A, const mbedtls_mpi *B, const mbedtls_mpi * so d[n] == 1 and we want to set A to the result of the subtraction * which is d - (2^biL)^n, i.e. the n least significant limbs of d. * This exactly corresponds to a conditional assignment. */ - mpi_safe_cond_assign( n, A->p, d, (unsigned char) d[n] ); + mbedtls_cf_mpi_uint_cond_assign( n, A->p, d, (unsigned char) d[n] ); } /* @@ -2238,7 +2238,7 @@ static void mpi_montred( mbedtls_mpi *A, const mbedtls_mpi *N, * This function is implemented without using comparison operators, as those * might be translated to branches by some compilers on some platforms. */ -static size_t mbedtls_mpi_cf_bool_eq( size_t x, size_t y ) +static size_t mbedtls_cf_size_bool_eq( size_t x, size_t y ) { /* diff = 0 if x == y, non-zero otherwise */ const size_t diff = x ^ y; @@ -2285,7 +2285,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_mpi_cf_bool_eq( i, idx ) ) ); + (unsigned char) mbedtls_cf_size_bool_eq( i, idx ) ) ); } cleanup: diff --git a/library/rsa.c b/library/rsa.c index 268d025e6..02b40d05c 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -1499,7 +1499,7 @@ cleanup: * \param value The value to analyze. * \return Zero if \p value is zero, otherwise all-bits-one. */ -static unsigned all_or_nothing_int( unsigned value ) +static unsigned mbedtls_cf_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 */ @@ -1523,7 +1523,7 @@ static unsigned all_or_nothing_int( unsigned value ) * \return \c 0 if `size <= max`. * \return \c 1 if `size > max`. */ -static unsigned size_greater_than( size_t size, size_t max ) +static unsigned mbedtls_cf_size_gt( size_t size, size_t max ) { /* Return the sign bit (1 for negative) of (max - size). */ return( ( max - size ) >> ( sizeof( size_t ) * 8 - 1 ) ); @@ -1539,16 +1539,17 @@ static unsigned size_greater_than( size_t size, size_t max ) * \param if0 Value to use if \p cond is zero. * \return \c if1 if \p cond is nonzero, otherwise \c if0. */ -static unsigned if_int( unsigned cond, unsigned if1, unsigned if0 ) +static unsigned mbedtls_cf_uint_if( unsigned cond, unsigned if1, unsigned if0 ) { - unsigned mask = all_or_nothing_int( cond ); + unsigned mask = mbedtls_cf_uint_mask( cond ); return( ( mask & if1 ) | (~mask & if0 ) ); } /** Shift some data towards the left inside a buffer without leaking * the length of the data through side channels. * - * `mem_move_to_left(start, total, offset)` is functionally equivalent to + * `mbedtls_cf_mem_move_to_left(start, total, offset)` is functionally + * equivalent to * ``` * memmove(start, start + offset, total - offset); * memset(start + offset, 0, total - offset); @@ -1561,9 +1562,9 @@ static unsigned if_int( unsigned cond, unsigned if1, unsigned if0 ) * \param total Total size of the buffer. * \param offset Offset from which to copy \p total - \p offset bytes. */ -static void mem_move_to_left( void *start, - size_t total, - size_t offset ) +static void mbedtls_cf_mem_move_to_left( void *start, + size_t total, + size_t offset ) { volatile unsigned char *buf = start; size_t i, n; @@ -1571,7 +1572,7 @@ static void mem_move_to_left( void *start, return; for( i = 0; i < total; i++ ) { - unsigned no_op = size_greater_than( total - offset, i ); + unsigned no_op = mbedtls_cf_size_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. */ @@ -1579,9 +1580,9 @@ static void mem_move_to_left( void *start, { unsigned char current = buf[n]; unsigned char next = buf[n+1]; - buf[n] = if_int( no_op, current, next ); + buf[n] = mbedtls_cf_uint_if( no_op, current, next ); } - buf[total-1] = if_int( no_op, buf[total-1], 0 ); + buf[total-1] = mbedtls_cf_uint_if( no_op, buf[total-1], 0 ); } } @@ -1669,17 +1670,17 @@ int mbedtls_rsa_rsaes_pkcs1_v15_decrypt( mbedtls_rsa_context *ctx, * If there's a non-0xff byte in the padding, the padding is bad. */ for( i = 2; i < ilen; i++ ) { - pad_done |= if_int( buf[i], 0, 1 ); - pad_count += if_int( pad_done, 0, 1 ); - bad |= if_int( pad_done, 0, buf[i] ^ 0xFF ); + pad_done |= mbedtls_cf_uint_if( buf[i], 0, 1 ); + pad_count += mbedtls_cf_uint_if( pad_done, 0, 1 ); + bad |= mbedtls_cf_uint_if( pad_done, 0, buf[i] ^ 0xFF ); } } /* If pad_done is still zero, there's no data, only unfinished padding. */ - bad |= if_int( pad_done, 0, 1 ); + bad |= mbedtls_cf_uint_if( pad_done, 0, 1 ); /* There must be at least 8 bytes of padding. */ - bad |= size_greater_than( 8, pad_count ); + bad |= mbedtls_cf_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 @@ -1688,23 +1689,25 @@ int mbedtls_rsa_rsaes_pkcs1_v15_decrypt( mbedtls_rsa_context *ctx, * 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 = if_int( bad, - (unsigned) plaintext_max_size, - (unsigned) ( ilen - pad_count - 3 ) ); + plaintext_size = mbedtls_cf_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 = size_greater_than( plaintext_size, - plaintext_max_size ); + output_too_large = mbedtls_cf_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) if_int( bad, - MBEDTLS_ERR_RSA_INVALID_PADDING, - if_int( output_too_large, - MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE, - 0 ) ); + ret = - (int) mbedtls_cf_uint_if( + bad, - MBEDTLS_ERR_RSA_INVALID_PADDING, + mbedtls_cf_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. @@ -1712,7 +1715,7 @@ int mbedtls_rsa_rsaes_pkcs1_v15_decrypt( mbedtls_rsa_context *ctx, * 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 = all_or_nothing_int( bad | output_too_large ); + bad = mbedtls_cf_uint_mask( bad | output_too_large ); for( i = 11; i < ilen; i++ ) buf[i] &= ~bad; @@ -1720,9 +1723,9 @@ int mbedtls_rsa_rsaes_pkcs1_v15_decrypt( mbedtls_rsa_context *ctx, * 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 = if_int( output_too_large, - (unsigned) plaintext_max_size, - (unsigned) plaintext_size ); + plaintext_size = mbedtls_cf_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 @@ -1730,9 +1733,9 @@ int mbedtls_rsa_rsaes_pkcs1_v15_decrypt( mbedtls_rsa_context *ctx, * does not depend on the plaintext size. After this move, the * starting location of the plaintext is no longer sensitive * information. */ - mem_move_to_left( buf + ilen - plaintext_max_size, - plaintext_max_size, - plaintext_max_size - plaintext_size ); + mbedtls_cf_mem_move_to_left( buf + 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 diff --git a/library/ssl_invasive.h b/library/ssl_invasive.h index babbc2768..5cb29cb0a 100644 --- a/library/ssl_invasive.h +++ b/library/ssl_invasive.h @@ -65,7 +65,7 @@ * \retval MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED * The hardware accelerator failed. */ -int mbedtls_ssl_cf_hmac( +int mbedtls_cf_hmac( mbedtls_md_context_t *ctx, const unsigned char *add_data, size_t add_data_len, const unsigned char *data, size_t data_len_secret, @@ -90,11 +90,11 @@ int mbedtls_ssl_cf_hmac( * \param offset_max The maximal value of \p offset_secret. * \param len The number of bytes to copy. */ -void mbedtls_ssl_cf_memcpy_offset( unsigned char *dst, - const unsigned char *src_base, - size_t offset_secret, - size_t offset_min, size_t offset_max, - size_t len ); +void mbedtls_cf_memcpy_offset( unsigned char *dst, + const unsigned char *src_base, + size_t offset_secret, + size_t offset_min, size_t offset_max, + size_t len ); #endif /* MBEDTLS_TEST_HOOKS && MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */ #endif /* MBEDTLS_SSL_INVASIVE_H */ diff --git a/library/ssl_msg.c b/library/ssl_msg.c index 7da567412..916456f31 100644 --- a/library/ssl_msg.c +++ b/library/ssl_msg.c @@ -1055,7 +1055,7 @@ int mbedtls_ssl_encrypt_buf( mbedtls_ssl_context *ssl, * This function is implemented without using comparison operators, as those * might be translated to branches by some compilers on some platforms. */ -static size_t mbedtls_ssl_cf_mask_from_bit( size_t bit ) +static size_t mbedtls_cf_size_mask( size_t bit ) { /* MSVC has a warning about unary minus on unsigned integer types, * but this is well-defined and precisely what we want to do here. */ @@ -1080,7 +1080,7 @@ static size_t mbedtls_ssl_cf_mask_from_bit( size_t bit ) * This function is implemented without using comparison operators, as those * might be translated to branches by some compilers on some platforms. */ -static size_t mbedtls_ssl_cf_mask_lt( size_t x, size_t y ) +static size_t mbedtls_cf_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; @@ -1089,7 +1089,7 @@ static size_t mbedtls_ssl_cf_mask_lt( size_t x, size_t y ) const size_t sub1 = sub >> ( sizeof( sub ) * 8 - 1 ); /* mask = (x < y) ? 0xff... : 0x00... */ - const size_t mask = mbedtls_ssl_cf_mask_from_bit( sub1 ); + const size_t mask = mbedtls_cf_size_mask( sub1 ); return( mask ); } @@ -1105,9 +1105,9 @@ static size_t mbedtls_ssl_cf_mask_lt( size_t x, size_t y ) * This function is implemented without using comparison operators, as those * might be translated to branches by some compilers on some platforms. */ -static size_t mbedtls_ssl_cf_mask_ge( size_t x, size_t y ) +static size_t mbedtls_cf_size_mask_ge( size_t x, size_t y ) { - return( ~mbedtls_ssl_cf_mask_lt( x, y ) ); + return( ~mbedtls_cf_size_mask_lt( x, y ) ); } /* @@ -1116,12 +1116,12 @@ static size_t mbedtls_ssl_cf_mask_ge( size_t x, size_t y ) * * This function can be used to write constant-time code by replacing branches * with bit operations - it can be used in conjunction with - * mbedtls_ssl_cf_mask_from_bit(). + * mbedtls_cf_size_mask(). * * This function is implemented without using comparison operators, as those * might be translated to branches by some compilers on some platforms. */ -static size_t mbedtls_ssl_cf_bool_eq( size_t x, size_t y ) +static size_t mbedtls_cf_size_bool_eq( size_t x, size_t y ) { /* diff = 0 if x == y, non-zero otherwise */ const size_t diff = x ^ y; @@ -1155,14 +1155,14 @@ static size_t mbedtls_ssl_cf_bool_eq( size_t x, size_t y ) * This function is implemented without using comparison operators, as those * might be translated to branches by some compilers on some platforms. */ -static void mbedtls_ssl_cf_memcpy_if_eq( unsigned char *dst, - const unsigned char *src, - size_t len, - size_t c1, size_t c2 ) +static void mbedtls_cf_memcpy_if_eq( unsigned char *dst, + const unsigned char *src, + size_t len, + size_t c1, size_t c2 ) { /* mask = c1 == c2 ? 0xff : 0x00 */ - const size_t equal = mbedtls_ssl_cf_bool_eq( c1, c2 ); - const unsigned char mask = (unsigned char) mbedtls_ssl_cf_mask_from_bit( equal ); + const size_t equal = mbedtls_cf_size_bool_eq( c1, c2 ); + const unsigned char mask = (unsigned char) mbedtls_cf_size_mask( equal ); /* dst[i] = c1 == c2 ? src[i] : dst[i] */ for( size_t i = 0; i < len; i++ ) @@ -1175,7 +1175,7 @@ static void mbedtls_ssl_cf_memcpy_if_eq( unsigned char *dst, * Only works with MD-5, SHA-1, SHA-256 and SHA-384. * (Otherwise, computation of block_size needs to be adapted.) */ -MBEDTLS_STATIC_TESTABLE int mbedtls_ssl_cf_hmac( +MBEDTLS_STATIC_TESTABLE int mbedtls_cf_hmac( mbedtls_md_context_t *ctx, const unsigned char *add_data, size_t add_data_len, const unsigned char *data, size_t data_len_secret, @@ -1231,8 +1231,8 @@ MBEDTLS_STATIC_TESTABLE int mbedtls_ssl_cf_hmac( 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_ssl_cf_memcpy_if_eq( output, aux_out, hash_size, - offset, data_len_secret ); + mbedtls_cf_memcpy_if_eq( output, aux_out, hash_size, + offset, data_len_secret ); if( offset < max_data_len ) MD_CHK( mbedtls_md_update( ctx, data + offset, 1 ) ); @@ -1262,7 +1262,7 @@ cleanup: * - functionally equivalent to memcpy(dst, src + offset_secret, len) * - but with execution flow independent from the value of offset_secret. */ -MBEDTLS_STATIC_TESTABLE void mbedtls_ssl_cf_memcpy_offset( +MBEDTLS_STATIC_TESTABLE void mbedtls_cf_memcpy_offset( unsigned char *dst, const unsigned char *src_base, size_t offset_secret, @@ -1273,8 +1273,8 @@ MBEDTLS_STATIC_TESTABLE void mbedtls_ssl_cf_memcpy_offset( for( offset = offset_min; offset <= offset_max; offset++ ) { - mbedtls_ssl_cf_memcpy_if_eq( dst, src_base + offset, len, - offset, offset_secret ); + mbedtls_cf_memcpy_if_eq( dst, src_base + offset, len, + offset, offset_secret ); } } #endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */ @@ -1620,7 +1620,7 @@ int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl, if( auth_done == 1 ) { - const size_t mask = mbedtls_ssl_cf_mask_ge( + const size_t mask = mbedtls_cf_size_mask_ge( rec->data_len, padlen + 1 ); correct &= mask; @@ -1640,7 +1640,7 @@ int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl, } #endif - const size_t mask = mbedtls_ssl_cf_mask_ge( + const size_t mask = mbedtls_cf_size_mask_ge( rec->data_len, transform->maclen + padlen + 1 ); correct &= mask; @@ -1696,18 +1696,18 @@ int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl, /* pad_count += (idx >= padding_idx) && * (check[idx] == padlen - 1); */ - const size_t mask = mbedtls_ssl_cf_mask_ge( idx, padding_idx ); - const size_t equal = mbedtls_ssl_cf_bool_eq( check[idx], - padlen - 1 ); + const size_t mask = mbedtls_cf_size_mask_ge( idx, padding_idx ); + const size_t equal = mbedtls_cf_size_bool_eq( check[idx], + padlen - 1 ); pad_count += mask & equal; } - correct &= mbedtls_ssl_cf_bool_eq( pad_count, padlen ); + correct &= mbedtls_cf_size_bool_eq( pad_count, padlen ); #if defined(MBEDTLS_SSL_DEBUG_ALL) if( padlen > 0 && correct == 0 ) MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad padding byte detected" ) ); #endif - padlen &= mbedtls_ssl_cf_mask_from_bit( correct ); + padlen &= mbedtls_cf_size_mask( correct ); } else #endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ @@ -1791,20 +1791,20 @@ int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl, const size_t max_len = rec->data_len + padlen; const size_t min_len = ( max_len > 256 ) ? max_len - 256 : 0; - ret = mbedtls_ssl_cf_hmac( &transform->md_ctx_dec, - add_data, add_data_len, - data, rec->data_len, min_len, max_len, - mac_expect ); + ret = mbedtls_cf_hmac( &transform->md_ctx_dec, + add_data, add_data_len, + data, rec->data_len, min_len, max_len, + mac_expect ); if( ret != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_cf_hmac", ret ); return( ret ); } - mbedtls_ssl_cf_memcpy_offset( mac_peer, data, - rec->data_len, - min_len, max_len, - transform->maclen ); + mbedtls_cf_memcpy_offset( mac_peer, data, + rec->data_len, + min_len, max_len, + transform->maclen ); } else #endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 3eeea44a8..83a5e2cb8 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -4428,7 +4428,7 @@ void resize_buffers_renegotiate_mfl( int mfl, int legacy_renegotiation, void ssl_cf_hmac( int hash ) { /* - * Test the function mbedtls_ssl_cf_hmac() against a reference + * Test the function mbedtls_cf_hmac() against a reference * implementation. */ mbedtls_md_context_t ctx, ref_ctx; @@ -4487,10 +4487,10 @@ void ssl_cf_hmac( int hash ) /* Get the function's result */ TEST_CF_SECRET( &in_len, sizeof( in_len ) ); - TEST_EQUAL( 0, mbedtls_ssl_cf_hmac( &ctx, add_data, sizeof( add_data ), - data, in_len, - min_in_len, max_in_len, - out ) ); + TEST_EQUAL( 0, mbedtls_cf_hmac( &ctx, add_data, sizeof( add_data ), + data, in_len, + min_in_len, max_in_len, + out ) ); TEST_CF_PUBLIC( &in_len, sizeof( in_len ) ); TEST_CF_PUBLIC( out, out_len ); @@ -4537,8 +4537,8 @@ 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 ) ); - mbedtls_ssl_cf_memcpy_offset( dst, src, secret, - offset_min, offset_max, len ); + mbedtls_cf_memcpy_offset( dst, src, secret, + offset_min, offset_max, len ); TEST_CF_PUBLIC( &secret, sizeof( secret ) ); TEST_CF_PUBLIC( dst, len ); From 944c107744fd89bcc40c3ebef4400f863350607c Mon Sep 17 00:00:00 2001 From: gabor-mezei-arm Date: Mon, 27 Sep 2021 11:28:54 +0200 Subject: [PATCH 03/53] Move contatnt-time memcmp functions to the contant-time module Signed-off-by: Gabor Mezei --- include/mbedtls/ssl_internal.h | 20 --------- library/cipher.c | 22 +--------- library/constant_time.c | 74 ++++++++++++++++++++++++++++++++++ library/constant_time.h | 30 ++++++++++++++ library/nist_kw.c | 21 +--------- library/rsa.c | 17 +------- library/ssl_cli.c | 1 + library/ssl_cookie.c | 1 + library/ssl_msg.c | 1 + library/ssl_srv.c | 1 + library/ssl_tls.c | 1 + 11 files changed, 112 insertions(+), 77 deletions(-) create mode 100644 library/constant_time.h diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h index 2097a6dd9..bc303061d 100644 --- a/include/mbedtls/ssl_internal.h +++ b/include/mbedtls/ssl_internal.h @@ -1212,26 +1212,6 @@ void mbedtls_ssl_dtls_replay_update( mbedtls_ssl_context *ssl ); int mbedtls_ssl_session_copy( mbedtls_ssl_session *dst, const mbedtls_ssl_session *src ); -/* constant-time buffer comparison */ -static inline int mbedtls_ssl_safer_memcmp( const void *a, const void *b, size_t n ) -{ - size_t i; - volatile const unsigned char *A = (volatile const unsigned char *) a; - volatile const unsigned char *B = (volatile const unsigned char *) b; - volatile unsigned char diff = 0; - - for( i = 0; i < n; i++ ) - { - /* Read volatile data in order before computing diff. - * This avoids IAR compiler warning: - * 'the order of volatile accesses is undefined ..' */ - unsigned char x = A[i], y = B[i]; - diff |= x ^ y; - } - - return( diff ); -} - #if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ defined(MBEDTLS_SSL_PROTO_TLS1_1) int mbedtls_ssl_get_key_exchange_md_ssl_tls( mbedtls_ssl_context *ssl, diff --git a/library/cipher.c b/library/cipher.c index b956030da..147241345 100644 --- a/library/cipher.c +++ b/library/cipher.c @@ -29,6 +29,7 @@ #include "mbedtls/cipher_internal.h" #include "mbedtls/platform_util.h" #include "mbedtls/error.h" +#include "constant_time.h" #include #include @@ -74,27 +75,6 @@ #define CIPHER_VALIDATE( cond ) \ MBEDTLS_INTERNAL_VALIDATE( cond ) -#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C) -/* Compare the contents of two buffers in constant time. - * Returns 0 if the contents are bitwise identical, otherwise returns - * a non-zero value. - * This is currently only used by GCM and ChaCha20+Poly1305. - */ -static int mbedtls_constant_time_memcmp( const void *v1, const void *v2, - size_t len ) -{ - const unsigned char *p1 = (const unsigned char*) v1; - const unsigned char *p2 = (const unsigned char*) v2; - size_t i; - unsigned char diff; - - for( diff = 0, i = 0; i < len; i++ ) - diff |= p1[i] ^ p2[i]; - - return( (int)diff ); -} -#endif /* MBEDTLS_GCM_C || MBEDTLS_CHACHAPOLY_C */ - static int supported_init = 0; const int *mbedtls_cipher_list( void ) diff --git a/library/constant_time.c b/library/constant_time.c index 9f0229bd5..cb156bc9b 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -18,3 +18,77 @@ */ #include "common.h" +#include "constant_time.h" + +/* constant-time buffer comparison */ +int mbedtls_ssl_safer_memcmp( const void *a, const void *b, size_t n ) +{ + size_t i; + volatile const unsigned char *A = (volatile const unsigned char *) a; + volatile const unsigned char *B = (volatile const unsigned char *) b; + volatile unsigned char diff = 0; + + for( i = 0; i < n; i++ ) + { + /* Read volatile data in order before computing diff. + * This avoids IAR compiler warning: + * 'the order of volatile accesses is undefined ..' */ + unsigned char x = A[i], y = B[i]; + diff |= x ^ y; + } + + return( diff ); +} + +/* Compare the contents of two buffers in constant time. + * Returns 0 if the contents are bitwise identical, otherwise returns + * a non-zero value. + * This is currently only used by GCM and ChaCha20+Poly1305. + */ +int mbedtls_constant_time_memcmp( const void *v1, const void *v2, + size_t len ) +{ + const unsigned char *p1 = (const unsigned char*) v1; + const unsigned char *p2 = (const unsigned char*) v2; + size_t i; + unsigned char diff; + + for( diff = 0, i = 0; i < len; i++ ) + diff |= p1[i] ^ p2[i]; + + return( (int)diff ); +} + +/* constant-time buffer comparison */ +unsigned char mbedtls_nist_kw_safer_memcmp( const void *a, const void *b, size_t n ) +{ + size_t i; + volatile const unsigned char *A = (volatile const unsigned char *) a; + volatile const unsigned char *B = (volatile const unsigned char *) b; + volatile unsigned char diff = 0; + + for( i = 0; i < n; i++ ) + { + /* Read volatile data in order before computing diff. + * This avoids IAR compiler warning: + * 'the order of volatile accesses is undefined ..' */ + unsigned char x = A[i], y = B[i]; + diff |= x ^ y; + } + + return( diff ); +} + +/* constant-time buffer comparison */ +int mbedtls_safer_memcmp( const void *a, const void *b, size_t n ) +{ + size_t i; + const unsigned char *A = (const unsigned char *) a; + const unsigned char *B = (const unsigned char *) b; + unsigned char diff = 0; + + for( i = 0; i < n; i++ ) + diff |= A[i] ^ B[i]; + + return( diff ); +} diff --git a/library/constant_time.h b/library/constant_time.h new file mode 100644 index 000000000..e14232b8b --- /dev/null +++ b/library/constant_time.h @@ -0,0 +1,30 @@ +/** + * Constant-time functions + * + * 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. + */ + +#include "common.h" + +#include + +int mbedtls_ssl_safer_memcmp( const void *a, const void *b, size_t n ); + +int mbedtls_constant_time_memcmp( const void *v1, const void *v2, size_t len ); + +unsigned char mbedtls_nist_kw_safer_memcmp( const void *a, const void *b, size_t n ); + +int mbedtls_safer_memcmp( const void *a, const void *b, size_t n ); diff --git a/library/nist_kw.c b/library/nist_kw.c index e2ab2566f..6262a7b0c 100644 --- a/library/nist_kw.c +++ b/library/nist_kw.c @@ -34,6 +34,7 @@ #include "mbedtls/nist_kw.h" #include "mbedtls/platform_util.h" #include "mbedtls/error.h" +#include "constant_time.h" #include #include @@ -52,26 +53,6 @@ #define KW_SEMIBLOCK_LENGTH 8 #define MIN_SEMIBLOCKS_COUNT 3 -/* constant-time buffer comparison */ -static inline unsigned char mbedtls_nist_kw_safer_memcmp( const void *a, const void *b, size_t n ) -{ - size_t i; - volatile const unsigned char *A = (volatile const unsigned char *) a; - volatile const unsigned char *B = (volatile const unsigned char *) b; - volatile unsigned char diff = 0; - - for( i = 0; i < n; i++ ) - { - /* Read volatile data in order before computing diff. - * This avoids IAR compiler warning: - * 'the order of volatile accesses is undefined ..' */ - unsigned char x = A[i], y = B[i]; - diff |= x ^ y; - } - - return( diff ); -} - /*! The 64-bit default integrity check value (ICV) for KW mode. */ static const unsigned char NIST_KW_ICV1[] = {0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6}; /*! The 32-bit default integrity check value (ICV) for KWP mode. */ diff --git a/library/rsa.c b/library/rsa.c index 02b40d05c..06653a582 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -44,6 +44,7 @@ #include "mbedtls/oid.h" #include "mbedtls/platform_util.h" #include "mbedtls/error.h" +#include "constant_time.h" #include @@ -72,22 +73,6 @@ #define RSA_VALIDATE( cond ) \ MBEDTLS_INTERNAL_VALIDATE( cond ) -#if defined(MBEDTLS_PKCS1_V15) -/* constant-time buffer comparison */ -static inline int mbedtls_safer_memcmp( const void *a, const void *b, size_t n ) -{ - size_t i; - const unsigned char *A = (const unsigned char *) a; - const unsigned char *B = (const unsigned char *) b; - unsigned char diff = 0; - - for( i = 0; i < n; i++ ) - diff |= A[i] ^ B[i]; - - return( diff ); -} -#endif /* MBEDTLS_PKCS1_V15 */ - int mbedtls_rsa_import( mbedtls_rsa_context *ctx, const mbedtls_mpi *N, const mbedtls_mpi *P, const mbedtls_mpi *Q, diff --git a/library/ssl_cli.c b/library/ssl_cli.c index b02a3a5e4..912b5d007 100644 --- a/library/ssl_cli.c +++ b/library/ssl_cli.c @@ -33,6 +33,7 @@ #include "mbedtls/ssl_internal.h" #include "mbedtls/debug.h" #include "mbedtls/error.h" +#include "constant_time.h" #if defined(MBEDTLS_USE_PSA_CRYPTO) #include "mbedtls/psa_util.h" diff --git a/library/ssl_cookie.c b/library/ssl_cookie.c index 071e55e9a..84fbab1a4 100644 --- a/library/ssl_cookie.c +++ b/library/ssl_cookie.c @@ -36,6 +36,7 @@ #include "mbedtls/ssl_internal.h" #include "mbedtls/error.h" #include "mbedtls/platform_util.h" +#include "constant_time.h" #include diff --git a/library/ssl_msg.c b/library/ssl_msg.c index 916456f31..b3bd80435 100644 --- a/library/ssl_msg.c +++ b/library/ssl_msg.c @@ -44,6 +44,7 @@ #include "mbedtls/error.h" #include "mbedtls/platform_util.h" #include "mbedtls/version.h" +#include "constant_time.h" #include "ssl_invasive.h" diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 210e0d371..b9e4bc0f6 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -34,6 +34,7 @@ #include "mbedtls/debug.h" #include "mbedtls/error.h" #include "mbedtls/platform_util.h" +#include "constant_time.h" #include diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 2e9c4011b..607981a8d 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -43,6 +43,7 @@ #include "mbedtls/error.h" #include "mbedtls/platform_util.h" #include "mbedtls/version.h" +#include "constant_time.h" #include From c11cac9f1ba1ef34492a651cd486c81f02da5541 Mon Sep 17 00:00:00 2001 From: gabor-mezei-arm Date: Mon, 27 Sep 2021 11:40:03 +0200 Subject: [PATCH 04/53] Move mbedtls_cf_uint_mask function to the constant-time module Signed-off-by: Gabor Mezei --- library/constant_time.c | 19 +++++++++++++++++++ library/constant_time.h | 3 +++ library/rsa.c | 19 ------------------- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index cb156bc9b..0c5c04c1f 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -92,3 +92,22 @@ int mbedtls_safer_memcmp( const void *a, const void *b, size_t n ) return( diff ); } + +/** Turn zero-or-nonzero into zero-or-all-bits-one, without branches. + * + * \param value The value to analyze. + * \return Zero if \p value is zero, otherwise all-bits-one. + */ +unsigned mbedtls_cf_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 +} diff --git a/library/constant_time.h b/library/constant_time.h index e14232b8b..0d6c0fdfc 100644 --- a/library/constant_time.h +++ b/library/constant_time.h @@ -28,3 +28,6 @@ int mbedtls_constant_time_memcmp( const void *v1, const void *v2, size_t len ); unsigned char mbedtls_nist_kw_safer_memcmp( const void *a, const void *b, size_t n ); int mbedtls_safer_memcmp( const void *a, const void *b, size_t n ); + + +unsigned mbedtls_cf_uint_mask( unsigned value ); diff --git a/library/rsa.c b/library/rsa.c index 06653a582..d5151a5e0 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -1479,25 +1479,6 @@ cleanup: #endif /* MBEDTLS_PKCS1_V21 */ #if defined(MBEDTLS_PKCS1_V15) -/** Turn zero-or-nonzero into zero-or-all-bits-one, without branches. - * - * \param value The value to analyze. - * \return Zero if \p value is zero, otherwise all-bits-one. - */ -static unsigned mbedtls_cf_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 -} - /** Check whether a size is out of bounds, without branches. * * This is equivalent to `size > max`, but is likely to be compiled to From d361ccd663a3bfaa837aa984c29e374c86c038af Mon Sep 17 00:00:00 2001 From: gabor-mezei-arm Date: Mon, 27 Sep 2021 11:49:42 +0200 Subject: [PATCH 05/53] Move mbedtls_cf_size_mask function to the constant-time module Signed-off-by: Gabor Mezei --- library/constant_time.c | 25 +++++++++++++++++++++++++ library/constant_time.h | 2 ++ library/ssl_msg.c | 25 ------------------------- 3 files changed, 27 insertions(+), 25 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index 0c5c04c1f..604859f0f 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -111,3 +111,28 @@ unsigned mbedtls_cf_uint_mask( unsigned value ) #pragma warning( pop ) #endif } + +/* + * Turn a bit into a mask: + * - if bit == 1, return the all-bits 1 mask, aka (size_t) -1 + * - if bit == 0, return the all-bits 0 mask, aka 0 + * + * This function can be used to write constant-time code by replacing branches + * with bit operations using masks. + * + * This function is implemented without using comparison operators, as those + * might be translated to branches by some compilers on some platforms. + */ +size_t mbedtls_cf_size_mask( size_t bit ) +{ + /* 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 -bit; +#if defined(_MSC_VER) +#pragma warning( pop ) +#endif +} diff --git a/library/constant_time.h b/library/constant_time.h index 0d6c0fdfc..3cbabe1d3 100644 --- a/library/constant_time.h +++ b/library/constant_time.h @@ -31,3 +31,5 @@ int mbedtls_safer_memcmp( const void *a, const void *b, size_t n ); unsigned mbedtls_cf_uint_mask( unsigned value ); + +size_t mbedtls_cf_size_mask( size_t bit ); diff --git a/library/ssl_msg.c b/library/ssl_msg.c index b3bd80435..3efb74c9d 100644 --- a/library/ssl_msg.c +++ b/library/ssl_msg.c @@ -1045,31 +1045,6 @@ int mbedtls_ssl_encrypt_buf( mbedtls_ssl_context *ssl, } #if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) -/* - * Turn a bit into a mask: - * - if bit == 1, return the all-bits 1 mask, aka (size_t) -1 - * - if bit == 0, return the all-bits 0 mask, aka 0 - * - * This function can be used to write constant-time code by replacing branches - * with bit operations using masks. - * - * This function is implemented without using comparison operators, as those - * might be translated to branches by some compilers on some platforms. - */ -static size_t mbedtls_cf_size_mask( size_t bit ) -{ - /* 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 -bit; -#if defined(_MSC_VER) -#pragma warning( pop ) -#endif -} - /* * Constant-flow mask generation for "less than" comparison: * - if x < y, return all bits 1, that is (size_t) -1 From 4d6b14624e30b897bf25dc0f2a6a300a0e6f74ad Mon Sep 17 00:00:00 2001 From: gabor-mezei-arm Date: Mon, 27 Sep 2021 11:53:54 +0200 Subject: [PATCH 06/53] Move mbedtls_cf_size_mask_lt function to the constant-time module Signed-off-by: Gabor Mezei --- library/constant_time.c | 25 +++++++++++++++++++++++++ library/constant_time.h | 2 ++ library/ssl_msg.c | 25 ------------------------- 3 files changed, 27 insertions(+), 25 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index 604859f0f..928b9b7fe 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -136,3 +136,28 @@ size_t mbedtls_cf_size_mask( size_t bit ) #pragma warning( pop ) #endif } + +/* + * Constant-flow mask generation for "less than" comparison: + * - if x < 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. + * + * This function is implemented without using comparison operators, as those + * might be translated to branches by some compilers on some platforms. + */ +size_t mbedtls_cf_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_cf_size_mask( sub1 ); + + return( mask ); +} diff --git a/library/constant_time.h b/library/constant_time.h index 3cbabe1d3..0b759000a 100644 --- a/library/constant_time.h +++ b/library/constant_time.h @@ -33,3 +33,5 @@ int mbedtls_safer_memcmp( const void *a, const void *b, size_t n ); unsigned mbedtls_cf_uint_mask( unsigned value ); size_t mbedtls_cf_size_mask( size_t bit ); + +size_t mbedtls_cf_size_mask_lt( size_t x, size_t y ); diff --git a/library/ssl_msg.c b/library/ssl_msg.c index 3efb74c9d..de350ebc0 100644 --- a/library/ssl_msg.c +++ b/library/ssl_msg.c @@ -1045,31 +1045,6 @@ int mbedtls_ssl_encrypt_buf( mbedtls_ssl_context *ssl, } #if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) -/* - * Constant-flow mask generation for "less than" comparison: - * - if x < 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. - * - * This function is implemented without using comparison operators, as those - * might be translated to branches by some compilers on some platforms. - */ -static size_t mbedtls_cf_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_cf_size_mask( sub1 ); - - return( mask ); -} - /* * Constant-flow mask generation for "greater or equal" comparison: * - if x >= y, return all bits 1, that is (size_t) -1 From a2bcabceb2e32995dc71c2b3baf452ce6a0bd1cd Mon Sep 17 00:00:00 2001 From: gabor-mezei-arm Date: Mon, 27 Sep 2021 11:58:31 +0200 Subject: [PATCH 07/53] Move mbedtls_cf_size_mask_ge function to the constant-time module Signed-off-by: Gabor Mezei --- library/constant_time.c | 16 ++++++++++++++++ library/constant_time.h | 2 ++ library/ssl_msg.c | 16 ---------------- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index 928b9b7fe..b53d06ba6 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -161,3 +161,19 @@ size_t mbedtls_cf_size_mask_lt( size_t x, size_t y ) return( mask ); } + +/* + * Constant-flow mask generation for "greater or equal" comparison: + * - if x >= 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. + * + * This function is implemented without using comparison operators, as those + * might be translated to branches by some compilers on some platforms. + */ +size_t mbedtls_cf_size_mask_ge( size_t x, size_t y ) +{ + return( ~mbedtls_cf_size_mask_lt( x, y ) ); +} diff --git a/library/constant_time.h b/library/constant_time.h index 0b759000a..8e8992d6f 100644 --- a/library/constant_time.h +++ b/library/constant_time.h @@ -35,3 +35,5 @@ unsigned mbedtls_cf_uint_mask( unsigned value ); size_t mbedtls_cf_size_mask( size_t bit ); size_t mbedtls_cf_size_mask_lt( size_t x, size_t y ); + +size_t mbedtls_cf_size_mask_ge( size_t x, size_t y ); diff --git a/library/ssl_msg.c b/library/ssl_msg.c index de350ebc0..1ea7c5fc0 100644 --- a/library/ssl_msg.c +++ b/library/ssl_msg.c @@ -1045,22 +1045,6 @@ int mbedtls_ssl_encrypt_buf( mbedtls_ssl_context *ssl, } #if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) -/* - * Constant-flow mask generation for "greater or equal" comparison: - * - if x >= 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. - * - * This function is implemented without using comparison operators, as those - * might be translated to branches by some compilers on some platforms. - */ -static size_t mbedtls_cf_size_mask_ge( size_t x, size_t y ) -{ - return( ~mbedtls_cf_size_mask_lt( x, y ) ); -} - /* * Constant-flow boolean "equal" comparison: * return x == y From 96584ddd4bf9cb821b5037b534cdf009675aa762 Mon Sep 17 00:00:00 2001 From: gabor-mezei-arm Date: Mon, 27 Sep 2021 12:15:19 +0200 Subject: [PATCH 08/53] Move mbedtls_cf_size_bool_eq function to the constant-time module There were multiple functions called mbedtls_cf_size_bool_eq. They had exactly the same behavior, so move the one in bignum.c and remove the other. Signed-off-by: Gabor Mezei --- library/bignum.c | 37 +------------------------------------ library/constant_time.c | 36 ++++++++++++++++++++++++++++++++++++ library/constant_time.h | 2 ++ library/ssl_msg.c | 35 ----------------------------------- 4 files changed, 39 insertions(+), 71 deletions(-) diff --git a/library/bignum.c b/library/bignum.c index d15bc1a96..bc2dbfa16 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -41,6 +41,7 @@ #include "mbedtls/bn_mul.h" #include "mbedtls/platform_util.h" #include "mbedtls/error.h" +#include "constant_time.h" #include @@ -2227,42 +2228,6 @@ static void mpi_montred( mbedtls_mpi *A, const mbedtls_mpi *N, mpi_montmul( A, &U, N, mm, T ); } -/* - * Constant-flow boolean "equal" comparison: - * return x == y - * - * This function can be used to write constant-time code by replacing branches - * with bit operations - it can be used in conjunction with - * mbedtls_ssl_cf_mask_from_bit(). - * - * This function is implemented without using comparison operators, as those - * might be translated to branches by some compilers on some platforms. - */ -static size_t mbedtls_cf_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 size_t diff1 = diff_msb >> ( sizeof( diff_msb ) * 8 - 1 ); - - return( 1 ^ diff1 ); -} - /** * Select an MPI from a table without leaking the index. * diff --git a/library/constant_time.c b/library/constant_time.c index b53d06ba6..d73f4fe44 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -177,3 +177,39 @@ size_t mbedtls_cf_size_mask_ge( size_t x, size_t y ) { return( ~mbedtls_cf_size_mask_lt( x, y ) ); } + +/* + * Constant-flow boolean "equal" comparison: + * return x == y + * + * This function can be used to write constant-time code by replacing branches + * with bit operations - it can be used in conjunction with + * mbedtls_ssl_cf_mask_from_bit(). + * + * This function is implemented without using comparison operators, as those + * might be translated to branches by some compilers on some platforms. + */ +size_t mbedtls_cf_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 size_t diff1 = diff_msb >> ( sizeof( diff_msb ) * 8 - 1 ); + + return( 1 ^ diff1 ); +} diff --git a/library/constant_time.h b/library/constant_time.h index 8e8992d6f..50108d7d9 100644 --- a/library/constant_time.h +++ b/library/constant_time.h @@ -37,3 +37,5 @@ size_t mbedtls_cf_size_mask( size_t bit ); size_t mbedtls_cf_size_mask_lt( size_t x, size_t y ); size_t mbedtls_cf_size_mask_ge( size_t x, size_t y ); + +size_t mbedtls_cf_size_bool_eq( size_t x, size_t y ); diff --git a/library/ssl_msg.c b/library/ssl_msg.c index 1ea7c5fc0..020abf637 100644 --- a/library/ssl_msg.c +++ b/library/ssl_msg.c @@ -1045,41 +1045,6 @@ int mbedtls_ssl_encrypt_buf( mbedtls_ssl_context *ssl, } #if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) -/* - * Constant-flow boolean "equal" comparison: - * return x == y - * - * This function can be used to write constant-time code by replacing branches - * with bit operations - it can be used in conjunction with - * mbedtls_cf_size_mask(). - * - * This function is implemented without using comparison operators, as those - * might be translated to branches by some compilers on some platforms. - */ -static size_t mbedtls_cf_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 | -diff ); - -#if defined(_MSC_VER) -#pragma warning( pop ) -#endif - - /* diff1 = (x != y) ? 1 : 0 */ - const size_t diff1 = diff_msb >> ( sizeof( diff_msb ) * 8 - 1 ); - - return( 1 ^ diff1 ); -} /* * Constant-flow conditional memcpy: From 9d7bf09333cd1f1704377f204f18e4dde6f6ce07 Mon Sep 17 00:00:00 2001 From: gabor-mezei-arm Date: Mon, 27 Sep 2021 12:25:07 +0200 Subject: [PATCH 09/53] Move mbedtls_cf_size_gt function to the constant-time module Signed-off-by: Gabor Mezei --- library/constant_time.c | 16 ++++++++++++++++ library/constant_time.h | 2 ++ library/rsa.c | 16 ---------------- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index d73f4fe44..7da404662 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -213,3 +213,19 @@ size_t mbedtls_cf_size_bool_eq( size_t x, size_t y ) return( 1 ^ diff1 ); } + +/** Check whether a size is out of bounds, without branches. + * + * This is equivalent to `size > max`, but is likely to be compiled to + * to code using bitwise operation rather than a branch. + * + * \param size Size to check. + * \param max Maximum desired value for \p size. + * \return \c 0 if `size <= max`. + * \return \c 1 if `size > max`. + */ +unsigned mbedtls_cf_size_gt( size_t size, size_t max ) +{ + /* Return the sign bit (1 for negative) of (max - size). */ + return( ( max - size ) >> ( sizeof( size_t ) * 8 - 1 ) ); +} diff --git a/library/constant_time.h b/library/constant_time.h index 50108d7d9..eff7f446f 100644 --- a/library/constant_time.h +++ b/library/constant_time.h @@ -39,3 +39,5 @@ size_t mbedtls_cf_size_mask_lt( size_t x, size_t y ); size_t mbedtls_cf_size_mask_ge( size_t x, size_t y ); size_t mbedtls_cf_size_bool_eq( size_t x, size_t y ); + +unsigned mbedtls_cf_size_gt( size_t size, size_t max ); diff --git a/library/rsa.c b/library/rsa.c index d5151a5e0..26b6d3422 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -1479,22 +1479,6 @@ cleanup: #endif /* MBEDTLS_PKCS1_V21 */ #if defined(MBEDTLS_PKCS1_V15) -/** Check whether a size is out of bounds, without branches. - * - * This is equivalent to `size > max`, but is likely to be compiled to - * to code using bitwise operation rather than a branch. - * - * \param size Size to check. - * \param max Maximum desired value for \p size. - * \return \c 0 if `size <= max`. - * \return \c 1 if `size > max`. - */ -static unsigned mbedtls_cf_size_gt( size_t size, size_t max ) -{ - /* Return the sign bit (1 for negative) of (max - size). */ - return( ( max - size ) >> ( sizeof( size_t ) * 8 - 1 ) ); -} - /** Choose between two integer values, without branches. * * This is equivalent to `cond ? if1 : if0`, but is likely to be compiled From 17da4f2a4e3e612ca9fa91d57088b61793423a0b Mon Sep 17 00:00:00 2001 From: gabor-mezei-arm Date: Mon, 27 Sep 2021 12:47:06 +0200 Subject: [PATCH 10/53] Remove module dependency Elinimate macros defined by modules locally in the functions that are moving to the new constant-time module. Signed-off-by: Gabor Mezei --- library/bignum.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/bignum.c b/library/bignum.c index bc2dbfa16..5f0e735e2 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -1277,7 +1277,7 @@ static unsigned mbedtls_cf_mpi_uint_lt( const mbedtls_mpi_uint x, ret |= y & cond; - ret = ret >> ( biL - 1 ); + ret = ret >> ( sizeof( mbedtls_mpi_uint ) * 8 - 1 ); return (unsigned) ret; } From 097d4f555e8504f86f34dc6477324c49d4359da2 Mon Sep 17 00:00:00 2001 From: gabor-mezei-arm Date: Mon, 27 Sep 2021 12:55:33 +0200 Subject: [PATCH 11/53] Move mbedtls_cf_mpi_uint_lt function to the constant-time module Signed-off-by: Gabor Mezei --- library/bignum.c | 35 -------------------------------- library/constant_time.c | 44 +++++++++++++++++++++++++++++++++++++++++ library/constant_time.h | 11 +++++++++++ 3 files changed, 55 insertions(+), 35 deletions(-) diff --git a/library/bignum.c b/library/bignum.c index 5f0e735e2..a97bbe9f4 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -1247,41 +1247,6 @@ int mbedtls_mpi_cmp_mpi( const mbedtls_mpi *X, const mbedtls_mpi *Y ) return( 0 ); } -/** Decide if an integer is less than the other, without branches. - * - * \param x First integer. - * \param y Second integer. - * - * \return 1 if \p x is less than \p y, 0 otherwise - */ -static unsigned mbedtls_cf_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; -} - /* * Compare signed values in constant time */ diff --git a/library/constant_time.c b/library/constant_time.c index 7da404662..b513c6a9d 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -20,6 +20,11 @@ #include "common.h" #include "constant_time.h" +#if defined(MBEDTLS_BIGNUM_C) +#include "mbedtls/bignum.h" +#endif + + /* constant-time buffer comparison */ int mbedtls_ssl_safer_memcmp( const void *a, const void *b, size_t n ) { @@ -229,3 +234,42 @@ unsigned mbedtls_cf_size_gt( size_t size, size_t max ) /* Return the sign bit (1 for negative) of (max - size). */ return( ( max - size ) >> ( sizeof( size_t ) * 8 - 1 ) ); } + +#if defined(MBEDTLS_BIGNUM_C) + +/** Decide if an integer is less than the other, without branches. + * + * \param x First integer. + * \param y Second integer. + * + * \return 1 if \p x is less than \p y, 0 otherwise + */ +unsigned mbedtls_cf_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 */ diff --git a/library/constant_time.h b/library/constant_time.h index eff7f446f..3c18b4ef9 100644 --- a/library/constant_time.h +++ b/library/constant_time.h @@ -19,6 +19,10 @@ #include "common.h" +#if defined(MBEDTLS_BIGNUM_C) +#include "mbedtls/bignum.h" +#endif + #include int mbedtls_ssl_safer_memcmp( const void *a, const void *b, size_t n ); @@ -41,3 +45,10 @@ size_t mbedtls_cf_size_mask_ge( size_t x, size_t y ); size_t mbedtls_cf_size_bool_eq( size_t x, size_t y ); unsigned mbedtls_cf_size_gt( size_t size, size_t max ); + +#if defined(MBEDTLS_BIGNUM_C) + +unsigned mbedtls_cf_mpi_uint_lt( const mbedtls_mpi_uint x, + const mbedtls_mpi_uint y ); + +#endif /* MBEDTLS_BIGNUM_C */ From 75332531259083504df336ae4c1eb5fb2bea1ca2 Mon Sep 17 00:00:00 2001 From: gabor-mezei-arm Date: Mon, 27 Sep 2021 12:59:30 +0200 Subject: [PATCH 12/53] Move mbedtls_cf_uint_if function to the constant-time module Signed-off-by: Gabor Mezei --- library/constant_time.c | 16 ++++++++++++++++ library/constant_time.h | 3 +++ library/rsa.c | 16 ---------------- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index b513c6a9d..6d531345c 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -273,3 +273,19 @@ unsigned mbedtls_cf_mpi_uint_lt( const mbedtls_mpi_uint x, } #endif /* MBEDTLS_BIGNUM_C */ + +/** Choose between two integer values, without branches. + * + * This is equivalent to `cond ? if1 : if0`, but is likely to be compiled + * to code using bitwise operation rather than a branch. + * + * \param cond Condition to test. + * \param if1 Value to use if \p cond is nonzero. + * \param if0 Value to use if \p cond is zero. + * \return \c if1 if \p cond is nonzero, otherwise \c if0. + */ +unsigned mbedtls_cf_uint_if( unsigned cond, unsigned if1, unsigned if0 ) +{ + unsigned mask = mbedtls_cf_uint_mask( cond ); + return( ( mask & if1 ) | (~mask & if0 ) ); +} diff --git a/library/constant_time.h b/library/constant_time.h index 3c18b4ef9..973e856d6 100644 --- a/library/constant_time.h +++ b/library/constant_time.h @@ -52,3 +52,6 @@ unsigned mbedtls_cf_mpi_uint_lt( const mbedtls_mpi_uint x, const mbedtls_mpi_uint y ); #endif /* MBEDTLS_BIGNUM_C */ + +unsigned mbedtls_cf_uint_if( unsigned cond, unsigned if1, unsigned if0 ); + diff --git a/library/rsa.c b/library/rsa.c index 26b6d3422..2cee36f27 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -1479,22 +1479,6 @@ cleanup: #endif /* MBEDTLS_PKCS1_V21 */ #if defined(MBEDTLS_PKCS1_V15) -/** Choose between two integer values, without branches. - * - * This is equivalent to `cond ? if1 : if0`, but is likely to be compiled - * to code using bitwise operation rather than a branch. - * - * \param cond Condition to test. - * \param if1 Value to use if \p cond is nonzero. - * \param if0 Value to use if \p cond is zero. - * \return \c if1 if \p cond is nonzero, otherwise \c if0. - */ -static unsigned mbedtls_cf_uint_if( unsigned cond, unsigned if1, unsigned if0 ) -{ - unsigned mask = mbedtls_cf_uint_mask( cond ); - return( ( mask & if1 ) | (~mask & if0 ) ); -} - /** Shift some data towards the left inside a buffer without leaking * the length of the data through side channels. * From 5cec8b44a82c49ad24a7fc55123aa15dd94a38f0 Mon Sep 17 00:00:00 2001 From: gabor-mezei-arm Date: Mon, 27 Sep 2021 13:03:57 +0200 Subject: [PATCH 13/53] Move mbedtls_cf_cond_select_sign function to the constant-time module Signed-off-by: Gabor Mezei --- library/bignum.c | 30 ------------------------------ library/constant_time.c | 30 ++++++++++++++++++++++++++++++ library/constant_time.h | 1 + 3 files changed, 31 insertions(+), 30 deletions(-) diff --git a/library/bignum.c b/library/bignum.c index a97bbe9f4..7caace776 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -269,36 +269,6 @@ void mbedtls_mpi_swap( mbedtls_mpi *X, mbedtls_mpi *Y ) memcpy( Y, &T, sizeof( mbedtls_mpi ) ); } -/** - * Select between two sign values in constant-time. - * - * This is functionally equivalent to second ? a : b but uses only bit - * operations in order to avoid branches. - * - * \param[in] a The first sign; must be either +1 or -1. - * \param[in] b The second sign; must be either +1 or -1. - * \param[in] second Must be either 1 (return b) or 0 (return a). - * - * \return The selected sign value. - */ -static int mbedtls_cf_cond_select_sign( int a, int b, unsigned char second ) -{ - /* In order to avoid questions about what we can reasonnably assume about - * the representations of signed integers, move everything to unsigned - * by taking advantage of the fact that a and b are either +1 or -1. */ - unsigned ua = a + 1; - unsigned ub = b + 1; - - /* second was 0 or 1, mask is 0 or 2 as are ua and ub */ - const unsigned mask = second << 1; - - /* select ua or ub */ - unsigned ur = ( ua & ~mask ) | ( ub & mask ); - - /* ur is now 0 or 2, convert back to -1 or +1 */ - return( (int) ur - 1 ); -} - /* * Conditionally assign dest = src, without leaking information * about whether the assignment was made or not. diff --git a/library/constant_time.c b/library/constant_time.c index 6d531345c..6f59884ef 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -289,3 +289,33 @@ unsigned mbedtls_cf_uint_if( unsigned cond, unsigned if1, unsigned if0 ) unsigned mask = mbedtls_cf_uint_mask( cond ); return( ( mask & if1 ) | (~mask & if0 ) ); } + +/** + * Select between two sign values in constant-time. + * + * This is functionally equivalent to second ? a : b but uses only bit + * operations in order to avoid branches. + * + * \param[in] a The first sign; must be either +1 or -1. + * \param[in] b The second sign; must be either +1 or -1. + * \param[in] second Must be either 1 (return b) or 0 (return a). + * + * \return The selected sign value. + */ +int mbedtls_cf_cond_select_sign( int a, int b, unsigned char second ) +{ + /* In order to avoid questions about what we can reasonnably assume about + * the representations of signed integers, move everything to unsigned + * by taking advantage of the fact that a and b are either +1 or -1. */ + unsigned ua = a + 1; + unsigned ub = b + 1; + + /* second was 0 or 1, mask is 0 or 2 as are ua and ub */ + const unsigned mask = second << 1; + + /* select ua or ub */ + unsigned ur = ( ua & ~mask ) | ( ub & mask ); + + /* ur is now 0 or 2, convert back to -1 or +1 */ + return( (int) ur - 1 ); +} diff --git a/library/constant_time.h b/library/constant_time.h index 973e856d6..f97c57e7c 100644 --- a/library/constant_time.h +++ b/library/constant_time.h @@ -55,3 +55,4 @@ unsigned mbedtls_cf_mpi_uint_lt( const mbedtls_mpi_uint x, unsigned mbedtls_cf_uint_if( unsigned cond, unsigned if1, unsigned if0 ); +int mbedtls_cf_cond_select_sign( int a, int b, unsigned char second ); From 043192d2090595e3f0d40f88566b860c1d670ab4 Mon Sep 17 00:00:00 2001 From: gabor-mezei-arm Date: Mon, 27 Sep 2021 13:17:15 +0200 Subject: [PATCH 14/53] Move mbedtls_cf_mpi_uint_cond_assign function to the constant-time module Signed-off-by: Gabor Mezei --- library/bignum.c | 31 ------------------------------- library/constant_time.c | 35 +++++++++++++++++++++++++++++++++++ library/constant_time.h | 9 +++++++++ 3 files changed, 44 insertions(+), 31 deletions(-) diff --git a/library/bignum.c b/library/bignum.c index 7caace776..51a64974b 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -269,37 +269,6 @@ void mbedtls_mpi_swap( mbedtls_mpi *X, mbedtls_mpi *Y ) memcpy( Y, &T, sizeof( mbedtls_mpi ) ); } -/* - * Conditionally assign dest = src, without leaking information - * about whether the assignment was made or not. - * dest and src must be arrays of limbs of size n. - * assign must be 0 or 1. - */ -void mbedtls_cf_mpi_uint_cond_assign( size_t n, - mbedtls_mpi_uint *dest, - const mbedtls_mpi_uint *src, - unsigned char assign ) -{ - 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 assign is 1, all-bits 0 if assign is 0 */ - const mbedtls_mpi_uint mask = -assign; - -#if defined(_MSC_VER) -#pragma warning( pop ) -#endif - - for( i = 0; i < n; i++ ) - dest[i] = ( src[i] & mask ) | ( dest[i] & ~mask ); -} - /* * Conditionally assign X = Y, without leaking information * about whether the assignment was made or not. diff --git a/library/constant_time.c b/library/constant_time.c index 6f59884ef..b48305a1f 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -319,3 +319,38 @@ int mbedtls_cf_cond_select_sign( int a, int b, unsigned char second ) /* ur is now 0 or 2, convert back to -1 or +1 */ return( (int) ur - 1 ); } + +#if defined(MBEDTLS_BIGNUM_C) + +/* + * Conditionally assign dest = src, without leaking information + * about whether the assignment was made or not. + * dest and src must be arrays of limbs of size n. + * assign must be 0 or 1. + */ +void mbedtls_cf_mpi_uint_cond_assign( size_t n, + mbedtls_mpi_uint *dest, + const mbedtls_mpi_uint *src, + unsigned char assign ) +{ + 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 assign is 1, all-bits 0 if assign is 0 */ + const mbedtls_mpi_uint mask = -assign; + +#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 */ diff --git a/library/constant_time.h b/library/constant_time.h index f97c57e7c..588181ec9 100644 --- a/library/constant_time.h +++ b/library/constant_time.h @@ -56,3 +56,12 @@ unsigned mbedtls_cf_mpi_uint_lt( const mbedtls_mpi_uint x, unsigned mbedtls_cf_uint_if( unsigned cond, unsigned if1, unsigned if0 ); int mbedtls_cf_cond_select_sign( int a, int b, unsigned char second ); + +#if defined(MBEDTLS_BIGNUM_C) + +void mbedtls_cf_mpi_uint_cond_assign( size_t n, + mbedtls_mpi_uint *dest, + const mbedtls_mpi_uint *src, + unsigned char assign ); + +#endif /* MBEDTLS_BIGNUM_C */ From 7b23c0b46d5367917aa3f100a24b22581fe8f60c Mon Sep 17 00:00:00 2001 From: gabor-mezei-arm Date: Mon, 27 Sep 2021 13:31:06 +0200 Subject: [PATCH 15/53] Move mbedtls_cf_mem_move_to_left function to the constant-time module Signed-off-by: Gabor Mezei --- library/constant_time.c | 41 +++++++++++++++++++++++++++++++++++++++++ library/constant_time.h | 4 ++++ library/rsa.c | 41 ----------------------------------------- 3 files changed, 45 insertions(+), 41 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index b48305a1f..281df6400 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -354,3 +354,44 @@ void mbedtls_cf_mpi_uint_cond_assign( size_t n, } #endif /* MBEDTLS_BIGNUM_C */ + +/** Shift some data towards the left inside a buffer without leaking + * the length of the data through side channels. + * + * `mbedtls_cf_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_cf_mem_move_to_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_cf_size_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++ ) + { + unsigned char current = buf[n]; + unsigned char next = buf[n+1]; + buf[n] = mbedtls_cf_uint_if( no_op, current, next ); + } + buf[total-1] = mbedtls_cf_uint_if( no_op, buf[total-1], 0 ); + } +} diff --git a/library/constant_time.h b/library/constant_time.h index 588181ec9..5a932cc6f 100644 --- a/library/constant_time.h +++ b/library/constant_time.h @@ -65,3 +65,7 @@ void mbedtls_cf_mpi_uint_cond_assign( size_t n, unsigned char assign ); #endif /* MBEDTLS_BIGNUM_C */ + +void mbedtls_cf_mem_move_to_left( void *start, + size_t total, + size_t offset ); diff --git a/library/rsa.c b/library/rsa.c index 2cee36f27..b8be89ca7 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -1479,47 +1479,6 @@ cleanup: #endif /* MBEDTLS_PKCS1_V21 */ #if defined(MBEDTLS_PKCS1_V15) -/** Shift some data towards the left inside a buffer without leaking - * the length of the data through side channels. - * - * `mbedtls_cf_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_cf_mem_move_to_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_cf_size_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++ ) - { - unsigned char current = buf[n]; - unsigned char next = buf[n+1]; - buf[n] = mbedtls_cf_uint_if( no_op, current, next ); - } - buf[total-1] = mbedtls_cf_uint_if( no_op, buf[total-1], 0 ); - } -} - /* * Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-DECRYPT function */ From ee06febbb45477f052f94ba1602507a50fda404d Mon Sep 17 00:00:00 2001 From: gabor-mezei-arm Date: Mon, 27 Sep 2021 13:34:25 +0200 Subject: [PATCH 16/53] Move mbedtls_cf_memcpy_if_eq function to the constant-time module Signed-off-by: Gabor Mezei --- library/constant_time.c | 23 +++++++++++++++++++++++ library/constant_time.h | 5 +++++ library/ssl_msg.c | 23 ----------------------- 3 files changed, 28 insertions(+), 23 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index 281df6400..cbfc8e59a 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -395,3 +395,26 @@ void mbedtls_cf_mem_move_to_left( void *start, buf[total-1] = mbedtls_cf_uint_if( no_op, buf[total-1], 0 ); } } + +/* + * Constant-flow conditional memcpy: + * - if c1 == c2, equivalent to memcpy(dst, src, len), + * - otherwise, a no-op, + * but with execution flow independent of the values of c1 and c2. + * + * This function is implemented without using comparison operators, as those + * might be translated to branches by some compilers on some platforms. + */ +void mbedtls_cf_memcpy_if_eq( unsigned char *dst, + const unsigned char *src, + size_t len, + size_t c1, size_t c2 ) +{ + /* mask = c1 == c2 ? 0xff : 0x00 */ + const size_t equal = mbedtls_cf_size_bool_eq( c1, c2 ); + const unsigned char mask = (unsigned char) mbedtls_cf_size_mask( equal ); + + /* dst[i] = c1 == c2 ? src[i] : dst[i] */ + for( size_t i = 0; i < len; i++ ) + dst[i] = ( src[i] & mask ) | ( dst[i] & ~mask ); +} diff --git a/library/constant_time.h b/library/constant_time.h index 5a932cc6f..ae491b892 100644 --- a/library/constant_time.h +++ b/library/constant_time.h @@ -69,3 +69,8 @@ void mbedtls_cf_mpi_uint_cond_assign( size_t n, void mbedtls_cf_mem_move_to_left( void *start, size_t total, size_t offset ); + +void mbedtls_cf_memcpy_if_eq( unsigned char *dst, + const unsigned char *src, + size_t len, + size_t c1, size_t c2 ); diff --git a/library/ssl_msg.c b/library/ssl_msg.c index 020abf637..42579ea9a 100644 --- a/library/ssl_msg.c +++ b/library/ssl_msg.c @@ -1046,29 +1046,6 @@ int mbedtls_ssl_encrypt_buf( mbedtls_ssl_context *ssl, #if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) -/* - * Constant-flow conditional memcpy: - * - if c1 == c2, equivalent to memcpy(dst, src, len), - * - otherwise, a no-op, - * but with execution flow independent of the values of c1 and c2. - * - * This function is implemented without using comparison operators, as those - * might be translated to branches by some compilers on some platforms. - */ -static void mbedtls_cf_memcpy_if_eq( unsigned char *dst, - const unsigned char *src, - size_t len, - size_t c1, size_t c2 ) -{ - /* mask = c1 == c2 ? 0xff : 0x00 */ - const size_t equal = mbedtls_cf_size_bool_eq( c1, c2 ); - const unsigned char mask = (unsigned char) mbedtls_cf_size_mask( equal ); - - /* dst[i] = c1 == c2 ? src[i] : dst[i] */ - for( size_t i = 0; i < len; i++ ) - dst[i] = ( src[i] & mask ) | ( dst[i] & ~mask ); -} - /* * Compute HMAC of variable-length data with constant flow. * From 0f7b9e43e9729073bb342f1810bd2301893662fc Mon Sep 17 00:00:00 2001 From: gabor-mezei-arm Date: Mon, 27 Sep 2021 13:57:45 +0200 Subject: [PATCH 17/53] Move mbedtls_cf_memcpy_offset function to the constant-time module Signed-off-by: Gabor Mezei --- library/constant_time.c | 21 +++++++++++++++++++++ library/constant_time.h | 24 ++++++++++++++++++++++++ library/ssl_msg.c | 21 --------------------- 3 files changed, 45 insertions(+), 21 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index cbfc8e59a..d48d646ee 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -418,3 +418,24 @@ void mbedtls_cf_memcpy_if_eq( unsigned char *dst, for( size_t i = 0; i < len; i++ ) dst[i] = ( src[i] & mask ) | ( dst[i] & ~mask ); } + +/* + * Constant-flow memcpy from variable position in buffer. + * - functionally equivalent to memcpy(dst, src + offset_secret, len) + * - but with execution flow independent from the value of offset_secret. + */ +void mbedtls_cf_memcpy_offset( + unsigned char *dst, + const unsigned char *src_base, + size_t offset_secret, + size_t offset_min, size_t offset_max, + size_t len ) +{ + size_t offset; + + for( offset = offset_min; offset <= offset_max; offset++ ) + { + mbedtls_cf_memcpy_if_eq( dst, src_base + offset, len, + offset, offset_secret ); + } +} diff --git a/library/constant_time.h b/library/constant_time.h index ae491b892..060aca388 100644 --- a/library/constant_time.h +++ b/library/constant_time.h @@ -74,3 +74,27 @@ void mbedtls_cf_memcpy_if_eq( unsigned char *dst, 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. + * + * \param dst The destination buffer. This must point to a writable + * buffer of at least \p len bytes. + * \param src_base The base of the source buffer. This must point to a + * readable buffer of at least \p offset_max + \p len + * bytes. + * \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_secret. + * \param offset_max The maximal value of \p offset_secret. + * \param len The number of bytes to copy. + */ +void mbedtls_cf_memcpy_offset( unsigned char *dst, + const unsigned char *src_base, + size_t offset_secret, + size_t offset_min, size_t offset_max, + size_t len ); diff --git a/library/ssl_msg.c b/library/ssl_msg.c index 42579ea9a..fe73130b2 100644 --- a/library/ssl_msg.c +++ b/library/ssl_msg.c @@ -1133,27 +1133,6 @@ cleanup: mbedtls_md_free( &aux ); return( ret ); } - -/* - * Constant-flow memcpy from variable position in buffer. - * - functionally equivalent to memcpy(dst, src + offset_secret, len) - * - but with execution flow independent from the value of offset_secret. - */ -MBEDTLS_STATIC_TESTABLE void mbedtls_cf_memcpy_offset( - unsigned char *dst, - const unsigned char *src_base, - size_t offset_secret, - size_t offset_min, size_t offset_max, - size_t len ) -{ - size_t offset; - - for( offset = offset_min; offset <= offset_max; offset++ ) - { - mbedtls_cf_memcpy_if_eq( dst, src_base + offset, len, - offset, offset_secret ); - } -} #endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */ int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl, From cb4317b7236ccaafd2be4c8fd1699d11e30dd864 Mon Sep 17 00:00:00 2001 From: gabor-mezei-arm Date: Mon, 27 Sep 2021 14:28:31 +0200 Subject: [PATCH 18/53] Move mbedtls_cf_hmac function to the constant-time module Signed-off-by: Gabor Mezei --- library/constant_time.c | 97 +++++++++++++++++++++++++++++++++++++++++ library/constant_time.h | 48 ++++++++++++++++++++ library/ssl_msg.c | 91 -------------------------------------- 3 files changed, 145 insertions(+), 91 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index d48d646ee..c5fce5b54 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -19,11 +19,16 @@ #include "common.h" #include "constant_time.h" +#include "mbedtls/error.h" #if defined(MBEDTLS_BIGNUM_C) #include "mbedtls/bignum.h" #endif +#if defined(MBEDTLS_SSL_TLS_C) +#include "mbedtls/ssl_internal.h" +#endif + /* constant-time buffer comparison */ int mbedtls_ssl_safer_memcmp( const void *a, const void *b, size_t n ) @@ -439,3 +444,95 @@ void mbedtls_cf_memcpy_offset( offset, offset_secret ); } } + +#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) + +/* + * Compute HMAC of variable-length data with constant flow. + * + * Only works with MD-5, SHA-1, SHA-256 and SHA-384. + * (Otherwise, computation of block_size needs to be adapted.) + */ +int mbedtls_cf_hmac( + mbedtls_md_context_t *ctx, + const unsigned char *add_data, size_t add_data_len, + const unsigned char *data, size_t data_len_secret, + size_t min_data_len, size_t max_data_len, + unsigned char *output ) +{ + /* + * This function breaks the HMAC abstraction and uses the md_clone() + * extension to the MD API in order to get constant-flow behaviour. + * + * HMAC(msg) is defined as HASH(okey + HASH(ikey + msg)) where + means + * concatenation, and okey/ikey are the XOR of the key with some fixed bit + * patterns (see RFC 2104, sec. 2), which are stored in ctx->hmac_ctx. + * + * We'll first compute inner_hash = HASH(ikey + msg) by hashing up to + * minlen, then cloning the context, and for each byte up to maxlen + * finishing up the hash computation, keeping only the correct result. + * + * Then we only need to compute HASH(okey + inner_hash) and we're done. + */ + const mbedtls_md_type_t md_alg = mbedtls_md_get_type( ctx->md_info ); + /* TLS 1.0-1.2 only support SHA-384, SHA-256, SHA-1, MD-5, + * all of which have the same block size except SHA-384. */ + const size_t block_size = md_alg == MBEDTLS_MD_SHA384 ? 128 : 64; + const unsigned char * const ikey = ctx->hmac_ctx; + const unsigned char * const okey = ikey + block_size; + const size_t hash_size = mbedtls_md_get_size( ctx->md_info ); + + unsigned char aux_out[MBEDTLS_MD_MAX_SIZE]; + mbedtls_md_context_t aux; + size_t offset; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + mbedtls_md_init( &aux ); + +#define MD_CHK( func_call ) \ + do { \ + ret = (func_call); \ + if( ret != 0 ) \ + goto cleanup; \ + } while( 0 ) + + MD_CHK( mbedtls_md_setup( &aux, ctx->md_info, 0 ) ); + + /* After hmac_start() of hmac_reset(), ikey has already been hashed, + * so we can start directly with the message */ + MD_CHK( mbedtls_md_update( ctx, add_data, add_data_len ) ); + MD_CHK( mbedtls_md_update( ctx, data, min_data_len ) ); + + /* For each possible length, compute the hash up to that point */ + for( offset = min_data_len; offset <= max_data_len; offset++ ) + { + MD_CHK( mbedtls_md_clone( &aux, ctx ) ); + MD_CHK( mbedtls_md_finish( &aux, aux_out ) ); + /* Keep only the correct inner_hash in the output buffer */ + mbedtls_cf_memcpy_if_eq( output, aux_out, hash_size, + offset, data_len_secret ); + + if( offset < max_data_len ) + MD_CHK( mbedtls_md_update( ctx, data + offset, 1 ) ); + } + + /* The context needs to finish() before it starts() again */ + MD_CHK( mbedtls_md_finish( ctx, aux_out ) ); + + /* Now compute HASH(okey + inner_hash) */ + MD_CHK( mbedtls_md_starts( ctx ) ); + MD_CHK( mbedtls_md_update( ctx, okey, block_size ) ); + MD_CHK( mbedtls_md_update( ctx, output, hash_size ) ); + MD_CHK( mbedtls_md_finish( ctx, output ) ); + + /* Done, get ready for next time */ + MD_CHK( mbedtls_md_hmac_reset( ctx ) ); + +#undef MD_CHK + +cleanup: + mbedtls_md_free( &aux ); + return( ret ); +} + +#endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */ diff --git a/library/constant_time.h b/library/constant_time.h index 060aca388..a8d142b85 100644 --- a/library/constant_time.h +++ b/library/constant_time.h @@ -23,6 +23,10 @@ #include "mbedtls/bignum.h" #endif +#if defined(MBEDTLS_SSL_TLS_C) +#include "mbedtls/ssl_internal.h" +#endif + #include int mbedtls_ssl_safer_memcmp( const void *a, const void *b, size_t n ); @@ -98,3 +102,47 @@ void mbedtls_cf_memcpy_offset( unsigned char *dst, size_t offset_secret, size_t offset_min, size_t offset_max, size_t len ); + +#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) + +/** Compute the HMAC of variable-length data with constant flow. + * + * This function computes the HMAC of the concatenation of \p add_data and \p + * data, and does with a code flow and memory access pattern that does not + * depend on \p data_len_secret, but only on \p min_data_len and \p + * max_data_len. In particular, this function always reads exactly \p + * max_data_len bytes from \p data. + * + * \param ctx The HMAC context. It must have keys configured + * with mbedtls_md_hmac_starts() and use one of the + * following hashes: SHA-384, SHA-256, SHA-1 or MD-5. + * It is reset using mbedtls_md_hmac_reset() after + * the computation is complete to prepare for the + * next computation. + * \param add_data The additional data prepended to \p data. This + * must point to a readable buffer of \p add_data_len + * bytes. + * \param add_data_len The length of \p add_data in bytes. + * \param data The data appended to \p add_data. This must point + * to a readable buffer of \p max_data_len bytes. + * \param data_len_secret The length of the data to process in \p data. + * This must be no less than \p min_data_len and no + * greater than \p max_data_len. + * \param min_data_len The minimal length of \p data in bytes. + * \param max_data_len The maximal length of \p data in bytes. + * \param output The HMAC will be written here. This must point to + * a writable buffer of sufficient size to hold the + * HMAC value. + * + * \retval 0 on success. + * \retval MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED + * The hardware accelerator failed. + */ +int mbedtls_ssl_cf_hmac( + mbedtls_md_context_t *ctx, + const unsigned char *add_data, size_t add_data_len, + const unsigned char *data, size_t data_len_secret, + size_t min_data_len, size_t max_data_len, + unsigned char *output ); + +#endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */ diff --git a/library/ssl_msg.c b/library/ssl_msg.c index fe73130b2..d80421cca 100644 --- a/library/ssl_msg.c +++ b/library/ssl_msg.c @@ -1044,97 +1044,6 @@ int mbedtls_ssl_encrypt_buf( mbedtls_ssl_context *ssl, return( 0 ); } -#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) - -/* - * Compute HMAC of variable-length data with constant flow. - * - * Only works with MD-5, SHA-1, SHA-256 and SHA-384. - * (Otherwise, computation of block_size needs to be adapted.) - */ -MBEDTLS_STATIC_TESTABLE int mbedtls_cf_hmac( - mbedtls_md_context_t *ctx, - const unsigned char *add_data, size_t add_data_len, - const unsigned char *data, size_t data_len_secret, - size_t min_data_len, size_t max_data_len, - unsigned char *output ) -{ - /* - * This function breaks the HMAC abstraction and uses the md_clone() - * extension to the MD API in order to get constant-flow behaviour. - * - * HMAC(msg) is defined as HASH(okey + HASH(ikey + msg)) where + means - * concatenation, and okey/ikey are the XOR of the key with some fixed bit - * patterns (see RFC 2104, sec. 2), which are stored in ctx->hmac_ctx. - * - * We'll first compute inner_hash = HASH(ikey + msg) by hashing up to - * minlen, then cloning the context, and for each byte up to maxlen - * finishing up the hash computation, keeping only the correct result. - * - * Then we only need to compute HASH(okey + inner_hash) and we're done. - */ - const mbedtls_md_type_t md_alg = mbedtls_md_get_type( ctx->md_info ); - /* TLS 1.0-1.2 only support SHA-384, SHA-256, SHA-1, MD-5, - * all of which have the same block size except SHA-384. */ - const size_t block_size = md_alg == MBEDTLS_MD_SHA384 ? 128 : 64; - const unsigned char * const ikey = ctx->hmac_ctx; - const unsigned char * const okey = ikey + block_size; - const size_t hash_size = mbedtls_md_get_size( ctx->md_info ); - - unsigned char aux_out[MBEDTLS_MD_MAX_SIZE]; - mbedtls_md_context_t aux; - size_t offset; - int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; - - mbedtls_md_init( &aux ); - -#define MD_CHK( func_call ) \ - do { \ - ret = (func_call); \ - if( ret != 0 ) \ - goto cleanup; \ - } while( 0 ) - - MD_CHK( mbedtls_md_setup( &aux, ctx->md_info, 0 ) ); - - /* After hmac_start() of hmac_reset(), ikey has already been hashed, - * so we can start directly with the message */ - MD_CHK( mbedtls_md_update( ctx, add_data, add_data_len ) ); - MD_CHK( mbedtls_md_update( ctx, data, min_data_len ) ); - - /* For each possible length, compute the hash up to that point */ - for( offset = min_data_len; offset <= max_data_len; offset++ ) - { - MD_CHK( mbedtls_md_clone( &aux, ctx ) ); - MD_CHK( mbedtls_md_finish( &aux, aux_out ) ); - /* Keep only the correct inner_hash in the output buffer */ - mbedtls_cf_memcpy_if_eq( output, aux_out, hash_size, - offset, data_len_secret ); - - if( offset < max_data_len ) - MD_CHK( mbedtls_md_update( ctx, data + offset, 1 ) ); - } - - /* The context needs to finish() before it starts() again */ - MD_CHK( mbedtls_md_finish( ctx, aux_out ) ); - - /* Now compute HASH(okey + inner_hash) */ - MD_CHK( mbedtls_md_starts( ctx ) ); - MD_CHK( mbedtls_md_update( ctx, okey, block_size ) ); - MD_CHK( mbedtls_md_update( ctx, output, hash_size ) ); - MD_CHK( mbedtls_md_finish( ctx, output ) ); - - /* Done, get ready for next time */ - MD_CHK( mbedtls_md_hmac_reset( ctx ) ); - -#undef MD_CHK - -cleanup: - mbedtls_md_free( &aux ); - return( ret ); -} -#endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */ - int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl, mbedtls_ssl_transform *transform, mbedtls_record *rec ) From 6e4ace6b40778a81cf4b9f1f62120cf4a96d6d39 Mon Sep 17 00:00:00 2001 From: gabor-mezei-arm Date: Mon, 27 Sep 2021 14:36:10 +0200 Subject: [PATCH 19/53] Delete ssl_invasive.h due to duplicated function declarations All function declaration provided by ssl_invasive.h is needed only for testing purposes and all of them are provided by constant_time.h as well. Signed-off-by: Gabor Mezei --- library/ssl_invasive.h | 100 --------------------------- library/ssl_msg.c | 2 - tests/suites/test_suite_ssl.function | 2 +- 3 files changed, 1 insertion(+), 103 deletions(-) delete mode 100644 library/ssl_invasive.h diff --git a/library/ssl_invasive.h b/library/ssl_invasive.h deleted file mode 100644 index 5cb29cb0a..000000000 --- a/library/ssl_invasive.h +++ /dev/null @@ -1,100 +0,0 @@ -/** - * \file ssl_invasive.h - * - * \brief SSL 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_SSL_INVASIVE_H -#define MBEDTLS_SSL_INVASIVE_H - -#include "common.h" -#include "mbedtls/md.h" - -#if defined(MBEDTLS_TEST_HOOKS) && \ - defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) -/** \brief Compute the HMAC of variable-length data with constant flow. - * - * This function computes the HMAC of the concatenation of \p add_data and \p - * data, and does with a code flow and memory access pattern that does not - * depend on \p data_len_secret, but only on \p min_data_len and \p - * max_data_len. In particular, this function always reads exactly \p - * max_data_len bytes from \p data. - * - * \param ctx The HMAC context. It must have keys configured - * with mbedtls_md_hmac_starts() and use one of the - * following hashes: SHA-384, SHA-256, SHA-1 or MD-5. - * It is reset using mbedtls_md_hmac_reset() after - * the computation is complete to prepare for the - * next computation. - * \param add_data The additional data prepended to \p data. This - * must point to a readable buffer of \p add_data_len - * bytes. - * \param add_data_len The length of \p add_data in bytes. - * \param data The data appended to \p add_data. This must point - * to a readable buffer of \p max_data_len bytes. - * \param data_len_secret The length of the data to process in \p data. - * This must be no less than \p min_data_len and no - * greater than \p max_data_len. - * \param min_data_len The minimal length of \p data in bytes. - * \param max_data_len The maximal length of \p data in bytes. - * \param output The HMAC will be written here. This must point to - * a writable buffer of sufficient size to hold the - * HMAC value. - * - * \retval 0 - * Success. - * \retval MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED - * The hardware accelerator failed. - */ -int mbedtls_cf_hmac( - mbedtls_md_context_t *ctx, - const unsigned char *add_data, size_t add_data_len, - const unsigned char *data, size_t data_len_secret, - size_t min_data_len, size_t max_data_len, - unsigned char *output ); - -/** \brief 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. - * - * \param dst The destination buffer. This must point to a writable - * buffer of at least \p len bytes. - * \param src_base The base of the source buffer. This must point to a - * readable buffer of at least \p offset_max + \p len - * bytes. - * \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_secret. - * \param offset_max The maximal value of \p offset_secret. - * \param len The number of bytes to copy. - */ -void mbedtls_cf_memcpy_offset( unsigned char *dst, - const unsigned char *src_base, - size_t offset_secret, - size_t offset_min, size_t offset_max, - size_t len ); -#endif /* MBEDTLS_TEST_HOOKS && MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */ - -#endif /* MBEDTLS_SSL_INVASIVE_H */ diff --git a/library/ssl_msg.c b/library/ssl_msg.c index d80421cca..0b940ec36 100644 --- a/library/ssl_msg.c +++ b/library/ssl_msg.c @@ -46,8 +46,6 @@ #include "mbedtls/version.h" #include "constant_time.h" -#include "ssl_invasive.h" - #include #if defined(MBEDTLS_USE_PSA_CRYPTO) diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 83a5e2cb8..37e8067f6 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -8,7 +8,7 @@ #include #include -#include +#include #include From b8caeeed5c6e8254377b422298e87224925b1902 Mon Sep 17 00:00:00 2001 From: gabor-mezei-arm Date: Mon, 27 Sep 2021 15:33:35 +0200 Subject: [PATCH 20/53] Move mbedtls_mpi_safe_cond_assign function to the constant-time module Signed-off-by: Gabor Mezei --- library/bignum.c | 42 ----------------------------------- library/constant_time.c | 49 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 42 deletions(-) diff --git a/library/bignum.c b/library/bignum.c index 51a64974b..b3e275525 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -269,48 +269,6 @@ void mbedtls_mpi_swap( mbedtls_mpi *X, mbedtls_mpi *Y ) memcpy( Y, &T, sizeof( mbedtls_mpi ) ); } -/* - * 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.) - */ -int mbedtls_mpi_safe_cond_assign( mbedtls_mpi *X, const mbedtls_mpi *Y, unsigned char assign ) -{ - int ret = 0; - size_t i; - mbedtls_mpi_uint limb_mask; - MPI_VALIDATE_RET( X != NULL ); - MPI_VALIDATE_RET( Y != NULL ); - - /* 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 - - /* make sure assign is 0 or 1 in a time-constant manner */ - assign = (assign | (unsigned char)-assign) >> (sizeof( assign ) * 8 - 1); - /* all-bits 1 if assign is 1, all-bits 0 if assign is 0 */ - limb_mask = -assign; - -#if defined(_MSC_VER) -#pragma warning( pop ) -#endif - - MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) ); - - X->s = mbedtls_cf_cond_select_sign( X->s, Y->s, assign ); - - mbedtls_cf_mpi_uint_cond_assign( Y->n, X->p, Y->p, assign ); - - for( 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. diff --git a/library/constant_time.c b/library/constant_time.c index c5fce5b54..1fc7a019c 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -536,3 +536,52 @@ cleanup: } #endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */ + +#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.) + */ +int mbedtls_mpi_safe_cond_assign( mbedtls_mpi *X, const mbedtls_mpi *Y, unsigned char assign ) +{ + int ret = 0; + size_t i; + mbedtls_mpi_uint limb_mask; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( Y != NULL ); + + /* 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 + + /* make sure assign is 0 or 1 in a time-constant manner */ + assign = (assign | (unsigned char)-assign) >> (sizeof( assign ) * 8 - 1); + /* all-bits 1 if assign is 1, all-bits 0 if assign is 0 */ + limb_mask = -assign; + +#if defined(_MSC_VER) +#pragma warning( pop ) +#endif + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) ); + + X->s = mbedtls_cf_cond_select_sign( X->s, Y->s, assign ); + + mbedtls_cf_mpi_uint_cond_assign( Y->n, X->p, Y->p, assign ); + + for( i = Y->n; i < X->n; i++ ) + X->p[i] &= ~limb_mask; + +cleanup: + return( ret ); +} + +#endif /* MBEDTLS_BIGNUM_C */ From 58fc8a65ab57322e8facaf0f6ef51289af9e2551 Mon Sep 17 00:00:00 2001 From: gabor-mezei-arm Date: Mon, 27 Sep 2021 15:37:50 +0200 Subject: [PATCH 21/53] Move mbedtls_mpi_safe_cond_swap function to the constant-time module Signed-off-by: Gabor Mezei --- library/bignum.c | 53 ----------------------------------------- library/constant_time.c | 53 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 53 deletions(-) diff --git a/library/bignum.c b/library/bignum.c index b3e275525..e9d090463 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -269,59 +269,6 @@ void mbedtls_mpi_swap( mbedtls_mpi *X, mbedtls_mpi *Y ) memcpy( Y, &T, sizeof( mbedtls_mpi ) ); } -/* - * 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 whould 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, s; - size_t i; - mbedtls_mpi_uint limb_mask; - mbedtls_mpi_uint tmp; - MPI_VALIDATE_RET( X != NULL ); - MPI_VALIDATE_RET( Y != NULL ); - - if( X == Y ) - return( 0 ); - - /* 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 - - /* make sure swap is 0 or 1 in a time-constant manner */ - swap = (swap | (unsigned char)-swap) >> (sizeof( swap ) * 8 - 1); - /* all-bits 1 if swap is 1, all-bits 0 if swap is 0 */ - limb_mask = -swap; - -#if defined(_MSC_VER) -#pragma warning( pop ) -#endif - - MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) ); - MBEDTLS_MPI_CHK( mbedtls_mpi_grow( Y, X->n ) ); - - s = X->s; - X->s = mbedtls_cf_cond_select_sign( X->s, Y->s, swap ); - Y->s = mbedtls_cf_cond_select_sign( Y->s, s, swap ); - - - for( i = 0; i < X->n; i++ ) - { - tmp = X->p[i]; - X->p[i] = ( X->p[i] & ~limb_mask ) | ( Y->p[i] & limb_mask ); - Y->p[i] = ( Y->p[i] & ~limb_mask ) | ( tmp & limb_mask ); - } - -cleanup: - return( ret ); -} - /* * Set value from integer */ diff --git a/library/constant_time.c b/library/constant_time.c index 1fc7a019c..65547a9a0 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -584,4 +584,57 @@ 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 whould 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, s; + size_t i; + mbedtls_mpi_uint limb_mask; + mbedtls_mpi_uint tmp; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( Y != NULL ); + + if( X == Y ) + return( 0 ); + + /* 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 + + /* make sure swap is 0 or 1 in a time-constant manner */ + swap = (swap | (unsigned char)-swap) >> (sizeof( swap ) * 8 - 1); + /* all-bits 1 if swap is 1, all-bits 0 if swap is 0 */ + limb_mask = -swap; + +#if defined(_MSC_VER) +#pragma warning( pop ) +#endif + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( Y, X->n ) ); + + s = X->s; + X->s = mbedtls_cf_cond_select_sign( X->s, Y->s, swap ); + Y->s = mbedtls_cf_cond_select_sign( Y->s, s, swap ); + + + for( i = 0; i < X->n; i++ ) + { + tmp = X->p[i]; + X->p[i] = ( X->p[i] & ~limb_mask ) | ( Y->p[i] & limb_mask ); + Y->p[i] = ( Y->p[i] & ~limb_mask ) | ( tmp & limb_mask ); + } + +cleanup: + return( ret ); +} + #endif /* MBEDTLS_BIGNUM_C */ From b10301d2fcc3cbca231694179630581de2270ff7 Mon Sep 17 00:00:00 2001 From: gabor-mezei-arm Date: Mon, 27 Sep 2021 15:41:30 +0200 Subject: [PATCH 22/53] Move mbedtls_mpi_lt_mpi_ct function to the constant-time module Signed-off-by: Gabor Mezei --- library/bignum.c | 66 ----------------------------------------- library/constant_time.c | 66 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 66 deletions(-) diff --git a/library/bignum.c b/library/bignum.c index e9d090463..a15c6f11b 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -1091,72 +1091,6 @@ int mbedtls_mpi_cmp_mpi( const mbedtls_mpi *X, const mbedtls_mpi *Y ) return( 0 ); } -/* - * 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_cf_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_cf_mpi_uint_lt( X->p[i - 1], Y->p[i - 1] ); - *ret |= cond & ( 1 - done ) & ( 1 - X_is_negative ); - done |= cond; - } - - return( 0 ); -} - /* * Compare signed values */ diff --git a/library/constant_time.c b/library/constant_time.c index 65547a9a0..9ddd21d19 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -637,4 +637,70 @@ cleanup: 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_cf_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_cf_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 */ From bc3a288b2c7aa6f2317025938fa77cfd371d75aa Mon Sep 17 00:00:00 2001 From: gabor-mezei-arm Date: Mon, 27 Sep 2021 15:47:00 +0200 Subject: [PATCH 23/53] Create mbedtls_cf_size_if function Add a constant-time function with size_t parameter for choosing between two integer values, like the ?: ternary operator. Signed-off-by: Gabor Mezei --- library/constant_time.c | 6 ++++++ library/constant_time.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/library/constant_time.c b/library/constant_time.c index 9ddd21d19..aa291d75c 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -295,6 +295,12 @@ unsigned mbedtls_cf_uint_if( unsigned cond, unsigned if1, unsigned if0 ) return( ( mask & if1 ) | (~mask & if0 ) ); } +size_t mbedtls_cf_size_if( unsigned cond, size_t if1, size_t if0 ) +{ + size_t mask = mbedtls_cf_size_mask( cond ); + return( ( mask & if1 ) | (~mask & if0 ) ); +} + /** * Select between two sign values in constant-time. * diff --git a/library/constant_time.h b/library/constant_time.h index a8d142b85..fdbaf1fb1 100644 --- a/library/constant_time.h +++ b/library/constant_time.h @@ -59,6 +59,8 @@ unsigned mbedtls_cf_mpi_uint_lt( const mbedtls_mpi_uint x, unsigned mbedtls_cf_uint_if( unsigned cond, unsigned if1, unsigned if0 ); +size_t mbedtls_cf_size_if( unsigned cond, size_t if1, size_t if0 ); + int mbedtls_cf_cond_select_sign( int a, int b, unsigned char second ); #if defined(MBEDTLS_BIGNUM_C) From c2aee6fc0bc5070ea944e7367dfe2387dd178aad Mon Sep 17 00:00:00 2001 From: gabor-mezei-arm Date: Sun, 26 Sep 2021 15:20:48 +0200 Subject: [PATCH 24/53] Move the constant-time part of mbedtls_rsa_rsaes_pkcs1_v15_decrypt to a function Tne unpadding part of `mbedtls_rsa_rsaes_pkcs1_v15_decrypt` function is contant-time therefore it moved to a separate function to be prepared for moving to the contant-time module. Signed-off-by: Gabor Mezei --- library/rsa.c | 92 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 56 insertions(+), 36 deletions(-) diff --git a/library/rsa.c b/library/rsa.c index b8be89ca7..9bba9dc60 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -1479,20 +1479,16 @@ cleanup: #endif /* MBEDTLS_PKCS1_V21 */ #if defined(MBEDTLS_PKCS1_V15) -/* - * Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-DECRYPT function - */ -int mbedtls_rsa_rsaes_pkcs1_v15_decrypt( mbedtls_rsa_context *ctx, - int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng, - int mode, size_t *olen, - const unsigned char *input, - unsigned char *output, - size_t output_max_len ) +int mbedtls_cf_rsaes_pkcs1_v15_unpadding( int mode, + size_t ilen, + size_t *olen, + unsigned char *output, + size_t output_max_len, + unsigned char *buf ) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; - size_t ilen, i, plaintext_max_size; - unsigned char buf[MBEDTLS_MPI_MAX_SIZE]; + 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 @@ -1509,30 +1505,9 @@ int mbedtls_rsa_rsaes_pkcs1_v15_decrypt( mbedtls_rsa_context *ctx, size_t plaintext_size = 0; unsigned output_too_large; - RSA_VALIDATE_RET( ctx != NULL ); - RSA_VALIDATE_RET( mode == MBEDTLS_RSA_PRIVATE || - mode == MBEDTLS_RSA_PUBLIC ); - RSA_VALIDATE_RET( output_max_len == 0 || output != NULL ); - RSA_VALIDATE_RET( input != NULL ); - RSA_VALIDATE_RET( olen != NULL ); - - ilen = ctx->len; - plaintext_max_size = ( output_max_len > ilen - 11 ? - ilen - 11 : - output_max_len ); - - if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 ) - return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); - - if( ilen < 16 || ilen > sizeof( buf ) ) - return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); - - ret = ( mode == MBEDTLS_RSA_PUBLIC ) - ? mbedtls_rsa_public( ctx, input, buf ) - : mbedtls_rsa_private( ctx, f_rng, p_rng, input, buf ); - - if( ret != 0 ) - goto cleanup; + plaintext_max_size = mbedtls_cf_size_if( 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. */ @@ -1646,6 +1621,51 @@ int mbedtls_rsa_rsaes_pkcs1_v15_decrypt( mbedtls_rsa_context *ctx, * to the good case limits the risks of leaking the padding validity. */ *olen = plaintext_size; + return( ret ); +} + +/* + * Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-DECRYPT function + */ +int mbedtls_rsa_rsaes_pkcs1_v15_decrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len ) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t ilen; + unsigned char buf[MBEDTLS_MPI_MAX_SIZE]; + + RSA_VALIDATE_RET( ctx != NULL ); + RSA_VALIDATE_RET( mode == MBEDTLS_RSA_PRIVATE || + mode == MBEDTLS_RSA_PUBLIC ); + RSA_VALIDATE_RET( output_max_len == 0 || output != NULL ); + RSA_VALIDATE_RET( input != NULL ); + RSA_VALIDATE_RET( olen != NULL ); + + ilen = ctx->len; + + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + if( ilen < 16 || ilen > sizeof( buf ) ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + ret = ( mode == MBEDTLS_RSA_PUBLIC ) + ? mbedtls_rsa_public( ctx, input, buf ) + : mbedtls_rsa_private( ctx, f_rng, p_rng, input, buf ); + + if( ret != 0 ) + goto cleanup; + + ret = mbedtls_cf_rsaes_pkcs1_v15_unpadding( mode, ilen, olen, output, + output_max_len, + (unsigned char *) &buf ); + cleanup: mbedtls_platform_zeroize( buf, sizeof( buf ) ); From f52941ef7351ec184eb227f79653da8035a02377 Mon Sep 17 00:00:00 2001 From: gabor-mezei-arm Date: Mon, 27 Sep 2021 16:11:12 +0200 Subject: [PATCH 25/53] Move mbedtls_cf_rsaes_pkcs1_v15_unpadding function to the constant-time module Signed-off-by: Gabor Mezei --- library/constant_time.c | 150 ++++++++++++++++++++++++++++++++++++++++ library/constant_time.h | 11 +++ library/rsa.c | 145 -------------------------------------- 3 files changed, 161 insertions(+), 145 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index aa291d75c..712008a92 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -29,6 +29,7 @@ #include "mbedtls/ssl_internal.h" #endif +#include /* constant-time buffer comparison */ int mbedtls_ssl_safer_memcmp( const void *a, const void *b, size_t n ) @@ -710,3 +711,152 @@ int mbedtls_mpi_lt_mpi_ct( const mbedtls_mpi *X, const mbedtls_mpi *Y, } #endif /* MBEDTLS_BIGNUM_C */ + +#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) + +int mbedtls_cf_rsaes_pkcs1_v15_unpadding( int mode, + size_t ilen, + size_t *olen, + unsigned char *output, + size_t output_max_len, + unsigned char *buf ) +{ + 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 = mbedtls_cf_size_if( 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 |= buf[0]; + + if( mode == MBEDTLS_RSA_PRIVATE ) + { + /* Decode EME-PKCS1-v1_5 padding: 0x00 || 0x02 || PS || 0x00 + * where PS must be at least 8 nonzero bytes. */ + bad |= buf[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 |= ((buf[i] | (unsigned char)-buf[i]) >> 7) ^ 1; + pad_count += ((pad_done | (unsigned char)-pad_done) >> 7) ^ 1; + } + } + else + { + /* Decode EMSA-PKCS1-v1_5 padding: 0x00 || 0x01 || PS || 0x00 + * where PS must be at least 8 bytes with the value 0xFF. */ + bad |= buf[1] ^ MBEDTLS_RSA_SIGN; + + /* Read the whole buffer. Set pad_done to nonzero if we find + * the 0x00 byte and remember the padding length in pad_count. + * If there's a non-0xff byte in the padding, the padding is bad. */ + for( i = 2; i < ilen; i++ ) + { + pad_done |= mbedtls_cf_uint_if( buf[i], 0, 1 ); + pad_count += mbedtls_cf_uint_if( pad_done, 0, 1 ); + bad |= mbedtls_cf_uint_if( pad_done, 0, buf[i] ^ 0xFF ); + } + } + + /* If pad_done is still zero, there's no data, only unfinished padding. */ + bad |= mbedtls_cf_uint_if( pad_done, 0, 1 ); + + /* There must be at least 8 bytes of padding. */ + bad |= mbedtls_cf_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_cf_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_cf_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_cf_uint_if( + bad, - MBEDTLS_ERR_RSA_INVALID_PADDING, + mbedtls_cf_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_cf_uint_mask( bad | output_too_large ); + for( i = 11; i < ilen; i++ ) + buf[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_cf_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_cf_mem_move_to_left( buf + 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, buf + 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.h b/library/constant_time.h index fdbaf1fb1..609fe046b 100644 --- a/library/constant_time.h +++ b/library/constant_time.h @@ -148,3 +148,14 @@ int mbedtls_ssl_cf_hmac( unsigned char *output ); #endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */ + +#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) + +int mbedtls_cf_rsaes_pkcs1_v15_unpadding( int mode, + size_t ilen, + size_t *olen, + unsigned char *output, + size_t output_max_len, + unsigned char *buf ); + +#endif /* MBEDTLS_PKCS1_V15 && MBEDTLS_RSA_C && ! MBEDTLS_RSA_ALT */ diff --git a/library/rsa.c b/library/rsa.c index 9bba9dc60..3f076f0e5 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -1479,151 +1479,6 @@ cleanup: #endif /* MBEDTLS_PKCS1_V21 */ #if defined(MBEDTLS_PKCS1_V15) -int mbedtls_cf_rsaes_pkcs1_v15_unpadding( int mode, - size_t ilen, - size_t *olen, - unsigned char *output, - size_t output_max_len, - unsigned char *buf ) -{ - 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 = mbedtls_cf_size_if( 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 |= buf[0]; - - if( mode == MBEDTLS_RSA_PRIVATE ) - { - /* Decode EME-PKCS1-v1_5 padding: 0x00 || 0x02 || PS || 0x00 - * where PS must be at least 8 nonzero bytes. */ - bad |= buf[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 |= ((buf[i] | (unsigned char)-buf[i]) >> 7) ^ 1; - pad_count += ((pad_done | (unsigned char)-pad_done) >> 7) ^ 1; - } - } - else - { - /* Decode EMSA-PKCS1-v1_5 padding: 0x00 || 0x01 || PS || 0x00 - * where PS must be at least 8 bytes with the value 0xFF. */ - bad |= buf[1] ^ MBEDTLS_RSA_SIGN; - - /* Read the whole buffer. Set pad_done to nonzero if we find - * the 0x00 byte and remember the padding length in pad_count. - * If there's a non-0xff byte in the padding, the padding is bad. */ - for( i = 2; i < ilen; i++ ) - { - pad_done |= mbedtls_cf_uint_if( buf[i], 0, 1 ); - pad_count += mbedtls_cf_uint_if( pad_done, 0, 1 ); - bad |= mbedtls_cf_uint_if( pad_done, 0, buf[i] ^ 0xFF ); - } - } - - /* If pad_done is still zero, there's no data, only unfinished padding. */ - bad |= mbedtls_cf_uint_if( pad_done, 0, 1 ); - - /* There must be at least 8 bytes of padding. */ - bad |= mbedtls_cf_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_cf_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_cf_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_cf_uint_if( - bad, - MBEDTLS_ERR_RSA_INVALID_PADDING, - mbedtls_cf_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_cf_uint_mask( bad | output_too_large ); - for( i = 11; i < ilen; i++ ) - buf[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_cf_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_cf_mem_move_to_left( buf + 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, buf + 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 ); -} - /* * Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-DECRYPT function */ From 04087dffcd29f9020e6f9e56745d17720a67e04b Mon Sep 17 00:00:00 2001 From: gabor-mezei-arm Date: Mon, 27 Sep 2021 16:29:52 +0200 Subject: [PATCH 26/53] Typo: Unify indentation of function parameters Signed-off-by: Gabor Mezei --- library/constant_time.c | 91 ++++++++++++++++++++++++++--------------- library/constant_time.h | 57 ++++++++++++++++++-------- 2 files changed, 97 insertions(+), 51 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index 712008a92..822285a77 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -32,7 +32,9 @@ #include /* constant-time buffer comparison */ -int mbedtls_ssl_safer_memcmp( const void *a, const void *b, size_t n ) +int mbedtls_ssl_safer_memcmp( const void *a, + const void *b, + size_t n ) { size_t i; volatile const unsigned char *A = (volatile const unsigned char *) a; @@ -56,7 +58,8 @@ int mbedtls_ssl_safer_memcmp( const void *a, const void *b, size_t n ) * a non-zero value. * This is currently only used by GCM and ChaCha20+Poly1305. */ -int mbedtls_constant_time_memcmp( const void *v1, const void *v2, +int mbedtls_constant_time_memcmp( const void *v1, + const void *v2, size_t len ) { const unsigned char *p1 = (const unsigned char*) v1; @@ -71,7 +74,9 @@ int mbedtls_constant_time_memcmp( const void *v1, const void *v2, } /* constant-time buffer comparison */ -unsigned char mbedtls_nist_kw_safer_memcmp( const void *a, const void *b, size_t n ) +unsigned char mbedtls_nist_kw_safer_memcmp( const void *a, + const void *b, + size_t n ) { size_t i; volatile const unsigned char *A = (volatile const unsigned char *) a; @@ -91,7 +96,9 @@ unsigned char mbedtls_nist_kw_safer_memcmp( const void *a, const void *b, size_t } /* constant-time buffer comparison */ -int mbedtls_safer_memcmp( const void *a, const void *b, size_t n ) +int mbedtls_safer_memcmp( const void *a, + const void *b, + size_t n ) { size_t i; const unsigned char *A = (const unsigned char *) a; @@ -159,7 +166,8 @@ size_t mbedtls_cf_size_mask( size_t bit ) * This function is implemented without using comparison operators, as those * might be translated to branches by some compilers on some platforms. */ -size_t mbedtls_cf_size_mask_lt( size_t x, size_t y ) +size_t mbedtls_cf_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; @@ -184,7 +192,8 @@ size_t mbedtls_cf_size_mask_lt( size_t x, size_t y ) * This function is implemented without using comparison operators, as those * might be translated to branches by some compilers on some platforms. */ -size_t mbedtls_cf_size_mask_ge( size_t x, size_t y ) +size_t mbedtls_cf_size_mask_ge( size_t x, + size_t y ) { return( ~mbedtls_cf_size_mask_lt( x, y ) ); } @@ -200,7 +209,8 @@ size_t mbedtls_cf_size_mask_ge( size_t x, size_t y ) * This function is implemented without using comparison operators, as those * might be translated to branches by some compilers on some platforms. */ -size_t mbedtls_cf_size_bool_eq( size_t x, size_t y ) +size_t mbedtls_cf_size_bool_eq( size_t x, + size_t y ) { /* diff = 0 if x == y, non-zero otherwise */ const size_t diff = x ^ y; @@ -235,7 +245,8 @@ size_t mbedtls_cf_size_bool_eq( size_t x, size_t y ) * \return \c 0 if `size <= max`. * \return \c 1 if `size > max`. */ -unsigned mbedtls_cf_size_gt( size_t size, size_t max ) +unsigned mbedtls_cf_size_gt( size_t size, + size_t max ) { /* Return the sign bit (1 for negative) of (max - size). */ return( ( max - size ) >> ( sizeof( size_t ) * 8 - 1 ) ); @@ -251,7 +262,7 @@ unsigned mbedtls_cf_size_gt( size_t size, size_t max ) * \return 1 if \p x is less than \p y, 0 otherwise */ unsigned mbedtls_cf_mpi_uint_lt( const mbedtls_mpi_uint x, - const mbedtls_mpi_uint y ) + const mbedtls_mpi_uint y ) { mbedtls_mpi_uint ret; mbedtls_mpi_uint cond; @@ -290,13 +301,17 @@ unsigned mbedtls_cf_mpi_uint_lt( const mbedtls_mpi_uint x, * \param if0 Value to use if \p cond is zero. * \return \c if1 if \p cond is nonzero, otherwise \c if0. */ -unsigned mbedtls_cf_uint_if( unsigned cond, unsigned if1, unsigned if0 ) +unsigned mbedtls_cf_uint_if( unsigned cond, + unsigned if1, + unsigned if0 ) { unsigned mask = mbedtls_cf_uint_mask( cond ); return( ( mask & if1 ) | (~mask & if0 ) ); } -size_t mbedtls_cf_size_if( unsigned cond, size_t if1, size_t if0 ) +size_t mbedtls_cf_size_if( unsigned cond, + size_t if1, + size_t if0 ) { size_t mask = mbedtls_cf_size_mask( cond ); return( ( mask & if1 ) | (~mask & if0 ) ); @@ -314,7 +329,9 @@ size_t mbedtls_cf_size_if( unsigned cond, size_t if1, size_t if0 ) * * \return The selected sign value. */ -int mbedtls_cf_cond_select_sign( int a, int b, unsigned char second ) +int mbedtls_cf_cond_select_sign( int a, + int b, + unsigned char second ) { /* In order to avoid questions about what we can reasonnably assume about * the representations of signed integers, move everything to unsigned @@ -385,8 +402,8 @@ void mbedtls_cf_mpi_uint_cond_assign( size_t n, * \param offset Offset from which to copy \p total - \p offset bytes. */ void mbedtls_cf_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; @@ -418,9 +435,10 @@ void mbedtls_cf_mem_move_to_left( void *start, * might be translated to branches by some compilers on some platforms. */ void mbedtls_cf_memcpy_if_eq( unsigned char *dst, - const unsigned char *src, - size_t len, - size_t c1, size_t c2 ) + const unsigned char *src, + size_t len, + size_t c1, + size_t c2 ) { /* mask = c1 == c2 ? 0xff : 0x00 */ const size_t equal = mbedtls_cf_size_bool_eq( c1, c2 ); @@ -436,12 +454,12 @@ void mbedtls_cf_memcpy_if_eq( unsigned char *dst, * - functionally equivalent to memcpy(dst, src + offset_secret, len) * - but with execution flow independent from the value of offset_secret. */ -void mbedtls_cf_memcpy_offset( - unsigned char *dst, - const unsigned char *src_base, - size_t offset_secret, - size_t offset_min, size_t offset_max, - size_t len ) +void mbedtls_cf_memcpy_offset( unsigned char *dst, + const unsigned char *src_base, + size_t offset_secret, + size_t offset_min, + size_t offset_max, + size_t len ) { size_t offset; @@ -460,12 +478,14 @@ void mbedtls_cf_memcpy_offset( * Only works with MD-5, SHA-1, SHA-256 and SHA-384. * (Otherwise, computation of block_size needs to be adapted.) */ -int mbedtls_cf_hmac( - mbedtls_md_context_t *ctx, - const unsigned char *add_data, size_t add_data_len, - const unsigned char *data, size_t data_len_secret, - size_t min_data_len, size_t max_data_len, - unsigned char *output ) +int mbedtls_cf_hmac( mbedtls_md_context_t *ctx, + const unsigned char *add_data, + size_t add_data_len, + const unsigned char *data, + size_t data_len_secret, + size_t min_data_len, + size_t max_data_len, + unsigned char *output ) { /* * This function breaks the HMAC abstraction and uses the md_clone() @@ -554,7 +574,9 @@ cleanup: * about whether the assignment was made or not. * (Leaking information about the respective sizes of X and Y is ok however.) */ -int mbedtls_mpi_safe_cond_assign( mbedtls_mpi *X, const mbedtls_mpi *Y, unsigned char assign ) +int mbedtls_mpi_safe_cond_assign( mbedtls_mpi *X, + const mbedtls_mpi *Y, + unsigned char assign ) { int ret = 0; size_t i; @@ -597,7 +619,9 @@ cleanup: * Here it is not ok to simply swap the pointers, which whould 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 mbedtls_mpi_safe_cond_swap( mbedtls_mpi *X, + mbedtls_mpi *Y, + unsigned char swap ) { int ret, s; size_t i; @@ -647,8 +671,9 @@ cleanup: /* * Compare signed values in constant time */ -int mbedtls_mpi_lt_mpi_ct( const mbedtls_mpi *X, const mbedtls_mpi *Y, - unsigned *ret ) +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. */ diff --git a/library/constant_time.h b/library/constant_time.h index 609fe046b..e6deb45b1 100644 --- a/library/constant_time.h +++ b/library/constant_time.h @@ -29,26 +29,38 @@ #include -int mbedtls_ssl_safer_memcmp( const void *a, const void *b, size_t n ); +int mbedtls_ssl_safer_memcmp( const void *a, + const void *b, + size_t n ); -int mbedtls_constant_time_memcmp( const void *v1, const void *v2, size_t len ); +int mbedtls_constant_time_memcmp( const void *v1, + const void *v2, + size_t len ); -unsigned char mbedtls_nist_kw_safer_memcmp( const void *a, const void *b, size_t n ); +unsigned char mbedtls_nist_kw_safer_memcmp( const void *a, + const void *b, + size_t n ); -int mbedtls_safer_memcmp( const void *a, const void *b, size_t n ); +int mbedtls_safer_memcmp( const void *a, + const void *b, + size_t n ); unsigned mbedtls_cf_uint_mask( unsigned value ); size_t mbedtls_cf_size_mask( size_t bit ); -size_t mbedtls_cf_size_mask_lt( size_t x, size_t y ); +size_t mbedtls_cf_size_mask_lt( size_t x, + size_t y ); -size_t mbedtls_cf_size_mask_ge( size_t x, size_t y ); +size_t mbedtls_cf_size_mask_ge( size_t x, + size_t y ); -size_t mbedtls_cf_size_bool_eq( size_t x, size_t y ); +size_t mbedtls_cf_size_bool_eq( size_t x, + size_t y ); -unsigned mbedtls_cf_size_gt( size_t size, size_t max ); +unsigned mbedtls_cf_size_gt( size_t size, + size_t max ); #if defined(MBEDTLS_BIGNUM_C) @@ -57,11 +69,17 @@ unsigned mbedtls_cf_mpi_uint_lt( const mbedtls_mpi_uint x, #endif /* MBEDTLS_BIGNUM_C */ -unsigned mbedtls_cf_uint_if( unsigned cond, unsigned if1, unsigned if0 ); +unsigned mbedtls_cf_uint_if( unsigned cond, + unsigned if1, + unsigned if0 ); -size_t mbedtls_cf_size_if( unsigned cond, size_t if1, size_t if0 ); +size_t mbedtls_cf_size_if( unsigned cond, + size_t if1, + size_t if0 ); -int mbedtls_cf_cond_select_sign( int a, int b, unsigned char second ); +int mbedtls_cf_cond_select_sign( int a, + int b, + unsigned char second ); #if defined(MBEDTLS_BIGNUM_C) @@ -102,7 +120,8 @@ void mbedtls_cf_memcpy_if_eq( unsigned char *dst, void mbedtls_cf_memcpy_offset( unsigned char *dst, const unsigned char *src_base, size_t offset_secret, - size_t offset_min, size_t offset_max, + size_t offset_min, + size_t offset_max, size_t len ); #if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) @@ -140,12 +159,14 @@ void mbedtls_cf_memcpy_offset( unsigned char *dst, * \retval MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED * The hardware accelerator failed. */ -int mbedtls_ssl_cf_hmac( - mbedtls_md_context_t *ctx, - const unsigned char *add_data, size_t add_data_len, - const unsigned char *data, size_t data_len_secret, - size_t min_data_len, size_t max_data_len, - unsigned char *output ); +int mbedtls_cf_hmac( mbedtls_md_context_t *ctx, + const unsigned char *add_data, + size_t add_data_len, + const unsigned char *data, + size_t data_len_secret, + size_t min_data_len, + size_t max_data_len, + unsigned char *output ); #endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */ From 378e7eb5cc149ac6267426b109ba1c68e2dd7729 Mon Sep 17 00:00:00 2001 From: gabor-mezei-arm Date: Mon, 19 Jul 2021 15:19:19 +0200 Subject: [PATCH 27/53] Unify memcmp functions Signed-off-by: Gabor Mezei --- library/cipher.c | 4 +-- library/constant_time.c | 65 ++--------------------------------------- library/constant_time.h | 18 ++---------- library/nist_kw.c | 4 +-- library/rsa.c | 6 ++-- library/ssl_cli.c | 4 +-- library/ssl_cookie.c | 2 +- library/ssl_msg.c | 10 +++---- library/ssl_srv.c | 4 +-- library/ssl_tls.c | 2 +- 10 files changed, 24 insertions(+), 95 deletions(-) diff --git a/library/cipher.c b/library/cipher.c index 147241345..f38eb0403 100644 --- a/library/cipher.c +++ b/library/cipher.c @@ -1139,7 +1139,7 @@ int mbedtls_cipher_check_tag( mbedtls_cipher_context_t *ctx, } /* Check the tag in "constant-time" */ - if( mbedtls_constant_time_memcmp( tag, check_tag, tag_len ) != 0 ) + if( mbedtls_cf_memcmp( tag, check_tag, tag_len ) != 0 ) return( MBEDTLS_ERR_CIPHER_AUTH_FAILED ); return( 0 ); @@ -1161,7 +1161,7 @@ int mbedtls_cipher_check_tag( mbedtls_cipher_context_t *ctx, } /* Check the tag in "constant-time" */ - if( mbedtls_constant_time_memcmp( tag, check_tag, tag_len ) != 0 ) + if( mbedtls_cf_memcmp( tag, check_tag, tag_len ) != 0 ) return( MBEDTLS_ERR_CIPHER_AUTH_FAILED ); return( 0 ); diff --git a/library/constant_time.c b/library/constant_time.c index 822285a77..59e2c877a 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -31,10 +31,9 @@ #include -/* constant-time buffer comparison */ -int mbedtls_ssl_safer_memcmp( const void *a, - const void *b, - size_t n ) +int mbedtls_cf_memcmp( const void *a, + const void *b, + size_t n ) { size_t i; volatile const unsigned char *A = (volatile const unsigned char *) a; @@ -50,67 +49,9 @@ int mbedtls_ssl_safer_memcmp( const void *a, diff |= x ^ y; } - return( diff ); -} - -/* Compare the contents of two buffers in constant time. - * Returns 0 if the contents are bitwise identical, otherwise returns - * a non-zero value. - * This is currently only used by GCM and ChaCha20+Poly1305. - */ -int mbedtls_constant_time_memcmp( const void *v1, - const void *v2, - size_t len ) -{ - const unsigned char *p1 = (const unsigned char*) v1; - const unsigned char *p2 = (const unsigned char*) v2; - size_t i; - unsigned char diff; - - for( diff = 0, i = 0; i < len; i++ ) - diff |= p1[i] ^ p2[i]; - return( (int)diff ); } -/* constant-time buffer comparison */ -unsigned char mbedtls_nist_kw_safer_memcmp( const void *a, - const void *b, - size_t n ) -{ - size_t i; - volatile const unsigned char *A = (volatile const unsigned char *) a; - volatile const unsigned char *B = (volatile const unsigned char *) b; - volatile unsigned char diff = 0; - - for( i = 0; i < n; i++ ) - { - /* Read volatile data in order before computing diff. - * This avoids IAR compiler warning: - * 'the order of volatile accesses is undefined ..' */ - unsigned char x = A[i], y = B[i]; - diff |= x ^ y; - } - - return( diff ); -} - -/* constant-time buffer comparison */ -int mbedtls_safer_memcmp( const void *a, - const void *b, - size_t n ) -{ - size_t i; - const unsigned char *A = (const unsigned char *) a; - const unsigned char *B = (const unsigned char *) b; - unsigned char diff = 0; - - for( i = 0; i < n; i++ ) - diff |= A[i] ^ B[i]; - - return( diff ); -} - /** Turn zero-or-nonzero into zero-or-all-bits-one, without branches. * * \param value The value to analyze. diff --git a/library/constant_time.h b/library/constant_time.h index e6deb45b1..ae43081dc 100644 --- a/library/constant_time.h +++ b/library/constant_time.h @@ -29,22 +29,10 @@ #include -int mbedtls_ssl_safer_memcmp( const void *a, - const void *b, - size_t n ); - -int mbedtls_constant_time_memcmp( const void *v1, - const void *v2, - size_t len ); - -unsigned char mbedtls_nist_kw_safer_memcmp( const void *a, - const void *b, - size_t n ); - -int mbedtls_safer_memcmp( const void *a, - const void *b, - size_t n ); +int mbedtls_cf_memcmp( const void *a, + const void *b, + size_t n ); unsigned mbedtls_cf_uint_mask( unsigned value ); diff --git a/library/nist_kw.c b/library/nist_kw.c index 6262a7b0c..98c237be4 100644 --- a/library/nist_kw.c +++ b/library/nist_kw.c @@ -379,7 +379,7 @@ int mbedtls_nist_kw_unwrap( mbedtls_nist_kw_context *ctx, goto cleanup; /* Check ICV in "constant-time" */ - diff = mbedtls_nist_kw_safer_memcmp( NIST_KW_ICV1, A, KW_SEMIBLOCK_LENGTH ); + diff = mbedtls_cf_memcmp( NIST_KW_ICV1, A, KW_SEMIBLOCK_LENGTH ); if( diff != 0 ) { @@ -428,7 +428,7 @@ int mbedtls_nist_kw_unwrap( mbedtls_nist_kw_context *ctx, } /* Check ICV in "constant-time" */ - diff = mbedtls_nist_kw_safer_memcmp( NIST_KW_ICV2, A, KW_SEMIBLOCK_LENGTH / 2 ); + diff = mbedtls_cf_memcmp( NIST_KW_ICV2, A, KW_SEMIBLOCK_LENGTH / 2 ); if( diff != 0 ) { diff --git a/library/rsa.c b/library/rsa.c index 3f076f0e5..a387d0989 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -1933,7 +1933,7 @@ int mbedtls_rsa_rsassa_pkcs1_v15_sign( mbedtls_rsa_context *ctx, MBEDTLS_MPI_CHK( mbedtls_rsa_private( ctx, f_rng, p_rng, sig, sig_try ) ); MBEDTLS_MPI_CHK( mbedtls_rsa_public( ctx, sig_try, verif ) ); - if( mbedtls_safer_memcmp( verif, sig, ctx->len ) != 0 ) + if( mbedtls_cf_memcmp( verif, sig, ctx->len ) != 0 ) { ret = MBEDTLS_ERR_RSA_PRIVATE_FAILED; goto cleanup; @@ -2231,8 +2231,8 @@ int mbedtls_rsa_rsassa_pkcs1_v15_verify( mbedtls_rsa_context *ctx, * Compare */ - if( ( ret = mbedtls_safer_memcmp( encoded, encoded_expected, - sig_len ) ) != 0 ) + if( ( ret = mbedtls_cf_memcmp( encoded, encoded_expected, + sig_len ) ) != 0 ) { ret = MBEDTLS_ERR_RSA_VERIFY_FAILED; goto cleanup; diff --git a/library/ssl_cli.c b/library/ssl_cli.c index 912b5d007..0bc39fa74 100644 --- a/library/ssl_cli.c +++ b/library/ssl_cli.c @@ -1459,9 +1459,9 @@ static int ssl_parse_renegotiation_info( mbedtls_ssl_context *ssl, /* Check verify-data in constant-time. The length OTOH is no secret */ if( len != 1 + ssl->verify_data_len * 2 || buf[0] != ssl->verify_data_len * 2 || - mbedtls_ssl_safer_memcmp( buf + 1, + mbedtls_cf_memcmp( buf + 1, ssl->own_verify_data, ssl->verify_data_len ) != 0 || - mbedtls_ssl_safer_memcmp( buf + 1 + ssl->verify_data_len, + mbedtls_cf_memcmp( buf + 1 + ssl->verify_data_len, ssl->peer_verify_data, ssl->verify_data_len ) != 0 ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-matching renegotiation info" ) ); diff --git a/library/ssl_cookie.c b/library/ssl_cookie.c index 84fbab1a4..d19a13a35 100644 --- a/library/ssl_cookie.c +++ b/library/ssl_cookie.c @@ -225,7 +225,7 @@ int mbedtls_ssl_cookie_check( void *p_ctx, if( ret != 0 ) return( ret ); - if( mbedtls_ssl_safer_memcmp( cookie + 4, ref_hmac, sizeof( ref_hmac ) ) != 0 ) + if( mbedtls_cf_memcmp( cookie + 4, ref_hmac, sizeof( ref_hmac ) ) != 0 ) return( -1 ); #if defined(MBEDTLS_HAVE_TIME) diff --git a/library/ssl_msg.c b/library/ssl_msg.c index 0b940ec36..57a56f4cd 100644 --- a/library/ssl_msg.c +++ b/library/ssl_msg.c @@ -1281,7 +1281,7 @@ int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl, * * Afterwards, we know that data + data_len is followed by at * least maclen Bytes, which justifies the call to - * mbedtls_ssl_safer_memcmp() below. + * mbedtls_cf_memcmp() below. * * Further, we still know that data_len > minlen */ rec->data_len -= transform->maclen; @@ -1304,8 +1304,8 @@ int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl, transform->maclen ); /* Compare expected MAC with MAC at the end of the record. */ - if( mbedtls_ssl_safer_memcmp( data + rec->data_len, mac_expect, - transform->maclen ) != 0 ) + if( mbedtls_cf_memcmp( data + rec->data_len, mac_expect, + transform->maclen ) != 0 ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "message mac does not match" ) ); return( MBEDTLS_ERR_SSL_INVALID_MAC ); @@ -1582,8 +1582,8 @@ int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl, MBEDTLS_SSL_DEBUG_BUF( 4, "message mac", mac_peer, transform->maclen ); #endif - if( mbedtls_ssl_safer_memcmp( mac_peer, mac_expect, - transform->maclen ) != 0 ) + if( mbedtls_cf_memcmp( mac_peer, mac_expect, + transform->maclen ) != 0 ) { #if defined(MBEDTLS_SSL_DEBUG_ALL) MBEDTLS_SSL_DEBUG_MSG( 1, ( "message mac does not match" ) ); diff --git a/library/ssl_srv.c b/library/ssl_srv.c index b9e4bc0f6..9c1bea2bc 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -197,7 +197,7 @@ static int ssl_parse_renegotiation_info( mbedtls_ssl_context *ssl, /* Check verify-data in constant-time. The length OTOH is no secret */ if( len != 1 + ssl->verify_data_len || buf[0] != ssl->verify_data_len || - mbedtls_ssl_safer_memcmp( buf + 1, ssl->peer_verify_data, + mbedtls_cf_memcmp( buf + 1, ssl->peer_verify_data, ssl->verify_data_len ) != 0 ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-matching renegotiation info" ) ); @@ -4064,7 +4064,7 @@ static int ssl_parse_client_psk_identity( mbedtls_ssl_context *ssl, unsigned cha /* Identity is not a big secret since clients send it in the clear, * but treat it carefully anyway, just in case */ if( n != ssl->conf->psk_identity_len || - mbedtls_ssl_safer_memcmp( ssl->conf->psk_identity, *p, n ) != 0 ) + mbedtls_cf_memcmp( ssl->conf->psk_identity, *p, n ) != 0 ) { ret = MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY; } diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 607981a8d..3fafb7d84 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -3604,7 +3604,7 @@ int mbedtls_ssl_parse_finished( mbedtls_ssl_context *ssl ) return( MBEDTLS_ERR_SSL_BAD_HS_FINISHED ); } - if( mbedtls_ssl_safer_memcmp( ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ), + if( mbedtls_cf_memcmp( ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ), buf, hash_len ) != 0 ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad finished message" ) ); From 5e4882498e0e20f6c92af0b1d0b22bb3dcf163c8 Mon Sep 17 00:00:00 2001 From: gabor-mezei-arm Date: Tue, 10 Aug 2021 20:36:09 +0200 Subject: [PATCH 28/53] Unify function parameters Signed-off-by: Gabor Mezei --- library/constant_time.c | 83 +++++++++++++++++++++-------------------- library/constant_time.h | 18 ++++----- 2 files changed, 51 insertions(+), 50 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index 59e2c877a..3913f2c78 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -178,19 +178,19 @@ size_t mbedtls_cf_size_bool_eq( size_t x, /** Check whether a size is out of bounds, without branches. * - * This is equivalent to `size > max`, but is likely to be compiled to + * This is equivalent to `x > y`, but is likely to be compiled to * to code using bitwise operation rather than a branch. * - * \param size Size to check. - * \param max Maximum desired value for \p size. - * \return \c 0 if `size <= max`. - * \return \c 1 if `size > max`. + * \param x Size to check. + * \param y Maximum desired value for \p size. + * \return \c 0 if `x <= y`. + * \return \c 1 if `x > y`. */ -unsigned mbedtls_cf_size_gt( size_t size, - size_t max ) +unsigned mbedtls_cf_size_gt( size_t x, + size_t y ) { - /* Return the sign bit (1 for negative) of (max - size). */ - return( ( max - size ) >> ( sizeof( size_t ) * 8 - 1 ) ); + /* Return the sign bit (1 for negative) of (y - x). */ + return( ( y - x ) >> ( sizeof( size_t ) * 8 - 1 ) ); } #if defined(MBEDTLS_BIGNUM_C) @@ -234,57 +234,58 @@ unsigned mbedtls_cf_mpi_uint_lt( const mbedtls_mpi_uint x, /** Choose between two integer values, without branches. * - * This is equivalent to `cond ? if1 : if0`, but is likely to be compiled + * This is equivalent to `condition ? if1 : if0`, but is likely to be compiled * to code using bitwise operation rather than a branch. * - * \param cond Condition to test. - * \param if1 Value to use if \p cond is nonzero. - * \param if0 Value to use if \p cond is zero. - * \return \c if1 if \p cond is nonzero, otherwise \c if0. + * \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_cf_uint_if( unsigned cond, + +unsigned mbedtls_cf_uint_if( unsigned condition, unsigned if1, unsigned if0 ) { - unsigned mask = mbedtls_cf_uint_mask( cond ); + unsigned mask = mbedtls_cf_uint_mask( condition ); return( ( mask & if1 ) | (~mask & if0 ) ); } -size_t mbedtls_cf_size_if( unsigned cond, +size_t mbedtls_cf_size_if( unsigned condition, size_t if1, size_t if0 ) { - size_t mask = mbedtls_cf_size_mask( cond ); + size_t mask = mbedtls_cf_size_mask( condition ); return( ( mask & if1 ) | (~mask & if0 ) ); } /** * Select between two sign values in constant-time. * - * This is functionally equivalent to second ? a : b but uses only bit + * This is functionally equivalent to condition ? if1 : if0 but uses only bit * operations in order to avoid branches. * - * \param[in] a The first sign; must be either +1 or -1. - * \param[in] b The second sign; must be either +1 or -1. - * \param[in] second Must be either 1 (return b) or 0 (return a). + * \param[in] condition Must be either 1 (return \p if1) or 0 (return \pp if0). + * \param[in] if1 The first sign; must be either +1 or -1. + * \param[in] if0 The second sign; must be either +1 or -1. * - * \return The selected sign value. + * \return \c if1 if \p condition is nonzero, otherwise \c if0. */ -int mbedtls_cf_cond_select_sign( int a, - int b, - unsigned char second ) +int mbedtls_cf_cond_select_sign( unsigned char condition, + int if1, + int if0 ) { /* In order to avoid questions about what we can reasonnably assume about * the representations of signed integers, move everything to unsigned * by taking advantage of the fact that a and b are either +1 or -1. */ - unsigned ua = a + 1; - unsigned ub = b + 1; + unsigned uif1 = if1 + 1; + unsigned uif0 = if0 + 1; - /* second was 0 or 1, mask is 0 or 2 as are ua and ub */ - const unsigned mask = second << 1; + /* condition was 0 or 1, mask is 0 or 2 as are ua and ub */ + const unsigned mask = condition << 1; /* select ua or ub */ - unsigned ur = ( ua & ~mask ) | ( ub & mask ); + unsigned ur = ( uif0 & ~mask ) | ( uif1 & mask ); /* ur is now 0 or 2, convert back to -1 or +1 */ return( (int) ur - 1 ); @@ -296,12 +297,12 @@ int mbedtls_cf_cond_select_sign( int a, * Conditionally assign dest = src, without leaking information * about whether the assignment was made or not. * dest and src must be arrays of limbs of size n. - * assign must be 0 or 1. + * condition must be 0 or 1. */ void mbedtls_cf_mpi_uint_cond_assign( size_t n, mbedtls_mpi_uint *dest, const mbedtls_mpi_uint *src, - unsigned char assign ) + unsigned char condition ) { size_t i; @@ -312,8 +313,8 @@ void mbedtls_cf_mpi_uint_cond_assign( size_t n, #pragma warning( disable : 4146 ) #endif - /* all-bits 1 if assign is 1, all-bits 0 if assign is 0 */ - const mbedtls_mpi_uint mask = -assign; + /* 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 ) @@ -375,7 +376,7 @@ void mbedtls_cf_mem_move_to_left( void *start, * This function is implemented without using comparison operators, as those * might be translated to branches by some compilers on some platforms. */ -void mbedtls_cf_memcpy_if_eq( unsigned char *dst, +void mbedtls_cf_memcpy_if_eq( unsigned char *dest, const unsigned char *src, size_t len, size_t c1, @@ -385,9 +386,9 @@ void mbedtls_cf_memcpy_if_eq( unsigned char *dst, const size_t equal = mbedtls_cf_size_bool_eq( c1, c2 ); const unsigned char mask = (unsigned char) mbedtls_cf_size_mask( equal ); - /* dst[i] = c1 == c2 ? src[i] : dst[i] */ + /* dest[i] = c1 == c2 ? src[i] : dest[i] */ for( size_t i = 0; i < len; i++ ) - dst[i] = ( src[i] & mask ) | ( dst[i] & ~mask ); + dest[i] = ( src[i] & mask ) | ( dest[i] & ~mask ); } /* @@ -543,7 +544,7 @@ int mbedtls_mpi_safe_cond_assign( mbedtls_mpi *X, MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) ); - X->s = mbedtls_cf_cond_select_sign( X->s, Y->s, assign ); + X->s = mbedtls_cf_cond_select_sign( assign, Y->s, X->s ); mbedtls_cf_mpi_uint_cond_assign( Y->n, X->p, Y->p, assign ); @@ -594,8 +595,8 @@ int mbedtls_mpi_safe_cond_swap( mbedtls_mpi *X, MBEDTLS_MPI_CHK( mbedtls_mpi_grow( Y, X->n ) ); s = X->s; - X->s = mbedtls_cf_cond_select_sign( X->s, Y->s, swap ); - Y->s = mbedtls_cf_cond_select_sign( Y->s, s, swap ); + X->s = mbedtls_cf_cond_select_sign( swap, Y->s, X->s ); + Y->s = mbedtls_cf_cond_select_sign( swap, s, Y->s ); for( i = 0; i < X->n; i++ ) diff --git a/library/constant_time.h b/library/constant_time.h index ae43081dc..1c5df7c52 100644 --- a/library/constant_time.h +++ b/library/constant_time.h @@ -47,8 +47,8 @@ size_t mbedtls_cf_size_mask_ge( size_t x, size_t mbedtls_cf_size_bool_eq( size_t x, size_t y ); -unsigned mbedtls_cf_size_gt( size_t size, - size_t max ); +unsigned mbedtls_cf_size_gt( size_t x, + size_t y ); #if defined(MBEDTLS_BIGNUM_C) @@ -57,24 +57,24 @@ unsigned mbedtls_cf_mpi_uint_lt( const mbedtls_mpi_uint x, #endif /* MBEDTLS_BIGNUM_C */ -unsigned mbedtls_cf_uint_if( unsigned cond, +unsigned mbedtls_cf_uint_if( unsigned condition, unsigned if1, unsigned if0 ); -size_t mbedtls_cf_size_if( unsigned cond, +size_t mbedtls_cf_size_if( unsigned condition, size_t if1, size_t if0 ); -int mbedtls_cf_cond_select_sign( int a, - int b, - unsigned char second ); +int mbedtls_cf_cond_select_sign( unsigned char condition, + int if1, + int if0 ); #if defined(MBEDTLS_BIGNUM_C) void mbedtls_cf_mpi_uint_cond_assign( size_t n, mbedtls_mpi_uint *dest, const mbedtls_mpi_uint *src, - unsigned char assign ); + unsigned char condition ); #endif /* MBEDTLS_BIGNUM_C */ @@ -82,7 +82,7 @@ void mbedtls_cf_mem_move_to_left( void *start, size_t total, size_t offset ); -void mbedtls_cf_memcpy_if_eq( unsigned char *dst, +void mbedtls_cf_memcpy_if_eq( unsigned char *dest, const unsigned char *src, size_t len, size_t c1, size_t c2 ); From 2f2c0bead3654e4022c844921bbcf2d0c277a8b6 Mon Sep 17 00:00:00 2001 From: gabor-mezei-arm Date: Tue, 10 Aug 2021 20:56:21 +0200 Subject: [PATCH 29/53] Unify mask generation functions Generate all-bits 0 or all bits 1 mask from a value instead of from a bit. Signed-off-by: Gabor Mezei --- library/constant_time.c | 10 +++++----- library/constant_time.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index 3913f2c78..59a22e325 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -72,9 +72,9 @@ unsigned mbedtls_cf_uint_mask( unsigned value ) } /* - * Turn a bit into a mask: - * - if bit == 1, return the all-bits 1 mask, aka (size_t) -1 - * - if bit == 0, return the all-bits 0 mask, aka 0 + * Turn a value into a mask: + * - if value != 0, return the all-bits 1 mask, aka (size_t) -1 + * - if value == 0, return the all-bits 0 mask, aka 0 * * This function can be used to write constant-time code by replacing branches * with bit operations using masks. @@ -82,7 +82,7 @@ unsigned mbedtls_cf_uint_mask( unsigned value ) * This function is implemented without using comparison operators, as those * might be translated to branches by some compilers on some platforms. */ -size_t mbedtls_cf_size_mask( size_t bit ) +size_t mbedtls_cf_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. */ @@ -90,7 +90,7 @@ size_t mbedtls_cf_size_mask( size_t bit ) #pragma warning( push ) #pragma warning( disable : 4146 ) #endif - return -bit; + return( - ( ( value | - value ) >> ( sizeof( value ) * 8 - 1 ) ) ); #if defined(_MSC_VER) #pragma warning( pop ) #endif diff --git a/library/constant_time.h b/library/constant_time.h index 1c5df7c52..58eee19d3 100644 --- a/library/constant_time.h +++ b/library/constant_time.h @@ -36,7 +36,7 @@ int mbedtls_cf_memcmp( const void *a, unsigned mbedtls_cf_uint_mask( unsigned value ); -size_t mbedtls_cf_size_mask( size_t bit ); +size_t mbedtls_cf_size_mask( size_t value ); size_t mbedtls_cf_size_mask_lt( size_t x, size_t y ); From 60febd5d8a46e791fe4ec6d8cf3f2c0dedcb9f3e Mon Sep 17 00:00:00 2001 From: gabor-mezei-arm Date: Wed, 11 Aug 2021 15:07:02 +0200 Subject: [PATCH 30/53] Propagate usage of mask generation functions Signed-off-by: Gabor Mezei --- library/constant_time.c | 48 +++++++++++++++++------------------------ library/constant_time.h | 6 ++++++ library/ssl_srv.c | 11 +--------- 3 files changed, 27 insertions(+), 38 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index 59a22e325..cb0b309e9 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -96,6 +96,24 @@ size_t mbedtls_cf_size_mask( size_t value ) #endif } +#if defined(MBEDTLS_BIGNUM_C) + +mbedtls_mpi_uint mbedtls_cf_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 */ + /* * Constant-flow mask generation for "less than" comparison: * - if x < y, return all bits 1, that is (size_t) -1 @@ -526,21 +544,8 @@ int mbedtls_mpi_safe_cond_assign( mbedtls_mpi *X, MPI_VALIDATE_RET( X != NULL ); MPI_VALIDATE_RET( Y != NULL ); - /* 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 - - /* make sure assign is 0 or 1 in a time-constant manner */ - assign = (assign | (unsigned char)-assign) >> (sizeof( assign ) * 8 - 1); /* all-bits 1 if assign is 1, all-bits 0 if assign is 0 */ - limb_mask = -assign; - -#if defined(_MSC_VER) -#pragma warning( pop ) -#endif + limb_mask = mbedtls_cf_mpi_uint_mask( assign );; MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) ); @@ -575,21 +580,8 @@ int mbedtls_mpi_safe_cond_swap( mbedtls_mpi *X, if( X == Y ) return( 0 ); - /* 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 - - /* make sure swap is 0 or 1 in a time-constant manner */ - swap = (swap | (unsigned char)-swap) >> (sizeof( swap ) * 8 - 1); /* all-bits 1 if swap is 1, all-bits 0 if swap is 0 */ - limb_mask = -swap; - -#if defined(_MSC_VER) -#pragma warning( pop ) -#endif + limb_mask = mbedtls_cf_mpi_uint_mask( swap ); MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_grow( Y, X->n ) ); diff --git a/library/constant_time.h b/library/constant_time.h index 58eee19d3..32e0dfe3d 100644 --- a/library/constant_time.h +++ b/library/constant_time.h @@ -38,6 +38,12 @@ unsigned mbedtls_cf_uint_mask( unsigned value ); size_t mbedtls_cf_size_mask( size_t value ); +#if defined(MBEDTLS_BIGNUM_C) + +mbedtls_mpi_uint mbedtls_cf_mpi_uint_mask( mbedtls_mpi_uint value ); + +#endif /* MBEDTLS_BIGNUM_C */ + size_t mbedtls_cf_size_mask_lt( size_t x, size_t y ); diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 9c1bea2bc..c50ce9238 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -3972,16 +3972,7 @@ static int ssl_parse_encrypted_pms( mbedtls_ssl_context *ssl, diff |= peer_pms[1] ^ ver[1]; /* mask = diff ? 0xff : 0x00 using bit operations to avoid branches */ - /* MSVC has a warning about unary minus on unsigned, but this is - * well-defined and precisely what we want to do here */ -#if defined(_MSC_VER) -#pragma warning( push ) -#pragma warning( disable : 4146 ) -#endif - mask = - ( ( diff | - diff ) >> ( sizeof( unsigned int ) * 8 - 1 ) ); -#if defined(_MSC_VER) -#pragma warning( pop ) -#endif + mask = mbedtls_cf_uint_mask( diff ); /* * Protection against Bleichenbacher's attack: invalid PKCS#1 v1.5 padding From 1ffd0ccf02c40eb7062f587085d910f7c02a1400 Mon Sep 17 00:00:00 2001 From: gabor-mezei-arm Date: Wed, 11 Aug 2021 17:28:49 +0200 Subject: [PATCH 31/53] Unify equality checker functions return value The equality checker functions always return 0 or 1 value, thus the type of return value can be the same dispite of the size of the parameters. Signed-off-by: Gabor Mezei --- library/constant_time.c | 6 +++--- library/constant_time.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index cb0b309e9..680d7a1e5 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -168,8 +168,8 @@ size_t mbedtls_cf_size_mask_ge( size_t x, * This function is implemented without using comparison operators, as those * might be translated to branches by some compilers on some platforms. */ -size_t mbedtls_cf_size_bool_eq( size_t x, - size_t y ) +unsigned mbedtls_cf_size_bool_eq( size_t x, + size_t y ) { /* diff = 0 if x == y, non-zero otherwise */ const size_t diff = x ^ y; @@ -189,7 +189,7 @@ size_t mbedtls_cf_size_bool_eq( size_t x, #endif /* diff1 = (x != y) ? 1 : 0 */ - const size_t diff1 = diff_msb >> ( sizeof( diff_msb ) * 8 - 1 ); + const unsigned diff1 = diff_msb >> ( sizeof( diff_msb ) * 8 - 1 ); return( 1 ^ diff1 ); } diff --git a/library/constant_time.h b/library/constant_time.h index 32e0dfe3d..962af368b 100644 --- a/library/constant_time.h +++ b/library/constant_time.h @@ -50,8 +50,8 @@ size_t mbedtls_cf_size_mask_lt( size_t x, size_t mbedtls_cf_size_mask_ge( size_t x, size_t y ); -size_t mbedtls_cf_size_bool_eq( size_t x, - size_t y ); +unsigned mbedtls_cf_size_bool_eq( size_t x, + size_t y ); unsigned mbedtls_cf_size_gt( size_t x, size_t y ); From 7e6a1eaf8ff5ae84ba84ca2acfe5c644108ad817 Mon Sep 17 00:00:00 2001 From: gabor-mezei-arm Date: Wed, 11 Aug 2021 16:40:35 +0200 Subject: [PATCH 32/53] Add documentation for the functions Signed-off-by: Gabor Mezei --- library/constant_time.c | 132 ---------------------- library/constant_time.h | 243 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 243 insertions(+), 132 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index 680d7a1e5..f96bd1ae7 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -52,11 +52,6 @@ int mbedtls_cf_memcmp( const void *a, return( (int)diff ); } -/** Turn zero-or-nonzero into zero-or-all-bits-one, without branches. - * - * \param value The value to analyze. - * \return Zero if \p value is zero, otherwise all-bits-one. - */ unsigned mbedtls_cf_uint_mask( unsigned value ) { /* MSVC has a warning about unary minus on unsigned, but this is @@ -71,17 +66,6 @@ unsigned mbedtls_cf_uint_mask( unsigned value ) #endif } -/* - * Turn a value into a mask: - * - if value != 0, return the all-bits 1 mask, aka (size_t) -1 - * - if value == 0, return the all-bits 0 mask, aka 0 - * - * This function can be used to write constant-time code by replacing branches - * with bit operations using masks. - * - * This function is implemented without using comparison operators, as those - * might be translated to branches by some compilers on some platforms. - */ size_t mbedtls_cf_size_mask( size_t value ) { /* MSVC has a warning about unary minus on unsigned integer types, @@ -114,17 +98,6 @@ mbedtls_mpi_uint mbedtls_cf_mpi_uint_mask( mbedtls_mpi_uint value ) #endif /* MBEDTLS_BIGNUM_C */ -/* - * Constant-flow mask generation for "less than" comparison: - * - if x < 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. - * - * This function is implemented without using comparison operators, as those - * might be translated to branches by some compilers on some platforms. - */ size_t mbedtls_cf_size_mask_lt( size_t x, size_t y ) { @@ -140,34 +113,12 @@ size_t mbedtls_cf_size_mask_lt( size_t x, return( mask ); } -/* - * Constant-flow mask generation for "greater or equal" comparison: - * - if x >= 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. - * - * This function is implemented without using comparison operators, as those - * might be translated to branches by some compilers on some platforms. - */ size_t mbedtls_cf_size_mask_ge( size_t x, size_t y ) { return( ~mbedtls_cf_size_mask_lt( x, y ) ); } -/* - * Constant-flow boolean "equal" comparison: - * return x == y - * - * This function can be used to write constant-time code by replacing branches - * with bit operations - it can be used in conjunction with - * mbedtls_ssl_cf_mask_from_bit(). - * - * This function is implemented without using comparison operators, as those - * might be translated to branches by some compilers on some platforms. - */ unsigned mbedtls_cf_size_bool_eq( size_t x, size_t y ) { @@ -194,16 +145,6 @@ unsigned mbedtls_cf_size_bool_eq( size_t x, return( 1 ^ diff1 ); } -/** Check whether a size is out of bounds, without branches. - * - * This is equivalent to `x > y`, but is likely to be compiled to - * to code using bitwise operation rather than a branch. - * - * \param x Size to check. - * \param y Maximum desired value for \p size. - * \return \c 0 if `x <= y`. - * \return \c 1 if `x > y`. - */ unsigned mbedtls_cf_size_gt( size_t x, size_t y ) { @@ -213,13 +154,6 @@ unsigned mbedtls_cf_size_gt( size_t x, #if defined(MBEDTLS_BIGNUM_C) -/** Decide if an integer is less than the other, without branches. - * - * \param x First integer. - * \param y Second integer. - * - * \return 1 if \p x is less than \p y, 0 otherwise - */ unsigned mbedtls_cf_mpi_uint_lt( const mbedtls_mpi_uint x, const mbedtls_mpi_uint y ) { @@ -250,17 +184,6 @@ unsigned mbedtls_cf_mpi_uint_lt( const mbedtls_mpi_uint x, #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_cf_uint_if( unsigned condition, unsigned if1, unsigned if0 ) @@ -277,18 +200,6 @@ size_t mbedtls_cf_size_if( unsigned condition, return( ( mask & if1 ) | (~mask & if0 ) ); } -/** - * Select between two sign values in constant-time. - * - * This is functionally equivalent to condition ? if1 : if0 but uses only bit - * operations in order to avoid branches. - * - * \param[in] condition Must be either 1 (return \p if1) or 0 (return \pp if0). - * \param[in] if1 The first sign; must be either +1 or -1. - * \param[in] if0 The second sign; must be either +1 or -1. - * - * \return \c if1 if \p condition is nonzero, otherwise \c if0. - */ int mbedtls_cf_cond_select_sign( unsigned char condition, int if1, int if0 ) @@ -311,12 +222,6 @@ int mbedtls_cf_cond_select_sign( unsigned char condition, #if defined(MBEDTLS_BIGNUM_C) -/* - * Conditionally assign dest = src, without leaking information - * about whether the assignment was made or not. - * dest and src must be arrays of limbs of size n. - * condition must be 0 or 1. - */ void mbedtls_cf_mpi_uint_cond_assign( size_t n, mbedtls_mpi_uint *dest, const mbedtls_mpi_uint *src, @@ -344,23 +249,6 @@ void mbedtls_cf_mpi_uint_cond_assign( size_t n, #endif /* MBEDTLS_BIGNUM_C */ -/** Shift some data towards the left inside a buffer without leaking - * the length of the data through side channels. - * - * `mbedtls_cf_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_cf_mem_move_to_left( void *start, size_t total, size_t offset ) @@ -385,15 +273,6 @@ void mbedtls_cf_mem_move_to_left( void *start, } } -/* - * Constant-flow conditional memcpy: - * - if c1 == c2, equivalent to memcpy(dst, src, len), - * - otherwise, a no-op, - * but with execution flow independent of the values of c1 and c2. - * - * This function is implemented without using comparison operators, as those - * might be translated to branches by some compilers on some platforms. - */ void mbedtls_cf_memcpy_if_eq( unsigned char *dest, const unsigned char *src, size_t len, @@ -409,11 +288,6 @@ void mbedtls_cf_memcpy_if_eq( unsigned char *dest, dest[i] = ( src[i] & mask ) | ( dest[i] & ~mask ); } -/* - * Constant-flow memcpy from variable position in buffer. - * - functionally equivalent to memcpy(dst, src + offset_secret, len) - * - but with execution flow independent from the value of offset_secret. - */ void mbedtls_cf_memcpy_offset( unsigned char *dst, const unsigned char *src_base, size_t offset_secret, @@ -432,12 +306,6 @@ void mbedtls_cf_memcpy_offset( unsigned char *dst, #if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) -/* - * Compute HMAC of variable-length data with constant flow. - * - * Only works with MD-5, SHA-1, SHA-256 and SHA-384. - * (Otherwise, computation of block_size needs to be adapted.) - */ int mbedtls_cf_hmac( mbedtls_md_context_t *ctx, const unsigned char *add_data, size_t add_data_len, diff --git a/library/constant_time.h b/library/constant_time.h index 962af368b..83329b175 100644 --- a/library/constant_time.h +++ b/library/constant_time.h @@ -30,53 +30,241 @@ #include +/** Constant-time buffer comparison without branches. + * + * This is equivalent to the standard memncmp function, but is likely to be + * compiled to code using bitwise operation rather than a branch. + * + * This function can be used to write constant-time code by replacing branches + * with bit operations using masks. + * + * This function is implemented without using comparison operators, as those + * might be translated to branches by some compilers on some platforms. + * + * \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. + * + * \return Zero if the content of the two buffer is the same, + * otherwise non-zero. + */ int mbedtls_cf_memcmp( const void *a, const void *b, size_t n ); +/** 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. + * + * This function is implemented without using comparison operators, as those + * might be translated to branches by some compilers on some platforms. + * + * \param value The value to analyze. + * + * \return Zero if \p value is zero, otherwise all-bits-one. + */ unsigned mbedtls_cf_uint_mask( unsigned value ); +/** 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. + * + * This function is implemented without using comparison operators, as those + * might be translated to branches by some compilers on some platforms. + * + * \param value The value to analyze. + * + * \return Zero if \p value is zero, otherwise all-bits-one. + */ size_t mbedtls_cf_size_mask( size_t value ); #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 (size_t) -1 + * + * This function can be used to write constant-time code by replacing branches + * with bit operations using masks. + * + * This function is implemented without using comparison operators, as those + * might be translated to branches by some compilers on some platforms. + * + * \param value The value to analyze. + * + * \return Zero if \p value is zero, otherwise all-bits-one. + */ mbedtls_mpi_uint mbedtls_cf_mpi_uint_mask( mbedtls_mpi_uint value ); #endif /* MBEDTLS_BIGNUM_C */ +/** 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. + * + * This function is implemented without using comparison operators, as those + * might be translated to branches by some compilers on some platforms. + * + * \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. + */ size_t mbedtls_cf_size_mask_lt( size_t x, size_t y ); +/** 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. + * + * This function is implemented without using comparison operators, as those + * might be translated to branches by some compilers on some platforms. + * + * \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_cf_size_mask_ge( size_t x, size_t y ); +/** 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. + * + * This function is implemented without using comparison operators, as those + * might be translated to branches by some compilers on some platforms. + * + * \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_cf_size_bool_eq( size_t x, size_t y ); +/** 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. + * + * This function is implemented without using comparison operators, as those + * might be translated to branches by some compilers on some platforms. + * + * \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_cf_size_gt( 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. + * + * This function is implemented without using comparison operators, as those + * might be translated to branches by some compilers on some platforms. + * + * \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_cf_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. + * + * This function is implemented without using comparison operators, as those + * might be translated to branches by some compilers on some platforms. + * + * \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_cf_uint_if( unsigned condition, unsigned if1, unsigned if0 ); +/** 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. + * + * This function is implemented without using comparison operators, as those + * might be translated to branches by some compilers on some platforms. + * + * \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. + */ size_t mbedtls_cf_size_if( unsigned condition, size_t if1, size_t if0 ); +/** Select between two sign values witout branches. + * + * This is functionally equivalent to `condition ? if1 : if0` but uses only bit + * operations in order to avoid branches. + * + * This function is implemented without using comparison operators, as those + * might be translated to branches by some compilers on some platforms. + * + * \param condition Condition to test. + * \param if1 The first sign; must be either +1 or -1. + * \param if0 The second sign; must be either +1 or -1. + * + * \return \c if1 if \p condition is nonzero, otherwise \c if0. */ int mbedtls_cf_cond_select_sign( unsigned char condition, int if1, int 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. + * + * This function is implemented without using comparison operators, as those + * might be translated to branches by some compilers on some platforms. + * + * \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_cf_mpi_uint_cond_assign( size_t n, mbedtls_mpi_uint *dest, const mbedtls_mpi_uint *src, @@ -84,10 +272,41 @@ void mbedtls_cf_mpi_uint_cond_assign( size_t n, #endif /* MBEDTLS_BIGNUM_C */ + +/** Shift some data towards the left inside a buffer. + * + * `mbedtls_cf_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_cf_mem_move_to_left( void *start, size_t total, size_t offset ); +/** Conditional memcpy without branches. + * + * This is equivalent to `if ( c1 == c2 ) memcpy(dst, src, len)`, but is likely + * to be compiled to code using bitwise operation rather than a branch. + * + * This function is implemented without using comparison operators, as those + * might be translated to branches by some compilers on some platforms. + * + * \param dest The pointer to conditionally copy to. + * \param src The pointer to copy from. + * \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_cf_memcpy_if_eq( unsigned char *dest, const unsigned char *src, size_t len, @@ -98,6 +317,7 @@ void mbedtls_cf_memcpy_if_eq( unsigned char *dest, * 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). * * \param dst The destination buffer. This must point to a writable * buffer of at least \p len bytes. @@ -166,6 +386,29 @@ int mbedtls_cf_hmac( mbedtls_md_context_t *ctx, #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 (RSAES-PKCS1-v1_5-DECRYPT). + * + * \note The output buffer length \c output_max_len should be + * as large as the size \p ctx->len of \p ctx->N, for example, + * 128 Bytes if RSA-1024 is used, to be able to hold an + * arbitrary decrypted message. If it is not large enough to + * hold the decryption of the particular ciphertext provided, + * the function returns #MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE. + * + * \param mode The mode of operation. This must be either + * #MBEDTLS_RSA_PRIVATE or #MBEDTLS_RSA_PUBLIC (deprecated). + * \param ilen The length of the ciphertext. + * \param olen The address at which to store the length of + * the plaintext. This must not be \c NULL. + * \param output The buffer used to hold the plaintext. This must + * be a writable buffer of length \p output_max_len Bytes. + * \param output_max_len The length in Bytes of the output buffer \p output. + * \param buf The input buffer for the unpadding operation. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ int mbedtls_cf_rsaes_pkcs1_v15_unpadding( int mode, size_t ilen, size_t *olen, From 10117d673e2540e608ccbffd8f040416a93d4b88 Mon Sep 17 00:00:00 2001 From: gabor-mezei-arm Date: Wed, 25 Aug 2021 20:39:07 +0200 Subject: [PATCH 33/53] Add changelog entry Signed-off-by: Gabor Mezei --- ChangeLog.d/constant_time_module.txt | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 ChangeLog.d/constant_time_module.txt diff --git a/ChangeLog.d/constant_time_module.txt b/ChangeLog.d/constant_time_module.txt new file mode 100644 index 000000000..5e76deaa8 --- /dev/null +++ b/ChangeLog.d/constant_time_module.txt @@ -0,0 +1,6 @@ +Changes + * The mbedcrypto library includes new a source code module constant_time.c, + containing various functions meant to resist timing side channel attacks. + This module does not have a separate configuration option, and functions + from this module will be included in the build as required. Currently + the interface of this module is private and may change at any time. From d5a392aa2ca8e5db0e50c731ea1747046a0652d1 Mon Sep 17 00:00:00 2001 From: gabor-mezei-arm Date: Wed, 29 Sep 2021 10:50:31 +0200 Subject: [PATCH 34/53] Fix missing includes Signed-off-by: Gabor Mezei --- library/constant_time.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/constant_time.c b/library/constant_time.c index f96bd1ae7..98f69db71 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -20,6 +20,7 @@ #include "common.h" #include "constant_time.h" #include "mbedtls/error.h" +#include "mbedtls/platform_util.h" #if defined(MBEDTLS_BIGNUM_C) #include "mbedtls/bignum.h" @@ -29,6 +30,10 @@ #include "mbedtls/ssl_internal.h" #endif +#if defined(MBEDTLS_RSA_C) +#include "mbedtls/rsa.h" +#endif + #include int mbedtls_cf_memcmp( const void *a, From 2c5ed2244b37776d72ab35f5bf1d7d02872ce6c6 Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Mon, 18 Oct 2021 16:05:50 +0200 Subject: [PATCH 35/53] Make mbedtls_cf_size_mask_lt function static The mbedtls_cf_size_mask_lt is solely used as an auxiliary function for mbedtls_cf_size_mask_ge. Signed-off-by: Gabor Mezei --- library/constant_time.c | 16 ++++++++++++++-- library/constant_time.h | 18 ------------------ 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index 98f69db71..84d961cfa 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -103,8 +103,20 @@ mbedtls_mpi_uint mbedtls_cf_mpi_uint_mask( mbedtls_mpi_uint value ) #endif /* MBEDTLS_BIGNUM_C */ -size_t mbedtls_cf_size_mask_lt( size_t x, - size_t y ) +/** 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_cf_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; diff --git a/library/constant_time.h b/library/constant_time.h index 83329b175..3877272d2 100644 --- a/library/constant_time.h +++ b/library/constant_time.h @@ -104,24 +104,6 @@ mbedtls_mpi_uint mbedtls_cf_mpi_uint_mask( mbedtls_mpi_uint value ); #endif /* MBEDTLS_BIGNUM_C */ -/** 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. - * - * This function is implemented without using comparison operators, as those - * might be translated to branches by some compilers on some platforms. - * - * \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. - */ -size_t mbedtls_cf_size_mask_lt( size_t x, - size_t y ); - /** 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 From 3c38b6e9e1d1f025713a995525bc386449d74a63 Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Mon, 18 Oct 2021 16:09:41 +0200 Subject: [PATCH 36/53] Move implementation specific comment This comment is about how the functions are implemented, not about their public interface, so it doesn't belong in the header file. It applies to everything in constant_time.c so moved there. Signed-off-by: Gabor Mezei --- library/constant_time.c | 5 +++++ library/constant_time.h | 38 -------------------------------------- 2 files changed, 5 insertions(+), 38 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index 84d961cfa..ea21692b6 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -17,6 +17,11 @@ * limitations under the License. */ + /* + * The following functiona are implemented without using comparison operators, as those + * might be translated to branches by some compilers on some platforms. + */ + #include "common.h" #include "constant_time.h" #include "mbedtls/error.h" diff --git a/library/constant_time.h b/library/constant_time.h index 3877272d2..7767268f0 100644 --- a/library/constant_time.h +++ b/library/constant_time.h @@ -38,9 +38,6 @@ * This function can be used to write constant-time code by replacing branches * with bit operations using masks. * - * This function is implemented without using comparison operators, as those - * might be translated to branches by some compilers on some platforms. - * * \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. @@ -59,9 +56,6 @@ int mbedtls_cf_memcmp( const void *a, * This function can be used to write constant-time code by replacing branches * with bit operations using masks. * - * This function is implemented without using comparison operators, as those - * might be translated to branches by some compilers on some platforms. - * * \param value The value to analyze. * * \return Zero if \p value is zero, otherwise all-bits-one. @@ -75,9 +69,6 @@ unsigned mbedtls_cf_uint_mask( unsigned value ); * This function can be used to write constant-time code by replacing branches * with bit operations using masks. * - * This function is implemented without using comparison operators, as those - * might be translated to branches by some compilers on some platforms. - * * \param value The value to analyze. * * \return Zero if \p value is zero, otherwise all-bits-one. @@ -93,9 +84,6 @@ size_t mbedtls_cf_size_mask( size_t value ); * This function can be used to write constant-time code by replacing branches * with bit operations using masks. * - * This function is implemented without using comparison operators, as those - * might be translated to branches by some compilers on some platforms. - * * \param value The value to analyze. * * \return Zero if \p value is zero, otherwise all-bits-one. @@ -111,9 +99,6 @@ mbedtls_mpi_uint mbedtls_cf_mpi_uint_mask( mbedtls_mpi_uint value ); * This function can be used to write constant-time code by replacing branches * with bit operations using masks. * - * This function is implemented without using comparison operators, as those - * might be translated to branches by some compilers on some platforms. - * * \param x The first value to analyze. * \param y The second value to analyze. * @@ -129,9 +114,6 @@ size_t mbedtls_cf_size_mask_ge( size_t x, * This is equivalent to \p x == \p y, but is likely to be compiled * to code using bitwise operation rather than a branch. * - * This function is implemented without using comparison operators, as those - * might be translated to branches by some compilers on some platforms. - * * \param x The first value to analyze. * \param y The second value to analyze. * @@ -146,9 +128,6 @@ unsigned mbedtls_cf_size_bool_eq( size_t x, * This is equivalent to \p x > \p y, but is likely to be compiled * to code using bitwise operation rather than a branch. * - * This function is implemented without using comparison operators, as those - * might be translated to branches by some compilers on some platforms. - * * \param x The first value to analyze. * \param y The second value to analyze. * @@ -164,9 +143,6 @@ unsigned mbedtls_cf_size_gt( size_t x, * This is equivalent to \p x < \p y, but is likely to be compiled * to code using bitwise operation rather than a branch. * - * This function is implemented without using comparison operators, as those - * might be translated to branches by some compilers on some platforms. - * * \param x The first value to analyze. * \param y The second value to analyze. * @@ -182,9 +158,6 @@ unsigned mbedtls_cf_mpi_uint_lt( const mbedtls_mpi_uint x, * This is equivalent to `condition ? if1 : if0`, but is likely to be compiled * to code using bitwise operation rather than a branch. * - * This function is implemented without using comparison operators, as those - * might be translated to branches by some compilers on some platforms. - * * \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. @@ -200,9 +173,6 @@ unsigned mbedtls_cf_uint_if( unsigned condition, * This is equivalent to `condition ? if1 : if0`, but is likely to be compiled * to code using bitwise operation rather than a branch. * - * This function is implemented without using comparison operators, as those - * might be translated to branches by some compilers on some platforms. - * * \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. @@ -218,8 +188,6 @@ size_t mbedtls_cf_size_if( unsigned condition, * This is functionally equivalent to `condition ? if1 : if0` but uses only bit * operations in order to avoid branches. * - * This function is implemented without using comparison operators, as those - * might be translated to branches by some compilers on some platforms. * * \param condition Condition to test. * \param if1 The first sign; must be either +1 or -1. @@ -237,9 +205,6 @@ int mbedtls_cf_cond_select_sign( unsigned char condition, * This is equivalent to `if ( condition ) dest = src`, but is likely * to be compiled to code using bitwise operation rather than a branch. * - * This function is implemented without using comparison operators, as those - * might be translated to branches by some compilers on some platforms. - * * \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. @@ -280,9 +245,6 @@ void mbedtls_cf_mem_move_to_left( void *start, * This is equivalent to `if ( c1 == c2 ) memcpy(dst, src, len)`, but is likely * to be compiled to code using bitwise operation rather than a branch. * - * This function is implemented without using comparison operators, as those - * might be translated to branches by some compilers on some platforms. - * * \param dest The pointer to conditionally copy to. * \param src The pointer to copy from. * \param len The number of bytes to copy. From 150bdee12673c01502f30690fd65cc12e2327ae7 Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Mon, 18 Oct 2021 16:12:45 +0200 Subject: [PATCH 37/53] Use condition for not sensitive data Signed-off-by: Gabor Mezei --- library/constant_time.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index ea21692b6..85e0e76ad 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -589,9 +589,8 @@ int mbedtls_cf_rsaes_pkcs1_v15_unpadding( int mode, size_t plaintext_size = 0; unsigned output_too_large; - plaintext_max_size = mbedtls_cf_size_if( output_max_len > ilen - 11, - ilen - 11, - output_max_len ); + 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. */ From 91deea7765eb7a0765e75676136a1e623ac8870c Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Mon, 18 Oct 2021 16:17:57 +0200 Subject: [PATCH 38/53] Rename and reorder function parameters Signed-off-by: Gabor Mezei --- library/constant_time.c | 36 ++++++++++++++++++------------------ library/constant_time.h | 28 ++++++++++++++-------------- library/rsa.c | 5 ++--- 3 files changed, 34 insertions(+), 35 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index 85e0e76ad..1ea79de4c 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -310,19 +310,19 @@ void mbedtls_cf_memcpy_if_eq( unsigned char *dest, dest[i] = ( src[i] & mask ) | ( dest[i] & ~mask ); } -void mbedtls_cf_memcpy_offset( unsigned char *dst, - const unsigned char *src_base, - size_t offset_secret, +void mbedtls_cf_memcpy_offset( unsigned char *dest, + const unsigned char *src, + size_t offset, size_t offset_min, size_t offset_max, size_t len ) { - size_t offset; + size_t offsetval; - for( offset = offset_min; offset <= offset_max; offset++ ) + for( offsetval = offset_min; offsetval <= offset_max; offsetval++ ) { - mbedtls_cf_memcpy_if_eq( dst, src_base + offset, len, - offset, offset_secret ); + mbedtls_cf_memcpy_if_eq( dest, src + offsetval, len, + offsetval, offset ); } } @@ -564,11 +564,11 @@ int mbedtls_mpi_lt_mpi_ct( const mbedtls_mpi *X, #if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) int mbedtls_cf_rsaes_pkcs1_v15_unpadding( int mode, + unsigned char *input, size_t ilen, - size_t *olen, unsigned char *output, size_t output_max_len, - unsigned char *buf ) + size_t *olen ) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; size_t i, plaintext_max_size; @@ -594,19 +594,19 @@ int mbedtls_cf_rsaes_pkcs1_v15_unpadding( int mode, /* Check and get padding length in constant time and constant * memory trace. The first byte must be 0. */ - bad |= buf[0]; + bad |= input[0]; if( mode == MBEDTLS_RSA_PRIVATE ) { /* Decode EME-PKCS1-v1_5 padding: 0x00 || 0x02 || PS || 0x00 * where PS must be at least 8 nonzero bytes. */ - bad |= buf[1] ^ MBEDTLS_RSA_CRYPT; + 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 |= ((buf[i] | (unsigned char)-buf[i]) >> 7) ^ 1; + pad_done |= ((input[i] | (unsigned char)-input[i]) >> 7) ^ 1; pad_count += ((pad_done | (unsigned char)-pad_done) >> 7) ^ 1; } } @@ -614,16 +614,16 @@ int mbedtls_cf_rsaes_pkcs1_v15_unpadding( int mode, { /* Decode EMSA-PKCS1-v1_5 padding: 0x00 || 0x01 || PS || 0x00 * where PS must be at least 8 bytes with the value 0xFF. */ - bad |= buf[1] ^ MBEDTLS_RSA_SIGN; + bad |= input[1] ^ MBEDTLS_RSA_SIGN; /* Read the whole buffer. Set pad_done to nonzero if we find * the 0x00 byte and remember the padding length in pad_count. * If there's a non-0xff byte in the padding, the padding is bad. */ for( i = 2; i < ilen; i++ ) { - pad_done |= mbedtls_cf_uint_if( buf[i], 0, 1 ); + pad_done |= mbedtls_cf_uint_if( input[i], 0, 1 ); pad_count += mbedtls_cf_uint_if( pad_done, 0, 1 ); - bad |= mbedtls_cf_uint_if( pad_done, 0, buf[i] ^ 0xFF ); + bad |= mbedtls_cf_uint_if( pad_done, 0, input[i] ^ 0xFF ); } } @@ -668,7 +668,7 @@ int mbedtls_cf_rsaes_pkcs1_v15_unpadding( int mode, * through memory or cache access patterns. */ bad = mbedtls_cf_uint_mask( bad | output_too_large ); for( i = 11; i < ilen; i++ ) - buf[i] &= ~bad; + 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 @@ -684,7 +684,7 @@ int mbedtls_cf_rsaes_pkcs1_v15_unpadding( int mode, * does not depend on the plaintext size. After this move, the * starting location of the plaintext is no longer sensitive * information. */ - mbedtls_cf_mem_move_to_left( buf + ilen - plaintext_max_size, + mbedtls_cf_mem_move_to_left( input + ilen - plaintext_max_size, plaintext_max_size, plaintext_max_size - plaintext_size ); @@ -696,7 +696,7 @@ int mbedtls_cf_rsaes_pkcs1_v15_unpadding( int mode, * length, validity of padding, success of the decryption, and other * secrets. */ if( output_max_len != 0 ) - memcpy( output, buf + ilen - plaintext_max_size, plaintext_max_size ); + 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 diff --git a/library/constant_time.h b/library/constant_time.h index 7767268f0..bed22c5ed 100644 --- a/library/constant_time.h +++ b/library/constant_time.h @@ -263,21 +263,21 @@ void mbedtls_cf_memcpy_if_eq( unsigned char *dest, * offset_secret, but only on \p offset_min, \p offset_max and \p len. * Functionally equivalent to memcpy(dst, src + offset_secret, len). * - * \param dst The destination buffer. This must point to a writable + * \param dest The destination buffer. This must point to a writable * buffer of at least \p len bytes. - * \param src_base The base of the source buffer. This must point to a + * \param src The base of the source buffer. This must point to a * readable buffer of at least \p offset_max + \p len - * bytes. - * \param offset_secret The offset in the source buffer from which to copy. + * 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_secret. - * \param offset_max The maximal value of \p offset_secret. + * \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_cf_memcpy_offset( unsigned char *dst, - const unsigned char *src_base, - size_t offset_secret, +void mbedtls_cf_memcpy_offset( unsigned char *dest, + const unsigned char *src, + size_t offset, size_t offset_min, size_t offset_max, size_t len ); @@ -342,22 +342,22 @@ int mbedtls_cf_hmac( mbedtls_md_context_t *ctx, * * \param mode The mode of operation. This must be either * #MBEDTLS_RSA_PRIVATE or #MBEDTLS_RSA_PUBLIC (deprecated). + * \param input The input buffer for the unpadding operation. * \param ilen The length of the ciphertext. - * \param olen The address at which to store the length of - * the plaintext. This must not be \c NULL. * \param output The buffer used to hold the plaintext. This must * be a writable buffer of length \p output_max_len Bytes. * \param output_max_len The length in Bytes of the output buffer \p output. - * \param buf The input buffer for the unpadding operation. + * \param olen The address at which to store the length of + * the plaintext. This must not be \c NULL. * * \return \c 0 on success. * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. */ int mbedtls_cf_rsaes_pkcs1_v15_unpadding( int mode, + unsigned char *input, size_t ilen, - size_t *olen, unsigned char *output, size_t output_max_len, - unsigned char *buf ); + size_t *olen ); #endif /* MBEDTLS_PKCS1_V15 && MBEDTLS_RSA_C && ! MBEDTLS_RSA_ALT */ diff --git a/library/rsa.c b/library/rsa.c index a387d0989..ea888713b 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -1517,9 +1517,8 @@ int mbedtls_rsa_rsaes_pkcs1_v15_decrypt( mbedtls_rsa_context *ctx, if( ret != 0 ) goto cleanup; - ret = mbedtls_cf_rsaes_pkcs1_v15_unpadding( mode, ilen, olen, output, - output_max_len, - (unsigned char *) &buf ); + ret = mbedtls_cf_rsaes_pkcs1_v15_unpadding( mode, buf, ilen, + output, output_max_len, olen ); cleanup: mbedtls_platform_zeroize( buf, sizeof( buf ) ); From 4b4e4d8880d19792a07422334db420a85525aaec Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Mon, 18 Oct 2021 16:28:27 +0200 Subject: [PATCH 39/53] Update documentation and comments Signed-off-by: Gabor Mezei --- library/constant_time.c | 6 ++-- library/constant_time.h | 64 ++++++++++++++++++++++++----------------- 2 files changed, 40 insertions(+), 30 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index 1ea79de4c..dc06b3e48 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -228,14 +228,14 @@ int mbedtls_cf_cond_select_sign( unsigned char condition, { /* In order to avoid questions about what we can reasonnably assume about * the representations of signed integers, move everything to unsigned - * by taking advantage of the fact that a and b are either +1 or -1. */ + * by taking advantage of the fact that if1 and if0 are either +1 or -1. */ unsigned uif1 = if1 + 1; unsigned uif0 = if0 + 1; - /* condition was 0 or 1, mask is 0 or 2 as are ua and ub */ + /* condition was 0 or 1, mask is 0 or 2 as are uif1 and uif0 */ const unsigned mask = condition << 1; - /* select ua or ub */ + /* select uif1 or uif0 */ unsigned ur = ( uif0 & ~mask ) | ( uif1 & mask ); /* ur is now 0 or 2, convert back to -1 or +1 */ diff --git a/library/constant_time.h b/library/constant_time.h index bed22c5ed..f35b9a546 100644 --- a/library/constant_time.h +++ b/library/constant_time.h @@ -51,7 +51,7 @@ int mbedtls_cf_memcmp( const void *a, /** 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 + * - 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. @@ -79,7 +79,7 @@ size_t mbedtls_cf_size_mask( size_t value ); /** 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 + * - 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. @@ -188,6 +188,8 @@ size_t mbedtls_cf_size_if( unsigned condition, * This is functionally equivalent to `condition ? if1 : if0` but uses only bit * operations in order to avoid branches. * + * \note if1 and if0 must be either 1 or -1, otherwise the result + * is undefined. * * \param condition Condition to test. * \param if1 The first sign; must be either +1 or -1. @@ -246,7 +248,7 @@ void mbedtls_cf_mem_move_to_left( void *start, * 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. + * \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. @@ -261,7 +263,7 @@ void mbedtls_cf_memcpy_if_eq( unsigned char *dest, * 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). + * Functionally equivalent to `memcpy(dst, src + offset_secret, len)`. * * \param dest The destination buffer. This must point to a writable * buffer of at least \p len bytes. @@ -298,23 +300,26 @@ void mbedtls_cf_memcpy_offset( unsigned char *dest, * It is reset using mbedtls_md_hmac_reset() after * the computation is complete to prepare for the * next computation. - * \param add_data The additional data prepended to \p data. This - * must point to a readable buffer of \p add_data_len - * bytes. + * \param add_data 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 data appended to \p add_data. This must point - * to a readable buffer of \p max_data_len 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 \p data in bytes. - * \param max_data_len The maximal length of \p data in bytes. + * \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 + * \retval #MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED * The hardware accelerator failed. */ int mbedtls_cf_hmac( mbedtls_md_context_t *ctx, @@ -331,27 +336,32 @@ int mbedtls_cf_hmac( mbedtls_md_context_t *ctx, #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 (RSAES-PKCS1-v1_5-DECRYPT). + * operation (EME-PKCS1-v1_5 decoding). * - * \note The output buffer length \c output_max_len should be - * as large as the size \p ctx->len of \p ctx->N, for example, - * 128 Bytes if RSA-1024 is used, to be able to hold an - * arbitrary decrypted message. If it is not large enough to - * hold the decryption of the particular ciphertext provided, - * the function returns #MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE. + * \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 mode The mode of operation. This must be either * #MBEDTLS_RSA_PRIVATE or #MBEDTLS_RSA_PUBLIC (deprecated). - * \param input The input buffer for the unpadding operation. - * \param ilen The length of the ciphertext. - * \param output The buffer used to hold the plaintext. This must - * be a writable buffer of length \p output_max_len Bytes. - * \param output_max_len The length in Bytes of the output buffer \p output. + * \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 plaintext. This must not be \c NULL. + * 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 An \c MBEDTLS_ERR_RSA_XXX error code on failure. + * \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_cf_rsaes_pkcs1_v15_unpadding( int mode, unsigned char *input, From fd8a42d914c44dfa006f041eaed6ed51c24f60fb Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Mon, 18 Oct 2021 16:35:23 +0200 Subject: [PATCH 40/53] Make functions static These functions are only used as an auxiliary function for constant-time functions. Signed-off-by: Gabor Mezei --- library/constant_time.c | 74 +++++++++++++++++++++++++++++++++++------ library/constant_time.h | 65 ------------------------------------ 2 files changed, 63 insertions(+), 76 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index dc06b3e48..9bdd8c9a5 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -167,8 +167,19 @@ unsigned mbedtls_cf_size_bool_eq( size_t x, return( 1 ^ diff1 ); } -unsigned mbedtls_cf_size_gt( size_t x, - size_t y ) +/** 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_cf_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 ) ); @@ -214,17 +225,42 @@ unsigned mbedtls_cf_uint_if( unsigned condition, return( ( mask & if1 ) | (~mask & if0 ) ); } -size_t mbedtls_cf_size_if( unsigned condition, - size_t if1, - size_t if0 ) +/** 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. + */ +static size_t mbedtls_cf_size_if( unsigned condition, + size_t if1, + size_t if0 ) { size_t mask = mbedtls_cf_size_mask( condition ); return( ( mask & if1 ) | (~mask & if0 ) ); } -int mbedtls_cf_cond_select_sign( unsigned char condition, - int if1, - int if0 ) +/** Select between two sign values witout branches. + * + * This is functionally equivalent to `condition ? if1 : if0` but uses only bit + * operations in order to avoid branches. + * + * \note if1 and if0 must be either 1 or -1, otherwise the result + * is undefined. + * + * \param condition Condition to test. + * \param if1 The first sign; must be either +1 or -1. + * \param if0 The second sign; must be either +1 or -1. + * + * \return \c if1 if \p condition is nonzero, otherwise \c if0. + * */ +static int mbedtls_cf_cond_select_sign( unsigned char condition, + int if1, + int if0 ) { /* In order to avoid questions about what we can reasonnably assume about * the representations of signed integers, move everything to unsigned @@ -271,9 +307,25 @@ void mbedtls_cf_mpi_uint_cond_assign( size_t n, #endif /* MBEDTLS_BIGNUM_C */ -void mbedtls_cf_mem_move_to_left( void *start, - size_t total, - size_t offset ) +/** Shift some data towards the left inside a buffer. + * + * `mbedtls_cf_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_cf_mem_move_to_left( void *start, + size_t total, + size_t offset ) { volatile unsigned char *buf = start; size_t i, n; diff --git a/library/constant_time.h b/library/constant_time.h index f35b9a546..d2301aaa5 100644 --- a/library/constant_time.h +++ b/library/constant_time.h @@ -122,19 +122,6 @@ size_t mbedtls_cf_size_mask_ge( size_t x, unsigned mbedtls_cf_size_bool_eq( size_t x, size_t y ); -/** 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_cf_size_gt( size_t x, - size_t y ); #if defined(MBEDTLS_BIGNUM_C) @@ -168,38 +155,6 @@ unsigned mbedtls_cf_uint_if( unsigned condition, unsigned if1, unsigned if0 ); -/** 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. - */ -size_t mbedtls_cf_size_if( unsigned condition, - size_t if1, - size_t if0 ); - -/** Select between two sign values witout branches. - * - * This is functionally equivalent to `condition ? if1 : if0` but uses only bit - * operations in order to avoid branches. - * - * \note if1 and if0 must be either 1 or -1, otherwise the result - * is undefined. - * - * \param condition Condition to test. - * \param if1 The first sign; must be either +1 or -1. - * \param if0 The second sign; must be either +1 or -1. - * - * \return \c if1 if \p condition is nonzero, otherwise \c if0. */ -int mbedtls_cf_cond_select_sign( unsigned char condition, - int if1, - int if0 ); - #if defined(MBEDTLS_BIGNUM_C) /** Conditionally assign a value without branches. @@ -222,26 +177,6 @@ void mbedtls_cf_mpi_uint_cond_assign( size_t n, #endif /* MBEDTLS_BIGNUM_C */ -/** Shift some data towards the left inside a buffer. - * - * `mbedtls_cf_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_cf_mem_move_to_left( void *start, - size_t total, - size_t offset ); - /** Conditional memcpy without branches. * * This is equivalent to `if ( c1 == c2 ) memcpy(dst, src, len)`, but is likely From 4e2de62fefd37a60e3ce6a208f644269e64c0b3e Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Mon, 18 Oct 2021 17:02:29 +0200 Subject: [PATCH 41/53] Remove unused function Signed-off-by: Gabor Mezei --- library/constant_time.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index 9bdd8c9a5..0c82c0943 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -225,24 +225,6 @@ unsigned mbedtls_cf_uint_if( unsigned condition, return( ( mask & if1 ) | (~mask & if0 ) ); } -/** 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. - */ -static size_t mbedtls_cf_size_if( unsigned condition, - size_t if1, - size_t if0 ) -{ - size_t mask = mbedtls_cf_size_mask( condition ); - return( ( mask & if1 ) | (~mask & if0 ) ); -} /** Select between two sign values witout branches. * From 2b35880d418a14dcc49d7f17ffe24d0d332c492d Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Mon, 18 Oct 2021 17:05:06 +0200 Subject: [PATCH 42/53] Bind functions' availability for config options Signed-off-by: Gabor Mezei --- library/constant_time.c | 19 +++++++++++++++---- library/constant_time.h | 8 +++++--- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/library/constant_time.c b/library/constant_time.c index 0c82c0943..952528d98 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -108,6 +108,8 @@ mbedtls_mpi_uint mbedtls_cf_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 "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 @@ -141,6 +143,8 @@ size_t mbedtls_cf_size_mask_ge( size_t x, return( ~mbedtls_cf_size_mask_lt( x, y ) ); } +#endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */ + unsigned mbedtls_cf_size_bool_eq( size_t x, size_t y ) { @@ -167,6 +171,8 @@ unsigned mbedtls_cf_size_bool_eq( size_t x, return( 1 ^ diff1 ); } +#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) + /** Constant-flow "greater than" comparison: * return x > y * @@ -185,6 +191,8 @@ static unsigned mbedtls_cf_size_gt( size_t 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_cf_mpi_uint_lt( const mbedtls_mpi_uint x, @@ -225,6 +233,7 @@ unsigned mbedtls_cf_uint_if( unsigned condition, return( ( mask & if1 ) | (~mask & if0 ) ); } +#if defined(MBEDTLS_BIGNUM_C) /** Select between two sign values witout branches. * @@ -260,8 +269,6 @@ static int mbedtls_cf_cond_select_sign( unsigned char condition, return( (int) ur - 1 ); } -#if defined(MBEDTLS_BIGNUM_C) - void mbedtls_cf_mpi_uint_cond_assign( size_t n, mbedtls_mpi_uint *dest, const mbedtls_mpi_uint *src, @@ -289,6 +296,8 @@ void mbedtls_cf_mpi_uint_cond_assign( size_t n, #endif /* MBEDTLS_BIGNUM_C */ +#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) + /** Shift some data towards the left inside a buffer. * * `mbedtls_cf_mem_move_to_left(start, total, offset)` is functionally @@ -329,6 +338,10 @@ static void mbedtls_cf_mem_move_to_left( void *start, } } +#endif /* MBEDTLS_PKCS1_V15 && MBEDTLS_RSA_C && ! MBEDTLS_RSA_ALT */ + +#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) + void mbedtls_cf_memcpy_if_eq( unsigned char *dest, const unsigned char *src, size_t len, @@ -360,8 +373,6 @@ void mbedtls_cf_memcpy_offset( unsigned char *dest, } } -#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) - int mbedtls_cf_hmac( mbedtls_md_context_t *ctx, const unsigned char *add_data, size_t add_data_len, diff --git a/library/constant_time.h b/library/constant_time.h index d2301aaa5..5796f120d 100644 --- a/library/constant_time.h +++ b/library/constant_time.h @@ -92,6 +92,8 @@ mbedtls_mpi_uint mbedtls_cf_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 @@ -108,6 +110,8 @@ mbedtls_mpi_uint mbedtls_cf_mpi_uint_mask( mbedtls_mpi_uint value ); size_t mbedtls_cf_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 * @@ -122,7 +126,6 @@ size_t mbedtls_cf_size_mask_ge( size_t x, unsigned mbedtls_cf_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. @@ -176,6 +179,7 @@ void mbedtls_cf_mpi_uint_cond_assign( size_t n, #endif /* MBEDTLS_BIGNUM_C */ +#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) /** Conditional memcpy without branches. * @@ -219,8 +223,6 @@ void mbedtls_cf_memcpy_offset( unsigned char *dest, size_t offset_max, size_t len ); -#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) - /** Compute the HMAC of variable-length data with constant flow. * * This function computes the HMAC of the concatenation of \p add_data and \p From 6e0e9905441c410a2053b9c8f58f31b8de90bf44 Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Tue, 19 Oct 2021 11:27:17 +0200 Subject: [PATCH 43/53] Add macro guard for header file Signed-off-by: Gabor Mezei --- library/constant_time.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/constant_time.h b/library/constant_time.h index 5796f120d..26e0dd097 100644 --- a/library/constant_time.h +++ b/library/constant_time.h @@ -17,6 +17,9 @@ * limitations under the License. */ +#ifndef MBEDTLS_CONSTANT_TIME_INTERNAL_H +#define MBEDTLS_CONSTANT_TIME_INTERNAL_H + #include "common.h" #if defined(MBEDTLS_BIGNUM_C) @@ -308,3 +311,5 @@ int mbedtls_cf_rsaes_pkcs1_v15_unpadding( int mode, size_t *olen ); #endif /* MBEDTLS_PKCS1_V15 && MBEDTLS_RSA_C && ! MBEDTLS_RSA_ALT */ + +#endif /* MBEDTLS_CONSTANT_TIME_INTERNAL_H */ From e24dea8225465635fed7dc3d7c7f0a112351c8bd Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Tue, 19 Oct 2021 12:22:25 +0200 Subject: [PATCH 44/53] Move mbedtls_cf_memcmp to a new public header Signed-off-by: Gabor Mezei --- include/mbedtls/constant_time.h | 47 +++++++++++++++++++++++++++++++++ library/cipher.c | 2 +- library/constant_time.c | 1 + library/constant_time.h | 19 ------------- library/nist_kw.c | 2 +- library/rsa.c | 1 + library/ssl_cli.c | 2 +- library/ssl_cookie.c | 2 +- library/ssl_msg.c | 1 + library/ssl_srv.c | 1 + library/ssl_tls.c | 2 +- 11 files changed, 56 insertions(+), 24 deletions(-) create mode 100644 include/mbedtls/constant_time.h diff --git a/include/mbedtls/constant_time.h b/include/mbedtls/constant_time.h new file mode 100644 index 000000000..69df954d4 --- /dev/null +++ b/include/mbedtls/constant_time.h @@ -0,0 +1,47 @@ +/** + * Constant-time functions + * + * 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_H +#define MBEDTLS_CONSTANT_TIME_H + +#include "common.h" + +#include + + +/** Constant-time buffer comparison without branches. + * + * This is equivalent to the standard memncmp function, but is likely to be + * compiled to code using bitwise operation rather than a branch. + * + * 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. + * + * \return Zero if the content of the two buffer is the same, + * otherwise non-zero. + */ +int mbedtls_cf_memcmp( const void *a, + const void *b, + size_t n ); + +#endif /* MBEDTLS_CONSTANT_TIME_H */ diff --git a/library/cipher.c b/library/cipher.c index f38eb0403..a0354d68e 100644 --- a/library/cipher.c +++ b/library/cipher.c @@ -29,7 +29,7 @@ #include "mbedtls/cipher_internal.h" #include "mbedtls/platform_util.h" #include "mbedtls/error.h" -#include "constant_time.h" +#include "mbedtls/constant_time.h" #include #include diff --git a/library/constant_time.c b/library/constant_time.c index 952528d98..977971278 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -24,6 +24,7 @@ #include "common.h" #include "constant_time.h" +#include "mbedtls/constant_time.h" #include "mbedtls/error.h" #include "mbedtls/platform_util.h" diff --git a/library/constant_time.h b/library/constant_time.h index 26e0dd097..d78dd70f5 100644 --- a/library/constant_time.h +++ b/library/constant_time.h @@ -33,25 +33,6 @@ #include -/** Constant-time buffer comparison without branches. - * - * This is equivalent to the standard memncmp function, but is likely to be - * compiled to code using bitwise operation rather than a branch. - * - * 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. - * - * \return Zero if the content of the two buffer is the same, - * otherwise non-zero. - */ -int mbedtls_cf_memcmp( const void *a, - const void *b, - size_t n ); - /** 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 diff --git a/library/nist_kw.c b/library/nist_kw.c index 98c237be4..e5d7fcd87 100644 --- a/library/nist_kw.c +++ b/library/nist_kw.c @@ -34,7 +34,7 @@ #include "mbedtls/nist_kw.h" #include "mbedtls/platform_util.h" #include "mbedtls/error.h" -#include "constant_time.h" +#include "mbedtls/constant_time.h" #include #include diff --git a/library/rsa.c b/library/rsa.c index ea888713b..351f4af52 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -45,6 +45,7 @@ #include "mbedtls/platform_util.h" #include "mbedtls/error.h" #include "constant_time.h" +#include "mbedtls/constant_time.h" #include diff --git a/library/ssl_cli.c b/library/ssl_cli.c index 0bc39fa74..def6c7b45 100644 --- a/library/ssl_cli.c +++ b/library/ssl_cli.c @@ -33,7 +33,7 @@ #include "mbedtls/ssl_internal.h" #include "mbedtls/debug.h" #include "mbedtls/error.h" -#include "constant_time.h" +#include "mbedtls/constant_time.h" #if defined(MBEDTLS_USE_PSA_CRYPTO) #include "mbedtls/psa_util.h" diff --git a/library/ssl_cookie.c b/library/ssl_cookie.c index d19a13a35..cdc236414 100644 --- a/library/ssl_cookie.c +++ b/library/ssl_cookie.c @@ -36,7 +36,7 @@ #include "mbedtls/ssl_internal.h" #include "mbedtls/error.h" #include "mbedtls/platform_util.h" -#include "constant_time.h" +#include "mbedtls/constant_time.h" #include diff --git a/library/ssl_msg.c b/library/ssl_msg.c index 57a56f4cd..83c4a4bd5 100644 --- a/library/ssl_msg.c +++ b/library/ssl_msg.c @@ -45,6 +45,7 @@ #include "mbedtls/platform_util.h" #include "mbedtls/version.h" #include "constant_time.h" +#include "mbedtls/constant_time.h" #include diff --git a/library/ssl_srv.c b/library/ssl_srv.c index c50ce9238..d9d49a22d 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -35,6 +35,7 @@ #include "mbedtls/error.h" #include "mbedtls/platform_util.h" #include "constant_time.h" +#include "mbedtls/constant_time.h" #include diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 3fafb7d84..f6c593de8 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -43,7 +43,7 @@ #include "mbedtls/error.h" #include "mbedtls/platform_util.h" #include "mbedtls/version.h" -#include "constant_time.h" +#include "mbedtls/constant_time.h" #include From 61bf64fbd0e18f2def90450a2c75a436d909fa30 Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Wed, 20 Oct 2021 11:17:43 +0200 Subject: [PATCH 45/53] Bind functions' availability for config options Signed-off-by: Gabor Mezei --- library/constant_time.c | 4 ++++ library/constant_time.h | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/library/constant_time.c b/library/constant_time.c index 977971278..5bbdf1c3e 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -77,6 +77,8 @@ unsigned mbedtls_cf_uint_mask( unsigned value ) #endif } +#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) + size_t mbedtls_cf_size_mask( size_t value ) { /* MSVC has a warning about unary minus on unsigned integer types, @@ -91,6 +93,8 @@ size_t mbedtls_cf_size_mask( size_t value ) #endif } +#endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */ + #if defined(MBEDTLS_BIGNUM_C) mbedtls_mpi_uint mbedtls_cf_mpi_uint_mask( mbedtls_mpi_uint value ) diff --git a/library/constant_time.h b/library/constant_time.h index d78dd70f5..011f601ce 100644 --- a/library/constant_time.h +++ b/library/constant_time.h @@ -46,6 +46,8 @@ */ unsigned mbedtls_cf_uint_mask( unsigned value ); +#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) + /** 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 @@ -59,6 +61,8 @@ unsigned mbedtls_cf_uint_mask( unsigned value ); */ size_t mbedtls_cf_size_mask( size_t value ); +#endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */ + #if defined(MBEDTLS_BIGNUM_C) /** Turn a value into a mask: From da20651b73048a45736fd12c1e9cc1a0877d7ffc Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Wed, 20 Oct 2021 11:18:37 +0200 Subject: [PATCH 46/53] Fix documentation Signed-off-by: Gabor Mezei --- library/constant_time.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/constant_time.h b/library/constant_time.h index 011f601ce..6fd23c97a 100644 --- a/library/constant_time.h +++ b/library/constant_time.h @@ -236,9 +236,9 @@ void mbedtls_cf_memcpy_offset( unsigned char *dest, * 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. + * message, read from \p data. * \param max_data_len The maximal length of the second part of the - * message, read from /p data. + * 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. From f127a0e2b19611f55c6ab695e662427f3214daac Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Wed, 20 Oct 2021 11:19:16 +0200 Subject: [PATCH 47/53] Remove unneeded include Signed-off-by: Gabor Mezei --- include/mbedtls/constant_time.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/mbedtls/constant_time.h b/include/mbedtls/constant_time.h index 69df954d4..bd7758fff 100644 --- a/include/mbedtls/constant_time.h +++ b/include/mbedtls/constant_time.h @@ -20,8 +20,6 @@ #ifndef MBEDTLS_CONSTANT_TIME_H #define MBEDTLS_CONSTANT_TIME_H -#include "common.h" - #include From 18a44949d0773d1c363f4d21008504d3de617b76 Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Wed, 20 Oct 2021 11:59:27 +0200 Subject: [PATCH 48/53] Rename constant-time functions to have mbedtls_ct prefix Rename functions to better suite with the module name. Signed-off-by: Gabor Mezei --- include/mbedtls/constant_time.h | 2 +- library/bignum.c | 4 +- library/cipher.c | 4 +- library/constant_time.c | 96 ++++++++++++++-------------- library/constant_time.h | 24 +++---- library/nist_kw.c | 4 +- library/rsa.c | 6 +- library/ssl_cli.c | 4 +- library/ssl_cookie.c | 2 +- library/ssl_msg.c | 22 +++---- library/ssl_srv.c | 6 +- library/ssl_tls.c | 2 +- tests/suites/test_suite_ssl.function | 6 +- 13 files changed, 91 insertions(+), 91 deletions(-) diff --git a/include/mbedtls/constant_time.h b/include/mbedtls/constant_time.h index bd7758fff..b7f9a861d 100644 --- a/include/mbedtls/constant_time.h +++ b/include/mbedtls/constant_time.h @@ -38,7 +38,7 @@ * \return Zero if the content of the two buffer is the same, * otherwise non-zero. */ -int mbedtls_cf_memcmp( const void *a, +int mbedtls_ct_memcmp( const void *a, const void *b, size_t n ); diff --git a/library/bignum.c b/library/bignum.c index a15c6f11b..846f5a331 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -1951,7 +1951,7 @@ static void mpi_montmul( mbedtls_mpi *A, const mbedtls_mpi *B, const mbedtls_mpi * so d[n] == 1 and we want to set A to the result of the subtraction * which is d - (2^biL)^n, i.e. the n least significant limbs of d. * This exactly corresponds to a conditional assignment. */ - mbedtls_cf_mpi_uint_cond_assign( n, A->p, d, (unsigned char) d[n] ); + mbedtls_ct_mpi_uint_cond_assign( n, A->p, d, (unsigned char) d[n] ); } /* @@ -1993,7 +1993,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_cf_size_bool_eq( i, idx ) ) ); + (unsigned char) mbedtls_ct_size_bool_eq( i, idx ) ) ); } cleanup: diff --git a/library/cipher.c b/library/cipher.c index a0354d68e..d51ccd77f 100644 --- a/library/cipher.c +++ b/library/cipher.c @@ -1139,7 +1139,7 @@ int mbedtls_cipher_check_tag( mbedtls_cipher_context_t *ctx, } /* Check the tag in "constant-time" */ - if( mbedtls_cf_memcmp( tag, check_tag, tag_len ) != 0 ) + if( mbedtls_ct_memcmp( tag, check_tag, tag_len ) != 0 ) return( MBEDTLS_ERR_CIPHER_AUTH_FAILED ); return( 0 ); @@ -1161,7 +1161,7 @@ int mbedtls_cipher_check_tag( mbedtls_cipher_context_t *ctx, } /* Check the tag in "constant-time" */ - if( mbedtls_cf_memcmp( tag, check_tag, tag_len ) != 0 ) + if( mbedtls_ct_memcmp( tag, check_tag, tag_len ) != 0 ) return( MBEDTLS_ERR_CIPHER_AUTH_FAILED ); return( 0 ); diff --git a/library/constant_time.c b/library/constant_time.c index 5bbdf1c3e..3836d54d5 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -42,7 +42,7 @@ #include -int mbedtls_cf_memcmp( const void *a, +int mbedtls_ct_memcmp( const void *a, const void *b, size_t n ) { @@ -63,7 +63,7 @@ int mbedtls_cf_memcmp( const void *a, return( (int)diff ); } -unsigned mbedtls_cf_uint_mask( unsigned value ) +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 */ @@ -79,7 +79,7 @@ unsigned mbedtls_cf_uint_mask( unsigned value ) #if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) -size_t mbedtls_cf_size_mask( size_t value ) +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. */ @@ -97,7 +97,7 @@ size_t mbedtls_cf_size_mask( size_t value ) #if defined(MBEDTLS_BIGNUM_C) -mbedtls_mpi_uint mbedtls_cf_mpi_uint_mask( mbedtls_mpi_uint value ) +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 */ @@ -127,7 +127,7 @@ mbedtls_mpi_uint mbedtls_cf_mpi_uint_mask( mbedtls_mpi_uint value ) * * \return All-bits-one if \p x is less than \p y, otherwise zero. */ -static size_t mbedtls_cf_size_mask_lt( size_t x, +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 */ @@ -137,20 +137,20 @@ static size_t mbedtls_cf_size_mask_lt( size_t x, const size_t sub1 = sub >> ( sizeof( sub ) * 8 - 1 ); /* mask = (x < y) ? 0xff... : 0x00... */ - const size_t mask = mbedtls_cf_size_mask( sub1 ); + const size_t mask = mbedtls_ct_size_mask( sub1 ); return( mask ); } -size_t mbedtls_cf_size_mask_ge( size_t x, +size_t mbedtls_ct_size_mask_ge( size_t x, size_t y ) { - return( ~mbedtls_cf_size_mask_lt( x, y ) ); + return( ~mbedtls_ct_size_mask_lt( x, y ) ); } #endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */ -unsigned mbedtls_cf_size_bool_eq( size_t x, +unsigned mbedtls_ct_size_bool_eq( size_t x, size_t y ) { /* diff = 0 if x == y, non-zero otherwise */ @@ -189,7 +189,7 @@ unsigned mbedtls_cf_size_bool_eq( size_t x, * * \return 1 if \p x greater than \p y, otherwise 0. */ -static unsigned mbedtls_cf_size_gt( size_t x, +static unsigned mbedtls_ct_size_gt( size_t x, size_t y ) { /* Return the sign bit (1 for negative) of (y - x). */ @@ -200,7 +200,7 @@ static unsigned mbedtls_cf_size_gt( size_t x, #if defined(MBEDTLS_BIGNUM_C) -unsigned mbedtls_cf_mpi_uint_lt( const mbedtls_mpi_uint x, +unsigned mbedtls_ct_mpi_uint_lt( const mbedtls_mpi_uint x, const mbedtls_mpi_uint y ) { mbedtls_mpi_uint ret; @@ -230,11 +230,11 @@ unsigned mbedtls_cf_mpi_uint_lt( const mbedtls_mpi_uint x, #endif /* MBEDTLS_BIGNUM_C */ -unsigned mbedtls_cf_uint_if( unsigned condition, +unsigned mbedtls_ct_uint_if( unsigned condition, unsigned if1, unsigned if0 ) { - unsigned mask = mbedtls_cf_uint_mask( condition ); + unsigned mask = mbedtls_ct_uint_mask( condition ); return( ( mask & if1 ) | (~mask & if0 ) ); } @@ -254,7 +254,7 @@ unsigned mbedtls_cf_uint_if( unsigned condition, * * \return \c if1 if \p condition is nonzero, otherwise \c if0. * */ -static int mbedtls_cf_cond_select_sign( unsigned char condition, +static int mbedtls_ct_cond_select_sign( unsigned char condition, int if1, int if0 ) { @@ -274,7 +274,7 @@ static int mbedtls_cf_cond_select_sign( unsigned char condition, return( (int) ur - 1 ); } -void mbedtls_cf_mpi_uint_cond_assign( size_t n, +void mbedtls_ct_mpi_uint_cond_assign( size_t n, mbedtls_mpi_uint *dest, const mbedtls_mpi_uint *src, unsigned char condition ) @@ -305,7 +305,7 @@ void mbedtls_cf_mpi_uint_cond_assign( size_t n, /** Shift some data towards the left inside a buffer. * - * `mbedtls_cf_mem_move_to_left(start, total, offset)` is functionally + * `mbedtls_ct_mem_move_to_left(start, total, offset)` is functionally * equivalent to * ``` * memmove(start, start + offset, total - offset); @@ -319,7 +319,7 @@ void mbedtls_cf_mpi_uint_cond_assign( size_t n, * \param total Total size of the buffer. * \param offset Offset from which to copy \p total - \p offset bytes. */ -static void mbedtls_cf_mem_move_to_left( void *start, +static void mbedtls_ct_mem_move_to_left( void *start, size_t total, size_t offset ) { @@ -329,7 +329,7 @@ static void mbedtls_cf_mem_move_to_left( void *start, return; for( i = 0; i < total; i++ ) { - unsigned no_op = mbedtls_cf_size_gt( total - offset, i ); + unsigned no_op = mbedtls_ct_size_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. */ @@ -337,9 +337,9 @@ static void mbedtls_cf_mem_move_to_left( void *start, { unsigned char current = buf[n]; unsigned char next = buf[n+1]; - buf[n] = mbedtls_cf_uint_if( no_op, current, next ); + buf[n] = mbedtls_ct_uint_if( no_op, current, next ); } - buf[total-1] = mbedtls_cf_uint_if( no_op, buf[total-1], 0 ); + buf[total-1] = mbedtls_ct_uint_if( no_op, buf[total-1], 0 ); } } @@ -347,22 +347,22 @@ static void mbedtls_cf_mem_move_to_left( void *start, #if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) -void mbedtls_cf_memcpy_if_eq( unsigned char *dest, +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_cf_size_bool_eq( c1, c2 ); - const unsigned char mask = (unsigned char) mbedtls_cf_size_mask( equal ); + const size_t equal = mbedtls_ct_size_bool_eq( c1, c2 ); + const unsigned char mask = (unsigned char) mbedtls_ct_size_mask( equal ); /* dest[i] = c1 == c2 ? src[i] : dest[i] */ for( size_t i = 0; i < len; i++ ) dest[i] = ( src[i] & mask ) | ( dest[i] & ~mask ); } -void mbedtls_cf_memcpy_offset( unsigned char *dest, +void mbedtls_ct_memcpy_offset( unsigned char *dest, const unsigned char *src, size_t offset, size_t offset_min, @@ -373,12 +373,12 @@ void mbedtls_cf_memcpy_offset( unsigned char *dest, for( offsetval = offset_min; offsetval <= offset_max; offsetval++ ) { - mbedtls_cf_memcpy_if_eq( dest, src + offsetval, len, + mbedtls_ct_memcpy_if_eq( dest, src + offsetval, len, offsetval, offset ); } } -int mbedtls_cf_hmac( mbedtls_md_context_t *ctx, +int mbedtls_ct_hmac( mbedtls_md_context_t *ctx, const unsigned char *add_data, size_t add_data_len, const unsigned char *data, @@ -436,7 +436,7 @@ int mbedtls_cf_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_cf_memcpy_if_eq( output, aux_out, hash_size, + mbedtls_ct_memcpy_if_eq( output, aux_out, hash_size, offset, data_len_secret ); if( offset < max_data_len ) @@ -485,13 +485,13 @@ int mbedtls_mpi_safe_cond_assign( mbedtls_mpi *X, MPI_VALIDATE_RET( Y != NULL ); /* all-bits 1 if assign is 1, all-bits 0 if assign is 0 */ - limb_mask = mbedtls_cf_mpi_uint_mask( assign );; + limb_mask = mbedtls_ct_mpi_uint_mask( assign );; MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) ); - X->s = mbedtls_cf_cond_select_sign( assign, Y->s, X->s ); + X->s = mbedtls_ct_cond_select_sign( assign, Y->s, X->s ); - mbedtls_cf_mpi_uint_cond_assign( Y->n, X->p, Y->p, assign ); + mbedtls_ct_mpi_uint_cond_assign( Y->n, X->p, Y->p, assign ); for( i = Y->n; i < X->n; i++ ) X->p[i] &= ~limb_mask; @@ -521,14 +521,14 @@ int mbedtls_mpi_safe_cond_swap( mbedtls_mpi *X, return( 0 ); /* all-bits 1 if swap is 1, all-bits 0 if swap is 0 */ - limb_mask = mbedtls_cf_mpi_uint_mask( swap ); + limb_mask = mbedtls_ct_mpi_uint_mask( swap ); MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) ); MBEDTLS_MPI_CHK( mbedtls_mpi_grow( Y, X->n ) ); s = X->s; - X->s = mbedtls_cf_cond_select_sign( swap, Y->s, X->s ); - Y->s = mbedtls_cf_cond_select_sign( swap, s, Y->s ); + X->s = mbedtls_ct_cond_select_sign( swap, Y->s, X->s ); + Y->s = mbedtls_ct_cond_select_sign( swap, s, Y->s ); for( i = 0; i < X->n; i++ ) @@ -590,7 +590,7 @@ int mbedtls_mpi_lt_mpi_ct( const mbedtls_mpi *X, * 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_cf_mpi_uint_lt( Y->p[i - 1], X->p[i - 1] ); + cond = mbedtls_ct_mpi_uint_lt( Y->p[i - 1], X->p[i - 1] ); *ret |= cond & ( 1 - done ) & X_is_negative; done |= cond; @@ -601,7 +601,7 @@ int mbedtls_mpi_lt_mpi_ct( const mbedtls_mpi *X, * 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_cf_mpi_uint_lt( X->p[i - 1], Y->p[i - 1] ); + cond = mbedtls_ct_mpi_uint_lt( X->p[i - 1], Y->p[i - 1] ); *ret |= cond & ( 1 - done ) & ( 1 - X_is_negative ); done |= cond; } @@ -613,7 +613,7 @@ int mbedtls_mpi_lt_mpi_ct( const mbedtls_mpi *X, #if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) -int mbedtls_cf_rsaes_pkcs1_v15_unpadding( int mode, +int mbedtls_ct_rsaes_pkcs1_v15_unpadding( int mode, unsigned char *input, size_t ilen, unsigned char *output, @@ -671,17 +671,17 @@ int mbedtls_cf_rsaes_pkcs1_v15_unpadding( int mode, * If there's a non-0xff byte in the padding, the padding is bad. */ for( i = 2; i < ilen; i++ ) { - pad_done |= mbedtls_cf_uint_if( input[i], 0, 1 ); - pad_count += mbedtls_cf_uint_if( pad_done, 0, 1 ); - bad |= mbedtls_cf_uint_if( pad_done, 0, input[i] ^ 0xFF ); + pad_done |= mbedtls_ct_uint_if( input[i], 0, 1 ); + pad_count += mbedtls_ct_uint_if( pad_done, 0, 1 ); + bad |= mbedtls_ct_uint_if( pad_done, 0, input[i] ^ 0xFF ); } } /* If pad_done is still zero, there's no data, only unfinished padding. */ - bad |= mbedtls_cf_uint_if( pad_done, 0, 1 ); + bad |= mbedtls_ct_uint_if( pad_done, 0, 1 ); /* There must be at least 8 bytes of padding. */ - bad |= mbedtls_cf_size_gt( 8, pad_count ); + 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 @@ -690,13 +690,13 @@ int mbedtls_cf_rsaes_pkcs1_v15_unpadding( int mode, * 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_cf_uint_if( + 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_cf_size_gt( plaintext_size, + output_too_large = mbedtls_ct_size_gt( plaintext_size, plaintext_max_size ); /* Set ret without branches to avoid timing attacks. Return: @@ -704,9 +704,9 @@ int mbedtls_cf_rsaes_pkcs1_v15_unpadding( int mode, * - 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_cf_uint_if( + ret = - (int) mbedtls_ct_uint_if( bad, - MBEDTLS_ERR_RSA_INVALID_PADDING, - mbedtls_cf_uint_if( output_too_large, + mbedtls_ct_uint_if( output_too_large, - MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE, 0 ) ); @@ -716,7 +716,7 @@ int mbedtls_cf_rsaes_pkcs1_v15_unpadding( int mode, * 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_cf_uint_mask( bad | output_too_large ); + bad = mbedtls_ct_uint_mask( bad | output_too_large ); for( i = 11; i < ilen; i++ ) input[i] &= ~bad; @@ -724,7 +724,7 @@ int mbedtls_cf_rsaes_pkcs1_v15_unpadding( int mode, * 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_cf_uint_if( output_too_large, + plaintext_size = mbedtls_ct_uint_if( output_too_large, (unsigned) plaintext_max_size, (unsigned) plaintext_size ); @@ -734,7 +734,7 @@ int mbedtls_cf_rsaes_pkcs1_v15_unpadding( int mode, * does not depend on the plaintext size. After this move, the * starting location of the plaintext is no longer sensitive * information. */ - mbedtls_cf_mem_move_to_left( input + ilen - plaintext_max_size, + mbedtls_ct_mem_move_to_left( input + ilen - plaintext_max_size, plaintext_max_size, plaintext_max_size - plaintext_size ); diff --git a/library/constant_time.h b/library/constant_time.h index 6fd23c97a..61681084b 100644 --- a/library/constant_time.h +++ b/library/constant_time.h @@ -44,7 +44,7 @@ * * \return Zero if \p value is zero, otherwise all-bits-one. */ -unsigned mbedtls_cf_uint_mask( unsigned value ); +unsigned mbedtls_ct_uint_mask( unsigned value ); #if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) @@ -59,7 +59,7 @@ unsigned mbedtls_cf_uint_mask( unsigned value ); * * \return Zero if \p value is zero, otherwise all-bits-one. */ -size_t mbedtls_cf_size_mask( size_t value ); +size_t mbedtls_ct_size_mask( size_t value ); #endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */ @@ -76,7 +76,7 @@ size_t mbedtls_cf_size_mask( size_t value ); * * \return Zero if \p value is zero, otherwise all-bits-one. */ -mbedtls_mpi_uint mbedtls_cf_mpi_uint_mask( mbedtls_mpi_uint value ); +mbedtls_mpi_uint mbedtls_ct_mpi_uint_mask( mbedtls_mpi_uint value ); #endif /* MBEDTLS_BIGNUM_C */ @@ -95,7 +95,7 @@ mbedtls_mpi_uint mbedtls_cf_mpi_uint_mask( mbedtls_mpi_uint value ); * \return All-bits-one if \p x is greater or equal than \p y, * otherwise zero. */ -size_t mbedtls_cf_size_mask_ge( size_t x, +size_t mbedtls_ct_size_mask_ge( size_t x, size_t y ); #endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */ @@ -111,7 +111,7 @@ size_t mbedtls_cf_size_mask_ge( size_t x, * * \return 1 if \p x equals to \p y, otherwise 0. */ -unsigned mbedtls_cf_size_bool_eq( size_t x, +unsigned mbedtls_ct_size_bool_eq( size_t x, size_t y ); #if defined(MBEDTLS_BIGNUM_C) @@ -126,7 +126,7 @@ unsigned mbedtls_cf_size_bool_eq( size_t x, * * \return 1 if \p x is less than \p y, otherwise 0. */ -unsigned mbedtls_cf_mpi_uint_lt( const mbedtls_mpi_uint x, +unsigned mbedtls_ct_mpi_uint_lt( const mbedtls_mpi_uint x, const mbedtls_mpi_uint y ); #endif /* MBEDTLS_BIGNUM_C */ @@ -142,7 +142,7 @@ unsigned mbedtls_cf_mpi_uint_lt( const mbedtls_mpi_uint x, * * \return \c if1 if \p condition is nonzero, otherwise \c if0. */ -unsigned mbedtls_cf_uint_if( unsigned condition, +unsigned mbedtls_ct_uint_if( unsigned condition, unsigned if1, unsigned if0 ); @@ -160,7 +160,7 @@ unsigned mbedtls_cf_uint_if( unsigned condition, * initialized MPI. * \param condition Condition to test, must be 0 or 1. */ -void mbedtls_cf_mpi_uint_cond_assign( size_t n, +void mbedtls_ct_mpi_uint_cond_assign( size_t n, mbedtls_mpi_uint *dest, const mbedtls_mpi_uint *src, unsigned char condition ); @@ -180,7 +180,7 @@ void mbedtls_cf_mpi_uint_cond_assign( size_t n, * \param c1 The first value to analyze in the condition. * \param c2 The second value to analyze in the condition. */ -void mbedtls_cf_memcpy_if_eq( unsigned char *dest, +void mbedtls_ct_memcpy_if_eq( unsigned char *dest, const unsigned char *src, size_t len, size_t c1, size_t c2 ); @@ -204,7 +204,7 @@ void mbedtls_cf_memcpy_if_eq( unsigned char *dest, * \param offset_max The maximal value of \p offset. * \param len The number of bytes to copy. */ -void mbedtls_cf_memcpy_offset( unsigned char *dest, +void mbedtls_ct_memcpy_offset( unsigned char *dest, const unsigned char *src, size_t offset, size_t offset_min, @@ -247,7 +247,7 @@ void mbedtls_cf_memcpy_offset( unsigned char *dest, * \retval #MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED * The hardware accelerator failed. */ -int mbedtls_cf_hmac( mbedtls_md_context_t *ctx, +int mbedtls_ct_hmac( mbedtls_md_context_t *ctx, const unsigned char *add_data, size_t add_data_len, const unsigned char *data, @@ -288,7 +288,7 @@ int mbedtls_cf_hmac( mbedtls_md_context_t *ctx, * \return #MBEDTLS_ERR_RSA_INVALID_PADDING * The input doesn't contain properly formatted padding. */ -int mbedtls_cf_rsaes_pkcs1_v15_unpadding( int mode, +int mbedtls_ct_rsaes_pkcs1_v15_unpadding( int mode, unsigned char *input, size_t ilen, unsigned char *output, diff --git a/library/nist_kw.c b/library/nist_kw.c index e5d7fcd87..1aea0b634 100644 --- a/library/nist_kw.c +++ b/library/nist_kw.c @@ -379,7 +379,7 @@ int mbedtls_nist_kw_unwrap( mbedtls_nist_kw_context *ctx, goto cleanup; /* Check ICV in "constant-time" */ - diff = mbedtls_cf_memcmp( NIST_KW_ICV1, A, KW_SEMIBLOCK_LENGTH ); + diff = mbedtls_ct_memcmp( NIST_KW_ICV1, A, KW_SEMIBLOCK_LENGTH ); if( diff != 0 ) { @@ -428,7 +428,7 @@ int mbedtls_nist_kw_unwrap( mbedtls_nist_kw_context *ctx, } /* Check ICV in "constant-time" */ - diff = mbedtls_cf_memcmp( NIST_KW_ICV2, A, KW_SEMIBLOCK_LENGTH / 2 ); + diff = mbedtls_ct_memcmp( NIST_KW_ICV2, A, KW_SEMIBLOCK_LENGTH / 2 ); if( diff != 0 ) { diff --git a/library/rsa.c b/library/rsa.c index 351f4af52..3866b7341 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -1518,7 +1518,7 @@ int mbedtls_rsa_rsaes_pkcs1_v15_decrypt( mbedtls_rsa_context *ctx, if( ret != 0 ) goto cleanup; - ret = mbedtls_cf_rsaes_pkcs1_v15_unpadding( mode, buf, ilen, + ret = mbedtls_ct_rsaes_pkcs1_v15_unpadding( mode, buf, ilen, output, output_max_len, olen ); cleanup: @@ -1933,7 +1933,7 @@ int mbedtls_rsa_rsassa_pkcs1_v15_sign( mbedtls_rsa_context *ctx, MBEDTLS_MPI_CHK( mbedtls_rsa_private( ctx, f_rng, p_rng, sig, sig_try ) ); MBEDTLS_MPI_CHK( mbedtls_rsa_public( ctx, sig_try, verif ) ); - if( mbedtls_cf_memcmp( verif, sig, ctx->len ) != 0 ) + if( mbedtls_ct_memcmp( verif, sig, ctx->len ) != 0 ) { ret = MBEDTLS_ERR_RSA_PRIVATE_FAILED; goto cleanup; @@ -2231,7 +2231,7 @@ int mbedtls_rsa_rsassa_pkcs1_v15_verify( mbedtls_rsa_context *ctx, * Compare */ - if( ( ret = mbedtls_cf_memcmp( encoded, encoded_expected, + if( ( ret = mbedtls_ct_memcmp( encoded, encoded_expected, sig_len ) ) != 0 ) { ret = MBEDTLS_ERR_RSA_VERIFY_FAILED; diff --git a/library/ssl_cli.c b/library/ssl_cli.c index def6c7b45..0e802e9dd 100644 --- a/library/ssl_cli.c +++ b/library/ssl_cli.c @@ -1459,9 +1459,9 @@ static int ssl_parse_renegotiation_info( mbedtls_ssl_context *ssl, /* Check verify-data in constant-time. The length OTOH is no secret */ if( len != 1 + ssl->verify_data_len * 2 || buf[0] != ssl->verify_data_len * 2 || - mbedtls_cf_memcmp( buf + 1, + mbedtls_ct_memcmp( buf + 1, ssl->own_verify_data, ssl->verify_data_len ) != 0 || - mbedtls_cf_memcmp( buf + 1 + ssl->verify_data_len, + mbedtls_ct_memcmp( buf + 1 + ssl->verify_data_len, ssl->peer_verify_data, ssl->verify_data_len ) != 0 ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-matching renegotiation info" ) ); diff --git a/library/ssl_cookie.c b/library/ssl_cookie.c index cdc236414..faf92e7c0 100644 --- a/library/ssl_cookie.c +++ b/library/ssl_cookie.c @@ -225,7 +225,7 @@ int mbedtls_ssl_cookie_check( void *p_ctx, if( ret != 0 ) return( ret ); - if( mbedtls_cf_memcmp( cookie + 4, ref_hmac, sizeof( ref_hmac ) ) != 0 ) + if( mbedtls_ct_memcmp( cookie + 4, ref_hmac, sizeof( ref_hmac ) ) != 0 ) return( -1 ); #if defined(MBEDTLS_HAVE_TIME) diff --git a/library/ssl_msg.c b/library/ssl_msg.c index 83c4a4bd5..58f41be88 100644 --- a/library/ssl_msg.c +++ b/library/ssl_msg.c @@ -1282,7 +1282,7 @@ int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl, * * Afterwards, we know that data + data_len is followed by at * least maclen Bytes, which justifies the call to - * mbedtls_cf_memcmp() below. + * mbedtls_ct_memcmp() below. * * Further, we still know that data_len > minlen */ rec->data_len -= transform->maclen; @@ -1305,7 +1305,7 @@ int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl, transform->maclen ); /* Compare expected MAC with MAC at the end of the record. */ - if( mbedtls_cf_memcmp( data + rec->data_len, mac_expect, + if( mbedtls_ct_memcmp( data + rec->data_len, mac_expect, transform->maclen ) != 0 ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "message mac does not match" ) ); @@ -1384,7 +1384,7 @@ int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl, if( auth_done == 1 ) { - const size_t mask = mbedtls_cf_size_mask_ge( + const size_t mask = mbedtls_ct_size_mask_ge( rec->data_len, padlen + 1 ); correct &= mask; @@ -1404,7 +1404,7 @@ int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl, } #endif - const size_t mask = mbedtls_cf_size_mask_ge( + const size_t mask = mbedtls_ct_size_mask_ge( rec->data_len, transform->maclen + padlen + 1 ); correct &= mask; @@ -1460,18 +1460,18 @@ int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl, /* pad_count += (idx >= padding_idx) && * (check[idx] == padlen - 1); */ - const size_t mask = mbedtls_cf_size_mask_ge( idx, padding_idx ); - const size_t equal = mbedtls_cf_size_bool_eq( check[idx], + 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; } - correct &= mbedtls_cf_size_bool_eq( pad_count, padlen ); + correct &= mbedtls_ct_size_bool_eq( pad_count, padlen ); #if defined(MBEDTLS_SSL_DEBUG_ALL) if( padlen > 0 && correct == 0 ) MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad padding byte detected" ) ); #endif - padlen &= mbedtls_cf_size_mask( correct ); + padlen &= mbedtls_ct_size_mask( correct ); } else #endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ @@ -1555,7 +1555,7 @@ int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl, const size_t max_len = rec->data_len + padlen; const size_t min_len = ( max_len > 256 ) ? max_len - 256 : 0; - ret = mbedtls_cf_hmac( &transform->md_ctx_dec, + ret = mbedtls_ct_hmac( &transform->md_ctx_dec, add_data, add_data_len, data, rec->data_len, min_len, max_len, mac_expect ); @@ -1565,7 +1565,7 @@ int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl, return( ret ); } - mbedtls_cf_memcpy_offset( mac_peer, data, + mbedtls_ct_memcpy_offset( mac_peer, data, rec->data_len, min_len, max_len, transform->maclen ); @@ -1583,7 +1583,7 @@ int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl, MBEDTLS_SSL_DEBUG_BUF( 4, "message mac", mac_peer, transform->maclen ); #endif - if( mbedtls_cf_memcmp( mac_peer, mac_expect, + if( mbedtls_ct_memcmp( mac_peer, mac_expect, transform->maclen ) != 0 ) { #if defined(MBEDTLS_SSL_DEBUG_ALL) diff --git a/library/ssl_srv.c b/library/ssl_srv.c index d9d49a22d..8ef8e905a 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -198,7 +198,7 @@ static int ssl_parse_renegotiation_info( mbedtls_ssl_context *ssl, /* Check verify-data in constant-time. The length OTOH is no secret */ if( len != 1 + ssl->verify_data_len || buf[0] != ssl->verify_data_len || - mbedtls_cf_memcmp( buf + 1, ssl->peer_verify_data, + mbedtls_ct_memcmp( buf + 1, ssl->peer_verify_data, ssl->verify_data_len ) != 0 ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-matching renegotiation info" ) ); @@ -3973,7 +3973,7 @@ static int ssl_parse_encrypted_pms( mbedtls_ssl_context *ssl, diff |= peer_pms[1] ^ ver[1]; /* mask = diff ? 0xff : 0x00 using bit operations to avoid branches */ - mask = mbedtls_cf_uint_mask( diff ); + mask = mbedtls_ct_uint_mask( diff ); /* * Protection against Bleichenbacher's attack: invalid PKCS#1 v1.5 padding @@ -4056,7 +4056,7 @@ static int ssl_parse_client_psk_identity( mbedtls_ssl_context *ssl, unsigned cha /* Identity is not a big secret since clients send it in the clear, * but treat it carefully anyway, just in case */ if( n != ssl->conf->psk_identity_len || - mbedtls_cf_memcmp( ssl->conf->psk_identity, *p, n ) != 0 ) + mbedtls_ct_memcmp( ssl->conf->psk_identity, *p, n ) != 0 ) { ret = MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY; } diff --git a/library/ssl_tls.c b/library/ssl_tls.c index f6c593de8..8195af2f9 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -3604,7 +3604,7 @@ int mbedtls_ssl_parse_finished( mbedtls_ssl_context *ssl ) return( MBEDTLS_ERR_SSL_BAD_HS_FINISHED ); } - if( mbedtls_cf_memcmp( ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ), + if( mbedtls_ct_memcmp( ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ), buf, hash_len ) != 0 ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad finished message" ) ); diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 37e8067f6..a7efb0400 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -4428,7 +4428,7 @@ void resize_buffers_renegotiate_mfl( int mfl, int legacy_renegotiation, void ssl_cf_hmac( int hash ) { /* - * Test the function mbedtls_cf_hmac() against a reference + * Test the function mbedtls_ct_hmac() against a reference * implementation. */ mbedtls_md_context_t ctx, ref_ctx; @@ -4487,7 +4487,7 @@ void ssl_cf_hmac( int hash ) /* Get the function's result */ TEST_CF_SECRET( &in_len, sizeof( in_len ) ); - TEST_EQUAL( 0, mbedtls_cf_hmac( &ctx, add_data, sizeof( add_data ), + TEST_EQUAL( 0, mbedtls_ct_hmac( &ctx, add_data, sizeof( add_data ), data, in_len, min_in_len, max_in_len, out ) ); @@ -4537,7 +4537,7 @@ 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 ) ); - mbedtls_cf_memcpy_offset( dst, src, secret, + mbedtls_ct_memcpy_offset( dst, src, secret, offset_min, offset_max, len ); TEST_CF_PUBLIC( &secret, sizeof( secret ) ); TEST_CF_PUBLIC( dst, len ); From c0ae1cf45a1fc84f2debdad55ff4a4715329706b Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Wed, 20 Oct 2021 12:09:35 +0200 Subject: [PATCH 49/53] Rename internal header constant_time.h to constant_time_internal.h Signed-off-by: Gabor Mezei --- library/bignum.c | 2 +- library/constant_time.c | 2 +- library/{constant_time.h => constant_time_internal.h} | 0 library/rsa.c | 2 +- library/ssl_msg.c | 2 +- library/ssl_srv.c | 2 +- tests/suites/test_suite_ssl.function | 2 +- 7 files changed, 6 insertions(+), 6 deletions(-) rename library/{constant_time.h => constant_time_internal.h} (100%) diff --git a/library/bignum.c b/library/bignum.c index 846f5a331..b147a543a 100644 --- a/library/bignum.c +++ b/library/bignum.c @@ -41,7 +41,7 @@ #include "mbedtls/bn_mul.h" #include "mbedtls/platform_util.h" #include "mbedtls/error.h" -#include "constant_time.h" +#include "constant_time_internal.h" #include diff --git a/library/constant_time.c b/library/constant_time.c index 3836d54d5..651bbcb15 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -23,7 +23,7 @@ */ #include "common.h" -#include "constant_time.h" +#include "constant_time_internal.h" #include "mbedtls/constant_time.h" #include "mbedtls/error.h" #include "mbedtls/platform_util.h" diff --git a/library/constant_time.h b/library/constant_time_internal.h similarity index 100% rename from library/constant_time.h rename to library/constant_time_internal.h diff --git a/library/rsa.c b/library/rsa.c index 3866b7341..a395542c3 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -44,7 +44,7 @@ #include "mbedtls/oid.h" #include "mbedtls/platform_util.h" #include "mbedtls/error.h" -#include "constant_time.h" +#include "constant_time_internal.h" #include "mbedtls/constant_time.h" #include diff --git a/library/ssl_msg.c b/library/ssl_msg.c index 58f41be88..59cb9d288 100644 --- a/library/ssl_msg.c +++ b/library/ssl_msg.c @@ -44,7 +44,7 @@ #include "mbedtls/error.h" #include "mbedtls/platform_util.h" #include "mbedtls/version.h" -#include "constant_time.h" +#include "constant_time_internal.h" #include "mbedtls/constant_time.h" #include diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 8ef8e905a..d9f226cd1 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -34,7 +34,7 @@ #include "mbedtls/debug.h" #include "mbedtls/error.h" #include "mbedtls/platform_util.h" -#include "constant_time.h" +#include "constant_time_internal.h" #include "mbedtls/constant_time.h" #include diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index a7efb0400..b18ed423d 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -8,7 +8,7 @@ #include #include -#include +#include #include From dbe0f892b343a0a3ee3e32a8790e2f6523b1d86f Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Wed, 3 Nov 2021 16:13:32 +0100 Subject: [PATCH 50/53] Fix documentation and comments Signed-off-by: Gabor Mezei --- include/mbedtls/constant_time.h | 2 +- library/constant_time.c | 6 +++--- library/constant_time_internal.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/mbedtls/constant_time.h b/include/mbedtls/constant_time.h index b7f9a861d..c5de57a01 100644 --- a/include/mbedtls/constant_time.h +++ b/include/mbedtls/constant_time.h @@ -25,7 +25,7 @@ /** Constant-time buffer comparison without branches. * - * This is equivalent to the standard memncmp function, but is likely to be + * This is equivalent to the standard memcmp function, but is likely to be * compiled to code using bitwise operation rather than a branch. * * This function can be used to write constant-time code by replacing branches diff --git a/library/constant_time.c b/library/constant_time.c index 651bbcb15..b0e5ddec7 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -18,7 +18,7 @@ */ /* - * The following functiona are implemented without using comparison operators, as those + * The following functions are implemented without using comparison operators, as those * might be translated to branches by some compilers on some platforms. */ @@ -240,7 +240,7 @@ unsigned mbedtls_ct_uint_if( unsigned condition, #if defined(MBEDTLS_BIGNUM_C) -/** Select between two sign values witout branches. +/** Select between two sign values without branches. * * This is functionally equivalent to `condition ? if1 : if0` but uses only bit * operations in order to avoid branches. @@ -258,7 +258,7 @@ static int mbedtls_ct_cond_select_sign( unsigned char condition, int if1, int if0 ) { - /* In order to avoid questions about what we can reasonnably assume about + /* In order to avoid questions about what we can reasonably assume about * the representations of signed integers, move everything to unsigned * by taking advantage of the fact that if1 and if0 are either +1 or -1. */ unsigned uif1 = if1 + 1; diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h index 61681084b..69cd09209 100644 --- a/library/constant_time_internal.h +++ b/library/constant_time_internal.h @@ -171,7 +171,7 @@ void mbedtls_ct_mpi_uint_cond_assign( size_t n, /** Conditional memcpy without branches. * - * This is equivalent to `if ( c1 == c2 ) memcpy(dst, src, len)`, but is likely + * 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. From 84d739846c98d8149929a02390efa61c1da64c94 Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Wed, 3 Nov 2021 17:12:56 +0100 Subject: [PATCH 51/53] Update changelog with the new public API Signed-off-by: Gabor Mezei --- ChangeLog.d/constant_time_module.txt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ChangeLog.d/constant_time_module.txt b/ChangeLog.d/constant_time_module.txt index 5e76deaa8..ebb0b7fb9 100644 --- a/ChangeLog.d/constant_time_module.txt +++ b/ChangeLog.d/constant_time_module.txt @@ -1,6 +1,10 @@ Changes - * The mbedcrypto library includes new a source code module constant_time.c, + * The mbedcrypto library includes a new source code module constant_time.c, containing various functions meant to resist timing side channel attacks. This module does not have a separate configuration option, and functions from this module will be included in the build as required. Currently - the interface of this module is private and may change at any time. + most of the interface of this module is private and may change at any + time. + +Features + * Add new API mbedtls_ct_memcmp for constant time buffer comparison. From b9e1f2a3cffbdf17b3127d33c4fee8f1bb729253 Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Thu, 11 Nov 2021 15:42:41 +0100 Subject: [PATCH 52/53] Update generated files Signed-off-by: Gabor Mezei --- visualc/VS2010/mbedTLS.vcxproj | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/visualc/VS2010/mbedTLS.vcxproj b/visualc/VS2010/mbedTLS.vcxproj index 5d5b1d392..962e8680c 100644 --- a/visualc/VS2010/mbedTLS.vcxproj +++ b/visualc/VS2010/mbedTLS.vcxproj @@ -163,6 +163,7 @@ + @@ -256,6 +257,7 @@ + @@ -275,7 +277,6 @@ - @@ -300,6 +301,7 @@ + From 2dcccbfc19410856c6725677b24635eb1a3f7410 Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Tue, 16 Nov 2021 13:34:05 +0100 Subject: [PATCH 53/53] Fix function name in debug message Signed-off-by: Gabor Mezei --- library/ssl_msg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/ssl_msg.c b/library/ssl_msg.c index 59cb9d288..928d6fc86 100644 --- a/library/ssl_msg.c +++ b/library/ssl_msg.c @@ -1561,7 +1561,7 @@ int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl, mac_expect ); if( ret != 0 ) { - MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_cf_hmac", ret ); + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ct_hmac", ret ); return( ret ); }