[coreboot-gerrit] Patch set updated for coreboot: cbfstool: Add version code, flags, variable-width hash to file headers

Patrick Georgi (pgeorgi@google.com) gerrit at coreboot.org
Wed Jul 8 19:49:07 CEST 2015


Patrick Georgi (pgeorgi at google.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/10147

-gerrit

commit 7f0a15ad4f31ed98d9a64e4f7fd91d20059ee3fa
Author: Sol Boucher <solb at chromium.org>
Date:   Thu May 7 21:00:05 2015 -0700

    cbfstool: Add version code, flags, variable-width hash to file headers
    
    This new format is intended to fully replace the CBFS master header,
    and is only used when working with new-format images without one. The
    cbfstool utility remains backwards-compatible with legacy images that
    still use a master header, and will continue to generate old-format
    headers when operating on such files. However, because it always
    generates updated headers when working with new-format images, the
    very first version of cbfstool to support the new layout will be
    unable to read/write images created/edited by this and future
    versions.
    
    For the first time, cbfstool actually supports hashing files as they
    are added; invoking an add action with the -A switch set to sha1,
    sha256, or sha512 will generate a hash and store it in the entry
    header's new hash field. Subsequent print actions will detect the
    hashes and verify them using the same algorithm.
    
    BUG=chromium:482652
    TEST=Build panther and nyan_big coreboot.rom and image.bin images with
    and without this patch, diff their hexdumps, and note that no
    locations differ except for those that do between subsequent builds of
    the same codebase. Try adding hashed files, ensuring that the stored
    hashes match those produced by the sha1sum, sha256sum, and sha512
    commands, and that the print action correctly detects hashes that
    match and don't (due to intentional tampering).
    BRANCH=None
    
    Change-Id: Ibef7989b9b5830666925e5f8b5cad14cec2e3551
    Signed-off-by: Sol Boucher <solb at chromium.org>
    Original-Change-Id: I1a117a9473e895feaf455bb30d0f945f57de51eb
    Original-Signed-off-by: Sol Boucher <solb at chromium.org>
---
 src/cpu/ti/am335x/Makefile.inc |   2 +-
 util/cbfstool/Makefile         |  11 ++
 util/cbfstool/Makefile.inc     |  15 +++
 util/cbfstool/cbfs.h           |  35 ++++--
 util/cbfstool/cbfs_image.c     | 276 ++++++++++++++++++++++++++++++++++-------
 util/cbfstool/cbfs_image.h     |  25 +++-
 util/cbfstool/cbfstool.c       | 138 +++++++++++----------
 util/cbfstool/common.c         |  20 ++-
 util/cbfstool/common.h         |  13 +-
 util/cbfstool/swab.h           |  12 ++
 10 files changed, 412 insertions(+), 135 deletions(-)

diff --git a/src/cpu/ti/am335x/Makefile.inc b/src/cpu/ti/am335x/Makefile.inc
index 8e8dab1..e9fd4b7 100644
--- a/src/cpu/ti/am335x/Makefile.inc
+++ b/src/cpu/ti/am335x/Makefile.inc
@@ -27,7 +27,7 @@ header_ld = $(obj)/cpu/ti/am335x/header.omap-header.ld
 get_header_size= \
 	$(eval omap_header_info=$(shell $(CBFSTOOL) $(1) print | grep $(2))) \
 	$(shell echo $$(($(word 2,$(omap_header_info)) + \
-			 $(word 4,$(omap_header_info)))))
+			 $(word 6,$(omap_header_info)))))
 
 $(obj)/omap-header.bin: $$(omap-header-objs) $(obj)/coreboot.rom
 	@printf "    CC         $(subst $(obj)/,,$(@))\n"
diff --git a/util/cbfstool/Makefile b/util/cbfstool/Makefile
index 65d5710..764bc9a 100644
--- a/util/cbfstool/Makefile
+++ b/util/cbfstool/Makefile
@@ -8,7 +8,10 @@ CFLAGS += -Wcast-qual -Wmissing-prototypes -Wredundant-decls -Wshadow
 CFLAGS += -Wstrict-prototypes -Wwrite-strings
 CPPFLAGS += -D_DEFAULT_SOURCE # memccpy() from string.h
 CPPFLAGS += -D_POSIX_C_SOURCE=200809L # strdup() from string.h
+CPPFLAGS += -DNEED_VB2_SHA_LIBRARY
 CPPFLAGS += -Iflashmap
+CPPFLAGS += -I../../3rdparty/vboot/firmware/include
+CPPFLAGS += -I../../3rdparty/vboot/firmware/2lib/include
 LDFLAGS += -g3
 
 CBFSTOOL_BINARY:=$(obj)/cbfstool
@@ -23,6 +26,11 @@ CBFSTOOL_COMMON+=flashmap/fmap.o
 CBFSTOOL_COMMON+=flashmap/kv_pair.o flashmap/valstr.o
 
 CBFSTOOL_COMMON:=$(addprefix $(obj)/,$(CBFSTOOL_COMMON))
+# CRYPTOLIB
+CBFSTOOL_COMMON+=../../3rdparty/vboot/firmware/2lib/2sha_utility.o
+CBFSTOOL_COMMON+=../../3rdparty/vboot/firmware/2lib/2sha1.o
+CBFSTOOL_COMMON+=../../3rdparty/vboot/firmware/2lib/2sha256.o
+CBFSTOOL_COMMON+=../../3rdparty/vboot/firmware/2lib/2sha512.o
 
 FMAPTOOL_BINARY:=$(obj)/fmaptool
 FMAPTOOL_COMMON:=cbfs_sections.o fmap_from_fmd.o
@@ -102,5 +110,8 @@ $(obj)/fmd_scanner.o: CFLAGS += -Wno-redundant-decls
 $(obj)/fmd_scanner.o: CFLAGS += -Wno-unused-function
 # Tolerate lzma sdk warnings
 $(obj)/lzma/C/LzmaEnc.o: CFLAGS += -Wno-sign-compare -Wno-cast-qual
+# Tolerate vboot warnings
+../../3rdparty/vboot/firmware/2lib/2sha_utility.o: CFLAGS += -Wno-sign-compare
+../../3rdparty/vboot/firmware/2lib/2sha1.o: CFLAGS += -Wno-cast-qual
 
 -include .dependencies
diff --git a/util/cbfstool/Makefile.inc b/util/cbfstool/Makefile.inc
index 976f0c2..8aa1330 100644
--- a/util/cbfstool/Makefile.inc
+++ b/util/cbfstool/Makefile.inc
@@ -14,6 +14,11 @@ cbfsobj += lzma.o
 cbfsobj += LzFind.o
 cbfsobj += LzmaDec.o
 cbfsobj += LzmaEnc.o
+# CRYPTOLIB
+cbfsobj += 2sha_utility.o
+cbfsobj += 2sha1.o
+cbfsobj += 2sha256.o
+cbfsobj += 2sha512.o
 # FMAP
 cbfsobj += fmap.o
 cbfsobj += kv_pair.o
@@ -49,6 +54,9 @@ TOOLCPPFLAGS += -D_XOPEN_SOURCE=700 # strdup() from string.h
 TOOLCPPFLAGS += -I$(top)/util/cbfstool/flashmap
 TOOLCPPFLAGS += -I$(top)/util/cbfstool
 TOOLCPPFLAGS += -I$(objutil)/cbfstool
