Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/sim.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ jobs:
- "sig-rsa validate-primary-slot ram-load multiimage"
- "sig-rsa validate-primary-slot direct-xip multiimage"
- "sig-ecdsa hw-rollback-protection multiimage"
- "enc-xip-ec256,enc-xip-ec256 swap-move,enc-xip-ec256 swap-offset"
- "sig-ecdsa enc-xip-ec256 validate-primary-slot,enc-xip-ec256 overwrite-only"
- "sig-ecdsa-psa,sig-ecdsa-psa sig-p384,sig-ecdsa-psa swap-move bootstrap max-align-16"
- "sig-ecdsa-psa enc-ec256 max-align-16, sig-ecdsa-psa enc-ec256 swap-offset validate-primary-slot max-align-16"
- "ram-load enc-aes256-kw multiimage"
Expand Down
4 changes: 2 additions & 2 deletions boot/boot_serial/src/boot_serial.c
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ bs_list(struct boot_loader_state *state, char *buf, int len)
{
BOOT_HOOK_CALL_FIH(boot_image_check_hook,
FIH_BOOT_HOOK_REGULAR,
fih_rc, image_index, slot);
fih_rc, NULL, image_index, slot);
if (FIH_EQ(fih_rc, FIH_BOOT_HOOK_REGULAR))
{
#if defined(MCUBOOT_ENC_IMAGES)
Expand Down Expand Up @@ -574,7 +574,7 @@ bs_set(struct boot_loader_state *state, char *buf, int len)

BOOT_HOOK_CALL_FIH(boot_image_check_hook,
FIH_BOOT_HOOK_REGULAR,
fih_rc, image_index, slot);
fih_rc, NULL, image_index, slot);
if (FIH_EQ(fih_rc, FIH_BOOT_HOOK_REGULAR))
{
#ifdef MCUBOOT_ENC_IMAGES
Expand Down
19 changes: 17 additions & 2 deletions boot/bootutil/include/bootutil/boot_hooks.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,14 +127,29 @@ int boot_read_image_header_hook(int img_index, int slot,
* This Hook may be used to overide image validation procedure or doing
* a custom action before.
*
* @param state boot loader state (may be NULL when called outside
* the normal boot flow, e.g. serial recovery)
* @param img_index the index of the image pair
* @param slot slot number
*
*
* @retval FIH_SUCCESS: image is valid, skip direct validation
* FIH_FAILURE: image is invalid, skip direct validation
* FIH_BOOT_HOOK_REGULAR: follow the normal execution path.
*/
fih_ret boot_image_check_hook(int img_index, int slot);
fih_ret boot_image_check_hook(struct boot_loader_state *state,
int img_index, int slot);

#if defined(MCUBOOT_ENC_IMAGES_XIP)
/** Hook for populating XIP encryption key/IV in boot response.
*
* Called after fill_rsp() to copy the image's encryption key and IV
* into boot_rsp for post-boot hardware crypto region setup.
*
* @param img_index the index of the current image
* @param rsp the boot response struct to populate
*/
void boot_xip_populate_rsp(int img_index, struct boot_rsp *rsp);
#endif

/** Hook for implement image update
*
Expand Down
6 changes: 6 additions & 0 deletions boot/bootutil/include/bootutil/bootutil.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ struct boot_rsp {
*/
uint8_t br_flash_dev_id;
uint32_t br_image_off;
#if defined(MCUBOOT_ENC_IMAGES_XIP)
/** AES-128 key for post-boot XIP hardware crypto setup. */
uint32_t br_xip_key[4];
/** IV/nonce for post-boot XIP hardware crypto setup. */
uint32_t br_xip_iv[4];
#endif
};

/* This is not actually used by mcuboot's code but can be used by apps
Expand Down
1 change: 1 addition & 0 deletions boot/bootutil/include/bootutil/caps.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ uint32_t bootutil_get_caps(void);
#define BOOTUTIL_CAP_HW_ROLLBACK_PROT (1<<18)
#define BOOTUTIL_CAP_ECDSA_P384 (1<<19)
#define BOOTUTIL_CAP_SWAP_USING_OFFSET (1<<20)
#define BOOTUTIL_CAP_ENC_XIP_EC256 (1<<21)

/*
* Query the number of images this bootloader is configured for. This
Expand Down
2 changes: 1 addition & 1 deletion boot/bootutil/src/bootutil_loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ boot_check_header_valid(struct boot_loader_state *state, int slot)
return false;
}

#if !defined(MCUBOOT_ENC_IMAGES)
#if !defined(MCUBOOT_ENC_IMAGES) && !defined(MCUBOOT_ENC_IMAGES_XIP)
if (IS_ENCRYPTED(hdr)) {
return false;
}
Expand Down
6 changes: 6 additions & 0 deletions boot/bootutil/src/bootutil_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,12 @@ _Static_assert(sizeof(boot_img_magic) == BOOT_MAGIC_SZ, "Invalid size for image
#endif /* MCUBOOT_DIRECT_XIP && MCUBOOT_ENC_IMAGES */
#endif /* MCUBOOT_DIRECT_XIP || MCUBOOT_RAM_LOAD */

#if defined(MCUBOOT_ENC_IMAGES) && defined(MCUBOOT_ENC_IMAGES_XIP)
#error "MCUBOOT_ENC_IMAGES and MCUBOOT_ENC_IMAGES_XIP are mutually exclusive. " \
"XIP encryption keeps images encrypted in both slots and does not use " \
"the standard encrypt/decrypt-during-swap mechanism."
#endif

#define BOOT_LOG_IMAGE_INFO(slot, hdr) \
BOOT_LOG_INF("%-9s slot: version=%u.%u.%u+%u", \
((slot) == BOOT_SLOT_PRIMARY) ? "Primary" : "Secondary", \
Expand Down
3 changes: 3 additions & 0 deletions boot/bootutil/src/caps.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ uint32_t bootutil_get_caps(void)
#if defined(MCUBOOT_HW_ROLLBACK_PROT)
res |= BOOTUTIL_CAP_HW_ROLLBACK_PROT;
#endif
#if defined(MCUBOOT_ENC_IMAGES_XIP)
res |= BOOTUTIL_CAP_ENC_XIP_EC256;
#endif

return res;
}
Expand Down
16 changes: 15 additions & 1 deletion boot/bootutil/src/loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@
#include "bootutil/enc_key.h"
#endif

#if defined(MCUBOOT_ENC_IMAGES_XIP)
#include "xip_enc/xip_enc.h"
#endif

#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)
#include <os/os_malloc.h>
#endif
Expand Down Expand Up @@ -636,7 +640,7 @@ boot_validate_slot(struct boot_loader_state *state, int slot,
fih_rc = FIH_FAILURE;
} else {
BOOT_HOOK_CALL_FIH(boot_image_check_hook, FIH_BOOT_HOOK_REGULAR,
fih_rc, BOOT_CURR_IMG(state), slot);
fih_rc, state, BOOT_CURR_IMG(state), slot);
if (FIH_EQ(fih_rc, FIH_BOOT_HOOK_REGULAR)) {
FIH_CALL(boot_check_image, fih_rc, state, bs, slot);
}
Expand Down Expand Up @@ -1970,6 +1974,11 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp)

