feat: enable key manager and HUK support for S31

This commit is contained in:
nilesh.kale
2026-05-13 13:18:46 +05:30
parent e1d429ba30
commit a530aab0a6
16 changed files with 831 additions and 13 deletions

View File

@@ -94,6 +94,14 @@ static inline ds_key_check_t ds_ll_key_error_source(void)
}
}
/**
* @brief Set the DS key source.
*/
static inline void ds_ll_set_key_source(ds_key_source_t key_source)
{
REG_WRITE(DS_STATIC_REG, key_source);
}
/**
* @brief Write the initialization vector to the corresponding register field.
*/

View File

@@ -0,0 +1,129 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use it in application code.
******************************************************************************/
#pragma once
#include "soc/soc_caps.h"
#if SOC_KEY_MANAGER_SUPPORTED
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "hal/huk_types.h"
#include "soc/huk_reg.h"
#include "soc/soc_caps.h"
#ifdef __cplusplus
extern "C" {
#endif
static inline void huk_ll_power_up(void)
{
}
/* @brief Configure the HUK mode */
static inline void huk_ll_configure_mode(const esp_huk_mode_t huk_mode)
{
REG_SET_FIELD(HUK_CONF_REG, HUK_MODE, huk_mode);
}
static inline void huk_ll_write_info(const uint8_t *buffer, const size_t size)
{
memcpy((uint8_t *)HUK_INFO_MEM, buffer, size);
}
static inline void huk_ll_read_info(uint8_t *buffer, const size_t size)
{
memcpy(buffer, (uint8_t *)HUK_INFO_MEM, size);
}
/* @brief Start the HUK at IDLE state */
static inline void huk_ll_start(void)
{
REG_SET_FIELD(HUK_START_REG, HUK_START, 1);
}
/* @brief Continue HUK operation at LOAD/GAIN state */
static inline void huk_ll_continue(void)
{
REG_SET_FIELD(HUK_START_REG, HUK_CONTINUE, 1);
}
/* @bried Enable or Disable the HUK interrupts */
static inline void huk_ll_configure_interrupt(const esp_huk_interrupt_type_t intr, const bool en)
{
switch (intr) {
case ESP_HUK_INT_PREP_DONE:
REG_SET_FIELD(HUK_INT_ENA_REG, HUK_PREP_DONE_INT_ENA, en);
break;
case ESP_HUK_INT_PROC_DONE:
REG_SET_FIELD(HUK_INT_ENA_REG, HUK_PROC_DONE_INT_ENA, en);
break;
case ESP_HUK_INT_POST_DONE:
REG_SET_FIELD(HUK_INT_ENA_REG, HUK_POST_DONE_INT_ENA, en);
break;
default:
return;
}
}
/* @bried Clear the HUK interrupts */
static inline void huk_ll_clear_int(const esp_huk_interrupt_type_t intr)
{
switch (intr) {
case ESP_HUK_INT_PREP_DONE:
REG_SET_FIELD(HUK_INT_CLR_REG, HUK_PREP_DONE_INT_CLR, 1);
break;
case ESP_HUK_INT_PROC_DONE:
REG_SET_FIELD(HUK_INT_CLR_REG, HUK_PROC_DONE_INT_CLR, 1);
break;
case ESP_HUK_INT_POST_DONE:
REG_SET_FIELD(HUK_INT_CLR_REG, HUK_POST_DONE_INT_CLR, 1);
break;
default:
return;
}
}
/**
* @brief Read state of Hardware Unique Key Generator
*
* @return esp_huk_state_t
*/
static inline esp_huk_state_t huk_ll_get_state(void)
{
return (esp_huk_state_t) REG_GET_FIELD(HUK_STATE_REG, HUK_STATE);
}
/**
* @brief Get the HUK generation status
*/
static inline esp_huk_gen_status_t huk_ll_get_gen_status(void)
{
return (esp_huk_gen_status_t) REG_GET_FIELD(HUK_STATUS_REG, HUK_STATUS);
}
/**
* @brief Read the HUK date information
*/
static inline uint32_t huk_ll_get_date_info(void)
{
// Only the least significant 28 bits have desired information
return (uint32_t)(0x0FFFFFFF & REG_READ(HUK_DATE_REG));
}
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,470 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use it in application code.
******************************************************************************/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "hal/assert.h"
#include "hal/key_mgr_types.h"
#include "soc/keymng_reg.h"
#include "soc/hp_sys_clkrst_struct.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* ESP32-S31 Key Manager register differences from ESP32-P4:
*
* - use_efuse_key: Packed 5-bit field KEYMNG_USE_EFUSE_KEY[4:0] in KEYMNG_STATIC_REG
* bit 0: ECDSA, bit 1: Flash, bit 2: HMAC, bit 3: DS, bit 4: PSRAM
* - use_efuse_key_lock: Packed 5-bit field KEYMNG_USE_EFUSE_KEY_LOCK[4:0] in KEYMNG_LOCK_REG
* Same bit assignment as use_efuse_key
* - Clock/Reset: key_manager_ctrl0 register (not peri_clk_ctrl25 / hp_rst_en2)
*/
/* Bit positions within the packed KEYMNG_USE_EFUSE_KEY field */
#define KEY_MGR_EFUSE_KEY_ECDSA_BIT 0
#define KEY_MGR_EFUSE_KEY_FLASH_BIT 1
#define KEY_MGR_EFUSE_KEY_HMAC_BIT 2
#define KEY_MGR_EFUSE_KEY_DS_BIT 3
#define KEY_MGR_EFUSE_KEY_PSRAM_BIT 4
static inline void key_mgr_ll_power_up(void)
{
}
static inline void key_mgr_ll_power_down(void)
{
}
/**
* @brief Enable the bus clock for Key Manager peripheral
* Note: Please use key_mgr_ll_enable_bus_clock which requires the critical section
* and do not use _key_mgr_ll_enable_bus_clock
* @param true to enable, false to disable
*/
static inline void _key_mgr_ll_enable_bus_clock(bool enable)
{
HP_SYS_CLKRST.key_manager_ctrl0.reg_key_manager_sys_clk_en = enable;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define key_mgr_ll_enable_bus_clock(...) do { \
(void)__DECLARE_RCC_ATOMIC_ENV; \
_key_mgr_ll_enable_bus_clock(__VA_ARGS__); \
} while(0)
/**
* @brief Enable the peripheral clock for Key Manager
*
* Note: Please use key_mgr_ll_enable_peripheral_clock which requires the critical section
* and do not use _key_mgr_ll_enable_peripheral_clock
* @param true to enable, false to disable
*/
static inline void _key_mgr_ll_enable_peripheral_clock(bool enable)
{
HP_SYS_CLKRST.key_manager_ctrl0.reg_crypto_km_clk_en = enable;
}
#define key_mgr_ll_enable_peripheral_clock(...) do { \
(void)__DECLARE_RCC_ATOMIC_ENV; \
_key_mgr_ll_enable_peripheral_clock(__VA_ARGS__); \
} while(0)
/**
* @brief Read state of Key Manager
*
* @return esp_key_mgr_state_t
*/
static inline esp_key_mgr_state_t key_mgr_ll_get_state(void)
{
return (esp_key_mgr_state_t) REG_GET_FIELD(KEYMNG_STATE_REG, KEYMNG_STATE);
}
/**
* @brief Reset the Key Manager peripheral
* Note: Please use key_mgr_ll_reset_register which requires the critical section
* and do not use _key_mgr_ll_reset_register
*/
static inline void _key_mgr_ll_reset_register(void)
{
HP_SYS_CLKRST.key_manager_ctrl0.reg_crypto_km_rst_en = 1;
HP_SYS_CLKRST.key_manager_ctrl0.reg_crypto_km_rst_en = 0;
while (key_mgr_ll_get_state() != ESP_KEY_MGR_STATE_IDLE) {
};
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define key_mgr_ll_reset_register(...) do { \
(void)__DECLARE_RCC_ATOMIC_ENV; \
_key_mgr_ll_reset_register(__VA_ARGS__); \
} while(0)
/* @brief Start the key manager at IDLE state */
static inline void key_mgr_ll_start(void)
{
REG_SET_BIT(KEYMNG_START_REG, KEYMNG_START);
}
/* @brief Continue key manager operation at LOAD/GAIN state */
static inline void key_mgr_ll_continue(void)
{
REG_SET_BIT(KEYMNG_START_REG, KEYMNG_CONTINUE);
}
/* @brief Enable or Disable the KEY_MGR interrupts */
static inline void key_mgr_ll_configure_interrupt(const esp_key_mgr_interrupt_type_t intr, bool en)
{
switch (intr) {
case ESP_KEY_MGR_INT_PREP_DONE:
REG_SET_FIELD(KEYMNG_INT_ENA_REG, KEYMNG_PREP_DONE_INT_ENA, en);
break;
case ESP_KEY_MGR_INT_PROC_DONE:
REG_SET_FIELD(KEYMNG_INT_ENA_REG, KEYMNG_PROC_DONE_INT_ENA, en);
break;
case ESP_KEY_MGR_INT_POST_DONE:
REG_SET_FIELD(KEYMNG_INT_ENA_REG, KEYMNG_POST_DONE_INT_ENA, en);
break;
default:
return;
}
}
/* @brief Clear the KEY_MGR interrupts */
static inline void key_mgr_ll_clear_int(const esp_key_mgr_interrupt_type_t intr)
{
switch (intr) {
case ESP_KEY_MGR_INT_PREP_DONE:
REG_SET_FIELD(KEYMNG_INT_CLR_REG, KEYMNG_PREP_DONE_INT_CLR, 1);
break;
case ESP_KEY_MGR_INT_PROC_DONE:
REG_SET_FIELD(KEYMNG_INT_CLR_REG, KEYMNG_PROC_DONE_INT_CLR, 1);
break;
case ESP_KEY_MGR_INT_POST_DONE:
REG_SET_FIELD(KEYMNG_INT_CLR_REG, KEYMNG_POST_DONE_INT_CLR, 1);
break;
default:
return;
}
}
/**
* @brief Helper: get the bit position for a key type in the packed use_efuse_key field
*/
static inline int _key_mgr_ll_get_efuse_key_bit(const esp_key_mgr_key_type_t key_type)
{
switch (key_type) {
case ESP_KEY_MGR_ECDSA_KEY:
return KEY_MGR_EFUSE_KEY_ECDSA_BIT;
case ESP_KEY_MGR_FLASH_XTS_AES_KEY:
return KEY_MGR_EFUSE_KEY_FLASH_BIT;
case ESP_KEY_MGR_HMAC_KEY:
return KEY_MGR_EFUSE_KEY_HMAC_BIT;
case ESP_KEY_MGR_DS_KEY:
return KEY_MGR_EFUSE_KEY_DS_BIT;
case ESP_KEY_MGR_PSRAM_XTS_AES_KEY:
return KEY_MGR_EFUSE_KEY_PSRAM_BIT;
default:
HAL_ASSERT(false && "Unsupported key type");
return -1;
}
}
/**
* @brief Set the key manager to use the software provided init key
*/
static inline void key_mgr_ll_use_sw_init_key(void)
{
REG_SET_BIT(KEYMNG_STATIC_REG, KEYMNG_USE_SW_INIT_KEY);
}
/**
* @brief Configure the key manager key usage policy for a particular key type
*
* On ESP32-S31, use_efuse_key is a packed 5-bit field. We use read-modify-write
* to set/clear individual bits.
*/
static inline void key_mgr_ll_set_key_usage(const esp_key_mgr_key_type_t key_type, const esp_key_mgr_key_usage_t key_usage)
{
int bit = _key_mgr_ll_get_efuse_key_bit(key_type);
if (bit < 0) {
return;
}
uint32_t val = REG_GET_FIELD(KEYMNG_STATIC_REG, KEYMNG_USE_EFUSE_KEY);
if (key_usage == ESP_KEY_MGR_USE_EFUSE_KEY) {
val |= (1U << bit);
} else {
val &= ~(1U << bit);
}
REG_SET_FIELD(KEYMNG_STATIC_REG, KEYMNG_USE_EFUSE_KEY, val);
}
static inline esp_key_mgr_key_usage_t key_mgr_ll_get_key_usage(esp_key_mgr_key_type_t key_type)
{
int bit = _key_mgr_ll_get_efuse_key_bit(key_type);
if (bit < 0) {
return ESP_KEY_MGR_USAGE_INVALID;
}
uint32_t val = REG_GET_FIELD(KEYMNG_STATIC_REG, KEYMNG_USE_EFUSE_KEY);
return (val & (1U << bit)) ? ESP_KEY_MGR_USE_EFUSE_KEY : ESP_KEY_MGR_USE_OWN_KEY;
}
/**
* @brief Set the lock for the use_sw_init_key_reg
* After this lock has been set,
* The Key manager configuration about the use of software init key cannot be changed
*/
static inline void key_mgr_ll_lock_use_sw_init_key_reg(void)
{
REG_SET_BIT(KEYMNG_LOCK_REG, KEYMNG_USE_SW_INIT_KEY_LOCK);
}
/**
* @brief Set the lock for use_efuse_key for a particular key type
* After this lock has been set,
* The Key manager configuration about whether to use a particular key from efuse or key manager cannot be changed.
*
* On ESP32-S31, use_efuse_key_lock is a packed 5-bit field (same bit positions as use_efuse_key).
*/
static inline void key_mgr_ll_lock_use_efuse_key_reg(esp_key_mgr_key_type_t key_type)
{
int bit = _key_mgr_ll_get_efuse_key_bit(key_type);
if (bit < 0) {
return;
}
uint32_t val = REG_GET_FIELD(KEYMNG_LOCK_REG, KEYMNG_USE_EFUSE_KEY_LOCK);
val |= (1U << bit);
REG_SET_FIELD(KEYMNG_LOCK_REG, KEYMNG_USE_EFUSE_KEY_LOCK, val);
}
/* @brief Configure the key purpose to be used by the Key Manager for key generator operation */
static inline void key_mgr_ll_set_key_purpose(const esp_key_mgr_key_purpose_t key_purpose)
{
REG_SET_FIELD(KEYMNG_CONF_REG, KEYMNG_KEY_PURPOSE, key_purpose);
}
/**
* @brief Configure the mode which is used by the Key Manager for the generator key deployment process
*/
static inline void key_mgr_ll_set_key_generator_mode(const esp_key_mgr_key_generator_mode_t mode)
{
REG_SET_FIELD(KEYMNG_CONF_REG, KEYMNG_KGEN_MODE, mode);
}
/**
* @brief Read the key manager process result
* @return 1 for Success
* 0 for failure
*/
static inline bool key_mgr_ll_is_result_success(void)
{
return REG_GET_FIELD(KEYMNG_RESULT_REG, KEYMNG_PROC_RESULT);
}
/**
* @brief Check if the deployed key is valid or not
* @return 1 for Success
* 0 for failure
*/
static inline bool key_mgr_ll_is_key_deployment_valid(const esp_key_mgr_key_type_t key_type, const esp_key_mgr_key_len_t key_len)
{
switch (key_type) {
case ESP_KEY_MGR_ECDSA_KEY:
switch (key_len) {
case ESP_KEY_MGR_ECDSA_LEN_192:
return REG_GET_FIELD(KEYMNG_KEY_VLD_REG, KEYMNG_KEY_ECDSA_192_VLD);
case ESP_KEY_MGR_ECDSA_LEN_256:
return REG_GET_FIELD(KEYMNG_KEY_VLD_REG, KEYMNG_KEY_ECDSA_256_VLD);
case ESP_KEY_MGR_ECDSA_LEN_384:
return REG_GET_FIELD(KEYMNG_KEY_VLD_REG, KEYMNG_KEY_ECDSA_384_VLD);
default:
HAL_ASSERT(false && "Unsupported key type");
return 0;
}
case ESP_KEY_MGR_FLASH_XTS_AES_KEY:
switch (key_len) {
case ESP_KEY_MGR_XTS_AES_LEN_128:
case ESP_KEY_MGR_XTS_AES_LEN_256:
return REG_GET_FIELD(KEYMNG_KEY_VLD_REG, KEYMNG_KEY_FLASH_VLD);
default:
HAL_ASSERT(false && "Unsupported key type");
return 0;
}
case ESP_KEY_MGR_HMAC_KEY:
return REG_GET_FIELD(KEYMNG_KEY_VLD_REG, KEYMNG_KEY_HMAC_VLD);
case ESP_KEY_MGR_DS_KEY:
return REG_GET_FIELD(KEYMNG_KEY_VLD_REG, KEYMNG_KEY_DS_VLD);
case ESP_KEY_MGR_PSRAM_XTS_AES_KEY:
switch (key_len) {
case ESP_KEY_MGR_XTS_AES_LEN_128:
case ESP_KEY_MGR_XTS_AES_LEN_256:
return REG_GET_FIELD(KEYMNG_KEY_VLD_REG, KEYMNG_KEY_PSRAM_VLD);
default:
HAL_ASSERT(false && "Unsupported key type");
return 0;
}
default:
HAL_ASSERT(false && "Unsupported mode");
return 0;
}
}
/*
* @brief Write the SW init key in the key manager registers
*
* @input
* sw_init_key_buf Init key buffer, this should be a readable buffer of data_len size which should contain the sw init key. The buffer must be 32 bit aligned
* data_len Length of the init key buffer
*/
static inline void key_mgr_ll_write_sw_init_key(const uint8_t *sw_init_key_buf, const size_t data_len)
{
memcpy((uint8_t *)KEYMNG_SW_INIT_KEY_MEM, sw_init_key_buf, data_len);
}
/*
* @brief Write the Assist info in the key manager registers
*
* @input
* assist_info_buf Assist info buffer, this should be a readable buffer of data_len size which should contain the assist info. The buffer must be 32 bit aligned
* data_len Length of the assist info buffer
*/
static inline void key_mgr_ll_write_assist_info(const uint8_t *assist_info_buf, const size_t data_len)
{
memcpy((uint8_t *)KEYMNG_ASSIST_INFO_MEM, assist_info_buf, data_len);
}
/*
* @brief Read the Assist info from the key manager registers
*
* @input
* assist_info_buf Assist info buffer, this should be a writable buffer of size KEY_MGR_ASSIST_INFO_LEN. The buffer must be 32 bit aligned
*/
static inline void key_mgr_ll_read_assist_info(uint8_t *assist_info_buf)
{
memcpy(assist_info_buf, (uint8_t *)KEYMNG_ASSIST_INFO_MEM, KEY_MGR_ASSIST_INFO_LEN);
}
/*
* @brief Write the Public info in the key manager registers
* @input
* public_info_buf Public info buffer, this should be a readable buffer of data_len size which should contain the public info. The buffer must be 32 bit aligned
* data_len Length of the public info buffer
*/
static inline void key_mgr_ll_write_public_info(const uint8_t *public_info_buf, const size_t data_len)
{
memcpy((uint8_t *)KEYMNG_PUBLIC_INFO_MEM, public_info_buf, data_len);
}
/*
* @brief Read the Public info in the key manager registers
* @input
* public_info_buf Public info buffer, this should be a writable buffer of read_len, The buffer must be 32 bit aligned
* read_len Length of the public info buffer
*/
static inline void key_mgr_ll_read_public_info(uint8_t *public_info_buf, const size_t read_len)
{
memcpy(public_info_buf, (uint8_t *)KEYMNG_PUBLIC_INFO_MEM, read_len);
}
static inline bool key_mgr_ll_is_huk_valid(void)
{
return REG_GET_FIELD(KEYMNG_HUK_VLD_REG, KEYMNG_HUK_VALID);
}
/* @brief Set the XTS-AES (Flash Encryption) key length for the Key Manager */
static inline void key_mgr_ll_set_xts_aes_key_len(const esp_key_mgr_key_type_t key_type, const esp_key_mgr_key_len_t key_len)
{
uint32_t key_len_bit_mask;
if (key_type == ESP_KEY_MGR_FLASH_XTS_AES_KEY) {
key_len_bit_mask = KEYMNG_FLASH_KEY_LEN;
} else if (key_type == ESP_KEY_MGR_PSRAM_XTS_AES_KEY) {
key_len_bit_mask = KEYMNG_PSRAM_KEY_LEN;
} else {
HAL_ASSERT(false && "Unsupported key type");
return;
}
switch (key_len) {
case ESP_KEY_MGR_XTS_AES_LEN_128:
REG_CLR_BIT(KEYMNG_STATIC_REG, key_len_bit_mask);
break;
case ESP_KEY_MGR_XTS_AES_LEN_256:
REG_SET_BIT(KEYMNG_STATIC_REG, key_len_bit_mask);
break;
default:
HAL_ASSERT(false && "Unsupported key length");
return;
}
}
/* @brief Get the XTS-AES (Flash Encryption) key length for the Key Manager */
static inline esp_key_mgr_key_len_t key_mgr_ll_get_xts_aes_key_len(const esp_key_mgr_key_type_t key_type)
{
uint32_t key_len_bit = 0;
if (key_type == ESP_KEY_MGR_FLASH_XTS_AES_KEY) {
key_len_bit = REG_GET_BIT(KEYMNG_STATIC_REG, KEYMNG_FLASH_KEY_LEN);
} else if (key_type == ESP_KEY_MGR_PSRAM_XTS_AES_KEY) {
key_len_bit = REG_GET_BIT(KEYMNG_STATIC_REG, KEYMNG_PSRAM_KEY_LEN);
} else {
HAL_ASSERT(false && "Unsupported key type");
return (esp_key_mgr_key_len_t) key_len_bit;
}
switch (key_len_bit) {
case 0:
return ESP_KEY_MGR_XTS_AES_LEN_128;
case 1:
return ESP_KEY_MGR_XTS_AES_LEN_256;
default:
HAL_ASSERT(false && "Unsupported key length");
return (esp_key_mgr_key_len_t) key_len_bit;
}
}
/**
* @brief Read the Key Manager date information
*/
static inline uint32_t key_mgr_ll_get_date_info(void)
{
// Only the least significant 28 bits have desired information
return (uint32_t)(0x0FFFFFFF & REG_READ(KEYMNG_DATE_REG));
}
static inline bool key_mgr_ll_is_supported(void)
{
return true;
}
static inline bool key_mgr_ll_flash_encryption_supported(void)
{
if (!key_mgr_ll_is_supported()) {
return false;
}
return true;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,112 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "soc/soc_caps.h"
#if SOC_KEY_MANAGER_SUPPORTED
#include <stdint.h>
#include "esp_attr.h"
#include "ets_sys.h"
#include "km.h"
#if __cplusplus
extern "C" {
#endif
struct huk_info {
// store huk info, occupy 165 words
#define HUK_INFO_LEN 660
uint8_t info[HUK_INFO_LEN];
uint32_t crc;
} PACKED_ATTR;
// store key info, occupy 512 bits
struct key_info {
#define KEY_INFO_LEN 64
uint8_t info[KEY_INFO_LEN];
uint32_t crc;
} PACKED_ATTR;
struct huk_key_block {
#define KEY_HUK_SECTOR_MAGIC 0xDEA5CE5A
uint32_t magic;
uint32_t version; // for backward compatibility
uint8_t reserved[16];
struct huk_info huk_info;
struct key_info key_info[2]; // at most 2 key info (XTS-512_1 and XTS-512_2), at least use 1
} WORD_ALIGNED_ATTR PACKED_ATTR;
/*
* We define two info sectors "active" and "backup" here
* Most rom code would rely only on the "active" sector for the key information
*
* But there could be a situation where the huk and key information must be regenerated
* based on ageing and other factors. For that scenario, we need a "backup" sector
*/
#define KEY_HUK_SECTOR_OFFSET(i) ((i)*0x1000)
#define ACTIVE_SECTOR_OFFSET KEY_HUK_SECTOR_OFFSET(0)
#define BACKUP_SECTOR_OFFSET KEY_HUK_SECTOR_OFFSET(1)
#define KM_PERI_ECDSA (BIT(0))
#define KM_PERI_XTS (BIT(1))
struct km_deploy_ops {
#define KM_KEY_PURPOSE_ECDSA_KEY_192 1
#define KM_KEY_PURPOSE_ECDSA_KEY_256 2
#define KM_KEY_PURPOSE_FLASH_XTS_256_1 3
#define KM_KEY_PURPOSE_FLASH_XTS_256_2 4
#define KM_KEY_PURPOSE_FLASH_XTS_128 5
#define KM_KEY_PURPOSE_HMAC 6
#define KM_KEY_PURPOSE_DS 7
#define KM_KEY_PURPOSE_PSRAM_XTS_256_1 8
#define KM_KEY_PURPOSE_PSRAM_XTS_256_2 9
#define KM_KEY_PURPOSE_PSRAM_XTS_128 10
#define KM_KEY_PURPOSE_ECDSA_KEY_384_L 11
#define KM_KEY_PURPOSE_ECDSA_KEY_384_H 12
int km_key_purpose;
#define KM_DEPLOY_MODE_RANDOM 0
#define KM_DEPLOY_MODE_AES 1
#define KM_DEPLOY_MODE_ECDH0 2
#define KM_DEPLOY_MODE_ECDH1 3
#define KM_DEPLOY_MODE_RECOVER 4
#define KM_DEPLOY_MODE_EXPORT 5
int deploy_mode;
uint8_t *init_key; // 256 bits, only used in aes and ecdh1 deploy mode
int deploy_only_once;
int force_use_km_key;
int km_use_efuse_key;
uint32_t efuse_km_rnd_switch_cycle; // 0 means use default
uint32_t km_rnd_switch_cycle; // 0 means use default
int km_use_sw_init_key;
struct huk_info *huk_info;
struct key_info *key_info;
};
/* state of km */
#define KM_STATE_IDLE 0
#define KM_STATE_LOAD 1
#define KM_STATE_GAIN 2
#define KM_STATE_BUSY 3
#define KM_STATE_INVALID 4
/* state of huk generator
* values defined same as km
*/
#define HUK_STATE_IDLE 0
#define HUK_STATE_LOAD 1
#define HUK_STATE_GAIN 2
#define HUK_STATE_BUSY 3
#define HUK_NOT_GENERATED 0
#define HUK_GEN_VALID 1
#define HUK_GEN_INVALID 2
#if __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,63 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _KM_H
#define _KM_H
#include "soc/soc_caps.h"
#if SOC_KEY_MANAGER_SUPPORTED
#include <stdint.h>
#include "soc/soc.h"
#include "ets_sys.h"
#if __cplusplus
extern "C" {
#endif
/* huk mode type */
typedef enum {
HUK_MODE_RECOVER = 0,
HUK_MODE_GEN = 1,
} huk_mode_t;
/**
* @brief Recover efuse key or key manager key if flash encryption is enabled
*
* @param do_log : if km process print log
*
* @return ETS_OK when key is recovered, ETS_FAILED when key not recovered
*/
ETS_STATUS esp_rom_check_recover_key(int do_log);
/**
* @brief Configure huk mode
*
* @param mode : HUK_MODE_RECOVER or HUK_MODE_GEN
*
* @param huk_info : uint8_t pointer to the buffer which will feed the huk info or
* gain the huk info
*
* @return ETS_OK when huk configuration is done, else ETS_FAILED
*/
ETS_STATUS esp_rom_km_huk_conf(huk_mode_t mode, uint8_t *huk_info);
/**
* @brief Get huk risk. The risk level of HUK is 0-6: the higher the risk level is,
* the more error bits there are in the PUF SRAM. 7: Error level, HUK is invalid
*
* @param None
*
* @return The huk risk
*/
int esp_rom_km_huk_risk(void);
#ifdef __cplusplus
}
#endif
#endif
#endif /* _KM_H */

View File

@@ -3,10 +3,6 @@
components/esp_security/test_apps/crypto_drivers:
enable:
- if: ((SOC_HMAC_SUPPORTED == 1) or (SOC_DIG_SIGN_SUPPORTED == 1)) or (SOC_KEY_MANAGER_SUPPORTED == 1)
disable:
- if: IDF_TARGET == "esp32s31"
temporary: true
reason: not supported yet # TODO: IDF-14626
depends_components:
- esp_security
- esp_hal_security

View File

@@ -1,3 +1,3 @@
| Supported Targets | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- |
| Supported Targets | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | ESP32-S31 |
| ----------------- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | --------- |

View File

@@ -68,6 +68,7 @@ static const char *TAG = "key_mgr_test";
} \
} while (0)
#if SOC_KEY_MANAGER_FE_KEY_DEPLOY
#define ENCRYPTED_DATA_SIZE 128
static const uint8_t plaintext_data[ENCRYPTED_DATA_SIZE] = {
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
@@ -90,6 +91,7 @@ static const uint8_t expected_ciphertext[ENCRYPTED_DATA_SIZE] = {
0x85, 0xe2, 0x69, 0x26, 0xfb, 0x61, 0x7e, 0x15, 0x11, 0x26, 0x59, 0xf1, 0x4f, 0xeb, 0x4d, 0x25,
0x8e, 0xc5, 0xb9, 0x64, 0xdf, 0xc7, 0x52, 0x87, 0x2d, 0xb, 0xd6, 0xdd, 0xb1, 0xb3, 0xfe, 0xaf,
};
#endif /* SOC_KEY_MANAGER_FE_KEY_DEPLOY */
/* Big endian */
static const uint8_t init_key[] = {
@@ -105,11 +107,13 @@ static const uint8_t k2_info[] = {
0x88, 0x9d, 0x0b, 0x2b, 0x40, 0x87, 0x6e, 0x58, 0xf3, 0xf3, 0x63, 0x62, 0xd1, 0x5c, 0x9a, 0xe8
};
#if SOC_KEY_MANAGER_FE_KEY_DEPLOY
/* Big endian */
static const uint8_t k1_xts_aes_encrypt[] = {
0x0a, 0x43, 0x2a, 0xee, 0xb5, 0xd0, 0x6b, 0x58, 0x34, 0x2d, 0x0d, 0xbf, 0xf7, 0x04, 0x60, 0x81,
0x08, 0x79, 0x38, 0xb3, 0xb5, 0xdf, 0x25, 0xb4, 0x38, 0x8e, 0x93, 0x5d, 0xbf, 0xd1, 0x91, 0x6d,
};
#endif /* SOC_KEY_MANAGER_FE_KEY_DEPLOY */
static const uint8_t k1_hmac_encrypt[] = {
0x02, 0xf7, 0x05, 0x75, 0xfd, 0x12, 0x99, 0xc2, 0xb9, 0xc0, 0x2e, 0x40, 0xd0, 0x69, 0xb0, 0x83,

View File

@@ -8,7 +8,7 @@ from pytest_embedded_idf.utils import idf_parametrize
@pytest.mark.generic
@idf_parametrize(
'target',
['esp32s2', 'esp32s3', 'esp32c3', 'esp32c6', 'esp32h2', 'esp32h4', 'esp32p4', 'esp32c5'],
['esp32s2', 'esp32s3', 'esp32c3', 'esp32c6', 'esp32h2', 'esp32h4', 'esp32p4', 'esp32c5', 'esp32s31'],
indirect=['target'],
)
def test_crypto_drivers(dut: Dut) -> None:

View File

@@ -0,0 +1,3 @@
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"

View File

@@ -1079,6 +1079,30 @@ config SOC_EFUSE_ECDSA_KEY_P384
bool
default y
config SOC_HUK_SUPPORTED
bool
default y
config SOC_KEY_MANAGER_SUPPORTED
bool
default y
config SOC_KEY_MANAGER_SUPPORT_KEY_DEPLOYMENT
bool
default y
config SOC_KEY_MANAGER_ECDSA_KEY_DEPLOY
bool
default y
config SOC_KEY_MANAGER_HMAC_KEY_DEPLOY
bool
default y
config SOC_KEY_MANAGER_DS_KEY_DEPLOY
bool
default y
config SOC_LCDCAM_CAM_SUPPORT_RGB_YUV_CONV
bool
default y

View File

@@ -412,10 +412,17 @@
#define SOC_EFUSE_ECDSA_KEY_P192 1
#define SOC_EFUSE_ECDSA_KEY_P384 1
/*-------------------------- HUK CAPS----------------------------*/
#define SOC_HUK_SUPPORTED 1
/*-------------------------- Key Manager CAPS----------------------------*/
// TODO: [ESP32S31] IDF-14626
// #define SOC_KEY_MANAGER_ECDSA_KEY_DEPLOY 1 /*!< Key manager responsible to deploy ECDSA key */
// #define SOC_KEY_MANAGER_FE_KEY_DEPLOY 1 /*!< Key manager responsible to deploy Flash Encryption key */
#define SOC_KEY_MANAGER_SUPPORTED 1
#define SOC_KEY_MANAGER_SUPPORT_KEY_DEPLOYMENT 1 /*!< Key manager supports key deployment */
#define SOC_KEY_MANAGER_ECDSA_KEY_DEPLOY 1 /*!< Key manager responsible to deploy ECDSA key */
#define SOC_KEY_MANAGER_HMAC_KEY_DEPLOY 1 /*!< Key manager responsible to deploy HMAC key */
#define SOC_KEY_MANAGER_DS_KEY_DEPLOY 1 /*!< Key manager responsible to deploy DS key */
// SOC_KEY_MANAGER_FE_KEY_DEPLOY (incl. XTS-AES-128/256) will be enabled along with Flash Encryption support.
/*--------------------------- CAM ---------------------------------*/
#define SOC_LCDCAM_CAM_SUPPORT_RGB_YUV_CONV (1)

View File

@@ -11,6 +11,8 @@ INPUT += \
$(PROJECT_PATH)/components/esp_driver_touch_sens/include/driver/touch_sens_types.h\
$(PROJECT_PATH)/components/esp_phy/include/esp_phy_init.h \
$(PROJECT_PATH)/components/esp_phy/include/esp_phy_cert_test.h \
$(PROJECT_PATH)/components/esp_security/include/esp_key_mgr.h \
$(PROJECT_PATH)/components/esp_hal_security/include/hal/key_mgr_types.h \
$(PROJECT_PATH)/components/bt/include/esp32s31/include/esp_bt.h \
$(PROJECT_PATH)/components/bt/include/esp32s31/include/esp_bt_vs.h \
$(PROJECT_PATH)/components/ulp/lp_core/include/lp_core_i2c.h \

View File

@@ -435,7 +435,7 @@ To test flash encryption process, take the following steps:
This command will write to flash memory unencrypted images: the second stage bootloader, the partition table and applications. Once the flashing is complete, {IDF_TARGET_NAME} will reset. On the next boot, the second stage bootloader encrypts: the second stage bootloader, application partitions and partitions marked as ``encrypted`` then resets. Encrypting in-place can take time, up to a minute for large partitions. After that, the application is decrypted at runtime and executed.
.. only:: SOC_KEY_MANAGER_SUPPORTED
.. only:: SOC_KEY_MANAGER_FE_KEY_DEPLOY
A sample output of the first {IDF_TARGET_NAME} boot after enabling flash encryption using a Key Manager-based key is given below:

View File

@@ -435,7 +435,7 @@ flash 加密设置
该命令将向 flash 写入未加密的镜像:二级引导加载程序、分区表和应用程序。烧录完成后,{IDF_TARGET_NAME} 将复位。在下一次启动时,二级引导加载程序会加密:二级引导加载程序、应用程序分区和标记为 ``encrypted`` 分区,然后复位。就地加密可能需要时间,对于大分区最多需要一分钟。之后,应用程序在运行时解密并执行。
.. only:: SOC_KEY_MANAGER_SUPPORTED
.. only:: SOC_KEY_MANAGER_FE_KEY_DEPLOY
下面是使用基于密钥管理器的密钥启用 flash 加密后,{IDF_TARGET_NAME} 首次启动时的样例输出:

View File

@@ -1,5 +1,5 @@
| Supported Targets | ESP32-C5 | ESP32-P4 |
| ----------------- | -------- | -------- |
| Supported Targets | ESP32-C5 | ESP32-P4 | ESP32-S31 |
| ----------------- | -------- | -------- | --------- |
# Key Manager Signing Example