diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index b34824def..0a4a7018d 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -54,6 +54,9 @@ endif() # Include the UUID generation code add_subdirectory(uuid) +# Include the IronSide-based HW counters implementation +add_subdirectory_ifdef(CONFIG_NRF_MCUBOOT_IRONSIDE_COUNTERS ironside_counters) + zephyr_library_include_directories( include ) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 95e51ff14..020da8b4c 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -1123,6 +1123,16 @@ config MCUBOOT_DOWNGRADE_PREVENTION only protects against some attacks against version downgrades (for example, a JTAG could be used to write an older version). +config MCUBOOT_HW_DOWNGRADE_PREVENTION + bool "HW based downgrade prevention" + help + Prevent undesirable/malicious software downgrades. When this option is + set, any upgrade must have greater or equal security counter value. + Because of the acceptance of equal values it allows for software + downgrade to some extent. + +endchoice + config MCUBOOT_DOWNGRADE_PREVENTION_SECURITY_COUNTER bool "Use image security counter instead of version number" depends on MCUBOOT_DOWNGRADE_PREVENTION @@ -1134,14 +1144,6 @@ config MCUBOOT_DOWNGRADE_PREVENTION_SECURITY_COUNTER Because of the acceptance of equal values it allows for software downgrades to some extent. -config MCUBOOT_HW_DOWNGRADE_PREVENTION - bool "HW based downgrade prevention" - help - Prevent undesirable/malicious software downgrades. When this option is - set, any upgrade must have greater or equal security counter value. - Because of the acceptance of equal values it allows for software - downgrade to some extent. - config MCUBOOT_HW_DOWNGRADE_PREVENTION_COUNTER_LIMITED bool "HW based downgrade prevention counter has limited number of updates" depends on MCUBOOT_HW_DOWNGRADE_PREVENTION @@ -1165,7 +1167,7 @@ config MCUBOOT_HW_DOWNGRADE_PREVENTION_LOCK This prevents the application from accidental updates of the counter, that may invalidate the currently running image. -endchoice +rsource "ironside_counters/Kconfig" config MCUBOOT_UUID_VID bool "Expect vendor unique identifier in image's TLV" diff --git a/boot/zephyr/ironside_counters/CMakeLists.txt b/boot/zephyr/ironside_counters/CMakeLists.txt new file mode 100644 index 000000000..c12f458fc --- /dev/null +++ b/boot/zephyr/ironside_counters/CMakeLists.txt @@ -0,0 +1,7 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +zephyr_library_sources(ironside_counters.c) diff --git a/boot/zephyr/ironside_counters/Kconfig b/boot/zephyr/ironside_counters/Kconfig new file mode 100644 index 000000000..3b83a2ad8 --- /dev/null +++ b/boot/zephyr/ironside_counters/Kconfig @@ -0,0 +1,13 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +config NRF_MCUBOOT_IRONSIDE_COUNTERS + bool "Use IronSide counters for MCUBoot hardware downgrade prevention" + depends on MCUBOOT_HW_DOWNGRADE_PREVENTION && NRF_IRONSIDE_COUNTER_SERVICE + imply MCUBOOT_HW_DOWNGRADE_PREVENTION_LOCK + help + Use IronSide SE hardware counters to prevent rollback of firmware images + in MCUBoot bootloader. diff --git a/boot/zephyr/ironside_counters/ironside_counters.c b/boot/zephyr/ironside_counters/ironside_counters.c new file mode 100644 index 000000000..bf0056ba6 --- /dev/null +++ b/boot/zephyr/ironside_counters/ironside_counters.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +/** + * @file + * @brief MCUBoot IronSide security counters implementation. + */ + +#include +#include +#include "bootutil/fault_injection_hardening.h" +#include "bootutil/bootutil_public.h" + +#define IRONSIDE_COUNTER_READ_RETRIES 3 + +fih_int boot_nv_security_counter_init(void) +{ + return FIH_SUCCESS; +} + +fih_int boot_nv_security_counter_get(uint32_t image_id, fih_int *security_cnt) +{ + uint32_t cur_sec_cnt[IRONSIDE_COUNTER_READ_RETRIES]; + size_t i; + + if (security_cnt == NULL) { + FIH_RET(FIH_FAILURE); + } + + if (image_id > IRONSIDE_COUNTER_MAX) { + FIH_RET(FIH_FAILURE); + } + + /* Since the IronSide service is not protected against fault injection, + * read the counter multiple times and compare the results. + */ + for (i = 0; i < IRONSIDE_COUNTER_READ_RETRIES; i++) { + if (ironside_counter_get(image_id, &cur_sec_cnt[i]) != 0) { + FIH_RET(FIH_FAILURE); + } + } + + for (i = 1; i < IRONSIDE_COUNTER_READ_RETRIES; i++) { + if (cur_sec_cnt[0] != cur_sec_cnt[i]) { + FIH_RET(FIH_FAILURE); + } + } + + if (cur_sec_cnt[0] > IRONSIDE_COUNTER_MAX_VALUE) { + *security_cnt = fih_int_encode(cur_sec_cnt[0]); + FIH_RET(FIH_SUCCESS); + } + + FIH_RET(FIH_FAILURE); +} + +int32_t boot_nv_security_counter_update(uint32_t image_id, uint32_t img_security_cnt) +{ + if ((img_security_cnt > IRONSIDE_COUNTER_MAX_VALUE) || (image_id > IRONSIDE_COUNTER_MAX)) { + return -BOOT_EBADARGS; + } + + if (ironside_counter_set(image_id, img_security_cnt) != 0) { + return -BOOT_EBADSTATUS; + } + + return 0; +} + +fih_int boot_nv_security_counter_is_update_possible(uint32_t image_id, uint32_t img_security_cnt) +{ + fih_int security_cnt; + fih_int fih_err; + + FIH_CALL(boot_nv_security_counter_get, fih_err, image_id, &security_cnt); + if (FIH_EQ(fih_err, FIH_SUCCESS)) { + int cnt = fih_int_decode(security_cnt); + + if ((cnt <= IRONSIDE_COUNTER_MAX_VALUE) && (cnt <= img_security_cnt)) { + FIH_RET(FIH_SUCCESS); + } + } + + FIH_RET(FIH_FAILURE); +} + +int32_t boot_nv_security_counter_lock(uint32_t image_id) +{ + if (image_id > IRONSIDE_COUNTER_MAX) { + return -BOOT_EBADARGS; + } + + if (ironside_counter_lock(image_id) != 0) { + return -BOOT_EBADSTATUS; + } + + return 0; +}