summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/rollback.c11
-rw-r--r--common/util.c12
-rw-r--r--include/util.h13
-rw-r--r--test/utils.c20
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();
}