fill_rsp(state, rsp);

#if defined(MCUBOOT_ENC_IMAGES_XIP)
boot_xip_populate_rsp(BOOT_CURR_IMG(state), rsp);
xip_enc_clear_keys();
#endif

fih_rc = FIH_SUCCESS;
out:
/*
Expand Down Expand Up @@ -2454,6 +2463,11 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp)

fill_rsp(state, rsp);

#if defined(MCUBOOT_ENC_IMAGES_XIP)
boot_xip_populate_rsp(BOOT_CURR_IMG(state), rsp);
xip_enc_clear_keys();
#endif

close:
boot_close_all_flash_areas(state);

Expand Down
113 changes: 113 additions & 0 deletions boot/bootutil/src/xip_enc/xip_enc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* XIP Multi-Key Encryption Library
* Self-contained library for XIP encryption support in MCUBoot.
* Interfaces with MCUBoot via boot_image_check_hook (existing hook).
*/
#ifndef XIP_ENC_H
#define XIP_ENC_H

#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "bootutil/bootutil.h"
#include "bootutil/image.h"
#include "flash_map_backend/flash_map_backend.h"
#include "mcuboot_config/mcuboot_config.h"

#if defined(MCUBOOT_ENC_IMAGES) && defined(MCUBOOT_ENC_IMAGES_XIP)
#error "MCUBOOT_ENC_IMAGES and MCUBOOT_ENC_IMAGES_XIP are mutually exclusive."
#endif

