diff --git a/components/esp_hw_support/include/soc/esp32s3/esp_crypto_lock.h b/components/esp_hw_support/include/soc/esp32s3/esp_crypto_lock.h index ee59893baa..d45cc2e322 100644 --- a/components/esp_hw_support/include/soc/esp32s3/esp_crypto_lock.h +++ b/components/esp_hw_support/include/soc/esp32s3/esp_crypto_lock.h @@ -18,6 +18,20 @@ extern "C" { * Other unrelated components must not use it. */ +/** + * @brief Acquire lock for HMAC cryptography peripheral + * + * Internally also takes the SHA & AES lock, as the HMAC depends on the SHA peripheral + */ +void esp_crypto_hmac_lock_acquire(void); + +/** + * @brief Release lock for HMAC cryptography peripheral + * + * Internally also releases the SHA & AES lock, as the HMAC depends on the SHA peripheral + */ +void esp_crypto_hmac_lock_release(void); + /** * @brief Acquire lock for the SHA and AES cryptography peripheral. * diff --git a/components/esp_hw_support/include/soc/esp32s3/esp_hmac.h b/components/esp_hw_support/include/soc/esp32s3/esp_hmac.h new file mode 100644 index 0000000000..8f8677e38c --- /dev/null +++ b/components/esp_hw_support/include/soc/esp32s3/esp_hmac.h @@ -0,0 +1,55 @@ +/* + * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * The possible efuse keys for the HMAC peripheral + */ +typedef enum { + HMAC_KEY0 = 0, + HMAC_KEY1, + HMAC_KEY2, + HMAC_KEY3, + HMAC_KEY4, + HMAC_KEY5, + HMAC_KEY_MAX +} hmac_key_id_t; + +/** + * @brief + * Calculate the HMAC of a given message. + * + * Calculate the HMAC \c hmac of a given message \c message with length \c message_len. + * SHA256 is used for the calculation (fixed on ESP32S3). + * + * @note Uses the HMAC peripheral in "upstream" mode. + * + * @param key_id Determines which of the 6 key blocks in the efuses should be used for the HMAC calcuation. + * The corresponding purpose field of the key block in the efuse must be set to the HMAC upstream purpose value. + * @param message the message for which to calculate the HMAC + * @param message_len message length + * @param [out] hmac the hmac result; the buffer behind the provided pointer must be 32 bytes long + * + * @return + * * ESP_OK, if the calculation was successful, + * * ESP_ERR_INVALID_ARG if message or hmac is a nullptr or if key_id out of range + * * ESP_FAIL, if the hmac calculation failed + */ +esp_err_t esp_hmac_calculate(hmac_key_id_t key_id, + const void *message, + size_t message_len, + uint8_t *hmac); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hw_support/port/esp32s3/CMakeLists.txt b/components/esp_hw_support/port/esp32s3/CMakeLists.txt index 5d65ede6e6..e607f84f04 100644 --- a/components/esp_hw_support/port/esp32s3/CMakeLists.txt +++ b/components/esp_hw_support/port/esp32s3/CMakeLists.txt @@ -15,6 +15,7 @@ set(srcs if(NOT BOOTLOADER_BUILD) list(APPEND srcs "../async_memcpy_impl_gdma.c" "dport_access.c" + "esp_hmac.c" "esp_crypto_lock.c" "memprot.c" "spiram.c") diff --git a/components/esp_hw_support/port/esp32s3/esp_crypto_lock.c b/components/esp_hw_support/port/esp32s3/esp_crypto_lock.c index 0957395442..3e99a08ea4 100644 --- a/components/esp_hw_support/port/esp32s3/esp_crypto_lock.c +++ b/components/esp_hw_support/port/esp32s3/esp_crypto_lock.c @@ -16,20 +16,34 @@ HMAC: needs SHA DS: needs HMAC (which needs SHA), AES and MPI */ -/* Single lock for SHA and AES, sharing a reserved GDMA channel */ -static _lock_t s_crypto_sha_aes_lock; +/* + * Single lock for SHA, HMAC, DS and AES peripherals. + * SHA and AES share a reserved GDMA channel. + * DS uses HMAC, HMAC uses SHA, so they may also not be used simulaneously. + */ +static _lock_t s_crypto_sha_aes_hmac_ds_lock; /* Lock for the MPI/RSA peripheral, also used by the DS peripheral */ static _lock_t s_crypto_mpi_lock; +void esp_crypto_hmac_lock_acquire(void) +{ + _lock_acquire_recursive(&s_crypto_sha_aes_hmac_ds_lock); +} + +void esp_crypto_hmac_lock_release(void) +{ + _lock_release_recursive(&s_crypto_sha_aes_hmac_ds_lock); +} + void esp_crypto_sha_aes_lock_acquire(void) { - _lock_acquire(&s_crypto_sha_aes_lock); + _lock_acquire_recursive(&s_crypto_sha_aes_hmac_ds_lock); } void esp_crypto_sha_aes_lock_release(void) { - _lock_release(&s_crypto_sha_aes_lock); + _lock_release_recursive(&s_crypto_sha_aes_hmac_ds_lock); } void esp_crypto_mpi_lock_acquire(void) diff --git a/components/esp_hw_support/port/esp32s3/esp_hmac.c b/components/esp_hw_support/port/esp32s3/esp_hmac.c new file mode 100644 index 0000000000..54ec775625 --- /dev/null +++ b/components/esp_hw_support/port/esp32s3/esp_hmac.c @@ -0,0 +1,124 @@ +/* + * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "driver/periph_ctrl.h" +#include "esp32s3/rom/hmac.h" +#include "esp32s3/rom/ets_sys.h" +#include "esp_hmac.h" +#include "esp_crypto_lock.h" + +#include "hal/hmac_hal.h" + +#define SHA256_BLOCK_SZ 64 +#define SHA256_PAD_SZ 8 + +/** + * @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 on ESP32S3, 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 ESP32S3 TRM). + 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. + periph_module_enable(PERIPH_HMAC_MODULE); + periph_module_enable(PERIPH_SHA_MODULE); + periph_module_enable(PERIPH_DS_MODULE); + + 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); + + periph_module_disable(PERIPH_DS_MODULE); + periph_module_disable(PERIPH_SHA_MODULE); + periph_module_disable(PERIPH_HMAC_MODULE); + + esp_crypto_hmac_lock_release(); + + return ESP_OK; +} diff --git a/components/esp_hw_support/test/test_hmac.c b/components/esp_hw_support/test/test_hmac.c index c8ada1b9f6..fee1f8d4f6 100644 --- a/components/esp_hw_support/test/test_hmac.c +++ b/components/esp_hw_support/test/test_hmac.c @@ -14,8 +14,6 @@ #if CONFIG_IDF_ENV_FPGA -#include "esp32s2/rom/efuse.h" - /* Allow testing varying message lengths (truncating the same message) for various results */ typedef struct { @@ -23,25 +21,29 @@ typedef struct { uint8_t result[32]; } hmac_result; -static const ets_efuse_block_t key_block = ETS_EFUSE_BLOCK_KEY4; -static const char *TAG = "test_hmac"; +static const esp_efuse_block_t key_block = EFUSE_BLK_KEY0; static void setup_keyblock(void) { const uint8_t key_data[32] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, 25,26,27,28,29,30,31,32 }; - int ets_status = ets_efuse_write_key(key_block, - ETS_EFUSE_KEY_PURPOSE_HMAC_UP, + esp_err_t status = esp_efuse_write_key(key_block, + ESP_EFUSE_KEY_PURPOSE_HMAC_UP, key_data, sizeof(key_data)); - if (ets_status == ESP_OK) { - printf("written key!\n"); + if (status == ESP_OK) { + printf("Written key!\n"); + } else if (ESP_ERR_EFUSE_REPEATED_PROG) { + printf("Key written already.\n"); } else { - printf("writing key failed, maybe written already\n"); + printf("ERROR while writing key.\n"); } } +#if !CONFIG_IDF_TARGET_ESP32S3 // TODO: IDF-3664: S3 JTAG enable hasn't been implemented yet +#include "esp32s2/rom/efuse.h" +static const char *TAG = "test_hmac"; TEST_CASE("HMAC 'downstream' JTAG Enable mode", "[hw_crypto]") { int ets_status; @@ -99,6 +101,7 @@ TEST_CASE("HMAC 'downstream' JTAG Disable", "[hw_crypto]") TEST_ASSERT_EQUAL_HEX32_MESSAGE(ESP_OK, esp_hmac_jtag_disable(), "JTAG should be disabled now, please manually verify"); } +#endif TEST_CASE("HMAC 'upstream' MAC generation with zeroes", "[hw_crypto]") { @@ -1015,6 +1018,12 @@ TEST_CASE("HMAC 'upstream' wait lock", "[hw_crypto]") } } +#endif // CONFIG_IDF_ENV_FPGA + +/** + * This test is just a parameter test and does not write any keys to efuse. + * It can be done safely on any chip which supports HMAC. + */ TEST_CASE("HMAC key out of range", "[hw_crypto]") { uint8_t hmac[32]; @@ -1026,6 +1035,4 @@ TEST_CASE("HMAC key out of range", "[hw_crypto]") TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_hmac_calculate(HMAC_KEY5 + 1, message, 47, hmac)); } -#endif // CONFIG_IDF_ENV_FPGA - #endif // SOC_HMAC_SUPPORTED diff --git a/components/hal/CMakeLists.txt b/components/hal/CMakeLists.txt index b298d44ae8..ba6e51db8b 100644 --- a/components/hal/CMakeLists.txt +++ b/components/hal/CMakeLists.txt @@ -82,6 +82,7 @@ if(NOT BOOTLOADER_BUILD) "touch_sensor_hal.c" "usb_hal.c" "esp32s3/brownout_hal.c" + "esp32s3/hmac_hal.c" "esp32s3/interrupt_descriptor_table.c" "esp32s3/touch_sensor_hal.c" "usbh_hal.c") diff --git a/components/hal/esp32s3/hmac_hal.c b/components/hal/esp32s3/hmac_hal.c new file mode 100644 index 0000000000..ef2b2c5e12 --- /dev/null +++ b/components/hal/esp32s3/hmac_hal.c @@ -0,0 +1,74 @@ +/* + * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "hal/hmac_hal.h" +#include "hal/hmac_ll.h" + +void hmac_hal_start(void) +{ + hmac_ll_wait_idle(); + hmac_ll_start(); +} + +uint32_t hmac_hal_configure(hmac_hal_output_t config, uint32_t key_id) +{ + hmac_ll_wait_idle(); + hmac_ll_config_output(config); + hmac_ll_config_hw_key_id(key_id); + hmac_ll_config_finish(); + hmac_ll_wait_idle(); + + uint32_t conf_error = hmac_ll_query_config_error(); + if (conf_error) { + hmac_ll_calc_finish(); + return 1; + } else if (config != HMAC_OUTPUT_USER) { + // In "downstream" mode, this will be the last hmac operation. Make sure HMAC is ready for + // the other peripheral. + hmac_ll_wait_idle(); + } + + return 0; +} + +void hmac_hal_write_one_block_512(const void *block) +{ + hmac_ll_wait_idle(); + hmac_ll_write_block_512(block); + hmac_ll_wait_idle(); + hmac_ll_msg_one_block(); +} + +void hmac_hal_write_block_512(const void *block) +{ + hmac_ll_wait_idle(); + hmac_ll_write_block_512(block); +} + +void hmac_hal_next_block_padding(void) +{ + hmac_ll_wait_idle(); + hmac_ll_msg_padding(); +} + +void hmac_hal_next_block_normal(void) +{ + hmac_ll_wait_idle(); + hmac_ll_msg_continue(); +} + +void hmac_hal_read_result_256(void *result) +{ + hmac_ll_wait_idle(); + hmac_ll_read_result_256(result); + hmac_ll_calc_finish(); +} + +void hmac_hal_clean(void) +{ + hmac_ll_wait_idle(); + hmac_ll_clean(); +} diff --git a/components/hal/esp32s3/include/hal/clk_gate_ll.h b/components/hal/esp32s3/include/hal/clk_gate_ll.h index 2068963ee5..3f3fe70fd6 100644 --- a/components/hal/esp32s3/include/hal/clk_gate_ll.h +++ b/components/hal/esp32s3/include/hal/clk_gate_ll.h @@ -1,16 +1,8 @@ -// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #pragma once @@ -99,6 +91,10 @@ static inline uint32_t periph_ll_get_clk_en_mask(periph_module_t periph) return SYSTEM_CRYPTO_SHA_CLK_EN; case PERIPH_RSA_MODULE: return SYSTEM_CRYPTO_RSA_CLK_EN; + case PERIPH_HMAC_MODULE: + return SYSTEM_CRYPTO_HMAC_CLK_EN; + case PERIPH_DS_MODULE: + return SYSTEM_CRYPTO_DS_CLK_EN; default: return 0; } @@ -106,9 +102,6 @@ static inline uint32_t periph_ll_get_clk_en_mask(periph_module_t periph) static inline uint32_t periph_ll_get_rst_en_mask(periph_module_t periph, bool enable) { - - (void)enable; // unused - switch (periph) { case PERIPH_RMT_MODULE: return SYSTEM_RMT_RST; @@ -162,6 +155,8 @@ static inline uint32_t periph_ll_get_rst_en_mask(periph_module_t periph, bool en return SYSTEM_RST_EN_DEDICATED_GPIO; case PERIPH_GDMA_MODULE: return SYSTEM_DMA_RST; + case PERIPH_HMAC_MODULE: + return SYSTEM_CRYPTO_HMAC_RST; case PERIPH_AES_MODULE: if (enable == true) { // Clear reset on digital signature, otherwise AES unit is held in reset also. @@ -207,6 +202,7 @@ static uint32_t periph_ll_get_clk_en_reg(periph_module_t periph) case PERIPH_SDMMC_MODULE: case PERIPH_LCD_CAM_MODULE: case PERIPH_GDMA_MODULE: + case PERIPH_HMAC_MODULE: case PERIPH_AES_MODULE: case PERIPH_SHA_MODULE: case PERIPH_RSA_MODULE: @@ -230,8 +226,9 @@ static uint32_t periph_ll_get_rst_en_reg(periph_module_t periph) return SYSTEM_CORE_RST_EN_REG; case PERIPH_UART2_MODULE: case PERIPH_SDMMC_MODULE: - case PERIPH_GDMA_MODULE: case PERIPH_LCD_CAM_MODULE: + case PERIPH_GDMA_MODULE: + case PERIPH_HMAC_MODULE: case PERIPH_AES_MODULE: case PERIPH_SHA_MODULE: case PERIPH_RSA_MODULE: diff --git a/components/hal/esp32s3/include/hal/hmac_hal.h b/components/hal/esp32s3/include/hal/hmac_hal.h new file mode 100644 index 0000000000..af6fb65af4 --- /dev/null +++ b/components/hal/esp32s3/include/hal/hmac_hal.h @@ -0,0 +1,101 @@ +/* + * SPDX-FileCopyrightText: 2015-2021 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. + * See readme.md in soc/include/hal/readme.md + ******************************************************************************/ + +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * The HMAC peripheral can be configured to deliver its output to the user directly, or to deliver + * the output directly to another peripheral instead, e.g. the Digital Signature peripheral. + */ +typedef enum { + HMAC_OUTPUT_USER = 0, /**< Let user provide a message and read the HMAC result */ + HMAC_OUTPUT_DS = 1, /**< HMAC is provided to the DS peripheral to decrypt DS private key parameters */ + HMAC_OUTPUT_JTAG_ENABLE = 2, /**< HMAC is used to enable JTAG after soft-disabling it */ + HMAC_OUTPUT_ALL = 3 /**< HMAC is used for both as DS input for or enabling JTAG */ +} hmac_hal_output_t; + +/** + * @brief Make the peripheral ready for use. + * + * This triggers any further steps necessary after enabling the device + */ +void hmac_hal_start(void); + +/** + * @brief Configure which hardware key slot should be used and configure the target of the HMAC output. + * + * @note Writing out-of-range values is undefined behavior. The user has to ensure that the parameters are in range. + * + * @param config The target of the HMAC. Possible targets are described in \c hmac_hal_output_t. + * See the ESP32S3 TRM for more details. + * @param key_id The ID of the hardware key slot to be used. + * + * @return 0 if the configuration was successful, non-zero if not. + * An unsuccessful configuration means that the purpose value in the eFuse of the corresponding key slot + * doesn't match to supplied value of \c config. + */ +uint32_t hmac_hal_configure(hmac_hal_output_t config, uint32_t key_id); + +/** + * @brief Write a padded single-block message of 512 bits to the HMAC peripheral. + * + * The message must not be longer than one block (512 bits) and the padding has to be applied by software before + * writing. The padding has to be able to fit into the block after the message. + * For more information on HMAC padding, see the ESP32S3 TRM. + */ +void hmac_hal_write_one_block_512(const void *block); + +/** + * @brief Write a message block of 512 bits to the HMAC peripheral. + * + * This function must be used incombination with \c hmac_hal_next_block_normal() or \c hmac_hal_next_block_padding(). + * The first message block is written without any prerequisite. + * All message blocks which are not the last one, need a call to \c hmac_hal_next_block_normal() before, indicating + * to the hardware that a "normal", i.e. non-padded block will follow. This is even the case for a block which begins + * padding already but where the padding doesn't fit in (remaining message size > (block size - padding size)). + * Before writing the last block which contains the padding, a call to \c hmac_hal_next_block_padding() is necessary + * to indicate to the hardware that a block with padding will be written. + * + * For more information on HMAC padding, see the ESP32S3 TRM. + */ +void hmac_hal_write_block_512(const void *block); + +/** + * @brief Indicate to the hardware that a normal block will be written. + */ +void hmac_hal_next_block_normal(void); + +/** + * @brief Indicate to the hardware that a block with padding will be written. + */ +void hmac_hal_next_block_padding(void); + +/** + * @brief Read the 256 bit HMAC result from the hardware. + */ +void hmac_hal_read_result_256(void *result); + +/** + * @brief Clear (invalidate) the HMAC result provided to other hardware. + */ +void hmac_hal_clean(void); + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32s3/include/hal/hmac_ll.h b/components/hal/esp32s3/include/hal/hmac_ll.h new file mode 100644 index 0000000000..a4cfb68830 --- /dev/null +++ b/components/hal/esp32s3/include/hal/hmac_ll.h @@ -0,0 +1,187 @@ +/* + * SPDX-FileCopyrightText: 2015-2021 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. + * See readme.md in soc/include/hal/readme.md + ******************************************************************************/ + +#pragma once + +#include "soc/hwcrypto_reg.h" + +#define SHA256_BLOCK_SZ 64 +#define SHA256_DIGEST_SZ 32 + +#define HMAC_LL_EFUSE_KEY_PURPOSE_DOWN_JTAG 6 +#define HMAC_LL_EFUSE_KEY_PURPOSE_DOWN_DIGITAL_SIGNATURE 7 +#define HMAC_LL_EFUSE_KEY_PURPOSE_UP 8 +#define HMAC_LL_EFUSE_KEY_PURPOSE_DOWN_ALL 5 + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Makes the peripheral ready for use, after enabling it. + */ +static inline void hmac_ll_start(void) +{ + REG_WRITE(HMAC_SET_START_REG, 1); +} + +/** + * @brief Determine where the HMAC output should go. + * + * The HMAC peripheral can be configured to deliver its output to the user directly, or to deliver + * the output directly to another peripheral instead, e.g. the Digital Signature peripheral. + */ +static inline void hmac_ll_config_output(hmac_hal_output_t config) +{ + switch(config) { + case HMAC_OUTPUT_USER: + REG_WRITE(HMAC_SET_PARA_PURPOSE_REG, HMAC_LL_EFUSE_KEY_PURPOSE_UP); + break; + case HMAC_OUTPUT_DS: + REG_WRITE(HMAC_SET_PARA_PURPOSE_REG, HMAC_LL_EFUSE_KEY_PURPOSE_DOWN_DIGITAL_SIGNATURE); + break; + case HMAC_OUTPUT_JTAG_ENABLE: + REG_WRITE(HMAC_SET_PARA_PURPOSE_REG, HMAC_LL_EFUSE_KEY_PURPOSE_DOWN_JTAG); + break; + case HMAC_OUTPUT_ALL: + REG_WRITE(HMAC_SET_PARA_PURPOSE_REG, HMAC_LL_EFUSE_KEY_PURPOSE_DOWN_ALL); + break; + default: + ; // do nothing, error will be indicated by hmac_hal_config_error() + } +} + +/** + * @brief Selects which hardware key should be used. + */ +static inline void hmac_ll_config_hw_key_id(uint32_t key_id) +{ + REG_WRITE(HMAC_SET_PARA_KEY_REG, key_id); +} + +/** + * @brief Apply and check configuration. + * + * Afterwards, the configuration can be checked for errors with hmac_hal_config_error(). + */ +static inline void hmac_ll_config_finish(void) +{ + REG_WRITE(HMAC_SET_PARA_FINISH_REG, 1); +} + +/** + * + * @brief Query HMAC error state after configuration actions. + * + * @return + * - 1 or greater on error + * - 0 on success + */ +static inline uint32_t hmac_ll_query_config_error(void) +{ + return REG_READ(HMAC_QUERY_ERROR_REG); +} + +/** + * Wait until the HAL is ready for the next interaction. + */ +static inline void hmac_ll_wait_idle(void) +{ + uint32_t query; + do { + query = REG_READ(HMAC_QUERY_BUSY_REG); + } while(query != 0); +} + +/** + * @brief Write a message block of 512 bits to the HMAC peripheral. + */ +static inline void hmac_ll_write_block_512(const uint32_t *block) +{ + const size_t REG_WIDTH = sizeof(uint32_t); + for (size_t i = 0; i < SHA256_BLOCK_SZ / REG_WIDTH; i++) { + REG_WRITE(HMAC_WDATA_BASE + (i * REG_WIDTH), block[i]); + } + + REG_WRITE(HMAC_SET_MESSAGE_ONE_REG, 1); +} + +/** + * @brief Read the 256 bit HMAC. + */ +static inline void hmac_ll_read_result_256(uint32_t *result) +{ + const size_t REG_WIDTH = sizeof(uint32_t); + for (size_t i = 0; i < SHA256_DIGEST_SZ / REG_WIDTH; i++) { + result[i] = REG_READ(HMAC_RDATA_BASE + (i * REG_WIDTH)); + } +} + +/** + * @brief Clean the HMAC result provided to other hardware. + */ +static inline void hmac_ll_clean(void) +{ + REG_WRITE(HMAC_SET_INVALIDATE_DS_REG, 1); + REG_WRITE(HMAC_SET_INVALIDATE_JTAG_REG, 1); +} + +/** + * @brief Signals that the following block will be the padded last block. + */ +static inline void hmac_ll_msg_padding(void) +{ + REG_WRITE(HMAC_SET_MESSAGE_PAD_REG, 1); +} + +/** + * @brief Signals that all blocks have been written and a padding block will automatically be applied by hardware. + * + * Only applies if the message length is a multiple of 512 bits. + * See ESP32S3 TRM HMAC chapter for more details. + */ +static inline void hmac_ll_msg_end(void) +{ + REG_WRITE(HMAC_SET_MESSAGE_END_REG, 1); +} + +/** + * @brief The message including padding fits into one block, so no further action needs to be taken. + * + * This is called after the one-block-message has been written. + */ +static inline void hmac_ll_msg_one_block(void) +{ + REG_WRITE(HMAC_ONE_BLOCK_REG, 1); +} + +/** + * @brief Indicate that more blocks will be written after the last block. + */ +static inline void hmac_ll_msg_continue(void) +{ + REG_WRITE(HMAC_SET_MESSAGE_ING_REG, 1); +} + +/** + * @brief Clear the HMAC result. + * + * Use this after reading the HMAC result or if aborting after any of the other steps above. + */ +static inline void hmac_ll_calc_finish(void) +{ + REG_WRITE(HMAC_SET_RESULT_FINISH_REG, 2); +} + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/esp32s3/include/soc/periph_defs.h b/components/soc/esp32s3/include/soc/periph_defs.h index 6c4c4c6d13..8c1b2aaa8b 100644 --- a/components/soc/esp32s3/include/soc/periph_defs.h +++ b/components/soc/esp32s3/include/soc/periph_defs.h @@ -52,6 +52,8 @@ typedef enum { PERIPH_BT_LC_MODULE, PERIPH_AES_MODULE, PERIPH_SHA_MODULE, + PERIPH_HMAC_MODULE, + PERIPH_DS_MODULE, PERIPH_RSA_MODULE, PERIPH_SYSTIMER_MODULE, PERIPH_GDMA_MODULE, diff --git a/components/soc/esp32s3/include/soc/soc_caps.h b/components/soc/esp32s3/include/soc/soc_caps.h index b8f2d55260..848c0b1e01 100644 --- a/components/soc/esp32s3/include/soc/soc_caps.h +++ b/components/soc/esp32s3/include/soc/soc_caps.h @@ -19,7 +19,7 @@ #define SOC_RTC_SLOW_MEM_SUPPORTED 1 #define SOC_CCOMP_TIMER_SUPPORTED 1 #define SOC_DIG_SIGN_SUPPORTED 0 -#define SOC_HMAC_SUPPORTED 0 +#define SOC_HMAC_SUPPORTED 1 #define SOC_ASYNC_MEMCPY_SUPPORTED 1 #define SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS 3 #define SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS 1 diff --git a/docs/conf_common.py b/docs/conf_common.py index 390b106f95..013822e253 100644 --- a/docs/conf_common.py +++ b/docs/conf_common.py @@ -194,7 +194,6 @@ ESP32_DOCS = ['api-guides/ulp_instruction_set.rst', ESP32S2_DOCS = ['hw-reference/esp32s2/**', 'api-guides/ulps2_instruction_set.rst', 'api-guides/usb-console.rst', - 'api-reference/peripherals/hmac.rst', 'api-reference/peripherals/ds.rst', 'api-reference/peripherals/spi_slave_hd.rst', 'api-reference/peripherals/temp_sensor.rst', diff --git a/docs/doxygen/Doxyfile_esp32s3 b/docs/doxygen/Doxyfile_esp32s3 index ccee7a0e58..fdeff6008f 100644 --- a/docs/doxygen/Doxyfile_esp32s3 +++ b/docs/doxygen/Doxyfile_esp32s3 @@ -1,5 +1,6 @@ INPUT += \ $(IDF_PATH)/components/ulp/include/$(IDF_TARGET)/ulp.h \ + $(IDF_PATH)/components/esp_hw_support/include/soc/$(IDF_TARGET)/esp_hmac.h \ $(IDF_PATH)/components/hal/include/hal/mcpwm_types.h \ $(IDF_PATH)/components/driver/include/driver/mcpwm.h \ $(IDF_PATH)/components/hal/include/hal/pcnt_types.h \