Merge BoringSSL 92b7c89: Add a value barrier to constant-time selects.

This commit is contained in:
Brian Smith 2019-07-02 17:01:41 -10:00
commit 4bbba957f8
3 changed files with 51 additions and 3 deletions

View File

@ -183,6 +183,36 @@ typedef uint32_t crypto_word;
#define CONSTTIME_TRUE_W ~((crypto_word)0)
#define CONSTTIME_FALSE_W ((crypto_word)0)
// value_barrier_w returns |a|, but prevents GCC and Clang from reasoning about
// the returned value. This is used to mitigate compilers undoing constant-time
// code, until we can express our requirements directly in the language.
//
// Note the compiler is aware that |value_barrier_w| has no side effects and
// always has the same output for a given input. This allows it to eliminate
// dead code, move computations across loops, and vectorize.
static inline crypto_word value_barrier_w(crypto_word a) {
#if !defined(OPENSSL_NO_ASM) && (defined(__GNUC__) || defined(__clang__))
__asm__("" : "+r"(a) : /* no inputs */);
#endif
return a;
}
// value_barrier_u32 behaves like |value_barrier_w| but takes a |uint32_t|.
static inline uint32_t value_barrier_u32(uint32_t a) {
#if !defined(OPENSSL_NO_ASM) && (defined(__GNUC__) || defined(__clang__))
__asm__("" : "+r"(a) : /* no inputs */);
#endif
return a;
}
// value_barrier_u64 behaves like |value_barrier_w| but takes a |uint64_t|.
static inline uint64_t value_barrier_u64(uint64_t a) {
#if !defined(OPENSSL_NO_ASM) && (defined(__GNUC__) || defined(__clang__))
__asm__("" : "+r"(a) : /* no inputs */);
#endif
return a;
}
// constant_time_msb_w returns the given value with the MSB copied to all the
// other bits.
static inline crypto_word constant_time_msb_w(crypto_word a) {
@ -221,7 +251,13 @@ static inline crypto_word constant_time_eq_w(crypto_word a,
static inline crypto_word constant_time_select_w(crypto_word mask,
crypto_word a,
crypto_word b) {
return (mask & a) | (~mask & b);
// Clang recognizes this pattern as a select. While it usually transforms it
// to a cmov, it sometimes further transforms it into a branch, which we do
// not want.
//
// Adding barriers to both |mask| and |~mask| breaks the relationship between
// the two, which makes the compiler stick with bitmasks.
return (value_barrier_w(mask) & a) | (value_barrier_w(~mask) & b);
}
// from_be_u32_ptr returns the 32-bit big-endian-encoded value at |data|.

8
third_party/fiat/curve25519_32.h generated vendored
View File

@ -90,7 +90,13 @@ static void fiat_25519_subborrowx_u25(uint32_t* out1, fiat_25519_uint1* out2, fi
static void fiat_25519_cmovznz_u32(uint32_t* out1, fiat_25519_uint1 arg1, uint32_t arg2, uint32_t arg3) {
fiat_25519_uint1 x1 = (!(!arg1));
uint32_t x2 = ((fiat_25519_int1)(0x0 - x1) & UINT32_C(0xffffffff));
uint32_t x3 = ((x2 & arg3) | ((~x2) & arg2));
// Note this line has been patched from the synthesized code to add value
// barriers.
//
// Clang recognizes this pattern as a select. While it usually transforms it
// to a cmov, it sometimes further transforms it into a branch, which we do
// not want.
uint32_t x3 = ((value_barrier_u32(x2) & arg3) | (value_barrier_u32(~x2) & arg2));
*out1 = x3;
}

8
third_party/fiat/curve25519_64.h generated vendored
View File

@ -58,7 +58,13 @@ static void fiat_25519_subborrowx_u51(uint64_t* out1, fiat_25519_uint1* out2, fi
static void fiat_25519_cmovznz_u64(uint64_t* out1, fiat_25519_uint1 arg1, uint64_t arg2, uint64_t arg3) {
fiat_25519_uint1 x1 = (!(!arg1));
uint64_t x2 = ((fiat_25519_int1)(0x0 - x1) & UINT64_C(0xffffffffffffffff));
uint64_t x3 = ((x2 & arg3) | ((~x2) & arg2));
// Note this line has been patched from the synthesized code to add value
// barriers.
//
// Clang recognizes this pattern as a select. While it usually transforms it
// to a cmov, it sometimes further transforms it into a branch, which we do
// not want.
uint64_t x3 = ((value_barrier_u64(x2) & arg3) | (value_barrier_u64(~x2) & arg2));
*out1 = x3;
}