/**
* Secure zeroization -- uses volatile pointer to prevent compiler optimization.
*/
static inline void xip_enc_zeroize(void *p, size_t n)
{
volatile unsigned char *v = (volatile unsigned char *)p;
for (size_t i = 0; i < n; i++) {
v[i] = 0;
}
}

/**
* Constant-time comparison to avoid timing side-channels.
* Returns 0 if equal, non-zero otherwise.
*/
static inline int xip_enc_ct_compare(const uint8_t *a, const uint8_t *b,
size_t size)
{
uint8_t result = 0;
for (size_t i = 0; i < size; i++) {
result |= a[i] ^ b[i];
}
return (int)result;
}

#define XIP_ENC_KEY_SIZE 16u
#define XIP_ENC_IV_SIZE 16u
#define XIP_ENC_MAX_IMAGES 3u

/*
* boot_image_check_hook() is declared in bootutil/boot_hooks.h (upstream).
* The library provides the implementation in xip_enc_validate.c.
* Do NOT redeclare here.
*/

/**
* Called by MCUBoot after fill_rsp() to populate xip_key/xip_iv in boot_rsp.
* Copies key/IV from library-internal storage for the specified image.
*
* @param img_index Image index (passed via BOOT_CURR_IMG from MCUBoot)
* @param rsp Boot response to populate
*/
void boot_xip_populate_rsp(int img_index, struct boot_rsp *rsp);

/**
* Platform-provided: decrypt image payload using SMIF hardware.
* Used during hash computation to decrypt AES-CTR encrypted payload.
*
* @param image_index Current image index
* @param fap Flash area of the image
* @param off Offset within flash area
* @param sz Size of data to decrypt
* @param buf Buffer with data to decrypt (in-place)
*
* @return 0 on success, negative on error
*/
int boot_decrypt_xip(int image_index, const struct flash_area *fap,
uint32_t off, uint32_t sz, uint8_t *buf);

/**
* Store key/IV for an image (called by validation hook after ECIES unwrap).
*/
void xip_enc_store_key(int img_index, const uint8_t *key, const uint8_t *iv);

/**
* Retrieve stored key/IV for an image.
*
* @return 0 on success, -1 if not valid
*/
int xip_enc_get_key(int img_index, uint8_t *key, uint8_t *iv);

/**
* Zeroize all stored keys. Call before launching application.
*/
void xip_enc_clear_keys(void);

/**
* ECIES-P256 key unwrap with extended TLV support.
* Extracts AES key and XIP IV from ECIES envelope.
*
* @param tlv_buf ECIES TLV data read from image
* @param tlv_len Length of TLV data (113 standard, up to 177 extended)
* @param out_key Output: 16-byte AES key
* @param out_iv Output: 16-byte XIP IV
*
* @return 0 on success, negative on error
*/
int xip_enc_ecies_unwrap(const uint8_t *tlv_buf, uint16_t tlv_len,
uint8_t *out_key, uint8_t *out_iv);

#endif /* XIP_ENC_H */
123 changes: 123 additions & 0 deletions boot/bootutil/src/xip_enc/xip_enc_decrypt.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* XIP Encryption Library -- Default Decryption (Software AES-CTR)
*
* Provides a __weak boot_decrypt_xip() using bootutil AES-CTR wrappers.
* Works with any crypto backend (tinycrypt, mbedTLS, PSA).
*
* Platforms with hardware crypto (e.g., SMIF) should provide a strong
* override for better performance.
*/

