diff --git a/cmake/sysbuild/provision_hex.cmake b/cmake/sysbuild/provision_hex.cmake index d8002fc33a42..ef2570ab1e7b 100644 --- a/cmake/sysbuild/provision_hex.cmake +++ b/cmake/sysbuild/provision_hex.cmake @@ -10,7 +10,7 @@ include(${CMAKE_CURRENT_LIST_DIR}/sign.cmake) include(${CMAKE_CURRENT_LIST_DIR}/debug_keys.cmake) -function(provision application prefix_name) +function(provision application prefix_name mcuboot_downgrade_protection) ExternalProject_Get_Property(${application} BINARY_DIR) import_kconfig(CONFIG_ ${BINARY_DIR}/zephyr/.config) @@ -64,13 +64,9 @@ function(provision application prefix_name) # Adjustment to be able to load into sysbuild if(CONFIG_SOC_NRF5340_CPUNET OR "${domain}" STREQUAL "CPUNET") set(partition_manager_target partition_manager_CPUNET) - set(s0_arg --s0-addr $) - set(s1_arg) set(cpunet_target y) else() set(partition_manager_target partition_manager) - set(s0_arg --s0-addr $) - set(s1_arg --s1-addr $) set(cpunet_target n) endif() @@ -84,7 +80,7 @@ function(provision application prefix_name) endif() endif() - if(SB_CONFIG_MCUBOOT_HARDWARE_DOWNGRADE_PREVENTION) + if(mcuboot_downgrade_protection AND SB_CONFIG_MCUBOOT_HARDWARE_DOWNGRADE_PREVENTION) set(mcuboot_counters_slots --mcuboot-counters-slots ${SB_CONFIG_MCUBOOT_HW_DOWNGRADE_PREVENTION_COUNTER_SLOTS}) endif() @@ -99,8 +95,6 @@ function(provision application prefix_name) COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_NRF_MODULE_DIR}/scripts/bootloader/provision.py - ${s0_arg} - ${s1_arg} --provision-addr $ ${public_keys_file_arg} --output ${PROVISION_HEX} @@ -119,7 +113,8 @@ function(provision application prefix_name) "Creating data to be provisioned to the Bootloader, storing to ${PROVISION_HEX_NAME}" USES_TERMINAL ) - elseif(SB_CONFIG_MCUBOOT_HARDWARE_DOWNGRADE_PREVENTION) + elseif(mcuboot_downgrade_protection) +# elseif(SB_CONFIG_MCUBOOT_HARDWARE_DOWNGRADE_PREVENTION) add_custom_command( OUTPUT ${PROVISION_HEX} @@ -179,12 +174,12 @@ if(NCS_SYSBUILD_PARTITION_MANAGER) # Get the main app of the domain that secure boot should handle. if(SB_CONFIG_SECURE_BOOT AND SB_CONFIG_SECURE_BOOT_APPCORE) if(SB_CONFIG_BOOTLOADER_MCUBOOT) - provision("mcuboot" "app_") + provision("mcuboot" "app_" y) else() - provision("${DEFAULT_IMAGE}" "app_") + provision("${DEFAULT_IMAGE}" "app_" n) endif() elseif(SB_CONFIG_MCUBOOT_HARDWARE_DOWNGRADE_PREVENTION) - provision("${DEFAULT_IMAGE}" "app_") + provision("${DEFAULT_IMAGE}" "app_" y) endif() if(SB_CONFIG_SECURE_BOOT_NETCORE) @@ -195,6 +190,6 @@ if(NCS_SYSBUILD_PARTITION_MANAGER) " but no image is selected for this domain.") endif() - provision("${main_app}" "net_") + provision("${main_app}" "net_" n) endif() endif() diff --git a/include/bl_storage.h b/include/bl_storage.h index 1a9c26657afc..77d91e7b716f 100644 --- a/include/bl_storage.h +++ b/include/bl_storage.h @@ -39,25 +39,27 @@ typedef uint32_t lcs_reserved_t; #define EHASHFF 113 /* A hash contains too many 0xFs. */ #define EREADLCS 114 /* LCS field of OTP is in an invalid state */ -#define EINVALIDLCS 115 /* Invalid LCS*/ +#define EINVALIDLCS 115 /* Invalid LCS */ /* We truncate the 32 byte sha256 down to 16 bytes before storing it */ #define SB_PUBLIC_KEY_HASH_LEN 16 /* Supported collection types. */ enum collection_type { - BL_COLLECTION_TYPE_MONOTONIC_COUNTERS = 1, - BL_COLLECTION_TYPE_VARIABLE_DATA = 0x9312, -}; + /** Counter used by NSIB to check the firmware version. */ + BL_MONOTONIC_COUNTERS_DESC_NSIB = 0, -/* Counter used by NSIB to check the firmware version */ -#define BL_MONOTONIC_COUNTERS_DESC_NSIB 0x1 + /** + * Counter used by MCUBOOT to check the firmware version. Suffixed with ID0 as we might + * support checking the version of multiple images in the future. + */ + BL_MONOTONIC_COUNTERS_DESC_MCUBOOT_ID0, -/* Counter used by MCUBOOT to check the firmware version. Suffixed - * with ID0 as we might support checking the version of multiple - * images in the future. - */ -#define BL_MONOTONIC_COUNTERS_DESC_MCUBOOT_ID0 0x2 + /** Variable data #variable_data_type. */ + BL_VARIABLE_DATA, +}; + +#define BL_COLLECTION_TYPE_VARIABLE_DATA 0x9312 /** Storage for the PRoT Security Lifecycle state, that consists of 4 states: * - Device assembly and test @@ -81,42 +83,11 @@ struct life_cycle_state_data { lcs_data_t decommissioned; }; -/** This library implements monotonic counters where each time the counter - * is increased, a new slot is written. - * This way, the counter can be updated without erase. This is, among other things, - * necessary so the counter can be used in the OTP section of the UICR - * (available on e.g. nRF91 and nRF53). - */ -struct monotonic_counter { - /* Counter description. What the counter is used for. See - * BL_MONOTONIC_COUNTERS_DESC_x. - */ - uint16_t description; - /* Number of entries in 'counter_slots' list. */ - uint16_t num_counter_slots; - counter_t counter_slots[]; -}; - -/** Common part for all collections. */ -struct collection { - uint16_t type; - uint16_t count; -}; - -/** The second data structure in the provision page. It has unknown length since - * 'counters' is repeated. Note that each entry in counters also has unknown - * length, and each entry can have different length from the others, so the - * entries beyond the first cannot be accessed through array indices. - */ -struct counter_collection { - struct collection collection; /* Type must be BL_COLLECTION_TYPE_MONOTONIC_COUNTERS */ - struct monotonic_counter counters[]; -}; - /* Variable data types. */ enum variable_data_type { BL_VARIABLE_DATA_TYPE_PSA_CERTIFICATION_REFERENCE = 0x1 }; + struct variable_data { uint8_t type; uint8_t length; @@ -131,7 +102,8 @@ struct variable_data { * cannot be accessed through array indices. */ struct variable_data_collection { - struct collection collection; /* Type must be BL_COLLECTION_TYPE_VARIABLE_DATA */ + uint16_t magic; + uint16_t count; struct variable_data variable_data[]; }; @@ -143,8 +115,6 @@ struct bl_storage_data { /* NB: When placed in OTP, reads must be 4 bytes and 4 byte aligned */ struct life_cycle_state_data lcs; uint8_t implementation_id[32]; - uint32_t s0_address; - uint32_t s1_address; uint32_t num_public_keys; /* Number of entries in 'key_data' list. */ struct { uint32_t valid; @@ -152,24 +122,16 @@ struct bl_storage_data { } key_data[]; /* Monotonic counter collection: - * uint16_t type; - * uint16_t count; - * struct { - * uint16_t description; - * uint16_t num_counter_slots; - * counter_t counter_slots[]; - * } counters[]; + * counter_t counter_slots[counters][slots]; */ /* Variable data collection: - * uint16_t type; * uint16_t count; * struct { * uint8_t type; * uint8_t length; * uint8_t data[]; * } variable_data[]; - * uint8_t padding[]; // Padding to align to 4 bytes */ }; diff --git a/modules/mcuboot/Kconfig b/modules/mcuboot/Kconfig index 7b40bc0f6d8c..afec984b4c8d 100644 --- a/modules/mcuboot/Kconfig +++ b/modules/mcuboot/Kconfig @@ -1,5 +1,14 @@ menu "MCUboot" +if MCUBOOT_HW_DOWNGRADE_PREVENTION + +config MCUBOOT_HW_DOWNGRADE_PREVENTION_COUNTER_SLOTS + int "Number of available hardware counter slots" + default 240 + range 2 300 + +endif # MCUBOOT_HW_DOWNGRADE_PREVENTION + if BOOTLOADER_MCUBOOT menuconfig MCUBOOT_HARDWARE_DOWNGRADE_PREVENTION diff --git a/samples/bootloader/twister/CMakeLists.txt b/samples/bootloader/twister/CMakeLists.txt new file mode 100644 index 000000000000..eea1ced07e41 --- /dev/null +++ b/samples/bootloader/twister/CMakeLists.txt @@ -0,0 +1,19 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +cmake_minimum_required(VERSION 3.20.0) + +set(APPLICATION_CONFIG_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../") + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(bootloader) + +zephyr_library_sources(../src/main.c) + +# Dummy config values due to building a proper project +zephyr_compile_definitions(CONFIG_PARTITION_MANAGER_ENABLED=y) +zephyr_compile_definitions(PM_S0_ADDRESS=0x10000) +zephyr_compile_definitions(PM_S1_ADDRESS=0x80000) diff --git a/samples/bootloader/sample.yaml b/samples/bootloader/twister/sample.yaml similarity index 100% rename from samples/bootloader/sample.yaml rename to samples/bootloader/twister/sample.yaml diff --git a/samples/nrf5340/netboot/Kconfig b/samples/nrf5340/netboot/Kconfig index 3bf61c484b86..b9eb4f9a159e 100644 --- a/samples/nrf5340/netboot/Kconfig +++ b/samples/nrf5340/netboot/Kconfig @@ -16,10 +16,10 @@ config B0N_SIZE default 0x8580 if PM_PARTITION_SIZE_PROVISION=0x280 default 0x8800 help - Since the locking granularity is 2kB, ensure that B0N_SIZE is - set such that the size of the `b0n_container` is aligned to this - size. If the minimal config is enabled the binary will be around - 5kB. Note: The provision partition is 0x280 bytes. + Since the locking granularity is 2kB, ensure that B0N_SIZE is + set such that the size of the `b0n_container` is aligned to this + size. If the minimal config is enabled the binary will be around + 5kB. Note: The provision partition is 0x280 bytes. endmenu diff --git a/samples/nrf5340/netboot/twister/CMakeLists.txt b/samples/nrf5340/netboot/twister/CMakeLists.txt new file mode 100644 index 000000000000..1f3525ad6c70 --- /dev/null +++ b/samples/nrf5340/netboot/twister/CMakeLists.txt @@ -0,0 +1,15 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +cmake_minimum_required(VERSION 3.20.0) + +set(APPLICATION_CONFIG_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../") + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(network_core_bootloader) + +zephyr_library_sources(../src/main.c) +zephyr_compile_definitions(CONFIG_PARTITION_MANAGER_ENABLED=y) diff --git a/samples/nrf5340/netboot/twister/Kconfig b/samples/nrf5340/netboot/twister/Kconfig new file mode 100644 index 000000000000..52242dc253a3 --- /dev/null +++ b/samples/nrf5340/netboot/twister/Kconfig @@ -0,0 +1,7 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +rsource "../Kconfig" diff --git a/samples/nrf5340/netboot/sample.yaml b/samples/nrf5340/netboot/twister/sample.yaml similarity index 100% rename from samples/nrf5340/netboot/sample.yaml rename to samples/nrf5340/netboot/twister/sample.yaml diff --git a/samples/nrf5340/netboot/sysbuild.conf b/samples/nrf5340/netboot/twister/sysbuild.conf similarity index 100% rename from samples/nrf5340/netboot/sysbuild.conf rename to samples/nrf5340/netboot/twister/sysbuild.conf diff --git a/scripts/bootloader/provision.py b/scripts/bootloader/provision.py index c653a3509a4f..da8db54b3ae5 100644 --- a/scripts/bootloader/provision.py +++ b/scripts/bootloader/provision.py @@ -48,17 +48,17 @@ def add_hw_counters(provision_data, num_counter_slots_version, mcuboot_counters_ assert num_counter_slots_version % 2 == 0, "--num-counters-slots-version must be an even number" assert mcuboot_counters_slots % 2 == 0, "--mcuboot-counters-slots must be an even number" - provision_data += struct.pack(' 0: - provision_data += struct.pack(' 0: - provision_data += struct.pack(' #include #include +#include + #if !defined(CONFIG_BUILD_WITH_TFM) #include #endif -#define COUNTER_DESC_VERSION 1 /* Counter description value for firmware version. */ +LOG_MODULE_REGISTER(bl_storage, CONFIG_SECURE_BOOT_STORAGE_LOG_LEVEL); +//LOG_MODULE_REGISTER(bl_storage, 4); #define ALIGN_TO_WORD(x) ((uint32_t)x & 0x3) @@ -102,15 +105,31 @@ static uint16_t bl_storage_otp_halfword_read(uint32_t address) * we read it as if it were a UICR address as it is safe (although * inefficient) to do so. */ +#if defined(CONFIG_IS_SECURE_BOOTLOADER) || defined(CONFIG_SECURE_BOOT) uint32_t s0_address_read(void) { - return bl_storage_word_read((uint32_t)&BL_STORAGE->s0_address); +#ifdef CONFIG_PARTITION_MANAGER_ENABLED +#if defined(CONFIG_SOC_NRF5340_CPUNET) + return PM_APP_ADDRESS; +#else + return PM_S0_ADDRESS; +#endif +#else +#error "Not currently supported" +#endif } +#if !defined(CONFIG_SOC_NRF5340_CPUNET) uint32_t s1_address_read(void) { - return bl_storage_word_read((uint32_t)&BL_STORAGE->s1_address); +#ifdef CONFIG_PARTITION_MANAGER_ENABLED + return PM_S1_ADDRESS; +#else +#error "Not currently supported" +#endif } +#endif +#endif uint32_t num_public_keys_read(void) { @@ -246,70 +265,64 @@ void invalidate_public_key(uint32_t key_idx) } } -static const struct collection *get_first_collection(void) +static const uint8_t *get_first_collection(void) { - return (const struct collection *)&BL_STORAGE->key_data[num_public_keys_read()]; + return (const uint8_t *)&BL_STORAGE->key_data[num_public_keys_read()]; } -static uint16_t get_collection_type(const struct collection *collection) +static const uint16_t get_collection_slots(uint16_t type) { - return bl_storage_otp_halfword_read((uint32_t)&collection->type); + switch (type) { +#if defined(CONFIG_SB_NUM_VER_COUNTER_SLOTS) && CONFIG_SB_NUM_VER_COUNTER_SLOTS > 0 + case BL_MONOTONIC_COUNTERS_DESC_NSIB: + { + return CONFIG_SB_NUM_VER_COUNTER_SLOTS; + } +#endif +#if defined(CONFIG_MCUBOOT_HW_DOWNGRADE_PREVENTION_COUNTER_SLOTS) && CONFIG_MCUBOOT_HW_DOWNGRADE_PREVENTION_COUNTER_SLOTS > 0 + case BL_MONOTONIC_COUNTERS_DESC_MCUBOOT_ID0: + { + return CONFIG_MCUBOOT_HW_DOWNGRADE_PREVENTION_COUNTER_SLOTS; + } +#endif + default: + { + return 0; + } + }; } -/** Get the counter_collection data structure in the provision data. */ -static const struct counter_collection *get_counter_collection(void) +static const uint16_t get_collection_size(uint16_t type) { - const struct collection *collection = get_first_collection(); - - return get_collection_type(collection) == BL_COLLECTION_TYPE_MONOTONIC_COUNTERS - ? (const struct counter_collection *)collection - : NULL; + return get_collection_slots(type) * sizeof(counter_t); } -/** Get one of the (possibly multiple) counters in the provision data. - * - * param[in] description Which counter to get. See COUNTER_DESC_*. - */ -static const struct monotonic_counter *get_counter_struct(uint16_t description) +/** Get the counter_collection data structure in the provision data. */ +static const uint8_t *get_counter_collection(uint16_t type) { - const struct counter_collection *counters = get_counter_collection(); + uint16_t i = 0; + const uint8_t *collection = get_first_collection(); - if (counters == NULL) { - return NULL; + while (i < type) { + collection += get_collection_size(i); + ++i; } - const struct monotonic_counter *current = counters->counters; +LOG_ERR("get_counter_collection for %d = %p", type, collection); - for (size_t i = 0; i < bl_storage_otp_halfword_read( - (uint32_t)&counters->collection.count); i++) { - uint16_t num_slots = bl_storage_otp_halfword_read( - (uint32_t)¤t->num_counter_slots); - - if (bl_storage_otp_halfword_read((uint32_t)¤t->description) == description) { - return current; - } - - current = (const struct monotonic_counter *) - ¤t->counter_slots[num_slots]; - } - return NULL; + return collection; } int num_monotonic_counter_slots(uint16_t counter_desc, uint16_t *counter_slots) { - const struct monotonic_counter *counter = get_counter_struct(counter_desc); + const uint8_t *counters = get_counter_collection(counter_desc); + const uint16_t num_slots = get_collection_slots(counter_desc); - if (counter == NULL || counter_slots == NULL) { + if (counters == NULL || counter_slots == NULL) { return -EINVAL; } - uint16_t num_slots = bl_storage_otp_halfword_read((uint32_t)&counter->num_counter_slots); - - if (num_slots == 0xFFFF) { - /* We consider the 0xFFFF as invalid since it is the default value of the OTP */ - *counter_slots = 0; - return -EINVAL; - } +LOG_ERR("slots for %d = %d", counter_desc, num_slots); *counter_slots = num_slots; return 0; @@ -327,35 +340,42 @@ int num_monotonic_counter_slots(uint16_t counter_desc, uint16_t *counter_slots) */ int get_counter(uint16_t counter_desc, counter_t *counter_value, const counter_t **free_slot) { - const counter_t *slots; counter_t highest_counter = 0; const counter_t *addr = NULL; - const struct monotonic_counter *counter_obj = get_counter_struct(counter_desc); + const uint8_t *counter_obj = get_counter_collection(counter_desc); uint16_t num_counter_slots; +LOG_ERR("counter_obj: %p, %p", counter_obj, counter_value); + if (counter_obj == NULL || counter_value == NULL) { return -EINVAL; } - slots = counter_obj->counter_slots; - num_counter_slots = bl_storage_otp_halfword_read((uint32_t)&counter_obj->num_counter_slots); + num_counter_slots = get_collection_slots(counter_desc); +LOG_ERR("slots for %d = %d", counter_desc, num_counter_slots); for (uint16_t i = 0; i < num_counter_slots; i++) { - counter_t counter = bl_storage_counter_get((uint32_t)&slots[i]); + const counter_t *slot_addr = (counter_t *)(counter_obj + (i * sizeof(counter_t))); + counter_t counter = bl_storage_counter_get((uint32_t)slot_addr); + +//LOG_ERR("read @ 0x%x = %u", slot_addr, counter); if (counter == 0) { - addr = &slots[i]; + addr = (counter_t *)slot_addr; break; } + if (highest_counter < counter) { highest_counter = counter; } } +LOG_ERR("free slot: %p, addr: %p", free_slot, addr); if (free_slot != NULL) { *free_slot = addr; } +LOG_ERR("highest count: %d", highest_counter); *counter_value = highest_counter; return 0; } @@ -503,59 +523,15 @@ void read_implementation_id_from_otp(uint8_t *buf) BL_STORAGE_IMPLEMENTATION_ID_SIZE); } -static uint32_t get_monotonic_counter_collection_size(const struct counter_collection *collection) -{ - /* Add only the constant part of the counter_collection. */ - uint32_t size = sizeof(struct collection); - uint16_t num_counters = - bl_storage_otp_halfword_read((uint32_t)&collection->collection.count); - const struct monotonic_counter *counter = collection->counters; - uint16_t num_slots; - - for (int i = 0; i < num_counters; i++) { - /* Add only the constant part of the monotonic_counter. */ - size += sizeof(struct monotonic_counter); - - num_slots = bl_storage_otp_halfword_read((uint32_t)&counter->num_counter_slots); - size += (num_slots * sizeof(counter_t)); - - /* Move to the next monotonic counter. */ - counter = (const struct monotonic_counter *)&counter->counter_slots[num_slots]; - } - - return size; -} - -static const struct variable_data_collection *get_variable_data_collection(void) -{ - /* We expect to find variable data after the monotonic counters. */ - const struct collection *collection = get_first_collection(); - - if (get_collection_type(collection) == BL_COLLECTION_TYPE_MONOTONIC_COUNTERS) { - /* Advance to next collection. */ - collection = (const struct collection *)((uint8_t *)collection + - get_monotonic_counter_collection_size( - (const struct counter_collection *) - collection)); - - /* Verify that we found variable collection. */ - return get_collection_type(collection) == BL_COLLECTION_TYPE_VARIABLE_DATA - ? (const struct variable_data_collection *)collection - : NULL; - - } else if (get_collection_type(collection) == BL_COLLECTION_TYPE_VARIABLE_DATA) { - /* Bit of a special scenario where monotonic counters are not present. */ - return (const struct variable_data_collection *)collection; - } - - return NULL; -} - int read_variable_data(enum variable_data_type data_type, uint8_t *buf, uint32_t *buf_len) { - const struct variable_data_collection *collection; + const struct variable_data_collection *collection = + (const struct variable_data_collection *)get_counter_collection( + BL_VARIABLE_DATA); +// BL_COLLECTION_TYPE_VARIABLE_DATA); const struct variable_data *variable_data; uint16_t count; + uint16_t magic; uint8_t type; uint8_t length; @@ -563,16 +539,17 @@ int read_variable_data(enum variable_data_type data_type, uint8_t *buf, uint32_t return -EINVAL; } - collection = get_variable_data_collection(); - if (collection == NULL) { - /* Variable data collection does not necessarily exist. Exit gracefully. */ - *buf_len = 0; - return 0; - } - /* Loop through all variable data entries. */ +LOG_ERR("qq"); variable_data = collection->variable_data; - count = bl_storage_otp_halfword_read((uint32_t)&collection->collection.count); + magic = bl_storage_otp_halfword_read((uint32_t)&collection->magic); + +if (magic != BL_COLLECTION_TYPE_VARIABLE_DATA) { +goto finish; +} + + count = bl_storage_otp_halfword_read((uint32_t)&collection->count); +LOG_ERR("variable_data = %p, count = %d", variable_data, count); for (int i = 0; i < count; i++) { /* Read the type and length of the variable data. */ otp_copy((uint8_t *)&type, (uint8_t *)&variable_data->type, sizeof(type)); @@ -594,6 +571,7 @@ int read_variable_data(enum variable_data_type data_type, uint8_t *buf, uint32_t (const struct variable_data *)((uint8_t *)&variable_data->data + length); } +finish: /* No matching variable data. */ *buf_len = 0; diff --git a/subsys/bootloader/bl_validation/bl_validation.c b/subsys/bootloader/bl_validation/bl_validation.c index 29c0d014f3dc..ef0aa3cd6541 100644 --- a/subsys/bootloader/bl_validation/bl_validation.c +++ b/subsys/bootloader/bl_validation/bl_validation.c @@ -53,6 +53,7 @@ int get_monotonic_version(counter_t *version_out) counter_t monotonic_version_and_slot; int err; +LOG_ERR("d1"); if (version_out == NULL) { return -EINVAL; } @@ -63,6 +64,7 @@ int get_monotonic_version(counter_t *version_out) return err; } +LOG_ERR("d4 = %d", monotonic_version_and_slot); *version_out = monotonic_version_and_slot >> 1; return err; diff --git a/sysbuild/CMakeLists.txt b/sysbuild/CMakeLists.txt index accf9d1e96c4..bc6a4fe5443c 100644 --- a/sysbuild/CMakeLists.txt +++ b/sysbuild/CMakeLists.txt @@ -420,6 +420,7 @@ function(${SYSBUILD_CURRENT_MODULE_NAME}_pre_cmake) if(SB_CONFIG_MCUBOOT_HARDWARE_DOWNGRADE_PREVENTION) set_config_bool(mcuboot CONFIG_MCUBOOT_HW_DOWNGRADE_PREVENTION y) + set_config_int(mcuboot CONFIG_MCUBOOT_HW_DOWNGRADE_PREVENTION_COUNTER_SLOTS ${SB_CONFIG_MCUBOOT_HW_DOWNGRADE_PREVENTION_COUNTER_SLOTS}) set_config_bool(mcuboot CONFIG_SECURE_BOOT_STORAGE y) set_config_bool(mcuboot CONFIG_SECURE_BOOT_CRYPTO y) else() @@ -538,6 +539,14 @@ function(${SYSBUILD_CURRENT_MODULE_NAME}_pre_cmake) set_config_bool(b0 CONFIG_SB_CRYPTO_NO_ECDSA_SECP256R1 y) endif() endif() + + # Set number of counter slots + set_config_int(b0 CONFIG_SB_NUM_VER_COUNTER_SLOTS ${SB_CONFIG_SECURE_BOOT_APPCORE_COUNTER_SLOTS}) + + if(SB_CONFIG_MCUBOOT_HARDWARE_DOWNGRADE_PREVENTION) + set_config_bool(mcuboot CONFIG_SB_MONOTONIC_COUNTER y) + set_config_int(mcuboot CONFIG_SB_NUM_VER_COUNTER_SLOTS ${SB_CONFIG_SECURE_BOOT_APPCORE_COUNTER_SLOTS}) + endif() endif() if(SB_CONFIG_SECURE_BOOT_BOOTCONF_LOCK_WRITES) @@ -570,6 +579,9 @@ function(${SYSBUILD_CURRENT_MODULE_NAME}_pre_cmake) endif() endif() + # Set number of counter slots + set_config_int(b0n CONFIG_SB_NUM_VER_COUNTER_SLOTS ${SB_CONFIG_SECURE_BOOT_NETCORE_COUNTER_SLOTS}) + if(SB_CONFIG_BOOTLOADER_MCUBOOT) if(SB_CONFIG_NETCORE_APP_UPDATE) set_config_bool(mcuboot CONFIG_PCD_APP y) diff --git a/sysbuild/Kconfig.mcuboot b/sysbuild/Kconfig.mcuboot index db00de57de3d..ff48367498e6 100644 --- a/sysbuild/Kconfig.mcuboot +++ b/sysbuild/Kconfig.mcuboot @@ -21,7 +21,6 @@ config MCUBOOT_BUILD_DIRECT_XIP_VARIANT menuconfig MCUBOOT_HARDWARE_DOWNGRADE_PREVENTION bool "Downgrade prevention using hardware security counters" depends on (SOC_NRF5340_CPUAPP || SOC_SERIES_NRF91X || SOC_SERIES_NRF54LX) - depends on !SECURE_BOOT_APPCORE depends on !QSPI_XIP_SPLIT_IMAGE help This option can be enabled by the application and will ensure that the diff --git a/sysbuild/Kconfig.secureboot b/sysbuild/Kconfig.secureboot index 5f0b30c89cde..872ade1de6e8 100644 --- a/sysbuild/Kconfig.secureboot +++ b/sysbuild/Kconfig.secureboot @@ -106,6 +106,28 @@ config SECURE_BOOT_APPCORE_SIGNATURE_TYPE_UNUSED endchoice +config SECURE_BOOT_APPCORE_COUNTER_SLOTS + int "Number of available counter slots" + default 20 if BOOTLOADER_MCUBOOT + default 240 + range 2 300 if SOC_NRF5340_CPUAPP || SOC_SERIES_NRF91X || SOC_SERIES_NRF54LX + range 2 1800 if SOC_SERIES_NRF52X + range 2 400 if SOC_SERIES_NRF51X + help + The number of monotonic counter slots available for the counter, + i.e., the number of times the counter can be updated. + The slots are 16 bits each. The number of slots must be an even + number to ensure that the total size of header and slots is aligned on a 32-bit word. + Rationale for the default number (240): Assume one update a month for + 10 years, then double that value just in case. This default fits + comfortably within the OTP region of UICR. + When a second stage bootloader is enabled, such as MCUboot, this counter is used + for the updates of the second stage bootloader and not of the application image. Thus + the default when MCUboot is enabled is 20, to allow two updates a year for 10 years. + Regarding ranges: The actual maximum depends on the number of + provisioned public keys, since they share the space. The same is true if + other data is stored in the "OTP" region (on for example nRF91 and nRF53). + endif # SECURE_BOOT_APPCORE menuconfig SECURE_BOOT_NETCORE @@ -183,6 +205,24 @@ config SECURE_BOOT_NETCORE_SIGNATURE_TYPE_UNUSED endchoice +config SECURE_BOOT_NETCORE_COUNTER_SLOTS + int "Number of available counter slots" + default 240 + help + The number of monotonic counter slots available for the counter, + i.e., the number of times the counter can be updated. + The slots are 16 bits each. The number of slots must be an even + number to ensure that the total size of header and slots is aligned on a 32-bit word. + Rationale for the default number (240): Assume one update a month for + 10 years, then double that value just in case. This default fits + comfortably within the OTP region of UICR. + When a second stage bootloader is enabled, such as MCUboot, this counter is used + for the updates of the second stage bootloader and not of the application image. Thus + the default when MCUboot is enabled is 20, to allow two updates a year for 10 years. + Regarding ranges: The actual maximum depends on the number of + provisioned public keys, since they share the space. The same is true if + other data is stored in the "OTP" region (on for example nRF91 and nRF53). + endif # SECURE_BOOT_NETCORE if SECURE_BOOT diff --git a/west.yml b/west.yml index b1ed29b95fab..7eac434d4070 100644 --- a/west.yml +++ b/west.yml @@ -65,7 +65,7 @@ manifest: # https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/zephyr/guides/modules.html - name: zephyr repo-path: sdk-zephyr - revision: 331f27b4aa44c555882267c531c71e6d2e4b96a4 + revision: pull/3080/head import: # In addition to the zephyr repository itself, NCS also # imports the contents of zephyr/west.yml at the above