summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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;
+}