+TOOLCPPFLAGS += -DNEED_VB2_SHA_LIBRARY
+TOOLCPPFLAGS += -I$(top)/3rdparty/vboot/firmware/include
+TOOLCPPFLAGS += -I$(top)/3rdparty/vboot/firmware/2lib/include
 TOOLLDFLAGS ?=
 
 ifeq ($(shell uname -s | cut -c-7 2>/dev/null), MINGW32)
@@ -75,6 +83,10 @@ $(objutil)/cbfstool/%.o: $(top)/util/cbfstool/lzma/C/%.c
 	printf "    HOSTCC     $(subst $(objutil)/,,$(@))\n"
 	$(HOSTCC) $(TOOLCPPFLAGS) $(TOOLCFLAGS) $(HOSTCFLAGS) -c -o $@ $<
 
+$(objutil)/cbfstool/%.o: $(top)/3rdparty/vboot/firmware/2lib/%.c
+	printf "    HOSTCC     $(subst $(objutil)/,,$(@))\n"
+	$(HOSTCC) $(TOOLCPPFLAGS) $(TOOLCFLAGS) $(HOSTCFLAGS) -c -o $@ $<
+
 $(objutil)/cbfstool/cbfstool: $(addprefix $(objutil)/cbfstool/,$(cbfsobj))
 	printf "    HOSTCC     $(subst $(objutil)/,,$(@)) (link)\n"
 	$(HOSTCC) $(TOOLLDFLAGS) -o $@ $(addprefix $(objutil)/cbfstool/,$(cbfsobj))
@@ -95,6 +107,9 @@ $(objutil)/cbfstool/fmd_scanner.o: TOOLCFLAGS += -Wno-redundant-decls
 $(objutil)/cbfstool/fmd_scanner.o: TOOLCFLAGS += -Wno-unused-function
 # Tolerate lzma sdk warnings
 $(objutil)/cbfstool/LzmaEnc.o: TOOLCFLAGS += -Wno-sign-compare -Wno-cast-qual
+# Tolerate vboot warnings
+$(objutil)/cbfstool/2sha_utility.o: TOOLCFLAGS += -Wno-sign-compare
+$(objutil)/cbfstool/2sha1.o: TOOLCFLAGS += -Wno-cast-qual
 
 $(objutil)/cbfstool/fmd.o: $(objutil)/cbfstool/fmd_parser.h
 $(objutil)/cbfstool/fmd.o: $(objutil)/cbfstool/fmd_scanner.h
diff --git a/util/cbfstool/cbfs.h b/util/cbfstool/cbfs.h
index 8092057..5226ba3 100644
--- a/util/cbfstool/cbfs.h
+++ b/util/cbfstool/cbfs.h
@@ -21,6 +21,9 @@
 
 #include <stdint.h>
 
+/* Endianess */
+#include "swab.h"
+
 /* create a magic number in host-byte order.
  * b3 is the high order byte.
  * in the coreboot tools, we go with the 32-bit
@@ -66,14 +69,22 @@ struct cbfs_header {
 #define CBFS_ARCHITECTURE_RISCV    0xc001d0de
 
 #define CBFS_FILE_MAGIC "LARCHIVE"
+#define CBFS_FILE_VERSION 1
+#define CBFS_FILE_V0_LEN (6 * sizeof(uint32_t))
 
 struct cbfs_file {
 	uint8_t magic[8];
-	uint32_t len;
+	uint32_t len;         /* Of the file described by this header */
 	uint32_t type;
-	uint32_t checksum;
-	uint32_t offset;
+	uint16_t version;
+	uint16_t flags;       /* V1 */
+	uint32_t offset;      /* To the file described by this header */
+	uint32_t header_len;  /* V1: Of header, up to the *beginning* of name */
+	uint16_t hash_type;   /* V1: Also determines size of the hash */
+	uint16_t hash_offset; /* V1: From the beginning of header */
 } __PACKED;
+/* Should be immediately followed by the hash (and any future variable-width
+   fields), then the (NUL-terminated) variable-length name. */
 
 struct cbfs_stage {
 	uint32_t compression;
@@ -134,15 +145,23 @@ struct cbfs_payload {
  */
 #define CBFS_COMPONENT_NULL 0xFFFFFFFF
 
-#define CBFS_NAME(_c) (((char *) (_c)) + sizeof(struct cbfs_file))
-#define CBFS_SUBHEADER(_p) ( (void *) ((((uint8_t *) (_p)) + ntohl((_p)->offset))) )
-/* cbfs_image.c */
-uint32_t get_cbfs_entry_type(const char *name, uint32_t default_value);
-uint32_t get_cbfs_compression(const char *name, uint32_t unknown);
+#define CBFS_HEADER_LEN(_c) (ntohs((_c)->version) >= 1 ? \
+				ntohl((_c)->header_len) : CBFS_FILE_V0_LEN)
+#define CBFS_NAME(_c) (ntohs((_c)->version) >= 1 ? \
+				((char *) (_c)) + ntohl((_c)->header_len) : \
+				((char *) (_c)) + CBFS_FILE_V0_LEN)
+#define CBFS_SUBHEADER(_p) ((void *) (((uint8_t *) (_p)) + ntohl((_p)->offset)))
+#define CBFS_HASH(_c) ((_c)->version >= 1 && (_c)->hash_type && \
+							(_c)->hash_offset ? \
+			(((uint8_t *) (_c)) + ntohs((_c)->hash_offset)) : NULL)
 
 /* common.c */
 void cbfs_file_get_header(struct buffer *buf, struct cbfs_file *file);
 
+/* cbfs_image.c */
+uint32_t get_cbfs_entry_type(const char *name, uint32_t default_value);
+uint32_t get_cbfs_compression(const char *name, uint32_t unknown);
+
 /* cbfs-mkpayload.c */
 void xdr_segs(struct buffer *output,
 	      struct cbfs_payload_segment *segs, int nseg);
diff --git a/util/cbfstool/cbfs_image.c b/util/cbfstool/cbfs_image.c
index 2ce4bdd..3b6f8c1 100644
--- a/util/cbfstool/cbfs_image.c
+++ b/util/cbfstool/cbfs_image.c
@@ -77,15 +77,32 @@ static const struct typedesc_t types_cbfs_entry[] = {
 	{CBFS_COMPONENT_MRC_CACHE, "mrc_cache"},
 	{CBFS_COMPONENT_DELETED, "deleted"},
 	{CBFS_COMPONENT_NULL, "null"},
-	{0, NULL},
+	{0, NULL}
 };
 
 static const struct typedesc_t types_cbfs_compression[] = {
 	{CBFS_COMPRESS_NONE, "none"},
 	{CBFS_COMPRESS_LZMA, "LZMA"},
-	{0, NULL},
+	{0, NULL}
 };
 
