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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions boot/zephyr/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
Expand Down
20 changes: 11 additions & 9 deletions boot/zephyr/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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"
Expand Down
7 changes: 7 additions & 0 deletions boot/zephyr/ironside_counters/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#
# Copyright (c) 2025 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
#

zephyr_library_sources(ironside_counters.c)
13 changes: 13 additions & 0 deletions boot/zephyr/ironside_counters/Kconfig
Original file line number Diff line number Diff line change
@@ -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.
101 changes: 101 additions & 0 deletions boot/zephyr/ironside_counters/ironside_counters.c
Original file line number Diff line number Diff line change
@@ -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 <stdint.h>
#include <nrf_ironside/counter.h>
#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;
}