futility: updater: override signature id for phaser360

Because of lacking CL:1501614 in octopus factory branch, dopefish
root key is written to some phaser360 devices. That will lead to
firmware updater not be able to verify RW vblock and AU will fail.
This CL will fix that by using root key info and model name to
make firmware updater get a proper sig_id so that in-field machines
can be updated by AU.

BUG=b:146876241, b:133901651, b:146482979
BRANCH=none
TEST=using a DUT of phaser360 (without whitelabel_tag = dopefish)
     which is flashed dopefish rootkey and hwid, using command
     'chromeos-firmwareupdate -m autoupdate --wp=1' to flash
     firmware, RW firmware can be updated and DUT can boot normally.

Change-Id: I163c16189c28a996ed08bf2a7b162e6ee3b13be6
Signed-off-by: Paul Ma <magf@bitland.corp-partner.google.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/1981650
Reviewed-by: Hung-Te Lin <hungte@chromium.org>
Commit-Queue: Hung-Te Lin <hungte@chromium.org>
(cherry picked from commit 5ea8fe68b1d9c498b6f58303afa3e36cf025d280)
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/1992725
Reviewed-by: Justin TerAvest <teravest@chromium.org>
Commit-Queue: Justin TerAvest <teravest@chromium.org>
Tested-by: Justin TerAvest <teravest@chromium.org>
diff --git a/futility/updater.c b/futility/updater.c
index 6a7d8ff..f634c22 100644
--- a/futility/updater.c
+++ b/futility/updater.c
@@ -660,7 +660,7 @@
 /*
  * Returns a valid root key from GBB header, or NULL on failure.
  */
-static const struct vb2_packed_key *get_rootkey(
+const struct vb2_packed_key *get_rootkey(
 		const struct vb2_gbb_header *gbb)
 {
 	struct vb2_packed_key *key = NULL;
@@ -1352,6 +1352,10 @@
 			ERROR("Failed to get system current firmware\n");
 			return 1;
 		}
+		if (get_config_quirk(QUIRK_OVERRIDE_SIGNATURE_ID, cfg) &&
+		    is_write_protection_enabled(cfg))
+			quirk_override_signature_id(
+					cfg, model, &signature_id);
 	}
 	return !!model_apply_white_label(
 			model, cfg->archive, signature_id, tmp_image);
diff --git a/futility/updater.h b/futility/updater.h
index c83ebfc..e11cc74 100644
--- a/futility/updater.h
+++ b/futility/updater.h
@@ -43,6 +43,7 @@
 	QUIRK_EVE_SMM_STORE,
 	QUIRK_ALLOW_EMPTY_WLTAG,
 	QUIRK_EC_PARTIAL_RECOVERY,
+	QUIRK_OVERRIDE_SIGNATURE_ID,
 	QUIRK_MAX,
 };
 
@@ -124,6 +125,12 @@
 extern const char * const updater_error_messages[];
 
 /*
+ * Returns a valid root key from GBB header, or NULL on failure.
+ */
+const struct vb2_packed_key *get_rootkey(
+		const struct vb2_gbb_header *gbb);
+
+/*
  * The main updater to update system firmware using the configuration parameter.
  * Returns UPDATE_ERR_DONE if success, otherwise failure.
  */
@@ -168,6 +175,14 @@
  */
 const char * const updater_get_default_quirks(struct updater_config *cfg);
 
+/*
+ * Overrides signature id if the device was shipped with known
+ * special rootkey.
+ */
+int quirk_override_signature_id(struct updater_config *cfg,
+				struct model_config *model,
+				const char **signature_id);
+
 /* Functions from updater_archive.c */
 
 /*
diff --git a/futility/updater_quirks.c b/futility/updater_quirks.c
index 1dfbedd..a2015f6 100644
--- a/futility/updater_quirks.c
+++ b/futility/updater_quirks.c
@@ -55,6 +55,8 @@
         { .match = "Google_Reks.", .quirks = "allow_empty_wltag" },
         { .match = "Google_Relm.", .quirks = "allow_empty_wltag" },
         { .match = "Google_Wizpig.", .quirks = "allow_empty_wltag" },
+
+        { .match = "Google_Phaser.", .quirks = "override_signature_id" },
 };
 
 /* Preserves meta data and reload image contents from given file path. */
