mirror of
https://github.com/Mbed-TLS/mbedtls.git
synced 2025-08-01 10:06:53 +03:00
Merge pull request #7578 from daverodgman/safer-ct5
Improve constant-time interface
This commit is contained in:
130
library/bignum.c
130
library/bignum.c
@ -54,6 +54,132 @@
|
||||
#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 different_sign, 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).
|
||||
*/
|
||||
different_sign = mbedtls_ct_bool_xor(X_is_negative, Y_is_negative); // non-zero if different sign
|
||||
result = mbedtls_ct_bool_and(different_sign, X_is_negative);
|
||||
|
||||
/*
|
||||
* Assuming signs are the same, compare X and Y. We switch the comparison
|
||||
* order if they are negative so that we get the right result, regardles of
|
||||
* sign.
|
||||
*/
|
||||
|
||||
/* This array is used to conditionally swap the pointers in const time */
|
||||
void * const p[2] = { X->p, Y->p };
|
||||
size_t i = mbedtls_ct_size_if_else_0(X_is_negative, 1);
|
||||
mbedtls_ct_condition_t lt = mbedtls_mpi_core_lt_ct(p[i], p[i ^ 1], X->n);
|
||||
|
||||
/*
|
||||
* Store in result iff the signs are the same (i.e., iff different_sign == false). If
|
||||
* the signs differ, result has already been set, so we don't change it.
|
||||
*/
|
||||
result = mbedtls_ct_bool_or(result,
|
||||
mbedtls_ct_bool_and(mbedtls_ct_bool_not(different_sign), lt));
|
||||
|
||||
*ret = mbedtls_ct_uint_if_else_0(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_if_else_0(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 */
|
||||
#define mbedtls_mpi_zeroize_and_free(v, n) mbedtls_zeroize_and_free(v, ciL * (n))
|
||||
|
||||
@ -1624,10 +1750,8 @@ static int mpi_select(mbedtls_mpi *R, const mbedtls_mpi *T, size_t T_size, size_
|
||||
|
||||
for (size_t i = 0; i < T_size; i++) {
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_assign(R, &T[i],
|
||||
(unsigned char) mbedtls_ct_size_bool_eq(i,
|
||||
idx)));
|
||||
(unsigned char) mbedtls_ct_uint_eq(i, idx)));
|
||||
}
|
||||
|
||||
cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
Reference in New Issue
Block a user