diff options
author | Nicolas Boichat <drinkcat@chromium.org> | 2017-08-15 15:53:30 +0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2017-09-15 03:08:26 -0700 |
commit | 94279fc38fae533e86425102082e0c681d98d259 (patch) | |
tree | 2012cd0153497e193fa417d2ce71941b0264a408 | |
parent | e18d9dd5300d5e1693ec3d4c72dd105efcff4393 (diff) | |
download | chrome-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-- | 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; +} |