diff --git a/.github/workflows/sim.yaml b/.github/workflows/sim.yaml index 79765fbd5..c1d91a673 100644 --- a/.github/workflows/sim.yaml +++ b/.github/workflows/sim.yaml @@ -44,6 +44,7 @@ jobs: - "sig-rsa validate-primary-slot ram-load multiimage" - "sig-rsa validate-primary-slot direct-xip multiimage" - "sig-ecdsa hw-rollback-protection multiimage" + - "sig-ecdsa-psa,sig-ecdsa-psa sig-p384" - "ram-load enc-aes256-kw multiimage" - "ram-load enc-aes256-kw sig-ecdsa-mbedtls multiimage" runs-on: ubuntu-latest diff --git a/README.md b/README.md index a400a4def..7211e2284 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ [![Coverity Scan Build Status](https://scan.coverity.com/projects/12307/badge.svg)][coverity] [![Build Status (Sim)](https://github.com/mcu-tools/mcuboot/workflows/Sim/badge.svg)][sim] [![Build Status (Mynewt)](https://github.com/mcu-tools/mcuboot/workflows/Mynewt/badge.svg)][mynewt] +[![Build Status (Espressif)](https://github.com/mcu-tools/mcuboot/workflows/Espressif/badge.svg)][espressif] [![Publishing Status (imgtool)](https://github.com/mcu-tools/mcuboot/workflows/imgtool/badge.svg)][imgtool] [![Build Status (Travis CI)](https://img.shields.io/travis/mcu-tools/mcuboot/main.svg?label=travis-ci)][travis] [![Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)][license] @@ -12,11 +13,12 @@ [coverity]: https://scan.coverity.com/projects/mcuboot [sim]: https://github.com/mcu-tools/mcuboot/actions?query=workflow:Sim [mynewt]: https://github.com/mcu-tools/mcuboot/actions?query=workflow:Mynewt +[espressif]: https://github.com/mcu-tools/mcuboot/actions?query=workflow:Espressif [imgtool]: https://github.com/mcu-tools/mcuboot/actions?query=workflow:imgtool [travis]: https://travis-ci.org/mcu-tools/mcuboot [license]: https://github.com/mcu-tools/mcuboot/blob/main/LICENSE -This is MCUboot version 1.11.0-dev +This is MCUboot version 2.1.0-dev MCUboot is a secure bootloader for 32-bits microcontrollers. It defines a common infrastructure for the bootloader and the system flash layout on diff --git a/boot/boot_serial/src/boot_serial.c b/boot/boot_serial/src/boot_serial.c index 3e3175ba4..bc07e2d60 100644 --- a/boot/boot_serial/src/boot_serial.c +++ b/boot/boot_serial/src/boot_serial.c @@ -231,7 +231,7 @@ bs_list_img_ver(char *dst, int maxlen, struct image_version *ver) (uint16_t)ver->iv_minor, ver->iv_revision); if (ver->iv_build_num != 0 && len > 0 && len < maxlen) { - snprintf(&dst[len], (maxlen - len), "%u", ver->iv_build_num); + snprintf(&dst[len], (maxlen - len), ".%u", ver->iv_build_num); } } #endif /* !MCUBOOT_USE_SNPRINTF */ @@ -259,7 +259,11 @@ bs_list(char *buf, int len) int swap_status = boot_swap_type_multi(image_index); #endif +#ifdef MCUBOOT_SINGLE_APPLICATION_SLOT + for (slot = 0; slot < 1; slot++) { +#else for (slot = 0; slot < 2; slot++) { +#endif FIH_DECLARE(fih_rc, FIH_FAILURE); uint8_t tmpbuf[64]; @@ -289,15 +293,26 @@ bs_list(char *buf, int len) fih_rc, image_index, slot); if (FIH_EQ(fih_rc, FIH_BOOT_HOOK_REGULAR)) { -#ifdef MCUBOOT_ENC_IMAGES - if (IS_ENCRYPTED(&hdr)) { +#if defined(MCUBOOT_ENC_IMAGES) +#if !defined(MCUBOOT_SINGLE_APPLICATION_SLOT) + if (IS_ENCRYPTED(&hdr) && MUST_DECRYPT(fap, image_index, &hdr)) { FIH_CALL(boot_image_validate_encrypted, fih_rc, fap, &hdr, tmpbuf, sizeof(tmpbuf)); } else { #endif + if (IS_ENCRYPTED(&hdr)) { + /* + * There is an image present which has an encrypted flag set but is + * not encrypted, therefore remove the flag from the header and run a + * normal image validation on it. + */ + hdr.ih_flags &= ~ENCRYPTIONFLAGS; + } +#endif + FIH_CALL(bootutil_img_validate, fih_rc, NULL, 0, &hdr, fap, tmpbuf, sizeof(tmpbuf), NULL, 0, NULL); -#ifdef MCUBOOT_ENC_IMAGES +#if defined(MCUBOOT_ENC_IMAGES) && !defined(MCUBOOT_SINGLE_APPLICATION_SLOT) } #endif } @@ -1010,11 +1025,11 @@ boot_serial_input(char *buf, int len) } } else if (hdr->nh_group == MGMT_GROUP_ID_DEFAULT) { switch (hdr->nh_id) { - case NMGR_ID_ECHO: #ifdef MCUBOOT_BOOT_MGMT_ECHO + case NMGR_ID_ECHO: bs_echo(buf, len); -#endif break; +#endif case NMGR_ID_CONS_ECHO_CTRL: bs_rc_rsp(0); break; @@ -1189,6 +1204,10 @@ boot_serial_read_console(const struct boot_uart_funcs *f,int timeout_in_ms) int max_input; int elapsed_in_ms = 0; +#ifndef MCUBOOT_SERIAL_WAIT_FOR_DFU + bool allow_idle = true; +#endif + boot_uf = f; max_input = sizeof(in_buf); @@ -1200,7 +1219,10 @@ boot_serial_read_console(const struct boot_uart_funcs *f,int timeout_in_ms) * from serial console (if single-thread mode is used). */ #ifndef MCUBOOT_SERIAL_WAIT_FOR_DFU - MCUBOOT_CPU_IDLE(); + if (allow_idle == true) { + MCUBOOT_CPU_IDLE(); + allow_idle = false; + } #endif MCUBOOT_WATCHDOG_FEED(); #ifdef MCUBOOT_SERIAL_WAIT_FOR_DFU @@ -1208,6 +1230,9 @@ boot_serial_read_console(const struct boot_uart_funcs *f,int timeout_in_ms) #endif rc = f->read(in_buf + off, sizeof(in_buf) - off, &full_line); if (rc <= 0 && !full_line) { +#ifndef MCUBOOT_SERIAL_WAIT_FOR_DFU + allow_idle = true; +#endif goto check_timeout; } off += rc; diff --git a/boot/bootutil/include/bootutil/boot_status.h b/boot/bootutil/include/bootutil/boot_status.h index 149e45e87..8ec0619aa 100644 --- a/boot/bootutil/include/bootutil/boot_status.h +++ b/boot/bootutil/include/bootutil/boot_status.h @@ -122,7 +122,8 @@ enum mcuboot_mode { MCUBOOT_MODE_SWAP_USING_MOVE, MCUBOOT_MODE_DIRECT_XIP, MCUBOOT_MODE_DIRECT_XIP_WITH_REVERT, - MCUBOOT_MODE_RAM_LOAD + MCUBOOT_MODE_RAM_LOAD, + MCUBOOT_MODE_FIRMWARE_LOADER }; enum mcuboot_signature_type { diff --git a/boot/bootutil/include/bootutil/bootutil_public.h b/boot/bootutil/include/bootutil/bootutil_public.h index e8d83a1d2..b2d5a5de8 100644 --- a/boot/bootutil/include/bootutil/bootutil_public.h +++ b/boot/bootutil/include/bootutil/bootutil_public.h @@ -85,8 +85,10 @@ extern "C" { #ifdef MCUBOOT_BOOT_MAX_ALIGN +#if defined(MCUBOOT_SWAP_USING_MOVE) || defined(MCUBOOT_SWAP_USING_SCRATCH) _Static_assert(MCUBOOT_BOOT_MAX_ALIGN >= 8 && MCUBOOT_BOOT_MAX_ALIGN <= 32, - "Unsupported value for MCUBOOT_BOOT_MAX_ALIGN"); + "Unsupported value for MCUBOOT_BOOT_MAX_ALIGN for SWAP upgrade modes"); +#endif #define BOOT_MAX_ALIGN MCUBOOT_BOOT_MAX_ALIGN #define BOOT_MAGIC_ALIGN_SIZE ALIGN_UP(BOOT_MAGIC_SZ, BOOT_MAX_ALIGN) diff --git a/boot/bootutil/include/bootutil/caps.h b/boot/bootutil/include/bootutil/caps.h index e29b9365f..f4ff37334 100644 --- a/boot/bootutil/include/bootutil/caps.h +++ b/boot/bootutil/include/bootutil/caps.h @@ -52,6 +52,7 @@ uint32_t bootutil_get_caps(void); #define BOOTUTIL_CAP_RAM_LOAD (1<<16) #define BOOTUTIL_CAP_DIRECT_XIP (1<<17) #define BOOTUTIL_CAP_HW_ROLLBACK_PROT (1<<18) +#define BOOTUTIL_CAP_ECDSA_P384 (1<<19) /* * Query the number of images this bootloader is configured for. This diff --git a/boot/bootutil/include/bootutil/crypto/ecdsa.h b/boot/bootutil/include/bootutil/crypto/ecdsa.h index 0c0f16a6b..949ec82bf 100644 --- a/boot/bootutil/include/bootutil/crypto/ecdsa.h +++ b/boot/bootutil/include/bootutil/crypto/ecdsa.h @@ -80,8 +80,9 @@ extern "C" { #endif -#if defined(MCUBOOT_USE_TINYCRYPT) || defined(MCUBOOT_USE_MBED_TLS) || defined(MCUBOOT_USE_CC310) \ - || defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO) +#if (defined(MCUBOOT_USE_TINYCRYPT) || defined(MCUBOOT_USE_MBED_TLS) || \ + defined(MCUBOOT_USE_CC310) || defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO)) \ + && !defined(MCUBOOT_USE_PSA_CRYPTO) /* * Declaring these like this adds NULL termination. */ @@ -131,7 +132,7 @@ static int bootutil_import_key(uint8_t **cp, uint8_t *end) return 0; } -#endif /* MCUBOOT_USE_TINYCRYPT || MCUBOOT_USE_MBED_TLS || MCUBOOT_USE_CC310 */ +#endif /* (MCUBOOT_USE_TINYCRYPT || MCUBOOT_USE_MBED_TLS || MCUBOOT_USE_CC310) && !MCUBOOT_USE_PSA_CRYPTO */ /* * cp points to ASN1 string containing an integer. diff --git a/boot/bootutil/include/bootutil/crypto/sha256.h b/boot/bootutil/include/bootutil/crypto/sha.h similarity index 61% rename from boot/bootutil/include/bootutil/crypto/sha256.h rename to boot/bootutil/include/bootutil/crypto/sha.h index 7d6d07a9e..4e52dd06d 100644 --- a/boot/bootutil/include/bootutil/crypto/sha256.h +++ b/boot/bootutil/include/bootutil/crypto/sha.h @@ -18,8 +18,8 @@ * the MCUBOOT_USE_PSA_CRYPTO will take precedence. */ -#ifndef __BOOTUTIL_CRYPTO_SHA256_H_ -#define __BOOTUTIL_CRYPTO_SHA256_H_ +#ifndef __BOOTUTIL_CRYPTO_SHA_H_ +#define __BOOTUTIL_CRYPTO_SHA_H_ #include "mcuboot_config/mcuboot_config.h" #include "mcuboot_config/mcuboot_logging.h" @@ -35,8 +35,16 @@ #error "One crypto backend must be defined: either CC310/MBED_TLS/TINYCRYPT/PSA_CRYPTO" #endif +#if defined(MCUBOOT_SIGN_EC384) + #define IMAGE_HASH_SIZE (48) + #define EXPECTED_HASH_TLV IMAGE_TLV_SHA384 +#else + #define IMAGE_HASH_SIZE (32) + #define EXPECTED_HASH_TLV IMAGE_TLV_SHA256 +#endif /* MCUBOOT_SIGN_EC384 */ + /* Universal defines for SHA-256 */ -#define BOOTUTIL_CRYPTO_SHA256_BLOCK_SIZE (64) +#define BOOTUTIL_CRYPTO_SHA256_BLOCK_SIZE (64) #define BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE (32) #if defined(MCUBOOT_USE_PSA_CRYPTO) @@ -70,45 +78,54 @@ extern "C" { #if defined(MCUBOOT_USE_PSA_CRYPTO) -typedef psa_hash_operation_t bootutil_sha256_context; +typedef psa_hash_operation_t bootutil_sha_context; -static inline int bootutil_sha256_init(bootutil_sha256_context *ctx) +static inline int bootutil_sha_init(bootutil_sha_context *ctx) { *ctx = psa_hash_operation_init(); - return (int)psa_hash_setup(ctx, PSA_ALG_SHA_256); +#if defined(MCUBOOT_SIGN_EC384) + psa_status_t status = psa_hash_setup(ctx, PSA_ALG_SHA_384); +#else + psa_status_t status = psa_hash_setup(ctx, PSA_ALG_SHA_256); +#endif + return (int)status; } -static inline int bootutil_sha256_drop(bootutil_sha256_context *ctx) +static inline int bootutil_sha_drop(bootutil_sha_context *ctx) { return (int)psa_hash_abort(ctx); } -static inline int bootutil_sha256_update(bootutil_sha256_context *ctx, - const void *data, - uint32_t data_len) +static inline int bootutil_sha_update(bootutil_sha_context *ctx, + const void *data, + uint32_t data_len) { return (int)psa_hash_update(ctx, data, data_len); } -static inline int bootutil_sha256_finish(bootutil_sha256_context *ctx, - uint8_t *output) +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_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 } #elif defined(MCUBOOT_USE_MBED_TLS) -typedef mbedtls_sha256_context bootutil_sha256_context; +typedef mbedtls_sha256_context bootutil_sha_context; -static inline int bootutil_sha256_init(bootutil_sha256_context *ctx) +static inline int bootutil_sha_init(bootutil_sha_context *ctx) { mbedtls_sha256_init(ctx); return mbedtls_sha256_starts_ret(ctx, 0); } -static inline int bootutil_sha256_drop(bootutil_sha256_context *ctx) +static inline int bootutil_sha_drop(bootutil_sha_context *ctx) { /* XXX: config defines MBEDTLS_PLATFORM_NO_STD_FUNCTIONS so no need to free */ /* (void)mbedtls_sha256_free(ctx); */ @@ -116,15 +133,15 @@ static inline int bootutil_sha256_drop(bootutil_sha256_context *ctx) return 0; } -static inline int bootutil_sha256_update(bootutil_sha256_context *ctx, - const void *data, - uint32_t data_len) +static inline int bootutil_sha_update(bootutil_sha_context *ctx, + const void *data, + uint32_t data_len) { return mbedtls_sha256_update_ret(ctx, data, data_len); } -static inline int bootutil_sha256_finish(bootutil_sha256_context *ctx, - uint8_t *output) +static inline int bootutil_sha_finish(bootutil_sha_context *ctx, + uint8_t *output) { return mbedtls_sha256_finish_ret(ctx, output); } @@ -132,57 +149,58 @@ static inline int bootutil_sha256_finish(bootutil_sha256_context *ctx, #endif /* MCUBOOT_USE_MBED_TLS */ #if defined(MCUBOOT_USE_TINYCRYPT) -typedef struct tc_sha256_state_struct bootutil_sha256_context; -static inline int bootutil_sha256_init(bootutil_sha256_context *ctx) +typedef struct tc_sha256_state_struct bootutil_sha_context; + +static inline int bootutil_sha_init(bootutil_sha_context *ctx) { tc_sha256_init(ctx); return 0; } -static inline int bootutil_sha256_drop(bootutil_sha256_context *ctx) +static inline int bootutil_sha_drop(bootutil_sha_context *ctx) { (void)ctx; return 0; } -static inline int bootutil_sha256_update(bootutil_sha256_context *ctx, - const void *data, - uint32_t data_len) +static inline int bootutil_sha_update(bootutil_sha_context *ctx, + const void *data, + uint32_t data_len) { return tc_sha256_update(ctx, data, data_len); } -static inline int bootutil_sha256_finish(bootutil_sha256_context *ctx, - uint8_t *output) +static inline int bootutil_sha_finish(bootutil_sha_context *ctx, + uint8_t *output) { return tc_sha256_final(output, ctx); } #endif /* MCUBOOT_USE_TINYCRYPT */ #if defined(MCUBOOT_USE_CC310) -static inline int bootutil_sha256_init(bootutil_sha256_context *ctx) +static inline int bootutil_sha_init(bootutil_sha_context *ctx) { cc310_sha256_init(ctx); return 0; } -static inline int bootutil_sha256_drop(bootutil_sha256_context *ctx) +static inline int bootutil_sha_drop(bootutil_sha_context *ctx) { (void)ctx; nrf_cc310_disable(); return 0; } -static inline int bootutil_sha256_update(bootutil_sha256_context *ctx, - const void *data, - uint32_t data_len) +static inline int 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_sha256_finish(bootutil_sha256_context *ctx, - uint8_t *output) +static inline int bootutil_sha_finish(bootutil_sha_context *ctx, + uint8_t *output) { cc310_sha256_finalize(ctx, output); return 0; @@ -224,4 +242,4 @@ static inline int bootutil_sha256_finish(bootutil_sha256_context *ctx, } #endif -#endif /* __BOOTUTIL_CRYPTO_SHA256_H_ */ +#endif /* __BOOTUTIL_CRYPTO_SHA_H_ */ diff --git a/boot/bootutil/include/bootutil/image.h b/boot/bootutil/include/bootutil/image.h index 69ff033b3..d3e5f93af 100644 --- a/boot/bootutil/include/bootutil/image.h +++ b/boot/bootutil/include/bootutil/image.h @@ -80,7 +80,6 @@ struct flash_area; * Image trailer TLV types. * * Signature is generated by computing signature over the image hash. - * Currently the only image hash type is SHA256. * * Signature comes in the form of 2 TLVs. * 1st on identifies the public key which should be used to verify it. @@ -89,6 +88,7 @@ struct flash_area; #define IMAGE_TLV_KEYHASH 0x01 /* hash of the public key */ #define IMAGE_TLV_PUBKEY 0x02 /* public key */ #define IMAGE_TLV_SHA256 0x10 /* SHA256 of image hdr and body */ +#define IMAGE_TLV_SHA384 0x11 /* SHA384 of image hdr and body */ #define IMAGE_TLV_RSA2048_PSS 0x20 /* RSA2048 of hash output */ #define IMAGE_TLV_ECDSA224 0x21 /* ECDSA of hash output - Not supported anymore */ #define IMAGE_TLV_ECDSA_SIG 0x22 /* ECDSA of hash output */ diff --git a/boot/bootutil/src/boot_record.c b/boot/bootutil/src/boot_record.c index 8f02fe626..64a36d7c1 100644 --- a/boot/bootutil/src/boot_record.c +++ b/boot/bootutil/src/boot_record.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2021 Arm Limited + * Copyright (c) 2018-2023 Arm Limited * Copyright (c) 2020 Linaro Limited * Copyright (c) 2023, Nordic Semiconductor ASA * @@ -23,6 +23,7 @@ #include #include "mcuboot_config/mcuboot_config.h" +#include "bootutil/crypto/sha.h" #if defined(MCUBOOT_MEASURED_BOOT) || defined(MCUBOOT_DATA_SHARING) #include "bootutil/boot_record.h" @@ -31,6 +32,7 @@ #include "bootutil/image.h" #include "flash_map_backend/flash_map_backend.h" +#if !defined(MCUBOOT_CUSTOM_DATA_SHARING_FUNCTION) /** * @var shared_memory_init_done * @@ -112,6 +114,7 @@ boot_add_data_to_shared_area(uint8_t major_type, return SHARED_MEMORY_OK; } #endif /* MCUBOOT_MEASURED_BOOT OR MCUBOOT_DATA_SHARING */ +#endif /* !MCUBOOT_CUSTOM_DATA_SHARING_FUNCTION */ #ifdef MCUBOOT_MEASURED_BOOT /* See in boot_record.h */ @@ -127,7 +130,7 @@ boot_save_boot_status(uint8_t sw_module, uint16_t type; uint16_t ias_minor; size_t record_len = 0; - uint8_t image_hash[32]; /* SHA256 - 32 Bytes */ + uint8_t image_hash[IMAGE_HASH_SIZE]; uint8_t buf[MAX_BOOT_RECORD_SZ]; bool boot_record_found = false; bool hash_found = false; @@ -165,7 +168,7 @@ boot_save_boot_status(uint8_t sw_module, record_len = len; boot_record_found = true; - } else if (type == IMAGE_TLV_SHA256) { + } else if (type == EXPECTED_HASH_TLV) { /* Get the image's hash value from the manifest section. */ if (len > sizeof(image_hash)) { return -1; @@ -247,6 +250,8 @@ int boot_save_shared_data(const struct image_header *hdr, const struct flash_are #endif #elif defined(MCUBOOT_RAM_LOAD) uint8_t mode = MCUBOOT_MODE_RAM_LOAD; +#elif defined(MCUBOOT_FIRMWARE_LOADER) + uint8_t mode = MCUBOOT_MODE_FIRMWARE_LOADER; #else #error "Unknown mcuboot operating mode" #endif diff --git a/boot/bootutil/src/bootutil_misc.c b/boot/bootutil/src/bootutil_misc.c index 0caad7ff1..87b863507 100644 --- a/boot/bootutil/src/bootutil_misc.c +++ b/boot/bootutil/src/bootutil_misc.c @@ -333,7 +333,8 @@ boot_write_enc_key(const struct flash_area *fap, uint8_t slot, uint32_t bootutil_max_image_size(const struct flash_area *fap) { -#if defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SINGLE_APPLICATION_SLOT) +#if defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SINGLE_APPLICATION_SLOT) || \ + defined(MCUBOOT_FIRMWARE_LOADER) return boot_status_off(fap); #elif defined(MCUBOOT_SWAP_USING_MOVE) struct flash_sector sector; diff --git a/boot/bootutil/src/bootutil_priv.h b/boot/bootutil/src/bootutil_priv.h index 059bfcd1f..32f996e78 100644 --- a/boot/bootutil/src/bootutil_priv.h +++ b/boot/bootutil/src/bootutil_priv.h @@ -57,15 +57,17 @@ struct flash_area; #if (defined(MCUBOOT_OVERWRITE_ONLY) + \ defined(MCUBOOT_SWAP_USING_MOVE) + \ defined(MCUBOOT_DIRECT_XIP) + \ - defined(MCUBOOT_RAM_LOAD)) > 1 -#error "Please enable only one of MCUBOOT_OVERWRITE_ONLY, MCUBOOT_SWAP_USING_MOVE, MCUBOOT_DIRECT_XIP or MCUBOOT_RAM_LOAD" + defined(MCUBOOT_RAM_LOAD) + \ + defined(MCUBOOT_FIRMWARE_LOADER)) > 1 +#error "Please enable only one of MCUBOOT_OVERWRITE_ONLY, MCUBOOT_SWAP_USING_MOVE, MCUBOOT_DIRECT_XIP, MCUBOOT_RAM_LOAD or MCUBOOT_FIRMWARE_LOADER" #endif #if !defined(MCUBOOT_OVERWRITE_ONLY) && \ !defined(MCUBOOT_SWAP_USING_MOVE) && \ !defined(MCUBOOT_DIRECT_XIP) && \ !defined(MCUBOOT_RAM_LOAD) && \ - !defined(MCUBOOT_SINGLE_APPLICATION_SLOT) + !defined(MCUBOOT_SINGLE_APPLICATION_SLOT) && \ + !defined(MCUBOOT_FIRMWARE_LOADER) #define MCUBOOT_SWAP_USING_SCRATCH 1 #endif diff --git a/boot/bootutil/src/caps.c b/boot/bootutil/src/caps.c index 49bdfecf7..d7cd59042 100644 --- a/boot/bootutil/src/caps.c +++ b/boot/bootutil/src/caps.c @@ -35,6 +35,9 @@ uint32_t bootutil_get_caps(void) #if defined(MCUBOOT_SIGN_EC256) res |= BOOTUTIL_CAP_ECDSA_P256; #endif +#if defined(MCUBOOT_SIGN_EC384) + res |= BOOTUTIL_CAP_ECDSA_P384; +#endif #if defined(MCUBOOT_SIGN_ED25519) res |= BOOTUTIL_CAP_ED25519; #endif diff --git a/boot/bootutil/src/encrypted.c b/boot/bootutil/src/encrypted.c index 82435a425..bc4d917bd 100644 --- a/boot/bootutil/src/encrypted.c +++ b/boot/bootutil/src/encrypted.c @@ -30,7 +30,7 @@ #endif #if defined(MCUBOOT_ENCRYPT_EC256) || defined(MCUBOOT_ENCRYPT_X25519) -#include "bootutil/crypto/sha256.h" +#include "bootutil/crypto/sha.h" #include "bootutil/crypto/hmac_sha256.h" #include "mbedtls/oid.h" #include "mbedtls/asn1.h" diff --git a/boot/bootutil/src/image_rsa.c b/boot/bootutil/src/image_rsa.c index 34ee85bbd..37c35e05e 100644 --- a/boot/bootutil/src/image_rsa.c +++ b/boot/bootutil/src/image_rsa.c @@ -43,7 +43,7 @@ */ #if !defined(MCUBOOT_USE_PSA_CRYPTO) -#include "bootutil/crypto/sha256.h" +#include "bootutil/crypto/sha.h" /* * Constants for this particular constrained implementation of @@ -86,17 +86,17 @@ static const uint8_t pss_zeros[8] = {0}; static void pss_mgf1(uint8_t *mask, const uint8_t *hash) { - bootutil_sha256_context ctx; + bootutil_sha_context ctx; uint8_t counter[4] = { 0, 0, 0, 0 }; uint8_t htmp[PSS_HLEN]; int count = PSS_MASK_LEN; int bytes; while (count > 0) { - bootutil_sha256_init(&ctx); - bootutil_sha256_update(&ctx, hash, PSS_HLEN); - bootutil_sha256_update(&ctx, counter, 4); - bootutil_sha256_finish(&ctx, htmp); + bootutil_sha_init(&ctx); + bootutil_sha_update(&ctx, hash, PSS_HLEN); + bootutil_sha_update(&ctx, counter, 4); + bootutil_sha_finish(&ctx, htmp); counter[3]++; @@ -109,7 +109,7 @@ pss_mgf1(uint8_t *mask, const uint8_t *hash) count -= bytes; } - bootutil_sha256_drop(&ctx); + bootutil_sha_drop(&ctx); } /* @@ -121,7 +121,7 @@ static fih_ret bootutil_cmp_rsasig(bootutil_rsa_context *ctx, uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen) { - bootutil_sha256_context shactx; + bootutil_sha_context shactx; uint8_t em[MBEDTLS_MPI_MAX_SIZE]; uint8_t db_mask[PSS_MASK_LEN]; uint8_t h2[PSS_HLEN]; @@ -221,12 +221,12 @@ bootutil_cmp_rsasig(bootutil_rsa_context *ctx, uint8_t *hash, uint32_t hlen, /* Step 12. Let M' = 0x00 00 00 00 00 00 00 00 || mHash || salt; */ /* Step 13. Let H' = Hash(M') */ - bootutil_sha256_init(&shactx); - bootutil_sha256_update(&shactx, pss_zeros, 8); - bootutil_sha256_update(&shactx, hash, PSS_HLEN); - bootutil_sha256_update(&shactx, &db_mask[PSS_MASK_SALT_POS], PSS_SLEN); - bootutil_sha256_finish(&shactx, h2); - bootutil_sha256_drop(&shactx); + bootutil_sha_init(&shactx); + bootutil_sha_update(&shactx, pss_zeros, 8); + bootutil_sha_update(&shactx, hash, PSS_HLEN); + bootutil_sha_update(&shactx, &db_mask[PSS_MASK_SALT_POS], PSS_SLEN); + bootutil_sha_finish(&shactx, h2); + bootutil_sha_drop(&shactx); /* Step 14. If H = H', output "consistent". Otherwise, output * "inconsistent". */ diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c index 8260e5949..d045a3e79 100644 --- a/boot/bootutil/src/image_validate.c +++ b/boot/bootutil/src/image_validate.c @@ -33,7 +33,7 @@ #include #include "bootutil/image.h" -#include "bootutil/crypto/sha256.h" +#include "bootutil/crypto/sha.h" #include "bootutil/sign_key.h" #include "bootutil/security_cnt.h" #include "bootutil/fault_injection_hardening.h" @@ -57,7 +57,9 @@ #include "bootutil_priv.h" /* - * Compute SHA256 over the image. + * Compute SHA hash over the image. + * (SHA384 if ECDSA-P384 is being used, + * SHA256 otherwise). */ static int bootutil_img_hash(struct enc_key_data *enc_state, int image_index, @@ -65,7 +67,7 @@ bootutil_img_hash(struct enc_key_data *enc_state, int image_index, uint8_t *tmp_buf, uint32_t tmp_buf_sz, uint8_t *hash_result, uint8_t *seed, int seed_len) { - bootutil_sha256_context sha256_ctx; + bootutil_sha_context sha_ctx; uint32_t blk_sz; uint32_t size; uint16_t hdr_size; @@ -99,12 +101,12 @@ bootutil_img_hash(struct enc_key_data *enc_state, int image_index, } #endif - bootutil_sha256_init(&sha256_ctx); + bootutil_sha_init(&sha_ctx); /* in some cases (split image) the hash is seeded with data from * the loader image */ if (seed && (seed_len > 0)) { - bootutil_sha256_update(&sha256_ctx, seed, seed_len); + bootutil_sha_update(&sha_ctx, seed, seed_len); } /* Hash is computed over image header and image itself. */ @@ -116,9 +118,9 @@ bootutil_img_hash(struct enc_key_data *enc_state, int image_index, size += hdr->ih_protect_tlv_size; #ifdef MCUBOOT_RAM_LOAD - bootutil_sha256_update(&sha256_ctx, - (void*)(IMAGE_RAM_BASE + hdr->ih_load_addr), - size); + bootutil_sha_update(&sha_ctx, + (void*)(IMAGE_RAM_BASE + hdr->ih_load_addr), + size); #else for (off = 0; off < size; off += blk_sz) { blk_sz = size - off; @@ -140,7 +142,7 @@ bootutil_img_hash(struct enc_key_data *enc_state, int image_index, #endif rc = flash_area_read(fap, off, tmp_buf, blk_sz); if (rc) { - bootutil_sha256_drop(&sha256_ctx); + bootutil_sha_drop(&sha_ctx); return rc; } #ifdef MCUBOOT_ENC_IMAGES @@ -153,11 +155,11 @@ bootutil_img_hash(struct enc_key_data *enc_state, int image_index, } } #endif - bootutil_sha256_update(&sha256_ctx, tmp_buf, blk_sz); + bootutil_sha_update(&sha_ctx, tmp_buf, blk_sz); } #endif /* MCUBOOT_RAM_LOAD */ - bootutil_sha256_finish(&sha256_ctx, hash_result); - bootutil_sha256_drop(&sha256_ctx); + bootutil_sha_finish(&sha_ctx, hash_result); + bootutil_sha_drop(&sha_ctx); return 0; } @@ -170,6 +172,7 @@ bootutil_img_hash(struct enc_key_data *enc_state, int image_index, */ #if (defined(MCUBOOT_SIGN_RSA) + \ defined(MCUBOOT_SIGN_EC256) + \ + defined(MCUBOOT_SIGN_EC384) + \ defined(MCUBOOT_SIGN_ED25519)) > 1 #error "Only a single signature type is supported!" #endif @@ -185,6 +188,7 @@ bootutil_img_hash(struct enc_key_data *enc_state, int image_index, # define SIG_BUF_SIZE (MCUBOOT_SIGN_RSA_LEN / 8) # define EXPECTED_SIG_LEN(x) ((x) == SIG_BUF_SIZE) /* 2048 bits */ #elif defined(MCUBOOT_SIGN_EC256) || \ + defined(MCUBOOT_SIGN_EC384) || \ defined(MCUBOOT_SIGN_EC) # define EXPECTED_SIG_TLV IMAGE_TLV_ECDSA_SIG # define SIG_BUF_SIZE 128 @@ -202,26 +206,26 @@ bootutil_img_hash(struct enc_key_data *enc_state, int image_index, static int bootutil_find_key(uint8_t *keyhash, uint8_t keyhash_len) { - bootutil_sha256_context sha256_ctx; + bootutil_sha_context sha_ctx; int i; const struct bootutil_key *key; - uint8_t hash[32]; + uint8_t hash[IMAGE_HASH_SIZE]; - if (keyhash_len > 32) { + if (keyhash_len > IMAGE_HASH_SIZE) { return -1; } for (i = 0; i < bootutil_key_cnt; i++) { key = &bootutil_keys[i]; - bootutil_sha256_init(&sha256_ctx); - bootutil_sha256_update(&sha256_ctx, key->key, *key->len); - bootutil_sha256_finish(&sha256_ctx, hash); + bootutil_sha_init(&sha_ctx); + bootutil_sha_update(&sha_ctx, key->key, *key->len); + bootutil_sha_finish(&sha_ctx, hash); if (!memcmp(hash, keyhash, keyhash_len)) { - bootutil_sha256_drop(&sha256_ctx); + bootutil_sha_drop(&sha_ctx); return i; } } - bootutil_sha256_drop(&sha256_ctx); + bootutil_sha_drop(&sha_ctx); return -1; } #else @@ -229,17 +233,17 @@ extern unsigned int pub_key_len; static int bootutil_find_key(uint8_t image_index, uint8_t *key, uint16_t key_len) { - bootutil_sha256_context sha256_ctx; - uint8_t hash[32]; - uint8_t key_hash[32]; + 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); int rc; FIH_DECLARE(fih_rc, FIH_FAILURE); - bootutil_sha256_init(&sha256_ctx); - bootutil_sha256_update(&sha256_ctx, key, key_len); - bootutil_sha256_finish(&sha256_ctx, hash); - bootutil_sha256_drop(&sha256_ctx); + 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 = boot_retrieve_public_key_hash(image_index, key_hash, &key_hash_size); if (rc) { @@ -337,7 +341,7 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, uint32_t off; uint16_t len; uint16_t type; - int sha256_valid = 0; + int image_hash_valid = 0; #ifdef EXPECTED_SIG_TLV FIH_DECLARE(valid_signature, FIH_FAILURE); int key_id = -1; @@ -348,7 +352,7 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, #endif /* EXPECTED_SIG_TLV */ struct image_tlv_iter it; uint8_t buf[SIG_BUF_SIZE]; - uint8_t hash[32]; + uint8_t hash[IMAGE_HASH_SIZE]; int rc = 0; FIH_DECLARE(fih_rc, FIH_FAILURE); #ifdef MCUBOOT_HW_ROLLBACK_PROT @@ -364,7 +368,7 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, } if (out_hash) { - memcpy(out_hash, hash, 32); + memcpy(out_hash, hash, IMAGE_HASH_SIZE); } rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, false); @@ -389,11 +393,8 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, break; } - if (type == IMAGE_TLV_SHA256) { - /* - * Verify the SHA256 image hash. This must always be - * present. - */ + if (type == EXPECTED_HASH_TLV) { + /* Verify the image hash. This must always be present. */ if (len != sizeof(hash)) { rc = -1; goto out; @@ -409,14 +410,14 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, goto out; } - sha256_valid = 1; + image_hash_valid = 1; #ifdef EXPECTED_SIG_TLV #ifndef MCUBOOT_HW_KEY } else if (type == IMAGE_TLV_KEYHASH) { /* * Determine which key we should be checking. */ - if (len > 32) { + if (len > IMAGE_HASH_SIZE) { rc = -1; goto out; } @@ -506,7 +507,7 @@ bootutil_img_validate(struct enc_key_data *enc_state, int image_index, } } - rc = !sha256_valid; + rc = !image_hash_valid; if (rc) { goto out; } diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 623f670a7..f1bb10803 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -2229,11 +2229,22 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp) fa_id = flash_area_id_from_multi_image_slot(image_index, slot); rc = flash_area_open(fa_id, &BOOT_IMG_AREA(state, slot)); assert(rc == 0); + + if (rc != 0) { + BOOT_LOG_ERR("Failed to open flash area ID %d (image %d slot %d): %d, " + "cannot continue", fa_id, image_index, (int8_t)slot, rc); + FIH_PANIC; + } } #if MCUBOOT_SWAP_USING_SCRATCH rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH, &BOOT_SCRATCH_AREA(state)); assert(rc == 0); + + if (rc != 0) { + BOOT_LOG_ERR("Failed to open scratch flash area: %d, cannot continue", rc); + FIH_PANIC; + } #endif /* Determine swap type and complete swap if it has been aborted. */ diff --git a/boot/espressif/CMakeLists.txt b/boot/espressif/CMakeLists.txt index bc7868f8f..bc703fc24 100644 --- a/boot/espressif/CMakeLists.txt +++ b/boot/espressif/CMakeLists.txt @@ -11,8 +11,6 @@ if (NOT DEFINED MCUBOOT_TARGET) message(FATAL_ERROR "MCUBOOT_TARGET not defined. Please pass -DMCUBOOT_TARGET flag.") endif() -project(mcuboot_${MCUBOOT_TARGET}) - add_definitions(-DMCUBOOT_TARGET=${MCUBOOT_TARGET}) add_definitions(-D__ESPRESSIF__=1) @@ -27,6 +25,41 @@ elseif("${MCUBOOT_TARGET}" STREQUAL "esp32c3" OR set(MCUBOOT_ARCH "riscv") endif() +if (NOT DEFINED CMAKE_TOOLCHAIN_FILE) + if (DEFINED TOOLCHAIN_BIN_DIR) + message("CMAKE_TOOLCHAIN_FILE not defined, searching for toolchain compiler in TOOLCHAIN_BIN_DIR: ${TOOLCHAIN_BIN_DIR}") + set(CMAKE_SYSTEM_NAME Generic) + + file(GLOB C_COMPILER_BIN "${TOOLCHAIN_BIN_DIR}/*${MCUBOOT_ARCH}*elf-gcc") + if (NOT C_COMPILER_BIN) + message(FATAL_ERROR "No C compiler found. Please ensure that TOOLCHAIN_BIN_DIR directory contains a set of C compiling tools compatible with the target") + endif() + set(CMAKE_C_COMPILER ${C_COMPILER_BIN}) + set(CMAKE_ASM_COMPILER ${C_COMPILER_BIN}) + message("C compiler found: ${CMAKE_C_COMPILER}") + + file(GLOB CXX_COMPILER_BIN "${TOOLCHAIN_BIN_DIR}/*${MCUBOOT_ARCH}*elf-g++") + if (NOT CXX_COMPILER_BIN) + message(FATAL_ERROR "No C++ compiler found. Please ensure that TOOLCHAIN_BIN_DIR directory contains a set of C++ compiling tools compatible with the target") + endif() + set(CMAKE_CXX_COMPILER ${CXX_COMPILER_BIN}) + message("CXX compiler found: ${CMAKE_CXX_COMPILER}") + else() + # Set toolchain file that expect the same toolchain as IDF sets on PATH + set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_LIST_DIR}/tools/toolchain-${MCUBOOT_TARGET}.cmake) + message("No user-defined toolchain, setting default toolchain file: ${CMAKE_TOOLCHAIN_FILE}") + endif() + + # This flag is needed when redefining a different compiler toolchain at this point + # on CMakeLists, the reason is that CMake does a compiler testing prior to building + # that may fail due to cross-compilation + set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY") +else() + message("CMAKE_TOOLCHAIN_FILE: ${CMAKE_TOOLCHAIN_FILE}") +endif() + +project(mcuboot_${MCUBOOT_TARGET}) + # Set the minimum revision for each supported chip if ("${MCUBOOT_TARGET}" STREQUAL "esp32") set(ESP_MIN_REVISION 3) @@ -50,10 +83,12 @@ if (NOT DEFINED ESP_HAL_PATH) if (DEFINED ENV{ESP_HAL_PATH}) set(ESP_HAL_PATH $ENV{ESP_HAL_PATH}) else() - message(WARNING "ESP_HAL_PATH not found. Please set -DESP_HAL_PATH parameter or define ESP_HAL_PATH environment variable.") + message(WARNING "ESP_HAL_PATH not defined, checking if IDF_PATH exists.") if (DEFINED ENV{IDF_PATH}) set(ESP_HAL_PATH $ENV{IDF_PATH}) message("IDF installation found in the system, using IDF_PATH as ESP_HAL_PATH.") + else () + message(FATAL_ERROR "Please set -DESP_HAL_PATH parameter or define ESP_HAL_PATH environment variable.") endif() endif() endif() diff --git a/boot/espressif/hal/CMakeLists.txt b/boot/espressif/hal/CMakeLists.txt index 7f3d1bbb4..d248c2670 100644 --- a/boot/espressif/hal/CMakeLists.txt +++ b/boot/espressif/hal/CMakeLists.txt @@ -71,11 +71,8 @@ set(hal_srcs ${esp_hal_dir}/components/bootloader_support/src/bootloader_random_${MCUBOOT_TARGET}.c ${esp_hal_dir}/components/bootloader_support/src/bootloader_utility.c ${esp_hal_dir}/components/bootloader_support/src/esp_image_format.c - ${esp_hal_dir}/components/bootloader_support/src/secure_boot_v2/secure_boot_signatures_bootloader.c ${esp_hal_dir}/components/bootloader_support/src/${MCUBOOT_TARGET}/bootloader_soc.c ${esp_hal_dir}/components/bootloader_support/src/${MCUBOOT_TARGET}/bootloader_sha.c - ${esp_hal_dir}/components/bootloader_support/src/${MCUBOOT_TARGET}/secure_boot_secure_features.c - ${esp_hal_dir}/components/bootloader_support/src/${MCUBOOT_TARGET}/flash_encryption_secure_features.c ${esp_hal_dir}/components/hal/mpu_hal.c ${esp_hal_dir}/components/hal/efuse_hal.c ${esp_hal_dir}/components/hal/mmu_hal.c @@ -103,12 +100,23 @@ set(hal_srcs if(DEFINED CONFIG_SECURE_BOOT_V2_ENABLED) list(APPEND hal_srcs ${src_dir}/secure_boot.c + ${esp_hal_dir}/components/bootloader_support/src/secure_boot_v2/secure_boot_signatures_bootloader.c + ${esp_hal_dir}/components/bootloader_support/src/${MCUBOOT_TARGET}/secure_boot_secure_features.c + ) + list(APPEND include_dirs + ${esp_hal_dir}/components/bootloader_support/src/secure_boot_v2 ) endif() if(DEFINED CONFIG_SECURE_FLASH_ENC_ENABLED) list(APPEND hal_srcs ${src_dir}/flash_encrypt.c + ${esp_hal_dir}/components/bootloader_support/src/${MCUBOOT_TARGET}/flash_encryption_secure_features.c + ) + set_source_files_properties( + ${src_dir}/flash_encrypt.c + PROPERTIES COMPILE_FLAGS + "-Wno-unused-variable" ) endif() diff --git a/boot/espressif/hal/include/esp32c6/esp32c6.cmake b/boot/espressif/hal/include/esp32c6/esp32c6.cmake index 23b6b0091..d26c5f0dc 100644 --- a/boot/espressif/hal/include/esp32c6/esp32c6.cmake +++ b/boot/espressif/hal/include/esp32c6/esp32c6.cmake @@ -8,7 +8,7 @@ list(APPEND include_dirs list(APPEND hal_srcs ${esp_hal_dir}/components/hal/cache_hal.c - ${esp_hal_dir}/components/hal/${MCUBOOT_TARGET}/lp_timer_hal.c + ${esp_hal_dir}/components/hal/lp_timer_hal.c ${esp_hal_dir}/components/efuse/src/efuse_controller/keys/with_key_purposes/esp_efuse_api_key.c ${esp_hal_dir}/components/esp_rom/patches/esp_rom_regi2c_${MCUBOOT_TARGET}.c ) diff --git a/boot/espressif/hal/include/esp32h2/esp32h2.cmake b/boot/espressif/hal/include/esp32h2/esp32h2.cmake index 9160eaba5..d26c5f0dc 100644 --- a/boot/espressif/hal/include/esp32h2/esp32h2.cmake +++ b/boot/espressif/hal/include/esp32h2/esp32h2.cmake @@ -8,6 +8,7 @@ list(APPEND include_dirs list(APPEND hal_srcs ${esp_hal_dir}/components/hal/cache_hal.c + ${esp_hal_dir}/components/hal/lp_timer_hal.c ${esp_hal_dir}/components/efuse/src/efuse_controller/keys/with_key_purposes/esp_efuse_api_key.c ${esp_hal_dir}/components/esp_rom/patches/esp_rom_regi2c_${MCUBOOT_TARGET}.c ) diff --git a/boot/espressif/hal/src/flash_encrypt.c b/boot/espressif/hal/src/flash_encrypt.c index 222e32e2a..d064d8b7b 100644 --- a/boot/espressif/hal/src/flash_encrypt.c +++ b/boot/espressif/hal/src/flash_encrypt.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -15,7 +15,11 @@ #include "esp_efuse_table.h" #include "esp_log.h" #include "hal/wdt_hal.h" +#include "hal/efuse_hal.h" #include "soc/soc_caps.h" +#ifdef CONFIG_SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK +#include "soc/sensitive_reg.h" +#endif #include "esp_mcuboot_image.h" @@ -27,6 +31,8 @@ #define WR_DIS_CRYPT_CNT ESP_EFUSE_WR_DIS_SPI_BOOT_CRYPT_CNT #endif +#define FLASH_ENC_CNT_MAX (CRYPT_CNT[0]->bit_count) + /* This file implements FLASH ENCRYPTION related APIs to perform * various operations such as programming necessary flash encryption * eFuses, detect whether flash encryption is enabled (by reading eFuse) @@ -36,10 +42,9 @@ static const char *TAG = "flash_encrypt"; /* Static functions for stages of flash encryption */ -static esp_err_t initialise_flash_encryption(void); -static esp_err_t encrypt_flash_contents(uint32_t flash_crypt_cnt, bool flash_crypt_wr_dis) __attribute__((unused)); static esp_err_t encrypt_bootloader(void); static esp_err_t encrypt_primary_slot(void); +static size_t get_flash_encrypt_cnt_value(void); /** * This former inlined function must not be defined in the header file anymore. @@ -50,15 +55,14 @@ static esp_err_t encrypt_primary_slot(void); */ bool IRAM_ATTR esp_flash_encryption_enabled(void) { - uint32_t flash_crypt_cnt = 0; #ifndef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH - flash_crypt_cnt = efuse_ll_get_flash_crypt_cnt(); + return efuse_hal_flash_encryption_enabled(); #else + uint32_t flash_crypt_cnt = 0; #if CONFIG_IDF_TARGET_ESP32 esp_efuse_read_field_blob(ESP_EFUSE_FLASH_CRYPT_CNT, &flash_crypt_cnt, ESP_EFUSE_FLASH_CRYPT_CNT[0]->bit_count); #else esp_efuse_read_field_blob(ESP_EFUSE_SPI_BOOT_CRYPT_CNT, &flash_crypt_cnt, ESP_EFUSE_SPI_BOOT_CRYPT_CNT[0]->bit_count); -#endif #endif /* __builtin_parity is in flash, so we calculate parity inline */ bool enabled = false; @@ -69,34 +73,84 @@ bool IRAM_ATTR esp_flash_encryption_enabled(void) flash_crypt_cnt >>= 1; } return enabled; +#endif // CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH } -esp_err_t esp_flash_encrypt_check_and_update(void) +static size_t get_flash_encrypt_cnt_value(void) { size_t flash_crypt_cnt = 0; esp_efuse_read_field_cnt(CRYPT_CNT, &flash_crypt_cnt); - bool flash_crypt_wr_dis = esp_efuse_read_field_bit(WR_DIS_CRYPT_CNT); + return flash_crypt_cnt; +} + +bool esp_flash_encrypt_initialized_once(void) +{ + return get_flash_encrypt_cnt_value() != 0; +} + +bool esp_flash_encrypt_is_write_protected(bool print_error) +{ + if (esp_efuse_read_field_bit(WR_DIS_CRYPT_CNT)) { + if (print_error) { + ESP_LOGE(TAG, "Flash Encryption cannot be enabled (CRYPT_CNT (%d) is write protected)", get_flash_encrypt_cnt_value()); + } + return true; + } + return false; +} + +bool esp_flash_encrypt_state(void) +{ + size_t flash_crypt_cnt = get_flash_encrypt_cnt_value(); + bool flash_crypt_wr_dis = esp_flash_encrypt_is_write_protected(false); ESP_LOGV(TAG, "CRYPT_CNT %d, write protection %d", flash_crypt_cnt, flash_crypt_wr_dis); if (flash_crypt_cnt % 2 == 1) { /* Flash is already encrypted */ - int left = (CRYPT_CNT[0]->bit_count - flash_crypt_cnt) / 2; + int left = (FLASH_ENC_CNT_MAX - flash_crypt_cnt) / 2; if (flash_crypt_wr_dis) { left = 0; /* can't update FLASH_CRYPT_CNT, no more flashes */ } ESP_LOGI(TAG, "flash encryption is enabled (%d plaintext flashes left)", left); - return ESP_OK; - } else { + return true; + } + return false; +} + +esp_err_t esp_flash_encrypt_check_and_update(void) +{ + bool flash_encryption_enabled = esp_flash_encrypt_state(); + if (!flash_encryption_enabled) { #ifndef CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED - /* Flash is not encrypted, so encrypt it! */ - return encrypt_flash_contents(flash_crypt_cnt, flash_crypt_wr_dis); + if (esp_flash_encrypt_is_write_protected(true)) { + return ESP_FAIL; + } + + esp_err_t err = esp_flash_encrypt_init(); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Initialization of Flash encryption key failed (%d)", err); + return err; + } + + err = esp_flash_encrypt_contents(); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Encryption flash contents failed (%d)", err); + return err; + } + + err = esp_flash_encrypt_enable(); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Enabling of Flash encryption failed (%d)", err); + return err; + } #else ESP_LOGE(TAG, "flash encryption is not enabled, and SECURE_FLASH_REQUIRE_ALREADY_ENABLED " "is set, refusing to boot."); return ESP_ERR_INVALID_STATE; #endif // CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED } + return ESP_OK; } static esp_err_t check_and_generate_encryption_keys(void) @@ -126,11 +180,19 @@ static esp_err_t check_and_generate_encryption_keys(void) ESP_LOGE(TAG, "XTS_AES_128_KEY is already in use, XTS_AES_256_KEY_1/2 can not be used"); return ESP_ERR_INVALID_STATE; } +#else +#ifdef CONFIG_SECURE_FLASH_ENCRYPTION_AES128_DERIVED + enum { BLOCKS_NEEDED = 1 }; + esp_efuse_purpose_t purposes[BLOCKS_NEEDED] = { + ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY_DERIVED_FROM_128_EFUSE_BITS, + }; + key_size = 16; #else enum { BLOCKS_NEEDED = 1 }; esp_efuse_purpose_t purposes[BLOCKS_NEEDED] = { ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY, }; +#endif // CONFIG_SECURE_FLASH_ENCRYPTION_AES128_DERIVED #endif // CONFIG_SECURE_FLASH_ENCRYPTION_AES256 #endif // CONFIG_IDF_TARGET_ESP32 @@ -181,8 +243,14 @@ static esp_err_t check_and_generate_encryption_keys(void) return ESP_OK; } -static esp_err_t initialise_flash_encryption(void) +esp_err_t esp_flash_encrypt_init(void) { + if (esp_flash_encryption_enabled() || esp_flash_encrypt_initialized_once()) { + return ESP_OK; + } + + /* Very first flash encryption pass: generate keys, etc. */ + esp_efuse_batch_write_begin(); /* Batch all efuse writes at the end of this function */ /* Before first flash encryption pass, need to initialise key & crypto config */ @@ -198,26 +266,6 @@ static esp_err_t initialise_flash_encryption(void) return err; } -#if defined(SOC_SUPPORTS_SECURE_DL_MODE) && defined(CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE) - ESP_LOGI(TAG, "Enabling Secure Download mode..."); - err = esp_efuse_enable_rom_secure_download_mode(); - if (err != ESP_OK) { - ESP_LOGE(TAG, "Could not enable Secure Download mode..."); - esp_efuse_batch_write_cancel(); - return err; - } -#elif CONFIG_SECURE_DISABLE_ROM_DL_MODE - ESP_LOGI(TAG, "Disable ROM Download mode..."); - err = esp_efuse_disable_rom_download_mode(); - if (err != ESP_OK) { - ESP_LOGE(TAG, "Could not disable ROM Download mode..."); - esp_efuse_batch_write_cancel(); - return err; - } -#else - ESP_LOGW(TAG, "UART ROM Download mode kept enabled - SECURITY COMPROMISED"); -#endif - err = esp_efuse_batch_write_commit(); if (err != ESP_OK) { ESP_LOGE(TAG, "Error programming security eFuses (err=0x%x).", err); @@ -228,24 +276,13 @@ static esp_err_t initialise_flash_encryption(void) } /* Encrypt all flash data that should be encrypted */ -static esp_err_t encrypt_flash_contents(uint32_t flash_crypt_cnt, bool flash_crypt_wr_dis) +esp_err_t esp_flash_encrypt_contents(void) { esp_err_t err; - /* If all flash_crypt_cnt bits are burned or write-disabled, the - device can't re-encrypt itself. */ - if (flash_crypt_wr_dis || flash_crypt_cnt == CRYPT_CNT[0]->bit_count) { - ESP_LOGE(TAG, "Cannot re-encrypt data CRYPT_CNT %d write disabled %d", flash_crypt_cnt, flash_crypt_wr_dis); - return ESP_FAIL; - } - - if (flash_crypt_cnt == 0) { - /* Very first flash of encrypted data: generate keys, etc. */ - err = initialise_flash_encryption(); - if (err != ESP_OK) { - return err; - } - } +#ifdef CONFIG_SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK + REG_WRITE(SENSITIVE_XTS_AES_KEY_UPDATE_REG, 1); +#endif err = encrypt_bootloader(); if (err != ESP_OK) { @@ -292,20 +329,48 @@ static esp_err_t encrypt_flash_contents(uint32_t flash_crypt_cnt, bool flash_cry } #endif + ESP_LOGI(TAG, "Flash encryption completed"); + + return ESP_OK; +} + +esp_err_t esp_flash_encrypt_enable(void) +{ + esp_err_t err = ESP_OK; + if (!esp_flash_encryption_enabled()) { + + if (esp_flash_encrypt_is_write_protected(true)) { + return ESP_FAIL; + } + + size_t flash_crypt_cnt = get_flash_encrypt_cnt_value(); + #ifdef CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE - // Go straight to max, permanently enabled - ESP_LOGI(TAG, "Setting CRYPT_CNT for permanent encryption"); - size_t new_flash_crypt_cnt = CRYPT_CNT[0]->bit_count - flash_crypt_cnt; + // Go straight to max, permanently enabled + ESP_LOGI(TAG, "Setting CRYPT_CNT for permanent encryption"); + size_t new_flash_crypt_cnt = FLASH_ENC_CNT_MAX - flash_crypt_cnt; #else - /* Set least significant 0-bit in flash_crypt_cnt */ - size_t new_flash_crypt_cnt = 1; + /* Set least significant 0-bit in flash_crypt_cnt */ + size_t new_flash_crypt_cnt = 1; +#endif + ESP_LOGD(TAG, "CRYPT_CNT %d -> %d", flash_crypt_cnt, new_flash_crypt_cnt); + err = esp_efuse_write_field_cnt(CRYPT_CNT, new_flash_crypt_cnt); + +#if defined(CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE) && defined(CONFIG_SOC_FLASH_ENCRYPTION_XTS_AES_128_DERIVED) + // For AES128_DERIVED, FE key is 16 bytes and XTS_KEY_LENGTH_256 is 0. + // It is important to protect XTS_KEY_LENGTH_256 from further changing it to 1. Set write protection for this bit. + // Burning WR_DIS_CRYPT_CNT, blocks further changing of eFuses: DOWNLOAD_DIS_MANUAL_ENCRYPT, SPI_BOOT_CRYPT_CNT, [XTS_KEY_LENGTH_256], SECURE_BOOT_EN. + esp_efuse_write_field_bit(WR_DIS_CRYPT_CNT); #endif - ESP_LOGD(TAG, "CRYPT_CNT %d -> %d", flash_crypt_cnt, new_flash_crypt_cnt); - err = esp_efuse_write_field_cnt(CRYPT_CNT, new_flash_crypt_cnt); + } ESP_LOGI(TAG, "Flash encryption completed"); - return ESP_OK; +#ifdef CONFIG_EFUSE_VIRTUAL + ESP_LOGW(TAG, "Flash encryption not really completed. Must disable virtual efuses"); +#endif + + return err; } static esp_err_t encrypt_bootloader(void) diff --git a/boot/espressif/hal/src/secure_boot.c b/boot/espressif/hal/src/secure_boot.c index f724f0e88..8ad29ae7c 100644 --- a/boot/espressif/hal/src/secure_boot.c +++ b/boot/espressif/hal/src/secure_boot.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -14,7 +14,8 @@ #include "esp_image_format.h" #include "esp_efuse.h" #include "esp_efuse_table.h" -#include "rom/secure_boot.h" +#include "secure_boot_signature_priv.h" + /* The following API implementations are used only when called * from the bootloader code. @@ -99,12 +100,20 @@ static esp_err_t s_calculate_image_public_key_digests(uint32_t flash_offset, uin /* Generating the SHA of the public key components in the signature block */ bootloader_sha256_handle_t sig_block_sha; sig_block_sha = bootloader_sha256_start(); +#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME bootloader_sha256_data(sig_block_sha, &block->key, sizeof(block->key)); +#elif CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME + bootloader_sha256_data(sig_block_sha, &block->ecdsa.key, sizeof(block->ecdsa.key)); +#endif bootloader_sha256_finish(sig_block_sha, key_digest); // Check we can verify the image using this signature and this key uint8_t temp_verified_digest[ESP_SECURE_BOOT_DIGEST_LEN]; +#if CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME bool verified = ets_rsa_pss_verify(&block->key, block->signature, image_digest, temp_verified_digest); +#elif CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME + bool verified = ets_ecdsa_verify(&block->ecdsa.key.point[0], block->ecdsa.signature, block->ecdsa.key.curve_id, image_digest, temp_verified_digest); +#endif if (!verified) { /* We don't expect this: the signature blocks before we enable secure boot should all be verifiable or invalid, @@ -133,21 +142,22 @@ esp_err_t check_and_generate_secure_boot_keys(void) { esp_err_t ret; #ifdef CONFIG_IDF_TARGET_ESP32 - esp_efuse_purpose_t secure_boot_key_purpose[SECURE_BOOT_NUM_BLOCKS] = { - ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_V2, - }; esp_efuse_coding_scheme_t coding_scheme = esp_efuse_get_coding_scheme(EFUSE_BLK_SECURE_BOOT); if (coding_scheme != EFUSE_CODING_SCHEME_NONE) { ESP_LOGE(TAG, "No coding schemes are supported in secure boot v2.(Detected scheme: 0x%x)", coding_scheme); return ESP_ERR_NOT_SUPPORTED; } -#else +#endif // CONFIG_IDF_TARGET_ESP32 + esp_efuse_purpose_t secure_boot_key_purpose[SECURE_BOOT_NUM_BLOCKS] = { +#if SECURE_BOOT_NUM_BLOCKS == 1 + ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_V2, +#else ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST0, ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST1, ESP_EFUSE_KEY_PURPOSE_SECURE_BOOT_DIGEST2, +#endif }; -#endif // CONFIG_IDF_TARGET_ESP32 /* Verify the bootloader */ esp_image_metadata_t bootloader_data = { 0 }; @@ -209,17 +219,24 @@ esp_err_t check_and_generate_secure_boot_keys(void) continue; } #endif +#ifndef CONFIG_SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK if (esp_efuse_get_key_dis_read(blocks[i])) { ESP_LOGE(TAG, "Key digest (BLK%d) read protected, aborting...", blocks[i]); return ESP_FAIL; } +#endif if (esp_efuse_block_is_empty(blocks[i])) { ESP_LOGE(TAG, "%d eFuse block is empty, aborting...", blocks[i]); return ESP_FAIL; } esp_efuse_set_key_dis_write(blocks[i]); - ret = esp_efuse_read_block(blocks[i], boot_key_digests.key_digests[boot_key_digests.num_digests], 0, - sizeof(boot_key_digests.key_digests[0]) * 8); +#ifdef CONFIG_SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK + size_t offset = 128; +#else + size_t offset = 0; +#endif + ret = esp_efuse_read_block(blocks[i], boot_key_digests.key_digests[boot_key_digests.num_digests], offset, + ESP_SECURE_BOOT_KEY_DIGEST_LEN * 8); if (ret) { ESP_LOGE(TAG, "Error during reading %d eFuse block (err=0x%x)", blocks[i], ret); return ret; diff --git a/boot/espressif/main.c b/boot/espressif/main.c index 9e1aa0704..3f4d5a064 100644 --- a/boot/espressif/main.c +++ b/boot/espressif/main.c @@ -12,6 +12,7 @@ #include "bootloader_init.h" #include "bootloader_utility.h" #include "bootloader_random.h" +#include "bootloader_soc.h" #include "esp_assert.h" @@ -118,6 +119,21 @@ int main() esp_efuse_init_virtual_mode_in_flash(CONFIG_EFUSE_VIRTUAL_OFFSET, CONFIG_EFUSE_VIRTUAL_SIZE); #endif +#if defined(CONFIG_SECURE_BOOT) || defined(CONFIG_SECURE_FLASH_ENC_ENABLED) + esp_err_t err; +#endif + +#ifdef CONFIG_SECURE_BOOT_FLASH_ENC_KEYS_BURN_TOGETHER + if (esp_secure_boot_enabled() ^ esp_flash_encrypt_initialized_once()) { + BOOT_LOG_ERR("Secure Boot and Flash Encryption cannot be enabled separately, only together (their keys go into one eFuse key block)"); + FIH_PANIC; + } + + if (!esp_secure_boot_enabled() || !esp_flash_encryption_enabled()) { + esp_efuse_batch_write_begin(); + } +#endif // CONFIG_SECURE_BOOT_FLASH_ENC_KEYS_BURN_TOGETHER + #ifdef CONFIG_SECURE_BOOT /* Steps 1 (see above for full description): * 1) Compute digest of the public key. @@ -132,7 +148,6 @@ int main() } else { esp_efuse_batch_write_begin(); /* Batch all efuse writes at the end of this function */ - esp_err_t err; err = check_and_generate_secure_boot_keys(); if (err != ESP_OK) { esp_efuse_batch_write_cancel(); @@ -178,7 +193,6 @@ int main() if (!sb_hw_enabled) { BOOT_LOG_INF("blowing secure boot efuse..."); - esp_err_t err; err = esp_secure_boot_enable_secure_features(); if (err != ESP_OK) { esp_efuse_batch_write_cancel(); @@ -195,8 +209,10 @@ int main() assert(esp_efuse_read_field_bit(ESP_EFUSE_SECURE_BOOT_AGGRESSIVE_REVOKE)); #endif +#ifndef CONFIG_SECURE_BOOT_FLASH_ENC_KEYS_BURN_TOGETHER assert(esp_secure_boot_enabled()); BOOT_LOG_INF("Secure boot permanently enabled"); +#endif } #endif @@ -206,16 +222,50 @@ int main() * 5) Encrypt flash in-place including bootloader, image primary/secondary slot and scratch. * 6) Burn EFUSE to enable flash encryption */ - - int rc; - BOOT_LOG_INF("Checking flash encryption..."); - bool flash_encryption_enabled = esp_flash_encryption_enabled(); - rc = esp_flash_encrypt_check_and_update(); - if (rc != ESP_OK) { - BOOT_LOG_ERR("Flash encryption check failed (%d).", rc); + bool flash_encryption_enabled = esp_flash_encrypt_state(); + if (!flash_encryption_enabled) { +#ifdef CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED + BOOT_LOG_ERR("flash encryption is not enabled, and SECURE_FLASH_REQUIRE_ALREADY_ENABLED is set, refusing to boot."); FIH_PANIC; +#endif // CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED + + if (esp_flash_encrypt_is_write_protected(true)) { + FIH_PANIC; + } + + err = esp_flash_encrypt_init(); + if (err != ESP_OK) { + BOOT_LOG_ERR("Initialization of Flash Encryption key failed (%d)", err); + FIH_PANIC; + } + } + + if (!flash_encryption_enabled) { + err = esp_flash_encrypt_contents(); + if (err != ESP_OK) { + BOOT_LOG_ERR("Encryption flash contents failed (%d)", err); + FIH_PANIC; + } + + err = esp_flash_encrypt_enable(); + if (err != ESP_OK) { + BOOT_LOG_ERR("Enabling of Flash encryption failed (%d)", err); + FIH_PANIC; + } + } + +#ifdef CONFIG_SECURE_BOOT_FLASH_ENC_KEYS_BURN_TOGETHER + if (!esp_secure_boot_enabled() || !flash_encryption_enabled) { + err = esp_efuse_batch_write_commit(); + if (err != ESP_OK) { + BOOT_LOG_ERR("Error programming eFuses (err=0x%x).", err); + FIH_PANIC; + } + assert(esp_secure_boot_enabled()); + BOOT_LOG_INF("Secure boot permanently enabled"); } +#endif // CONFIG_SECURE_BOOT_FLASH_ENC_KEYS_BURN_TOGETHER /* Step 7 (see above for full description): * 7) Reset system to ensure flash encryption cache resets properly. @@ -229,6 +279,12 @@ int main() BOOT_LOG_INF("Disabling RNG early entropy source..."); bootloader_random_disable(); + /* Disable glitch reset after all the security checks are completed. + * Glitch detection can be falsely triggered by EMI interference (high RF TX power, etc) + * and to avoid such false alarms, disable it. + */ + bootloader_ana_clock_glitch_reset_config(false); + #ifdef CONFIG_ESP_MULTI_PROCESSOR_BOOT /* Multi image independent boot * Boot on the second processor happens before the image0 boot diff --git a/boot/espressif/port/esp32c2/bootloader.conf b/boot/espressif/port/esp32c2/bootloader.conf index 286b1a197..54f797e71 100644 --- a/boot/espressif/port/esp32c2/bootloader.conf +++ b/boot/espressif/port/esp32c2/bootloader.conf @@ -63,6 +63,12 @@ CONFIG_ESP_CONSOLE_UART_NUM=0 # using imgtool instead of use the existent sample # CONFIG_ESP_SIGN_KEY_FILE=root-ec-p256.pem +# Hardware Secure Boot related options +# CONFIG_SECURE_SIGNED_ON_BOOT=1 +# CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME=1 +# CONFIG_SECURE_BOOT=1 +# CONFIG_SECURE_BOOT_V2_ENABLED=1 + # Hardware Flash Encryption related options # CONFIG_SECURE_FLASH_ENC_ENABLED=1 # CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC=1 @@ -72,6 +78,10 @@ CONFIG_ESP_CONSOLE_UART_NUM=0 # CONFIG_SECURE_BOOT_ALLOW_JTAG=1 # CONFIG_SECURE_BOOT_ALLOW_ROM_BASIC=1 +# This option must be also enabled when enabling both Secure Boot +# and Flash Encryption at same time +# CONFIG_SECURE_BOOT_FLASH_ENC_KEYS_BURN_TOGETHER=1 + # Options for enabling eFuse emulation in Flash # CONFIG_EFUSE_VIRTUAL=1 # CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH=1 diff --git a/boot/espressif/port/esp32c3/ld/bootloader.ld b/boot/espressif/port/esp32c3/ld/bootloader.ld index 65f15cc4d..747b54914 100644 --- a/boot/espressif/port/esp32c3/ld/bootloader.ld +++ b/boot/espressif/port/esp32c3/ld/bootloader.ld @@ -13,8 +13,8 @@ MEMORY { iram_seg (RWX) : org = 0x403C7000, len = 0x9000 - iram_loader_seg (RWX) : org = 0x403D0000, len = 0x5000 - dram_seg (RW) : org = 0x3FCD5000, len = 0xA000 + iram_loader_seg (RWX) : org = 0x403D0000, len = 0x5400 + dram_seg (RW) : org = 0x3FCD5400, len = 0xA000 } /* Default entry point: */ diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 2e41259a4..3ad6e6edd 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -6,26 +6,6 @@ cmake_minimum_required(VERSION 3.13.1) -# Enable Zephyr runner options which request mass erase if so -# configured. -# -# Note that this also disables the default "leave" option when -# targeting STM32 DfuSe devices with dfu-util, making the chip stay in -# the bootloader after flashing. -# -# That's the right thing, because mcuboot has nothing to do since the -# chip was just erased. The next thing the user is going to want to do -# is flash the application. (Developers can reset DfuSE devices -# manually to test mcuboot behavior on an otherwise erased flash -# device.) -macro(app_set_runner_args) - if(CONFIG_ZEPHYR_TRY_MASS_ERASE) - board_runner_args(dfu-util "--dfuse-modifiers=force:mass-erase") - board_runner_args(pyocd "--flash-opt=-e=chip") - board_runner_args(nrfjprog "--erase") - endif() -endmacro() - # find_package(Zephyr) in order to load application boilerplate: # http://docs.zephyrproject.org/application/application.html find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) @@ -73,6 +53,7 @@ endif() # Zephyr port-specific sources. zephyr_library_sources( main.c + io.c flash_map_extended.c os.c keys.c @@ -82,6 +63,17 @@ if(DEFINED CONFIG_ENABLE_MGMT_PERUSER) zephyr_library_sources( boot_serial_extensions.c ) + + zephyr_linker_sources_ifdef( + CONFIG_ENABLE_MGMT_PERUSER + SECTIONS include/boot_serial/boot_serial.ld + ) + + if(DEFINED CONFIG_BOOT_MGMT_CUSTOM_STORAGE_ERASE OR DEFINED CONFIG_BOOT_MGMT_CUSTOM_IMG_LIST) + zephyr_library_sources( + boot_serial_extension_zephyr_basic.c + ) + endif() endif() if(NOT DEFINED CONFIG_FLASH_PAGE_LAYOUT) @@ -90,6 +82,12 @@ if(NOT DEFINED CONFIG_FLASH_PAGE_LAYOUT) ) endif() +if(DEFINED CONFIG_BOOT_SHARE_BACKEND_RETENTION) + zephyr_library_sources( + shared_data.c + ) +endif() + # Generic bootutil sources and includes. zephyr_library_include_directories(${BOOT_DIR}/bootutil/include) zephyr_library_sources( @@ -103,6 +101,19 @@ zephyr_library_sources( ${BOOT_DIR}/bootutil/src/fault_injection_hardening.c ) +if(DEFINED CONFIG_MEASURED_BOOT OR DEFINED CONFIG_BOOT_SHARE_DATA) + zephyr_library_sources( + ${BOOT_DIR}/bootutil/src/boot_record.c + ) + + # Set a define for this file which will allow inclusion of the Zephyr version + # include file + set_source_files_properties( + ${BOOT_DIR}/bootutil/src/boot_record.c + PROPERTIES COMPILE_FLAGS -DZEPHYR_VER_INCLUDE=1 + ) +endif() + # library which might be common source code for MCUBoot and an application zephyr_link_libraries(MCUBOOT_BOOTUTIL) @@ -117,6 +128,11 @@ zephyr_library_sources( ${BOOT_DIR}/zephyr/single_loader.c ) zephyr_library_include_directories(${BOOT_DIR}/bootutil/src) +elseif(CONFIG_BOOT_FIRMWARE_LOADER) +zephyr_library_sources( + ${BOOT_DIR}/zephyr/firmware_loader.c + ) +zephyr_library_include_directories(${BOOT_DIR}/bootutil/src) else() zephyr_library_sources( ${BOOT_DIR}/bootutil/src/loader.c diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 5c71f79e1..e9d5be0a4 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -32,6 +32,7 @@ config BOOT_USE_TINYCRYPT # When building for ECDSA, we use our own copy of mbedTLS, so the # Zephyr one must not be enabled or the MBEDTLS_CONFIG_FILE macros # will collide. + select MBEDTLS_PROMPTLESS help Use TinyCrypt for crypto primitives. @@ -257,6 +258,18 @@ config BOOT_RAM_LOAD The address that the image is copied to is specified using the load-addr argument to the imgtool.py script which writes it to the image header. +config BOOT_FIRMWARE_LOADER + bool "Firmware loader" + help + If y, mcuboot will have a single application slot, and the secondary + slot will be for a non-upgradeable firmware loaded image (e.g. for + loading firmware via Bluetooth). The main application will boot by + default unless there is an error with it or the boot mode has been + forced to the firmware loader. + + Note: The firmware loader image must be signed with the same signing + key as the primary image. + endchoice # Workaround for not being able to have commas in macro arguments @@ -376,17 +389,91 @@ config BOOT_MAX_IMG_SECTORS memory usage; larger values allow it to support larger images. If unsure, leave at the default value. -config MEASURED_BOOT - bool "Store the boot state/measurements in shared memory" +config BOOT_SHARE_BACKEND_AVAILABLE + bool + default n + help + Hidden open which indicates if there is a sharing backend available. + +# Workaround for not being able to have commas in macro arguments +DT_CHOSEN_BOOTLOADER_INFO := zephyr,bootloader-info + +config BOOT_SHARE_BACKEND_AVAILABLE + bool default n + help + Hidden open which indicates if there is a sharing backend available. + +choice BOOT_SHARE_BACKEND + prompt "Shared data backend" + default BOOT_SHARE_BACKEND_DISABLED + +config BOOT_SHARE_BACKEND_DISABLED + bool "Disabled" + help + No data sharing support. + +config BOOT_SHARE_BACKEND_RETENTION + bool "Retention" + depends on RETENTION + depends on $(dt_chosen_enabled,$(DT_CHOSEN_BOOTLOADER_INFO)) + select BOOT_SHARE_BACKEND_AVAILABLE + help + Use retention to share data with application. Requires: + - Retained memory area + - Retention partition of retained memory area + - Chosen node "zephyr,bootloader-info" to be set to the retention + partition + +config BOOT_SHARE_BACKEND_EXTERNAL + bool "External (user-provided code)" + select BOOT_SHARE_BACKEND_AVAILABLE + help + Use a custom user-specified storage. + +endchoice + +menuconfig BOOT_SHARE_DATA + bool "Save application specific data" + default n + depends on BOOT_SHARE_BACKEND_AVAILABLE + help + This will allow data to be shared between MCUboot and an application, + it does not include any informatiom by default. + + Note: This requires a backend to function, see + BOOT_SHARE_BACKEND_RETENTION for details on using the retention + subsystem as a backend. + +config BOOT_SHARE_DATA_BOOTINFO + bool "Save boot information data" + default n + depends on BOOT_SHARE_DATA + help + This will place information about the MCUboot configuration and + running application into a shared memory area. + +menuconfig MEASURED_BOOT + bool "Store the boot state/measurements in shared memory area" + default n + depends on BOOT_SHARE_BACKEND_AVAILABLE help If enabled, the bootloader will store certain boot measurements such as the hash of the firmware image in a shared memory area. This data can be used later by runtime services (e.g. by a device attestation service). -config BOOT_SHARE_DATA - bool "Save application specific data in shared memory area" - default n + Note: This requires a backend to function, see + BOOT_SHARE_BACKEND_RETENTION for details on using the retention + subsystem as a backend. + +config MEASURED_BOOT_MAX_CBOR_SIZE + int "Maximum CBOR size of boot state/measurements" + default 64 + range 0 256 + depends on MEASURED_BOOT + help + The maximum size of the CBOR message which stores boot + state/measurements. choice BOOT_FAULT_INJECTION_HARDENING_PROFILE prompt "Fault injection hardening profile" @@ -474,20 +561,6 @@ config BOOT_USB_DFU_DETECT_DELAY endif # BOOT_USB_DFU_GPIO -config ZEPHYR_TRY_MASS_ERASE - bool "Try to mass erase flash when flashing MCUboot image (DEPRECATED)" - select DEPRECATED - help - If y, attempt to configure the Zephyr build system's "flash" - target to mass-erase the flash device before flashing the - MCUboot image. This ensures the scratch and other partitions - are in a consistent state. - - This is not available for all targets. - - This option has been deprecated, to perform a mass erase when - flashing a board, `west flash --erase` should be used instead. - config BOOT_USE_BENCH bool "Enable benchmark code" default n @@ -523,6 +596,8 @@ config MCUBOOT_INDICATION_LED rsource "Kconfig.serial_recovery" +rsource "Kconfig.firmware_loader" + config BOOT_INTR_VEC_RELOC bool "Relocate the interrupt vector to the application" default n diff --git a/boot/zephyr/Kconfig.firmware_loader b/boot/zephyr/Kconfig.firmware_loader new file mode 100644 index 000000000..1ba223949 --- /dev/null +++ b/boot/zephyr/Kconfig.firmware_loader @@ -0,0 +1,47 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +if BOOT_FIRMWARE_LOADER + +menu "Firmware loader entrance methods" + +menuconfig BOOT_FIRMWARE_LOADER_ENTRANCE_GPIO + bool "GPIO" + depends on GPIO + help + Use a GPIO to enter firmware loader mode. + +config BOOT_FIRMWARE_LOADER_DETECT_DELAY + int "Serial detect pin detection delay time [ms]" + default 0 + depends on BOOT_FIRMWARE_LOADER_ENTRANCE_GPIO + help + Used to prevent the bootloader from loading on button press. + Useful for powering on when using the same button as + the one used to place the device in bootloader mode. + +config BOOT_FIRMWARE_LOADER_BOOT_MODE + bool "Check boot mode via retention subsystem" + depends on RETENTION_BOOT_MODE + help + Allows for entering firmware loader mode by using Zephyr's boot mode + retention system (i.e. an application must set the boot mode to stay + in firmware loader mode and reboot the module). + +config BOOT_FIRMWARE_LOADER_NO_APPLICATION + bool "Stay in bootloader if no application" + help + Allows for entering firmware loader mode if there is no bootable + application that the bootloader can jump to. + +config BOOT_FIRMWARE_LOADER_PIN_RESET + bool "Check for device reset by pin" + select HWINFO + help + Checks if the module reset was caused by the reset pin and will + remain in bootloader firmware loader mode if it was. + +endmenu + +endif diff --git a/boot/zephyr/Kconfig.serial_recovery b/boot/zephyr/Kconfig.serial_recovery index 52ec3b013..74bced750 100644 --- a/boot/zephyr/Kconfig.serial_recovery +++ b/boot/zephyr/Kconfig.serial_recovery @@ -13,6 +13,7 @@ menuconfig MCUBOOT_SERIAL select BASE64 select CRC select ZCBOR + depends on !BOOT_FIRMWARE_LOADER help If y, enables a serial-port based update mode. This allows MCUboot itself to load update images into flash over a UART. @@ -128,12 +129,6 @@ config BOOT_MGMT_CUSTOM_STORAGE_ERASE Note that the storage partition needs to be defined, in DTS, otherwise enabling the option will cause a compilation to fail. -config BOOT_MGMT_CUSTOM_IMG_LIST - bool "Enable custom image list command" - help - The option enables command which returns versions and installation - statuses (custom property) for all images. - endif # ENABLE_MGMT_PERUSER menu "Entrance methods" diff --git a/boot/zephyr/VERSION b/boot/zephyr/VERSION index 465a40304..428a3550d 100644 --- a/boot/zephyr/VERSION +++ b/boot/zephyr/VERSION @@ -1,5 +1,5 @@ -VERSION_MAJOR = 1 -VERSION_MINOR = 11 -PATCHLEVEL = 99 +VERSION_MAJOR = 2 +VERSION_MINOR = 1 +PATCHLEVEL = 0 VERSION_TWEAK = 0 EXTRAVERSION = dev diff --git a/boot/zephyr/boards/circuitdojo_feather_nrf9160.conf b/boot/zephyr/boards/circuitdojo_feather_nrf9160.conf index 656239c81..c23f92ca0 100644 --- a/boot/zephyr/boards/circuitdojo_feather_nrf9160.conf +++ b/boot/zephyr/boards/circuitdojo_feather_nrf9160.conf @@ -11,6 +11,3 @@ CONFIG_BOOT_MAX_IMG_SECTORS=256 CONFIG_MCUBOOT_SERIAL=y CONFIG_BOOT_SERIAL_DETECT_DELAY=450 CONFIG_MCUBOOT_INDICATION_LED=y - -# Size of mcuboot partition -CONFIG_SIZE_OPTIMIZATIONS=y \ No newline at end of file diff --git a/boot/zephyr/boards/conexio_stratus.conf b/boot/zephyr/boards/conexio_stratus.conf index 5a2900035..79ba798e7 100644 --- a/boot/zephyr/boards/conexio_stratus.conf +++ b/boot/zephyr/boards/conexio_stratus.conf @@ -13,6 +13,3 @@ CONFIG_BOOT_MAX_IMG_SECTORS=256 CONFIG_MCUBOOT_SERIAL=y CONFIG_BOOT_SERIAL_DETECT_DELAY=450 CONFIG_MCUBOOT_INDICATION_LED=y - -# Size of mcuboot partition -CONFIG_SIZE_OPTIMIZATIONS=y diff --git a/boot/zephyr/boards/esp32_devkitc_wroom.conf b/boot/zephyr/boards/esp32_devkitc_wroom.conf index 1b1e862be..76a126cb4 100644 --- a/boot/zephyr/boards/esp32_devkitc_wroom.conf +++ b/boot/zephyr/boards/esp32_devkitc_wroom.conf @@ -15,3 +15,4 @@ CONFIG_LOG_DEFAULT_LEVEL=0 CONFIG_DEBUG=n CONFIG_HEAP_MEM_POOL_SIZE=4096 +CONFIG_MINIMAL_LIBC=y diff --git a/boot/zephyr/boards/esp32_devkitc_wrover.conf b/boot/zephyr/boards/esp32_devkitc_wrover.conf index 1b1e862be..76a126cb4 100644 --- a/boot/zephyr/boards/esp32_devkitc_wrover.conf +++ b/boot/zephyr/boards/esp32_devkitc_wrover.conf @@ -15,3 +15,4 @@ CONFIG_LOG_DEFAULT_LEVEL=0 CONFIG_DEBUG=n CONFIG_HEAP_MEM_POOL_SIZE=4096 +CONFIG_MINIMAL_LIBC=y diff --git a/boot/zephyr/boards/esp32_ethernet_kit.conf b/boot/zephyr/boards/esp32_ethernet_kit.conf index 70a092a8b..b2b405922 100644 --- a/boot/zephyr/boards/esp32_ethernet_kit.conf +++ b/boot/zephyr/boards/esp32_ethernet_kit.conf @@ -16,3 +16,4 @@ CONFIG_LOG_DEFAULT_LEVEL=0 CONFIG_DEBUG=n CONFIG_HEAP_MEM_POOL_SIZE=4096 +CONFIG_MINIMAL_LIBC=y diff --git a/boot/zephyr/boards/esp32c3_devkitm.conf b/boot/zephyr/boards/esp32c3_devkitm.conf index 8a90ef8ea..56298cd4f 100644 --- a/boot/zephyr/boards/esp32c3_devkitm.conf +++ b/boot/zephyr/boards/esp32c3_devkitm.conf @@ -17,3 +17,4 @@ CONFIG_DEBUG=n CONFIG_XIP=n CONFIG_HEAP_MEM_POOL_SIZE=4096 +CONFIG_MINIMAL_LIBC=y diff --git a/boot/zephyr/boards/esp32s2_franzininho.conf b/boot/zephyr/boards/esp32s2_franzininho.conf index 70a092a8b..b2b405922 100644 --- a/boot/zephyr/boards/esp32s2_franzininho.conf +++ b/boot/zephyr/boards/esp32s2_franzininho.conf @@ -16,3 +16,4 @@ CONFIG_LOG_DEFAULT_LEVEL=0 CONFIG_DEBUG=n CONFIG_HEAP_MEM_POOL_SIZE=4096 +CONFIG_MINIMAL_LIBC=y diff --git a/boot/zephyr/boards/esp32s2_saola.conf b/boot/zephyr/boards/esp32s2_saola.conf index 70a092a8b..b2b405922 100644 --- a/boot/zephyr/boards/esp32s2_saola.conf +++ b/boot/zephyr/boards/esp32s2_saola.conf @@ -16,3 +16,4 @@ CONFIG_LOG_DEFAULT_LEVEL=0 CONFIG_DEBUG=n CONFIG_HEAP_MEM_POOL_SIZE=4096 +CONFIG_MINIMAL_LIBC=y diff --git a/boot/zephyr/boards/esp32s3_devkitm.conf b/boot/zephyr/boards/esp32s3_devkitm.conf index 70a092a8b..b2b405922 100644 --- a/boot/zephyr/boards/esp32s3_devkitm.conf +++ b/boot/zephyr/boards/esp32s3_devkitm.conf @@ -16,3 +16,4 @@ CONFIG_LOG_DEFAULT_LEVEL=0 CONFIG_DEBUG=n CONFIG_HEAP_MEM_POOL_SIZE=4096 +CONFIG_MINIMAL_LIBC=y diff --git a/boot/zephyr/boards/esp_wrover_kit.conf b/boot/zephyr/boards/esp_wrover_kit.conf index 70a092a8b..b2b405922 100644 --- a/boot/zephyr/boards/esp_wrover_kit.conf +++ b/boot/zephyr/boards/esp_wrover_kit.conf @@ -16,3 +16,4 @@ CONFIG_LOG_DEFAULT_LEVEL=0 CONFIG_DEBUG=n CONFIG_HEAP_MEM_POOL_SIZE=4096 +CONFIG_MINIMAL_LIBC=y diff --git a/boot/zephyr/boards/heltec_wifi_lora32_v2.conf b/boot/zephyr/boards/heltec_wifi_lora32_v2.conf index 70a092a8b..b2b405922 100644 --- a/boot/zephyr/boards/heltec_wifi_lora32_v2.conf +++ b/boot/zephyr/boards/heltec_wifi_lora32_v2.conf @@ -16,3 +16,4 @@ CONFIG_LOG_DEFAULT_LEVEL=0 CONFIG_DEBUG=n CONFIG_HEAP_MEM_POOL_SIZE=4096 +CONFIG_MINIMAL_LIBC=y diff --git a/boot/zephyr/boards/icev_wireless.conf b/boot/zephyr/boards/icev_wireless.conf index 792e0e325..5d761a5b3 100644 --- a/boot/zephyr/boards/icev_wireless.conf +++ b/boot/zephyr/boards/icev_wireless.conf @@ -16,3 +16,4 @@ CONFIG_LOG_DEFAULT_LEVEL=0 CONFIG_XIP=n CONFIG_HEAP_MEM_POOL_SIZE=4096 +CONFIG_MINIMAL_LIBC=y diff --git a/boot/zephyr/boards/lpcxpresso55s06.conf b/boot/zephyr/boards/lpcxpresso55s06.conf new file mode 100644 index 000000000..c0f96374c --- /dev/null +++ b/boot/zephyr/boards/lpcxpresso55s06.conf @@ -0,0 +1,6 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +#LPC does not support the MCUBoot swap mode. +CONFIG_BOOT_UPGRADE_ONLY=y +CONFIG_BOOT_MAX_IMG_SECTORS=256 diff --git a/boot/zephyr/boards/lpcxpresso55s16.conf b/boot/zephyr/boards/lpcxpresso55s16.conf new file mode 100644 index 000000000..c0f96374c --- /dev/null +++ b/boot/zephyr/boards/lpcxpresso55s16.conf @@ -0,0 +1,6 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +#LPC does not support the MCUBoot swap mode. +CONFIG_BOOT_UPGRADE_ONLY=y +CONFIG_BOOT_MAX_IMG_SECTORS=256 diff --git a/boot/zephyr/boards/lpcxpresso55s28.conf b/boot/zephyr/boards/lpcxpresso55s28.conf new file mode 100644 index 000000000..fbe7b6723 --- /dev/null +++ b/boot/zephyr/boards/lpcxpresso55s28.conf @@ -0,0 +1,6 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +#LPC does not support the MCUBoot swap mode. +CONFIG_BOOT_UPGRADE_ONLY=y +CONFIG_BOOT_MAX_IMG_SECTORS=512 diff --git a/boot/zephyr/boards/lpcxpresso55s36.conf b/boot/zephyr/boards/lpcxpresso55s36.conf new file mode 100644 index 000000000..c0f96374c --- /dev/null +++ b/boot/zephyr/boards/lpcxpresso55s36.conf @@ -0,0 +1,6 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +#LPC does not support the MCUBoot swap mode. +CONFIG_BOOT_UPGRADE_ONLY=y +CONFIG_BOOT_MAX_IMG_SECTORS=256 diff --git a/boot/zephyr/boards/lpcxpresso55s69_cpu0.conf b/boot/zephyr/boards/lpcxpresso55s69_cpu0.conf new file mode 100644 index 000000000..fbe7b6723 --- /dev/null +++ b/boot/zephyr/boards/lpcxpresso55s69_cpu0.conf @@ -0,0 +1,6 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +#LPC does not support the MCUBoot swap mode. +CONFIG_BOOT_UPGRADE_ONLY=y +CONFIG_BOOT_MAX_IMG_SECTORS=512 diff --git a/boot/zephyr/boards/m5stickc_plus.conf b/boot/zephyr/boards/m5stickc_plus.conf index 70a092a8b..b2b405922 100644 --- a/boot/zephyr/boards/m5stickc_plus.conf +++ b/boot/zephyr/boards/m5stickc_plus.conf @@ -16,3 +16,4 @@ CONFIG_LOG_DEFAULT_LEVEL=0 CONFIG_DEBUG=n CONFIG_HEAP_MEM_POOL_SIZE=4096 +CONFIG_MINIMAL_LIBC=y diff --git a/boot/zephyr/boards/mimxrt1010_evk.conf b/boot/zephyr/boards/mimxrt1010_evk.conf new file mode 100644 index 000000000..e7737afde --- /dev/null +++ b/boot/zephyr/boards/mimxrt1010_evk.conf @@ -0,0 +1,4 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_BOOT_MAX_IMG_SECTORS=2048 diff --git a/boot/zephyr/boards/mimxrt1015_evk.conf b/boot/zephyr/boards/mimxrt1015_evk.conf new file mode 100644 index 000000000..e7737afde --- /dev/null +++ b/boot/zephyr/boards/mimxrt1015_evk.conf @@ -0,0 +1,4 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_BOOT_MAX_IMG_SECTORS=2048 diff --git a/boot/zephyr/boards/mimxrt1040_evk.conf b/boot/zephyr/boards/mimxrt1040_evk.conf new file mode 100644 index 000000000..35f90d455 --- /dev/null +++ b/boot/zephyr/boards/mimxrt1040_evk.conf @@ -0,0 +1,4 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_BOOT_MAX_IMG_SECTORS=1024 diff --git a/boot/zephyr/boards/nrf51dk_nrf51422.conf b/boot/zephyr/boards/nrf51dk_nrf51422.conf index bd4eaac8d..b6d5ae599 100644 --- a/boot/zephyr/boards/nrf51dk_nrf51422.conf +++ b/boot/zephyr/boards/nrf51dk_nrf51422.conf @@ -3,4 +3,3 @@ # partition size with a zephyr DTS overlay to make MCUboot's debug # builds fit. CONFIG_LOG=n -CONFIG_SIZE_OPTIMIZATIONS=y diff --git a/boot/zephyr/boards/nrf52840dongle_nrf52840.conf b/boot/zephyr/boards/nrf52840dongle_nrf52840.conf index c1a938447..d219f351d 100644 --- a/boot/zephyr/boards/nrf52840dongle_nrf52840.conf +++ b/boot/zephyr/boards/nrf52840dongle_nrf52840.conf @@ -3,13 +3,10 @@ # Disable logging. CONFIG_LOG=n -# The build won't fit on the partition allocated for it without size -# optimizations. -CONFIG_SIZE_OPTIMIZATIONS=y - # Serial +CONFIG_CONSOLE=n CONFIG_SERIAL=y -CONFIG_UART_NRFX=y +CONFIG_UART_NRFX=n CONFIG_UART_INTERRUPT_DRIVEN=y CONFIG_UART_LINE_CTRL=y @@ -25,7 +22,5 @@ CONFIG_MULTITHREADING=y CONFIG_USB_DEVICE_STACK=y CONFIG_USB_DEVICE_REMOTE_WAKEUP=n CONFIG_USB_DEVICE_PRODUCT="MCUBOOT" -CONFIG_USB_COMPOSITE_DEVICE=n -CONFIG_USB_MASS_STORAGE=n CONFIG_NORDIC_QSPI_NOR=n diff --git a/boot/zephyr/boards/nrf52_minimal_footprint.conf b/boot/zephyr/boards/nrf52_minimal_footprint.conf index c315b441a..a290312be 100644 --- a/boot/zephyr/boards/nrf52_minimal_footprint.conf +++ b/boot/zephyr/boards/nrf52_minimal_footprint.conf @@ -16,7 +16,6 @@ CONFIG_BOOT_SIGNATURE_KEY_FILE="root-ec-p256.pem" # by reliability reason. CONFIG_BOOT_UPGRADE_ONLY=y -# CONFIG_ZEPHYR_TRY_MASS_ERASE is not set # CONFIG_BOARD_ENABLE_DCDC is not set CONFIG_SOC_SERIES_NRF52X=y CONFIG_SOC_NRF52832_QFAA=y @@ -60,6 +59,3 @@ CONFIG_BOOT_DELAY=0 # Console CONFIG_STDOUT_CONSOLE=n - -# Build -CONFIG_SIZE_OPTIMIZATIONS=y diff --git a/boot/zephyr/boards/odroid_go.conf b/boot/zephyr/boards/odroid_go.conf index be139d66d..916d6cf5f 100644 --- a/boot/zephyr/boards/odroid_go.conf +++ b/boot/zephyr/boards/odroid_go.conf @@ -18,3 +18,4 @@ CONFIG_DEBUG=n CONFIG_HEAP_MEM_POOL_SIZE=4096 CONFIG_REGULATOR=n +CONFIG_MINIMAL_LIBC=y diff --git a/boot/zephyr/boards/olimex_esp32_evb.conf b/boot/zephyr/boards/olimex_esp32_evb.conf index 70a092a8b..b2b405922 100644 --- a/boot/zephyr/boards/olimex_esp32_evb.conf +++ b/boot/zephyr/boards/olimex_esp32_evb.conf @@ -16,3 +16,4 @@ CONFIG_LOG_DEFAULT_LEVEL=0 CONFIG_DEBUG=n CONFIG_HEAP_MEM_POOL_SIZE=4096 +CONFIG_MINIMAL_LIBC=y diff --git a/boot/zephyr/boards/sparkfun_thing_plus_nrf9160.conf b/boot/zephyr/boards/sparkfun_thing_plus_nrf9160.conf index 656239c81..c23f92ca0 100644 --- a/boot/zephyr/boards/sparkfun_thing_plus_nrf9160.conf +++ b/boot/zephyr/boards/sparkfun_thing_plus_nrf9160.conf @@ -11,6 +11,3 @@ CONFIG_BOOT_MAX_IMG_SECTORS=256 CONFIG_MCUBOOT_SERIAL=y CONFIG_BOOT_SERIAL_DETECT_DELAY=450 CONFIG_MCUBOOT_INDICATION_LED=y - -# Size of mcuboot partition -CONFIG_SIZE_OPTIMIZATIONS=y \ No newline at end of file diff --git a/boot/zephyr/boards/stamp_c3.conf b/boot/zephyr/boards/stamp_c3.conf index 8a90ef8ea..56298cd4f 100644 --- a/boot/zephyr/boards/stamp_c3.conf +++ b/boot/zephyr/boards/stamp_c3.conf @@ -17,3 +17,4 @@ CONFIG_DEBUG=n CONFIG_XIP=n CONFIG_HEAP_MEM_POOL_SIZE=4096 +CONFIG_MINIMAL_LIBC=y diff --git a/boot/zephyr/boards/xiao_esp32c3.conf b/boot/zephyr/boards/xiao_esp32c3.conf index 8a90ef8ea..56298cd4f 100644 --- a/boot/zephyr/boards/xiao_esp32c3.conf +++ b/boot/zephyr/boards/xiao_esp32c3.conf @@ -17,3 +17,4 @@ CONFIG_DEBUG=n CONFIG_XIP=n CONFIG_HEAP_MEM_POOL_SIZE=4096 +CONFIG_MINIMAL_LIBC=y diff --git a/boot/zephyr/boot_serial_extension_zephyr_basic.c b/boot/zephyr/boot_serial_extension_zephyr_basic.c new file mode 100644 index 000000000..b0c75f4a7 --- /dev/null +++ b/boot/zephyr/boot_serial_extension_zephyr_basic.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2021-2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include <../subsys/mgmt/mcumgr/transport/include/mgmt/mcumgr/transport/smp_internal.h> + +#include +#include + +#include "bootutil/bootutil_log.h" +#include "../boot_serial/src/boot_serial_priv.h" +#include + +#include "bootutil/image.h" +#include "bootutil/bootutil_public.h" +#include "bootutil/boot_hooks.h" + +#include + +BOOT_LOG_MODULE_DECLARE(mcuboot); + +#ifdef CONFIG_BOOT_MGMT_CUSTOM_STORAGE_ERASE +static int bs_custom_storage_erase(const struct nmgr_hdr *hdr, + const char *buffer, int len, + zcbor_state_t *cs) +{ + int rc; + const struct flash_area *fa; + + (void)buffer; + (void)len; + + if (hdr->nh_group != ZEPHYR_MGMT_GRP_BASIC || hdr->nh_op != NMGR_OP_WRITE || + hdr->nh_id != ZEPHYR_MGMT_GRP_BASIC_CMD_ERASE_STORAGE) { + return MGMT_ERR_ENOTSUP; + } + + rc = flash_area_open(FIXED_PARTITION_ID(storage_partition), &fa); + + if (rc < 0) { + BOOT_LOG_ERR("failed to open flash area"); + } else { + rc = flash_area_erase(fa, 0, flash_area_get_size(fa)); + if (rc < 0) { + BOOT_LOG_ERR("failed to erase flash area"); + } + flash_area_close(fa); + } + if (rc == 0) { + rc = MGMT_ERR_OK; + } else { + rc = MGMT_ERR_EUNKNOWN; + } + + zcbor_map_start_encode(cs, 10); + zcbor_tstr_put_lit(cs, "rc"); + zcbor_uint32_put(cs, rc); + zcbor_map_end_encode(cs, 10); + + return rc; +} + +MCUMGR_HANDLER_DEFINE(storage_erase, bs_custom_storage_erase); +#endif diff --git a/boot/zephyr/boot_serial_extensions.c b/boot/zephyr/boot_serial_extensions.c index b8bcd3e95..abbb65173 100644 --- a/boot/zephyr/boot_serial_extensions.c +++ b/boot/zephyr/boot_serial_extensions.c @@ -1,161 +1,30 @@ /* - * Copyright (c) 2021 Nordic Semiconductor ASA + * Copyright (c) 2021-2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ -#include #include -#include -#include -#include -#include <../subsys/mgmt/mcumgr/transport/include/mgmt/mcumgr/transport/smp_internal.h> - -#include -#include #include "bootutil/bootutil_log.h" #include "../boot_serial/src/boot_serial_priv.h" #include - -#include "bootutil/image.h" -#include "bootutil/bootutil_public.h" -#include "bootutil/boot_hooks.h" +#include BOOT_LOG_MODULE_DECLARE(mcuboot); -#ifdef CONFIG_BOOT_MGMT_CUSTOM_STORAGE_ERASE -static int bs_custom_storage_erase(zcbor_state_t *cs) -{ - int rc; - - const struct flash_area *fa; - - rc = flash_area_open(FIXED_PARTITION_ID(storage_partition), &fa); - - if (rc < 0) { - BOOT_LOG_ERR("failed to open flash area"); - } else { - rc = flash_area_erase(fa, 0, flash_area_get_size(fa)); - if (rc < 0) { - BOOT_LOG_ERR("failed to erase flash area"); - } - flash_area_close(fa); - } - if (rc == 0) { - rc = MGMT_ERR_OK; - } else { - rc = MGMT_ERR_EUNKNOWN; - } - - zcbor_map_start_encode(cs, 10); - zcbor_tstr_put_lit(cs, "rc"); - zcbor_uint32_put(cs, rc); - zcbor_map_end_encode(cs, 10); - - return rc; -} -#endif - -#ifdef MCUBOOT_MGMT_CUSTOM_IMG_LIST -static int custom_img_status(int image_index, uint32_t slot,char *buffer, - ssize_t len) -{ - uint32_t area_id; - struct flash_area const *fap; - struct image_header hdr; - int rc; - int img_install_stat; - - rc = BOOT_HOOK_CALL(boot_img_install_stat_hook, BOOT_HOOK_REGULAR, - image_index, slot, &img_install_stat); - if (rc == BOOT_HOOK_REGULAR) - { - img_install_stat = 0; - } - - rc = BOOT_HOOK_CALL(boot_read_image_header_hook, BOOT_HOOK_REGULAR, - image_index, slot, &hdr); - if (rc == BOOT_HOOK_REGULAR) - { - area_id = flash_area_id_from_multi_image_slot(image_index, slot); - - rc = flash_area_open(area_id, &fap); - if (rc) { - return rc; - } - - rc = flash_area_read(fap, 0, &hdr, sizeof(hdr)); - - flash_area_close(fap); - } - - if (rc == 0) { - if (hdr.ih_magic == IMAGE_MAGIC) { - snprintf(buffer, len, "ver=%d.%d.%d.%d,install_stat=%d", - hdr.ih_ver.iv_major, - hdr.ih_ver.iv_minor, - hdr.ih_ver.iv_revision, - hdr.ih_ver.iv_build_num, - img_install_stat); - } else { - rc = 1; - } - } - - return rc; -} - -static int bs_custom_img_list(zcbor_state_t *cs) -{ - int rc = 0; - char tmpbuf[64]; /* Buffer should fit version and flags */ - - zcbor_map_start_encode(cs, 10); - - for (int img = 0; img < MCUBOOT_IMAGE_NUMBER; img++) { - for (int slot = 0; slot < 2; slot++) { - rc = custom_img_status(img, slot, tmpbuf, sizeof(tmpbuf)); - - zcbor_int32_put(cs, img * 2 + slot + 1); - if (rc == 0) { - zcbor_tstr_put_term(cs, tmpbuf); - } else { - zcbor_tstr_put_lit(cs, ""); - } - } - } - - zcbor_tstr_put_lit(cs, "rc"); - zcbor_uint32_put(cs, MGMT_ERR_OK); - zcbor_map_end_encode(cs, 10); - - return rc; -} - -#ifndef ZEPHYR_MGMT_GRP_BASIC_CMD_IMAGE_LIST - #define ZEPHYR_MGMT_GRP_BASIC_CMD_IMAGE_LIST 1 -#endif -#endif /*MCUBOOT_MGMT_CUSTOM_IMG_LIST*/ - int bs_peruser_system_specific(const struct nmgr_hdr *hdr, const char *buffer, int len, zcbor_state_t *cs) { int mgmt_rc = MGMT_ERR_ENOTSUP; - if (hdr->nh_group == ZEPHYR_MGMT_GRP_BASIC) { - if (hdr->nh_op == NMGR_OP_WRITE) { -#ifdef CONFIG_BOOT_MGMT_CUSTOM_STORAGE_ERASE - if (hdr->nh_id == ZEPHYR_MGMT_GRP_BASIC_CMD_ERASE_STORAGE) { - mgmt_rc = bs_custom_storage_erase(cs); - } -#endif - } else if (hdr->nh_op == NMGR_OP_READ) { -#ifdef MCUBOOT_MGMT_CUSTOM_IMG_LIST - if (hdr->nh_id == ZEPHYR_MGMT_GRP_BASIC_CMD_IMAGE_LIST) { - mgmt_rc = bs_custom_img_list(cs); + STRUCT_SECTION_FOREACH(mcuboot_bs_custom_handlers, function) { + if (function->handler) { + mgmt_rc = function->handler(hdr, buffer, len, cs); + + if (mgmt_rc != MGMT_ERR_ENOTSUP) { + break; } -#endif } } diff --git a/boot/zephyr/firmware_loader.c b/boot/zephyr/firmware_loader.c new file mode 100644 index 000000000..11b461c41 --- /dev/null +++ b/boot/zephyr/firmware_loader.c @@ -0,0 +1,196 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2020 Arm Limited + * Copyright (c) 2020-2023 Nordic Semiconductor ASA + */ + +#include +#include +#include +#include +#include "bootutil/image.h" +#include "bootutil_priv.h" +#include "bootutil/bootutil_log.h" +#include "bootutil/bootutil_public.h" +#include "bootutil/fault_injection_hardening.h" + +#include "io/io.h" +#include "mcuboot_config/mcuboot_config.h" + +BOOT_LOG_MODULE_DECLARE(mcuboot); + +/* Variables passed outside of unit via poiters. */ +static const struct flash_area *_fa_p; +static struct image_header _hdr = { 0 }; + +#if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT) || defined(MCUBOOT_VALIDATE_PRIMARY_SLOT_ONCE) +/** + * Validate hash of a primary boot image. + * + * @param[in] fa_p flash area pointer + * @param[in] hdr boot image header pointer + * + * @return FIH_SUCCESS on success, error code otherwise + */ +fih_ret +boot_image_validate(const struct flash_area *fa_p, + struct image_header *hdr) +{ + static uint8_t tmpbuf[BOOT_TMPBUF_SZ]; + FIH_DECLARE(fih_rc, FIH_FAILURE); + + /* NOTE: The first argument to boot_image_validate, for enc_state pointer, + * is allowed to be NULL only because the single image loader compiles + * with BOOT_IMAGE_NUMBER == 1, which excludes the code that uses + * the pointer from compilation. + */ + /* Validate hash */ + if (IS_ENCRYPTED(hdr)) + { + /* Clear the encrypted flag we didn't supply a key + * This flag could be set if there was a decryption in place + * was performed. We will try to validate the image, and if still + * encrypted the validation will fail, and go in panic mode + */ + hdr->ih_flags &= ~(ENCRYPTIONFLAGS); + } + FIH_CALL(bootutil_img_validate, fih_rc, NULL, 0, hdr, fa_p, tmpbuf, + BOOT_TMPBUF_SZ, NULL, 0, NULL); + + FIH_RET(fih_rc); +} +#endif /* MCUBOOT_VALIDATE_PRIMARY_SLOT || MCUBOOT_VALIDATE_PRIMARY_SLOT_ONCE*/ + +#if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT_ONCE) +inline static fih_ret +boot_image_validate_once(const struct flash_area *fa_p, + struct image_header *hdr) +{ + static struct boot_swap_state state; + int rc; + FIH_DECLARE(fih_rc, FIH_FAILURE); + + memset(&state, 0, sizeof(struct boot_swap_state)); + rc = boot_read_swap_state(fa_p, &state); + if (rc != 0) + FIH_RET(FIH_FAILURE); + if (state.magic != BOOT_MAGIC_GOOD + || state.image_ok != BOOT_FLAG_SET) { + /* At least validate the image once */ + FIH_CALL(boot_image_validate, fih_rc, fa_p, hdr); + if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) { + FIH_RET(FIH_FAILURE); + } + if (state.magic != BOOT_MAGIC_GOOD) { + rc = boot_write_magic(fa_p); + if (rc != 0) + FIH_RET(FIH_FAILURE); + } + rc = boot_write_image_ok(fa_p); + if (rc != 0) + FIH_RET(FIH_FAILURE); + } + FIH_RET(FIH_SUCCESS); +} +#endif + +/** + * Validates that an image in a slot is OK to boot. + * + * @param[in] slot Slot number to check + * @param[out] rsp Parameters for booting image, on success + * + * @return FIH_SUCCESS on success; non-zero on failure. + */ +static fih_ret validate_image_slot(int slot, struct boot_rsp *rsp) +{ + int rc = -1; + FIH_DECLARE(fih_rc, FIH_FAILURE); + + rc = flash_area_open(slot, &_fa_p); + assert(rc == 0); + + rc = boot_image_load_header(_fa_p, &_hdr); + if (rc != 0) { + goto other; + } + +#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT + FIH_CALL(boot_image_validate, fih_rc, _fa_p, &_hdr); + if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) { + goto other; + } +#elif defined(MCUBOOT_VALIDATE_PRIMARY_SLOT_ONCE) + FIH_CALL(boot_image_validate_once, fih_rc, _fa_p, &_hdr); + if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) { + goto other; + } +#else + fih_rc = FIH_SUCCESS; +#endif /* MCUBOOT_VALIDATE_PRIMARY_SLOT */ + + rsp->br_flash_dev_id = flash_area_get_device_id(_fa_p); + rsp->br_image_off = flash_area_get_off(_fa_p); + rsp->br_hdr = &_hdr; + +other: + flash_area_close(_fa_p); + + FIH_RET(fih_rc); +} + +/** + * Gather information on image and prepare for booting. Will boot from main + * image if none of the enabled entrance modes for the firmware loader are set, + * otherwise will boot the firmware loader. Note: firmware loader must be a + * valid signed image with the same signing key as the application image. + * + * @param[out] rsp Parameters for booting image, on success + * + * @return FIH_SUCCESS on success; non-zero on failure. + */ +fih_ret +boot_go(struct boot_rsp *rsp) +{ + bool boot_firmware_loader = false; + FIH_DECLARE(fih_rc, FIH_FAILURE); + +#ifdef CONFIG_BOOT_FIRMWARE_LOADER_ENTRANCE_GPIO + if (io_detect_pin() && + !io_boot_skip_serial_recovery()) { + boot_firmware_loader = true; + } +#endif + +#ifdef CONFIG_BOOT_FIRMWARE_LOADER_PIN_RESET + if (io_detect_pin_reset()) { + boot_firmware_loader = true; + } +#endif + +#ifdef CONFIG_BOOT_FIRMWARE_LOADER_BOOT_MODE + if (io_detect_boot_mode()) { + boot_firmware_loader = true; + } +#endif + + /* Check if firmware loader button is pressed. TODO: check all entrance methods */ + if (boot_firmware_loader == true) { + FIH_CALL(validate_image_slot, fih_rc, FLASH_AREA_IMAGE_SECONDARY(0), rsp); + + if (FIH_EQ(fih_rc, FIH_SUCCESS)) { + FIH_RET(fih_rc); + } + } + + FIH_CALL(validate_image_slot, fih_rc, FLASH_AREA_IMAGE_PRIMARY(0), rsp); + +#ifdef CONFIG_BOOT_FIRMWARE_LOADER_NO_APPLICATION + if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) { + FIH_CALL(validate_image_slot, fih_rc, FLASH_AREA_IMAGE_SECONDARY(0), rsp); + } +#endif + + FIH_RET(fih_rc); +} diff --git a/boot/zephyr/include/boot_serial/boot_serial.ld b/boot/zephyr/include/boot_serial/boot_serial.ld new file mode 100644 index 000000000..c0e82ad35 --- /dev/null +++ b/boot/zephyr/include/boot_serial/boot_serial.ld @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +ITERABLE_SECTION_ROM(mcuboot_bs_custom_handlers, 4) diff --git a/boot/zephyr/include/boot_serial/boot_serial_extensions.h b/boot/zephyr/include/boot_serial/boot_serial_extensions.h new file mode 100644 index 000000000..6eea574fa --- /dev/null +++ b/boot/zephyr/include/boot_serial/boot_serial_extensions.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef H_BOOT_SERIAL_EXTENTIONS_ +#define H_BOOT_SERIAL_EXTENTIONS_ + +#include +#include +#include + +/** + * Callback handler prototype for boot serial extensions. + * + * @param[in] hdr MCUmgr header + * @param[in] buffer Buffer with first MCUmgr message + * @param[in] len Length of data in buffer + * @param[out] cs Response + * + * @return MGMT_ERR_ENOTSUP to run other handlers, other MGMT_ERR_* value + * when expected handler has ran. + */ +typedef int (*bs_custom_handler_cb)(const struct nmgr_hdr *hdr, + const char *buffer, int len, + zcbor_state_t *cs); + +struct mcuboot_bs_custom_handlers { + const bs_custom_handler_cb handler; +}; + +/* Used to create an iterable section containing a boot serial handler + * function + */ +#define MCUMGR_HANDLER_DEFINE(name, _handler) \ + STRUCT_SECTION_ITERABLE(mcuboot_bs_custom_handlers, name) = { \ + .handler = _handler, \ + } + +#endif /* H_BOOT_SERIAL_EXTENTIONS_ */ diff --git a/boot/zephyr/include/io/io.h b/boot/zephyr/include/io/io.h new file mode 100644 index 000000000..145530bb8 --- /dev/null +++ b/boot/zephyr/include/io/io.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2012-2014 Wind River Systems, Inc. + * Copyright (c) 2020 Arm Limited + * Copyright (c) 2021-2023 Nordic Semiconductor ASA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef H_IO_ +#define H_IO_ + +#include + +#ifdef CONFIG_SOC_FAMILY_NRF +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Initialises the configured LED. + */ +void io_led_init(void); + +/* + * Sets value of the configured LED. + */ +void io_led_set(int value); + +/* + * Checks if GPIO is set in the required way to remain in serial recovery mode + * + * @retval false for normal boot, true for serial recovery boot + */ +bool io_detect_pin(void); + +/* + * Checks if board was reset using reset pin and if device should stay in + * serial recovery mode + * + * @retval false for normal boot, true for serial recovery boot + */ +bool io_detect_pin_reset(void); + +/* + * Checks board boot mode via retention subsystem and if device should stay in + * serial recovery mode + * + * @retval false for normal boot, true for serial recovery boot + */ +bool io_detect_boot_mode(void); + +#ifdef CONFIG_SOC_FAMILY_NRF +static inline bool io_boot_skip_serial_recovery() +{ + uint32_t rr = nrfx_reset_reason_get(); + + return !(rr == 0 || (rr & NRFX_RESET_REASON_RESETPIN_MASK)); +} +#else +static inline bool io_boot_skip_serial_recovery() +{ + return false; +} +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/boot/zephyr/include/mcuboot_config/mcuboot_config.h b/boot/zephyr/include/mcuboot_config/mcuboot_config.h index d576ecb54..101e2d1ae 100644 --- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h +++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h @@ -87,6 +87,10 @@ #define IMAGE_EXECUTABLE_RAM_SIZE CONFIG_BOOT_IMAGE_EXECUTABLE_RAM_SIZE #endif +#ifdef CONFIG_BOOT_FIRMWARE_LOADER +#define MCUBOOT_FIRMWARE_LOADER +#endif + #ifdef CONFIG_UPDATEABLE_IMAGE_NUMBER #define MCUBOOT_IMAGE_NUMBER CONFIG_UPDATEABLE_IMAGE_NUMBER #else @@ -154,6 +158,18 @@ #define MCUBOOT_DATA_SHARING #endif +#ifdef CONFIG_BOOT_SHARE_BACKEND_RETENTION +#define MCUBOOT_CUSTOM_DATA_SHARING_FUNCTION +#endif + +#ifdef CONFIG_BOOT_SHARE_DATA_BOOTINFO +#define MCUBOOT_DATA_SHARING_BOOTINFO +#endif + +#ifdef CONFIG_MEASURED_BOOT_MAX_CBOR_SIZE +#define MAX_BOOT_RECORD_SZ CONFIG_MEASURED_BOOT_MAX_CBOR_SIZE +#endif + #ifdef CONFIG_BOOT_FIH_PROFILE_OFF #define MCUBOOT_FIH_PROFILE_OFF #endif @@ -192,6 +208,10 @@ #define MCUBOOT_VERIFY_IMG_ADDRESS #endif +#ifdef CONFIG_MCUBOOT_SERIAL +#define MCUBOOT_SERIAL +#endif + /* * The configuration option enables direct image upload with the * serial recovery. @@ -265,6 +285,15 @@ #define MCUBOOT_SERIAL_UNALIGNED_BUFFER_SIZE CONFIG_BOOT_SERIAL_UNALIGNED_BUFFER_SIZE #endif +#if defined(MCUBOOT_DATA_SHARING) && defined(ZEPHYR_VER_INCLUDE) +#include + +#define MCUBOOT_VERSION_AVAILABLE +#define MCUBOOT_VERSION_MAJOR APP_VERSION_MAJOR +#define MCUBOOT_VERSION_MINOR APP_VERSION_MINOR +#define MCUBOOT_VERSION_PATCHLEVEL APP_PATCHLEVEL +#endif + /* Support 32-byte aligned flash sizes */ #if DT_HAS_CHOSEN(zephyr_flash) #if DT_PROP_OR(DT_CHOSEN(zephyr_flash), write_block_size, 0) > 8 diff --git a/boot/zephyr/include/sysflash/sysflash.h b/boot/zephyr/include/sysflash/sysflash.h index 501c0b2e5..6db393b00 100644 --- a/boot/zephyr/include/sysflash/sysflash.h +++ b/boot/zephyr/include/sysflash/sysflash.h @@ -18,7 +18,7 @@ #include #include -#ifndef CONFIG_SINGLE_APPLICATION_SLOT +#if !defined(CONFIG_SINGLE_APPLICATION_SLOT) && !defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SINGLE_APP) /* Each pair of slots is separated by , and there is no terminating character */ #define FLASH_AREA_IMAGE_0_SLOTS slot0_partition, slot1_partition @@ -56,7 +56,7 @@ static inline uint32_t __flash_area_ids_for_slot(int img, int slot) #define FLASH_AREA_IMAGE_SCRATCH FIXED_PARTITION_ID(scratch_partition) #endif -#else /* CONFIG_SINGLE_APPLICATION_SLOT */ +#else /* !CONFIG_SINGLE_APPLICATION_SLOT && !CONFIG_MCUBOOT_BOOTLOADER_MODE_SINGLE_APP */ #define FLASH_AREA_IMAGE_PRIMARY(x) FIXED_PARTITION_ID(slot0_partition) #define FLASH_AREA_IMAGE_SECONDARY(x) FIXED_PARTITION_ID(slot0_partition) diff --git a/boot/zephyr/io.c b/boot/zephyr/io.c new file mode 100644 index 000000000..309f1ab94 --- /dev/null +++ b/boot/zephyr/io.c @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2012-2014 Wind River Systems, Inc. + * Copyright (c) 2020 Arm Limited + * Copyright (c) 2021-2023 Nordic Semiconductor ASA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "target.h" +#include "bootutil/bootutil_log.h" + +#if defined(CONFIG_BOOT_SERIAL_PIN_RESET) || defined(CONFIG_BOOT_FIRMWARE_LOADER_PIN_RESET) +#include +#endif + +#if defined(CONFIG_BOOT_SERIAL_BOOT_MODE) || defined(CONFIG_BOOT_FIRMWARE_LOADER_BOOT_MODE) +#include +#endif + +/* Validate serial recovery configuration */ +#ifdef CONFIG_MCUBOOT_SERIAL +#if !defined(CONFIG_BOOT_SERIAL_ENTRANCE_GPIO) && \ + !defined(CONFIG_BOOT_SERIAL_WAIT_FOR_DFU) && \ + !defined(CONFIG_BOOT_SERIAL_BOOT_MODE) && \ + !defined(CONFIG_BOOT_SERIAL_NO_APPLICATION) && \ + !defined(CONFIG_BOOT_SERIAL_PIN_RESET) +#error "Serial recovery selected without an entrance mode set" +#endif +#endif + +/* Validate firmware loader configuration */ +#ifdef CONFIG_BOOT_FIRMWARE_LOADER +#if !defined(CONFIG_BOOT_FIRMWARE_LOADER_ENTRANCE_GPIO) && \ + !defined(CONFIG_BOOT_FIRMWARE_LOADER_BOOT_MODE) && \ + !defined(CONFIG_BOOT_FIRMWARE_LOADER_NO_APPLICATION) && \ + !defined(CONFIG_BOOT_FIRMWARE_LOADER_PIN_RESET) +#error "Firmware loader selected without an entrance mode set" +#endif +#endif + +#ifdef CONFIG_MCUBOOT_INDICATION_LED + +/* + * The led0 devicetree alias is optional. If present, we'll use it + * to turn on the LED whenever the button is pressed. + */ +#if DT_NODE_EXISTS(DT_ALIAS(mcuboot_led0)) +#define LED0_NODE DT_ALIAS(mcuboot_led0) +#elif DT_NODE_EXISTS(DT_ALIAS(bootloader_led0)) +#warning "bootloader-led0 alias is deprecated; use mcuboot-led0 instead" +#define LED0_NODE DT_ALIAS(bootloader_led0) +#endif + +#if DT_NODE_HAS_STATUS(LED0_NODE, okay) && DT_NODE_HAS_PROP(LED0_NODE, gpios) +static const struct gpio_dt_spec led0 = GPIO_DT_SPEC_GET(LED0_NODE, gpios); +#else +/* A build error here means your board isn't set up to drive an LED. */ +#error "Unsupported board: led0 devicetree alias is not defined" +#endif + +BOOT_LOG_MODULE_DECLARE(mcuboot); + +void io_led_init(void) +{ + if (!device_is_ready(led0.port)) { + BOOT_LOG_ERR("Didn't find LED device referred by the LED0_NODE\n"); + return; + } + + gpio_pin_configure_dt(&led0, GPIO_OUTPUT); + gpio_pin_set_dt(&led0, 0); +} + +void io_led_set(int value) +{ + gpio_pin_set_dt(&led0, value); +} +#endif /* CONFIG_MCUBOOT_INDICATION_LED */ + +#if defined(CONFIG_BOOT_SERIAL_ENTRANCE_GPIO) || defined(CONFIG_BOOT_USB_DFU_GPIO) || \ + defined(CONFIG_BOOT_FIRMWARE_LOADER_ENTRANCE_GPIO) + +#if defined(CONFIG_MCUBOOT_SERIAL) +#define BUTTON_0_DETECT_DELAY CONFIG_BOOT_SERIAL_DETECT_DELAY +#elif defined(CONFIG_BOOT_FIRMWARE_LOADER) +#define BUTTON_0_DETECT_DELAY CONFIG_BOOT_FIRMWARE_LOADER_DETECT_DELAY +#else +#define BUTTON_0_DETECT_DELAY CONFIG_BOOT_USB_DFU_DETECT_DELAY +#endif + +#define BUTTON_0_NODE DT_ALIAS(mcuboot_button0) + +#if DT_NODE_EXISTS(BUTTON_0_NODE) && DT_NODE_HAS_PROP(BUTTON_0_NODE, gpios) +static const struct gpio_dt_spec button0 = GPIO_DT_SPEC_GET(BUTTON_0_NODE, gpios); +#else +#error "Serial recovery/USB DFU button must be declared in device tree as 'mcuboot_button0'" +#endif + +bool io_detect_pin(void) +{ + int rc; + int pin_active; + + if (!device_is_ready(button0.port)) { + __ASSERT(false, "GPIO device is not ready.\n"); + return false; + } + + rc = gpio_pin_configure_dt(&button0, GPIO_INPUT); + __ASSERT(rc == 0, "Failed to initialize boot detect pin.\n"); + + rc = gpio_pin_get_dt(&button0); + pin_active = rc; + + __ASSERT(rc >= 0, "Failed to read boot detect pin.\n"); + + if (pin_active) { + if (BUTTON_0_DETECT_DELAY > 0) { +#ifdef CONFIG_MULTITHREADING + k_sleep(K_MSEC(50)); +#else + k_busy_wait(50000); +#endif + + /* Get the uptime for debounce purposes. */ + int64_t timestamp = k_uptime_get(); + + for(;;) { + rc = gpio_pin_get_dt(&button0); + pin_active = rc; + __ASSERT(rc >= 0, "Failed to read boot detect pin.\n"); + + /* Get delta from when this started */ + uint32_t delta = k_uptime_get() - timestamp; + + /* If not pressed OR if pressed > debounce period, stop. */ + if (delta >= BUTTON_0_DETECT_DELAY || !pin_active) { + break; + } + + /* Delay 1 ms */ +#ifdef CONFIG_MULTITHREADING + k_sleep(K_MSEC(1)); +#else + k_busy_wait(1000); +#endif + } + } + } + + return (bool)pin_active; +} +#endif + +#if defined(CONFIG_BOOT_SERIAL_PIN_RESET) || defined(CONFIG_BOOT_FIRMWARE_LOADER_PIN_RESET) +bool io_detect_pin_reset(void) +{ + uint32_t reset_cause; + int rc; + + rc = hwinfo_get_reset_cause(&reset_cause); + + if (rc == 0 && reset_cause == RESET_PIN) { + (void)hwinfo_clear_reset_cause(); + return true; + } + + return false; +} +#endif + +#if defined(CONFIG_BOOT_SERIAL_BOOT_MODE) || defined(CONFIG_BOOT_FIRMWARE_LOADER_BOOT_MODE) +bool io_detect_boot_mode(void) +{ + int32_t boot_mode; + + boot_mode = bootmode_check(BOOT_MODE_TYPE_BOOTLOADER); + + if (boot_mode == 1) { + /* Boot mode to stay in bootloader, clear status and enter serial + * recovery mode + */ + bootmode_clear(); + + return true; + } + + return false; +} +#endif diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index 270397003..35465c170 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -27,8 +27,11 @@ #include #include +#if defined(CONFIG_ARM) #include +#endif +#include "io/io.h" #include "target.h" #include "bootutil/bootutil_log.h" @@ -76,10 +79,6 @@ const struct boot_uart_funcs boot_funcs = { }; #endif -#ifdef CONFIG_BOOT_SERIAL_BOOT_MODE -#include -#endif - #if defined(CONFIG_BOOT_USB_DFU_WAIT) || defined(CONFIG_BOOT_USB_DFU_GPIO) #include #endif @@ -165,49 +164,6 @@ static inline bool boot_skip_serial_recovery() BOOT_LOG_MODULE_REGISTER(mcuboot); -/* Validate serial recovery configuration */ -#ifdef CONFIG_MCUBOOT_SERIAL -#if !defined(CONFIG_BOOT_SERIAL_ENTRANCE_GPIO) && \ - !defined(CONFIG_BOOT_SERIAL_WAIT_FOR_DFU) && \ - !defined(CONFIG_BOOT_SERIAL_BOOT_MODE) && \ - !defined(CONFIG_BOOT_SERIAL_NO_APPLICATION) && \ - !defined(CONFIG_BOOT_SERIAL_PIN_RESET) -#error "Serial recovery selected without an entrance mode set" -#endif -#endif - -#ifdef CONFIG_MCUBOOT_INDICATION_LED - -/* - * The led0 devicetree alias is optional. If present, we'll use it - * to turn on the LED whenever the button is pressed. - */ -#if DT_NODE_EXISTS(DT_ALIAS(mcuboot_led0)) -#define LED0_NODE DT_ALIAS(mcuboot_led0) -#elif DT_NODE_EXISTS(DT_ALIAS(bootloader_led0)) -#warning "bootloader-led0 alias is deprecated; use mcuboot-led0 instead" -#define LED0_NODE DT_ALIAS(bootloader_led0) -#endif - -#if DT_NODE_HAS_STATUS(LED0_NODE, okay) && DT_NODE_HAS_PROP(LED0_NODE, gpios) -static const struct gpio_dt_spec led0 = GPIO_DT_SPEC_GET(LED0_NODE, gpios); -#else -/* A build error here means your board isn't set up to drive an LED. */ -#error "Unsupported board: led0 devicetree alias is not defined" -#endif - -void led_init(void) -{ - if (!device_is_ready(led0.port)) { - BOOT_LOG_ERR("Didn't find LED device referred by the LED0_NODE\n"); - return; - } - - gpio_pin_configure_dt(&led0, GPIO_OUTPUT); - gpio_pin_set_dt(&led0, 0); -} -#endif /* CONFIG_MCUBOOT_INDICATION_LED */ - void os_heap_init(void); #if defined(CONFIG_ARM) @@ -473,85 +429,13 @@ void zephyr_boot_log_stop(void) * !defined(CONFIG_LOG_PROCESS_THREAD) && !defined(ZEPHYR_LOG_MODE_MINIMAL) */ -#if defined(CONFIG_BOOT_SERIAL_ENTRANCE_GPIO) || defined(CONFIG_BOOT_USB_DFU_GPIO) - -#ifdef CONFIG_MCUBOOT_SERIAL -#define BUTTON_0_DETECT_DELAY CONFIG_BOOT_SERIAL_DETECT_DELAY -#else -#define BUTTON_0_DETECT_DELAY CONFIG_BOOT_USB_DFU_DETECT_DELAY -#endif - -#define BUTTON_0_NODE DT_ALIAS(mcuboot_button0) - -#if DT_NODE_EXISTS(BUTTON_0_NODE) && DT_NODE_HAS_PROP(BUTTON_0_NODE, gpios) -static const struct gpio_dt_spec button0 = GPIO_DT_SPEC_GET(BUTTON_0_NODE, gpios); -#else -#error "Serial recovery/USB DFU button must be declared in device tree as 'mcuboot_button0'" -#endif - -static bool detect_pin(void) -{ - int rc; - int pin_active; - - if (!device_is_ready(button0.port)) { - __ASSERT(false, "GPIO device is not ready.\n"); - return false; - } - - rc = gpio_pin_configure_dt(&button0, GPIO_INPUT); - __ASSERT(rc == 0, "Failed to initialize boot detect pin.\n"); - - rc = gpio_pin_get_dt(&button0); - pin_active = rc; - - __ASSERT(rc >= 0, "Failed to read boot detect pin.\n"); - - if (pin_active) { - if (BUTTON_0_DETECT_DELAY > 0) { -#ifdef CONFIG_MULTITHREADING - k_sleep(K_MSEC(50)); -#else - k_busy_wait(50000); -#endif - - /* Get the uptime for debounce purposes. */ - int64_t timestamp = k_uptime_get(); - - for(;;) { - rc = gpio_pin_get_dt(&button0); - pin_active = rc; - __ASSERT(rc >= 0, "Failed to read boot detect pin.\n"); - - /* Get delta from when this started */ - uint32_t delta = k_uptime_get() - timestamp; - - /* If not pressed OR if pressed > debounce period, stop. */ - if (delta >= BUTTON_0_DETECT_DELAY || !pin_active) { - break; - } - - /* Delay 1 ms */ -#ifdef CONFIG_MULTITHREADING - k_sleep(K_MSEC(1)); -#else - k_busy_wait(1000); -#endif - } - } - } - - return (bool)pin_active; -} -#endif - #ifdef CONFIG_MCUBOOT_SERIAL static void boot_serial_enter() { int rc; #ifdef CONFIG_MCUBOOT_INDICATION_LED - gpio_pin_set_dt(&led0, 1); + io_led_set(1); #endif mcuboot_status_change(MCUBOOT_STATUS_SERIAL_DFU_ENTERED); @@ -570,14 +454,6 @@ int main(void) int rc; FIH_DECLARE(fih_rc, FIH_FAILURE); -#ifdef CONFIG_BOOT_SERIAL_BOOT_MODE - int32_t boot_mode; -#endif - -#ifdef CONFIG_BOOT_SERIAL_PIN_RESET - uint32_t reset_cause; -#endif - MCUBOOT_WATCHDOG_SETUP(); MCUBOOT_WATCHDOG_FEED(); @@ -589,7 +465,7 @@ int main(void) #ifdef CONFIG_MCUBOOT_INDICATION_LED /* LED init */ - led_init(); + io_led_init(); #endif os_heap_init(); @@ -601,25 +477,22 @@ int main(void) mcuboot_status_change(MCUBOOT_STATUS_STARTUP); #ifdef CONFIG_BOOT_SERIAL_ENTRANCE_GPIO - if (detect_pin() && - !boot_skip_serial_recovery()) { + if (io_detect_pin() && + !io_boot_skip_serial_recovery()) { boot_serial_enter(); } #endif #ifdef CONFIG_BOOT_SERIAL_PIN_RESET - rc = hwinfo_get_reset_cause(&reset_cause); - - if (rc == 0 && reset_cause == RESET_PIN) { - (void)hwinfo_clear_reset_cause(); + if (io_detect_pin_reset()) { boot_serial_enter(); } #endif #if defined(CONFIG_BOOT_USB_DFU_GPIO) - if (detect_pin()) { + if (io_detect_pin()) { #ifdef CONFIG_MCUBOOT_INDICATION_LED - gpio_pin_set_dt(&led0, 1); + io_led_set(1); #endif mcuboot_status_change(MCUBOOT_STATUS_USB_DFU_ENTERED); @@ -658,18 +531,19 @@ int main(void) rc = boot_console_init(); int timeout_in_ms = CONFIG_BOOT_SERIAL_WAIT_FOR_DFU_TIMEOUT; uint32_t start = k_uptime_get_32(); + +#ifdef CONFIG_MCUBOOT_INDICATION_LED + io_led_set(1); +#endif #endif FIH_CALL(boot_go, fih_rc, &rsp); #ifdef CONFIG_BOOT_SERIAL_BOOT_MODE - boot_mode = bootmode_check(BOOT_MODE_TYPE_BOOTLOADER); - - if (boot_mode == 1) { + if (io_detect_boot_mode()) { /* Boot mode to stay in bootloader, clear status and enter serial * recovery mode */ - bootmode_clear(); boot_serial_enter(); } #endif @@ -681,6 +555,10 @@ int main(void) timeout_in_ms = 1; } boot_serial_check_start(&boot_funcs,timeout_in_ms); + +#ifdef CONFIG_MCUBOOT_INDICATION_LED + io_led_set(0); +#endif #endif if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) { diff --git a/boot/zephyr/prj.conf b/boot/zephyr/prj.conf index 394a6e6dc..23b5f3b93 100644 --- a/boot/zephyr/prj.conf +++ b/boot/zephyr/prj.conf @@ -34,6 +34,6 @@ CONFIG_LOG_DEFAULT_LEVEL=0 CONFIG_MCUBOOT_LOG_LEVEL_INF=y ### Decrease footprint by ~4 KB in comparison to CBPRINTF_COMPLETE=y CONFIG_CBPRINTF_NANO=y -CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT=0 ### Use the minimal C library to reduce flash usage CONFIG_MINIMAL_LIBC=y +CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT=0 diff --git a/boot/zephyr/serial_adapter.c b/boot/zephyr/serial_adapter.c index d6be6857a..de2e5c511 100644 --- a/boot/zephyr/serial_adapter.c +++ b/boot/zephyr/serial_adapter.c @@ -25,15 +25,21 @@ #if defined(CONFIG_BOOT_SERIAL_UART) && defined(CONFIG_UART_CONSOLE) && \ (!DT_HAS_CHOSEN(zephyr_uart_mcumgr) || \ DT_SAME_NODE(DT_CHOSEN(zephyr_uart_mcumgr), DT_CHOSEN(zephyr_console))) -#error Zephyr UART console must been disabled if serial_adapter module is used. +#error Zephyr UART console must be disabled if serial_adapter module is used. #endif #if defined(CONFIG_BOOT_SERIAL_CDC_ACM) && \ - defined(CONFIG_UART_CONSOLE) && !DT_HAS_CHOSEN(zephyr_uart_mcumgr) -#error Zephyr UART console must been disabled if CDC ACM is enabled and MCUmgr \ + defined(CONFIG_UART_CONSOLE) && (!DT_HAS_CHOSEN(zephyr_uart_mcumgr) || \ + DT_SAME_NODE(DT_CHOSEN(zephyr_uart_mcumgr), DT_CHOSEN(zephyr_console))) +#error Zephyr UART console must be disabled if CDC ACM is enabled and MCUmgr \ has not been redirected to other UART with DTS chosen zephyr,uart-mcumgr. #endif +#if defined(CONFIG_BOOT_SERIAL_CDC_ACM) && CONFIG_MAIN_THREAD_PRIORITY < 0 +#error CONFIG_MAIN_THREAD_PRIORITY must be preemptible to support USB CDC ACM \ + (0 or above) +#endif + BOOT_LOG_MODULE_REGISTER(serial_adapter); /** @brief Console input representation @@ -199,7 +205,6 @@ boot_uart_fifo_getline(char **line) static int boot_uart_fifo_init(void) { - #if defined(CONFIG_BOOT_SERIAL_UART) #if DT_HAS_CHOSEN(zephyr_uart_mcumgr) diff --git a/boot/zephyr/shared_data.c b/boot/zephyr/shared_data.c new file mode 100644 index 000000000..5554a7ec9 --- /dev/null +++ b/boot/zephyr/shared_data.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2023, Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include <../../bootutil/src/bootutil_priv.h> + +#define SHARED_MEMORY_MIN_SIZE 8 + +LOG_MODULE_REGISTER(bootloader_info, CONFIG_RETENTION_LOG_LEVEL); + +static bool shared_memory_init_done = false; +static uint16_t shared_data_size = SHARED_DATA_HEADER_SIZE; +static ssize_t shared_data_max_size = 0; +static const struct device *bootloader_info_dev = + DEVICE_DT_GET(DT_CHOSEN(zephyr_bootloader_info)); + +BUILD_ASSERT(SHARED_MEMORY_MIN_SIZE < \ + DT_REG_SIZE_BY_IDX(DT_CHOSEN(zephyr_bootloader_info), 0), \ + "zephyr,bootloader-info area is too small for bootloader information struct"); + +int boot_add_data_to_shared_area(uint8_t major_type, + uint16_t minor_type, + size_t size, + const uint8_t *data) +{ + struct shared_data_tlv_header header = { + .tlv_magic = SHARED_DATA_TLV_INFO_MAGIC, + .tlv_tot_len = shared_data_size, + }; + struct shared_data_tlv_entry tlv_entry = {0}; + uint16_t boot_data_size; + uintptr_t tlv_end, offset; + int rc; + + if (data == NULL) { + return SHARED_MEMORY_GEN_ERROR; + } + + /* Check whether first time to call this function. If does then initialise + * shared data area. + */ + if (!shared_memory_init_done) { + retention_clear(bootloader_info_dev); + shared_data_max_size = retention_size(bootloader_info_dev); + shared_memory_init_done = true; + } + + /* Check whether TLV entry is already added. + * Get the boundaries of TLV section + */ + tlv_end = shared_data_size; + offset = SHARED_DATA_HEADER_SIZE; + + /* Iterates over the TLV section looks for the same entry if found then + * returns with error: SHARED_MEMORY_OVERWRITE + */ + while (offset < tlv_end) { + /* Create local copy to avoid unaligned access */ + rc = retention_read(bootloader_info_dev, offset, (void *)&tlv_entry, + SHARED_DATA_ENTRY_HEADER_SIZE); + + if (rc) { + return SHARED_MEMORY_READ_ERROR; + } + + if (GET_MAJOR(tlv_entry.tlv_type) == major_type && + GET_MINOR(tlv_entry.tlv_type) == minor_type) { + return SHARED_MEMORY_OVERWRITE; + } + + offset += SHARED_DATA_ENTRY_SIZE(tlv_entry.tlv_len); + } + + /* Add TLV entry */ + tlv_entry.tlv_type = SET_TLV_TYPE(major_type, minor_type); + tlv_entry.tlv_len = size; + + if (!boot_u16_safe_add(&boot_data_size, shared_data_size, + SHARED_DATA_ENTRY_SIZE(size))) { + return SHARED_MEMORY_GEN_ERROR; + } + + /* Verify overflow of shared area */ + if (boot_data_size > shared_data_max_size) { + return SHARED_MEMORY_OVERFLOW; + } + + offset = shared_data_size; + rc = retention_write(bootloader_info_dev, offset, (void*)&tlv_entry, + SHARED_DATA_ENTRY_HEADER_SIZE); + if (rc) { + LOG_ERR("Shared data TLV header write failed: %d", rc); + return SHARED_MEMORY_WRITE_ERROR; + } + + offset += SHARED_DATA_ENTRY_HEADER_SIZE; + rc = retention_write(bootloader_info_dev, offset, data, size); + + if (rc) { + LOG_ERR("Shared data TLV data write failed: %d", rc); + return SHARED_MEMORY_WRITE_ERROR; + } + + shared_data_size += SHARED_DATA_ENTRY_SIZE(size); + header.tlv_tot_len = shared_data_size; + + rc = retention_write(bootloader_info_dev, 0, (void *)&header, + sizeof(header)); + + if (rc) { + return SHARED_MEMORY_WRITE_ERROR; + } + + return SHARED_MEMORY_OK; +} diff --git a/boot/zephyr/single_loader.c b/boot/zephyr/single_loader.c index 5d1e76fcf..75374d2db 100644 --- a/boot/zephyr/single_loader.c +++ b/boot/zephyr/single_loader.c @@ -58,6 +58,7 @@ boot_image_validate(const struct flash_area *fa_p, } #endif /* MCUBOOT_VALIDATE_PRIMARY_SLOT || MCUBOOT_VALIDATE_PRIMARY_SLOT_ONCE*/ +#if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT_ONCE) inline static fih_ret boot_image_validate_once(const struct flash_area *fa_p, struct image_header *hdr) @@ -88,6 +89,7 @@ boot_image_validate_once(const struct flash_area *fa_p, } FIH_RET(FIH_SUCCESS); } +#endif /** * Gather information on image and prepare for booting. diff --git a/boot/zephyr/usb_cdc_acm_log_recovery.conf b/boot/zephyr/usb_cdc_acm_log_recovery.conf index ae412fed5..2312c0ece 100644 --- a/boot/zephyr/usb_cdc_acm_log_recovery.conf +++ b/boot/zephyr/usb_cdc_acm_log_recovery.conf @@ -1,16 +1,11 @@ CONFIG_LOG=y -# The build won't fit on the partition allocated for it without size -# optimizations. -CONFIG_SIZE_OPTIMIZATIONS=y - # Serial +CONFIG_UART_CONSOLE=n +CONFIG_CONSOLE=n CONFIG_SERIAL=y CONFIG_UART_LINE_CTRL=y # MCUBoot serial CONFIG_MCUBOOT_SERIAL=y CONFIG_BOOT_SERIAL_CDC_ACM=y - -CONFIG_LOG_BACKEND_UART=y -CONFIG_LOG_BACKEND_RTT=n diff --git a/ci/sim_run.sh b/ci/sim_run.sh index 59d65e10d..7a9ff2de4 100755 --- a/ci/sim_run.sh +++ b/ci/sim_run.sh @@ -43,10 +43,20 @@ fi if [[ ! -z $MULTI_FEATURES ]]; then IFS=',' read -ra multi_features <<< "$MULTI_FEATURES" + + # psa crypto tests require single thread mode + TEST_ARGS='' + for features in "${multi_features[@]}"; do + if [[ $features =~ "psa" ]]; then + TEST_ARGS='--test-threads=1' + break + fi + done + for features in "${multi_features[@]}"; do echo "Running cargo for features=\"${features}\"" - time cargo test --no-run --features "$features" - time cargo test --features "$features" + time cargo test --no-run --features "$features" -- $TEST_ARGS + time cargo test --features "$features" -- $TEST_ARGS rc=$? && [ $rc -ne 0 ] && EXIT_CODE=$rc done fi diff --git a/docs/Gemfile b/docs/Gemfile index 3c56a3b5e..b88481b27 100644 --- a/docs/Gemfile +++ b/docs/Gemfile @@ -21,3 +21,6 @@ gem "github-pages", group: :jekyll_plugins # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] +gem "jemoji", "~> 0.12.0" + +gem "webrick", "~> 1.8" diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index 02c41d290..433585667 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -1,49 +1,47 @@ GEM remote: https://rubygems.org/ specs: - activesupport (6.0.6.1) + activesupport (7.0.7.2) concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 0.7, < 2) - minitest (~> 5.1) - tzinfo (~> 1.1) - zeitwerk (~> 2.2, >= 2.2.2) - addressable (2.8.0) - public_suffix (>= 2.0.2, < 5.0) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + addressable (2.8.5) + public_suffix (>= 2.0.2, < 6.0) coffee-script (2.4.1) coffee-script-source execjs coffee-script-source (1.11.1) colorator (1.1.0) - commonmarker (0.17.13) - ruby-enum (~> 0.5) - concurrent-ruby (1.2.0) - dnsruby (1.61.5) - simpleidn (~> 0.1) - em-websocket (0.5.2) + commonmarker (0.23.10) + concurrent-ruby (1.2.2) + dnsruby (1.70.0) + simpleidn (~> 0.2.1) + em-websocket (0.5.3) eventmachine (>= 0.12.9) - http_parser.rb (~> 0.6.0) - ethon (0.12.0) - ffi (>= 1.3.0) + http_parser.rb (~> 0) + ethon (0.16.0) + ffi (>= 1.15.0) eventmachine (1.2.7) - execjs (2.7.0) - faraday (1.3.0) - faraday-net_http (~> 1.0) - multipart-post (>= 1.2, < 3) - ruby2_keywords - faraday-net_http (1.0.1) - ffi (1.15.0) + execjs (2.8.1) + faraday (2.7.10) + faraday-net_http (>= 2.0, < 3.1) + ruby2_keywords (>= 0.0.4) + faraday-net_http (3.0.2) + ffi (1.15.5) forwardable-extended (2.6.0) gemoji (3.0.1) - github-pages (214) - github-pages-health-check (= 1.17.0) - jekyll (= 3.9.0) + github-pages (228) + github-pages-health-check (= 1.17.9) + jekyll (= 3.9.3) jekyll-avatar (= 0.7.0) jekyll-coffeescript (= 1.1.1) - jekyll-commonmark-ghpages (= 0.1.6) + jekyll-commonmark-ghpages (= 0.4.0) jekyll-default-layout (= 0.1.4) jekyll-feed (= 0.15.1) jekyll-gist (= 1.5.0) jekyll-github-metadata (= 2.13.0) + jekyll-include-cache (= 0.2.1) jekyll-mentions (= 1.6.0) jekyll-optional-front-matter (= 0.3.2) jekyll-paginate (= 1.1.0) @@ -52,49 +50,49 @@ GEM jekyll-relative-links (= 0.6.1) jekyll-remote-theme (= 0.4.3) jekyll-sass-converter (= 1.5.2) - jekyll-seo-tag (= 2.7.1) + jekyll-seo-tag (= 2.8.0) jekyll-sitemap (= 1.4.0) jekyll-swiss (= 1.0.0) - jekyll-theme-architect (= 0.1.1) - jekyll-theme-cayman (= 0.1.1) - jekyll-theme-dinky (= 0.1.1) - jekyll-theme-hacker (= 0.1.2) - jekyll-theme-leap-day (= 0.1.1) - jekyll-theme-merlot (= 0.1.1) - jekyll-theme-midnight (= 0.1.1) - jekyll-theme-minimal (= 0.1.1) - jekyll-theme-modernist (= 0.1.1) - jekyll-theme-primer (= 0.5.4) - jekyll-theme-slate (= 0.1.1) - jekyll-theme-tactile (= 0.1.1) - jekyll-theme-time-machine (= 0.1.1) + jekyll-theme-architect (= 0.2.0) + jekyll-theme-cayman (= 0.2.0) + jekyll-theme-dinky (= 0.2.0) + jekyll-theme-hacker (= 0.2.0) + jekyll-theme-leap-day (= 0.2.0) + jekyll-theme-merlot (= 0.2.0) + jekyll-theme-midnight (= 0.2.0) + jekyll-theme-minimal (= 0.2.0) + jekyll-theme-modernist (= 0.2.0) + jekyll-theme-primer (= 0.6.0) + jekyll-theme-slate (= 0.2.0) + jekyll-theme-tactile (= 0.2.0) + jekyll-theme-time-machine (= 0.2.0) jekyll-titles-from-headings (= 0.5.3) jemoji (= 0.12.0) - kramdown (= 2.3.1) + kramdown (= 2.3.2) kramdown-parser-gfm (= 1.1.0) - liquid (= 4.0.3) + liquid (= 4.0.4) mercenary (~> 0.3) minima (= 2.5.1) - nokogiri (>= 1.10.4, < 2.0) + nokogiri (>= 1.13.6, < 2.0) rouge (= 3.26.0) terminal-table (~> 1.4) - github-pages-health-check (1.17.0) + github-pages-health-check (1.17.9) addressable (~> 2.3) dnsruby (~> 1.60) octokit (~> 4.0) - public_suffix (>= 2.0.2, < 5.0) + public_suffix (>= 3.0, < 5.0) typhoeus (~> 1.3) - html-pipeline (2.14.0) + html-pipeline (2.14.3) activesupport (>= 2) nokogiri (>= 1.4) - http_parser.rb (0.6.0) - i18n (0.9.5) + http_parser.rb (0.8.0) + i18n (1.14.1) concurrent-ruby (~> 1.0) - jekyll (3.9.0) + jekyll (3.9.3) addressable (~> 2.4) colorator (~> 1.0) em-websocket (~> 0.5) - i18n (~> 0.7) + i18n (>= 0.7, < 2) jekyll-sass-converter (~> 1.0) jekyll-watch (~> 2.0) kramdown (>= 1.17, < 3) @@ -108,13 +106,13 @@ GEM jekyll-coffeescript (1.1.1) coffee-script (~> 2.2) coffee-script-source (~> 1.11.1) - jekyll-commonmark (1.3.1) - commonmarker (~> 0.14) - jekyll (>= 3.7, < 5.0) - jekyll-commonmark-ghpages (0.1.6) - commonmarker (~> 0.17.6) - jekyll-commonmark (~> 1.2) - rouge (>= 2.0, < 4.0) + jekyll-commonmark (1.4.0) + commonmarker (~> 0.22) + jekyll-commonmark-ghpages (0.4.0) + commonmarker (~> 0.23.7) + jekyll (~> 3.9.0) + jekyll-commonmark (~> 1.4.0) + rouge (>= 2.0, < 5.0) jekyll-default-layout (0.1.4) jekyll (~> 3.0) jekyll-feed (0.15.1) @@ -124,6 +122,8 @@ GEM jekyll-github-metadata (2.13.0) jekyll (>= 3.4, < 5.0) octokit (~> 4.0, != 4.4.0) + jekyll-include-cache (0.2.1) + jekyll (>= 3.7, < 5.0) jekyll-mentions (1.6.0) html-pipeline (~> 2.3) jekyll (>= 3.7, < 5.0) @@ -143,50 +143,50 @@ GEM rubyzip (>= 1.3.0, < 3.0) jekyll-sass-converter (1.5.2) sass (~> 3.4) - jekyll-seo-tag (2.7.1) + jekyll-seo-tag (2.8.0) jekyll (>= 3.8, < 5.0) jekyll-sitemap (1.4.0) jekyll (>= 3.7, < 5.0) jekyll-swiss (1.0.0) - jekyll-theme-architect (0.1.1) - jekyll (~> 3.5) + jekyll-theme-architect (0.2.0) + jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) - jekyll-theme-cayman (0.1.1) - jekyll (~> 3.5) + jekyll-theme-cayman (0.2.0) + jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) - jekyll-theme-dinky (0.1.1) - jekyll (~> 3.5) + jekyll-theme-dinky (0.2.0) + jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) - jekyll-theme-hacker (0.1.2) + jekyll-theme-hacker (0.2.0) jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) - jekyll-theme-leap-day (0.1.1) - jekyll (~> 3.5) + jekyll-theme-leap-day (0.2.0) + jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) - jekyll-theme-merlot (0.1.1) - jekyll (~> 3.5) + jekyll-theme-merlot (0.2.0) + jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) - jekyll-theme-midnight (0.1.1) - jekyll (~> 3.5) + jekyll-theme-midnight (0.2.0) + jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) - jekyll-theme-minimal (0.1.1) - jekyll (~> 3.5) + jekyll-theme-minimal (0.2.0) + jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) - jekyll-theme-modernist (0.1.1) - jekyll (~> 3.5) + jekyll-theme-modernist (0.2.0) + jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) - jekyll-theme-primer (0.5.4) + jekyll-theme-primer (0.6.0) jekyll (> 3.5, < 5.0) jekyll-github-metadata (~> 2.9) jekyll-seo-tag (~> 2.0) - jekyll-theme-slate (0.1.1) - jekyll (~> 3.5) + jekyll-theme-slate (0.2.0) + jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) - jekyll-theme-tactile (0.1.1) - jekyll (~> 3.5) + jekyll-theme-tactile (0.2.0) + jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) - jekyll-theme-time-machine (0.1.1) - jekyll (~> 3.5) + jekyll-theme-time-machine (0.2.0) + jekyll (> 3.5, < 5.0) jekyll-seo-tag (~> 2.0) jekyll-titles-from-headings (0.5.3) jekyll (>= 3.3, < 5.0) @@ -196,71 +196,69 @@ GEM gemoji (~> 3.0) html-pipeline (~> 2.2) jekyll (>= 3.0, < 5.0) - kramdown (2.3.1) + kramdown (2.3.2) rexml kramdown-parser-gfm (1.1.0) kramdown (~> 2.0) - liquid (4.0.3) - listen (3.5.1) + liquid (4.0.4) + listen (3.8.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) mercenary (0.3.6) - mini_portile2 (2.8.1) + mini_portile2 (2.8.4) minima (2.5.1) jekyll (>= 3.5, < 5.0) jekyll-feed (~> 0.9) jekyll-seo-tag (~> 2.1) - minitest (5.17.0) - multipart-post (2.1.1) - nokogiri (1.14.3) - mini_portile2 (~> 2.8.0) + minitest (5.19.0) + nokogiri (1.15.4) + mini_portile2 (~> 2.8.2) racc (~> 1.4) - octokit (4.20.0) - faraday (>= 0.9) - sawyer (~> 0.8.0, >= 0.5.3) + octokit (4.25.1) + faraday (>= 1, < 3) + sawyer (~> 0.9) pathutil (0.16.2) forwardable-extended (~> 2.6) - public_suffix (4.0.6) - racc (1.6.2) - rb-fsevent (0.10.4) + public_suffix (4.0.7) + racc (1.7.1) + rb-fsevent (0.11.2) rb-inotify (0.10.1) ffi (~> 1.0) - rexml (3.2.5) + rexml (3.2.6) rouge (3.26.0) - ruby-enum (0.9.0) - i18n - ruby2_keywords (0.0.4) - rubyzip (2.3.0) + ruby2_keywords (0.0.5) + rubyzip (2.3.2) safe_yaml (1.0.5) sass (3.7.4) sass-listen (~> 4.0.0) sass-listen (4.0.0) rb-fsevent (~> 0.9, >= 0.9.4) rb-inotify (~> 0.9, >= 0.9.7) - sawyer (0.8.2) + sawyer (0.9.2) addressable (>= 2.3.5) - faraday (> 0.8, < 2.0) + faraday (>= 0.17.3, < 3) simpleidn (0.2.1) unf (~> 0.1.4) terminal-table (1.8.0) unicode-display_width (~> 1.1, >= 1.1.1) - thread_safe (0.3.6) typhoeus (1.4.0) ethon (>= 0.9.0) - tzinfo (1.2.11) - thread_safe (~> 0.1) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) unf (0.1.4) unf_ext - unf_ext (0.0.7.7) - unicode-display_width (1.7.0) - zeitwerk (2.6.7) + unf_ext (0.0.8.2) + unicode-display_width (1.8.0) + webrick (1.8.1) PLATFORMS ruby DEPENDENCIES github-pages + jemoji (~> 0.12.0) tzinfo-data + webrick (~> 1.8) BUNDLED WITH 1.17.2 diff --git a/docs/_config.yml b/docs/_config.yml index 277f1f2c5..be854e842 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1 +1,3 @@ theme: jekyll-theme-cayman +plugins: + - jemoji diff --git a/docs/imgtool.md b/docs/imgtool.md index 9d50e672f..b4dc3b554 100644 --- a/docs/imgtool.md +++ b/docs/imgtool.md @@ -61,7 +61,7 @@ primary slot and adds a header and trailer that the bootloader is expecting: Options: -k, --key filename --public-key-format [hash|full] - --align [1|2|4|8] [required] + --align [1|2|4|8|16|32] Alignment used by swap update modes. -v, --version TEXT [required] -s, --security-counter TEXT Specify the value of security counter. Use the `auto` keyword to automatically generate diff --git a/docs/readme-espressif.md b/docs/readme-espressif.md index cc2fa8bd1..21004df98 100644 --- a/docs/readme-espressif.md +++ b/docs/readme-espressif.md @@ -1,67 +1,89 @@ # [Building and using MCUboot with Espressif's chips](#building-and-using-mcuboot-with-espressifs-chips) -The MCUBoot Espressif's port depends on HAL (Hardware Abstraction Layer) sources based on ESP-IDF or 3rd party frameworks as such as Zephyr-RTOS (`zephyrproject-rtos/hal_espressif/`) or NuttX RTOS (`espressif/esp-hal-3rdparty`). Building the MCUboot Espressif's port and its features is platform dependent, therefore, the system environment including toolchains, must be set accordingly. A standalone build version means that ESP-IDF and its toolchain are used as source. For 3rd parties framework, HAL path and toolchain must be set. +The MCUBoot Espressif's port depends on HAL (Hardware Abstraction Layer) sources based on ESP-IDF +or 3rd party frameworks as such as Zephyr-RTOS (`zephyrproject-rtos/hal_espressif/`) or NuttX RTOS +(`espressif/esp-hal-3rdparty`). Building the MCUboot Espressif's port and its features is platform +dependent, therefore, the system environment including toolchains, must be set accordingly. A +standalone build version means that ESP-IDF and its toolchain are used as source. For 3rd parties +framework, HAL path and toolchain must be set. -Documentation about the MCUboot bootloader design, operation and features can be found in the [design document](design.md). +Documentation about the MCUboot bootloader design, operation and features can be found in the +[design document](design.md). ## [SoC support availability](#soc-support-availability) The current port is available for use in the following SoCs within the OSes: -| | ESP32 | ESP32-S2 | ESP32-C3 | ESP32-S3 | ESP32-C2 | ESP32-C6 | ESP32-H2 | -| :-----: | :-----: | :-----: | :-----: | :-----: | :-----: | :-----: | :-----: | +| | ESP32 | ESP32-S2 | ESP32-C3 | ESP32-S3 | ESP32-C2 | ESP32-C6 | ESP32-H2 | +| :----: | :-----: | :-----: | :-----: | :-----: | :---------: | :-----: | :-----: | | Zephyr | Supported | Supported | Supported | Supported | In progress | In progress | In progress | -| NuttX | Supported | Supported | Supported | Supported | In progress | In progress | In progress | +| NuttX | Supported | Supported | Supported | Supported | In progress | In progress | In progress | -Notice that any customization in the memory layout from the OS application must be done aware of the bootloader own memory layout to avoid overlapping. More information on the section [Memory map organization for OS compatibility](#memory-map-organization-for-os-compatibility). +Notice that any customization in the memory layout from the OS application must be done aware of +the bootloader own memory layout to avoid overlapping. More information on the section +[Memory map organization for OS compatibility](#memory-map-organization-for-os-compatibility). ## [Installing requirements and dependencies](#installing-requirements-and-dependencies) The following instructions considers a MCUboot Espressif port standalone build. 1. Install additional packages required for development with MCUboot: -```bash -cd ~/mcuboot # or to your directory where MCUboot is cloned -``` -```bash -pip3 install --user -r scripts/requirements.txt -``` + + ```bash + cd ~/mcuboot # or to your directory where MCUboot is cloned + ``` + + ```bash + pip3 install --user -r scripts/requirements.txt + ``` 2. Update the Mbed TLS submodule required by MCUboot: -```bash -git submodule update --init --recursive ext/mbedtls -``` -3. If ESP-IDF is the chosen option for use as HAL layer and the system already have ESP-IDF installed, ensure that the environment is set: -```bash -/install.sh -``` -```bash -. /export.sh -``` + ```bash + git submodule update --init --recursive ext/mbedtls + ``` ---- -***Note*** +3. If ESP-IDF is the chosen option for use as HAL layer and the system already have ESP-IDF + installed, ensure that the environment is set: -*If desirable, instructions for ESP-IDF installation can be found [here](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/index.html#manual-installation)* + ```bash + /install.sh + ``` ---- + ```bash + . /export.sh + ``` ---- -***Note*** + --- + ***Note*** -*The other HALs mentioned above like `hal_espressif` from Zephyr RTOS or `esp-hal-3rdparty` from NuttX RTOS environments also can be used for the bootloader standalone build, however as eventually code revision may differ from what is currently expected, it is recommended using them only within their RTOS build system.* + *If desirable, instructions for ESP-IDF installation can be found + [here](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/index.html#manual-installation)* ---- + --- + + --- + ***Note*** + + *The other HALs mentioned above like `hal_espressif` from Zephyr RTOS or `esp-hal-3rdparty` + from NuttX RTOS environments also can be used for the bootloader standalone build, however as + eventually code revision may differ from what is currently expected, it is recommended using + them only within their RTOS build system.* + + --- 4. If ESP-IDF is not installed and will not be used, install `esptool`: -```bash -pip3 install esptool -``` + + ```bash + pip3 install esptool + ``` ## [Building the bootloader itself](#building-the-bootloader-itself) -The MCUboot Espressif port bootloader is built using the toolchain and tools provided by Espressif. Additional configuration related to MCUboot features and slot partitioning may be made using the `port//bootloader.conf` file or passing a custom config file using the `-DMCUBOOT_CONFIG_FILE` argument on the first step below. +The MCUboot Espressif port bootloader is built using the toolchain and tools provided by Espressif. +Additional configuration related to MCUboot features and slot partitioning may be made using the +`port//bootloader.conf` file or passing a custom config file using the +`-DMCUBOOT_CONFIG_FILE` argument on the first step below. --- ***Note*** @@ -71,126 +93,159 @@ The MCUboot Espressif port bootloader is built using the toolchain and tools pro --- 1. Compile and generate the BIN: -```bash -cmake -DCMAKE_TOOLCHAIN_FILE=tools/toolchain-.cmake -DMCUBOOT_TARGET= -DESP_HAL_PATH= -DMCUBOOT_FLASH_PORT= -B build -GNinja -``` -```bash -ninja -C build/ -``` ---- -***Note*** + ```bash + cmake -DCMAKE_TOOLCHAIN_FILE=tools/toolchain-.cmake -DMCUBOOT_TARGET= -DESP_HAL_PATH= -DMCUBOOT_FLASH_PORT= -B build -GNinja + ``` -*If using ESP-IDF as HAL layer source, `ESP_HAL_PATH` can be ommited.* + ```bash + ninja -C build/ + ``` ---- + --- + ***Note*** + + *If using ESP-IDF as HAL layer source, `ESP_HAL_PATH` can be ommited.* + + *If desirable, `` can be defined with the path for a different compatible + toolchain, however it is recommended to actually create a CMake toolchain file and + pass it through `` variable since it may require a distinct set of + compilation flags.* + + --- 2. Flash MCUboot in your device: -```bash -ninja -C build/ flash -``` -If `MCUBOOT_FLASH_PORT` arg was not passed to `cmake`, the default `PORT` for flashing will be `/dev/ttyUSB0`. + ```bash + ninja -C build/ flash + ``` -Alternatively: -```bash -esptool.py -p -b --before default_reset --after no_reset --chip write_flash --flash_mode dio --flash_size --flash_freq 40m build/mcuboot_.bin -``` ---- -***Note*** + If `MCUBOOT_FLASH_PORT` arg was not passed to `cmake`, the default `PORT` for flashing will be + `/dev/ttyUSB0`. -You may adjust the port `` (like `/dev/ttyUSB0`) and baud rate `` (like `2000000`) according to the connection with your board. -You can also skip `` and `` parameters so that esptool tries to automatically detect it. + Alternatively: -*`` can be found using the command below:* -```bash -esptool.py -p -b flash_id -``` -The output contains device information and its flash size: -``` -Detected flash size: 4MB -``` + ```bash + esptool.py -p -b --before default_reset --after no_reset --chip write_flash --flash_mode dio --flash_size --flash_freq 40m build/mcuboot_.bin + ``` + --- + ***Note*** -*`` value must follow one of the addresses below:* + You may adjust the port `` (like `/dev/ttyUSB0`) and baud rate `` (like `2000000`) + according to the connection with your board. You can also skip `` and `` parameters + so that esptool tries to automatically detect it. -| ESP32 | ESP32-S2 | ESP32-C3 | ESP32-S3 | ESP32-C2 | ESP32-C6 | ESP32-H2 | -| :-----: | :-----: | :-----: | :-----: | :-----: | :-----: | :-----: | -| 0x1000 | 0x1000 | 0x0000 | 0x0000 | 0x0000 | 0x0000 | 0x0000 | + *`` can be found using the command below:* ---- + ```bash + esptool.py -p -b flash_id + ``` + + The output contains device information and its flash size: + + ``` + Detected flash size: 4MB + ``` + + *`` value must follow one of the addresses below:* + + | ESP32 | ESP32-S2 | ESP32-C3 | ESP32-S3 | ESP32-C2 | ESP32-C6 | ESP32-H2 | + | :-----: | :-----: | :-----: | :-----: | :-----: | :-----: | :-----: | + | 0x1000 | 0x1000 | 0x0000 | 0x0000 | 0x0000 | 0x0000 | 0x0000 | + + --- 3. Reset your device ## [Signing and flashing an application](#signing-and-flashing-an-application) 1. Images can be regularly signed with the `scripts/imgtool.py` script: -```bash -imgtool.py sign --align 4 -v 0 -H 32 --pad-header -S -``` ---- + ```bash + imgtool.py sign --align 4 -v 0 -H 32 --pad-header -S + ``` -***Note*** + --- -`` is the size of the slot to be used. -Default slot0 size is `0x100000`, but it can change as per application flash partitions. + ***Note*** -For Zephyr images, `--pad-header` is not needed as it already has the padding for MCUboot header. + `` is the size of the slot to be used. + Default slot0 size is `0x100000`, but it can change as per application flash partitions. ---- + For Zephyr images, `--pad-header` is not needed as it already has the padding for MCUboot + header. -:warning: ***ATTENTION*** + --- -*This is the basic signing needed for adding MCUboot headers and trailers. -For signing with a crypto key and guarantee the authenticity of the image being booted, see the section [MCUboot image signature verification](#mcuboot-image-signature-verification) below.* + :warning: ***ATTENTION*** ---- + *This is the basic signing needed for adding MCUboot headers and trailers. + For signing with a crypto key and guarantee the authenticity of the image being booted, see the + section [MCUboot image signature verification](#mcuboot-image-signature-verification) below.* + + --- 2. Flash the signed application: -```bash -esptool.py -p -b --before default_reset --after hard_reset --chip write_flash --flash_mode dio --flash_size --flash_freq 40m -``` + + ```bash + esptool.py -p -b --before default_reset --after hard_reset --chip write_flash --flash_mode dio --flash_size --flash_freq 40m + ``` # [Downgrade prevention](#downgrade-prevention) -Downgrade prevention (avoid updating of images to an older version) can be enabled using the following configuration: +Downgrade prevention (avoid updating of images to an older version) can be enabled using the +following configuration: ``` CONFIG_ESP_DOWNGRADE_PREVENTION=y ``` -MCUboot will then verify and compare the new image version number with the current one before perform an update swap. +MCUboot will then verify and compare the new image version number with the current one before +perform an update swap. -Version number is added to the image when signing it with `imgtool` (`-v` parameter, e.g. `-v 1.0.0`). +Version number is added to the image when signing it with `imgtool` (`-v` parameter, e.g. +`-v 1.0.0`). ### [Downgrade prevention with security counter](#downgrade-prevention-with-security-counter) -It is also possible to rely on a security counter, also added to the image when signing with `imgtool` (`-s` parameter), apart from version number. This allows image downgrade at some extent, since any update must have greater or equal security counter value. Enable using the following configuration: +It is also possible to rely on a security counter, also added to the image when signing with +`imgtool` (`-s` parameter), apart from version number. This allows image downgrade at some extent, +since any update must have greater or equal security counter value. Enable using the following +configuration: ``` CONFIG_ESP_DOWNGRADE_PREVENTION_SECURITY_COUNTER=y ``` -E.g.: if the current image was signed using `-s 1` parameter, an eventual update image must have been signed using security counter `-s 1` or greater. +E.g.: if the current image was signed using `-s 1` parameter, an eventual update image must have +been signed using security counter `-s 1` or greater. # [Security Chain on Espressif port](#security-chain-on-espressif-port) -[MCUboot encrypted images](encrypted_images.md) do not provide full code confidentiality when only external storage is available (see [Threat model](encrypted_images.md#threat-model)) since by MCUboot design the image in Primary Slot, from where the image is executed, is stored plaintext. -Espressif chips have off-chip flash memory, so to ensure a security chain along with MCUboot image signature verification, the hardware-assisted Secure Boot and Flash Encryption were made available on the MCUboot Espressif port. +[MCUboot encrypted images](encrypted_images.md) do not provide full code confidentiality when only +external storage is available (see [Threat model](encrypted_images.md#threat-model)) since by +MCUboot design the image in Primary Slot, from where the image is executed, is stored plaintext. +Espressif chips have off-chip flash memory, so to ensure a security chain along with MCUboot image +signature verification, the hardware-assisted Secure Boot and Flash Encryption were made available +on the MCUboot Espressif port. ## [MCUboot image signature verification](#mcuboot-image-signature-verification) -The image that MCUboot is booting can be signed with 4 types of keys: RSA-2048, RSA-3072, EC256 and ED25519. In order to enable the feature, the **bootloader** must be compiled with the following configurations: +The image that MCUboot is booting can be signed with 4 types of keys: RSA-2048, RSA-3072, EC256 and +ED25519. In order to enable the feature, the **bootloader** must be compiled with the following +configurations: --- ***Note*** -*It is strongly recommended to generate a new signing key using `imgtool` instead of use the existent samples.* +*It is strongly recommended to generate a new signing key using `imgtool` instead of use the +existent samples.* --- #### For EC256 algorithm use + ``` CONFIG_ESP_SIGN_EC256=y @@ -201,6 +256,7 @@ CONFIG_ESP_SIGN_KEY_FILE= ``` #### For ED25519 algorithm use + ``` CONFIG_ESP_SIGN_ED25519=y @@ -211,6 +267,7 @@ CONFIG_ESP_SIGN_KEY_FILE= ``` #### For RSA (2048 or 3072) algorithm use + ``` CONFIG_ESP_SIGN_RSA=y # RSA_LEN is 2048 or 3072 @@ -222,39 +279,64 @@ CONFIG_ESP_USE_MBEDTLS=y CONFIG_ESP_SIGN_KEY_FILE= ``` -Notice that the public key will be embedded in the bootloader code, since the hardware key storage is not supported by Espressif port. +Notice that the public key will be embedded in the bootloader code, since the hardware key storage +is not supported by Espressif port. ### [Signing the image](#signing-the-image) Now you need to sign the **image binary**, use the `imgtool` with `-k` parameter: + ```bash imgtool.py sign -k --pad --pad-sig --align 4 -v 0 -H 32 --pad-header -S 0x00100000 ``` -If signing a Zephyr image, the `--pad-header` is not needed, as it already have the padding for MCUboot header. + +If signing a Zephyr image, the `--pad-header` is not needed, as it already have the padding for +MCUboot header. ## [Secure Boot](#secure-boot) -The Secure Boot implementation is based on [IDF's Secure Boot V2](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/security/secure-boot-v2.html), is hardware-assisted and RSA based, and has the role for ensuring that only authorized code will be executed on the device. This is done through bootloader signature checking by the ROM bootloader. \ -***Note***: ROM bootloader is the First Stage Bootloader, while the Espressif MCUboot port is the Second Stage Bootloader. +The Secure Boot implementation is based on +[IDF's Secure Boot V2](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/security/secure-boot-v2.html), +is hardware-assisted and RSA based - except ESP32-C2 that uses ECDSA signing scheme - and has the +role for ensuring that only authorized code will be executed on the device. This is done through +bootloader signature checking by the ROM bootloader. -***Note***: Currently on MCUboot Espressif Port, the Secure Boot V2 for ESP32-C2 is not supported yet. +***Note***: ROM bootloader is the First Stage Bootloader, while the Espressif MCUboot port is the +Second Stage Bootloader. ### [Building bootloader with Secure Boot](#building-bootloader-with-secure-boot) In order to build the bootloader with the feature on, the following configurations must be enabled: + ``` CONFIG_SECURE_BOOT=1 CONFIG_SECURE_BOOT_V2_ENABLED=1 CONFIG_SECURE_SIGNED_ON_BOOT=1 +``` + +For the currently supported chips, with exception of ESP32-C2, enable RSA signing scheme: + +``` CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME=1 CONFIG_SECURE_BOOT_SUPPORTS_RSA=1 ``` +For ESP32-C2, enable ECDSA signing scheme and, if working with Flash Encryption too, enable the +configuration to burn keys to efuse together: + +``` +CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME=1 + +CONFIG_SECURE_BOOT_FLASH_ENC_KEYS_BURN_TOGETHER=1 +``` + --- :warning: ***ATTENTION*** -*On development phase is recommended add the following configuration in order to keep the debugging enabled and also to avoid any unrecoverable/permanent state change:* +*On development phase is recommended add the following configuration in order to keep the debugging +enabled and also to avoid any unrecoverable/permanent state change:* + ``` CONFIG_SECURE_BOOT_ALLOW_JTAG=1 CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE=1 @@ -263,20 +345,23 @@ CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE=1 CONFIG_EFUSE_VIRTUAL=1 CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH=1 ``` - --- --- :warning: ***ATTENTION*** *You can disable UART Download Mode by adding the following configuration:* + ``` CONFIG_SECURE_DISABLE_ROM_DL_MODE=1 ``` -*This may be suitable for **production** builds. **After disabling UART Download Mode you will not be able to flash other images through UART.*** +*This may be suitable for __production__ builds. __After disabling UART Download Mode you will not +be able to flash other images through UART.__* + +*Otherwise, you can switch the UART ROM Download Mode to the Secure Download Mode. It will limit +the use of Download Mode functions to simple flash read, write and erase operations.* -*Otherwise, you can switch the UART ROM Download Mode to the Secure Download Mode. It will limit the use of Download Mode functions to simple flash read, write and erase operations.* ``` CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE=1 ``` @@ -285,14 +370,17 @@ CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE=1 --- -Once the **bootloader image** is built, the resulting binary file is required to be signed with `espsecure.py` tool. +Once the **bootloader image** is built, the resulting binary file is required to be signed with +`espsecure.py` tool. First create a signing key: + ```bash espsecure.py generate_signing_key --version 2 ``` Then sign the bootloader image: + ```bash espsecure.py sign_data --version 2 --keyfile -o ``` @@ -300,58 +388,81 @@ espsecure.py sign_data --version 2 --keyfile -o -b 2000000 --after no_reset --chip write_flash --flash_mode dio --flash_size --flash_freq 40m ``` ### [Secure Boot Process](#secure-boot-process) -Secure boot uses a signature block appended to the bootloader image in order to verify the authenticity. The signature block contains the RSA-3072 signature of that image and the RSA-3072 public key. +Secure boot uses a signature block appended to the bootloader image in order to verify the +authenticity. The signature block contains the RSA-3072 signature of that image and the RSA-3072 +public key. -On its **first boot** the Secure Boot is not enabled on the device eFuses yet, neither the key nor digests. So the first boot will have the following process: +On its **first boot** the Secure Boot is not enabled on the device eFuses yet, neither the key nor +digests. So the first boot will have the following process: -1. On startup, since it is the first boot, the ROM bootloader will not verify the bootloader image (the Secure Boot bit in the eFuse is disabled) yet, so it proceeds to execute it (our MCUboot bootloader port). +1. On startup, since it is the first boot, the ROM bootloader will not verify the bootloader image + (the Secure Boot bit in the eFuse is disabled) yet, so it proceeds to execute it (our MCUboot + bootloader port). 2. Bootloader calculates the SHA-256 hash digest of the public key and writes the result to eFuse. 3. Bootloader validates the application images and prepare the booting process (MCUboot phase). 4. Bootloader burns eFuse to enable Secure Boot V2. 5. Bootloader proceeds to load the Primary image. -After that the Secure Boot feature is permanently enabled and on every next boot the ROM bootloader will verify the MCUboot bootloader image. -The process of an usual boot: - -1. On startup, the ROM bootloader checks the Secure Boot enable bit in the eFuse. If it is enabled, the boot will proceed as following. -2. ROM bootloader verifies the bootloader's signature block integrity (magic number and CRC). Interrupt boot if it fails. -3. ROM bootloader verifies the bootloader image, interrupt boot if any step fails.: \ -3.1. Compare the SHA-256 hash digest of the public key embedded in the bootloader’s signature block with the digest saved in the eFuses. \ -3.2. Generate the application image digest and match it with the image digest in the signature block. \ -3.3. Use the public key to verify the signature of the bootloader image, using RSA-PSS with the image digest calculated from previous step for comparison. +After that the Secure Boot feature is permanently enabled and on every next boot the ROM bootloader +will verify the MCUboot bootloader image. The process of an usual boot: + +1. On startup, the ROM bootloader checks the Secure Boot enable bit in the eFuse. If it is enabled, + the boot will proceed as following. +2. ROM bootloader verifies the bootloader's signature block integrity (magic number and CRC). + Interrupt boot if it fails. +3. ROM bootloader verifies the bootloader image, interrupt boot if any step fails: + 1. Compare the SHA-256 hash digest of the public key embedded in the bootloader’s signature + block with the digest saved in the eFuses. + 2. Generate the application image digest and match it with the image digest in the signature + block. + 3. Use the public key to verify the signature of the bootloader image, using RSA-PSS with the + image digest calculated from previous step for comparison. 4. ROM bootloader executes the bootloader image. 5. Bootloader does the usual verification (MCUboot phase). 6. Proceeds to boot the Primary image. ## [Flash Encryption](#flash-encryption) -The Espressif Flash Encryption is hardware-assisted, transparent to the MCUboot process and is an additional security measure beyond MCUboot existent features. -The Flash Encryption implementation is also based on [IDF](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/security/flash-encryption.html) and is intended for encrypting off-chip flash memory contents, so it is protected against physical reading. +The Espressif Flash Encryption is hardware-assisted, transparent to the MCUboot process and is an +additional security measure beyond MCUboot existent features. +The Flash Encryption implementation is also based on +[IDF](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/security/flash-encryption.html) +and is intended for encrypting off-chip flash memory contents, so it is protected against physical +reading. -When enabling the Flash Encryption, the user can encrypt the content either using a **device generated key** (remains unknown and unreadable) or a **host generated key** (owner is responsible for keeping the key private and safe). After the flash encryption gets enabled through eFuse burning on the device, all read and write operations are decrypted/encrypted in runtime. +When enabling the Flash Encryption, the user can encrypt the content either using a **device +generated key** (remains unknown and unreadable) or a **host generated key** (owner is responsible +for keeping the key private and safe). After the flash encryption gets enabled through eFuse +burning on the device, all read and write operations are decrypted/encrypted in runtime. ### [Building bootloader with Flash Encryption](#building-bootloader-with-flash-encryption) In order to build the bootloader with the feature on, the following configurations must be enabled: For **release mode**: + ``` CONFIG_SECURE_FLASH_ENC_ENABLED=1 CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE=1 ``` For **development mode**: + ``` CONFIG_SECURE_FLASH_ENC_ENABLED=1 CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT=1 @@ -360,7 +471,9 @@ CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT=1 --- :warning: ***ATTENTION*** -*On development phase is strongly recommended adding the following configuration in order to keep the debugging enabled and also to avoid any unrecoverable/permanent state change:* +*On development phase is strongly recommended adding the following configuration in order to keep +the debugging enabled and also to avoid any unrecoverable/permanent state change:* + ``` CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC=1 CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_DEC=1 @@ -376,18 +489,27 @@ CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH=1 --- :warning: ***ATTENTION*** -*Unless the recommended flags for **DEVELOPMENT MODE** were enabled, the actions made by Flash Encryption process are **PERMANENT**.* \ -*Once the bootloader is flashed and the device resets, the **first boot will enable Flash Encryption, encrypt the flash content including bootloader and image slots, burn the eFuses that no longer can be modified** and if device generated the key **it will not be recoverable**.* \ -*When on **RELEASE MODE**, **ENSURE** that the application with an update agent is flashed before reset the device.* +*Unless the recommended flags for __DEVELOPMENT MODE__ were enabled, the actions made by Flash +Encryption process are __PERMANENT__.* \ +*Once the bootloader is flashed and the device resets, the __first boot will enable Flash +Encryption, encrypt the flash content including bootloader and image slots, burn the eFuses that no +longer can be modified__ and if device generated the key __it will not be recoverable__.* \ +*When on __RELEASE MODE__, __ENSURE__ that the application with an update agent is flashed before +reset the device.* + +*In the same way as Secure Boot feature, you can disable UART Download Mode by adding the following +configuration:* -*In the same way as Secure Boot feature, you can disable UART Download Mode by adding the following configuration:* ``` CONFIG_SECURE_DISABLE_ROM_DL_MODE=1 ``` -*This may be suitable for **production** builds. **After disabling UART Download Mode you will not be able to flash other images through UART.*** +*This may be suitable for __production__ builds. __After disabling UART Download Mode you will not +be able to flash other images through UART.__* + +*Otherwise, you can switch the UART Download Mode to the Secure Download Mode. It will limit the +use of Download Mode functions to simple flash read, write and erase operations.* -*Otherwise, you can switch the UART Download Mode to the Secure Download Mode. It will limit the use of Download Mode functions to simple flash read, write and erase operations.* ``` CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE=1 ``` @@ -398,25 +520,30 @@ CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE=1 ### [Signing the image when working with Flash Encryption](#signing-the-image-when-working-with-flash-encryption) -When enabling flash encryption, it is required to signed the image using 32-byte alignment: `--align 32 --max-align 32`. +When enabling flash encryption, it is required to signed the image using 32-byte alignment: +`--align 32 --max-align 32`. Command example: + ```bash imgtool.py sign -k --pad --pad-sig --align 32 --max-align 32 -v 0 -H 32 --pad-header -S ``` ### [Device generated key](#device-generated-key) -First ensure that the application image is able to perform encrypted read and write operations to the SPI Flash. -Flash the bootloader and application normally: +First ensure that the application image is able to perform encrypted read and write operations to +the SPI Flash. Flash the bootloader and application normally: + ```bash esptool.py -p -b 2000000 --after no_reset --chip write_flash --flash_mode dio --flash_size --flash_freq 40m ``` + ```bash esptool.py -p -b 2000000 --after no_reset --chip write_flash --flash_mode dio --flash_size --flash_freq 40m ``` On the **first boot**, the bootloader will: + 1. Generate Flash Encryption key and write to eFuse. 2. Encrypt flash in-place including bootloader, image primary/secondary slot and scratch. 3. Burn eFuse to enable Flash Encryption. @@ -424,55 +551,73 @@ On the **first boot**, the bootloader will: ### [Host generated key](#host-generated-key) -First ensure that the application image is able to perform encrypted read and write operations to the SPI Flash. Also ensure that the **UART ROM Download Mode is not disabled** - or that the **Secure Download Mode is enabled**. -Before flashing, generate the encryption key using `espsecure.py` tool: +First ensure that the application image is able to perform encrypted read and write operations to +the SPI Flash. Also ensure that the **UART ROM Download Mode is not disabled** - or that the +**Secure Download Mode is enabled**. Before flashing, generate the encryption key using +`espsecure.py` tool: + ```bash espsecure.py generate_flash_encryption_key ``` -Burn the key into the device's eFuse (keep a copy on the host), this action can be done **only once**: +Burn the key into the device's eFuse (keep a copy on the host), this action can be done **only +once**: --- :warning: ***ATTENTION*** -*eFuse emulation in Flash configuration options do not have any effect, so if the key burning command below is used, it will actually burn the physical eFuse.* +*eFuse emulation in Flash configuration options do not have any effect, so if the key burning +command below is used, it will actually burn the physical eFuse.* --- - ESP32 + ```bash espefuse.py --port PORT burn_key flash_encryption ``` - ESP32S2, ESP32C3 and ESP32S3 + ```bash espefuse.py --port PORT burn_key BLOCK ``` -BLOCK is a free keyblock between BLOCK_KEY0 and BLOCK_KEY5. And KEYPURPOSE is either XTS_AES_128_KEY, XTS_AES_256_KEY_1, XTS_AES_256_KEY_2 (AES XTS 256 is available only in ESP32S2). +`BLOCK` is a free keyblock between `BLOCK_KEY0` and `BLOCK_KEY5`. And `KEYPURPOSE` is either +`XTS_AES_128_KEY`, `XTS_AES_256_KEY_1`, `XTS_AES_256_KEY_2` (AES XTS 256 is available only in +ESP32S2). -Now, similar as the Device generated key, the bootloader and application can be flashed plaintext. The **first boot** will encrypt the flash content using the host key burned in the eFuse instead of generate a new one. +Now, similar as the Device generated key, the bootloader and application can be flashed plaintext. +The **first boot** will encrypt the flash content using the host key burned in the eFuse instead +of generate a new one. Flashing the bootloader and application: + ```bash esptool.py -p -b 2000000 --after no_reset --chip write_flash --flash_mode dio --flash_size --flash_freq 40m ``` + ```bash esptool.py -p -b 2000000 --after no_reset --chip write_flash --flash_mode dio --flash_size --flash_freq 40m ``` On the **first boot**, the bootloader will: -1. Encrypt flash in-place including bootloader, image primary/secondary slot and scratch using the written key. + +1. Encrypt flash in-place including bootloader, image primary/secondary slot and scratch using the + written key. 2. Burn eFuse to enable Flash Encryption. 3. Reset system to ensure Flash Encryption cache resets properly. Encrypting data on the host: + - ESP32 + ```bash espsecure.py encrypt_flash_data --keyfile --address --output ``` - ESP32-S2, ESP32-C3 and ESP32-S3 + ```bash espsecure.py encrypt_flash_data --aes_xts --keyfile --address --output ``` @@ -480,36 +625,51 @@ espsecure.py encrypt_flash_data --aes_xts --keyfile - --- ***Note*** -OTA updates are required to be sent plaintext. The reason is that, as said before, after the Flash Encryption is enabled all read/write operations are decrypted/encrypted in runtime, so as e.g. if pre-encrypted data is sent for an OTA update, it would be wrongly double-encrypted when the update agent writes to the flash. +OTA updates are required to be sent plaintext. The reason is that, as said before, after the Flash +Encryption is enabled all read/write operations are decrypted/encrypted in runtime, so as e.g. if +pre-encrypted data is sent for an OTA update, it would be wrongly double-encrypted when the update +agent writes to the flash. -For updating with an image encrypted on the host, flash it through serial using `esptool.py` as above. **UART ROM Download Mode must not be disabled**. +For updating with an image encrypted on the host, flash it through serial using `esptool.py` as +above. **UART ROM Download Mode must not be disabled**. --- ## [Security Chain scheme](#security-chain-scheme) -Using the 3 features, Secure Boot, Image signature verification and Flash Encryption, a Security Chain can be established so only trusted code is executed, and also the code and content residing in the off-chip flash are protected against undesirable reading. +Using the 3 features, Secure Boot, Image signature verification and Flash Encryption, a Security +Chain can be established so only trusted code is executed, and also the code and content residing +in the off-chip flash are protected against undesirable reading. The overall final process when all features are enabled: + 1. ROM bootloader validates the MCUboot bootloader using RSA signature verification. -2. MCUboot bootloader validates the image using the chosen algorithm EC256/RSA/ED25519. It also validates an upcoming image when updating. +2. MCUboot bootloader validates the image using the chosen algorithm EC256/RSA/ED25519. It also + validates an upcoming image when updating. 3. Flash Encryption guarantees that code and data are not exposed. ### [Size Limitation](#size-limitation) -When all 3 features are enable at same time, the bootloader size may exceed the fixed limit for the ROM bootloader checking on the Espressif chips **depending on which algorithm** was chosen for MCUboot image signing. The issue https://github.com/mcu-tools/mcuboot/issues/1262 was created to track this limitation. +When all 3 features are enable at same time, the bootloader size may exceed the fixed limit for +the ROM bootloader checking on the Espressif chips **depending on which algorithm** was chosen for +MCUboot image signing. The issue was created to +track this limitation. ## [Multi image](#multi-image) -The multi image feature (currently limited to 2 images) allows the images to be updated separately (each one has its own primary and secondary slot) by MCUboot. +The multi image feature (currently limited to 2 images) allows the images to be updated separately +(each one has its own primary and secondary slot) by MCUboot. The Espressif port bootloader handles the boot in two different approaches: ### [Host OS boots second image](#host-os-boots-second-image) -Host OS from the *first image* is responsible for booting the *second image*, therefore the bootloader is aware of the second image regions and can update it, however it does not load neither boots it. +Host OS from the *first image* is responsible for booting the *second image*, therefore the +bootloader is aware of the second image regions and can update it, however it does not load +neither boots it. Configuration example (`bootloader.conf`): + ``` CONFIG_ESP_BOOTLOADER_SIZE=0xF000 CONFIG_ESP_MCUBOOT_WDT_ENABLE=y @@ -532,7 +692,10 @@ CONFIG_ESP_SCRATCH_SIZE=0x40000 ### [Multi boot](#multi-boot) -In the multi boot approach the bootloader is responsible for booting two different images in two different CPUs, firstly the *second image* on the APP CPU and then the *first image* on the PRO CPU (current CPU), it is also responsible for update both images as well. Thus multi boot will be only supported by Espressif multi core chips - currently only ESP32 is implemented. +In the multi boot approach the bootloader is responsible for booting two different images in two +different CPUs, firstly the *second image* on the APP CPU and then the *first image* on the PRO +CPU (current CPU), it is also responsible for update both images as well. Thus multi boot will be +only supported by Espressif multi core chips - currently only ESP32 is implemented. --- ***Note*** @@ -542,6 +705,7 @@ In the multi boot approach the bootloader is responsible for booting two differe --- Configuration example: + ``` CONFIG_ESP_BOOTLOADER_SIZE=0xF000 CONFIG_ESP_MCUBOOT_WDT_ENABLE=y @@ -569,29 +733,38 @@ CONFIG_ESP_SCRATCH_SIZE=0x40000 ### [Image version dependency](#image-version-dependency) -MCUboot allows version dependency check between the images when updating them. As `imgtool.py` allows a version assigment when signing an image, it is also possible to add the version dependency constraint: +MCUboot allows version dependency check between the images when updating them. As `imgtool.py` +allows a version assigment when signing an image, it is also possible to add the version +dependency constraint: + ```bash imgtool.py sign --align 4 -v -d "(, )" -H 32 --pad-header -S ``` - `` defines the version of the image being signed. -- `"(, )"` defines the minimum version and from which image is needed to satisfy the dependency. +- `"(, )"` defines the minimum version and from which image is + needed to satisfy the dependency. --- Example: + ```bash imgtool.py sign --align 4 -v 1.0.0 -d "(1, 0.0.1+0)" -H 32 --pad-header -S 0x100000 image0.bin image0-signed.bin ``` -Supposing that the image 0 is being signed, its version is 1.0.0 and it depends on image 1 with version at least 0.0.1+0. +Supposing that the image 0 is being signed, its version is 1.0.0 and it depends on image 1 with +version at least 0.0.1+0. --- ## [Serial recovery mode](#serial-recovery-mode) -Serial recovery mode allows management through MCUMGR (more information and how to install it: https://github.com/apache/mynewt-mcumgr-cli) for communicating and uploading a firmware to the device. +Serial recovery mode allows management through MCUMGR (more information and how to install it: +) for communicating and uploading a firmware to the +device. Configuration example: + ``` # Enables the MCUboot Serial Recovery, that allows the use of # MCUMGR to upload a firmware through the serial port @@ -612,20 +785,28 @@ CONFIG_ESP_SERIAL_BOOT_GPIO_RX=25 CONFIG_ESP_SERIAL_BOOT_GPIO_TX=26 ``` -When enabled, the bootloader checks the if the GPIO `` configured has the signal value `` for approximately `` seconds for entering the Serial recovery mode. Example: a button configured on GPIO 32 pressed for 5 seconds. +When enabled, the bootloader checks the if the GPIO `` +configured has the signal value `` for approximately +`` seconds for entering the Serial recovery mode. Example: +a button configured on GPIO 32 pressed for 5 seconds. -Serial mode then uses the UART port configured for communication (``, pins ``, ``). +Serial mode then uses the UART port configured for communication +(``, pins ``, +``). ### [Serial Recovery through USB JTAG Serial port](#serial-recovery-through-usb-jtag-serial-port) -Some chips, like ESP32-C3 and ESP32-S3 have an integrated USB JTAG Serial Controller that implements a serial port (CDC) that can also be used for handling MCUboot Serial Recovery. +Some chips, like ESP32-C3 and ESP32-S3 have an integrated USB JTAG Serial Controller that +implements a serial port (CDC) that can also be used for handling MCUboot Serial Recovery. More information about the USB pins and hardware configuration: -- ESP32-C3: https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/api-guides/usb-serial-jtag-console.html -- ESP32-S3: https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-guides/usb-serial-jtag-console.html. -- ESP32-C6: https://docs.espressif.com/projects/esp-idf/en/latest/esp32c6/api-guides/usb-serial-jtag-console.html -- ESP32-H2: https://docs.espressif.com/projects/esp-idf/en/latest/esp32h2/api-guides/usb-serial-jtag-console.html + +- ESP32-C3: +- ESP32-S3: +- ESP32-C6: +- ESP32-H2: Configuration example: + ``` # Use Serial through USB JTAG Serial port for Serial Recovery CONFIG_ESP_MCUBOOT_SERIAL_USB_SERIAL_JTAG=y @@ -645,7 +826,8 @@ CONFIG_ESP_SERIAL_BOOT_DETECT_DELAY_S=5 --- :warning: ***ATTENTION*** -*When working with Flash Encryption enabled, `CONFIG_ESP_MCUBOOT_ERASE_PROGRESSIVELY` must be ***disabled***, although it is recommended for common Serial Recovery usage* +*When working with Flash Encryption enabled, `CONFIG_ESP_MCUBOOT_ERASE_PROGRESSIVELY` must be +__disabled__, although it is recommended for common Serial Recovery usage* --- @@ -671,28 +853,39 @@ mcumgr -c esp reset --- :warning: ***ATTENTION*** -*Serial recovery mode uploads the image to the PRIMARY_SLOT, therefore if the upload process gets interrupted the image may be corrupted and unable to boot* +*Serial recovery mode uploads the image to the PRIMARY_SLOT, therefore if the upload process gets +interrupted the image may be corrupted and unable to boot* --- ## [Memory map organization for OS compatibility](#memory-map-organization-for-os-compatibility) -When adding support for this MCUboot port to an OS or even customizing an already supported application memory layout, it is mandatory for the OS linker script to avoid overlaping on `iram_loader_seg` and `dram_seg` bootloader RAM regions. Although part of the RAM becomes initially unavailable, it is reclaimable by the OS after boot as heap. +When adding support for this MCUboot port to an OS or even customizing an already supported +application memory layout, it is mandatory for the OS linker script to avoid overlaping on +`iram_loader_seg` and `dram_seg` bootloader RAM regions. Although part of the RAM becomes initially +unavailable, it is reclaimable by the OS after boot as heap. Therefore, the application must be designed aware of the bootloader memory usage. --- ***Note*** -*Mostly of the Espressif chips have a separation on the address space for the same physical memory ammount: IRAM (accessed by the instruction bus) and DRAM (accessed by the data bus), which means that they need to be accessed by different addresses ranges depending on type, but refer to the same region. More information on the [Espressif TRMs](https://www.espressif.com/en/support/documents/technical-documents?keys=&field_download_document_type_tid%5B%5D=963).* +*Mostly of the Espressif chips have a separation on the address space for the same physical memory +ammount: IRAM (accessed by the instruction bus) and DRAM (accessed by the data bus), which means +that they need to be accessed by different addresses ranges depending on type, but refer to the +same region. More information on the +[Espressif TRMs](https://www.espressif.com/en/support/documents/technical-documents?keys=&field_download_document_type_tid%5B%5D=963).* --- -The following diagrams illustrate a memory organization from the bootloader point of view (notice that the addresses and sizes may vary depending on the chip), they reflect the linker script `boot/espressif/port//ld/bootloader.ld`: +The following diagrams illustrate a memory organization from the bootloader point of view (notice +that the addresses and sizes may vary depending on the chip), they reflect the linker script +`boot/espressif/port//ld/bootloader.ld`: ### ESP32 #### ESP32 standard + ``` SRAM0 IRAM ADDR / DRAM ADDR @@ -736,7 +929,9 @@ The following diagrams illustrate a memory organization from the bootloader poin * | | | * | v | * +--------+--------------+------+ 0x400BFFFF / 0x3FFE0000 - SRAM1 END - Note: On ESP32 the SRAM1 addresses are accessed in reverse order comparing Instruction bus (IRAM) and Data bus (DRAM), but refer to the same location. See the TRM for more information. + Note: On ESP32 the SRAM1 addresses are accessed in reverse order comparing Instruction + bus (IRAM) and Data bus (DRAM), but refer to the same location. See the TRM for more + information. SRAM2 IRAM ADDR / DRAM ADDR @@ -747,7 +942,10 @@ The following diagrams illustrate a memory organization from the bootloader poin #### ESP32 Multi Processor Boot -This is the linker script mapping when the `CONFIG_ESP_MULTI_PROCESSOR_BOOT` is enabled ([Multi boot](#multi-boot)) since APP CPU Cache region cannot be used for `iram_loader_seg` region as there would be conflict when the bootloader starts the APP CPU before jump to the main application. +This is the linker script mapping when the `CONFIG_ESP_MULTI_PROCESSOR_BOOT` is enabled +([Multi boot](#multi-boot)) since APP CPU Cache region cannot be used for `iram_loader_seg` region +as there would be conflict when the bootloader starts the APP CPU before jump to the main +application. ``` SRAM0 @@ -791,7 +989,9 @@ This is the linker script mapping when the `CONFIG_ESP_MULTI_PROCESSOR_BOOT` is * | | | * | v | * +--------+--------------+------+ 0x400BFFFF / 0x3FFE0000 - SRAM1 END - Note: On ESP32 the SRAM1 addresses are accessed in reverse order comparing Instruction bus (IRAM) and Data bus (DRAM), but refer to the same location. See the TRM for more information. + Note: On ESP32 the SRAM1 addresses are accessed in reverse order comparing Instruction + bus (IRAM) and Data bus (DRAM), but refer to the same location. See the TRM for more + information. SRAM2 IRAM ADDR / DRAM ADDR @@ -969,7 +1169,7 @@ This is the linker script mapping when the `CONFIG_ESP_MULTI_PROCESSOR_BOOT` is * | | | *** OS CAN RECLAIM IT AFTER BOOT LATER AS HEAP *** * | | | * | v | - * +------------------------------+ 0x403D5000 / 0x3FCD5000 + * +------------------------------+ 0x403D5400 / 0x3FCD5400 * | ^ | * | | | * | | dram_seg | *** SHOULD NOT BE OVERLAPPED *** diff --git a/docs/release-notes.d/boot-serial-echo.md b/docs/release-notes.d/boot-serial-echo.md new file mode 100644 index 000000000..2667f733c --- /dev/null +++ b/docs/release-notes.d/boot-serial-echo.md @@ -0,0 +1 @@ +- Boot serial: Add response to echo command if support is not enabled, previously the command would have been accepted but no response indicating that the command is not supported would have been sent. diff --git a/docs/release-notes.d/cddl-change.md b/docs/release-notes.d/cddl-change.md deleted file mode 100644 index 17852eda1..000000000 --- a/docs/release-notes.d/cddl-change.md +++ /dev/null @@ -1,2 +0,0 @@ -- CDDL auto-generated function code has been replaced with zcbor function - calls, this now allows the parameters to be supplied in any order. diff --git a/docs/release-notes.d/data-sharing.md b/docs/release-notes.d/data-sharing.md deleted file mode 100644 index 767aaada1..000000000 --- a/docs/release-notes.d/data-sharing.md +++ /dev/null @@ -1,2 +0,0 @@ -- Added currently running slot ID and maximum application size to - shared data function definition. diff --git a/docs/release-notes.d/ecdsa-tlv-p384.md b/docs/release-notes.d/ecdsa-tlv-p384.md deleted file mode 100644 index 48a70f2cd..000000000 --- a/docs/release-notes.d/ecdsa-tlv-p384.md +++ /dev/null @@ -1,2 +0,0 @@ -- Make the ECDSA256 TLV curve agnostic and rename it to ECDSA_SIG. -- imgtool: add P384 support along with SHA384. diff --git a/docs/release-notes.d/espressif-hal-updates.md b/docs/release-notes.d/espressif-hal-updates.md deleted file mode 100644 index 121c8853a..000000000 --- a/docs/release-notes.d/espressif-hal-updates.md +++ /dev/null @@ -1,3 +0,0 @@ -- espressif: refactor after removing IDF submodule -- espressif: add ESP32-C6, ESP32-C2 and ESP32-H2 new chips support -- espressif: adjustments after IDF v5.1 compatibility, secure boot build and memory map organization diff --git a/docs/release-notes.d/img-state.md b/docs/release-notes.d/img-state.md deleted file mode 100644 index 1302be365..000000000 --- a/docs/release-notes.d/img-state.md +++ /dev/null @@ -1 +0,0 @@ -- Serial recovery image state and image set state optional commands added diff --git a/docs/release-notes.d/imgtool-getpub-hash.md b/docs/release-notes.d/imgtool-getpub-hash.md deleted file mode 100644 index 1613876ae..000000000 --- a/docs/release-notes.d/imgtool-getpub-hash.md +++ /dev/null @@ -1 +0,0 @@ -- imgtool: add 'getpubhash' command to dump the sha256 hash of the public key diff --git a/docs/release-notes.d/imgtool-getpub-output-file.md b/docs/release-notes.d/imgtool-getpub-output-file.md deleted file mode 100644 index 414a7c934..000000000 --- a/docs/release-notes.d/imgtool-getpub-output-file.md +++ /dev/null @@ -1 +0,0 @@ -- imgtool's getpub can print the output to a file diff --git a/docs/release-notes.d/imgtool-getpub-raw.md b/docs/release-notes.d/imgtool-getpub-raw.md deleted file mode 100644 index 468edd6c1..000000000 --- a/docs/release-notes.d/imgtool-getpub-raw.md +++ /dev/null @@ -1 +0,0 @@ -- imgtool can dump the raw versions of the public keys diff --git a/docs/release-notes.d/imgtool_dumpinfo.md b/docs/release-notes.d/imgtool_dumpinfo.md deleted file mode 100644 index 81e97e324..000000000 --- a/docs/release-notes.d/imgtool_dumpinfo.md +++ /dev/null @@ -1 +0,0 @@ -- imgtool: add 'dumpinfo' command for signed image parsing. diff --git a/docs/release-notes.d/p224-removal.md b/docs/release-notes.d/p224-removal.md deleted file mode 100644 index 07a5d92da..000000000 --- a/docs/release-notes.d/p224-removal.md +++ /dev/null @@ -1 +0,0 @@ -- Drop ECDSA P224 support diff --git a/docs/release-notes.d/zcbor-fix.md b/docs/release-notes.d/zcbor-fix.md deleted file mode 100644 index 6f191df91..000000000 --- a/docs/release-notes.d/zcbor-fix.md +++ /dev/null @@ -1,3 +0,0 @@ -- Fixed an issue with the boot_serial zcbor setup encoder function - wrongly including the buffer address in the size which caused - serial recovery to fail on some platforms. diff --git a/docs/release-notes.d/zcbor-update.md b/docs/release-notes.d/zcbor-update.md deleted file mode 100644 index ec6c7908a..000000000 --- a/docs/release-notes.d/zcbor-update.md +++ /dev/null @@ -1 +0,0 @@ -- zcbor library files have been updated to version 0.7.0 diff --git a/docs/release-notes.d/zephyr-debug.md b/docs/release-notes.d/zephyr-debug.md deleted file mode 100644 index 71a09f75e..000000000 --- a/docs/release-notes.d/zephyr-debug.md +++ /dev/null @@ -1,2 +0,0 @@ -- Zephyr no longer builds in optimize for debug mode, this saves a - significant amount of flash space. diff --git a/docs/release-notes.d/zephyr-encryption.md b/docs/release-notes.d/zephyr-encryption.md deleted file mode 100644 index f60e18f84..000000000 --- a/docs/release-notes.d/zephyr-encryption.md +++ /dev/null @@ -1,9 +0,0 @@ -- Reworked image encryption support for Zephyr, static dummy key files - are no longer in the code, a pem file must be supplied to extract - the private and public keys. The Kconfig menu has changed to only - show a single option for enabling encryption and selecting the key - file. -- Serial recovery can now read and handle encrypted seondary slot - partitions. -- Serial recovery with MBEDTLS no longer has undefined operations which - led to usage faults when the secondary slot image was encrypted. diff --git a/docs/release-notes.d/zephyr-firmware-loader.md b/docs/release-notes.d/zephyr-firmware-loader.md new file mode 100644 index 000000000..8f6acf455 --- /dev/null +++ b/docs/release-notes.d/zephyr-firmware-loader.md @@ -0,0 +1,4 @@ +- Added firmware loader configuration type support for Zephyr, this + allows for a single application slot and firmware loader image in + the secondary slot which is used to update the primary image + (loading it in any way it sees fit e.g. via Bluetooth). diff --git a/docs/release-notes.d/zephyr-usb.md b/docs/release-notes.d/zephyr-usb.md new file mode 100644 index 000000000..7154f58ea --- /dev/null +++ b/docs/release-notes.d/zephyr-usb.md @@ -0,0 +1,2 @@ +- Zephyr: Add USB CDC serial recovery check that now causes a build failure if console is enabled and device is the same as the USB CDC device. +- Zephyr: Add USB CDC serial recovery check that now causes a build failure if the main thread priority is below 0 (cooperative thread), this would prevent USB CDC from working as the driver would not have been able to fire callbacks. diff --git a/docs/release-notes.md b/docs/release-notes.md index 00bb6261e..45b32e6e2 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -3,6 +3,69 @@ - Table of Contents {:toc} +## Version 2.0.0 + +Note that this release, 2.0.0 is a new major number, and contains a small API +change in the interface between mcuboot and the platform. All platforms +contained within the MCUboot tree have been updated, but any external platforms +will have to be adjusted. The following commit makes the API change, in the +function `boot_save_shared_data`. + + commit 3016d00cd765e7c09a14af55fb4dcad945e4b982 + Author: Jamie McCrae + Date: Tue Mar 14 12:35:51 2023 +0000 + + bootutil: Add active slot number and max app size to shared data + +### About this release + +- Add error when flash device fails to open. +- Panic bootloader when flash device fails to open. +- Fixed issue with serial recovery not showing image details for + decrypted images. +- Fixes issue with serial recovery in single slot mode wrongly + iterating over 2 image slots. +- CDDL auto-generated function code has been replaced with zcbor function + calls, this now allows the parameters to be supplied in any order. +- Added currently running slot ID and maximum application size to + shared data function definition. +- Make the ECDSA256 TLV curve agnostic and rename it to ECDSA_SIG. +- imgtool: add P384 support along with SHA384. +- espressif: refactor after removing IDF submodule +- espressif: add ESP32-C6, ESP32-C2 and ESP32-H2 new chips support +- espressif: adjustments after IDF v5.1 compatibility, secure boot build and memory map organization +- Serial recovery image state and image set state optional commands added +- imgtool: add 'dumpinfo' command for signed image parsing. +- imgtool: add 'getpubhash' command to dump the sha256 hash of the public key +- imgtool's getpub can print the output to a file +- imgtool can dump the raw versions of the public keys +- Drop ECDSA P224 support +- Fixed an issue with boot_serial repeats not being processed when + output was sent, this would lead to a divergence of commands + whereby later commands being sent would have the previous command + output sent instead. +- Fixed an issue with the boot_serial zcbor setup encoder function + wrongly including the buffer address in the size which caused + serial recovery to fail on some platforms. +- zcbor library files have been updated to version 0.7.0 +- Reworked boot serial extensions so that they can be used by modules + or from user repositories by switching to iterable sections. +- Removed Zephyr custom img list boot serial extension support. +- (Zephyr) Adds support for sharing boot information with + application via retention subsystem +- Zephyr no longer builds in optimize for debug mode, this saves a + significant amount of flash space. +- Reworked image encryption support for Zephyr, static dummy key files + are no longer in the code, a pem file must be supplied to extract + the private and public keys. The Kconfig menu has changed to only + show a single option for enabling encryption and selecting the key + file. +- Serial recovery can now read and handle encrypted seondary slot + partitions. +- Serial recovery with MBEDTLS no longer has undefined operations which + led to usage faults when the secondary slot image was encrypted. +- espressif: allow the use of a different toolchain for building + ## Version 1.10.0 The 1.10.0 release of MCUboot contains... diff --git a/ext/nrf/cc310_glue.h b/ext/nrf/cc310_glue.h index 395cfc531..22eb94911 100644 --- a/ext/nrf/cc310_glue.h +++ b/ext/nrf/cc310_glue.h @@ -32,7 +32,7 @@ #define NRF_CRYPTOCELL NRF_CRYPTOCELL_S #endif -typedef nrf_cc310_bl_hash_context_sha256_t bootutil_sha256_context; +typedef nrf_cc310_bl_hash_context_sha256_t bootutil_sha_context; int cc310_ecdsa_verify_secp256r1(uint8_t *hash, uint8_t *public_key, @@ -66,7 +66,7 @@ static inline void cc310_sha256_init(nrf_cc310_bl_hash_context_sha256_t * ctx) nrf_cc310_bl_hash_sha256_init(ctx); } -static inline void cc310_sha256_finalize(bootutil_sha256_context *ctx, +static inline void cc310_sha256_finalize(nrf_cc310_bl_hash_context_sha256_t *ctx, uint8_t *output) { nrf_cc310_bl_hash_sha256_finalize(ctx, diff --git a/repository.yml b/repository.yml index 43023035e..fab3830da 100644 --- a/repository.yml +++ b/repository.yml @@ -36,9 +36,12 @@ repo.versions: "1.8.0": "v1.8.0" "1.9.0": "v1.9.0" "1.10.0": "v1.10.0" + "2.0.0": "v2.0.0" "0-dev": "0.0.0" # main - "0-latest": "1.10.0" # latest stable release - "1-latest": "1.10.0" # latest stable release + "0-latest": "2.0.0" # latest stable release + "1-latest": "1.11.0" + "2-latest": "2.0.0" - "1.0-latest": "1.10.0" + "1.0-latest": "1.11.0" + "2.0-latest": "2.0.0" diff --git a/root-ec-p384-pkcs8.pem b/root-ec-p384-pkcs8.pem new file mode 100644 index 000000000..4d4894cc3 --- /dev/null +++ b/root-ec-p384-pkcs8.pem @@ -0,0 +1,6 @@ +-----BEGIN PRIVATE KEY----- +MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDC8ZQWjooCCaLQJ9DJN +KMyPoUoFcqGluXGu13Zf526RX6TdRhnkExtL1T7fC13n32ChZANiAAQMdsqucjql +6PDU8Ra1Au93oRuTYXjACSZ7O0Cc7kmF4MlP5/K6l2zzgmUULPUMczNNMueb00LM +lVrl4vX0bkXg7SA1XK9SNYHU3JzjniI++z8iENpwAzetqPJI/jpgaaU= +-----END PRIVATE KEY----- diff --git a/root-ec-p384.pem b/root-ec-p384.pem new file mode 100644 index 000000000..916c80032 --- /dev/null +++ b/root-ec-p384.pem @@ -0,0 +1,6 @@ +-----BEGIN EC PRIVATE KEY----- +MIGkAgEBBDC8ZQWjooCCaLQJ9DJNKMyPoUoFcqGluXGu13Zf526RX6TdRhnkExtL +1T7fC13n32CgBwYFK4EEACKhZANiAAQMdsqucjql6PDU8Ra1Au93oRuTYXjACSZ7 +O0Cc7kmF4MlP5/K6l2zzgmUULPUMczNNMueb00LMlVrl4vX0bkXg7SA1XK9SNYHU +3JzjniI++z8iENpwAzetqPJI/jpgaaU= +-----END EC PRIVATE KEY----- diff --git a/samples/zephyr/hello-world/prj.conf b/samples/zephyr/hello-world/prj.conf index cc674062a..12990aacb 100644 --- a/samples/zephyr/hello-world/prj.conf +++ b/samples/zephyr/hello-world/prj.conf @@ -7,3 +7,6 @@ CONFIG_STDOUT_CONSOLE=y # Enable Zephyr application to be booted by MCUboot CONFIG_BOOTLOADER_MCUBOOT=y + +# Use the default MCUBoot PEM key file (BOOT_SIGNATURE_KEY_FILE) +CONFIG_MCUBOOT_SIGNATURE_KEY_FILE="bootloader/mcuboot/root-rsa-2048.pem" diff --git a/scripts/imgtool/__init__.py b/scripts/imgtool/__init__.py index ea5502494..249e23c95 100644 --- a/scripts/imgtool/__init__.py +++ b/scripts/imgtool/__init__.py @@ -14,4 +14,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -imgtool_version = "1.10.0" +imgtool_version = "2.0.0" diff --git a/scripts/imgtool/main.py b/scripts/imgtool/main.py index c3fce5435..9dd033c41 100755 --- a/scripts/imgtool/main.py +++ b/scripts/imgtool/main.py @@ -377,7 +377,8 @@ def convert(self, value, param, ctx): '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', '16', '32']), - required=True) + required=False, + help='Alignment used by swap update modes.') @click.option('--max-align', type=click.Choice(['8', '16', '32']), required=False, help='Maximum flash alignment. Set if flash alignment of the ' diff --git a/scripts/requirements.txt b/scripts/requirements.txt index 244692809..79883b6da 100644 --- a/scripts/requirements.txt +++ b/scripts/requirements.txt @@ -2,3 +2,4 @@ cryptography>=2.6 intelhex click cbor2 +pyyaml diff --git a/sim/Cargo.toml b/sim/Cargo.toml index 1689a3c4b..7cef823d8 100644 --- a/sim/Cargo.toml +++ b/sim/Cargo.toml @@ -11,6 +11,8 @@ sig-rsa = ["mcuboot-sys/sig-rsa"] sig-rsa3072 = ["mcuboot-sys/sig-rsa3072"] sig-ecdsa = ["mcuboot-sys/sig-ecdsa"] sig-ecdsa-mbedtls = ["mcuboot-sys/sig-ecdsa-mbedtls"] +sig-ecdsa-psa = ["mcuboot-sys/sig-ecdsa-psa", "mcuboot-sys/psa-crypto-api"] +sig-p384 = ["mcuboot-sys/sig-p384"] sig-ed25519 = ["mcuboot-sys/sig-ed25519"] overwrite-only = ["mcuboot-sys/overwrite-only"] swap-move = ["mcuboot-sys/swap-move"] @@ -31,7 +33,6 @@ direct-xip = ["mcuboot-sys/direct-xip"] downgrade-prevention = ["mcuboot-sys/downgrade-prevention"] max-align-32 = ["mcuboot-sys/max-align-32"] hw-rollback-protection = ["mcuboot-sys/hw-rollback-protection"] -psa-crypto-api = ["mcuboot-sys/psa-crypto-api"] [dependencies] byteorder = "1.4" diff --git a/sim/mcuboot-sys/Cargo.toml b/sim/mcuboot-sys/Cargo.toml index f4f2aceb3..ab97bbfe1 100644 --- a/sim/mcuboot-sys/Cargo.toml +++ b/sim/mcuboot-sys/Cargo.toml @@ -24,6 +24,12 @@ sig-ecdsa = [] # Verify ECDSA (secp256r1) signatures using mbed TLS sig-ecdsa-mbedtls = [] +# Verify ECDSA (p256 or p384) signatures using PSA Crypto API +sig-ecdsa-psa = [] + +# Enable P384 Curve support (instead of P256) for PSA Crypto +sig-p384 = [] + # Verify ED25519 signatures. sig-ed25519 = [] diff --git a/sim/mcuboot-sys/build.rs b/sim/mcuboot-sys/build.rs index 88316effe..4221292f5 100644 --- a/sim/mcuboot-sys/build.rs +++ b/sim/mcuboot-sys/build.rs @@ -15,6 +15,8 @@ fn main() { let sig_rsa3072 = env::var("CARGO_FEATURE_SIG_RSA3072").is_ok(); let sig_ecdsa = env::var("CARGO_FEATURE_SIG_ECDSA").is_ok(); let sig_ecdsa_mbedtls = env::var("CARGO_FEATURE_SIG_ECDSA_MBEDTLS").is_ok(); + let sig_ecdsa_psa = env::var("CARGO_FEATURE_SIG_ECDSA_PSA").is_ok(); + let sig_p384 = env::var("CARGO_FEATURE_SIG_P384").is_ok(); let sig_ed25519 = env::var("CARGO_FEATURE_SIG_ED25519").is_ok(); let overwrite_only = env::var("CARGO_FEATURE_OVERWRITE_ONLY").is_ok(); let swap_move = env::var("CARGO_FEATURE_SWAP_MOVE").is_ok(); @@ -205,6 +207,24 @@ fn main() { conf.file("../../ext/mbedtls/library/ecp_curves.c"); conf.file("../../ext/mbedtls/library/platform.c"); conf.file("../../ext/mbedtls/library/platform_util.c"); + } else if sig_ecdsa_psa { + conf.conf.include("../../ext/mbedtls/include"); + + if sig_p384 { + conf.conf.define("MCUBOOT_SIGN_EC384", None); + conf.file("../../ext/mbedtls/library/sha512.c"); + } else { + conf.conf.define("MCUBOOT_SIGN_EC256", None); + conf.file("../../ext/mbedtls/library/sha256.c"); + } + + conf.file("csupport/keys.c"); + conf.file("../../ext/mbedtls/library/asn1parse.c"); + conf.file("../../ext/mbedtls/library/bignum.c"); + conf.file("../../ext/mbedtls/library/ecp.c"); + conf.file("../../ext/mbedtls/library/ecp_curves.c"); + conf.file("../../ext/mbedtls/library/platform.c"); + conf.file("../../ext/mbedtls/library/platform_util.c"); } else if sig_ed25519 { conf.conf.define("MCUBOOT_SIGN_ED25519", None); conf.conf.define("MCUBOOT_USE_TINYCRYPT", None); @@ -421,17 +441,19 @@ fn main() { conf.conf.define("MBEDTLS_CONFIG_FILE", Some("")); } else if enc_aes256_x25519 { conf.conf.define("MBEDTLS_CONFIG_FILE", Some("")); + } else if sig_ecdsa_psa { + conf.conf.define("MBEDTLS_CONFIG_FILE", Some("")); } conf.file("../../boot/bootutil/src/image_validate.c"); if sig_rsa || sig_rsa3072 { conf.file("../../boot/bootutil/src/image_rsa.c"); - } else if sig_ecdsa || sig_ecdsa_mbedtls { - conf.conf.include("../../ext/mbedtls/include"); + } else if sig_ecdsa || sig_ecdsa_mbedtls || sig_ecdsa_psa { conf.file("../../boot/bootutil/src/image_ecdsa.c"); } else if sig_ed25519 { conf.file("../../boot/bootutil/src/image_ed25519.c"); } + conf.file("../../boot/bootutil/src/loader.c"); conf.file("../../boot/bootutil/src/swap_misc.c"); conf.file("../../boot/bootutil/src/swap_scratch.c"); diff --git a/sim/mcuboot-sys/csupport/config-ec-psa.h b/sim/mcuboot-sys/csupport/config-ec-psa.h new file mode 100644 index 000000000..709330ff8 --- /dev/null +++ b/sim/mcuboot-sys/csupport/config-ec-psa.h @@ -0,0 +1,37 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 Arm Limited + */ + +#ifndef MCUBOOT_PSA_CRYPTO_CONFIG_ECDSA +#define MCUBOOT_PSA_CRYPTO_CONFIG_ECDSA + +#if defined(MCUBOOT_USE_PSA_CRYPTO) +#include "config-add-psa-crypto.h" +#endif + +#define MBEDTLS_ECP_C +#define MBEDTLS_ECP_NIST_OPTIM +#define MBEDTLS_ECDSA_C + +/* mbed TLS modules */ +#define MBEDTLS_ASN1_PARSE_C +#define MBEDTLS_ASN1_WRITE_C +#define MBEDTLS_AES_C +#define MBEDTLS_BIGNUM_C +#define MBEDTLS_MD_C +#define MBEDTLS_OID_C +#if defined(MCUBOOT_SIGN_EC384) +#define MBEDTLS_SHA384_C +#define MBEDTLS_SHA512_C +#define MBEDTLS_ECP_DP_SECP384R1_ENABLED +#else +#define MBEDTLS_SHA256_C +#define MBEDTLS_SHA224_C +#define MBEDTLS_ECP_DP_SECP256R1_ENABLED +#endif /* MCUBOOT_SIGN_EC384 */ + +#include "mbedtls/check_config.h" + +#endif /* MCUBOOT_PSA_CRYPTO_CONFIG_ECDSA */ diff --git a/sim/mcuboot-sys/csupport/keys.c b/sim/mcuboot-sys/csupport/keys.c index f9325be45..82a746ba0 100644 --- a/sim/mcuboot-sys/csupport/keys.c +++ b/sim/mcuboot-sys/csupport/keys.c @@ -106,8 +106,10 @@ const unsigned char root_pub_der[] = { }; const unsigned int root_pub_der_len = 398; #endif -#elif defined(MCUBOOT_SIGN_EC256) +#elif defined(MCUBOOT_SIGN_EC256) || \ + defined(MCUBOOT_SIGN_EC384) #define HAVE_KEYS +#ifndef MCUBOOT_SIGN_EC384 const unsigned char root_pub_der[] = { 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, @@ -122,6 +124,26 @@ const unsigned char root_pub_der[] = { 0x8b, 0x68, 0x34, 0xcc, 0x3a, 0x6a, 0xfc, 0x53, 0x8e, 0xfa, 0xc1, }; const unsigned int root_pub_der_len = 91; +#else /* MCUBOOT_SIGN_EC384 */ +const unsigned char root_pub_der[] = { + 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, + 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, + 0x81, 0x04, 0x00, 0x22, 0x03, 0x62, 0x00, 0x04, + 0x0c, 0x76, 0xca, 0xae, 0x72, 0x3a, 0xa5, 0xe8, + 0xf0, 0xd4, 0xf1, 0x16, 0xb5, 0x02, 0xef, 0x77, + 0xa1, 0x1b, 0x93, 0x61, 0x78, 0xc0, 0x09, 0x26, + 0x7b, 0x3b, 0x40, 0x9c, 0xee, 0x49, 0x85, 0xe0, + 0xc9, 0x4f, 0xe7, 0xf2, 0xba, 0x97, 0x6c, 0xf3, + 0x82, 0x65, 0x14, 0x2c, 0xf5, 0x0c, 0x73, 0x33, + 0x4d, 0x32, 0xe7, 0x9b, 0xd3, 0x42, 0xcc, 0x95, + 0x5a, 0xe5, 0xe2, 0xf5, 0xf4, 0x6e, 0x45, 0xe0, + 0xed, 0x20, 0x35, 0x5c, 0xaf, 0x52, 0x35, 0x81, + 0xd4, 0xdc, 0x9c, 0xe3, 0x9e, 0x22, 0x3e, 0xfb, + 0x3f, 0x22, 0x10, 0xda, 0x70, 0x03, 0x37, 0xad, + 0xa8, 0xf2, 0x48, 0xfe, 0x3a, 0x60, 0x69, 0xa5, +}; +const unsigned int root_pub_der_len = 120; +#endif /* MCUBOOT_SIGN_EC384 */ #elif defined(MCUBOOT_SIGN_ED25519) #define HAVE_KEYS const unsigned char root_pub_der[] = { diff --git a/sim/src/caps.rs b/sim/src/caps.rs index 54631730c..d8dd068ec 100644 --- a/sim/src/caps.rs +++ b/sim/src/caps.rs @@ -29,6 +29,7 @@ pub enum Caps { RamLoad = (1 << 16), DirectXip = (1 << 17), HwRollbackProtection = (1 << 18), + EcdsaP384 = (1 << 19), } impl Caps { @@ -39,7 +40,7 @@ impl Caps { /// Does this build have ECDSA of some type enabled for signatures. pub fn has_ecdsa() -> bool { - Caps::EcdsaP256.present() + Caps::EcdsaP256.present() || Caps::EcdsaP384.present() } /// Query for the number of images that have been configured into this diff --git a/sim/src/ecdsa_pub_key-rs.txt b/sim/src/ecdsa_pub_key-rs.txt index e3a0cc1af..3d8643674 100644 --- a/sim/src/ecdsa_pub_key-rs.txt +++ b/sim/src/ecdsa_pub_key-rs.txt @@ -12,3 +12,21 @@ static ECDSA256_PUB_KEY: &[u8] = &[ 0x8b, 0x68, 0x34, 0xcc, 0x3a, 0x6a, 0xfc, 0x53, 0x8e, 0xfa, 0xc1, ]; + +static ECDSAP384_PUB_KEY: &[u8] = &[ + 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, + 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, + 0x81, 0x04, 0x00, 0x22, 0x03, 0x62, 0x00, 0x04, + 0x0c, 0x76, 0xca, 0xae, 0x72, 0x3a, 0xa5, 0xe8, + 0xf0, 0xd4, 0xf1, 0x16, 0xb5, 0x02, 0xef, 0x77, + 0xa1, 0x1b, 0x93, 0x61, 0x78, 0xc0, 0x09, 0x26, + 0x7b, 0x3b, 0x40, 0x9c, 0xee, 0x49, 0x85, 0xe0, + 0xc9, 0x4f, 0xe7, 0xf2, 0xba, 0x97, 0x6c, 0xf3, + 0x82, 0x65, 0x14, 0x2c, 0xf5, 0x0c, 0x73, 0x33, + 0x4d, 0x32, 0xe7, 0x9b, 0xd3, 0x42, 0xcc, 0x95, + 0x5a, 0xe5, 0xe2, 0xf5, 0xf4, 0x6e, 0x45, 0xe0, + 0xed, 0x20, 0x35, 0x5c, 0xaf, 0x52, 0x35, 0x81, + 0xd4, 0xdc, 0x9c, 0xe3, 0x9e, 0x22, 0x3e, 0xfb, + 0x3f, 0x22, 0x10, 0xda, 0x70, 0x03, 0x37, 0xad, + 0xa8, 0xf2, 0x48, 0xfe, 0x3a, 0x60, 0x69, 0xa5, +]; diff --git a/sim/src/image.rs b/sim/src/image.rs index 54e4f31b0..632dfa568 100644 --- a/sim/src/image.rs +++ b/sim/src/image.rs @@ -1999,7 +1999,7 @@ fn make_tlv() -> TlvGen { TlvGen::new_rsa_pss() } else if Caps::RSA3072.present() { TlvGen::new_rsa3072_pss() - } else if Caps::EcdsaP256.present() { + } else if Caps::EcdsaP256.present() || Caps::EcdsaP384.present() { TlvGen::new_ecdsa() } else if Caps::Ed25519.present() { TlvGen::new_ed25519() diff --git a/sim/src/tlv.rs b/sim/src/tlv.rs index 5541f112b..ce6876e9d 100644 --- a/sim/src/tlv.rs +++ b/sim/src/tlv.rs @@ -29,6 +29,7 @@ use ring::signature::{ EcdsaKeyPair, ECDSA_P256_SHA256_ASN1_SIGNING, Ed25519KeyPair, + ECDSA_P384_SHA384_ASN1_SIGNING, }; use aes::{ Aes128, @@ -50,6 +51,7 @@ use typenum::{U16, U32}; pub enum TlvKinds { KEYHASH = 0x01, SHA256 = 0x10, + SHA384 = 0x11, RSA2048 = 0x20, ECDSASIG = 0x22, RSA3072 = 0x23, @@ -166,8 +168,13 @@ impl TlvGen { #[allow(dead_code)] pub fn new_ecdsa() -> TlvGen { + let hash_kind = if cfg!(feature = "sig-p384") { + TlvKinds::SHA384 + } else { + TlvKinds::SHA256 + }; TlvGen { - kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSASIG], + kinds: vec![hash_kind, TlvKinds::ECDSASIG], ..Default::default() } } @@ -369,6 +376,8 @@ impl ManifestGen for TlvGen { // Estimate the size of the image hash. if self.kinds.contains(&TlvKinds::SHA256) { estimate += 4 + 32; + } else if self.kinds.contains(&TlvKinds::SHA384) { + estimate += 4 + 48; } // Add an estimate in for each of the signature algorithms. @@ -385,12 +394,17 @@ impl ManifestGen for TlvGen { estimate += 4 + 64; // ED25519 signature. } if self.kinds.contains(&TlvKinds::ECDSASIG) { - estimate += 4 + 32; // keyhash - - // ECDSA signatures are encoded as ASN.1 with the x and y values stored as signed - // integers. As such, the size can vary by 2 bytes, if the 256-bit value has the high - // bit, it takes an extra 0 byte to avoid it being seen as a negative number. - estimate += 4 + 72; // ECDSA256 (varies) + // ECDSA signatures are encoded as ASN.1 with the x and y values + // stored as signed integers. As such, the size can vary by 2 bytes, + // if for example the 256-bit value has the high bit, it takes an + // extra 0 byte to avoid it being seen as a negative number. + if self.kinds.contains(&TlvKinds::SHA384) { + estimate += 4 + 48; // SHA384 + estimate += 4 + 104; // ECDSA384 (varies) + } else { + estimate += 4 + 32; // SHA256 + estimate += 4 + 72; // ECDSA256 (varies) + } } // Estimate encryption. @@ -473,7 +487,7 @@ impl ManifestGen for TlvGen { // Placeholder for the size. result.write_u16::(0).unwrap(); - if self.kinds.contains(&TlvKinds::SHA256) { + if self.kinds.iter().any(|v| v == &TlvKinds::SHA256 || v == &TlvKinds::SHA384) { // If a signature is not requested, corrupt the hash we are // generating. But, if there is a signature, output the // correct hash. We want the hash test to pass so that the @@ -491,13 +505,20 @@ impl ManifestGen for TlvGen { if corrupt_hash { sig_payload[0] ^= 1; } - - let hash = digest::digest(&digest::SHA256, &sig_payload); + let (hash,hash_size,tlv_kind) = if self.kinds.contains(&TlvKinds::SHA256) + { + let hash = digest::digest(&digest::SHA256, &sig_payload); + (hash,32,TlvKinds::SHA256) + } + else { + let hash = digest::digest(&digest::SHA384, &sig_payload); + (hash,48,TlvKinds::SHA384) + }; let hash = hash.as_ref(); - assert!(hash.len() == 32); - result.write_u16::(TlvKinds::SHA256 as u16).unwrap(); - result.write_u16::(32).unwrap(); + assert!(hash.len() == hash_size); + result.write_u16::(tlv_kind as u16).unwrap(); + result.write_u16::(hash_size as u16).unwrap(); result.extend_from_slice(hash); // Undo the corruption. @@ -559,17 +580,25 @@ impl ManifestGen for TlvGen { if self.kinds.contains(&TlvKinds::ECDSASIG) { let rng = rand::SystemRandom::new(); - let keyhash = digest::digest(&digest::SHA256, ECDSA256_PUB_KEY); - let key_bytes = pem::parse(include_bytes!("../../root-ec-p256-pkcs8.pem").as_ref()).unwrap(); - let sign_algo = &ECDSA_P256_SHA256_ASN1_SIGNING; - let key_pair = EcdsaKeyPair::from_pkcs8(sign_algo, &key_bytes.contents).unwrap(); - let signature = key_pair.sign(&rng,&sig_payload).unwrap(); + let (signature, keyhash, keyhash_size) = if self.kinds.contains(&TlvKinds::SHA384) { + let keyhash = digest::digest(&digest::SHA384, ECDSAP384_PUB_KEY); + let key_bytes = pem::parse(include_bytes!("../../root-ec-p384-pkcs8.pem").as_ref()).unwrap(); + let sign_algo = &ECDSA_P384_SHA384_ASN1_SIGNING; + let key_pair = EcdsaKeyPair::from_pkcs8(sign_algo, &key_bytes.contents).unwrap(); + (key_pair.sign(&rng, &sig_payload).unwrap(), keyhash, 48) + } else { + let keyhash = digest::digest(&digest::SHA256, ECDSA256_PUB_KEY); + let key_bytes = pem::parse(include_bytes!("../../root-ec-p256-pkcs8.pem").as_ref()).unwrap(); + let sign_algo = &ECDSA_P256_SHA256_ASN1_SIGNING; + let key_pair = EcdsaKeyPair::from_pkcs8(sign_algo, &key_bytes.contents).unwrap(); + (key_pair.sign(&rng, &sig_payload).unwrap(), keyhash, 32) + }; // Write public key let keyhash_slice = keyhash.as_ref(); - assert!(keyhash_slice.len() == 32); + assert!(keyhash_slice.len() == keyhash_size); result.write_u16::(TlvKinds::KEYHASH as u16).unwrap(); - result.write_u16::(32).unwrap(); + result.write_u16::(keyhash_size as u16).unwrap(); result.extend_from_slice(keyhash_slice); // Write signature @@ -578,6 +607,7 @@ impl ManifestGen for TlvGen { result.write_u16::(signature.len() as u16).unwrap(); result.extend_from_slice(&signature); } + if self.kinds.contains(&TlvKinds::ED25519) { let keyhash = digest::digest(&digest::SHA256, ED25519_PUB_KEY); let keyhash = keyhash.as_ref();