diff --git a/boot/bootutil/include/bootutil/crypto/sha.h b/boot/bootutil/include/bootutil/crypto/sha.h index d136a7f533..6a009ff95c 100644 --- a/boot/bootutil/include/bootutil/crypto/sha.h +++ b/boot/bootutil/include/bootutil/crypto/sha.h @@ -69,7 +69,11 @@ #endif /* MCUBOOT_USE_MBED_TLS */ #if defined(MCUBOOT_USE_TINYCRYPT) +#if defined(MCUBOOT_SHA512) + #include +#else #include +#endif #include #endif /* MCUBOOT_USE_TINYCRYPT */ @@ -192,11 +196,19 @@ static inline int bootutil_sha_finish(bootutil_sha_context *ctx, #endif /* MCUBOOT_USE_MBED_TLS */ #if defined(MCUBOOT_USE_TINYCRYPT) +#if defined(MCUBOOT_SHA512) +typedef struct tc_sha512_state_struct bootutil_sha_context; +#else typedef struct tc_sha256_state_struct bootutil_sha_context; +#endif static inline int bootutil_sha_init(bootutil_sha_context *ctx) { +#if defined(MCUBOOT_SHA512) + tc_sha512_init(ctx); +#else tc_sha256_init(ctx); +#endif return 0; } @@ -210,13 +222,21 @@ static inline int bootutil_sha_update(bootutil_sha_context *ctx, const void *data, uint32_t data_len) { +#if defined(MCUBOOT_SHA512) + return tc_sha512_update(ctx, data, data_len); +#else return tc_sha256_update(ctx, data, data_len); +#endif } static inline int bootutil_sha_finish(bootutil_sha_context *ctx, uint8_t *output) { +#if defined(MCUBOOT_SHA512) + return tc_sha512_final(output, ctx); +#else return tc_sha256_final(output, ctx); +#endif } #endif /* MCUBOOT_USE_TINYCRYPT */ diff --git a/boot/bootutil/src/bootutil_priv.h b/boot/bootutil/src/bootutil_priv.h index 345933a5f9..5703f627a0 100644 --- a/boot/bootutil/src/bootutil_priv.h +++ b/boot/bootutil/src/bootutil_priv.h @@ -267,9 +267,18 @@ struct boot_loader_state { #endif /* MCUBOOT_DIRECT_XIP || MCUBOOT_RAM_LOAD */ }; +/* The function is intended for verification of image hash against + * provided signature. + */ fih_ret bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen, uint8_t key_id); +/* The function is intended for direct verification of image + * against provided signature. + */ +fih_ret bootutil_verify_img(uint8_t *img, uint32_t size, + uint8_t *sig, size_t slen, uint8_t key_id); + fih_ret boot_fih_memequal(const void *s1, const void *s2, size_t n); int boot_find_status(int image_index, const struct flash_area **fap); diff --git a/boot/bootutil/src/image_ed25519.c b/boot/bootutil/src/image_ed25519.c index 4e2423a08e..238c9d6714 100644 --- a/boot/bootutil/src/image_ed25519.c +++ b/boot/bootutil/src/image_ed25519.c @@ -21,12 +21,14 @@ #include "bootutil/crypto/common.h" #include "bootutil/crypto/sha.h" +#define EDDSA_SIGNATURE_LENGTH 64 + static const uint8_t ed25519_pubkey_oid[] = MBEDTLS_OID_ISO_IDENTIFIED_ORG "\x65\x70"; #define NUM_ED25519_BYTES 32 extern int ED25519_verify(const uint8_t *message, size_t message_len, - const uint8_t signature[64], - const uint8_t public_key[32]); + const uint8_t signature[EDDSA_SIGNATURE_LENGTH], + const uint8_t public_key[NUM_ED25519_BYTES]); /* * Parse the public key used for signing. @@ -67,16 +69,23 @@ bootutil_import_key(uint8_t **cp, uint8_t *end) return 0; } -fih_ret -bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen, - uint8_t key_id) +/* Signature verification base function. + * The function takes buffer of specified length and tries to verify + * it against provided signature. + * The function does key import and checks whether signature is + * of expected length. + */ +static fih_ret +bootutil_verify(uint8_t *buf, uint32_t blen, + uint8_t *sig, size_t slen, + uint8_t key_id) { int rc; FIH_DECLARE(fih_rc, FIH_FAILURE); uint8_t *pubkey; uint8_t *end; - if (hlen != IMAGE_HASH_SIZE || slen != 64) { + if (slen != EDDSA_SIGNATURE_LENGTH) { FIH_SET(fih_rc, FIH_FAILURE); goto out; } @@ -90,7 +99,7 @@ bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen, goto out; } - rc = ED25519_verify(hash, IMAGE_HASH_SIZE, sig, pubkey); + rc = ED25519_verify(buf, blen, sig, pubkey); if (rc == 0) { /* if verify returns 0, there was an error. */ @@ -104,4 +113,45 @@ bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen, FIH_RET(fih_rc); } +/* Hash signature verification function. + * Verifies hash against provided signature. + * The function verifies that hash is of expected size and then + * calls bootutil_verify to do the signature verification. + */ +fih_ret +bootutil_verify_sig(uint8_t *hash, uint32_t hlen, + uint8_t *sig, size_t slen, + uint8_t key_id) +{ + FIH_DECLARE(fih_rc, FIH_FAILURE); + + if (hlen != IMAGE_HASH_SIZE) { + FIH_SET(fih_rc, FIH_FAILURE); + goto out; + } + + FIH_CALL(bootutil_verify, fih_rc, hash, IMAGE_HASH_SIZE, sig, + slen, key_id); + +out: + FIH_RET(fih_rc); +} + +/* Image verification function. + * The function directly calls bootutil_verify to verify signature + * of image. + */ +fih_ret +bootutil_verify_img(uint8_t *img, uint32_t size, + uint8_t *sig, size_t slen, + uint8_t key_id) +{ + FIH_DECLARE(fih_rc, FIH_FAILURE); + + FIH_CALL(bootutil_verify, fih_rc, img, size, sig, + slen, key_id); + + FIH_RET(fih_rc); +} + #endif /* MCUBOOT_SIGN_ED25519 */ diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c index ec5d986df3..e038f22fe9 100644 --- a/boot/bootutil/src/image_validate.c +++ b/boot/bootutil/src/image_validate.c @@ -56,6 +56,7 @@ #include "bootutil_priv.h" +#ifndef MCUBOOT_SIGN_PURE /* * Compute SHA hash over the image. * (SHA384 if ECDSA-P384 is being used, @@ -68,13 +69,15 @@ bootutil_img_hash(struct enc_key_data *enc_state, int image_index, uint8_t *seed, int seed_len) { bootutil_sha_context sha_ctx; - uint32_t blk_sz; uint32_t size; uint16_t hdr_size; - uint32_t off; - int rc; uint32_t blk_off; uint32_t tlv_off; +#if !defined(MCUBOOT_HASH_STORAGE_DIRECTLY) + int rc; + uint32_t off; + uint32_t blk_sz; +#endif #if (BOOT_IMAGE_NUMBER == 1) || !defined(MCUBOOT_ENC_IMAGES) || \ defined(MCUBOOT_RAM_LOAD) @@ -117,6 +120,12 @@ bootutil_img_hash(struct enc_key_data *enc_state, int image_index, /* If protected TLVs are present they are also hashed. */ size += hdr->ih_protect_tlv_size; +#ifdef MCUBOOT_HASH_STORAGE_DIRECTLY + /* No chunk loading, storage is mapped to address space and can + * be directly given to hashing function. + */ + bootutil_sha_update(&sha_ctx, (void *)flash_area_get_off(fap), size); +#else /* MCUBOOT_HASH_STORAGE_DIRECTLY */ #ifdef MCUBOOT_RAM_LOAD bootutil_sha_update(&sha_ctx, (void*)(IMAGE_RAM_BASE + hdr->ih_load_addr), @@ -161,11 +170,13 @@ bootutil_img_hash(struct enc_key_data *enc_state, int image_index, bootutil_sha_update(&sha_ctx, tmp_buf, blk_sz); } #endif /* MCUBOOT_RAM_LOAD */ +#endif /* MCUBOOT_HASH_STORAGE_DIRECTLY */ bootutil_sha_finish(&sha_ctx, hash_result); bootutil_sha_drop(&sha_ctx); return 0; } +#endif /* * Currently, we only support being able to verify one type of @@ -352,6 +363,44 @@ bootutil_get_img_security_cnt(struct image_header *hdr, return 0; } +#if defined(MCUBOOT_SIGN_PURE) +/* Returns: + * 0 -- found + * 1 -- not found or found but not true + * -1 -- failed for some reason + * + * Value of TLV does not matter, presence decides. + */ +static int bootutil_check_for_pure(const struct image_header *hdr, + const struct flash_area *fap) +{ + struct image_tlv_iter it; + uint32_t off; + uint16_t len; + int32_t rc; + + rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_SIG_PURE, false); + if (rc) { + return -1; + } + + /* Search for the TLV */ + rc = bootutil_tlv_iter_next(&it, &off, &len, NULL); + if (rc == 0 && len == 1) { + uint8_t val; + + rc = LOAD_IMAGE_DATA(hdr, fap, off, &val, sizeof(val)); + if (rc == 0) { + return (val == 1) ? 0 : 1; + } else { + return -1; + } + } + + return 1; +} +#endif + #ifndef ALLOW_ROGUE_TLVS /* * The following list of TLVs are the only entries allowed in the unprotected @@ -368,6 +417,9 @@ static const uint16_t allowed_unprot_tlvs[] = { IMAGE_TLV_ECDSA_SIG, IMAGE_TLV_RSA3072_PSS, IMAGE_TLV_ED25519, +#if defined(MCUBOOT_SIGN_PURE) + IMAGE_TLV_SIG_PURE, +#endif IMAGE_TLV_ENC_RSA2048, IMAGE_TLV_ENC_KW, IMAGE_TLV_ENC_EC256, @@ -390,7 +442,6 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, uint32_t off; uint16_t len; uint16_t type; - int image_hash_valid = 0; #ifdef EXPECTED_SIG_TLV FIH_DECLARE(valid_signature, FIH_FAILURE); #ifndef MCUBOOT_BUILTIN_KEY @@ -407,7 +458,10 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, #endif /* EXPECTED_SIG_TLV */ struct image_tlv_iter it; uint8_t buf[SIG_BUF_SIZE]; +#if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE) + int image_hash_valid = 0; uint8_t hash[IMAGE_HASH_SIZE]; +#endif int rc = 0; FIH_DECLARE(fih_rc, FIH_FAILURE); #ifdef MCUBOOT_HW_ROLLBACK_PROT @@ -416,6 +470,7 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, FIH_DECLARE(security_counter_valid, FIH_FAILURE); #endif +#if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE) rc = bootutil_img_hash(enc_state, image_index, hdr, fap, tmp_buf, tmp_buf_sz, hash, seed, seed_len); if (rc) { @@ -425,6 +480,15 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, if (out_hash) { memcpy(out_hash, hash, IMAGE_HASH_SIZE); } +#endif + +#if defined(MCUBOOT_SIGN_PURE) + /* If Pure type signature is expected then it has to be there */ + rc = bootutil_check_for_pure(hdr, fap); + if (rc != 0) { + goto out; + } +#endif rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, false); if (rc) { @@ -468,8 +532,10 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, } } #endif - - if (type == EXPECTED_HASH_TLV) { + switch(type) { +#if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE) + case EXPECTED_HASH_TLV: + { /* Verify the image hash. This must always be present. */ if (len != sizeof(hash)) { rc = -1; @@ -487,8 +553,12 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, } image_hash_valid = 1; + break; + } +#endif /* defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE) */ #ifdef EXPECTED_KEY_TLV - } else if (type == EXPECTED_KEY_TLV) { + case EXPECTED_KEY_TLV: + { /* * Determine which key we should be checking. */ @@ -513,9 +583,12 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, * The key may not be found, which is acceptable. There * can be multiple signatures, each preceded by a key. */ + break; + } #endif /* EXPECTED_KEY_TLV */ #ifdef EXPECTED_SIG_TLV - } else if (type == EXPECTED_SIG_TLV) { + case EXPECTED_SIG_TLV: + { /* Ignore this signature if it is out of bounds. */ if (key_id < 0 || key_id >= bootutil_key_cnt) { key_id = -1; @@ -529,12 +602,25 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, if (rc) { goto out; } +#ifndef MCUBOOT_SIGN_PURE FIH_CALL(bootutil_verify_sig, valid_signature, hash, sizeof(hash), buf, len, key_id); +#else + /* Directly check signature on the image, by using the mapping of + * a device to memory. The pointer is beginning of image in flash, + * so offset of area, the range is header + image + protected tlvs. + */ + FIH_CALL(bootutil_verify_img, valid_signature, (void *)flash_area_get_off(fap), + hdr->ih_hdr_size + hdr->ih_img_size + hdr->ih_protect_tlv_size, + buf, len, key_id); +#endif key_id = -1; + break; + } #endif /* EXPECTED_SIG_TLV */ #ifdef MCUBOOT_HW_ROLLBACK_PROT - } else if (type == IMAGE_TLV_SEC_CNT) { + case IMAGE_TLV_SEC_CNT: + { /* * Verify the image's security counter. * This must always be present. @@ -569,14 +655,21 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, /* The image's security counter has been successfully verified. */ security_counter_valid = fih_rc; + break; + } #endif /* MCUBOOT_HW_ROLLBACK_PROT */ } } +#if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE) rc = !image_hash_valid; if (rc) { goto out; } +#elif defined(MCUBOOT_SIGN_PURE) + /* This returns true on EQ, rc is err on non-0 */ + rc = FIH_NOT_EQ(valid_signature, FIH_SUCCESS); +#endif #ifdef EXPECTED_SIG_TLV FIH_SET(fih_rc, valid_signature); #endif diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index d930141925..cc5329a5e4 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -88,6 +88,22 @@ config BOOT_IMG_HASH_ALG_SHA512_ALLOW help Hidden option set by configurations that allow SHA512 +config BOOT_IMG_HASH_DIRECTLY_ON_STORAGE + bool "Hash calculation functions access storage through address space" + depends on !BOOT_ENCRYPT_IMAGE + help + When possible to map storage device, at least for read operations, + to address space or RAM area, enabling this option allows hash + calculation functions to directly access the storage through that address + space or using its own DMA. This reduces flash read overhead done + by MCUboot. + Notes: + - not supported when encrypted images are in use, because calculating + SHA requires image to be decrypted first, which is done in RAM. + - currently only supported on internal storage of devices; this + option will not work with devices that use external storage for + either of the image slots. + choice BOOT_IMG_HASH_ALG prompt "Selected image hash algorithm" default BOOT_IMG_HASH_ALG_SHA256 if BOOT_IMG_HASH_ALG_SHA256_ALLOW @@ -118,6 +134,14 @@ config BOOT_IMG_HASH_ALG_SHA512 endchoice # BOOT_IMG_HASH_ALG +config BOOT_SIGNATURE_TYPE_PURE_ALLOW + bool + help + Hidden option set by configurations that allow Pure variant, + for example ed25519. The pure variant means that image + signature is calculated over entire image instead of hash + of an image. + choice BOOT_SIGNATURE_TYPE prompt "Signature type" default BOOT_SIGNATURE_TYPE_RSA @@ -167,16 +191,35 @@ endif config BOOT_SIGNATURE_TYPE_ED25519 bool "Edwards curve digital signatures using ed25519" - select BOOT_ENCRYPTION_SUPPORT - select BOOT_IMG_HASH_ALG_SHA256_ALLOW + select BOOT_ENCRYPTION_SUPPORT if !BOOT_SIGNATURE_TYPE_PURE + select BOOT_IMG_HASH_ALG_SHA256_ALLOW if !BOOT_SIGNATURE_TYPE_PURE + # The SHA is used only for key hashing, not for images. + select BOOT_SIGNATURE_TYPE_PURE_ALLOW + help + This is ed25519 signature calculated over SHA512 of SHA256 of application + image. + To check signature over entire image directly, rather than hash, + select BOOT_SIGNATURE_TYPE_PURE. if BOOT_SIGNATURE_TYPE_ED25519 + +config BOOT_SIGNATURE_TYPE_PURE + bool "Use Pure signature of image" + depends on BOOT_SIGNATURE_TYPE_PURE_ALLOW + help + The Pure signature is calculated directly over image rather than + hash of an image, as the BOOT_SIGNATURE_TYPE_ED25519 does by + default. + Image to be verified needs to be accessible through memory address + space that cryptography functions can access via pointers. + choice BOOT_ED25519_IMPLEMENTATION prompt "Ecdsa implementation" default BOOT_ED25519_TINYCRYPT config BOOT_ED25519_TINYCRYPT bool "Use tinycrypt" select BOOT_USE_TINYCRYPT + select BOOT_IMG_HASH_ALG_SHA512_ALLOW config BOOT_ED25519_MBEDTLS bool "Use mbedTLS" select BOOT_USE_MBEDTLS diff --git a/boot/zephyr/include/mcuboot_config/mcuboot_config.h b/boot/zephyr/include/mcuboot_config/mcuboot_config.h index 60fb8e6009..b15c1682ff 100644 --- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h +++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h @@ -149,6 +149,17 @@ #define MCUBOOT_DECOMPRESS_IMAGES #endif +/* Invoke hashing functions directly on storage device. This requires the device + * be able to map storage to address space or RAM. + */ +#ifdef CONFIG_BOOT_IMG_HASH_DIRECTLY_ON_STORAGE +#define MCUBOOT_HASH_STORAGE_DIRECTLY +#endif + +#ifdef CONFIG_BOOT_SIGNATURE_TYPE_PURE +#define MCUBOOT_SIGN_PURE +#endif + #ifdef CONFIG_BOOT_BOOTSTRAP #define MCUBOOT_BOOTSTRAP 1 #endif diff --git a/docs/design.md b/docs/design.md index 7fa06fe6ba..b1979a7c2f 100755 --- a/docs/design.md +++ b/docs/design.md @@ -111,6 +111,8 @@ struct image_tlv { #define IMAGE_TLV_ECDSA_SIG 0x22 /* ECDSA of hash output */ #define IMAGE_TLV_RSA3072_PSS 0x23 /* RSA3072 of hash output */ #define IMAGE_TLV_ED25519 0x24 /* ED25519 of hash output */ +#define IMAGE_TLV_SIG_PURE 0x25 /* If true then any signature found has been + calculated over image directly. */ #define IMAGE_TLV_ENC_RSA2048 0x30 /* Key encrypted with RSA-OAEP-2048 */ #define IMAGE_TLV_ENC_KW 0x31 /* Key encrypted with AES-KW-128 or 256 */