diff options
-rw-r--r-- | common/rwsig.c | 3 | ||||
-rw-r--r-- | common/update_fw.c | 3 | ||||
-rw-r--r-- | common/vboot/vb21_lib.c | 64 | ||||
-rw-r--r-- | include/ec_commands.h | 42 | ||||
-rw-r--r-- | include/vboot.h | 8 | ||||
-rw-r--r-- | util/ectool.c | 177 |
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}, |