#include "mcuboot_config/mcuboot_config.h"

#if defined(MCUBOOT_ENC_IMAGES_XIP)

#include <stdint.h>
#include <string.h>
#include "bootutil/crypto/aes_ctr.h"
#include "flash_map_backend/flash_map_backend.h"
#include "xip_enc.h"

/*
* Default (weak) boot_decrypt_xip -- software AES-CTR decryption.
*
* Retrieves key/IV from xip_enc_get_key() (populated by the validation
* hook during ECIES unwrap). Builds AES-CTR nonce and decrypts buf in-place.
*
* Nonce format (edgeprotecttools-aligned):
* bits 0..31 = absolute XIP address (little-endian)
* bits 32..127 = xip_iv[0:12]
* Counter increments by 16 per AES block (absolute address).
*
* Platforms with hardware XIP decryption (e.g., Infineon SMIF) should
* provide a strong override of this function.
*/
__attribute__((weak))
int boot_decrypt_xip(int image_index, const struct flash_area *fap,
uint32_t off, uint32_t sz, uint8_t *buf)
{
bootutil_aes_ctr_context aes_ctr;
uint8_t key[XIP_ENC_KEY_SIZE];
uint8_t iv[XIP_ENC_IV_SIZE];
uint8_t nonce[16];
uintptr_t flash_base;
uint32_t abs_off;
uint32_t pos;
uint32_t blk_sz;
int rc;

if (sz == 0u) {
return 0;
}

/* Retrieve key/IV stored by boot_image_check_hook */
if (xip_enc_get_key(image_index, key, iv) != 0) {
return -1;
}

/* Compute absolute XIP address for AES-CTR counter.
* Matches edgeprotecttools / imgtool: initial_counter = base_address + off
* where base_address = flash_device_base + fap->fa_off.
*/
flash_base = 0;
rc = flash_device_base(flash_area_get_device_id(fap), &flash_base);
if (rc != 0) {
xip_enc_zeroize(key, sizeof(key));
return -1;
}
abs_off = (uint32_t)flash_base + flash_area_get_off(fap) + off;

bootutil_aes_ctr_init(&aes_ctr);
rc = bootutil_aes_ctr_set_key(&aes_ctr, key);
if (rc != 0) {
bootutil_aes_ctr_drop(&aes_ctr);
xip_enc_zeroize(key, sizeof(key));
xip_enc_zeroize(iv, sizeof(iv));
return -1;
}

/*
* Per-block AES-CTR using SMIF/edgeprotecttools counter format:
* nonce = counter_LE32 || iv[0:12]
* counter = abs_off, increments by 16 per block
*
* We call bootutil_aes_ctr_encrypt once per block with a fresh nonce.
* The library's internal counter increment is irrelevant because
* each call processes exactly one block with a freshly built nonce.
*/
for (pos = 0; pos < sz; pos += 16u) {
uint32_t ctr_val = abs_off + pos;

(void)memset(nonce, 0, sizeof(nonce));
nonce[0] = (uint8_t)(ctr_val);
nonce[1] = (uint8_t)(ctr_val >> 8);
nonce[2] = (uint8_t)(ctr_val >> 16);
nonce[3] = (uint8_t)(ctr_val >> 24);
(void)memcpy(&nonce[4], iv, 12);

blk_sz = sz - pos;
if (blk_sz > 16u) {
blk_sz = 16u;
}

rc = bootutil_aes_ctr_encrypt(&aes_ctr, nonce,
&buf[pos], blk_sz,
0, &buf[pos]);
if (rc != 0) {
break;
}
}

bootutil_aes_ctr_drop(&aes_ctr);

/* Zeroize all sensitive material from stack */
xip_enc_zeroize(key, sizeof(key));
xip_enc_zeroize(iv, sizeof(iv));
xip_enc_zeroize(nonce, sizeof(nonce));

return rc;
}

#endif /* MCUBOOT_ENC_IMAGES_XIP */
Loading
Loading