Merge remote-tracking branch 'origin/development' into safer-ct5
diff --git a/library/base64.c b/library/base64.c
index 3eb9e7c..fa22e53 100644
--- a/library/base64.c
+++ b/library/base64.c
@@ -24,6 +24,7 @@
#if defined(MBEDTLS_BASE64_C)
#include "mbedtls/base64.h"
+#include "base64_internal.h"
#include "constant_time_internal.h"
#include <stdint.h>
@@ -33,6 +34,39 @@
#include "mbedtls/platform.h"
#endif /* MBEDTLS_SELF_TEST */
+MBEDTLS_STATIC_TESTABLE
+unsigned char mbedtls_ct_base64_enc_char(unsigned char value)
+{
+ unsigned char digit = 0;
+ /* For each range of values, if value is in that range, mask digit with
+ * the corresponding value. Since value can only be in a single range,
+ * only at most one masking will change digit. */
+ digit |= mbedtls_ct_uchar_in_range_if(0, 25, value, 'A' + value);
+ digit |= mbedtls_ct_uchar_in_range_if(26, 51, value, 'a' + value - 26);
+ digit |= mbedtls_ct_uchar_in_range_if(52, 61, value, '0' + value - 52);
+ digit |= mbedtls_ct_uchar_in_range_if(62, 62, value, '+');
+ digit |= mbedtls_ct_uchar_in_range_if(63, 63, value, '/');
+ return digit;
+}
+
+MBEDTLS_STATIC_TESTABLE
+signed char mbedtls_ct_base64_dec_value(unsigned char c)
+{
+ unsigned char val = 0;
+ /* For each range of digits, if c is in that range, mask val with
+ * the corresponding value. Since c can only be in a single range,
+ * only at most one masking will change val. Set val to one plus
+ * the desired value so that it stays 0 if c is in none of the ranges. */
+ val |= mbedtls_ct_uchar_in_range_if('A', 'Z', c, c - 'A' + 0 + 1);
+ val |= mbedtls_ct_uchar_in_range_if('a', 'z', c, c - 'a' + 26 + 1);
+ val |= mbedtls_ct_uchar_in_range_if('0', '9', c, c - '0' + 52 + 1);
+ val |= mbedtls_ct_uchar_in_range_if('+', '+', c, c - '+' + 62 + 1);
+ val |= mbedtls_ct_uchar_in_range_if('/', '/', c, c - '/' + 63 + 1);
+ /* At this point, val is 0 if c is an invalid digit and v+1 if c is
+ * a digit with the value v. */
+ return val - 1;
+}
+
/*
* Encode a buffer into base64 format
*/
diff --git a/library/base64_internal.h b/library/base64_internal.h
new file mode 100644
index 0000000..f9f56d7
--- /dev/null
+++ b/library/base64_internal.h
@@ -0,0 +1,57 @@
+/**
+ * \file base64_internal.h
+ *
+ * \brief RFC 1521 base64 encoding/decoding: interfaces for invasive testing
+ */
+/*
+ * Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MBEDTLS_BASE64_INTERNAL
+#define MBEDTLS_BASE64_INTERNAL
+
+#include "common.h"
+
+#if defined(MBEDTLS_TEST_HOOKS)
+
+/** Given a value in the range 0..63, return the corresponding Base64 digit.
+ *
+ * The implementation assumes that letters are consecutive (e.g. ASCII
+ * but not EBCDIC).
+ *
+ * \param value A value in the range 0..63.
+ *
+ * \return A base64 digit converted from \p value.
+ */
+unsigned char mbedtls_ct_base64_enc_char(unsigned char value);
+
+/** Given a Base64 digit, return its value.
+ *
+ * If c is not a Base64 digit ('A'..'Z', 'a'..'z', '0'..'9', '+' or '/'),
+ * return -1.
+ *
+ * The implementation assumes that letters are consecutive (e.g. ASCII
+ * but not EBCDIC).
+ *
+ * \param c A base64 digit.
+ *
+ * \return The value of the base64 digit \p c.
+ */
+signed char mbedtls_ct_base64_dec_value(unsigned char c);
+
+#endif /* MBEDTLS_TEST_HOOKS */
+
+#endif /* MBEDTLS_BASE64_INTERNAL */
diff --git a/library/bignum.c b/library/bignum.c
index 36effaf..8ad7258 100644
--- a/library/bignum.c
+++ b/library/bignum.c
@@ -54,6 +54,129 @@
#define MPI_VALIDATE(cond) \
MBEDTLS_INTERNAL_VALIDATE(cond)
+/*
+ * Compare signed values in constant time
+ */
+int mbedtls_mpi_lt_mpi_ct(const mbedtls_mpi *X,
+ const mbedtls_mpi *Y,
+ unsigned *ret)
+{
+ mbedtls_ct_condition_t cond, X_is_negative, Y_is_negative, result;
+
+ 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 = mbedtls_ct_bool((X->s & 2) >> 1);
+ Y_is_negative = mbedtls_ct_bool((Y->s & 2) >> 1);
+
+ /*
+ * If the signs are different, then the positive operand is the bigger.
+ * That is if X is negative (X_is_negative == 1), then X < Y is true and it
+ * is false if X is positive (X_is_negative == 0).
+ */
+ cond = mbedtls_ct_bool_xor(X_is_negative, Y_is_negative); // non-zero if different sign
+ result = mbedtls_ct_bool_and(cond, X_is_negative);
+
+ /* Assuming signs are the same, compare X and Y. We switch the comparison
+ * order if they are negative so that we get the right result, regardles of
+ * sign.
+ *
+ * Store in ret iff the signs are the same (i.e., iff cond == 0). If
+ * the signs differ, done has already been set.
+ */
+
+ /* This is used to conditionally swap the pointers in const time */
+ void * const p[2] = { X->p, Y->p };
+ size_t i = mbedtls_ct_size_if0(X_is_negative, 1);
+ mbedtls_ct_condition_t lt = mbedtls_mpi_core_lt_ct(p[i], p[i ^ 1], X->n);
+
+ result = mbedtls_ct_bool_or(result, mbedtls_ct_bool_and(mbedtls_ct_bool_not(cond), lt));
+
+ *ret = mbedtls_ct_uint_if0(result, 1);
+
+ return 0;
+}
+
+/*
+ * Conditionally assign X = Y, without leaking information
+ * about whether the assignment was made or not.
+ * (Leaking information about the respective sizes of X and Y is ok however.)
+ */
+#if defined(_MSC_VER) && defined(_M_ARM64) && (_MSC_FULL_VER < 193131103)
+/*
+ * MSVC miscompiles this function if it's inlined prior to Visual Studio 2022 version 17.1. See:
+ * https://developercommunity.visualstudio.com/t/c-compiler-miscompiles-part-of-mbedtls-library-on/1646989
+ */
+__declspec(noinline)
+#endif
+int mbedtls_mpi_safe_cond_assign(mbedtls_mpi *X,
+ const mbedtls_mpi *Y,
+ unsigned char assign)
+{
+ int ret = 0;
+ MPI_VALIDATE_RET(X != NULL);
+ MPI_VALIDATE_RET(Y != NULL);
+
+ MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, Y->n));
+
+ mbedtls_ct_condition_t do_assign = mbedtls_ct_bool(assign);
+
+ 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_ct_condition_t do_not_assign = mbedtls_ct_bool_not(do_assign);
+ for (size_t i = Y->n; i < X->n; i++) {
+ X->p[i] = mbedtls_ct_mpi_uint_if0(do_not_assign, X->p[i]);
+ }
+
+cleanup:
+ return ret;
+}
+
+/*
+ * Conditionally swap X and Y, without leaking information
+ * about whether the swap was made or not.
+ * Here it is not ok to simply swap the pointers, which would lead to
+ * different memory access patterns when X and Y are used afterwards.
+ */
+int mbedtls_mpi_safe_cond_swap(mbedtls_mpi *X,
+ mbedtls_mpi *Y,
+ unsigned char swap)
+{
+ int ret = 0;
+ int s;
+ MPI_VALIDATE_RET(X != NULL);
+ MPI_VALIDATE_RET(Y != NULL);
+
+ if (X == Y) {
+ return 0;
+ }
+
+ mbedtls_ct_condition_t do_swap = mbedtls_ct_bool(swap);
+
+ MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, Y->n));
+ MBEDTLS_MPI_CHK(mbedtls_mpi_grow(Y, X->n));
+
+ s = X->s;
+ X->s = (int) mbedtls_ct_uint_if(do_swap, Y->s, X->s);
+ Y->s = (int) mbedtls_ct_uint_if(do_swap, s, Y->s);
+
+ mbedtls_mpi_core_cond_swap(X->p, Y->p, X->n, do_swap);
+
+cleanup:
+ return ret;
+}
+
/* Implementation that should never be optimized out by the compiler */
static void mbedtls_mpi_zeroize(mbedtls_mpi_uint *v, size_t n)
{
@@ -1602,10 +1725,8 @@
for (size_t i = 0; i < T_size; i++) {
MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_assign(R, &T[i],
- (unsigned char) mbedtls_ct_size_bool_eq(i,
- idx)));
+ (unsigned char) mbedtls_ct_bool_eq(i, idx)));
}
-
cleanup:
return ret;
}
diff --git a/library/bignum_core.c b/library/bignum_core.c
index de57cfc..5e19590 100644
--- a/library/bignum_core.c
+++ b/library/bignum_core.c
@@ -148,54 +148,92 @@
/* Whether min <= A, in constant time.
* A_limbs must be at least 1. */
-unsigned mbedtls_mpi_core_uint_le_mpi(mbedtls_mpi_uint min,
- const mbedtls_mpi_uint *A,
- size_t A_limbs)
+mbedtls_ct_condition_t mbedtls_mpi_core_uint_le_mpi(mbedtls_mpi_uint min,
+ const mbedtls_mpi_uint *A,
+ size_t A_limbs)
{
/* min <= least significant limb? */
- unsigned min_le_lsl = 1 ^ mbedtls_ct_mpi_uint_lt(A[0], min);
+ mbedtls_ct_condition_t min_le_lsl = mbedtls_ct_bool_ge(A[0], min);
/* limbs other than the least significant one are all zero? */
- mbedtls_mpi_uint msll_mask = 0;
+ mbedtls_ct_condition_t msll_mask = MBEDTLS_CT_FALSE;
for (size_t i = 1; i < A_limbs; i++) {
- msll_mask |= A[i];
+ msll_mask = mbedtls_ct_bool_or(msll_mask, mbedtls_ct_bool(A[i]));
}
- /* The most significant limbs of A are not all zero iff msll_mask != 0. */
- unsigned msll_nonzero = mbedtls_ct_mpi_uint_mask(msll_mask) & 1;
/* min <= A iff the lowest limb of A is >= min or the other limbs
* are not all zero. */
- return min_le_lsl | msll_nonzero;
+ return mbedtls_ct_bool_or(msll_mask, min_le_lsl);
+}
+
+mbedtls_ct_condition_t mbedtls_mpi_core_lt_ct(const mbedtls_mpi_uint *A,
+ const mbedtls_mpi_uint *B,
+ size_t limbs)
+{
+ mbedtls_ct_condition_t ret = MBEDTLS_CT_FALSE, cond = MBEDTLS_CT_FALSE, done = MBEDTLS_CT_FALSE;
+
+ for (size_t i = limbs; i > 0; i--) {
+ /*
+ * If B[i - 1] < A[i - 1] then A < B is false and the result must
+ * remain 0.
+ *
+ * Again even if we can make a decision, we just mark the result and
+ * the fact that we are done and continue looping.
+ */
+ cond = mbedtls_ct_bool_lt(B[i - 1], A[i - 1]);
+ done = mbedtls_ct_bool_or(done, cond);
+
+ /*
+ * If A[i - 1] < B[i - 1] then A < B is true.
+ *
+ * Again even if we can make a decision, we just mark the result and
+ * the fact that we are done and continue looping.
+ */
+ cond = mbedtls_ct_bool_lt(A[i - 1], B[i - 1]);
+ ret = mbedtls_ct_bool_or(ret, mbedtls_ct_bool_and(cond, mbedtls_ct_bool_not(done)));
+ done = mbedtls_ct_bool_or(done, cond);
+ }
+
+ /*
+ * If all the limbs were equal, then the numbers are equal, A < B is false
+ * and leaving the result 0 is correct.
+ */
+
+ return ret;
}
void mbedtls_mpi_core_cond_assign(mbedtls_mpi_uint *X,
const mbedtls_mpi_uint *A,
size_t limbs,
- unsigned char assign)
+ mbedtls_ct_condition_t assign)
{
if (X == A) {
return;
}
- mbedtls_ct_mpi_uint_cond_assign(limbs, X, A, assign);
+ /* This function is very performance-sensitive for RSA. For this reason
+ * we have the loop below, instead of calling mbedtls_ct_memcpy_if
+ * (this is more optimal since here we don't have to handle the case where
+ * we copy awkwardly sized data).
+ */
+ for (size_t i = 0; i < limbs; i++) {
+ X[i] = mbedtls_ct_mpi_uint_if(assign, A[i], X[i]);
+ }
}
void mbedtls_mpi_core_cond_swap(mbedtls_mpi_uint *X,
mbedtls_mpi_uint *Y,
size_t limbs,
- unsigned char swap)
+ mbedtls_ct_condition_t swap)
{
if (X == Y) {
return;
}
- /* all-bits 1 if swap is 1, all-bits 0 if swap is 0 */
- mbedtls_mpi_uint limb_mask = mbedtls_ct_mpi_uint_mask(swap);
-
for (size_t i = 0; i < limbs; i++) {
mbedtls_mpi_uint tmp = X[i];
- X[i] = (X[i] & ~limb_mask) | (Y[i] & limb_mask);
- Y[i] = (Y[i] & ~limb_mask) | (tmp & limb_mask);
+ X[i] = mbedtls_ct_mpi_uint_if(swap, Y[i], X[i]);
+ Y[i] = mbedtls_ct_mpi_uint_if(swap, tmp, Y[i]);
}
}
@@ -426,11 +464,10 @@
{
mbedtls_mpi_uint c = 0;
- /* all-bits 0 if cond is 0, all-bits 1 if cond is non-0 */
- const mbedtls_mpi_uint mask = mbedtls_ct_mpi_uint_mask(cond);
+ mbedtls_ct_condition_t do_add = mbedtls_ct_bool(cond);
for (size_t i = 0; i < limbs; i++) {
- mbedtls_mpi_uint add = mask & A[i];
+ mbedtls_mpi_uint add = mbedtls_ct_mpi_uint_if0(do_add, A[i]);
mbedtls_mpi_uint t = c + X[i];
c = (t < X[i]);
t += add;
@@ -572,7 +609,11 @@
* So the correct return value is already in X if (carry ^ borrow) = 0,
* but is in (the lower AN_limbs limbs of) T if (carry ^ borrow) = 1.
*/
- mbedtls_ct_mpi_uint_cond_assign(AN_limbs, X, T, (unsigned char) (carry ^ borrow));
+ mbedtls_ct_memcpy_if(mbedtls_ct_bool(carry ^ borrow),
+ (unsigned char *) X,
+ (unsigned char *) T,
+ NULL,
+ AN_limbs * sizeof(mbedtls_mpi_uint));
}
int mbedtls_mpi_core_get_mont_r2_unsafe(mbedtls_mpi *X,
@@ -597,7 +638,7 @@
size_t index)
{
for (size_t i = 0; i < count; i++, table += limbs) {
- unsigned char assign = mbedtls_ct_size_bool_eq(i, index);
+ mbedtls_ct_condition_t assign = mbedtls_ct_bool_eq(i, index);
mbedtls_mpi_core_cond_assign(dest, table, limbs, assign);
}
}
@@ -637,7 +678,7 @@
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng)
{
- unsigned ge_lower = 1, lt_upper = 0;
+ mbedtls_ct_condition_t ge_lower = MBEDTLS_CT_TRUE, lt_upper = MBEDTLS_CT_FALSE;
size_t n_bits = mbedtls_mpi_core_bitlen(N, limbs);
size_t n_bytes = (n_bits + 7) / 8;
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
@@ -682,7 +723,7 @@
ge_lower = mbedtls_mpi_core_uint_le_mpi(min, X, limbs);
lt_upper = mbedtls_mpi_core_lt_ct(X, N, limbs);
- } while (ge_lower == 0 || lt_upper == 0);
+ } while (mbedtls_ct_bool_and(ge_lower, lt_upper) == MBEDTLS_CT_FALSE);
cleanup:
return ret;
diff --git a/library/bignum_core.h b/library/bignum_core.h
index 21a5a11..64d51b9 100644
--- a/library/bignum_core.h
+++ b/library/bignum_core.h
@@ -86,6 +86,8 @@
#include "mbedtls/bignum.h"
#endif
+#include "constant_time_internal.h"
+
#define ciL (sizeof(mbedtls_mpi_uint)) /** chars in limb */
#define biL (ciL << 3) /** bits in limb */
#define biH (ciL << 2) /** half limb size */
@@ -142,11 +144,29 @@
* \param A_limbs The number of limbs of \p A.
* This must be at least 1.
*
- * \return 1 if \p min is less than or equal to \p A, otherwise 0.
+ * \return MBEDTLS_CT_TRUE if \p min is less than or equal to \p A, otherwise MBEDTLS_CT_FALSE.
*/
-unsigned mbedtls_mpi_core_uint_le_mpi(mbedtls_mpi_uint min,
- const mbedtls_mpi_uint *A,
- size_t A_limbs);
+mbedtls_ct_condition_t mbedtls_mpi_core_uint_le_mpi(mbedtls_mpi_uint min,
+ const mbedtls_mpi_uint *A,
+ size_t A_limbs);
+
+/**
+ * \brief Check if one unsigned MPI is less than another in constant
+ * time.
+ *
+ * \param A The left-hand MPI. This must point to an array of limbs
+ * with the same allocated length as \p B.
+ * \param B The right-hand MPI. This must point to an array of limbs
+ * with the same allocated length as \p A.
+ * \param limbs The number of limbs in \p A and \p B.
+ * This must not be 0.
+ *
+ * \return MBEDTLS_CT_TRUE if \p A is less than \p B.
+ * MBEDTLS_CT_FALSE if \p A is greater than or equal to \p B.
+ */
+mbedtls_ct_condition_t mbedtls_mpi_core_lt_ct(const mbedtls_mpi_uint *A,
+ const mbedtls_mpi_uint *B,
+ size_t limbs);
/**
* \brief Perform a safe conditional copy of an MPI which doesn't reveal
@@ -158,21 +178,15 @@
* \param[in] A The address of the source MPI. This must be initialized.
* \param limbs The number of limbs of \p A.
* \param assign The condition deciding whether to perform the
- * assignment or not. Must be either 0 or 1:
- * * \c 1: Perform the assignment `X = A`.
- * * \c 0: Keep the original value of \p X.
+ * assignment or not.
*
* \note This function avoids leaking any information about whether
* the assignment was done or not.
- *
- * \warning If \p assign is neither 0 nor 1, the result of this function
- * is indeterminate, and the resulting value in \p X might be
- * neither its original value nor the value in \p A.
*/
void mbedtls_mpi_core_cond_assign(mbedtls_mpi_uint *X,
const mbedtls_mpi_uint *A,
size_t limbs,
- unsigned char assign);
+ mbedtls_ct_condition_t assign);
/**
* \brief Perform a safe conditional swap of two MPIs which doesn't reveal
@@ -184,21 +198,15 @@
* This must be initialized.
* \param limbs The number of limbs of \p X and \p Y.
* \param swap The condition deciding whether to perform
- * the swap or not. Must be either 0 or 1:
- * * \c 1: Swap the values of \p X and \p Y.
- * * \c 0: Keep the original values of \p X and \p Y.
+ * the swap or not.
*
* \note This function avoids leaking any information about whether
* the swap was done or not.
- *
- * \warning If \p swap is neither 0 nor 1, the result of this function
- * is indeterminate, and both \p X and \p Y might end up with
- * values different to either of the original ones.
*/
void mbedtls_mpi_core_cond_swap(mbedtls_mpi_uint *X,
mbedtls_mpi_uint *Y,
size_t limbs,
- unsigned char swap);
+ mbedtls_ct_condition_t swap);
/** Import X from unsigned binary data, little-endian.
*
diff --git a/library/bignum_mod_raw.c b/library/bignum_mod_raw.c
index bf72c18..c539197 100644
--- a/library/bignum_mod_raw.c
+++ b/library/bignum_mod_raw.c
@@ -40,7 +40,7 @@
const mbedtls_mpi_mod_modulus *N,
unsigned char assign)
{
- mbedtls_mpi_core_cond_assign(X, A, N->limbs, assign);
+ mbedtls_mpi_core_cond_assign(X, A, N->limbs, mbedtls_ct_bool(assign));
}
void mbedtls_mpi_mod_raw_cond_swap(mbedtls_mpi_uint *X,
@@ -48,7 +48,7 @@
const mbedtls_mpi_mod_modulus *N,
unsigned char swap)
{
- mbedtls_mpi_core_cond_swap(X, Y, N->limbs, swap);
+ mbedtls_mpi_core_cond_swap(X, Y, N->limbs, mbedtls_ct_bool(swap));
}
int mbedtls_mpi_mod_raw_read(mbedtls_mpi_uint *X,
diff --git a/library/constant_time.c b/library/constant_time.c
index 5265005..f2cdddf 100644
--- a/library/constant_time.c
+++ b/library/constant_time.c
@@ -22,29 +22,14 @@
* might be translated to branches by some compilers on some platforms.
*/
+#include <limits.h>
+
#include "common.h"
#include "constant_time_internal.h"
#include "mbedtls/constant_time.h"
#include "mbedtls/error.h"
#include "mbedtls/platform_util.h"
-#if defined(MBEDTLS_BIGNUM_C)
-#include "mbedtls/bignum.h"
-#include "bignum_core.h"
-#endif
-
-#if defined(MBEDTLS_SSL_TLS_C)
-#include "ssl_misc.h"
-#endif
-
-#if defined(MBEDTLS_RSA_C)
-#include "mbedtls/rsa.h"
-#endif
-
-#if defined(MBEDTLS_BASE64_C)
-#include "constant_time_invasive.h"
-#endif
-
#include <string.h>
#if defined(MBEDTLS_USE_PSA_CRYPTO) && defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC)
@@ -60,6 +45,15 @@
#define PSA_TO_MBEDTLS_ERR(status) local_err_translation(status)
#endif
+#if !defined(MBEDTLS_CT_ASM)
+/*
+ * Define an object with the value zero, such that the compiler cannot prove that it
+ * has the value zero (because it is volatile, it "may be modified in ways unknown to
+ * the implementation").
+ */
+volatile mbedtls_ct_uint_t mbedtls_ct_zero = 0;
+#endif
+
/*
* Define MBEDTLS_EFFICIENT_UNALIGNED_VOLATILE_ACCESS where assembly is present to
* perform fast unaligned access to volatile data.
@@ -70,15 +64,12 @@
* Some of these definitions could be moved into alignment.h but for now they are
* only used here.
*/
-#if defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS) && defined(MBEDTLS_HAVE_ASM)
-#if ((defined(__arm__) || defined(__thumb__) || defined(__thumb2__)) && \
- (UINTPTR_MAX == 0xfffffffful)) || defined(__aarch64__)
+#if defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS) && \
+ ((defined(MBEDTLS_CT_ARM_ASM) && (UINTPTR_MAX == 0xfffffffful)) || \
+ defined(MBEDTLS_CT_AARCH64_ASM))
/* We check pointer sizes to avoid issues with them not matching register size requirements */
#define MBEDTLS_EFFICIENT_UNALIGNED_VOLATILE_ACCESS
-#endif
-#endif
-#if defined(MBEDTLS_EFFICIENT_UNALIGNED_VOLATILE_ACCESS)
static inline uint32_t mbedtls_get_unaligned_volatile_uint32(volatile const unsigned char *p)
{
/* This is UB, even where it's safe:
@@ -86,14 +77,17 @@
* so instead the same thing is expressed in assembly below.
*/
uint32_t r;
-#if defined(__arm__) || defined(__thumb__) || defined(__thumb2__)
+#if defined(MBEDTLS_CT_ARM_ASM)
asm volatile ("ldr %0, [%1]" : "=r" (r) : "r" (p) :);
-#elif defined(__aarch64__)
+#elif defined(MBEDTLS_CT_AARCH64_ASM)
asm volatile ("ldr %w0, [%1]" : "=r" (r) : MBEDTLS_ASM_AARCH64_PTR_CONSTRAINT(p) :);
+#else
+#error No assembly defined for mbedtls_get_unaligned_volatile_uint32
#endif
return r;
}
-#endif /* MBEDTLS_EFFICIENT_UNALIGNED_VOLATILE_ACCESS */
+#endif /* defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS) &&
+ (defined(MBEDTLS_CT_ARM_ASM) || defined(MBEDTLS_CT_AARCH64_ASM)) */
int mbedtls_ct_memcmp(const void *a,
const void *b,
@@ -129,336 +123,70 @@
return (int) diff;
}
-unsigned mbedtls_ct_uint_mask(unsigned value)
-{
- /* MSVC has a warning about unary minus on unsigned, but this is
- * well-defined and precisely what we want to do here */
-#if defined(_MSC_VER)
-#pragma warning( push )
-#pragma warning( disable : 4146 )
-#endif
- return -((value | -value) >> (sizeof(value) * 8 - 1));
-#if defined(_MSC_VER)
-#pragma warning( pop )
-#endif
-}
-
-#if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC)
-
-size_t mbedtls_ct_size_mask(size_t value)
-{
- /* MSVC has a warning about unary minus on unsigned integer types,
- * but this is well-defined and precisely what we want to do here. */
-#if defined(_MSC_VER)
-#pragma warning( push )
-#pragma warning( disable : 4146 )
-#endif
- return -((value | -value) >> (sizeof(value) * 8 - 1));
-#if defined(_MSC_VER)
-#pragma warning( pop )
-#endif
-}
-
-#endif /* MBEDTLS_SSL_SOME_SUITES_USE_MAC */
-
-#if defined(MBEDTLS_BIGNUM_C)
-
-mbedtls_mpi_uint mbedtls_ct_mpi_uint_mask(mbedtls_mpi_uint value)
-{
- /* MSVC has a warning about unary minus on unsigned, but this is
- * well-defined and precisely what we want to do here */
-#if defined(_MSC_VER)
-#pragma warning( push )
-#pragma warning( disable : 4146 )
-#endif
- return -((value | -value) >> (sizeof(value) * 8 - 1));
-#if defined(_MSC_VER)
-#pragma warning( pop )
-#endif
-}
-
-#endif /* MBEDTLS_BIGNUM_C */
-
-#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC)
-
-/** Constant-flow mask generation for "less than" comparison:
- * - if \p x < \p y, return all-bits 1, that is (size_t) -1
- * - otherwise, return all bits 0, that is 0
- *
- * This function can be used to write constant-time code by replacing branches
- * with bit operations using masks.
- *
- * \param x The first value to analyze.
- * \param y The second value to analyze.
- *
- * \return All-bits-one if \p x is less than \p y, otherwise zero.
- */
-static size_t mbedtls_ct_size_mask_lt(size_t x,
- size_t y)
-{
- /* This has the most significant bit set if and only if x < y */
- const size_t sub = x - y;
-
- /* sub1 = (x < y) ? 1 : 0 */
- const size_t sub1 = sub >> (sizeof(sub) * 8 - 1);
-
- /* mask = (x < y) ? 0xff... : 0x00... */
- const size_t mask = mbedtls_ct_size_mask(sub1);
-
- return mask;
-}
-
-size_t mbedtls_ct_size_mask_ge(size_t x,
- size_t y)
-{
- return ~mbedtls_ct_size_mask_lt(x, y);
-}
-
-#endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */
-
-#if defined(MBEDTLS_BASE64_C)
-
-/* Return 0xff if low <= c <= high, 0 otherwise.
- *
- * Constant flow with respect to c.
- */
-MBEDTLS_STATIC_TESTABLE
-unsigned char mbedtls_ct_uchar_mask_of_range(unsigned char low,
- unsigned char high,
- unsigned char c)
-{
- /* low_mask is: 0 if low <= c, 0x...ff if low > c */
- unsigned low_mask = ((unsigned) c - low) >> 8;
- /* high_mask is: 0 if c <= high, 0x...ff if c > high */
- unsigned high_mask = ((unsigned) high - c) >> 8;
- return ~(low_mask | high_mask) & 0xff;
-}
-
-#endif /* MBEDTLS_BASE64_C */
-
-unsigned mbedtls_ct_size_bool_eq(size_t x,
- size_t y)
-{
- /* diff = 0 if x == y, non-zero otherwise */
- const size_t diff = x ^ y;
-
- /* MSVC has a warning about unary minus on unsigned integer types,
- * but this is well-defined and precisely what we want to do here. */
-#if defined(_MSC_VER)
-#pragma warning( push )
-#pragma warning( disable : 4146 )
-#endif
-
- /* diff_msb's most significant bit is equal to x != y */
- const size_t diff_msb = (diff | (size_t) -diff);
-
-#if defined(_MSC_VER)
-#pragma warning( pop )
-#endif
-
- /* diff1 = (x != y) ? 1 : 0 */
- const unsigned diff1 = diff_msb >> (sizeof(diff_msb) * 8 - 1);
-
- return 1 ^ diff1;
-}
-
#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT)
-/** Constant-flow "greater than" comparison:
- * return x > y
- *
- * This is equivalent to \p x > \p y, but is likely to be compiled
- * to code using bitwise operation rather than a branch.
- *
- * \param x The first value to analyze.
- * \param y The second value to analyze.
- *
- * \return 1 if \p x greater than \p y, otherwise 0.
- */
-static unsigned mbedtls_ct_size_gt(size_t x,
- size_t y)
+void mbedtls_ct_memmove_left(void *start, size_t total, size_t offset)
{
- /* Return the sign bit (1 for negative) of (y - x). */
- return (y - x) >> (sizeof(size_t) * 8 - 1);
-}
+ /* Iterate over the array, reading each byte once and writing each byte once. */
+ for (size_t i = 0; i < total; i++) {
+ /* Each iteration, read one byte, and write it to start[i].
+ *
+ * The source address will either be the "true" source address, if it's in the range
+ * where data is getting moved, or (if the source address is off the end of the
+ * array), it will wrap back to the start.
+ *
+ * If the source address is out of range, mask it to zero.
+ */
-#endif /* MBEDTLS_PKCS1_V15 && MBEDTLS_RSA_C && ! MBEDTLS_RSA_ALT */
+ // The address that we will read from
+ // TODO: if offset is marked as secret, this upsets Memsan.
+ size_t j = i + offset;
-#if defined(MBEDTLS_BIGNUM_C)
+ // Is the address off the end of the array?
+ mbedtls_ct_condition_t not_dummy = mbedtls_ct_bool_lt(j, total);
-unsigned mbedtls_ct_mpi_uint_lt(const mbedtls_mpi_uint x,
- const mbedtls_mpi_uint y)
-{
- mbedtls_mpi_uint ret;
- mbedtls_mpi_uint cond;
+ // Bring read address into range
+ j = j % total;
- /*
- * 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<y.
- */
- ret = (x - y) & ~cond;
- /*
- * If the MSB are different, then the operand with the MSB of 1 is the
- * bigger. (That is if y has MSB of 1, then x<y is true and it is false if
- * the MSB of y is 0.)
- */
- ret |= y & cond;
+ // Read a byte
+ uint8_t b = ((uint8_t *) start)[j];
+ // Set it to zero if it's out of range
+ b = mbedtls_ct_uint_if0(not_dummy, b);
- ret = ret >> (sizeof(mbedtls_mpi_uint) * 8 - 1);
-
- return (unsigned) ret;
-}
-
-#endif /* MBEDTLS_BIGNUM_C */
-
-unsigned mbedtls_ct_uint_if(unsigned condition,
- unsigned if1,
- unsigned if0)
-{
- unsigned mask = mbedtls_ct_uint_mask(condition);
- return (mask & if1) | (~mask & if0);
-}
-
-#if defined(MBEDTLS_BIGNUM_C)
-
-void mbedtls_ct_mpi_uint_cond_assign(size_t n,
- mbedtls_mpi_uint *dest,
- const mbedtls_mpi_uint *src,
- unsigned char condition)
-{
- size_t i;
-
- /* MSVC has a warning about unary minus on unsigned integer types,
- * but this is well-defined and precisely what we want to do here. */
-#if defined(_MSC_VER)
-#pragma warning( push )
-#pragma warning( disable : 4146 )
-#endif
-
- /* all-bits 1 if condition is 1, all-bits 0 if condition is 0 */
- const mbedtls_mpi_uint mask = -condition;
-
-#if defined(_MSC_VER)
-#pragma warning( pop )
-#endif
-
- for (i = 0; i < n; i++) {
- dest[i] = (src[i] & mask) | (dest[i] & ~mask);
- }
-}
-
-#endif /* MBEDTLS_BIGNUM_C */
-
-#if defined(MBEDTLS_BASE64_C)
-
-unsigned char mbedtls_ct_base64_enc_char(unsigned char value)
-{
- unsigned char digit = 0;
- /* For each range of values, if value is in that range, mask digit with
- * the corresponding value. Since value can only be in a single range,
- * only at most one masking will change digit. */
- digit |= mbedtls_ct_uchar_mask_of_range(0, 25, value) & ('A' + value);
- digit |= mbedtls_ct_uchar_mask_of_range(26, 51, value) & ('a' + value - 26);
- digit |= mbedtls_ct_uchar_mask_of_range(52, 61, value) & ('0' + value - 52);
- digit |= mbedtls_ct_uchar_mask_of_range(62, 62, value) & '+';
- digit |= mbedtls_ct_uchar_mask_of_range(63, 63, value) & '/';
- return digit;
-}
-
-signed char mbedtls_ct_base64_dec_value(unsigned char c)
-{
- unsigned char val = 0;
- /* For each range of digits, if c is in that range, mask val with
- * the corresponding value. Since c can only be in a single range,
- * only at most one masking will change val. Set val to one plus
- * the desired value so that it stays 0 if c is in none of the ranges. */
- val |= mbedtls_ct_uchar_mask_of_range('A', 'Z', c) & (c - 'A' + 0 + 1);
- val |= mbedtls_ct_uchar_mask_of_range('a', 'z', c) & (c - 'a' + 26 + 1);
- val |= mbedtls_ct_uchar_mask_of_range('0', '9', c) & (c - '0' + 52 + 1);
- val |= mbedtls_ct_uchar_mask_of_range('+', '+', c) & (c - '+' + 62 + 1);
- val |= mbedtls_ct_uchar_mask_of_range('/', '/', c) & (c - '/' + 63 + 1);
- /* At this point, val is 0 if c is an invalid digit and v+1 if c is
- * a digit with the value v. */
- return val - 1;
-}
-
-#endif /* MBEDTLS_BASE64_C */
-
-#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT)
-
-/** Shift some data towards the left inside a buffer.
- *
- * `mbedtls_ct_mem_move_to_left(start, total, offset)` is functionally
- * equivalent to
- * ```
- * memmove(start, start + offset, total - offset);
- * memset(start + offset, 0, total - offset);
- * ```
- * but it strives to use a memory access pattern (and thus total timing)
- * that does not depend on \p offset. This timing independence comes at
- * the expense of performance.
- *
- * \param start Pointer to the start of the buffer.
- * \param total Total size of the buffer.
- * \param offset Offset from which to copy \p total - \p offset bytes.
- */
-static void mbedtls_ct_mem_move_to_left(void *start,
- size_t total,
- size_t offset)
-{
- volatile unsigned char *buf = start;
- size_t i, n;
- if (total == 0) {
- return;
- }
- for (i = 0; i < total; i++) {
- unsigned no_op = mbedtls_ct_size_gt(total - offset, i);
- /* 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_ct_uint_if(no_op, current, next);
- }
- buf[total-1] = mbedtls_ct_uint_if(no_op, buf[total-1], 0);
+ // Write the byte to start[i]
+ ((uint8_t *) start)[i] = b;
}
}
#endif /* MBEDTLS_PKCS1_V15 && MBEDTLS_RSA_C && ! MBEDTLS_RSA_ALT */
-#if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC)
-
-void mbedtls_ct_memcpy_if_eq(unsigned char *dest,
- const unsigned char *src,
- size_t len,
- size_t c1,
- size_t c2)
+void mbedtls_ct_memcpy_if(mbedtls_ct_condition_t condition,
+ unsigned char *dest,
+ const unsigned char *src1,
+ const unsigned char *src2,
+ size_t len)
{
- /* mask = c1 == c2 ? 0xff : 0x00 */
- const size_t equal = mbedtls_ct_size_bool_eq(c1, c2);
+ const uint32_t mask = (uint32_t) condition;
+ const uint32_t not_mask = (uint32_t) ~mbedtls_ct_compiler_opaque(condition);
+
+ /* If src2 is NULL and condition == 0, then this function has no effect.
+ * In this case, copy from dest back into dest. */
+ if (src2 == NULL) {
+ src2 = dest;
+ }
/* dest[i] = c1 == c2 ? src[i] : dest[i] */
size_t i = 0;
#if defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS)
- const uint32_t mask32 = (uint32_t) mbedtls_ct_size_mask(equal);
- const unsigned char mask = (unsigned char) mask32 & 0xff;
-
for (; (i + 4) <= len; i += 4) {
- uint32_t a = mbedtls_get_unaligned_uint32(src + i) & mask32;
- uint32_t b = mbedtls_get_unaligned_uint32(dest + i) & ~mask32;
+ uint32_t a = mbedtls_get_unaligned_uint32(src1 + i) & mask;
+ uint32_t b = mbedtls_get_unaligned_uint32(src2 + i) & not_mask;
mbedtls_put_unaligned_uint32(dest + i, a | b);
}
-#else
- const unsigned char mask = (unsigned char) mbedtls_ct_size_mask(equal);
#endif /* MBEDTLS_EFFICIENT_UNALIGNED_ACCESS */
for (; i < len; i++) {
- dest[i] = (src[i] & mask) | (dest[i] & ~mask);
+ dest[i] = (src1[i] & mask) | (src2[i] & not_mask);
}
}
@@ -472,547 +200,27 @@
size_t offsetval;
for (offsetval = offset_min; offsetval <= offset_max; offsetval++) {
- mbedtls_ct_memcpy_if_eq(dest, src + offsetval, len,
- offsetval, offset);
+ mbedtls_ct_memcpy_if(mbedtls_ct_bool_eq(offsetval, offset), dest, src + offsetval, NULL,
+ len);
}
}
-#if defined(MBEDTLS_USE_PSA_CRYPTO)
-
-#if defined(PSA_WANT_ALG_SHA_384)
-#define MAX_HASH_BLOCK_LENGTH PSA_HASH_BLOCK_LENGTH(PSA_ALG_SHA_384)
-#elif defined(PSA_WANT_ALG_SHA_256)
-#define MAX_HASH_BLOCK_LENGTH PSA_HASH_BLOCK_LENGTH(PSA_ALG_SHA_256)
-#else /* See check_config.h */
-#define MAX_HASH_BLOCK_LENGTH PSA_HASH_BLOCK_LENGTH(PSA_ALG_SHA_1)
-#endif
-
-int mbedtls_ct_hmac(mbedtls_svc_key_id_t key,
- psa_algorithm_t mac_alg,
- const unsigned char *add_data,
- size_t add_data_len,
- const unsigned char *data,
- size_t data_len_secret,
- size_t min_data_len,
- size_t max_data_len,
- unsigned char *output)
-{
- /*
- * This function breaks the HMAC abstraction and uses psa_hash_clone()
- * extension in order to get constant-flow behaviour.
- *
- * HMAC(msg) is defined as HASH(okey + HASH(ikey + msg)) where + means
- * concatenation, and okey/ikey are the XOR of the key with some fixed bit
- * patterns (see RFC 2104, sec. 2).
- *
- * We'll first compute ikey/okey, then inner_hash = HASH(ikey + msg) by
- * hashing up to minlen, then cloning the context, and for each byte up
- * to maxlen finishing up the hash computation, keeping only the
- * correct result.
- *
- * Then we only need to compute HASH(okey + inner_hash) and we're done.
- */
- psa_algorithm_t hash_alg = PSA_ALG_HMAC_GET_HASH(mac_alg);
- const size_t block_size = PSA_HASH_BLOCK_LENGTH(hash_alg);
- unsigned char key_buf[MAX_HASH_BLOCK_LENGTH];
- const size_t hash_size = PSA_HASH_LENGTH(hash_alg);
- psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT;
- size_t hash_length;
-
- unsigned char aux_out[PSA_HASH_MAX_SIZE];
- psa_hash_operation_t aux_operation = PSA_HASH_OPERATION_INIT;
- size_t offset;
- psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
-
- size_t mac_key_length;
- size_t i;
-
-#define PSA_CHK(func_call) \
- do { \
- status = (func_call); \
- if (status != PSA_SUCCESS) \
- goto cleanup; \
- } while (0)
-
- /* Export MAC key
- * We assume key length is always exactly the output size
- * which is never more than the block size, thus we use block_size
- * as the key buffer size.
- */
- PSA_CHK(psa_export_key(key, key_buf, block_size, &mac_key_length));
-
- /* Calculate ikey */
- for (i = 0; i < mac_key_length; i++) {
- key_buf[i] = (unsigned char) (key_buf[i] ^ 0x36);
- }
- for (; i < block_size; ++i) {
- key_buf[i] = 0x36;
- }
-
- PSA_CHK(psa_hash_setup(&operation, hash_alg));
-
- /* Now compute inner_hash = HASH(ikey + msg) */
- PSA_CHK(psa_hash_update(&operation, key_buf, block_size));
- PSA_CHK(psa_hash_update(&operation, add_data, add_data_len));
- PSA_CHK(psa_hash_update(&operation, data, min_data_len));
-
- /* Fill the hash buffer in advance with something that is
- * not a valid hash (barring an attack on the hash and
- * deliberately-crafted input), in case the caller doesn't
- * check the return status properly. */
- memset(output, '!', hash_size);
-
- /* For each possible length, compute the hash up to that point */
- for (offset = min_data_len; offset <= max_data_len; offset++) {
- PSA_CHK(psa_hash_clone(&operation, &aux_operation));
- PSA_CHK(psa_hash_finish(&aux_operation, aux_out,
- PSA_HASH_MAX_SIZE, &hash_length));
- /* Keep only the correct inner_hash in the output buffer */
- mbedtls_ct_memcpy_if_eq(output, aux_out, hash_size,
- offset, data_len_secret);
-
- if (offset < max_data_len) {
- PSA_CHK(psa_hash_update(&operation, data + offset, 1));
- }
- }
-
- /* Abort current operation to prepare for final operation */
- PSA_CHK(psa_hash_abort(&operation));
-
- /* Calculate okey */
- for (i = 0; i < mac_key_length; i++) {
- key_buf[i] = (unsigned char) ((key_buf[i] ^ 0x36) ^ 0x5C);
- }
- for (; i < block_size; ++i) {
- key_buf[i] = 0x5C;
- }
-
- /* Now compute HASH(okey + inner_hash) */
- PSA_CHK(psa_hash_setup(&operation, hash_alg));
- PSA_CHK(psa_hash_update(&operation, key_buf, block_size));
- PSA_CHK(psa_hash_update(&operation, output, hash_size));
- PSA_CHK(psa_hash_finish(&operation, output, hash_size, &hash_length));
-
-#undef PSA_CHK
-
-cleanup:
- mbedtls_platform_zeroize(key_buf, MAX_HASH_BLOCK_LENGTH);
- mbedtls_platform_zeroize(aux_out, PSA_HASH_MAX_SIZE);
-
- psa_hash_abort(&operation);
- psa_hash_abort(&aux_operation);
- return PSA_TO_MBEDTLS_ERR(status);
-}
-
-#undef MAX_HASH_BLOCK_LENGTH
-
-#else
-int mbedtls_ct_hmac(mbedtls_md_context_t *ctx,
- const unsigned char *add_data,
- size_t add_data_len,
- const unsigned char *data,
- size_t data_len_secret,
- size_t min_data_len,
- size_t max_data_len,
- unsigned char *output)
-{
- /*
- * This function breaks the HMAC abstraction and uses the md_clone()
- * extension to the MD API in order to get constant-flow behaviour.
- *
- * HMAC(msg) is defined as HASH(okey + HASH(ikey + msg)) where + means
- * concatenation, and okey/ikey are the XOR of the key with some fixed bit
- * patterns (see RFC 2104, sec. 2), which are stored in ctx->hmac_ctx.
- *
- * We'll first compute inner_hash = HASH(ikey + msg) by hashing up to
- * minlen, then cloning the context, and for each byte up to maxlen
- * finishing up the hash computation, keeping only the correct result.
- *
- * Then we only need to compute HASH(okey + inner_hash) and we're done.
- */
- const mbedtls_md_type_t md_alg = mbedtls_md_get_type(ctx->md_info);
- /* TLS 1.2 only supports SHA-384, SHA-256, SHA-1, MD-5,
- * all of which have the same block size except SHA-384. */
- const size_t block_size = md_alg == MBEDTLS_MD_SHA384 ? 128 : 64;
- const unsigned char * const ikey = ctx->hmac_ctx;
- const unsigned char * const okey = ikey + block_size;
- const size_t hash_size = mbedtls_md_get_size(ctx->md_info);
-
- unsigned char aux_out[MBEDTLS_MD_MAX_SIZE];
- mbedtls_md_context_t aux;
- size_t offset;
- int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
-
- mbedtls_md_init(&aux);
-
-#define MD_CHK(func_call) \
- do { \
- ret = (func_call); \
- if (ret != 0) \
- goto cleanup; \
- } while (0)
-
- MD_CHK(mbedtls_md_setup(&aux, ctx->md_info, 0));
-
- /* After hmac_start() of hmac_reset(), ikey has already been hashed,
- * so we can start directly with the message */
- MD_CHK(mbedtls_md_update(ctx, add_data, add_data_len));
- MD_CHK(mbedtls_md_update(ctx, data, min_data_len));
-
- /* Fill the hash buffer in advance with something that is
- * not a valid hash (barring an attack on the hash and
- * deliberately-crafted input), in case the caller doesn't
- * check the return status properly. */
- memset(output, '!', hash_size);
-
- /* For each possible length, compute the hash up to that point */
- for (offset = min_data_len; offset <= max_data_len; offset++) {
- MD_CHK(mbedtls_md_clone(&aux, ctx));
- MD_CHK(mbedtls_md_finish(&aux, aux_out));
- /* Keep only the correct inner_hash in the output buffer */
- mbedtls_ct_memcpy_if_eq(output, aux_out, hash_size,
- offset, data_len_secret);
-
- if (offset < max_data_len) {
- MD_CHK(mbedtls_md_update(ctx, data + offset, 1));
- }
- }
-
- /* The context needs to finish() before it starts() again */
- MD_CHK(mbedtls_md_finish(ctx, aux_out));
-
- /* Now compute HASH(okey + inner_hash) */
- MD_CHK(mbedtls_md_starts(ctx));
- MD_CHK(mbedtls_md_update(ctx, okey, block_size));
- MD_CHK(mbedtls_md_update(ctx, output, hash_size));
- MD_CHK(mbedtls_md_finish(ctx, output));
-
- /* Done, get ready for next time */
- MD_CHK(mbedtls_md_hmac_reset(ctx));
-
-#undef MD_CHK
-
-cleanup:
- mbedtls_md_free(&aux);
- return ret;
-}
-#endif /* MBEDTLS_USE_PSA_CRYPTO */
-
-#endif /* MBEDTLS_SSL_SOME_SUITES_USE_MAC */
-
-#if defined(MBEDTLS_BIGNUM_C)
-
-#define MPI_VALIDATE_RET(cond) \
- MBEDTLS_INTERNAL_VALIDATE_RET(cond, MBEDTLS_ERR_MPI_BAD_INPUT_DATA)
-
-/*
- * Conditionally assign X = Y, without leaking information
- * about whether the assignment was made or not.
- * (Leaking information about the respective sizes of X and Y is ok however.)
- */
-#if defined(_MSC_VER) && defined(_M_ARM64) && (_MSC_FULL_VER < 193131103)
-/*
- * MSVC miscompiles this function if it's inlined prior to Visual Studio 2022 version 17.1. See:
- * https://developercommunity.visualstudio.com/t/c-compiler-miscompiles-part-of-mbedtls-library-on/1646989
- */
-__declspec(noinline)
-#endif
-int mbedtls_mpi_safe_cond_assign(mbedtls_mpi *X,
- const mbedtls_mpi *Y,
- unsigned char assign)
-{
- int ret = 0;
- MPI_VALIDATE_RET(X != NULL);
- MPI_VALIDATE_RET(Y != NULL);
-
- /* all-bits 1 if assign is 1, all-bits 0 if assign is 0 */
- mbedtls_mpi_uint limb_mask = mbedtls_ct_mpi_uint_mask(assign);
-
- MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, Y->n));
-
- X->s = (int) mbedtls_ct_uint_if(assign, Y->s, X->s);
-
- mbedtls_mpi_core_cond_assign(X->p, Y->p, Y->n, assign);
-
- for (size_t i = Y->n; i < X->n; i++) {
- X->p[i] &= ~limb_mask;
- }
-
-cleanup:
- return ret;
-}
-
-/*
- * Conditionally swap X and Y, without leaking information
- * about whether the swap was made or not.
- * Here it is not ok to simply swap the pointers, which would lead to
- * different memory access patterns when X and Y are used afterwards.
- */
-int mbedtls_mpi_safe_cond_swap(mbedtls_mpi *X,
- mbedtls_mpi *Y,
- unsigned char swap)
-{
- int ret = 0;
- int s;
- MPI_VALIDATE_RET(X != NULL);
- MPI_VALIDATE_RET(Y != NULL);
-
- if (X == Y) {
- return 0;
- }
-
- MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, Y->n));
- MBEDTLS_MPI_CHK(mbedtls_mpi_grow(Y, X->n));
-
- s = X->s;
- X->s = (int) mbedtls_ct_uint_if(swap, Y->s, X->s);
- Y->s = (int) mbedtls_ct_uint_if(swap, s, Y->s);
-
- mbedtls_mpi_core_cond_swap(X->p, Y->p, X->n, swap);
-
-cleanup:
- return ret;
-}
-
-/*
- * Compare unsigned values in constant time
- */
-unsigned mbedtls_mpi_core_lt_ct(const mbedtls_mpi_uint *A,
- const mbedtls_mpi_uint *B,
- size_t limbs)
-{
- unsigned ret, cond, done;
-
- /* The value of any of these variables is either 0 or 1 for the rest of
- * their scope. */
- ret = cond = done = 0;
-
- for (size_t i = limbs; i > 0; i--) {
- /*
- * If B[i - 1] < A[i - 1] then A < B is false and the result must
- * remain 0.
- *
- * Again even if we can make a decision, we just mark the result and
- * the fact that we are done and continue looping.
- */
- cond = mbedtls_ct_mpi_uint_lt(B[i - 1], A[i - 1]);
- done |= cond;
-
- /*
- * If A[i - 1] < B[i - 1] then A < B is true.
- *
- * Again even if we can make a decision, we just mark the result and
- * the fact that we are done and continue looping.
- */
- cond = mbedtls_ct_mpi_uint_lt(A[i - 1], B[i - 1]);
- ret |= cond & (1 - done);
- done |= cond;
- }
-
- /*
- * If all the limbs were equal, then the numbers are equal, A < B is false
- * and leaving the result 0 is correct.
- */
-
- return ret;
-}
-
-/*
- * Compare signed values in constant time
- */
-int mbedtls_mpi_lt_mpi_ct(const mbedtls_mpi *X,
- const mbedtls_mpi *Y,
- unsigned *ret)
-{
- size_t i;
- /* The value of any of these variables is either 0 or 1 at all times. */
- unsigned cond, done, X_is_negative, Y_is_negative;
-
- MPI_VALIDATE_RET(X != NULL);
- MPI_VALIDATE_RET(Y != NULL);
- MPI_VALIDATE_RET(ret != NULL);
-
- if (X->n != Y->n) {
- return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
- }
-
- /*
- * Set sign_N to 1 if N >= 0, 0 if N < 0.
- * We know that N->s == 1 if N >= 0 and N->s == -1 if N < 0.
- */
- X_is_negative = (X->s & 2) >> 1;
- Y_is_negative = (Y->s & 2) >> 1;
-
- /*
- * If the signs are different, then the positive operand is the bigger.
- * That is if X is negative (X_is_negative == 1), then X < Y is true and it
- * is false if X is positive (X_is_negative == 0).
- */
- cond = (X_is_negative ^ Y_is_negative);
- *ret = cond & X_is_negative;
-
- /*
- * This is a constant-time function. We might have the result, but we still
- * need to go through the loop. Record if we have the result already.
- */
- done = cond;
-
- for (i = X->n; i > 0; i--) {
- /*
- * If Y->p[i - 1] < X->p[i - 1] then X < Y is true if and only if both
- * X and Y are negative.
- *
- * Again even if we can make a decision, we just mark the result and
- * the fact that we are done and continue looping.
- */
- cond = mbedtls_ct_mpi_uint_lt(Y->p[i - 1], X->p[i - 1]);
- *ret |= cond & (1 - done) & X_is_negative;
- done |= cond;
-
- /*
- * If X->p[i - 1] < Y->p[i - 1] then X < Y is true if and only if both
- * X and Y are positive.
- *
- * Again even if we can make a decision, we just mark the result and
- * the fact that we are done and continue looping.
- */
- cond = mbedtls_ct_mpi_uint_lt(X->p[i - 1], Y->p[i - 1]);
- *ret |= cond & (1 - done) & (1 - X_is_negative);
- done |= cond;
- }
-
- return 0;
-}
-
-#endif /* MBEDTLS_BIGNUM_C */
-
#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT)
-int mbedtls_ct_rsaes_pkcs1_v15_unpadding(unsigned char *input,
- size_t ilen,
- unsigned char *output,
- size_t output_max_len,
- size_t *olen)
+void mbedtls_ct_zeroize_if(mbedtls_ct_condition_t condition, void *buf, size_t len)
{
- int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
- size_t i, plaintext_max_size;
-
- /* The following variables take sensitive values: their value must
- * not leak into the observable behavior of the function other than
- * the designated outputs (output, olen, return value). Otherwise
- * this would open the execution of the function to
- * side-channel-based variants of the Bleichenbacher padding oracle
- * attack. Potential side channels include overall timing, memory
- * access patterns (especially visible to an adversary who has access
- * to a shared memory cache), and branches (especially visible to
- * an adversary who has access to a shared code cache or to a shared
- * branch predictor). */
- size_t pad_count = 0;
- unsigned bad = 0;
- unsigned char pad_done = 0;
- size_t plaintext_size = 0;
- unsigned output_too_large;
-
- plaintext_max_size = (output_max_len > ilen - 11) ? ilen - 11
- : output_max_len;
-
- /* Check and get padding length in constant time and constant
- * memory trace. The first byte must be 0. */
- bad |= input[0];
-
-
- /* Decode EME-PKCS1-v1_5 padding: 0x00 || 0x02 || PS || 0x00
- * where PS must be at least 8 nonzero bytes. */
- bad |= input[1] ^ MBEDTLS_RSA_CRYPT;
-
- /* Read the whole buffer. Set pad_done to nonzero if we find
- * the 0x00 byte and remember the padding length in pad_count. */
- for (i = 2; i < ilen; i++) {
- pad_done |= ((input[i] | (unsigned char) -input[i]) >> 7) ^ 1;
- pad_count += ((pad_done | (unsigned char) -pad_done) >> 7) ^ 1;
+ uint32_t mask = (uint32_t) ~condition;
+ uint8_t *p = (uint8_t *) buf;
+ size_t i = 0;
+#if defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS)
+ for (; (i + 4) <= len; i += 4) {
+ mbedtls_put_unaligned_uint32((void *) (p + i),
+ mbedtls_get_unaligned_uint32((void *) (p + i)) & mask);
}
-
-
- /* If pad_done is still zero, there's no data, only unfinished padding. */
- bad |= mbedtls_ct_uint_if(pad_done, 0, 1);
-
- /* There must be at least 8 bytes of padding. */
- bad |= mbedtls_ct_size_gt(8, pad_count);
-
- /* If the padding is valid, set plaintext_size to the number of
- * remaining bytes after stripping the padding. If the padding
- * is invalid, avoid leaking this fact through the size of the
- * output: use the maximum message size that fits in the output
- * buffer. Do it without branches to avoid leaking the padding
- * validity through timing. RSA keys are small enough that all the
- * size_t values involved fit in unsigned int. */
- plaintext_size = mbedtls_ct_uint_if(
- bad, (unsigned) plaintext_max_size,
- (unsigned) (ilen - pad_count - 3));
-
- /* Set output_too_large to 0 if the plaintext fits in the output
- * buffer and to 1 otherwise. */
- output_too_large = mbedtls_ct_size_gt(plaintext_size,
- plaintext_max_size);
-
- /* Set ret without branches to avoid timing attacks. Return:
- * - INVALID_PADDING if the padding is bad (bad != 0).
- * - OUTPUT_TOO_LARGE if the padding is good but the decrypted
- * plaintext does not fit in the output buffer.
- * - 0 if the padding is correct. */
- ret = -(int) mbedtls_ct_uint_if(
- bad, -MBEDTLS_ERR_RSA_INVALID_PADDING,
- mbedtls_ct_uint_if(output_too_large,
- -MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE,
- 0));
-
- /* If the padding is bad or the plaintext is too large, zero the
- * data that we're about to copy to the output buffer.
- * We need to copy the same amount of data
- * from the same buffer whether the padding is good or not to
- * avoid leaking the padding validity through overall timing or
- * through memory or cache access patterns. */
- bad = mbedtls_ct_uint_mask(bad | output_too_large);
- for (i = 11; i < ilen; i++) {
- input[i] &= ~bad;
+#endif
+ for (; i < len; i++) {
+ p[i] = p[i] & mask;
}
-
- /* If the plaintext is too large, truncate it to the buffer size.
- * Copy anyway to avoid revealing the length through timing, because
- * revealing the length is as bad as revealing the padding validity
- * for a Bleichenbacher attack. */
- plaintext_size = mbedtls_ct_uint_if(output_too_large,
- (unsigned) plaintext_max_size,
- (unsigned) plaintext_size);
-
- /* Move the plaintext to the leftmost position where it can start in
- * the working buffer, i.e. make it start plaintext_max_size from
- * the end of the buffer. Do this with a memory access trace that
- * does not depend on the plaintext size. After this move, the
- * starting location of the plaintext is no longer sensitive
- * information. */
- mbedtls_ct_mem_move_to_left(input + ilen - plaintext_max_size,
- plaintext_max_size,
- plaintext_max_size - plaintext_size);
-
- /* Finally copy the decrypted plaintext plus trailing zeros into the output
- * buffer. If output_max_len is 0, then output may be an invalid pointer
- * and the result of memcpy() would be undefined; prevent undefined
- * behavior making sure to depend only on output_max_len (the size of the
- * user-provided output buffer), which is independent from plaintext
- * length, validity of padding, success of the decryption, and other
- * secrets. */
- if (output_max_len != 0) {
- memcpy(output, input + ilen - plaintext_max_size, plaintext_max_size);
- }
-
- /* Report the amount of data we copied to the output buffer. In case
- * of errors (bad padding or output too large), the value of *olen
- * when this function returns is not specified. Making it equivalent
- * to the good case limits the risks of leaking the padding validity. */
- *olen = plaintext_size;
-
- return ret;
}
-#endif /* MBEDTLS_PKCS1_V15 && MBEDTLS_RSA_C && ! MBEDTLS_RSA_ALT */
+#endif /* defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) */
diff --git a/library/constant_time_impl.h b/library/constant_time_impl.h
new file mode 100644
index 0000000..91418e5
--- /dev/null
+++ b/library/constant_time_impl.h
@@ -0,0 +1,279 @@
+/**
+ * Constant-time functions
+ *
+ * For readability, the static inline definitions are here, and
+ * constant_time_internal.h has only the declarations.
+ *
+ * This results in duplicate declarations of the form:
+ * static inline void f() { ... }
+ * static inline void f();
+ * when constant_time_internal.h is included. This appears to behave
+ * exactly as if the declaration-without-definition was not present.
+ *
+ * Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MBEDTLS_CONSTANT_TIME_IMPL_H
+#define MBEDTLS_CONSTANT_TIME_IMPL_H
+
+#include <stddef.h>
+
+#include "common.h"
+
+#if defined(MBEDTLS_BIGNUM_C)
+#include "mbedtls/bignum.h"
+#endif
+
+
+/* Disable asm under Memsan because it confuses Memsan and generates false errors */
+#if defined(MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN)
+#define MBEDTLS_CT_NO_ASM
+#elif defined(__has_feature)
+#if __has_feature(memory_sanitizer)
+#define MBEDTLS_CT_NO_ASM
+#endif
+#endif
+
+/* armcc5 --gnu defines __GNUC__ but doesn't support GNU's extended asm */
+#if defined(MBEDTLS_HAVE_ASM) && defined(__GNUC__) && (!defined(__ARMCC_VERSION) || \
+ __ARMCC_VERSION >= 6000000) && !defined(MBEDTLS_CT_NO_ASM)
+#define MBEDTLS_CT_ASM
+#if (defined(__arm__) || defined(__thumb__) || defined(__thumb2__))
+#define MBEDTLS_CT_ARM_ASM
+#elif defined(__aarch64__)
+#define MBEDTLS_CT_AARCH64_ASM
+#endif
+#endif
+
+#define MBEDTLS_CT_SIZE (sizeof(mbedtls_ct_uint_t) * 8)
+
+
+/* ============================================================================
+ * Core const-time primitives
+ */
+
+/* Ensure that the compiler cannot know the value of x (i.e., cannot optimise
+ * based on its value) after this function is called.
+ *
+ * If we are not using assembly, this will be fairly inefficient, so its use
+ * should be minimised.
+ */
+
+#if !defined(MBEDTLS_CT_ASM)
+extern volatile mbedtls_ct_uint_t mbedtls_ct_zero;
+#endif
+
+static inline mbedtls_ct_uint_t mbedtls_ct_compiler_opaque(mbedtls_ct_uint_t x)
+{
+#if defined(MBEDTLS_CT_ASM)
+ asm volatile ("" : [x] "+r" (x) :);
+ return x;
+#else
+ return x ^ mbedtls_ct_zero;
+#endif
+}
+
+/* Convert a number into a condition in constant time. */
+static inline mbedtls_ct_condition_t mbedtls_ct_bool(mbedtls_ct_uint_t x)
+{
+ /*
+ * Define mask-generation code that, as far as possible, will not use branches or conditional instructions.
+ *
+ * For some platforms / type sizes, we define assembly to assure this.
+ *
+ * Otherwise, we define a plain C fallback which (in May 2023) does not get optimised into
+ * conditional instructions or branches by trunk clang, gcc, or MSVC v19.
+ */
+ const mbedtls_ct_uint_t xo = mbedtls_ct_compiler_opaque(x);
+#if defined(_MSC_VER)
+ /* MSVC has a warning about unary minus on unsigned, but this is
+ * well-defined and precisely what we want to do here */
+#pragma warning( push )
+#pragma warning( disable : 4146 )
+#endif
+ return (mbedtls_ct_condition_t) (((mbedtls_ct_int_t) ((-xo) | -(xo >> 1))) >>
+ (MBEDTLS_CT_SIZE - 1));
+#if defined(_MSC_VER)
+#pragma warning( pop )
+#endif
+}
+
+static inline mbedtls_ct_uint_t mbedtls_ct_if(mbedtls_ct_condition_t condition,
+ mbedtls_ct_uint_t if1,
+ mbedtls_ct_uint_t if0)
+{
+ mbedtls_ct_condition_t not_cond =
+ (mbedtls_ct_condition_t) (~mbedtls_ct_compiler_opaque(condition));
+ return (mbedtls_ct_uint_t) ((condition & if1) | (not_cond & if0));
+}
+
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_lt(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y)
+{
+ /* Ensure that the compiler cannot optimise the following operations over x and y,
+ * even if it knows the value of x and y.
+ */
+ const mbedtls_ct_uint_t xo = mbedtls_ct_compiler_opaque(x);
+ const mbedtls_ct_uint_t yo = mbedtls_ct_compiler_opaque(y);
+ /*
+ * Check if the most significant bits (MSB) of the operands are different.
+ * cond is true iff the MSBs differ.
+ */
+ mbedtls_ct_condition_t cond = mbedtls_ct_bool((xo ^ yo) >> (MBEDTLS_CT_SIZE - 1));
+
+ /*
+ * If the MSB are the same then the difference x-y will be negative (and
+ * have its MSB set to 1 during conversion to unsigned) if and only if x<y.
+ *
+ * If the MSB are different, then the operand with the MSB of 1 is the
+ * bigger. (That is if y has MSB of 1, then x<y is true and it is false if
+ * the MSB of y is 0.)
+ */
+
+ // Select either y, or x - y
+ mbedtls_ct_uint_t ret = mbedtls_ct_if(cond, yo, (mbedtls_ct_uint_t) (xo - yo));
+
+ // Extract only the MSB of ret
+ ret = ret >> (MBEDTLS_CT_SIZE - 1);
+
+ // Convert to a condition (i.e., all bits set iff non-zero)
+ return mbedtls_ct_bool(ret);
+}
+
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_ne(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y)
+{
+ /* diff = 0 if x == y, non-zero otherwise */
+ const mbedtls_ct_uint_t diff = mbedtls_ct_compiler_opaque(x) ^ mbedtls_ct_compiler_opaque(y);
+
+ /* all ones if x != y, 0 otherwise */
+ return mbedtls_ct_bool(diff);
+}
+
+static inline unsigned char mbedtls_ct_uchar_in_range_if(unsigned char low,
+ unsigned char high,
+ unsigned char c,
+ unsigned char t)
+{
+ const unsigned char co = (const unsigned char) mbedtls_ct_compiler_opaque(c);
+ const unsigned char to = (const unsigned char) mbedtls_ct_compiler_opaque(t);
+
+ /* low_mask is: 0 if low <= c, 0x...ff if low > c */
+ unsigned low_mask = ((unsigned) co - low) >> 8;
+ /* high_mask is: 0 if c <= high, 0x...ff if c > high */
+ unsigned high_mask = ((unsigned) high - co) >> 8;
+
+ return (unsigned char) (~(low_mask | high_mask)) & to;
+}
+
+
+/* ============================================================================
+ * Everything below here is trivial wrapper functions
+ */
+
+static inline size_t mbedtls_ct_size_if(mbedtls_ct_condition_t condition,
+ size_t if1,
+ size_t if0)
+{
+ return (size_t) mbedtls_ct_if(condition, (mbedtls_ct_uint_t) if1, (mbedtls_ct_uint_t) if0);
+}
+
+static inline unsigned mbedtls_ct_uint_if(mbedtls_ct_condition_t condition,
+ unsigned if1,
+ unsigned if0)
+{
+ return (unsigned) mbedtls_ct_if(condition, (mbedtls_ct_uint_t) if1, (mbedtls_ct_uint_t) if0);
+}
+
+#if defined(MBEDTLS_BIGNUM_C)
+
+static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if(mbedtls_ct_condition_t condition,
+ mbedtls_mpi_uint if1,
+ mbedtls_mpi_uint if0)
+{
+ return (mbedtls_mpi_uint) mbedtls_ct_if(condition,
+ (mbedtls_ct_uint_t) if1,
+ (mbedtls_ct_uint_t) if0);
+}
+
+#endif
+
+static inline size_t mbedtls_ct_size_if0(mbedtls_ct_condition_t condition, size_t if1)
+{
+ return (size_t) (condition & if1);
+}
+
+static inline unsigned mbedtls_ct_uint_if0(mbedtls_ct_condition_t condition, unsigned if1)
+{
+ return (unsigned) (condition & if1);
+}
+
+#if defined(MBEDTLS_BIGNUM_C)
+
+static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if0(mbedtls_ct_condition_t condition,
+ mbedtls_mpi_uint if1)
+{
+ return (mbedtls_mpi_uint) (condition & if1);
+}
+
+#endif /* MBEDTLS_BIGNUM_C */
+
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_eq(mbedtls_ct_uint_t x,
+ mbedtls_ct_uint_t y)
+{
+ return ~mbedtls_ct_bool_ne(x, y);
+}
+
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_gt(mbedtls_ct_uint_t x,
+ mbedtls_ct_uint_t y)
+{
+ return mbedtls_ct_bool_lt(y, x);
+}
+
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_ge(mbedtls_ct_uint_t x,
+ mbedtls_ct_uint_t y)
+{
+ return ~mbedtls_ct_bool_lt(x, y);
+}
+
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_le(mbedtls_ct_uint_t x,
+ mbedtls_ct_uint_t y)
+{
+ return ~mbedtls_ct_bool_gt(x, y);
+}
+
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_xor(mbedtls_ct_condition_t x,
+ mbedtls_ct_condition_t y)
+{
+ return (mbedtls_ct_condition_t) (x ^ y);
+}
+
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_and(mbedtls_ct_condition_t x,
+ mbedtls_ct_condition_t y)
+{
+ return (mbedtls_ct_condition_t) (x & y);
+}
+
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_or(mbedtls_ct_condition_t x,
+ mbedtls_ct_condition_t y)
+{
+ return (mbedtls_ct_condition_t) (x | y);
+}
+
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_not(mbedtls_ct_condition_t x)
+{
+ return (mbedtls_ct_condition_t) (~x);
+}
+
+#endif /* MBEDTLS_CONSTANT_TIME_IMPL_H */
diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h
index c4a32c7..9660758 100644
--- a/library/constant_time_internal.h
+++ b/library/constant_time_internal.h
@@ -20,224 +20,427 @@
#ifndef MBEDTLS_CONSTANT_TIME_INTERNAL_H
#define MBEDTLS_CONSTANT_TIME_INTERNAL_H
+#include <stdint.h>
+#include <stddef.h>
+
#include "common.h"
#if defined(MBEDTLS_BIGNUM_C)
#include "mbedtls/bignum.h"
#endif
-#if defined(MBEDTLS_SSL_TLS_C)
-#include "ssl_misc.h"
+/* The constant-time interface provides various operations that are likely
+ * to result in constant-time code that does not branch or use conditional
+ * instructions for secret data (for secret pointers, this also applies to
+ * the data pointed to).
+ *
+ * It has three main parts:
+ *
+ * - boolean operations
+ * These are all named mbedtls_ct_bool_<operation>, and operate over
+ * mbedtls_ct_condition_t.
+ * All arguments are considered secret.
+ * example: bool x = y | z => x = mbedtls_ct_bool_or(y, z)
+ *
+ * - conditional data selection
+ * These are all named mbedtls_ct_<type>_if and mbedtls_ct_<type>_if0
+ * All arguments are considered secret.
+ * example: size_t a = x ? b : c => a = mbedtls_ct_size_if(x, b, c)
+ * example: unsigned a = x ? b : 0 => a = mbedtls_ct_uint_if0(x, b)
+ *
+ * - block memory operations
+ * Only some arguments are considered secret, as documented for each
+ * function.
+ * example: if (x) memcpy(...) => mbedtls_ct_memcpy_if(x, ...)
+ *
+ * mbedtls_ct_condition_t should be treated as opaque and only manipulated
+ * via the functions in this header.
+ *
+ * mbedtls_ct_uint_t is an unsigned integer type over which constant time
+ * operations may be performed via the functions in this header. It is as big
+ * as the larger of size_t and mbedtls_mpi_uint, i.e. it is safe to cast
+ * to/from "unsigned int", "size_t", and "mbedtls_mpi_uint" (and any other
+ * not-larger integer types).
+ *
+ * For Arm (32-bit, 64-bit and Thumb), x86 and x86-64, assembly implementations
+ * are used to ensure that the generated code is constant time. For other
+ * architectures, a plain C fallback designed to yield constant-time code (this
+ * has been observed to be constant-time on latest gcc, clang and MSVC as of
+ * May 2023).
+ */
+
+#if (SIZE_MAX > 0xffffffffffffffffULL)
+/* Pointer size > 64-bit */
+typedef size_t mbedtls_ct_condition_t;
+typedef size_t mbedtls_ct_uint_t;
+typedef ptrdiff_t mbedtls_ct_int_t;
+#define MBEDTLS_CT_TRUE ((mbedtls_ct_condition_t) SIZE_MAX)
+#elif (SIZE_MAX > 0xffffffff) || defined(MBEDTLS_HAVE_INT64)
+/* 32-bit < pointer size <= 64-bit, or 64-bit MPI */
+typedef uint64_t mbedtls_ct_condition_t;
+typedef uint64_t mbedtls_ct_uint_t;
+typedef int64_t mbedtls_ct_int_t;
+#define MBEDTLS_CT_TRUE ((mbedtls_ct_condition_t) UINT64_MAX)
+#else
+/* Pointer size <= 32-bit, and no 64-bit MPIs */
+typedef uint32_t mbedtls_ct_condition_t;
+typedef uint32_t mbedtls_ct_uint_t;
+typedef int32_t mbedtls_ct_int_t;
+#define MBEDTLS_CT_TRUE ((mbedtls_ct_condition_t) UINT32_MAX)
#endif
+#define MBEDTLS_CT_FALSE ((mbedtls_ct_condition_t) 0)
-#include <stddef.h>
-
-
-/** Turn a value into a mask:
- * - if \p value == 0, return the all-bits 0 mask, aka 0
- * - otherwise, return the all-bits 1 mask, aka (unsigned) -1
- *
- * This function can be used to write constant-time code by replacing branches
- * with bit operations using masks.
- *
- * \param value The value to analyze.
- *
- * \return Zero if \p value is zero, otherwise all-bits-one.
+/* constant_time_impl.h contains all the static inline implementations,
+ * so that constant_time_internal.h is more readable.
*/
-unsigned mbedtls_ct_uint_mask(unsigned value);
+#include "constant_time_impl.h"
-#if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC)
-/** Turn a value into a mask:
- * - if \p value == 0, return the all-bits 0 mask, aka 0
- * - otherwise, return the all-bits 1 mask, aka (size_t) -1
- *
- * This function can be used to write constant-time code by replacing branches
- * with bit operations using masks.
- *
- * \param value The value to analyze.
- *
- * \return Zero if \p value is zero, otherwise all-bits-one.
+/* ============================================================================
+ * Boolean operations
*/
-size_t mbedtls_ct_size_mask(size_t value);
-#endif /* MBEDTLS_SSL_SOME_SUITES_USE_MAC */
-
-#if defined(MBEDTLS_BIGNUM_C)
-
-/** Turn a value into a mask:
- * - if \p value == 0, return the all-bits 0 mask, aka 0
- * - otherwise, return the all-bits 1 mask, aka (mbedtls_mpi_uint) -1
+/** Convert a number into a mbedtls_ct_condition_t.
*
- * This function can be used to write constant-time code by replacing branches
- * with bit operations using masks.
+ * \param x Number to convert.
*
- * \param value The value to analyze.
+ * \return MBEDTLS_CT_TRUE if \p x != 0, or MBEDTLS_CT_FALSE if \p x == 0
*
- * \return Zero if \p value is zero, otherwise all-bits-one.
*/
-mbedtls_mpi_uint mbedtls_ct_mpi_uint_mask(mbedtls_mpi_uint value);
+static inline mbedtls_ct_condition_t mbedtls_ct_bool(mbedtls_ct_uint_t x);
-#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
+/** Boolean "not equal" operation.
*
- * This function can be used to write constant-time code by replacing branches
- * with bit operations using masks.
+ * Functionally equivalent to:
+ *
+ * \p x != \p y
*
* \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.
+ * \return MBEDTLS_CT_TRUE if \p x != \p y, otherwise MBEDTLS_CT_FALSE.
*/
-size_t mbedtls_ct_size_mask_ge(size_t x,
- size_t y);
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_ne(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y);
-#endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */
-
-/** Constant-flow boolean "equal" comparison:
- * return x == y
+/** Boolean "equals" operation.
*
- * This is equivalent to \p x == \p y, but is likely to be compiled
- * to code using bitwise operation rather than a branch.
+ * Functionally equivalent to:
+ *
+ * \p x == \p y
*
* \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.
+ * \return MBEDTLS_CT_TRUE if \p x == \p y, otherwise MBEDTLS_CT_FALSE.
*/
-unsigned mbedtls_ct_size_bool_eq(size_t x,
- size_t y);
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_eq(mbedtls_ct_uint_t x,
+ mbedtls_ct_uint_t y);
-#if defined(MBEDTLS_BIGNUM_C)
-
-/** Decide if an integer is less than the other, without branches.
+/** Boolean "less than" operation.
*
- * This is equivalent to \p x < \p y, but is likely to be compiled
- * to code using bitwise operation rather than a branch.
+ * Functionally equivalent to:
+ *
+ * \p x < \p y
*
* \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.
+ * \return MBEDTLS_CT_TRUE if \p x < \p y, otherwise MBEDTLS_CT_FALSE.
*/
-unsigned mbedtls_ct_mpi_uint_lt(const mbedtls_mpi_uint x,
- const mbedtls_mpi_uint y);
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_lt(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y);
-/**
- * \brief Check if one unsigned MPI is less than another in constant
- * time.
+/** Boolean "greater than" operation.
*
- * \param A The left-hand MPI. This must point to an array of limbs
- * with the same allocated length as \p B.
- * \param B The right-hand MPI. This must point to an array of limbs
- * with the same allocated length as \p A.
- * \param limbs The number of limbs in \p A and \p B.
- * This must not be 0.
+ * Functionally equivalent to:
*
- * \return The result of the comparison:
- * \c 1 if \p A is less than \p B.
- * \c 0 if \p A is greater than or equal to \p B.
+ * \p x > \p y
+ *
+ * \param x The first value to analyze.
+ * \param y The second value to analyze.
+ *
+ * \return MBEDTLS_CT_TRUE if \p x > \p y, otherwise MBEDTLS_CT_FALSE.
*/
-unsigned mbedtls_mpi_core_lt_ct(const mbedtls_mpi_uint *A,
- const mbedtls_mpi_uint *B,
- size_t limbs);
-#endif /* MBEDTLS_BIGNUM_C */
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_gt(mbedtls_ct_uint_t x,
+ mbedtls_ct_uint_t y);
-/** Choose between two integer values without branches.
+/** Boolean "greater or equal" operation.
*
- * This is equivalent to `condition ? if1 : if0`, but is likely to be compiled
- * to code using bitwise operation rather than a branch.
+ * Functionally equivalent to:
+ *
+ * \p x >= \p y
+ *
+ * \param x The first value to analyze.
+ * \param y The second value to analyze.
+ *
+ * \return MBEDTLS_CT_TRUE if \p x >= \p y,
+ * otherwise MBEDTLS_CT_FALSE.
+ */
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_ge(mbedtls_ct_uint_t x,
+ mbedtls_ct_uint_t y);
+
+/** Boolean "less than or equal" operation.
+ *
+ * Functionally equivalent to:
+ *
+ * \p x <= \p y
+ *
+ * \param x The first value to analyze.
+ * \param y The second value to analyze.
+ *
+ * \return MBEDTLS_CT_TRUE if \p x <= \p y,
+ * otherwise MBEDTLS_CT_FALSE.
+ */
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_le(mbedtls_ct_uint_t x,
+ mbedtls_ct_uint_t y);
+
+/** Boolean "xor" operation.
+ *
+ * Functionally equivalent to:
+ *
+ * \p x ^ \p y
+ *
+ * \param x The first value to analyze.
+ * \param y The second value to analyze.
+ *
+ * \note This is more efficient than mbedtls_ct_bool_ne if both arguments are
+ * mbedtls_ct_condition_t.
+ *
+ * \return MBEDTLS_CT_TRUE if \p x ^ \p y,
+ * otherwise MBEDTLS_CT_FALSE.
+ */
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_xor(mbedtls_ct_condition_t x,
+ mbedtls_ct_condition_t y);
+
+/** Boolean "and" operation.
+ *
+ * Functionally equivalent to:
+ *
+ * \p x && \p y
+ *
+ * \param x The first value to analyze.
+ * \param y The second value to analyze.
+ *
+ * \return MBEDTLS_CT_TRUE if \p x && \p y,
+ * otherwise MBEDTLS_CT_FALSE.
+ */
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_and(mbedtls_ct_condition_t x,
+ mbedtls_ct_condition_t y);
+
+/** Boolean "or" operation.
+ *
+ * Functionally equivalent to:
+ *
+ * \p x || \p y
+ *
+ * \param x The first value to analyze.
+ * \param y The second value to analyze.
+ *
+ * \return MBEDTLS_CT_TRUE if \p x || \p y,
+ * otherwise MBEDTLS_CT_FALSE.
+ */
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_or(mbedtls_ct_condition_t x,
+ mbedtls_ct_condition_t y);
+
+/** Boolean "not" operation.
+ *
+ * Functionally equivalent to:
+ *
+ * ! \p x
+ *
+ * \param x The value to invert
+ *
+ * \return MBEDTLS_CT_FALSE if \p x, otherwise MBEDTLS_CT_TRUE.
+ */
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_not(mbedtls_ct_condition_t x);
+
+
+/* ============================================================================
+ * Data selection operations
+ */
+
+/** Choose between two size_t values.
+ *
+ * Functionally equivalent to:
+ *
+ * condition ? if1 : if0.
*
* \param condition Condition to test.
- * \param if1 Value to use if \p condition is nonzero.
- * \param if0 Value to use if \p condition is zero.
+ * \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 is nonzero, otherwise \c if0.
+ * \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise \c if0.
*/
-unsigned mbedtls_ct_uint_if(unsigned condition,
- unsigned if1,
- unsigned if0);
+static inline size_t mbedtls_ct_size_if(mbedtls_ct_condition_t condition,
+ size_t if1,
+ size_t if0);
+
+/** Choose between two unsigned values.
+ *
+ * Functionally equivalent to:
+ *
+ * condition ? if1 : if0.
+ *
+ * \param condition Condition to test.
+ * \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE.
+ * \param if0 Value to use if \p condition == MBEDTLS_CT_FALSE.
+ *
+ * \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise \c if0.
+ */
+static inline unsigned mbedtls_ct_uint_if(mbedtls_ct_condition_t condition,
+ unsigned if1,
+ unsigned if0);
#if defined(MBEDTLS_BIGNUM_C)
-/** Conditionally assign a value without branches.
+/** Choose between two mbedtls_mpi_uint values.
*
- * This is equivalent to `if ( condition ) dest = src`, but is likely
- * to be compiled to code using bitwise operation rather than a branch.
+ * Functionally equivalent to:
*
- * \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.
+ * 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.
*/
-void mbedtls_ct_mpi_uint_cond_assign(size_t n,
- mbedtls_mpi_uint *dest,
- const mbedtls_mpi_uint *src,
- unsigned char condition);
+static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if(mbedtls_ct_condition_t condition, \
+ mbedtls_mpi_uint if1, \
+ mbedtls_mpi_uint if0);
-#endif /* MBEDTLS_BIGNUM_C */
+#endif
-#if defined(MBEDTLS_BASE64_C)
-
-/** Given a value in the range 0..63, return the corresponding Base64 digit.
+/** Choose between an unsigned value and 0.
*
- * The implementation assumes that letters are consecutive (e.g. ASCII
- * but not EBCDIC).
+ * Functionally equivalent to:
*
- * \param value A value in the range 0..63.
+ * condition ? if1 : 0.
*
- * \return A base64 digit converted from \p value.
+ * Functionally equivalent tombedtls_ct_uint_if(condition, if1, 0) but
+ * results in smaller code size.
+ *
+ * \param condition Condition to test.
+ * \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE.
+ *
+ * \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise 0.
*/
-unsigned char mbedtls_ct_base64_enc_char(unsigned char value);
+static inline unsigned mbedtls_ct_uint_if0(mbedtls_ct_condition_t condition, unsigned if1);
-/** Given a Base64 digit, return its value.
+#if defined(MBEDTLS_BIGNUM_C)
+
+/** Choose between an mbedtls_mpi_uint value and 0.
*
- * If c is not a Base64 digit ('A'..'Z', 'a'..'z', '0'..'9', '+' or '/'),
- * return -1.
+ * Functionally equivalent to:
*
- * The implementation assumes that letters are consecutive (e.g. ASCII
- * but not EBCDIC).
+ * condition ? if1 : 0.
*
- * \param c A base64 digit.
+ * Functionally equivalent tombedtls_ct_mpi_uint_if(condition, if1, 0) but
+ * results in smaller code size.
*
- * \return The value of the base64 digit \p c.
+ * \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.
*/
-signed char mbedtls_ct_base64_dec_value(unsigned char c);
+static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if0(mbedtls_ct_condition_t condition,
+ mbedtls_mpi_uint if1);
-#endif /* MBEDTLS_BASE64_C */
+#endif
-#if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC)
-
-/** Conditional memcpy without branches.
+/** Constant-flow char selection
*
- * 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 low Secret. Bottom of range
+ * \param high Secret. Top of range
+ * \param c Secret. Value to compare to range
+ * \param t Secret. Value to return, if in range
*
- * \param dest The pointer to conditionally copy to.
- * \param src The pointer to copy from. Shouldn't overlap with \p dest.
- * \param len The number of bytes to copy.
- * \param c1 The first value to analyze in the condition.
- * \param c2 The second value to analyze in the condition.
+ * \return \p t if \p low <= \p c <= \p high, 0 otherwise.
*/
-void mbedtls_ct_memcpy_if_eq(unsigned char *dest,
- const unsigned char *src,
- size_t len,
- size_t c1, size_t c2);
+static inline unsigned char mbedtls_ct_uchar_in_range_if(unsigned char low,
+ unsigned char high,
+ unsigned char c,
+ unsigned char t);
-/** Copy data from a secret position with constant flow.
+
+/* ============================================================================
+ * Block memory operations
+ */
+
+#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT)
+
+/** Conditionally set a block of memory to zero.
*
- * 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)`.
+ * Regardless of the condition, every byte will be read once and written to
+ * once.
+ *
+ * \param condition Secret. Condition to test.
+ * \param buf Secret. Pointer to the start of the buffer.
+ * \param len Number of bytes to set to zero.
+ *
+ * \warning Unlike mbedtls_platform_zeroize, this does not have the same guarantees
+ * about not being optimised away if the memory is never read again.
+ */
+void mbedtls_ct_zeroize_if(mbedtls_ct_condition_t condition, void *buf, size_t len);
+
+/** Shift some data towards the left inside a buffer.
+ *
+ * Functionally equivalent to:
+ *
+ * memmove(start, start + offset, total - offset);
+ * memset(start + (total - offset), 0, offset);
+ *
+ * Timing independence comes at the expense of performance.
+ *
+ * \param start Secret. Pointer to the start of the buffer.
+ * \param total Total size of the buffer.
+ * \param offset Secret. Offset from which to copy \p total - \p offset bytes.
+ */
+void mbedtls_ct_memmove_left(void *start,
+ size_t total,
+ size_t offset);
+
+#endif /* defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) */
+
+/** Conditional memcpy.
+ *
+ * Functionally equivalent to:
+ *
+ * if (condition) {
+ * memcpy(dest, src1, len);
+ * } else {
+ * if (src2 != NULL)
+ * memcpy(dest, src2, len);
+ * }
+ *
+ * It will always read len bytes from src1.
+ * If src2 != NULL, it will always read len bytes from src2.
+ * If src2 == NULL, it will instead read len bytes from dest (as if src2 == dest).
+ *
+ * \param condition The condition
+ * \param dest Secret. Destination pointer.
+ * \param src1 Secret. Pointer to copy from (if \p condition == MBEDTLS_CT_TRUE).
+ * This may be equal to \p dest, but may not overlap in other ways.
+ * \param src2 Secret (contents only - may branch to test if src2 == NULL).
+ * Pointer to copy from (if \p condition == MBEDTLS_CT_FALSE and \p src2 is not NULL). May be NULL.
+ * This may be equal to \p dest, but may not overlap it in other ways. It may overlap with \p src1.
+ * \param len Number of bytes to copy.
+ */
+void mbedtls_ct_memcpy_if(mbedtls_ct_condition_t condition,
+ unsigned char *dest,
+ const unsigned char *src1,
+ const unsigned char *src2,
+ size_t len
+ );
+
+/** Copy data from a secret position.
+ *
+ * Functionally equivalent to:
+ *
+ * memcpy(dst, src + offset, len)
+ *
+ * This function copies \p len bytes from \p src_base + \p offset to \p
+ * dst, with a code flow and memory access pattern that does not depend on
+ * \p offset, but only on \p offset_min, \p offset_max and \p len.
*
* \note This function reads from \p dest, but the value that
* is read does not influence the result and this
@@ -246,12 +449,12 @@
* positives from static or dynamic analyzers, especially
* if \p dest is not initialized.
*
- * \param dest The destination buffer. This must point to a writable
+ * \param dest Secret. The destination buffer. This must point to a writable
* buffer of at least \p len bytes.
- * \param src The base of the source buffer. This must point to a
+ * \param src Secret. The base of the source buffer. This must point to a
* readable buffer of at least \p offset_max + \p len
- * bytes. Shouldn't overlap with \p dest.
- * \param offset The offset in the source buffer from which to copy.
+ * bytes. Shouldn't overlap with \p dest
+ * \param offset Secret. The offset in the source buffer from which to copy.
* This must be no less than \p offset_min and no greater
* than \p offset_max.
* \param offset_min The minimal value of \p offset.
@@ -265,99 +468,9 @@
size_t offset_max,
size_t len);
-/** Compute the HMAC of variable-length data with constant flow.
- *
- * This function computes the HMAC of the concatenation of \p add_data and \p
- * data, and does with a code flow and memory access pattern that does not
- * depend on \p data_len_secret, but only on \p min_data_len and \p
- * max_data_len. In particular, this function always reads exactly \p
- * max_data_len bytes from \p data.
- *
- * \param ctx The HMAC context. It must have keys configured
- * with mbedtls_md_hmac_starts() and use one of the
- * following hashes: SHA-384, SHA-256, SHA-1 or MD-5.
- * It is reset using mbedtls_md_hmac_reset() after
- * the computation is complete to prepare for the
- * next computation.
- * \param add_data The first part of the message whose HMAC is being
- * calculated. This must point to a readable buffer
- * of \p add_data_len bytes.
- * \param add_data_len The length of \p add_data in bytes.
- * \param data The buffer containing the second part of the
- * message. This must point to a readable buffer
- * of \p max_data_len bytes.
- * \param data_len_secret The length of the data to process in \p data.
- * This must be no less than \p min_data_len and no
- * greater than \p max_data_len.
- * \param min_data_len The minimal length of the second part of the
- * message, read from \p data.
- * \param max_data_len The maximal length of the second part of the
- * message, read from \p data.
- * \param output The HMAC will be written here. This must point to
- * a writable buffer of sufficient size to hold the
- * HMAC value.
- *
- * \retval 0 on success.
- * \retval #MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED
- * The hardware accelerator failed.
- */
-#if defined(MBEDTLS_USE_PSA_CRYPTO)
-int mbedtls_ct_hmac(mbedtls_svc_key_id_t key,
- psa_algorithm_t alg,
- const unsigned char *add_data,
- size_t add_data_len,
- const unsigned char *data,
- size_t data_len_secret,
- size_t min_data_len,
- size_t max_data_len,
- unsigned char *output);
-#else
-int mbedtls_ct_hmac(mbedtls_md_context_t *ctx,
- const unsigned char *add_data,
- size_t add_data_len,
- const unsigned char *data,
- size_t data_len_secret,
- size_t min_data_len,
- size_t max_data_len,
- unsigned char *output);
-#endif /* MBEDTLS_USE_PSA_CRYPTO */
-
-#endif /* MBEDTLS_SSL_SOME_SUITES_USE_MAC */
-
-#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT)
-
-/** This function performs the unpadding part of a PKCS#1 v1.5 decryption
- * operation (EME-PKCS1-v1_5 decoding).
- *
- * \note The return value from this function is a sensitive value
- * (this is unusual). #MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE shouldn't happen
- * in a well-written application, but 0 vs #MBEDTLS_ERR_RSA_INVALID_PADDING
- * is often a situation that an attacker can provoke and leaking which
- * one is the result is precisely the information the attacker wants.
- *
- * \param input The input buffer which is the payload inside PKCS#1v1.5
- * encryption padding, called the "encoded message EM"
- * by the terminology.
- * \param ilen The length of the payload in the \p input buffer.
- * \param output The buffer for the payload, called "message M" by the
- * PKCS#1 terminology. This must be a writable buffer of
- * length \p output_max_len bytes.
- * \param olen The address at which to store the length of
- * the payload. This must not be \c NULL.
- * \param output_max_len The length in bytes of the output buffer \p output.
- *
- * \return \c 0 on success.
- * \return #MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE
- * The output buffer is too small for the unpadded payload.
- * \return #MBEDTLS_ERR_RSA_INVALID_PADDING
- * The input doesn't contain properly formatted padding.
- */
-int mbedtls_ct_rsaes_pkcs1_v15_unpadding(unsigned char *input,
- size_t ilen,
- unsigned char *output,
- size_t output_max_len,
- size_t *olen);
-
-#endif /* MBEDTLS_PKCS1_V15 && MBEDTLS_RSA_C && ! MBEDTLS_RSA_ALT */
+/* Documented in include/mbedtls/constant_time.h. a and b are secret. */
+int mbedtls_ct_memcmp(const void *a,
+ const void *b,
+ size_t n);
#endif /* MBEDTLS_CONSTANT_TIME_INTERNAL_H */
diff --git a/library/constant_time_invasive.h b/library/constant_time_invasive.h
deleted file mode 100644
index c176b28..0000000
--- a/library/constant_time_invasive.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/**
- * \file constant_time_invasive.h
- *
- * \brief Constant-time module: interfaces for invasive testing only.
- *
- * The interfaces in this file are intended for testing purposes only.
- * They SHOULD NOT be made available in library integrations except when
- * building the library for testing.
- */
-/*
- * Copyright The Mbed TLS Contributors
- * SPDX-License-Identifier: Apache-2.0
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef MBEDTLS_CONSTANT_TIME_INVASIVE_H
-#define MBEDTLS_CONSTANT_TIME_INVASIVE_H
-
-#include "common.h"
-
-#if defined(MBEDTLS_TEST_HOOKS)
-
-/** Turn a value into a mask:
- * - if \p low <= \p c <= \p high,
- * return the all-bits 1 mask, aka (unsigned) -1
- * - otherwise, return the all-bits 0 mask, aka 0
- *
- * \param low The value to analyze.
- * \param high The value to analyze.
- * \param c The value to analyze.
- *
- * \return All-bits-one if \p low <= \p c <= \p high, otherwise zero.
- */
-unsigned char mbedtls_ct_uchar_mask_of_range(unsigned char low,
- unsigned char high,
- unsigned char c);
-
-#endif /* MBEDTLS_TEST_HOOKS */
-
-#endif /* MBEDTLS_CONSTANT_TIME_INVASIVE_H */
diff --git a/library/rsa.c b/library/rsa.c
index 8126ae9..4e85bbc 100644
--- a/library/rsa.c
+++ b/library/rsa.c
@@ -56,6 +56,164 @@
#include "mbedtls/platform.h"
+
+#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT)
+
+/** This function performs the unpadding part of a PKCS#1 v1.5 decryption
+ * operation (EME-PKCS1-v1_5 decoding).
+ *
+ * \note The return value from this function is a sensitive value
+ * (this is unusual). #MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE shouldn't happen
+ * in a well-written application, but 0 vs #MBEDTLS_ERR_RSA_INVALID_PADDING
+ * is often a situation that an attacker can provoke and leaking which
+ * one is the result is precisely the information the attacker wants.
+ *
+ * \param input The input buffer which is the payload inside PKCS#1v1.5
+ * encryption padding, called the "encoded message EM"
+ * by the terminology.
+ * \param ilen The length of the payload in the \p input buffer.
+ * \param output The buffer for the payload, called "message M" by the
+ * PKCS#1 terminology. This must be a writable buffer of
+ * length \p output_max_len bytes.
+ * \param olen The address at which to store the length of
+ * the payload. This must not be \c NULL.
+ * \param output_max_len The length in bytes of the output buffer \p output.
+ *
+ * \return \c 0 on success.
+ * \return #MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE
+ * The output buffer is too small for the unpadded payload.
+ * \return #MBEDTLS_ERR_RSA_INVALID_PADDING
+ * The input doesn't contain properly formatted padding.
+ */
+static int mbedtls_ct_rsaes_pkcs1_v15_unpadding(unsigned char *input,
+ size_t ilen,
+ unsigned char *output,
+ size_t output_max_len,
+ size_t *olen)
+{
+ int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+ size_t i, plaintext_max_size;
+
+ /* The following variables take sensitive values: their value must
+ * not leak into the observable behavior of the function other than
+ * the designated outputs (output, olen, return value). Otherwise
+ * this would open the execution of the function to
+ * side-channel-based variants of the Bleichenbacher padding oracle
+ * attack. Potential side channels include overall timing, memory
+ * access patterns (especially visible to an adversary who has access
+ * to a shared memory cache), and branches (especially visible to
+ * an adversary who has access to a shared code cache or to a shared
+ * branch predictor). */
+ size_t pad_count = 0;
+ mbedtls_ct_condition_t bad;
+ mbedtls_ct_condition_t pad_done;
+ size_t plaintext_size = 0;
+ mbedtls_ct_condition_t output_too_large;
+
+ plaintext_max_size = (output_max_len > ilen - 11) ? ilen - 11
+ : output_max_len;
+
+ /* Check and get padding length in constant time and constant
+ * memory trace. The first byte must be 0. */
+ bad = mbedtls_ct_bool(input[0]);
+
+
+ /* Decode EME-PKCS1-v1_5 padding: 0x00 || 0x02 || PS || 0x00
+ * where PS must be at least 8 nonzero bytes. */
+ bad = mbedtls_ct_bool_or(bad, mbedtls_ct_bool_ne(input[1], MBEDTLS_RSA_CRYPT));
+
+ /* Read the whole buffer. Set pad_done to nonzero if we find
+ * the 0x00 byte and remember the padding length in pad_count. */
+ pad_done = MBEDTLS_CT_FALSE;
+ for (i = 2; i < ilen; i++) {
+ mbedtls_ct_condition_t found = mbedtls_ct_bool_eq(input[i], 0);
+ pad_done = mbedtls_ct_bool_or(pad_done, found);
+ pad_count += mbedtls_ct_uint_if0(mbedtls_ct_bool_not(pad_done), 1);
+ }
+
+ /* If pad_done is still zero, there's no data, only unfinished padding. */
+ bad = mbedtls_ct_bool_or(bad, mbedtls_ct_bool_not(pad_done));
+
+ /* There must be at least 8 bytes of padding. */
+ bad = mbedtls_ct_bool_or(bad, mbedtls_ct_bool_gt(8, pad_count));
+
+ /* If the padding is valid, set plaintext_size to the number of
+ * remaining bytes after stripping the padding. If the padding
+ * is invalid, avoid leaking this fact through the size of the
+ * output: use the maximum message size that fits in the output
+ * buffer. Do it without branches to avoid leaking the padding
+ * validity through timing. RSA keys are small enough that all the
+ * size_t values involved fit in unsigned int. */
+ plaintext_size = mbedtls_ct_uint_if(
+ bad, (unsigned) plaintext_max_size,
+ (unsigned) (ilen - pad_count - 3));
+
+ /* Set output_too_large to 0 if the plaintext fits in the output
+ * buffer and to 1 otherwise. */
+ output_too_large = mbedtls_ct_bool_gt(plaintext_size,
+ plaintext_max_size);
+
+ /* Set ret without branches to avoid timing attacks. Return:
+ * - INVALID_PADDING if the padding is bad (bad != 0).
+ * - OUTPUT_TOO_LARGE if the padding is good but the decrypted
+ * plaintext does not fit in the output buffer.
+ * - 0 if the padding is correct. */
+ ret = -(int) mbedtls_ct_uint_if(
+ bad,
+ (unsigned) (-(MBEDTLS_ERR_RSA_INVALID_PADDING)),
+ mbedtls_ct_uint_if0(
+ output_too_large,
+ (unsigned) (-(MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE)))
+ );
+
+ /* If the padding is bad or the plaintext is too large, zero the
+ * data that we're about to copy to the output buffer.
+ * 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. */
+ mbedtls_ct_zeroize_if(mbedtls_ct_bool_or(bad, output_too_large), input + 11, ilen - 11);
+
+ /* If the plaintext is too large, truncate it to the buffer size.
+ * Copy anyway to avoid revealing the length through timing, because
+ * revealing the length is as bad as revealing the padding validity
+ * for a Bleichenbacher attack. */
+ plaintext_size = mbedtls_ct_uint_if(output_too_large,
+ (unsigned) plaintext_max_size,
+ (unsigned) plaintext_size);
+
+ /* Move the plaintext to the leftmost position where it can start in
+ * the working buffer, i.e. make it start plaintext_max_size from
+ * the end of the buffer. Do this with a memory access trace that
+ * does not depend on the plaintext size. After this move, the
+ * starting location of the plaintext is no longer sensitive
+ * information. */
+ mbedtls_ct_memmove_left(input + ilen - plaintext_max_size,
+ plaintext_max_size,
+ plaintext_max_size - plaintext_size);
+
+ /* Finally copy the decrypted plaintext plus trailing zeros into the output
+ * buffer. If output_max_len is 0, then output may be an invalid pointer
+ * and the result of memcpy() would be undefined; prevent undefined
+ * behavior making sure to depend only on output_max_len (the size of the
+ * user-provided output buffer), which is independent from plaintext
+ * length, validity of padding, success of the decryption, and other
+ * secrets. */
+ if (output_max_len != 0) {
+ memcpy(output, input + ilen - plaintext_max_size, plaintext_max_size);
+ }
+
+ /* Report the amount of data we copied to the output buffer. In case
+ * of errors (bad padding or output too large), the value of *olen
+ * when this function returns is not specified. Making it equivalent
+ * to the good case limits the risks of leaking the padding validity. */
+ *olen = plaintext_size;
+
+ return ret;
+}
+
+#endif /* MBEDTLS_PKCS1_V15 && MBEDTLS_RSA_C && ! MBEDTLS_RSA_ALT */
+
#if !defined(MBEDTLS_RSA_ALT)
int mbedtls_rsa_import(mbedtls_rsa_context *ctx,
diff --git a/library/ssl_misc.h b/library/ssl_misc.h
index 2d6d7ba..0145903 100644
--- a/library/ssl_misc.h
+++ b/library/ssl_misc.h
@@ -2787,4 +2787,64 @@
int mbedtls_ssl_tls13_finalize_client_hello(mbedtls_ssl_context *ssl);
#endif
+#if defined(MBEDTLS_TEST_HOOKS) && defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC)
+
+/** Compute the HMAC of variable-length data with constant flow.
+ *
+ * This function computes the HMAC of the concatenation of \p add_data and \p
+ * data, and does with a code flow and memory access pattern that does not
+ * depend on \p data_len_secret, but only on \p min_data_len and \p
+ * max_data_len. In particular, this function always reads exactly \p
+ * max_data_len bytes from \p data.
+ *
+ * \param ctx The HMAC context. It must have keys configured
+ * with mbedtls_md_hmac_starts() and use one of the
+ * following hashes: SHA-384, SHA-256, SHA-1 or MD-5.
+ * It is reset using mbedtls_md_hmac_reset() after
+ * the computation is complete to prepare for the
+ * next computation.
+ * \param add_data The first part of the message whose HMAC is being
+ * calculated. This must point to a readable buffer
+ * of \p add_data_len bytes.
+ * \param add_data_len The length of \p add_data in bytes.
+ * \param data The buffer containing the second part of the
+ * message. This must point to a readable buffer
+ * of \p max_data_len bytes.
+ * \param data_len_secret The length of the data to process in \p data.
+ * This must be no less than \p min_data_len and no
+ * greater than \p max_data_len.
+ * \param min_data_len The minimal length of the second part of the
+ * message, read from \p data.
+ * \param max_data_len The maximal length of the second part of the
+ * message, read from \p data.
+ * \param output The HMAC will be written here. This must point to
+ * a writable buffer of sufficient size to hold the
+ * HMAC value.
+ *
+ * \retval 0 on success.
+ * \retval #MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED
+ * The hardware accelerator failed.
+ */
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+int mbedtls_ct_hmac(mbedtls_svc_key_id_t key,
+ psa_algorithm_t mac_alg,
+ const unsigned char *add_data,
+ size_t add_data_len,
+ const unsigned char *data,
+ size_t data_len_secret,
+ size_t min_data_len,
+ size_t max_data_len,
+ unsigned char *output);
+#else
+int mbedtls_ct_hmac(mbedtls_md_context_t *ctx,
+ const unsigned char *add_data,
+ size_t add_data_len,
+ const unsigned char *data,
+ size_t data_len_secret,
+ size_t min_data_len,
+ size_t max_data_len,
+ unsigned char *output);
+#endif /* defined(MBEDTLS_USE_PSA_CRYPTO) */
+#endif /* MBEDTLS_TEST_HOOKS && defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC) */
+
#endif /* ssl_misc.h */
diff --git a/library/ssl_msg.c b/library/ssl_msg.c
index e905023..e07be05 100644
--- a/library/ssl_msg.c
+++ b/library/ssl_msg.c
@@ -60,6 +60,234 @@
#define PSA_TO_MBEDTLS_ERR(status) local_err_translation(status)
#endif
+#if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC)
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+
+#if defined(PSA_WANT_ALG_SHA_384)
+#define MAX_HASH_BLOCK_LENGTH PSA_HASH_BLOCK_LENGTH(PSA_ALG_SHA_384)
+#elif defined(PSA_WANT_ALG_SHA_256)
+#define MAX_HASH_BLOCK_LENGTH PSA_HASH_BLOCK_LENGTH(PSA_ALG_SHA_256)
+#else /* See check_config.h */
+#define MAX_HASH_BLOCK_LENGTH PSA_HASH_BLOCK_LENGTH(PSA_ALG_SHA_1)
+#endif
+
+MBEDTLS_STATIC_TESTABLE
+int mbedtls_ct_hmac(mbedtls_svc_key_id_t key,
+ psa_algorithm_t mac_alg,
+ const unsigned char *add_data,
+ size_t add_data_len,
+ const unsigned char *data,
+ size_t data_len_secret,
+ size_t min_data_len,
+ size_t max_data_len,
+ unsigned char *output)
+{
+ /*
+ * This function breaks the HMAC abstraction and uses psa_hash_clone()
+ * extension in order to get constant-flow behaviour.
+ *
+ * HMAC(msg) is defined as HASH(okey + HASH(ikey + msg)) where + means
+ * concatenation, and okey/ikey are the XOR of the key with some fixed bit
+ * patterns (see RFC 2104, sec. 2).
+ *
+ * We'll first compute ikey/okey, then inner_hash = HASH(ikey + msg) by
+ * hashing up to minlen, then cloning the context, and for each byte up
+ * to maxlen finishing up the hash computation, keeping only the
+ * correct result.
+ *
+ * Then we only need to compute HASH(okey + inner_hash) and we're done.
+ */
+ psa_algorithm_t hash_alg = PSA_ALG_HMAC_GET_HASH(mac_alg);
+ const size_t block_size = PSA_HASH_BLOCK_LENGTH(hash_alg);
+ unsigned char key_buf[MAX_HASH_BLOCK_LENGTH];
+ const size_t hash_size = PSA_HASH_LENGTH(hash_alg);
+ psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT;
+ size_t hash_length;
+
+ unsigned char aux_out[PSA_HASH_MAX_SIZE];
+ psa_hash_operation_t aux_operation = PSA_HASH_OPERATION_INIT;
+ size_t offset;
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+ size_t mac_key_length;
+ size_t i;
+
+#define PSA_CHK(func_call) \
+ do { \
+ status = (func_call); \
+ if (status != PSA_SUCCESS) \
+ goto cleanup; \
+ } while (0)
+
+ /* Export MAC key
+ * We assume key length is always exactly the output size
+ * which is never more than the block size, thus we use block_size
+ * as the key buffer size.
+ */
+ PSA_CHK(psa_export_key(key, key_buf, block_size, &mac_key_length));
+
+ /* Calculate ikey */
+ for (i = 0; i < mac_key_length; i++) {
+ key_buf[i] = (unsigned char) (key_buf[i] ^ 0x36);
+ }
+ for (; i < block_size; ++i) {
+ key_buf[i] = 0x36;
+ }
+
+ PSA_CHK(psa_hash_setup(&operation, hash_alg));
+
+ /* Now compute inner_hash = HASH(ikey + msg) */
+ PSA_CHK(psa_hash_update(&operation, key_buf, block_size));
+ PSA_CHK(psa_hash_update(&operation, add_data, add_data_len));
+ PSA_CHK(psa_hash_update(&operation, data, min_data_len));
+
+ /* Fill the hash buffer in advance with something that is
+ * not a valid hash (barring an attack on the hash and
+ * deliberately-crafted input), in case the caller doesn't
+ * check the return status properly. */
+ memset(output, '!', hash_size);
+
+ /* For each possible length, compute the hash up to that point */
+ for (offset = min_data_len; offset <= max_data_len; offset++) {
+ PSA_CHK(psa_hash_clone(&operation, &aux_operation));
+ PSA_CHK(psa_hash_finish(&aux_operation, aux_out,
+ PSA_HASH_MAX_SIZE, &hash_length));
+ /* Keep only the correct inner_hash in the output buffer */
+ mbedtls_ct_memcpy_if(mbedtls_ct_bool_eq(offset, data_len_secret),
+ output, aux_out, NULL, hash_size);
+
+ if (offset < max_data_len) {
+ PSA_CHK(psa_hash_update(&operation, data + offset, 1));
+ }
+ }
+
+ /* Abort current operation to prepare for final operation */
+ PSA_CHK(psa_hash_abort(&operation));
+
+ /* Calculate okey */
+ for (i = 0; i < mac_key_length; i++) {
+ key_buf[i] = (unsigned char) ((key_buf[i] ^ 0x36) ^ 0x5C);
+ }
+ for (; i < block_size; ++i) {
+ key_buf[i] = 0x5C;
+ }
+
+ /* Now compute HASH(okey + inner_hash) */
+ PSA_CHK(psa_hash_setup(&operation, hash_alg));
+ PSA_CHK(psa_hash_update(&operation, key_buf, block_size));
+ PSA_CHK(psa_hash_update(&operation, output, hash_size));
+ PSA_CHK(psa_hash_finish(&operation, output, hash_size, &hash_length));
+
+#undef PSA_CHK
+
+cleanup:
+ mbedtls_platform_zeroize(key_buf, MAX_HASH_BLOCK_LENGTH);
+ mbedtls_platform_zeroize(aux_out, PSA_HASH_MAX_SIZE);
+
+ psa_hash_abort(&operation);
+ psa_hash_abort(&aux_operation);
+ return PSA_TO_MBEDTLS_ERR(status);
+}
+
+#undef MAX_HASH_BLOCK_LENGTH
+
+#else
+MBEDTLS_STATIC_TESTABLE
+int mbedtls_ct_hmac(mbedtls_md_context_t *ctx,
+ const unsigned char *add_data,
+ size_t add_data_len,
+ const unsigned char *data,
+ size_t data_len_secret,
+ size_t min_data_len,
+ size_t max_data_len,
+ unsigned char *output)
+{
+ /*
+ * This function breaks the HMAC abstraction and uses the md_clone()
+ * extension to the MD API in order to get constant-flow behaviour.
+ *
+ * HMAC(msg) is defined as HASH(okey + HASH(ikey + msg)) where + means
+ * concatenation, and okey/ikey are the XOR of the key with some fixed bit
+ * patterns (see RFC 2104, sec. 2), which are stored in ctx->hmac_ctx.
+ *
+ * We'll first compute inner_hash = HASH(ikey + msg) by hashing up to
+ * minlen, then cloning the context, and for each byte up to maxlen
+ * finishing up the hash computation, keeping only the correct result.
+ *
+ * Then we only need to compute HASH(okey + inner_hash) and we're done.
+ */
+ const mbedtls_md_type_t md_alg = mbedtls_md_get_type(ctx->md_info);
+ /* TLS 1.2 only supports SHA-384, SHA-256, SHA-1, MD-5,
+ * all of which have the same block size except SHA-384. */
+ const size_t block_size = md_alg == MBEDTLS_MD_SHA384 ? 128 : 64;
+ const unsigned char * const ikey = ctx->hmac_ctx;
+ const unsigned char * const okey = ikey + block_size;
+ const size_t hash_size = mbedtls_md_get_size(ctx->md_info);
+
+ unsigned char aux_out[MBEDTLS_MD_MAX_SIZE];
+ mbedtls_md_context_t aux;
+ size_t offset;
+ int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+
+ mbedtls_md_init(&aux);
+
+#define MD_CHK(func_call) \
+ do { \
+ ret = (func_call); \
+ if (ret != 0) \
+ goto cleanup; \
+ } while (0)
+
+ MD_CHK(mbedtls_md_setup(&aux, ctx->md_info, 0));
+
+ /* After hmac_start() of hmac_reset(), ikey has already been hashed,
+ * so we can start directly with the message */
+ MD_CHK(mbedtls_md_update(ctx, add_data, add_data_len));
+ MD_CHK(mbedtls_md_update(ctx, data, min_data_len));
+
+ /* Fill the hash buffer in advance with something that is
+ * not a valid hash (barring an attack on the hash and
+ * deliberately-crafted input), in case the caller doesn't
+ * check the return status properly. */
+ memset(output, '!', hash_size);
+
+ /* For each possible length, compute the hash up to that point */
+ for (offset = min_data_len; offset <= max_data_len; offset++) {
+ MD_CHK(mbedtls_md_clone(&aux, ctx));
+ MD_CHK(mbedtls_md_finish(&aux, aux_out));
+ /* Keep only the correct inner_hash in the output buffer */
+ mbedtls_ct_memcpy_if(mbedtls_ct_bool_eq(offset, data_len_secret),
+ output, aux_out, NULL, hash_size);
+
+ if (offset < max_data_len) {
+ MD_CHK(mbedtls_md_update(ctx, data + offset, 1));
+ }
+ }
+
+ /* The context needs to finish() before it starts() again */
+ MD_CHK(mbedtls_md_finish(ctx, aux_out));
+
+ /* Now compute HASH(okey + inner_hash) */
+ MD_CHK(mbedtls_md_starts(ctx));
+ MD_CHK(mbedtls_md_update(ctx, okey, block_size));
+ MD_CHK(mbedtls_md_update(ctx, output, hash_size));
+ MD_CHK(mbedtls_md_finish(ctx, output));
+
+ /* Done, get ready for next time */
+ MD_CHK(mbedtls_md_hmac_reset(ctx));
+
+#undef MD_CHK
+
+cleanup:
+ mbedtls_md_free(&aux);
+ return ret;
+}
+
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+#endif /* MBEDTLS_SSL_SOME_SUITES_USE_MAC */
+
static uint32_t ssl_get_hs_total_len(mbedtls_ssl_context const *ssl);
/*
@@ -1690,11 +1918,11 @@
padlen = data[rec->data_len - 1];
if (auth_done == 1) {
- const size_t mask = mbedtls_ct_size_mask_ge(
+ const mbedtls_ct_condition_t ge = mbedtls_ct_bool_ge(
rec->data_len,
padlen + 1);
- correct &= mask;
- padlen &= mask;
+ correct = mbedtls_ct_size_if0(ge, correct);
+ padlen = mbedtls_ct_size_if0(ge, padlen);
} else {
#if defined(MBEDTLS_SSL_DEBUG_ALL)
if (rec->data_len < transform->maclen + padlen + 1) {
@@ -1706,12 +1934,11 @@
padlen + 1));
}
#endif
-
- const size_t mask = mbedtls_ct_size_mask_ge(
+ const mbedtls_ct_condition_t ge = mbedtls_ct_bool_ge(
rec->data_len,
transform->maclen + padlen + 1);
- correct &= mask;
- padlen &= mask;
+ correct = mbedtls_ct_size_if0(ge, correct);
+ padlen = mbedtls_ct_size_if0(ge, padlen);
}
padlen++;
@@ -1740,19 +1967,20 @@
/* pad_count += (idx >= padding_idx) &&
* (check[idx] == padlen - 1);
*/
- const size_t mask = mbedtls_ct_size_mask_ge(idx, padding_idx);
- const size_t equal = mbedtls_ct_size_bool_eq(check[idx],
- padlen - 1);
- pad_count += mask & equal;
+ const mbedtls_ct_condition_t a = mbedtls_ct_bool_ge(idx, padding_idx);
+ size_t increment = mbedtls_ct_size_if0(a, 1);
+ const mbedtls_ct_condition_t b = mbedtls_ct_bool_eq(check[idx], padlen - 1);
+ increment = mbedtls_ct_size_if0(b, increment);
+ pad_count += increment;
}
- correct &= mbedtls_ct_size_bool_eq(pad_count, padlen);
+ correct = mbedtls_ct_size_if0(mbedtls_ct_bool_eq(pad_count, padlen), padlen);
#if defined(MBEDTLS_SSL_DEBUG_ALL)
if (padlen > 0 && correct == 0) {
MBEDTLS_SSL_DEBUG_MSG(1, ("bad padding byte detected"));
}
#endif
- padlen &= mbedtls_ct_size_mask(correct);
+ padlen = mbedtls_ct_size_if0(mbedtls_ct_bool(correct), padlen);
#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
diff --git a/library/ssl_tls12_server.c b/library/ssl_tls12_server.c
index 5060277..006ce17 100644
--- a/library/ssl_tls12_server.c
+++ b/library/ssl_tls12_server.c
@@ -3500,9 +3500,8 @@
unsigned char *pms = ssl->handshake->premaster + pms_offset;
unsigned char ver[2];
unsigned char fake_pms[48], peer_pms[48];
- unsigned char mask;
- size_t i, peer_pmslen;
- unsigned int diff;
+ size_t peer_pmslen;
+ mbedtls_ct_condition_t diff;
/* In case of a failure in decryption, the decryption may write less than
* 2 bytes of output, but we always read the first two bytes. It doesn't
@@ -3531,13 +3530,10 @@
/* Avoid data-dependent branches while checking for invalid
* padding, to protect against timing-based Bleichenbacher-type
* attacks. */
- diff = (unsigned int) ret;
- diff |= peer_pmslen ^ 48;
- diff |= peer_pms[0] ^ ver[0];
- diff |= peer_pms[1] ^ ver[1];
-
- /* mask = diff ? 0xff : 0x00 using bit operations to avoid branches */
- mask = mbedtls_ct_uint_mask(diff);
+ diff = mbedtls_ct_bool(ret);
+ diff = mbedtls_ct_bool_or(diff, mbedtls_ct_bool_ne(peer_pmslen, 48));
+ diff = mbedtls_ct_bool_or(diff, mbedtls_ct_bool_ne(peer_pms[0], ver[0]));
+ diff = mbedtls_ct_bool_or(diff, mbedtls_ct_bool_ne(peer_pms[1], ver[1]));
/*
* Protection against Bleichenbacher's attack: invalid PKCS#1 v1.5 padding
@@ -3556,7 +3552,7 @@
}
#if defined(MBEDTLS_SSL_DEBUG_ALL)
- if (diff != 0) {
+ if (diff != MBEDTLS_CT_FALSE) {
MBEDTLS_SSL_DEBUG_MSG(1, ("bad client key exchange message"));
}
#endif
@@ -3570,9 +3566,7 @@
/* Set pms to either the true or the fake PMS, without
* data-dependent branches. */
- for (i = 0; i < ssl->handshake->pmslen; i++) {
- pms[i] = (mask & fake_pms[i]) | ((~mask) & peer_pms[i]);
- }
+ mbedtls_ct_memcpy_if(diff, pms, fake_pms, peer_pms, ssl->handshake->pmslen);
return 0;
}
diff --git a/tests/suites/test_suite_base64.data b/tests/suites/test_suite_base64.data
index 5556668..3999e73 100644
--- a/tests/suites/test_suite_base64.data
+++ b/tests/suites/test_suite_base64.data
@@ -1,27 +1,3 @@
-mask_of_range empty (1..0)
-mask_of_range:1:0
-
-mask_of_range empty (255..0)
-mask_of_range:255:0
-
-mask_of_range empty (42..7)
-mask_of_range:42:7
-
-mask_of_range 0..0
-mask_of_range:0:0
-
-mask_of_range 42..42
-mask_of_range:42:42
-
-mask_of_range 255..255
-mask_of_range:255:255
-
-mask_of_range 0..255
-mask_of_range:0:255
-
-mask_of_range 'A'..'Z'
-mask_of_range:65:90
-
enc_char (all digits)
enc_chars:
diff --git a/tests/suites/test_suite_base64.function b/tests/suites/test_suite_base64.function
index ce6bd42..e351ad8 100644
--- a/tests/suites/test_suite_base64.function
+++ b/tests/suites/test_suite_base64.function
@@ -1,7 +1,7 @@
/* BEGIN_HEADER */
#include "mbedtls/base64.h"
+#include "base64_internal.h"
#include "constant_time_internal.h"
-#include "constant_time_invasive.h"
#include <test/constant_flow.h>
#if defined(MBEDTLS_TEST_HOOKS)
@@ -17,26 +17,6 @@
*/
/* BEGIN_CASE depends_on:MBEDTLS_TEST_HOOKS */
-void mask_of_range(int low_arg, int high_arg)
-{
- unsigned char low = low_arg, high = high_arg;
- unsigned c;
- for (c = 0; c <= 0xff; c++) {
- mbedtls_test_set_step(c);
- TEST_CF_SECRET(&c, sizeof(c));
- unsigned char m = mbedtls_ct_uchar_mask_of_range(low, high, c);
- TEST_CF_PUBLIC(&c, sizeof(c));
- TEST_CF_PUBLIC(&m, sizeof(m));
- if (low <= c && c <= high) {
- TEST_EQUAL(m, 0xff);
- } else {
- TEST_EQUAL(m, 0);
- }
- }
-}
-/* END_CASE */
-
-/* BEGIN_CASE depends_on:MBEDTLS_TEST_HOOKS */
void enc_chars()
{
for (unsigned value = 0; value < 64; value++) {
diff --git a/tests/suites/test_suite_bignum.function b/tests/suites/test_suite_bignum.function
index 7f858e5..caa7e04 100644
--- a/tests/suites/test_suite_bignum.function
+++ b/tests/suites/test_suite_bignum.function
@@ -438,7 +438,7 @@
TEST_ASSERT(mbedtls_mpi_lt_mpi_ct(&X, &Y, &ret) == input_err);
if (input_err == 0) {
- TEST_ASSERT(ret == input_uret);
+ TEST_EQUAL(ret, input_uret);
}
exit:
diff --git a/tests/suites/test_suite_bignum_core.function b/tests/suites/test_suite_bignum_core.function
index 81a3a45..7ac03d0 100644
--- a/tests/suites/test_suite_bignum_core.function
+++ b/tests/suites/test_suite_bignum_core.function
@@ -358,7 +358,7 @@
TEST_CF_SECRET(Y, X_limbs * sizeof(mbedtls_mpi_uint));
ret = mbedtls_mpi_core_lt_ct(X, Y, X_limbs);
- TEST_EQUAL(ret, exp_ret);
+ TEST_EQUAL(!!ret, exp_ret);
exit:
mbedtls_free(X);
@@ -384,25 +384,25 @@
TEST_CF_SECRET(A, A_limbs * sizeof(*A));
- TEST_EQUAL(mbedtls_mpi_core_uint_le_mpi(0, A, A_limbs), 1);
- TEST_EQUAL(mbedtls_mpi_core_uint_le_mpi(A[0], A, A_limbs), 1);
+ TEST_EQUAL(!!mbedtls_mpi_core_uint_le_mpi(0, A, A_limbs), 1);
+ TEST_EQUAL(!!mbedtls_mpi_core_uint_le_mpi(A[0], A, A_limbs), 1);
if (is_large) {
- TEST_EQUAL(mbedtls_mpi_core_uint_le_mpi(A[0] + 1,
- A, A_limbs), 1);
- TEST_EQUAL(mbedtls_mpi_core_uint_le_mpi((mbedtls_mpi_uint) (-1) >> 1,
- A, A_limbs), 1);
- TEST_EQUAL(mbedtls_mpi_core_uint_le_mpi((mbedtls_mpi_uint) (-1),
- A, A_limbs), 1);
+ TEST_EQUAL(!!mbedtls_mpi_core_uint_le_mpi(A[0] + 1,
+ A, A_limbs), 1);
+ TEST_EQUAL(!!mbedtls_mpi_core_uint_le_mpi((mbedtls_mpi_uint) (-1) >> 1,
+ A, A_limbs), 1);
+ TEST_EQUAL(!!mbedtls_mpi_core_uint_le_mpi((mbedtls_mpi_uint) (-1),
+ A, A_limbs), 1);
} else {
- TEST_EQUAL(mbedtls_mpi_core_uint_le_mpi(A[0] + 1,
- A, A_limbs),
+ TEST_EQUAL(!!mbedtls_mpi_core_uint_le_mpi(A[0] + 1,
+ A, A_limbs),
A[0] + 1 <= A[0]);
- TEST_EQUAL(mbedtls_mpi_core_uint_le_mpi((mbedtls_mpi_uint) (-1) >> 1,
- A, A_limbs),
+ TEST_EQUAL(!!mbedtls_mpi_core_uint_le_mpi((mbedtls_mpi_uint) (-1) >> 1,
+ A, A_limbs),
(mbedtls_mpi_uint) (-1) >> 1 <= A[0]);
- TEST_EQUAL(mbedtls_mpi_core_uint_le_mpi((mbedtls_mpi_uint) (-1),
- A, A_limbs),
+ TEST_EQUAL(!!mbedtls_mpi_core_uint_le_mpi((mbedtls_mpi_uint) (-1),
+ A, A_limbs),
(mbedtls_mpi_uint) (-1) <= A[0]);
}
@@ -447,7 +447,7 @@
TEST_CF_SECRET(X, bytes);
TEST_CF_SECRET(Y, bytes);
- mbedtls_mpi_core_cond_assign(X, Y, copy_limbs, 1);
+ mbedtls_mpi_core_cond_assign(X, Y, copy_limbs, mbedtls_ct_bool(1));
TEST_CF_PUBLIC(X, bytes);
TEST_CF_PUBLIC(Y, bytes);
@@ -515,7 +515,7 @@
TEST_CF_SECRET(X, bytes);
TEST_CF_SECRET(Y, bytes);
- mbedtls_mpi_core_cond_swap(X, Y, copy_limbs, 1);
+ mbedtls_mpi_core_cond_swap(X, Y, copy_limbs, mbedtls_ct_bool(1));
TEST_CF_PUBLIC(X, bytes);
TEST_CF_PUBLIC(Y, bytes);
diff --git a/tests/suites/test_suite_bignum_random.function b/tests/suites/test_suite_bignum_random.function
index e4db3d7..51ff4d8 100644
--- a/tests/suites/test_suite_bignum_random.function
+++ b/tests/suites/test_suite_bignum_random.function
@@ -134,7 +134,7 @@
if (expected_ret == 0) {
TEST_EQUAL(0, mbedtls_mpi_core_lt_ct(result, lower_bound, limbs));
- TEST_EQUAL(1, mbedtls_mpi_core_lt_ct(result, upper_bound, limbs));
+ TEST_ASSERT(0 != mbedtls_mpi_core_lt_ct(result, upper_bound, limbs));
}
exit:
@@ -429,8 +429,7 @@
* size as the modulus, otherwise it's a mistake in the test data. */
TEST_EQUAL(result_limbs, N.limbs);
/* Sanity check: check that the result is in range */
- TEST_EQUAL(mbedtls_mpi_core_lt_ct(result_digits, N.p, N.limbs),
- 1);
+ TEST_ASSERT(0 != mbedtls_mpi_core_lt_ct(result_digits, N.p, N.limbs));
/* Check result >= min (changes result) */
TEST_EQUAL(mbedtls_mpi_core_sub_int(result_digits, result_digits, min,
result_limbs),
@@ -444,8 +443,7 @@
mbedtls_test_rnd_std_rand, NULL),
expected_ret);
if (expected_ret == 0) {
- TEST_EQUAL(mbedtls_mpi_core_lt_ct(result_digits, N.p, N.limbs),
- 1);
+ TEST_ASSERT(0 != mbedtls_mpi_core_lt_ct(result_digits, N.p, N.limbs));
TEST_EQUAL(mbedtls_mpi_core_sub_int(result_digits, result.p, min,
result_limbs),
0);
diff --git a/tests/suites/test_suite_constant_time.data b/tests/suites/test_suite_constant_time.data
index 91a25fa..1b0b964 100644
--- a/tests/suites/test_suite_constant_time.data
+++ b/tests/suites/test_suite_constant_time.data
@@ -1,14 +1,14 @@
# these are the numbers we'd get with an empty plaintext and truncated HMAC
Constant-flow memcpy from offset: small
-ssl_cf_memcpy_offset:0:5:10
+mbedtls_ct_memcpy_offset:0:5:10
# we could get this with 255-bytes plaintext and untruncated SHA-256
Constant-flow memcpy from offset: medium
-ssl_cf_memcpy_offset:0:255:32
+mbedtls_ct_memcpy_offset:0:255:32
# we could get this with 255-bytes plaintext and untruncated SHA-384
Constant-flow memcpy from offset: large
-ssl_cf_memcpy_offset:100:339:48
+mbedtls_ct_memcpy_offset:100:339:48
mbedtls_ct_memcmp NULL
mbedtls_ct_memcmp_null
@@ -91,47 +91,611 @@
mbedtls_ct_memcmp len 17 offset 3
mbedtls_ct_memcmp:-1:17:3
-mbedtls_ct_memcpy_if_eq len 1 offset 0
-mbedtls_ct_memcpy_if_eq:1:1:0
+mbedtls_ct_memcpy_if len 1 offset 0
+mbedtls_ct_memcpy_if:1:1:0
-mbedtls_ct_memcpy_if_eq len 1 offset 1
-mbedtls_ct_memcpy_if_eq:1:1:1
+mbedtls_ct_memcpy_if len 1 offset 1
+mbedtls_ct_memcpy_if:1:1:1
-mbedtls_ct_memcpy_if_eq len 4 offset 0
-mbedtls_ct_memcpy_if_eq:1:1:0
+mbedtls_ct_memcpy_if len 4 offset 0
+mbedtls_ct_memcpy_if:1:1:0
-mbedtls_ct_memcpy_if_eq len 4 offset 1
-mbedtls_ct_memcpy_if_eq:1:1:1
+mbedtls_ct_memcpy_if len 4 offset 1
+mbedtls_ct_memcpy_if:1:1:1
-mbedtls_ct_memcpy_if_eq len 4 offset 2
-mbedtls_ct_memcpy_if_eq:1:1:2
+mbedtls_ct_memcpy_if len 4 offset 2
+mbedtls_ct_memcpy_if:1:1:2
-mbedtls_ct_memcpy_if_eq len 4 offset 3
-mbedtls_ct_memcpy_if_eq:1:1:3
+mbedtls_ct_memcpy_if len 4 offset 3
+mbedtls_ct_memcpy_if:1:1:3
-mbedtls_ct_memcpy_if_eq len 15 offset 0
-mbedtls_ct_memcpy_if_eq:1:15:0
+mbedtls_ct_memcpy_if len 15 offset 0
+mbedtls_ct_memcpy_if:1:15:0
-mbedtls_ct_memcpy_if_eq len 15 offset 1
-mbedtls_ct_memcpy_if_eq:1:15:1
+mbedtls_ct_memcpy_if len 15 offset 1
+mbedtls_ct_memcpy_if:1:15:1
-mbedtls_ct_memcpy_if_eq len 16 offset 0
-mbedtls_ct_memcpy_if_eq:1:16:0
+mbedtls_ct_memcpy_if len 16 offset 0
+mbedtls_ct_memcpy_if:1:16:0
-mbedtls_ct_memcpy_if_eq len 16 offset 1
-mbedtls_ct_memcpy_if_eq:1:16:1
+mbedtls_ct_memcpy_if len 16 offset 1
+mbedtls_ct_memcpy_if:1:16:1
-mbedtls_ct_memcpy_if_eq len 17 offset 0
-mbedtls_ct_memcpy_if_eq:1:17:0
+mbedtls_ct_memcpy_if len 17 offset 0
+mbedtls_ct_memcpy_if:1:17:0
-mbedtls_ct_memcpy_if_eq len 17 offset 1
-mbedtls_ct_memcpy_if_eq:1:17:1
+mbedtls_ct_memcpy_if len 17 offset 1
+mbedtls_ct_memcpy_if:1:17:1
-mbedtls_ct_memcpy_if_eq len 0 not eq
-mbedtls_ct_memcpy_if_eq:0:17:0
+mbedtls_ct_memcpy_if len 0 not eq
+mbedtls_ct_memcpy_if:0:17:0
-mbedtls_ct_memcpy_if_eq len 5 offset 1 not eq
-mbedtls_ct_memcpy_if_eq:0:5:1
+mbedtls_ct_memcpy_if len 5 offset 1 not eq
+mbedtls_ct_memcpy_if:0:5:1
-mbedtls_ct_memcpy_if_eq len 17 offset 3 not eq
-mbedtls_ct_memcpy_if_eq:0:17:3
+mbedtls_ct_memcpy_if len 17 offset 3 not eq
+mbedtls_ct_memcpy_if:0:17:3
+
+mbedtls_ct_bool 0
+mbedtls_ct_bool:"0x0"
+
+mbedtls_ct_bool 1
+mbedtls_ct_bool:"0x1"
+
+mbedtls_ct_bool 4
+mbedtls_ct_bool:"0x4"
+
+mbedtls_ct_bool 0xfffffff
+mbedtls_ct_bool:"0xfffffff"
+
+mbedtls_ct_bool 0x7fffffff
+mbedtls_ct_bool:"0x7fffffff"
+
+mbedtls_ct_bool 0xfffffffe
+mbedtls_ct_bool:"0xfffffffe"
+
+mbedtls_ct_bool 0xffffffff
+mbedtls_ct_bool:"0xffffffff"
+
+mbedtls_ct_bool 0x0fffffffffffffff
+mbedtls_ct_bool:"0x0fffffffffffffff"
+
+mbedtls_ct_bool 0x7fffffffffffffff
+mbedtls_ct_bool:"0x7fffffffffffffff"
+
+mbedtls_ct_bool 0xffffffffffffffff
+mbedtls_ct_bool:"0xffffffffffffffff"
+
+mbedtls_ct_bool_xxx 0x0 0x0
+mbedtls_ct_bool_xxx:"0x0":"0x0"
+
+mbedtls_ct_bool_xxx 0x0 0x1
+mbedtls_ct_bool_xxx:"0x0":"0x1"
+
+mbedtls_ct_bool_xxx 0x0 0x7fffffff
+mbedtls_ct_bool_xxx:"0x0":"0x7fffffff"
+
+mbedtls_ct_bool_xxx 0x0 0xffffffff
+mbedtls_ct_bool_xxx:"0x0":"0xffffffff"
+
+mbedtls_ct_bool_xxx 0x0 0x7fffffffffffffff
+mbedtls_ct_bool_xxx:"0x0":"0x7fffffffffffffff"
+
+mbedtls_ct_bool_xxx 0x0 0xffffffffffffffff
+mbedtls_ct_bool_xxx:"0x0":"0xffffffffffffffff"
+
+mbedtls_ct_bool_xxx 0x1 0x0
+mbedtls_ct_bool_xxx:"0x1":"0x0"
+
+mbedtls_ct_bool_xxx 0x1 0x1
+mbedtls_ct_bool_xxx:"0x1":"0x1"
+
+mbedtls_ct_bool_xxx 0x1 0x7fffffff
+mbedtls_ct_bool_xxx:"0x1":"0x7fffffff"
+
+mbedtls_ct_bool_xxx 0x1 0xffffffff
+mbedtls_ct_bool_xxx:"0x1":"0xffffffff"
+
+mbedtls_ct_bool_xxx 0x1 0x7fffffffffffffff
+mbedtls_ct_bool_xxx:"0x1":"0x7fffffffffffffff"
+
+mbedtls_ct_bool_xxx 0x1 0xffffffffffffffff
+mbedtls_ct_bool_xxx:"0x1":"0xffffffffffffffff"
+
+mbedtls_ct_bool_xxx 0x7fffffff 0x0
+mbedtls_ct_bool_xxx:"0x7fffffff":"0x0"
+
+mbedtls_ct_bool_xxx 0x7fffffff 0x1
+mbedtls_ct_bool_xxx:"0x7fffffff":"0x1"
+
+mbedtls_ct_bool_xxx 0x7fffffff 0x7fffffff
+mbedtls_ct_bool_xxx:"0x7fffffff":"0x7fffffff"
+
+mbedtls_ct_bool_xxx 0x7fffffff 0xffffffff
+mbedtls_ct_bool_xxx:"0x7fffffff":"0xffffffff"
+
+mbedtls_ct_bool_xxx 0x7fffffff 0x7fffffffffffffff
+mbedtls_ct_bool_xxx:"0x7fffffff":"0x7fffffffffffffff"
+
+mbedtls_ct_bool_xxx 0x7fffffff 0xffffffffffffffff
+mbedtls_ct_bool_xxx:"0x7fffffff":"0xffffffffffffffff"
+
+mbedtls_ct_bool_xxx 0xffffffff 0x0
+mbedtls_ct_bool_xxx:"0xffffffff":"0x0"
+
+mbedtls_ct_bool_xxx 0xffffffff 0x1
+mbedtls_ct_bool_xxx:"0xffffffff":"0x1"
+
+mbedtls_ct_bool_xxx 0xffffffff 0x7fffffff
+mbedtls_ct_bool_xxx:"0xffffffff":"0x7fffffff"
+
+mbedtls_ct_bool_xxx 0xffffffff 0xffffffff
+mbedtls_ct_bool_xxx:"0xffffffff":"0xffffffff"
+
+mbedtls_ct_bool_xxx 0xffffffff 0x7fffffffffffffff
+mbedtls_ct_bool_xxx:"0xffffffff":"0x7fffffffffffffff"
+
+mbedtls_ct_bool_xxx 0xffffffff 0xffffffffffffffff
+mbedtls_ct_bool_xxx:"0xffffffff":"0xffffffffffffffff"
+
+mbedtls_ct_bool_xxx 0x7fffffffffffffff 0x0
+mbedtls_ct_bool_xxx:"0x7fffffffffffffff":"0x0"
+
+mbedtls_ct_bool_xxx 0x7fffffffffffffff 0x1
+mbedtls_ct_bool_xxx:"0x7fffffffffffffff":"0x1"
+
+mbedtls_ct_bool_xxx 0x7fffffffffffffff 0x7fffffff
+mbedtls_ct_bool_xxx:"0x7fffffffffffffff":"0x7fffffff"
+
+mbedtls_ct_bool_xxx 0x7fffffffffffffff 0xffffffff
+mbedtls_ct_bool_xxx:"0x7fffffffffffffff":"0xffffffff"
+
+mbedtls_ct_bool_xxx 0x7fffffffffffffff 0x7fffffffffffffff
+mbedtls_ct_bool_xxx:"0x7fffffffffffffff":"0x7fffffffffffffff"
+
+mbedtls_ct_bool_xxx 0x7fffffffffffffff 0xffffffffffffffff
+mbedtls_ct_bool_xxx:"0x7fffffffffffffff":"0xffffffffffffffff"
+
+mbedtls_ct_bool_xxx 0xffffffffffffffff 0x0
+mbedtls_ct_bool_xxx:"0xffffffffffffffff":"0x0"
+
+mbedtls_ct_bool_xxx 0xffffffffffffffff 0x1
+mbedtls_ct_bool_xxx:"0xffffffffffffffff":"0x1"
+
+mbedtls_ct_bool_xxx 0xffffffffffffffff 0x7fffffff
+mbedtls_ct_bool_xxx:"0xffffffffffffffff":"0x7fffffff"
+
+mbedtls_ct_bool_xxx 0xffffffffffffffff 0xffffffff
+mbedtls_ct_bool_xxx:"0xffffffffffffffff":"0xffffffff"
+
+mbedtls_ct_bool_xxx 0xffffffffffffffff 0x7fffffffffffffff
+mbedtls_ct_bool_xxx:"0xffffffffffffffff":"0x7fffffffffffffff"
+
+mbedtls_ct_bool_xxx 0xffffffffffffffff 0xffffffffffffffff
+mbedtls_ct_bool_xxx:"0xffffffffffffffff":"0xffffffffffffffff"
+
+mbedtls_ct_bool_xxx 138 256
+mbedtls_ct_bool_xxx:"138":"256"
+
+mbedtls_ct_bool_xxx 256 138
+mbedtls_ct_bool_xxx:"256":"138"
+
+mbedtls_ct_bool_xxx 6 6
+mbedtls_ct_bool_xxx:"0x6":"0x6"
+
+mbedtls_ct_uchar_in_range_if 0 0 0
+mbedtls_ct_uchar_in_range_if:0:0:0
+
+mbedtls_ct_uchar_in_range_if 0 0 100
+mbedtls_ct_uchar_in_range_if:0:0:100
+
+mbedtls_ct_uchar_in_range_if 0 0 255
+mbedtls_ct_uchar_in_range_if:0:0:255
+
+mbedtls_ct_uchar_in_range_if 0 65 0
+mbedtls_ct_uchar_in_range_if:0:65:0
+
+mbedtls_ct_uchar_in_range_if 0 65 100
+mbedtls_ct_uchar_in_range_if:0:65:100
+
+mbedtls_ct_uchar_in_range_if 0 65 255
+mbedtls_ct_uchar_in_range_if:0:65:255
+
+mbedtls_ct_uchar_in_range_if 0 90 0
+mbedtls_ct_uchar_in_range_if:0:90:0
+
+mbedtls_ct_uchar_in_range_if 0 90 100
+mbedtls_ct_uchar_in_range_if:0:90:100
+
+mbedtls_ct_uchar_in_range_if 0 90 255
+mbedtls_ct_uchar_in_range_if:0:90:255
+
+mbedtls_ct_uchar_in_range_if 0 255 0
+mbedtls_ct_uchar_in_range_if:0:255:0
+
+mbedtls_ct_uchar_in_range_if 0 255 100
+mbedtls_ct_uchar_in_range_if:0:255:100
+
+mbedtls_ct_uchar_in_range_if 0 255 255
+mbedtls_ct_uchar_in_range_if:0:255:255
+
+mbedtls_ct_uchar_in_range_if 65 0 0
+mbedtls_ct_uchar_in_range_if:65:0:0
+
+mbedtls_ct_uchar_in_range_if 65 0 100
+mbedtls_ct_uchar_in_range_if:65:0:100
+
+mbedtls_ct_uchar_in_range_if 65 0 255
+mbedtls_ct_uchar_in_range_if:65:0:255
+
+mbedtls_ct_uchar_in_range_if 65 65 0
+mbedtls_ct_uchar_in_range_if:65:65:0
+
+mbedtls_ct_uchar_in_range_if 65 65 100
+mbedtls_ct_uchar_in_range_if:65:65:100
+
+mbedtls_ct_uchar_in_range_if 65 65 255
+mbedtls_ct_uchar_in_range_if:65:65:255
+
+mbedtls_ct_uchar_in_range_if 65 90 0
+mbedtls_ct_uchar_in_range_if:65:90:0
+
+mbedtls_ct_uchar_in_range_if 65 90 100
+mbedtls_ct_uchar_in_range_if:65:90:100
+
+mbedtls_ct_uchar_in_range_if 65 90 255
+mbedtls_ct_uchar_in_range_if:65:90:255
+
+mbedtls_ct_uchar_in_range_if 65 255 0
+mbedtls_ct_uchar_in_range_if:65:255:0
+
+mbedtls_ct_uchar_in_range_if 65 255 100
+mbedtls_ct_uchar_in_range_if:65:255:100
+
+mbedtls_ct_uchar_in_range_if 65 255 255
+mbedtls_ct_uchar_in_range_if:65:255:255
+
+mbedtls_ct_uchar_in_range_if 90 0 0
+mbedtls_ct_uchar_in_range_if:90:0:0
+
+mbedtls_ct_uchar_in_range_if 90 0 100
+mbedtls_ct_uchar_in_range_if:90:0:100
+
+mbedtls_ct_uchar_in_range_if 90 0 255
+mbedtls_ct_uchar_in_range_if:90:0:255
+
+mbedtls_ct_uchar_in_range_if 90 65 0
+mbedtls_ct_uchar_in_range_if:90:65:0
+
+mbedtls_ct_uchar_in_range_if 90 65 100
+mbedtls_ct_uchar_in_range_if:90:65:100
+
+mbedtls_ct_uchar_in_range_if 90 65 255
+mbedtls_ct_uchar_in_range_if:90:65:255
+
+mbedtls_ct_uchar_in_range_if 90 90 0
+mbedtls_ct_uchar_in_range_if:90:90:0
+
+mbedtls_ct_uchar_in_range_if 90 90 100
+mbedtls_ct_uchar_in_range_if:90:90:100
+
+mbedtls_ct_uchar_in_range_if 90 90 255
+mbedtls_ct_uchar_in_range_if:90:90:255
+
+mbedtls_ct_uchar_in_range_if 90 255 0
+mbedtls_ct_uchar_in_range_if:90:255:0
+
+mbedtls_ct_uchar_in_range_if 90 255 100
+mbedtls_ct_uchar_in_range_if:90:255:100
+
+mbedtls_ct_uchar_in_range_if 90 255 255
+mbedtls_ct_uchar_in_range_if:90:255:255
+
+mbedtls_ct_uchar_in_range_if 255 0 0
+mbedtls_ct_uchar_in_range_if:255:0:0
+
+mbedtls_ct_uchar_in_range_if 255 0 100
+mbedtls_ct_uchar_in_range_if:255:0:100
+
+mbedtls_ct_uchar_in_range_if 255 0 255
+mbedtls_ct_uchar_in_range_if:255:0:255
+
+mbedtls_ct_uchar_in_range_if 255 65 0
+mbedtls_ct_uchar_in_range_if:255:65:0
+
+mbedtls_ct_uchar_in_range_if 255 65 100
+mbedtls_ct_uchar_in_range_if:255:65:100
+
+mbedtls_ct_uchar_in_range_if 255 65 255
+mbedtls_ct_uchar_in_range_if:255:65:255
+
+mbedtls_ct_uchar_in_range_if 255 90 0
+mbedtls_ct_uchar_in_range_if:255:90:0
+
+mbedtls_ct_uchar_in_range_if 255 90 100
+mbedtls_ct_uchar_in_range_if:255:90:100
+
+mbedtls_ct_uchar_in_range_if 255 90 255
+mbedtls_ct_uchar_in_range_if:255:90:255
+
+mbedtls_ct_uchar_in_range_if 255 255 0
+mbedtls_ct_uchar_in_range_if:255:255:0
+
+mbedtls_ct_uchar_in_range_if 255 255 100
+mbedtls_ct_uchar_in_range_if:255:255:100
+
+mbedtls_ct_uchar_in_range_if 255 255 255
+mbedtls_ct_uchar_in_range_if:255:255:255
+
+mbedtls_ct_if 0x0 0x0 0x0
+mbedtls_ct_if:"0x0":"0x0":"0x0"
+
+mbedtls_ct_if 0x0 0x0 0x1
+mbedtls_ct_if:"0x0":"0x0":"0x1"
+
+mbedtls_ct_if 0x0 0x0 0x7fffffff
+mbedtls_ct_if:"0x0":"0x0":"0x7fffffff"
+
+mbedtls_ct_if 0x0 0x0 0xffffffff
+mbedtls_ct_if:"0x0":"0x0":"0xffffffff"
+
+mbedtls_ct_if 0x0 0x0 0x7fffffffffffffff
+mbedtls_ct_if:"0x0":"0x0":"0x7fffffffffffffff"
+
+mbedtls_ct_if 0x0 0x0 0xffffffffffffffff
+mbedtls_ct_if:"0x0":"0x0":"0xffffffffffffffff"
+
+mbedtls_ct_if 0x0 0x1 0x0
+mbedtls_ct_if:"0x0":"0x1":"0x0"
+
+mbedtls_ct_if 0x0 0x1 0x1
+mbedtls_ct_if:"0x0":"0x1":"0x1"
+
+mbedtls_ct_if 0x0 0x1 0x7fffffff
+mbedtls_ct_if:"0x0":"0x1":"0x7fffffff"
+
+mbedtls_ct_if 0x0 0x1 0xffffffff
+mbedtls_ct_if:"0x0":"0x1":"0xffffffff"
+
+mbedtls_ct_if 0x0 0x1 0x7fffffffffffffff
+mbedtls_ct_if:"0x0":"0x1":"0x7fffffffffffffff"
+
+mbedtls_ct_if 0x0 0x1 0xffffffffffffffff
+mbedtls_ct_if:"0x0":"0x1":"0xffffffffffffffff"
+
+mbedtls_ct_if 0x0 0x7fffffff 0x0
+mbedtls_ct_if:"0x0":"0x7fffffff":"0x0"
+
+mbedtls_ct_if 0x0 0x7fffffff 0x1
+mbedtls_ct_if:"0x0":"0x7fffffff":"0x1"
+
+mbedtls_ct_if 0x0 0x7fffffff 0x7fffffff
+mbedtls_ct_if:"0x0":"0x7fffffff":"0x7fffffff"
+
+mbedtls_ct_if 0x0 0x7fffffff 0xffffffff
+mbedtls_ct_if:"0x0":"0x7fffffff":"0xffffffff"
+
+mbedtls_ct_if 0x0 0x7fffffff 0x7fffffffffffffff
+mbedtls_ct_if:"0x0":"0x7fffffff":"0x7fffffffffffffff"
+
+mbedtls_ct_if 0x0 0x7fffffff 0xffffffffffffffff
+mbedtls_ct_if:"0x0":"0x7fffffff":"0xffffffffffffffff"
+
+mbedtls_ct_if 0x0 0xffffffff 0x0
+mbedtls_ct_if:"0x0":"0xffffffff":"0x0"
+
+mbedtls_ct_if 0x0 0xffffffff 0x1
+mbedtls_ct_if:"0x0":"0xffffffff":"0x1"
+
+mbedtls_ct_if 0x0 0xffffffff 0x7fffffff
+mbedtls_ct_if:"0x0":"0xffffffff":"0x7fffffff"
+
+mbedtls_ct_if 0x0 0xffffffff 0xffffffff
+mbedtls_ct_if:"0x0":"0xffffffff":"0xffffffff"
+
+mbedtls_ct_if 0x0 0xffffffff 0x7fffffffffffffff
+mbedtls_ct_if:"0x0":"0xffffffff":"0x7fffffffffffffff"
+
+mbedtls_ct_if 0x0 0xffffffff 0xffffffffffffffff
+mbedtls_ct_if:"0x0":"0xffffffff":"0xffffffffffffffff"
+
+mbedtls_ct_if 0x0 0x7fffffffffffffff 0x0
+mbedtls_ct_if:"0x0":"0x7fffffffffffffff":"0x0"
+
+mbedtls_ct_if 0x0 0x7fffffffffffffff 0x1
+mbedtls_ct_if:"0x0":"0x7fffffffffffffff":"0x1"
+
+mbedtls_ct_if 0x0 0x7fffffffffffffff 0x7fffffff
+mbedtls_ct_if:"0x0":"0x7fffffffffffffff":"0x7fffffff"
+
+mbedtls_ct_if 0x0 0x7fffffffffffffff 0xffffffff
+mbedtls_ct_if:"0x0":"0x7fffffffffffffff":"0xffffffff"
+
+mbedtls_ct_if 0x0 0x7fffffffffffffff 0x7fffffffffffffff
+mbedtls_ct_if:"0x0":"0x7fffffffffffffff":"0x7fffffffffffffff"
+
+mbedtls_ct_if 0x0 0x7fffffffffffffff 0xffffffffffffffff
+mbedtls_ct_if:"0x0":"0x7fffffffffffffff":"0xffffffffffffffff"
+
+mbedtls_ct_if 0x0 0xffffffffffffffff 0x0
+mbedtls_ct_if:"0x0":"0xffffffffffffffff":"0x0"
+
+mbedtls_ct_if 0x0 0xffffffffffffffff 0x1
+mbedtls_ct_if:"0x0":"0xffffffffffffffff":"0x1"
+
+mbedtls_ct_if 0x0 0xffffffffffffffff 0x7fffffff
+mbedtls_ct_if:"0x0":"0xffffffffffffffff":"0x7fffffff"
+
+mbedtls_ct_if 0x0 0xffffffffffffffff 0xffffffff
+mbedtls_ct_if:"0x0":"0xffffffffffffffff":"0xffffffff"
+
+mbedtls_ct_if 0x0 0xffffffffffffffff 0x7fffffffffffffff
+mbedtls_ct_if:"0x0":"0xffffffffffffffff":"0x7fffffffffffffff"
+
+mbedtls_ct_if 0x0 0xffffffffffffffff 0xffffffffffffffff
+mbedtls_ct_if:"0x0":"0xffffffffffffffff":"0xffffffffffffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0x0 0x0
+mbedtls_ct_if:"0xffffffffffffffff":"0x0":"0x0"
+
+mbedtls_ct_if 0xffffffffffffffff 0x0 0x1
+mbedtls_ct_if:"0xffffffffffffffff":"0x0":"0x1"
+
+mbedtls_ct_if 0xffffffffffffffff 0x0 0x7fffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0x0":"0x7fffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0x0 0xffffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0x0":"0xffffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0x0 0x7fffffffffffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0x0":"0x7fffffffffffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0x0 0xffffffffffffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0x0":"0xffffffffffffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0x1 0x0
+mbedtls_ct_if:"0xffffffffffffffff":"0x1":"0x0"
+
+mbedtls_ct_if 0xffffffffffffffff 0x1 0x1
+mbedtls_ct_if:"0xffffffffffffffff":"0x1":"0x1"
+
+mbedtls_ct_if 0xffffffffffffffff 0x1 0x7fffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0x1":"0x7fffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0x1 0xffffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0x1":"0xffffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0x1 0x7fffffffffffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0x1":"0x7fffffffffffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0x1 0xffffffffffffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0x1":"0xffffffffffffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0x7fffffff 0x0
+mbedtls_ct_if:"0xffffffffffffffff":"0x7fffffff":"0x0"
+
+mbedtls_ct_if 0xffffffffffffffff 0x7fffffff 0x1
+mbedtls_ct_if:"0xffffffffffffffff":"0x7fffffff":"0x1"
+
+mbedtls_ct_if 0xffffffffffffffff 0x7fffffff 0x7fffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0x7fffffff":"0x7fffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0x7fffffff 0xffffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0x7fffffff":"0xffffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0x7fffffff 0x7fffffffffffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0x7fffffff":"0x7fffffffffffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0x7fffffff 0xffffffffffffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0x7fffffff":"0xffffffffffffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0xffffffff 0x0
+mbedtls_ct_if:"0xffffffffffffffff":"0xffffffff":"0x0"
+
+mbedtls_ct_if 0xffffffffffffffff 0xffffffff 0x1
+mbedtls_ct_if:"0xffffffffffffffff":"0xffffffff":"0x1"
+
+mbedtls_ct_if 0xffffffffffffffff 0xffffffff 0x7fffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0xffffffff":"0x7fffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0xffffffff 0xffffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0xffffffff":"0xffffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0xffffffff 0x7fffffffffffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0xffffffff":"0x7fffffffffffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0xffffffff 0xffffffffffffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0xffffffff":"0xffffffffffffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0x7fffffffffffffff 0x0
+mbedtls_ct_if:"0xffffffffffffffff":"0x7fffffffffffffff":"0x0"
+
+mbedtls_ct_if 0xffffffffffffffff 0x7fffffffffffffff 0x1
+mbedtls_ct_if:"0xffffffffffffffff":"0x7fffffffffffffff":"0x1"
+
+mbedtls_ct_if 0xffffffffffffffff 0x7fffffffffffffff 0x7fffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0x7fffffffffffffff":"0x7fffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0x7fffffffffffffff 0xffffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0x7fffffffffffffff":"0xffffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0x7fffffffffffffff 0x7fffffffffffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0x7fffffffffffffff":"0x7fffffffffffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0x7fffffffffffffff 0xffffffffffffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0x7fffffffffffffff":"0xffffffffffffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0xffffffffffffffff 0x0
+mbedtls_ct_if:"0xffffffffffffffff":"0xffffffffffffffff":"0x0"
+
+mbedtls_ct_if 0xffffffffffffffff 0xffffffffffffffff 0x1
+mbedtls_ct_if:"0xffffffffffffffff":"0xffffffffffffffff":"0x1"
+
+mbedtls_ct_if 0xffffffffffffffff 0xffffffffffffffff 0x7fffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0xffffffffffffffff":"0x7fffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0xffffffffffffffff 0xffffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0xffffffffffffffff":"0xffffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0xffffffffffffffff 0x7fffffffffffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0xffffffffffffffff":"0x7fffffffffffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0xffffffffffffffff 0xffffffffffffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0xffffffffffffffff":"0xffffffffffffffff"
+
+mbedtls_ct_zeroize_if 0x0 0
+mbedtls_ct_zeroize_if:"0x0":0
+
+mbedtls_ct_zeroize_if 0x0 1
+mbedtls_ct_zeroize_if:"0x0":1
+
+mbedtls_ct_zeroize_if 0x0 1024
+mbedtls_ct_zeroize_if:"0x0":1024
+
+mbedtls_ct_zeroize_if 0xffffffffffffffff 0
+mbedtls_ct_zeroize_if:"0xffffffffffffffff":0
+
+mbedtls_ct_zeroize_if 0xffffffffffffffff 1
+mbedtls_ct_zeroize_if:"0xffffffffffffffff":1
+
+mbedtls_ct_zeroize_if 0xffffffffffffffff 4
+mbedtls_ct_zeroize_if:"0xffffffffffffffff":4
+
+mbedtls_ct_zeroize_if 0xffffffffffffffff 5
+mbedtls_ct_zeroize_if:"0xffffffffffffffff":5
+
+mbedtls_ct_zeroize_if 0xffffffffffffffff 7
+mbedtls_ct_zeroize_if:"0xffffffffffffffff":7
+
+mbedtls_ct_zeroize_if 0xffffffffffffffff 8
+mbedtls_ct_zeroize_if:"0xffffffffffffffff":8
+
+mbedtls_ct_zeroize_if 0xffffffffffffffff 9
+mbedtls_ct_zeroize_if:"0xffffffffffffffff":9
+
+mbedtls_ct_zeroize_if 0xffffffffffffffff 1024
+mbedtls_ct_zeroize_if:"0xffffffffffffffff":1024
+
+mbedtls_ct_memmove_left 0 0
+mbedtls_ct_memmove_left:0:0
+
+mbedtls_ct_memmove_left 1 0
+mbedtls_ct_memmove_left:1:0
+
+mbedtls_ct_memmove_left 1 1
+mbedtls_ct_memmove_left:1:1
+
+mbedtls_ct_memmove_left 16 0
+mbedtls_ct_memmove_left:16:0
+
+mbedtls_ct_memmove_left 16 1
+mbedtls_ct_memmove_left:16:1
+
+mbedtls_ct_memmove_left 16 4
+mbedtls_ct_memmove_left:16:4
+
+mbedtls_ct_memmove_left 16 15
+mbedtls_ct_memmove_left:16:15
+
+mbedtls_ct_memmove_left 16 16
+mbedtls_ct_memmove_left:16:16
diff --git a/tests/suites/test_suite_constant_time.function b/tests/suites/test_suite_constant_time.function
index a2bf396..cce5b84 100644
--- a/tests/suites/test_suite_constant_time.function
+++ b/tests/suites/test_suite_constant_time.function
@@ -8,9 +8,15 @@
* under MSan or Valgrind will detect a non-constant-time implementation.
*/
+#include <stdio.h>
+
+#include <limits.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <mbedtls/bignum.h>
#include <mbedtls/constant_time.h>
#include <constant_time_internal.h>
-#include <constant_time_invasive.h>
#include <test/constant_flow.h>
/* END_HEADER */
@@ -26,15 +32,152 @@
/* END_CASE */
/* BEGIN_CASE */
+void mbedtls_ct_bool(char *input)
+{
+ mbedtls_ct_uint_t v = (mbedtls_ct_uint_t) strtoull(input, NULL, 16);
+ TEST_ASSERT(errno == 0);
+
+ mbedtls_ct_condition_t expected = (v != 0) ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE;
+ TEST_CF_SECRET(&v, sizeof(v));
+ TEST_EQUAL(mbedtls_ct_bool(v), expected);
+ TEST_CF_PUBLIC(&v, sizeof(v));
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void mbedtls_ct_bool_xxx(char *x_str, char *y_str)
+{
+ mbedtls_ct_uint_t x = strtoull(x_str, NULL, 0);
+ mbedtls_ct_uint_t y = strtoull(y_str, NULL, 0);
+
+ mbedtls_ct_uint_t x1 = x;
+ mbedtls_ct_uint_t y1 = y;
+
+ TEST_CF_SECRET(&x, sizeof(x));
+ TEST_CF_SECRET(&y, sizeof(y));
+
+ mbedtls_ct_condition_t expected = x1 ? MBEDTLS_CT_FALSE : MBEDTLS_CT_TRUE;
+ TEST_EQUAL(mbedtls_ct_bool_not(mbedtls_ct_bool(x)), expected);
+
+ expected = x1 != y1 ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE;
+ TEST_EQUAL(mbedtls_ct_bool_ne(x, y), expected);
+
+ expected = x1 == y1 ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE;
+ TEST_EQUAL(mbedtls_ct_bool_eq(x, y), expected);
+
+ expected = x1 > y1 ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE;
+ TEST_EQUAL(mbedtls_ct_bool_gt(x, y), expected);
+
+ expected = x1 < y1 ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE;
+ TEST_EQUAL(mbedtls_ct_bool_lt(x, y), expected);
+
+ expected = x1 >= y1 ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE;
+ TEST_EQUAL(mbedtls_ct_bool_ge(x, y), expected);
+
+ expected = x1 <= y1 ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE;
+ TEST_EQUAL(mbedtls_ct_bool_le(x, y), expected);
+
+ expected = mbedtls_ct_bool(x) ^ mbedtls_ct_bool(y) ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE;
+ TEST_EQUAL(mbedtls_ct_bool_xor(mbedtls_ct_bool(x), mbedtls_ct_bool(y)), expected);
+
+ expected = mbedtls_ct_bool(x) & mbedtls_ct_bool(y) ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE;
+ TEST_EQUAL(mbedtls_ct_bool_and(mbedtls_ct_bool(x), mbedtls_ct_bool(y)), expected);
+
+ expected = mbedtls_ct_bool(x) | mbedtls_ct_bool(y) ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE;
+ TEST_EQUAL(mbedtls_ct_bool_or(mbedtls_ct_bool(x), mbedtls_ct_bool(y)), expected);
+
+ TEST_CF_PUBLIC(&x, sizeof(x));
+ TEST_CF_PUBLIC(&y, sizeof(y));
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_BASE64_C */
+void mbedtls_ct_uchar_in_range_if(int li, int hi, int ti)
+{
+ unsigned char l = li, h = hi, t = ti;
+
+ for (unsigned x = 0; x <= 255; x++) {
+ unsigned char expected = (x >= l) && (x <= h) ? t : 0;
+
+ TEST_CF_SECRET(&x, sizeof(x));
+ TEST_CF_SECRET(&l, sizeof(l));
+ TEST_CF_SECRET(&h, sizeof(h));
+ TEST_CF_SECRET(&t, sizeof(t));
+
+ TEST_EQUAL(mbedtls_ct_uchar_in_range_if(l, h, (unsigned char) x, t), expected);
+
+ TEST_CF_PUBLIC(&x, sizeof(x));
+ TEST_CF_PUBLIC(&l, sizeof(l));
+ TEST_CF_PUBLIC(&h, sizeof(h));
+ TEST_CF_PUBLIC(&t, sizeof(t));
+ }
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void mbedtls_ct_if(char *c_str, char *t_str, char *f_str)
+{
+ mbedtls_ct_condition_t c = mbedtls_ct_bool(strtoull(c_str, NULL, 16));
+ mbedtls_ct_uint_t t = (mbedtls_ct_uint_t) strtoull(t_str, NULL, 16);
+ mbedtls_ct_uint_t f = (mbedtls_ct_uint_t) strtoull(f_str, NULL, 16);
+
+ mbedtls_ct_uint_t expected = c ? t : f;
+ mbedtls_ct_uint_t expected0 = c ? t : 0;
+
+ TEST_CF_SECRET(&c, sizeof(c));
+ TEST_CF_SECRET(&t, sizeof(t));
+ TEST_CF_SECRET(&f, sizeof(f));
+
+ TEST_EQUAL(mbedtls_ct_if(c, t, f), expected);
+ TEST_EQUAL(mbedtls_ct_size_if(c, t, f), (size_t) expected);
+ TEST_EQUAL(mbedtls_ct_uint_if(c, t, f), (unsigned) expected);
+#if defined(MBEDTLS_BIGNUM_C)
+ TEST_EQUAL(mbedtls_ct_mpi_uint_if(c, t, f), (mbedtls_mpi_uint) expected);
+#endif
+
+ TEST_EQUAL(mbedtls_ct_uint_if0(c, t), (unsigned) expected0);
+#if defined(MBEDTLS_BIGNUM_C)
+ TEST_EQUAL(mbedtls_ct_mpi_uint_if0(c, t), (mbedtls_mpi_uint) expected0);
+#endif
+
+ TEST_CF_PUBLIC(&c, sizeof(c));
+ TEST_CF_PUBLIC(&t, sizeof(t));
+ TEST_CF_PUBLIC(&f, sizeof(f));
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_PKCS1_V15:MBEDTLS_RSA_C:!MBEDTLS_RSA_ALT */
+void mbedtls_ct_zeroize_if(char *c_str, int len)
+{
+ uint8_t *buf = NULL;
+ mbedtls_ct_condition_t c = mbedtls_ct_bool(strtoull(c_str, NULL, 16));
+
+ ASSERT_ALLOC(buf, len);
+ for (size_t i = 0; i < (size_t) len; i++) {
+ buf[i] = 1;
+ }
+
+ TEST_CF_SECRET(&c, sizeof(c));
+ TEST_CF_SECRET(buf, len);
+ mbedtls_ct_zeroize_if(c, buf, len);
+ TEST_CF_PUBLIC(&c, sizeof(c));
+ TEST_CF_PUBLIC(buf, len);
+
+ for (size_t i = 0; i < (size_t) len; i++) {
+ TEST_EQUAL(buf[i], c != 0 ? 0 : 1);
+ }
+exit:
+ mbedtls_free(buf);
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
void mbedtls_ct_memcmp(int same, int size, int offset)
{
uint8_t *a = NULL, *b = NULL;
ASSERT_ALLOC(a, size + offset);
ASSERT_ALLOC(b, size + offset);
- TEST_CF_SECRET(a + offset, size);
- TEST_CF_SECRET(b + offset, size);
-
/* Construct data that matches, if same == -1, otherwise
* same gives the number of bytes (after the initial offset)
* that will match; after that it will differ.
@@ -49,9 +192,15 @@
}
int reference = memcmp(a + offset, b + offset, size);
+
+ TEST_CF_SECRET(a, size + offset);
+ TEST_CF_SECRET(b, size + offset);
+
int actual = mbedtls_ct_memcmp(a + offset, b + offset, size);
- TEST_CF_PUBLIC(a + offset, size);
- TEST_CF_PUBLIC(b + offset, size);
+
+ TEST_CF_PUBLIC(a, size + offset);
+ TEST_CF_PUBLIC(b, size + offset);
+ TEST_CF_PUBLIC(&actual, sizeof(actual));
if (same == -1 || same >= size) {
TEST_ASSERT(reference == 0);
@@ -66,59 +215,140 @@
}
/* END_CASE */
-/* BEGIN_CASE depends_on:MBEDTLS_SSL_SOME_SUITES_USE_MAC */
-void mbedtls_ct_memcpy_if_eq(int eq, int size, int offset)
+/* BEGIN_CASE */
+void mbedtls_ct_memcpy_if(int eq, int size, int offset)
{
- uint8_t *src = NULL, *result = NULL, *expected = NULL;
+ uint8_t *src = NULL, *src2 = NULL, *result = NULL, *expected = NULL;
ASSERT_ALLOC(src, size + offset);
+ ASSERT_ALLOC(src2, size + offset);
ASSERT_ALLOC(result, size + offset);
ASSERT_ALLOC(expected, size + offset);
+ /* Apply offset to result only */
for (int i = 0; i < size + offset; i++) {
- src[i] = 1;
- result[i] = 0xff;
+ src[i] = 1;
+ result[i] = 0xff;
expected[i] = eq ? 1 : 0xff;
}
- int one, secret_eq;
- TEST_CF_SECRET(&one, sizeof(one));
- TEST_CF_SECRET(&secret_eq, sizeof(secret_eq));
- one = 1;
- secret_eq = eq;
+ int secret_eq = eq;
+ TEST_CF_SECRET(&secret_eq, sizeof(secret_eq));
+ TEST_CF_SECRET(src, size + offset);
+ TEST_CF_SECRET(result, size + offset);
- mbedtls_ct_memcpy_if_eq(result + offset, src, size, secret_eq, one);
+ mbedtls_ct_memcpy_if(mbedtls_ct_bool(secret_eq), result + offset, src, NULL, size);
- TEST_CF_PUBLIC(&one, sizeof(one));
TEST_CF_PUBLIC(&secret_eq, sizeof(secret_eq));
+ TEST_CF_PUBLIC(src, size + offset);
+ TEST_CF_PUBLIC(result, size + offset);
ASSERT_COMPARE(expected, size, result + offset, size);
+
+ /* Apply offset to src only */
for (int i = 0; i < size + offset; i++) {
src[i] = 1;
result[i] = 0xff;
expected[i] = eq ? 1 : 0xff;
}
- TEST_CF_SECRET(&one, sizeof(one));
- TEST_CF_SECRET(&secret_eq, sizeof(secret_eq));
- one = 1;
- secret_eq = eq;
+ TEST_CF_SECRET(&secret_eq, sizeof(secret_eq));
+ TEST_CF_SECRET(src, size + offset);
+ TEST_CF_SECRET(result, size + offset);
- mbedtls_ct_memcpy_if_eq(result, src + offset, size, secret_eq, one);
+ mbedtls_ct_memcpy_if(mbedtls_ct_bool(secret_eq), result, src + offset, NULL, size);
- TEST_CF_PUBLIC(&one, sizeof(one));
TEST_CF_PUBLIC(&secret_eq, sizeof(secret_eq));
+ TEST_CF_PUBLIC(src, size + offset);
+ TEST_CF_PUBLIC(result, size + offset);
ASSERT_COMPARE(expected, size, result, size);
+
+
+ /* Apply offset to src and src2 */
+ for (int i = 0; i < size + offset; i++) {
+ src[i] = 1;
+ src2[i] = 2;
+ result[i] = 0xff;
+ expected[i] = eq ? 1 : 2;
+ }
+
+ TEST_CF_SECRET(&secret_eq, sizeof(secret_eq));
+ TEST_CF_SECRET(src, size + offset);
+ TEST_CF_SECRET(src2, size + offset);
+ TEST_CF_SECRET(result, size + offset);
+
+ mbedtls_ct_memcpy_if(mbedtls_ct_bool(secret_eq), result, src + offset, src2 + offset, size);
+
+ TEST_CF_PUBLIC(&secret_eq, sizeof(secret_eq));
+ TEST_CF_PUBLIC(src, size + offset);
+ TEST_CF_SECRET(src2, size + offset);
+ TEST_CF_PUBLIC(result, size + offset);
+
+ ASSERT_COMPARE(expected, size, result, size);
+
+
+ /* result == src == dest */
+ for (int i = 0; i < size + offset; i++) {
+ src[i] = 2;
+ expected[i] = 2;
+ }
+
+ TEST_CF_SECRET(&secret_eq, sizeof(secret_eq));
+ TEST_CF_SECRET(src, size + offset);
+ TEST_CF_SECRET(result, size + offset);
+
+ mbedtls_ct_memcpy_if(mbedtls_ct_bool(secret_eq), src + offset, src + offset, src + offset,
+ size);
+
+ TEST_CF_PUBLIC(&secret_eq, sizeof(secret_eq));
+ TEST_CF_PUBLIC(src, size + offset);
+ TEST_CF_PUBLIC(result, size + offset);
+
+ ASSERT_COMPARE(expected, size, src + offset, size);
exit:
mbedtls_free(src);
+ mbedtls_free(src2);
mbedtls_free(result);
mbedtls_free(expected);
}
/* END_CASE */
-/* BEGIN_CASE depends_on:MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC:MBEDTLS_TEST_HOOKS */
-void ssl_cf_memcpy_offset(int offset_min, int offset_max, int len)
+/* BEGIN_CASE depends_on:MBEDTLS_PKCS1_V15:MBEDTLS_RSA_C:!MBEDTLS_RSA_ALT */
+void mbedtls_ct_memmove_left(int len, int offset)
+{
+ size_t l = (size_t) len;
+ size_t o = (size_t) offset;
+
+ uint8_t *buf = NULL, *buf_expected = NULL;
+ ASSERT_ALLOC(buf, l);
+ ASSERT_ALLOC(buf_expected, l);
+
+ for (size_t i = 0; i < l; i++) {
+ buf[i] = (uint8_t) i;
+ buf_expected[i] = buf[i];
+ }
+
+ //Note: Marking o as secret causes false positives from Memsan
+ //TEST_CF_SECRET(&o, sizeof(o));
+ TEST_CF_SECRET(buf, l);
+ mbedtls_ct_memmove_left(buf, l, o);
+ //TEST_CF_PUBLIC(&o, sizeof(o));
+ TEST_CF_PUBLIC(buf, l);
+
+ if (l > 0) {
+ memmove(buf_expected, buf_expected + o, l - o);
+ memset(buf_expected + (l - o), 0, o);
+ TEST_ASSERT(memcmp(buf, buf_expected, l) == 0);
+ }
+exit:
+ mbedtls_free(buf);
+ mbedtls_free(buf_expected);
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_SSL_SOME_SUITES_USE_MAC */
+void mbedtls_ct_memcpy_offset(int offset_min, int offset_max, int len)
{
unsigned char *dst = NULL;
unsigned char *src = NULL;
@@ -135,9 +365,12 @@
mbedtls_test_set_step((int) secret);
TEST_CF_SECRET(&secret, sizeof(secret));
+ TEST_CF_SECRET(src, len);
+ TEST_CF_SECRET(dst, len);
mbedtls_ct_memcpy_offset(dst, src, secret,
offset_min, offset_max, len);
TEST_CF_PUBLIC(&secret, sizeof(secret));
+ TEST_CF_PUBLIC(src, len);
TEST_CF_PUBLIC(dst, len);
ASSERT_COMPARE(dst, len, src + secret, len);
diff --git a/tests/suites/test_suite_constant_time_hmac.function b/tests/suites/test_suite_constant_time_hmac.function
index 9ee372b..902acfa 100644
--- a/tests/suites/test_suite_constant_time_hmac.function
+++ b/tests/suites/test_suite_constant_time_hmac.function
@@ -8,7 +8,7 @@
#include <test/constant_flow.h>
/* END_HEADER */
-/* BEGIN_CASE depends_on:MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC:MBEDTLS_TEST_HOOKS */
+/* BEGIN_CASE depends_on:MBEDTLS_SSL_SOME_SUITES_USE_MAC:MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC:MBEDTLS_TEST_HOOKS */
void ssl_cf_hmac(int hash)
{
/*
diff --git a/tests/suites/test_suite_ecp.function b/tests/suites/test_suite_ecp.function
index 2658a43..77c79e1 100644
--- a/tests/suites/test_suite_ecp.function
+++ b/tests/suites/test_suite_ecp.function
@@ -1622,7 +1622,7 @@
TEST_EQUAL(0, mbedtls_mpi_mod_random(&rX, 1, &m,
mbedtls_test_rnd_std_rand, NULL));
- TEST_ASSERT(mbedtls_mpi_core_lt_ct(rX.p, m.p, limbs) == 1);
+ TEST_ASSERT(mbedtls_mpi_core_lt_ct(rX.p, m.p, limbs) == MBEDTLS_CT_TRUE);
exit:
mbedtls_mpi_mod_modulus_free(&m);