mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
nvs_flash: Added helper component nvs_sec_provider
- For processing NVS encryption-related security configuration
This commit is contained in:
parent
c1bed366ba
commit
8efe2f86e9
@ -125,6 +125,7 @@
|
|||||||
/components/mqtt/ @esp-idf-codeowners/network
|
/components/mqtt/ @esp-idf-codeowners/network
|
||||||
/components/newlib/ @esp-idf-codeowners/system @esp-idf-codeowners/tools
|
/components/newlib/ @esp-idf-codeowners/system @esp-idf-codeowners/tools
|
||||||
/components/nvs_flash/ @esp-idf-codeowners/storage
|
/components/nvs_flash/ @esp-idf-codeowners/storage
|
||||||
|
/components/nvs_sec_provider/ @esp-idf-codeowners/storage @esp-idf-codeowners/security
|
||||||
/components/openthread/ @esp-idf-codeowners/ieee802154
|
/components/openthread/ @esp-idf-codeowners/ieee802154
|
||||||
/components/partition_table/ @esp-idf-codeowners/system
|
/components/partition_table/ @esp-idf-codeowners/system
|
||||||
/components/perfmon/ @esp-idf-codeowners/tools
|
/components/perfmon/ @esp-idf-codeowners/tools
|
||||||
|
@ -72,6 +72,9 @@
|
|||||||
#if __has_include("nvs.h")
|
#if __has_include("nvs.h")
|
||||||
#include "nvs.h"
|
#include "nvs.h"
|
||||||
#endif
|
#endif
|
||||||
|
#if __has_include("nvs_sec_provider.h")
|
||||||
|
#include "nvs_sec_provider.h"
|
||||||
|
#endif
|
||||||
#if __has_include("spi_flash_mmap.h")
|
#if __has_include("spi_flash_mmap.h")
|
||||||
#include "spi_flash_mmap.h"
|
#include "spi_flash_mmap.h"
|
||||||
#endif
|
#endif
|
||||||
@ -829,6 +832,25 @@ static const esp_err_msg_t esp_err_msg_table[] = {
|
|||||||
# endif
|
# endif
|
||||||
# ifdef ESP_ERR_TCP_TRANSPORT_NO_MEM
|
# ifdef ESP_ERR_TCP_TRANSPORT_NO_MEM
|
||||||
ERR_TBL_IT(ESP_ERR_TCP_TRANSPORT_NO_MEM), /* 57348 0xe004 Memory allocation failed */
|
ERR_TBL_IT(ESP_ERR_TCP_TRANSPORT_NO_MEM), /* 57348 0xe004 Memory allocation failed */
|
||||||
|
# endif
|
||||||
|
// components/nvs_sec_provider/include/nvs_sec_provider.h
|
||||||
|
# ifdef ESP_ERR_NVS_SEC_BASE
|
||||||
|
ERR_TBL_IT(ESP_ERR_NVS_SEC_BASE), /* 61440 0xf000 Starting number of error codes */
|
||||||
|
# endif
|
||||||
|
# ifdef ESP_ERR_NVS_SEC_HMAC_KEY_NOT_FOUND
|
||||||
|
ERR_TBL_IT(ESP_ERR_NVS_SEC_HMAC_KEY_NOT_FOUND), /* 61441 0xf001 HMAC Key required to generate the NVS
|
||||||
|
encryption keys not found */
|
||||||
|
# endif
|
||||||
|
# ifdef ESP_ERR_NVS_SEC_HMAC_KEY_BLK_ALREADY_USED
|
||||||
|
ERR_TBL_IT(ESP_ERR_NVS_SEC_HMAC_KEY_BLK_ALREADY_USED), /* 61442 0xf002 Provided eFuse block for HMAC key
|
||||||
|
generation is already in use */
|
||||||
|
# endif
|
||||||
|
# ifdef ESP_ERR_NVS_SEC_HMAC_KEY_GENERATION_FAILED
|
||||||
|
ERR_TBL_IT(ESP_ERR_NVS_SEC_HMAC_KEY_GENERATION_FAILED), /* 61443 0xf003 Failed to generate/write the HMAC key to eFuse */
|
||||||
|
# endif
|
||||||
|
# ifdef ESP_ERR_NVS_SEC_HMAC_XTS_KEYS_DERIV_FAILED
|
||||||
|
ERR_TBL_IT(ESP_ERR_NVS_SEC_HMAC_XTS_KEYS_DERIV_FAILED), /* 61444 0xf004 Failed to derive the NVS encryption keys
|
||||||
|
based on the HMAC-based scheme */
|
||||||
# endif
|
# endif
|
||||||
};
|
};
|
||||||
#endif //CONFIG_ESP_ERR_TO_NAME_LOOKUP
|
#endif //CONFIG_ESP_ERR_TO_NAME_LOOKUP
|
||||||
|
12
components/nvs_sec_provider/CMakeLists.txt
Normal file
12
components/nvs_sec_provider/CMakeLists.txt
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
idf_component_register(SRCS "nvs_sec_provider.c"
|
||||||
|
INCLUDE_DIRS include
|
||||||
|
PRIV_REQUIRES bootloader_support efuse esp_partition nvs_flash)
|
||||||
|
|
||||||
|
# NOTE: In a case where only the default NVS partition is to be encrypted
|
||||||
|
# and no custom NVS partitions exist, `nvs_flash_init` is the only API that
|
||||||
|
# needs to be called. No API from the `nvs_sec_provider` component is called
|
||||||
|
# as neither the `nvs_flash` component nor the user app depends on it.
|
||||||
|
# Thus, the symbols from this component are not placed in the .map file and
|
||||||
|
# hence the constructor, which initialises the encryption scheme for the default
|
||||||
|
# NVS partition, never executes. The following is a workaround for the same.
|
||||||
|
target_link_libraries(${COMPONENT_LIB} PRIVATE "-u nvs_sec_provider_include_impl")
|
46
components/nvs_sec_provider/Kconfig
Normal file
46
components/nvs_sec_provider/Kconfig
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
menu "NVS Security Provider"
|
||||||
|
visible if NVS_ENCRYPTION
|
||||||
|
|
||||||
|
choice NVS_SEC_KEY_PROTECTION_SCHEME
|
||||||
|
prompt "NVS Encryption: Key Protection Scheme"
|
||||||
|
depends on NVS_ENCRYPTION
|
||||||
|
default NVS_SEC_KEY_PROTECT_USING_FLASH_ENC
|
||||||
|
help
|
||||||
|
This choice defines the default NVS encryption keys protection scheme;
|
||||||
|
which will be used for the default NVS partition.
|
||||||
|
Users can use the corresponding scheme registration APIs to register other
|
||||||
|
schemes for the default as well as other NVS partitions.
|
||||||
|
|
||||||
|
config NVS_SEC_KEY_PROTECT_USING_FLASH_ENC
|
||||||
|
bool "Using Flash Encryption"
|
||||||
|
depends on SECURE_FLASH_ENC_ENABLED
|
||||||
|
help
|
||||||
|
Protect the NVS Encryption Keys using Flash Encryption
|
||||||
|
Requires a separate 'nvs_keys' partition (which will be encrypted by flash encryption)
|
||||||
|
for storing the NVS encryption keys
|
||||||
|
|
||||||
|
config NVS_SEC_KEY_PROTECT_USING_HMAC
|
||||||
|
bool "Using HMAC peripheral"
|
||||||
|
depends on SOC_HMAC_SUPPORTED
|
||||||
|
help
|
||||||
|
Derive and protect the NVS Encryption Keys using the HMAC peripheral
|
||||||
|
Requires the specified eFuse block (NVS_SEC_HMAC_EFUSE_KEY_ID or the v2 API argument)
|
||||||
|
to be empty or pre-written with a key with the purpose ESP_EFUSE_KEY_PURPOSE_HMAC_UP
|
||||||
|
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
config NVS_SEC_HMAC_EFUSE_KEY_ID
|
||||||
|
int "eFuse key ID storing the HMAC key"
|
||||||
|
depends on NVS_SEC_KEY_PROTECT_USING_HMAC
|
||||||
|
range 0 6
|
||||||
|
default 6
|
||||||
|
help
|
||||||
|
eFuse block key ID storing the HMAC key for deriving the NVS encryption keys
|
||||||
|
|
||||||
|
Note: The eFuse block key ID required by the HMAC scheme
|
||||||
|
(CONFIG_NVS_SEC_KEY_PROTECT_USING_HMAC) is set using this config when the default
|
||||||
|
NVS partition is initialized with nvs_flash_init(). The eFuse block key ID can
|
||||||
|
also be set at runtime by passing the appropriate value to the NVS security scheme
|
||||||
|
registration APIs.
|
||||||
|
|
||||||
|
endmenu
|
114
components/nvs_sec_provider/include/nvs_sec_provider.h
Normal file
114
components/nvs_sec_provider/include/nvs_sec_provider.h
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include "soc/soc_caps.h"
|
||||||
|
|
||||||
|
#include "nvs_flash.h"
|
||||||
|
#include "esp_partition.h"
|
||||||
|
|
||||||
|
#if SOC_HMAC_SUPPORTED
|
||||||
|
#include "esp_hmac.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ESP_ERR_NVS_SEC_BASE 0xF000 /*!< Starting number of error codes */
|
||||||
|
|
||||||
|
#define ESP_ERR_NVS_SEC_HMAC_KEY_NOT_FOUND (ESP_ERR_NVS_SEC_BASE + 0x01) /*!< HMAC Key required to generate the NVS encryption keys not found */
|
||||||
|
#define ESP_ERR_NVS_SEC_HMAC_KEY_BLK_ALREADY_USED (ESP_ERR_NVS_SEC_BASE + 0x02) /*!< Provided eFuse block for HMAC key generation is already in use */
|
||||||
|
#define ESP_ERR_NVS_SEC_HMAC_KEY_GENERATION_FAILED (ESP_ERR_NVS_SEC_BASE + 0x03) /*!< Failed to generate/write the HMAC key to eFuse */
|
||||||
|
#define ESP_ERR_NVS_SEC_HMAC_XTS_KEYS_DERIV_FAILED (ESP_ERR_NVS_SEC_BASE + 0x04) /*!< Failed to derive the NVS encryption keys based on the HMAC-based scheme */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief NVS Encryption Keys Protection Scheme
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
NVS_SEC_SCHEME_FLASH_ENC = 0, /*!< Protect NVS encryption keys using Flash Encryption */
|
||||||
|
NVS_SEC_SCHEME_HMAC, /*!< Protect NVS encryption keys using HMAC peripheral */
|
||||||
|
NVS_SEC_SCHEME_MAX
|
||||||
|
} nvs_sec_scheme_id_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Flash encryption-based scheme specific configuration data
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
const esp_partition_t *nvs_keys_part; /*!< Partition of subtype `nvs_keys` holding the NVS encryption keys */
|
||||||
|
} nvs_sec_config_flash_enc_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Helper for populating the Flash encryption-based scheme specific configuration data
|
||||||
|
*/
|
||||||
|
#define NVS_SEC_PROVIDER_CFG_FLASH_ENC_DEFAULT() { \
|
||||||
|
.nvs_keys_part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, \
|
||||||
|
ESP_PARTITION_SUBTYPE_DATA_NVS_KEYS, \
|
||||||
|
NULL), \
|
||||||
|
}
|
||||||
|
|
||||||
|
#if SOC_HMAC_SUPPORTED
|
||||||
|
/**
|
||||||
|
* @brief HMAC-based scheme specific configuration data
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
hmac_key_id_t hmac_key_id; /*!< HMAC Key ID used for generating the NVS encryption keys */
|
||||||
|
} nvs_sec_config_hmac_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Helper for populating the HMAC-based scheme specific configuration data
|
||||||
|
*/
|
||||||
|
#define NVS_SEC_PROVIDER_CFG_HMAC_DEFAULT() { \
|
||||||
|
.hmac_key_id = (hmac_key_id_t)(CONFIG_NVS_SEC_HMAC_EFUSE_KEY_ID), \
|
||||||
|
}
|
||||||
|
#endif /* SOC_HMAC_SUPPORTED */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Register the Flash-Encryption based scheme for NVS Encryption
|
||||||
|
*
|
||||||
|
* @param[in] sec_scheme_cfg Security scheme specific configuration data
|
||||||
|
* @param[out] sec_scheme_handle_out Security scheme specific configuration handle
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK, if `sec_scheme_handle_out` was populated successfully with the scheme configuration;
|
||||||
|
* - ESP_ERR_INVALID_ARG, if `scheme_cfg_hmac` is NULL;
|
||||||
|
* - ESP_ERR_NO_MEM, No memory for the scheme-specific handle `sec_scheme_handle_out`
|
||||||
|
* - ESP_ERR_NOT_FOUND, if no `nvs_keys` partition is found
|
||||||
|
*/
|
||||||
|
esp_err_t nvs_sec_provider_register_flash_enc(const nvs_sec_config_flash_enc_t *sec_scheme_cfg, nvs_sec_scheme_t **sec_scheme_handle_out);
|
||||||
|
|
||||||
|
#if SOC_HMAC_SUPPORTED
|
||||||
|
/**
|
||||||
|
* @brief Register the HMAC-based scheme for NVS Encryption
|
||||||
|
*
|
||||||
|
* @param[in] sec_scheme_cfg Security scheme specific configuration data
|
||||||
|
* @param[out] sec_scheme_handle_out Security scheme specific configuration handle
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK, if `sec_scheme_handle_out` was populated successfully with the scheme configuration;
|
||||||
|
* - ESP_ERR_INVALID_ARG, if `scheme_cfg_hmac` is NULL;
|
||||||
|
* - ESP_ERR_NO_MEM, No memory for the scheme-specific handle `sec_scheme_handle_out`
|
||||||
|
*/
|
||||||
|
esp_err_t nvs_sec_provider_register_hmac(const nvs_sec_config_hmac_t *sec_scheme_cfg, nvs_sec_scheme_t **sec_scheme_handle_out);
|
||||||
|
#endif /* SOC_HMAC_SUPPORTED */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Deregister the NVS encryption scheme registered with the given handle
|
||||||
|
*
|
||||||
|
* @param[in] sec_scheme_handle Security scheme specific configuration handle
|
||||||
|
|
||||||
|
* @return
|
||||||
|
* - ESP_OK, if the scheme registered with `sec_scheme_handle` was deregistered successfully
|
||||||
|
* - ESP_ERR_INVALID_ARG, if `sec_scheme_handle` is NULL;
|
||||||
|
*/
|
||||||
|
esp_err_t nvs_sec_provider_deregister(nvs_sec_scheme_t *sec_scheme_handle);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
279
components/nvs_sec_provider/nvs_sec_provider.c
Normal file
279
components/nvs_sec_provider/nvs_sec_provider.c
Normal file
@ -0,0 +1,279 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_fault.h"
|
||||||
|
#include "soc/soc_caps.h"
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
|
||||||
|
#include "nvs_flash.h"
|
||||||
|
#include "nvs_sec_provider.h"
|
||||||
|
|
||||||
|
#if SOC_HMAC_SUPPORTED
|
||||||
|
#include "bootloader_random.h"
|
||||||
|
#include "esp_random.h"
|
||||||
|
|
||||||
|
#include "esp_efuse.h"
|
||||||
|
#include "esp_efuse_chip.h"
|
||||||
|
#endif // SOC_HMAC_SUPPORTED
|
||||||
|
|
||||||
|
static __attribute__((unused)) const char *TAG = "nvs_sec_provider";
|
||||||
|
|
||||||
|
#if CONFIG_NVS_SEC_KEY_PROTECT_USING_FLASH_ENC
|
||||||
|
|
||||||
|
static esp_err_t generate_keys_flash_enc(const void* sec_scheme_cfg, nvs_sec_cfg_t* cfg)
|
||||||
|
{
|
||||||
|
if (sec_scheme_cfg == NULL || cfg == NULL) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
nvs_sec_config_flash_enc_t *scheme_cfg_flash_enc = (nvs_sec_config_flash_enc_t *)sec_scheme_cfg;
|
||||||
|
return nvs_flash_generate_keys(scheme_cfg_flash_enc->nvs_keys_part, cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t read_security_cfg_flash_enc(const void* sec_scheme_cfg, nvs_sec_cfg_t* cfg)
|
||||||
|
{
|
||||||
|
if (sec_scheme_cfg == NULL || cfg == NULL) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
nvs_sec_config_flash_enc_t *scheme_cfg_flash_enc = (nvs_sec_config_flash_enc_t *)sec_scheme_cfg;
|
||||||
|
return nvs_flash_read_security_cfg(scheme_cfg_flash_enc->nvs_keys_part, cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t nvs_sec_provider_register_flash_enc(const nvs_sec_config_flash_enc_t *sec_scheme_cfg, nvs_sec_scheme_t **sec_scheme_handle_out)
|
||||||
|
{
|
||||||
|
if (sec_scheme_cfg == NULL || sec_scheme_handle_out == NULL) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
nvs_sec_scheme_t *sec_scheme = calloc(1, sizeof(nvs_sec_scheme_t));
|
||||||
|
if (sec_scheme == NULL) {
|
||||||
|
return ESP_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
sec_scheme->scheme_id = NVS_SEC_SCHEME_FLASH_ENC;
|
||||||
|
sec_scheme->nvs_flash_key_gen = &generate_keys_flash_enc;
|
||||||
|
sec_scheme->nvs_flash_read_cfg = &read_security_cfg_flash_enc;
|
||||||
|
|
||||||
|
sec_scheme->scheme_data = calloc(1, sizeof(nvs_sec_config_flash_enc_t));
|
||||||
|
if (sec_scheme->scheme_data == NULL) {
|
||||||
|
return ESP_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
memcpy(sec_scheme->scheme_data, (void *)sec_scheme_cfg, sizeof(nvs_sec_config_flash_enc_t));
|
||||||
|
|
||||||
|
esp_err_t err = nvs_flash_register_security_scheme(sec_scheme);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
*sec_scheme_handle_out = sec_scheme;
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __attribute__((constructor)) nvs_sec_provider_register_flash_enc_ctr(void)
|
||||||
|
{
|
||||||
|
ESP_EARLY_LOGI(TAG, "NVS Encryption - Registering Flash encryption-based scheme...");
|
||||||
|
|
||||||
|
nvs_sec_config_flash_enc_t sec_scheme_cfg = NVS_SEC_PROVIDER_CFG_FLASH_ENC_DEFAULT();
|
||||||
|
nvs_sec_scheme_t *sec_scheme_handle_out = NULL;
|
||||||
|
|
||||||
|
nvs_sec_provider_register_flash_enc(&sec_scheme_cfg, &sec_scheme_handle_out);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if SOC_HMAC_SUPPORTED
|
||||||
|
|
||||||
|
#if CONFIG_NVS_SEC_HMAC_EFUSE_KEY_ID > 5
|
||||||
|
#error "NVS Encryption (HMAC): Configured eFuse block (CONFIG_NVS_SEC_HMAC_EFUSE_KEY_ID) out of range!"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static esp_err_t compute_nvs_keys_with_hmac(hmac_key_id_t hmac_key_id, nvs_sec_cfg_t* cfg)
|
||||||
|
{
|
||||||
|
uint32_t ekey_seed[8] = {[0 ... 7] = 0xAEBE5A5A};
|
||||||
|
uint32_t tkey_seed[8] = {[0 ... 7] = 0xCEDEA5A5};
|
||||||
|
|
||||||
|
esp_err_t err = esp_hmac_calculate(hmac_key_id, ekey_seed, sizeof(ekey_seed), (uint8_t *)cfg->eky);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "Failed to calculate seed HMAC: [0x%02X] (%s)", err, esp_err_to_name(err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
ESP_FAULT_ASSERT(err == ESP_OK);
|
||||||
|
|
||||||
|
err = esp_hmac_calculate(hmac_key_id, tkey_seed, sizeof(tkey_seed), (uint8_t *)cfg->tky);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "Failed to calculate seed HMAC: [0x%02X] (%s)", err, esp_err_to_name(err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
ESP_FAULT_ASSERT(err == ESP_OK);
|
||||||
|
|
||||||
|
/* NOTE: If the XTS E-key and T-key are the same, we have a hash collision */
|
||||||
|
ESP_FAULT_ASSERT(memcmp(cfg->eky, cfg->tky, NVS_KEY_SIZE) != 0);
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_efuse_block_t convert_key_type(hmac_key_id_t key_id) {
|
||||||
|
return (esp_efuse_block_t)(EFUSE_BLK_KEY0 + (esp_efuse_block_t) key_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_hmac_key_burnt_in_efuse(hmac_key_id_t hmac_key_id)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
esp_efuse_block_t hmac_key_blk = convert_key_type(hmac_key_id);
|
||||||
|
|
||||||
|
esp_efuse_purpose_t hmac_efuse_blk_purpose = esp_efuse_get_key_purpose(hmac_key_blk);
|
||||||
|
if (hmac_efuse_blk_purpose == ESP_EFUSE_KEY_PURPOSE_HMAC_UP) {
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t generate_keys_hmac(const void* scheme_cfg, nvs_sec_cfg_t* cfg)
|
||||||
|
{
|
||||||
|
if (cfg == NULL) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
nvs_sec_config_hmac_t *scheme_cfg_hmac = (nvs_sec_config_hmac_t *)scheme_cfg;
|
||||||
|
|
||||||
|
hmac_key_id_t hmac_key = scheme_cfg_hmac->hmac_key_id;
|
||||||
|
if (hmac_key >= HMAC_KEY_MAX) {
|
||||||
|
ESP_LOGE(TAG, "Invalid HMAC key ID received!");
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t err = ESP_FAIL;
|
||||||
|
|
||||||
|
if (!is_hmac_key_burnt_in_efuse(hmac_key)) {
|
||||||
|
uint8_t hmac_key_buf[32] = {0};
|
||||||
|
|
||||||
|
bootloader_random_enable();
|
||||||
|
esp_fill_random(hmac_key_buf, sizeof(hmac_key_buf));
|
||||||
|
bootloader_random_disable();
|
||||||
|
|
||||||
|
esp_efuse_block_t hmac_key_blk = convert_key_type(hmac_key);
|
||||||
|
|
||||||
|
err = esp_efuse_write_key(hmac_key_blk, ESP_EFUSE_KEY_PURPOSE_HMAC_UP, hmac_key_buf, sizeof(hmac_key_buf));
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
if (err == ESP_ERR_EFUSE_REPEATED_PROG) {
|
||||||
|
ESP_LOGE(TAG, "Configured eFuse block for HMAC key already-in-use!");
|
||||||
|
return ESP_ERR_NVS_SEC_HMAC_KEY_BLK_ALREADY_USED;
|
||||||
|
}
|
||||||
|
ESP_LOGE(TAG, "Failed to write the HMAC key to eFuse: [0x%02X] (%s)", err, esp_err_to_name(err));
|
||||||
|
return ESP_ERR_NVS_SEC_HMAC_KEY_GENERATION_FAILED;
|
||||||
|
}
|
||||||
|
memset(hmac_key_buf, 0x00, sizeof(hmac_key_buf));
|
||||||
|
} else {
|
||||||
|
ESP_LOGW(TAG, "HMAC Key already present in configured eFuse block, using the same for NVS encryption!");
|
||||||
|
}
|
||||||
|
|
||||||
|
err = compute_nvs_keys_with_hmac(hmac_key, cfg);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "Failed to derive the encryption keys using HMAC!");
|
||||||
|
return ESP_ERR_NVS_SEC_HMAC_XTS_KEYS_DERIV_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t read_security_cfg_hmac(const void* scheme_cfg, nvs_sec_cfg_t* cfg)
|
||||||
|
{
|
||||||
|
if (cfg == NULL) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
nvs_sec_config_hmac_t *scheme_cfg_hmac = (nvs_sec_config_hmac_t *)scheme_cfg;
|
||||||
|
|
||||||
|
hmac_key_id_t hmac_key = scheme_cfg_hmac->hmac_key_id;
|
||||||
|
if (hmac_key >= HMAC_KEY_MAX) {
|
||||||
|
ESP_LOGE(TAG, "Invalid HMAC key ID received!");
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_hmac_key_burnt_in_efuse(hmac_key)) {
|
||||||
|
ESP_LOGE(TAG, "Could not find HMAC key in configured eFuse block!");
|
||||||
|
return ESP_ERR_NVS_SEC_HMAC_KEY_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t err = compute_nvs_keys_with_hmac(hmac_key, cfg);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "Failed to derive the encryption keys using HMAC!");
|
||||||
|
return ESP_ERR_NVS_SEC_HMAC_XTS_KEYS_DERIV_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t nvs_sec_provider_register_hmac(const nvs_sec_config_hmac_t *sec_scheme_cfg, nvs_sec_scheme_t **sec_scheme_handle_out)
|
||||||
|
{
|
||||||
|
if (sec_scheme_cfg == NULL || sec_scheme_handle_out == NULL) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
nvs_sec_scheme_t *sec_scheme = calloc(1, sizeof(nvs_sec_scheme_t));
|
||||||
|
if (sec_scheme == NULL) {
|
||||||
|
return ESP_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
sec_scheme->scheme_id = NVS_SEC_SCHEME_HMAC;
|
||||||
|
sec_scheme->nvs_flash_key_gen = &generate_keys_hmac;
|
||||||
|
sec_scheme->nvs_flash_read_cfg = &read_security_cfg_hmac;
|
||||||
|
|
||||||
|
sec_scheme->scheme_data = calloc(1, sizeof(nvs_sec_config_hmac_t));
|
||||||
|
if (sec_scheme->scheme_data == NULL) {
|
||||||
|
return ESP_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(sec_scheme->scheme_data, (void *)sec_scheme_cfg, sizeof(nvs_sec_config_hmac_t));
|
||||||
|
|
||||||
|
esp_err_t err = nvs_flash_register_security_scheme(sec_scheme);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
*sec_scheme_handle_out = sec_scheme;
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CONFIG_NVS_SEC_KEY_PROTECT_USING_HMAC
|
||||||
|
static void __attribute__((constructor)) nvs_sec_provider_register_hmac_ctr(void)
|
||||||
|
{
|
||||||
|
ESP_EARLY_LOGI(TAG, "NVS Encryption - Registering HMAC-based scheme...");
|
||||||
|
|
||||||
|
nvs_sec_config_hmac_t sec_scheme_cfg = NVS_SEC_PROVIDER_CFG_HMAC_DEFAULT();
|
||||||
|
nvs_sec_scheme_t *sec_scheme_handle_out = NULL;
|
||||||
|
|
||||||
|
nvs_sec_provider_register_hmac(&sec_scheme_cfg, &sec_scheme_handle_out);
|
||||||
|
}
|
||||||
|
#endif // CONFIG_NVS_SEC_KEY_PROTECT_USING_HMAC
|
||||||
|
|
||||||
|
#endif // SOC_HMAC_SUPPORTED
|
||||||
|
|
||||||
|
esp_err_t nvs_sec_provider_deregister(nvs_sec_scheme_t *sec_scheme_handle)
|
||||||
|
{
|
||||||
|
if (sec_scheme_handle == NULL) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sec_scheme_handle->scheme_data != NULL) {
|
||||||
|
free(sec_scheme_handle->scheme_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(sec_scheme_handle);
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nvs_sec_provider_include_impl(void)
|
||||||
|
{
|
||||||
|
// Linker hook, exists for no other purpose
|
||||||
|
}
|
@ -54,7 +54,8 @@ menu "Partition Table"
|
|||||||
for more information.
|
for more information.
|
||||||
config PARTITION_TABLE_SINGLE_APP_ENCRYPTED_NVS
|
config PARTITION_TABLE_SINGLE_APP_ENCRYPTED_NVS
|
||||||
bool "Single factory app, no OTA, encrypted NVS"
|
bool "Single factory app, no OTA, encrypted NVS"
|
||||||
depends on !ESP32_COREDUMP_ENABLE_TO_FLASH && NVS_ENCRYPTION
|
depends on !ESP32_COREDUMP_ENABLE_TO_FLASH && NVS_SEC_KEY_PROTECT_USING_FLASH_ENC
|
||||||
|
|
||||||
help
|
help
|
||||||
This is a variation of the default "Single factory app, no OTA" partition table
|
This is a variation of the default "Single factory app, no OTA" partition table
|
||||||
that supports encrypted NVS when using flash encryption. See the Flash Encryption section
|
that supports encrypted NVS when using flash encryption. See the Flash Encryption section
|
||||||
@ -64,7 +65,7 @@ menu "Partition Table"
|
|||||||
components/partition_table/partitions_singleapp_encr_nvs.csv
|
components/partition_table/partitions_singleapp_encr_nvs.csv
|
||||||
config PARTITION_TABLE_SINGLE_APP_LARGE_ENC_NVS
|
config PARTITION_TABLE_SINGLE_APP_LARGE_ENC_NVS
|
||||||
bool "Single factory app (large), no OTA, encrypted NVS"
|
bool "Single factory app (large), no OTA, encrypted NVS"
|
||||||
depends on !ESP32_COREDUMP_ENABLE_TO_FLASH && NVS_ENCRYPTION
|
depends on !ESP32_COREDUMP_ENABLE_TO_FLASH && NVS_SEC_KEY_PROTECT_USING_FLASH_ENC
|
||||||
help
|
help
|
||||||
This is a variation of the "Single factory app (large), no OTA" partition table
|
This is a variation of the "Single factory app (large), no OTA" partition table
|
||||||
that supports encrypted NVS when using flash encryption. See the Flash Encryption section
|
that supports encrypted NVS when using flash encryption. See the Flash Encryption section
|
||||||
@ -74,7 +75,7 @@ menu "Partition Table"
|
|||||||
components/partition_table/partitions_singleapp_large_encr_nvs.csv
|
components/partition_table/partitions_singleapp_large_encr_nvs.csv
|
||||||
config PARTITION_TABLE_TWO_OTA_ENCRYPTED_NVS
|
config PARTITION_TABLE_TWO_OTA_ENCRYPTED_NVS
|
||||||
bool "Factory app, two OTA definitions, encrypted NVS"
|
bool "Factory app, two OTA definitions, encrypted NVS"
|
||||||
depends on !ESP_COREDUMP_ENABLE_TO_FLASH && NVS_ENCRYPTION
|
depends on !ESP_COREDUMP_ENABLE_TO_FLASH && NVS_SEC_KEY_PROTECT_USING_FLASH_ENC
|
||||||
help
|
help
|
||||||
This is a variation of the "Factory app, two OTA definitions" partition table
|
This is a variation of the "Factory app, two OTA definitions" partition table
|
||||||
that supports encrypted NVS when using flash encryption. See the Flash Encryption section
|
that supports encrypted NVS when using flash encryption. See the Flash Encryption section
|
||||||
|
Loading…
Reference in New Issue
Block a user