summaryrefslogtreecommitdiff
path: root/futility
diff options
context:
space:
mode:
Diffstat (limited to 'futility')
-rw-r--r--futility/cmd_show.c68
-rw-r--r--futility/file_type_bios.c138
-rw-r--r--futility/file_type_bios.h16
-rw-r--r--futility/file_type_rwsig.c10
-rw-r--r--futility/futility.h5
-rw-r--r--futility/misc.c52
-rw-r--r--futility/vb2_helper.c16
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);