Path: blob/master/thirdparty/mbedtls/library/constant_time_impl.h
9898 views
/**1* Constant-time functions2*3* Copyright The Mbed TLS Contributors4* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later5*/67#ifndef MBEDTLS_CONSTANT_TIME_IMPL_H8#define MBEDTLS_CONSTANT_TIME_IMPL_H910#include <stddef.h>1112#include "common.h"1314#if defined(MBEDTLS_BIGNUM_C)15#include "mbedtls/bignum.h"16#endif1718/*19* To improve readability of constant_time_internal.h, the static inline20* definitions are here, and constant_time_internal.h has only the declarations.21*22* This results in duplicate declarations of the form:23* static inline void f(); // from constant_time_internal.h24* static inline void f() { ... } // from constant_time_impl.h25* when constant_time_internal.h is included.26*27* This appears to behave as if the declaration-without-definition was not present28* (except for warnings if gcc -Wredundant-decls or similar is used).29*30* Disable -Wredundant-decls so that gcc does not warn about this. This is re-enabled31* at the bottom of this file.32*/33#if defined(MBEDTLS_COMPILER_IS_GCC) && (__GNUC__ > 4)34#pragma GCC diagnostic push35#pragma GCC diagnostic ignored "-Wredundant-decls"36#endif3738/* armcc5 --gnu defines __GNUC__ but doesn't support GNU's extended asm */39#if defined(MBEDTLS_HAVE_ASM) && defined(__GNUC__) && (!defined(__ARMCC_VERSION) || \40__ARMCC_VERSION >= 6000000)41#define MBEDTLS_CT_ASM42#if (defined(__arm__) || defined(__thumb__) || defined(__thumb2__))43#define MBEDTLS_CT_ARM_ASM44#elif defined(__aarch64__)45#define MBEDTLS_CT_AARCH64_ASM46#elif defined(__amd64__) || defined(__x86_64__)47#define MBEDTLS_CT_X86_64_ASM48#elif defined(__i386__)49#define MBEDTLS_CT_X86_ASM50#endif51#endif5253#define MBEDTLS_CT_SIZE (sizeof(mbedtls_ct_uint_t) * 8)545556/* ============================================================================57* Core const-time primitives58*/5960/* Ensure that the compiler cannot know the value of x (i.e., cannot optimise61* based on its value) after this function is called.62*63* If we are not using assembly, this will be fairly inefficient, so its use64* should be minimised.65*/6667#if !defined(MBEDTLS_CT_ASM)68extern volatile mbedtls_ct_uint_t mbedtls_ct_zero;69#endif7071/**72* \brief Ensure that a value cannot be known at compile time.73*74* \param x The value to hide from the compiler.75* \return The same value that was passed in, such that the compiler76* cannot prove its value (even for calls of the form77* x = mbedtls_ct_compiler_opaque(1), x will be unknown).78*79* \note This is mainly used in constructing mbedtls_ct_condition_t80* values and performing operations over them, to ensure that81* there is no way for the compiler to ever know anything about82* the value of an mbedtls_ct_condition_t.83*/84static inline mbedtls_ct_uint_t mbedtls_ct_compiler_opaque(mbedtls_ct_uint_t x)85{86#if defined(MBEDTLS_CT_ASM)87asm volatile ("" : [x] "+r" (x) :);88return x;89#else90return x ^ mbedtls_ct_zero;91#endif92}9394/*95* Selecting unified syntax is needed for gcc, and harmless on clang.96*97* This is needed because on Thumb 1, condition flags are always set, so98* e.g. "negs" is supported but "neg" is not (on Thumb 2, both exist).99*100* Under Thumb 1 unified syntax, only the "negs" form is accepted, and101* under divided syntax, only the "neg" form is accepted. clang only102* supports unified syntax.103*104* On Thumb 2 and Arm, both compilers are happy with the "s" suffix,105* although we don't actually care about setting the flags.106*107* For old versions of gcc (see #8516 for details), restore divided108* syntax afterwards - otherwise old versions of gcc seem to apply109* unified syntax globally, which breaks other asm code.110*/111#if defined(MBEDTLS_COMPILER_IS_GCC) && defined(__thumb__) && !defined(__thumb2__) && \112(__GNUC__ < 11) && !defined(__ARM_ARCH_2__)113#define RESTORE_ASM_SYNTAX ".syntax divided \n\t"114#else115#define RESTORE_ASM_SYNTAX116#endif117118/* Convert a number into a condition in constant time. */119static inline mbedtls_ct_condition_t mbedtls_ct_bool(mbedtls_ct_uint_t x)120{121/*122* Define mask-generation code that, as far as possible, will not use branches or conditional instructions.123*124* For some platforms / type sizes, we define assembly to assure this.125*126* Otherwise, we define a plain C fallback which (in May 2023) does not get optimised into127* conditional instructions or branches by trunk clang, gcc, or MSVC v19.128*/129#if defined(MBEDTLS_CT_AARCH64_ASM) && (defined(MBEDTLS_CT_SIZE_32) || defined(MBEDTLS_CT_SIZE_64))130mbedtls_ct_uint_t s;131asm volatile ("neg %x[s], %x[x] \n\t"132"orr %x[x], %x[s], %x[x] \n\t"133"asr %x[x], %x[x], 63 \n\t"134:135[s] "=&r" (s),136[x] "+&r" (x)137:138:139);140return (mbedtls_ct_condition_t) x;141#elif defined(MBEDTLS_CT_ARM_ASM) && defined(MBEDTLS_CT_SIZE_32)142uint32_t s;143asm volatile (".syntax unified \n\t"144"negs %[s], %[x] \n\t"145"orrs %[x], %[x], %[s] \n\t"146"asrs %[x], %[x], #31 \n\t"147RESTORE_ASM_SYNTAX148:149[s] "=&l" (s),150[x] "+&l" (x)151:152:153"cc" /* clobbers flag bits */154);155return (mbedtls_ct_condition_t) x;156#elif defined(MBEDTLS_CT_X86_64_ASM) && (defined(MBEDTLS_CT_SIZE_32) || defined(MBEDTLS_CT_SIZE_64))157uint64_t s;158asm volatile ("mov %[x], %[s] \n\t"159"neg %[s] \n\t"160"or %[x], %[s] \n\t"161"sar $63, %[s] \n\t"162:163[s] "=&a" (s)164:165[x] "D" (x)166:167);168return (mbedtls_ct_condition_t) s;169#elif defined(MBEDTLS_CT_X86_ASM) && defined(MBEDTLS_CT_SIZE_32)170uint32_t s;171asm volatile ("mov %[x], %[s] \n\t"172"neg %[s] \n\t"173"or %[s], %[x] \n\t"174"sar $31, %[x] \n\t"175:176[s] "=&c" (s),177[x] "+&a" (x)178:179:180);181return (mbedtls_ct_condition_t) x;182#else183const mbedtls_ct_uint_t xo = mbedtls_ct_compiler_opaque(x);184#if defined(_MSC_VER)185/* MSVC has a warning about unary minus on unsigned, but this is186* well-defined and precisely what we want to do here */187#pragma warning( push )188#pragma warning( disable : 4146 )189#endif190// y is negative (i.e., top bit set) iff x is non-zero191mbedtls_ct_int_t y = (-xo) | -(xo >> 1);192193// extract only the sign bit of y so that y == 1 (if x is non-zero) or 0 (if x is zero)194y = (((mbedtls_ct_uint_t) y) >> (MBEDTLS_CT_SIZE - 1));195196// -y has all bits set (if x is non-zero), or all bits clear (if x is zero)197return (mbedtls_ct_condition_t) (-y);198#if defined(_MSC_VER)199#pragma warning( pop )200#endif201#endif202}203204static inline mbedtls_ct_uint_t mbedtls_ct_if(mbedtls_ct_condition_t condition,205mbedtls_ct_uint_t if1,206mbedtls_ct_uint_t if0)207{208#if defined(MBEDTLS_CT_AARCH64_ASM) && (defined(MBEDTLS_CT_SIZE_32) || defined(MBEDTLS_CT_SIZE_64))209asm volatile ("and %x[if1], %x[if1], %x[condition] \n\t"210"mvn %x[condition], %x[condition] \n\t"211"and %x[condition], %x[condition], %x[if0] \n\t"212"orr %x[condition], %x[if1], %x[condition]"213:214[condition] "+&r" (condition),215[if1] "+&r" (if1)216:217[if0] "r" (if0)218:219);220return (mbedtls_ct_uint_t) condition;221#elif defined(MBEDTLS_CT_ARM_ASM) && defined(MBEDTLS_CT_SIZE_32)222asm volatile (".syntax unified \n\t"223"ands %[if1], %[if1], %[condition] \n\t"224"mvns %[condition], %[condition] \n\t"225"ands %[condition], %[condition], %[if0] \n\t"226"orrs %[condition], %[if1], %[condition] \n\t"227RESTORE_ASM_SYNTAX228:229[condition] "+&l" (condition),230[if1] "+&l" (if1)231:232[if0] "l" (if0)233:234"cc"235);236return (mbedtls_ct_uint_t) condition;237#elif defined(MBEDTLS_CT_X86_64_ASM) && (defined(MBEDTLS_CT_SIZE_32) || defined(MBEDTLS_CT_SIZE_64))238asm volatile ("and %[condition], %[if1] \n\t"239"not %[condition] \n\t"240"and %[condition], %[if0] \n\t"241"or %[if1], %[if0] \n\t"242:243[condition] "+&D" (condition),244[if1] "+&S" (if1),245[if0] "+&a" (if0)246:247:248);249return if0;250#elif defined(MBEDTLS_CT_X86_ASM) && defined(MBEDTLS_CT_SIZE_32)251asm volatile ("and %[condition], %[if1] \n\t"252"not %[condition] \n\t"253"and %[if0], %[condition] \n\t"254"or %[condition], %[if1] \n\t"255:256[condition] "+&c" (condition),257[if1] "+&a" (if1)258:259[if0] "b" (if0)260:261);262return if1;263#else264mbedtls_ct_condition_t not_cond =265(mbedtls_ct_condition_t) (~mbedtls_ct_compiler_opaque(condition));266return (mbedtls_ct_uint_t) ((condition & if1) | (not_cond & if0));267#endif268}269270static inline mbedtls_ct_condition_t mbedtls_ct_uint_lt(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y)271{272#if defined(MBEDTLS_CT_AARCH64_ASM) && (defined(MBEDTLS_CT_SIZE_32) || defined(MBEDTLS_CT_SIZE_64))273uint64_t s1;274asm volatile ("eor %x[s1], %x[y], %x[x] \n\t"275"sub %x[x], %x[x], %x[y] \n\t"276"bic %x[x], %x[x], %x[s1] \n\t"277"and %x[s1], %x[s1], %x[y] \n\t"278"orr %x[s1], %x[x], %x[s1] \n\t"279"asr %x[x], %x[s1], 63"280:281[s1] "=&r" (s1),282[x] "+&r" (x)283:284[y] "r" (y)285:286);287return (mbedtls_ct_condition_t) x;288#elif defined(MBEDTLS_CT_ARM_ASM) && defined(MBEDTLS_CT_SIZE_32)289uint32_t s1;290asm volatile (291".syntax unified \n\t"292#if defined(__thumb__) && !defined(__thumb2__)293"movs %[s1], %[x] \n\t"294"eors %[s1], %[s1], %[y] \n\t"295#else296"eors %[s1], %[x], %[y] \n\t"297#endif298"subs %[x], %[x], %[y] \n\t"299"bics %[x], %[x], %[s1] \n\t"300"ands %[y], %[s1], %[y] \n\t"301"orrs %[x], %[x], %[y] \n\t"302"asrs %[x], %[x], #31 \n\t"303RESTORE_ASM_SYNTAX304:305[s1] "=&l" (s1),306[x] "+&l" (x),307[y] "+&l" (y)308:309:310"cc"311);312return (mbedtls_ct_condition_t) x;313#elif defined(MBEDTLS_CT_X86_64_ASM) && (defined(MBEDTLS_CT_SIZE_32) || defined(MBEDTLS_CT_SIZE_64))314uint64_t s;315asm volatile ("mov %[x], %[s] \n\t"316"xor %[y], %[s] \n\t"317"sub %[y], %[x] \n\t"318"and %[s], %[y] \n\t"319"not %[s] \n\t"320"and %[s], %[x] \n\t"321"or %[y], %[x] \n\t"322"sar $63, %[x] \n\t"323:324[s] "=&a" (s),325[x] "+&D" (x),326[y] "+&S" (y)327:328:329);330return (mbedtls_ct_condition_t) x;331#elif defined(MBEDTLS_CT_X86_ASM) && defined(MBEDTLS_CT_SIZE_32)332uint32_t s;333asm volatile ("mov %[x], %[s] \n\t"334"xor %[y], %[s] \n\t"335"sub %[y], %[x] \n\t"336"and %[s], %[y] \n\t"337"not %[s] \n\t"338"and %[s], %[x] \n\t"339"or %[y], %[x] \n\t"340"sar $31, %[x] \n\t"341:342[s] "=&b" (s),343[x] "+&a" (x),344[y] "+&c" (y)345:346:347);348return (mbedtls_ct_condition_t) x;349#else350/* Ensure that the compiler cannot optimise the following operations over x and y,351* even if it knows the value of x and y.352*/353const mbedtls_ct_uint_t xo = mbedtls_ct_compiler_opaque(x);354const mbedtls_ct_uint_t yo = mbedtls_ct_compiler_opaque(y);355/*356* Check if the most significant bits (MSB) of the operands are different.357* cond is true iff the MSBs differ.358*/359mbedtls_ct_condition_t cond = mbedtls_ct_bool((xo ^ yo) >> (MBEDTLS_CT_SIZE - 1));360361/*362* If the MSB are the same then the difference x-y will be negative (and363* have its MSB set to 1 during conversion to unsigned) if and only if x<y.364*365* If the MSB are different, then the operand with the MSB of 1 is the366* bigger. (That is if y has MSB of 1, then x<y is true and it is false if367* the MSB of y is 0.)368*/369370// Select either y, or x - y371mbedtls_ct_uint_t ret = mbedtls_ct_if(cond, yo, (mbedtls_ct_uint_t) (xo - yo));372373// Extract only the MSB of ret374ret = ret >> (MBEDTLS_CT_SIZE - 1);375376// Convert to a condition (i.e., all bits set iff non-zero)377return mbedtls_ct_bool(ret);378#endif379}380381static inline mbedtls_ct_condition_t mbedtls_ct_uint_ne(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y)382{383/* diff = 0 if x == y, non-zero otherwise */384const mbedtls_ct_uint_t diff = mbedtls_ct_compiler_opaque(x) ^ mbedtls_ct_compiler_opaque(y);385386/* all ones if x != y, 0 otherwise */387return mbedtls_ct_bool(diff);388}389390static inline unsigned char mbedtls_ct_uchar_in_range_if(unsigned char low,391unsigned char high,392unsigned char c,393unsigned char t)394{395const unsigned char co = (unsigned char) mbedtls_ct_compiler_opaque(c);396const unsigned char to = (unsigned char) mbedtls_ct_compiler_opaque(t);397398/* low_mask is: 0 if low <= c, 0x...ff if low > c */399unsigned low_mask = ((unsigned) co - low) >> 8;400/* high_mask is: 0 if c <= high, 0x...ff if c > high */401unsigned high_mask = ((unsigned) high - co) >> 8;402403return (unsigned char) (~(low_mask | high_mask)) & to;404}405406/* ============================================================================407* Everything below here is trivial wrapper functions408*/409410static inline size_t mbedtls_ct_size_if(mbedtls_ct_condition_t condition,411size_t if1,412size_t if0)413{414return (size_t) mbedtls_ct_if(condition, (mbedtls_ct_uint_t) if1, (mbedtls_ct_uint_t) if0);415}416417static inline unsigned mbedtls_ct_uint_if(mbedtls_ct_condition_t condition,418unsigned if1,419unsigned if0)420{421return (unsigned) mbedtls_ct_if(condition, (mbedtls_ct_uint_t) if1, (mbedtls_ct_uint_t) if0);422}423424static inline mbedtls_ct_condition_t mbedtls_ct_bool_if(mbedtls_ct_condition_t condition,425mbedtls_ct_condition_t if1,426mbedtls_ct_condition_t if0)427{428return (mbedtls_ct_condition_t) mbedtls_ct_if(condition, (mbedtls_ct_uint_t) if1,429(mbedtls_ct_uint_t) if0);430}431432#if defined(MBEDTLS_BIGNUM_C)433434static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if(mbedtls_ct_condition_t condition,435mbedtls_mpi_uint if1,436mbedtls_mpi_uint if0)437{438return (mbedtls_mpi_uint) mbedtls_ct_if(condition,439(mbedtls_ct_uint_t) if1,440(mbedtls_ct_uint_t) if0);441}442443#endif444445static inline size_t mbedtls_ct_size_if_else_0(mbedtls_ct_condition_t condition, size_t if1)446{447return (size_t) (condition & if1);448}449450static inline unsigned mbedtls_ct_uint_if_else_0(mbedtls_ct_condition_t condition, unsigned if1)451{452return (unsigned) (condition & if1);453}454455static inline mbedtls_ct_condition_t mbedtls_ct_bool_if_else_0(mbedtls_ct_condition_t condition,456mbedtls_ct_condition_t if1)457{458return (mbedtls_ct_condition_t) (condition & if1);459}460461#if defined(MBEDTLS_BIGNUM_C)462463static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if_else_0(mbedtls_ct_condition_t condition,464mbedtls_mpi_uint if1)465{466return (mbedtls_mpi_uint) (condition & if1);467}468469#endif /* MBEDTLS_BIGNUM_C */470471static inline int mbedtls_ct_error_if(mbedtls_ct_condition_t condition, int if1, int if0)472{473/* Coverting int -> uint -> int here is safe, because we require if1 and if0 to be474* in the range -32767..0, and we require 32-bit int and uint types.475*476* This means that (0 <= -if0 < INT_MAX), so negating if0 is safe, and similarly for477* converting back to int.478*/479return -((int) mbedtls_ct_if(condition, (mbedtls_ct_uint_t) (-if1),480(mbedtls_ct_uint_t) (-if0)));481}482483static inline int mbedtls_ct_error_if_else_0(mbedtls_ct_condition_t condition, int if1)484{485return -((int) (condition & (-if1)));486}487488static inline mbedtls_ct_condition_t mbedtls_ct_uint_eq(mbedtls_ct_uint_t x,489mbedtls_ct_uint_t y)490{491return ~mbedtls_ct_uint_ne(x, y);492}493494static inline mbedtls_ct_condition_t mbedtls_ct_uint_gt(mbedtls_ct_uint_t x,495mbedtls_ct_uint_t y)496{497return mbedtls_ct_uint_lt(y, x);498}499500static inline mbedtls_ct_condition_t mbedtls_ct_uint_ge(mbedtls_ct_uint_t x,501mbedtls_ct_uint_t y)502{503return ~mbedtls_ct_uint_lt(x, y);504}505506static inline mbedtls_ct_condition_t mbedtls_ct_uint_le(mbedtls_ct_uint_t x,507mbedtls_ct_uint_t y)508{509return ~mbedtls_ct_uint_gt(x, y);510}511512static inline mbedtls_ct_condition_t mbedtls_ct_bool_ne(mbedtls_ct_condition_t x,513mbedtls_ct_condition_t y)514{515return (mbedtls_ct_condition_t) (x ^ y);516}517518static inline mbedtls_ct_condition_t mbedtls_ct_bool_and(mbedtls_ct_condition_t x,519mbedtls_ct_condition_t y)520{521return (mbedtls_ct_condition_t) (x & y);522}523524static inline mbedtls_ct_condition_t mbedtls_ct_bool_or(mbedtls_ct_condition_t x,525mbedtls_ct_condition_t y)526{527return (mbedtls_ct_condition_t) (x | y);528}529530static inline mbedtls_ct_condition_t mbedtls_ct_bool_not(mbedtls_ct_condition_t x)531{532return (mbedtls_ct_condition_t) (~x);533}534535#if defined(MBEDTLS_COMPILER_IS_GCC) && (__GNUC__ > 4)536/* Restore warnings for -Wredundant-decls on gcc */537#pragma GCC diagnostic pop538#endif539540#endif /* MBEDTLS_CONSTANT_TIME_IMPL_H */541542543