diff --git a/boot/bootutil/CMakeLists.txt b/boot/bootutil/CMakeLists.txt index b6abb7fff7..9873f87e7f 100644 --- a/boot/bootutil/CMakeLists.txt +++ b/boot/bootutil/CMakeLists.txt @@ -33,6 +33,7 @@ target_sources(bootutil src/image_rsa.c src/image_validate.c src/loader.c + src/sha.c src/swap_misc.c src/swap_move.c src/swap_scratch.c diff --git a/boot/bootutil/include/bootutil/crypto/hmac_sha256.h b/boot/bootutil/include/bootutil/crypto/hmac_sha256.h deleted file mode 100644 index e6840182c2..0000000000 --- a/boot/bootutil/include/bootutil/crypto/hmac_sha256.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * This module provides a thin abstraction over some of the crypto - * primitives to make it easier to swap out the used crypto library. - * - * At this point, there are two choices: MCUBOOT_USE_MBED_TLS, or - * MCUBOOT_USE_TINYCRYPT. It is a compile error there is not exactly - * one of these defined. - */ - -#ifndef __BOOTUTIL_CRYPTO_HMAC_SHA256_H_ -#define __BOOTUTIL_CRYPTO_HMAC_SHA256_H_ - -#include "mcuboot_config/mcuboot_config.h" - -#if (defined(MCUBOOT_USE_MBED_TLS) + \ - defined(MCUBOOT_USE_TINYCRYPT)) != 1 - #error "One crypto backend must be defined: either MBED_TLS or TINYCRYPT" -#endif - -#if defined(MCUBOOT_USE_MBED_TLS) - #include - #include - #include - #include -#endif /* MCUBOOT_USE_MBED_TLS */ - -#if defined(MCUBOOT_USE_TINYCRYPT) - #include - #include - #include - #include -#endif /* MCUBOOT_USE_TINYCRYPT */ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(MCUBOOT_USE_TINYCRYPT) -typedef struct tc_hmac_state_struct bootutil_hmac_sha256_context; -static inline void bootutil_hmac_sha256_init(bootutil_hmac_sha256_context *ctx) -{ - (void)ctx; -} - -static inline void bootutil_hmac_sha256_drop(bootutil_hmac_sha256_context *ctx) -{ - (void)ctx; -} - -static inline int bootutil_hmac_sha256_set_key(bootutil_hmac_sha256_context *ctx, const uint8_t *key, unsigned int key_size) -{ - int rc; - rc = tc_hmac_set_key(ctx, key, key_size); - if (rc != TC_CRYPTO_SUCCESS) { - return -1; - } - rc = tc_hmac_init(ctx); - if (rc != TC_CRYPTO_SUCCESS) { - return -1; - } - return 0; -} - -static inline int bootutil_hmac_sha256_update(bootutil_hmac_sha256_context *ctx, const void *data, unsigned int data_length) -{ - int rc; - rc = tc_hmac_update(ctx, data, data_length); - if (rc != TC_CRYPTO_SUCCESS) { - return -1; - } - return 0; -} - -static inline int bootutil_hmac_sha256_finish(bootutil_hmac_sha256_context *ctx, uint8_t *tag, unsigned int taglen) -{ - int rc; - rc = tc_hmac_final(tag, taglen, ctx); - if (rc != TC_CRYPTO_SUCCESS) { - return -1; - } - return 0; -} -#endif /* MCUBOOT_USE_TINYCRYPT */ - -#if defined(MCUBOOT_USE_MBED_TLS) -/** - * The generic message-digest context. - */ -typedef mbedtls_md_context_t bootutil_hmac_sha256_context; - -static inline void bootutil_hmac_sha256_init(bootutil_hmac_sha256_context *ctx) -{ - mbedtls_md_init(ctx); -} - -static inline void bootutil_hmac_sha256_drop(bootutil_hmac_sha256_context *ctx) -{ - mbedtls_md_free(ctx); -} - -static inline int bootutil_hmac_sha256_set_key(bootutil_hmac_sha256_context *ctx, const uint8_t *key, unsigned int key_size) -{ - int rc; - - rc = mbedtls_md_setup(ctx, mbedtls_md_info_from_string("SHA256"), 1); - if (rc != 0) { - return rc; - } - rc = mbedtls_md_hmac_starts(ctx, key, key_size); - return rc; -} - -static inline int bootutil_hmac_sha256_update(bootutil_hmac_sha256_context *ctx, const void *data, unsigned int data_length) -{ - return mbedtls_md_hmac_update(ctx, data, data_length); -} - -static inline int bootutil_hmac_sha256_finish(bootutil_hmac_sha256_context *ctx, uint8_t *tag, unsigned int taglen) -{ - (void)taglen; - /* - * HMAC the key and check that our received MAC matches the generated tag - */ - return mbedtls_md_hmac_finish(ctx, tag); -} -#endif /* MCUBOOT_USE_MBED_TLS */ - -#ifdef __cplusplus -} -#endif - -#endif /* __BOOTUTIL_CRYPTO_HMAC_SHA256_H_ */ diff --git a/boot/bootutil/include/bootutil/crypto/sha.h b/boot/bootutil/include/bootutil/crypto/sha.h index 6a009ff95c..916e5c6263 100644 --- a/boot/bootutil/include/bootutil/crypto/sha.h +++ b/boot/bootutil/include/bootutil/crypto/sha.h @@ -4,6 +4,7 @@ * Copyright (c) 2017-2019 Linaro LTD * Copyright (c) 2017-2019 JUUL Labs * Copyright (c) 2021-2023 Arm Limited + * Copyright (c) 2025 Siemens AG */ /* @@ -81,6 +82,7 @@ #include #endif /* MCUBOOT_USE_CC310 */ +#include #include #ifdef __cplusplus @@ -89,177 +91,179 @@ extern "C" { #if defined(MCUBOOT_USE_PSA_CRYPTO) -typedef psa_hash_operation_t bootutil_sha_context; +typedef struct { + psa_hash_operation_t operation; + psa_status_t status; +} bootutil_sha_context; -static inline int bootutil_sha_init(bootutil_sha_context *ctx) +static inline void bootutil_sha_init(bootutil_sha_context *ctx) { - *ctx = psa_hash_operation_init(); + ctx->operation = psa_hash_operation_init(); #if defined(MCUBOOT_SHA512) - psa_status_t status = psa_hash_setup(ctx, PSA_ALG_SHA_512); + ctx->status = psa_hash_setup(&ctx->operation, PSA_ALG_SHA_512); #elif defined(MCUBOOT_SIGN_EC384) - psa_status_t status = psa_hash_setup(ctx, PSA_ALG_SHA_384); + ctx->status = psa_hash_setup(&ctx->operation, PSA_ALG_SHA_384); #else - psa_status_t status = psa_hash_setup(ctx, PSA_ALG_SHA_256); + ctx->status = psa_hash_setup(&ctx->operation, PSA_ALG_SHA_256); #endif - return (int)status; } -static inline int bootutil_sha_drop(bootutil_sha_context *ctx) +static inline void bootutil_sha_drop(bootutil_sha_context *ctx) { - return (int)psa_hash_abort(ctx); + psa_hash_abort(&ctx->operation); } -static inline int bootutil_sha_update(bootutil_sha_context *ctx, +static inline void bootutil_sha_update(bootutil_sha_context *ctx, const void *data, uint32_t data_len) { - return (int)psa_hash_update(ctx, data, data_len); + if (ctx->status) { + return; + } + ctx->status = psa_hash_update(&ctx->operation, data, data_len); } static inline int bootutil_sha_finish(bootutil_sha_context *ctx, uint8_t *output) { - size_t hash_length = 0; - /* Assumes the output buffer is at least the expected size of the hash */ -#if defined(MCUBOOT_SHA512) - return (int)psa_hash_finish(ctx, output, PSA_HASH_LENGTH(PSA_ALG_SHA_512), &hash_length); -#elif defined(MCUBOOT_SIGN_EC384) - return (int)psa_hash_finish(ctx, output, PSA_HASH_LENGTH(PSA_ALG_SHA_384), &hash_length); -#else - return (int)psa_hash_finish(ctx, output, PSA_HASH_LENGTH(PSA_ALG_SHA_256), &hash_length); -#endif + size_t hash_length; + + if (ctx->status) { + return (int)ctx->status; + } + return (int)psa_hash_finish(&ctx->operation, output, IMAGE_HASH_SIZE, &hash_length); } #elif defined(MCUBOOT_USE_MBED_TLS) +typedef struct { #ifdef MCUBOOT_SHA512 -typedef mbedtls_sha512_context bootutil_sha_context; + mbedtls_sha512_context mbedtls_ctx; #else -typedef mbedtls_sha256_context bootutil_sha_context; + mbedtls_sha256_context mbedtls_ctx; #endif + int error_code; +} bootutil_sha_context; -static inline int bootutil_sha_init(bootutil_sha_context *ctx) +static inline void bootutil_sha_init(bootutil_sha_context *ctx) { - int ret; - #ifdef MCUBOOT_SHA512 - mbedtls_sha512_init(ctx); - ret = mbedtls_sha512_starts_ret(ctx, 0); + mbedtls_sha512_init(&ctx->mbedtls_ctx); + ctx->error_code = mbedtls_sha512_starts_ret(&ctx->mbedtls_ctx, 0); #else - mbedtls_sha256_init(ctx); - ret = mbedtls_sha256_starts_ret(ctx, 0); + mbedtls_sha256_init(&ctx->mbedtls_ctx); + ctx->error_code = mbedtls_sha256_starts_ret(&ctx->mbedtls_ctx, 0); #endif - - return ret; } -static inline int bootutil_sha_drop(bootutil_sha_context *ctx) +static inline void bootutil_sha_drop(bootutil_sha_context *ctx) { #ifdef MCUBOOT_SHA512 - mbedtls_sha512_free(ctx); + mbedtls_sha512_free(&ctx->mbedtls_ctx); #else - mbedtls_sha256_free(ctx); + mbedtls_sha256_free(&ctx->mbedtls_ctx); #endif - - return 0; } -static inline int bootutil_sha_update(bootutil_sha_context *ctx, +static inline void bootutil_sha_update(bootutil_sha_context *ctx, const void *data, uint32_t data_len) { - int ret; - + if (ctx->error_code) { + return; + } #ifdef MCUBOOT_SHA512 - ret = mbedtls_sha512_update_ret(ctx, data, data_len); + ctx->error_code = mbedtls_sha512_update_ret(&ctx->mbedtls_ctx, data, data_len); #else - ret = mbedtls_sha256_update_ret(ctx, data, data_len); + ctx->error_code = mbedtls_sha256_update_ret(&ctx->mbedtls_ctx, data, data_len); #endif - - return ret; } static inline int bootutil_sha_finish(bootutil_sha_context *ctx, uint8_t *output) { - int ret; - + if (ctx->error_code) { + return ctx->error_code; + } #ifdef MCUBOOT_SHA512 - ret = mbedtls_sha512_finish_ret(ctx, output); + return mbedtls_sha512_finish_ret(&ctx->mbedtls_ctx, output); #else - ret = mbedtls_sha256_finish_ret(ctx, output); + return mbedtls_sha256_finish_ret(&ctx->mbedtls_ctx, output); #endif - - return ret; } #endif /* MCUBOOT_USE_MBED_TLS */ #if defined(MCUBOOT_USE_TINYCRYPT) + +typedef struct { #if defined(MCUBOOT_SHA512) -typedef struct tc_sha512_state_struct bootutil_sha_context; + struct tc_sha512_state_struct state_struct; #else -typedef struct tc_sha256_state_struct bootutil_sha_context; + struct tc_sha256_state_struct state_struct; #endif + int status; +} bootutil_sha_context; -static inline int bootutil_sha_init(bootutil_sha_context *ctx) +static inline void bootutil_sha_init(bootutil_sha_context *ctx) { #if defined(MCUBOOT_SHA512) - tc_sha512_init(ctx); + ctx->status = tc_sha512_init(&ctx->state_struct); #else - tc_sha256_init(ctx); + ctx->status = tc_sha256_init(&ctx->state_struct); #endif - return 0; } -static inline int bootutil_sha_drop(bootutil_sha_context *ctx) +static inline void bootutil_sha_drop(bootutil_sha_context *ctx) { (void)ctx; - return 0; } -static inline int bootutil_sha_update(bootutil_sha_context *ctx, - const void *data, - uint32_t data_len) +static inline void bootutil_sha_update(bootutil_sha_context *ctx, + const void *data, + uint32_t data_len) { + if (ctx->status == TC_CRYPTO_FAIL) { + return; + } #if defined(MCUBOOT_SHA512) - return tc_sha512_update(ctx, data, data_len); + ctx->status = tc_sha512_update(&ctx->state_struct, data, data_len); #else - return tc_sha256_update(ctx, data, data_len); + ctx->status = tc_sha256_update(&ctx->state_struct, data, data_len); #endif } static inline int bootutil_sha_finish(bootutil_sha_context *ctx, uint8_t *output) { + if (ctx->status == TC_CRYPTO_FAIL) { + return 1; + } #if defined(MCUBOOT_SHA512) - return tc_sha512_final(output, ctx); + return TC_CRYPTO_FAIL == tc_sha512_final(output, &ctx->state_struct); #else - return tc_sha256_final(output, ctx); + return TC_CRYPTO_FAIL == tc_sha256_final(output, &ctx->state_struct); #endif } #endif /* MCUBOOT_USE_TINYCRYPT */ #if defined(MCUBOOT_USE_CC310) -static inline int bootutil_sha_init(bootutil_sha_context *ctx) +static inline void bootutil_sha_init(bootutil_sha_context *ctx) { cc310_sha256_init(ctx); - return 0; } -static inline int bootutil_sha_drop(bootutil_sha_context *ctx) +static inline void bootutil_sha_drop(bootutil_sha_context *ctx) { (void)ctx; nrf_cc310_disable(); - return 0; } -static inline int bootutil_sha_update(bootutil_sha_context *ctx, - const void *data, - uint32_t data_len) +static inline void bootutil_sha_update(bootutil_sha_context *ctx, + const void *data, + uint32_t data_len) { cc310_sha256_update(ctx, data, data_len); - return 0; } static inline int bootutil_sha_finish(bootutil_sha_context *ctx, @@ -270,6 +274,83 @@ static inline int bootutil_sha_finish(bootutil_sha_context *ctx, } #endif /* MCUBOOT_USE_CC310 */ +/** + * Does bootutil_sha_init, bootutil_sha_update, and bootutil_sha_finish at once. + * + * @param data Pointer to the data to hash. + * @param data_len Length of @c data in bytes. + * @param digest Pointer to where the resulting digest shall be stored. + * + * @return @c 0 on success and nonzero otherwise. + */ +int bootutil_sha(const uint8_t *data, size_t data_len, + uint8_t digest[static IMAGE_HASH_SIZE]); + +/** + * Computes an HMAC as per RFC 2104. + * + * @param key The key to authenticate with. + * @param key_len Length of @c key in bytes. + * @param data The data to authenticate. + * @param data_len Length of @c data in bytes. + * @param hmac Pointer to where the resulting HMAC shall be stored. + * + * @return @c 0 on success and nonzero otherwise. + */ +int bootutil_sha_hmac(const uint8_t *key, size_t key_len, + const uint8_t *data, size_t data_len, + uint8_t hmac[static IMAGE_HASH_SIZE]); + +/** + * Extracts a key as per RFC 5869. + * + * @param salt Optional salt value. + * @param salt_len Length of @c salt in bytes. + * @param ikm Input keying material. + * @param ikm_len Length of @c ikm in bytes. + * @param prk Pointer to where the extracted key shall be stored. + * + * @return @c 0 on success and nonzero otherwise. + */ +int bootutil_sha_hkdf_extract(const uint8_t *salt, size_t salt_len, + const uint8_t *ikm, size_t ikm_len, + uint8_t prk[static IMAGE_HASH_SIZE]); + +/** + * Expands a key as per RFC 5869. + * + * @param prk A pseudorandom key of at least @c IMAGE_HASH_SIZE bytes. + * @param prk_len Length of @c prk in bytes. + * @param info Optional context and application specific information. + * @param info_len Length of @c info in bytes. + * @param okm Output keying material. + * @param okm_len Length of @c okm in bytes (<= 255 * @c IMAGE_HASH_SIZE). + * + * @return @c 0 on success and nonzero otherwise. + */ +int bootutil_sha_hkdf_expand(const uint8_t *prk, size_t prk_len, + const uint8_t *info, size_t info_len, + uint8_t *okm, uint_fast16_t okm_len); + +/** + * Performs both extraction and expansion as per RFC 5869. + * + * @param salt Optional salt value. + * @param salt_len Length of @c salt in bytes. + * @param ikm Input keying material. + * @param ikm_len Length of @c ikm in bytes. + * @param info Optional context and application specific information. + * @param info_len Length of @c info in bytes. + * @param okm Output keying material. + * @param okm_len Length of @c okm in bytes (<= 255 * @c IMAGE_HASH_SIZE). + * + * @return @c 0 on success and nonzero otherwise. + */ +int bootutil_sha_hkdf(const uint8_t *salt, size_t salt_len, + const uint8_t *ikm, size_t ikm_len, + const uint8_t *info, size_t info_len, + uint8_t *okm, uint_fast16_t okm_len); + #ifdef __cplusplus } #endif diff --git a/boot/bootutil/src/bootutil_find_key.c b/boot/bootutil/src/bootutil_find_key.c index 0d958002a0..7079411c0b 100644 --- a/boot/bootutil/src/bootutil_find_key.c +++ b/boot/bootutil/src/bootutil_find_key.c @@ -55,9 +55,9 @@ BOOT_LOG_MODULE_DECLARE(mcuboot); #if !defined(MCUBOOT_HW_KEY) int bootutil_find_key(uint8_t *keyhash, uint8_t keyhash_len) { - bootutil_sha_context sha_ctx; int i; const struct bootutil_key *key; + int rc; uint8_t hash[IMAGE_HASH_SIZE]; BOOT_LOG_DBG("bootutil_find_key"); @@ -68,10 +68,11 @@ int bootutil_find_key(uint8_t *keyhash, uint8_t keyhash_len) for (i = 0; i < bootutil_key_cnt; i++) { key = &bootutil_keys[i]; - bootutil_sha_init(&sha_ctx); - bootutil_sha_update(&sha_ctx, key->key, *key->len); - bootutil_sha_finish(&sha_ctx, hash); - bootutil_sha_drop(&sha_ctx); + rc = bootutil_sha(key->key, *key->len, hash); + if (rc) { + BOOT_LOG_ERR("bootutil_find_key: bootutil_sha failed: %d", rc); + return -1; + } if (!memcmp(hash, keyhash, keyhash_len)) { return i; } @@ -82,7 +83,6 @@ int bootutil_find_key(uint8_t *keyhash, uint8_t keyhash_len) extern unsigned int pub_key_len; int bootutil_find_key(uint8_t image_index, uint8_t *key, uint16_t key_len) { - bootutil_sha_context sha_ctx; uint8_t hash[IMAGE_HASH_SIZE]; uint8_t key_hash[IMAGE_HASH_SIZE]; size_t key_hash_size = sizeof(key_hash); @@ -91,10 +91,11 @@ int bootutil_find_key(uint8_t image_index, uint8_t *key, uint16_t key_len) BOOT_LOG_DBG("bootutil_find_key: image_index %d", image_index); - bootutil_sha_init(&sha_ctx); - bootutil_sha_update(&sha_ctx, key, key_len); - bootutil_sha_finish(&sha_ctx, hash); - bootutil_sha_drop(&sha_ctx); + rc = bootutil_sha(key, key_len, hash); + if (rc) { + BOOT_LOG_ERR("bootutil_find_key: bootutil_sha failed: %d", rc); + return -1; + } rc = boot_retrieve_public_key_hash(image_index, key_hash, &key_hash_size); if (rc) { diff --git a/boot/bootutil/src/bootutil_img_hash.c b/boot/bootutil/src/bootutil_img_hash.c index 3643b3e7d5..db7e0f0a68 100644 --- a/boot/bootutil/src/bootutil_img_hash.c +++ b/boot/bootutil/src/bootutil_img_hash.c @@ -190,9 +190,9 @@ bootutil_img_hash(struct boot_loader_state *state, } #endif /* MCUBOOT_RAM_LOAD */ #endif /* MCUBOOT_HASH_STORAGE_DIRECTLY */ - bootutil_sha_finish(&sha_ctx, hash_result); + rc = bootutil_sha_finish(&sha_ctx, hash_result); bootutil_sha_drop(&sha_ctx); - return 0; + return rc; } #endif /* !MCUBOOT_SIGN_PURE */ diff --git a/boot/bootutil/src/encrypted.c b/boot/bootutil/src/encrypted.c index 9f86bb457b..682ace5692 100644 --- a/boot/bootutil/src/encrypted.c +++ b/boot/bootutil/src/encrypted.c @@ -4,6 +4,7 @@ * Copyright (c) 2018-2019 JUUL Labs * Copyright (c) 2019-2024 Arm Limited * Copyright (c) 2025 Nordic Semiconductor ASA + * Copyright (c) 2025 Siemens AG */ #include "mcuboot_config/mcuboot_config.h" @@ -33,7 +34,6 @@ #if defined(MCUBOOT_ENCRYPT_EC256) || defined(MCUBOOT_ENCRYPT_X25519) #include "bootutil/crypto/sha.h" -#include "bootutil/crypto/hmac_sha256.h" #include "mbedtls/oid.h" #include "mbedtls/asn1.h" #endif @@ -226,117 +226,6 @@ parse_priv_enckey(uint8_t **p, uint8_t *end, uint8_t *private_key) } #endif /* defined(MCUBOOT_ENCRYPT_X25519) */ -#if defined(MCUBOOT_ENCRYPT_EC256) || defined(MCUBOOT_ENCRYPT_X25519) -/* - * HKDF as described by RFC5869. - * - * @param ikm The input data to be derived. - * @param ikm_len Length of the input data. - * @param info An information tag. - * @param info_len Length of the information tag. - * @param okm Output of the KDF computation. - * @param okm_len On input the requested length; on output the generated length - */ -static int -hkdf(const uint8_t *ikm, size_t ikm_len, const uint8_t *info, size_t info_len, - uint8_t *okm, size_t *okm_len) -{ - bootutil_hmac_sha256_context hmac; - uint8_t salt[BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE]; - uint8_t prk[BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE]; - uint8_t T[BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE]; - size_t off; - size_t len; - uint8_t counter; - bool first; - int rc; - - /* - * Extract - */ - - if (ikm == NULL || okm == NULL || ikm_len == 0) { - return -1; - } - - bootutil_hmac_sha256_init(&hmac); - - memset(salt, 0, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE); - rc = bootutil_hmac_sha256_set_key(&hmac, salt, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE); - if (rc != 0) { - goto error; - } - - rc = bootutil_hmac_sha256_update(&hmac, ikm, ikm_len); - if (rc != 0) { - goto error; - } - - rc = bootutil_hmac_sha256_finish(&hmac, prk, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE); - if (rc != 0) { - goto error; - } - - bootutil_hmac_sha256_drop(&hmac); - - /* - * Expand - */ - - len = *okm_len; - counter = 1; - first = true; - for (off = 0; len > 0; off += BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE, ++counter) { - bootutil_hmac_sha256_init(&hmac); - - rc = bootutil_hmac_sha256_set_key(&hmac, prk, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE); - if (rc != 0) { - goto error; - } - - if (first) { - first = false; - } else { - rc = bootutil_hmac_sha256_update(&hmac, T, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE); - if (rc != 0) { - goto error; - } - } - - rc = bootutil_hmac_sha256_update(&hmac, info, info_len); - if (rc != 0) { - goto error; - } - - rc = bootutil_hmac_sha256_update(&hmac, &counter, 1); - if (rc != 0) { - goto error; - } - - rc = bootutil_hmac_sha256_finish(&hmac, T, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE); - if (rc != 0) { - goto error; - } - - bootutil_hmac_sha256_drop(&hmac); - - if (len > BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE) { - memcpy(&okm[off], T, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE); - len -= BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE; - } else { - memcpy(&okm[off], T, len); - len = 0; - } - } - - return 0; - -error: - bootutil_hmac_sha256_drop(&hmac); - return -1; -} -#endif /* MCUBOOT_ENCRYPT_EC256 || MCUBOOT_ENCRYPT_X25519 */ - #if !defined(MCUBOOT_ENC_BUILTIN_KEY) extern const struct bootutil_key bootutil_enc_key; @@ -380,9 +269,8 @@ int boot_decrypt_key(const uint8_t *buf, uint8_t *enckey) { #if defined(MCUBOOT_ENCRYPT_EC256) || defined(MCUBOOT_ENCRYPT_X25519) - bootutil_hmac_sha256_context hmac; bootutil_aes_ctr_context aes_ctr; - uint8_t tag[BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE]; + uint8_t tag[IMAGE_HASH_SIZE]; uint8_t shared[EC_SHARED_LEN]; uint8_t derived_key[BOOT_ENC_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE]; uint8_t private_key[EC_PRIVK_LEN]; @@ -392,6 +280,8 @@ boot_decrypt_key(const uint8_t *buf, uint8_t *enckey) bootutil_key_exchange_ctx pk_ctx; uint8_t *cp; uint8_t *cpend; +#endif +#if defined(MCUBOOT_ENCRYPT_RSA) size_t len; #endif struct bootutil_key *bootutil_enc_key = NULL; @@ -492,38 +382,21 @@ boot_decrypt_key(const uint8_t *buf, uint8_t *enckey) /* * Expand shared secret to create keys for AES-128-CTR + HMAC-SHA256 */ - - len = BOOT_ENC_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE; - rc = hkdf(shared, EC_SHARED_LEN, (uint8_t *)"MCUBoot_ECIES_v1", 16, - derived_key, &len); - if (rc != 0 || len != (BOOT_ENC_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE)) { + rc = bootutil_sha_hkdf(NULL, 0, + shared, EC_SHARED_LEN, + (uint8_t *)"MCUBoot_ECIES_v1", 16, + derived_key, BOOT_ENC_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE); + if (rc != 0) { return -1; } /* - * HMAC the key and check that our received MAC matches the generated tag - */ - - bootutil_hmac_sha256_init(&hmac); - - /* First BOOT_ENC_KEY_SIZE are used for decryption, remaining 32 bytes are used - * for MAC tag key + * First BOOT_ENC_KEY_SIZE bytes are used for decryption, remaining + * BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE bytes serve as HMAC key. */ - rc = bootutil_hmac_sha256_set_key(&hmac, &derived_key[BOOT_ENC_KEY_SIZE], 32); - if (rc != 0) { - (void)bootutil_hmac_sha256_drop(&hmac); - return -1; - } - - rc = bootutil_hmac_sha256_update(&hmac, &buf[EC_CIPHERKEY_INDEX], BOOT_ENC_KEY_SIZE); - if (rc != 0) { - (void)bootutil_hmac_sha256_drop(&hmac); - return -1; - } - - /* Assumes the tag buffer is at least sizeof(hmac_tag_size(state)) bytes */ - rc = bootutil_hmac_sha256_finish(&hmac, tag, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE); - (void)bootutil_hmac_sha256_drop(&hmac); + rc = bootutil_sha_hmac(&derived_key[BOOT_ENC_KEY_SIZE], BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE, + &buf[EC_CIPHERKEY_INDEX], BOOT_ENC_KEY_SIZE, + tag); if (rc != 0) { return -1; } diff --git a/boot/bootutil/src/sha.c b/boot/bootutil/src/sha.c new file mode 100644 index 0000000000..9d09aadefb --- /dev/null +++ b/boot/bootutil/src/sha.c @@ -0,0 +1,238 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2025 Siemens AG + */ + +#include "bootutil/crypto/sha.h" +#include "mcuboot_config/mcuboot_config.h" +#include +#include + +#if defined(MCUBOOT_USE_MBED_TLS) +#if defined(MBEDTLS_HKDF_C) +#include "mbedtls/hkdf.h" +#endif /* MBEDTLS_HKDF_C */ +#include "mbedtls/md.h" +#else /* MCUBOOT_USE_MBED_TLS */ +#include +#endif /* MCUBOOT_USE_MBED_TLS */ + +int +bootutil_sha(const uint8_t *const data, size_t data_len, + uint8_t digest[static IMAGE_HASH_SIZE]) +{ + bootutil_sha_context ctx; + int rc; + + bootutil_sha_init(&ctx); + bootutil_sha_update(&ctx, data, data_len); + rc = bootutil_sha_finish(&ctx, digest); + bootutil_sha_drop(&ctx); + return rc; +} + +#if defined(MCUBOOT_USE_MBED_TLS) + +static const mbedtls_md_type_t md_type = +#if defined(MCUBOOT_SHA512) + MBEDTLS_MD_SHA384; +#elif defined(MCUBOOT_SIGN_EC384) + MBEDTLS_MD_SHA384; +#else + MBEDTLS_MD_SHA256; +#endif /* MCUBOOT_SIGN */ + +int +bootutil_sha_hmac(const uint8_t *const key, size_t key_len, + const uint8_t *const data, size_t data_len, + uint8_t hmac[static IMAGE_HASH_SIZE]) +{ + return mbedtls_md_hmac(mbedtls_md_info_from_type(md_type), + key, key_len, + data, data_len, + hmac); +} + +#if defined(MBEDTLS_HKDF_C) +int +bootutil_sha_hkdf_extract(const uint8_t *const salt, size_t salt_len, + const uint8_t *const ikm, size_t ikm_len, + uint8_t prk[static IMAGE_HASH_SIZE]) +{ + return mbedtls_hkdf_extract(mbedtls_md_info_from_type(md_type), + salt, salt_len, + ikm, ikm_len, + prk); +} + +int +bootutil_sha_hkdf_expand(const uint8_t *const prk, size_t prk_len, + const uint8_t *const info, size_t info_len, + uint8_t *const okm, uint_fast16_t okm_len) +{ + return mbedtls_hkdf_expand(mbedtls_md_info_from_type(md_type), + prk, prk_len, + info, info_len, + okm, okm_len); +} + +int +bootutil_sha_hkdf(const uint8_t *const salt, size_t salt_len, + const uint8_t *const ikm, size_t ikm_len, + const uint8_t *const info, size_t info_len, + uint8_t *const okm, uint_fast16_t okm_len) +{ + return mbedtls_hkdf(mbedtls_md_info_from_type(md_type), + salt, salt_len, + ikm, ikm_len, + info, info_len, + okm, okm_len); +} +#endif /* MBEDTLS_HKDF_C */ +#else /* MCUBOOT_USE_MBED_TLS */ + +#if defined(MCUBOOT_SHA512) || defined(MCUBOOT_SIGN_EC384) +#define BLOCK_SIZE 128 +#else +#define BLOCK_SIZE BOOTUTIL_CRYPTO_SHA256_BLOCK_SIZE +#endif + +struct hmac_context { + bootutil_sha_context sha_ctx; + uint8_t opad[BLOCK_SIZE]; + int status; +}; + +static void +hmac_init(struct hmac_context *const hmac_ctx, + const uint8_t *key, size_t key_len) +{ + uint8_t hashed_key[IMAGE_HASH_SIZE]; + uint_fast8_t i; + uint8_t ipad[BLOCK_SIZE]; + + if (key_len > BLOCK_SIZE) { + hmac_ctx->status = bootutil_sha(key, key_len, hashed_key); + if (hmac_ctx->status) { + return; + } + key_len = IMAGE_HASH_SIZE; + key = hashed_key; + } else { + hmac_ctx->status = 0; + } + for (i = 0; i < key_len; i++) { + ipad[i] = key[i] ^ 0x36; + hmac_ctx->opad[i] = key[i] ^ 0x5c; + } + for (; i < BLOCK_SIZE; i++) { + ipad[i] = 0x36; + hmac_ctx->opad[i] = 0x5c; + } + bootutil_sha_init(&hmac_ctx->sha_ctx); + bootutil_sha_update(&hmac_ctx->sha_ctx, ipad, sizeof(ipad)); +} + +static void +hmac_update(struct hmac_context *const hmac_ctx, + const uint8_t *const data, size_t data_len) +{ + if (hmac_ctx->status) { + return; + } + bootutil_sha_update(&hmac_ctx->sha_ctx, data, data_len); +} + +static int +hmac_finish(struct hmac_context *const hmac_ctx, + uint8_t hmac[static IMAGE_HASH_SIZE]) +{ + if (hmac_ctx->status) { + return hmac_ctx->status; + } + hmac_ctx->status = bootutil_sha_finish(&hmac_ctx->sha_ctx, hmac); + bootutil_sha_drop(&hmac_ctx->sha_ctx); + if (hmac_ctx->status) { + return hmac_ctx->status; + } + bootutil_sha_init(&hmac_ctx->sha_ctx); + bootutil_sha_update(&hmac_ctx->sha_ctx, hmac_ctx->opad, sizeof(hmac_ctx->opad)); + bootutil_sha_update(&hmac_ctx->sha_ctx, hmac, IMAGE_HASH_SIZE); + hmac_ctx->status = bootutil_sha_finish(&hmac_ctx->sha_ctx, hmac); + bootutil_sha_drop(&hmac_ctx->sha_ctx); + return hmac_ctx->status; +} + +int +bootutil_sha_hmac(const uint8_t *const key, size_t key_len, + const uint8_t *const data, size_t data_len, + uint8_t hmac[static IMAGE_HASH_SIZE]) +{ + struct hmac_context hmac_ctx; + + hmac_init(&hmac_ctx, key, key_len); + hmac_update(&hmac_ctx, data, data_len); + return hmac_finish(&hmac_ctx, hmac); +} + +int +bootutil_sha_hkdf_extract(const uint8_t *const salt, size_t salt_len, + const uint8_t *const ikm, size_t ikm_len, + uint8_t prk[static IMAGE_HASH_SIZE]) +{ + return bootutil_sha_hmac(salt, salt_len, ikm, ikm_len, prk); +} + + +int +bootutil_sha_hkdf_expand(const uint8_t *const prk, size_t prk_len, + const uint8_t *const info, size_t info_len, + uint8_t *const okm, uint_fast16_t okm_len) +{ + uint_fast8_t n; + uint8_t i; + struct hmac_context hmac_ctx; + uint8_t t_i[IMAGE_HASH_SIZE]; + int rc; + + if (okm_len > 255 * IMAGE_HASH_SIZE) { + return 1; + } + n = okm_len / IMAGE_HASH_SIZE + (okm_len % IMAGE_HASH_SIZE ? 1 : 0); + + for (i = 1; i <= n; i++) { + hmac_init(&hmac_ctx, prk, prk_len); + if (i != 1) { + hmac_update(&hmac_ctx, t_i, sizeof(t_i)); + } + hmac_update(&hmac_ctx, info, info_len); + hmac_update(&hmac_ctx, &i, sizeof(i)); + rc = hmac_finish(&hmac_ctx, t_i); + if (rc) { + return rc; + } + memcpy(okm + ((i - 1) * IMAGE_HASH_SIZE), + t_i, + okm_len > IMAGE_HASH_SIZE ? IMAGE_HASH_SIZE : okm_len); + okm_len -= IMAGE_HASH_SIZE; + } + return 0; +} + +int +bootutil_sha_hkdf(const uint8_t *const salt, size_t salt_len, + const uint8_t *const ikm, size_t ikm_len, + const uint8_t *const info, size_t info_len, + uint8_t *const okm, uint_fast16_t okm_len) +{ + int rc; + uint8_t prk[IMAGE_HASH_SIZE]; + + rc = bootutil_sha_hkdf_extract(salt, salt_len, ikm, ikm_len, prk); + if (rc) { + return rc; + } + return bootutil_sha_hkdf_expand(prk, sizeof(prk), info, info_len, okm, okm_len); +} +#endif /* MCUBOOT_USE_MBED_TLS */ diff --git a/boot/espressif/CMakeLists.txt b/boot/espressif/CMakeLists.txt index e77eca83b9..a3bf3b7993 100644 --- a/boot/espressif/CMakeLists.txt +++ b/boot/espressif/CMakeLists.txt @@ -253,6 +253,7 @@ set(bootutil_srcs ${BOOTUTIL_DIR}/src/image_rsa.c ${BOOTUTIL_DIR}/src/image_validate.c ${BOOTUTIL_DIR}/src/loader.c + ${BOOTUTIL_DIR}/src/sha.c ${BOOTUTIL_DIR}/src/swap_misc.c ${BOOTUTIL_DIR}/src/swap_move.c ${BOOTUTIL_DIR}/src/swap_scratch.c diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 2053008559..0ae1539ef0 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -113,6 +113,7 @@ zephyr_library_sources( ${BOOT_DIR}/bootutil/src/bootutil_area.c ${BOOT_DIR}/bootutil/src/bootutil_loader.c ${BOOT_DIR}/bootutil/src/fault_injection_hardening.c + ${BOOT_DIR}/bootutil/src/sha.c ) if((CONFIG_BOOT_ENCRYPT_X25519 AND CONFIG_BOOT_ED25519_PSA) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index d9b80d570b..d51f081ec8 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -1,6 +1,7 @@ # Copyright (c) 2017-2020 Linaro Limited # Copyright (c) 2020 Arm Limited # Copyright (c) 2023 Nordic Semiconductor ASA +# Copyright (c) 2025 Siemens AG # # SPDX-License-Identifier: Apache-2.0 # @@ -175,6 +176,13 @@ config BOOT_IMG_HASH_ALG_SHA512_ALLOW help Hidden option set by configurations that allow SHA512 +config BOOT_SOMETHING_USES_HKDF + bool + select MBEDTLS_HKDF_C if BOOT_USE_MBEDTLS + select MBEDTLS_MD_C if BOOT_USE_MBEDTLS + help + Hidden option that should be selected when something requires HKDF. + config BOOT_IMG_HASH_DIRECTLY_ON_STORAGE bool "Hash calculation functions access storage through address space" depends on !BOOT_ENCRYPT_IMAGE @@ -699,11 +707,13 @@ config BOOT_ENCRYPT_RSA config BOOT_ENCRYPT_EC256 bool + select SOMETHING_USES_HKDF help Hidden option selecting EC256 encryption. config BOOT_ENCRYPT_X25519 bool + select SOMETHING_USES_HKDF help Hidden option selecting x25519 encryption. diff --git a/sim/mcuboot-sys/build.rs b/sim/mcuboot-sys/build.rs index 5276fbeb73..7c29fb9fa5 100644 --- a/sim/mcuboot-sys/build.rs +++ b/sim/mcuboot-sys/build.rs @@ -395,6 +395,7 @@ fn main() { conf.file("../../ext/mbedtls/library/constant_time.c"); conf.file("../../ext/mbedtls/library/nist_kw.c"); conf.file("../../ext/mbedtls/library/ecdh.c"); + conf.file("../../ext/mbedtls/library/hkdf.c"); conf.file("../../ext/mbedtls/library/md.c"); conf.file("../../ext/mbedtls/library/aes.c"); conf.file("../../ext/mbedtls/library/ecp.c"); @@ -448,6 +449,7 @@ fn main() { conf.file("../../ext/mbedtls/library/platform_util.c"); conf.file("../../ext/mbedtls/library/aes.c"); conf.file("../../ext/mbedtls/library/sha256.c"); + conf.file("../../ext/mbedtls/library/hkdf.c"); conf.file("../../ext/mbedtls/library/md.c"); conf.file("../../ext/mbedtls/library/sha512.c"); } @@ -495,6 +497,7 @@ fn main() { conf.file("../../boot/bootutil/src/bootutil_area.c"); conf.file("../../boot/bootutil/src/bootutil_loader.c"); conf.file("../../boot/bootutil/src/bootutil_public.c"); + conf.file("../../boot/bootutil/src/sha.c"); conf.file("../../boot/bootutil/src/tlv.c"); conf.file("../../boot/bootutil/src/fault_injection_hardening.c"); conf.file("csupport/run.c"); diff --git a/sim/mcuboot-sys/csupport/config-ec.h b/sim/mcuboot-sys/csupport/config-ec.h index 2ce3b8fc2e..c7cb7caa52 100644 --- a/sim/mcuboot-sys/csupport/config-ec.h +++ b/sim/mcuboot-sys/csupport/config-ec.h @@ -62,6 +62,7 @@ #define MBEDTLS_ECP_DP_SECP256R1_ENABLED #define MBEDTLS_ECP_NIST_OPTIM #define MBEDTLS_BIGNUM_C +#define MBEDTLS_HKDF_C #define MBEDTLS_MD_C #define MBEDTLS_OID_C #define MBEDTLS_SHA256_C diff --git a/sim/mcuboot-sys/csupport/config-ed25519.h b/sim/mcuboot-sys/csupport/config-ed25519.h index 09b3c21125..b042b8847a 100644 --- a/sim/mcuboot-sys/csupport/config-ed25519.h +++ b/sim/mcuboot-sys/csupport/config-ed25519.h @@ -57,6 +57,7 @@ /* mbed TLS modules */ #define MBEDTLS_ASN1_PARSE_C #define MBEDTLS_BIGNUM_C +#define MBEDTLS_HKDF_C #define MBEDTLS_MD_C #define MBEDTLS_OID_C #define MBEDTLS_SHA256_C