Skip to content

Commit 6a51d79

Browse files
committed
bootloader: Add support for IronSide counters
Add an implementation of HW rollback prevention, based on the IronSide secure counters service. Ref: NCSDK-36295 Signed-off-by: Tomasz Chyrwicz <[email protected]>
1 parent 26ce7e6 commit 6a51d79

File tree

5 files changed

+133
-0
lines changed

5 files changed

+133
-0
lines changed

subsys/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ add_subdirectory_ifdef(CONFIG_IS_SECURE_BOOTLOADER bootloader)
1010
add_subdirectory_ifdef(CONFIG_SECURE_BOOT_CRYPTO bootloader/bl_crypto)
1111
add_subdirectory_ifdef(CONFIG_SECURE_BOOT_VALIDATION bootloader/bl_validation)
1212
add_subdirectory_ifdef(CONFIG_SECURE_BOOT_STORAGE bootloader/bl_storage)
13+
add_subdirectory_ifdef(CONFIG_NRF_MCUBOOT_IRONSIDE_COUNTERS bootloader/ironside_counters)
1314

1415
add_subdirectory_ifdef(CONFIG_NRF_SECURITY nrf_security)
1516
add_subdirectory_ifdef(CONFIG_TRUSTED_STORAGE trusted_storage)

subsys/bootloader/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,4 +188,6 @@ config NCS_MCUBOOT_BOOTLOADER_SIGN_MERGED_BINARY
188188
help
189189
This is a Kconfig which is informative only, the value should not be changed.
190190

191+
rsource "ironside_counters/Kconfig"
192+
191193
endmenu
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#
2+
# Copyright (c) 2025 Nordic Semiconductor ASA
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
7+
if(CONFIG_NRF_MCUBOOT_IRONSIDE_COUNTERS)
8+
zephyr_library()
9+
zephyr_library_sources(ironside_counters.c)
10+
endif()
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#
2+
# Copyright (c) 2025 Nordic Semiconductor ASA
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
7+
config NRF_MCUBOOT_IRONSIDE_COUNTERS
8+
bool "Use IRonSide counters for MCUBoot hardware downgrade prevention"
9+
depends on MCUBOOT_HW_DOWNGRADE_PREVENTION && NRF_IRONSIDE_COUNTER_SERVICE
10+
imply MCUBOOT_HW_DOWNGRADE_PREVENTION_LOCK
11+
help
12+
Use IronSide SE hardware counters to prevent rollback of firmware images
13+
in MCUBoot bootloader.
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
*/
6+
7+
/**
8+
* @file
9+
* @brief MCUBoot IronSide security counters implementation.
10+
*/
11+
12+
#include <stdint.h>
13+
#include <nrf_ironside/counter.h>
14+
#include "bootutil/fault_injection_hardening.h"
15+
#include "bootutil/bootutil_public.h"
16+
17+
#define IRONSIDE_COUNTER_READ_RETRIES 3
18+
19+
fih_int boot_nv_security_counter_init(void)
20+
{
21+
return FIH_SUCCESS;
22+
}
23+
24+
fih_int boot_nv_security_counter_get(uint32_t image_id, fih_int *security_cnt)
25+
{
26+
uint32_t cur_sec_cnt[IRONSIDE_COUNTER_READ_RETRIES];
27+
size_t i;
28+
int err;
29+
30+
if (security_cnt == NULL) {
31+
FIH_RET(FIH_FAILURE);
32+
}
33+
34+
if (image_id > IRONSIDE_COUNTER_MAX) {
35+
FIH_RET(FIH_FAILURE);
36+
}
37+
38+
/* Since the IronSide service is not protected against fault injection,
39+
* read the counter multiple times and compare the results.
40+
*/
41+
for (i = 0; i < IRONSIDE_COUNTER_READ_RETRIES; i++) {
42+
err = ironside_counter_get(image_id, &cur_sec_cnt[i]);
43+
if (err != 0) {
44+
FIH_RET(FIH_FAILURE);
45+
}
46+
}
47+
48+
for (i = 1; i < IRONSIDE_COUNTER_READ_RETRIES; i++) {
49+
if (cur_sec_cnt[0] != cur_sec_cnt[i]) {
50+
FIH_RET(FIH_FAILURE);
51+
}
52+
}
53+
54+
if (cur_sec_cnt[0] != IRONSIDE_COUNTER_MAX_VALUE) {
55+
*security_cnt = fih_int_encode(cur_sec_cnt[0]);
56+
FIH_RET(FIH_SUCCESS);
57+
}
58+
59+
FIH_RET(FIH_FAILURE);
60+
}
61+
62+
int32_t boot_nv_security_counter_update(uint32_t image_id, uint32_t img_security_cnt)
63+
{
64+
int err;
65+
66+
if ((img_security_cnt > IRONSIDE_COUNTER_MAX_VALUE) || (image_id > IRONSIDE_COUNTER_MAX)) {
67+
return -BOOT_EBADARGS;
68+
}
69+
70+
err = ironside_counter_set(image_id, img_security_cnt);
71+
72+
return err == 0 ? 0 : -BOOT_EBADSTATUS;
73+
}
74+
75+
fih_int boot_nv_security_counter_is_update_possible(uint32_t image_id, uint32_t img_security_cnt)
76+
{
77+
fih_int security_cnt;
78+
fih_int fih_err;
79+
80+
FIH_CALL(boot_nv_security_counter_get, fih_err, image_id, &security_cnt);
81+
if (FIH_NOT_EQ(fih_err, FIH_SUCCESS)) {
82+
FIH_RET(FIH_FAILURE);
83+
}
84+
85+
if (fih_int_decode(security_cnt) == IRONSIDE_COUNTER_MAX_VALUE) {
86+
FIH_RET(FIH_FAILURE);
87+
}
88+
89+
if (fih_int_decode(security_cnt) <= img_security_cnt) {
90+
FIH_RET(FIH_SUCCESS);
91+
}
92+
93+
FIH_RET(FIH_FAILURE);
94+
}
95+
96+
int32_t boot_nv_security_counter_lock(uint32_t image_id)
97+
{
98+
int err;
99+
100+
if (image_id > IRONSIDE_COUNTER_MAX) {
101+
return -BOOT_EBADARGS;
102+
}
103+
104+
err = ironside_counter_lock(image_id);
105+
106+
return err == 0 ? 0 : -BOOT_EBADSTATUS;
107+
}

0 commit comments

Comments
 (0)