summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Hughes <tomhughes@chromium.org>2020-01-02 10:39:52 -0800
committerCommit Bot <commit-bot@chromium.org>2020-12-30 07:16:28 +0000
commitd8fd3f42def615702cdaa911dd512cf518018eca (patch)
treef811bede12e8d6fb1c70e586eeb3f8f7c7f17832
parentc15c9fffa70d180c74c28a3682b9ec2f17841153 (diff)
downloadchrome-ec-d8fd3f42def615702cdaa911dd512cf518018eca.tar.gz
common/vboot: Add rwsig info command
The rwsig info command provides additional details on the verified boot key used to sign the RW firmware. The information about the key can be used by factory tests to validate that the factory is flashing firmware that is signed by the expected key. In addition, we refactor the "rwsig"-related commands into a generic "rwsig" command that takes additional subcommands. This allows adding an "rwsig dump" command that allows displaying individual fields, which is useful in scripts and tests. "rwsigstatus" becomes "rwsig status" "rwsigaction" becomes "rwsig action" The old commands are preserved for backward compatibility. BRANCH=none BUG=b:144958737 TEST=(kohaku) $ ectool --name=cros_fp rwsig info TEST=(kohaku) $ ectool --name=cros_fp rwsig dump key_id TEST=(kohaku) $ ectool --name=cros_fp reboot_ec; sleep 0.5; ectool --name=cros_fp rwsig action abort; sleep 2; ectool --name=cros_fp version | grep "Firmware copy" => Firmware copy: RO TEST=On dragonclaw v0.2 console: rwsiginfo Change-Id: Ib0ee4be33e6636ff702eeaef941cc3abed0594cb Signed-off-by: Tom Hughes <tomhughes@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1999607 Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org> Reviewed-by: Denis Brockus <dbrockus@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2607028 Tested-by: Chen-Tsung Hsieh <chentsung@chromium.org> Reviewed-by: Chen-Tsung Hsieh <chentsung@chromium.org> Commit-Queue: Chen-Tsung Hsieh <chentsung@chromium.org>
-rw-r--r--common/rwsig.c3
-rw-r--r--common/update_fw.c3
-rw-r--r--common/vboot/vb21_lib.c64
-rw-r--r--include/ec_commands.h42
-rw-r--r--include/vboot.h8
-rw-r--r--util/ectool.c177
6 files changed, 284 insertions, 13 deletions
diff --git a/common/rwsig.c b/common/rwsig.c
index 8bccd2acb1..0d0a8e765c 100644
--- a/common/rwsig.c
+++ b/common/rwsig.c
@@ -21,6 +21,7 @@
#include "usb_pd.h"
#include "util.h"
#include "vb21_struct.h"
+#include "vboot.h"
#include "version.h"
/* Console output macros */
@@ -142,7 +143,7 @@ int rwsig_check_signature(void)
sig = (const uint8_t *)CONFIG_RW_SIG_ADDR;
rwlen = CONFIG_RW_SIZE - CONFIG_RW_SIG_SIZE;
#elif defined(CONFIG_RWSIG_TYPE_RWSIG)
- vb21_key = (const struct vb21_packed_key *)CONFIG_RO_PUBKEY_ADDR;
+ vb21_key = vb21_get_packed_key();
vb21_sig = (const struct vb21_signature *)CONFIG_RW_SIG_ADDR;
if (vb21_key->c.magic != VB21_MAGIC_PACKED_KEY ||
diff --git a/common/update_fw.c b/common/update_fw.c
index 2501f29934..f9927fec9d 100644
--- a/common/update_fw.c
+++ b/common/update_fw.c
@@ -17,6 +17,7 @@
#include "update_fw.h"
#include "util.h"
#include "vb21_struct.h"
+#include "vboot.h"
#if defined(CONFIG_TOUCHPAD_VIRTUAL_OFF) && defined(CONFIG_TOUCHPAD_HASH_FW)
#define CONFIG_TOUCHPAD_FW_CHUNKS \
@@ -203,7 +204,7 @@ void fw_update_start(struct first_response_pdu *rpdu)
#endif
#ifdef CONFIG_RWSIG_TYPE_RWSIG
- vb21_key = (const struct vb21_packed_key *)CONFIG_RO_PUBKEY_ADDR;
+ vb21_key = vb21_get_packed_key();
rpdu->common.key_version = htobe32(vb21_key->key_version);
#endif
diff --git a/common/vboot/vb21_lib.c b/common/vboot/vb21_lib.c
index c85ecbbd75..a2b6993c13 100644
--- a/common/vboot/vb21_lib.c
+++ b/common/vboot/vb21_lib.c
@@ -8,8 +8,10 @@
*/
#include "common.h"
+#include "host_command.h"
#include "rsa.h"
#include "rwsig.h"
+#include "system.h"
#include "vb21_struct.h"
#include "vboot.h"
@@ -42,3 +44,65 @@ int vb21_is_signature_valid(const struct vb21_signature *sig,
return EC_ERROR_VBOOT_DATA_SIZE;
return EC_SUCCESS;
}
+
+const struct vb21_packed_key *vb21_get_packed_key(void)
+{
+ return (const struct vb21_packed_key *)(CONFIG_RO_PUBKEY_ADDR);
+}
+
+static void read_rwsig_info(struct ec_response_rwsig_info *r)
+{
+
+ const struct vb21_packed_key *vb21_key;
+ int rv;
+
+ vb21_key = vb21_get_packed_key();
+
+ r->sig_alg = vb21_key->sig_alg;
+ r->hash_alg = vb21_key->hash_alg;
+ r->key_version = vb21_key->key_version;
+ { BUILD_ASSERT(sizeof(r->key_id) == sizeof(vb21_key->id),
+ "key ID sizes must match"); }
+ { BUILD_ASSERT(sizeof(vb21_key->id) == sizeof(vb21_key->id.raw),
+ "key ID sizes must match"); }
+ memcpy(r->key_id, vb21_key->id.raw, sizeof(r->key_id));
+
+ rv = vb21_is_packed_key_valid(vb21_key);
+ r->key_is_valid = (rv == EC_SUCCESS);
+}
+
+static int command_rwsig_info(int argc, char **argv)
+{
+ int i;
+ struct ec_response_rwsig_info r;
+
+ read_rwsig_info(&r);
+
+ ccprintf("sig_alg: %d\n", r.sig_alg);
+ ccprintf("key_version: %d\n", r.key_version);
+ ccprintf("hash_alg: %d\n", r.hash_alg);
+ ccprintf("key_is_valid: %d\n", r.key_is_valid);
+
+ ccprintf("key_id: ");
+ for (i = 0; i < sizeof(r.key_id); i++)
+ ccprintf("%x", r.key_id[i]);
+ ccprintf("\n");
+
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(rwsiginfo, command_rwsig_info, NULL,
+ "Display rwsig info on console.");
+
+static enum ec_status
+host_command_rwsig_info(struct host_cmd_handler_args *args)
+{
+ struct ec_response_rwsig_info *r = args->response;
+
+ read_rwsig_info(r);
+ args->response_size = sizeof(*r);
+
+ return EC_RES_SUCCESS;
+}
+
+DECLARE_HOST_COMMAND(EC_CMD_RWSIG_INFO, host_command_rwsig_info,
+ EC_VER_MASK(EC_VER_RWSIG_INFO));
diff --git a/include/ec_commands.h b/include/ec_commands.h
index 1f6e746510..2b7cb31f90 100644
--- a/include/ec_commands.h
+++ b/include/ec_commands.h
@@ -1783,6 +1783,48 @@ struct ec_response_rand_num {
BUILD_ASSERT(sizeof(struct ec_response_rand_num) == 0);
+/**
+ * Get information about the key used to sign the RW firmware.
+ * For more details on the fields, see "struct vb21_packed_key".
+ */
+#define EC_CMD_RWSIG_INFO 0x001B
+#define EC_VER_RWSIG_INFO 0
+
+#define VBOOT2_KEY_ID_BYTES 20
+
+#ifdef CHROMIUM_EC
+/* Don't force external projects to depend on the vboot headers. */
+#include "vb21_struct.h"
+BUILD_ASSERT(sizeof(struct vb2_id) == VBOOT2_KEY_ID_BYTES);
+#endif
+
+struct ec_response_rwsig_info {
+ /**
+ * Signature algorithm used by the key
+ * (enum vb2_signature_algorithm).
+ */
+ uint16_t sig_alg;
+
+ /**
+ * Hash digest algorithm used with the key
+ * (enum vb2_hash_algorithm).
+ */
+ uint16_t hash_alg;
+
+ /** Key version. */
+ uint32_t key_version;
+
+ /** Key ID (struct vb2_id). */
+ uint8_t key_id[VBOOT2_KEY_ID_BYTES];
+
+ uint8_t key_is_valid;
+
+ /** Alignment padding. */
+ uint8_t reserved[3];
+} __ec_align4;
+
+BUILD_ASSERT(sizeof(struct ec_response_rwsig_info) == 32);
+
/*****************************************************************************/
/* PWM commands */
diff --git a/include/vboot.h b/include/vboot.h
index d757d0a3e7..776cc16441 100644
--- a/include/vboot.h
+++ b/include/vboot.h
@@ -25,6 +25,14 @@ int vb21_is_packed_key_valid(const struct vb21_packed_key *key);
int vb21_is_signature_valid(const struct vb21_signature *sig,
const struct vb21_packed_key *key);
+
+/**
+ * Returns the public key in RO that was used to sign RW.
+ *
+ * @return pointer to key, never NULL
+ */
+const struct vb21_packed_key *vb21_get_packed_key(void);
+
/**
* Check data region is filled with ones
*
diff --git a/util/ectool.c b/util/ectool.c
index c7cac69a7c..b73b8ce1e0 100644
--- a/util/ectool.c
+++ b/util/ectool.c
@@ -265,9 +265,14 @@ const char help_str[] =
" Set real-time clock alarm to go off in <sec> seconds\n"
" rwhashpd <dev_id> <HASH[0] ... <HASH[4]>\n"
" Set entry in PD MCU's device rw_hash table.\n"
- " rwsigaction\n"
+ " rwsig <info|dump|action|status> ...\n"
+ " info: get all info about rwsig\n"
+ " dump: show individual rwsig field\n"
+ " action: Control the behavior of RWSIG task.\n"
+ " status: Run RW signature verification and get status.\n{"
+ " rwsigaction (DEPRECATED; use \"rwsig action\")\n"
" Control the behavior of RWSIG task.\n"
- " rwsigstatus\n"
+ " rwsigstatus (DEPRECATED; use \"rwsig status\"\n"
" Run RW signature verification and get status.\n"
" sertest\n"
" Serial output test for COM2\n"
@@ -1452,18 +1457,13 @@ int cmd_rwsig_status(int argc, char *argv[])
return 0;
}
-int cmd_rwsig_action(int argc, char *argv[])
+static int rwsig_action(const char *command)
{
struct ec_params_rwsig_action req;
- if (argc < 2) {
- fprintf(stderr, "Usage: %s abort | continue\n", argv[0]);
- return -1;
- }
-
- if (!strcasecmp(argv[1], "abort"))
+ if (!strcasecmp(command, "abort"))
req.action = RWSIG_ACTION_ABORT;
- else if (!strcasecmp(argv[1], "continue"))
+ else if (!strcasecmp(command, "continue"))
req.action = RWSIG_ACTION_CONTINUE;
else
return -1;
@@ -1471,6 +1471,160 @@ int cmd_rwsig_action(int argc, char *argv[])
return ec_command(EC_CMD_RWSIG_ACTION, 0, &req, sizeof(req), NULL, 0);
}
+int cmd_rwsig_action_legacy(int argc, char *argv[])
+{
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s [abort | continue]\n", argv[0]);
+ return -1;
+ }
+
+ return rwsig_action(argv[1]);
+}
+
+int cmd_rwsig_action(int argc, char *argv[])
+{
+ if (argc < 2) {
+ fprintf(stderr, "Usage: ectool rwsig action [abort | "
+ "continue]\n");
+ return -1;
+ }
+
+ return rwsig_action(argv[1]);
+}
+
+enum rwsig_info_fields {
+ RWSIG_INFO_FIELD_SIG_ALG = BIT(0),
+ RWSIG_INFO_FIELD_KEY_VERSION = BIT(1),
+ RWSIG_INFO_FIELD_HASH_ALG = BIT(2),
+ RWSIG_INFO_FIELD_KEY_IS_VALID = BIT(3),
+ RWSIG_INFO_FIELD_KEY_ID = BIT(4),
+ RWSIG_INFO_FIELD_ALL = RWSIG_INFO_FIELD_SIG_ALG |
+ RWSIG_INFO_FIELD_KEY_VERSION | RWSIG_INFO_FIELD_HASH_ALG |
+ RWSIG_INFO_FIELD_KEY_IS_VALID | RWSIG_INFO_FIELD_KEY_ID
+};
+
+static int rwsig_info(enum rwsig_info_fields fields)
+{
+ int i;
+ int rv;
+ struct ec_response_rwsig_info r;
+ bool print_prefix = false;
+
+ rv = ec_command(EC_CMD_RWSIG_INFO, EC_VER_RWSIG_INFO, NULL, 0, &r,
+ sizeof(r));
+ if (rv < 0) {
+ fprintf(stderr, "rwsig info command failed\n");
+ return -1;
+ }
+
+ if ((fields & RWSIG_INFO_FIELD_ALL) == RWSIG_INFO_FIELD_ALL)
+ print_prefix = true;
+
+ if (fields & RWSIG_INFO_FIELD_SIG_ALG) {
+ if (print_prefix)
+ printf("sig_alg: ");
+
+ printf("%d\n", r.sig_alg);
+ }
+ if (fields & RWSIG_INFO_FIELD_KEY_VERSION) {
+ if (print_prefix)
+ printf("key_version: ");
+
+ printf("%d\n", r.key_version);
+ }
+ if (fields & RWSIG_INFO_FIELD_HASH_ALG) {
+ if (print_prefix)
+ printf("hash_alg: ");
+
+ printf("%d\n", r.hash_alg);
+ }
+ if (fields & RWSIG_INFO_FIELD_KEY_IS_VALID) {
+ if (print_prefix)
+ printf("key_is_valid: ");
+
+ printf("%d\n", r.key_is_valid);
+ }
+ if (fields & RWSIG_INFO_FIELD_KEY_ID) {
+ if (print_prefix)
+ printf("key_id: ");
+
+ for (i = 0; i < sizeof(r.key_id); i++)
+ printf("%x", r.key_id[i]);
+ printf("\n");
+ }
+
+ return 0;
+}
+
+static int cmd_rwsig_info(int argc, char *argv[])
+{
+ int i;
+
+ struct rwsig_dump_cmds {
+ const char *cmd;
+ enum rwsig_info_fields field;
+ };
+
+ struct rwsig_dump_cmds cmd_map[] = {
+ { "sig_alg", RWSIG_INFO_FIELD_SIG_ALG },
+ { "key_version", RWSIG_INFO_FIELD_KEY_VERSION },
+ { "hash_alg", RWSIG_INFO_FIELD_HASH_ALG },
+ { "key_valid", RWSIG_INFO_FIELD_KEY_IS_VALID },
+ { "key_id", RWSIG_INFO_FIELD_KEY_ID },
+ };
+
+ if (argc == 0)
+ return -1;
+
+ if (strcmp(argv[0], "info") == 0)
+ return rwsig_info(RWSIG_INFO_FIELD_ALL);
+
+ if (strcmp(argv[0], "dump") == 0) {
+ if (argc != 2) {
+ fprintf(stderr,
+ "Usage: rwsig dump "
+ "[sig_alg|key_version|hash_alg|key_valid|key_id]\n");
+ return -1;
+ }
+ for (i = 0; i < ARRAY_SIZE(cmd_map); i++)
+ if (strcmp(argv[1], cmd_map[i].cmd) == 0)
+ return rwsig_info(cmd_map[i].field);
+
+ return -1;
+ }
+
+ return -1;
+}
+
+int cmd_rwsig(int argc, char **argv)
+{
+ struct rwsig_subcommand {
+ const char *subcommand;
+ int (*handler)(int argc, char *argv[]);
+ };
+
+ const struct rwsig_subcommand rwsig_subcommands[] = {
+ { "info", cmd_rwsig_info },
+ { "dump", cmd_rwsig_info },
+ { "action", cmd_rwsig_action },
+ { "status", cmd_rwsig_status }
+ };
+
+ int i;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s <info|dump|action|status>\n",
+ argv[0]);
+ return -1;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(rwsig_subcommands); i++)
+ if (strcmp(argv[1], rwsig_subcommands[i].subcommand) == 0)
+ return rwsig_subcommands[i].handler(--argc, &argv[1]);
+
+ return -1;
+}
+
int cmd_rollback_info(int argc, char *argv[])
{
struct ec_response_rollback_info r;
@@ -9150,7 +9304,8 @@ const struct command commands[] = {
{"rtcset", cmd_rtc_set},
{"rtcsetalarm", cmd_rtc_set_alarm},
{"rwhashpd", cmd_rw_hash_pd},
- {"rwsigaction", cmd_rwsig_action},
+ {"rwsig", cmd_rwsig},
+ {"rwsigaction", cmd_rwsig_action_legacy},
{"rwsigstatus", cmd_rwsig_status},
{"sertest", cmd_serial_test},
{"stress", cmd_stress_test},