diff options
Diffstat (limited to 'futility')
-rw-r--r-- | futility/cmd_show.c | 68 | ||||
-rw-r--r-- | futility/file_type_bios.c | 138 | ||||
-rw-r--r-- | futility/file_type_bios.h | 16 | ||||
-rw-r--r-- | futility/file_type_rwsig.c | 10 | ||||
-rw-r--r-- | futility/futility.h | 5 | ||||
-rw-r--r-- | futility/misc.c | 52 | ||||
-rw-r--r-- | futility/vb2_helper.c | 16 |
7 files changed, 186 insertions, 119 deletions
diff --git a/futility/cmd_show.c b/futility/cmd_show.c index 6ed15435..4b11b50f 100644 --- a/futility/cmd_show.c +++ b/futility/cmd_show.c @@ -22,6 +22,7 @@ #include "2common.h" #include "2sha.h" #include "2sysincludes.h" +#include "cbfstool.h" #include "file_type_bios.h" #include "file_type.h" #include "fmap.h" @@ -181,6 +182,53 @@ done: return retval; } +static int fw_show_metadata_hash(const char *name, enum bios_component body_c, + struct vb2_fw_preamble *pre) +{ + struct vb2_hash real_hash; + struct vb2_hash *body_hash = + (struct vb2_hash *)vb2_signature_data(&pre->body_signature); + const uint32_t bhsize = vb2_digest_size(body_hash->algo); + + if (!bhsize || pre->body_signature.sig_size < + offsetof(struct vb2_hash, raw) + bhsize) { + fprintf(stderr, "Body signature data is too small to " + "fit metadata hash.\n"); + return 1; + } + + printf(" Body metadata hash: %s", + vb2_get_hash_algorithm_name(body_hash->algo)); + if (vb2_digest_size(body_hash->algo)) { + putchar(':'); + print_bytes((uint8_t *)body_hash->raw, + vb2_digest_size(body_hash->algo)); + } + putchar('\n'); + + if (cbfstool_get_metadata_hash(name, fmap_name[body_c], &real_hash) != + VB2_SUCCESS || + real_hash.algo == VB2_HASH_INVALID) { + fprintf(stderr, "Failed to get metadata hash. Firmware body is" + " corrupted or is not a valid CBFS.\n"); + return 1; + } + + if (body_hash->algo != real_hash.algo || + !vb2_digest_size(body_hash->algo) || + memcmp(body_hash->raw, real_hash.raw, + vb2_digest_size(body_hash->algo))) { + printf(" MISMATCH! Real hash: %s:", + vb2_get_hash_algorithm_name(real_hash.algo)); + print_bytes(&real_hash.raw, vb2_digest_size(real_hash.algo)); + putchar('\n'); + fprintf(stderr, "Signature hash does not match with" + " real metadata hash.\n"); + return 1; + } + return 0; +} + int show_fw_preamble_buf(const char *name, uint8_t *buf, uint32_t len, void *data) { @@ -190,6 +238,7 @@ int show_fw_preamble_buf(const char *name, uint8_t *buf, uint32_t len, uint8_t *fv_data = show_option.fv; uint64_t fv_size = show_option.fv_size; struct bios_area_s *fw_body_area = 0; + enum bios_component body_c; int good_sig = 0; int retval = 0; @@ -217,9 +266,8 @@ int show_fw_preamble_buf(const char *name, uint8_t *buf, uint32_t len, } /* Identify the firmware body for this VBLOCK */ - enum bios_component body_c = state->c == BIOS_FMAP_VBLOCK_A - ? BIOS_FMAP_FW_MAIN_A - : BIOS_FMAP_FW_MAIN_B; + body_c = state->c == BIOS_FMAP_VBLOCK_A ? BIOS_FMAP_FW_MAIN_A + : BIOS_FMAP_FW_MAIN_B; fw_body_area = &state->area[body_c]; } @@ -288,11 +336,15 @@ int show_fw_preamble_buf(const char *name, uint8_t *buf, uint32_t len, return 0; } - if (VB2_SUCCESS != - vb2_verify_data(fv_data, fv_size, &pre2->body_signature, - &data_key, &wb)) { - fprintf(stderr, "Error verifying firmware body.\n"); - return 1; + if (pre2->body_signature.data_size) { + if (vb2_verify_data(fv_data, fv_size, &pre2->body_signature, + &data_key, &wb) != VB2_SUCCESS) { + fprintf(stderr, "Error verifying firmware body.\n"); + return 1; + } + } else if (state) { /* Only works for images with at least FW_MAIN_A */ + if (fw_show_metadata_hash(name, body_c, pre2)) + return 1; } done: diff --git a/futility/file_type_bios.c b/futility/file_type_bios.c index e900f271..884dfc8e 100644 --- a/futility/file_type_bios.c +++ b/futility/file_type_bios.c @@ -19,15 +19,6 @@ #include "host_common.h" #include "vb1_helper.h" -static const char * const fmap_name[] = { - "GBB", /* BIOS_FMAP_GBB */ - "FW_MAIN_A", /* BIOS_FMAP_FW_MAIN_A */ - "FW_MAIN_B", /* BIOS_FMAP_FW_MAIN_B */ - "VBLOCK_A", /* BIOS_FMAP_VBLOCK_A */ - "VBLOCK_B", /* BIOS_FMAP_VBLOCK_B */ -}; -_Static_assert(ARRAY_SIZE(fmap_name) == NUM_BIOS_COMPONENTS, - "Size of fmap_name[] should match NUM_BIOS_COMPONENTS"); static void fmap_limit_area(FmapAreaHeader *ah, uint32_t len) { @@ -248,9 +239,15 @@ static int write_new_preamble(struct bios_area_s *vblock, struct vb2_fw_preamble *preamble = NULL; int retval = 1; - body_sig = vb2_calculate_signature(fw_body->buf, fw_body->len, signkey); + if (fw_body->metadata_hash.algo != VB2_HASH_INVALID) + body_sig = + vb2_create_signature_from_hash(&fw_body->metadata_hash); + else + body_sig = vb2_calculate_signature(fw_body->buf, fw_body->len, + signkey); + if (!body_sig) { - ERROR("Error calculating body signature\n"); + ERROR("Error calculating or creating body signature\n"); goto end; } @@ -355,8 +352,8 @@ static int sign_bios_at_end(struct bios_state_s *state) /* Prepare firmware slot for signing. If fw_size is not zero, then it will be used as new length of signed area, for zero the length will be taken form FlashMap or preamble. */ -static int prepare_slot(uint8_t *buf, uint32_t len, size_t fw_size, - enum bios_component fw_c, enum bios_component vblock_c, +static int prepare_slot(uint8_t *buf, uint32_t len, enum bios_component fw_c, + enum bios_component vblock_c, struct bios_state_s *state) { FmapHeader *fmap; @@ -380,14 +377,16 @@ static int prepare_slot(uint8_t *buf, uint32_t len, size_t fw_size, fmap_limit_area(ah, len); state->area[fw_c].buf = buf + ah->area_offset; state->area[fw_c].is_valid = 1; - if (fw_size > ah->area_size) { + if (state->area[fw_c].fw_size > ah->area_size) { ERROR("%s size is incorrect.\n", fmap_name[fw_c]); return 1; - } else if (fw_size) { - state->area[fw_c].len = fw_size; + } else if (state->area[fw_c].fw_size) { + state->area[fw_c].len = state->area[fw_c].fw_size; } else { - WARN("%s does not contain CBFS. Trying to sign entire area.\n", - fmap_name[fw_c]); + if (state->area[fw_c].metadata_hash.algo == VB2_HASH_INVALID) + WARN("%s does not contain CBFS. Trying to sign entire " + "area.\n", + fmap_name[fw_c]); state->area[fw_c].len = ah->area_size; } @@ -441,7 +440,7 @@ static int prepare_slot(uint8_t *buf, uint32_t len, size_t fw_size, goto end; } - if (fw_size == 0) { + if (state->area[fw_c].fw_size == 0) { if (preamble->body_signature.data_size > state->area[fw_c].len) { ERROR("%s says the firmware is larger than we have.\n", @@ -475,6 +474,63 @@ end: return 0; } +static bool image_uses_cbfs_integration(const char *file) +{ + char *value; + bool rv = false; + + if (cbfstool_get_config_value(file, NULL, + "CONFIG_VBOOT_CBFS_INTEGRATION", + &value) != VB2_SUCCESS) + return false; + + if (value && strcmp("y", value) == 0) + rv = true; + + free(value); + return rv; +} + +static void image_check_and_prepare_cbfs(const char *file, + enum bios_component fw_c, + bool uses_cbfs_integration, + struct bios_state_s *state) +{ + if (!uses_cbfs_integration) { + if (cbfstool_truncate(file, fmap_name[fw_c], + &state->area[fw_c].fw_size) != + VB2_SUCCESS) { + VB2_DEBUG("CBFS not found in area %s\n", + fmap_name[fw_c]); + return; + } + VB2_DEBUG("CBFS found in area %s\n", fmap_name[fw_c]); + return; + } + + if (cbfstool_get_metadata_hash(file, fmap_name[fw_c], + &state->area[fw_c].metadata_hash) != + VB2_SUCCESS) + FATAL("CBFS metadata hash not found in area" + " %s. It is required for images with" + " VBOOT_CBFS_INTEGRATION", + fmap_name[fw_c]); + + VB2_DEBUG("CBFS metadata hash found in area %s\n", fmap_name[fw_c]); +} + +static void check_slot_after_prepare(enum bios_component fw_c, + bool uses_cbfs_integration, + struct bios_state_s *state) +{ + if (state->area[fw_c].is_valid && uses_cbfs_integration && + state->area[fw_c].metadata_hash.algo == VB2_HASH_INVALID) + FATAL("CBFS with metadata hash not found in area %s." + " It is required for images with" + " VBOOT_CBFS_INTEGRATION", + fmap_name[fw_c]); +} + int ft_sign_bios(const char *name, void *data) { int retval = 0; @@ -482,47 +538,35 @@ int ft_sign_bios(const char *name, void *data) int fd = -1; uint8_t *buf = NULL; uint32_t len = 0; - size_t fw_main_a_size = 0; - size_t fw_main_b_size = 0; - - bool fw_main_a_in_cbfs_mode = - cbfstool_truncate(name, fmap_name[BIOS_FMAP_FW_MAIN_A], - &fw_main_a_size) == VB2_SUCCESS; - - bool fw_main_b_in_cbfs_mode = - cbfstool_truncate(name, fmap_name[BIOS_FMAP_FW_MAIN_B], - &fw_main_b_size) == VB2_SUCCESS; + bool uses_cbfs_integration = + image_uses_cbfs_integration(name); - if (fw_main_a_in_cbfs_mode) - VB2_DEBUG("CBFS found in area %s\n", - fmap_name[BIOS_FMAP_FW_MAIN_A]); - else - VB2_DEBUG("CBFS not found in area %s\n", - fmap_name[BIOS_FMAP_FW_MAIN_A]); + memset(&state, 0, sizeof(state)); - if (fw_main_b_in_cbfs_mode) - VB2_DEBUG("CBFS found in area %s\n", - fmap_name[BIOS_FMAP_FW_MAIN_B]); - else - VB2_DEBUG("CBFS not found in area %s\n", - fmap_name[BIOS_FMAP_FW_MAIN_B]); + image_check_and_prepare_cbfs(name, BIOS_FMAP_FW_MAIN_A, + uses_cbfs_integration, &state); + image_check_and_prepare_cbfs(name, BIOS_FMAP_FW_MAIN_B, + uses_cbfs_integration, &state); if (futil_open_and_map_file(name, &fd, FILE_MODE_SIGN(sign_option), &buf, &len)) return 1; - memset(&state, 0, sizeof(state)); - - retval = prepare_slot(buf, len, fw_main_a_size, BIOS_FMAP_FW_MAIN_A, - BIOS_FMAP_VBLOCK_A, &state); + retval = prepare_slot(buf, len, BIOS_FMAP_FW_MAIN_A, BIOS_FMAP_VBLOCK_A, + &state); if (retval) goto done; - retval = prepare_slot(buf, len, fw_main_b_size, BIOS_FMAP_FW_MAIN_B, - BIOS_FMAP_VBLOCK_B, &state); + retval = prepare_slot(buf, len, BIOS_FMAP_FW_MAIN_B, BIOS_FMAP_VBLOCK_B, + &state); if (retval && state.area[BIOS_FMAP_FW_MAIN_B].is_valid) goto done; + check_slot_after_prepare(BIOS_FMAP_FW_MAIN_A, uses_cbfs_integration, + &state); + check_slot_after_prepare(BIOS_FMAP_FW_MAIN_B, uses_cbfs_integration, + &state); + retval = sign_bios_at_end(&state); done: futil_unmap_and_close_file(fd, FILE_MODE_SIGN(sign_option), buf, len); diff --git a/futility/file_type_bios.h b/futility/file_type_bios.h index 469e3fd0..1f957b1c 100644 --- a/futility/file_type_bios.h +++ b/futility/file_type_bios.h @@ -8,6 +8,8 @@ #include <stdint.h> +#include "futility.h" + /* * The Chrome OS BIOS must contain specific FMAP areas, which we want to look * at in a certain order. @@ -22,6 +24,16 @@ enum bios_component { NUM_BIOS_COMPONENTS }; +static const char * const fmap_name[] = { + "GBB", /* BIOS_FMAP_GBB */ + "FW_MAIN_A", /* BIOS_FMAP_FW_MAIN_A */ + "FW_MAIN_B", /* BIOS_FMAP_FW_MAIN_B */ + "VBLOCK_A", /* BIOS_FMAP_VBLOCK_A */ + "VBLOCK_B", /* BIOS_FMAP_VBLOCK_B */ +}; +_Static_assert(ARRAY_SIZE(fmap_name) == NUM_BIOS_COMPONENTS, + "Size of fmap_name[] should match NUM_BIOS_COMPONENTS"); + /* Location information for each component */ struct bios_area_s { uint32_t offset; /* to avoid pointer math */ @@ -32,6 +44,10 @@ struct bios_area_s { /* VBLOCK only */ uint32_t flags; uint32_t version; + + /* FW_MAIN only */ + size_t fw_size; /* effective size from cbfstool (if available) */ + struct vb2_hash metadata_hash; }; /* State to track as we visit all components */ diff --git a/futility/file_type_rwsig.c b/futility/file_type_rwsig.c index 86e9bf29..56d92c5f 100644 --- a/futility/file_type_rwsig.c +++ b/futility/file_type_rwsig.c @@ -32,14 +32,6 @@ #define SIGNATURE_RSVD_SIZE 1024 #define EC_RW_FILENAME "EC_RW.bin" -static inline void vb2_print_bytes(const void *ptr, uint32_t len) -{ - const uint8_t *buf = (const uint8_t *)ptr; - int i; - for (i = 0; i < len; i++) - printf("%02x", *buf++); -} - static void show_sig(const char *name, const struct vb21_signature *sig) { printf("Signature: %s\n", name); @@ -52,7 +44,7 @@ static void show_sig(const char *name, const struct vb21_signature *sig) printf(" Total size: %#x (%d)\n", sig->c.total_size, sig->c.total_size); printf(" ID: "); - vb2_print_bytes(&sig->id, sizeof(sig->id)); + print_bytes(&sig->id, sizeof(sig->id)); printf("\n"); printf(" Data size: %#x (%d)\n", sig->data_size, sig->data_size); diff --git a/futility/futility.h b/futility/futility.h index 18063d97..2bf3d7f4 100644 --- a/futility/futility.h +++ b/futility/futility.h @@ -159,6 +159,11 @@ enum futil_file_err futil_unmap_and_close_file(int fd, enum file_mode mode, */ void parse_digest_or_die(uint8_t *buf, int len, const char *str); +/* + * Print provided buffer as hex string + */ +void print_bytes(const void *ptr, size_t len); + /* The CPU architecture is occasionally important */ enum arch_t { ARCH_UNSPECIFIED, diff --git a/futility/misc.c b/futility/misc.c index 8366bc92..85358b29 100644 --- a/futility/misc.c +++ b/futility/misc.c @@ -27,6 +27,7 @@ #include "cgptlib_internal.h" #include "file_type.h" #include "futility.h" +#include "host_misc.h" /* Default is to support everything we can */ enum vboot_version vboot_version = VBOOT_VERSION_ALL; @@ -420,53 +421,18 @@ enum futil_file_type ft_recognize_gpt(uint8_t *buf, uint32_t len) return FILE_TYPE_CHROMIUMOS_DISK; } -static int parse_hex(uint8_t *val, const char *str) +void parse_digest_or_die(uint8_t *buf, int len, const char *str) { - uint8_t v = 0; - char c; - int digit; - - for (digit = 0; digit < 2; digit++) { - c = *str; - if (!c) - return 0; - if (!isxdigit(c)) - return 0; - c = tolower(c); - if (c >= '0' && c <= '9') - v += c - '0'; - else - v += 10 + c - 'a'; - if (!digit) - v <<= 4; - str++; + if (!parse_hash(buf, len, str)) { + fprintf(stderr, "Invalid DIGEST \"%s\"\n", str); + exit(1); } - - *val = v; - return 1; } -void parse_digest_or_die(uint8_t *buf, int len, const char *str) +void print_bytes(const void *ptr, size_t len) { - const char *s = str; - int i; - - for (i = 0; i < len; i++) { - /* skip whitespace */ - while (*s && isspace(*s)) - s++; - if (!*s) - break; - if (!parse_hex(buf, s)) - break; - - /* on to the next byte */ - s += 2; - buf++; - } + const uint8_t *buf = (const uint8_t *)ptr; - if ((i != len) || *s) { - fprintf(stderr, "Invalid DIGEST \"%s\"\n", str); - exit(1); - } + for (size_t i = 0; i < len; i++) + printf("%02x", *buf++); } diff --git a/futility/vb2_helper.c b/futility/vb2_helper.c index 9e875b98..afc0019f 100644 --- a/futility/vb2_helper.c +++ b/futility/vb2_helper.c @@ -38,14 +38,6 @@ enum futil_file_type ft_recognize_vb21_key(uint8_t *buf, uint32_t len) return FILE_TYPE_UNKNOWN; } -static inline void vb2_print_bytes(const void *ptr, uint32_t len) -{ - const uint8_t *buf = (const uint8_t *)ptr; - int i; - for (i = 0; i < len; i++) - printf("%02x", *buf++); -} - static int vb2_public_key_sha1sum(struct vb2_public_key *key, struct vb2_hash *hash) { @@ -81,12 +73,12 @@ int show_vb21_pubkey_buf(const char *name, uint8_t *buf, uint32_t len, vb2_get_hash_algorithm_name(key.hash_alg)); printf(" Version: 0x%08x\n", key.version); printf(" ID: "); - vb2_print_bytes(key.id, sizeof(*key.id)); + print_bytes(key.id, sizeof(*key.id)); printf("\n"); if (vb2_public_key_sha1sum(&key, &hash) && memcmp(key.id, hash.sha1, sizeof(*key.id))) { printf(" Key sha1sum: "); - vb2_print_bytes(hash.sha1, sizeof(hash.sha1)); + print_bytes(hash.sha1, sizeof(hash.sha1)); printf("\n"); } return 0; @@ -148,12 +140,12 @@ int ft_show_vb21_privkey(const char *name, void *data) printf(" Hash Algorithm: %d %s\n", key->hash_alg, vb2_get_hash_algorithm_name(key->hash_alg)); printf(" ID: "); - vb2_print_bytes(&key->id, sizeof(key->id)); + print_bytes(&key->id, sizeof(key->id)); printf("\n"); if (vb2_private_key_sha1sum(key, &hash) && memcmp(&key->id, hash.sha1, sizeof(key->id))) { printf(" Key sha1sum: "); - vb2_print_bytes(hash.sha1, sizeof(hash.sha1)); + print_bytes(hash.sha1, sizeof(hash.sha1)); printf("\n"); } vb2_private_key_free(key); |