Skip to content

Commit 5b17375

Browse files
committed
test(nvs_flash): Extend the nvs_flash test app to support encrypted NVS reads
1 parent 3b7d71e commit 5b17375

13 files changed

+293
-6
lines changed

components/nvs_flash/.build-test-rules.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,10 @@ components/nvs_flash/test_apps_bootloader:
2121
- spi_flash
2222
- nvs_flash
2323
- esp_partition
24+
disable:
25+
- if: CONFIG_NAME == "nvs_enc_flash_enc" and (SOC_AES_SUPPORTED != 1 and ESP_ROM_HAS_MBEDTLS_CRYPTO_LIB != 1)
26+
- if: (CONFIG_NAME == "nvs_enc_hmac" or CONFIG_NAME == "nvs_enc_hmac_no_cfg") and (SOC_HMAC_SUPPORTED != 1 or (SOC_HMAC_SUPPORTED == 1 and (SOC_AES_SUPPORTED != 1 and ESP_ROM_HAS_MBEDTLS_CRYPTO_LIB != 1)))
27+
28+
reason: As of now in such cases, we do not have any way to perform AES operations in the bootloader build
2429
disable_test:
2530
- if: IDF_TARGET not in ["esp32", "esp32c3"]

components/nvs_flash/test_apps_bootloader/main/CMakeLists.txt

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,19 @@
1-
idf_component_register(SRCS "test_app_main.c" "test_nvs_bootloader.c"
1+
set(srcs "test_app_main.c" "test_nvs_bootloader.c")
2+
set(embed_txtfiles "")
3+
4+
if(CONFIG_NVS_ENCRYPTION OR SOC_HMAC_SUPPORTED)
5+
list(APPEND srcs "test_encrypted_nvs_bootloader.c")
6+
list(APPEND embed_txtfiles "nvs_partition.bin" "partition_encrypted.bin" "partition_encrypted_hmac.bin")
7+
endif()
8+
9+
if(CONFIG_NVS_SEC_KEY_PROTECT_USING_FLASH_ENC)
10+
list(APPEND embed_txtfiles "encryption_keys.bin")
11+
endif()
12+
13+
idf_component_register(SRCS "${srcs}"
214
INCLUDE_DIRS "."
3-
REQUIRES unity nvs_flash
15+
REQUIRES unity nvs_flash nvs_sec_provider bootloader_support
16+
EMBED_TXTFILES "${embed_txtfiles}"
417
WHOLE_ARCHIVE
518
)
619

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""""""""""""""""""""""""""""""",��<��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������

components/nvs_flash/test_apps_bootloader/main/nvs_enc_hmac_key.bin

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+

2+

Binary file not shown.
Binary file not shown.
Binary file not shown.
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
#include <inttypes.h>
7+
#include <stdio.h>
8+
#include <string.h>
9+
#include <sys/param.h>
10+
11+
#include "esp_err.h"
12+
#include "esp_flash_encrypt.h"
13+
#include "esp_partition.h"
14+
#include "nvs_sec_provider.h"
15+
#include "unity.h"
16+
17+
#include "nvs_bootloader.h"
18+
19+
static esp_err_t configure_nvs_sec_cfg(nvs_sec_cfg_t *cfg, nvs_sec_scheme_t **sec_scheme_handle)
20+
{
21+
const esp_partition_t* nvs_part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL);
22+
TEST_ASSERT(nvs_part && "partition table must have an NVS partition");
23+
printf("\n nvs_part size:%" PRId32 "\n", nvs_part->size);
24+
ESP_ERROR_CHECK(esp_partition_erase_range(nvs_part, 0, nvs_part->size));
25+
26+
#if CONFIG_NVS_SEC_KEY_PROTECT_USING_FLASH_ENC
27+
if (!esp_flash_encryption_enabled()) {
28+
TEST_IGNORE_MESSAGE("flash encryption disabled, skipping nvs_api tests with encryption enabled");
29+
}
30+
31+
extern const char nvs_key_start[] asm("_binary_encryption_keys_bin_start");
32+
extern const char nvs_key_end[] asm("_binary_encryption_keys_bin_end");
33+
extern const char nvs_data_sch0_start[] asm("_binary_partition_encrypted_bin_start");
34+
extern const char nvs_data_sch0_end[] asm("_binary_partition_encrypted_bin_end");
35+
36+
const esp_partition_t* key_part = esp_partition_find_first(
37+
ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS_KEYS, NULL);
38+
39+
assert(key_part && "partition table must have a KEY partition");
40+
TEST_ASSERT_TRUE((nvs_key_end - nvs_key_start - 1) == key_part->erase_size);
41+
42+
ESP_ERROR_CHECK(esp_partition_erase_range(key_part, 0, key_part->size));
43+
44+
for (int i = 0; i < key_part->size; i+= key_part->erase_size) {
45+
ESP_ERROR_CHECK( esp_partition_write(key_part, i, nvs_key_start + i, key_part->erase_size) );
46+
}
47+
48+
const int content_size = nvs_data_sch0_end - nvs_data_sch0_start - 1;
49+
TEST_ASSERT_TRUE((content_size % key_part->erase_size) == 0);
50+
51+
const int size_to_write = MIN(content_size, nvs_part->size);
52+
for (int i = 0; i < size_to_write; i+= nvs_part->erase_size) {
53+
ESP_ERROR_CHECK( esp_partition_write(nvs_part, i, nvs_data_sch0_start + i, nvs_part->erase_size) );
54+
}
55+
56+
nvs_sec_config_flash_enc_t sec_scheme_cfg = {
57+
.nvs_keys_part = key_part
58+
};
59+
60+
TEST_ESP_OK(nvs_sec_provider_register_flash_enc(&sec_scheme_cfg, sec_scheme_handle));
61+
return nvs_flash_read_security_cfg_v2(*sec_scheme_handle, cfg);
62+
63+
#elif SOC_HMAC_SUPPORTED
64+
extern const char nvs_data_sch1_start[] asm("_binary_partition_encrypted_hmac_bin_start");
65+
extern const char nvs_data_sch1_end[] asm("_binary_partition_encrypted_hmac_bin_end");
66+
67+
const int content_size = nvs_data_sch1_end - nvs_data_sch1_start - 1;
68+
TEST_ASSERT_TRUE((content_size % nvs_part->erase_size) == 0);
69+
70+
const int size_to_write = MIN(content_size, nvs_part->size);
71+
for (int i = 0; i < size_to_write; i+= nvs_part->erase_size) {
72+
ESP_ERROR_CHECK( esp_partition_write(nvs_part, i, nvs_data_sch1_start + i, nvs_part->erase_size) );
73+
}
74+
75+
#ifndef CONFIG_NVS_ENCRYPTION
76+
nvs_sec_config_hmac_t sec_scheme_cfg = {
77+
.hmac_key_id = HMAC_KEY0,
78+
};
79+
#else
80+
nvs_sec_config_hmac_t sec_scheme_cfg = NVS_SEC_PROVIDER_CFG_HMAC_DEFAULT();
81+
#endif /* CONFIG_NVS_ENCRYPTION */
82+
83+
TEST_ESP_OK(nvs_sec_provider_register_hmac(&sec_scheme_cfg, sec_scheme_handle));
84+
return nvs_flash_read_security_cfg_v2(*sec_scheme_handle, cfg);
85+
#endif
86+
87+
return ESP_FAIL;
88+
}
89+
90+
static void restore_nvs_partition(void)
91+
{
92+
const esp_partition_t* nvs_part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL);
93+
TEST_ASSERT(nvs_part && "partition table must have an NVS partition");
94+
printf("\n nvs_part size:%" PRId32 "\n", nvs_part->size);
95+
ESP_ERROR_CHECK(esp_partition_erase_range(nvs_part, 0, nvs_part->size));
96+
97+
extern const char nvs_data_start[] asm("_binary_nvs_partition_bin_start");
98+
extern const char nvs_data_end[] asm("_binary_nvs_partition_bin_end");
99+
100+
const int content_size = nvs_data_end - nvs_data_start - 1;
101+
TEST_ASSERT_TRUE((content_size % nvs_part->erase_size) == 0);
102+
103+
const int size_to_write = MIN(content_size, nvs_part->size);
104+
for (int i = 0; i < size_to_write; i+= nvs_part->erase_size) {
105+
ESP_ERROR_CHECK(esp_partition_write(nvs_part, i, nvs_data_start + i, nvs_part->erase_size));
106+
}
107+
}
108+
109+
TEST_CASE("Verify encrypted nvs bootloader read_list result_code and value if bootloader read is successful", "[nvs_encrypted_bootloader]")
110+
{
111+
nvs_sec_cfg_t xts_cfg;
112+
nvs_sec_scheme_t *sec_scheme_handle = NULL;
113+
TEST_ESP_OK(configure_nvs_sec_cfg(&xts_cfg, &sec_scheme_handle));
114+
115+
nvs_bootloader_read_list_t read_list[] = {
116+
// {namespace_name, key_name, value_type, result_code, value, namespace_index}}
117+
{ .namespace_name = "storage", .key_name = "u8_key", .value_type = NVS_TYPE_U8 }, //0 OK
118+
{ .namespace_name = "storage", .key_name = "u16_key", .value_type = NVS_TYPE_U16 }, //1 OK
119+
{ .namespace_name = "storage", .key_name = "u32_key", .value_type = NVS_TYPE_U32 }, //2 OK
120+
{ .namespace_name = "storage", .key_name = "i32_key", .value_type = NVS_TYPE_I32 }, //3 OK
121+
{ .namespace_name = "storage", .key_name = "i8_key", .value_type = NVS_TYPE_U8 }, //4 Type mismatch
122+
{ .namespace_name = "storage", .key_name = "i16_key", .value_type = NVS_TYPE_I16 }, //5 Not found
123+
};
124+
uint8_t size = sizeof(read_list) / sizeof(read_list[0]);
125+
126+
TEST_ESP_OK(nvs_bootloader_secure_init(&xts_cfg));
127+
TEST_ESP_OK(nvs_bootloader_read("nvs", size, read_list));
128+
nvs_bootloader_secure_deinit();
129+
130+
TEST_ASSERT_EQUAL(ESP_OK, read_list[0].result_code);
131+
TEST_ASSERT_EQUAL(ESP_OK, read_list[1].result_code);
132+
TEST_ASSERT_EQUAL(ESP_OK, read_list[2].result_code);
133+
TEST_ASSERT_EQUAL(ESP_OK, read_list[3].result_code);
134+
TEST_ASSERT_EQUAL(ESP_ERR_NVS_TYPE_MISMATCH, read_list[4].result_code);
135+
TEST_ASSERT_EQUAL(ESP_ERR_NVS_NOT_FOUND, read_list[5].result_code);
136+
137+
TEST_ASSERT_EQUAL(255, read_list[0].value.u8_val);
138+
TEST_ASSERT_EQUAL(65535, read_list[1].value.u16_val);
139+
TEST_ASSERT_EQUAL(4294967295, read_list[2].value.u32_val);
140+
TEST_ASSERT_EQUAL(-2147483648, read_list[3].value.i32_val);
141+
142+
TEST_ESP_OK(nvs_sec_provider_deregister(sec_scheme_handle));
143+
restore_nvs_partition();
144+
}
145+
146+
TEST_CASE("Verify encrypted nvs bootloader read_list result_code if bootloader read fails", "[nvs_encrypted_bootloader]")
147+
{
148+
nvs_sec_cfg_t xts_cfg;
149+
nvs_sec_scheme_t *sec_scheme_handle = NULL;
150+
TEST_ESP_OK(configure_nvs_sec_cfg(&xts_cfg, &sec_scheme_handle));
151+
152+
nvs_bootloader_read_list_t read_list[] = {
153+
// {namespace_name, key_name, value_type, result_code, value, namespace_index}}
154+
{ .namespace_name = "too_long_namespace", .key_name = "i32_key", .value_type = NVS_TYPE_I32 }, //0 Invalid name
155+
{ .namespace_name = "nvs", .key_name = "too_long_key_name", .value_type = NVS_TYPE_I32 }, //1 Key too long
156+
{ .namespace_name = "nvs", .key_name = "str_key", .value_type = NVS_TYPE_BLOB }, //2 Invalid arg
157+
{ .namespace_name = "nvs", .key_name = "i32_key", .value_type = NVS_TYPE_I32 }, //3 Not found
158+
};
159+
uint8_t size = sizeof(read_list) / sizeof(read_list[0]);
160+
161+
TEST_ESP_OK(nvs_bootloader_secure_init(&xts_cfg));
162+
esp_err_t ret = nvs_bootloader_read("nvs", size, read_list);
163+
164+
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, ret);
165+
TEST_ASSERT_EQUAL(ESP_ERR_NVS_INVALID_NAME, read_list[0].result_code);
166+
TEST_ASSERT_EQUAL(ESP_ERR_NVS_KEY_TOO_LONG, read_list[1].result_code);
167+
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, read_list[2].result_code);
168+
TEST_ASSERT_EQUAL(ESP_ERR_NVS_NOT_FOUND, read_list[3].result_code);
169+
170+
nvs_bootloader_secure_deinit();
171+
172+
TEST_ESP_OK(nvs_sec_provider_deregister(sec_scheme_handle));
173+
restore_nvs_partition();
174+
}
175+
176+
TEST_CASE("Verify nvs_bootloader_read_encrypted failure cases", "[nvs_encrypted_bootloader]")
177+
{
178+
nvs_sec_cfg_t xts_cfg;
179+
nvs_sec_scheme_t *sec_scheme_handle = NULL;
180+
TEST_ESP_OK(configure_nvs_sec_cfg(&xts_cfg, &sec_scheme_handle));
181+
182+
nvs_bootloader_read_list_t read_list[] = {
183+
// {namespace_name, key_name, value_type, result_code, value, namespace_index}}
184+
{ "nvs", "i32_key", NVS_TYPE_I32, ESP_OK, {0}, 0}
185+
};
186+
uint8_t size = sizeof(read_list) / sizeof(read_list[0]);
187+
188+
TEST_ESP_OK(nvs_bootloader_secure_init(&xts_cfg));
189+
esp_err_t ret = nvs_bootloader_read("nvs_partition_name_too_long", size, read_list);
190+
TEST_ASSERT_EQUAL(ESP_ERR_NVS_INVALID_NAME, ret);
191+
192+
ret = nvs_bootloader_read("nvs_part", size, read_list);
193+
TEST_ASSERT_EQUAL(ESP_ERR_NVS_PART_NOT_FOUND, ret);
194+
195+
nvs_bootloader_secure_deinit();
196+
TEST_ESP_OK(nvs_sec_provider_deregister(sec_scheme_handle));
197+
restore_nvs_partition();
198+
}
Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,36 @@
1-
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
2-
# SPDX-License-Identifier: CC0-1.0
1+
# SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
2+
# SPDX-License-Identifier: Apache-2.0
33
import pytest
4-
from pytest_embedded import Dut
4+
from pytest_embedded_idf.dut import IdfDut
55

