Merge branch 'development' into more-aes-checks
Signed-off-by: Dave Rodgman <dave.rodgman@arm.com>
diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt
index 2b1fd43..6a4ce51 100644
--- a/library/CMakeLists.txt
+++ b/library/CMakeLists.txt
@@ -268,17 +268,20 @@
${mbedtls_static_target})
endif()
+set(p256m_target "${MBEDTLS_TARGET_PREFIX}p256m")
+set(everest_target "${MBEDTLS_TARGET_PREFIX}everest")
+
if(USE_STATIC_MBEDTLS_LIBRARY)
add_library(${mbedcrypto_static_target} STATIC ${src_crypto})
set_target_properties(${mbedcrypto_static_target} PROPERTIES OUTPUT_NAME mbedcrypto)
target_link_libraries(${mbedcrypto_static_target} PUBLIC ${libs})
- if(TARGET everest)
- target_link_libraries(${mbedcrypto_static_target} PUBLIC everest)
+ if(TARGET ${everest_target})
+ target_link_libraries(${mbedcrypto_static_target} PUBLIC ${everest_target})
endif()
- if(TARGET p256m)
- target_link_libraries(${mbedcrypto_static_target} PUBLIC p256m)
+ if(TARGET ${p256m_target})
+ target_link_libraries(${mbedcrypto_static_target} PUBLIC ${p256m_target})
endif()
add_library(${mbedx509_static_target} STATIC ${src_x509})
@@ -293,23 +296,23 @@
if(USE_SHARED_MBEDTLS_LIBRARY)
set(CMAKE_LIBRARY_PATH ${CMAKE_CURRENT_BINARY_DIR})
add_library(${mbedcrypto_target} SHARED ${src_crypto})
- set_target_properties(${mbedcrypto_target} PROPERTIES VERSION 3.4.1 SOVERSION 14)
+ set_target_properties(${mbedcrypto_target} PROPERTIES VERSION 3.5.0 SOVERSION 15)
target_link_libraries(${mbedcrypto_target} PUBLIC ${libs})
- if(TARGET everest)
- target_link_libraries(${mbedcrypto_target} PUBLIC everest)
+ if(TARGET ${everest_target})
+ target_link_libraries(${mbedcrypto_target} PUBLIC ${everest_target})
endif()
- if(TARGET p256m)
- target_link_libraries(${mbedcrypto_target} PUBLIC p256m)
+ if(TARGET ${p256m_target})
+ target_link_libraries(${mbedcrypto_target} PUBLIC ${p256m_target})
endif()
add_library(${mbedx509_target} SHARED ${src_x509})
- set_target_properties(${mbedx509_target} PROPERTIES VERSION 3.4.1 SOVERSION 5)
+ set_target_properties(${mbedx509_target} PROPERTIES VERSION 3.5.0 SOVERSION 6)
target_link_libraries(${mbedx509_target} PUBLIC ${libs} ${mbedcrypto_target})
add_library(${mbedtls_target} SHARED ${src_tls})
- set_target_properties(${mbedtls_target} PROPERTIES VERSION 3.4.1 SOVERSION 19)
+ set_target_properties(${mbedtls_target} PROPERTIES VERSION 3.5.0 SOVERSION 20)
target_link_libraries(${mbedtls_target} PUBLIC ${libs} ${mbedx509_target})
endif(USE_SHARED_MBEDTLS_LIBRARY)
diff --git a/library/Makefile b/library/Makefile
index a5b1ef0..9e2d723 100644
--- a/library/Makefile
+++ b/library/Makefile
@@ -51,9 +51,9 @@
endif
endif
-SOEXT_TLS?=so.19
-SOEXT_X509?=so.5
-SOEXT_CRYPTO?=so.14
+SOEXT_TLS?=so.20
+SOEXT_X509?=so.6
+SOEXT_CRYPTO?=so.15
# Set AR_DASH= (empty string) to use an ar implementation that does not accept
# the - prefix for command line options (e.g. llvm-ar)
diff --git a/library/aes.c b/library/aes.c
index d232229..b61d089 100644
--- a/library/aes.c
+++ b/library/aes.c
@@ -34,23 +34,15 @@
#include "mbedtls/platform_util.h"
#include "mbedtls/error.h"
-#if defined(MBEDTLS_ARCH_IS_ARM64)
-#if !defined(MBEDTLS_AESCE_C) && defined(MBEDTLS_AES_USE_HARDWARE_ONLY)
-#error "MBEDTLS_AES_USE_HARDWARE_ONLY defined, but not all prerequisites"
-#endif
-#endif
-
-#if defined(MBEDTLS_ARCH_IS_X64)
-#if !defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_AES_USE_HARDWARE_ONLY)
+#if defined(MBEDTLS_AES_USE_HARDWARE_ONLY)
+#if !((defined(MBEDTLS_ARCH_IS_ARM64) && defined(MBEDTLS_AESCE_C)) || \
+ (defined(MBEDTLS_ARCH_IS_X64) && defined(MBEDTLS_AESNI_C)) || \
+ (defined(MBEDTLS_ARCH_IS_X86) && defined(MBEDTLS_AESNI_C)))
#error "MBEDTLS_AES_USE_HARDWARE_ONLY defined, but not all prerequisites"
#endif
#endif
#if defined(MBEDTLS_ARCH_IS_X86)
-#if defined(MBEDTLS_AES_USE_HARDWARE_ONLY) && !defined(MBEDTLS_AESNI_C)
-#error "MBEDTLS_AES_USE_HARDWARE_ONLY defined, but not all prerequisites"
-#endif
-
#if defined(MBEDTLS_PADLOCK_C)
#if !defined(MBEDTLS_HAVE_ASM)
#error "MBEDTLS_PADLOCK_C defined, but not all prerequisites"
@@ -339,7 +331,7 @@
/*
* Round constants
*/
-MBEDTLS_MAYBE_UNUSED static const uint32_t RCON[10] =
+MBEDTLS_MAYBE_UNUSED static const uint32_t round_constants[10] =
{
0x00000001, 0x00000002, 0x00000004, 0x00000008,
0x00000010, 0x00000020, 0x00000040, 0x00000080,
@@ -370,7 +362,7 @@
/*
* Round constants
*/
-MBEDTLS_MAYBE_UNUSED static uint32_t RCON[10];
+MBEDTLS_MAYBE_UNUSED static uint32_t round_constants[10];
/*
* Tables generation code
@@ -401,7 +393,7 @@
* calculate the round constants
*/
for (i = 0, x = 1; i < 10; i++) {
- RCON[i] = x;
+ round_constants[i] = x;
x = XTIME(x);
}
@@ -625,7 +617,7 @@
case 10:
for (unsigned int i = 0; i < 10; i++, RK += 4) {
- RK[4] = RK[0] ^ RCON[i] ^
+ RK[4] = RK[0] ^ round_constants[i] ^
((uint32_t) FSb[MBEDTLS_BYTE_1(RK[3])]) ^
((uint32_t) FSb[MBEDTLS_BYTE_2(RK[3])] << 8) ^
((uint32_t) FSb[MBEDTLS_BYTE_3(RK[3])] << 16) ^
@@ -641,7 +633,7 @@
case 12:
for (unsigned int i = 0; i < 8; i++, RK += 6) {
- RK[6] = RK[0] ^ RCON[i] ^
+ RK[6] = RK[0] ^ round_constants[i] ^
((uint32_t) FSb[MBEDTLS_BYTE_1(RK[5])]) ^
((uint32_t) FSb[MBEDTLS_BYTE_2(RK[5])] << 8) ^
((uint32_t) FSb[MBEDTLS_BYTE_3(RK[5])] << 16) ^
@@ -658,7 +650,7 @@
case 14:
for (unsigned int i = 0; i < 7; i++, RK += 8) {
- RK[8] = RK[0] ^ RCON[i] ^
+ RK[8] = RK[0] ^ round_constants[i] ^
((uint32_t) FSb[MBEDTLS_BYTE_1(RK[7])]) ^
((uint32_t) FSb[MBEDTLS_BYTE_2(RK[7])] << 8) ^
((uint32_t) FSb[MBEDTLS_BYTE_3(RK[7])] << 16) ^
diff --git a/library/bignum.c b/library/bignum.c
index 61353ca..7c265e0 100644
--- a/library/bignum.c
+++ b/library/bignum.c
@@ -83,7 +83,7 @@
* 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).
*/
- different_sign = mbedtls_ct_bool_xor(X_is_negative, Y_is_negative); // true if different sign
+ different_sign = mbedtls_ct_bool_ne(X_is_negative, Y_is_negative); // true if different sign
result = mbedtls_ct_bool_and(different_sign, X_is_negative);
/*
@@ -131,15 +131,17 @@
MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, Y->n));
- mbedtls_ct_condition_t do_assign = mbedtls_ct_bool(assign);
+ {
+ mbedtls_ct_condition_t do_assign = mbedtls_ct_bool(assign);
- X->s = (int) mbedtls_ct_uint_if(do_assign, Y->s, X->s);
+ X->s = (int) mbedtls_ct_uint_if(do_assign, Y->s, X->s);
- mbedtls_mpi_core_cond_assign(X->p, Y->p, Y->n, do_assign);
+ mbedtls_mpi_core_cond_assign(X->p, Y->p, Y->n, do_assign);
- mbedtls_ct_condition_t do_not_assign = mbedtls_ct_bool_not(do_assign);
- for (size_t i = Y->n; i < X->n; i++) {
- X->p[i] = mbedtls_ct_mpi_uint_if_else_0(do_not_assign, X->p[i]);
+ mbedtls_ct_condition_t do_not_assign = mbedtls_ct_bool_not(do_assign);
+ for (size_t i = Y->n; i < X->n; i++) {
+ X->p[i] = mbedtls_ct_mpi_uint_if_else_0(do_not_assign, X->p[i]);
+ }
}
cleanup:
@@ -386,7 +388,7 @@
/* Convert x to a sign, i.e. to 1, if x is positive, or -1, if x is negative.
* This looks awkward but generates smaller code than (x < 0 ? -1 : 1) */
-#define TO_SIGN(x) ((((mbedtls_mpi_uint) x) >> (biL - 1)) * -2 + 1)
+#define TO_SIGN(x) ((mbedtls_mpi_sint) (((mbedtls_mpi_uint) x) >> (biL - 1)) * -2 + 1)
/*
* Set value from integer
diff --git a/library/ccm.c b/library/ccm.c
index bc61376..237ef9f 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 <string.h>
@@ -532,13 +533,8 @@
const unsigned char *tag2,
size_t tag_len)
{
- unsigned char i;
- int diff;
-
/* Check tag in "constant-time" */
- for (diff = 0, i = 0; i < tag_len; i++) {
- diff |= tag1[i] ^ tag2[i];
- }
+ int diff = mbedtls_ct_memcmp(tag1, tag2, tag_len);
if (diff != 0) {
return MBEDTLS_ERR_CCM_AUTH_FAILED;
diff --git a/library/chachapoly.c b/library/chachapoly.c
index 0124d75..aebc646 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 <string.h>
@@ -310,7 +311,6 @@
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
unsigned char check_tag[16];
- size_t i;
int diff;
if ((ret = chachapoly_crypt_and_tag(ctx,
@@ -320,9 +320,7 @@
}
/* 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 69ee6d7..9f9f107 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 <stdlib.h>
#include <string.h>
@@ -268,17 +269,6 @@
ctx->cipher_info = cipher_info;
-#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING)
- /*
- * Ignore possible errors caused by a cipher mode that doesn't use padding
- */
-#if defined(MBEDTLS_CIPHER_PADDING_PKCS7)
- (void) mbedtls_cipher_set_padding_mode(ctx, MBEDTLS_PADDING_PKCS7);
-#else
- (void) mbedtls_cipher_set_padding_mode(ctx, MBEDTLS_PADDING_NONE);
-#endif
-#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */
-
return 0;
}
@@ -848,7 +838,7 @@
size_t *data_len)
{
size_t i, pad_idx;
- unsigned char padding_len, bad = 0;
+ unsigned char padding_len;
if (NULL == input || NULL == data_len) {
return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
@@ -857,18 +847,19 @@
padding_len = input[input_len - 1];
*data_len = input_len - padding_len;
- /* Avoid logical || since it results in a branch */
- bad |= padding_len > input_len;
- bad |= padding_len == 0;
+ mbedtls_ct_condition_t bad = mbedtls_ct_uint_gt(padding_len, input_len);
+ bad = mbedtls_ct_bool_or(bad, mbedtls_ct_uint_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);
+ mbedtls_ct_condition_t in_padding = mbedtls_ct_uint_ge(i, pad_idx);
+ mbedtls_ct_condition_t different = mbedtls_ct_uint_ne(input[i], padding_len);
+ bad = mbedtls_ct_bool_or(bad, mbedtls_ct_bool_and(in_padding, different));
}
- return MBEDTLS_ERR_CIPHER_INVALID_PADDING * (bad != 0);
+ return mbedtls_ct_error_if_else_0(bad, MBEDTLS_ERR_CIPHER_INVALID_PADDING);
}
#endif /* MBEDTLS_CIPHER_PADDING_PKCS7 */
@@ -891,24 +882,28 @@
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;
-
if (NULL == input || NULL == data_len) {
return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
}
- bad = 0x80;
+ mbedtls_ct_condition_t in_padding = MBEDTLS_CT_TRUE;
+ mbedtls_ct_condition_t bad = MBEDTLS_CT_TRUE;
+
*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);
+
+ for (ptrdiff_t i = (ptrdiff_t) (input_len) - 1; i >= 0; i--) {
+ mbedtls_ct_condition_t is_nonzero = mbedtls_ct_bool(input[i]);
+
+ mbedtls_ct_condition_t hit_first_nonzero = mbedtls_ct_bool_and(is_nonzero, in_padding);
+
+ *data_len = mbedtls_ct_size_if(hit_first_nonzero, i, *data_len);
+
+ bad = mbedtls_ct_bool_if(hit_first_nonzero, mbedtls_ct_uint_ne(input[i], 0x80), bad);
+
+ in_padding = mbedtls_ct_bool_and(in_padding, mbedtls_ct_bool_not(is_nonzero));
}
- return MBEDTLS_ERR_CIPHER_INVALID_PADDING * (bad != 0);
-
+ return mbedtls_ct_error_if_else_0(bad, MBEDTLS_ERR_CIPHER_INVALID_PADDING);
}
#endif /* MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS */
@@ -932,7 +927,8 @@
size_t *data_len)
{
size_t i, pad_idx;
- unsigned char padding_len, bad = 0;
+ unsigned char padding_len;
+ mbedtls_ct_condition_t bad;
if (NULL == input || NULL == data_len) {
return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
@@ -942,16 +938,19 @@
*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_uint_gt(padding_len, input_len);
+ bad = mbedtls_ct_bool_or(bad, mbedtls_ct_uint_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);
+ mbedtls_ct_condition_t is_padding = mbedtls_ct_uint_ge(i, pad_idx);
+ mbedtls_ct_condition_t nonzero_pad_byte;
+ nonzero_pad_byte = mbedtls_ct_bool_if_else_0(is_padding, mbedtls_ct_bool(input[i]));
+ bad = mbedtls_ct_bool_or(bad, nonzero_pad_byte);
}
- return MBEDTLS_ERR_CIPHER_INVALID_PADDING * (bad != 0);
+ return mbedtls_ct_error_if_else_0(bad, MBEDTLS_ERR_CIPHER_INVALID_PADDING);
}
#endif /* MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN */
@@ -962,18 +961,14 @@
static void add_zeros_padding(unsigned char *output,
size_t output_len, size_t data_len)
{
- size_t i;
-
- for (i = data_len; i < output_len; i++) {
- output[i] = 0x00;
- }
+ memset(output + data_len, 0, output_len - data_len);
}
static int get_zeros_padding(unsigned char *input, size_t input_len,
size_t *data_len)
{
size_t i;
- unsigned char done = 0, prev_done;
+ mbedtls_ct_condition_t done = MBEDTLS_CT_FALSE, prev_done;
if (NULL == input || NULL == data_len) {
return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
@@ -982,8 +977,8 @@
*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_bool_or(done, mbedtls_ct_uint_ne(input[i-1], 0));
+ *data_len = mbedtls_ct_size_if(mbedtls_ct_bool_ne(done, prev_done), i, *data_len);
}
return 0;
@@ -1027,6 +1022,16 @@
*olen = 0;
+#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING)
+ /* CBC mode requires padding so we make sure a call to
+ * mbedtls_cipher_set_padding_mode has been done successfully. */
+ if (MBEDTLS_MODE_CBC == ((mbedtls_cipher_mode_t) ctx->cipher_info->mode)) {
+ if (ctx->get_padding == NULL) {
+ return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
+ }
+ }
+#endif
+
if (MBEDTLS_MODE_CFB == ((mbedtls_cipher_mode_t) ctx->cipher_info->mode) ||
MBEDTLS_MODE_OFB == ((mbedtls_cipher_mode_t) ctx->cipher_info->mode) ||
MBEDTLS_MODE_CTR == ((mbedtls_cipher_mode_t) ctx->cipher_info->mode) ||
diff --git a/library/cmac.c b/library/cmac.c
index 333248e..c079686 100644
--- a/library/cmac.c
+++ b/library/cmac.c
@@ -114,7 +114,7 @@
unsigned char *K1, unsigned char *K2)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
- unsigned char L[MBEDTLS_CIPHER_BLKSIZE_MAX];
+ unsigned char L[MBEDTLS_CMAC_MAX_BLOCK_SIZE];
size_t olen, block_size;
mbedtls_platform_zeroize(L, sizeof(L));
@@ -152,7 +152,7 @@
* We can't use the padding option from the cipher layer, as it only works for
* CBC and we use ECB mode, and anyway we need to XOR K1 or K2 in addition.
*/
-static void cmac_pad(unsigned char padded_block[MBEDTLS_CIPHER_BLKSIZE_MAX],
+static void cmac_pad(unsigned char padded_block[MBEDTLS_CMAC_MAX_BLOCK_SIZE],
size_t padded_block_len,
const unsigned char *last_block,
size_t last_block_len)
@@ -283,9 +283,9 @@
{
mbedtls_cmac_context_t *cmac_ctx;
unsigned char *state, *last_block;
- unsigned char K1[MBEDTLS_CIPHER_BLKSIZE_MAX];
- unsigned char K2[MBEDTLS_CIPHER_BLKSIZE_MAX];
- unsigned char M_last[MBEDTLS_CIPHER_BLKSIZE_MAX];
+ unsigned char K1[MBEDTLS_CMAC_MAX_BLOCK_SIZE];
+ unsigned char K2[MBEDTLS_CMAC_MAX_BLOCK_SIZE];
+ unsigned char M_last[MBEDTLS_CMAC_MAX_BLOCK_SIZE];
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t olen, block_size;
@@ -332,7 +332,7 @@
mbedtls_platform_zeroize(cmac_ctx->unprocessed_block,
sizeof(cmac_ctx->unprocessed_block));
- mbedtls_platform_zeroize(state, MBEDTLS_CIPHER_BLKSIZE_MAX);
+ mbedtls_platform_zeroize(state, MBEDTLS_CMAC_MAX_BLOCK_SIZE);
return ret;
}
@@ -750,8 +750,8 @@
int i, ret = 0;
mbedtls_cipher_context_t ctx;
const mbedtls_cipher_info_t *cipher_info;
- unsigned char K1[MBEDTLS_CIPHER_BLKSIZE_MAX];
- unsigned char K2[MBEDTLS_CIPHER_BLKSIZE_MAX];
+ unsigned char K1[MBEDTLS_CMAC_MAX_BLOCK_SIZE];
+ unsigned char K2[MBEDTLS_CMAC_MAX_BLOCK_SIZE];
cipher_info = mbedtls_cipher_info_from_type(cipher_type);
if (cipher_info == NULL) {
@@ -845,7 +845,7 @@
{
const mbedtls_cipher_info_t *cipher_info;
int i, ret = 0;
- unsigned char output[MBEDTLS_CIPHER_BLKSIZE_MAX];
+ unsigned char output[MBEDTLS_CMAC_MAX_BLOCK_SIZE];
cipher_info = mbedtls_cipher_info_from_type(cipher_type);
if (cipher_info == NULL) {
diff --git a/library/constant_time.c b/library/constant_time.c
index d3c69cf..8b41aed 100644
--- a/library/constant_time.c
+++ b/library/constant_time.c
@@ -22,6 +22,7 @@
* might be translated to branches by some compilers on some platforms.
*/
+#include <stdint.h>
#include <limits.h>
#include "common.h"
@@ -120,9 +121,56 @@
diff |= x ^ y;
}
+
+#if (INT_MAX < INT32_MAX)
+ /* We don't support int smaller than 32-bits, but if someone tried to build
+ * with this configuration, there is a risk that, for differing data, the
+ * only bits set in diff are in the top 16-bits, and would be lost by a
+ * simple cast from uint32 to int.
+ * This would have significant security implications, so protect against it. */
+#error "mbedtls_ct_memcmp() requires minimum 32-bit ints"
+#else
+ /* The bit-twiddling ensures that when we cast uint32_t to int, we are casting
+ * a value that is in the range 0..INT_MAX - a value larger than this would
+ * result in implementation defined behaviour.
+ *
+ * This ensures that the value returned by the function is non-zero iff
+ * diff is non-zero.
+ */
+ return (int) ((diff & 0xffff) | (diff >> 16));
+#endif
+}
+
+#if defined(MBEDTLS_NIST_KW_C)
+
+int mbedtls_ct_memcmp_partial(const void *a,
+ const void *b,
+ size_t n,
+ size_t skip_head,
+ size_t skip_tail)
+{
+ unsigned int diff = 0;
+
+ volatile const unsigned char *A = (volatile const unsigned char *) a;
+ volatile const unsigned char *B = (volatile const unsigned char *) b;
+
+ size_t valid_end = n - skip_tail;
+
+ for (size_t i = 0; i < n; i++) {
+ unsigned char x = A[i], y = B[i];
+ unsigned int d = x ^ y;
+ mbedtls_ct_condition_t valid = mbedtls_ct_bool_and(mbedtls_ct_uint_ge(i, skip_head),
+ mbedtls_ct_uint_lt(i, valid_end));
+ diff |= mbedtls_ct_uint_if_else_0(valid, d);
+ }
+
+ /* Since we go byte-by-byte, the only bits set will be in the bottom 8 bits, so the
+ * cast from uint to int is safe. */
return (int) diff;
}
+#endif
+
#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT)
void mbedtls_ct_memmove_left(void *start, size_t total, size_t offset)
diff --git a/library/constant_time_impl.h b/library/constant_time_impl.h
index 4290e60..7759ac3 100644
--- a/library/constant_time_impl.h
+++ b/library/constant_time_impl.h
@@ -429,7 +429,6 @@
return (unsigned char) (~(low_mask | high_mask)) & to;
}
-
/* ============================================================================
* Everything below here is trivial wrapper functions
*/
@@ -448,6 +447,14 @@
return (unsigned) mbedtls_ct_if(condition, (mbedtls_ct_uint_t) if1, (mbedtls_ct_uint_t) if0);
}
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_if(mbedtls_ct_condition_t condition,
+ mbedtls_ct_condition_t if1,
+ mbedtls_ct_condition_t if0)
+{
+ return (mbedtls_ct_condition_t) mbedtls_ct_if(condition, (mbedtls_ct_uint_t) if1,
+ (mbedtls_ct_uint_t) if0);
+}
+
#if defined(MBEDTLS_BIGNUM_C)
static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if(mbedtls_ct_condition_t condition,
@@ -471,6 +478,12 @@
return (unsigned) (condition & if1);
}
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_if_else_0(mbedtls_ct_condition_t condition,
+ mbedtls_ct_condition_t if1)
+{
+ return (mbedtls_ct_condition_t) (condition & if1);
+}
+
#if defined(MBEDTLS_BIGNUM_C)
static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if_else_0(mbedtls_ct_condition_t condition,
@@ -481,6 +494,23 @@
#endif /* MBEDTLS_BIGNUM_C */
+static inline int mbedtls_ct_error_if(mbedtls_ct_condition_t condition, int if1, int if0)
+{
+ /* Coverting int -> uint -> int here is safe, because we require if1 and if0 to be
+ * in the range -32767..0, and we require 32-bit int and uint types.
+ *
+ * This means that (0 <= -if0 < INT_MAX), so negating if0 is safe, and similarly for
+ * converting back to int.
+ */
+ return -((int) mbedtls_ct_if(condition, (mbedtls_ct_uint_t) (-if1),
+ (mbedtls_ct_uint_t) (-if0)));
+}
+
+static inline int mbedtls_ct_error_if_else_0(mbedtls_ct_condition_t condition, int if1)
+{
+ return -((int) (condition & (-if1)));
+}
+
static inline mbedtls_ct_condition_t mbedtls_ct_uint_eq(mbedtls_ct_uint_t x,
mbedtls_ct_uint_t y)
{
@@ -505,8 +535,8 @@
return ~mbedtls_ct_uint_gt(x, y);
}
-static inline mbedtls_ct_condition_t mbedtls_ct_bool_xor(mbedtls_ct_condition_t x,
- mbedtls_ct_condition_t y)
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_ne(mbedtls_ct_condition_t x,
+ mbedtls_ct_condition_t y)
{
return (mbedtls_ct_condition_t) (x ^ y);
}
diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h
index ff7ccc1..cc26edc 100644
--- a/library/constant_time_internal.h
+++ b/library/constant_time_internal.h
@@ -194,11 +194,11 @@
static inline mbedtls_ct_condition_t mbedtls_ct_uint_le(mbedtls_ct_uint_t x,
mbedtls_ct_uint_t y);
-/** Boolean "xor" operation.
+/** Boolean not-equals operation.
*
* Functionally equivalent to:
*
- * \p x ^ \p y
+ * \p x != \p y
*
* \param x The first value to analyze.
* \param y The second value to analyze.
@@ -206,11 +206,11 @@
* \note This is more efficient than mbedtls_ct_uint_ne if both arguments are
* mbedtls_ct_condition_t.
*
- * \return MBEDTLS_CT_TRUE if \p x ^ \p y,
+ * \return MBEDTLS_CT_TRUE if \p x != \p y,
* otherwise MBEDTLS_CT_FALSE.
*/
-static inline mbedtls_ct_condition_t mbedtls_ct_bool_xor(mbedtls_ct_condition_t x,
- mbedtls_ct_condition_t y);
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_ne(mbedtls_ct_condition_t x,
+ mbedtls_ct_condition_t y);
/** Boolean "and" operation.
*
@@ -291,6 +291,22 @@
unsigned if1,
unsigned if0);
+/** Choose between two mbedtls_ct_condition_t values.
+ *
+ * Functionally equivalent to:
+ *
+ * condition ? if1 : if0.
+ *
+ * \param condition Condition to test.
+ * \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE.
+ * \param if0 Value to use if \p condition == MBEDTLS_CT_FALSE.
+ *
+ * \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise \c if0.
+ */
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_if(mbedtls_ct_condition_t condition,
+ mbedtls_ct_condition_t if1,
+ mbedtls_ct_condition_t if0);
+
#if defined(MBEDTLS_BIGNUM_C)
/** Choose between two mbedtls_mpi_uint values.
@@ -327,6 +343,23 @@
*/
static inline unsigned mbedtls_ct_uint_if_else_0(mbedtls_ct_condition_t condition, unsigned if1);
+/** Choose between an mbedtls_ct_condition_t and 0.
+ *
+ * Functionally equivalent to:
+ *
+ * condition ? if1 : 0.
+ *
+ * Functionally equivalent to mbedtls_ct_bool_if(condition, if1, 0) but
+ * results in smaller code size.
+ *
+ * \param condition Condition to test.
+ * \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE.
+ *
+ * \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise 0.
+ */
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_if_else_0(mbedtls_ct_condition_t condition,
+ mbedtls_ct_condition_t if1);
+
/** Choose between a size_t value and 0.
*
* Functionally equivalent to:
@@ -378,6 +411,35 @@
unsigned char c,
unsigned char t);
+/** Choose between two error values. The values must be in the range [-32767..0].
+ *
+ * Functionally equivalent to:
+ *
+ * condition ? if1 : if0.
+ *
+ * \param condition Condition to test.
+ * \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE.
+ * \param if0 Value to use if \p condition == MBEDTLS_CT_FALSE.
+ *
+ * \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise \c if0.
+ */
+static inline int mbedtls_ct_error_if(mbedtls_ct_condition_t condition, int if1, int if0);
+
+/** Choose between an error value and 0. The error value must be in the range [-32767..0].
+ *
+ * Functionally equivalent to:
+ *
+ * condition ? if1 : 0.
+ *
+ * Functionally equivalent to mbedtls_ct_error_if(condition, if1, 0) but
+ * results in smaller code size.
+ *
+ * \param condition Condition to test.
+ * \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE.
+ *
+ * \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise 0.
+ */
+static inline int mbedtls_ct_error_if_else_0(mbedtls_ct_condition_t condition, int if1);
/* ============================================================================
* Block memory operations
@@ -492,6 +554,37 @@
size_t n);
*/
+#if defined(MBEDTLS_NIST_KW_C)
+
+/** Constant-time buffer comparison without branches.
+ *
+ * Similar to mbedtls_ct_memcmp, except that the result only depends on part of
+ * the input data - differences in the head or tail are ignored. Functionally equivalent to:
+ *
+ * memcmp(a + skip_head, b + skip_head, size - skip_head - skip_tail)
+ *
+ * Time taken depends on \p n, but not on \p skip_head or \p skip_tail .
+ *
+ * Behaviour is undefined if ( \p skip_head + \p skip_tail) > \p n.
+ *
+ * \param a Secret. Pointer to the first buffer, containing at least \p n bytes. May not be NULL.
+ * \param b Secret. Pointer to the second buffer, containing at least \p n bytes. May not be NULL.
+ * \param n The number of bytes to examine (total size of the buffers).
+ * \param skip_head Secret. The number of bytes to treat as non-significant at the start of the buffer.
+ * These bytes will still be read.
+ * \param skip_tail Secret. The number of bytes to treat as non-significant at the end of the buffer.
+ * These bytes will still be read.
+ *
+ * \return Zero if the contents of the two buffers are the same, otherwise non-zero.
+ */
+int mbedtls_ct_memcmp_partial(const void *a,
+ const void *b,
+ size_t n,
+ size_t skip_head,
+ size_t skip_tail);
+
+#endif
+
/* Include the implementation of static inline functions above. */
#include "constant_time_impl.h"
diff --git a/library/gcm.c b/library/gcm.c
index b06ca4a..c8618be 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 <string.h>
@@ -601,7 +602,6 @@
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
unsigned char check_tag[16];
- size_t i;
int diff;
if ((ret = mbedtls_gcm_crypt_and_tag(ctx, MBEDTLS_GCM_DECRYPT, length,
@@ -611,9 +611,7 @@
}
/* 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 fbd7221..7bdc807 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 <stdint.h>
#include <string.h>
@@ -333,9 +334,9 @@
unsigned char *output, size_t *out_len, size_t out_size)
{
int ret = 0;
- size_t i, olen;
+ size_t olen;
unsigned char A[KW_SEMIBLOCK_LENGTH];
- unsigned char diff, bad_padding = 0;
+ int diff;
*out_len = 0;
if (out_size < in_len - KW_SEMIBLOCK_LENGTH) {
@@ -420,19 +421,15 @@
* 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 = mbedtls_ct_error_if(mbedtls_ct_uint_gt(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];
- }
- }
+ const uint8_t zero[KW_SEMIBLOCK_LENGTH] = { 0 };
+ diff = mbedtls_ct_memcmp_partial(
+ &output[*out_len - KW_SEMIBLOCK_LENGTH], zero,
+ KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH - padlen, 0);
if (diff != 0) {
ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
@@ -454,7 +451,6 @@
*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/pk.c b/library/pk.c
index 03c1e35..96b8ef9 100644
--- a/library/pk.c
+++ b/library/pk.c
@@ -514,9 +514,11 @@
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
const mbedtls_pk_rsassa_pss_options *pss_opts;
+#if SIZE_MAX > UINT_MAX
if (md_alg == MBEDTLS_MD_NONE && UINT_MAX < hash_len) {
return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
}
+#endif
if (options == NULL) {
return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
diff --git a/library/pk_internal.h b/library/pk_internal.h
index 67ee5fe..004660e 100644
--- a/library/pk_internal.h
+++ b/library/pk_internal.h
@@ -117,5 +117,14 @@
#endif /* MBEDTLS_ECP_HAVE_CURVE25519 || MBEDTLS_ECP_DP_CURVE448 */
#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
+#if defined(MBEDTLS_TEST_HOOKS)
+
+MBEDTLS_STATIC_TESTABLE int mbedtls_pk_parse_key_pkcs8_encrypted_der(
+ mbedtls_pk_context *pk,
+ unsigned char *key, size_t keylen,
+ const unsigned char *pwd, size_t pwdlen,
+ int (*f_rng)(void *, unsigned char *, size_t), void *p_rng);
+
+#endif
#endif /* MBEDTLS_PK_INTERNAL_H */
diff --git a/library/pk_wrap.c b/library/pk_wrap.c
index e67138b..436876a 100644
--- a/library/pk_wrap.c
+++ b/library/pk_wrap.c
@@ -208,9 +208,11 @@
PSA_ALG_RSA_PKCS1V15_SIGN(mbedtls_md_psa_alg_from_type(md_alg));
size_t rsa_len = mbedtls_rsa_get_len(rsa);
+#if SIZE_MAX > UINT_MAX
if (md_alg == MBEDTLS_MD_NONE && UINT_MAX < hash_len) {
return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
}
+#endif
if (sig_len < rsa_len) {
return MBEDTLS_ERR_RSA_VERIFY_FAILED;
@@ -262,9 +264,11 @@
mbedtls_rsa_context *rsa = (mbedtls_rsa_context *) pk->pk_ctx;
size_t rsa_len = mbedtls_rsa_get_len(rsa);
+#if SIZE_MAX > UINT_MAX
if (md_alg == MBEDTLS_MD_NONE && UINT_MAX < hash_len) {
return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
}
+#endif
if (sig_len < rsa_len) {
return MBEDTLS_ERR_RSA_VERIFY_FAILED;
@@ -382,9 +386,11 @@
{
mbedtls_rsa_context *rsa = (mbedtls_rsa_context *) pk->pk_ctx;
+#if SIZE_MAX > UINT_MAX
if (md_alg == MBEDTLS_MD_NONE && UINT_MAX < hash_len) {
return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
}
+#endif
*sig_len = mbedtls_rsa_get_len(rsa);
if (sig_size < *sig_len) {
@@ -1565,9 +1571,11 @@
{
mbedtls_rsa_alt_context *rsa_alt = pk->pk_ctx;
+#if SIZE_MAX > UINT_MAX
if (UINT_MAX < hash_len) {
return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
}
+#endif
*sig_len = rsa_alt->key_len_func(rsa_alt->key);
if (*sig_len > MBEDTLS_PK_SIGNATURE_MAX_SIZE) {
diff --git a/library/pkcs12.c b/library/pkcs12.c
index db31722..4db2a4b 100644
--- a/library/pkcs12.c
+++ b/library/pkcs12.c
@@ -129,18 +129,49 @@
#undef PKCS12_MAX_PWDLEN
+#if !defined(MBEDTLS_CIPHER_PADDING_PKCS7)
+int mbedtls_pkcs12_pbe_ext(mbedtls_asn1_buf *pbe_params, int mode,
+ mbedtls_cipher_type_t cipher_type, mbedtls_md_type_t md_type,
+ const unsigned char *pwd, size_t pwdlen,
+ const unsigned char *data, size_t len,
+ unsigned char *output, size_t output_size,
+ size_t *output_len);
+#endif
+
+#if !defined(MBEDTLS_DEPRECATED_REMOVED)
int mbedtls_pkcs12_pbe(mbedtls_asn1_buf *pbe_params, int mode,
mbedtls_cipher_type_t cipher_type, mbedtls_md_type_t md_type,
const unsigned char *pwd, size_t pwdlen,
const unsigned char *data, size_t len,
unsigned char *output)
{
+ size_t output_len = 0;
+
+ /* We assume caller of the function is providing a big enough output buffer
+ * so we pass output_size as SIZE_MAX to pass checks, However, no guarantees
+ * for the output size actually being correct.
+ */
+ return mbedtls_pkcs12_pbe_ext(pbe_params, mode, cipher_type, md_type,
+ pwd, pwdlen, data, len, output, SIZE_MAX,
+ &output_len);
+}
+#endif
+
+int mbedtls_pkcs12_pbe_ext(mbedtls_asn1_buf *pbe_params, int mode,
+ mbedtls_cipher_type_t cipher_type, mbedtls_md_type_t md_type,
+ const unsigned char *pwd, size_t pwdlen,
+ const unsigned char *data, size_t len,
+ unsigned char *output, size_t output_size,
+ size_t *output_len)
+{
int ret, keylen = 0;
unsigned char key[32];
unsigned char iv[16];
const mbedtls_cipher_info_t *cipher_info;
mbedtls_cipher_context_t cipher_ctx;
- size_t olen = 0;
+ size_t iv_len = 0;
+ size_t finish_olen = 0;
+ unsigned int padlen = 0;
if (pwd == NULL && pwdlen != 0) {
return MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA;
@@ -153,9 +184,23 @@
keylen = (int) mbedtls_cipher_info_get_key_bitlen(cipher_info) / 8;
+ if (mode == MBEDTLS_PKCS12_PBE_DECRYPT) {
+ if (output_size < len) {
+ return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
+ }
+ }
+
+ if (mode == MBEDTLS_PKCS12_PBE_ENCRYPT) {
+ padlen = cipher_info->block_size - (len % cipher_info->block_size);
+ if (output_size < (len + padlen)) {
+ return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
+ }
+ }
+
+ iv_len = mbedtls_cipher_info_get_iv_size(cipher_info);
if ((ret = pkcs12_pbe_derive_key_iv(pbe_params, md_type, pwd, pwdlen,
key, keylen,
- iv, mbedtls_cipher_info_get_iv_size(cipher_info))) != 0) {
+ iv, iv_len)) != 0) {
return ret;
}
@@ -165,31 +210,37 @@
goto exit;
}
- if ((ret =
- mbedtls_cipher_setkey(&cipher_ctx, key, 8 * keylen,
- (mbedtls_operation_t) mode)) != 0) {
+ if ((ret = mbedtls_cipher_setkey(&cipher_ctx, key, 8 * keylen,
+ (mbedtls_operation_t) mode)) != 0) {
goto exit;
}
- if ((ret =
- mbedtls_cipher_set_iv(&cipher_ctx, iv,
- mbedtls_cipher_info_get_iv_size(cipher_info))) != 0) {
+#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING)
+ /* PKCS12 uses CBC with PKCS7 padding */
+
+ mbedtls_cipher_padding_t padding = MBEDTLS_PADDING_PKCS7;
+#if !defined(MBEDTLS_CIPHER_PADDING_PKCS7)
+ /* For historical reasons, when decrypting, this function works when
+ * decrypting even when support for PKCS7 padding is disabled. In this
+ * case, it ignores the padding, and so will never report a
+ * password mismatch.
+ */
+ if (mode == MBEDTLS_PKCS12_PBE_DECRYPT) {
+ padding = MBEDTLS_PADDING_NONE;
+ }
+#endif
+ if ((ret = mbedtls_cipher_set_padding_mode(&cipher_ctx, padding)) != 0) {
goto exit;
}
+#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */
- if ((ret = mbedtls_cipher_reset(&cipher_ctx)) != 0) {
- goto exit;
- }
-
- if ((ret = mbedtls_cipher_update(&cipher_ctx, data, len,
- output, &olen)) != 0) {
- goto exit;
- }
-
- if ((ret = mbedtls_cipher_finish(&cipher_ctx, output + olen, &olen)) != 0) {
+ ret = mbedtls_cipher_crypt(&cipher_ctx, iv, iv_len, data, len, output, &finish_olen);
+ if (ret == MBEDTLS_ERR_CIPHER_INVALID_PADDING) {
ret = MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH;
}
+ *output_len += finish_olen;
+
exit:
mbedtls_platform_zeroize(key, sizeof(key));
mbedtls_platform_zeroize(iv, sizeof(iv));
diff --git a/library/pkcs5.c b/library/pkcs5.c
index 5d415ca..2756d05 100644
--- a/library/pkcs5.c
+++ b/library/pkcs5.c
@@ -111,21 +111,47 @@
return 0;
}
+#if !defined(MBEDTLS_CIPHER_PADDING_PKCS7)
+int mbedtls_pkcs5_pbes2_ext(const mbedtls_asn1_buf *pbe_params, int mode,
+ const unsigned char *pwd, size_t pwdlen,
+ const unsigned char *data, size_t datalen,
+ unsigned char *output, size_t output_size,
+ size_t *output_len);
+#endif
+
+#if !defined(MBEDTLS_DEPRECATED_REMOVED)
int mbedtls_pkcs5_pbes2(const mbedtls_asn1_buf *pbe_params, int mode,
const unsigned char *pwd, size_t pwdlen,
const unsigned char *data, size_t datalen,
unsigned char *output)
{
+ size_t output_len = 0;
+
+ /* We assume caller of the function is providing a big enough output buffer
+ * so we pass output_size as SIZE_MAX to pass checks, However, no guarantees
+ * for the output size actually being correct.
+ */
+ return mbedtls_pkcs5_pbes2_ext(pbe_params, mode, pwd, pwdlen, data,
+ datalen, output, SIZE_MAX, &output_len);
+}
+#endif
+
+int mbedtls_pkcs5_pbes2_ext(const mbedtls_asn1_buf *pbe_params, int mode,
+ const unsigned char *pwd, size_t pwdlen,
+ const unsigned char *data, size_t datalen,
+ unsigned char *output, size_t output_size,
+ size_t *output_len)
+{
int ret, iterations = 0, keylen = 0;
unsigned char *p, *end;
mbedtls_asn1_buf kdf_alg_oid, enc_scheme_oid, kdf_alg_params, enc_scheme_params;
mbedtls_asn1_buf salt;
mbedtls_md_type_t md_type = MBEDTLS_MD_SHA1;
unsigned char key[32], iv[32];
- size_t olen = 0;
const mbedtls_cipher_info_t *cipher_info;
mbedtls_cipher_type_t cipher_alg;
mbedtls_cipher_context_t cipher_ctx;
+ unsigned int padlen = 0;
p = pbe_params->p;
end = p + pbe_params->len;
@@ -183,6 +209,19 @@
return MBEDTLS_ERR_PKCS5_INVALID_FORMAT;
}
+ if (mode == MBEDTLS_PKCS5_DECRYPT) {
+ if (output_size < datalen) {
+ return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
+ }
+ }
+
+ if (mode == MBEDTLS_PKCS5_ENCRYPT) {
+ padlen = cipher_info->block_size - (datalen % cipher_info->block_size);
+ if (output_size < (datalen + padlen)) {
+ return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
+ }
+ }
+
mbedtls_cipher_init(&cipher_ctx);
memcpy(iv, enc_scheme_params.p, enc_scheme_params.len);
@@ -202,8 +241,28 @@
goto exit;
}
+#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING)
+ /* PKCS5 uses CBC with PKCS7 padding (which is the same as
+ * "PKCS5 padding" except that it's typically only called PKCS5
+ * with 64-bit-block ciphers).
+ */
+ mbedtls_cipher_padding_t padding = MBEDTLS_PADDING_PKCS7;
+#if !defined(MBEDTLS_CIPHER_PADDING_PKCS7)
+ /* For historical reasons, when decrypting, this function works when
+ * decrypting even when support for PKCS7 padding is disabled. In this
+ * case, it ignores the padding, and so will never report a
+ * password mismatch.
+ */
+ if (mode == MBEDTLS_DECRYPT) {
+ padding = MBEDTLS_PADDING_NONE;
+ }
+#endif
+ if ((ret = mbedtls_cipher_set_padding_mode(&cipher_ctx, padding)) != 0) {
+ goto exit;
+ }
+#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */
if ((ret = mbedtls_cipher_crypt(&cipher_ctx, iv, enc_scheme_params.len,
- data, datalen, output, &olen)) != 0) {
+ data, datalen, output, output_len)) != 0) {
ret = MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH;
}
diff --git a/library/pkparse.c b/library/pkparse.c
index 83291c4..e1422df 100644
--- a/library/pkparse.c
+++ b/library/pkparse.c
@@ -1417,6 +1417,12 @@
#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
return MBEDTLS_ERR_PK_UNKNOWN_PK_ALG;
+ end = p + len;
+ if (end != (key + keylen)) {
+ return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT,
+ MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
+ }
+
return 0;
}
@@ -1430,7 +1436,7 @@
*
*/
#if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C)
-static int pk_parse_key_pkcs8_encrypted_der(
+MBEDTLS_STATIC_TESTABLE int mbedtls_pk_parse_key_pkcs8_encrypted_der(
mbedtls_pk_context *pk,
unsigned char *key, size_t keylen,
const unsigned char *pwd, size_t pwdlen,
@@ -1445,6 +1451,7 @@
mbedtls_cipher_type_t cipher_alg;
mbedtls_md_type_t md_alg;
#endif
+ size_t outlen = 0;
p = key;
end = p + keylen;
@@ -1490,9 +1497,9 @@
*/
#if defined(MBEDTLS_PKCS12_C)
if (mbedtls_oid_get_pkcs12_pbe_alg(&pbe_alg_oid, &md_alg, &cipher_alg) == 0) {
- if ((ret = mbedtls_pkcs12_pbe(&pbe_params, MBEDTLS_PKCS12_PBE_DECRYPT,
- cipher_alg, md_alg,
- pwd, pwdlen, p, len, buf)) != 0) {
+ if ((ret = mbedtls_pkcs12_pbe_ext(&pbe_params, MBEDTLS_PKCS12_PBE_DECRYPT,
+ cipher_alg, md_alg,
+ pwd, pwdlen, p, len, buf, len, &outlen)) != 0) {
if (ret == MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH) {
return MBEDTLS_ERR_PK_PASSWORD_MISMATCH;
}
@@ -1505,8 +1512,8 @@
#endif /* MBEDTLS_PKCS12_C */
#if defined(MBEDTLS_PKCS5_C)
if (MBEDTLS_OID_CMP(MBEDTLS_OID_PKCS5_PBES2, &pbe_alg_oid) == 0) {
- if ((ret = mbedtls_pkcs5_pbes2(&pbe_params, MBEDTLS_PKCS5_DECRYPT, pwd, pwdlen,
- p, len, buf)) != 0) {
+ if ((ret = mbedtls_pkcs5_pbes2_ext(&pbe_params, MBEDTLS_PKCS5_DECRYPT, pwd, pwdlen,
+ p, len, buf, len, &outlen)) != 0) {
if (ret == MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH) {
return MBEDTLS_ERR_PK_PASSWORD_MISMATCH;
}
@@ -1524,8 +1531,7 @@
if (decrypted == 0) {
return MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE;
}
-
- return pk_parse_key_pkcs8_unencrypted_der(pk, buf, len, f_rng, p_rng);
+ return pk_parse_key_pkcs8_unencrypted_der(pk, buf, outlen, f_rng, p_rng);
}
#endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */
@@ -1644,8 +1650,8 @@
key, NULL, 0, &len);
}
if (ret == 0) {
- if ((ret = pk_parse_key_pkcs8_encrypted_der(pk, pem.buf, pem.buflen,
- pwd, pwdlen, f_rng, p_rng)) != 0) {
+ if ((ret = mbedtls_pk_parse_key_pkcs8_encrypted_der(pk, pem.buf, pem.buflen,
+ pwd, pwdlen, f_rng, p_rng)) != 0) {
mbedtls_pk_free(pk);
}
@@ -1677,8 +1683,8 @@
memcpy(key_copy, key, keylen);
- ret = pk_parse_key_pkcs8_encrypted_der(pk, key_copy, keylen,
- pwd, pwdlen, f_rng, p_rng);
+ ret = mbedtls_pk_parse_key_pkcs8_encrypted_der(pk, key_copy, keylen,
+ pwd, pwdlen, f_rng, p_rng);
mbedtls_zeroize_and_free(key_copy, keylen);
}
diff --git a/library/psa_crypto_core.h b/library/psa_crypto_core.h
index 575f302..29b3b94 100644
--- a/library/psa_crypto_core.h
+++ b/library/psa_crypto_core.h
@@ -21,7 +21,14 @@
#ifndef PSA_CRYPTO_CORE_H
#define PSA_CRYPTO_CORE_H
-#include "mbedtls/build_info.h"
+/*
+ * Include the build-time configuration information header. Here, we do not
+ * include `"mbedtls/build_info.h"` directly but `"psa/build_info.h"`, which
+ * is basically just an alias to it. This is to ease the maintenance of the
+ * TF-PSA-Crypto repository which has a different build system and
+ * configuration.
+ */
+#include "psa/build_info.h"
#include "psa/crypto.h"
#include "psa/crypto_se_driver.h"
diff --git a/library/psa_crypto_invasive.h b/library/psa_crypto_invasive.h
index a900dd8..408c39b 100644
--- a/library/psa_crypto_invasive.h
+++ b/library/psa_crypto_invasive.h
@@ -28,7 +28,14 @@
#ifndef PSA_CRYPTO_INVASIVE_H
#define PSA_CRYPTO_INVASIVE_H
-#include "mbedtls/build_info.h"
+/*
+ * Include the build-time configuration information header. Here, we do not
+ * include `"mbedtls/build_info.h"` directly but `"psa/build_info.h"`, which
+ * is basically just an alias to it. This is to ease the maintenance of the
+ * TF-PSA-Crypto repository which has a different build system and
+ * configuration.
+ */
+#include "psa/build_info.h"
#include "psa/crypto.h"
#include "common.h"
diff --git a/library/psa_crypto_pake.c b/library/psa_crypto_pake.c
index 7a904d9..db00cbd 100644
--- a/library/psa_crypto_pake.c
+++ b/library/psa_crypto_pake.c
@@ -304,10 +304,10 @@
#if defined(MBEDTLS_PSA_BUILTIN_ALG_JPAKE)
/*
- * The PSA CRYPTO PAKE and MbedTLS JPAKE API have a different
+ * The PSA CRYPTO PAKE and Mbed TLS JPAKE API have a different
* handling of output sequencing.
*
- * The MbedTLS JPAKE API outputs the whole X1+X2 and X2S steps data
+ * The Mbed TLS JPAKE API outputs the whole X1+X2 and X2S steps data
* at once, on the other side the PSA CRYPTO PAKE api requires
* the KEY_SHARE/ZP_PUBLIC/ZK_PROOF parts of X1, X2 & X2S to be
* retrieved in sequence.
@@ -423,17 +423,17 @@
#if defined(MBEDTLS_PSA_BUILTIN_ALG_JPAKE)
/*
- * The PSA CRYPTO PAKE and MbedTLS JPAKE API have a different
+ * The PSA CRYPTO PAKE and Mbed TLS JPAKE API have a different
* handling of input sequencing.
*
- * The MbedTLS JPAKE API takes the whole X1+X2 or X4S steps data
+ * The Mbed TLS JPAKE API takes the whole X1+X2 or X4S steps data
* at once as input, on the other side the PSA CRYPTO PAKE api requires
* the KEY_SHARE/ZP_PUBLIC/ZK_PROOF parts of X1, X2 & X4S to be
* given in sequence.
*
* In order to achieve API compatibility, each X1+X2 or X4S step data
* is stored sequentially in an intermediate buffer and given to the
- * MbedTLS JPAKE API on the last step.
+ * Mbed TLS JPAKE API on the last step.
*
* This causes any input error to be only detected on the last step.
*/
diff --git a/library/psa_crypto_rsa.c b/library/psa_crypto_rsa.c
index 508a68b..065e55a 100644
--- a/library/psa_crypto_rsa.c
+++ b/library/psa_crypto_rsa.c
@@ -328,9 +328,11 @@
/* The Mbed TLS RSA module uses an unsigned int for hash length
* parameters. Validate that it fits so that we don't risk an
* overflow later. */
+#if SIZE_MAX > UINT_MAX
if (hash_length > UINT_MAX) {
return PSA_ERROR_INVALID_ARGUMENT;
}
+#endif
/* For signatures using a hash, the hash length must be correct. */
if (alg != PSA_ALG_RSA_PKCS1V15_SIGN_RAW) {
diff --git a/library/psa_crypto_se.h b/library/psa_crypto_se.h
index a1e5e09..850ea8f 100644
--- a/library/psa_crypto_se.h
+++ b/library/psa_crypto_se.h
@@ -21,7 +21,14 @@
#ifndef PSA_CRYPTO_SE_H
#define PSA_CRYPTO_SE_H
-#include "mbedtls/build_info.h"
+/*
+ * Include the build-time configuration information header. Here, we do not
+ * include `"mbedtls/build_info.h"` directly but `"psa/build_info.h"`, which
+ * is basically just an alias to it. This is to ease the maintenance of the
+ * TF-PSA-Crypto repository which has a different build system and
+ * configuration.
+ */
+#include "psa/build_info.h"
#include "psa/crypto.h"
#include "psa/crypto_se_driver.h"
diff --git a/library/rsa.c b/library/rsa.c
index d0782f5..3c538bf 100644
--- a/library/rsa.c
+++ b/library/rsa.c
@@ -158,12 +158,10 @@
* - OUTPUT_TOO_LARGE if the padding is good but the decrypted
* plaintext does not fit in the output buffer.
* - 0 if the padding is correct. */
- ret = -(int) mbedtls_ct_uint_if(
+ ret = mbedtls_ct_error_if(
bad,
- (unsigned) (-(MBEDTLS_ERR_RSA_INVALID_PADDING)),
- mbedtls_ct_uint_if_else_0(
- output_too_large,
- (unsigned) (-(MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE)))
+ MBEDTLS_ERR_RSA_INVALID_PADDING,
+ mbedtls_ct_error_if_else_0(output_too_large, MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE)
);
/* If the padding is bad or the plaintext is too large, zero the
@@ -1541,7 +1539,8 @@
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t ilen, i, pad_len;
- unsigned char *p, bad, pad_done;
+ unsigned char *p;
+ mbedtls_ct_condition_t bad, in_padding;
unsigned char buf[MBEDTLS_MPI_MAX_SIZE];
unsigned char lhash[MBEDTLS_MD_MAX_SIZE];
unsigned int hlen;
@@ -1601,28 +1600,26 @@
* Check contents, in "constant-time"
*/
p = buf;
- bad = 0;
- bad |= *p++; /* First byte must be 0 */
+ bad = mbedtls_ct_bool(*p++); /* First byte must be 0 */
p += hlen; /* Skip seed */
/* Check lHash */
- for (i = 0; i < hlen; i++) {
- bad |= lhash[i] ^ *p++;
- }
+ bad = mbedtls_ct_bool_or(bad, mbedtls_ct_bool(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) */
pad_len = 0;
- pad_done = 0;
+ in_padding = MBEDTLS_CT_TRUE;
for (i = 0; i < ilen - 2 * hlen - 2; i++) {
- pad_done |= p[i];
- pad_len += ((pad_done | (unsigned char) -pad_done) >> 7) ^ 1;
+ in_padding = mbedtls_ct_bool_and(in_padding, mbedtls_ct_uint_eq(p[i], 0));
+ pad_len += mbedtls_ct_uint_if_else_0(in_padding, 1);
}
p += pad_len;
- bad |= *p++ ^ 0x01;
+ bad = mbedtls_ct_bool_or(bad, mbedtls_ct_uint_ne(*p++, 0x01));
/*
* The only information "leaked" is whether the padding was correct or not
@@ -1630,7 +1627,7 @@
* recommendations in PKCS#1 v2.2: an opponent cannot distinguish between
* the different error conditions.
*/
- if (bad != 0) {
+ if (bad != MBEDTLS_CT_FALSE) {
ret = MBEDTLS_ERR_RSA_INVALID_PADDING;
goto cleanup;
}
diff --git a/library/sha256.c b/library/sha256.c
index 5375255..223badf 100644
--- a/library/sha256.c
+++ b/library/sha256.c
@@ -681,6 +681,7 @@
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
uint32_t used;
uint32_t high, low;
+ int truncated = 0;
/*
* Add padding: 0x80 then 0x00 until 8 bytes remain for the length
@@ -728,7 +729,6 @@
MBEDTLS_PUT_UINT32_BE(ctx->state[5], output, 20);
MBEDTLS_PUT_UINT32_BE(ctx->state[6], output, 24);
- int truncated = 0;
#if defined(MBEDTLS_SHA224_C)
truncated = ctx->is224;
#endif
diff --git a/library/sha512.c b/library/sha512.c
index a91d792..e739af2 100644
--- a/library/sha512.c
+++ b/library/sha512.c
@@ -828,6 +828,7 @@
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
unsigned used;
uint64_t high, low;
+ int truncated = 0;
/*
* Add padding: 0x80 then 0x00 until 16 bytes remain for the length
@@ -874,7 +875,6 @@
sha512_put_uint64_be(ctx->state[4], output, 32);
sha512_put_uint64_be(ctx->state[5], output, 40);
- int truncated = 0;
#if defined(MBEDTLS_SHA384_C)
truncated = ctx->is384;
#endif
diff --git a/library/ssl_ciphersuites.c b/library/ssl_ciphersuites.c
index 736b142..2368489 100644
--- a/library/ssl_ciphersuites.c
+++ b/library/ssl_ciphersuites.c
@@ -1920,7 +1920,7 @@
psa_algorithm_t alg;
size_t key_bits;
- status = mbedtls_ssl_cipher_to_psa(info->cipher,
+ status = mbedtls_ssl_cipher_to_psa((mbedtls_cipher_type_t) info->cipher,
info->flags & MBEDTLS_CIPHERSUITE_SHORT_TAG ? 8 : 16,
&alg, &key_type, &key_bits);
@@ -1969,10 +1969,10 @@
case MBEDTLS_KEY_EXCHANGE_DHE_RSA:
case MBEDTLS_KEY_EXCHANGE_ECDHE_RSA:
return PSA_ALG_RSA_PKCS1V15_SIGN(
- mbedtls_md_psa_alg_from_type(info->mac));
+ mbedtls_md_psa_alg_from_type((mbedtls_md_type_t) info->mac));
case MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA:
- return PSA_ALG_ECDSA(mbedtls_md_psa_alg_from_type(info->mac));
+ return PSA_ALG_ECDSA(mbedtls_md_psa_alg_from_type((mbedtls_md_type_t) info->mac));
case MBEDTLS_KEY_EXCHANGE_ECDH_RSA:
case MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA:
diff --git a/library/ssl_msg.c b/library/ssl_msg.c
index 47a206d..c312d81 100644
--- a/library/ssl_msg.c
+++ b/library/ssl_msg.c
@@ -1547,8 +1547,16 @@
#if defined(MBEDTLS_SSL_SOME_SUITES_USE_STREAM)
if (ssl_mode == MBEDTLS_SSL_MODE_STREAM) {
+ if (rec->data_len < transform->maclen) {
+ MBEDTLS_SSL_DEBUG_MSG(1,
+ ("Record too short for MAC:"
+ " %" MBEDTLS_PRINTF_SIZET " < %" MBEDTLS_PRINTF_SIZET,
+ rec->data_len, transform->maclen));
+ return MBEDTLS_ERR_SSL_INVALID_MAC;
+ }
+
/* The only supported stream cipher is "NULL",
- * so there's nothing to do here.*/
+ * so there's no encryption to do here.*/
} else
#endif /* MBEDTLS_SSL_SOME_SUITES_USE_STREAM */
#if defined(MBEDTLS_GCM_C) || \
@@ -2011,7 +2019,7 @@
unsigned char mac_expect[MBEDTLS_SSL_MAC_ADD] = { 0 };
unsigned char mac_peer[MBEDTLS_SSL_MAC_ADD] = { 0 };
- /* If the initial value of padlen was such that
+ /* For CBC+MAC, If the initial value of padlen was such that
* data_len < maclen + padlen + 1, then padlen
* got reset to 1, and the initial check
* data_len >= minlen + maclen + 1
@@ -2023,6 +2031,9 @@
* subtracted either padlen + 1 (if the padding was correct)
* or 0 (if the padding was incorrect) since then,
* hence data_len >= maclen in any case.
+ *
+ * For stream ciphers, we checked above that
+ * data_len >= maclen.
*/
rec->data_len -= transform->maclen;
ssl_extract_add_data_from_record(add_data, &add_data_len, rec,
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index fc3fb85..d3a7ddb 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -2427,7 +2427,8 @@
psa_algorithm_t alg;
psa_key_type_t type;
size_t size;
- status = mbedtls_ssl_cipher_to_psa(suite->cipher, 0, &alg, &type, &size);
+ status = mbedtls_ssl_cipher_to_psa((mbedtls_cipher_type_t) suite->cipher,
+ 0, &alg, &type, &size);
if (status == PSA_SUCCESS) {
base_mode = mbedtls_ssl_get_base_mode(alg);
}
@@ -6406,7 +6407,7 @@
mbedtls_svc_key_id_t psk;
psa_key_derivation_operation_t derivation =
PSA_KEY_DERIVATION_OPERATION_INIT;
- mbedtls_md_type_t hash_alg = handshake->ciphersuite_info->mac;
+ mbedtls_md_type_t hash_alg = (mbedtls_md_type_t) handshake->ciphersuite_info->mac;
MBEDTLS_SSL_DEBUG_MSG(2, ("perform PSA-based PSK-to-MS expansion"));
@@ -8208,7 +8209,7 @@
}
#if defined(MBEDTLS_USE_PSA_CRYPTO)
- if ((status = mbedtls_ssl_cipher_to_psa(ciphersuite_info->cipher,
+ if ((status = mbedtls_ssl_cipher_to_psa((mbedtls_cipher_type_t) ciphersuite_info->cipher,
transform->taglen,
&alg,
&key_type,
@@ -8227,7 +8228,7 @@
#endif /* MBEDTLS_USE_PSA_CRYPTO */
#if defined(MBEDTLS_USE_PSA_CRYPTO)
- mac_alg = mbedtls_md_psa_alg_from_type(ciphersuite_info->mac);
+ mac_alg = mbedtls_md_psa_alg_from_type((mbedtls_md_type_t) ciphersuite_info->mac);
if (mac_alg == 0) {
MBEDTLS_SSL_DEBUG_MSG(1, ("mbedtls_md_psa_alg_from_type for %u not found",
(unsigned) ciphersuite_info->mac));
diff --git a/library/ssl_tls12_client.c b/library/ssl_tls12_client.c
index cc22a3f..27bbafa 100644
--- a/library/ssl_tls12_client.c
+++ b/library/ssl_tls12_client.c
@@ -1727,7 +1727,7 @@
unsigned char *end)
{
uint16_t tls_id;
- uint8_t ecpoint_len;
+ size_t ecpoint_len;
mbedtls_ssl_handshake_params *handshake = ssl->handshake;
psa_key_type_t key_type = PSA_KEY_TYPE_NONE;
size_t ec_bits = 0;
@@ -1779,7 +1779,7 @@
return MBEDTLS_ERR_SSL_DECODE_ERROR;
}
- if (ecpoint_len > PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_ECC_MAX_CURVE_BITS)) {
+ if (ecpoint_len > sizeof(handshake->xxdh_psa_peerkey)) {
return MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE;
}
@@ -2059,7 +2059,7 @@
ret = mbedtls_ecp_point_write_binary(&peer_key->grp, &peer_key->Q,
MBEDTLS_ECP_PF_UNCOMPRESSED, &olen,
ssl->handshake->xxdh_psa_peerkey,
- MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH);
+ sizeof(ssl->handshake->xxdh_psa_peerkey));
if (ret != 0) {
MBEDTLS_SSL_DEBUG_RET(1, ("mbedtls_ecp_point_write_binary"), ret);
diff --git a/library/ssl_tls12_server.c b/library/ssl_tls12_server.c
index d2143ac..6ebd506 100644
--- a/library/ssl_tls12_server.c
+++ b/library/ssl_tls12_server.c
@@ -3718,22 +3718,32 @@
psa_status_t status = PSA_ERROR_GENERIC_ERROR;
mbedtls_ssl_handshake_params *handshake = ssl->handshake;
- MBEDTLS_SSL_DEBUG_MSG(1, ("Read the peer's public key."));
+ MBEDTLS_SSL_DEBUG_MSG(3, ("Read the peer's public key."));
/*
* We must have at least two bytes (1 for length, at least 1 for data)
*/
if (buf_len < 2) {
- MBEDTLS_SSL_DEBUG_MSG(1, ("Invalid buffer length"));
- return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
+ MBEDTLS_SSL_DEBUG_MSG(1, ("Invalid buffer length: %" MBEDTLS_PRINTF_SIZET,
+ buf_len));
+ return MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE;
}
if (data_len < 1 || data_len > buf_len) {
- MBEDTLS_SSL_DEBUG_MSG(1, ("Invalid data length"));
- return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
+ MBEDTLS_SSL_DEBUG_MSG(1, ("Invalid data length: %" MBEDTLS_PRINTF_SIZET
+ " > %" MBEDTLS_PRINTF_SIZET,
+ data_len, buf_len));
+ return MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE;
}
/* Store peer's ECDH public key. */
+ if (data_len > sizeof(handshake->xxdh_psa_peerkey)) {
+ MBEDTLS_SSL_DEBUG_MSG(1, ("Invalid public key length: %" MBEDTLS_PRINTF_SIZET
+ " > %" MBEDTLS_PRINTF_SIZET,
+ data_len,
+ sizeof(handshake->xxdh_psa_peerkey)));
+ return MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE;
+ }
memcpy(handshake->xxdh_psa_peerkey, p, data_len);
handshake->xxdh_psa_peerkey_len = data_len;
diff --git a/library/ssl_tls13_client.c b/library/ssl_tls13_client.c
index d018bee..c6fa3b3 100644
--- a/library/ssl_tls13_client.c
+++ b/library/ssl_tls13_client.c
@@ -686,7 +686,7 @@
ciphersuite_info = mbedtls_ssl_ciphersuite_from_id(ciphersuite);
if (ciphersuite_info != NULL) {
- return mbedtls_md_psa_alg_from_type(ciphersuite_info->mac);
+ return mbedtls_md_psa_alg_from_type((mbedtls_md_type_t) ciphersuite_info->mac);
}
return PSA_ALG_NONE;
@@ -1140,7 +1140,7 @@
return ret;
}
- if (mbedtls_md_psa_alg_from_type(ssl->handshake->ciphersuite_info->mac)
+ if (mbedtls_md_psa_alg_from_type((mbedtls_md_type_t) ssl->handshake->ciphersuite_info->mac)
!= hash_alg) {
MBEDTLS_SSL_DEBUG_MSG(
1, ("Invalid ciphersuite for external psk."));
@@ -2858,7 +2858,7 @@
return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
}
- psa_hash_alg = mbedtls_md_psa_alg_from_type(ciphersuite_info->mac);
+ psa_hash_alg = mbedtls_md_psa_alg_from_type((mbedtls_md_type_t) ciphersuite_info->mac);
hash_length = PSA_HASH_LENGTH(psa_hash_alg);
if (hash_length == -1 ||
(size_t) hash_length > sizeof(session->resumption_key)) {
diff --git a/library/ssl_tls13_generic.c b/library/ssl_tls13_generic.c
index 81fa514..3c8d448 100644
--- a/library/ssl_tls13_generic.c
+++ b/library/ssl_tls13_generic.c
@@ -369,7 +369,7 @@
*/
ret = mbedtls_ssl_get_handshake_transcript(
ssl,
- ssl->handshake->ciphersuite_info->mac,
+ (mbedtls_md_type_t) ssl->handshake->ciphersuite_info->mac,
transcript, sizeof(transcript),
&transcript_len);
if (ret != 0) {
@@ -967,7 +967,7 @@
int mbedtls_ssl_tls13_check_sig_alg_cert_key_match(uint16_t sig_alg,
mbedtls_pk_context *key)
{
- mbedtls_pk_type_t pk_type = mbedtls_ssl_sig_from_pk(key);
+ mbedtls_pk_type_t pk_type = (mbedtls_pk_type_t) mbedtls_ssl_sig_from_pk(key);
size_t key_size = mbedtls_pk_get_bitlen(key);
switch (pk_type) {
@@ -1035,7 +1035,7 @@
}
ret = mbedtls_ssl_get_handshake_transcript(
- ssl, ssl->handshake->ciphersuite_info->mac,
+ ssl, (mbedtls_md_type_t) ssl->handshake->ciphersuite_info->mac,
handshake_hash, sizeof(handshake_hash), &handshake_hash_len);
if (ret != 0) {
return ret;
@@ -1464,7 +1464,7 @@
MBEDTLS_SSL_DEBUG_MSG(3, ("Reset SSL session for HRR"));
- ret = mbedtls_ssl_get_handshake_transcript(ssl, ciphersuite_info->mac,
+ ret = mbedtls_ssl_get_handshake_transcript(ssl, (mbedtls_md_type_t) ciphersuite_info->mac,
hash_transcript + 4,
PSA_HASH_MAX_SIZE,
&hash_len);
@@ -1516,7 +1516,13 @@
/* Check if key size is consistent with given buffer length. */
MBEDTLS_SSL_CHK_BUF_READ_PTR(p, end, peerkey_len);
- /* Store peer's ECDH public key. */
+ /* Store peer's ECDH/FFDH public key. */
+ if (peerkey_len > sizeof(handshake->xxdh_psa_peerkey)) {
+ MBEDTLS_SSL_DEBUG_MSG(1, ("Invalid public key length: %u > %" MBEDTLS_PRINTF_SIZET,
+ (unsigned) peerkey_len,
+ sizeof(handshake->xxdh_psa_peerkey)));
+ return MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE;
+ }
memcpy(handshake->xxdh_psa_peerkey, p, peerkey_len);
handshake->xxdh_psa_peerkey_len = peerkey_len;
diff --git a/library/ssl_tls13_keys.c b/library/ssl_tls13_keys.c
index afd84a9..6905d92 100644
--- a/library/ssl_tls13_keys.c
+++ b/library/ssl_tls13_keys.c
@@ -685,7 +685,7 @@
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_ssl_handshake_params *handshake = ssl->handshake;
psa_algorithm_t const hash_alg = mbedtls_md_psa_alg_from_type(
- handshake->ciphersuite_info->mac);
+ (mbedtls_md_type_t) handshake->ciphersuite_info->mac);
/*
* Compute MasterSecret
@@ -797,10 +797,10 @@
mbedtls_ssl_tls13_handshake_secrets *tls13_hs_secrets =
&ssl->handshake->tls13_hs_secrets;
- mbedtls_md_type_t const md_type = ssl->handshake->ciphersuite_info->mac;
+ mbedtls_md_type_t const md_type = (mbedtls_md_type_t) ssl->handshake->ciphersuite_info->mac;
psa_algorithm_t hash_alg = mbedtls_md_psa_alg_from_type(
- ssl->handshake->ciphersuite_info->mac);
+ (mbedtls_md_type_t) ssl->handshake->ciphersuite_info->mac);
size_t const hash_len = PSA_HASH_LENGTH(hash_alg);
MBEDTLS_SSL_DEBUG_MSG(2, ("=> mbedtls_ssl_tls13_calculate_verify_data"));
@@ -1059,7 +1059,7 @@
/*
* Setup psa keys and alg
*/
- if ((status = mbedtls_ssl_cipher_to_psa(ciphersuite_info->cipher,
+ if ((status = mbedtls_ssl_cipher_to_psa((mbedtls_cipher_type_t) ciphersuite_info->cipher,
transform->taglen,
&alg,
&key_type,
@@ -1118,7 +1118,7 @@
taglen = 16;
}
- status = mbedtls_ssl_cipher_to_psa(ciphersuite_info->cipher, taglen,
+ status = mbedtls_ssl_cipher_to_psa((mbedtls_cipher_type_t) ciphersuite_info->cipher, taglen,
&alg, &key_type, &key_bits);
if (status != PSA_SUCCESS) {
return PSA_TO_MBEDTLS_ERR(status);
@@ -1168,9 +1168,9 @@
goto cleanup;
}
- md_type = ciphersuite_info->mac;
+ md_type = (mbedtls_md_type_t) ciphersuite_info->mac;
- hash_alg = mbedtls_md_psa_alg_from_type(ciphersuite_info->mac);
+ hash_alg = mbedtls_md_psa_alg_from_type((mbedtls_md_type_t) ciphersuite_info->mac);
hash_len = PSA_HASH_LENGTH(hash_alg);
ret = mbedtls_ssl_get_handshake_transcript(ssl, md_type,
@@ -1298,7 +1298,7 @@
return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
}
- hash_alg = mbedtls_md_psa_alg_from_type(handshake->ciphersuite_info->mac);
+ hash_alg = mbedtls_md_psa_alg_from_type((mbedtls_md_type_t) handshake->ciphersuite_info->mac);
#if defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_SOME_PSK_ENABLED)
if (mbedtls_ssl_tls13_key_exchange_mode_with_psk(ssl)) {
ret = mbedtls_ssl_tls13_export_handshake_psk(ssl, &psk, &psk_len);
@@ -1370,9 +1370,9 @@
return ret;
}
- md_type = ciphersuite_info->mac;
+ md_type = (mbedtls_md_type_t) ciphersuite_info->mac;
- hash_alg = mbedtls_md_psa_alg_from_type(ciphersuite_info->mac);
+ hash_alg = mbedtls_md_psa_alg_from_type((mbedtls_md_type_t) ciphersuite_info->mac);
hash_len = PSA_HASH_LENGTH(hash_alg);
ret = mbedtls_ssl_get_handshake_transcript(ssl, md_type,
@@ -1480,7 +1480,7 @@
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_ssl_handshake_params *handshake = ssl->handshake;
psa_algorithm_t const hash_alg = mbedtls_md_psa_alg_from_type(
- handshake->ciphersuite_info->mac);
+ (mbedtls_md_type_t) handshake->ciphersuite_info->mac);
unsigned char *shared_secret = NULL;
size_t shared_secret_len = 0;
@@ -1617,9 +1617,9 @@
goto cleanup;
}
- md_type = handshake->ciphersuite_info->mac;
+ md_type = (mbedtls_md_type_t) handshake->ciphersuite_info->mac;
- hash_alg = mbedtls_md_psa_alg_from_type(handshake->ciphersuite_info->mac);
+ hash_alg = mbedtls_md_psa_alg_from_type((mbedtls_md_type_t) handshake->ciphersuite_info->mac);
hash_len = PSA_HASH_LENGTH(hash_alg);
/* Compute current handshake transcript. It's the caller's responsibility
@@ -1767,7 +1767,7 @@
MBEDTLS_SSL_DEBUG_MSG(
2, ("=> mbedtls_ssl_tls13_compute_resumption_master_secret"));
- md_type = handshake->ciphersuite_info->mac;
+ md_type = (mbedtls_md_type_t) handshake->ciphersuite_info->mac;
ret = mbedtls_ssl_get_handshake_transcript(ssl, md_type,
transcript, sizeof(transcript),
diff --git a/library/ssl_tls13_server.c b/library/ssl_tls13_server.c
index 89bba04..b8201f0 100644
--- a/library/ssl_tls13_server.c
+++ b/library/ssl_tls13_server.c
@@ -408,7 +408,8 @@
/* MAC of selected ciphersuite MUST be same with PSK binder if exist.
* Otherwise, client should reject.
*/
- if (psk_hash_alg == mbedtls_md_psa_alg_from_type(ciphersuite_info->mac)) {
+ if (psk_hash_alg ==
+ mbedtls_md_psa_alg_from_type((mbedtls_md_type_t) ciphersuite_info->mac)) {
*selected_ciphersuite = cipher_suite;
*selected_ciphersuite_info = ciphersuite_info;
return 0;
@@ -614,7 +615,7 @@
ret = ssl_tls13_offered_psks_check_binder_match(
ssl, binder, binder_len, psk_type,
- mbedtls_md_psa_alg_from_type(ciphersuite_info->mac));
+ mbedtls_md_psa_alg_from_type((mbedtls_md_type_t) ciphersuite_info->mac));
if (ret != SSL_TLS1_3_OFFERED_PSK_MATCH) {
/* For security reasons, the handshake should be aborted when we
* fail to validate a binder value. See RFC 8446 section 4.2.11.2
@@ -2793,7 +2794,7 @@
ciphersuite_info =
(mbedtls_ssl_ciphersuite_t *) ssl->handshake->ciphersuite_info;
- psa_hash_alg = mbedtls_md_psa_alg_from_type(ciphersuite_info->mac);
+ psa_hash_alg = mbedtls_md_psa_alg_from_type((mbedtls_md_type_t) ciphersuite_info->mac);
hash_length = PSA_HASH_LENGTH(psa_hash_alg);
if (hash_length == -1 ||
(size_t) hash_length > sizeof(session->resumption_key)) {
@@ -3015,7 +3016,7 @@
}
MBEDTLS_SSL_DEBUG_MSG(2, ("tls13 server state: %s(%d)",
- mbedtls_ssl_states_str(ssl->state),
+ mbedtls_ssl_states_str((mbedtls_ssl_states) ssl->state),
ssl->state));
switch (ssl->state) {
diff --git a/library/x509_create.c b/library/x509_create.c
index 1c489a3..2583cdd 100644
--- a/library/x509_create.c
+++ b/library/x509_create.c
@@ -185,51 +185,107 @@
return 0;
}
-static int parse_attribute_value_der_encoded(const char *s,
- int len,
- unsigned char *data,
- size_t *data_len,
- int *tag)
+/** Parse a hexstring containing a DER-encoded string.
+ *
+ * \param s A string of \p len bytes hexadecimal digits.
+ * \param len Number of bytes to read from \p s.
+ * \param data Output buffer of size \p data_size.
+ * On success, it contains the payload that's DER-encoded
+ * in the input (content without the tag and length).
+ * If the DER tag is a string tag, the payload is guaranteed
+ * not to contain null bytes.
+ * \param data_size Length of the \p data buffer.
+ * \param data_len On success, the length of the parsed string.
+ * It is guaranteed to be less than
+ * #MBEDTLS_X509_MAX_DN_NAME_SIZE.
+ * \param tag The ASN.1 tag that the payload in \p data is encoded in.
+ *
+ * \retval 0 on success.
+ * \retval #MBEDTLS_ERR_X509_INVALID_NAME if \p s does not contain
+ * a valid hexstring,
+ * or if the decoded hexstring is not valid DER,
+ * or if the payload does not fit in \p data,
+ * or if the payload is more than
+ * #MBEDTLS_X509_MAX_DN_NAME_SIZE bytes,
+ * of if \p *tag is an ASN.1 string tag and the payload
+ * contains a null byte.
+ * \retval #MBEDTLS_ERR_X509_ALLOC_FAILED on low memory.
+ */
+static int parse_attribute_value_hex_der_encoded(const char *s,
+ size_t len,
+ unsigned char *data,
+ size_t data_size,
+ size_t *data_len,
+ int *tag)
{
- const char *c = s;
- const char *end = c + len;
- unsigned char asn1_der_buf[MBEDTLS_X509_MAX_DN_NAME_SIZE];
- unsigned char *asn1_der_end;
- unsigned char *p;
- unsigned char *d = data;
- int n;
+ /* Step 1: preliminary length checks. */
+ /* Each byte is encoded by exactly two hexadecimal digits. */
+ if (len % 2 != 0) {
+ /* Odd number of hex digits */
+ return MBEDTLS_ERR_X509_INVALID_NAME;
+ }
+ size_t const der_length = len / 2;
+ if (der_length > MBEDTLS_X509_MAX_DN_NAME_SIZE + 4) {
+ /* The payload would be more than MBEDTLS_X509_MAX_DN_NAME_SIZE
+ * (after subtracting the ASN.1 tag and length). Reject this early
+ * to avoid allocating a large intermediate buffer. */
+ return MBEDTLS_ERR_X509_INVALID_NAME;
+ }
+ if (der_length < 1) {
+ /* Avoid empty-buffer shenanigans. A valid DER encoding is never
+ * empty. */
+ return MBEDTLS_ERR_X509_INVALID_NAME;
+ }
- /* Converting from hexstring to raw binary so we can use asn1parse.c */
- if ((len < 5) || (*c != '#')) {
- return MBEDTLS_ERR_X509_INVALID_NAME;
+ /* Step 2: Decode the hex string into an intermediate buffer. */
+ unsigned char *der = mbedtls_calloc(1, der_length);
+ if (der == NULL) {
+ return MBEDTLS_ERR_X509_ALLOC_FAILED;
}
- c++;
- if ((*tag = hexpair_to_int(c)) == -1) {
- return MBEDTLS_ERR_X509_INVALID_NAME;
- }
- c += 2;
- p = asn1_der_buf;
- for (p = asn1_der_buf; c < end; c += 2) {
- if ((c + 1 >= end) || (n = hexpair_to_int(c)) == -1) {
- return MBEDTLS_ERR_X509_INVALID_NAME;
+ /* Beyond this point, der needs to be freed on exit. */
+ for (size_t i = 0; i < der_length; i++) {
+ int c = hexpair_to_int(s + 2 * i);
+ if (c < 0) {
+ goto error;
}
- if (MBEDTLS_ASN1_IS_STRING_TAG(*tag) && n == 0) {
- return MBEDTLS_ERR_X509_INVALID_NAME;
+ der[i] = c;
+ }
+
+ /* Step 3: decode the DER. */
+ /* We've checked that der_length >= 1 above. */
+ *tag = der[0];
+ unsigned char *p = der + 1;
+ if (mbedtls_asn1_get_len(&p, der + der_length, data_len) != 0) {
+ goto error;
+ }
+ /* Now p points to the first byte of the payload inside der,
+ * and *data_len is the length of the payload. */
+
+ /* Step 4: payload validation */
+ if (*data_len > MBEDTLS_X509_MAX_DN_NAME_SIZE) {
+ goto error;
+ }
+ /* Strings must not contain null bytes. */
+ if (MBEDTLS_ASN1_IS_STRING_TAG(*tag)) {
+ for (size_t i = 0; i < *data_len; i++) {
+ if (p[i] == 0) {
+ goto error;
+ }
}
- *(p++) = n;
- }
- asn1_der_end = p;
-
- p = asn1_der_buf;
- if (mbedtls_asn1_get_len(&p, asn1_der_end, data_len) != 0) {
- return MBEDTLS_ERR_X509_INVALID_NAME;
}
- while (p < asn1_der_end) {
- *(d++) = *(p++);
+ /* Step 5: output the payload. */
+ if (*data_len > data_size) {
+ goto error;
}
+ memcpy(data, p, *data_len);
+ mbedtls_free(der);
return 0;
+
+error:
+ mbedtls_free(der);
+ return MBEDTLS_ERR_X509_INVALID_NAME;
}
int mbedtls_x509_string_to_names(mbedtls_asn1_named_data **head, const char *name)
@@ -273,11 +329,14 @@
mbedtls_free(oid.p);
return MBEDTLS_ERR_X509_INVALID_NAME;
} else if (*s == '#') {
- if ((parse_ret =
- parse_attribute_value_der_encoded(s, (int) (c - s), data, &data_len,
- &tag)) != 0) {
+ /* We know that c >= s (loop invariant) and c != s (in this
+ * else branch), hence c - s - 1 >= 0. */
+ parse_ret = parse_attribute_value_hex_der_encoded(
+ s + 1, c - s - 1,
+ data, sizeof(data), &data_len, &tag);
+ if (parse_ret != 0) {
mbedtls_free(oid.p);
- return MBEDTLS_ERR_X509_INVALID_NAME;
+ return parse_ret;
}
} else {
if (numericoid) {