+static const struct typedesc_t types_cbfs_hash[] = {
+	{VB2_HASH_INVALID, "none"},
+	{VB2_HASH_SHA1, "sha1"},
+	{VB2_HASH_SHA256, "sha256"},
+	{VB2_HASH_SHA512, "sha512"},
+	{0, NULL}
+};
+
+static size_t widths_cbfs_hash[] = {
+	[VB2_HASH_INVALID] = 0,
+	[VB2_HASH_SHA1] = 20,
+	[VB2_HASH_SHA256] = 32,
+	[VB2_HASH_SHA512] = 64,
+};
+#define CBFS_NUM_SUPPORTED_HASHES (sizeof(widths_cbfs_hash) / \
+						sizeof(*(widths_cbfs_hash)))
+
 static const char *lookup_name_by_type(const struct typedesc_t *desc, uint32_t type,
 				const char *default_value)
 {
@@ -96,17 +113,46 @@ static const char *lookup_name_by_type(const struct typedesc_t *desc, uint32_t t
 	return default_value;
 }
 
+static int lookup_type_by_name(const struct typedesc_t *desc, const char *name)
+{
+	int i;
+	for (i = 0; desc[i].name && strcasecmp(name, desc[i].name); ++i);
+	return desc[i].name ? (int)desc[i].type : -1;
+}
+
 static const char *get_cbfs_entry_type_name(uint32_t type)
 {
 	return lookup_name_by_type(types_cbfs_entry, type, "(unknown)");
 }
 
+int cbfs_parse_comp_algo(const char *name)
+{
+	return lookup_type_by_name(types_cbfs_compression, name);
+}
+
+int cbfs_parse_hash_algo(const char *name)
+{
+	return lookup_type_by_name(types_cbfs_hash, name);
+}
+
 /* CBFS image */
 
-static size_t cbfs_calculate_file_header_size(const char *name)
+static size_t cbfs_calculate_file_header_size_without_name(
+				enum vb2_hash_algorithm hash, bool legacy)
 {
-	return (sizeof(struct cbfs_file) +
-		align_up(strlen(name) + 1, CBFS_FILENAME_ALIGN));
+	if (legacy)
+		return CBFS_FILE_V0_LEN;
+	else
+		return sizeof(struct cbfs_file) + widths_cbfs_hash[hash];
+}
+
+static size_t cbfs_calculate_file_header_size(const char *name,
+					      enum vb2_hash_algorithm hash,
+					      bool legacy)
+{
+	return align_up(
+		cbfs_calculate_file_header_size_without_name(hash, legacy) +
+					strlen(name) + 1, CBFS_FILENAME_ALIGN);
 }
 
 /* Only call on legacy CBFSes possessing a master header. */
@@ -190,7 +236,8 @@ int cbfs_image_create(struct cbfs_image *image, size_t entries_size)
 	assert(image);
 	assert(image->buffer.data);
 
-	size_t empty_header_len = cbfs_calculate_file_header_size("");
+	size_t empty_header_len = cbfs_calculate_file_header_size("",
+				VB2_HASH_INVALID, cbfs_is_legacy_cbfs(image));
 	uint32_t entries_offset = 0;
 	uint32_t align = CBFS_ENTRY_ALIGNMENT;
 	if (image->has_header) {
@@ -231,7 +278,8 @@ int cbfs_image_create(struct cbfs_image *image, size_t entries_size)
 
 	size_t capacity = entries_size - empty_header_len;
 	LOG("Created CBFS (capacity = %zu bytes)\n", capacity);
-	return cbfs_create_empty_entry(entry_header, capacity, "");
+	return cbfs_create_empty_entry(entry_header, capacity, "", 0,
+				VB2_HASH_INVALID, cbfs_is_legacy_cbfs(image));
 }
 
 int cbfs_legacy_image_create(struct cbfs_image *image,
@@ -422,12 +470,13 @@ int cbfs_copy_instance(struct cbfs_image *image, size_t copy_offset,
 
 	/* Last entry size is all the room above it. */
 	last_entry_size = copy_end - ((char *)dst_entry - image->buffer.data)
-		- cbfs_calculate_file_header_size("");
+		- cbfs_calculate_file_header_size("", VB2_HASH_INVALID, true);
 
 	if (last_entry_size < 0)
 		WARN("No room to create the last entry!\n")
 	else
-		cbfs_create_empty_entry(dst_entry, last_entry_size, "");
+		cbfs_create_empty_entry(dst_entry, last_entry_size, "", 0,
+							VB2_HASH_INVALID, true);
 
 	return 0;
 }
@@ -441,20 +490,84 @@ int cbfs_image_delete(struct cbfs_image *image)
 	return 0;
 }
 
+/* Might be out of range. VB2_HASH_INVALID if file isn't protected by a hash. */
+static uint16_t cbfs_read_hash_type(struct cbfs_file *entry)
+{
+	return ntohs(entry->version) >= 1 ?
+				ntohs(entry->hash_type) : VB2_HASH_INVALID;
+}
+
+/* Retrieve hash field and its type. Returns < 0 for unknown/truncated hash. */
+static int cbfs_read_file_hash(uint8_t **hash, struct cbfs_file *entry)
+{
+	uint16_t type = cbfs_read_hash_type(entry);
+	if (type >= CBFS_NUM_SUPPORTED_HASHES) {
+		WARN("This version of cbfstool is too old to process hashes of the type used for this file\n");
+		return -1;
+	}
+
+	size_t width = widths_cbfs_hash[type];
+	uint8_t *stored = CBFS_HASH(entry);
+	if (stored && ((uintptr_t)stored) - ((uintptr_t)entry) +
+				((uintptr_t)width) > CBFS_HEADER_LEN(entry)) {
+		ERROR("This file header's hash field is truncated\n");
+		return -1;
+	}
+	if (hash)
+		*hash = stored;
+	return type;
+}
+
+/* 0 on success */
+static int cbfs_populate_file_hash(struct cbfs_file *entry)
+{
+	uint8_t *hash = NULL;
+	int type = cbfs_read_file_hash(&hash, entry);
+	if (type > 0) {
+		return vb2_digest_buffer(CBFS_SUBHEADER(entry),
+						ntohl(entry->len), type, hash,
+					widths_cbfs_hash[type]) != VB2_SUCCESS;
+	}
+	return type;
+}
+
+/* 0 on match, 1 on mismatch, < 0 on error */
+static int cbfs_check_hash(struct cbfs_file *entry)
+{
+	uint8_t *stored = NULL;
+	int type = cbfs_read_file_hash(&stored, entry);
+	if (type < 0)
+		return type;
+
+	size_t width = widths_cbfs_hash[type];
+	if (!width)
+		return 0;
+
+	uint8_t computed[width];
+	if (vb2_digest_buffer(CBFS_SUBHEADER(entry), ntohl(entry->len), type,
+						computed, width) != VB2_SUCCESS)
+		return -1;
+	return memcmp(computed, stored, width) == 0 ? 0 : 1;
+}
+
 /* Tries to add an entry with its data (CBFS_SUBHEADER) at given offset. */
 static int cbfs_add_entry_at(struct cbfs_image *image,
 			     struct cbfs_file *entry,
 			     uint32_t size,
 			     const char *name,
 			     uint32_t type,
+			     uint16_t flags,
+			     enum vb2_hash_algorithm hash,
 			     const void *data,
 			     uint32_t content_offset)
 {
 	struct cbfs_file *next = cbfs_find_next_entry(image, entry);
 	uint32_t addr = cbfs_get_entry_addr(image, entry),
 		 addr_next = cbfs_get_entry_addr(image, next);
-	uint32_t header_size = cbfs_calculate_file_header_size(name),
-		 min_entry_size = cbfs_calculate_file_header_size("");
+	uint32_t header_size = cbfs_calculate_file_header_size(name, hash,
+						cbfs_is_legacy_cbfs(image)),
+		 min_entry_size = cbfs_calculate_file_header_size("",
+				VB2_HASH_INVALID, cbfs_is_legacy_cbfs(image));
 	uint32_t len, target;
 	uint32_t align = image->has_header ? image->header.align :
 							CBFS_ENTRY_ALIGNMENT;
@@ -471,14 +584,16 @@ static int cbfs_add_entry_at(struct cbfs_image *image,
 	if (target - addr > min_entry_size) {
 		DEBUG("|min|...|header|content|... <create new entry>\n");
 		len = target - addr - min_entry_size;
-		cbfs_create_empty_entry(entry, len, "");
+		cbfs_create_empty_entry(entry, len, "", 0, VB2_HASH_INVALID,
+						cbfs_is_legacy_cbfs(image));
 		if (verbose > 1) cbfs_print_entry_info(image, entry, stderr);
 		entry = cbfs_find_next_entry(image, entry);
 		addr = cbfs_get_entry_addr(image, entry);
 	}
 
 	len = size + (content_offset - addr - header_size);
-	cbfs_create_empty_entry(entry, len, name);
+	cbfs_create_empty_entry(entry, len, name, flags, hash,
+						cbfs_is_legacy_cbfs(image));
 	if (len != size) {
 		DEBUG("|..|header|content|... <use offset to create entry>\n");
 		DEBUG("before: offset=0x%x, len=0x%x\n",
@@ -499,6 +614,7 @@ static int cbfs_add_entry_at(struct cbfs_image *image,
 	assert((char*)CBFS_SUBHEADER(entry) - image->buffer.data ==
 	       (ptrdiff_t)content_offset);
 	memcpy(CBFS_SUBHEADER(entry), data, size);
+	cbfs_populate_file_hash(entry);
 	if (verbose > 1) cbfs_print_entry_info(image, entry, stderr);
 
 	// Process buffer AFTER entry.
@@ -518,13 +634,15 @@ static int cbfs_add_entry_at(struct cbfs_image *image,
 	}
 
 	len = addr_next - addr - min_entry_size;
-	cbfs_create_empty_entry(entry, len, "");
+	cbfs_create_empty_entry(entry, len, "", 0, VB2_HASH_INVALID,
+						cbfs_is_legacy_cbfs(image));
 	if (verbose > 1) cbfs_print_entry_info(image, entry, stderr);
 	return 0;
 }
 
 int cbfs_add_entry(struct cbfs_image *image, struct buffer *buffer,
-		   const char *name, uint32_t type, uint32_t content_offset)
+		   const char *name, uint32_t type, uint16_t flags,
+		   enum vb2_hash_algorithm hash, uint32_t content_offset)
 {
 	assert(image);
 	assert(buffer);
@@ -537,7 +655,8 @@ int cbfs_add_entry(struct cbfs_image *image, struct buffer *buffer,
 	struct cbfs_file *entry, *next;
 	uint32_t header_size, need_size, new_size;
 
-	header_size = cbfs_calculate_file_header_size(name);
+	header_size = cbfs_calculate_file_header_size(name, hash,
+						cbfs_is_legacy_cbfs(image));
 
 	need_size = header_size + buffer->size;
 	DEBUG("cbfs_add_entry('%s'@0x%x) => need_size = %u+%zu=%u\n",
@@ -572,9 +691,12 @@ int cbfs_add_entry(struct cbfs_image *image, struct buffer *buffer,
 		if (!content_offset || content_offset == addr + header_size) {
 			DEBUG("Filling new entry data (%zd bytes).\n",
 			      buffer->size);
-			cbfs_create_empty_entry(entry, buffer->size, name);
+			cbfs_create_empty_entry(entry, buffer->size, name,
+								flags, hash,
+						cbfs_is_legacy_cbfs(image));
 			entry->type = htonl(type);
 			memcpy(CBFS_SUBHEADER(entry), buffer->data, buffer->size);
+			cbfs_populate_file_hash(entry);
 			if (verbose)
 				cbfs_print_entry_info(image, entry, stderr);
 
@@ -585,7 +707,9 @@ int cbfs_add_entry(struct cbfs_image *image, struct buffer *buffer,
 				    cbfs_get_entry_addr(image, entry));
 
 			/* Entry was added and no space for new "empty" entry */
-			if (new_size < cbfs_calculate_file_header_size("")) {
+			if (new_size < cbfs_calculate_file_header_size("",
+							VB2_HASH_INVALID,
+						cbfs_is_legacy_cbfs(image))) {
 				DEBUG("No need for new \"empty\" entry\n");
 				/* No need to increase the size of the just
 				 * stored file to extend to next file. Alignment
@@ -593,9 +717,13 @@ int cbfs_add_entry(struct cbfs_image *image, struct buffer *buffer,
 				 */
 				return 0;
 			}
-			new_size -= cbfs_calculate_file_header_size("");
+			new_size -= cbfs_calculate_file_header_size("",
+							VB2_HASH_INVALID,
+						cbfs_is_legacy_cbfs(image));
 			DEBUG("new size: %d\n", new_size);
-			cbfs_create_empty_entry(entry, new_size, "");
+			cbfs_create_empty_entry(entry, new_size, "", 0,
+							VB2_HASH_INVALID,
+						cbfs_is_legacy_cbfs(image));
 			if (verbose)
 				cbfs_print_entry_info(image, entry, stderr);
 			return 0;
@@ -624,7 +752,7 @@ int cbfs_add_entry(struct cbfs_image *image, struct buffer *buffer,
 		      addr, addr_next - addr, content_offset);
 
 		if (cbfs_add_entry_at(image, entry, buffer->size, name, type,
-				      buffer->data, content_offset) == 0) {
+			      flags, hash, buffer->data, content_offset) == 0) {
 			return 0;
 		}
 		break;
@@ -662,6 +790,19 @@ int cbfs_export_entry(struct cbfs_image *image, const char *entry_name,
 	    entry_name, cbfs_get_entry_addr(image, entry),
 	    get_cbfs_entry_type_name(ntohl(entry->type)), ntohl(entry->len));
 
+	if (cbfs_read_hash_type(entry) != VB2_HASH_INVALID) {
+		switch (cbfs_check_hash(entry)) {
+		case 0: // match
+			LOG("File hash successfully verified\n");
+			break;
+		case 1: // mismatch
+			WARN("File hash mismatch (corrupt file?)\n");
+			break;
+		default: // error
+			WARN("Unable to verify file consistency; attempting to extract anyway\n");
+		}
+	}
+
 	if (ntohl(entry->type) != CBFS_COMPONENT_RAW) {
 		WARN("Only 'raw' files are safe to extract.\n");
 	}
@@ -682,25 +823,26 @@ int cbfs_export_entry(struct cbfs_image *image, const char *entry_name,
 
 int cbfs_remove_entry(struct cbfs_image *image, const char *name)
 {
-	struct cbfs_file *entry, *next;
-	size_t len;
-	entry = cbfs_get_entry(image, name);
+	struct cbfs_file *entry = cbfs_get_entry(image, name);
 	if (!entry) {
 		ERROR("CBFS file %s not found.\n", name);
 		return -1;
 	}
-	next = cbfs_find_next_entry(image, entry);
+	struct cbfs_file *next = cbfs_find_next_entry(image, entry);
 	assert(next);
+	ptrdiff_t len = (uintptr_t)next - (uintptr_t)entry -
+					cbfs_calculate_file_header_size("",
+				VB2_HASH_INVALID, cbfs_is_legacy_cbfs(image));
+	if (len < 0) {
+		// Not enough space to fit current generation empty header.
+		ERROR("Only the older version of cbfstool that created this image can remove that file\n");
+		return -1;
+	}
+	cbfs_create_empty_entry(entry, len, "", 0, VB2_HASH_INVALID,
+						cbfs_is_legacy_cbfs(image));
+	entry->type = htonl(CBFS_COMPONENT_DELETED);
 	DEBUG("cbfs_remove_entry: Removed %s @ 0x%x\n",
 	      CBFS_NAME(entry), cbfs_get_entry_addr(image, entry));
-	entry->type = htonl(CBFS_COMPONENT_DELETED);
-	len = (cbfs_get_entry_addr(image, next) -
-	       cbfs_get_entry_addr(image, entry));
-	entry->offset = htonl(cbfs_calculate_file_header_size(""));
-	entry->len = htonl(len - ntohl(entry->offset));
-	memset(CBFS_NAME(entry), 0, ntohl(entry->offset) - sizeof(*entry));
-	memset(CBFS_SUBHEADER(entry), CBFS_CONTENT_DEFAULT_VALUE,
-	       ntohl(entry->len));
 	return 0;
 }
 
@@ -799,10 +941,30 @@ int cbfs_print_entry_info(struct cbfs_image *image, struct cbfs_file *entry,
 	if (!fp)
 		fp = stdout;
 
-	fprintf(fp, "%-30s 0x%-8x %-12s %d\n",
+	char hash_status[20];
+	uint16_t type = cbfs_read_hash_type(entry);
+	const char *typename =
+		lookup_name_by_type(types_cbfs_hash, type, "unrecognized");
+	const char *status = "N/A";
+	if (type != VB2_HASH_INVALID) {
+		switch (cbfs_check_hash(entry)) {
+		case 0: // match
+			status = "verified";
+			break;
+		case 1: // mismatch
+			status = "MISMATCH";
+			break;
+		default: // error
+			status = "?!";
+		}
+	}
+	sprintf(hash_status, "%s (%s)", status, typename);
+
+	fprintf(fp, "%-30s 0x%-8x %-12s %-20s %d\n",
 		*name ? name : "(empty)",
 		cbfs_get_entry_addr(image, entry),
 		get_cbfs_entry_type_name(ntohl(entry->type)),
+		hash_status,
 		ntohl(entry->len));
 
 	if (!verbose)
@@ -844,7 +1006,8 @@ int cbfs_print_directory(struct cbfs_image *image)
 {
 	if (cbfs_is_legacy_cbfs(image))
 		cbfs_print_header_info(image);
-	printf("%-30s %-10s %-12s Size\n", "Name", "Offset", "Type");
+	printf("%-30s %-10s %-12s %-20s Size\n",
+					"Name", "Offset", "Type", "Hash");
 	cbfs_walk(image, cbfs_print_entry_info, NULL);
 	return 0;
 }
@@ -883,10 +1046,11 @@ int cbfs_merge_empty_entry(struct cbfs_image *image, struct cbfs_file *entry,
 		DEBUG("join_empty_entry: combine 0x%x+0x%x and 0x%x+0x%x.\n",
 		      cbfs_get_entry_addr(image, entry), ntohl(entry->len),
 		      cbfs_get_entry_addr(image, next), ntohl(next->len));
-		cbfs_create_empty_entry(entry,
-					(last_addr - addr -
-					 cbfs_calculate_file_header_size("")),
-					"");
+		cbfs_create_empty_entry(entry, (last_addr - addr -
+					 cbfs_calculate_file_header_size("",
+				VB2_HASH_INVALID, cbfs_is_legacy_cbfs(image))),
+							"", 0, VB2_HASH_INVALID,
+						cbfs_is_legacy_cbfs(image));
 		DEBUG("new empty entry: length=0x%x\n", ntohl(entry->len));
 		next = cbfs_find_next_entry(image, entry);
 	}
@@ -1016,16 +1180,32 @@ int cbfs_is_valid_entry(struct cbfs_image *image, struct cbfs_file *entry)
 						strlen(CBFS_FILE_MAGIC));
 }
 
-int cbfs_create_empty_entry(struct cbfs_file *entry,
-			    size_t len, const char *name)
+int cbfs_create_empty_entry(struct cbfs_file *entry, size_t len,
+			    const char *name, uint16_t flags,
+			    enum vb2_hash_algorithm hash, bool legacy)
 {
 	memset(entry, CBFS_CONTENT_DEFAULT_VALUE, sizeof(*entry));
 	memcpy(entry->magic, CBFS_FILE_MAGIC, sizeof(entry->magic));
 	entry->type = htonl(CBFS_COMPONENT_NULL);
 	entry->len = htonl(len);
-	entry->checksum = 0;  // TODO Build a checksum algorithm.
-	entry->offset = htonl(cbfs_calculate_file_header_size(name));
-	memset(CBFS_NAME(entry), 0, ntohl(entry->offset) - sizeof(*entry));
+	entry->offset = htonl(cbfs_calculate_file_header_size(name, hash,
+								legacy));
+	if (legacy) {
+		entry->version = 0;
+		entry->flags = 0;
+	} else {
+		entry->version = htons(CBFS_FILE_VERSION);
+		entry->flags = htons(flags);
+		entry->header_len =
+			htonl(cbfs_calculate_file_header_size_without_name(hash,
+									false));
+		entry->hash_type = htons(hash);
+		entry->hash_offset = htons(sizeof(*entry));
+		memset((uint8_t *)entry + sizeof(*entry), 0,
+				CBFS_HEADER_LEN(entry) - sizeof(*entry));
+	}
+	memset(CBFS_NAME(entry), 0,
+				ntohl(entry->offset) - CBFS_HEADER_LEN(entry));
 	strcpy(CBFS_NAME(entry), name);
 	memset(CBFS_SUBHEADER(entry), CBFS_CONTENT_DEFAULT_VALUE, len);
 	return 0;
@@ -1049,7 +1229,8 @@ static int is_in_range(uint32_t start, uint32_t end, uint32_t header_len,
 }
 
 int32_t cbfs_locate_entry(struct cbfs_image *image, const char *name,
-			  uint32_t size, uint32_t page_size, uint32_t align)
+			  uint32_t size, enum vb2_hash_algorithm hash,
+			  uint32_t page_size, uint32_t align)
 {
 	struct cbfs_file *entry;
 	size_t need_len;
@@ -1077,8 +1258,9 @@ int32_t cbfs_locate_entry(struct cbfs_image *image, const char *name,
 	 * (type) param in future. For right now, we assume cbfs_stage is the
 	 * largest structure and add it into header size. */
 	assert(sizeof(struct cbfs_stage) >= sizeof(struct cbfs_payload));
-	header_len = (cbfs_calculate_file_header_size(name) +
-		      sizeof(struct cbfs_stage));
+	header_len = (cbfs_calculate_file_header_size(name, hash,
+						cbfs_is_legacy_cbfs(image)) +
+						sizeof(struct cbfs_stage));
 	need_len = header_len + size;
 
 	// Merge empty entries to build get max available space.
diff --git a/util/cbfstool/cbfs_image.h b/util/cbfstool/cbfs_image.h
index 5df5dd2..cceffe2 100644
--- a/util/cbfstool/cbfs_image.h
+++ b/util/cbfstool/cbfs_image.h
@@ -19,6 +19,10 @@
 
 #ifndef __CBFS_IMAGE_H
 #define __CBFS_IMAGE_H
+
+#include <stddef.h>
+#include <vb2_api.h>
+
 #include "common.h"
 #include "cbfs.h"
 
@@ -32,6 +36,14 @@ struct cbfs_image {
 	struct cbfs_header header;
 };
 
+/* Given the string name of a compression algorithm, return the corresponding
+ * enum comp_algo if it's supported, or a number < 0 otherwise. */
+int cbfs_parse_comp_algo(const char *name);
+
+/* Given the string name of a hash algorithm, return the corresponding
+ * enum vb2_hash_algorithm if it's supported, or a number < 0 otherwise. */
+int cbfs_parse_hash_algo(const char *name);
+
 /* Given a pointer, serialize the header from host-native byte format
  * to cbfs format, i.e. big-endian. */
 void cbfs_put_header(void *dest, const struct cbfs_header *header);
@@ -89,22 +101,27 @@ int cbfs_export_entry(struct cbfs_image *image, const char *entry_name,
  * Never pass this function a top-aligned address: convert it to an offset.
  * Returns 0 on success, otherwise non-zero. */
 int cbfs_add_entry(struct cbfs_image *image, struct buffer *buffer,
-		   const char *name, uint32_t type, uint32_t content_offset);
+		   const char *name, uint32_t type, uint16_t flags,
+		   enum vb2_hash_algorithm hash, uint32_t content_offset);
 
 /* Removes an entry from CBFS image. Returns 0 on success, otherwise non-zero. */
 int cbfs_remove_entry(struct cbfs_image *image, const char *name);
 
 /* Initializes a new empty (type = NULL) entry with size and name in CBFS image.
+ * If a legacy entry is requested, it will be a version 0 header; otherwise, the
+ * most recently released revision will be chosen.
  * Returns 0 on success, otherwise (ex, not found) non-zero. */
-int cbfs_create_empty_entry(struct cbfs_file *entry,
-			    size_t len, const char *name);
+int cbfs_create_empty_entry(struct cbfs_file *entry, size_t len,
+			    const char *name, uint16_t flags,
+			    enum vb2_hash_algorithm hash, bool legacy);
 
 /* Finds a location to put given content by specified criteria:
  *  "page_size" limits the content to fit on same memory page, and
  *  "align" specifies starting address alignment.
  * Returns a valid offset, or -1 on failure. */
 int32_t cbfs_locate_entry(struct cbfs_image *image, const char *name,
-			  uint32_t size, uint32_t page_size, uint32_t align);
+			  uint32_t size, enum vb2_hash_algorithm hash,
+			  uint32_t page_size, uint32_t align);
 
 /* Callback function used by cbfs_walk.
  * Returns 0 on success, or non-zero to stop further iteration. */
diff --git a/util/cbfstool/cbfstool.c b/util/cbfstool/cbfstool.c
index 06d0cef..6a5e0d1 100644
--- a/util/cbfstool/cbfstool.c
+++ b/util/cbfstool/cbfstool.c
@@ -75,14 +75,16 @@ static struct param {
 	bool fill_partial_downward;
 	bool show_immutable;
 	int fit_empty_entries;
-	enum comp_algo algo;
+	enum comp_algo compression;
+	enum vb2_hash_algorithm hash;
 	/* for linux payloads */
 	char *initrd;
 	char *cmdline;
 } param = {
 	/* All variables not listed are initialized as zero. */
 	.arch = CBFS_ARCHITECTURE_UNKNOWN,
-	.algo = CBFS_COMPRESS_NONE,
+	.compression = CBFS_COMPRESS_NONE,
+	.hash = VB2_HASH_INVALID,
 	.headeroffset = ~0,
 	.region_name = SECTION_NAME_PRIMARY_CBFS,
 };
@@ -150,8 +152,8 @@ static int cbfs_add_integer_component(const char *name,
 		offset = convert_to_from_top_aligned(param.image_region,
 								-offset);
 
-	if (cbfs_add_entry(&image, &buffer, name, CBFS_COMPONENT_RAW, offset) !=
-									0) {
+	if (cbfs_add_entry(&image, &buffer, name, CBFS_COMPONENT_RAW, 0,
+						param.hash, offset) != 0) {
 		ERROR("Failed to add %llu into ROM image as '%s'.\n",
 					(long long unsigned)u64val, name);
 		goto done;
@@ -212,7 +214,8 @@ static int cbfs_add_component(const char *filename,
 		offset = convert_to_from_top_aligned(param.image_region,
 								-offset);
 
-	if (cbfs_add_entry(&image, &buffer, name, type, offset) != 0) {
+	if (cbfs_add_entry(&image, &buffer, name, type, 0, param.hash, offset)
+									!= 0) {
 		ERROR("Failed to add '%s' into ROM image.\n", filename);
 		buffer_delete(&buffer);
 		return 1;
@@ -225,10 +228,8 @@ static int cbfs_add_component(const char *filename,
 static int cbfstool_convert_mkstage(struct buffer *buffer, uint32_t *offset)
 {
 	struct buffer output;
-	int ret;
-	ret = parse_elf_to_stage(buffer, &output, param.algo, offset,
-							param.ignore_section);
-	if (ret != 0)
+	if (parse_elf_to_stage(buffer, &output, param.compression, offset,
+			       param.ignore_section) != 0)
 		return -1;
 	buffer_delete(buffer);
 	// direct assign, no dupe.
@@ -242,16 +243,16 @@ static int cbfstool_convert_mkpayload(struct buffer *buffer,
 	struct buffer output;
 	int ret;
 	/* per default, try and see if payload is an ELF binary */
-	ret = parse_elf_to_payload(buffer, &output, param.algo);
+	ret = parse_elf_to_payload(buffer, &output, param.compression);
 
 	/* If it's not an ELF, see if it's a UEFI FV */
 	if (ret != 0)
-		ret = parse_fv_to_payload(buffer, &output, param.algo);
+		ret = parse_fv_to_payload(buffer, &output, param.compression);
 
 	/* If it's neither ELF nor UEFI Fv, try bzImage */
 	if (ret != 0)
 		ret = parse_bzImage_to_payload(buffer, &output,
-				param.initrd, param.cmdline, param.algo);
+				param.initrd, param.cmdline, param.compression);
 
 	/* Not a supported payload type */
 	if (ret != 0) {
@@ -273,7 +274,7 @@ static int cbfstool_convert_mkflatpayload(struct buffer *buffer,
 	if (parse_flat_binary_to_payload(buffer, &output,
 					 param.loadaddress,
 					 param.entrypoint,
-					 param.algo) != 0) {
+					 param.compression) != 0) {
 		return -1;
 	}
 	buffer_delete(buffer);
@@ -474,7 +475,7 @@ static int cbfs_locate(void)
 	}
 
 	int32_t address = cbfs_locate_entry(&image, param.name, buffer.size,
-				    param.pagesize, param.alignment);
+			    param.hash, param.pagesize, param.alignment);
 	buffer_delete(&buffer);
 
 	if (address == -1) {
@@ -736,16 +737,17 @@ static bool cbfs_is_legacy_format(struct buffer *buffer)
 }
 
 static const struct command commands[] = {
-	{"add", "H:r:f:n:t:b:vh?", cbfs_add, true, true},
-	{"add-flat-binary", "H:r:f:n:l:e:c:b:vh?", cbfs_add_flat_binary, true,
+	{"add", "H:r:f:n:t:A:b:vh?", cbfs_add, true, true},
+	{"add-flat-binary", "H:r:f:n:l:e:A:c:b:vh?", cbfs_add_flat_binary, true,
 									true},
-	{"add-payload", "H:r:f:n:t:c:b:C:I:vh?", cbfs_add_payload, true, true},
-	{"add-stage", "H:r:f:n:t:c:b:S:vh?", cbfs_add_stage, true, true},
-	{"add-int", "H:r:i:n:b:vh?", cbfs_add_integer, true, true},
+	{"add-payload", "H:r:f:n:t:A:c:b:C:I:vh?", cbfs_add_payload, true,
+									true},
+	{"add-stage", "H:r:f:n:t:A:c:b:S:vh?", cbfs_add_stage, true, true},
+	{"add-int", "H:r:i:n:A:b:vh?", cbfs_add_integer, true, true},
 	{"copy", "H:D:s:h?", cbfs_copy, true, true},
 	{"create", "M:r:s:B:b:H:a:o:m:vh?", cbfs_create, true, true},
 	{"extract", "H:r:n:f:vh?", cbfs_extract, true, false},
-	{"locate", "H:r:f:n:P:a:Tvh?", cbfs_locate, true, false},
+	{"locate", "H:r:f:n:A:P:a:Tvh?", cbfs_locate, true, false},
 	{"layout", "wvh?", cbfs_layout, false, false},
 	{"print", "H:r:vh?", cbfs_print, true, false},
 	{"read", "r:f:vh?", cbfs_read, true, false},
@@ -755,35 +757,36 @@ static const struct command commands[] = {
 };
 
 static struct option long_options[] = {
-	{"alignment",     required_argument, 0, 'a' },
-	{"base-address",  required_argument, 0, 'b' },
-	{"bootblock",     required_argument, 0, 'B' },
-	{"cmdline",       required_argument, 0, 'C' },
-	{"compression",   required_argument, 0, 'c' },
-	{"copy-offset",   required_argument, 0, 'D' },
-	{"empty-fits",    required_argument, 0, 'x' },
-	{"entry-point",   required_argument, 0, 'e' },
-	{"file",          required_argument, 0, 'f' },
-	{"fill-downward", no_argument,       0, 'd' },
-	{"fill-upward",   no_argument,       0, 'u' },
-	{"flashmap",      required_argument, 0, 'M' },
-	{"fmap-regions",  required_argument, 0, 'r' },
-	{"header-offset", required_argument, 0, 'H' },
-	{"help",          no_argument,       0, 'h' },
-	{"ignore-sec",    required_argument, 0, 'S' },
-	{"initrd",        required_argument, 0, 'I' },
-	{"int",           required_argument, 0, 'i' },
-	{"load-address",  required_argument, 0, 'l' },
-	{"machine",       required_argument, 0, 'm' },
-	{"name",          required_argument, 0, 'n' },
-	{"offset",        required_argument, 0, 'o' },
-	{"page-size",     required_argument, 0, 'P' },
-	{"size",          required_argument, 0, 's' },
-	{"top-aligned",   required_argument, 0, 'T' },
-	{"type",          required_argument, 0, 't' },
-	{"verbose",       no_argument,       0, 'v' },
-	{"with-readonly", no_argument,       0, 'w' },
-	{NULL,            0,                 0,  0  }
+	{"alignment",     required_argument,  0, 'a' },
+	{"base-address",  required_argument,  0, 'b' },
+	{"bootblock",     required_argument,  0, 'B' },
+	{"cmdline",       required_argument,  0, 'C' },
+	{"compression",   required_argument,  0, 'c' },
+	{"copy-offset",   required_argument,  0, 'D' },
+	{"empty-fits",    required_argument,  0, 'x' },
+	{"entry-point",   required_argument,  0, 'e' },
+	{"file",          required_argument,  0, 'f' },
+	{"fill-downward", no_argument,        0, 'd' },
+	{"fill-upward",   no_argument,        0, 'u' },
+	{"flashmap",      required_argument,  0, 'M' },
+	{"fmap-regions",  required_argument,  0, 'r' },
+	{"hash-algorithm", required_argument, 0, 'A' },
+	{"header-offset", required_argument,  0, 'H' },
+	{"help",          no_argument,        0, 'h' },
+	{"ignore-sec",    required_argument,  0, 'S' },
+	{"initrd",        required_argument,  0, 'I' },
+	{"int",           required_argument,  0, 'i' },
+	{"load-address",  required_argument,  0, 'l' },
+	{"machine",       required_argument,  0, 'm' },
+	{"name",          required_argument,  0, 'n' },
+	{"offset",        required_argument,  0, 'o' },
+	{"page-size",     required_argument,  0, 'P' },
+	{"size",          required_argument,  0, 's' },
+	{"top-aligned",   required_argument,  0, 'T' },
+	{"type",          required_argument,  0, 't' },
+	{"verbose",       no_argument,        0, 'v' },
+	{"with-readonly", no_argument,        0, 'w' },
+	{NULL,            0,                  0,  0  }
 };
 
 static int dispatch_command(struct command command)
@@ -850,19 +853,19 @@ static void usage(char *name)
 	     "  -v               Provide verbose output\n"
 	     "  -h               Display this help message\n\n"
 	     "COMMANDs:\n"
-	     " add [-r image,regions] -f FILE -n NAME -t TYPE \\\n"
+	     " add [-r image,regions] -f FILE -n NAME -t TYPE [-A hash] \\\n"
 	     "        [-b base-address]                                    "
 			"Add a component\n"
-	     " add-payload [-r image,regions] -f FILE -n NAME \\\n"
+	     " add-payload [-r image,regions] -f FILE -n NAME [-A hash] \\\n"
 	     "        [-c compression] [-b base-address]                   "
 			"Add a payload to the ROM\n"
 	     "        (linux specific: [-C cmdline] [-I initrd])\n"
-	     " add-stage [-r image,regions] -f FILE -n NAME \\\n"
+	     " add-stage [-r image,regions] -f FILE -n NAME [-A hash] \\\n"
 	     "        [-c compression] [-b base] [-S section-to-ignore]    "
 			"Add a stage to the ROM\n"
 	     " add-flat-binary [-r image,regions] -f FILE -n NAME \\\n"
-	     "        -l load-address -e entry-point [-c compression] \\\n"
-	     "        [-b base]                                            "
+	     "        -l load-address -e entry-point [-A hash] \\\n"
+	     "        [-c compression] [-b base]                           "
 			"Add a 32bit flat mode binary\n"
 	     " add-int [-r image,regions] -i INTEGER -n NAME [-b base]     "
 			"Add a raw 64-bit integer value\n"
@@ -877,8 +880,8 @@ static void usage(char *name)
 			"Create a legacy ROM file with CBFS master header*\n"
 	     " create -M flashmap [-r list,of,regions,containing,cbfses]   "
 			"Create a new-style partitioned firmware image\n"
-	     " locate [-r image,regions] -f FILE -n NAME [-P page-size] \\\n"
-	     "        [-a align] [-T]                                      "
+	     " locate [-r image,regions] -f FILE -n NAME [-A hash] \\\n"
+	     "        [-P page-size] [-a align] [-T]                       "
 			"Find a place for a file of that size\n"
 	     " layout [-w]                                                 "
 			"List mutable (or, with -w, readable) image regions\n"
@@ -974,15 +977,24 @@ int main(int argc, char **argv)
 					WARN("Unknown type '%s' ignored\n",
 							optarg);
 				break;
-			case 'c':
-				if (!strncasecmp(optarg, "lzma", 5))
-					param.algo = CBFS_COMPRESS_LZMA;
-				else if (!strncasecmp(optarg, "none", 5))
-					param.algo = CBFS_COMPRESS_NONE;
+			case 'c': {
+				int algo = cbfs_parse_comp_algo(optarg);
+				if (algo >= 0)
+					param.compression = algo;
 				else
-					WARN("Unknown compression '%s'"
-					     " ignored.\n", optarg);
+					WARN("Unknown compression '%s' ignored.\n",
+									optarg);
 				break;
+			}
+			case 'A': {
+				int algo = cbfs_parse_hash_algo(optarg);
+				if (algo >= 0)
+					param.hash = algo;
+				else
+					WARN("Unknown hashing scheme '%s' ignored.\n",
+									optarg);
+				break;
+			}
 			case 'M':
 				param.fmap = optarg;
 				break;
diff --git a/util/cbfstool/common.c b/util/cbfstool/common.c
index fffd096..48012a0 100644
--- a/util/cbfstool/common.c
+++ b/util/cbfstool/common.c
@@ -19,6 +19,7 @@
  * Foundation, Inc.
  */
 
+#include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -26,6 +27,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#include <vb2_api.h>
 #include <libgen.h>
 #include "common.h"
 #include "cbfs.h"
@@ -128,11 +130,23 @@ void buffer_delete(struct buffer *buffer)
 
 void cbfs_file_get_header(struct buffer *buf, struct cbfs_file *file)
 {
+	// Fields that were present from the "zeroth" revision
 	bgets(buf, &file->magic, sizeof(file->magic));
 	file->len = xdr_be.get32(buf);
 	file->type = xdr_be.get32(buf);
-	file->checksum = xdr_be.get32(buf);
+	file->version = xdr_be.get16(buf);
+	file->flags = xdr_be.get16(buf);
 	file->offset = xdr_be.get32(buf);
+
+	// Fields that were added in subsequent header versions
+	file->header_len = CBFS_FILE_V0_LEN;
+	file->hash_type = VB2_HASH_INVALID;
+	file->hash_offset = 0;
+	if (file->version >= 1) {
+		file->header_len = xdr_be.get32(buf);
+		file->hash_type = xdr_be.get16(buf);
+		file->hash_offset = xdr_be.get16(buf);
+	}
 }
 
 static struct {
@@ -149,7 +163,7 @@ static struct {
 
 uint32_t string_to_arch(const char *arch_string)
 {
-	int i;
+	unsigned i;
 	uint32_t ret = CBFS_ARCHITECTURE_UNKNOWN;
 
 	for (i = 0; i < ARRAY_SIZE(arch_names); i++) {
@@ -164,7 +178,7 @@ uint32_t string_to_arch(const char *arch_string)
 
 const char *arch_to_string(uint32_t a)
 {
-	int i;
+	unsigned i;
 	const char *ret = NULL;
 
 	for (i = 0; i < ARRAY_SIZE(arch_names); i++) {
diff --git a/util/cbfstool/common.h b/util/cbfstool/common.h
index 06ee00b..17844b2 100644
--- a/util/cbfstool/common.h
+++ b/util/cbfstool/common.h
@@ -28,15 +28,6 @@
 
 /* Endianess */
 #include "swab.h"
-#if !defined(__APPLE__) && !defined(__NetBSD__)
-#define ntohl(x)	(is_big_endian() ? (uint32_t)(x) : swab32(x))
-#define htonl(x)	(is_big_endian() ? (uint32_t)(x) : swab32(x))
-#elif defined(__NetBSD__)
-#include <arpa/inet.h>
-#endif
-#define ntohll(x)	(is_big_endian() ? (uint64_t)(x) : swab64(x))
-#define htonll(x)	(is_big_endian() ? (uint64_t)(x) : swab64(x))
-int is_big_endian(void);
 
 /* Message output */
 extern int verbose;
@@ -47,7 +38,9 @@ extern int verbose;
 #define DEBUG(...) { if (verbose > 1) fprintf(stderr, "DEBUG: " __VA_ARGS__); }
 
 /* Helpers */
+#ifndef ARRAY_SIZE
 #define ARRAY_SIZE(a) (int)(sizeof(a) / sizeof((a)[0]))
+#endif
 #define ALIGN(val, by) (((val) + (by)-1)&~((by)-1))
 #define MAX(x, y) ((x) > (y) ? (x) : (y))
 #define MIN(x, y) ((x) < (y) ? (x) : (y))
@@ -159,6 +152,8 @@ typedef int (*comp_func_ptr) (char *, int, char *, int *);
 enum comp_algo { CBFS_COMPRESS_NONE = 0, CBFS_COMPRESS_LZMA = 1 };
 
 comp_func_ptr compression_function(enum comp_algo algo);
+typedef uint8_t *(*hash_func_ptr)(const uint8_t *, uint64_t, uint8_t *);
+
 
 uint64_t intfiletype(const char *name);
 
diff --git a/util/cbfstool/swab.h b/util/cbfstool/swab.h
index c5e4370..22ae8b4 100644
--- a/util/cbfstool/swab.h
+++ b/util/cbfstool/swab.h
@@ -15,6 +15,15 @@
  *
  */
 
+#if !defined(__APPLE__) && !defined(__NetBSD__)
+#define ntohl(x)	(is_big_endian() ? (uint32_t)(x) : swab32(x))
+#define htonl(x)	(is_big_endian() ? (uint32_t)(x) : swab32(x))
+#elif defined(__NetBSD__)
+#include <arpa/inet.h>
+#endif
+#define ntohll(x)	(is_big_endian() ? (uint64_t)(x) : swab64(x))
+#define htonll(x)	(is_big_endian() ? (uint64_t)(x) : swab64(x))
+
 /* casts are necessary for constants, because we never know how for sure
  * how U/UL/ULL map to __u16, __u32, __u64. At least not in a portable way.
  */
@@ -41,4 +50,7 @@
 		(((uint64_t)(x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \
 		(((uint64_t)(x) & (uint64_t)0xff00000000000000ULL) >> 56) ))
 
+/* common.c */
+int is_big_endian(void);
+
 #endif /* _SWAB_H */



More information about the coreboot-gerrit mailing list