mirror of
https://github.com/espressif/esp-idf.git
synced 2025-09-09 16:38:10 +00:00
feat(esp_security): Move DS, HMAC, DPA and crypto lock implementation
This commit is contained in:
10
components/esp_security/src/esp32/esp_crypto_clk.h
Normal file
10
components/esp_security/src/esp32/esp_crypto_clk.h
Normal file
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/* nothing to do */
|
||||
static inline void esp_crypto_clk_init(void) {}
|
10
components/esp_security/src/esp32c2/esp_crypto_clk.h
Normal file
10
components/esp_security/src/esp32c2/esp_crypto_clk.h
Normal file
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/* nothing to do */
|
||||
static inline void esp_crypto_clk_init(void) {}
|
10
components/esp_security/src/esp32c3/esp_crypto_clk.h
Normal file
10
components/esp_security/src/esp32c3/esp_crypto_clk.h
Normal file
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/* nothing to do */
|
||||
static inline void esp_crypto_clk_init(void) {}
|
@@ -3,10 +3,13 @@
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "soc/soc.h"
|
||||
#include "soc/pcr_reg.h"
|
||||
|
||||
__attribute__((weak)) void esp_crypto_clk_init(void)
|
||||
#pragma once
|
||||
|
||||
static inline void esp_crypto_clk_init(void)
|
||||
{
|
||||
// Set crypto clock (`clk_sec`) to use 480M SPLL clock
|
||||
REG_SET_FIELD(PCR_SEC_CONF_REG, PCR_SEC_CLK_SEL, 0x2);
|
10
components/esp_security/src/esp32c6/esp_crypto_clk.h
Normal file
10
components/esp_security/src/esp32c6/esp_crypto_clk.h
Normal file
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/* nothing to do */
|
||||
static inline void esp_crypto_clk_init(void) {}
|
16
components/esp_security/src/esp32c61/esp_crypto_clk.h
Normal file
16
components/esp_security/src/esp32c61/esp_crypto_clk.h
Normal file
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "soc/soc.h"
|
||||
#include "soc/pcr_reg.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
static inline void esp_crypto_clk_init(void)
|
||||
{
|
||||
// Set crypto clock (`clk_sec`) to use 480M SPLL clock
|
||||
REG_SET_FIELD(PCR_SEC_CONF_REG, PCR_SEC_CLK_SEL, 0x2);
|
||||
}
|
@@ -3,10 +3,13 @@
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "soc/soc.h"
|
||||
#include "soc/pcr_reg.h"
|
||||
|
||||
__attribute__((weak)) void esp_crypto_clk_init(void)
|
||||
#pragma once
|
||||
|
||||
static inline void esp_crypto_clk_init(void)
|
||||
{
|
||||
// Set crypto clock (`clk_sec`) to use 96M PLL clock
|
||||
REG_SET_FIELD(PCR_SEC_CONF_REG, PCR_SEC_CLK_SEL, 0x3);
|
@@ -6,7 +6,9 @@
|
||||
#include "soc/soc.h"
|
||||
#include "soc/hp_sys_clkrst_reg.h"
|
||||
|
||||
__attribute__((weak)) void esp_crypto_clk_init(void)
|
||||
#pragma once
|
||||
|
||||
static inline void esp_crypto_clk_init(void)
|
||||
{
|
||||
// Set crypto clock (`clk_sec`) to use 240M PLL clock
|
||||
REG_SET_FIELD(HP_SYS_CLKRST_PERI_CLK_CTRL25_REG, HP_SYS_CLKRST_REG_CRYPTO_CLK_SRC_SEL, 0x2);
|
10
components/esp_security/src/esp32s2/esp_crypto_clk.h
Normal file
10
components/esp_security/src/esp32s2/esp_crypto_clk.h
Normal file
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/* nothing to do */
|
||||
static inline void esp_crypto_clk_init(void) {}
|
10
components/esp_security/src/esp32s3/esp_crypto_clk.h
Normal file
10
components/esp_security/src/esp32s3/esp_crypto_clk.h
Normal file
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/* nothing to do */
|
||||
static inline void esp_crypto_clk_init(void) {}
|
@@ -16,12 +16,10 @@ static inline void esp_crypto_dpa_set_level(esp_crypto_dpa_sec_level_t level)
|
||||
REG_SET_FIELD(HP_SYSTEM_SEC_DPA_CONF_REG, HP_SYSTEM_SEC_DPA_LEVEL, level);
|
||||
}
|
||||
|
||||
#if CONFIG_ESP_CRYPTO_DPA_PROTECTION_AT_STARTUP
|
||||
static void __attribute__((constructor)) esp_crypto_dpa_protection_startup(void)
|
||||
void esp_crypto_dpa_protection_startup(void)
|
||||
{
|
||||
esp_crypto_dpa_set_level(CONFIG_ESP_CRYPTO_DPA_PROTECTION_LEVEL);
|
||||
}
|
||||
#endif
|
||||
|
||||
void esp_crypto_dpa_protection_enable(esp_crypto_dpa_sec_level_t level)
|
||||
{
|
||||
@@ -32,8 +30,3 @@ void esp_crypto_dpa_protection_disable(void)
|
||||
{
|
||||
REG_CLR_BIT(HP_SYSTEM_SEC_DPA_CONF_REG, HP_SYSTEM_SEC_DPA_CFG_SEL);
|
||||
}
|
||||
|
||||
void esp_crypto_dpa_prot_include_impl(void)
|
||||
{
|
||||
// Linker hook, exists for no other purpose
|
||||
}
|
480
components/esp_security/src/esp_ds.c
Normal file
480
components/esp_security/src/esp_ds.c
Normal file
@@ -0,0 +1,480 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#include "esp_timer.h"
|
||||
#include "esp_ds.h"
|
||||
#include "esp_crypto_lock.h"
|
||||
#include "esp_private/esp_crypto_lock_internal.h"
|
||||
#include "esp_hmac.h"
|
||||
#include "esp_memory_utils.h"
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/aes.h"
|
||||
#include "esp32s2/rom/sha.h"
|
||||
#include "esp32s2/rom/hmac.h"
|
||||
#include "soc/soc_memory_layout.h"
|
||||
#else /* CONFIG_IDF_TARGET_ESP32S2 */
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "hal/aes_ll.h"
|
||||
#include "hal/ds_hal.h"
|
||||
#include "hal/ds_ll.h"
|
||||
#include "hal/hmac_hal.h"
|
||||
#include "hal/hmac_ll.h"
|
||||
#include "hal/sha_ll.h"
|
||||
#endif /* !CONFIG_IDF_TARGET_ESP32S2 */
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/digital_signature.h"
|
||||
#endif
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
#include "esp32s3/rom/digital_signature.h"
|
||||
#endif
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
#include "esp32c3/rom/digital_signature.h"
|
||||
#endif
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32C6
|
||||
#include "esp32c6/rom/digital_signature.h"
|
||||
#endif
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32C5
|
||||
#include "esp32c5/rom/digital_signature.h"
|
||||
#endif
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32H2
|
||||
#include "esp32h2/rom/digital_signature.h"
|
||||
#endif
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32P4
|
||||
#include "esp32p4/rom/digital_signature.h"
|
||||
#endif
|
||||
|
||||
struct esp_ds_context {
|
||||
const ets_ds_data_t *data;
|
||||
};
|
||||
|
||||
/**
|
||||
* The vtask delay \c esp_ds_sign() is using while waiting for completion of the signing operation.
|
||||
*/
|
||||
#define ESP_DS_SIGN_TASK_DELAY_MS 10
|
||||
|
||||
#define RSA_LEN_MAX ((SOC_RSA_MAX_BIT_LEN/8) - 1)
|
||||
|
||||
/*
|
||||
* Check that the size of esp_ds_data_t and ets_ds_data_t is the same because both structs are converted using
|
||||
* raw casts.
|
||||
*/
|
||||
_Static_assert(sizeof(esp_ds_data_t) == sizeof(ets_ds_data_t),
|
||||
"The size and structure of esp_ds_data_t and ets_ds_data_t must match exactly, they're used in raw casts");
|
||||
|
||||
/*
|
||||
* esp_digital_signature_length_t is used in esp_ds_data_t in contrast to ets_ds_data_t, where unsigned is used.
|
||||
* Check esp_digital_signature_length_t's width here because it's converted to unsigned using raw casts.
|
||||
*/
|
||||
_Static_assert(sizeof(esp_digital_signature_length_t) == sizeof(unsigned),
|
||||
"The size of esp_digital_signature_length_t and unsigned has to be the same");
|
||||
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32S2
|
||||
|
||||
static void ds_acquire_enable(void)
|
||||
{
|
||||
/* Lock AES, SHA and RSA peripheral */
|
||||
esp_crypto_dma_lock_acquire();
|
||||
esp_crypto_mpi_lock_acquire();
|
||||
ets_hmac_enable();
|
||||
ets_ds_enable();
|
||||
}
|
||||
|
||||
static void ds_disable_release(void)
|
||||
{
|
||||
ets_ds_disable();
|
||||
ets_hmac_disable();
|
||||
esp_crypto_mpi_lock_release();
|
||||
esp_crypto_dma_lock_release();
|
||||
}
|
||||
|
||||
esp_err_t esp_ds_sign(const void *message,
|
||||
const esp_ds_data_t *data,
|
||||
hmac_key_id_t key_id,
|
||||
void *signature)
|
||||
{
|
||||
// Need to check signature here, otherwise the signature is only checked when the signing has finished and fails
|
||||
// but the signing isn't uninitialized and the mutex is still locked.
|
||||
if (!signature) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_ds_context_t *context;
|
||||
esp_err_t result = esp_ds_start_sign(message, data, key_id, &context);
|
||||
if (result != ESP_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
while (esp_ds_is_busy()) {
|
||||
vTaskDelay(ESP_DS_SIGN_TASK_DELAY_MS / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
return esp_ds_finish_sign(signature, context);
|
||||
}
|
||||
|
||||
esp_err_t esp_ds_start_sign(const void *message,
|
||||
const esp_ds_data_t *data,
|
||||
hmac_key_id_t key_id,
|
||||
esp_ds_context_t **esp_ds_ctx)
|
||||
{
|
||||
if (!message || !data || !esp_ds_ctx) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (key_id >= HMAC_KEY_MAX) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (!(data->rsa_length == ESP_DS_RSA_1024
|
||||
|| data->rsa_length == ESP_DS_RSA_2048
|
||||
|| data->rsa_length == ESP_DS_RSA_3072
|
||||
#if SOC_RSA_MAX_BIT_LEN == 4096
|
||||
|| data->rsa_length == ESP_DS_RSA_4096
|
||||
#endif
|
||||
)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
ds_acquire_enable();
|
||||
|
||||
// initiate hmac
|
||||
int r = ets_hmac_calculate_downstream(ETS_EFUSE_BLOCK_KEY0 + (ets_efuse_block_t) key_id,
|
||||
ETS_EFUSE_KEY_PURPOSE_HMAC_DOWN_DIGITAL_SIGNATURE);
|
||||
if (r != ETS_OK) {
|
||||
ds_disable_release();
|
||||
return ESP_ERR_HW_CRYPTO_DS_HMAC_FAIL;
|
||||
}
|
||||
|
||||
esp_ds_context_t *context = malloc(sizeof(esp_ds_context_t));
|
||||
if (!context) {
|
||||
ds_disable_release();
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
ets_ds_data_t *ds_data = (ets_ds_data_t *) data;
|
||||
|
||||
// initiate signing
|
||||
ets_ds_result_t result = ets_ds_start_sign(message, ds_data);
|
||||
|
||||
// ETS_DS_INVALID_PARAM only happens if a parameter is NULL or data->rsa_length is wrong
|
||||
// We checked all of that already
|
||||
assert(result != ETS_DS_INVALID_PARAM);
|
||||
|
||||
if (result == ETS_DS_INVALID_KEY) {
|
||||
ds_disable_release();
|
||||
free(context);
|
||||
return ESP_ERR_HW_CRYPTO_DS_INVALID_KEY;
|
||||
}
|
||||
|
||||
context->data = (const ets_ds_data_t *)ds_data;
|
||||
*esp_ds_ctx = context;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
bool esp_ds_is_busy(void)
|
||||
{
|
||||
return ets_ds_is_busy();
|
||||
}
|
||||
|
||||
esp_err_t esp_ds_finish_sign(void *signature, esp_ds_context_t *esp_ds_ctx)
|
||||
{
|
||||
if (!signature || !esp_ds_ctx) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
const ets_ds_data_t *ds_data = esp_ds_ctx->data;
|
||||
|
||||
ets_ds_result_t result = ets_ds_finish_sign(signature, ds_data);
|
||||
|
||||
esp_err_t return_value = ESP_OK;
|
||||
|
||||
// we checked all the parameters
|
||||
assert(result != ETS_DS_INVALID_PARAM);
|
||||
|
||||
if (result == ETS_DS_INVALID_DIGEST) {
|
||||
return_value = ESP_ERR_HW_CRYPTO_DS_INVALID_DIGEST;
|
||||
}
|
||||
if (result == ETS_DS_INVALID_PADDING) {
|
||||
return_value = ESP_ERR_HW_CRYPTO_DS_INVALID_PADDING;
|
||||
}
|
||||
|
||||
free(esp_ds_ctx);
|
||||
|
||||
int res = ets_hmac_invalidate_downstream(ETS_EFUSE_KEY_PURPOSE_HMAC_DOWN_DIGITAL_SIGNATURE);
|
||||
assert(res == ETS_OK); // should not fail if called with correct purpose
|
||||
(void)res;
|
||||
|
||||
ds_disable_release();
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
esp_err_t esp_ds_encrypt_params(esp_ds_data_t *data,
|
||||
const void *iv,
|
||||
const esp_ds_p_data_t *p_data,
|
||||
const void *key)
|
||||
{
|
||||
// p_data has to be valid, in internal memory and word aligned
|
||||
if (!p_data) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
assert(esp_ptr_internal(p_data) && esp_ptr_word_aligned(p_data));
|
||||
|
||||
esp_err_t result = ESP_OK;
|
||||
|
||||
esp_crypto_dma_lock_acquire();
|
||||
ets_aes_enable();
|
||||
ets_sha_enable();
|
||||
|
||||
ets_ds_data_t *ds_data = (ets_ds_data_t *) data;
|
||||
const ets_ds_p_data_t *ds_plain_data = (const ets_ds_p_data_t *) p_data;
|
||||
|
||||
ets_ds_result_t ets_result = ets_ds_encrypt_params(ds_data, iv, ds_plain_data, key, ETS_DS_KEY_HMAC);
|
||||
|
||||
if (ets_result == ETS_DS_INVALID_PARAM) {
|
||||
result = ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
ets_sha_disable();
|
||||
ets_aes_disable();
|
||||
esp_crypto_dma_lock_release();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#else /* !CONFIG_IDF_TARGET_ESP32S2 (targets other than esp32s2) */
|
||||
|
||||
static void ds_acquire_enable(void)
|
||||
{
|
||||
esp_crypto_ds_lock_acquire();
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
esp_crypto_mpi_lock_acquire();
|
||||
#endif
|
||||
// We also enable SHA and HMAC here. SHA is used by HMAC, HMAC is used by DS.
|
||||
HMAC_RCC_ATOMIC() {
|
||||
hmac_ll_enable_bus_clock(true);
|
||||
hmac_ll_reset_register();
|
||||
}
|
||||
|
||||
SHA_RCC_ATOMIC() {
|
||||
sha_ll_enable_bus_clock(true);
|
||||
sha_ll_reset_register();
|
||||
}
|
||||
|
||||
DS_RCC_ATOMIC() {
|
||||
ds_ll_enable_bus_clock(true);
|
||||
ds_ll_reset_register();
|
||||
}
|
||||
|
||||
hmac_hal_start();
|
||||
}
|
||||
|
||||
static void ds_disable_release(void)
|
||||
{
|
||||
ds_hal_finish();
|
||||
|
||||
DS_RCC_ATOMIC() {
|
||||
ds_ll_enable_bus_clock(false);
|
||||
}
|
||||
|
||||
SHA_RCC_ATOMIC() {
|
||||
sha_ll_enable_bus_clock(false);
|
||||
}
|
||||
|
||||
HMAC_RCC_ATOMIC() {
|
||||
hmac_ll_enable_bus_clock(false);
|
||||
}
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
esp_crypto_mpi_lock_release();
|
||||
#endif
|
||||
esp_crypto_ds_lock_release();
|
||||
}
|
||||
|
||||
esp_err_t esp_ds_sign(const void *message,
|
||||
const esp_ds_data_t *data,
|
||||
hmac_key_id_t key_id,
|
||||
void *signature)
|
||||
{
|
||||
// Need to check signature here, otherwise the signature is only checked when the signing has finished and fails
|
||||
// but the signing isn't uninitialized and the mutex is still locked.
|
||||
if (!signature) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_ds_context_t *context;
|
||||
esp_err_t result = esp_ds_start_sign(message, data, key_id, &context);
|
||||
if (result != ESP_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
while (esp_ds_is_busy()) {
|
||||
vTaskDelay(ESP_DS_SIGN_TASK_DELAY_MS / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
return esp_ds_finish_sign(signature, context);
|
||||
}
|
||||
|
||||
esp_err_t esp_ds_start_sign(const void *message,
|
||||
const esp_ds_data_t *data,
|
||||
hmac_key_id_t key_id,
|
||||
esp_ds_context_t **esp_ds_ctx)
|
||||
{
|
||||
if (!message || !data || !esp_ds_ctx) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (key_id >= HMAC_KEY_MAX) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (!(data->rsa_length == ESP_DS_RSA_1024
|
||||
|| data->rsa_length == ESP_DS_RSA_2048
|
||||
|| data->rsa_length == ESP_DS_RSA_3072
|
||||
#if SOC_RSA_MAX_BIT_LEN == 4096
|
||||
|| data->rsa_length == ESP_DS_RSA_4096
|
||||
#endif
|
||||
)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
ds_acquire_enable();
|
||||
|
||||
// initiate hmac
|
||||
uint32_t conf_error = hmac_hal_configure(HMAC_OUTPUT_DS, key_id);
|
||||
if (conf_error) {
|
||||
ds_disable_release();
|
||||
return ESP_ERR_HW_CRYPTO_DS_HMAC_FAIL;
|
||||
}
|
||||
|
||||
ds_hal_start();
|
||||
|
||||
// check encryption key from HMAC
|
||||
int64_t start_time = esp_timer_get_time();
|
||||
while (ds_ll_busy() != 0) {
|
||||
if ((esp_timer_get_time() - start_time) > SOC_DS_KEY_CHECK_MAX_WAIT_US) {
|
||||
ds_disable_release();
|
||||
return ESP_ERR_HW_CRYPTO_DS_INVALID_KEY;
|
||||
}
|
||||
}
|
||||
|
||||
esp_ds_context_t *context = malloc(sizeof(esp_ds_context_t));
|
||||
if (!context) {
|
||||
ds_disable_release();
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
size_t rsa_len = (data->rsa_length + 1) * 4;
|
||||
ds_hal_write_private_key_params(data->c);
|
||||
ds_hal_configure_iv((uint32_t *)data->iv);
|
||||
ds_hal_write_message(message, rsa_len);
|
||||
|
||||
// initiate signing
|
||||
ds_hal_start_sign();
|
||||
|
||||
context->data = (const ets_ds_data_t *)data;
|
||||
*esp_ds_ctx = context;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
bool esp_ds_is_busy(void)
|
||||
{
|
||||
return ds_hal_busy();
|
||||
}
|
||||
|
||||
esp_err_t esp_ds_finish_sign(void *signature, esp_ds_context_t *esp_ds_ctx)
|
||||
{
|
||||
if (!signature || !esp_ds_ctx) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
const esp_ds_data_t *data = (const esp_ds_data_t *)esp_ds_ctx->data;
|
||||
unsigned rsa_len = (data->rsa_length + 1) * 4;
|
||||
|
||||
while (ds_hal_busy()) { }
|
||||
|
||||
ds_signature_check_t sig_check_result = ds_hal_read_result((uint8_t *) signature, (size_t) rsa_len);
|
||||
|
||||
esp_err_t return_value = ESP_OK;
|
||||
|
||||
if (sig_check_result == DS_SIGNATURE_MD_FAIL || sig_check_result == DS_SIGNATURE_PADDING_AND_MD_FAIL) {
|
||||
return_value = ESP_ERR_HW_CRYPTO_DS_INVALID_DIGEST;
|
||||
}
|
||||
|
||||
if (sig_check_result == DS_SIGNATURE_PADDING_FAIL) {
|
||||
return_value = ESP_ERR_HW_CRYPTO_DS_INVALID_PADDING;
|
||||
}
|
||||
|
||||
free(esp_ds_ctx);
|
||||
|
||||
hmac_hal_clean();
|
||||
|
||||
ds_disable_release();
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
esp_err_t esp_ds_encrypt_params(esp_ds_data_t *data,
|
||||
const void *iv,
|
||||
const esp_ds_p_data_t *p_data,
|
||||
const void *key)
|
||||
{
|
||||
if (!p_data) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_err_t result = ESP_OK;
|
||||
|
||||
// The `esp_ds_encrypt_params` operation does not use the Digital Signature peripheral,
|
||||
// but just the AES and SHA peripherals, so acquiring locks just for these peripherals
|
||||
// would be enough rather than acquiring a lock for the Digital Signature peripheral.
|
||||
esp_crypto_sha_aes_lock_acquire();
|
||||
|
||||
AES_RCC_ATOMIC() {
|
||||
aes_ll_enable_bus_clock(true);
|
||||
aes_ll_reset_register();
|
||||
}
|
||||
|
||||
SHA_RCC_ATOMIC() {
|
||||
sha_ll_enable_bus_clock(true);
|
||||
sha_ll_reset_register();
|
||||
}
|
||||
|
||||
ets_ds_data_t *ds_data = (ets_ds_data_t *) data;
|
||||
const ets_ds_p_data_t *ds_plain_data = (const ets_ds_p_data_t *) p_data;
|
||||
|
||||
ets_ds_result_t ets_result = ets_ds_encrypt_params(ds_data, iv, ds_plain_data, key, ETS_DS_KEY_HMAC);
|
||||
|
||||
if (ets_result == ETS_DS_INVALID_PARAM) {
|
||||
result = ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
SHA_RCC_ATOMIC() {
|
||||
sha_ll_enable_bus_clock(false);
|
||||
}
|
||||
|
||||
AES_RCC_ATOMIC() {
|
||||
aes_ll_enable_bus_clock(false);
|
||||
}
|
||||
|
||||
esp_crypto_sha_aes_lock_release();
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
317
components/esp_security/src/esp_hmac.c
Normal file
317
components/esp_security/src/esp_hmac.c
Normal file
@@ -0,0 +1,317 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "rom/efuse.h"
|
||||
#include "rom/hmac.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "esp_hmac.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_crypto_lock.h"
|
||||
#include "esp_private/esp_crypto_lock_internal.h"
|
||||
#include "soc/hwcrypto_reg.h"
|
||||
#include "soc/system_reg.h"
|
||||
|
||||
#if !CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "hal/ds_ll.h"
|
||||
#include "hal/hmac_hal.h"
|
||||
#include "hal/hmac_ll.h"
|
||||
#include "hal/sha_ll.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#endif
|
||||
|
||||
#define SHA256_BLOCK_SZ 64
|
||||
#define SHA256_PAD_SZ 8
|
||||
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
#define JTAG_STATUS_BIT ESP_EFUSE_HARD_DIS_JTAG
|
||||
#else
|
||||
/* For ESP32C3, ESP32C6, ESP32H2, ESP32P4 */
|
||||
#define JTAG_STATUS_BIT ESP_EFUSE_DIS_PAD_JTAG
|
||||
#endif
|
||||
static const char *TAG = "esp_hmac";
|
||||
|
||||
#if !CONFIG_IDF_TARGET_ESP32S2
|
||||
/**
|
||||
* @brief Apply the HMAC padding without the embedded length.
|
||||
*
|
||||
* @note This function does not check the data length, it is the responsibility of the other functions in this
|
||||
* module to make sure that \c data_len is at most SHA256_BLOCK_SZ - 1 so the padding fits in.
|
||||
* Otherwise, this function has undefined behavior.
|
||||
* Note however, that for the actual HMAC implementation, the length also needs to be applied at the end
|
||||
* of the block. This function alone deosn't do that.
|
||||
*/
|
||||
static void write_and_padd(uint8_t *block, const uint8_t *data, uint16_t data_len)
|
||||
{
|
||||
memcpy(block, data, data_len);
|
||||
// Apply a one bit, followed by zero bits (refer to the TRM of respective target).
|
||||
block[data_len] = 0x80;
|
||||
bzero(block + data_len + 1, SHA256_BLOCK_SZ - data_len - 1);
|
||||
}
|
||||
|
||||
esp_err_t esp_hmac_calculate(hmac_key_id_t key_id,
|
||||
const void *message,
|
||||
size_t message_len,
|
||||
uint8_t *hmac)
|
||||
{
|
||||
const uint8_t *message_bytes = (const uint8_t *)message;
|
||||
|
||||
if (!message || !hmac) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (key_id >= HMAC_KEY_MAX) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_crypto_hmac_lock_acquire();
|
||||
|
||||
// We also enable SHA and DS here. SHA is used by HMAC, DS will otherwise hold SHA in reset state.
|
||||
HMAC_RCC_ATOMIC() {
|
||||
hmac_ll_enable_bus_clock(true);
|
||||
hmac_ll_reset_register();
|
||||
}
|
||||
|
||||
SHA_RCC_ATOMIC() {
|
||||
sha_ll_enable_bus_clock(true);
|
||||
sha_ll_reset_register();
|
||||
}
|
||||
|
||||
DS_RCC_ATOMIC() {
|
||||
ds_ll_enable_bus_clock(true);
|
||||
ds_ll_reset_register();
|
||||
}
|
||||
|
||||
hmac_hal_start();
|
||||
|
||||
uint32_t conf_error = hmac_hal_configure(HMAC_OUTPUT_USER, key_id);
|
||||
if (conf_error) {
|
||||
esp_crypto_hmac_lock_release();
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (message_len + 1 + SHA256_PAD_SZ <= SHA256_BLOCK_SZ) {
|
||||
// If message including padding is only one block...
|
||||
// Last message block, so apply SHA-256 padding rules in software
|
||||
uint8_t block[SHA256_BLOCK_SZ];
|
||||
uint64_t bit_len = __builtin_bswap64(message_len * 8 + 512);
|
||||
|
||||
write_and_padd(block, message_bytes, message_len);
|
||||
// Final block: append the bit length in this block and signal padding to peripheral
|
||||
memcpy(block + SHA256_BLOCK_SZ - sizeof(bit_len),
|
||||
&bit_len, sizeof(bit_len));
|
||||
hmac_hal_write_one_block_512(block);
|
||||
} else {
|
||||
// If message including padding is needs more than one block
|
||||
|
||||
// write all blocks without padding except the last one
|
||||
size_t remaining_blocks = message_len / SHA256_BLOCK_SZ;
|
||||
for (int i = 1; i < remaining_blocks; i++) {
|
||||
hmac_hal_write_block_512(message_bytes);
|
||||
message_bytes += SHA256_BLOCK_SZ;
|
||||
hmac_hal_next_block_normal();
|
||||
}
|
||||
|
||||
// If message fits into one block but without padding, we must not write another block.
|
||||
if (remaining_blocks) {
|
||||
hmac_hal_write_block_512(message_bytes);
|
||||
message_bytes += SHA256_BLOCK_SZ;
|
||||
}
|
||||
|
||||
size_t remaining = message_len % SHA256_BLOCK_SZ;
|
||||
// Last message block, so apply SHA-256 padding rules in software
|
||||
uint8_t block[SHA256_BLOCK_SZ];
|
||||
uint64_t bit_len = __builtin_bswap64(message_len * 8 + 512);
|
||||
|
||||
// If the remaining message and appended padding doesn't fit into a single block, we have to write an
|
||||
// extra block with the rest of the message and potential padding first.
|
||||
if (remaining >= SHA256_BLOCK_SZ - SHA256_PAD_SZ) {
|
||||
write_and_padd(block, message_bytes, remaining);
|
||||
hmac_hal_next_block_normal();
|
||||
hmac_hal_write_block_512(block);
|
||||
bzero(block, SHA256_BLOCK_SZ);
|
||||
} else {
|
||||
write_and_padd(block, message_bytes, remaining);
|
||||
}
|
||||
memcpy(block + SHA256_BLOCK_SZ - sizeof(bit_len),
|
||||
&bit_len, sizeof(bit_len));
|
||||
hmac_hal_next_block_padding();
|
||||
hmac_hal_write_block_512(block);
|
||||
}
|
||||
|
||||
// Read back result (bit swapped)
|
||||
hmac_hal_read_result_256(hmac);
|
||||
|
||||
DS_RCC_ATOMIC() {
|
||||
ds_ll_enable_bus_clock(false);
|
||||
}
|
||||
|
||||
SHA_RCC_ATOMIC() {
|
||||
sha_ll_enable_bus_clock(false);
|
||||
}
|
||||
|
||||
HMAC_RCC_ATOMIC() {
|
||||
hmac_ll_enable_bus_clock(false);
|
||||
}
|
||||
|
||||
esp_crypto_hmac_lock_release();
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static ets_efuse_block_t convert_key_type(hmac_key_id_t key_id)
|
||||
{
|
||||
return ETS_EFUSE_BLOCK_KEY0 + (ets_efuse_block_t) key_id;
|
||||
}
|
||||
|
||||
esp_err_t esp_hmac_jtag_enable(hmac_key_id_t key_id, const uint8_t *token)
|
||||
{
|
||||
int ets_status;
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
if ((!token) || (key_id >= HMAC_KEY_MAX)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
/* Check if JTAG is permanently disabled by HW Disable eFuse */
|
||||
if (esp_efuse_read_field_bit(JTAG_STATUS_BIT)) {
|
||||
ESP_LOGE(TAG, "JTAG disabled permanently.");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_crypto_hmac_lock_acquire();
|
||||
|
||||
ets_status = ets_jtag_enable_temporarily(token, convert_key_type(key_id));
|
||||
|
||||
if (ets_status != ETS_OK) {
|
||||
// ets_jtag_enable_temporarily returns either ETS_OK or ETS_FAIL
|
||||
err = ESP_FAIL;
|
||||
ESP_LOGE(TAG, "JTAG re-enabling failed (%d)", err);
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "HMAC computation in downstream mode is completed.");
|
||||
|
||||
HMAC_RCC_ATOMIC() {
|
||||
hmac_ll_enable_bus_clock(false);
|
||||
}
|
||||
|
||||
esp_crypto_hmac_lock_release();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t esp_hmac_jtag_disable()
|
||||
{
|
||||
esp_crypto_hmac_lock_acquire();
|
||||
|
||||
HMAC_RCC_ATOMIC() {
|
||||
hmac_ll_enable_bus_clock(true);
|
||||
}
|
||||
|
||||
REG_WRITE(HMAC_SET_INVALIDATE_JTAG_REG, 1);
|
||||
|
||||
HMAC_RCC_ATOMIC() {
|
||||
hmac_ll_enable_bus_clock(false);
|
||||
}
|
||||
|
||||
esp_crypto_hmac_lock_release();
|
||||
|
||||
ESP_LOGD(TAG, "Invalidate JTAG result register. JTAG disabled.");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
#else /* !CONFIG_IDF_TARGET_ESP32S2 */
|
||||
|
||||
static ets_efuse_block_t convert_key_type(hmac_key_id_t key_id)
|
||||
{
|
||||
return ETS_EFUSE_BLOCK_KEY0 + (ets_efuse_block_t) key_id;
|
||||
}
|
||||
|
||||
esp_err_t esp_hmac_calculate(hmac_key_id_t key_id,
|
||||
const void *message,
|
||||
size_t message_len,
|
||||
uint8_t *hmac)
|
||||
{
|
||||
int hmac_ret;
|
||||
if (!message || !hmac) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (key_id >= HMAC_KEY_MAX) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_crypto_dma_lock_acquire();
|
||||
|
||||
ets_hmac_enable();
|
||||
hmac_ret = ets_hmac_calculate_message(convert_key_type(key_id), message, message_len, hmac);
|
||||
ets_hmac_disable();
|
||||
|
||||
esp_crypto_dma_lock_release();
|
||||
|
||||
if (hmac_ret != 0) {
|
||||
return ESP_FAIL;
|
||||
} else {
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t esp_hmac_jtag_enable(hmac_key_id_t key_id, const uint8_t *token)
|
||||
{
|
||||
int ets_status;
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
if ((!token) || (key_id >= HMAC_KEY_MAX)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
/* Check if JTAG is permanently disabled by HW Disable eFuse */
|
||||
if (esp_efuse_read_field_bit(ESP_EFUSE_HARD_DIS_JTAG)) {
|
||||
ESP_LOGE(TAG, "JTAG disabled permanently.");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_crypto_dma_lock_acquire();
|
||||
|
||||
ets_hmac_enable();
|
||||
|
||||
/* Token updating into HMAC module. */
|
||||
for (int i = 0; i < 32; i += 4) {
|
||||
uint32_t key_word;
|
||||
memcpy(&key_word, &token[i], 4);
|
||||
REG_WRITE(DPORT_JTAG_CTRL_0_REG + i, __builtin_bswap32(key_word));
|
||||
}
|
||||
|
||||
ets_status = ets_hmac_calculate_downstream(convert_key_type(key_id), ETS_EFUSE_KEY_PURPOSE_HMAC_DOWN_JTAG);
|
||||
if (ets_status != ETS_OK) {
|
||||
err = ESP_FAIL;
|
||||
ESP_LOGE(TAG, "HMAC downstream JTAG enable mode setting failed. (%d)", err);
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "HMAC computation in downstream mode is completed.");
|
||||
|
||||
ets_hmac_disable();
|
||||
|
||||
esp_crypto_dma_lock_release();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t esp_hmac_jtag_disable()
|
||||
{
|
||||
esp_crypto_dma_lock_acquire();
|
||||
|
||||
ets_hmac_enable();
|
||||
REG_WRITE(HMAC_SET_INVALIDATE_JTAG_REG, 1);
|
||||
ets_hmac_disable();
|
||||
|
||||
esp_crypto_dma_lock_release();
|
||||
|
||||
ESP_LOGD(TAG, "Invalidate JTAG result register. JTAG disabled.");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif /* CONFIG_IDF_TARGET_ESP32S2*/
|
765
components/esp_security/src/esp_key_mgr.c
Normal file
765
components/esp_security/src/esp_key_mgr.c
Normal file
@@ -0,0 +1,765 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
// The Hardware Support layer for Key manager
|
||||
#include <string.h>
|
||||
#include <sys/lock.h>
|
||||
#include "assert.h"
|
||||
#include "esp_key_mgr.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "esp_crypto_lock.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_random.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_rom_crc.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "hal/key_mgr_types.h"
|
||||
#include "hal/key_mgr_hal.h"
|
||||
#include "hal/key_mgr_ll.h"
|
||||
#include "hal/huk_types.h"
|
||||
#include "hal/huk_hal.h"
|
||||
#include "rom/key_mgr.h"
|
||||
|
||||
#if CONFIG_LOG_DEFAULT_LEVEL_VERBOSE
|
||||
#include "soc/huk_reg.h"
|
||||
#include "soc/keymng_reg.h"
|
||||
#endif
|
||||
|
||||
static const char *TAG = "esp_key_mgr";
|
||||
|
||||
#define KEY_MANAGER_RCC_ATOMIC() PERIPH_RCC_ATOMIC()
|
||||
|
||||
static _lock_t s_key_mgr_ecdsa_key_lock;
|
||||
static _lock_t s_key_mgr_xts_aes_key_lock;
|
||||
|
||||
ESP_STATIC_ASSERT(sizeof(esp_key_mgr_key_recovery_info_t) == sizeof(struct huk_key_block), "Size of esp_key_mgr_key_recovery_info_t should match huk_key_block (from ROM)");
|
||||
|
||||
ESP_STATIC_ASSERT(sizeof(esp_key_mgr_key_info_t) == sizeof(struct key_info), "Size of esp_key_mgr_key_info_t should match key_info (from ROM)");
|
||||
|
||||
ESP_STATIC_ASSERT(sizeof(esp_key_mgr_huk_info_t) == sizeof(struct huk_info), "Size of esp_key_mgr_huk_info_t should match huk_info (from ROM)");
|
||||
|
||||
static void esp_key_mgr_acquire_key_lock(esp_key_mgr_key_type_t key_type)
|
||||
{
|
||||
switch (key_type) {
|
||||
case ESP_KEY_MGR_ECDSA_KEY:
|
||||
_lock_acquire(&s_key_mgr_ecdsa_key_lock);
|
||||
break;
|
||||
case ESP_KEY_MGR_XTS_AES_128_KEY:
|
||||
case ESP_KEY_MGR_XTS_AES_256_KEY:
|
||||
_lock_acquire(&s_key_mgr_xts_aes_key_lock);
|
||||
break;
|
||||
}
|
||||
ESP_LOGV(TAG, "Key lock acquired for key type %d", key_type);
|
||||
}
|
||||
|
||||
static void esp_key_mgr_release_key_lock(esp_key_mgr_key_type_t key_type)
|
||||
{
|
||||
switch (key_type) {
|
||||
case ESP_KEY_MGR_ECDSA_KEY:
|
||||
_lock_release(&s_key_mgr_ecdsa_key_lock);
|
||||
break;
|
||||
case ESP_KEY_MGR_XTS_AES_128_KEY:
|
||||
case ESP_KEY_MGR_XTS_AES_256_KEY:
|
||||
_lock_release(&s_key_mgr_xts_aes_key_lock);
|
||||
break;
|
||||
}
|
||||
ESP_LOGV(TAG, "Key lock released for key type %d", key_type);
|
||||
}
|
||||
|
||||
static void esp_key_mgr_acquire_hardware(bool deployment_mode)
|
||||
{
|
||||
if (deployment_mode) {
|
||||
// We only need explicit locks in the deployment mode
|
||||
esp_crypto_ecc_lock_acquire();
|
||||
esp_crypto_sha_aes_lock_acquire();
|
||||
esp_crypto_key_manager_lock_acquire();
|
||||
}
|
||||
// Reset the Key Manager Clock
|
||||
KEY_MANAGER_RCC_ATOMIC() {
|
||||
key_mgr_ll_enable_bus_clock(true);
|
||||
key_mgr_ll_enable_peripheral_clock(true);
|
||||
key_mgr_ll_reset_register();
|
||||
}
|
||||
}
|
||||
|
||||
static void esp_key_mgr_release_hardware(bool deployment_mode)
|
||||
{
|
||||
if (deployment_mode) {
|
||||
esp_crypto_ecc_lock_release();
|
||||
esp_crypto_sha_aes_lock_release();
|
||||
esp_crypto_key_manager_lock_release();
|
||||
}
|
||||
|
||||
// Reset the Key Manager Clock
|
||||
KEY_MANAGER_RCC_ATOMIC() {
|
||||
key_mgr_ll_enable_peripheral_clock(false);
|
||||
key_mgr_ll_enable_bus_clock(false);
|
||||
key_mgr_ll_reset_register();
|
||||
}
|
||||
}
|
||||
|
||||
static void key_mgr_wait_for_state(esp_key_mgr_state_t state)
|
||||
{
|
||||
while (key_mgr_hal_get_state() != state) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct aes_deploy {
|
||||
esp_key_mgr_key_purpose_t key_purpose;
|
||||
const uint8_t *k1_encrypted;
|
||||
const esp_key_mgr_aes_key_config_t *key_config;
|
||||
esp_key_mgr_key_recovery_info_t *key_info;
|
||||
bool huk_deployed;
|
||||
} aes_deploy_config_t;
|
||||
|
||||
static void check_huk_risk_level(void)
|
||||
{
|
||||
uint8_t huk_risk_level = huk_hal_get_risk_level();
|
||||
if (huk_risk_level > KEY_MGR_HUK_RISK_ALERT_LEVEL) {
|
||||
ESP_LOGE(TAG, "HUK Risk level too high (level %d)\n"
|
||||
"It is recommended to immediately regenerate HUK in order"
|
||||
"to avoid permanently losing the deployed keys", huk_risk_level);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "HUK Risk level - %" PRId8 " within acceptable limit (%" PRIu32 ")", huk_risk_level, (uint32_t)KEY_MGR_HUK_RISK_ALERT_LEVEL);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static bool check_huk_info_validity(const esp_key_mgr_huk_info_t *huk_info)
|
||||
{
|
||||
uint32_t calc_crc = esp_rom_crc32_le(0, huk_info->info, KEY_MGR_HUK_INFO_SIZE);
|
||||
if (calc_crc != huk_info->crc) {
|
||||
ESP_LOGE(TAG, "Calculated CRC for HUK %" PRIx32 " does not match with %" PRIx32, calc_crc, huk_info->crc);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool check_key_info_validity(const esp_key_mgr_key_info_t *key_info)
|
||||
{
|
||||
uint32_t calc_crc = esp_rom_crc32_le(0, key_info->info, KEY_MGR_KEY_RECOVERY_INFO_SIZE);
|
||||
if (calc_crc != key_info->crc) {
|
||||
ESP_LOGE(TAG, "Calculated CRC for Key info %" PRIx32 " does not match with %" PRIx32, calc_crc, key_info->crc);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
bool use_pre_generated_huk_info;
|
||||
const esp_key_mgr_huk_info_t *pre_generated_huk_info;
|
||||
esp_key_mgr_huk_info_t *huk_recovery_info;
|
||||
} huk_deploy_config_t;
|
||||
|
||||
static esp_err_t deploy_huk(huk_deploy_config_t *config)
|
||||
{
|
||||
esp_err_t esp_ret = ESP_FAIL;
|
||||
uint8_t *huk_recovery_info = (uint8_t *) heap_caps_calloc(1, KEY_MGR_HUK_INFO_SIZE, MALLOC_CAP_INTERNAL);
|
||||
if (!huk_recovery_info) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
if (config->use_pre_generated_huk_info) {
|
||||
// If HUK info is provided then recover the HUK from given info
|
||||
check_huk_risk_level();
|
||||
if (!check_huk_info_validity(config->pre_generated_huk_info)) {
|
||||
ESP_LOGE(TAG, "HUK info is not valid");
|
||||
heap_caps_free(huk_recovery_info);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
memcpy(huk_recovery_info, config->pre_generated_huk_info->info, KEY_MGR_HUK_INFO_SIZE);
|
||||
ESP_LOGI(TAG, "Recovering HUK from given HUK recovery info");
|
||||
esp_ret = huk_hal_configure(ESP_HUK_MODE_RECOVERY, huk_recovery_info);
|
||||
if (esp_ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to recover HUK");
|
||||
heap_caps_free(huk_recovery_info);
|
||||
return esp_ret;
|
||||
}
|
||||
// Copy the pre generated huk info in the output key recovery info
|
||||
memcpy(config->huk_recovery_info->info, huk_recovery_info, KEY_MGR_HUK_INFO_SIZE);
|
||||
config->huk_recovery_info->crc = config->pre_generated_huk_info->crc;
|
||||
} else {
|
||||
// Generate new HUK and corresponding HUK info
|
||||
ESP_LOGI(TAG, "Generating new HUK");
|
||||
esp_ret = huk_hal_configure(ESP_HUK_MODE_GENERATION, huk_recovery_info);
|
||||
if (esp_ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to generate HUK");
|
||||
heap_caps_free(huk_recovery_info);
|
||||
return esp_ret;
|
||||
}
|
||||
memcpy(config->huk_recovery_info->info, huk_recovery_info, KEY_MGR_HUK_INFO_SIZE);
|
||||
config->huk_recovery_info->crc = esp_rom_crc32_le(0, huk_recovery_info, KEY_MGR_HUK_INFO_SIZE);
|
||||
}
|
||||
|
||||
if (!key_mgr_hal_is_huk_valid()) {
|
||||
ESP_LOGE(TAG, "HUK is invalid");
|
||||
heap_caps_free(huk_recovery_info);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_LOG_BUFFER_HEX_LEVEL("HUK INFO", huk_recovery_info, KEY_MGR_HUK_INFO_SIZE, ESP_LOG_DEBUG);
|
||||
// Free the local buffer for huk recovery info
|
||||
heap_caps_free(huk_recovery_info);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t key_mgr_deploy_key_aes_mode(aes_deploy_config_t *config)
|
||||
{
|
||||
esp_err_t esp_ret = ESP_FAIL;
|
||||
key_mgr_wait_for_state(ESP_KEY_MGR_STATE_IDLE);
|
||||
if ((!key_mgr_hal_is_huk_valid()) || (!config->huk_deployed)) {
|
||||
// For purpose ESP_KEY_MGR_KEY_PURPOSE_XTS_AES_256_2 this part shall be already executed
|
||||
huk_deploy_config_t huk_deploy_config = {};
|
||||
huk_deploy_config.use_pre_generated_huk_info = config->key_config->use_pre_generated_huk_info;
|
||||
huk_deploy_config.pre_generated_huk_info = &config->key_config->huk_info;
|
||||
huk_deploy_config.huk_recovery_info = &config->key_info->huk_info;
|
||||
esp_ret = deploy_huk(&huk_deploy_config);
|
||||
if (esp_ret != ESP_OK) {
|
||||
return esp_ret;
|
||||
}
|
||||
ESP_LOGI(TAG, "HUK deployed successfully");
|
||||
}
|
||||
|
||||
// STEP 1: Init Step
|
||||
// Set mode
|
||||
key_mgr_hal_set_key_generator_mode(ESP_KEY_MGR_KEYGEN_MODE_AES);
|
||||
|
||||
uint8_t *key_recovery_info = (uint8_t *) heap_caps_calloc(1, KEY_MGR_KEY_RECOVERY_INFO_SIZE, MALLOC_CAP_INTERNAL);
|
||||
if (!key_recovery_info) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
// Set key purpose (XTS/ECDSA)
|
||||
ESP_LOGD(TAG, "Key purpose = %d", config->key_purpose);
|
||||
key_mgr_hal_set_key_purpose(config->key_purpose);
|
||||
|
||||
// Set key length for XTS-AES key
|
||||
esp_key_mgr_key_type_t key_type = (esp_key_mgr_key_type_t) config->key_config->key_type;
|
||||
|
||||
if (key_type == ESP_KEY_MGR_XTS_AES_128_KEY) {
|
||||
key_mgr_hal_set_xts_aes_key_len(ESP_KEY_MGR_XTS_AES_LEN_256);
|
||||
} else if (key_type == ESP_KEY_MGR_XTS_AES_256_KEY) {
|
||||
key_mgr_hal_set_xts_aes_key_len(ESP_KEY_MGR_XTS_AES_LEN_512);
|
||||
}
|
||||
|
||||
if (config->key_config->use_pre_generated_sw_init_key) {
|
||||
key_mgr_hal_use_sw_init_key();
|
||||
} else {
|
||||
if (!esp_efuse_find_purpose(ESP_EFUSE_KEY_PURPOSE_KM_INIT_KEY, NULL)) {
|
||||
ESP_LOGE(TAG, "Could not find key with purpose KM_INIT_KEY");
|
||||
heap_caps_free(key_recovery_info);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
key_mgr_hal_start();
|
||||
key_mgr_hal_continue();
|
||||
// Step 2: Load phase
|
||||
key_mgr_wait_for_state(ESP_KEY_MGR_STATE_LOAD);
|
||||
if (config->key_config->use_pre_generated_sw_init_key) {
|
||||
key_mgr_hal_write_sw_init_key(config->key_config->sw_init_key, KEY_MGR_SW_INIT_KEY_SIZE);
|
||||
}
|
||||
ESP_LOG_BUFFER_HEX_LEVEL("SW_INIT_KEY", config->key_config->sw_init_key, KEY_MGR_SW_INIT_KEY_SIZE, ESP_LOG_DEBUG);
|
||||
|
||||
ESP_LOGD(TAG, "Writing Information into Key Manager Registers");
|
||||
key_mgr_hal_write_assist_info(config->key_config->k2_info, KEY_MGR_K2_INFO_SIZE);
|
||||
ESP_LOG_BUFFER_HEX_LEVEL("K2_INFO", config->key_config->k2_info, KEY_MGR_K2_INFO_SIZE, ESP_LOG_DEBUG);
|
||||
key_mgr_hal_write_public_info(config->k1_encrypted, KEY_MGR_K1_ENCRYPTED_SIZE);
|
||||
ESP_LOG_BUFFER_HEX_LEVEL("K1_ENCRYPTED", config->k1_encrypted, KEY_MGR_K1_ENCRYPTED_SIZE, ESP_LOG_DEBUG);
|
||||
key_mgr_hal_continue();
|
||||
// Step 3: Gain phase
|
||||
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("KEY_RECOVERY_INFO", key_recovery_info, KEY_MGR_KEY_RECOVERY_INFO_SIZE, ESP_LOG_DEBUG);
|
||||
|
||||
if (config->key_purpose != ESP_KEY_MGR_KEY_PURPOSE_XTS_AES_256_1) {
|
||||
if (!key_mgr_hal_is_key_deployment_valid(config->key_config->key_type)) {
|
||||
ESP_LOGE(TAG, "Key deployment is not valid");
|
||||
heap_caps_free(key_recovery_info);
|
||||
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);
|
||||
if (config->key_purpose == ESP_KEY_MGR_KEY_PURPOSE_XTS_AES_256_2) {
|
||||
memcpy(config->key_info->key_info[1].info, key_recovery_info, KEY_MGR_KEY_RECOVERY_INFO_SIZE);
|
||||
config->key_info->key_info[1].crc = esp_rom_crc32_le(0, key_recovery_info, KEY_MGR_KEY_RECOVERY_INFO_SIZE);
|
||||
|
||||
} else {
|
||||
memcpy(config->key_info->key_info[0].info, key_recovery_info, KEY_MGR_KEY_RECOVERY_INFO_SIZE);
|
||||
config->key_info->key_info[0].crc = esp_rom_crc32_le(0, key_recovery_info, KEY_MGR_KEY_RECOVERY_INFO_SIZE);
|
||||
}
|
||||
heap_caps_free(key_recovery_info);
|
||||
config->key_info->key_type = config->key_config->key_type;
|
||||
config->key_info->magic = KEY_HUK_SECTOR_MAGIC;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_key_mgr_deploy_key_in_aes_mode(const esp_key_mgr_aes_key_config_t *key_config, esp_key_mgr_key_recovery_info_t *key_recovery_info)
|
||||
{
|
||||
if (key_config == NULL || key_recovery_info == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Key deployment in AES mode");
|
||||
|
||||
aes_deploy_config_t aes_deploy_config = {};
|
||||
aes_deploy_config.key_config = key_config;
|
||||
aes_deploy_config.key_info = key_recovery_info;
|
||||
aes_deploy_config.k1_encrypted = key_config->k1_encrypted[0];
|
||||
|
||||
esp_key_mgr_key_type_t key_type = (esp_key_mgr_key_type_t) key_config->key_type;
|
||||
if (key_type == ESP_KEY_MGR_ECDSA_KEY) {
|
||||
aes_deploy_config.key_purpose = ESP_KEY_MGR_KEY_PURPOSE_ECDSA;
|
||||
} else if (key_type == ESP_KEY_MGR_XTS_AES_128_KEY) {
|
||||
aes_deploy_config.key_purpose = ESP_KEY_MGR_KEY_PURPOSE_XTS_AES_128;
|
||||
} else if (key_type == ESP_KEY_MGR_XTS_AES_256_KEY) {
|
||||
aes_deploy_config.key_purpose = ESP_KEY_MGR_KEY_PURPOSE_XTS_AES_256_1;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Invalid key type");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_key_mgr_acquire_hardware(true);
|
||||
|
||||
esp_err_t esp_ret = key_mgr_deploy_key_aes_mode(&aes_deploy_config);
|
||||
if (esp_ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Key deployment in AES mode failed");
|
||||
}
|
||||
aes_deploy_config.huk_deployed = true;
|
||||
|
||||
if (key_type == ESP_KEY_MGR_XTS_AES_256_KEY) {
|
||||
aes_deploy_config.key_purpose = ESP_KEY_MGR_KEY_PURPOSE_XTS_AES_256_2;
|
||||
aes_deploy_config.k1_encrypted = key_config->k1_encrypted[1];
|
||||
esp_ret = key_mgr_deploy_key_aes_mode(&aes_deploy_config);
|
||||
if (esp_ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Key deployment in AES mode failed");
|
||||
}
|
||||
}
|
||||
|
||||
// Set the Key Manager Static Register to use own key for the respective key type
|
||||
key_mgr_hal_set_key_usage(key_type, ESP_KEY_MGR_USE_OWN_KEY);
|
||||
|
||||
esp_key_mgr_release_hardware(true);
|
||||
return esp_ret;
|
||||
}
|
||||
|
||||
typedef struct key_recovery_config {
|
||||
esp_key_mgr_key_purpose_t key_purpose;
|
||||
esp_key_mgr_key_recovery_info_t *key_recovery_info;
|
||||
bool huk_recovered;
|
||||
} key_recovery_config_t;
|
||||
|
||||
static esp_err_t key_mgr_recover_key(key_recovery_config_t *config)
|
||||
{
|
||||
key_mgr_wait_for_state(ESP_KEY_MGR_STATE_IDLE);
|
||||
if (!check_huk_info_validity(&config->key_recovery_info->huk_info)) {
|
||||
ESP_LOGE(TAG, "HUK info is not valid");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
ESP_LOGD(TAG, "HUK info valid");
|
||||
|
||||
if ((!key_mgr_hal_is_huk_valid()) || (!config->huk_recovered)) {
|
||||
check_huk_risk_level();
|
||||
esp_err_t esp_ret = huk_hal_configure(ESP_HUK_MODE_RECOVERY, config->key_recovery_info->huk_info.info);
|
||||
if (esp_ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to recover HUK");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (!key_mgr_hal_is_huk_valid()) {
|
||||
ESP_LOGE(TAG, "HUK is invalid");
|
||||
// TODO - define error code
|
||||
return ESP_FAIL;
|
||||
}
|
||||
ESP_LOGI(TAG, "HUK recovered successfully");
|
||||
ESP_LOG_BUFFER_HEX_LEVEL("HUK INFO", config->key_recovery_info->huk_info.info, KEY_MGR_HUK_INFO_SIZE, ESP_LOG_DEBUG);
|
||||
config->huk_recovered = true;
|
||||
}
|
||||
|
||||
key_mgr_hal_set_key_generator_mode(ESP_KEY_MGR_KEYGEN_MODE_RECOVER);
|
||||
|
||||
// Set AES-XTS key len
|
||||
esp_key_mgr_key_type_t key_type = (esp_key_mgr_key_type_t) config->key_recovery_info->key_type;
|
||||
if (key_type == ESP_KEY_MGR_XTS_AES_128_KEY) {
|
||||
key_mgr_hal_set_xts_aes_key_len(ESP_KEY_MGR_XTS_AES_LEN_256);
|
||||
} else if (key_type == ESP_KEY_MGR_XTS_AES_256_KEY) {
|
||||
key_mgr_hal_set_xts_aes_key_len(ESP_KEY_MGR_XTS_AES_LEN_512);
|
||||
}
|
||||
|
||||
key_mgr_hal_set_key_purpose(config->key_purpose);
|
||||
key_mgr_hal_start();
|
||||
key_mgr_hal_continue();
|
||||
key_mgr_wait_for_state(ESP_KEY_MGR_STATE_LOAD);
|
||||
if (config->key_purpose == ESP_KEY_MGR_KEY_PURPOSE_XTS_AES_256_2) {
|
||||
if (!check_key_info_validity(&config->key_recovery_info->key_info[1])) {
|
||||
ESP_LOGE(TAG, "Key info not valid");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
key_mgr_hal_write_assist_info(config->key_recovery_info->key_info[1].info, KEY_MGR_KEY_RECOVERY_INFO_SIZE);
|
||||
ESP_LOG_BUFFER_HEX_LEVEL("RECOVERY_INFO[1]", config->key_recovery_info->key_info[0].info, KEY_MGR_KEY_RECOVERY_INFO_SIZE, ESP_LOG_DEBUG);
|
||||
} else {
|
||||
if (!check_key_info_validity(&config->key_recovery_info->key_info[0])) {
|
||||
ESP_LOGE(TAG, "Key info not valid");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
key_mgr_hal_write_assist_info(config->key_recovery_info->key_info[0].info, KEY_MGR_KEY_RECOVERY_INFO_SIZE);
|
||||
ESP_LOG_BUFFER_HEX_LEVEL("RECOVERY_INFO[0]", config->key_recovery_info->key_info[0].info, KEY_MGR_KEY_RECOVERY_INFO_SIZE, ESP_LOG_DEBUG);
|
||||
}
|
||||
|
||||
key_mgr_hal_continue();
|
||||
key_mgr_wait_for_state(ESP_KEY_MGR_STATE_GAIN);
|
||||
if (config->key_purpose != ESP_KEY_MGR_KEY_PURPOSE_XTS_AES_256_1) {
|
||||
if (!key_mgr_hal_is_key_deployment_valid(config->key_recovery_info->key_type)) {
|
||||
ESP_LOGD(TAG, "Key deployment is not valid");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
ESP_LOGD(TAG, "Key Recovery valid");
|
||||
}
|
||||
key_mgr_hal_continue();
|
||||
key_mgr_wait_for_state(ESP_KEY_MGR_STATE_IDLE);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_key_mgr_activate_key(esp_key_mgr_key_recovery_info_t *key_recovery_info)
|
||||
{
|
||||
if (key_recovery_info == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_key_mgr_key_purpose_t key_purpose;
|
||||
ESP_LOGD(TAG, "Activating key of type %d", key_recovery_info->key_type);
|
||||
esp_key_mgr_key_type_t key_type = (esp_key_mgr_key_type_t) key_recovery_info->key_type;
|
||||
if (key_type == ESP_KEY_MGR_ECDSA_KEY) {
|
||||
key_purpose = ESP_KEY_MGR_KEY_PURPOSE_ECDSA;
|
||||
} else if (key_type == ESP_KEY_MGR_XTS_AES_128_KEY) {
|
||||
key_purpose = ESP_KEY_MGR_KEY_PURPOSE_XTS_AES_128;
|
||||
} else if (key_type == ESP_KEY_MGR_XTS_AES_256_KEY) {
|
||||
key_purpose = ESP_KEY_MGR_KEY_PURPOSE_XTS_AES_256_1;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Invalid key type");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_err_t esp_ret = ESP_FAIL;
|
||||
esp_key_mgr_acquire_key_lock(key_type);
|
||||
key_recovery_config_t key_recovery_config = {};
|
||||
key_recovery_config.key_recovery_info = key_recovery_info;
|
||||
key_recovery_config.key_purpose = key_purpose;
|
||||
|
||||
esp_key_mgr_acquire_hardware(false);
|
||||
|
||||
esp_ret = key_mgr_recover_key(&key_recovery_config);
|
||||
if (esp_ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to recover key");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (key_recovery_info->key_type == ESP_KEY_MGR_XTS_AES_256_KEY) {
|
||||
key_recovery_config.key_purpose = ESP_KEY_MGR_KEY_PURPOSE_XTS_AES_256_2;
|
||||
esp_ret = key_mgr_recover_key(&key_recovery_config);
|
||||
if (esp_ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to recover key");
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the Key Manager Static Register to use own key for the respective key type
|
||||
key_mgr_hal_set_key_usage(key_recovery_info->key_type, ESP_KEY_MGR_USE_OWN_KEY);
|
||||
ESP_LOGI(TAG, "Key activation for type %d successful", key_recovery_info->key_type);
|
||||
return ESP_OK;
|
||||
|
||||
cleanup:
|
||||
ESP_LOGI(TAG, "Key activation failed");
|
||||
esp_key_mgr_release_hardware(false);
|
||||
return esp_ret;
|
||||
}
|
||||
|
||||
esp_err_t esp_key_mgr_deactivate_key(esp_key_mgr_key_type_t key_type)
|
||||
{
|
||||
ESP_LOGD(TAG, "Deactivating key of type %d", key_type);
|
||||
esp_key_mgr_release_key_lock(key_type);
|
||||
esp_key_mgr_release_hardware(false);
|
||||
ESP_LOGI(TAG, "Key deactivation successful");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
typedef struct ecdh0_config {
|
||||
esp_key_mgr_key_purpose_t key_purpose;
|
||||
const uint8_t *k1_G;
|
||||
const esp_key_mgr_ecdh0_key_config_t *key_config;
|
||||
esp_key_mgr_key_recovery_info_t *key_info;
|
||||
uint8_t *ecdh0_key_info;
|
||||
bool huk_deployed;
|
||||
} ecdh0_deploy_config_t;
|
||||
|
||||
static esp_err_t key_mgr_deploy_key_ecdh0_mode(ecdh0_deploy_config_t *config)
|
||||
{
|
||||
esp_err_t esp_ret = ESP_FAIL;
|
||||
key_mgr_wait_for_state(ESP_KEY_MGR_STATE_IDLE);
|
||||
|
||||
if ((!key_mgr_hal_is_huk_valid()) || (!config->huk_deployed)) {
|
||||
// For purpose ESP_KEY_MGR_KEY_PURPOSE_XTS_AES_256_2 this part shall be already executed
|
||||
huk_deploy_config_t huk_deploy_config;
|
||||
huk_deploy_config.use_pre_generated_huk_info = config->key_config->use_pre_generated_huk_info;
|
||||
huk_deploy_config.pre_generated_huk_info = &config->key_config->huk_info;
|
||||
huk_deploy_config.huk_recovery_info = &config->key_info->huk_info;
|
||||
esp_ret = deploy_huk(&huk_deploy_config);
|
||||
if (esp_ret != ESP_OK) {
|
||||
return esp_ret;
|
||||
}
|
||||
ESP_LOGI(TAG, "HUK deployed successfully");
|
||||
}
|
||||
|
||||
uint8_t *key_recovery_info = (uint8_t *) heap_caps_calloc(1, KEY_MGR_KEY_RECOVERY_INFO_SIZE, MALLOC_CAP_INTERNAL);
|
||||
if (!key_recovery_info) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
// Step 1 : Initialization
|
||||
// Configure deployment mode to ECDH0
|
||||
key_mgr_hal_set_key_generator_mode(ESP_KEY_MGR_KEYGEN_MODE_ECDH0);
|
||||
|
||||
// Set AES-XTS key len
|
||||
esp_key_mgr_key_type_t key_type = (esp_key_mgr_key_type_t) config->key_config->key_type;
|
||||
if (key_type == ESP_KEY_MGR_XTS_AES_128_KEY) {
|
||||
key_mgr_hal_set_xts_aes_key_len(ESP_KEY_MGR_XTS_AES_LEN_256);
|
||||
} else if (key_type == ESP_KEY_MGR_XTS_AES_256_KEY) {
|
||||
key_mgr_hal_set_xts_aes_key_len(ESP_KEY_MGR_XTS_AES_LEN_512);
|
||||
}
|
||||
|
||||
// Set key purpose (XTS/ECDSA)
|
||||
key_mgr_hal_set_key_purpose(config->key_purpose);
|
||||
key_mgr_hal_start();
|
||||
key_mgr_hal_continue();
|
||||
|
||||
// Step 2: Load phase
|
||||
key_mgr_wait_for_state(ESP_KEY_MGR_STATE_LOAD);
|
||||
ESP_LOGD(TAG, "Writing Information into Key Manager Registers");
|
||||
key_mgr_hal_write_public_info(config->k1_G, KEY_MGR_ECDH0_INFO_SIZE);
|
||||
key_mgr_hal_continue();
|
||||
|
||||
// Step 3: Gain phase
|
||||
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(config->ecdh0_key_info);
|
||||
ESP_LOG_BUFFER_HEX_LEVEL("KEY_MGR KEY INFO", key_recovery_info, KEY_MGR_KEY_RECOVERY_INFO_SIZE, ESP_LOG_DEBUG);
|
||||
|
||||
ESP_LOGI(TAG, "HUK deplpoyed is Valid");
|
||||
|
||||
if (config->key_purpose != ESP_KEY_MGR_KEY_PURPOSE_XTS_AES_256_1) {
|
||||
if (!key_mgr_hal_is_key_deployment_valid(config->key_config->key_type)) {
|
||||
ESP_LOGE(TAG, "Key deployment is not valid");
|
||||
heap_caps_free(key_recovery_info);
|
||||
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);
|
||||
if (config->key_purpose == ESP_KEY_MGR_KEY_PURPOSE_XTS_AES_256_2) {
|
||||
memcpy(config->key_info->key_info[1].info, key_recovery_info, KEY_MGR_KEY_RECOVERY_INFO_SIZE);
|
||||
config->key_info->key_info[1].crc = esp_rom_crc32_le(0, key_recovery_info, KEY_MGR_KEY_RECOVERY_INFO_SIZE);
|
||||
|
||||
} else {
|
||||
memcpy(config->key_info->key_info[0].info, key_recovery_info, KEY_MGR_KEY_RECOVERY_INFO_SIZE);
|
||||
config->key_info->key_info[0].crc = esp_rom_crc32_le(0, key_recovery_info, KEY_MGR_KEY_RECOVERY_INFO_SIZE);
|
||||
}
|
||||
|
||||
config->key_info->key_type = config->key_config->key_type;
|
||||
config->key_info->magic = KEY_HUK_SECTOR_MAGIC;
|
||||
|
||||
heap_caps_free(key_recovery_info);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_key_mgr_deploy_key_in_ecdh0_mode(const esp_key_mgr_ecdh0_key_config_t *key_config,
|
||||
esp_key_mgr_key_recovery_info_t *key_info, esp_key_mgr_ecdh0_info_t *ecdh0_key_info)
|
||||
{
|
||||
if (key_config == NULL || key_info == NULL || ecdh0_key_info == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
ESP_LOGI(TAG, "Key Deployment in ECDH0 mode");
|
||||
esp_key_mgr_key_purpose_t key_purpose;
|
||||
esp_key_mgr_key_type_t key_type = (esp_key_mgr_key_type_t) key_config->key_type;
|
||||
|
||||
ecdh0_deploy_config_t ecdh0_deploy_config = {};
|
||||
ecdh0_deploy_config.key_config = key_config;
|
||||
ecdh0_deploy_config.key_info = key_info;
|
||||
ecdh0_deploy_config.k1_G = key_config->k1_G[0];
|
||||
|
||||
if (key_type == ESP_KEY_MGR_ECDSA_KEY) {
|
||||
ecdh0_deploy_config.key_purpose = ESP_KEY_MGR_KEY_PURPOSE_ECDSA;
|
||||
ecdh0_deploy_config.ecdh0_key_info = ecdh0_key_info->k2_G[0];
|
||||
} else if (key_type == ESP_KEY_MGR_XTS_AES_128_KEY) {
|
||||
ecdh0_deploy_config.key_purpose = ESP_KEY_MGR_KEY_PURPOSE_XTS_AES_128;
|
||||
ecdh0_deploy_config.ecdh0_key_info = ecdh0_key_info->k2_G[0];
|
||||
} else if (key_type == ESP_KEY_MGR_XTS_AES_256_KEY) {
|
||||
ecdh0_deploy_config.key_purpose = ESP_KEY_MGR_KEY_PURPOSE_XTS_AES_256_1;
|
||||
ecdh0_deploy_config.ecdh0_key_info = ecdh0_key_info->k2_G[0];
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Invalid key type");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_key_mgr_acquire_hardware(true);
|
||||
|
||||
esp_err_t esp_ret = key_mgr_deploy_key_ecdh0_mode(&ecdh0_deploy_config);
|
||||
if (esp_ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to deploy key in ECDH0 mode");
|
||||
}
|
||||
ecdh0_deploy_config.huk_deployed = true;
|
||||
|
||||
if (key_config->key_type == ESP_KEY_MGR_XTS_AES_256_KEY) {
|
||||
key_purpose = ESP_KEY_MGR_KEY_PURPOSE_XTS_AES_256_2;
|
||||
ecdh0_deploy_config.key_purpose = key_purpose;
|
||||
ecdh0_deploy_config.k1_G = key_config->k1_G[1];
|
||||
|
||||
ecdh0_deploy_config.ecdh0_key_info = ecdh0_key_info->k2_G[1];
|
||||
esp_ret = key_mgr_deploy_key_ecdh0_mode(&ecdh0_deploy_config);
|
||||
if (esp_ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to deploy key in ECDH0 mode");
|
||||
}
|
||||
}
|
||||
|
||||
// Set the Key Manager Static Register to use own key for the respective key type
|
||||
key_mgr_hal_set_key_usage(key_type, ESP_KEY_MGR_USE_OWN_KEY);
|
||||
|
||||
esp_key_mgr_release_hardware(true);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
typedef struct random_deploy {
|
||||
esp_key_mgr_key_purpose_t key_purpose;
|
||||
const esp_key_mgr_random_key_config_t *key_config;
|
||||
esp_key_mgr_key_recovery_info_t *key_info;
|
||||
bool huk_deployed;
|
||||
} random_deploy_config_t;
|
||||
|
||||
static esp_err_t key_mgr_deploy_key_random_mode(random_deploy_config_t *config)
|
||||
{
|
||||
esp_err_t esp_ret = ESP_FAIL;
|
||||
key_mgr_wait_for_state(ESP_KEY_MGR_STATE_IDLE);
|
||||
if ((!key_mgr_hal_is_huk_valid()) || (!config->huk_deployed)) {
|
||||
// For purpose ESP_KEY_MGR_KEY_PURPOSE_XTS_AES_256_2 this part shall be already executed
|
||||
huk_deploy_config_t huk_deploy_config = {};
|
||||
huk_deploy_config.use_pre_generated_huk_info = config->key_config->use_pre_generated_huk_info;
|
||||
huk_deploy_config.pre_generated_huk_info = &config->key_config->huk_info;
|
||||
huk_deploy_config.huk_recovery_info = &config->key_info->huk_info;
|
||||
esp_ret = deploy_huk(&huk_deploy_config);
|
||||
if (esp_ret != ESP_OK) {
|
||||
return esp_ret;
|
||||
}
|
||||
ESP_LOGI(TAG, "HUK deployed successfully");
|
||||
}
|
||||
|
||||
// Configure deployment mode to RANDOM
|
||||
key_mgr_hal_set_key_generator_mode(ESP_KEY_MGR_KEYGEN_MODE_RANDOM);
|
||||
|
||||
// Set AES-XTS key len
|
||||
esp_key_mgr_key_type_t key_type = (esp_key_mgr_key_type_t) config->key_config->key_type;
|
||||
if (key_type == ESP_KEY_MGR_XTS_AES_128_KEY) {
|
||||
key_mgr_hal_set_xts_aes_key_len(ESP_KEY_MGR_XTS_AES_LEN_256);
|
||||
} else if (key_type == ESP_KEY_MGR_XTS_AES_256_KEY) {
|
||||
key_mgr_hal_set_xts_aes_key_len(ESP_KEY_MGR_XTS_AES_LEN_512);
|
||||
}
|
||||
|
||||
uint8_t *key_recovery_info = (uint8_t *) heap_caps_calloc(1, KEY_MGR_KEY_RECOVERY_INFO_SIZE, MALLOC_CAP_INTERNAL);
|
||||
if (!key_recovery_info) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
// Set key purpose (XTS/ECDSA)
|
||||
key_mgr_hal_set_key_purpose(config->key_purpose);
|
||||
|
||||
key_mgr_hal_start();
|
||||
key_mgr_hal_continue();
|
||||
key_mgr_wait_for_state(ESP_KEY_MGR_STATE_LOAD);
|
||||
key_mgr_hal_continue();
|
||||
// No configuration for Random deploy mode
|
||||
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("KEY_MGR KEY INFO", key_recovery_info, KEY_MGR_KEY_RECOVERY_INFO_SIZE, ESP_LOG_DEBUG);
|
||||
|
||||
if (config->key_purpose != ESP_KEY_MGR_KEY_PURPOSE_XTS_AES_256_1) {
|
||||
if (!key_mgr_hal_is_key_deployment_valid(config->key_config->key_type)) {
|
||||
ESP_LOGE(TAG, "Key deployment is not valid");
|
||||
heap_caps_free(key_recovery_info);
|
||||
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);
|
||||
if (config->key_purpose == ESP_KEY_MGR_KEY_PURPOSE_XTS_AES_256_2) {
|
||||
memcpy(config->key_info->key_info[1].info, key_recovery_info, KEY_MGR_KEY_RECOVERY_INFO_SIZE);
|
||||
config->key_info->key_info[1].crc = esp_rom_crc32_le(0, key_recovery_info, KEY_MGR_KEY_RECOVERY_INFO_SIZE);
|
||||
|
||||
} else {
|
||||
memcpy(config->key_info->key_info[0].info, key_recovery_info, KEY_MGR_KEY_RECOVERY_INFO_SIZE);
|
||||
config->key_info->key_info[0].crc = esp_rom_crc32_le(0, key_recovery_info, KEY_MGR_KEY_RECOVERY_INFO_SIZE);
|
||||
}
|
||||
heap_caps_free(key_recovery_info);
|
||||
config->key_info->key_type = config->key_config->key_type;
|
||||
config->key_info->magic = KEY_HUK_SECTOR_MAGIC;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_key_mgr_deploy_key_in_random_mode(const esp_key_mgr_random_key_config_t *key_config, esp_key_mgr_key_recovery_info_t *key_recovery_info)
|
||||
{
|
||||
if (key_config == NULL || key_recovery_info == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Key deployment in Random mode");
|
||||
|
||||
random_deploy_config_t random_deploy_config = {};
|
||||
random_deploy_config.key_config = key_config;
|
||||
random_deploy_config.key_info = key_recovery_info;
|
||||
esp_key_mgr_key_type_t key_type = (esp_key_mgr_key_type_t) key_config->key_type;
|
||||
|
||||
if (key_type == ESP_KEY_MGR_ECDSA_KEY) {
|
||||
random_deploy_config.key_purpose = ESP_KEY_MGR_KEY_PURPOSE_ECDSA;
|
||||
} else if (key_type == ESP_KEY_MGR_XTS_AES_128_KEY) {
|
||||
random_deploy_config.key_purpose = ESP_KEY_MGR_KEY_PURPOSE_XTS_AES_128;
|
||||
} else if (key_type == ESP_KEY_MGR_XTS_AES_256_KEY) {
|
||||
random_deploy_config.key_purpose = ESP_KEY_MGR_KEY_PURPOSE_XTS_AES_256_1;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Invalid key type");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_key_mgr_acquire_hardware(true);
|
||||
|
||||
esp_err_t esp_ret = key_mgr_deploy_key_random_mode(&random_deploy_config);
|
||||
if (esp_ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Key deployment in Random mode failed");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
random_deploy_config.huk_deployed = true;
|
||||
|
||||
if (key_type == ESP_KEY_MGR_XTS_AES_256_KEY) {
|
||||
random_deploy_config.key_purpose = ESP_KEY_MGR_KEY_PURPOSE_XTS_AES_256_2;
|
||||
esp_ret = key_mgr_deploy_key_random_mode(&random_deploy_config);
|
||||
if (esp_ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Key deployment in Random mode failed");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the Key Manager Static Register to use own key for the respective key type
|
||||
key_mgr_hal_set_key_usage(key_config->key_type, ESP_KEY_MGR_USE_OWN_KEY);
|
||||
|
||||
esp_key_mgr_release_hardware(true);
|
||||
return esp_ret;
|
||||
}
|
11
components/esp_security/src/esp_security_priv.h
Normal file
11
components/esp_security/src/esp_security_priv.h
Normal file
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/* Private interface file */
|
||||
|
||||
void esp_crypto_dpa_protection_startup(void);
|
24
components/esp_security/src/init.c
Normal file
24
components/esp_security/src/init.c
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "esp_private/startup_internal.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_crypto_clk.h"
|
||||
#include "esp_security_priv.h"
|
||||
|
||||
ESP_SYSTEM_INIT_FN(esp_security_init, SECONDARY, BIT(0), 103)
|
||||
{
|
||||
esp_crypto_clk_init();
|
||||
#if CONFIG_ESP_CRYPTO_DPA_PROTECTION_AT_STARTUP
|
||||
esp_crypto_dpa_protection_startup();
|
||||
#endif
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void esp_security_init_include_impl(void)
|
||||
{
|
||||
// Linker hook, exists for no other purpose
|
||||
}
|
Reference in New Issue
Block a user