[coreboot-gerrit] Patch set updated for coreboot: cbfstool: Add support for hashes as file metadata

Patrick Georgi (pgeorgi@google.com) gerrit at coreboot.org
Thu Oct 1 14:00:24 CET 2015


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

-gerrit

commit 710e50a05d6eb7da73510a9dca73c6b7321f213b
Author: Patrick Georgi <patrick at georgi-clan.de>
Date:   Thu Oct 1 15:54:04 2015 +0200

    cbfstool: Add support for hashes as file metadata
    
    They allow optimizing a verification of a whole CBFS image by only
    dealing with the headers (assuming you choose to trust the hash
    algorithm(s)).
    
    The format allows for multiple hashes for a single file, and cbfstool
    can handle them, but right now it can't generate such headers.
    
    Loosely based on Sol's work in http://review.coreboot.org/#/c/10147/,
    but using the compatible file attribute format. vboot is now a hard
    dependency of the build process, but we import it into the tree for
    quite a while now.
    
    Change-Id: I9f14f30537d676ce209ad612e7327c6f4810b313
    Signed-off-by: Patrick Georgi <patrick at georgi-clan.de>
---
 util/cbfstool/Makefile.inc | 15 +++++++++
 util/cbfstool/cbfs.h       | 29 +++++++++++++++++
 util/cbfstool/cbfs_image.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++
 util/cbfstool/cbfs_image.h | 10 ++++++
 util/cbfstool/cbfstool.c   | 38 +++++++++++++++++-----
 5 files changed, 163 insertions(+), 8 deletions(-)

diff --git a/util/cbfstool/Makefile.inc b/util/cbfstool/Makefile.inc
index a1dbfc3..4994757 100644
--- a/util/cbfstool/Makefile.inc
+++ b/util/cbfstool/Makefile.inc
@@ -15,6 +15,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
@@ -51,6 +56,9 @@ TOOLCPPFLAGS += -I$(top)/util/cbfstool/flashmap
 TOOLCPPFLAGS += -I$(top)/util/cbfstool
 TOOLCPPFLAGS += -I$(objutil)/cbfstool
 TOOLCPPFLAGS += -I$(top)/src/commonlib/include
+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)
@@ -77,6 +85,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))
@@ -97,6 +109,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 579afa6..627a2b8 100644
--- a/util/cbfstool/cbfs.h
+++ b/util/cbfstool/cbfs.h
@@ -21,6 +21,8 @@
 
 #include <stdint.h>
 
+#include <vb2_api.h>
+
 /* cbfstool will fail when trying to build a cbfs_file header that's larger
  * than MAX_CBFS_FILE_HEADER_BUFFER. 1K should give plenty of room. */
 #define MAX_CBFS_FILE_HEADER_BUFFER 1024
