esp32c6: add esp_hw_support

This commit is contained in:
wuzhenghui
2022-07-12 19:46:23 +08:00
committed by Song Ruo Jing
parent 21663bd0b9
commit 23e37393a7
30 changed files with 1836 additions and 6 deletions

View File

@@ -0,0 +1,68 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Acquire lock for HMAC cryptography peripheral
*
* Internally also locks the SHA peripheral, 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 peripheral, as the HMAC depends on the SHA peripheral
*/
void esp_crypto_hmac_lock_release(void);
/**
* @brief Acquire lock for DS cryptography peripheral
*
* Internally also locks the HMAC (which locks SHA), AES and MPI peripheral, as the DS depends on these peripherals
*/
void esp_crypto_ds_lock_acquire(void);
/**
* @brief Release lock for DS cryptography peripheral
*
* Internally also releases the HMAC (which locks SHA), AES and MPI peripheral, as the DS depends on these peripherals
*/
void esp_crypto_ds_lock_release(void);
/**
* @brief Acquire lock for the SHA and AES cryptography peripheral.
*
*/
void esp_crypto_sha_aes_lock_acquire(void);
/**
* @brief Release lock for the SHA and AES cryptography peripheral.
*
*/
void esp_crypto_sha_aes_lock_release(void);
/**
* @brief Acquire lock for the mpi cryptography peripheral.
*
*/
void esp_crypto_mpi_lock_acquire(void);
/**
* @brief Release lock for the mpi/rsa cryptography peripheral.
*
*/
void esp_crypto_mpi_lock_release(void);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,220 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_hmac.h"
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
#define ESP32C6_ERR_HW_CRYPTO_DS_HMAC_FAIL ESP_ERR_HW_CRYPTO_BASE + 0x1 /*!< HMAC peripheral problem */
#define ESP32C6_ERR_HW_CRYPTO_DS_INVALID_KEY ESP_ERR_HW_CRYPTO_BASE + 0x2 /*!< given HMAC key isn't correct,
HMAC peripheral problem */
#define ESP32C6_ERR_HW_CRYPTO_DS_INVALID_DIGEST ESP_ERR_HW_CRYPTO_BASE + 0x4 /*!< message digest check failed,
result is invalid */
#define ESP32C6_ERR_HW_CRYPTO_DS_INVALID_PADDING ESP_ERR_HW_CRYPTO_BASE + 0x5 /*!< padding check failed, but result
is produced anyway and can be read*/
#define ESP_DS_IV_BIT_LEN 128
#define ESP_DS_IV_LEN (ESP_DS_IV_BIT_LEN / 8)
#define ESP_DS_SIGNATURE_MAX_BIT_LEN 3072
#define ESP_DS_SIGNATURE_MD_BIT_LEN 256
#define ESP_DS_SIGNATURE_M_PRIME_BIT_LEN 32
#define ESP_DS_SIGNATURE_L_BIT_LEN 32
#define ESP_DS_SIGNATURE_PADDING_BIT_LEN 64
/* Length of parameter 'C' stored in flash, in bytes
- Operands Y, M and r_bar; each 3072 bits
- Operand MD (message digest); 256 bits
- Operands M' and L; each 32 bits
- Operand beta (padding value; 64 bits
*/
#define ESP_DS_C_LEN (((ESP_DS_SIGNATURE_MAX_BIT_LEN * 3 \
+ ESP_DS_SIGNATURE_MD_BIT_LEN \
+ ESP_DS_SIGNATURE_M_PRIME_BIT_LEN \
+ ESP_DS_SIGNATURE_L_BIT_LEN \
+ ESP_DS_SIGNATURE_PADDING_BIT_LEN) / 8))
typedef struct esp_ds_context esp_ds_context_t;
typedef enum {
ESP_DS_RSA_1024 = (1024 / 32) - 1,
ESP_DS_RSA_2048 = (2048 / 32) - 1,
ESP_DS_RSA_3072 = (3072 / 32) - 1
} esp_digital_signature_length_t;
/**
* Encrypted private key data. Recommended to store in flash in this format.
*
* @note This struct has to match to one from the ROM code! This documentation is mostly taken from there.
*/
typedef struct esp_digital_signature_data {
/**
* RSA LENGTH register parameters
* (number of words in RSA key & operands, minus one).
*
* Max value 127 (for RSA 3072).
*
* This value must match the length field encrypted and stored in 'c',
* or invalid results will be returned. (The DS peripheral will
* always use the value in 'c', not this value, so an attacker can't
* alter the DS peripheral results this way, it will just truncate or
* extend the message and the resulting signature in software.)
*
* @note In IDF, the enum type length is the same as of type unsigned, so they can be used interchangably.
* See the ROM code for the original declaration of struct \c ets_ds_data_t.
*/
esp_digital_signature_length_t rsa_length;
/**
* IV value used to encrypt 'c'
*/
uint32_t iv[ESP_DS_IV_BIT_LEN / 32];
/**
* Encrypted Digital Signature parameters. Result of AES-CBC encryption
* of plaintext values. Includes an encrypted message digest.
*/
uint8_t c[ESP_DS_C_LEN];
} esp_ds_data_t;
/**
* Plaintext parameters used by Digital Signature.
*
* This is only used for encrypting the RSA parameters by calling esp_ds_encrypt_params().
* Afterwards, the result can be stored in flash or in other persistent memory.
* The encryption is a prerequisite step before any signature operation can be done.
*/
typedef struct {
uint32_t Y[ESP_DS_SIGNATURE_MAX_BIT_LEN / 32]; //!< RSA exponent
uint32_t M[ESP_DS_SIGNATURE_MAX_BIT_LEN / 32]; //!< RSA modulus
uint32_t Rb[ESP_DS_SIGNATURE_MAX_BIT_LEN / 32]; //!< RSA r inverse operand
uint32_t M_prime; //!< RSA M prime operand
uint32_t length; //!< RSA length in words (32 bit)
} esp_ds_p_data_t;
/**
* @brief Sign the message with a hardware key from specific key slot.
* The function calculates a plain RSA signature with help of the DS peripheral.
* The RSA encryption operation is as follows:
* Z = XY mod M where,
* Z is the signature, X is the input message,
* Y and M are the RSA private key parameters.
*
* This function is a wrapper around \c esp_ds_finish_sign() and \c esp_ds_start_sign(), so do not use them
* in parallel.
* It blocks until the signing is finished and then returns the signature.
*
* @note This function locks the HMAC, SHA, AES and RSA components during its entire execution time.
*
* @param message the message to be signed; its length should be (data->rsa_length + 1)*4 bytes
* @param data the encrypted signing key data (AES encrypted RSA key + IV)
* @param key_id the HMAC key ID determining the HMAC key of the HMAC which will be used to decrypt the
* signing key data
* @param signature the destination of the signature, should be (data->rsa_length + 1)*4 bytes long
*
* @return
* - ESP_OK if successful, the signature was written to the parameter \c signature.
* - ESP_ERR_INVALID_ARG if one of the parameters is NULL or data->rsa_length is too long or 0
* - ESP_ERR_HW_CRYPTO_DS_HMAC_FAIL if there was an HMAC failure during retrieval of the decryption key
* - ESP_ERR_NO_MEM if there hasn't been enough memory to allocate the context object
* - ESP_ERR_HW_CRYPTO_DS_INVALID_KEY if there's a problem with passing the HMAC key to the DS component
* - ESP_ERR_HW_CRYPTO_DS_INVALID_DIGEST if the message digest didn't match; the signature is invalid.
* - ESP_ERR_HW_CRYPTO_DS_INVALID_PADDING if the message padding is incorrect, the signature can be read though
* since the message digest matches.
*/
esp_err_t esp_ds_sign(const void *message,
const esp_ds_data_t *data,
hmac_key_id_t key_id,
void *signature);
/**
* @brief Start the signing process.
*
* This function yields a context object which needs to be passed to \c esp_ds_finish_sign() to finish the signing
* process.
* The function calculates a plain RSA signature with help of the DS peripheral.
* The RSA encryption operation is as follows:
* Z = XY mod M where,
* Z is the signature, X is the input message,
* Y and M are the RSA private key parameters.
*
* @note This function locks the HMAC, SHA, AES and RSA components, so the user has to ensure to call
* \c esp_ds_finish_sign() in a timely manner.
*
* @param message the message to be signed; its length should be (data->rsa_length + 1)*4 bytes
* @param data the encrypted signing key data (AES encrypted RSA key + IV)
* @param key_id the HMAC key ID determining the HMAC key of the HMAC which will be used to decrypt the
* signing key data
* @param esp_ds_ctx the context object which is needed for finishing the signing process later
*
* @return
* - ESP_OK if successful, the ds operation was started now and has to be finished with \c esp_ds_finish_sign()
* - ESP_ERR_INVALID_ARG if one of the parameters is NULL or data->rsa_length is too long or 0
* - ESP_ERR_HW_CRYPTO_DS_HMAC_FAIL if there was an HMAC failure during retrieval of the decryption key
* - ESP_ERR_NO_MEM if there hasn't been enough memory to allocate the context object
* - ESP_ERR_HW_CRYPTO_DS_INVALID_KEY if there's a problem with passing the HMAC key to the DS component
*/
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);
/**
* Return true if the DS peripheral is busy, otherwise false.
*
* @note Only valid if \c esp_ds_start_sign() was called before.
*/
bool esp_ds_is_busy(void);
/**
* @brief Finish the signing process.
*
* @param signature the destination of the signature, should be (data->rsa_length + 1)*4 bytes long
* @param esp_ds_ctx the context object retreived by \c esp_ds_start_sign()
*
* @return
* - ESP_OK if successful, the ds operation has been finished and the result is written to signature.
* - ESP_ERR_INVALID_ARG if one of the parameters is NULL
* - ESP_ERR_HW_CRYPTO_DS_INVALID_DIGEST if the message digest didn't match; the signature is invalid.
* This means that the encrypted RSA key parameters are invalid, indicating that they may have been tampered
* with or indicating a flash error, etc.
* - ESP_ERR_HW_CRYPTO_DS_INVALID_PADDING if the message padding is incorrect, the signature can be read though
* since the message digest matches (see TRM for more details).
*/
esp_err_t esp_ds_finish_sign(void *signature, esp_ds_context_t *esp_ds_ctx);
/**
* @brief Encrypt the private key parameters.
*
* The encryption is a prerequisite step before any signature operation can be done.
* It is not strictly necessary to use this encryption function, the encryption could also happen on an external
* device.
*
* @param data Output buffer to store encrypted data, suitable for later use generating signatures.
* The allocated memory must be in internal memory and word aligned since it's filled by DMA. Both is asserted
* at run time.
* @param iv Pointer to 16 byte IV buffer, will be copied into 'data'. Should be randomly generated bytes each time.
* @param p_data Pointer to input plaintext key data. The expectation is this data will be deleted after this process
* is done and 'data' is stored.
* @param key Pointer to 32 bytes of key data. Type determined by key_type parameter. The expectation is the
* corresponding HMAC key will be stored to efuse and then permanently erased.
*
* @return
* - ESP_OK if successful, the ds operation has been finished and the result is written to signature.
* - ESP_ERR_INVALID_ARG if one of the parameters is NULL or p_data->rsa_length is too long
*/
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);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,92 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _ESP_HMAC_H_
#define _ESP_HMAC_H_
#include <stdbool.h>
#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 ESP32S2).
*
* @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
* return ESP_ERR_INVALID_STATE if unsuccessful
* @param [out] hmac the hmac result; the buffer behind the provided pointer must be a writeable buffer of 32 bytes
*
* @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);
/**
* @brief Use HMAC peripheral in Downstream mode to re-enable the JTAG, if it is not permanently disabled by HW.
* In downstream mode, HMAC calculations performed by peripheral are used internally and not provided back to user.
*
* @param key_id Determines which of the 6 key blocks in the efuses should be used for the HMAC calculation.
* The corresponding purpose field of the key block in the efuse must be set to HMAC downstream purpose.
*
* @param token Pre calculated HMAC value of the 32-byte 0x00 using SHA-256 and the known private HMAC key. The key is already
* programmed to a eFuse key block. The key block number is provided as the first parameter to this function.
*
* @return
* * ESP_OK, if the key_purpose of the key_id matches to HMAC downstread mode,
* The API returns success even if calculated HMAC does not match with the provided token.
* However, The JTAG will be re-enabled only if the calculated HMAC value matches with provided token,
* otherwise JTAG will remain disabled.
* * ESP_FAIL, if the key_purpose of the key_id is not set to HMAC downstream purpose
* or JTAG is permanently disabled by EFUSE_HARD_DIS_JTAG eFuse parameter.
* * ESP_ERR_INVALID_ARG, invalid input arguments
*
* @note Return value of the API does not indicate the JTAG status.
*/
esp_err_t esp_hmac_jtag_enable(hmac_key_id_t key_id, const uint8_t *token);
/**
* @brief Disable the JTAG which might be enabled using the HMAC downstream mode. This function just clears the result generated
* by calling esp_hmac_jtag_enable() API.
*
* @return
* * ESP_OK return ESP_OK after writing the HMAC_SET_INVALIDATE_JTAG_REG with value 1.
*/
esp_err_t esp_hmac_jtag_disable(void);
#ifdef __cplusplus
}
#endif
#endif // _ESP_HMAC_H_

