boot: Add hardware key support
This change enables the public key (used for image authentication) to
be removed from MCUboot and be appended to the image instead. In this
case the key or its hash must be provisioned to the device and MCUboot
must be able to retrieve the key-hash from the hardware to compare it
with the calculated hash of the public key from the image manifest in
order to verify its validity before image authentication.
The source of this change:
https://review.trustedfirmware.org/c/trusted-firmware-m/+/1581
Change-Id: I36fe699732e0e4c113eaed331c22e707c722ed6e
Signed-off-by: David Vincze <david.vincze@linaro.org>
diff --git a/boot/bootutil/include/bootutil/image.h b/boot/bootutil/include/bootutil/image.h
index 2eb519f..a73dbf6 100644
--- a/boot/bootutil/include/bootutil/image.h
+++ b/boot/bootutil/include/bootutil/image.h
@@ -74,6 +74,7 @@
* 2nd one is the actual signature.
*/
#define IMAGE_TLV_KEYHASH 0x01 /* hash of the public key */
+#define IMAGE_TLV_PUBKEY 0x02 /* public key */
#define IMAGE_TLV_SHA256 0x10 /* SHA256 of image hdr and body */
#define IMAGE_TLV_RSA2048_PSS 0x20 /* RSA2048 of hash output */
#define IMAGE_TLV_ECDSA224 0x21 /* ECDSA of hash output */
diff --git a/boot/bootutil/include/bootutil/sign_key.h b/boot/bootutil/include/bootutil/sign_key.h
index 47b2570..13e5466 100644
--- a/boot/bootutil/include/bootutil/sign_key.h
+++ b/boot/bootutil/include/bootutil/sign_key.h
@@ -20,18 +20,43 @@
#ifndef __BOOTUTIL_SIGN_KEY_H_
#define __BOOTUTIL_SIGN_KEY_H_
+#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
+#ifndef MCUBOOT_HW_KEY
struct bootutil_key {
const uint8_t *key;
const unsigned int *len;
};
extern const struct bootutil_key bootutil_keys[];
+#else
+struct bootutil_key {
+ uint8_t *key;
+ unsigned int *len;
+};
+
+extern struct bootutil_key bootutil_keys[];
+
+/**
+ * Retrieve the hash of the corresponding public key for image authentication.
+ *
+ * @param[in] image_index Index of the image to be authenticated.
+ * @param[out] public_key_hash Buffer to store the key-hash in.
+ * @param[in,out] key_hash_size As input the size of the buffer. As output
+ * the actual key-hash length.
+ *
+ * @return 0 on success; nonzero on failure.
+ */
+int boot_retrieve_public_key_hash(uint8_t image_index,
+ uint8_t *public_key_hash,
+ size_t *key_hash_size);
+#endif /* !MCUBOOT_HW_KEY */
+
extern const int bootutil_key_cnt;
#ifdef __cplusplus
diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c
index 4390306..b16c038 100644
--- a/boot/bootutil/src/image_validate.c
+++ b/boot/bootutil/src/image_validate.c
@@ -177,6 +177,7 @@
#endif
#ifdef EXPECTED_SIG_TLV
+#if !defined(MCUBOOT_HW_KEY)
static int
bootutil_find_key(uint8_t *keyhash, uint8_t keyhash_len)
{
@@ -200,6 +201,34 @@
}
return -1;
}
+#else
+extern unsigned int pub_key_len;
+static int
+bootutil_find_key(uint8_t image_index, uint8_t *key, uint16_t key_len)
+{
+ bootutil_sha256_context sha256_ctx;
+ uint8_t hash[32];
+ uint8_t key_hash[32];
+ size_t key_hash_size = sizeof(key_hash);
+ int rc;
+
+ bootutil_sha256_init(&sha256_ctx);
+ bootutil_sha256_update(&sha256_ctx, key, key_len);
+ bootutil_sha256_finish(&sha256_ctx, hash);
+
+ rc = boot_retrieve_public_key_hash(image_index, key_hash, &key_hash_size);
+ if (rc) {
+ return rc;
+ }
+
+ if (!memcmp(hash, key_hash, key_hash_size)) {
+ bootutil_keys[0].key = key;
+ pub_key_len = key_len;
+ return 0;
+ }
+ return -1;
+}
+#endif /* !MCUBOOT_HW_KEY */
#endif
#ifdef MCUBOOT_HW_ROLLBACK_PROT
@@ -281,7 +310,11 @@
#ifdef EXPECTED_SIG_TLV
int valid_signature = 0;
int key_id = -1;
+#ifdef MCUBOOT_HW_KEY
+ /* Few extra bytes for encoding and for public exponent. */
+ uint8_t key_buf[SIG_BUF_SIZE + 24];
#endif
+#endif /* EXPECTED_SIG_TLV */
struct image_tlv_iter it;
uint8_t buf[SIG_BUF_SIZE];
uint8_t hash[32];
@@ -337,6 +370,7 @@
sha256_valid = 1;
#ifdef EXPECTED_SIG_TLV
+#ifndef MCUBOOT_HW_KEY
} else if (type == IMAGE_TLV_KEYHASH) {
/*
* Determine which key we should be checking.
@@ -353,6 +387,24 @@
* The key may not be found, which is acceptable. There
* can be multiple signatures, each preceded by a key.
*/
+#else
+ } else if (type == IMAGE_TLV_PUBKEY) {
+ /*
+ * Determine which key we should be checking.
+ */
+ if (len > sizeof(key_buf)) {
+ return -1;
+ }
+ rc = flash_area_read(fap, off, key_buf, len);
+ if (rc) {
+ return rc;
+ }
+ key_id = bootutil_find_key(image_index, key_buf, len);
+ /*
+ * The key may not be found, which is acceptable. There
+ * can be multiple signatures, each preceded by a key.
+ */
+#endif /* !MCUBOOT_HW_KEY */
} else if (type == EXPECTED_SIG_TLV) {
/* Ignore this signature if it is out of bounds. */
if (key_id < 0 || key_id >= bootutil_key_cnt) {
diff --git a/boot/cypress/MCUBootApp/keys.c b/boot/cypress/MCUBootApp/keys.c
index db2bf07..a09528c 100644
--- a/boot/cypress/MCUBootApp/keys.c
+++ b/boot/cypress/MCUBootApp/keys.c
@@ -57,6 +57,7 @@
#include <bootutil/sign_key.h>
#include <mcuboot_config/mcuboot_config.h>
+#if !defined(MCUBOOT_HW_KEY)
#if defined(MCUBOOT_SIGN_RSA)
const unsigned char rsa_pub_key[] = {
0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xd1, 0x06, 0x08,
@@ -163,3 +164,13 @@
};
const int bootutil_key_cnt = 1;
#endif
+#else
+unsigned int pub_key_len;
+struct bootutil_key bootutil_keys[1] = {
+ {
+ .key = 0,
+ .len = &pub_key_len,
+ }
+};
+const int bootutil_key_cnt = 1;
+#endif /* !MCUBOOT_HW_KEY */
diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig
index 31b6db3..374aef0 100644
--- a/boot/zephyr/Kconfig
+++ b/boot/zephyr/Kconfig
@@ -1,4 +1,4 @@
-# Copyright (c) 2017 Linaro Limited
+# Copyright (c) 2017-2020 Linaro Limited
# Copyright (c) 2020 Arm Limited
#
# SPDX-License-Identifier: Apache-2.0
@@ -128,6 +128,15 @@
config MBEDTLS_CFG_FILE
default "mcuboot-mbedtls-cfg.h"
+config BOOT_HW_KEY
+ bool "Use HW key for image verification"
+ default n
+ help
+ Use HW key for image verification, otherwise the public key is embedded
+ in MCUBoot. If enabled the public key is appended to the signed image
+ and requires the hash of the public key to be provisioned to the device
+ beforehand.
+
config BOOT_VALIDATE_SLOT0
bool "Validate image in the primary slot on every boot"
default y
diff --git a/boot/zephyr/include/mcuboot_config/mcuboot_config.h b/boot/zephyr/include/mcuboot_config/mcuboot_config.h
index c0584f3..a2749e8 100644
--- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h
+++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2018 Open Source Foundries Limited
* Copyright (c) 2019-2020 Arm Limited
+ * Copyright (c) 2019-2020 Linaro Limited
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -44,6 +45,10 @@
#endif
#endif
+#ifdef CONFIG_BOOT_HW_KEY
+#define MCUBOOT_HW_KEY
+#endif
+
#ifdef CONFIG_BOOT_VALIDATE_SLOT0
#define MCUBOOT_VALIDATE_PRIMARY_SLOT
#endif
diff --git a/boot/zephyr/keys.c b/boot/zephyr/keys.c
index 47943c9..d5aeba4 100644
--- a/boot/zephyr/keys.c
+++ b/boot/zephyr/keys.c
@@ -28,6 +28,7 @@
*/
#include <mcuboot_config/mcuboot_config.h>
+#if !defined(MCUBOOT_HW_KEY)
#if defined(MCUBOOT_SIGN_RSA)
#define HAVE_KEYS
extern const unsigned char rsa_pub_key[];
@@ -65,7 +66,17 @@
},
};
const int bootutil_key_cnt = 1;
-#endif
+#endif /* HAVE_KEYS */
+#else
+unsigned int pub_key_len;
+struct bootutil_key bootutil_keys[1] = {
+ {
+ .key = 0,
+ .len = &pub_key_len,
+ }
+};
+const int bootutil_key_cnt = 1;
+#endif /* !MCUBOOT_HW_KEY */
#if defined(MCUBOOT_ENCRYPT_RSA)
unsigned char enc_priv_key[] = {