@@ -107,6 +109,7 @@ struct cbfs_file_attribute {
 #define CBFS_FILE_ATTR_TAG_UNUSED 0
 #define CBFS_FILE_ATTR_TAG_UNUSED2 0xffffffff
 #define CBFS_FILE_ATTR_TAG_COMPRESSION 0x42435a4c
+#define CBFS_FILE_ATTR_TAG_HASH 0x68736148
 
 struct cbfs_file_attr_compression {
 	uint32_t tag;
@@ -116,6 +119,14 @@ struct cbfs_file_attr_compression {
 	uint32_t decompressed_size;
 } __PACKED;
 
+struct cbfs_file_attr_hash {
+	uint32_t tag;
+	uint32_t len;
+	uint32_t hash_type;
+	/* hash_data is len - sizeof(struct) bytes */
+	uint8_t  hash_data[];
+} __PACKED;
+
 struct cbfs_stage {
 	uint32_t compression;
 	uint64_t entry;
@@ -203,6 +214,24 @@ static struct typedesc_t filetypes[] unused = {
 	{CBFS_COMPONENT_NULL, "null"}
 };
 
+static const struct typedesc_t types_cbfs_hash[] unused = {
+	{VB2_HASH_INVALID, "none"},
+	{VB2_HASH_SHA1, "sha1"},
+	{VB2_HASH_SHA256, "sha256"},
+	{VB2_HASH_SHA512, "sha512"},
+	{0, NULL}
+};
+
+static size_t widths_cbfs_hash[] unused = {
+	[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)))
+
 #define CBFS_SUBHEADER(_p) ( (void *) ((((uint8_t *) (_p)) + ntohl((_p)->offset))) )
 
 /* cbfs_image.c */
diff --git a/util/cbfstool/cbfs_image.c b/util/cbfstool/cbfs_image.c
index 24ab0c4..fa67fc7 100644
--- a/util/cbfstool/cbfs_image.c
+++ b/util/cbfstool/cbfs_image.c
@@ -85,6 +85,16 @@ int cbfs_parse_comp_algo(const char *name)
 	return lookup_type_by_name(types_cbfs_compression, name);
 }
 
+static const char *get_hash_attr_name(uint16_t hash_type)
+{
+	return lookup_name_by_type(types_cbfs_hash, hash_type, "(invalid)");
+}
+
+int cbfs_parse_hash_algo(const char *name)
+{
+	return lookup_type_by_name(types_cbfs_hash, name);
+}
+
 /* CBFS image */
 
 size_t cbfs_calculate_file_header_size(const char *name)
@@ -173,6 +183,24 @@ static int cbfs_file_get_compression_info(struct cbfs_file *entry,
 	return compression;
 }
 
+static struct cbfs_file_attr_hash *cbfs_file_get_next_hash(
+	struct cbfs_file *entry, struct cbfs_file_attr_hash *cur)
+{
+	struct cbfs_file_attribute *attr = (struct cbfs_file_attribute *)cur;
+	if (attr == NULL) {
+		attr = cbfs_file_first_attr(entry);
+		if (attr == NULL)
+			return NULL;
+		if (ntohl(attr->tag) == CBFS_FILE_ATTR_TAG_HASH)
+			return (struct cbfs_file_attr_hash *)attr;
+	}
+	while ((attr = cbfs_file_next_attr(entry, attr)) != NULL) {
+		if (ntohl(attr->tag) == CBFS_FILE_ATTR_TAG_HASH)
+			return (struct cbfs_file_attr_hash *)attr;
+	};
+	return NULL;
+}
+
 void cbfs_get_header(struct cbfs_header *header, void *src)
 {
 	struct buffer outheader;
@@ -813,6 +841,31 @@ int cbfs_print_entry_info(struct cbfs_image *image, struct cbfs_file *entry,
 			);
 	}
 
+	struct cbfs_file_attr_hash *hash = NULL;
+	while ((hash = cbfs_file_get_next_hash(entry, hash)) != NULL) {
+		unsigned int hash_type = ntohl(hash->hash_type);
+		if (hash_type > CBFS_NUM_SUPPORTED_HASHES) {
+			fprintf(fp, "invalid hash type %d\n", hash_type);
+			break;
+		}
+		size_t hash_len = widths_cbfs_hash[hash_type];
+		char *hash_str = bintohex(hash->hash_data, hash_len);
+		uint8_t local_hash[hash_len];
+		if (vb2_digest_buffer(CBFS_SUBHEADER(entry),
+			ntohl(entry->len), hash_type, &local_hash,
+			hash_len) != VB2_SUCCESS) {
+			fprintf(fp, "failed to hash '%s'\n", name);
+			break;
+		}
+		int valid = memcmp(local_hash, hash->hash_data, hash_len) == 0;
+		const char *valid_str = valid?"valid":"invalid";
+
+		fprintf(fp, "    hash %s:%s %s\n",
+			get_hash_attr_name(hash_type),
+			hash_str, valid_str);
+		free(hash_str);
+	}
+
 	if (!verbose)
 		return 0;
 
@@ -1129,6 +1182,32 @@ struct cbfs_file_attribute *cbfs_add_file_attr(struct cbfs_file *header,
 	return attr;
 }
 
+int cbfs_add_file_hash(struct cbfs_file *header, struct buffer *buffer,
+	enum vb2_hash_algorithm hash_type)
+{
+	if (hash_type >= CBFS_NUM_SUPPORTED_HASHES)
+		return -1;
+
+	unsigned hash_size = widths_cbfs_hash[hash_type];
+	if (hash_size == 0)
+		return -1;
+
+	struct cbfs_file_attr_hash *attrs =
+		(struct cbfs_file_attr_hash *)cbfs_add_file_attr(header,
+			CBFS_FILE_ATTR_TAG_HASH,
+			sizeof(struct cbfs_file_attr_hash) + hash_size);
+
+	if (attrs == NULL)
+		return -1;
+
+	attrs->hash_type = htonl(hash_type);
+	if (vb2_digest_buffer((void *)buffer->data, buffer->size, hash_type,
+		attrs->hash_data, hash_size) != VB2_SUCCESS)
+		return -1;
+
+	return 0;
+}
+
 /* Finds a place to hold whole data in same memory page. */
 static int is_in_same_page(uint32_t start, uint32_t size, uint32_t page)
 {
diff --git a/util/cbfstool/cbfs_image.h b/util/cbfstool/cbfs_image.h
index baceb51..f602976 100644
--- a/util/cbfstool/cbfs_image.h
+++ b/util/cbfstool/cbfs_image.h
@@ -36,6 +36,10 @@ struct cbfs_image {
  * 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
+ * id 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);
@@ -184,4 +188,10 @@ struct cbfs_file_attribute *cbfs_file_next_attr(struct cbfs_file *file,
 struct cbfs_file_attribute *cbfs_add_file_attr(struct cbfs_file *header,
 					       uint32_t tag,
 					       uint32_t size);
+
+/* Adds an extended attribute to header, containing a hash of buffer's data of
+ * the type specified by hash_type.
+ * Returns 0 on success, -1 on error. */
+int cbfs_add_file_hash(struct cbfs_file *header, struct buffer *buffer,
+	enum vb2_hash_algorithm hash_type);
 #endif
diff --git a/util/cbfstool/cbfstool.c b/util/cbfstool/cbfstool.c
index 35747d3..2876702 100644
--- a/util/cbfstool/cbfstool.c
+++ b/util/cbfstool/cbfstool.c
@@ -76,6 +76,7 @@ static struct param {
 	bool stage_xip;
 	int fit_empty_entries;
 	enum comp_algo compression;
+	enum vb2_hash_algorithm hash;
 	/* for linux payloads */
 	char *initrd;
 	char *cmdline;
@@ -83,6 +84,7 @@ static struct param {
 	/* All variables not listed are initialized as zero. */
 	.arch = CBFS_ARCHITECTURE_UNKNOWN,
 	.compression = CBFS_COMPRESS_NONE,
+	.hash = VB2_HASH_INVALID,
 	.headeroffset = ~0,
 	.region_name = SECTION_NAME_PRIMARY_CBFS,
 };
@@ -327,6 +329,14 @@ static int cbfs_add_component(const char *filename,
 		return 1;
 	}
 
+	if (param.hash != VB2_HASH_INVALID)
+		if (cbfs_add_file_hash(header, &buffer, param.hash) == -1) {
+			ERROR("couldn't add hash for '%s'\n", name);
+			free(header);
+			buffer_delete(&buffer);
+			return 1;
+		}
+
 	if (IS_TOP_ALIGNED_ADDRESS(offset))
 		offset = convert_to_from_top_aligned(param.image_region,
 								-offset);
@@ -882,11 +892,11 @@ static int cbfs_copy(void)
 }
 
 static const struct command commands[] = {
-	{"add", "H:r:f:n:t:c:b:a: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:c:b:a:vA:h?", cbfs_add, true, true},
+	{"add-flat-binary", "H:r:f:n:l:e:c:b:vA:h?", 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", "a:H:r:f:n:t:c:b:P:S:yvh?", cbfs_add_stage, true, true},
+	{"add-payload", "H:r:f:n:t:c:b:C:I:vA:h?", cbfs_add_payload, true, true},
+	{"add-stage", "a:H:r:f:n:t:c:b:P:S:yvA:h?", cbfs_add_stage, true, true},
 	{"add-int", "H:r:i:n:b:vh?", cbfs_add_integer, true, true},
 	{"add-master-header", "H:r:vh?", cbfs_add_master_header, true, true},
 	{"copy", "H:D:s:h?", cbfs_copy, true, true},
@@ -914,6 +924,7 @@ static struct option long_options[] = {
 	{"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' },
@@ -997,18 +1008,18 @@ 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"
 	     "        [-c compression] [-b base-address | -a alignment]    "
 			"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]    "
 	     "        [-a alignment] [-y|--xip] [-P page-size]"
 			"Add a stage to the ROM\n"
-	     " add-flat-binary [-r image,regions] -f FILE -n NAME \\\n"
+	     " add-flat-binary [-r image,regions] -f FILE -n NAME [-A hash] \\\n"
 	     "        -l load-address -e entry-point [-c compression] \\\n"
 	     "        [-b base]                                            "
 			"Add a 32bit flat mode binary\n"
@@ -1132,6 +1143,17 @@ int main(int argc, char **argv)
 									optarg);
 				break;
 			}
+			case 'A': {
+				int algo = cbfs_parse_hash_algo(optarg);
+				if (algo >= 0)
+					param.hash = algo;
+				else {
+					ERROR("Unknown hash algorithm '%s'.\n",
+						optarg);
+					return 1;
+				}
+				break;
+			}
 			case 'M':
 				param.fmap = optarg;
 				break;



More information about the coreboot-gerrit mailing list