[sw/silicon_creator] Harden boot_data_digest_is_valid using shares
Signed-off-by: Alphan Ulusoy <alphan@google.com>
diff --git a/sw/device/silicon_creator/lib/boot_data.c b/sw/device/silicon_creator/lib/boot_data.c
index 54076a4..cd9438f 100644
--- a/sw/device/silicon_creator/lib/boot_data.c
+++ b/sw/device/silicon_creator/lib/boot_data.c
@@ -73,24 +73,48 @@
}
/**
+ * Shares for producing the `is_valid` value in `boot_data_digest_check()`.
+ * First 7 shares are generated using the `sparse-fsm-encode` script while the
+ * last share is `kHardenedBoolTrue ^ kHardenedBoolFalse ^ kDigestShares[0] ^
+ * ... ^ kDigestShares[7]` so that xor'ing all shares with the initial value of
+ * `is_valid`, i.e. `kHardenedBoolFalse`, produces `kHardenedBoolTrue`.
+ *
+ * Encoding generated with
+ * $ ./util/design/sparse-fsm-encode.py -d 6 -m 7 -n 32 \
+ * -s 266012770 --language=c
+ *
+ * Minimum hamming distance: 12
+ * Maximum hamming distance: 19
+ * Minimum hamming weight: 14
+ * Maximum hamming weight: 23
+ */
+static const uint32_t kDigestShares[kHmacDigestNumWords] = {
+ 0x0d0b4d17, 0xcd73e3ff, 0x07a6f2f4, 0xcedfd599,
+ 0x54eac5b2, 0x0723ff0a, 0x6e234ee1, 0x34ebfb31,
+};
+
+/**
* Checks whether the digest of a boot data entry is valid.
*
* @param boot_data A buffer that holds a boot data entry.
- * @param[out] is_valid Whether the digest of the entry is valid.
- * @return The result of the operation.
+ * @return Whether the digest of the entry is valid.
*/
-static rom_error_t boot_data_digest_is_valid(
- const boot_data_buffer_t *boot_data, hardened_bool_t *is_valid) {
+static hardened_bool_t boot_data_digest_is_valid(
+ const boot_data_buffer_t *boot_data) {
static_assert(offsetof(boot_data_t, digest) == 0,
"`digest` must be the first field of `boot_data_t`.");
- *is_valid = kHardenedBoolFalse;
+ hardened_bool_t is_valid = kHardenedBoolFalse;
hmac_digest_t act_digest;
boot_data_digest_compute(boot_data, &act_digest);
- if (memcmp(&act_digest, boot_data, sizeof(act_digest.digest)) == 0) {
- *is_valid = kHardenedBoolTrue;
+
+ size_t i = 0;
+ for (; launder32(i) < kHmacDigestNumWords; ++i) {
+ is_valid ^= boot_data->data[i] ^ act_digest.digest[i] ^ kDigestShares[i];
}
- return kErrorOk;
+ HARDENED_CHECK_EQ(i, kHmacDigestNumWords);
+
+ return is_valid;
}
/**
@@ -362,10 +386,8 @@
for (size_t i = start_index; i < kBootDataEntriesPerPage; --i) {
// Check the digest only if this entry can be valid.
if (sniff_results[i] == kBootDataIdentifier) {
- hardened_bool_t is_valid;
RETURN_IF_ERROR(boot_data_entry_read(page, i, &buf));
- RETURN_IF_ERROR(boot_data_digest_is_valid(&buf, &is_valid));
- if (is_valid == kHardenedBoolTrue) {
+ if (boot_data_digest_is_valid(&buf) == kHardenedBoolTrue) {
memcpy(&page_info->last_valid_entry, &buf, sizeof(boot_data_t));
page_info->last_valid_index = i;
page_info->has_valid_entry = kHardenedBoolTrue;