[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(