66

77
@pytest.mark.esp32
88
@pytest.mark.esp32c3
99
@pytest.mark.generic
1010
@pytest.mark.parametrize('config', ['default'], indirect=True)
11-
def test_nvs_bootloader_support(dut: Dut) -> None:
11+
def test_nvs_bootloader_support(dut: IdfDut) -> None:
12+
dut.run_all_single_board_cases(group='!nvs_encrypted_bootloader', timeout=120)
13+
14+
15+
@pytest.mark.esp32c3
16+
@pytest.mark.nvs_encr_hmac
17+
@pytest.mark.parametrize('config', ['nvs_enc_hmac'], indirect=True)
18+
def test_nvs_bootloader_support_encr_hmac(dut: IdfDut) -> None:
19+
dut.run_all_single_board_cases()
20+
21+
22+
@pytest.mark.esp32
23+
@pytest.mark.esp32c3
24+
@pytest.mark.flash_encryption
25+
@pytest.mark.parametrize('config', ['nvs_enc_flash_enc'], indirect=True)
26+
def test_nvs_bootloader_support_encr_flash_enc(dut: IdfDut) -> None:
27+
# Erase the nvs_key partition
28+
dut.serial.erase_partition('nvs_key')
29+
dut.run_all_single_board_cases()
30+
31+
32+
@pytest.mark.esp32c3
33+
@pytest.mark.nvs_encr_hmac
34+
@pytest.mark.parametrize('config', ['nvs_enc_hmac_no_cfg'], indirect=True)
35+
def test_nvs_bootloader_support_encr_hmac_no_cfg(dut: IdfDut) -> None:
1236
dut.run_all_single_board_cases()
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Enabling Flash Encryption
2+
CONFIG_SECURE_FLASH_ENC_ENABLED=y
3+
CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT=y
4+
CONFIG_SECURE_BOOT_ALLOW_ROM_BASIC=y
5+
CONFIG_SECURE_BOOT_ALLOW_JTAG=y
6+
CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC=y
7+
CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_DEC=y
8+
CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE=y
9+
CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED=y
10+
11+
# Enabling NVS Encryption (Flash Encryption-based scheme)
12+
CONFIG_NVS_ENCRYPTION=y
13+
CONFIG_NVS_SEC_KEY_PROTECT_USING_FLASH_ENC=y
14+
15+
CONFIG_PARTITION_TABLE_SINGLE_APP_ENCRYPTED_NVS=y

0 commit comments

Comments
 (0)