diff --git a/boot/bootutil/include/bootutil/bootutil.h b/boot/bootutil/include/bootutil/bootutil.h index f4555763..9c1fbab4 100644 --- a/boot/bootutil/include/bootutil/bootutil.h +++ b/boot/bootutil/include/bootutil/bootutil.h @@ -71,7 +71,10 @@ struct image_trailer { uint8_t pad2[BOOT_MAX_ALIGN - 1]; uint8_t image_ok; uint8_t pad3[BOOT_MAX_ALIGN - 1]; - uint8_t magic[16]; +#if BOOT_MAX_ALIGN > BOOT_MAGIC_SZ + uint8_t pad4[BOOT_MAGIC_ALIGN_SIZE - BOOT_MAGIC_SZ]; +#endif + uint8_t magic[BOOT_MAGIC_SZ]; }; /* you must have pre-allocated all the entries within this structure */ diff --git a/boot/bootutil/include/bootutil/bootutil_public.h b/boot/bootutil/include/bootutil/bootutil_public.h index 3a0e38ae..fcd667eb 100644 --- a/boot/bootutil/include/bootutil/bootutil_public.h +++ b/boot/bootutil/include/bootutil/bootutil_public.h @@ -47,6 +47,14 @@ extern "C" { #endif +#ifndef ALIGN_UP +#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1)) +#endif + +#ifndef ALIGN_DOWN +#define ALIGN_DOWN(num, align) ((num) & ~((align) - 1)) +#endif + /** Attempt to boot the contents of the primary slot. */ #define BOOT_SWAP_TYPE_NONE 1 @@ -71,7 +79,19 @@ extern "C" { /** Swapping encountered an unrecoverable error */ #define BOOT_SWAP_TYPE_PANIC 0xff +#define BOOT_MAGIC_SZ 16 + +#ifdef MCUBOOT_BOOT_MAX_ALIGN + +_Static_assert(MCUBOOT_BOOT_MAX_ALIGN >= 8 && MCUBOOT_BOOT_MAX_ALIGN <= 32, + "Unsupported value for MCUBOOT_BOOT_MAX_ALIGN"); + +#define BOOT_MAX_ALIGN MCUBOOT_BOOT_MAX_ALIGN +#define BOOT_MAGIC_ALIGN_SIZE ALIGN_UP(BOOT_MAGIC_SZ, BOOT_MAX_ALIGN) +#else #define BOOT_MAX_ALIGN 8 +#define BOOT_MAGIC_ALIGN_SIZE BOOT_MAGIC_SZ +#endif #define BOOT_MAGIC_GOOD 1 #define BOOT_MAGIC_BAD 2 @@ -87,8 +107,6 @@ extern "C" { #define BOOT_FLAG_UNSET 3 #define BOOT_FLAG_ANY 4 /* NOTE: control only, not dependent on sector */ -#define BOOT_MAGIC_SZ (sizeof boot_img_magic) - #define BOOT_EFLASH 1 #define BOOT_EFILE 2 #define BOOT_EBADIMAGE 3 diff --git a/boot/bootutil/include/bootutil/enc_key.h b/boot/bootutil/include/bootutil/enc_key.h index 779b0d4b..768dd8e7 100644 --- a/boot/bootutil/include/bootutil/enc_key.h +++ b/boot/bootutil/include/bootutil/enc_key.h @@ -38,10 +38,7 @@ extern "C" { #endif -#define BOOT_ENC_KEY_SIZE_BITS (BOOT_ENC_KEY_SIZE * 8) - -#define BOOT_ENC_TLV_ALIGN_SIZE \ - ((((BOOT_ENC_TLV_SIZE - 1) / BOOT_MAX_ALIGN) + 1) * BOOT_MAX_ALIGN) +#define BOOT_ENC_TLV_ALIGN_SIZE ALIGN_UP(BOOT_ENC_TLV_SIZE, BOOT_MAX_ALIGN) struct enc_key_data { uint8_t valid; diff --git a/boot/bootutil/include/bootutil/enc_key_public.h b/boot/bootutil/include/bootutil/enc_key_public.h index 420d0d63..6874cfbc 100644 --- a/boot/bootutil/include/bootutil/enc_key_public.h +++ b/boot/bootutil/include/bootutil/enc_key_public.h @@ -32,14 +32,20 @@ extern "C" { #endif +#ifndef ALIGN_UP +#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1)) +#endif + #ifdef MCUBOOT_AES_256 #define BOOT_ENC_KEY_SIZE 32 #else #define BOOT_ENC_KEY_SIZE 16 #endif +#define BOOT_ENC_KEY_ALIGN_SIZE ALIGN_UP(BOOT_ENC_KEY_SIZE, BOOT_MAX_ALIGN) + #define TLV_ENC_RSA_SZ 256 -#define TLV_ENC_KW_SZ BOOT_ENC_KEY_SIZE + 8 +#define TLV_ENC_KW_SZ (BOOT_ENC_KEY_SIZE + 8) #define TLV_ENC_EC256_SZ (65 + 32 + BOOT_ENC_KEY_SIZE) #define TLV_ENC_X25519_SZ (32 + 32 + BOOT_ENC_KEY_SIZE) diff --git a/boot/bootutil/src/bootutil_misc.c b/boot/bootutil/src/bootutil_misc.c index 4ae27b2e..f0b4a5d1 100644 --- a/boot/bootutil/src/bootutil_misc.c +++ b/boot/bootutil/src/bootutil_misc.c @@ -108,12 +108,12 @@ boot_trailer_info_sz(void) # if MCUBOOT_SWAP_SAVE_ENCTLV BOOT_ENC_TLV_ALIGN_SIZE * 2 + # else - BOOT_ENC_KEY_SIZE * 2 + + BOOT_ENC_KEY_ALIGN_SIZE * 2 + # endif #endif /* swap_type + copy_done + image_ok + swap_size */ BOOT_MAX_ALIGN * 4 + - BOOT_MAGIC_SZ + BOOT_MAGIC_ALIGN_SIZE ); } @@ -190,6 +190,15 @@ boot_status_off(const struct flash_area *fap) return flash_area_get_size(fap) - off_from_end; } +static int +boot_magic_decode(const uint32_t *magic) +{ + if (memcmp(magic, boot_img_magic, BOOT_MAGIC_SZ) == 0) { + return BOOT_MAGIC_GOOD; + } + return BOOT_MAGIC_BAD; +} + static inline uint32_t boot_magic_off(const struct flash_area *fap) { @@ -199,7 +208,7 @@ boot_magic_off(const struct flash_area *fap) static inline uint32_t boot_image_ok_off(const struct flash_area *fap) { - return boot_magic_off(fap) - BOOT_MAX_ALIGN; + return ALIGN_DOWN(boot_magic_off(fap) - BOOT_MAX_ALIGN, BOOT_MAX_ALIGN); } static inline uint32_t @@ -219,10 +228,9 @@ static inline uint32_t boot_enc_key_off(const struct flash_area *fap, uint8_t slot) { #if MCUBOOT_SWAP_SAVE_ENCTLV - return boot_swap_size_off(fap) - ((slot + 1) * - ((((BOOT_ENC_TLV_SIZE - 1) / BOOT_MAX_ALIGN) + 1) * BOOT_MAX_ALIGN)); + return boot_swap_size_off(fap) - ((slot + 1) * BOOT_ENC_TLV_ALIGN_SIZE); #else - return boot_swap_size_off(fap) - ((slot + 1) * BOOT_ENC_KEY_SIZE); + return boot_swap_size_off(fap) - ((slot + 1) * BOOT_ENC_KEY_ALIGN_SIZE); #endif } #endif @@ -272,7 +280,7 @@ boot_find_status(int image_index, const struct flash_area **fap) return rc; } - if (memcmp(magic, boot_img_magic, BOOT_MAGIC_SZ) == 0) { + if (BOOT_MAGIC_GOOD == boot_magic_decode(magic)) { return 0; } @@ -327,7 +335,7 @@ boot_read_enc_key(int image_index, uint8_t slot, struct boot_status *bs) } } #else - rc = flash_area_read(fap, off, bs->enckey[slot], BOOT_ENC_KEY_SIZE); + rc = flash_area_read(fap, off, bs->enckey[slot], BOOT_ENC_KEY_ALIGN_SIZE); #endif flash_area_close(fap); } @@ -375,7 +383,7 @@ boot_write_enc_key(const struct flash_area *fap, uint8_t slot, #if MCUBOOT_SWAP_SAVE_ENCTLV rc = flash_area_write(fap, off, bs->enctlv[slot], BOOT_ENC_TLV_ALIGN_SIZE); #else - rc = flash_area_write(fap, off, bs->enckey[slot], BOOT_ENC_KEY_SIZE); + rc = flash_area_write(fap, off, bs->enckey[slot], BOOT_ENC_KEY_ALIGN_SIZE); #endif if (rc != 0) { return BOOT_EFLASH; diff --git a/boot/bootutil/src/bootutil_priv.h b/boot/bootutil/src/bootutil_priv.h index 10a6e023..1ba292fa 100644 --- a/boot/bootutil/src/bootutil_priv.h +++ b/boot/bootutil/src/bootutil_priv.h @@ -82,7 +82,7 @@ struct boot_status { uint8_t swap_type; /* The type of swap in effect */ uint32_t swap_size; /* Total size of swapped image */ #ifdef MCUBOOT_ENC_IMAGES - uint8_t enckey[BOOT_NUM_SLOTS][BOOT_ENC_KEY_SIZE]; + uint8_t enckey[BOOT_NUM_SLOTS][BOOT_ENC_KEY_ALIGN_SIZE]; #if MCUBOOT_SWAP_SAVE_ENCTLV uint8_t enctlv[BOOT_NUM_SLOTS][BOOT_ENC_TLV_ALIGN_SIZE]; #endif @@ -109,16 +109,28 @@ struct boot_status { * | Encryption key 0 (16 octets) [*] | * | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | 0xff padding as needed | + * | (BOOT_MAX_ALIGN minus 16 octets from Encryption key 0) [*] | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Encryption key 1 (16 octets) [*] | * | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | 0xff padding as needed | + * | (BOOT_MAX_ALIGN minus 16 octets from Encryption key 1) [*] | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Swap size (4 octets) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Swap info | 0xff padding (7 octets) | + * | 0xff padding as needed | + * | (BOOT_MAX_ALIGN minus 4 octets from Swap size) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Copy done | 0xff padding (7 octets) | + * | Swap info | 0xff padding (BOOT_MAX_ALIGN minus 1 octet) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Image OK | 0xff padding (7 octets) | + * | Copy done | 0xff padding (BOOT_MAX_ALIGN minus 1 octet) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Image OK | 0xff padding (BOOT_MAX_ALIGN minus 1 octet) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | 0xff padding as needed | + * | (BOOT_MAX_ALIGN minus 16 octets from MAGIC) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | MAGIC (16 octets) | * | | diff --git a/boot/bootutil/src/bootutil_public.c b/boot/bootutil/src/bootutil_public.c index 15cdb0ec..63092f28 100644 --- a/boot/bootutil/src/bootutil_public.c +++ b/boot/bootutil/src/bootutil_public.c @@ -146,7 +146,7 @@ boot_magic_off(const struct flash_area *fap) static inline uint32_t boot_image_ok_off(const struct flash_area *fap) { - return boot_magic_off(fap) - BOOT_MAX_ALIGN; + return ALIGN_DOWN(boot_magic_off(fap) - BOOT_MAX_ALIGN, BOOT_MAX_ALIGN); } static inline uint32_t @@ -198,10 +198,9 @@ static inline uint32_t boot_enc_key_off(const struct flash_area *fap, uint8_t slot) { #if MCUBOOT_SWAP_SAVE_ENCTLV - return boot_swap_size_off(fap) - ((slot + 1) * - ((((BOOT_ENC_TLV_SIZE - 1) / BOOT_MAX_ALIGN) + 1) * BOOT_MAX_ALIGN)); + return boot_swap_size_off(fap) - ((slot + 1) * BOOT_ENC_TLV_ALIGN_SIZE); #else - return boot_swap_size_off(fap) - ((slot + 1) * BOOT_ENC_KEY_SIZE); + return boot_swap_size_off(fap) - ((slot + 1) * BOOT_ENC_KEY_ALIGN_SIZE); #endif } #endif @@ -316,14 +315,32 @@ int boot_write_magic(const struct flash_area *fap) { uint32_t off; + uint32_t pad_off; int rc; + uint8_t magic[BOOT_MAGIC_ALIGN_SIZE]; + uint8_t erased_val; off = boot_magic_off(fap); + /* image_trailer structure was modified with additional padding such that + * the pad+magic ends up in a flash minimum write region. The address + * returned by boot_magic_off() is the start of magic which is not the + * start of the flash write boundary and thus writes to the magic will fail. + * To account for this change, write to magic is first padded with 0xFF + * before writing to the trailer. + */ + pad_off = ALIGN_DOWN(off, BOOT_MAX_ALIGN); + + erased_val = flash_area_erased_val(fap); + + memset(&magic[0], erased_val, sizeof(magic)); + memcpy(&magic[BOOT_MAGIC_ALIGN_SIZE - BOOT_MAGIC_SZ], boot_img_magic, BOOT_MAGIC_SZ); + BOOT_LOG_DBG("writing magic; fa_id=%d off=0x%lx (0x%lx)", flash_area_get_id(fap), (unsigned long)off, (unsigned long)(flash_area_get_off(fap) + off)); - rc = flash_area_write(fap, off, boot_img_magic, BOOT_MAGIC_SZ); + rc = flash_area_write(fap, pad_off, &magic[0], BOOT_MAGIC_ALIGN_SIZE); + if (rc != 0) { return BOOT_EFLASH; } @@ -346,7 +363,7 @@ boot_write_trailer(const struct flash_area *fap, uint32_t off, int rc; align = flash_area_align(fap); - align = (inlen + align - 1) & ~(align - 1); + align = ALIGN_UP(inlen, align); if (align > BOOT_MAX_ALIGN) { return -1; } diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index a26159c2..10bd5c61 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -36,6 +36,7 @@ #include #include #include "bootutil/bootutil.h" +#include "bootutil/bootutil_public.h" #include "bootutil/image.h" #include "bootutil_priv.h" #include "swap_priv.h" @@ -79,6 +80,12 @@ static struct boot_loader_state boot_data; #define TARGET_STATIC #endif +#if BOOT_MAX_ALIGN > 1024 +#define BUF_SZ BOOT_MAX_ALIGN +#else +#define BUF_SZ 1024 +#endif + static int boot_read_image_headers(struct boot_loader_state *state, bool require_all, struct boot_status *bs) @@ -379,7 +386,7 @@ void boot_status_reset(struct boot_status *bs) { #ifdef MCUBOOT_ENC_IMAGES - memset(&bs->enckey, 0xff, BOOT_NUM_SLOTS * BOOT_ENC_KEY_SIZE); + memset(&bs->enckey, 0xff, BOOT_NUM_SLOTS * BOOT_ENC_KEY_ALIGN_SIZE); #if MCUBOOT_SWAP_SAVE_ENCTLV memset(&bs->enctlv, 0xff, BOOT_NUM_SLOTS * BOOT_ENC_TLV_ALIGN_SIZE); #endif @@ -944,7 +951,7 @@ boot_copy_region(struct boot_loader_state *state, uint8_t image_index; #endif - TARGET_STATIC uint8_t buf[1024] __attribute__((aligned(4))); + TARGET_STATIC uint8_t buf[BUF_SZ] __attribute__((aligned(4))); #if !defined(MCUBOOT_ENC_IMAGES) (void)state; @@ -1254,7 +1261,7 @@ boot_swap_image(struct boot_loader_state *state, struct boot_status *bs) rc = 0; } } else { - memset(bs->enckey[0], 0xff, BOOT_ENC_KEY_SIZE); + memset(bs->enckey[0], 0xff, BOOT_ENC_KEY_ALIGN_SIZE); } #endif @@ -1278,7 +1285,7 @@ boot_swap_image(struct boot_loader_state *state, struct boot_status *bs) rc = 0; } } else { - memset(bs->enckey[1], 0xff, BOOT_ENC_KEY_SIZE); + memset(bs->enckey[1], 0xff, BOOT_ENC_KEY_ALIGN_SIZE); } #endif diff --git a/scripts/imgtool/image.py b/scripts/imgtool/image.py index 684c6b35..66cee439 100644 --- a/scripts/imgtool/image.py +++ b/scripts/imgtool/image.py @@ -43,7 +43,7 @@ IMAGE_HEADER_SIZE = 32 BIN_EXT = "bin" INTEL_HEX_EXT = "hex" DEFAULT_MAX_SECTORS = 128 -MAX_ALIGN = 8 +DEFAULT_MAX_ALIGN = 8 DEP_IMAGES_KEY = "images" DEP_VERSIONS_KEY = "versions" MAX_SW_TYPE_LENGTH = 12 # Bytes @@ -135,7 +135,7 @@ class Image(): 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): + security_counter=None, max_align=DEFAULT_MAX_ALIGN): if load_addr and rom_fixed: raise click.UsageError("Can not set rom_fixed and load_addr at the same time") @@ -158,6 +158,7 @@ class Image(): self.enckey = None self.save_enctlv = save_enctlv self.enctlv_len = 0 + self.max_align = DEFAULT_MAX_ALIGN if max_align is None else int(max_align) if security_counter == 'auto': # Security counter has not been explicitly provided, @@ -231,9 +232,12 @@ class Image(): trailer_addr = (self.base_addr + self.slot_size) - trailer_size padding = bytearray([self.erased_val] * (trailer_size - len(boot_magic))) - if self.confirm and not self.overwrite_only: - padding[-MAX_ALIGN] = 0x01 # image_ok = 0x01 padding += boot_magic + if self.confirm and not self.overwrite_only: + magic_size = 16 + magic_align_size = (int((magic_size - 1) / self.max_align) + 1) * self.max_align + image_ok_idx = -(magic_align_size + self.max_align) + padding[image_ok_idx] = 0x01 # image_ok = 0x01 h.puts(trailer_addr, bytes(padding)) h.tofile(path, 'hex') else: @@ -517,10 +521,11 @@ class Image(): save_enctlv, enctlv_len): # NOTE: should already be checked by the argument parser magic_size = 16 + magic_align_size = (int((magic_size - 1) / self.max_align) + 1) * self.max_align if overwrite_only: - return MAX_ALIGN * 2 + magic_size + return self.max_align * 2 + magic_align_size else: - if write_size not in set([1, 2, 4, 8]): + if write_size not in set([1, 2, 4, 8, 16, 32]): raise click.BadParameter("Invalid alignment: {}".format( write_size)) m = DEFAULT_MAX_SECTORS if max_sectors is None else max_sectors @@ -528,12 +533,12 @@ class Image(): if enckey is not None: if save_enctlv: # TLV saved by the bootloader is aligned - keylen = (int((enctlv_len - 1) / MAX_ALIGN) + 1) * MAX_ALIGN + keylen = (int((enctlv_len - 1) / self.max_align) + 1) * self.max_align else: - keylen = 16 + keylen = (int((16 - 1) / self.max_align) + 1) * self.max_align trailer += keylen * 2 # encryption keys - trailer += MAX_ALIGN * 4 # image_ok/copy_done/swap_info/swap_size - trailer += magic_size + trailer += self.max_align * 4 # image_ok/copy_done/swap_info/swap_size + trailer += magic_align_size return trailer def pad_to(self, size): @@ -544,9 +549,12 @@ class Image(): padding = size - (len(self.payload) + tsize) pbytes = bytearray([self.erased_val] * padding) pbytes += bytearray([self.erased_val] * (tsize - len(boot_magic))) - if self.confirm and not self.overwrite_only: - pbytes[-MAX_ALIGN] = 0x01 # image_ok = 0x01 pbytes += boot_magic + if self.confirm and not self.overwrite_only: + magic_size = 16 + magic_align_size = (int((magic_size - 1) / self.max_align) + 1) * self.max_align + image_ok_idx = -(magic_align_size + self.max_align) + 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 dd6c0447..87eccd99 100755 --- a/scripts/imgtool/main.py +++ b/scripts/imgtool/main.py @@ -288,8 +288,10 @@ class BasedIntParamType(click.ParamType): help='Specify the value of security counter. Use the `auto` ' 'keyword to automatically generate it from the image version.') @click.option('-v', '--version', callback=validate_version, required=True) -@click.option('--align', type=click.Choice(['1', '2', '4', '8']), +@click.option('--align', type=click.Choice(['1', '2', '4', '8', '16', '32']), required=True) +@click.option('--max-align', type=click.Choice(['8', '16', '32']), + required=False) @click.option('--public-key-format', type=click.Choice(['hash', 'full']), default='hash', help='In what format to add the public key to ' 'the image manifest: full key or hash of the key.') @@ -301,7 +303,7 @@ def sign(key, public_key_format, align, version, pad_sig, header_size, pad_header, slot_size, pad, confirm, max_sectors, overwrite_only, endian, encrypt_keylen, encrypt, infile, outfile, dependencies, load_addr, hex_addr, erased_val, save_enctlv, security_counter, - boot_record, custom_tlv, rom_fixed): + boot_record, custom_tlv, rom_fixed, max_align): if confirm: # Confirmed but non-padded images don't make much sense, because @@ -313,7 +315,7 @@ def sign(key, public_key_format, align, version, pad_sig, header_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, - security_counter=security_counter) + security_counter=security_counter, max_align=max_align) img.load(infile) key = load_key(key) if key else None enckey = load_key(encrypt) if encrypt else None