diff --git a/library/ccm.c b/library/ccm.c index 2d2695e97..79a04a275 100644 --- a/library/ccm.c +++ b/library/ccm.c @@ -33,6 +33,7 @@ #include "mbedtls/ccm.h" #include "mbedtls/platform_util.h" #include "mbedtls/error.h" +#include "mbedtls/constant_time.h" #include @@ -362,7 +363,6 @@ int mbedtls_ccm_star_auth_decrypt(mbedtls_ccm_context *ctx, size_t length, { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; unsigned char check_tag[16]; - unsigned char i; int diff; CCM_VALIDATE_RET(ctx != NULL); @@ -379,9 +379,7 @@ int mbedtls_ccm_star_auth_decrypt(mbedtls_ccm_context *ctx, size_t length, } /* Check tag in "constant-time" */ - for (diff = 0, i = 0; i < tag_len; i++) { - diff |= tag[i] ^ check_tag[i]; - } + diff = mbedtls_ct_memcmp(tag, check_tag, tag_len); if (diff != 0) { mbedtls_platform_zeroize(output, length); diff --git a/library/chachapoly.c b/library/chachapoly.c index ceb429287..547ffb2ed 100644 --- a/library/chachapoly.c +++ b/library/chachapoly.c @@ -25,6 +25,7 @@ #include "mbedtls/chachapoly.h" #include "mbedtls/platform_util.h" #include "mbedtls/error.h" +#include "mbedtls/constant_time.h" #include @@ -337,7 +338,6 @@ int mbedtls_chachapoly_auth_decrypt(mbedtls_chachapoly_context *ctx, { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; unsigned char check_tag[16]; - size_t i; int diff; CHACHAPOLY_VALIDATE_RET(ctx != NULL); CHACHAPOLY_VALIDATE_RET(nonce != NULL); @@ -353,9 +353,7 @@ int mbedtls_chachapoly_auth_decrypt(mbedtls_chachapoly_context *ctx, } /* Check tag in "constant-time" */ - for (diff = 0, i = 0; i < sizeof(check_tag); i++) { - diff |= tag[i] ^ check_tag[i]; - } + diff = mbedtls_ct_memcmp(tag, check_tag, sizeof(check_tag)); if (diff != 0) { mbedtls_platform_zeroize(output, length); diff --git a/library/cipher.c b/library/cipher.c index 4b715d489..09ca686d8 100644 --- a/library/cipher.c +++ b/library/cipher.c @@ -30,6 +30,7 @@ #include "mbedtls/platform_util.h" #include "mbedtls/error.h" #include "mbedtls/constant_time.h" +#include "constant_time_internal.h" #include #include @@ -748,17 +749,17 @@ static int get_pkcs_padding(unsigned char *input, size_t input_len, *data_len = input_len - padding_len; /* Avoid logical || since it results in a branch */ - bad |= padding_len > input_len; - bad |= padding_len == 0; + bad |= ~mbedtls_ct_size_mask_ge(input_len, padding_len); + bad |= mbedtls_ct_size_bool_eq(padding_len, 0); /* The number of bytes checked must be independent of padding_len, * so pick input_len, which is usually 8 or 16 (one block) */ pad_idx = input_len - padding_len; for (i = 0; i < input_len; i++) { - bad |= (input[i] ^ padding_len) * (i >= pad_idx); + size_t mask = mbedtls_ct_size_mask_ge(i, pad_idx); + bad |= (input[i] ^ padding_len) & mask; } - - return MBEDTLS_ERR_CIPHER_INVALID_PADDING * (bad != 0); + return -(int) mbedtls_ct_uint_if(bad, -MBEDTLS_ERR_CIPHER_INVALID_PADDING, 0); } #endif /* MBEDTLS_CIPHER_PADDING_PKCS7 */ @@ -781,24 +782,29 @@ static void add_one_and_zeros_padding(unsigned char *output, static int get_one_and_zeros_padding(unsigned char *input, size_t input_len, size_t *data_len) { - size_t i; - unsigned char done = 0, prev_done, bad; + unsigned int bad = 1; if (NULL == input || NULL == data_len) { return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; } - bad = 0x80; *data_len = 0; - for (i = input_len; i > 0; i--) { - prev_done = done; - done |= (input[i - 1] != 0); - *data_len |= (i - 1) * (done != prev_done); - bad ^= input[i - 1] * (done != prev_done); + size_t in_padding = ~0; + + for (ptrdiff_t i = (ptrdiff_t) (input_len) - 1; i >= 0; i--) { + size_t is_nonzero = mbedtls_ct_uint_mask(input[i]); + + size_t hit_first_nonzero = is_nonzero & in_padding; + + *data_len = (*data_len & ~hit_first_nonzero) | ((size_t) i & hit_first_nonzero); + + bad = mbedtls_ct_uint_if((unsigned int) hit_first_nonzero, + !mbedtls_ct_size_bool_eq(input[i], 0x80), bad); + + in_padding = in_padding & ~is_nonzero; } - return MBEDTLS_ERR_CIPHER_INVALID_PADDING * (bad != 0); - + return -(int) mbedtls_ct_uint_if(bad, -MBEDTLS_ERR_CIPHER_INVALID_PADDING, 0); } #endif /* MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS */ @@ -832,16 +838,17 @@ static int get_zeros_and_len_padding(unsigned char *input, size_t input_len, *data_len = input_len - padding_len; /* Avoid logical || since it results in a branch */ - bad |= padding_len > input_len; - bad |= padding_len == 0; + bad |= mbedtls_ct_size_mask_ge(padding_len, input_len + 1); + bad |= mbedtls_ct_size_bool_eq(padding_len, 0); /* The number of bytes checked must be independent of padding_len */ pad_idx = input_len - padding_len; for (i = 0; i < input_len - 1; i++) { - bad |= input[i] * (i >= pad_idx); + size_t mask = mbedtls_ct_size_mask_ge(i, pad_idx); + bad |= input[i] & mask; } - return MBEDTLS_ERR_CIPHER_INVALID_PADDING * (bad != 0); + return -(int) mbedtls_ct_uint_if(bad, -MBEDTLS_ERR_CIPHER_INVALID_PADDING, 0); } #endif /* MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN */ @@ -872,8 +879,9 @@ static int get_zeros_padding(unsigned char *input, size_t input_len, *data_len = 0; for (i = input_len; i > 0; i--) { prev_done = done; - done |= (input[i-1] != 0); - *data_len |= i * (done != prev_done); + done |= !mbedtls_ct_size_bool_eq(input[i-1], 0); + size_t mask = mbedtls_ct_size_mask(done ^ prev_done); + *data_len |= i & mask; } return 0; diff --git a/library/constant_time.c b/library/constant_time.c index c0f53bbe7..2307ed53b 100644 --- a/library/constant_time.c +++ b/library/constant_time.c @@ -80,7 +80,8 @@ unsigned mbedtls_ct_uint_mask(unsigned value) #endif } -#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) +#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) || defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) || \ + defined(MBEDTLS_NIST_KW_C) || defined(MBEDTLS_CIPHER_MODE_CBC) size_t mbedtls_ct_size_mask(size_t value) { @@ -96,7 +97,8 @@ size_t mbedtls_ct_size_mask(size_t value) #endif } -#endif /* MBEDTLS_SSL_SOME_MODES_USE_MAC */ +#endif /* defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) || defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) || + defined(MBEDTLS_NIST_KW_C) || defined(MBEDTLS_CIPHER_MODE_CBC) */ #if defined(MBEDTLS_BIGNUM_C) @@ -116,7 +118,8 @@ mbedtls_mpi_uint mbedtls_ct_mpi_uint_mask(mbedtls_mpi_uint value) #endif /* MBEDTLS_BIGNUM_C */ -#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) +#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) || defined(MBEDTLS_NIST_KW_C) || \ + defined(MBEDTLS_CIPHER_MODE_CBC) /** Constant-flow mask generation for "less than" comparison: * - if \p x < \p y, return all-bits 1, that is (size_t) -1 @@ -151,7 +154,8 @@ size_t mbedtls_ct_size_mask_ge(size_t x, return ~mbedtls_ct_size_mask_lt(x, y); } -#endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */ +#endif /* defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) || defined(MBEDTLS_NIST_KW_C) || + defined(MBEDTLS_CIPHER_MODE_CBC) */ #if defined(MBEDTLS_BASE64_C) diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h index 402cf148b..0ba8a7a0b 100644 --- a/library/constant_time_internal.h +++ b/library/constant_time_internal.h @@ -45,7 +45,8 @@ */ unsigned mbedtls_ct_uint_mask(unsigned value); -#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) +#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) || defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) || \ + defined(MBEDTLS_NIST_KW_C) || defined(MBEDTLS_CIPHER_MODE_CBC) /** Turn a value into a mask: * - if \p value == 0, return the all-bits 0 mask, aka 0 @@ -60,7 +61,8 @@ unsigned mbedtls_ct_uint_mask(unsigned value); */ size_t mbedtls_ct_size_mask(size_t value); -#endif /* MBEDTLS_SSL_SOME_MODES_USE_MAC */ +#endif /* defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) || defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) || + defined(MBEDTLS_NIST_KW_C) || defined(MBEDTLS_CIPHER_MODE_CBC) */ #if defined(MBEDTLS_BIGNUM_C) @@ -79,7 +81,8 @@ mbedtls_mpi_uint mbedtls_ct_mpi_uint_mask(mbedtls_mpi_uint value); #endif /* MBEDTLS_BIGNUM_C */ -#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) +#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) || defined(MBEDTLS_NIST_KW_C) || \ + defined(MBEDTLS_CIPHER_MODE_CBC) /** Constant-flow mask generation for "greater or equal" comparison: * - if \p x >= \p y, return all-bits 1, that is (size_t) -1 @@ -97,7 +100,8 @@ mbedtls_mpi_uint mbedtls_ct_mpi_uint_mask(mbedtls_mpi_uint value); size_t mbedtls_ct_size_mask_ge(size_t x, size_t y); -#endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */ +#endif /* defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) || defined(MBEDTLS_NIST_KW_C) || + defined(MBEDTLS_CIPHER_MODE_CBC) */ /** Constant-flow boolean "equal" comparison: * return x == y diff --git a/library/gcm.c b/library/gcm.c index 0c958c729..71e7b2e9b 100644 --- a/library/gcm.c +++ b/library/gcm.c @@ -35,6 +35,7 @@ #include "mbedtls/platform.h" #include "mbedtls/platform_util.h" #include "mbedtls/error.h" +#include "mbedtls/constant_time.h" #include @@ -478,7 +479,6 @@ int mbedtls_gcm_auth_decrypt(mbedtls_gcm_context *ctx, { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; unsigned char check_tag[16]; - size_t i; int diff; GCM_VALIDATE_RET(ctx != NULL); @@ -495,9 +495,7 @@ int mbedtls_gcm_auth_decrypt(mbedtls_gcm_context *ctx, } /* Check tag in "constant-time" */ - for (diff = 0, i = 0; i < tag_len; i++) { - diff |= tag[i] ^ check_tag[i]; - } + diff = mbedtls_ct_memcmp(tag, check_tag, tag_len); if (diff != 0) { mbedtls_platform_zeroize(output, length); diff --git a/library/nist_kw.c b/library/nist_kw.c index 5817bf4f4..4ff5e41b4 100644 --- a/library/nist_kw.c +++ b/library/nist_kw.c @@ -35,6 +35,7 @@ #include "mbedtls/platform_util.h" #include "mbedtls/error.h" #include "mbedtls/constant_time.h" +#include "constant_time_internal.h" #include #include @@ -335,7 +336,7 @@ int mbedtls_nist_kw_unwrap(mbedtls_nist_kw_context *ctx, int ret = 0; size_t i, olen; unsigned char A[KW_SEMIBLOCK_LENGTH]; - unsigned char diff, bad_padding = 0; + unsigned char diff; *out_len = 0; if (out_size < in_len - KW_SEMIBLOCK_LENGTH) { @@ -420,18 +421,13 @@ int mbedtls_nist_kw_unwrap(mbedtls_nist_kw_context *ctx, * larger than 8, because of the type wrap around. */ padlen = in_len - KW_SEMIBLOCK_LENGTH - Plen; - if (padlen > 7) { - padlen &= 7; - ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED; - } + ret = -(int) mbedtls_ct_uint_if(padlen & ~7, -MBEDTLS_ERR_CIPHER_AUTH_FAILED, -ret); + padlen &= 7; /* Check padding in "constant-time" */ for (diff = 0, i = 0; i < KW_SEMIBLOCK_LENGTH; i++) { - if (i >= KW_SEMIBLOCK_LENGTH - padlen) { - diff |= output[*out_len - KW_SEMIBLOCK_LENGTH + i]; - } else { - bad_padding |= output[*out_len - KW_SEMIBLOCK_LENGTH + i]; - } + size_t mask = mbedtls_ct_size_mask_ge(i, KW_SEMIBLOCK_LENGTH - padlen); + diff |= (unsigned char) (mask & output[*out_len - KW_SEMIBLOCK_LENGTH + i]); } if (diff != 0) { @@ -454,7 +450,6 @@ cleanup: *out_len = 0; } - mbedtls_platform_zeroize(&bad_padding, sizeof(bad_padding)); mbedtls_platform_zeroize(&diff, sizeof(diff)); mbedtls_platform_zeroize(A, sizeof(A)); diff --git a/library/rsa.c b/library/rsa.c index f44b2c38b..01d0eb09d 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -1351,7 +1351,8 @@ int mbedtls_rsa_rsaes_oaep_decrypt(mbedtls_rsa_context *ctx, { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; size_t ilen, i, pad_len; - unsigned char *p, bad, pad_done; + unsigned char *p, pad_done; + int bad; unsigned char buf[MBEDTLS_MPI_MAX_SIZE]; unsigned char lhash[MBEDTLS_MD_MAX_SIZE]; unsigned int hlen; @@ -1439,9 +1440,8 @@ int mbedtls_rsa_rsaes_oaep_decrypt(mbedtls_rsa_context *ctx, p += hlen; /* Skip seed */ /* Check lHash */ - for (i = 0; i < hlen; i++) { - bad |= lhash[i] ^ *p++; - } + bad |= mbedtls_ct_memcmp(lhash, p, hlen); + p += hlen; /* Get zero-padding len, but always read till end of buffer * (minus one, for the 01 byte) */