diff options
-rw-r--r-- | common/rollback.c | 11 | ||||
-rw-r--r-- | common/util.c | 12 | ||||
-rw-r--r-- | include/util.h | 13 | ||||
-rw-r--r-- | test/utils.c | 20 |
4 files changed, 46 insertions, 10 deletions
diff --git a/common/rollback.c b/common/rollback.c index 4654b21b64..e62e4a09fd 100644 --- a/common/rollback.c +++ b/common/rollback.c @@ -180,23 +180,14 @@ test_mockable int rollback_get_secret(uint8_t *secret) { int ret = EC_ERROR_UNKNOWN; struct rollback_data data; - uint8_t first; - int i = 0; if (get_latest_rollback(&data) < 0) goto failed; /* Check that secret is not full of 0x00 or 0xff */ - first = data.secret[0]; - if (first == 0x00 || first == 0xff) { - for (i = 1; i < sizeof(data.secret); i++) { - if (data.secret[i] != first) - goto good; - } + if (bytes_are_trivial(data.secret, sizeof(data.secret))) goto failed; - } -good: memcpy(secret, data.secret, sizeof(data.secret)); ret = EC_SUCCESS; failed: diff --git a/common/util.c b/common/util.c index b9f11aad27..8d12dc59f4 100644 --- a/common/util.c +++ b/common/util.c @@ -539,6 +539,18 @@ int get_next_bit(uint32_t *mask) return bit; } +bool bytes_are_trivial(const uint8_t *buffer, size_t size) +{ + size_t i; + uint8_t result0 = 0; + uint8_t result1 = 0; + + for (i = 0; i < size; i++) { + result0 |= buffer[i] ^ 0x00; + result1 |= buffer[i] ^ 0xff; + } + return (result0 == 0) || (result1 == 0); +} /****************************************************************************/ /* stateful conditional stuff */ diff --git a/include/util.h b/include/util.h index 10d9b3661d..a6de67e3d8 100644 --- a/include/util.h +++ b/include/util.h @@ -13,6 +13,7 @@ #include "panic.h" #include "builtin/assert.h" /* For ASSERT(). */ +#include <stdbool.h> #include <stddef.h> #ifdef __cplusplus @@ -163,6 +164,18 @@ int uint64divmod(uint64_t *v, int by); int get_next_bit(uint32_t *mask); /** + * Check if |buffer| is full of 0x00 or 0xff. + * + * This function runs in constant execution time and is not vulnerable to + * timing attacks. + * + * @param buffer the buffer to check. + * @param size the number of bytes to check. + * @return true if |buffer| is full of 0x00 or 0xff, false otherwise. + */ +bool bytes_are_trivial(const uint8_t *buffer, size_t size); + +/** * Reverse's the byte-order of the provided buffer. */ void reverse(void *dest, size_t len); diff --git a/test/utils.c b/test/utils.c index c1cc1c301e..cd05aa9f3e 100644 --- a/test/utils.c +++ b/test/utils.c @@ -405,6 +405,25 @@ static int test_swap(void) return EC_SUCCESS; } +static int test_bytes_are_trivial(void) +{ + static const uint8_t all0x00[] = { 0x00, 0x00, 0x00 }; + static const uint8_t all0xff[] = { 0xff, 0xff, 0xff, 0xff }; + static const uint8_t nontrivial1[] = { 0x00, 0x01, 0x02 }; + static const uint8_t nontrivial2[] = { 0xdd, 0xee, 0xff }; + static const uint8_t nontrivial3[] = { 0x00, 0x00, 0x00, 0xff }; + static const uint8_t nontrivial4[] = { 0xff, 0x00, 0x00, 0x00 }; + + TEST_ASSERT(bytes_are_trivial(all0x00, sizeof(all0x00))); + TEST_ASSERT(bytes_are_trivial(all0xff, sizeof(all0xff))); + TEST_ASSERT(!bytes_are_trivial(nontrivial1, sizeof(nontrivial1))); + TEST_ASSERT(!bytes_are_trivial(nontrivial2, sizeof(nontrivial2))); + TEST_ASSERT(!bytes_are_trivial(nontrivial3, sizeof(nontrivial3))); + TEST_ASSERT(!bytes_are_trivial(nontrivial4, sizeof(nontrivial4))); + + return EC_SUCCESS; +} + void run_test(void) { test_reset(); @@ -422,6 +441,7 @@ void run_test(void) RUN_TEST(test_cond_t); RUN_TEST(test_mula32); RUN_TEST(test_swap); + RUN_TEST(test_bytes_are_trivial); test_print_result(); } |