diff --git a/components/bootloader/Kconfig.projbuild b/components/bootloader/Kconfig.projbuild index 918810fd22..339d636d78 100644 --- a/components/bootloader/Kconfig.projbuild +++ b/components/bootloader/Kconfig.projbuild @@ -776,6 +776,7 @@ menu "Security features" bool "Enable flash encryption on boot (READ DOCS FIRST)" default N select SPI_FLASH_ENABLE_ENCRYPTED_READ_WRITE + select NVS_ENCRYPTION help If this option is set, flash contents will be encrypted by the bootloader on first boot. diff --git a/components/nvs_flash/CMakeLists.txt b/components/nvs_flash/CMakeLists.txt index a26493ce3d..c0d9421f9f 100644 --- a/components/nvs_flash/CMakeLists.txt +++ b/components/nvs_flash/CMakeLists.txt @@ -36,9 +36,7 @@ if(${target} STREQUAL "linux") elseif(NOT CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin") message(WARNING "Missing LIBBSD library. Install libbsd-dev package and/or check linker directories.") endif() -endif() - -if(CONFIG_NVS_ENCRYPTION) +else() target_sources(${COMPONENT_LIB} PRIVATE "src/nvs_encrypted_partition.cpp") target_link_libraries(${COMPONENT_LIB} PRIVATE idf::mbedtls) endif() diff --git a/components/nvs_flash/Kconfig b/components/nvs_flash/Kconfig index 5cabecab27..38d0a311f3 100644 --- a/components/nvs_flash/Kconfig +++ b/components/nvs_flash/Kconfig @@ -2,13 +2,13 @@ menu "NVS" config NVS_ENCRYPTION bool "Enable NVS encryption" - default y - depends on SECURE_FLASH_ENC_ENABLED + depends on SECURE_FLASH_ENC_ENABLED || SOC_HMAC_SUPPORTED + default y if SECURE_FLASH_ENC_ENABLED help This option enables encryption for NVS. When enabled, XTS-AES is used to encrypt the complete NVS data, except the page headers. It requires XTS encryption keys - to be stored in an encrypted partition. This means enabling flash encryption is - a pre-requisite for this feature. + to be stored in an encrypted partition (enabling flash encryption is mandatory here) + or to be derived from an HMAC key burnt in eFuse. config NVS_COMPATIBLE_PRE_V4_3_ENCRYPTION_FLAG bool "NVS partition encrypted flag compatible with ESP-IDF before v4.3" diff --git a/components/nvs_flash/include/nvs_flash.h b/components/nvs_flash/include/nvs_flash.h index 7e3d6a7985..6503936f6b 100644 --- a/components/nvs_flash/include/nvs_flash.h +++ b/components/nvs_flash/include/nvs_flash.h @@ -1,16 +1,8 @@ -// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #ifndef nvs_flash_h #define nvs_flash_h @@ -32,6 +24,27 @@ typedef struct { uint8_t tky[NVS_KEY_SIZE]; /*!< XTS tweak key */ } nvs_sec_cfg_t; +/** + * @brief Callback function prototype for generating the NVS encryption keys + */ +typedef esp_err_t (*nvs_flash_generate_keys_t) (const void *scheme_data, nvs_sec_cfg_t* cfg); + +/** + * @brief Callback function prototype for reading the NVS encryption keys + */ +typedef esp_err_t (*nvs_flash_read_cfg_t) (const void *scheme_data, nvs_sec_cfg_t* cfg); + +/** + * @brief NVS encryption: Security scheme configuration structure + */ +typedef struct +{ + int scheme_id; /*!< Security Scheme ID (E.g. HMAC) */ + void *scheme_data; /*!< Scheme-specific data (E.g. eFuse block for HMAC-based key generation) */ + nvs_flash_generate_keys_t nvs_flash_key_gen; /*!< Callback for the nvs_flash_key_gen implementation */ + nvs_flash_read_cfg_t nvs_flash_read_cfg; /*!< Callback for the nvs_flash_read_keys implementation */ +} nvs_sec_scheme_t; + /** * @brief Initialize the default NVS partition. * @@ -220,9 +233,9 @@ esp_err_t nvs_flash_secure_init_partition(const char *partition_label, nvs_sec_c * * * @return - * -ESP_OK, if cfg was read successfully; - * -ESP_INVALID_ARG, if partition or cfg; - * -or error codes from esp_partition_write/erase APIs. + * - ESP_OK, if cfg was read successfully; + * - ESP_ERR_INVALID_ARG, if partition or cfg is NULL; + * - or error codes from esp_partition_write/erase APIs. */ esp_err_t nvs_flash_generate_keys(const esp_partition_t* partition, nvs_sec_cfg_t* cfg); @@ -240,15 +253,68 @@ esp_err_t nvs_flash_generate_keys(const esp_partition_t* partition, nvs_sec_cfg_ * @note Provided partition is assumed to be marked 'encrypted'. * * @return - * -ESP_OK, if cfg was read successfully; - * -ESP_INVALID_ARG, if partition or cfg; - * -ESP_ERR_NVS_KEYS_NOT_INITIALIZED, if the partition is not yet written with keys. - * -ESP_ERR_NVS_CORRUPT_KEY_PART, if the partition containing keys is found to be corrupt - * -or error codes from esp_partition_read API. + * - ESP_OK, if cfg was read successfully; + * - ESP_ERR_INVALID_ARG, if partition or cfg is NULL + * - ESP_ERR_NVS_KEYS_NOT_INITIALIZED, if the partition is not yet written with keys. + * - ESP_ERR_NVS_CORRUPT_KEY_PART, if the partition containing keys is found to be corrupt + * - or error codes from esp_partition_read API. */ esp_err_t nvs_flash_read_security_cfg(const esp_partition_t* partition, nvs_sec_cfg_t* cfg); +/** + * @brief Registers the given security scheme for NVS encryption + * The scheme registered with sec_scheme_id by this API be used as + * the default security scheme for the "nvs" partition. + * Users will have to call this API explicitly in their application. + * + * @param[in] scheme_cfg Pointer to the security scheme configuration structure + * that the user (or the nvs_key_provider) wants to register. + * + * @return + * - ESP_OK, if security scheme registration succeeds; + * - ESP_ERR_INVALID_ARG, if scheme_cfg is NULL; + * - ESP_FAIL, if security scheme registration fails + */ +esp_err_t nvs_flash_register_security_scheme(nvs_sec_scheme_t *scheme_cfg); + +/** + * @brief Fetch the configuration structure for the default active + * security scheme for NVS encryption + * + * @return Pointer to the default active security scheme configuration + * (NULL if no scheme is registered yet i.e. active) + */ +nvs_sec_scheme_t *nvs_flash_get_default_security_scheme(void); + +/** + * @brief Generate (and store) the NVS keys using the specified key-protection scheme + * + * @param[in] scheme_cfg Security scheme specific configuration + * + * @param[out] cfg Security configuration (encryption keys) + * + * @return + * - ESP_OK, if cfg was populated successfully with generated encryption keys; + * - ESP_ERR_INVALID_ARG, if scheme_cfg or cfg is NULL; + * - ESP_FAIL, if the key generation process fails + */ +esp_err_t nvs_flash_generate_keys_v2(nvs_sec_scheme_t *scheme_cfg, nvs_sec_cfg_t* cfg); + +/** + * @brief Read NVS security configuration set by the specified security scheme + * + * @param[in] scheme_cfg Security scheme specific configuration + * + * @param[out] cfg Security configuration (encryption keys) + * + * @return + * - ESP_OK, if cfg was read successfully; + * - ESP_ERR_INVALID_ARG, if scheme_cfg or cfg is NULL; + * - ESP_FAIL, if the key reading process fails + */ +esp_err_t nvs_flash_read_security_cfg_v2(nvs_sec_scheme_t *scheme_cfg, nvs_sec_cfg_t* cfg); + #ifdef __cplusplus } #endif diff --git a/components/nvs_flash/src/nvs_api.cpp b/components/nvs_flash/src/nvs_api.cpp index 8d8d0b013d..587f531352 100644 --- a/components/nvs_flash/src/nvs_api.cpp +++ b/components/nvs_flash/src/nvs_api.cpp @@ -23,6 +23,12 @@ #include "esp_log.h" static const char* TAG = "nvs"; +/** + * @brief Configuration structure for the active default security scheme + * for NVS Encryption + */ +static nvs_sec_scheme_t nvs_sec_default_scheme_cfg; + class NVSHandleEntry : public intrusive_list_node, public ExceptionlessAllocatable { public: NVSHandleEntry(nvs::NVSHandleSimple *handle, const char* part_name) @@ -133,28 +139,20 @@ extern "C" esp_err_t nvs_flash_init(void) { #ifdef CONFIG_NVS_ENCRYPTION esp_err_t ret = ESP_FAIL; - const esp_partition_t *key_part = esp_partition_find_first( - ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS_KEYS, NULL); - if (key_part == NULL) { - ESP_LOGE(TAG, "CONFIG_NVS_ENCRYPTION is enabled, but no partition with subtype nvs_keys found in the partition table."); - return ret; - } - nvs_sec_cfg_t cfg = {}; - ret = nvs_flash_read_security_cfg(key_part, &cfg); - if (ret == ESP_ERR_NVS_KEYS_NOT_INITIALIZED) { - ESP_LOGI(TAG, "NVS key partition empty, generating keys"); - ret = nvs_flash_generate_keys(key_part, &cfg); + + ret = nvs_flash_read_security_cfg_v2(&nvs_sec_default_scheme_cfg, &cfg); + if (ret != ESP_OK) { + ESP_LOGW(TAG, "Failed to read NVS security cfg: [0x%02X] (%s)", ret, esp_err_to_name(ret)); + ESP_LOGI(TAG, "Generating NVS encr-keys..."); + ret = nvs_flash_generate_keys_v2(&nvs_sec_default_scheme_cfg, &cfg); if (ret != ESP_OK) { - ESP_LOGE(TAG, "Failed to generate keys: [0x%02X] (%s)", ret, esp_err_to_name(ret)); + ESP_LOGE(TAG, "Failed to generate NVS encr-keys: [0x%02X] (%s)", ret, esp_err_to_name(ret)); return ret; } - } else if (ret != ESP_OK) { - ESP_LOGE(TAG, "Failed to read NVS security cfg: [0x%02X] (%s)", ret, esp_err_to_name(ret)); - return ret; } - ret = nvs_flash_secure_init_partition(NVS_DEFAULT_PART_NAME, &cfg); + ret = nvs_flash_secure_init(&cfg); if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { ESP_LOGE(TAG, "Failed to initialize NVS partition: [0x%02X] (%s)", ret, esp_err_to_name(ret)); return ret; @@ -166,7 +164,6 @@ extern "C" esp_err_t nvs_flash_init(void) #endif } -#ifdef CONFIG_NVS_ENCRYPTION extern "C" esp_err_t nvs_flash_secure_init_partition(const char *part_name, nvs_sec_cfg_t* cfg) { esp_err_t lock_result = Lock::init(); @@ -182,7 +179,6 @@ extern "C" esp_err_t nvs_flash_secure_init(nvs_sec_cfg_t* cfg) { return nvs_flash_secure_init_partition(NVS_DEFAULT_PART_NAME, cfg); } -#endif extern "C" esp_err_t nvs_flash_erase_partition(const char *part_name) { @@ -567,7 +563,7 @@ extern "C" esp_err_t nvs_get_used_entry_count(nvs_handle_t c_handle, size_t* use return err; } -#if (defined CONFIG_NVS_ENCRYPTION) && (!defined LINUX_TARGET) +#ifndef LINUX_TARGET extern "C" esp_err_t nvs_flash_generate_keys(const esp_partition_t* partition, nvs_sec_cfg_t* cfg) { @@ -704,7 +700,39 @@ extern "C" esp_err_t nvs_flash_read_security_cfg(const esp_partition_t* partitio return ESP_OK; } -#endif +#endif // ! LINUX_TARGET + +extern "C" esp_err_t nvs_flash_register_security_scheme(nvs_sec_scheme_t *scheme_cfg) +{ + if (scheme_cfg == nullptr) { + return ESP_ERR_INVALID_ARG; + } + + memcpy(&nvs_sec_default_scheme_cfg, scheme_cfg, sizeof(nvs_sec_scheme_t)); + + return ESP_OK; +} + +extern "C" nvs_sec_scheme_t *nvs_flash_get_default_security_scheme(void) +{ + return &nvs_sec_default_scheme_cfg; +} + +extern "C" esp_err_t nvs_flash_generate_keys_v2(nvs_sec_scheme_t *scheme_cfg, nvs_sec_cfg_t* cfg) +{ + if (scheme_cfg == nullptr || cfg == nullptr || scheme_cfg->nvs_flash_key_gen == nullptr) { + return ESP_ERR_INVALID_ARG; + } + return (scheme_cfg->nvs_flash_key_gen)(scheme_cfg->scheme_data, cfg); +} + +extern "C" esp_err_t nvs_flash_read_security_cfg_v2(nvs_sec_scheme_t *scheme_cfg, nvs_sec_cfg_t* cfg) +{ + if (scheme_cfg == nullptr || cfg == nullptr || scheme_cfg->nvs_flash_read_cfg == nullptr) { + return ESP_ERR_INVALID_ARG; + } + return (scheme_cfg->nvs_flash_read_cfg)(scheme_cfg->scheme_data, cfg); +} static nvs_iterator_t create_iterator(nvs::Storage *storage, nvs_type_t type) { diff --git a/components/nvs_flash/src/nvs_partition_lookup.cpp b/components/nvs_flash/src/nvs_partition_lookup.cpp index e9d27256fa..604049133a 100644 --- a/components/nvs_flash/src/nvs_partition_lookup.cpp +++ b/components/nvs_flash/src/nvs_partition_lookup.cpp @@ -1,9 +1,9 @@ #include "esp_partition.h" #include "nvs_partition_lookup.hpp" -#ifdef CONFIG_NVS_ENCRYPTION +#ifndef LINUX_TARGET #include "nvs_encrypted_partition.hpp" -#endif // CONFIG_NVS_ENCRYPTION +#endif // ! LINUX_TARGET namespace nvs { @@ -32,7 +32,7 @@ esp_err_t lookup_nvs_partition(const char* label, NVSPartition **p) return ESP_OK; } -#ifdef CONFIG_NVS_ENCRYPTION +#ifndef LINUX_TARGET esp_err_t lookup_nvs_encrypted_partition(const char* label, nvs_sec_cfg_t* cfg, NVSPartition **p) { const esp_partition_t* esp_partition = esp_partition_find_first( @@ -61,8 +61,7 @@ esp_err_t lookup_nvs_encrypted_partition(const char* label, nvs_sec_cfg_t* cfg, return ESP_OK; } - -#endif // CONFIG_NVS_ENCRYPTION +#endif // ! LINUX_TARGET } // partition_lookup diff --git a/components/nvs_flash/src/nvs_partition_lookup.hpp b/components/nvs_flash/src/nvs_partition_lookup.hpp index 62a8e8b6fe..5dcd5d692c 100644 --- a/components/nvs_flash/src/nvs_partition_lookup.hpp +++ b/components/nvs_flash/src/nvs_partition_lookup.hpp @@ -11,9 +11,7 @@ namespace partition_lookup { esp_err_t lookup_nvs_partition(const char* label, NVSPartition **p); -#ifdef CONFIG_NVS_ENCRYPTION esp_err_t lookup_nvs_encrypted_partition(const char* label, nvs_sec_cfg_t* cfg, NVSPartition **p); -#endif // CONFIG_NVS_ENCRYPTION } // partition_lookup diff --git a/components/nvs_flash/src/nvs_partition_manager.cpp b/components/nvs_flash/src/nvs_partition_manager.cpp index e90137eb2f..f43ca130a1 100644 --- a/components/nvs_flash/src/nvs_partition_manager.cpp +++ b/components/nvs_flash/src/nvs_partition_manager.cpp @@ -8,9 +8,9 @@ #include "nvs_partition_lookup.hpp" #include "nvs_internal.h" -#ifdef CONFIG_NVS_ENCRYPTION +#ifndef LINUX_TARGET #include "nvs_encrypted_partition.hpp" -#endif // CONFIG_NVS_ENCRYPTION +#endif // ! LINUX_TARGET namespace nvs { @@ -100,7 +100,6 @@ esp_err_t NVSPartitionManager::init_custom(Partition *partition, uint32_t baseSe return err; } -#ifdef CONFIG_NVS_ENCRYPTION #ifdef ESP_PLATFORM esp_err_t NVSPartitionManager::secure_init_partition(const char *part_name, nvs_sec_cfg_t* cfg) { @@ -140,7 +139,6 @@ esp_err_t NVSPartitionManager::secure_init_partition(const char *part_name, nvs_ return ESP_OK; } #endif // ESP_PLATFORM -#endif // CONFIG_NVS_ENCRYPTION esp_err_t NVSPartitionManager::deinit_partition(const char *partition_label) { diff --git a/components/nvs_flash/src/nvs_partition_manager.hpp b/components/nvs_flash/src/nvs_partition_manager.hpp index ebed1214e3..4b437d81e2 100644 --- a/components/nvs_flash/src/nvs_partition_manager.hpp +++ b/components/nvs_flash/src/nvs_partition_manager.hpp @@ -24,9 +24,7 @@ public: esp_err_t init_custom(Partition *partition, uint32_t baseSector, uint32_t sectorCount); -#ifdef CONFIG_NVS_ENCRYPTION esp_err_t secure_init_partition(const char *part_name, nvs_sec_cfg_t* cfg); -#endif esp_err_t deinit_partition(const char *partition_label); diff --git a/tools/ci/check_copyright_ignore.txt b/tools/ci/check_copyright_ignore.txt index 3efe7da1cf..fb5dc0f312 100644 --- a/tools/ci/check_copyright_ignore.txt +++ b/tools/ci/check_copyright_ignore.txt @@ -716,7 +716,6 @@ components/mqtt/host_test/mocks/include/freertos/portmacro.h components/mqtt/host_test/mocks/include/machine/endian.h components/mqtt/host_test/mocks/include/sys/queue.h components/nvs_flash/host_test/nvs_page_test/main/nvs_page_test.cpp -components/nvs_flash/include/nvs_flash.h components/nvs_flash/include/nvs_handle.hpp components/nvs_flash/src/nvs_cxx_api.cpp components/nvs_flash/src/nvs_encrypted_partition.hpp