View File

@@ -0,0 +1,32 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file esp32c6/rtc.h
*
* This file contains declarations of rtc related functions.
*/
/**
* @brief Get current value of RTC counter in microseconds
*
* Note: this function may take up to 1 RTC_SLOW_CLK cycle to execute
*
* @return current value of RTC counter in microseconds
*/
uint64_t esp_rtc_get_time_us(void);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,175 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
//////////////////////////////////////////////////////////
// ESP32-C6 PMS memory protection types
//
#pragma once
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Memory types recognized by PMS
*/
typedef enum {
MEMPROT_TYPE_NONE = 0x00000000,
MEMPROT_TYPE_IRAM0_SRAM = 0x00000001,
MEMPROT_TYPE_DRAM0_SRAM = 0x00000002,
MEMPROT_TYPE_IRAM0_RTCFAST = 0x00000004,
MEMPROT_TYPE_ALL = 0x7FFFFFFF,
MEMPROT_TYPE_INVALID = 0x80000000,
MEMPROT_TYPE_IRAM0_ANY = MEMPROT_TYPE_IRAM0_SRAM | MEMPROT_TYPE_IRAM0_RTCFAST
} esp_mprot_mem_t;
/**
* @brief Splitting address (line) type
*/
typedef enum {
MEMPROT_SPLIT_ADDR_NONE = 0x00000000,
MEMPROT_SPLIT_ADDR_IRAM0_DRAM0 = 0x00000001,
MEMPROT_SPLIT_ADDR_IRAM0_LINE_0 = 0x00000002,
MEMPROT_SPLIT_ADDR_IRAM0_LINE_1 = 0x00000004,
MEMPROT_SPLIT_ADDR_DRAM0_DMA_LINE_0 = 0x00000008,
MEMPROT_SPLIT_ADDR_DRAM0_DMA_LINE_1 = 0x00000010,
MEMPROT_SPLIT_ADDR_ALL = 0x7FFFFFFF,
MEMPROT_SPLIT_ADDR_INVALID = 0x80000000,
MEMPROT_SPLIT_ADDR_MAIN = MEMPROT_SPLIT_ADDR_IRAM0_DRAM0
} esp_mprot_split_addr_t;
/**
* @brief PMS area type (memory space between adjacent splitting addresses or above/below the main splt.address)
*/
typedef enum {
MEMPROT_PMS_AREA_NONE = 0x00000000,
MEMPROT_PMS_AREA_IRAM0_0 = 0x00000001,
MEMPROT_PMS_AREA_IRAM0_1 = 0x00000002,
MEMPROT_PMS_AREA_IRAM0_2 = 0x00000004,
MEMPROT_PMS_AREA_IRAM0_3 = 0x00000008,
MEMPROT_PMS_AREA_DRAM0_0 = 0x00000010,
MEMPROT_PMS_AREA_DRAM0_1 = 0x00000020,
MEMPROT_PMS_AREA_DRAM0_2 = 0x00000040,
MEMPROT_PMS_AREA_DRAM0_3 = 0x00000080,
MEMPROT_PMS_AREA_IRAM0_RTCFAST_LO = 0x00000100,
MEMPROT_PMS_AREA_IRAM0_RTCFAST_HI = 0x00000200,
MEMPROT_PMS_AREA_ALL = 0x7FFFFFFF,
MEMPROT_PMS_AREA_INVALID = 0x80000000
} esp_mprot_pms_area_t;
/**
* @brief Memory protection configuration
*/
typedef struct {
bool invoke_panic_handler; /*!< Register PMS violation interrupt for panic-handling */
bool lock_feature; /*!< Lock all PMS settings */
void *split_addr; /*!< Main I/D splitting address */
uint32_t mem_type_mask; /*!< Memory types required to protect. See esp_mprot_mem_t enum */
} esp_memp_config_t;
#define ESP_MEMPROT_DEFAULT_CONFIG() { \
.invoke_panic_handler = true, \
.lock_feature = true, \
.split_addr = NULL, \
.mem_type_mask = MEMPROT_TYPE_ALL \
}
/**
* @brief Converts Memory protection type to string
*
* @param mem_type Memory protection type
*/
static inline const char *esp_mprot_mem_type_to_str(const esp_mprot_mem_t mem_type)
{
switch (mem_type) {
case MEMPROT_TYPE_NONE:
return "NONE";
case MEMPROT_TYPE_IRAM0_SRAM:
return "IRAM0_SRAM";
case MEMPROT_TYPE_DRAM0_SRAM:
return "DRAM0_SRAM";
case MEMPROT_TYPE_IRAM0_RTCFAST:
return "IRAM0_RTCFAST";
case MEMPROT_TYPE_IRAM0_ANY:
return "IRAM0_ANY";
case MEMPROT_TYPE_ALL:
return "ALL";
default:
return "INVALID";
}
}
/**
* @brief Converts Splitting address type to string
*
* @param line_type Split line type
*/
static inline const char *esp_mprot_split_addr_to_str(const esp_mprot_split_addr_t line_type)
{
switch (line_type) {
case MEMPROT_SPLIT_ADDR_NONE:
return "SPLIT_ADDR_NONE";
case MEMPROT_SPLIT_ADDR_IRAM0_DRAM0:
return "SPLIT_ADDR_IRAM0_DRAM0";
case MEMPROT_SPLIT_ADDR_IRAM0_LINE_0:
return "SPLIT_ADDR_IRAM0_LINE_0";
case MEMPROT_SPLIT_ADDR_IRAM0_LINE_1:
return "SPLIT_ADDR_IRAM0_LINE_1";
case MEMPROT_SPLIT_ADDR_DRAM0_DMA_LINE_0:
return "SPLIT_ADDR_DRAM0_DMA_LINE_0";
case MEMPROT_SPLIT_ADDR_DRAM0_DMA_LINE_1:
return "SPLIT_ADDR_DRAM0_DMA_LINE_1";
case MEMPROT_SPLIT_ADDR_ALL:
return "SPLIT_ADDR_ALL";
default:
return "SPLIT_ADDR_INVALID";
}
}
/**
* @brief Converts PMS Area type to string
*
* @param area_type PMS Area type
*/
static inline const char *esp_mprot_pms_area_to_str(const esp_mprot_pms_area_t area_type)
{
switch (area_type) {
case MEMPROT_PMS_AREA_NONE:
return "PMS_AREA_NONE";
case MEMPROT_PMS_AREA_IRAM0_0:
return "PMS_AREA_IRAM0_0";
case MEMPROT_PMS_AREA_IRAM0_1:
return "PMS_AREA_IRAM0_1";
case MEMPROT_PMS_AREA_IRAM0_2:
return "PMS_AREA_IRAM0_2";
case MEMPROT_PMS_AREA_IRAM0_3:
return "PMS_AREA_IRAM0_3";
case MEMPROT_PMS_AREA_DRAM0_0:
return "PMS_AREA_DRAM0_0";
case MEMPROT_PMS_AREA_DRAM0_1:
return "PMS_AREA_DRAM0_1";
case MEMPROT_PMS_AREA_DRAM0_2:
return "PMS_AREA_DRAM0_2";
case MEMPROT_PMS_AREA_DRAM0_3:
return "PMS_AREA_DRAM0_3";
case MEMPROT_PMS_AREA_IRAM0_RTCFAST_LO:
return "PMS_AREA_IRAM0_RTCFAST_LO";
case MEMPROT_PMS_AREA_IRAM0_RTCFAST_HI:
return "PMS_AREA_IRAM0_RTCFAST_HI";
case MEMPROT_PMS_AREA_ALL:
return "PMS_AREA_ALL";
default:
return "PMS_AREA_INVALID";
}
}
#ifdef __cplusplus
}
#endif