summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Boichat <drinkcat@chromium.org>2017-08-15 15:53:30 +0800
committerchrome-bot <chrome-bot@chromium.org>2017-09-15 03:08:26 -0700
commit94279fc38fae533e86425102082e0c681d98d259 (patch)
tree2012cd0153497e193fa417d2ce71941b0264a408
parente18d9dd5300d5e1693ec3d4c72dd105efcff4393 (diff)
downloadchrome-ec-94279fc38fae533e86425102082e0c681d98d259.tar.gz
Makefile: Generate hashes for the touchpad FW
Based on the passed TOUCHPAD_FW parameter to the make command, the build system generates hashes for the touchpad FW. To generate the hashes, gen_touchpad_hash splits the touchpad FW in blocks of CONFIG_UPDATE_PDU_SIZE, that are hashed individually (SHA-256), and then stored in the EC image. This will allow the USB updater code to verify the integrity of the touchpad firmware being flashed. When no FW is provided, zeros are output, which do not match any valid data. BRANCH=none BUG=b:63993173 TEST=make TOUCHPAD_FW=SA459C-1211_ForGoogleHammer_3.0.bin \ BOARD=hammer -j TEST=Using variations of make TOUCHPAD_FW=SA459C-1211_ForGoogleHammer_3.0.bin \ BOARD=hammer -j make TOUCHPAD_FW=SA459C-1211_ForGoogleHammer_4.0.bin \ BOARD=hammer -j make BOARD=hammer -j Check that TPHASH touchpad_fw_hash.h is only regenerated when the parameter changes. Change-Id: Ie347270aa9c00342de13489c9422e45e681b94c2 Signed-off-by: Nicolas Boichat <drinkcat@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/615321 Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r--Makefile4
-rw-r--r--Makefile.rules3
-rw-r--r--common/build.mk22
-rw-r--r--common/update_fw.c11
-rw-r--r--include/config.h6
-rw-r--r--util/build.mk13
-rw-r--r--util/gen_touchpad_hash.c161
7 files changed, 220 insertions, 0 deletions
diff --git a/Makefile b/Makefile
index 92fd15a12f..feb72fcfed 100644
--- a/Makefile
+++ b/Makefile
@@ -36,6 +36,10 @@ config=$(out)/.config
# If no key file is provided, use the default dev key
PEM ?= $(BDIR)/dev_key.pem
+# If CONFIG_TOUCHPAD_HASH_FW is set, include hashes of a touchpad firmware in
+# the EC image (if no touchpad firmware is provided, just output blank hashes).
+TOUCHPAD_FW ?=
+
include Makefile.toolchain
# Define the traditional first target. The dependencies of this are near the
diff --git a/Makefile.rules b/Makefile.rules
index d589556558..0544d29d07 100644
--- a/Makefile.rules
+++ b/Makefile.rules
@@ -100,6 +100,9 @@ cmd_c_to_taskinfo = $(BUILDCC) \
cmd_link_taskinfo = $(BUILDCC) $(BUILD_CFLAGS) --shared -fPIC $^ \
$(BUILD_LDFLAGS) -flto -o $@
+cmd_tp_hash = $(out)/util/gen_touchpad_hash \
+ $(if $(TOUCHPAD_FW),-f $(TOUCHPAD_FW)) -o $@
+
# commands for RSA signature: rwsig does not need to sign the whole image
# (it signs the RW part separately). usbpd1 type needs to sign the final image.
ifeq ($(CONFIG_RWSIG_TYPE_RWSIG),)
diff --git a/common/build.mk b/common/build.mk
index 0e0b8ff66e..f775fee0da 100644
--- a/common/build.mk
+++ b/common/build.mk
@@ -148,3 +148,25 @@ ifneq ($(CONFIG_RSA_OPTIMIZED),)
$(out)/RW/common/rsa.o: CFLAGS+=-O3
$(out)/RO/common/rsa.o: CFLAGS+=-O3
endif
+
+ifneq ($(CONFIG_TOUCHPAD_HASH_FW),)
+$(out)/RO/common/update_fw.o: $(out)/touchpad_fw_hash.h
+$(out)/RW/common/update_fw.o: $(out)/touchpad_fw_hash.h
+
+$(out)/touchpad_fw_hash.h: $(out)/util/gen_touchpad_hash $(out)/.touchpad_fw
+ $(call quiet,tp_hash,TPHASH )
+
+# We only want to recompute the hash if: $(TOUCHPAD_FW) variable value has
+# changed, or the file pointed at by $(TOUCHPAD_FW) has changed. We do this
+# by recording the latest $(TOUCHPAD_FW) file information in .touchpad_fw.
+
+touchpad_fw_ls := $(shell ls -l "$(TOUCHPAD_FW)" 2>&1)
+old_touchpad_fw_ls := $(shell cat $(out)/.touchpad_fw 2>/dev/null)
+
+$(out)/.touchpad_fw: $(TOUCHPAD_FW)
+ @echo "$(touchpad_fw_ls)" > $@
+
+ifneq ($(touchpad_fw_ls),$(old_touchpad_fw_ls))
+.PHONY: $(out)/.touchpad_fw
+endif
+endif
diff --git a/common/update_fw.c b/common/update_fw.c
index 93206f4066..b7128583fe 100644
--- a/common/update_fw.c
+++ b/common/update_fw.c
@@ -18,6 +18,17 @@
#include "util.h"
#include "vb21_struct.h"
+#if defined(CONFIG_TOUCHPAD_VIRTUAL_OFF) && defined(CONFIG_TOUCHPAD_HASH_FW)
+#define CONFIG_TOUCHPAD_FW_CHUNKS \
+ (CONFIG_TOUCHPAD_VIRTUAL_SIZE / CONFIG_UPDATE_PDU_SIZE)
+
+#include "touchpad_fw_hash.h"
+
+BUILD_ASSERT(sizeof(touchpad_fw_hashes) ==
+ (CONFIG_TOUCHPAD_FW_CHUNKS * SHA256_DIGEST_SIZE));
+BUILD_ASSERT(sizeof(touchpad_fw_hashes[0]) == SHA256_DIGEST_SIZE);
+#endif
+
#define CPRINTF(format, args...) cprintf(CC_USB, format, ## args)
/* Section to be updated (i.e. not the current section). */
diff --git a/include/config.h b/include/config.h
index 1cea53e9f3..2d44770823 100644
--- a/include/config.h
+++ b/include/config.h
@@ -2347,6 +2347,12 @@
#undef CONFIG_TOUCHPAD_VIRTUAL_OFF
#undef CONFIG_TOUCHPAD_VIRTUAL_SIZE
+/*
+ * Include hashes of the touchpad FW in the EC image, passed as TOUCHPAD_FW
+ * parameter to make command.
+ */
+#undef CONFIG_TOUCHPAD_HASH_FW
+
/*****************************************************************************/
/* TPM-like configuration */
diff --git a/util/build.mk b/util/build.mk
index 2ae0e1c25f..c7a3b5b522 100644
--- a/util/build.mk
+++ b/util/build.mk
@@ -39,6 +39,19 @@ $(out)/util/usb_pd_policy.o: board/$(BOARD)/usb_pd_policy.c
deps-$(CONFIG_USB_POWER_DELIVERY) += $(out)/util/usb_pd_policy.o.d
endif # CONFIG_USB_POWER_DELIVERY
+ifneq ($(CONFIG_TOUCHPAD_HASH_FW),)
+build-util-bin += gen_touchpad_hash
+
+# Assume RW section (touchpad FW must be identical for both RO+RW)
+$(out)/util/gen_touchpad_hash: BUILD_LDFLAGS += -DSECTION_IS_RW
+
+OPENSSL_CFLAGS := $(shell $(PKG_CONFIG) --libs openssl)
+OPENSSL_LDFLAGS := $(shell $(PKG_CONFIG) --libs openssl)
+
+$(out)/util/gen_touchpad_hash: BUILD_CFLAGS += $(OPENSSL_CFLAGS)
+$(out)/util/gen_touchpad_hash: BUILD_LDFLAGS += $(OPENSSL_LDFLAGS)
+endif # CONFIG_TOUCHPAD_VIRTUAL_OFF
+
$(out)/util/export_taskinfo.so: $(out)/util/export_taskinfo_ro.o \
$(out)/util/export_taskinfo_rw.o
$(call quiet,link_taskinfo,BUILDLD)
diff --git a/util/gen_touchpad_hash.c b/util/gen_touchpad_hash.c
new file mode 100644
index 0000000000..379d083476
--- /dev/null
+++ b/util/gen_touchpad_hash.c
@@ -0,0 +1,161 @@
+/* Copyright 2017 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <err.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <openssl/sha.h>
+
+#include "config.h"
+
+static void print_hex(FILE *out, uint8_t digest[SHA256_DIGEST_LENGTH])
+{
+ int i;
+
+ fputs("\t{ ", out);
+ for (i = 0; i < SHA256_DIGEST_LENGTH; i++)
+ fprintf(out, "0x%02x, ", digest[i]);
+
+ fputs("},\n", out);
+}
+
+/* Output blank hashes */
+static int hash_fw_blank(FILE *hashes)
+{
+ uint8_t digest[SHA256_DIGEST_LENGTH] = { 0 };
+ int len;
+
+ fputs("{\n", hashes);
+ for (len = 0; len < CONFIG_TOUCHPAD_VIRTUAL_SIZE;
+ len += CONFIG_UPDATE_PDU_SIZE) {
+ print_hex(hashes, digest);
+ }
+ fputs("};\n", hashes);
+
+ return 0;
+}
+
+static int hash_fw(FILE *tp_fw, FILE *hashes)
+{
+ uint8_t buffer[CONFIG_UPDATE_PDU_SIZE];
+ int len = 0;
+ int rb;
+ SHA256_CTX ctx;
+ uint8_t digest[SHA256_DIGEST_LENGTH];
+
+ fputs("{\n", hashes);
+ while (1) {
+ rb = fread(buffer, 1, sizeof(buffer), tp_fw);
+ len += rb;
+
+ if (rb == 0)
+ break;
+
+ /* Calculate hash for the block. */
+ SHA256_Init(&ctx);
+ SHA256_Update(&ctx, buffer, rb);
+ SHA256_Final(digest, &ctx);
+
+ print_hex(hashes, digest);
+
+ if (rb < sizeof(buffer))
+ break;
+ }
+ fputs("};\n", hashes);
+
+ if (!feof(tp_fw) || ferror(tp_fw)) {
+ warn("Error reading input file");
+ return 1;
+ }
+
+ if (len != CONFIG_TOUCHPAD_VIRTUAL_SIZE) {
+ warnx("Incorrect TP FW size (%d vs %d)", len,
+ CONFIG_TOUCHPAD_VIRTUAL_SIZE);
+ return 1;
+ }
+
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ int nopt;
+ int ret;
+ const char *out = NULL;
+ char *tp_fw_name = NULL;
+ FILE *tp_fw = NULL;
+ FILE *hashes;
+ const char short_opt[] = "f:ho:";
+ const struct option long_opts[] = {
+ { "firmware", 1, NULL, 'f' },
+ { "help", 0, NULL, 'h' },
+ { "out", 1, NULL, 'o' },
+ { NULL }
+ };
+ const char usage[] = "USAGE: %s -f <touchpad FW> -o <output file>\n";
+
+ while ((nopt = getopt_long(argc, argv, short_opt,
+ long_opts, NULL)) != -1) {
+ switch (nopt) {
+ case 'f': /* -f or --firmware */
+ tp_fw_name = optarg;
+ break;
+
+ case 'h': /* -h or --help */
+ fprintf(stdout, usage, argv[0]);
+ return 0;
+
+ case 'o': /* -o or --out */
+ out = optarg;
+ break;
+
+ default: /* Invalid parameter. */
+ fprintf(stderr, usage, argv[0]);
+ return 1;
+ }
+ };
+
+ if (out == NULL)
+ return 1;
+
+ hashes = fopen(out, "we");
+ if (!hashes)
+ err(1, "Cannot open output file");
+
+ fputs("#include <stdint.h>\n\n", hashes);
+ fprintf(hashes, "const uint8_t touchpad_fw_hashes[%d][%d] = ",
+ CONFIG_TOUCHPAD_VIRTUAL_SIZE / CONFIG_UPDATE_PDU_SIZE,
+ SHA256_DIGEST_LENGTH);
+
+ if (tp_fw_name) {
+ tp_fw = fopen(tp_fw_name, "re");
+
+ if (!tp_fw) {
+ warn("Cannot open firmware");
+ ret = 1;
+ goto out;
+ }
+
+ ret = hash_fw(tp_fw, hashes);
+
+ fclose(tp_fw);
+ } else {
+ printf("No touchpad FW provided, outputting blank hashes.\n");
+ ret = hash_fw_blank(hashes);
+ }
+
+out:
+ fclose(hashes);
+
+ /* In case of failure, remove output file. */
+ if (ret != 0)
+ unlink(out);
+
+ return ret;
+}