Enable NVS and flash encryption at rest (fw 0.8.3).

Add initEncryptedStorage, development-mode Kconfig defaults, production overlay, and security HIL docs; wire NetBootstrap through encrypted NVS bring-up.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-07 07:46:59 +02:00
co-authored by Cursor
parent 9b46fe9465
commit a8f2fd1c6c
17 changed files with 259 additions and 48 deletions
@@ -2,6 +2,7 @@ idf_component_register(
SRCS
"src/NvsSecureStore.cpp"
"src/NvsAudioProfileStore.cpp"
"src/NvsPlatformInit.cpp"
INCLUDE_DIRS "include"
REQUIRES core nvs_flash
)
@@ -0,0 +1,48 @@
/**
* @file NvsPlatformInit.hpp
* @brief Encrypted NVS partition bring-up for ISecureStore backends.
*
* DigiRadio firmware — https://github.com/manvalan/DigiRadio
*
* Copyright 2026 Michele Bigi
* SPDX-License-Identifier: Apache-2.0
*
* @author Michele Bigi
* @date 2026-07-07
*/
#pragma once
#include <expected>
namespace secure_store {
/**
* @brief NvsInitError — failure mode for encrypted NVS initialisation.
*
* @dname NvsInitError
* @return n/a (type)
* @pubstate none
*
* @author Michele Bigi
* @date 2026-07-07
*/
enum class NvsInitError {
EraseFailed, ///< nvs_flash_erase failed during recovery.
InitFailed, ///< nvs_flash_init failed after recovery attempt.
};
/**
* @brief initEncryptedStorage — initialise default NVS (+ nvs_keys when enabled).
*
* @dname initEncryptedStorage
* @return Ok on success, or NvsInitError describing the failure.
* @pubstate When CONFIG_NVS_ENCRYPTION is set, nvs_flash_init() uses the
* nvs_keys partition and flash-encryption key protection per
* ESP-IDF v5.5 security docs. Erases and retries on layout mismatch.
*
* @author Michele Bigi
* @date 2026-07-07
*/
[[nodiscard]] std::expected<void, NvsInitError> initEncryptedStorage() noexcept;
} // namespace secure_store
@@ -12,9 +12,9 @@
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Production builds should enable NVS encryption (nvs_keys partition in
* partitions.csv) per ESP-IDF security docs; this slice uses plain NVS
* for development bring-up.
* Production: NVS encryption + flash encryption enabled in sdkconfig.defaults
* (fw 0.8.3+). Call secure_store::initEncryptedStorage() before first use;
* see docs/security-flash-nvs.md.
*
* @author Michele Bigi
* @date 2026-07-06
@@ -0,0 +1,75 @@
/**
* @file NvsPlatformInit.cpp
* @brief Encrypted NVS partition bring-up implementation.
*
* DigiRadio firmware — https://github.com/manvalan/DigiRadio
*
* Copyright 2026 Michele Bigi
* SPDX-License-Identifier: Apache-2.0
*
* @author Michele Bigi
* @date 2026-07-07
*/
#include "secure_store/NvsPlatformInit.hpp"
#include "esp_log.h"
#include "nvs_flash.h"
#include "sdkconfig.h"
namespace secure_store {
namespace {
constexpr char kTag[] = "NvsPlatformInit";
/**
* @brief logEncryptionMode — log active NVS security Kconfig (no secrets).
*
* @dname logEncryptionMode
* @pubstate none; INFO log only.
*
* @author Michele Bigi
* @date 2026-07-07
*/
void logEncryptionMode() noexcept
{
#if CONFIG_NVS_ENCRYPTION
ESP_LOGI(kTag, "NVS encryption enabled");
#if CONFIG_SECURE_FLASH_ENC_ENABLED
ESP_LOGI(kTag, "Flash encryption enabled (development=%d)",
static_cast<int>(CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT));
#else
ESP_LOGW(kTag, "NVS encryption without flash encryption — check Kconfig");
#endif
#else
ESP_LOGW(kTag, "NVS encryption disabled — not for production");
#endif
}
} // namespace
std::expected<void, NvsInitError> initEncryptedStorage() noexcept
{
logEncryptionMode();
esp_err_t err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES
|| err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_LOGW(kTag, "NVS partition needs erase (err=0x%x)", static_cast<unsigned>(err));
err = nvs_flash_erase();
if (err != ESP_OK) {
ESP_LOGE(kTag, "nvs_flash_erase failed (0x%x)", static_cast<unsigned>(err));
return std::unexpected(NvsInitError::EraseFailed);
}
err = nvs_flash_init();
}
if (err != ESP_OK) {
ESP_LOGE(kTag, "nvs_flash_init failed (0x%x)", static_cast<unsigned>(err));
return std::unexpected(NvsInitError::InitFailed);
}
return {};
}
} // namespace secure_store