Using |size_t| was correct, except for NaCl, which is a 64-bit build with 32-bit pointers. In that configuration, |size_t| is smaller than the native word size. This change adds |crypto_word_t|, an unsigned type with native size and switches constant-time functions to using it. Change-Id: Ib275127063d5edbb7c55d413132711b7c74206b0 Reviewed-on: https://boringssl-review.googlesource.com/15325 Reviewed-by: Adam Langley <agl@google.com>kris/onging/CECPQ3_patch15
@@ -262,7 +262,8 @@ static int aead_tls_open(const EVP_AEAD_CTX *ctx, uint8_t *out, | |||||
/* Remove CBC padding. Code from here on is timing-sensitive with respect to | /* Remove CBC padding. Code from here on is timing-sensitive with respect to | ||||
* |padding_ok| and |data_plus_mac_len| for CBC ciphers. */ | * |padding_ok| and |data_plus_mac_len| for CBC ciphers. */ | ||||
size_t padding_ok, data_plus_mac_len; | |||||
size_t data_plus_mac_len; | |||||
crypto_word_t padding_ok; | |||||
if (EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE) { | if (EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE) { | ||||
if (!EVP_tls_cbc_remove_padding( | if (!EVP_tls_cbc_remove_padding( | ||||
&padding_ok, &data_plus_mac_len, out, total, | &padding_ok, &data_plus_mac_len, out, total, | ||||
@@ -273,7 +274,7 @@ static int aead_tls_open(const EVP_AEAD_CTX *ctx, uint8_t *out, | |||||
return 0; | return 0; | ||||
} | } | ||||
} else { | } else { | ||||
padding_ok = CONSTTIME_TRUE_S; | |||||
padding_ok = CONSTTIME_TRUE_W; | |||||
data_plus_mac_len = total; | data_plus_mac_len = total; | ||||
/* |data_plus_mac_len| = |total| = |in_len| at this point. |in_len| has | /* |data_plus_mac_len| = |total| = |in_len| at this point. |in_len| has | ||||
* already been checked against the MAC size at the top of the function. */ | * already been checked against the MAC size at the top of the function. */ | ||||
@@ -332,7 +333,7 @@ static int aead_tls_open(const EVP_AEAD_CTX *ctx, uint8_t *out, | |||||
* safe to simply perform the padding check first, but it would not be under a | * safe to simply perform the padding check first, but it would not be under a | ||||
* different choice of MAC location on padding failure. See | * different choice of MAC location on padding failure. See | ||||
* EVP_tls_cbc_remove_padding. */ | * EVP_tls_cbc_remove_padding. */ | ||||
size_t good = | |||||
crypto_word_t good = | |||||
constant_time_eq_int(CRYPTO_memcmp(record_mac, mac, mac_len), 0); | constant_time_eq_int(CRYPTO_memcmp(record_mac, mac, mac_len), 0); | ||||
good &= padding_ok; | good &= padding_ok; | ||||
if (!good) { | if (!good) { | ||||
@@ -62,6 +62,7 @@ | |||||
#include <openssl/aead.h> | #include <openssl/aead.h> | ||||
#include <openssl/aes.h> | #include <openssl/aes.h> | ||||
#include "../internal.h" | |||||
#include "../fipsmodule/modes/internal.h" | #include "../fipsmodule/modes/internal.h" | ||||
#if defined(__cplusplus) | #if defined(__cplusplus) | ||||
@@ -113,7 +114,7 @@ struct evp_aead_st { | |||||
* If the function returns one, it runs in time independent of the contents of | * If the function returns one, it runs in time independent of the contents of | ||||
* |in|. It is also guaranteed that |*out_len| >= |mac_size|, satisfying | * |in|. It is also guaranteed that |*out_len| >= |mac_size|, satisfying | ||||
* |EVP_tls_cbc_copy_mac|'s precondition. */ | * |EVP_tls_cbc_copy_mac|'s precondition. */ | ||||
int EVP_tls_cbc_remove_padding(size_t *out_padding_ok, size_t *out_len, | |||||
int EVP_tls_cbc_remove_padding(crypto_word_t *out_padding_ok, size_t *out_len, | |||||
const uint8_t *in, size_t in_len, | const uint8_t *in, size_t in_len, | ||||
size_t block_size, size_t mac_size); | size_t block_size, size_t mac_size); | ||||
@@ -61,9 +61,6 @@ | |||||
#include "internal.h" | #include "internal.h" | ||||
/* TODO(davidben): unsigned should be size_t. The various constant_time | |||||
* functions need to be switched to size_t. */ | |||||
/* MAX_HASH_BIT_COUNT_BYTES is the maximum number of bytes in the hash's length | /* MAX_HASH_BIT_COUNT_BYTES is the maximum number of bytes in the hash's length | ||||
* field. (SHA-384/512 have 128-bit length.) */ | * field. (SHA-384/512 have 128-bit length.) */ | ||||
#define MAX_HASH_BIT_COUNT_BYTES 16 | #define MAX_HASH_BIT_COUNT_BYTES 16 | ||||
@@ -73,7 +70,7 @@ | |||||
* supported by TLS.) */ | * supported by TLS.) */ | ||||
#define MAX_HASH_BLOCK_SIZE 128 | #define MAX_HASH_BLOCK_SIZE 128 | ||||
int EVP_tls_cbc_remove_padding(size_t *out_padding_ok, size_t *out_len, | |||||
int EVP_tls_cbc_remove_padding(crypto_word_t *out_padding_ok, size_t *out_len, | |||||
const uint8_t *in, size_t in_len, | const uint8_t *in, size_t in_len, | ||||
size_t block_size, size_t mac_size) { | size_t block_size, size_t mac_size) { | ||||
const size_t overhead = 1 /* padding length byte */ + mac_size; | const size_t overhead = 1 /* padding length byte */ + mac_size; | ||||
@@ -85,7 +82,7 @@ int EVP_tls_cbc_remove_padding(size_t *out_padding_ok, size_t *out_len, | |||||
size_t padding_length = in[in_len - 1]; | size_t padding_length = in[in_len - 1]; | ||||
size_t good = constant_time_ge_s(in_len, overhead + padding_length); | |||||
crypto_word_t good = constant_time_ge_w(in_len, overhead + padding_length); | |||||
/* The padding consists of a length byte at the end of the record and | /* The padding consists of a length byte at the end of the record and | ||||
* then that many bytes of padding, all with the same value as the | * then that many bytes of padding, all with the same value as the | ||||
* length byte. Thus, with the length byte included, there are i+1 | * length byte. Thus, with the length byte included, there are i+1 | ||||
@@ -110,7 +107,7 @@ int EVP_tls_cbc_remove_padding(size_t *out_padding_ok, size_t *out_len, | |||||
/* If any of the final |padding_length+1| bytes had the wrong value, | /* If any of the final |padding_length+1| bytes had the wrong value, | ||||
* one or more of the lower eight bits of |good| will be cleared. */ | * one or more of the lower eight bits of |good| will be cleared. */ | ||||
good = constant_time_eq_s(0xff, good & 0xff); | |||||
good = constant_time_eq_w(0xff, good & 0xff); | |||||
/* Always treat |padding_length| as zero on error. If, assuming block size of | /* Always treat |padding_length| as zero on error. If, assuming block size of | ||||
* 16, a padding of [<15 arbitrary bytes> 15] treated |padding_length| as 16 | * 16, a padding of [<15 arbitrary bytes> 15] treated |padding_length| as 16 | ||||
@@ -151,7 +148,7 @@ void EVP_tls_cbc_copy_mac(uint8_t *out, size_t md_size, const uint8_t *in, | |||||
if (j >= md_size) { | if (j >= md_size) { | ||||
j -= md_size; | j -= md_size; | ||||
} | } | ||||
size_t is_mac_start = constant_time_eq_s(i, mac_start); | |||||
crypto_word_t is_mac_start = constant_time_eq_w(i, mac_start); | |||||
mac_started |= is_mac_start; | mac_started |= is_mac_start; | ||||
uint8_t mac_ended = constant_time_ge_8(i, mac_end); | uint8_t mac_ended = constant_time_ge_8(i, mac_end); | ||||
rotated_mac[j] |= in[i] & mac_started & ~mac_ended; | rotated_mac[j] |= in[i] & mac_started & ~mac_ended; | ||||
@@ -58,13 +58,13 @@ static uint8_t FromBool8(bool b) { | |||||
return b ? CONSTTIME_TRUE_8 : CONSTTIME_FALSE_8; | return b ? CONSTTIME_TRUE_8 : CONSTTIME_FALSE_8; | ||||
} | } | ||||
static size_t FromBoolS(bool b) { | |||||
return b ? CONSTTIME_TRUE_S : CONSTTIME_FALSE_S; | |||||
static crypto_word_t FromBoolW(bool b) { | |||||
return b ? CONSTTIME_TRUE_W : CONSTTIME_FALSE_W; | |||||
} | } | ||||
static const uint8_t test_values_8[] = {0, 1, 2, 20, 32, 127, 128, 129, 255}; | static const uint8_t test_values_8[] = {0, 1, 2, 20, 32, 127, 128, 129, 255}; | ||||
static size_t test_values_s[] = { | |||||
static crypto_word_t test_values_w[] = { | |||||
0, | 0, | ||||
1, | 1, | ||||
1024, | 1024, | ||||
@@ -77,11 +77,11 @@ static size_t test_values_s[] = { | |||||
0xffffffff - 1, | 0xffffffff - 1, | ||||
0xffffffff, | 0xffffffff, | ||||
#endif | #endif | ||||
std::numeric_limits<size_t>::max() / 2 - 1, | |||||
std::numeric_limits<size_t>::max() / 2, | |||||
std::numeric_limits<size_t>::max() / 2 + 1, | |||||
std::numeric_limits<size_t>::max() - 1, | |||||
std::numeric_limits<size_t>::max(), | |||||
std::numeric_limits<crypto_word_t>::max() / 2 - 1, | |||||
std::numeric_limits<crypto_word_t>::max() / 2, | |||||
std::numeric_limits<crypto_word_t>::max() / 2 + 1, | |||||
std::numeric_limits<crypto_word_t>::max() - 1, | |||||
std::numeric_limits<crypto_word_t>::max(), | |||||
}; | }; | ||||
static int signed_test_values[] = { | static int signed_test_values[] = { | ||||
@@ -89,26 +89,26 @@ static int signed_test_values[] = { | |||||
32000, -32000, INT_MAX, INT_MIN, INT_MAX - 1, INT_MIN + 1}; | 32000, -32000, INT_MAX, INT_MIN, INT_MAX - 1, INT_MIN + 1}; | ||||
TEST(ConstantTimeTest, Test) { | TEST(ConstantTimeTest, Test) { | ||||
for (size_t a : test_values_s) { | |||||
for (crypto_word_t a : test_values_w) { | |||||
SCOPED_TRACE(a); | SCOPED_TRACE(a); | ||||
EXPECT_EQ(FromBoolS(a == 0), constant_time_is_zero_s(a)); | |||||
EXPECT_EQ(FromBoolW(a == 0), constant_time_is_zero_w(a)); | |||||
EXPECT_EQ(FromBool8(a == 0), constant_time_is_zero_8(a)); | EXPECT_EQ(FromBool8(a == 0), constant_time_is_zero_8(a)); | ||||
for (size_t b : test_values_s) { | |||||
for (crypto_word_t b : test_values_w) { | |||||
SCOPED_TRACE(b); | SCOPED_TRACE(b); | ||||
EXPECT_EQ(FromBoolS(a < b), constant_time_lt_s(a, b)); | |||||
EXPECT_EQ(FromBoolW(a < b), constant_time_lt_w(a, b)); | |||||
EXPECT_EQ(FromBool8(a < b), constant_time_lt_8(a, b)); | EXPECT_EQ(FromBool8(a < b), constant_time_lt_8(a, b)); | ||||
EXPECT_EQ(FromBoolS(a >= b), constant_time_ge_s(a, b)); | |||||
EXPECT_EQ(FromBoolW(a >= b), constant_time_ge_w(a, b)); | |||||
EXPECT_EQ(FromBool8(a >= b), constant_time_ge_8(a, b)); | EXPECT_EQ(FromBool8(a >= b), constant_time_ge_8(a, b)); | ||||
EXPECT_EQ(FromBoolS(a == b), constant_time_eq_s(a, b)); | |||||
EXPECT_EQ(FromBoolW(a == b), constant_time_eq_w(a, b)); | |||||
EXPECT_EQ(FromBool8(a == b), constant_time_eq_8(a, b)); | EXPECT_EQ(FromBool8(a == b), constant_time_eq_8(a, b)); | ||||
EXPECT_EQ(a, constant_time_select_s(CONSTTIME_TRUE_S, a, b)); | |||||
EXPECT_EQ(b, constant_time_select_s(CONSTTIME_FALSE_S, a, b)); | |||||
EXPECT_EQ(a, constant_time_select_w(CONSTTIME_TRUE_W, a, b)); | |||||
EXPECT_EQ(b, constant_time_select_w(CONSTTIME_FALSE_W, a, b)); | |||||
} | } | ||||
} | } | ||||
@@ -117,10 +117,10 @@ TEST(ConstantTimeTest, Test) { | |||||
for (int b : signed_test_values) { | for (int b : signed_test_values) { | ||||
SCOPED_TRACE(b); | SCOPED_TRACE(b); | ||||
EXPECT_EQ(a, constant_time_select_int(CONSTTIME_TRUE_S, a, b)); | |||||
EXPECT_EQ(b, constant_time_select_int(CONSTTIME_FALSE_S, a, b)); | |||||
EXPECT_EQ(a, constant_time_select_int(CONSTTIME_TRUE_W, a, b)); | |||||
EXPECT_EQ(b, constant_time_select_int(CONSTTIME_FALSE_W, a, b)); | |||||
EXPECT_EQ(FromBoolS(a == b), constant_time_eq_int(a, b)); | |||||
EXPECT_EQ(FromBoolW(a == b), constant_time_eq_int(a, b)); | |||||
EXPECT_EQ(FromBool8(a == b), constant_time_eq_int_8(a, b)); | EXPECT_EQ(FromBool8(a == b), constant_time_eq_int_8(a, b)); | ||||
} | } | ||||
} | } | ||||
@@ -36,11 +36,11 @@ static void byte_reverse(polyval_block *b) { | |||||
static void reverse_and_mulX_ghash(polyval_block *b) { | static void reverse_and_mulX_ghash(polyval_block *b) { | ||||
uint64_t hi = b->u[0]; | uint64_t hi = b->u[0]; | ||||
uint64_t lo = b->u[1]; | uint64_t lo = b->u[1]; | ||||
const size_t carry = constant_time_eq_s(hi & 1, 1); | |||||
const crypto_word_t carry = constant_time_eq_w(hi & 1, 1); | |||||
hi >>= 1; | hi >>= 1; | ||||
hi |= lo << 63; | hi |= lo << 63; | ||||
lo >>= 1; | lo >>= 1; | ||||
lo ^= ((uint64_t) constant_time_select_s(carry, 0xe1, 0)) << 56; | |||||
lo ^= ((uint64_t) constant_time_select_w(carry, 0xe1, 0)) << 56; | |||||
b->u[0] = CRYPTO_bswap8(lo); | b->u[0] = CRYPTO_bswap8(lo); | ||||
b->u[1] = CRYPTO_bswap8(hi); | b->u[1] = CRYPTO_bswap8(hi); | ||||
@@ -183,22 +183,41 @@ static inline int buffers_alias(const uint8_t *a, size_t a_len, | |||||
* | * | ||||
* can be written as | * can be written as | ||||
* | * | ||||
* size_t lt = constant_time_lt_s(a, b); | |||||
* c = constant_time_select_s(lt, a, b); */ | |||||
* crypto_word_t lt = constant_time_lt_w(a, b); | |||||
* c = constant_time_select_w(lt, a, b); */ | |||||
/* crypto_word_t is the type that most constant-time functions use. Ideally we | |||||
* would like it to be |size_t|, but NaCl builds in 64-bit mode with 32-bit | |||||
* pointers, which means that |size_t| can be 32 bits when |BN_ULONG| is 64 | |||||
* bits. Since we want to be able to do constant-time operations on a | |||||
* |BN_ULONG|, |crypto_word_t| is defined as an unsigned value with the native | |||||
* word length. */ | |||||
#if defined(OPENSSL_64_BIT) | |||||
typedef uint64_t crypto_word_t; | |||||
#elif defined(OPENSSL_32_BIT) | |||||
typedef uint32_t crypto_word_t; | |||||
#else | |||||
#error "Must define either OPENSSL_32_BIT or OPENSSL_64_BIT" | |||||
#endif | |||||
#define CONSTTIME_TRUE_W ~((crypto_word_t)0) | |||||
#define CONSTTIME_FALSE_W ((crypto_word_t)0) | |||||
#define CONSTTIME_TRUE_8 ((uint8_t)0xff) | |||||
#define CONSTTIME_TRUE_S ~((size_t)0) | |||||
#define CONSTTIME_FALSE_S ((size_t)0) | |||||
#define CONSTTIME_TRUE_W ~((crypto_word_t)0) | |||||
#define CONSTTIME_FALSE_W ((crypto_word_t)0) | |||||
#define CONSTTIME_TRUE_8 ((uint8_t)0xff) | #define CONSTTIME_TRUE_8 ((uint8_t)0xff) | ||||
#define CONSTTIME_FALSE_8 ((uint8_t)0) | #define CONSTTIME_FALSE_8 ((uint8_t)0) | ||||
/* constant_time_msb_s returns the given value with the MSB copied to all the | |||||
/* constant_time_msb_w returns the given value with the MSB copied to all the | |||||
* other bits. */ | * other bits. */ | ||||
static inline size_t constant_time_msb_s(size_t a) { | |||||
static inline crypto_word_t constant_time_msb_w(crypto_word_t a) { | |||||
return 0u - (a >> (sizeof(a) * 8 - 1)); | return 0u - (a >> (sizeof(a) * 8 - 1)); | ||||
} | } | ||||
/* constant_time_lt_s returns 0xff..f if a < b and 0 otherwise. */ | |||||
static inline size_t constant_time_lt_s(size_t a, size_t b) { | |||||
/* constant_time_lt_w returns 0xff..f if a < b and 0 otherwise. */ | |||||
static inline crypto_word_t constant_time_lt_w(crypto_word_t a, | |||||
crypto_word_t b) { | |||||
/* Consider the two cases of the problem: | /* Consider the two cases of the problem: | ||||
* msb(a) == msb(b): a < b iff the MSB of a - b is set. | * msb(a) == msb(b): a < b iff the MSB of a - b is set. | ||||
* msb(a) != msb(b): a < b iff the MSB of b is set. | * msb(a) != msb(b): a < b iff the MSB of b is set. | ||||
@@ -230,28 +249,29 @@ static inline size_t constant_time_lt_s(size_t a, size_t b) { | |||||
* (check-sat) | * (check-sat) | ||||
* (get-model) | * (get-model) | ||||
*/ | */ | ||||
return constant_time_msb_s(a^((a^b)|((a-b)^a))); | |||||
return constant_time_msb_w(a^((a^b)|((a-b)^a))); | |||||
} | } | ||||
/* constant_time_lt_8 acts like |constant_time_lt_s| but returns an 8-bit | |||||
/* constant_time_lt_8 acts like |constant_time_lt_w| but returns an 8-bit | |||||
* mask. */ | * mask. */ | ||||
static inline uint8_t constant_time_lt_8(size_t a, size_t b) { | |||||
return (uint8_t)(constant_time_lt_s(a, b)); | |||||
static inline uint8_t constant_time_lt_8(crypto_word_t a, crypto_word_t b) { | |||||
return (uint8_t)(constant_time_lt_w(a, b)); | |||||
} | } | ||||
/* constant_time_ge_s returns 0xff..f if a >= b and 0 otherwise. */ | |||||
static inline size_t constant_time_ge_s(size_t a, size_t b) { | |||||
return ~constant_time_lt_s(a, b); | |||||
/* constant_time_ge_w returns 0xff..f if a >= b and 0 otherwise. */ | |||||
static inline crypto_word_t constant_time_ge_w(crypto_word_t a, | |||||
crypto_word_t b) { | |||||
return ~constant_time_lt_w(a, b); | |||||
} | } | ||||
/* constant_time_ge_8 acts like |constant_time_ge_s| but returns an 8-bit | |||||
/* constant_time_ge_8 acts like |constant_time_ge_w| but returns an 8-bit | |||||
* mask. */ | * mask. */ | ||||
static inline uint8_t constant_time_ge_8(size_t a, size_t b) { | |||||
return (uint8_t)(constant_time_ge_s(a, b)); | |||||
static inline uint8_t constant_time_ge_8(crypto_word_t a, crypto_word_t b) { | |||||
return (uint8_t)(constant_time_ge_w(a, b)); | |||||
} | } | ||||
/* constant_time_is_zero returns 0xff..f if a == 0 and 0 otherwise. */ | /* constant_time_is_zero returns 0xff..f if a == 0 and 0 otherwise. */ | ||||
static inline size_t constant_time_is_zero_s(size_t a) { | |||||
static inline crypto_word_t constant_time_is_zero_w(crypto_word_t a) { | |||||
/* Here is an SMT-LIB verification of this formula: | /* Here is an SMT-LIB verification of this formula: | ||||
* | * | ||||
* (define-fun is_zero ((a (_ BitVec 32))) (_ BitVec 32) | * (define-fun is_zero ((a (_ BitVec 32))) (_ BitVec 32) | ||||
@@ -264,42 +284,45 @@ static inline size_t constant_time_is_zero_s(size_t a) { | |||||
* (check-sat) | * (check-sat) | ||||
* (get-model) | * (get-model) | ||||
*/ | */ | ||||
return constant_time_msb_s(~a & (a - 1)); | |||||
return constant_time_msb_w(~a & (a - 1)); | |||||
} | } | ||||
/* constant_time_is_zero_8 acts like |constant_time_is_zero_s| but returns an | |||||
/* constant_time_is_zero_8 acts like |constant_time_is_zero_w| but returns an | |||||
* 8-bit mask. */ | * 8-bit mask. */ | ||||
static inline uint8_t constant_time_is_zero_8(size_t a) { | |||||
return (uint8_t)(constant_time_is_zero_s(a)); | |||||
static inline uint8_t constant_time_is_zero_8(crypto_word_t a) { | |||||
return (uint8_t)(constant_time_is_zero_w(a)); | |||||
} | } | ||||
/* constant_time_eq_s returns 0xff..f if a == b and 0 otherwise. */ | |||||
static inline size_t constant_time_eq_s(size_t a, size_t b) { | |||||
return constant_time_is_zero_s(a ^ b); | |||||
/* constant_time_eq_w returns 0xff..f if a == b and 0 otherwise. */ | |||||
static inline crypto_word_t constant_time_eq_w(crypto_word_t a, | |||||
crypto_word_t b) { | |||||
return constant_time_is_zero_w(a ^ b); | |||||
} | } | ||||
/* constant_time_eq_8 acts like |constant_time_eq_s| but returns an 8-bit | |||||
/* constant_time_eq_8 acts like |constant_time_eq_w| but returns an 8-bit | |||||
* mask. */ | * mask. */ | ||||
static inline uint8_t constant_time_eq_8(size_t a, size_t b) { | |||||
return (uint8_t)(constant_time_eq_s(a, b)); | |||||
static inline uint8_t constant_time_eq_8(crypto_word_t a, crypto_word_t b) { | |||||
return (uint8_t)(constant_time_eq_w(a, b)); | |||||
} | } | ||||
/* constant_time_eq_int acts like |constant_time_eq_s| but works on int | |||||
/* constant_time_eq_int acts like |constant_time_eq_w| but works on int | |||||
* values. */ | * values. */ | ||||
static inline size_t constant_time_eq_int(int a, int b) { | |||||
return constant_time_eq_s((size_t)(a), (size_t)(b)); | |||||
static inline crypto_word_t constant_time_eq_int(int a, int b) { | |||||
return constant_time_eq_w((crypto_word_t)(a), (crypto_word_t)(b)); | |||||
} | } | ||||
/* constant_time_eq_int_8 acts like |constant_time_eq_int| but returns an 8-bit | /* constant_time_eq_int_8 acts like |constant_time_eq_int| but returns an 8-bit | ||||
* mask. */ | * mask. */ | ||||
static inline uint8_t constant_time_eq_int_8(int a, int b) { | static inline uint8_t constant_time_eq_int_8(int a, int b) { | ||||
return constant_time_eq_8((size_t)(a), (size_t)(b)); | |||||
return constant_time_eq_8((crypto_word_t)(a), (crypto_word_t)(b)); | |||||
} | } | ||||
/* constant_time_select_s returns (mask & a) | (~mask & b). When |mask| is all | |||||
/* constant_time_select_w returns (mask & a) | (~mask & b). When |mask| is all | |||||
* 1s or all 0s (as returned by the methods above), the select methods return | * 1s or all 0s (as returned by the methods above), the select methods return | ||||
* either |a| (if |mask| is nonzero) or |b| (if |mask| is zero). */ | * either |a| (if |mask| is nonzero) or |b| (if |mask| is zero). */ | ||||
static inline size_t constant_time_select_s(size_t mask, size_t a, size_t b) { | |||||
static inline crypto_word_t constant_time_select_w(crypto_word_t mask, | |||||
crypto_word_t a, | |||||
crypto_word_t b) { | |||||
return (mask & a) | (~mask & b); | return (mask & a) | (~mask & b); | ||||
} | } | ||||
@@ -307,13 +330,14 @@ static inline size_t constant_time_select_s(size_t mask, size_t a, size_t b) { | |||||
* 8-bit values. */ | * 8-bit values. */ | ||||
static inline uint8_t constant_time_select_8(uint8_t mask, uint8_t a, | static inline uint8_t constant_time_select_8(uint8_t mask, uint8_t a, | ||||
uint8_t b) { | uint8_t b) { | ||||
return (uint8_t)(constant_time_select_s(mask, a, b)); | |||||
return (uint8_t)(constant_time_select_w(mask, a, b)); | |||||
} | } | ||||
/* constant_time_select_int acts like |constant_time_select| but operates on | /* constant_time_select_int acts like |constant_time_select| but operates on | ||||
* ints. */ | * ints. */ | ||||
static inline int constant_time_select_int(size_t mask, int a, int b) { | |||||
return (int)(constant_time_select_s(mask, (size_t)(a), (size_t)(b))); | |||||
static inline int constant_time_select_int(crypto_word_t mask, int a, int b) { | |||||
return (int)(constant_time_select_w(mask, (crypto_word_t)(a), | |||||
(crypto_word_t)(b))); | |||||
} | } | ||||
@@ -204,26 +204,26 @@ int RSA_padding_check_PKCS1_type_2(uint8_t *out, size_t *out_len, | |||||
return 0; | return 0; | ||||
} | } | ||||
size_t first_byte_is_zero = constant_time_eq_s(from[0], 0); | |||||
size_t second_byte_is_two = constant_time_eq_s(from[1], 2); | |||||
crypto_word_t first_byte_is_zero = constant_time_eq_w(from[0], 0); | |||||
crypto_word_t second_byte_is_two = constant_time_eq_w(from[1], 2); | |||||
size_t zero_index = 0, looking_for_index = CONSTTIME_TRUE_S; | |||||
crypto_word_t zero_index = 0, looking_for_index = CONSTTIME_TRUE_W; | |||||
for (size_t i = 2; i < from_len; i++) { | for (size_t i = 2; i < from_len; i++) { | ||||
size_t equals0 = constant_time_is_zero_s(from[i]); | |||||
crypto_word_t equals0 = constant_time_is_zero_w(from[i]); | |||||
zero_index = | zero_index = | ||||
constant_time_select_s(looking_for_index & equals0, i, zero_index); | |||||
looking_for_index = constant_time_select_s(equals0, 0, looking_for_index); | |||||
constant_time_select_w(looking_for_index & equals0, i, zero_index); | |||||
looking_for_index = constant_time_select_w(equals0, 0, looking_for_index); | |||||
} | } | ||||
/* The input must begin with 00 02. */ | /* The input must begin with 00 02. */ | ||||
size_t valid_index = first_byte_is_zero; | |||||
crypto_word_t valid_index = first_byte_is_zero; | |||||
valid_index &= second_byte_is_two; | valid_index &= second_byte_is_two; | ||||
/* We must have found the end of PS. */ | /* We must have found the end of PS. */ | ||||
valid_index &= ~looking_for_index; | valid_index &= ~looking_for_index; | ||||
/* PS must be at least 8 bytes long, and it starts two bytes into |from|. */ | /* PS must be at least 8 bytes long, and it starts two bytes into |from|. */ | ||||
valid_index &= constant_time_ge_s(zero_index, 2 + 8); | |||||
valid_index &= constant_time_ge_w(zero_index, 2 + 8); | |||||
/* Skip the zero byte. */ | /* Skip the zero byte. */ | ||||
zero_index++; | zero_index++; | ||||
@@ -436,17 +436,18 @@ int RSA_padding_check_PKCS1_OAEP_mgf1(uint8_t *out, size_t *out_len, | |||||
goto err; | goto err; | ||||
} | } | ||||
size_t bad = ~constant_time_is_zero_s(CRYPTO_memcmp(db, phash, mdlen)); | |||||
bad |= ~constant_time_is_zero_s(from[0]); | |||||
crypto_word_t bad = ~constant_time_is_zero_w(CRYPTO_memcmp(db, phash, mdlen)); | |||||
bad |= ~constant_time_is_zero_w(from[0]); | |||||
size_t looking_for_one_byte = CONSTTIME_TRUE_S, one_index = 0; | |||||
crypto_word_t looking_for_one_byte = CONSTTIME_TRUE_W; | |||||
size_t one_index = 0; | |||||
for (size_t i = mdlen; i < dblen; i++) { | for (size_t i = mdlen; i < dblen; i++) { | ||||
size_t equals1 = constant_time_eq_s(db[i], 1); | |||||
size_t equals0 = constant_time_eq_s(db[i], 0); | |||||
crypto_word_t equals1 = constant_time_eq_w(db[i], 1); | |||||
crypto_word_t equals0 = constant_time_eq_w(db[i], 0); | |||||
one_index = | one_index = | ||||
constant_time_select_s(looking_for_one_byte & equals1, i, one_index); | |||||
constant_time_select_w(looking_for_one_byte & equals1, i, one_index); | |||||
looking_for_one_byte = | looking_for_one_byte = | ||||
constant_time_select_s(equals1, 0, looking_for_one_byte); | |||||
constant_time_select_w(equals1, 0, looking_for_one_byte); | |||||
bad |= looking_for_one_byte & ~equals0; | bad |= looking_for_one_byte & ~equals0; | ||||
} | } | ||||
@@ -773,13 +773,13 @@ const BN_ULONG kBoringSSLRSASqrtTwo[] = { | |||||
const size_t kBoringSSLRSASqrtTwoLen = OPENSSL_ARRAY_SIZE(kBoringSSLRSASqrtTwo); | const size_t kBoringSSLRSASqrtTwoLen = OPENSSL_ARRAY_SIZE(kBoringSSLRSASqrtTwo); | ||||
int rsa_less_than_words(const BN_ULONG *a, const BN_ULONG *b, size_t len) { | int rsa_less_than_words(const BN_ULONG *a, const BN_ULONG *b, size_t len) { | ||||
OPENSSL_COMPILE_ASSERT(sizeof(BN_ULONG) <= sizeof(size_t), | |||||
size_t_constant_time_functions_too_small); | |||||
OPENSSL_COMPILE_ASSERT(sizeof(BN_ULONG) <= sizeof(crypto_word_t), | |||||
crypto_word_t_too_small); | |||||
int ret = 0; | int ret = 0; | ||||
/* Process the words in little-endian order. */ | /* Process the words in little-endian order. */ | ||||
for (size_t i = 0; i < len; i++) { | for (size_t i = 0; i < len; i++) { | ||||
size_t eq = constant_time_eq_s(a[i], b[i]); | |||||
size_t lt = constant_time_lt_s(a[i], b[i]); | |||||
crypto_word_t eq = constant_time_eq_w(a[i], b[i]); | |||||
crypto_word_t lt = constant_time_lt_w(a[i], b[i]); | |||||
ret = constant_time_select_int(eq, ret, constant_time_select_int(lt, 1, 0)); | ret = constant_time_select_int(eq, ret, constant_time_select_int(lt, 1, 0)); | ||||
} | } | ||||
return ret; | return ret; | ||||