From 29a23f9d6c533f8371be3ae0268c4c75866291b2 Mon Sep 17 00:00:00 2001 From: Heiko Schocher Date: Mon, 3 Mar 2014 12:19:30 +0100 Subject: [PATCH] tools, fit_check_sign: verify a signed fit image add host tool "fit_check_sign" which verifies, if a fit image is signed correct. Signed-off-by: Heiko Schocher Cc: Simon Glass --- common/image-sig.c | 18 ++++---- doc/uImage.FIT/signature.txt | 6 +++ include/fdt_support.h | 5 +++ include/image.h | 17 +++++--- lib/fdtdec.c | 20 +++++++++ lib/rsa/rsa-checksum.c | 10 +++-- lib/rsa/rsa-sign.c | 2 +- lib/rsa/rsa-verify.c | 18 ++++++-- test/vboot/vboot_test.sh | 20 +++++++++ tools/.gitignore | 1 + tools/Makefile | 7 ++- tools/fdt_host.h | 2 + tools/fdtdec.c | 1 + tools/fit_check_sign.c | 85 ++++++++++++++++++++++++++++++++++++ tools/image-host.c | 15 +++++++ tools/rsa-checksum.c | 1 + tools/rsa-verify.c | 1 + 17 files changed, 204 insertions(+), 25 deletions(-) create mode 100644 tools/fdtdec.c create mode 100644 tools/fit_check_sign.c create mode 100644 tools/rsa-checksum.c create mode 100644 tools/rsa-verify.c diff --git a/common/image-sig.c b/common/image-sig.c index 763960a45a..72284eb1d1 100644 --- a/common/image-sig.c +++ b/common/image-sig.c @@ -19,9 +19,14 @@ DECLARE_GLOBAL_DATA_PTR; #define IMAGE_MAX_HASHED_NODES 100 #ifdef USE_HOSTCC -__attribute__((weak)) void *get_blob(void) +void *host_blob; +void image_set_host_blob(void *blob) { - return NULL; + host_blob = blob; +} +void *image_get_host_blob(void) +{ + return host_blob; } #endif @@ -32,10 +37,9 @@ struct checksum_algo checksum_algos[] = { RSA2048_BYTES, #if IMAGE_ENABLE_SIGN EVP_sha1, -#else +#endif sha1_calculate, padding_sha1_rsa2048, -#endif }, { "sha256", @@ -43,10 +47,9 @@ struct checksum_algo checksum_algos[] = { RSA2048_BYTES, #if IMAGE_ENABLE_SIGN EVP_sha256, -#else +#endif sha256_calculate, padding_sha256_rsa2048, -#endif }, { "sha256", @@ -54,10 +57,9 @@ struct checksum_algo checksum_algos[] = { RSA4096_BYTES, #if IMAGE_ENABLE_SIGN EVP_sha256, -#else +#endif sha256_calculate, padding_sha256_rsa4096, -#endif } }; diff --git a/doc/uImage.FIT/signature.txt b/doc/uImage.FIT/signature.txt index 71f8b6c06a..9502037705 100644 --- a/doc/uImage.FIT/signature.txt +++ b/doc/uImage.FIT/signature.txt @@ -357,6 +357,9 @@ Build FIT with signed configuration Test Verified Boot Run: unsigned config: OK Sign images Test Verified Boot Run: signed config: OK +check signed config on the host +OK +Test Verified Boot Run: signed config: OK Test Verified Boot Run: signed config with bad hash: OK do sha256 test Build FIT with signed images @@ -367,6 +370,9 @@ Build FIT with signed configuration Test Verified Boot Run: unsigned config: OK Sign images Test Verified Boot Run: signed config: OK +check signed config on the host +OK +Test Verified Boot Run: signed config: OK Test Verified Boot Run: signed config with bad hash: OK Test passed diff --git a/include/fdt_support.h b/include/fdt_support.h index 9871e2f81a..76c9b2e776 100644 --- a/include/fdt_support.h +++ b/include/fdt_support.h @@ -115,4 +115,9 @@ static inline int fdt_status_disabled_by_alias(void *fdt, const char* alias) } #endif /* ifdef CONFIG_OF_LIBFDT */ + +#ifdef USE_HOSTCC +int fdtdec_get_int(const void *blob, int node, const char *prop_name, + int default_val); +#endif #endif /* ifndef __FDT_SUPPORT_H */ diff --git a/include/image.h b/include/image.h index 540afaaec5..2508d7d243 100644 --- a/include/image.h +++ b/include/image.h @@ -832,7 +832,7 @@ int calculate_hash(const void *data, int data_len, const char *algo, #if defined(CONFIG_FIT_SIGNATURE) # ifdef USE_HOSTCC # define IMAGE_ENABLE_SIGN 1 -# define IMAGE_ENABLE_VERIFY 0 +# define IMAGE_ENABLE_VERIFY 1 # include #else # define IMAGE_ENABLE_SIGN 0 @@ -844,7 +844,9 @@ int calculate_hash(const void *data, int data_len, const char *algo, #endif #ifdef USE_HOSTCC -# define gd_fdt_blob() NULL +void *image_get_host_blob(void); +void image_set_host_blob(void *host_blob); +# define gd_fdt_blob() image_get_host_blob() #else # define gd_fdt_blob() (gd->fdt_blob) #endif @@ -881,14 +883,11 @@ struct checksum_algo { const int checksum_len; const int pad_len; #if IMAGE_ENABLE_SIGN - const EVP_MD *(*calculate)(void); -#else -#if IMAGE_ENABLE_VERIFY + const EVP_MD *(*calculate_sign)(void); +#endif void (*calculate)(const struct image_region region[], int region_count, uint8_t *checksum); const uint8_t *rsa_padding; -#endif -#endif }; struct image_sig_algo { @@ -1009,7 +1008,11 @@ struct image_region *fit_region_make_list(const void *fit, static inline int fit_image_check_target_arch(const void *fdt, int node) { +#ifndef USE_HOSTCC return fit_image_check_arch(fdt, node, IH_ARCH_DEFAULT); +#else + return 0; +#endif } #ifdef CONFIG_FIT_VERBOSE diff --git a/lib/fdtdec.c b/lib/fdtdec.c index f65ab4f58f..8da2d74041 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -3,6 +3,7 @@ * SPDX-License-Identifier: GPL-2.0+ */ +#ifndef USE_HOSTCC #include #include #include @@ -643,3 +644,22 @@ int fdtdec_read_fmap_entry(const void *blob, int node, const char *name, return 0; } +#else +#include "libfdt.h" +#include "fdt_support.h" + +int fdtdec_get_int(const void *blob, int node, const char *prop_name, + int default_val) +{ + const int *cell; + int len; + + cell = fdt_getprop_w((void *)blob, node, prop_name, &len); + if (cell && len >= sizeof(int)) { + int val = fdt32_to_cpu(cell[0]); + + return val; + } + return default_val; +} +#endif diff --git a/lib/rsa/rsa-checksum.c b/lib/rsa/rsa-checksum.c index a9d096d455..32d6602e97 100644 --- a/lib/rsa/rsa-checksum.c +++ b/lib/rsa/rsa-checksum.c @@ -4,14 +4,18 @@ * SPDX-License-Identifier: GPL-2.0+ */ +#ifndef USE_HOSTCC #include #include -#include -#include -#include #include #include #include +#else +#include "fdt_host.h" +#endif +#include +#include +#include /* PKCS 1.5 paddings as described in the RSA PKCS#1 v2.1 standard. */ diff --git a/lib/rsa/rsa-sign.c b/lib/rsa/rsa-sign.c index 0fe6e9f9cf..ca8c120d97 100644 --- a/lib/rsa/rsa-sign.c +++ b/lib/rsa/rsa-sign.c @@ -193,7 +193,7 @@ static int rsa_sign_with_key(RSA *rsa, struct checksum_algo *checksum_algo, goto err_create; } EVP_MD_CTX_init(context); - if (!EVP_SignInit(context, checksum_algo->calculate())) { + if (!EVP_SignInit(context, checksum_algo->calculate_sign())) { ret = rsa_err("Signer setup failed"); goto err_sign; } diff --git a/lib/rsa/rsa-verify.c b/lib/rsa/rsa-verify.c index 09268ca293..587da5b470 100644 --- a/lib/rsa/rsa-verify.c +++ b/lib/rsa/rsa-verify.c @@ -4,17 +4,28 @@ * SPDX-License-Identifier: GPL-2.0+ */ +#ifndef USE_HOSTCC #include #include +#include +#include +#include +#include +#include +#else +#include "fdt_host.h" +#include "mkimage.h" +#include +#endif #include #include #include -#include -#include -#include #define UINT64_MULT32(v, multby) (((uint64_t)(v)) * ((uint32_t)(multby))) +#define get_unaligned_be32(a) fdt32_to_cpu(*(uint32_t *)a) +#define put_unaligned_be32(a, b) (*(uint32_t *)(b) = cpu_to_fdt32(a)) + /** * subtract_modulus() - subtract modulus from the given value * @@ -150,7 +161,6 @@ static int pow_mod(const struct rsa_public_key *key, uint32_t *inout) /* Convert to bigendian byte array */ for (i = key->len - 1, ptr = inout; (int)i >= 0; i--, ptr++) put_unaligned_be32(result[i], ptr); - return 0; } diff --git a/test/vboot/vboot_test.sh b/test/vboot/vboot_test.sh index 3e2856ed1f..3c6efa774e 100755 --- a/test/vboot/vboot_test.sh +++ b/test/vboot/vboot_test.sh @@ -47,6 +47,7 @@ O=$(readlink -f ${O}) dtc="-I dts -O dtb -p 2000" uboot="${O}/u-boot" mkimage="${O}/tools/mkimage" +fit_check_sign="${O}/tools/fit_check_sign" keys="${dir}/dev-keys" echo ${mkimage} -D "${dtc}" @@ -99,6 +100,25 @@ function do_test { run_uboot "signed config" "dev+" + echo check signed config on the host + if ! ${fit_check_sign} -f test.fit -k sandbox-u-boot.dtb >${tmp}; then + echo + echo "Verified boot key check on host failed, output follows:" + cat ${tmp} + false + else + if ! grep -q "dev+" ${tmp}; then + echo + echo "Verified boot key check failed, output follows:" + cat ${tmp} + false + else + echo "OK" + fi + fi + + run_uboot "signed config" "dev+" + # Increment the first byte of the signature, which should cause failure sig=$(fdtget -t bx test.fit /configurations/conf@1/signature@1 value) newbyte=$(printf %x $((0x${sig:0:2} + 1))) diff --git a/tools/.gitignore b/tools/.gitignore index 2f6ecc740a..b1e997fc3e 100644 --- a/tools/.gitignore +++ b/tools/.gitignore @@ -1,5 +1,6 @@ /bmp_logo /envcrc +/fit_check_sign /fit_info /gen_eth_addr /img2srec diff --git a/tools/Makefile b/tools/Makefile index 52fb69eae9..c5c378cf86 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -61,13 +61,13 @@ mkenvimage$(SFX)-objs := crc32.o mkenvimage.o os_support.o hostprogs-y += dumpimage$(SFX) mkimage$(SFX) ifdef CONFIG_FIT_SIGNATURE -hostprogs-y += fit_info$(SFX) +hostprogs-y += fit_info$(SFX) fit_check_sign$(SFX) endif FIT_SIG_OBJS-$(CONFIG_FIT_SIGNATURE) := image-sig.o # Flattened device tree objects LIBFDT_OBJS := fdt.o fdt_ro.o fdt_rw.o fdt_strerror.o fdt_wip.o -RSA_OBJS-$(CONFIG_FIT_SIGNATURE) := rsa-sign.o +RSA_OBJS-$(CONFIG_FIT_SIGNATURE) := rsa-sign.o rsa-verify.o rsa-checksum.o # common objs for dumpimage and mkimage dumpimage-mkimage-objs := aisimage.o \ @@ -97,6 +97,7 @@ dumpimage-mkimage-objs := aisimage.o \ dumpimage$(SFX)-objs := $(dumpimage-mkimage-objs) dumpimage.o mkimage$(SFX)-objs := $(dumpimage-mkimage-objs) mkimage.o fit_info$(SFX)-objs := $(dumpimage-mkimage-objs) fit_info.o +fit_check_sign$(SFX)-objs := $(dumpimage-mkimage-objs) fit_check_sign.o # TODO(sjg@chromium.org): Is this correct on Mac OS? @@ -105,6 +106,7 @@ ifneq ($(CONFIG_MX23)$(CONFIG_MX28),) HOSTLOADLIBES_dumpimage$(SFX) := -lssl -lcrypto HOSTLOADLIBES_mkimage$(SFX) := -lssl -lcrypto HOSTLOADLIBES_fit_info$(SFX) := -lssl -lcrypto +HOSTLOADLIBES_fit_check_sign$(SFX) := -lssl -lcrypto # Add CONFIG_MXS into host CFLAGS, so we can check whether or not register # the mxsimage support within tools/mxsimage.c . HOSTCFLAGS_mxsimage.o += -DCONFIG_MXS @@ -114,6 +116,7 @@ ifdef CONFIG_FIT_SIGNATURE HOSTLOADLIBES_dumpimage$(SFX) := -lssl -lcrypto HOSTLOADLIBES_mkimage$(SFX) := -lssl -lcrypto HOSTLOADLIBES_fit_info$(SFX) := -lssl -lcrypto +HOSTLOADLIBES_fit_check_sign$(SFX) := -lssl -lcrypto # This affects include/image.h, but including the board config file # is tricky, so manually define this options here. diff --git a/tools/fdt_host.h b/tools/fdt_host.h index c2b23c6217..134d965713 100644 --- a/tools/fdt_host.h +++ b/tools/fdt_host.h @@ -11,4 +11,6 @@ #include "../include/libfdt.h" #include "../include/fdt_support.h" +int fit_check_sign(const void *working_fdt, const void *key); + #endif /* __FDT_HOST_H__ */ diff --git a/tools/fdtdec.c b/tools/fdtdec.c new file mode 100644 index 0000000000..f1c22569ca --- /dev/null +++ b/tools/fdtdec.c @@ -0,0 +1 @@ +#include "../lib/fdtdec.c" diff --git a/tools/fit_check_sign.c b/tools/fit_check_sign.c new file mode 100644 index 0000000000..d6d9340094 --- /dev/null +++ b/tools/fit_check_sign.c @@ -0,0 +1,85 @@ +/* + * (C) Copyright 2014 + * DENX Software Engineering + * Heiko Schocher + * + * Based on: + * (C) Copyright 2008 Semihalf + * + * (C) Copyright 2000-2004 + * DENX Software Engineering + * Wolfgang Denk, wd@denx.de + * + * Updated-by: Prafulla Wadaskar + * FIT image specific code abstracted from mkimage.c + * some functions added to address abstraction + * + * All rights reserved. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "mkimage.h" +#include "fit_common.h" +#include +#include + +void usage(char *cmdname) +{ + fprintf(stderr, "Usage: %s -f fit file -k key file\n" + " -f ==> set fit file which should be checked'\n" + " -k ==> set key file which contains the key'\n", + cmdname); + exit(EXIT_FAILURE); +} + +int main(int argc, char **argv) +{ + int ffd = -1; + int kfd = -1; + struct stat fsbuf; + struct stat ksbuf; + void *fit_blob; + char *fdtfile = NULL; + char *keyfile = NULL; + char cmdname[50]; + int ret; + void *key_blob; + int c; + + strcpy(cmdname, *argv); + while ((c = getopt(argc, argv, "f:k:")) != -1) + switch (c) { + case 'f': + fdtfile = optarg; + break; + case 'k': + keyfile = optarg; + break; + default: + usage(cmdname); + break; + } + + ffd = mmap_fdt(cmdname, fdtfile, &fit_blob, &fsbuf, 0); + if (ffd < 0) + return EXIT_FAILURE; + kfd = mmap_fdt(cmdname, keyfile, &key_blob, &ksbuf, 0); + if (ffd < 0) + return EXIT_FAILURE; + + image_set_host_blob(key_blob); + ret = fit_check_sign(fit_blob, key_blob); + + if (ret) + ret = EXIT_SUCCESS; + else + ret = EXIT_FAILURE; + + (void) munmap((void *)fit_blob, fsbuf.st_size); + (void) munmap((void *)key_blob, ksbuf.st_size); + + close(ffd); + close(kfd); + exit(ret); +} diff --git a/tools/image-host.c b/tools/image-host.c index 8e185ec5df..651f1c2f8b 100644 --- a/tools/image-host.c +++ b/tools/image-host.c @@ -695,3 +695,18 @@ int fit_add_verification_data(const char *keydir, void *keydest, void *fit, return 0; } + +#ifdef CONFIG_FIT_SIGNATURE +int fit_check_sign(const void *working_fdt, const void *key) +{ + int cfg_noffset; + int ret; + + cfg_noffset = fit_conf_get_node(working_fdt, NULL); + if (!cfg_noffset) + return -1; + + ret = fit_config_verify(working_fdt, cfg_noffset); + return ret; +} +#endif diff --git a/tools/rsa-checksum.c b/tools/rsa-checksum.c new file mode 100644 index 0000000000..09033e6201 --- /dev/null +++ b/tools/rsa-checksum.c @@ -0,0 +1 @@ +#include "../lib/rsa/rsa-checksum.c" diff --git a/tools/rsa-verify.c b/tools/rsa-verify.c new file mode 100644 index 0000000000..bb662a1ef8 --- /dev/null +++ b/tools/rsa-verify.c @@ -0,0 +1 @@ +#include "../lib/rsa/rsa-verify.c"