[sw/silicon_creator] Read usage constraints from hardware during ROM_EXT verification
Fixes #5956.
Signed-off-by: Alphan Ulusoy <alphan@google.com>
diff --git a/sw/device/silicon_creator/lib/manifest.c b/sw/device/silicon_creator/lib/manifest.c
index aead7c2..3bbfcff 100644
--- a/sw/device/silicon_creator/lib/manifest.c
+++ b/sw/device/silicon_creator/lib/manifest.c
@@ -6,7 +6,7 @@
// Extern declarations for the inline functions in the manifest header.
extern rom_error_t manifest_check(const manifest_t *manifest);
-extern manifest_signed_region_t manifest_signed_region_get(
+extern manifest_digest_region_t manifest_digest_region_get(
const manifest_t *manifest);
extern epmp_region_t manifest_code_region_get(const manifest_t *manifest);
extern uintptr_t manifest_entry_point_get(const manifest_t *manifest);
diff --git a/sw/device/silicon_creator/lib/manifest.h b/sw/device/silicon_creator/lib/manifest.h
index bf774b8..e1ab6c0 100644
--- a/sw/device/silicon_creator/lib/manifest.h
+++ b/sw/device/silicon_creator/lib/manifest.h
@@ -125,9 +125,19 @@
*
* RSASSA-PKCS1-v1_5 signature of the image generated using a 3072-bit RSA
* private key and the SHA-256 hash function. The signed region of an image
- * starts immediately after this field and ends at the end of the image. The
- * start and the length of the signed region can be obtained using
- * `manifest_signed_region_get`.
+ * starts immediately after this field and ends at the end of the image.
+ *
+ * On-target verification should also integrate usage constraints comparison
+ * to signature verification to harden it against potential attacks. During
+ * verification, the digest of an image should be computed by first reading
+ * the usage constraints from the hardware and then concatenating the rest of
+ * the image:
+ *
+ * digest = SHA256(usage_constraints_from_hw || rest_of_the_image)
+ *
+ * The start and the length of the region that should be concatenated to the
+ * usage constraints read from the hardware can be obtained using
+ * `manifest_digest_region_get()`.
*/
sigverify_rsa_buffer_t signature;
/**
@@ -219,18 +229,18 @@
OT_ASSERT_SIZE(manifest_t, MANIFEST_SIZE);
/**
- * Signed region of an image.
+ * Region of an image that should be included in the digest computation.
*/
-typedef struct manifest_signed_region {
+typedef struct manifest_digest_region {
/**
- * Start of the signed region of an image.
+ * Start of the region.
*/
const void *start;
/**
- * Length of the signed region of an image in bytes.
+ * Length of the region in bytes.
*/
size_t length;
-} manifest_signed_region_t;
+} manifest_digest_region_t;
/**
* Allowed bounds for the `length` field.
@@ -279,16 +289,25 @@
}
/**
- * Gets the signed region of an image.
+ * Gets the region of the image that should be included in the digest
+ * computation.
*
- * @param manifest A manifest
- * return signed_region Signed region of an image.
+ * Digest region of an image starts immediately after the `usage_constraints`
+ * field of its manifest and ends at the end of the image.
+ *
+ * @param manifest A manifest.
+ * return digest_region Region of the image that should be included in the
+ * digest computation.
*/
-inline manifest_signed_region_t manifest_signed_region_get(
+inline manifest_digest_region_t manifest_digest_region_get(
const manifest_t *manifest) {
- return (manifest_signed_region_t){
- .start = (const char *)manifest + sizeof(manifest->signature),
- .length = manifest->length - sizeof(manifest->signature),
+ enum {
+ kDigestRegionOffset =
+ sizeof(manifest->signature) + sizeof(manifest->usage_constraints),
+ };
+ return (manifest_digest_region_t){
+ .start = (const char *)manifest + kDigestRegionOffset,
+ .length = manifest->length - kDigestRegionOffset,
};
}
@@ -324,7 +343,7 @@
* Declarations for the functions above that should be defined in tests.
*/
rom_error_t manifest_check(const manifest_t *manifest);
-manifest_signed_region_t manifest_signed_region_get(const manifest_t *manifest);
+manifest_digest_region_t manifest_digest_region_get(const manifest_t *manifest);
epmp_region_t manifest_code_region_get(const manifest_t *manifest);
uintptr_t manifest_entry_point_get(const manifest_t *manifest);
#endif
diff --git a/sw/device/silicon_creator/lib/manifest_unittest.cc b/sw/device/silicon_creator/lib/manifest_unittest.cc
index b2824dc..010de21 100644
--- a/sw/device/silicon_creator/lib/manifest_unittest.cc
+++ b/sw/device/silicon_creator/lib/manifest_unittest.cc
@@ -22,15 +22,17 @@
manifest_t manifest_{};
};
-TEST_F(ManifestTest, SignedRegionGet) {
- manifest_signed_region_t signed_region =
- manifest_signed_region_get(&manifest_);
+TEST_F(ManifestTest, DigestRegionGet) {
+ manifest_digest_region_t digest_region =
+ manifest_digest_region_get(&manifest_);
- // Signed region starts after `signature` and ends at the end of the image.
- EXPECT_EQ(signed_region.start, reinterpret_cast<const char *>(&manifest_) +
- sizeof(manifest_t::signature));
- EXPECT_EQ(signed_region.length,
- manifest_.length - sizeof(manifest_t::signature));
+ // Digest region starts immediately after `usage_constraints` and ends at the
+ // end of the image.
+ size_t digest_region_offset =
+ sizeof(manifest_t::signature) + sizeof(manifest_t::usage_constraints);
+ EXPECT_EQ(digest_region.start,
+ reinterpret_cast<const char *>(&manifest_) + digest_region_offset);
+ EXPECT_EQ(digest_region.length, manifest_.length - digest_region_offset);
}
TEST_F(ManifestTest, CodeRegionGet) {
diff --git a/sw/device/silicon_creator/lib/mock_manifest.h b/sw/device/silicon_creator/lib/mock_manifest.h
index 40be0cb..821e4ee 100644
--- a/sw/device/silicon_creator/lib/mock_manifest.h
+++ b/sw/device/silicon_creator/lib/mock_manifest.h
@@ -17,7 +17,7 @@
class MockManifest : public GlobalMock<MockManifest> {
public:
MOCK_METHOD(rom_error_t, Check, (const manifest_t *));
- MOCK_METHOD(manifest_signed_region_t, SignedRegion, (const manifest_t *));
+ MOCK_METHOD(manifest_digest_region_t, DigestRegion, (const manifest_t *));
MOCK_METHOD(epmp_region_t, CodeRegion, (const manifest_t *));
MOCK_METHOD(uintptr_t, EntryPoint, (const manifest_t *));
};
@@ -32,9 +32,9 @@
return MockManifest::Instance().Check(manifest);
}
-manifest_signed_region_t manifest_signed_region_get(
+manifest_digest_region_t manifest_digest_region_get(
const manifest_t *manifest) {
- return MockManifest::Instance().SignedRegion(manifest);
+ return MockManifest::Instance().DigestRegion(manifest);
}
epmp_region_t manifest_code_region_get(const manifest_t *manifest) {
diff --git a/sw/device/silicon_creator/mask_rom/mask_rom.c b/sw/device/silicon_creator/mask_rom/mask_rom.c
index 3a96741..0e60ea4 100644
--- a/sw/device/silicon_creator/mask_rom/mask_rom.c
+++ b/sw/device/silicon_creator/mask_rom/mask_rom.c
@@ -110,11 +110,18 @@
RETURN_IF_ERROR(sigverify_rsa_key_get(
sigverify_rsa_key_id_get(&manifest->modulus), lc_state, &key));
- // TODO(#5956): Manifest usage constraints.
- manifest_signed_region_t signed_region = manifest_signed_region_get(manifest);
hmac_sha256_init();
+ // Hash usage constraints.
+ manifest_usage_constraints_t usage_constraints_from_hw;
+ sigverify_usage_constraints_get(manifest->usage_constraints.selector_bits,
+ &usage_constraints_from_hw);
+ RETURN_IF_ERROR(hmac_sha256_update(&usage_constraints_from_hw,
+ sizeof(usage_constraints_from_hw)));
+ // Hash the remaining part of the image.
+ manifest_digest_region_t digest_region = manifest_digest_region_get(manifest);
RETURN_IF_ERROR(
- hmac_sha256_update(signed_region.start, signed_region.length));
+ hmac_sha256_update(digest_region.start, digest_region.length));
+ // Verify signature
hmac_digest_t act_digest;
RETURN_IF_ERROR(hmac_sha256_final(&act_digest));
RETURN_IF_ERROR(