diff --git a/boot/boot_serial/src/boot_serial.c b/boot/boot_serial/src/boot_serial.c index 495488ca9..9b4e689bc 100644 --- a/boot/boot_serial/src/boot_serial.c +++ b/boot/boot_serial/src/boot_serial.c @@ -660,7 +660,7 @@ bs_list_set(uint8_t op, char *buf, int len) bool area_opened = false; state = boot_get_loader_state(); - boot_state_clear(state); + boot_state_init(state); rc = boot_open_all_flash_areas(state); if (rc != 0) { @@ -696,6 +696,7 @@ bs_list_set(uint8_t op, char *buf, int len) if (area_opened) { boot_close_all_flash_areas(state); } + boot_state_clear(state); if (rc != 0) { bs_rc_rsp(rc); diff --git a/boot/boot_serial/src/boot_serial_encryption.c b/boot/boot_serial/src/boot_serial_encryption.c index de1f8b57a..5ee5f98d6 100644 --- a/boot/boot_serial/src/boot_serial_encryption.c +++ b/boot/boot_serial/src/boot_serial_encryption.c @@ -31,7 +31,11 @@ boot_image_validate_encrypted(struct boot_loader_state *state, int rc; if (MUST_DECRYPT(fa_p, BOOT_CURR_IMG(state), hdr)) { +#ifdef MCUBOOT_EMBEDDED_ENC_KEY + rc = boot_en_take_key(bs->enckey[BOOT_SLOT_SECONDARY], BOOT_CUR_IMG(state), BOOT_SLOT_SECONDARY); +#else rc = boot_enc_load(state, BOOT_SLOT_SECONDARY, hdr, fa_p, bs); +#endif if (rc < 0) { FIH_RET(fih_rc); } @@ -235,7 +239,11 @@ decrypt_image_inplace(const struct flash_area *fa_p, #endif memset(&boot_data, 0, sizeof(struct boot_loader_state)); /* Load the encryption keys into cache */ +#ifdef MCUBOOT_EMBEDDED_ENC_KEY + rc = boot_take_enc_key(bs->enckey[BOOT_SLOT_PRIMARY], BOOT_CURR_IMG(state), BOOT_SLOT_PRIMARY); +#else rc = boot_enc_load(state, BOOT_SLOT_PRIMARY, hdr, fa_p, bs); +#endif if (rc < 0) { FIH_RET(fih_rc); } diff --git a/boot/bootutil/include/bootutil/bootutil.h b/boot/bootutil/include/bootutil/bootutil.h index 48d56d1a8..98e7fa992 100644 --- a/boot/bootutil/include/bootutil/bootutil.h +++ b/boot/bootutil/include/bootutil/bootutil.h @@ -96,6 +96,13 @@ fih_ret context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp); */ struct boot_loader_state *boot_get_loader_state(void); +/** + * Initialize boot_loader_state object + * + * @param state Bootloader state. + */ +void boot_state_init(struct boot_loader_state *state); + #if defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO) || defined(MCUBOOT_DATA_SHARING) /** * Returns pointer to array of image maximum sizes. diff --git a/boot/bootutil/include/bootutil/crypto/aes_ctr.h b/boot/bootutil/include/bootutil/crypto/aes_ctr.h index 88ae87c39..38a600228 100644 --- a/boot/bootutil/include/bootutil/crypto/aes_ctr.h +++ b/boot/bootutil/include/bootutil/crypto/aes_ctr.h @@ -10,8 +10,6 @@ #ifndef __BOOTUTIL_CRYPTO_AES_CTR_H_ #define __BOOTUTIL_CRYPTO_AES_CTR_H_ -#include - #include "mcuboot_config/mcuboot_config.h" #if (defined(MCUBOOT_USE_MBED_TLS) + \ @@ -19,136 +17,16 @@ #error "One crypto backend must be defined: either MBED_TLS or TINYCRYPT or PSA" #endif -#include "bootutil/enc_key_public.h" - #if defined(MCUBOOT_USE_MBED_TLS) - #include - #define BOOT_ENC_BLOCK_SIZE (16) + #include "bootutil/crypto/aes_ctr_mbedtls.h" #endif /* MCUBOOT_USE_MBED_TLS */ #if defined(MCUBOOT_USE_TINYCRYPT) - #include - #include - #include - #include - #if defined(MCUBOOT_AES_256) || (BOOT_ENC_KEY_SIZE != TC_AES_KEY_SIZE) - #error "Cannot use AES-256 for encryption with Tinycrypt library." - #endif - #define BOOT_ENC_BLOCK_SIZE TC_AES_BLOCK_SIZE + #include "bootutil/crypto/aes_ctr_tinycrypt.h" #endif /* MCUBOOT_USE_TINYCRYPT */ #if defined(MCUBOOT_USE_PSA_CRYPTO) - #include - #define BOOT_ENC_BLOCK_SIZE (16) -#endif - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(MCUBOOT_USE_PSA_CRYPTO) -typedef struct { - /* Fixme: This should not be, here, psa_key_id should be passed */ - uint8_t key[BOOT_ENC_KEY_SIZE]; -} bootutil_aes_ctr_context; - -void bootutil_aes_ctr_init(bootutil_aes_ctr_context *ctx); - -static inline void bootutil_aes_ctr_drop(bootutil_aes_ctr_context *ctx) -{ - memset(ctx, 0, sizeof(*ctx)); -} - -static inline int bootutil_aes_ctr_set_key(bootutil_aes_ctr_context *ctx, const uint8_t *k) -{ - memcpy(ctx->key, k, sizeof(ctx->key)); - - return 0; -} - -int bootutil_aes_ctr_encrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, - const uint8_t *m, uint32_t mlen, size_t blk_off, uint8_t *c); -int bootutil_aes_ctr_decrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, - const uint8_t *c, uint32_t clen, size_t blk_off, uint8_t *m); -#endif - -#if defined(MCUBOOT_USE_MBED_TLS) -typedef mbedtls_aes_context bootutil_aes_ctr_context; -static inline void bootutil_aes_ctr_init(bootutil_aes_ctr_context *ctx) -{ - (void)mbedtls_aes_init(ctx); -} - -static inline void bootutil_aes_ctr_drop(bootutil_aes_ctr_context *ctx) -{ - mbedtls_aes_free(ctx); -} - -static inline int bootutil_aes_ctr_set_key(bootutil_aes_ctr_context *ctx, const uint8_t *k) -{ - return mbedtls_aes_setkey_enc(ctx, k, BOOT_ENC_KEY_SIZE * 8); -} - -static inline int bootutil_aes_ctr_encrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, const uint8_t *m, uint32_t mlen, size_t blk_off, uint8_t *c) -{ - uint8_t stream_block[BOOT_ENC_BLOCK_SIZE]; - return mbedtls_aes_crypt_ctr(ctx, mlen, &blk_off, counter, stream_block, m, c); -} - -static inline int bootutil_aes_ctr_decrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, const uint8_t *c, uint32_t clen, size_t blk_off, uint8_t *m) -{ - uint8_t stream_block[BOOT_ENC_BLOCK_SIZE]; - return mbedtls_aes_crypt_ctr(ctx, clen, &blk_off, counter, stream_block, c, m); -} -#endif /* MCUBOOT_USE_MBED_TLS */ - -#if defined(MCUBOOT_USE_TINYCRYPT) -typedef struct tc_aes_key_sched_struct bootutil_aes_ctr_context; -static inline void bootutil_aes_ctr_init(bootutil_aes_ctr_context *ctx) -{ - (void)ctx; -} - -static inline void bootutil_aes_ctr_drop(bootutil_aes_ctr_context *ctx) -{ - (void)ctx; -} - -static inline int bootutil_aes_ctr_set_key(bootutil_aes_ctr_context *ctx, const uint8_t *k) -{ - int rc; - rc = tc_aes128_set_encrypt_key(ctx, k); - if (rc != TC_CRYPTO_SUCCESS) { - return -1; - } - return 0; -} - -static int _bootutil_aes_ctr_crypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, const uint8_t *in, uint32_t inlen, uint32_t blk_off, uint8_t *out) -{ - int rc; - rc = tc_ctr_mode(out, inlen, in, inlen, counter, &blk_off, ctx); - if (rc != TC_CRYPTO_SUCCESS) { - return -1; - } - return 0; -} - -static inline int bootutil_aes_ctr_encrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, const uint8_t *m, uint32_t mlen, uint32_t blk_off, uint8_t *c) -{ - return _bootutil_aes_ctr_crypt(ctx, counter, m, mlen, blk_off, c); -} - -static inline int bootutil_aes_ctr_decrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, const uint8_t *c, uint32_t clen, uint32_t blk_off, uint8_t *m) -{ - return _bootutil_aes_ctr_crypt(ctx, counter, c, clen, blk_off, m); -} -#endif /* MCUBOOT_USE_TINYCRYPT */ - -#ifdef __cplusplus -} + #include "bootutil/crypto/aes_ctr_psa.h" #endif #endif /* __BOOTUTIL_CRYPTO_AES_CTR_H_ */ diff --git a/boot/bootutil/include/bootutil/crypto/aes_ctr_mbedtls.h b/boot/bootutil/include/bootutil/crypto/aes_ctr_mbedtls.h new file mode 100644 index 000000000..9e37aaa49 --- /dev/null +++ b/boot/bootutil/include/bootutil/crypto/aes_ctr_mbedtls.h @@ -0,0 +1,58 @@ +/* + * 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_AES_CTR_MBEDTLS_H_ +#define __BOOTUTIL_CRYPTO_AES_CTR_MBEDTLS_H_ + +#include +#include +#include "mcuboot_config/mcuboot_config.h" +#include "bootutil/enc_key_public.h" +#include + +#define BOOT_ENC_BLOCK_SIZE (16) + +#ifdef __cplusplus +extern "C" { +#endif + +typedef mbedtls_aes_context bootutil_aes_ctr_context; + +static inline void bootutil_aes_ctr_init(bootutil_aes_ctr_context *ctx) +{ + (void)mbedtls_aes_init(ctx); +} + +static inline void bootutil_aes_ctr_drop(bootutil_aes_ctr_context *ctx) +{ + mbedtls_aes_free(ctx); +} + +static inline int bootutil_aes_ctr_set_key(bootutil_aes_ctr_context *ctx, const uint8_t *k) +{ + return mbedtls_aes_setkey_enc(ctx, k, BOOT_ENC_KEY_SIZE * 8); +} + +static inline int bootutil_aes_ctr_encrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, const uint8_t *m, uint32_t mlen, size_t blk_off, uint8_t *c) +{ + uint8_t stream_block[BOOT_ENC_BLOCK_SIZE]; + return mbedtls_aes_crypt_ctr(ctx, mlen, &blk_off, counter, stream_block, m, c); +} + +static inline int bootutil_aes_ctr_decrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, const uint8_t *c, uint32_t clen, size_t blk_off, uint8_t *m) +{ + uint8_t stream_block[BOOT_ENC_BLOCK_SIZE]; + return mbedtls_aes_crypt_ctr(ctx, clen, &blk_off, counter, stream_block, c, m); +} + +#ifdef __cplusplus +} +#endif + +#endif /* __BOOTUTIL_CRYPTO_AES_CTR_MBEDTLS_H_ */ diff --git a/boot/bootutil/include/bootutil/crypto/aes_ctr_psa.h b/boot/bootutil/include/bootutil/crypto/aes_ctr_psa.h new file mode 100644 index 000000000..f6846b93c --- /dev/null +++ b/boot/bootutil/include/bootutil/crypto/aes_ctr_psa.h @@ -0,0 +1,41 @@ +/* + * 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_AES_CTR_PSA_H_ +#define __BOOTUTIL_CRYPTO_AES_CTR_PSA_H_ + +#include +#include +#include "mcuboot_config/mcuboot_config.h" +#include "bootutil/enc_key_public.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + psa_key_id_t key; +} bootutil_aes_ctr_context; + +void bootutil_aes_ctr_init(bootutil_aes_ctr_context *ctx); + +void bootutil_aes_ctr_drop(bootutil_aes_ctr_context *ctx); +int bootutil_aes_ctr_set_key(bootutil_aes_ctr_context *ctx, const uint8_t *k); + +int bootutil_aes_ctr_encrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, + const uint8_t *m, uint32_t mlen, size_t blk_off, uint8_t *c); +int bootutil_aes_ctr_decrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, + const uint8_t *c, uint32_t clen, size_t blk_off, uint8_t *m); + +#ifdef __cplusplus +} +#endif + +#endif /* __BOOTUTIL_CRYPTO_AES_CTR_H_ */ diff --git a/boot/bootutil/include/bootutil/crypto/aes_ctr_tinycrypt.h b/boot/bootutil/include/bootutil/crypto/aes_ctr_tinycrypt.h new file mode 100644 index 000000000..76831c4ef --- /dev/null +++ b/boot/bootutil/include/bootutil/crypto/aes_ctr_tinycrypt.h @@ -0,0 +1,77 @@ +/* + * 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_AES_CTR_TINYCRYPT_H_ +#define __BOOTUTIL_CRYPTO_AES_CTR_TINYCRYPT_H_ + +#include +#include +#include "mcuboot_config/mcuboot_config.h" +#include "bootutil/enc_key_public.h" + +#include +#include +#include + +#if defined(MCUBOOT_AES_256) || (BOOT_ENC_KEY_SIZE != TC_AES_KEY_SIZE) + #error "Cannot use AES-256 for encryption with Tinycrypt library." +#endif + +#define BOOT_ENC_BLOCK_SIZE TC_AES_BLOCK_SIZE + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct tc_aes_key_sched_struct bootutil_aes_ctr_context; +static inline void bootutil_aes_ctr_init(bootutil_aes_ctr_context *ctx) +{ + (void)ctx; +} + +static inline void bootutil_aes_ctr_drop(bootutil_aes_ctr_context *ctx) +{ + (void)ctx; +} + +static inline int bootutil_aes_ctr_set_key(bootutil_aes_ctr_context *ctx, const uint8_t *k) +{ + int rc; + rc = tc_aes128_set_encrypt_key(ctx, k); + if (rc != TC_CRYPTO_SUCCESS) { + return -1; + } + return 0; +} + +static int common_bootutil_aes_ctr_crypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, const uint8_t *in, uint32_t inlen, uint32_t blk_off, uint8_t *out) +{ + int rc; + rc = tc_ctr_mode(out, inlen, in, inlen, counter, &blk_off, ctx); + if (rc != TC_CRYPTO_SUCCESS) { + return -1; + } + return 0; +} + +static inline int bootutil_aes_ctr_encrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, const uint8_t *m, uint32_t mlen, uint32_t blk_off, uint8_t *c) +{ + return common_bootutil_aes_ctr_crypt(ctx, counter, m, mlen, blk_off, c); +} + +static inline int bootutil_aes_ctr_decrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, const uint8_t *c, uint32_t clen, uint32_t blk_off, uint8_t *m) +{ + return common_bootutil_aes_ctr_crypt(ctx, counter, c, clen, blk_off, m); +} + +#ifdef __cplusplus +} +#endif + +#endif /* __BOOTUTIL_CRYPTO_AES_CTR_TINYCRYPT_H_ */ diff --git a/boot/bootutil/include/bootutil/enc_key.h b/boot/bootutil/include/bootutil/enc_key.h index 6fa0db18e..461d4c00a 100644 --- a/boot/bootutil/include/bootutil/enc_key.h +++ b/boot/bootutil/include/bootutil/enc_key.h @@ -75,6 +75,9 @@ void boot_enc_decrypt(struct enc_key_data *enc_state, /* Note that boot_enc_zeorize takes BOOT_CURR_ENC, not BOOT_CURR_ENC_SLOT */ void boot_enc_zeroize(struct enc_key_data *enc_state); +/* Retrieve key for a slot */ +int boot_take_enc_key(uint8_t *key, int image, int slot); + #ifdef __cplusplus } #endif diff --git a/boot/bootutil/src/bootutil_loader.c b/boot/bootutil/src/bootutil_loader.c index 7a0e3a1f2..97184d63f 100644 --- a/boot/bootutil/src/bootutil_loader.c +++ b/boot/bootutil/src/bootutil_loader.c @@ -197,7 +197,11 @@ boot_check_image(struct boot_loader_state *state, struct boot_status *bs, int sl */ #if defined(MCUBOOT_ENC_IMAGES) && !defined(MCUBOOT_RAM_LOAD) if (MUST_DECRYPT(fap, BOOT_CURR_IMG(state), hdr)) { +#ifdef MCUBOOT_EMBEDDED_ENC_KEY + rc = boot_take_enc_key(bs->enckey[BOOT_SLOT_SECONDARY], BOOT_CURR_IMG(state), BOOT_SLOT_SECONDARY); +#else rc = boot_enc_load(state, BOOT_SLOT_SECONDARY, hdr, fap, bs); +#endif if (rc < 0) { FIH_RET(fih_rc); } @@ -434,3 +438,21 @@ boot_close_all_flash_areas(struct boot_loader_state *state) } } #endif /* !MCUBOOT_SINGLE_APPLICATION_SLOT_RAM_LOAD && !MCUBOOT_SINGLE_APPLICATION_SLOT */ + +void boot_state_init(struct boot_loader_state *state) +{ +#if defined(MCUBOOT_ENC_IMAGES) + int image; + int slot; +#endif + + memset(state, 0, sizeof(*state)); + +#if defined(MCUBOOT_ENC_IMAGES) + for (image = 0; image < BOOT_IMAGE_NUMBER; ++image) { + for (slot = 0; slot < BOOT_NUM_SLOTS; ++slot) { + boot_enc_init(&state->enc[image][slot]); + } + } +#endif +} diff --git a/boot/bootutil/src/bootutil_misc.c b/boot/bootutil/src/bootutil_misc.c index 648432381..502454cd0 100644 --- a/boot/bootutil/src/bootutil_misc.c +++ b/boot/bootutil/src/bootutil_misc.c @@ -240,33 +240,52 @@ boot_read_unprotected_tlv_sizes(const struct flash_area *fap, uint16_t *tlv_size } #endif -#ifdef MCUBOOT_ENC_IMAGES +#if defined(MCUBOOT_ENC_IMAGES) && !defined(MCUBOOT_EMBEDDED_ENC_KEY) int boot_read_enc_key(const struct flash_area *fap, uint8_t slot, struct boot_status *bs) { uint32_t off; -#if MCUBOOT_SWAP_SAVE_ENCTLV uint32_t i; -#endif int rc; + uint8_t *read_dst; + uint32_t read_size; - off = boot_enc_key_off(fap, slot); #if MCUBOOT_SWAP_SAVE_ENCTLV - rc = flash_area_read(fap, off, bs->enctlv[slot], BOOT_ENC_TLV_ALIGN_SIZE); + /* In this case we have stored entire encryted TLV in swap-state and bs->enckey + * will be decrypted from the TLV. + */ + BOOT_LOG_DBG("boot_read_enc_key: TLV"); + read_dst = bs->enctlv[slot]; + read_size = BOOT_ENC_TLV_ALIGN_SIZE; +#else + BOOT_LOG_DBG("boot_read_enc_key: RAW key"); + read_dst = bs->enckey[slot]; + read_size = BOOT_ENC_KEY_ALIGN_SIZE; +#endif + + off = boot_enc_key_off(fap, slot); + + rc = flash_area_read(fap, off, read_dst, read_size); if (rc == 0) { - for (i = 0; i < BOOT_ENC_TLV_ALIGN_SIZE; i++) { - if (bs->enctlv[slot][i] != 0xff) { + for (i = 0; i < read_size; i++) { + if (read_dst[i] != 0xff) { break; } } - /* Only try to decrypt non-erased TLV metadata */ - if (i != BOOT_ENC_TLV_ALIGN_SIZE) { + + if (i == read_size) { + BOOT_LOG_ERR("boot_read_enc_key: No key, read all 0xFF"); + rc = 1; + } +#if MCUBOOT_SWAP_SAVE_ENCTLV + else { + /* read_dst is the same as bs->enctlv[slot], and serves as a source + * of the encrypted key. + */ rc = boot_decrypt_key(bs->enctlv[slot], bs->enckey[slot]); } - } -#else - rc = flash_area_read(fap, off, bs->enckey[slot], BOOT_ENC_KEY_ALIGN_SIZE); #endif + } return rc; } @@ -678,15 +697,23 @@ const struct image_max_size *boot_get_max_app_size(void) * Clears the boot state, so that previous operations have no effect on new * ones. * - * @param state The state that should be cleared. If the value - * is NULL, the default bootloader state will be - * cleared. + * @param state The state that should be cleared. */ void boot_state_clear(struct boot_loader_state *state) { - if (state != NULL) { - memset(state, 0, sizeof(struct boot_loader_state)); - } else { - memset(boot_get_loader_state(), 0, sizeof(struct boot_loader_state)); +#if defined(MCUBOOT_ENC_IMAGES) + int image; + int slot; + + for (image = 0; image < BOOT_IMAGE_NUMBER; ++image) { + for (slot = 0; slot < BOOT_NUM_SLOTS; ++slot) { + /* Not using boot_enc_zeorize here, as it is redundant + * to the memset below that clears entire boot_loader_state. + */ + boot_enc_drop(&state->enc[image][slot]); + } } +#else + (void)state; +#endif } diff --git a/boot/bootutil/src/encrypted.c b/boot/bootutil/src/encrypted.c index 9f86bb457..049bf316a 100644 --- a/boot/bootutil/src/encrypted.c +++ b/boot/bootutil/src/encrypted.c @@ -370,6 +370,7 @@ static int fake_rng(void *p_rng, unsigned char *output, size_t len) #endif /* (MCUBOOT_ENCRYPT_RSA && MCUBOOT_USE_MBED_TLS && !MCUBOOT_USE_PSA_CRYPTO) || (MCUBOOT_ENCRYPT_EC256 && MCUBOOT_USE_MBED_TLS) */ +#if !defined(MCUBOOT_EMBEDDED_ENC_KEY) /* * Decrypt an encryption key TLV. * @@ -564,7 +565,9 @@ boot_decrypt_key(const uint8_t *buf, uint8_t *enckey) return rc; } #endif /* CONFIG_BOOT_ED25519_PSA && CONFIG_BOOT_ECDSA_PSA */ +#endif /* defined(MCUBOOT_EMBEDDED_ENC_KEY) */ +#if !defined(MCUBOOT_EMBEDDED_ENC_KEY) /* * Load encryption key. */ @@ -625,6 +628,7 @@ boot_enc_load(struct boot_loader_state *state, int slot, return boot_decrypt_key(buf, bs->enckey[slot]); } +#endif /* defined(MCUBOOT_EMBEDDED_ENC_KEY */ int boot_enc_init(struct enc_key_data *enc_state) diff --git a/boot/bootutil/src/encrypted_psa.c b/boot/bootutil/src/encrypted_psa.c index 1ef57184d..d6b470b94 100644 --- a/boot/bootutil/src/encrypted_psa.c +++ b/boot/bootutil/src/encrypted_psa.c @@ -190,12 +190,45 @@ void bootutil_aes_ctr_init(bootutil_aes_ctr_context *ctx) { psa_status_t psa_ret = psa_crypto_init(); - (void)ctx; - if (psa_ret != PSA_SUCCESS) { BOOT_LOG_ERR("AES init PSA crypto init failed %d", psa_ret); assert(0); } + + ctx->key = PSA_KEY_ID_NULL; +} + +void bootutil_aes_ctr_drop(bootutil_aes_ctr_context *ctx) +{ + psa_status_t psa_ret = psa_destroy_key(ctx->key); + + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_WRN("aes_ctr_drop: destruction failed %d", psa_ret); + /* This should never happen. If we fail to destroy key this happens + * either because it is invalid key number or something is really + * wrong; either way we have no way to recover. + */ + assert(0); + } + + ctx->key = PSA_KEY_ID_NULL; +} + +int bootutil_aes_ctr_set_key(bootutil_aes_ctr_context *ctx, const uint8_t *k) +{ + psa_status_t psa_ret = PSA_ERROR_BAD_STATE; + psa_key_attributes_t kattr = PSA_KEY_ATTRIBUTES_INIT; + + psa_set_key_type(&kattr, PSA_KEY_TYPE_AES); + psa_set_key_usage_flags(&kattr, PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_ENCRYPT); + psa_set_key_algorithm(&kattr, PSA_ALG_CTR); + + psa_ret = psa_import_key(&kattr, k, HKDF_AES_KEY_SIZE, &ctx->key); + if (psa_ret != PSA_SUCCESS) { + BOOT_LOG_ERR("aes_ctr_set_key; import failed %d", psa_ret); + return -1; + } + return 0; } #if defined(MCUBOOT_ENC_IMAGES) @@ -394,8 +427,7 @@ int bootutil_aes_ctr_encrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, { int ret = 0; psa_status_t psa_ret = PSA_ERROR_BAD_STATE; - psa_key_attributes_t kattr = PSA_KEY_ATTRIBUTES_INIT; - psa_key_id_t kid; + const psa_key_id_t kid = ctx->key; psa_cipher_operation_t psa_op; size_t elen = 0; /* Decrypted length */ @@ -411,21 +443,6 @@ int bootutil_aes_ctr_encrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, psa_op = psa_cipher_operation_init(); - /* Fixme: Import should happen when key is decrypted, but due to lack - * of key destruction there is no way to destroy key stored by - * psa other way than here. */ - psa_set_key_type(&kattr, PSA_KEY_TYPE_AES); - psa_set_key_usage_flags(&kattr, PSA_KEY_USAGE_ENCRYPT); - psa_set_key_algorithm(&kattr, PSA_ALG_CTR); - - psa_ret = psa_import_key(&kattr, ctx->key, BOOT_ENC_KEY_SIZE, &kid); - psa_reset_key_attributes(&kattr); - if (psa_ret != PSA_SUCCESS) { - BOOT_LOG_ERR("AES enc import key failed %d", psa_ret); - ret = -1; - goto gone; - } - /* This could be done with psa_cipher_decrypt one-shot operation, but * multi-part operation is used to avoid re-allocating input buffer * to account for IV in front of data. @@ -434,7 +451,7 @@ int bootutil_aes_ctr_encrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, if (psa_ret != PSA_SUCCESS) { BOOT_LOG_ERR("AES enc setup failed %d", psa_ret); ret = -1; - goto gone_with_key; + goto gone; } /* Fixme: hardcoded counter size, but it is hardcoded everywhere */ @@ -458,13 +475,6 @@ int bootutil_aes_ctr_encrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, BOOT_LOG_WRN("AES enc cipher abort failed %d", psa_ret); /* Intentionally not changing the ret */ } -gone_with_key: - /* Fixme: Should be removed once key is shared by id */ - psa_ret = psa_destroy_key(kid); - if (psa_ret != PSA_SUCCESS) { - BOOT_LOG_WRN("AES enc destroy key failed %d", psa_ret); - /* Intentionally not changing the ret */ - } gone: return ret; } @@ -474,8 +484,7 @@ int bootutil_aes_ctr_decrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, { int ret = 0; psa_status_t psa_ret = PSA_ERROR_BAD_STATE; - psa_key_attributes_t kattr = PSA_KEY_ATTRIBUTES_INIT; - psa_key_id_t kid; + const psa_key_id_t kid = ctx->key; psa_cipher_operation_t psa_op; size_t dlen = 0; /* Decrypted length */ @@ -491,21 +500,6 @@ int bootutil_aes_ctr_decrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, psa_op = psa_cipher_operation_init(); - /* Fixme: Import should happen when key is decrypted, but due to lack - * of key destruction there is no way to destroy key stored by - * psa other way than here. */ - psa_set_key_type(&kattr, PSA_KEY_TYPE_AES); - psa_set_key_usage_flags(&kattr, PSA_KEY_USAGE_DECRYPT); - psa_set_key_algorithm(&kattr, PSA_ALG_CTR); - - psa_ret = psa_import_key(&kattr, ctx->key, BOOT_ENC_KEY_SIZE, &kid); - psa_reset_key_attributes(&kattr); - if (psa_ret != PSA_SUCCESS) { - BOOT_LOG_ERR("AES dec import key failed %d", psa_ret); - ret = -1; - goto gone; - } - /* This could be done with psa_cipher_decrypt one-shot operation, but * multi-part operation is used to avoid re-allocating input buffer * to account for IV in front of data. @@ -514,7 +508,7 @@ int bootutil_aes_ctr_decrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, if (psa_ret != PSA_SUCCESS) { BOOT_LOG_ERR("AES dec setup failed %d", psa_ret); ret = -1; - goto gone_with_key; + goto gone; } /* Fixme: hardcoded counter size, but it is hardcoded everywhere */ @@ -538,12 +532,6 @@ int bootutil_aes_ctr_decrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, BOOT_LOG_WRN("PSA dec abort failed %d", psa_ret); /* Intentionally not changing the ret */ } -gone_with_key: - psa_ret = psa_destroy_key(kid); - if (psa_ret != PSA_SUCCESS) { - BOOT_LOG_WRN("PSA dec key failed %d", psa_ret); - /* Intentionally not changing the ret */ - } gone: return ret; } diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index b777b99cd..df23f82cb 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -1421,9 +1421,13 @@ boot_copy_image(struct boot_loader_state *state, struct boot_status *bs) #ifdef MCUBOOT_ENC_IMAGES if (IS_ENCRYPTED(boot_img_hdr(state, BOOT_SLOT_SECONDARY))) { +#ifdef MCUBOOT_EMBEDDED_ENC_KEY + rc = boot_take_enc_key(bs->enckey[BOOT_SLOT_SECONDARY], BOOT_CURR_IMG(state), BOOT_SLOT_SECONDARY); +#else rc = boot_enc_load(state, BOOT_SLOT_SECONDARY, boot_img_hdr(state, BOOT_SLOT_SECONDARY), fap_secondary_slot, bs); +#endif /* MCUBOOT_EMBEDDED_ENC_KEY */ if (rc < 0) { return BOOT_EBADIMAGE; @@ -1520,7 +1524,6 @@ boot_swap_image(struct boot_loader_state *state, struct boot_status *bs) const struct flash_area *fap; #ifdef MCUBOOT_ENC_IMAGES uint8_t slot; - uint8_t i; #endif uint32_t size; uint32_t copy_size; @@ -1546,7 +1549,11 @@ boot_swap_image(struct boot_loader_state *state, struct boot_status *bs) #ifdef MCUBOOT_ENC_IMAGES if (IS_ENCRYPTED(hdr)) { fap = BOOT_IMG_AREA(state, BOOT_SLOT_PRIMARY); +#ifdef MCUBOOT_EMBEDDED_ENC_KEY + rc = boot_take_enc_key(bs->enckey[BOOT_SLOT_PRIMARY], BOOT_CURR_IMG(state), BOOT_SLOT_PRIMARY); +#else rc = boot_enc_load(state, BOOT_SLOT_PRIMARY, hdr, fap, bs); +#endif /* MCUBOOT_EMBEDDED_ENC_KEY */ assert(rc >= 0); if (rc == 0) { @@ -1570,7 +1577,11 @@ boot_swap_image(struct boot_loader_state *state, struct boot_status *bs) hdr = boot_img_hdr(state, BOOT_SLOT_SECONDARY); if (IS_ENCRYPTED(hdr)) { fap = BOOT_IMG_AREA(state, BOOT_SLOT_SECONDARY); +#ifdef MCUBOOT_EMBEDDED_ENC_KEY + rc = boot_take_enc_key(bs->enckey[BOOT_SLOT_SECONDARY], BOOT_CURR_IMG(state), BOOT_SLOT_SECONDARY); +#else rc = boot_enc_load(state, BOOT_SLOT_SECONDARY, hdr, fap, bs); +#endif /* MCUBOOT_EMBEDDED_ENC_KEY */ assert(rc >= 0); if (rc == 0) { @@ -1607,20 +1618,19 @@ boot_swap_image(struct boot_loader_state *state, struct boot_status *bs) boot_enc_init(BOOT_CURR_ENC_SLOT(state, slot)); +#ifdef MCUBOOT_EMBEDDED_ENC_KEY + rc = boot_take_enc_key(bs->enckey[slot], image_index, slot); +#else rc = boot_read_enc_key(fap, slot, bs); - assert(rc == 0); - - for (i = 0; i < BOOT_ENC_KEY_SIZE; i++) { - if (bs->enckey[slot][i] != 0xff) { - break; - } - } - - if (i != BOOT_ENC_KEY_SIZE) { +#endif /* MCUBOOT_EMBEDDED_ENC_KEY */ + if (rc) { + BOOT_LOG_DBG("boot_swap_image: Failed loading key (%d, %d)", + image_index, slot); + } else { boot_enc_set_key(BOOT_CURR_ENC_SLOT(state, slot), bs->enckey[slot]); } } -#endif +#endif /* MCUBOOT_ENC_IMAGES */ flash_area_close(fap); } @@ -2960,9 +2970,12 @@ boot_go(struct boot_rsp *rsp) { FIH_DECLARE(fih_rc, FIH_FAILURE); - boot_state_clear(NULL); + boot_state_init(&boot_data); FIH_CALL(context_boot_go, fih_rc, &boot_data, rsp); + + boot_state_clear(&boot_data); + FIH_RET(fih_rc); } diff --git a/boot/bootutil/src/loader_manifest_xip.c b/boot/bootutil/src/loader_manifest_xip.c index abd60fcb1..f81880dcb 100644 --- a/boot/bootutil/src/loader_manifest_xip.c +++ b/boot/bootutil/src/loader_manifest_xip.c @@ -646,9 +646,12 @@ boot_go(struct boot_rsp *rsp) { FIH_DECLARE(fih_rc, FIH_FAILURE); - boot_state_clear(NULL); + boot_state_init(&boot_data); FIH_CALL(context_boot_go, fih_rc, &boot_data, rsp); + + boot_state_clear(&boot_data); + FIH_RET(fih_rc); } diff --git a/boot/mynewt/src/single_loader.c b/boot/mynewt/src/single_loader.c index 394fc372a..935d04881 100644 --- a/boot/mynewt/src/single_loader.c +++ b/boot/mynewt/src/single_loader.c @@ -49,6 +49,7 @@ boot_image_validate(const struct flash_area *fa_p, * was performed. We will try to validate the image, and if still * encrypted the validation will fail, and go in panic mode */ + BOOT_LOG_DBG("boot_image_validate: clearing encryption flags"); hdr->ih_flags &= ~(ENCRYPTIONFLAGS); } FIH_CALL(bootutil_img_validate, fih_rc, NULL, hdr, fa_p, tmpbuf, diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index f724da854..bdc7ecfa9 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -129,8 +129,7 @@ zephyr_library_sources( ${BOOT_DIR}/bootutil/src/fault_injection_hardening.c ) -if((CONFIG_BOOT_ENCRYPT_X25519 AND CONFIG_BOOT_ED25519_PSA) - OR (CONFIG_BOOT_ENCRYPT_EC256 AND CONFIG_BOOT_ECDSA_PSA)) +if(CONFIG_BOOT_ENCRYPT_IMAGE AND CONFIG_BOOT_USE_PSA_CRYPTO) zephyr_library_sources(${BOOT_DIR}/bootutil/src/encrypted_psa.c) endif() @@ -401,29 +400,19 @@ if(CONFIG_MCUBOOT_SERIAL) endif() endif() -if(NOT CONFIG_BOOT_SIGNATURE_USING_KMU AND NOT CONFIG_BOOT_SIGNATURE_KEY_FILE STREQUAL "") - # CONF_FILE points to the KConfig configuration files of the bootloader. - foreach (filepath ${CONF_FILE}) - file(READ ${filepath} temp_text) - string(FIND "${temp_text}" ${CONFIG_BOOT_SIGNATURE_KEY_FILE} match) - if (${match} GREATER_EQUAL 0) - if (NOT DEFINED CONF_DIR) - get_filename_component(CONF_DIR ${filepath} DIRECTORY) - else() - message(FATAL_ERROR "Signature key file defined in multiple conf files") - endif() - endif() - endforeach() +if(NOT CONFIG_BOOT_SIGNATURE_USING_KMU AND NOT CONFIG_BOOT_SIGNATURE_TYPE_NONE AND + NOT CONFIG_BOOT_SIGNATURE_KEY_FILE STREQUAL "") + set(key_file "${CONFIG_BOOT_SIGNATURE_KEY_FILE}") + string(CONFIGURE "${key_file}" key_file) - if(IS_ABSOLUTE ${CONFIG_BOOT_SIGNATURE_KEY_FILE}) - set(KEY_FILE ${CONFIG_BOOT_SIGNATURE_KEY_FILE}) - elseif((DEFINED CONF_DIR) AND - (EXISTS ${CONF_DIR}/${CONFIG_BOOT_SIGNATURE_KEY_FILE})) - set(KEY_FILE ${CONF_DIR}/${CONFIG_BOOT_SIGNATURE_KEY_FILE}) + if(IS_ABSOLUTE ${key_file}) + set(signing_key_file ${key_file}) + elseif(EXISTS ${APPLICATION_CONFIG_DIR}/${key_file}) + set(signing_key_file ${APPLICATION_CONFIG_DIR}/${key_file}) else() - set(KEY_FILE ${MCUBOOT_DIR}/${CONFIG_BOOT_SIGNATURE_KEY_FILE}) + set(signing_key_file ${MCUBOOT_DIR}/${key_file}) endif() - message("MCUBoot bootloader key file: ${KEY_FILE}") + message("MCUBoot bootloader key file: ${signing_key_file}") set_property( GLOBAL @@ -443,7 +432,7 @@ if(NOT CONFIG_BOOT_SIGNATURE_USING_KMU AND NOT CONFIG_BOOT_SIGNATURE_KEY_FILE ST ) # Emit a warning if using one of the default MCUboot key files - if(${KEY_FILE} IN_LIST mcuboot_default_signature_files) + if(${signing_key_file} IN_LIST mcuboot_default_signature_files) message(WARNING "WARNING: Using default MCUboot signing key file, this file is for debug use only and is not secure!") endif() @@ -455,65 +444,56 @@ if(NOT CONFIG_BOOT_SIGNATURE_USING_KMU AND NOT CONFIG_BOOT_SIGNATURE_KEY_FILE ST ${MCUBOOT_DIR}/scripts/imgtool.py getpub -k - ${KEY_FILE} + ${signing_key_file} > ${GENERATED_PUBKEY} - DEPENDS ${KEY_FILE} + DEPENDS ${signing_key_file} ) zephyr_library_sources(${GENERATED_PUBKEY}) endif() if(CONFIG_BOOT_ENCRYPTION_KEY_FILE AND NOT CONFIG_BOOT_ENCRYPTION_KEY_FILE STREQUAL "") - # CONF_FILE points to the KConfig configuration files of the bootloader. - unset(CONF_DIR) - foreach(filepath ${CONF_FILE}) - file(READ ${filepath} temp_text) - string(FIND "${temp_text}" ${CONFIG_BOOT_ENCRYPTION_KEY_FILE} match) - if(${match} GREATER_EQUAL 0) - if(NOT DEFINED CONF_DIR) - get_filename_component(CONF_DIR ${filepath} DIRECTORY) - else() - message(FATAL_ERROR "Encryption key file defined in multiple conf files") - endif() + if(CONFIG_BOOT_ENCRYPT_IMAGE_WITH_SHARED_KEY) + set(key_file "${CONFIG_BOOT_ENCRYPTION_KEY_FILE}") + string(CONFIGURE "${key_file}" key_file) + + if(IS_ABSOLUTE ${key_file}) + set(encryption_key_file ${key_file}) + elseif(EXISTS ${APPLICATION_CONFIG_DIR}/${key_file}) + set(encryption_key_file ${APPLICATION_CONFIG_DIR}/${key_file}) + else() + set(encryption_key_file ${MCUBOOT_DIR}/${key_file}) endif() - endforeach() + message("MCUBoot bootloader encryption key file: ${encryption_key_file}") + + # Emit a warning if using one of the default MCUboot key files + set(mcuboot_default_encryption_files + ${MCUBOOT_DIR}/enc-ec256-priv.pem + ${MCUBOOT_DIR}/enc-ec256-pub.pem + ${MCUBOOT_DIR}/enc-rsa2048-priv.pem + ${MCUBOOT_DIR}/enc-rsa2048-pub.pem + ${MCUBOOT_DIR}/enc-x25519-priv.pem + ${MCUBOOT_DIR}/enc-x25519-pub.pem + ) - if(IS_ABSOLUTE ${CONFIG_BOOT_ENCRYPTION_KEY_FILE}) - set(KEY_FILE ${CONFIG_BOOT_ENCRYPTION_KEY_FILE}) - elseif((DEFINED CONF_DIR) AND - (EXISTS ${CONF_DIR}/${CONFIG_BOOT_ENCRYPTION_KEY_FILE})) - set(KEY_FILE ${CONF_DIR}/${CONFIG_BOOT_ENCRYPTION_KEY_FILE}) - else() - set(KEY_FILE ${MCUBOOT_DIR}/${CONFIG_BOOT_ENCRYPTION_KEY_FILE}) - endif() - message("MCUBoot bootloader encryption key file: ${KEY_FILE}") + if(${encryption_key_file} IN_LIST mcuboot_default_encryption_files) + message(WARNING "WARNING: Using default MCUboot encryption key file, this file is for debug use only and is not secure!") + endif() - # Emit a warning if using one of the default MCUboot key files - set(mcuboot_default_encryption_files - ${MCUBOOT_DIR}/enc-ec256-priv.pem - ${MCUBOOT_DIR}/enc-ec256-pub.pem - ${MCUBOOT_DIR}/enc-rsa2048-priv.pem - ${MCUBOOT_DIR}/enc-rsa2048-pub.pem - ${MCUBOOT_DIR}/enc-x25519-priv.pem - ${MCUBOOT_DIR}/enc-x25519-pub.pem - ) + set(GENERATED_ENCKEY ${ZEPHYR_BINARY_DIR}/autogen-enckey.c) + add_custom_command( + OUTPUT ${GENERATED_ENCKEY} + COMMAND + ${PYTHON_EXECUTABLE} + ${MCUBOOT_DIR}/scripts/imgtool.py + getpriv + -k + ${encryption_key_file} + > ${GENERATED_ENCKEY} + DEPENDS ${encryption_key_file} + ) - if(${KEY_FILE} IN_LIST mcuboot_default_encryption_files) - message(WARNING "WARNING: Using default MCUboot encryption key file, this file is for debug use only and is not secure!") + zephyr_library_sources(${GENERATED_ENCKEY}) endif() - - set(GENERATED_ENCKEY ${ZEPHYR_BINARY_DIR}/autogen-enckey.c) - add_custom_command( - OUTPUT ${GENERATED_ENCKEY} - COMMAND - ${PYTHON_EXECUTABLE} - ${MCUBOOT_DIR}/scripts/imgtool.py - getpriv - -k - ${KEY_FILE} - > ${GENERATED_ENCKEY} - DEPENDS ${KEY_FILE} - ) - zephyr_library_sources(${GENERATED_ENCKEY}) endif() if(CONFIG_MCUBOOT_CLEANUP_ARM_CORE) @@ -627,7 +607,7 @@ if((CONFIG_BOOT_SWAP_USING_SCRATCH OR CONFIG_BOOT_SWAP_USING_MOVE OR CONFIG_BOOT zephyr_library_sources(flash_check.c) endif() -if(CONFIG_BOOT_RAM_LOAD) +if(CONFIG_MULTIPLE_EXECUTABLE_RAM_REGIONS_DEFAULT_FILE) zephyr_library_sources(ram_load.c) endif() @@ -823,3 +803,18 @@ if(SYSBUILD AND CONFIG_PCD_APP) set(RAM_FLASH_ADDR "${ram_flash_addr}" CACHE STRING "" FORCE) set(RAM_FLASH_SIZE "${ram_flash_size}" CACHE STRING "" FORCE) endif() + +if(${CONFIG_BOOT_ENCRYPT_IMAGE_GENERATE_BASIC_KEY_PROVIDER}) + # Need to generate single key provider source, from template. + # Take provided key, in form of a string and make it into C array, BOOT_AES_RAW_KEY_HEX_ARRAY, + # of byte size hex values. + set(BOOT_AES_RAW_KEY_HEX_STRING ${CONFIG_BOOT_ENCRYPT_IMAGE_EMBEDDED_RAW_KEY}) + string(REGEX REPLACE "(..)" "0x\\1, " BOOT_AES_RAW_KEY_HEX_ARRAY "${BOOT_AES_RAW_KEY_HEX_STRING}") + + # The tamplate references BOOT_AES_RAW_KEY_HEX_ARRAY where it expects the array to be substituted. + set(OUTPUT_BOOT_AES_RAW_KEY_SRC ${ZEPHYR_BINARY_DIR}/mcuboot_generated/builtin_aes_key_provider.c) + configure_file(templates/single_builtin_aes_key_provider.c.template ${OUTPUT_BOOT_AES_RAW_KEY_SRC} @ONLY) + + # Add generated source file to build + zephyr_library_sources(${OUTPUT_BOOT_AES_RAW_KEY_SRC}) +endif() diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index a99e0df2c..5d12ac4a3 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -96,15 +96,26 @@ config BOOT_ED25519_PSA_DEPENDENCIES if BOOT_ENCRYPT_IMAGE +config BOOT_AES_DEPENDENCIES + bool + default y if BOOT_USE_PSA_CRYPTO + select PSA_WANT_ALG_CTR + select PSA_WANT_KEY_TYPE_AES + select PSA_WANT_AES_KEY_SIZE_256 if BOOT_ENCRYPT_ALG_AES_256 + select PSA_WANT_AES_KEY_SIZE_128 if BOOT_ENCRYPT_ALG_AES_128 + help + PSA Dependencies for image encryption. At this point they select + AES CTR mode with support for key as selected by user. + +if !BOOT_ENCRYPT_IMAGE_WITH_EMBEDDED_KEY + config BOOT_X25519_PSA_DEPENDENCIES bool select PSA_WANT_ALG_ECDH select PSA_WANT_ALG_HMAC select PSA_WANT_ALG_HKDF - select PSA_WANT_ALG_CTR select PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT select PSA_WANT_KEY_TYPE_DERIVE - select PSA_WANT_KEY_TYPE_AES select PSA_WANT_ECC_MONTGOMERY_255 help Dependencies for x25519 shared-random key encryption and AES @@ -113,6 +124,8 @@ config BOOT_X25519_PSA_DEPENDENCIES to use with it; the others are used for shared key decryption and derivation. +endif # !BOOT_ENCRYPT_IMAGE_WITH_EMBEDDED_KEY + endif # BOOT_ENCRYPT_IMAGE config BOOT_ECDSA_PSA_DEPENDENCIES @@ -368,7 +381,7 @@ config BOOT_ED25519_PSA select BOOT_IMG_HASH_ALG_SHA256_ALLOW if !PSA_CORE_LITE select BOOT_IMG_HASH_ALG_SHA512_ALLOW if !PSA_CORE_LITE select BOOT_ED25519_PSA_DEPENDENCIES - select BOOT_X25519_PSA_DEPENDENCIES if BOOT_ENCRYPT_IMAGE + select BOOT_X25519_PSA_DEPENDENCIES if BOOT_ENCRYPT_IMAGE_WITH_SHARED_KEY endchoice @@ -466,6 +479,7 @@ if !BOOT_SIGNATURE_USING_KMU && !NCS_BOOT_SIGNATURE_USING_ITS config BOOT_SIGNATURE_KEY_FILE string "PEM key file" + depends on !BOOT_SIGNATURE_TYPE_NONE default "root-ec-p256.pem" if BOOT_SIGNATURE_TYPE_ECDSA_P256 default "root-ed25519.pem" if BOOT_SIGNATURE_TYPE_ED25519 default "root-rsa-3072.pem" if BOOT_SIGNATURE_TYPE_RSA && BOOT_SIGNATURE_TYPE_RSA_LEN=3072 @@ -474,13 +488,16 @@ config BOOT_SIGNATURE_KEY_FILE help You can use either absolute or relative path. In case relative path is used, the build system assumes that it starts - from the directory where the MCUBoot KConfig configuration file is - located. If the key file is not there, the build system uses relative - path that starts from the MCUBoot repository root directory. + from the APPLICATION_CONFIG_DIR directory. If the key file is not there, the build + system uses relative path that starts from the MCUBoot repository root directory. The key file will be parsed by imgtool's getpub command and a .c source with the public key information will be written in a format expected by MCUboot. + Note: In configuration files, escaped CMake variables can be used to refer to paths + e.g. \${CMAKE_CURRENT_LIST_DIR} will allow referencing a file in that directory, these + will be automatically configured by the build system. + endif config MCUBOOT_CLEANUP_ARM_CORE @@ -694,7 +711,8 @@ config BOOT_BOOTSTRAP config BOOT_SWAP_SAVE_ENCTLV bool "Save encrypted key TLVs instead of plaintext keys in swap metadata" - depends on BOOT_ENCRYPT_IMAGE + depends on BOOT_ENCRYPT_IMAGE_WITH_SHARED_KEY + depends on !BOOT_ENCRYPT_IMAGE_WITH_EMBEDDED_KEY help If y, instead of saving the encrypted image keys in plaintext in the swap resume metadata, save the encrypted image TLVs. This should be used @@ -736,6 +754,16 @@ config MULTIPLE_EXECUTABLE_RAM_REGIONS When selected, boot_get_image_exec_ram_info() should be updated to provide the information about the areas. +config MULTIPLE_EXECUTABLE_RAM_REGIONS_DEFAULT_FILE + bool "Default MCUboot multiple executable RAM region source file" + default y + depends on MULTIPLE_EXECUTABLE_RAM_REGIONS + help + When enabled, will include the default MCUboot file that has the + boot_get_image_exec_ram_info() implementation in it, for users with out-of-tree or + custom configuration then this option can be disabled and a custom file can be added + by a CMake module which defines the configuration for the intended board. + config FLASH_RUNTIME_SOURCES bool "Images are read from flash partitions defined at runtime" depends on SINGLE_APPLICATION_SLOT @@ -752,12 +780,62 @@ config BOOT_ENCRYPTION_SUPPORT help Hidden option used to check if image encryption is supported. -config BOOT_ENCRYPT_IMAGE - bool "Support for encrypted image updates" - depends on BOOT_ENCRYPTION_SUPPORT +config BOOT_ENCRYPT_IMAGE_WITH_EMBEDDED_KEY + bool "Use key that is already on board with MCUboot [EXPERIMENTAL]" + depends on BOOT_ENCRYPT_IMAGE + help + The key is supposed to be either compiled in or on board. + User is responsible for providing boot_enc_take_key + function that will be able to retrieve the key. + +if BOOT_ENCRYPT_IMAGE_WITH_EMBEDDED_KEY + +choice BOOT_ENCRYPT_IMAGE_EMBEDDED_KEY_PROVIDER + prompt "Embedded AES key provider" + default BOOT_ENCRYPT_IMAGE_GENERATE_BASIC_KEY_PROVIDER + +config BOOT_ENCRYPT_IMAGE_GENERATE_BASIC_KEY_PROVIDER + bool "Generate basic boot_enc_take_key" + depends on BOOT_ENCRYPT_IMAGE_WITH_EMBEDDED_KEY + help + Basic implementation of boot_enc_take_key will be implemented, + that will have single key built in, used for all images and + slots. + +config BOOT_ENCRYPT_IMAGE_USE_CUSTOM_KEY_PROVIDER + bool "User provides source code for key provider" + help + User is required to provide implementation for + the boot_enc_take_key function. + +endchoice # BOOT_ENCRYPT_IMAGE_EMBEDDED_KEY_PROVIDER + +config BOOT_ENCRYPT_IMAGE_EMBEDDED_RAW_KEY + string "Hexadecimal string representing AES key [EXPERIMENTAL]" + depends on BOOT_ENCRYPT_IMAGE_GENERATE_BASIC_KEY_PROVIDER + help + AES key in form of hexadecimal string that will be used to + generate boot_enc_take_key function, returning the key for + decryption and encryption of image. + The key character length should be the double of expected + AES key length in bytes. + +endif # BOOT_ENCRYPT_IMAGE_WITH_EMBEDDED_KEY + +config BOOT_ENCRYPT_IMAGE_WITH_SHARED_KEY + bool + default y if !BOOT_ENCRYPT_IMAGE_WITH_EMBEDDED_KEY + depends on BOOT_ENCRYPT_IMAGE select BOOT_ENCRYPT_RSA if BOOT_SIGNATURE_TYPE_RSA select BOOT_ENCRYPT_EC256 if BOOT_SIGNATURE_TYPE_ECDSA_P256 select BOOT_ENCRYPT_X25519 if BOOT_SIGNATURE_TYPE_ED25519 + help + Hidden option for default behaviour where AES encryption key + is derived from Public Key Cryptography key exchange. + +config BOOT_ENCRYPT_IMAGE + bool "Support for encrypted image updates" + depends on BOOT_ENCRYPTION_SUPPORT depends on !SINGLE_APPLICATION_SLOT || MCUBOOT_SERIAL help If y, images in the secondary slot can be encrypted and are decrypted @@ -846,13 +924,16 @@ config BOOT_ENCRYPTION_KEY_FILE help You can use either absolute or relative path. In case relative path is used, the build system assumes that it starts - from the directory where the MCUBoot KConfig configuration file is - located. If the key file is not there, the build system uses relative - path that starts from the MCUBoot repository root directory. + from the APPLICATION_CONFIG_DIR directory. If the key file is not there, the build + system uses relative path that starts from the MCUBoot repository root directory. The key file will be parsed by imgtool's getpriv command and a .c source with the public key information will be written in a format expected by MCUboot. + Note: In configuration files, escaped CMake variables can be used to refer to paths + e.g. \${CMAKE_CURRENT_LIST_DIR} will allow referencing a file in that directory, these + will be automatically configured by the build system. + config BOOT_MAX_IMG_SECTORS_AUTO bool "Calculate maximum sectors automatically" default y if !PARTITION_MANAGER_ENABLED diff --git a/boot/zephyr/include/mcuboot_config/mcuboot_config.h b/boot/zephyr/include/mcuboot_config/mcuboot_config.h index f67eea7a1..317ecb604 100644 --- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h +++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h @@ -157,6 +157,11 @@ #define MCUBOOT_USE_TLV_ALLOW_LIST 1 #endif +#ifdef CONFIG_BOOT_ENCRYPT_IMAGE_WITH_EMBEDDED_KEY +#define MCUBOOT_ENC_IMAGES +#define MCUBOOT_EMBEDDED_ENC_KEY +#endif + #ifdef CONFIG_BOOT_ENCRYPT_RSA #define MCUBOOT_ENC_IMAGES #define MCUBOOT_ENCRYPT_RSA diff --git a/boot/zephyr/ram_load.c b/boot/zephyr/ram_load.c index 92d521d80..85d054dcd 100644 --- a/boot/zephyr/ram_load.c +++ b/boot/zephyr/ram_load.c @@ -19,12 +19,10 @@ #include -#ifdef MULTIPLE_EXECUTABLE_RAM_REGIONS int boot_get_image_exec_ram_info(uint32_t image_id, uint32_t *exec_ram_start, uint32_t *exec_ram_size) { - #ifdef CONFIG_SOC_SERIES_STM32N6X *exec_ram_start = DT_PROP_BY_IDX(DT_NODELABEL(axisram1), reg, 0); *exec_ram_size = DT_PROP_BY_IDX(DT_NODELABEL(axisram1), reg, 1); @@ -32,4 +30,3 @@ int boot_get_image_exec_ram_info(uint32_t image_id, return 0; } -#endif /* MULTIPLE_EXECUTABLE_RAM_REGIONS */ diff --git a/boot/zephyr/templates/single_builtin_aes_key_provider.c.template b/boot/zephyr/templates/single_builtin_aes_key_provider.c.template new file mode 100644 index 000000000..ac3f9a78d --- /dev/null +++ b/boot/zephyr/templates/single_builtin_aes_key_provider.c.template @@ -0,0 +1,26 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2025 Nordic Semiconductor ASA + * + */ + +#include +#include +#include +#include +#include + +#include "mcuboot_config/mcuboot_config.h" +#include "bootutil/enc_key.h" + +int boot_take_enc_key(uint8_t *key, int image, int slot) +{ + const unsigned char array[] = { + @BOOT_AES_RAW_KEY_HEX_ARRAY@ + }; + + memcpy(key, array, sizeof(array)); + + return 0; +} diff --git a/scripts/imgtool/image.py b/scripts/imgtool/image.py index 4476b687e..3c5fc31d9 100755 --- a/scripts/imgtool/image.py +++ b/scripts/imgtool/image.py @@ -344,8 +344,8 @@ def __repr__(self): class Image: def __init__(self, version=None, header_size=IMAGE_HEADER_SIZE, - pad_header=False, pad=False, confirm=False, align=1, - slot_size=0, max_sectors=DEFAULT_MAX_SECTORS, + pad_header=False, pad=False, confirm=False, test=False, + align=1, slot_size=0, max_sectors=DEFAULT_MAX_SECTORS, overwrite_only=False, endian="little", load_addr=0, rom_fixed=None, erased_val=None, save_enctlv=False, security_counter=None, max_align=None, @@ -362,6 +362,7 @@ def __init__(self, version=None, header_size=IMAGE_HEADER_SIZE, self.pad_header = pad_header self.pad = pad self.confirm = confirm + self.test = test self.align = align self.slot_size = slot_size self.max_sectors = max_sectors @@ -494,12 +495,14 @@ def save(self, path, hex_addr=None): self.save_enctlv, self.enctlv_len) trailer_addr = (self.base_addr + self.slot_size) - trailer_size - if self.confirm and not self.overwrite_only: + if (self.test or self.confirm) and not self.overwrite_only: magic_align_size = align_up(len(self.boot_magic), self.max_align) image_ok_idx = -(magic_align_size + self.max_align) + # If test is set, we leave image_ok at the erased value flag = bytearray([self.erased_val] * self.max_align) - flag[0] = 0x01 # image_ok = 0x01 + if self.confirm: + flag[0] = 0x01 # image_ok = 0x01 h.puts(trailer_addr + trailer_size + image_ok_idx, bytes(flag)) h.puts(trailer_addr + (trailer_size - len(self.boot_magic)), @@ -567,7 +570,7 @@ def ecies_hkdf(self, enckey, plainkey, hmac_sha_alg): def create(self, key, public_key_format, enckey, dependencies=None, sw_type=None, custom_tlvs=None, compression_tlvs=None, - compression_type=None, encrypt_keylen=128, clear=False, + compression_type=None, aes_key=None, clear=False, fixed_sig=None, pub_key=None, vector_to_sign=None, user_sha='auto', hmac_sha='auto', is_pure=False, keep_comp_size=False, dont_encrypt=False): @@ -664,7 +667,7 @@ def create(self, key, public_key_format, enckey, dependencies=None, # # This adds the padding if image is not aligned to the 16 Bytes # in encrypted mode - if self.enckey is not None and dont_encrypt is False: + if aes_key is not None and dont_encrypt is False: pad_len = len(self.payload) % 16 if pad_len > 0: pad = bytes(16 - pad_len) @@ -679,10 +682,8 @@ def create(self, key, public_key_format, enckey, dependencies=None, if compression_type == "lzma2armthumb": compression_flags |= IMAGE_F['COMPRESSED_ARM_THUMB'] # This adds the header to the payload as well - if encrypt_keylen == 256: - self.add_header(enckey, protected_tlv_size, compression_flags, 256) - else: - self.add_header(enckey, protected_tlv_size, compression_flags) + aes_key_bits = 0 if aes_key is None else len(aes_key) * 8 + self.add_header(protected_tlv_size, compression_flags, aes_key_bits) prot_tlv = TLV(self.endian, TLV_PROT_INFO_MAGIC) @@ -803,12 +804,18 @@ def create(self, key, public_key_format, enckey, dependencies=None, if protected_tlv_off is not None: self.payload = self.payload[:protected_tlv_off] - if enckey is not None and dont_encrypt is False: - if encrypt_keylen == 256: - plainkey = os.urandom(32) - else: - plainkey = os.urandom(16) + # When passed AES key and clear flag, then do not encrypt, because the key + # is only passed to be stored in encryption key TLV, the payload stays clear text. + if aes_key and not clear: + nonce = bytes([0] * 16) + cipher = Cipher(algorithms.AES(aes_key), modes.CTR(nonce), + backend=default_backend()) + encryptor = cipher.encryptor() + img = bytes(self.payload[self.header_size:]) + self.payload[self.header_size:] = \ + encryptor.update(img) + encryptor.finalize() + if enckey is not None and dont_encrypt is False: if not isinstance(enckey, rsa.RSAPublic): if hmac_sha == 'auto' or hmac_sha == '256': hmac_sha = '256' @@ -822,19 +829,19 @@ def create(self, key, public_key_format, enckey, dependencies=None, if isinstance(enckey, rsa.RSAPublic): cipherkey = enckey._get_public().encrypt( - plainkey, padding.OAEP( + aes_key, padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None)) self.enctlv_len = len(cipherkey) tlv.add('ENCRSA2048', cipherkey) elif isinstance(enckey, ecdsa.ECDSA256P1Public): - cipherkey, mac, pubk = self.ecies_hkdf(enckey, plainkey, hmac_sha_alg) + cipherkey, mac, pubk = self.ecies_hkdf(enckey, aes_key, hmac_sha_alg) enctlv = pubk + mac + cipherkey self.enctlv_len = len(enctlv) tlv.add('ENCEC256', enctlv) elif isinstance(enckey, x25519.X25519Public): - cipherkey, mac, pubk = self.ecies_hkdf(enckey, plainkey, hmac_sha_alg) + cipherkey, mac, pubk = self.ecies_hkdf(enckey, aes_key, hmac_sha_alg) enctlv = pubk + mac + cipherkey self.enctlv_len = len(enctlv) if (hmac_sha == '256'): @@ -842,15 +849,6 @@ def create(self, key, public_key_format, enckey, dependencies=None, else: tlv.add('ENCX25519_SHA512', enctlv) - if not clear: - nonce = bytes([0] * 16) - cipher = Cipher(algorithms.AES(plainkey), modes.CTR(nonce), - backend=default_backend()) - encryptor = cipher.encryptor() - img = bytes(self.payload[self.header_size:]) - self.payload[self.header_size:] = \ - encryptor.update(img) + encryptor.finalize() - self.payload += prot_tlv.get() self.payload += tlv.get() @@ -865,11 +863,11 @@ def get_signature(self): def get_infile_data(self): return self.infile_data - def add_header(self, enckey, protected_tlv_size, compression_flags, aes_length=128): + def add_header(self, protected_tlv_size, compression_flags, aes_length=0): """Install the image header.""" flags = 0 - if enckey is not None: + if aes_length != 0: if aes_length == 128: flags |= IMAGE_F['ENCRYPTED_AES128'] else: @@ -944,11 +942,13 @@ def pad_to(self, size): pbytes = bytearray([self.erased_val] * padding) pbytes += bytearray([self.erased_val] * (tsize - len(self.boot_magic))) pbytes += self.boot_magic - if self.confirm and not self.overwrite_only: + if (self.test or self.confirm) and not self.overwrite_only: magic_size = 16 magic_align_size = align_up(magic_size, self.max_align) image_ok_idx = -(magic_align_size + self.max_align) - pbytes[image_ok_idx] = 0x01 # image_ok = 0x01 + # If test is set, set leave image_ok at the erased value + if self.confirm: + pbytes[image_ok_idx] = 0x01 # image_ok = 0x01 self.payload += pbytes @staticmethod diff --git a/scripts/imgtool/main.py b/scripts/imgtool/main.py index a7567bad4..1256bd5fa 100755 --- a/scripts/imgtool/main.py +++ b/scripts/imgtool/main.py @@ -20,6 +20,7 @@ import base64 import getpass import lzma +import os import re import struct import sys @@ -324,6 +325,14 @@ def create_lzma2_header(dictsize, pb, lc, lp): header.append( ( pb * 5 + lp) * 9 + lc) return header +def match_sig_enc_key(skey, ekey): + ok = ((isinstance(skey, keys.ECDSA256P1) and isinstance(ekey, keys.ECDSA256P1Public)) or + (isinstance(skey, keys.ECDSA384P1) and isinstance(ekey, keys.ECDSA384P1Public)) or + (isinstance(skey, keys.RSA) and isinstance(ekey, keys.RSAPublic)) + ) + + return ok + class BasedIntParamType(click.ParamType): name = 'integer' @@ -388,6 +397,9 @@ def convert(self, value, param, ctx): @click.option('--confirm', default=False, is_flag=True, help='When padding the image, mark it as confirmed (implies ' '--pad)') +@click.option('--test', default=False, is_flag=True, + help='When padding the image, mark it for a test swap (implies ' + '--pad)') @click.option('--pad', default=False, is_flag=True, help='Pad image to --slot-size bytes, adding trailer magic') @click.option('-S', '--slot-size', type=BasedIntParamType(), required=True, @@ -451,21 +463,25 @@ def convert(self, value, param, ctx): help='Unique image class identifier, format: (|)') @click.option('--manifest', default=None, required=False, help='Path to the update manifest file') -def sign(key, public_key_format, align, version, pad_sig, header_size, - pad_header, slot_size, pad, confirm, max_sectors, overwrite_only, +@click.option('--aes-key', default=None, required=False, + help='String representing raw AES key, format: hex byte string of 32 or 64' + 'hexadecimal characters') +@click.pass_context +def sign(ctx, key, public_key_format, align, version, pad_sig, header_size, + pad_header, slot_size, pad, confirm, test, max_sectors, overwrite_only, endian, encrypt_keylen, encrypt, compression, infile, outfile, dependencies, load_addr, hex_addr, erased_val, save_enctlv, security_counter, boot_record, custom_tlv, rom_fixed, max_align, clear, fix_sig, fix_sig_pubkey, sig_out, user_sha, hmac_sha, is_pure, - vector_to_sign, non_bootable, vid, cid, manifest): + vector_to_sign, non_bootable, vid, cid, manifest, aes_key): - if confirm: + if confirm or test: # Confirmed but non-padded images don't make much sense, because # otherwise there's no trailer area for writing the confirmed status. pad = True img = image.Image(version=decode_version(version), header_size=header_size, pad_header=pad_header, pad=pad, confirm=confirm, - align=int(align), slot_size=slot_size, + test=test, align=int(align), slot_size=slot_size, max_sectors=max_sectors, overwrite_only=overwrite_only, endian=endian, load_addr=load_addr, rom_fixed=rom_fixed, erased_val=erased_val, save_enctlv=save_enctlv, @@ -474,17 +490,23 @@ def sign(key, public_key_format, align, version, pad_sig, header_size, manifest=manifest) compression_tlvs = {} img.load(infile) + key = load_key(key) if key else None - enckey = load_key(encrypt) if encrypt else None - if enckey and key and ((isinstance(key, keys.ECDSA256P1) and - not isinstance(enckey, keys.ECDSA256P1Public)) - or (isinstance(key, keys.ECDSA384P1) and - not isinstance(enckey, keys.ECDSA384P1Public)) - or (isinstance(key, keys.RSA) and - not isinstance(enckey, keys.RSAPublic))): - # FIXME - raise click.UsageError("Signing and encryption must use the same " - "type of key") + enckey = None + if not aes_key: + enckey = load_key(encrypt) if encrypt else None + if enckey and not match_sig_enc_key(key, enckey): + # FIXME + raise click.UsageError("Signing and encryption must use the same " + "type of key") + else: + if encrypt: + encrypt = None + click.secho('Raw AES key overrides --key, there will be no encrypted key added to the image', err=True) + if clear: + click.secho('--clear overrides raw AES key, image will not be encrypted', err=True) + if ctx.get_parameter_source('encrypt_keylen') != click.core.ParameterSource.DEFAULT: + click.secho('Raw AES key len overrides --encrypt-keylen', err=True) if pad_sig and hasattr(key, 'pad_sig'): key.pad_sig = True @@ -529,9 +551,26 @@ def sign(key, public_key_format, align, version, pad_sig, header_size, 'Pure signatures, currently, enforces preferred hash algorithm, ' 'and forbids sha selection by user.') + plainkey = None + if aes_key: + # Converting the command line provided raw AES key to byte array; + # this aray will be truncated to desired len. + plainkey = bytes.fromhex(aes_key) + plainkey_len = len(plainkey) + if plainkey_len not in (16, 32): + raise click.UsageError("Provided keylen, {int(plainkey_len)} in bytes, not supported") + elif enckey: + if encrypt_keylen == 256: + encrypt_keylen_bytes = 32 + else: + encrypt_keylen_bytes = 16 + + # No AES plain key and there is request to encrypt, generate random AES key + plainkey = os.urandom(encrypt_keylen_bytes) + if compression in ["lzma2", "lzma2armthumb"]: img.create(key, public_key_format, enckey, dependencies, boot_record, - custom_tlvs, compression_tlvs, None, int(encrypt_keylen), clear, + custom_tlvs, compression_tlvs, None, None, clear, baked_signature, pub_key, vector_to_sign, user_sha=user_sha, hmac_sha=hmac_sha, is_pure=is_pure, keep_comp_size=False, dont_encrypt=True) compressed_img = image.Image(version=decode_version(version), @@ -577,13 +616,13 @@ def sign(key, public_key_format, align, version, pad_sig, header_size, keep_comp_size = True compressed_img.create(key, public_key_format, enckey, dependencies, boot_record, custom_tlvs, compression_tlvs, - compression, int(encrypt_keylen), clear, baked_signature, + compression, plainkey, clear, baked_signature, pub_key, vector_to_sign, user_sha=user_sha, hmac_sha=hmac_sha, is_pure=is_pure, keep_comp_size=keep_comp_size) img = compressed_img else: img.create(key, public_key_format, enckey, dependencies, boot_record, - custom_tlvs, compression_tlvs, None, int(encrypt_keylen), clear, + custom_tlvs, compression_tlvs, None, plainkey, clear, baked_signature, pub_key, vector_to_sign, user_sha=user_sha, hmac_sha=hmac_sha, is_pure=is_pure) img.save(outfile, hex_addr)