@@ -423,6 +425,12 @@
 	quirks->help = "chromium/1024401; recover EC by partial RO update.";
 	quirks->apply = quirk_ec_partial_recovery;
 	quirks->value = -1;  /* Decide at runtime. */
+
+	quirks = &cfg->quirks[QUIRK_OVERRIDE_SIGNATURE_ID];
+	quirks->name = "override_signature_id";
+	quirks->help = "chromium/146876241; override signature id for "
+			"devices shipped with different root key.";
+	quirks->apply = NULL; /* Simple config. */
 }
 
 /*
@@ -448,3 +456,30 @@
 	}
 	return NULL;
 }
+
+/*
+ * Overrides signature id if the device was shipped with known
+ * special rootkey.
+ */
+int quirk_override_signature_id(struct updater_config *cfg,
+				struct model_config *model,
+				const char **signature_id)
+{
+	const char * const DOPEFISH_KEY_HASH =
+				"9a1f2cc319e2f2e61237dc51125e35ddd4d20984";
+
+	/* b/146876241 */
+	assert(model);
+	if (strcmp(model->name, "phaser360") == 0) {
+		struct firmware_image *image = &cfg->image_current;
+		const char *key_hash = get_firmware_rootkey_hash(image);
+		if (key_hash && strcmp(key_hash, DOPEFISH_KEY_HASH) == 0) {
+			const char * const sig_dopefish = "phaser360-dopefish";
+			WARN("A Phaser360 with Dopefish rootkey - "
+			     "override signature_id to '%s'.\n", sig_dopefish);
+			*signature_id = sig_dopefish;
+		}
+	}
+
+	return 0;
+}
diff --git a/futility/updater_utils.c b/futility/updater_utils.c
index 7a8185b..3807fbb 100644
--- a/futility/updater_utils.c
+++ b/futility/updater_utils.c
@@ -12,6 +12,7 @@
 #include "2common.h"
 #include "crossystem.h"
 #include "host_misc.h"
+#include "util_misc.h"
 #include "updater.h"
 
 #define COMMAND_BUFFER_SIZE 256
@@ -662,3 +663,28 @@
 		free(head);
 	}
 }
+
+/*
+ * Returns rootkey hash of firmware image, or NULL on failure.
+ */
+const char *get_firmware_rootkey_hash(const struct firmware_image *image)
+{
+	const struct vb2_gbb_header *gbb = NULL;
+	const struct vb2_packed_key *rootkey = NULL;
+
+	assert(image->data);
+
+	gbb = find_gbb(image);
+	if (!gbb) {
+		WARN("No GBB found in image.\n");
+		return NULL;
+	}
+
+	rootkey = get_rootkey(gbb);
+	if (!rootkey) {
+		WARN("No rootkey found in image.\n");
+		return NULL;
+	}
+
+	return packed_key_sha1_string(rootkey);
+}
diff --git a/futility/updater_utils.h b/futility/updater_utils.h
index eb455d1..f5248f8 100644
--- a/futility/updater_utils.h
+++ b/futility/updater_utils.h
@@ -207,4 +207,9 @@
 /* Helper function to initialize system properties. */
 void init_system_properties(struct system_property *props, int num);
 
+/*
+ * Returns rootkey hash of firmware image, or NULL on failure.
+ */
+const char *get_firmware_rootkey_hash(const struct firmware_image *image);
+
 #endif  /* VBOOT_REFERENCE_FUTILITY_UPDATER_UTILS_H_ */