diff --git a/components/esp_hw_support/CMakeLists.txt b/components/esp_hw_support/CMakeLists.txt index dec7467301..309ebc3558 100644 --- a/components/esp_hw_support/CMakeLists.txt +++ b/components/esp_hw_support/CMakeLists.txt @@ -117,6 +117,10 @@ if(NOT BOOTLOADER_BUILD) list(APPEND srcs "esp_ds.c") endif() + if(CONFIG_SOC_KEY_MANAGER_SUPPORTED) + list(APPEND srcs "esp_key_mgr.c") + endif() + if(CONFIG_SOC_PAU_SUPPORTED) list(APPEND srcs "port/pau_regdma.c" "port/regdma_link.c") diff --git a/components/esp_hw_support/esp_key_mgr.c b/components/esp_hw_support/esp_key_mgr.c new file mode 100644 index 0000000000..c5b2e2d232 --- /dev/null +++ b/components/esp_hw_support/esp_key_mgr.c @@ -0,0 +1,219 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +// The Hardware Support layer for Key manager +#include "hal/key_mgr_types.h" +#include "hal/key_mgr_hal.h" +#include "hal/huk_types.h" +#include "hal/huk_hal.h" +#include "esp_key_mgr.h" +#include "hal/clk_gate_ll.h" +#include "esp_log.h" +#include "esp_err.h" +#include "assert.h" +#include "string.h" + +static const char *TAG = "esp_key_mgr"; +static void key_mgr_wait_for_state(esp_key_mgr_state_t state) +{ + while (key_mgr_hal_get_state() != state) { + ; + } +} + +esp_err_t esp_key_mgr_deploy_key_in_aes_mode(esp_key_mgr_aes_key_config_t *key_config, esp_key_mgr_key_recovery_info_t *key_info) +{ + ESP_LOGI(TAG, "Key Deployment"); + // Reset the Key Manager Clock + periph_ll_enable_clk_clear_rst(PERIPH_KEY_MANAGER_MODULE); + + key_mgr_wait_for_state(ESP_KEY_MGR_STATE_IDLE); + uint8_t *huk_recovery_info = (uint8_t *) calloc(1, sizeof(KEY_MGR_HUK_INFO_SIZE)); + if (!huk_recovery_info) { + return ESP_ERR_NO_MEM; + } + uint8_t *key_recovery_info = (uint8_t *) calloc(1, sizeof(KEY_MGR_KEY_RECOVERY_INFO_SIZE)); + if (!key_recovery_info) { + return ESP_ERR_NO_MEM; + } + + if (key_config->huk_info && key_config->huk_info_size) { + if (key_config->huk_info_size != KEY_MGR_HUK_INFO_SIZE) { + ESP_LOGE(TAG, "Invalid HUK info given"); + return ESP_ERR_INVALID_ARG; + } + ESP_LOGI(TAG, "Recovering key from given HUK recovery info"); + // If HUK info is provided then recover the HUK from given info + huk_hal_configure(ESP_HUK_MODE_RECOVERY, key_config->huk_info); + } else { + // Generate new HUK and corresponding HUK info + ESP_LOGI(TAG, "Generating new HUK"); + huk_hal_configure(ESP_HUK_MODE_GENERATION, huk_recovery_info); + } + + ESP_LOGI(TAG, "HUK generated successfully"); + // Configure deployment mode to AES + key_mgr_hal_set_key_generator_mode(ESP_KEY_MGR_KEYGEN_MODE_AES); + + // Set key purpose (XTS/ECDSA) + key_mgr_hal_set_key_purpose(key_config->key_purpose); + + if (key_config->use_sw_init_key) { + key_mgr_hal_use_sw_init_key(); + } + + key_mgr_hal_start(); + key_mgr_hal_continue(); + key_mgr_wait_for_state(ESP_KEY_MGR_STATE_LOAD); + if (key_config->use_sw_init_key) { + assert(key_config->sw_init_key_size == KEY_MGR_SW_INIT_KEY_SIZE); + key_mgr_hal_write_sw_init_key(key_config->sw_init_key, key_config->sw_init_key_size); + } + ESP_LOGI(TAG, "Writing Information into Key Manager Registers"); + key_mgr_hal_write_assist_info(key_config->k2_info, KEY_MGR_K2_INFO_SIZE); + key_mgr_hal_write_public_info(key_config->k1_encrypted, KEY_MGR_K1_ENCRYPTED_SIZE); + key_mgr_hal_continue(); + key_mgr_wait_for_state(ESP_KEY_MGR_STATE_GAIN); + key_mgr_hal_read_public_info(key_recovery_info, KEY_MGR_KEY_RECOVERY_INFO_SIZE); + ESP_LOG_BUFFER_HEX_LEVEL("HUK INFO", huk_recovery_info, KEY_MGR_HUK_INFO_SIZE, ESP_LOG_INFO); + ESP_LOG_BUFFER_HEX_LEVEL("KEY_MGR KEY INFO", key_recovery_info, KEY_MGR_KEY_RECOVERY_INFO_SIZE, ESP_LOG_INFO); + + //TODO - check if HUK is valid just after it is generated + if (!key_mgr_hal_is_huk_valid()) { + ESP_LOGE(TAG, "HUK is invalid"); + // TODO - define error code + return ESP_FAIL; + } + ESP_LOGI(TAG, "HUK deplpoyed is Valid"); + + if (!key_mgr_hal_is_key_deployment_valid(key_config->key_type)) { + ESP_LOGE(TAG, "Key deployment is not valid"); + // Todo - Define respective error code; + return ESP_FAIL; + } + ESP_LOGI(TAG, "Key deployment valid"); + // Wait till Key Manager deployment is complete + key_mgr_hal_continue(); + key_mgr_wait_for_state(ESP_KEY_MGR_STATE_IDLE); + //memcpy(&key_info->huk_recovery_info[0], huk_recovery_info, KEY_MGR_HUK_INFO_SIZE); + //memcpy(&key_info->key_recovery_info[0], key_recovery_info, KEY_MGR_KEY_RECOVERY_INFO_SIZE); + key_info->key_purpose = key_config->key_purpose; + free(key_recovery_info); + free(huk_recovery_info); + key_mgr_hal_set_key_usage(ESP_KEY_MGR_XTS_KEY, ESP_KEY_MGR_USE_OWN_KEY); + return ESP_OK; +} + +esp_err_t esp_key_mgr_recover_key(esp_key_mgr_key_recovery_info_t *key_recovery_info) +{ + periph_ll_enable_clk_clear_rst(PERIPH_KEY_MANAGER_MODULE); + key_mgr_wait_for_state(ESP_KEY_MGR_STATE_IDLE); + huk_hal_configure(ESP_HUK_MODE_RECOVERY, key_recovery_info->huk_recovery_info); + if (key_mgr_hal_is_huk_valid()) { + ESP_LOGD(TAG, "HUK is invalid"); + // TODO - define error code + return ESP_FAIL; + } + ESP_LOGI(TAG, "purpose = %d", key_recovery_info->key_purpose); + key_mgr_hal_set_key_purpose(key_recovery_info->key_purpose); + key_mgr_hal_start(); + key_mgr_hal_continue(); + key_mgr_wait_for_state(ESP_KEY_MGR_STATE_LOAD); + key_mgr_hal_write_assist_info(key_recovery_info->huk_recovery_info, KEY_MGR_HUK_INFO_SIZE); + key_mgr_hal_continue(); + key_mgr_wait_for_state(ESP_KEY_MGR_STATE_GAIN); + if (!key_mgr_hal_is_key_deployment_valid(key_recovery_info->key_type)) { + ESP_LOGD(TAG, "Key deployment is not valid"); + // Todo - Define respective error code; + return ESP_FAIL; + } + ESP_LOGI(TAG, "Key deployment valid"); + key_mgr_hal_continue(); + key_mgr_wait_for_state(ESP_KEY_MGR_STATE_IDLE); + return ESP_OK; +} + +esp_err_t esp_key_mgr_deploy_key_in_ecdh0_mode(esp_key_mgr_ecdh0_key_config_t *key_config, esp_key_mgr_key_recovery_info_t *key_info) +{ + ESP_LOGI(TAG, "Key Deployment"); + // Reset the Key Manager Clock + periph_ll_enable_clk_clear_rst(PERIPH_KEY_MANAGER_MODULE); + + key_mgr_wait_for_state(ESP_KEY_MGR_STATE_IDLE); + uint8_t *huk_recovery_info = (uint8_t *) calloc(1, sizeof(KEY_MGR_HUK_INFO_SIZE)); + if (!huk_recovery_info) { + return ESP_ERR_NO_MEM; + } + uint8_t *key_recovery_info = (uint8_t *) calloc(1, sizeof(KEY_MGR_KEY_RECOVERY_INFO_SIZE)); + if (!key_recovery_info) { + return ESP_ERR_NO_MEM; + } + + if (key_config->huk_info && key_config->huk_info_size) { + if (key_config->huk_info_size != KEY_MGR_HUK_INFO_SIZE) { + ESP_LOGE(TAG, "Invalid HUK info given"); + return ESP_ERR_INVALID_ARG; + } + ESP_LOGI(TAG, "Recovering key from given HUK recovery info"); + // If HUK info is provided then recover the HUK from given info + huk_hal_configure(ESP_HUK_MODE_RECOVERY, key_config->huk_info); + } else { + // Generate new HUK and corresponding HUK info + ESP_LOGI(TAG, "Generating new HUK"); + huk_hal_configure(ESP_HUK_MODE_GENERATION, huk_recovery_info); + } + + ESP_LOGI(TAG, "HUK generated successfully"); + // Configure deployment mode to AES + key_mgr_hal_set_key_generator_mode(ESP_KEY_MGR_KEYGEN_MODE_AES); + + // Set key purpose (XTS/ECDSA) + key_mgr_hal_set_key_purpose(key_config->key_purpose); + + if (key_config->use_sw_init_key) { + key_mgr_hal_use_sw_init_key(); + } + + key_mgr_hal_start(); + key_mgr_hal_continue(); + key_mgr_wait_for_state(ESP_KEY_MGR_STATE_LOAD); + if (key_config->use_sw_init_key) { + assert(key_config->sw_init_key_size == KEY_MGR_SW_INIT_KEY_SIZE); + key_mgr_hal_write_sw_init_key(key_config->sw_init_key, key_config->sw_init_key_size); + } + ESP_LOGI(TAG, "Writing Information into Key Manager Registers"); + key_mgr_hal_write_public_info(key_config->k1_G, KEY_MGR_ECDH0_INFO_SIZE); + key_mgr_hal_continue(); + key_mgr_wait_for_state(ESP_KEY_MGR_STATE_GAIN); + key_mgr_hal_read_public_info(key_recovery_info, KEY_MGR_KEY_RECOVERY_INFO_SIZE); + key_mgr_hal_read_assist_info(key_config->k2_G); + ESP_LOG_BUFFER_HEX_LEVEL("HUK INFO", huk_recovery_info, KEY_MGR_HUK_INFO_SIZE, ESP_LOG_INFO); + ESP_LOG_BUFFER_HEX_LEVEL("KEY_MGR KEY INFO", key_recovery_info, KEY_MGR_KEY_RECOVERY_INFO_SIZE, ESP_LOG_INFO); + + //TODO - check if HUK is valid just after it is generated + if (!key_mgr_hal_is_huk_valid()) { + ESP_LOGE(TAG, "HUK is invalid"); + // TODO - define error code + return ESP_FAIL; + } + ESP_LOGI(TAG, "HUK deplpoyed is Valid"); + + if (!key_mgr_hal_is_key_deployment_valid(key_config->key_type)) { + ESP_LOGE(TAG, "Key deployment is not valid"); + // Todo - Define respective error code; + return ESP_FAIL; + } + ESP_LOGI(TAG, "Key deployment valid"); + // Wait till Key Manager deployment is complete + key_mgr_hal_continue(); + key_mgr_wait_for_state(ESP_KEY_MGR_STATE_IDLE); + //memcpy(&key_info->huk_recovery_info[0], huk_recovery_info, KEY_MGR_HUK_INFO_SIZE); + //memcpy(&key_info->key_recovery_info[0], key_recovery_info, KEY_MGR_KEY_RECOVERY_INFO_SIZE); + key_info->key_purpose = key_config->key_purpose; + free(key_recovery_info); + free(huk_recovery_info); + key_mgr_hal_set_key_usage(ESP_KEY_MGR_XTS_KEY, ESP_KEY_MGR_USE_OWN_KEY); + return ESP_OK; +} diff --git a/components/esp_hw_support/include/esp_key_mgr.h b/components/esp_hw_support/include/esp_key_mgr.h new file mode 100644 index 0000000000..04ac53283f --- /dev/null +++ b/components/esp_hw_support/include/esp_key_mgr.h @@ -0,0 +1,93 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#include "hal/key_mgr_types.h" +#include "hal/huk_types.h" + +#define KEY_MGR_SW_INIT_KEY_SIZE 32 +#define KEY_MGR_ASSIST_INFO_SIZE 64 +#define KEY_MGR_KEY_RECOVERY_INFO_SIZE 64 +#define KEY_MGR_HUK_INFO_SIZE 64 +/* AES deploy mode */ +#define KEY_MGR_K2_INFO_SIZE 64 +#define KEY_MGR_K1_ENCRYPTED_SIZE 32 +#define KEY_MGR_ECDH0_INFO_SIZE 64 + +typedef struct { + // TODO - Should we use fixed arrays here instead of pointers ? + esp_key_mgr_key_type_t key_type; + uint8_t *huk_info; + size_t huk_info_size; + esp_key_mgr_key_purpose_t key_purpose; + bool use_sw_init_key; + uint8_t *sw_init_key; + size_t sw_init_key_size; + uint8_t k2_info[KEY_MGR_K2_INFO_SIZE]; + uint8_t k1_encrypted[KEY_MGR_K1_ENCRYPTED_SIZE]; +} esp_key_mgr_aes_key_config_t; + +typedef struct { + // TODO - Should we use fixed arrays here instead of pointers ? + esp_key_mgr_key_type_t key_type; + uint8_t *huk_info; + size_t huk_info_size; + esp_key_mgr_key_purpose_t key_purpose; + bool use_sw_init_key; + uint8_t *sw_init_key; + size_t sw_init_key_size; + uint8_t k1_G[KEY_MGR_ECDH0_INFO_SIZE]; + uint8_t k2_G[KEY_MGR_ECDH0_INFO_SIZE]; +} esp_key_mgr_ecdh0_key_config_t; + +typedef struct { + uint8_t huk_recovery_info[KEY_MGR_HUK_INFO_SIZE]; + uint8_t key_recovery_info[KEY_MGR_KEY_RECOVERY_INFO_SIZE]; + esp_key_mgr_key_type_t key_type; + esp_key_mgr_key_purpose_t key_purpose; +} __attribute__((packed)) esp_key_mgr_key_recovery_info_t; + +/** + * @brief Check if the deployed key is valid or not + * @input + * key_config(input) AES key configuration + * key_info(output) A writable struct of esp_key_mgr_key_info_t type. The recovery key info for the deplyed key shall be stored here + * @return + * ESP_OK for success + * ESP_FAIL/relevant error code for failure + */ +esp_err_t esp_key_mgr_deploy_key_in_aes_mode(esp_key_mgr_aes_key_config_t *key_config, esp_key_mgr_key_recovery_info_t *key_info); + +/** + * @brief Check if the deployed key is valid or not + * @input + * key_config(input) AES key configuration + * key_info(output) A writable struct of esp_key_mgr_key_info_t type. The recovery key info for the deplyed key shall be stored here + * @return + * ESP_OK for success + * ESP_FAIL/relevant error code for failure + */ +esp_err_t esp_key_mgr_deploy_key_in_aes_mode(esp_key_mgr_aes_key_config_t *key_config, esp_key_mgr_key_recovery_info_t *key_info); + +/* + * @brief Recover a key from the given key info + * + * @input + * key_info The key info required to recover the key + * @return + * ESP_OK for success + * ESP_FAIL/revevant error code for failure + */ +esp_err_t esp_key_mgr_recover_key(esp_key_mgr_key_recovery_info_t *key_recovery_info); +#ifdef __cplusplus +} +#endif diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index b2fb0c346f..1b99ded463 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -143,6 +143,10 @@ config SOC_ECDSA_SUPPORTED bool default y +config SOC_KEY_MANAGER_SUPPORTED + bool + default y + config SOC_FLASH_ENC_SUPPORTED bool default y diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 0358f666a3..b196fae992 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -60,7 +60,7 @@ #define SOC_ECC_SUPPORTED 1 #define SOC_ECC_EXTENDED_MODES_SUPPORTED 1 #define SOC_ECDSA_SUPPORTED 1 -// #define SOC_KEY_MANAGER_SUPPORTED 1 //TODO: IDF-7925 +#define SOC_KEY_MANAGER_SUPPORTED 1 #define SOC_FLASH_ENC_SUPPORTED 1 #define SOC_SECURE_BOOT_SUPPORTED 1 // #define SOC_BOD_SUPPORTED 1 //TODO: IDF-7519 diff --git a/examples/peripherals/README.md b/examples/peripherals/README.md index eef44e9462..363d8fcd27 100644 --- a/examples/peripherals/README.md +++ b/examples/peripherals/README.md @@ -1,3 +1,6 @@ +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | + # Peripherals Examples This section provides examples how to configure and use ESP32’s internal peripherals like GPIO, UART, I2C, SPI, timers, counters, ADC / DAC, PWM, etc.