741d423ef8
Signed-off-by: Dave Rodgman <dave.rodgman@arm.com>
488 lines
17 KiB
C
488 lines
17 KiB
C
/**
|
|
* Constant-time functions
|
|
*
|
|
* Copyright The Mbed TLS Contributors
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
* not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#ifndef MBEDTLS_CONSTANT_TIME_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
|
|
|
|
/* 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 must be treated as opaque and only created and
|
|
* manipulated via the functions in this header. The compiler should never
|
|
* be able to prove anything about its value at compile-time.
|
|
*
|
|
* 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) mbedtls_ct_compiler_opaque(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) mbedtls_ct_compiler_opaque(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) mbedtls_ct_compiler_opaque(UINT32_MAX))
|
|
#endif
|
|
#define MBEDTLS_CT_FALSE ((mbedtls_ct_condition_t) mbedtls_ct_compiler_opaque(0))
|
|
|
|
/* constant_time_impl.h contains all the static inline implementations,
|
|
* so that constant_time_internal.h is more readable.
|
|
*
|
|
* gcc generates warnings about duplicate declarations, so disable this
|
|
* warning.
|
|
*/
|
|
#ifdef __GNUC__
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wredundant-decls"
|
|
#endif
|
|
|
|
#include "constant_time_impl.h"
|
|
|
|
/* ============================================================================
|
|
* Boolean operations
|
|
*/
|
|
|
|
/** Convert a number into a mbedtls_ct_condition_t.
|
|
*
|
|
* \param x Number to convert.
|
|
*
|
|
* \return MBEDTLS_CT_TRUE if \p x != 0, or MBEDTLS_CT_FALSE if \p x == 0
|
|
*
|
|
*/
|
|
static inline mbedtls_ct_condition_t mbedtls_ct_bool(mbedtls_ct_uint_t x);
|
|
|
|
/** Boolean "not 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_ne(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y);
|
|
|
|
/** Boolean "equals" 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_eq(mbedtls_ct_uint_t x,
|
|
mbedtls_ct_uint_t y);
|
|
|
|
/** Boolean "less than" 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_lt(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y);
|
|
|
|
/** Boolean "greater than" 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_gt(mbedtls_ct_uint_t x,
|
|
mbedtls_ct_uint_t y);
|
|
|
|
/** Boolean "greater 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_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 == 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 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)
|
|
|
|
/** Choose between two mbedtls_mpi_uint values.
|
|
*
|
|
* Functionally equivalent to:
|
|
*
|
|
* condition ? if1 : if0.
|
|
*
|
|
* \param condition Condition to test.
|
|
* \param if1 Value to use if \p condition == MBEDTLS_CT_TRUE.
|
|
* \param if0 Value to use if \p condition == MBEDTLS_CT_FALSE.
|
|
*
|
|
* \return \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise \c if0.
|
|
*/
|
|
static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if(mbedtls_ct_condition_t condition, \
|
|
mbedtls_mpi_uint if1, \
|
|
mbedtls_mpi_uint if0);
|
|
|
|
#endif
|
|
|
|
/** Choose between an unsigned value and 0.
|
|
*
|
|
* Functionally equivalent to:
|
|
*
|
|
* condition ? if1 : 0.
|
|
*
|
|
* 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.
|
|
*/
|
|
static inline unsigned mbedtls_ct_uint_if0(mbedtls_ct_condition_t condition, unsigned if1);
|
|
|
|
#if defined(MBEDTLS_BIGNUM_C)
|
|
|
|
/** Choose between an mbedtls_mpi_uint value and 0.
|
|
*
|
|
* Functionally equivalent to:
|
|
*
|
|
* condition ? if1 : 0.
|
|
*
|
|
* Functionally equivalent tombedtls_ct_mpi_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.
|
|
*/
|
|
static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if0(mbedtls_ct_condition_t condition,
|
|
mbedtls_mpi_uint if1);
|
|
|
|
#endif
|
|
|
|
/** Constant-flow char selection
|
|
*
|
|
* \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
|
|
*
|
|
* \return \p t if \p low <= \p c <= \p high, 0 otherwise.
|
|
*/
|
|
static inline unsigned char mbedtls_ct_uchar_in_range_if(unsigned char low,
|
|
unsigned char high,
|
|
unsigned char c,
|
|
unsigned char t);
|
|
|
|
|
|
/* ============================================================================
|
|
* Block memory operations
|
|
*/
|
|
|
|
#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT)
|
|
|
|
/** Conditionally set a block of memory to zero.
|
|
*
|
|
* 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 determine if this parameter is 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
|
|
* function's behavior is well-defined regardless of the
|
|
* contents of the buffers. This may result in false
|
|
* positives from static or dynamic analyzers, especially
|
|
* if \p dest is not initialized.
|
|
*
|
|
* \param dest Secret. The destination buffer. This must point to a writable
|
|
* buffer of at least \p len bytes.
|
|
* \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 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.
|
|
* \param offset_max The maximal value of \p offset.
|
|
* \param len The number of bytes to copy.
|
|
*/
|
|
void mbedtls_ct_memcpy_offset(unsigned char *dest,
|
|
const unsigned char *src,
|
|
size_t offset,
|
|
size_t offset_min,
|
|
size_t offset_max,
|
|
size_t len);
|
|
|
|
/* 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);
|
|
|
|
#ifdef __GNUC__
|
|
#pragma GCC diagnostic pop
|
|
#endif
|
|
|
|
#endif /* MBEDTLS_CONSTANT_TIME_INTERNAL_H */
|