diff options
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | Makefile.rules | 3 | ||||
-rw-r--r-- | common/build.mk | 22 | ||||
-rw-r--r-- | common/update_fw.c | 11 | ||||
-rw-r--r-- | include/config.h | 6 | ||||
-rw-r--r-- | util/build.mk | 13 | ||||
-rw-r--r-- | util/gen_touchpad_hash.c | 161 |
7 files changed, 220 insertions, 0 deletions
@@ -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; +} |