Merge branch 'feat/add_opaque_ds_driver' into 'master'

feat: adds PSA opaque DS driver support

See merge request espressif/esp-idf!45008
This commit is contained in:
Mahavir Jain
2026-02-06 12:41:58 +05:30
28 changed files with 1723 additions and 1511 deletions
+1
View File
@@ -35,6 +35,7 @@ menu "ESP-TLS"
config ESP_TLS_USE_DS_PERIPHERAL
bool "Use Digital Signature (DS) Peripheral with ESP-TLS"
depends on ESP_TLS_USING_MBEDTLS && SOC_DIG_SIGN_SUPPORTED
select MBEDTLS_HARDWARE_RSA_DS_PERIPHERAL
default y
help
Enable use of the Digital Signature Peripheral for ESP-TLS.The DS peripheral
+52 -49
View File
@@ -44,7 +44,8 @@ static esp_err_t esp_set_atecc608a_pki_context(esp_tls_t *tls, const void *pki);
#if defined(CONFIG_ESP_TLS_USE_DS_PERIPHERAL)
#include <pk_wrap.h>
#include "rsa_sign_alt.h"
#include "psa/crypto.h"
#include "psa_crypto_driver_esp_rsa_ds.h"
static esp_err_t esp_mbedtls_init_pk_ctx_for_ds(const void *pki);
#endif /* CONFIG_ESP_TLS_USE_DS_PERIPHERAL */
@@ -117,7 +118,7 @@ typedef struct esp_tls_pki_t {
const unsigned char *privkey_password;
unsigned int privkey_password_len;
#ifdef CONFIG_ESP_TLS_USE_DS_PERIPHERAL
void *esp_ds_data;
void *esp_rsa_ds_data;
#endif
} esp_tls_pki_t;
@@ -289,9 +290,6 @@ int esp_mbedtls_handshake(esp_tls_t *tls, const esp_tls_cfg_t *cfg)
#endif
tls->conn_state = ESP_TLS_DONE;
#ifdef CONFIG_ESP_TLS_USE_DS_PERIPHERAL
esp_ds_release_ds_lock();
#endif
return 1;
} else {
if (ret != ESP_TLS_ERR_SSL_WANT_READ && ret != ESP_TLS_ERR_SSL_WANT_WRITE) {
@@ -503,6 +501,9 @@ void esp_mbedtls_cleanup(esp_tls_t *tls)
mbedtls_free(rsa);
rsa = NULL;
}
if (tls->clientkey.MBEDTLS_PRIVATE(priv_id) != PSA_KEY_ID_NULL) {
psa_destroy_key(tls->clientkey.MBEDTLS_PRIVATE(priv_id));
}
tls->clientkey.MBEDTLS_PRIVATE(pk_ctx) = NULL;
}
@@ -514,6 +515,9 @@ void esp_mbedtls_cleanup(esp_tls_t *tls)
mbedtls_free(rsa);
rsa = NULL;
}
if (tls->serverkey.MBEDTLS_PRIVATE(priv_id) != PSA_KEY_ID_NULL) {
psa_destroy_key(tls->serverkey.MBEDTLS_PRIVATE(priv_id));
}
tls->serverkey.MBEDTLS_PRIVATE(pk_ctx) = NULL;
}
#endif
@@ -551,9 +555,6 @@ void esp_mbedtls_cleanup(esp_tls_t *tls)
#ifdef CONFIG_ESP_TLS_USE_SECURE_ELEMENT
atcab_release();
#endif
#ifdef CONFIG_ESP_TLS_USE_DS_PERIPHERAL
esp_ds_release_ds_lock();
#endif
}
static esp_err_t set_ca_cert(esp_tls_t *tls, const unsigned char *cacert, size_t cacert_len)
@@ -600,10 +601,10 @@ static esp_err_t set_pki_context(esp_tls_t *tls, const esp_tls_pki_t *pki)
}
#ifdef CONFIG_ESP_TLS_USE_DS_PERIPHERAL
if (pki->esp_ds_data != NULL) {
if (pki->esp_rsa_ds_data != NULL) {
ret = esp_mbedtls_init_pk_ctx_for_ds(pki);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize pk context for esp_ds");
ESP_LOGE(TAG, "Failed to initialize pk context for esp_rsa_ds");
return ret;
}
} else
@@ -1062,7 +1063,7 @@ esp_err_t set_client_config(const char *hostname, size_t hostlen, esp_tls_cfg_t
ESP_LOGE(TAG, "Client certificate is also required with the DS parameters");
return ESP_ERR_INVALID_STATE;
}
esp_ds_set_session_timeout(cfg->timeout_ms);
esp_rsa_ds_opaque_set_session_timeout(cfg->timeout_ms);
/* set private key pointer to NULL since the DS peripheral with its own configuration data is used */
esp_tls_pki_t pki = {
.public_cert = &tls->clientcert,
@@ -1073,7 +1074,7 @@ esp_err_t set_client_config(const char *hostname, size_t hostlen, esp_tls_cfg_t
.privkey_pem_bytes = 0,
.privkey_password = NULL,
.privkey_password_len = 0,
.esp_ds_data = cfg->ds_data,
.esp_rsa_ds_data = cfg->ds_data,
};
esp_err_t esp_ret = set_pki_context(tls, &pki);
@@ -1403,47 +1404,49 @@ static esp_err_t esp_set_atecc608a_pki_context(esp_tls_t *tls, const void *pki)
#endif /* CONFIG_ESP_TLS_USE_SECURE_ELEMENT */
#ifdef CONFIG_ESP_TLS_USE_DS_PERIPHERAL
int esp_mbedtls_ds_can_do(mbedtls_pk_type_t type)
{
ESP_LOGI(TAG, "esp_mbedtls_ds_can_do called with type %d", type);
return type == MBEDTLS_PK_RSA || type == MBEDTLS_PK_RSASSA_PSS;
}
static esp_err_t esp_mbedtls_init_pk_ctx_for_ds(const void *pki)
{
int ret = -1;
/* initialize the mbedtls pk context with rsa context */
mbedtls_rsa_context *rsakey = calloc(1, sizeof(mbedtls_rsa_context));
if (rsakey == NULL) {
ESP_LOGE(TAG, "Failed to allocate memory for mbedtls_rsa_context");
return ESP_ERR_NO_MEM;
}
mbedtls_rsa_init(rsakey);
esp_tls_pki_t *pki_l = (esp_tls_pki_t *) pki;
mbedtls_pk_context *pk_context = (mbedtls_pk_context *) pki_l->pk_key;
mbedtls_pk_info_t *esp_ds_pk_info = calloc(1, sizeof(mbedtls_pk_info_t));
if (esp_ds_pk_info == NULL) {
ESP_LOGE(TAG, "Failed to allocate memory for mbedtls_pk_info_t");
ret = ESP_ERR_NO_MEM;
mbedtls_rsa_free(rsakey);
free(rsakey);
goto exit;
esp_ds_data_ctx_t *ds_data = ((const esp_tls_pki_t*)pki)->esp_rsa_ds_data;
if (ds_data == NULL) {
ESP_LOGE(TAG, "DS data context is NULL");
return ESP_ERR_INVALID_ARG;
}
esp_ds_pk_info->sign_func = esp_ds_rsa_sign_alt;
esp_ds_pk_info->get_bitlen = esp_ds_get_keylen_alt;
esp_ds_pk_info->can_do = esp_mbedtls_ds_can_do;
esp_ds_pk_info->type = MBEDTLS_PK_RSASSA_PSS;
pk_context->pk_info = esp_ds_pk_info;
pk_context->pk_ctx = rsakey;
ret = esp_ds_init_data_ctx(((const esp_tls_pki_t*)pki)->esp_ds_data);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize DS parameters from nvs");
goto exit;
esp_tls_pki_t *pki_l = (esp_tls_pki_t *) pki;
if (pki_l->pk_key == NULL) {
ESP_LOGE(TAG, "PK key context is NULL");
return ESP_ERR_INVALID_ARG;
}
ESP_LOGD(TAG, "DS peripheral params initialized.");
exit:
return ret;
psa_key_id_t ds_key_id = 0;
psa_status_t status = PSA_ERROR_GENERIC_ERROR;
psa_key_attributes_t ds_key_attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_algorithm_t alg = PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_ANY_HASH);
#ifdef CONFIG_MBEDTLS_SSL_PROTO_TLS1_3
psa_set_key_enrollment_algorithm(&ds_key_attributes, PSA_ALG_RSA_PSS(PSA_ALG_ANY_HASH));
#endif /* CONFIG_MBEDTLS_SSL_PROTO_TLS1_3 */
psa_set_key_type(&ds_key_attributes, PSA_KEY_TYPE_RSA_KEY_PAIR);
psa_set_key_bits(&ds_key_attributes, ds_data->rsa_length_bits);
psa_set_key_usage_flags(&ds_key_attributes, PSA_KEY_USAGE_SIGN_HASH);
psa_set_key_algorithm(&ds_key_attributes, alg);
psa_set_key_lifetime(&ds_key_attributes, PSA_KEY_LIFETIME_ESP_RSA_DS);
status = psa_import_key(&ds_key_attributes,
(const uint8_t *)ds_data,
sizeof(esp_ds_data_ctx_t),
&ds_key_id);
psa_reset_key_attributes(&ds_key_attributes);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "Failed to import DS key to PSA, status = %d", status);
return ESP_ERR_INVALID_STATE;
}
int ret = mbedtls_pk_wrap_psa(pki_l->pk_key, ds_key_id);
if (ret != 0) {
ESP_LOGE(TAG, "mbedtls_pk_wrap_psa failed with -0x%04X", -ret);
psa_destroy_key(ds_key_id);
return ESP_FAIL;
}
ESP_LOGD(TAG, "DS peripheral pk context initialized.");
return ESP_OK;
}
#endif /* CONFIG_ESP_TLS_USE_DS_PERIPHERAL */
@@ -149,10 +149,10 @@ static esp_err_t esp_ds_finish_sign(void *signature, const esp_ds_data_t *data)
return return_value;
}
esp_err_t esp_ds_sign(const void *message,
const esp_ds_data_t *data,
uint32_t key_id,
void *signature)
static esp_err_t esp_ds_sign(const void *message,
const esp_ds_data_t *data,
uint32_t key_id,
void *signature)
{
esp_err_t result = esp_ds_start_sign(message, data, key_id);
if (result != ESP_OK) {
@@ -247,7 +247,7 @@ static esp_err_t esp_ds_start_sign(const void *message,
return ESP_OK;
}
esp_err_t esp_ds_finish_sign(void *signature, const esp_ds_data_t *data)
static esp_err_t esp_ds_finish_sign(void *signature, const esp_ds_data_t *data)
{
ets_ds_result_t result = ets_ds_finish_sign(signature, (ets_ds_data_t*) data);
+7 -9
View File
@@ -278,8 +278,9 @@ endif()
target_sources(mbedtls PRIVATE ${mbedtls_target_sources})
if(NOT ${IDF_TARGET} STREQUAL "linux")
target_link_libraries(tfpsacrypto PRIVATE idf::esp_security)
target_link_libraries(tfpsacrypto PUBLIC idf::esp_security)
target_link_libraries(builtin PRIVATE idf::esp_security)
target_link_libraries(p256m PRIVATE idf::esp_security)
endif()
# Choose peripheral type
@@ -382,15 +383,12 @@ if(CONFIG_SOC_HMAC_SUPPORTED)
target_link_libraries(tfpsacrypto PRIVATE idf::efuse)
endif()
if(CONFIG_SOC_DIG_SIGN_SUPPORTED)
if(CONFIG_SOC_DIG_SIGN_SUPPORTED AND CONFIG_MBEDTLS_HARDWARE_RSA_DS_PERIPHERAL)
target_sources(tfpsacrypto PRIVATE
"${COMPONENT_DIR}/port/esp_ds/esp_rsa_sign_alt.c"
"${COMPONENT_DIR}/port/esp_ds/esp_rsa_dec_alt.c"
"${COMPONENT_DIR}/port/esp_ds/esp_ds_common.c")
endif()
# # CONFIG_ESP_TLS_USE_DS_PERIPHERAL can be enabled only for the supported targets.
if(CONFIG_ESP_TLS_USE_DS_PERIPHERAL)
target_sources(tfpsacrypto PRIVATE "${COMPONENT_DIR}/port/esp_ds/esp_rsa_sign_alt.c")
"${COMPONENT_DIR}/port/psa_driver/esp_rsa_ds/psa_crypto_driver_esp_rsa_ds.c"
"${COMPONENT_DIR}/port/psa_driver/esp_rsa_ds/psa_crypto_driver_esp_rsa_ds_utilities.c"
)
target_link_libraries(tfpsacrypto PRIVATE idf::efuse)
endif()
if(CONFIG_SOC_HMAC_SUPPORTED)
+7
View File
@@ -1543,6 +1543,13 @@ menu "mbedTLS"
help
This option enables hardware acceleration for ECDSA sign function, only
when using ATECC608A cryptoauth chip.
config MBEDTLS_HARDWARE_RSA_DS_PERIPHERAL
bool "Enable hardware RSA digital signature peripheral acceleration"
default n
depends on SOC_DIG_SIGN_SUPPORTED
help
Enable hardware accelerated digital signature peripheral for RSA digital signature generation.
endmenu
menu "Entropy and Random Number Generation"
@@ -1,235 +0,0 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "sdkconfig.h"
#include "esp_ds.h"
#include "esp_log.h"
#include "esp_ds_common.h"
#include "esp_memory_utils.h"
#include "esp_ds/esp_ds_rsa.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "psa/crypto.h"
#ifdef SOC_DIG_SIGN_SUPPORTED
#include "rom/digital_signature.h"
#else
#error "Selected target does not support DS peripheral"
#endif
#define FACTOR_KEYLEN_IN_BYTES 4
static const char *TAG = "ESP_DS_COMMON";
static hmac_key_id_t s_esp_ds_hmac_key_id = -1;
static esp_ds_data_t *s_ds_data = NULL;
static SemaphoreHandle_t s_ds_lock = NULL;
static int s_timeout_ms = 0;
esp_ds_data_t *esp_ds_get_data_ctx(void)
{
return s_ds_data;
}
hmac_key_id_t esp_ds_get_hmac_key_id(void)
{
return s_esp_ds_hmac_key_id;
}
size_t esp_ds_get_keylen(void *ctx)
{
if (s_ds_data == NULL) {
ESP_LOGE(TAG, "s_ds_data is NULL, cannot get key length");
return 0;
}
/* calculating the rsa_length in bytes */
return ((s_ds_data->rsa_length + 1) * FACTOR_KEYLEN_IN_BYTES);
}
size_t esp_ds_get_keylen_alt(mbedtls_pk_context *ctx)
{
if (s_ds_data == NULL) {
ESP_LOGE(TAG, "s_ds_data is NULL, cannot get key length");
return 0;
}
/* calculating the rsa_length in bytes */
return ((s_ds_data->rsa_length + 1) * FACTOR_KEYLEN_IN_BYTES);
}
/* Lock for the DS session, other TLS connections trying to use the DS peripheral will be blocked
* till this DS session is completed (i.e. TLS handshake for this connection is completed) */
static void __attribute__((constructor)) esp_ds_conn_lock(void)
{
if ((s_ds_lock = xSemaphoreCreateMutex()) == NULL) {
ESP_EARLY_LOGE(TAG, "mutex for the DS session lock could not be created");
}
}
void esp_ds_release_ds_lock(void)
{
if (s_ds_lock == NULL) {
ESP_LOGE(TAG, "s_ds_lock is NULL, cannot release lock");
return;
}
if (xSemaphoreGetMutexHolder(s_ds_lock) == xTaskGetCurrentTaskHandle()) {
/* Give back the semaphore (DS lock) */
xSemaphoreGive(s_ds_lock);
}
}
void esp_ds_set_session_timeout(int timeout)
{
/* add additional offset of 1000 ms to have enough time for deleting the TLS connection and free the previous ds context after exceeding timeout value (this offset also helps when timeout is set to 0) */
if (timeout > s_timeout_ms) {
s_timeout_ms = timeout + 1000;
}
}
esp_err_t esp_ds_init_data_ctx(esp_ds_data_ctx_t *ds_data)
{
if (ds_data == NULL || ds_data->esp_ds_data == NULL) {
return ESP_ERR_INVALID_ARG;
}
/* mutex is given back when the DS context is freed after the TLS handshake is completed or in case of failure (at cleanup) */
if ((xSemaphoreTake(s_ds_lock, s_timeout_ms / portTICK_PERIOD_MS) != pdTRUE)) {
ESP_LOGE(TAG, "ds_lock could not be obtained in specified time");
return ESP_FAIL;
}
s_ds_data = ds_data->esp_ds_data;
ESP_LOGD(TAG, "Using DS with key block %u, RSA length %u", ds_data->efuse_key_id, ds_data->rsa_length_bits);
s_esp_ds_hmac_key_id = (hmac_key_id_t) ds_data->efuse_key_id;
const unsigned rsa_length_int = (ds_data->rsa_length_bits / 32) - 1;
if (esp_ptr_byte_accessible(s_ds_data)) {
/* calculate the rsa_length in terms of esp_digital_signature_length_t which is required for the internal DS API */
s_ds_data->rsa_length = rsa_length_int;
} else if (s_ds_data->rsa_length != rsa_length_int) {
/*
* Configuration data is most likely from DROM segment and it
* is not properly formatted for all parameters consideration.
* Moreover, we can not modify as it is read-only and hence
* the error.
*/
ESP_LOGE(TAG, "RSA length mismatch %u, %u", s_ds_data->rsa_length, rsa_length_int);
return ESP_ERR_INVALID_ARG;
}
return ESP_OK;
}
esp_err_t esp_ds_deinit_data_ctx(void)
{
esp_ds_release_ds_lock();
s_ds_data = NULL;
s_esp_ds_hmac_key_id = -1;
return ESP_OK;
}
int esp_ds_mgf_mask(unsigned char *dst, size_t dlen, unsigned char *src,
size_t slen, mbedtls_md_type_t md_alg)
{
unsigned char counter[4];
unsigned char *p;
unsigned int hlen;
size_t i, use_len;
unsigned char mask[MBEDTLS_MD_MAX_SIZE];
int ret = 0;
const mbedtls_md_info_t *md_info;
mbedtls_md_context_t md_ctx;
mbedtls_md_init(&md_ctx);
md_info = mbedtls_md_info_from_type(md_alg);
if (md_info == NULL) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if ((ret = mbedtls_md_setup(&md_ctx, md_info, 0)) != 0) {
goto exit;
}
hlen = mbedtls_md_get_size(md_info);
memset(mask, 0, sizeof(mask));
memset(counter, 0, 4);
/* Generate and apply dbMask */
p = dst;
while (dlen > 0) {
use_len = hlen;
if (dlen < hlen) {
use_len = dlen;
}
if ((ret = mbedtls_md_starts(&md_ctx)) != 0) {
goto exit;
}
if ((ret = mbedtls_md_update(&md_ctx, src, slen)) != 0) {
goto exit;
}
if ((ret = mbedtls_md_update(&md_ctx, counter, 4)) != 0) {
goto exit;
}
if ((ret = mbedtls_md_finish(&md_ctx, mask)) != 0) {
goto exit;
}
for (i = 0; i < use_len; ++i) {
*p++ ^= mask[i];
}
counter[3]++;
dlen -= use_len;
}
exit:
mbedtls_platform_zeroize(mask, sizeof(mask));
mbedtls_md_free(&md_ctx);
return ret;
}
int esp_ds_hash_mprime(const unsigned char *hash, size_t hlen,
const unsigned char *salt, size_t slen,
unsigned char *out, mbedtls_md_type_t md_alg)
{
const unsigned char zeros[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
mbedtls_md_context_t md_ctx;
int ret = PSA_ERROR_INVALID_ARGUMENT;
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(md_alg);
if (md_info == NULL) {
return PSA_ERROR_INVALID_ARGUMENT;
}
mbedtls_md_init(&md_ctx);
if ((ret = mbedtls_md_setup(&md_ctx, md_info, 0)) != 0) {
goto exit;
}
if ((ret = mbedtls_md_starts(&md_ctx)) != 0) {
goto exit;
}
if ((ret = mbedtls_md_update(&md_ctx, zeros, sizeof(zeros))) != 0) {
goto exit;
}
if ((ret = mbedtls_md_update(&md_ctx, hash, hlen)) != 0) {
goto exit;
}
if ((ret = mbedtls_md_update(&md_ctx, salt, slen)) != 0) {
goto exit;
}
if ((ret = mbedtls_md_finish(&md_ctx, out)) != 0) {
goto exit;
}
exit:
mbedtls_md_free(&md_ctx);
return ret;
}
@@ -1,62 +0,0 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "mbedtls/md.h"
#define FACTOR_KEYLEN_IN_BYTES 4
#define SWAP_INT32(x) (((x) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | ((x) << 24))
/**
* @brief Get the data context for the digital signature.
*
* @return esp_ds_data_t* esp ds data context pointer.
*/
esp_ds_data_t *esp_ds_get_data_ctx(void);
/**
* @brief Get the HMAC key ID used for digital signature operations.
*
* @return hmac_key_id_t HMAC key ID.
*/
hmac_key_id_t esp_ds_get_hmac_key_id(void);
/**
* @brief Mask generation function (MGF) for TLS 1.3.
*
* @param[in] dst Pointer to the destination buffer.
* @param[in] dlen Length of the destination buffer.
* @param[in] src Pointer to the source buffer.
* @param[in] slen Length of the salt value.
* @param[in] md_alg The message digest algorithm type.
* @return int Returns 0 on success, or a negative error code on failure.
*/
int esp_ds_mgf_mask(unsigned char *dst, size_t dlen, unsigned char *src,
size_t slen, mbedtls_md_type_t md_alg);
/**
* @brief Generates a hash using the M-Prime algorithm as specified in RFC 8446.
*
* @param hash Pointer to the input hash.
* @param hlen Length of the input hash.
* @param salt Pointer to the salt value.
* @param slen Length of the salt value.
* @param out Pointer to the output buffer where the hash will be stored.
* @param md_alg The message digest algorithm type to use for hashing.
* @return int Returns 0 on success, or a negative error code on failure.
*/
int esp_ds_hash_mprime(const unsigned char *hash, size_t hlen,
const unsigned char *salt, size_t slen,
unsigned char *out, mbedtls_md_type_t md_alg);
#ifdef __cplusplus
}
#endif
@@ -1,297 +0,0 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "sdkconfig.h"
#include "esp_ds.h"
#include "rsa_dec_alt.h"
#include "mbedtls/private/rsa.h"
#include "psa/crypto.h"
#include "esp_ds_common.h"
#include "esp_log.h"
static const char *TAG = "ESP_RSA_DEC_ALT";
#define MIN_V15_PADDING_LEN 11
static int esp_ds_rsaes_pkcs1_v15_unpadding(unsigned char *input,
size_t ilen,
unsigned char *output,
size_t output_max_len,
size_t *olen)
{
if (ilen < MIN_V15_PADDING_LEN) {
return MBEDTLS_ERR_CIPHER_INVALID_PADDING;
}
unsigned char bad = 0;
size_t msg_len = 0;
size_t msg_max_len = 0;
unsigned char pad_done = 0;
size_t pad_count = 0;
msg_max_len = (output_max_len > ilen - MIN_V15_PADDING_LEN) ? ilen - MIN_V15_PADDING_LEN : output_max_len;
/* Check the first byte (0x00) */
bad |= input[0];
/* Check the padding type */
bad |= input[1] ^ 2; // MBEDTLS_RSA_CRYPT;
/* Scan for separator (0x00) and count padding bytes in constant time */
for (size_t i = 2; i < ilen; i++) {
unsigned char found = (input[i] == 0x00);
pad_done = pad_done | found;
pad_count += (pad_done == 0) ? 1 : 0;
}
/* Check if we found a separator and padding is long enough */
bad |= (pad_done == 0); /* No separator found */
bad |= (pad_count < 8); /* Padding too short (need at least 8 non-zero bytes) */
/* Calculate message length */
msg_len = ilen - pad_count - 3;
/* Check if separator is not at the very end */
bad |= (msg_len > output_max_len);
if (bad) {
msg_len = msg_max_len;
}
/* Verify padding bytes are non-zero in constant time */
#if defined(__clang__) && defined(__xtensa__)
#pragma clang loop vectorize(disable)
#endif
for (size_t i = 2; i < ilen; i++) {
unsigned char in_padding = (i < pad_count + 2);
unsigned char is_zero = (input[i] == 0x00);
bad |= in_padding & is_zero;
}
if (bad) {
return PSA_ERROR_INVALID_ARGUMENT;
}
*olen = msg_len;
if (*olen > 0) {
memcpy(output, input + ilen - msg_len, msg_len);
}
return 0;
}
static int esp_ds_compute_hash(mbedtls_md_type_t md_alg,
const unsigned char *input, size_t ilen,
unsigned char *output)
{
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(md_alg);
if (md_info == NULL) {
return PSA_ERROR_INVALID_ARGUMENT;
}
return mbedtls_md(md_info, input, ilen, output);
}
static int esp_ds_rsaes_pkcs1_v21_unpadding(unsigned char *input,
size_t ilen,
unsigned char *output,
size_t output_max_len,
size_t *olen)
{
int ret;
unsigned int hlen = mbedtls_md_get_size_from_type(MBEDTLS_MD_SHA256);
unsigned char bad = 0;
size_t pad_len = 0;
size_t msg_len = 0;
/* Validate input length */
bad |= (ilen < 2 * hlen + 2);
/* Apply MGF masks */
ret = esp_ds_mgf_mask(input + 1, hlen, input + hlen + 1, ilen - hlen - 1, MBEDTLS_MD_SHA256);
if (ret != 0) {
ESP_LOGE(TAG, "Error in MGF mask, returned %d", ret);
return ret;
}
ret = esp_ds_mgf_mask(input + hlen + 1, ilen - hlen - 1, input + 1, hlen, MBEDTLS_MD_SHA256);
if (ret != 0) {
ESP_LOGE(TAG, "Error in MGF mask, returned %d", ret);
return ret;
}
/* Check first byte (should be 0x00) */
bad |= input[0];
/* Skip the first byte and maskSeed */
unsigned char *db = input + 1 + hlen;
size_t db_len = ilen - hlen - 1;
/* Compute hash, label is NULL and label_len is 0 */
unsigned char lhash[MBEDTLS_MD_MAX_SIZE];
ret = esp_ds_compute_hash(MBEDTLS_MD_SHA256, NULL, 0, lhash);
if (ret != 0) {
ESP_LOGE(TAG, "Error in compute_hash, returned %d", ret);
return ret;
}
/* Verify hash portion of db against lhash */
for (size_t i = 0; i < hlen && i < db_len; i++) {
bad |= db[i] ^ lhash[i];
}
/* Skip past lhash in DB */
unsigned char *p = db + hlen;
size_t remaining = db_len - hlen;
/* Get zero-padding len, following mbedTLS pattern
* Always read till end of buffer (minus one, for the 01 byte) */
unsigned char in_padding = 1;
for (size_t i = 0; i < remaining - 1; i++) {
unsigned char is_zero = (p[i] == 0);
in_padding = in_padding & is_zero;
pad_len += in_padding;
}
p += pad_len;
bad |= (*p != 0x01);
p++;
/* Calculate message length */
msg_len = remaining - pad_len - 1;
/* Check output buffer size */
bad |= (output_max_len < msg_len);
if (bad) {
return PSA_ERROR_INVALID_ARGUMENT;
}
/* Copy message in constant time */
*olen = msg_len;
if (*olen > 0) {
memcpy(output, p, msg_len);
}
return 0;
}
int esp_ds_rsa_decrypt(void *ctx, size_t *olen,
const unsigned char *input, unsigned char *output,
size_t output_max_len)
{
int padding = MBEDTLS_PK_RSA_PKCS_V15;
if (ctx != NULL) {
mbedtls_rsa_context *rsa_ctx = (mbedtls_rsa_context *)ctx;
if (rsa_ctx->MBEDTLS_PRIVATE(padding) == MBEDTLS_RSA_PKCS_V15) {
padding = MBEDTLS_RSA_PKCS_V15;
} else if (rsa_ctx->MBEDTLS_PRIVATE(padding) == MBEDTLS_RSA_PKCS_V21) {
padding = MBEDTLS_RSA_PKCS_V21;
} else {
ESP_LOGE(TAG, "Unsupported padding type %d", rsa_ctx->MBEDTLS_PRIVATE(padding));
return -1;
}
}
size_t ilen = esp_ds_get_keylen(ctx);
if (ilen == 0) {
ESP_LOGE(TAG, "Invalid RSA key length");
return -1;
}
size_t data_len = ilen / 4;
uint32_t *output_tmp = NULL;
uint32_t *input_tmp = calloc(data_len, sizeof(uint32_t));
if (input_tmp == NULL) {
ESP_LOGE(TAG, "Could not allocate memory for internal DS operations");
return -1;
}
for (unsigned int i = 0; i < (data_len); i++) {
input_tmp[i] = SWAP_INT32(((uint32_t *)input)[(data_len) - (i + 1)]);
}
esp_ds_data_t *s_ds_data = esp_ds_get_data_ctx();
if (s_ds_data == NULL) {
ESP_LOGE(TAG, "s_ds_data is NULL, cannot perform decryption");
free(input_tmp);
return -1;
}
hmac_key_id_t s_esp_ds_hmac_key_id = esp_ds_get_hmac_key_id();
esp_ds_context_t *esp_ds_ctx = NULL;
esp_err_t ds_r = esp_ds_start_sign((const void *)input_tmp,
s_ds_data,
s_esp_ds_hmac_key_id,
&esp_ds_ctx);
if (ds_r != ESP_OK) {
ESP_LOGE(TAG, "Error in esp_ds_start_sign, returned %x ", ds_r);
goto exit;
}
ds_r = esp_ds_finish_sign((void *)input_tmp, esp_ds_ctx);
if (ds_r != ESP_OK) {
if (ds_r == ESP_ERR_HW_CRYPTO_DS_INVALID_DIGEST) {
ESP_LOGE(TAG, "Invalid digest in DS data reported by esp_ds_finish_sign");
} else {
ESP_LOGE(TAG, "Error in esp_ds_finish_sign, returned %x ", ds_r);
}
goto exit;
}
esp_ds_release_ds_lock();
output_tmp = calloc(data_len, sizeof(uint32_t));
if (output_tmp == NULL) {
ESP_LOGE(TAG, "Could not allocate memory for output_tmp");
goto exit;
}
for (unsigned int i = 0; i < (data_len); i++) {
((uint32_t *)output_tmp)[i] = SWAP_INT32(((uint32_t *)input_tmp)[(data_len) - (i + 1)]);
}
// Unpad the decrypted data
if (padding == MBEDTLS_PK_RSA_PKCS_V15) {
if (esp_ds_rsaes_pkcs1_v15_unpadding((uint8_t *)output_tmp, ilen, (uint8_t *)output_tmp, ilen, olen) != 0) {
ESP_LOGE(TAG, "Error in v15 unpadding");
goto exit;
}
} else if (padding == MBEDTLS_PK_RSA_PKCS_V21) {
if (esp_ds_rsaes_pkcs1_v21_unpadding((uint8_t *)output_tmp, ilen, (uint8_t *)output_tmp, ilen, olen) != 0) {
ESP_LOGE(TAG, "Error in v21 unpadding");
goto exit;
}
} else {
ESP_LOGE(TAG, "Unsupported padding type %d", padding);
goto exit;
}
// Copy the decrypted data to output buffer
if (output_max_len < *olen) {
ESP_LOGE(TAG, "Output buffer is too small, output_max_len: %zu, olen: %zu", output_max_len, *olen);
goto exit;
}
memcpy(output, output_tmp, *olen);
free(output_tmp);
free(input_tmp);
return 0;
exit:
esp_ds_release_ds_lock();
if (input_tmp) {
free(input_tmp);
}
if (output_tmp) {
free(output_tmp);
}
if (olen) {
*olen = 0; // Set olen to 0 in case of error
}
return -1;
}
@@ -1,408 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*
* SPDX-FileContributor: The Mbed TLS Contributors
*/
#include "sdkconfig.h"
#include "rsa_sign_alt.h"
#include "esp_ds.h"
#include "esp_ds_common.h"
#include "esp_log.h"
#include "esp_heap_caps.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "psa/crypto.h"
#include "mbedtls/psa_util.h"
#include "mbedtls/private/rsa.h"
#include "mbedtls/pk.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/asn1.h"
#include "mbedtls/md.h"
#include <string.h>
static const char *TAG = "ESP_RSA_SIGN_ALT";
/*
* Local OID lookup table for hash algorithms
* This replicates the OID data needed for PKCS#1 v1.5 DigestInfo encoding
* Since OID access has moved to internal driver headers in PSA transition,
* we maintain this local table for the hardware accelerator implementation.
*/
typedef struct {
mbedtls_md_type_t md_alg;
const char *oid;
size_t oid_len;
} oid_md_mapping_t;
static const oid_md_mapping_t oid_md_table[] = {
#if defined(PSA_WANT_ALG_MD5)
{ MBEDTLS_MD_MD5, "\x2a\x86\x48\x86\xf7\x0d\x02\x05", 8 },
#endif
#if defined(PSA_WANT_ALG_SHA_1)
{ MBEDTLS_MD_SHA1, "\x2b\x0e\x03\x02\x1a", 5 },
#endif
#if defined(PSA_WANT_ALG_SHA_224)
{ MBEDTLS_MD_SHA224, "\x60\x86\x48\x01\x65\x03\x04\x02\x04", 9 },
#endif
#if defined(PSA_WANT_ALG_SHA_256)
{ MBEDTLS_MD_SHA256, "\x60\x86\x48\x01\x65\x03\x04\x02\x01", 9 },
#endif
#if defined(PSA_WANT_ALG_SHA_384)
{ MBEDTLS_MD_SHA384, "\x60\x86\x48\x01\x65\x03\x04\x02\x02", 9 },
#endif
#if defined(PSA_WANT_ALG_SHA_512)
{ MBEDTLS_MD_SHA512, "\x60\x86\x48\x01\x65\x03\x04\x02\x03", 9 },
#endif
#if defined(PSA_WANT_ALG_RIPEMD160)
{ MBEDTLS_MD_RIPEMD160, "\x2b\x24\x03\x02\x01", 5 },
#endif
{ MBEDTLS_MD_NONE, NULL, 0 }
};
/**
* @brief Get OID for hash algorithm (local implementation)
*
* @param md_alg Hash algorithm type
* @param oid Output pointer for OID string
* @param olen Output pointer for OID length
* @return 0 on success, PSA_ERROR_NOT_SUPPORTED if not found
*/
static int esp_ds_get_oid_by_md(mbedtls_md_type_t md_alg, const char **oid, size_t *olen)
{
for (size_t i = 0; oid_md_table[i].md_alg != MBEDTLS_MD_NONE; i++) {
if (oid_md_table[i].md_alg == md_alg) {
*oid = oid_md_table[i].oid;
*olen = oid_md_table[i].oid_len;
return 0;
}
}
return PSA_ERROR_NOT_SUPPORTED;
}
static int rsa_rsassa_pkcs1_v15_encode( mbedtls_md_type_t md_alg,
unsigned int hashlen,
const unsigned char *hash,
size_t dst_len,
unsigned char *dst )
{
size_t oid_size = 0;
size_t nb_pad = dst_len;
unsigned char *p = dst;
const char *oid = NULL;
/* Are we signing hashed or raw data? */
if ( md_alg != MBEDTLS_MD_NONE ) {
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( md_alg );
if ( md_info == NULL ) {
return ( PSA_ERROR_INVALID_ARGUMENT );
}
if ( esp_ds_get_oid_by_md( md_alg, &oid, &oid_size ) != 0 ) {
return ( PSA_ERROR_INVALID_ARGUMENT );
}
hashlen = mbedtls_md_get_size( md_info );
/* Double-check that 8 + hashlen + oid_size can be used as a
* 1-byte ASN.1 length encoding and that there's no overflow. */
if ( 8 + hashlen + oid_size >= 0x80 ||
10 + hashlen < hashlen ||
10 + hashlen + oid_size < 10 + hashlen ) {
return ( PSA_ERROR_INVALID_ARGUMENT );
}
/*
* Static bounds check:
* - Need 10 bytes for five tag-length pairs.
* (Insist on 1-byte length encodings to protect against variants of
* Bleichenbacher's forgery attack against lax PKCS#1v1.5 verification)
* - Need hashlen bytes for hash
* - Need oid_size bytes for hash alg OID.
*/
if ( nb_pad < 10 + hashlen + oid_size ) {
return ( PSA_ERROR_INVALID_ARGUMENT );
}
nb_pad -= 10 + hashlen + oid_size;
} else {
if ( nb_pad < hashlen ) {
return ( PSA_ERROR_INVALID_ARGUMENT );
}
nb_pad -= hashlen;
}
/* Need space for signature header and padding delimiter (3 bytes),
* and 8 bytes for the minimal padding */
if ( nb_pad < 3 + 8 ) {
return ( PSA_ERROR_INVALID_ARGUMENT );
}
nb_pad -= 3;
/* Now nb_pad is the amount of memory to be filled
* with padding, and at least 8 bytes long. */
/* Write signature header and padding */
*p++ = 0;
*p++ = 1; //MBEDTLS_RSA_SIGN;
memset( p, 0xFF, nb_pad );
p += nb_pad;
*p++ = 0;
/* Are we signing raw data? */
if ( md_alg == MBEDTLS_MD_NONE ) {
memcpy( p, hash, hashlen );
return ( 0 );
}
/* Signing hashed data, add corresponding ASN.1 structure
*
* DigestInfo ::= SEQUENCE {
* digestAlgorithm DigestAlgorithmIdentifier,
* digest Digest }
* DigestAlgorithmIdentifier ::= AlgorithmIdentifier
* Digest ::= OCTET STRING
*
* Schematic:
* TAG-SEQ + LEN [ TAG-SEQ + LEN [ TAG-OID + LEN [ OID ]
* TAG-NULL + LEN [ NULL ] ]
* TAG-OCTET + LEN [ HASH ] ]
*/
*p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED;
*p++ = (unsigned char)( 0x08 + oid_size + hashlen );
*p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED;
*p++ = (unsigned char)( 0x04 + oid_size );
*p++ = MBEDTLS_ASN1_OID;
*p++ = (unsigned char) oid_size;
memcpy( p, oid, oid_size );
p += oid_size;
*p++ = MBEDTLS_ASN1_NULL;
*p++ = 0x00;
*p++ = MBEDTLS_ASN1_OCTET_STRING;
*p++ = (unsigned char) hashlen;
memcpy( p, hash, hashlen );
p += hashlen;
/* Just a sanity-check, should be automatic
* after the initial bounds check. */
if ( p != dst + dst_len ) {
mbedtls_platform_zeroize( dst, dst_len );
return ( PSA_ERROR_INVALID_ARGUMENT );
}
return ( 0 );
}
#ifdef CONFIG_MBEDTLS_SSL_PROTO_TLS1_3
static int rsa_rsassa_pss_pkcs1_v21_encode( int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
mbedtls_md_type_t md_alg,
unsigned int hashlen,
const unsigned char *hash,
int saltlen,
unsigned char *sig, size_t dst_len)
{
size_t olen;
unsigned char *p = sig;
unsigned char *salt = NULL;
size_t slen, min_slen, hlen, offset = 0;
int ret = PSA_ERROR_INVALID_ARGUMENT;
size_t msb;
if ((md_alg != MBEDTLS_MD_NONE || hashlen != 0) && hash == NULL) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if (f_rng == NULL) {
return PSA_ERROR_INVALID_ARGUMENT;
}
olen = dst_len;
if (md_alg != MBEDTLS_MD_NONE) {
/* Gather length of hash to sign */
size_t exp_hashlen = mbedtls_md_get_size_from_type(md_alg);
if (exp_hashlen == 0) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if (hashlen != exp_hashlen) {
return PSA_ERROR_INVALID_ARGUMENT;
}
}
hlen = mbedtls_md_get_size_from_type(md_alg);
if (hlen == 0) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if (saltlen == -1) {
/* Calculate the largest possible salt length, up to the hash size.
* Normally this is the hash length, which is the maximum salt length
* according to FIPS 185-4 5.5 (e) and common practice. If there is not
* enough room, use the maximum salt length that fits. The constraint is
* that the hash length plus the salt length plus 2 bytes must be at most
* the key length. This complies with FIPS 186-4 5.5 (e) and RFC 8017
* (PKCS#1 v2.2) 9.1.1 step 3. */
min_slen = hlen - 2;
if (olen < hlen + min_slen + 2) {
return PSA_ERROR_INVALID_ARGUMENT;
} else if (olen >= hlen + hlen + 2) {
slen = hlen;
} else {
slen = olen - hlen - 2;
}
} else if ((saltlen < 0) || (saltlen + hlen + 2 > olen)) {
return PSA_ERROR_INVALID_ARGUMENT;
} else {
slen = (size_t) saltlen;
}
memset(sig, 0, olen);
/* Note: EMSA-PSS encoding is over the length of N - 1 bits */
msb = dst_len * 8 - 1;
p += olen - hlen - slen - 2;
*p++ = 0x01;
/* Generate salt of length slen in place in the encoded message */
salt = p;
if ((ret = f_rng(p_rng, salt, slen)) != 0) {
return PSA_ERROR_INVALID_ARGUMENT;
}
p += slen;
/* Generate H = Hash( M' ) */
ret = esp_ds_hash_mprime(hash, hashlen, salt, slen, p, md_alg);
if (ret != 0) {
return ret;
}
/* Compensate for boundary condition when applying mask */
if (msb % 8 == 0) {
offset = 1;
}
/* maskedDB: Apply dbMask to DB */
ret = esp_ds_mgf_mask(sig + offset, olen - hlen - 1 - offset, p, hlen, md_alg);
if (ret != 0) {
return ret;
}
msb = dst_len * 8 - 1;
sig[0] &= 0xFF >> (olen * 8 - msb);
p += hlen;
*p++ = 0xBC;
return ret;
}
static int rsa_rsassa_pkcs1_v21_encode(int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
mbedtls_md_type_t md_alg,
unsigned int hashlen,
const unsigned char *hash,
size_t dst_len,
unsigned char *dst )
{
return rsa_rsassa_pss_pkcs1_v21_encode(f_rng, p_rng, md_alg, hashlen, hash, -1, dst, dst_len);
}
#endif /* CONFIG_MBEDTLS_SSL_PROTO_TLS1_3 */
int esp_ds_rsa_sign( void *ctx,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
mbedtls_md_type_t md_alg, unsigned int hashlen,
const unsigned char *hash, unsigned char *sig )
{
mbedtls_pk_context *pk = (mbedtls_pk_context *)ctx;
size_t sig_len = 0;
return esp_ds_rsa_sign_alt(pk, md_alg, hash, hashlen, sig, 0, &sig_len);
}
int esp_ds_rsa_sign_alt(mbedtls_pk_context *pk, mbedtls_md_type_t md_alg,
const unsigned char *hash, size_t hash_len,
unsigned char *sig, size_t sig_size, size_t *sig_len)
{
esp_ds_context_t *esp_ds_ctx = NULL;
esp_err_t ds_r;
int ret = -1;
/* This check is done to keep the compatibility with the previous versions of the API
* which allows NULL ctx. If ctx is NULL, then the default padding
* MBEDTLS_RSA_PKCS_V15 is used.
*/
int padding = MBEDTLS_PK_RSA_PKCS_V15;
void *ctx = NULL;
if (pk != NULL) {
ctx = pk->MBEDTLS_PRIVATE(pk_ctx);
}
if (ctx != NULL) {
mbedtls_rsa_context *rsa_ctx = (mbedtls_rsa_context *)ctx;
padding = rsa_ctx->MBEDTLS_PRIVATE(padding);
}
esp_ds_data_t *s_ds_data = esp_ds_get_data_ctx();
if (s_ds_data == NULL) {
ESP_LOGE(TAG, "Digital signature data context is NULL");
return -1;
}
const size_t data_len = s_ds_data->rsa_length + 1;
const size_t _sig_len = data_len * FACTOR_KEYLEN_IN_BYTES;
if (padding == MBEDTLS_PK_RSA_PKCS_V21) {
#ifdef CONFIG_MBEDTLS_SSL_PROTO_TLS1_3
if ((ret = (rsa_rsassa_pkcs1_v21_encode(mbedtls_psa_get_random, MBEDTLS_PSA_RANDOM_STATE ,md_alg, hash_len, hash, _sig_len, sig ))) != 0) {
ESP_LOGE(TAG, "Error in pkcs1_v21 encoding, returned %d", ret);
return -1;
}
#else /* CONFIG_MBEDTLS_SSL_PROTO_TLS1_3 */
ESP_LOGE(TAG, "RSA PKCS#1 v2.1 padding is not supported. Please enable CONFIG_MBEDTLS_SSL_PROTO_TLS1_3");
return -1;
#endif /* CONFIG_MBEDTLS_SSL_PROTO_TLS1_3 */
} else {
if ((ret = (rsa_rsassa_pkcs1_v15_encode(md_alg, hash_len, hash, _sig_len, sig ))) != 0) {
ESP_LOGE(TAG, "Error in pkcs1_v15 encoding, returned %d", ret);
return -1;
}
}
uint32_t *signature = heap_caps_malloc_prefer(_sig_len, 2, MALLOC_CAP_32BIT | MALLOC_CAP_INTERNAL, MALLOC_CAP_DEFAULT | MALLOC_CAP_INTERNAL);
if (signature == NULL) {
ESP_LOGE(TAG, "Could not allocate memory for internal DS operations");
return -1;
}
for (unsigned int i = 0; i < (data_len); i++) {
signature[i] = SWAP_INT32(((uint32_t *)sig)[(data_len) - (i + 1)]);
}
hmac_key_id_t s_esp_ds_hmac_key_id = esp_ds_get_hmac_key_id();
ds_r = esp_ds_start_sign((const void *)signature,
s_ds_data,
s_esp_ds_hmac_key_id,
&esp_ds_ctx);
if (ds_r != ESP_OK) {
ESP_LOGE(TAG, "Error in esp_ds_start_sign, returned %d ", ds_r);
heap_caps_free(signature);
return -1;
}
ds_r = esp_ds_finish_sign((void *)signature, esp_ds_ctx);
if (ds_r != ESP_OK) {
if (ds_r == ESP_ERR_HW_CRYPTO_DS_INVALID_DIGEST) {
ESP_LOGE(TAG, "Invalid digest in DS data reported by esp_ds_finish_sign");
} else {
ESP_LOGE(TAG, "Error in esp_ds_finish_sign, returned %d ", ds_r);
}
heap_caps_free(signature);
return -1;
}
for (unsigned int i = 0; i < (data_len); i++) {
((uint32_t *)sig)[i] = SWAP_INT32(((uint32_t *)signature)[(data_len) - (i + 1)]);
}
heap_caps_free(signature);
*sig_len = _sig_len;
return 0;
}
@@ -1,140 +0,0 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "esp_ds.h"
#include "mbedtls/md.h"
#include "mbedtls/pk.h"
/**
* @brief ESP-DS data context
*
* @note This structure includes encrypted private key parameters such as ciphertext_c, initialization vector, efuse_key_id, RSA key length, which are obtained when DS peripheral is configured.
*/
/* Context for encrypted private key data required for DS */
typedef struct esp_ds_data_ctx {
esp_ds_data_t *esp_ds_data;
uint8_t efuse_key_id; /* efuse block id in which DS_KEY is stored e.g. 0,1*/
uint16_t rsa_length_bits; /* length of RSA private key in bits e.g. 2048 */
} esp_ds_data_ctx_t;
/**
* @brief Initializes internal DS data context
*
* This function allocates and initializes internal ds data context which is used for Digital Signature operation.
*
* @in ds_data ds_data context containing encrypted private key parameters
* @return
* - ESP_OK In case of success
* - ESP_ERR_NO_MEM In case internal context could not be allocated.
* - ESP_ERR_INVALID_ARG in case input parametrers are NULL
*
*/
esp_err_t esp_ds_init_data_ctx(esp_ds_data_ctx_t *ds_data);
/**
* @brief Deinitializes internal DS data context
*
* This function deinitializes internal ds data context which is used for Digital Signature operation.
*
* @return esp_err_t
* - ESP_OK In case of success
* - ESP_ERR_INVALID_STATE In case internal context is not initialized
*/
esp_err_t esp_ds_deinit_data_ctx(void);
/**
*
* @brief Release the ds lock acquired for the DS operation (then the DS peripheral can be used for other TLS connection)
*
*/
void esp_ds_release_ds_lock(void);
/**
*
* @brief Alternate implementation for mbedtls_rsa_rsassa_pkcs1_v15_sign, Internally makes use
* of DS module to perform hardware accelerated RSA sign operation
*/
int esp_ds_rsa_sign( void *ctx,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
mbedtls_md_type_t md_alg, unsigned int hashlen,
const unsigned char *hash, unsigned char *sig );
/**
* @brief Alternate implementation for mbedtls_pk_sign, uses DS module for hardware accelerated RSA sign operation
*
* This function is an alternate implementation compatible with mbedtls_pk_sign interface.
* It internally makes use of the DS (Digital Signature) peripheral to perform hardware
* accelerated RSA signature operations.
*
* @param pk Pointer to the mbedtls_pk_context structure containing the public key context
* @param md_alg Message digest algorithm type used for hashing (e.g., MBEDTLS_MD_SHA256)
* @param hash Pointer to the hash value to be signed
* @param hash_len Length of the hash value in bytes
* @param sig Buffer to hold the generated signature
* @param sig_size Maximum size of the signature buffer in bytes
* @param sig_len Pointer to store the actual length of the generated signature in bytes
*
* @return
* - 0 on success
* - MBEDTLS_ERR_PK_BAD_INPUT_DATA if input parameters are invalid
* - MBEDTLS_ERR_PK_ALLOC_FAILED if memory allocation fails
* - Other mbedtls error codes on failure
*/
int esp_ds_rsa_sign_alt(mbedtls_pk_context *pk, mbedtls_md_type_t md_alg,
const unsigned char *hash, size_t hash_len,
unsigned char *sig, size_t sig_size, size_t *sig_len);
/*
* @brief Get RSA key length in bytes from internal DS context
*
* @return RSA key length in bytes
*/
size_t esp_ds_get_keylen(void *ctx);
/**
* @brief Get RSA key length in bytes from mbedtls_pk_context
*
* This function retrieves the RSA key length from an mbedtls_pk_context structure.
* It is an alternate implementation compatible with mbedtls PK interface.
*
* @param ctx Pointer to the mbedtls_pk_context structure
*
* @return RSA key length in bytes, or 0 if the context is invalid
*/
size_t esp_ds_get_keylen_alt(mbedtls_pk_context *ctx);
/*
* @brief Set timeout (equal to TLS session timeout), so that DS module usage can be synchronized in case of multiple TLS connections using DS module,
*/
void esp_ds_set_session_timeout(int timeout);
/**
* @brief Alternate implementation for mbedtls_rsa_decrypt, Internally makes use
* of DS module to perform hardware accelerated RSA decrypt operation
*
* @param ctx Context for the RSA operation. It should be a pointer to an mbedtls_rsa_context structure.
* The RSA context should have the correct padding type set (either MBEDTLS_RSA_PKCS_V15 or MBEDTLS_RSA_PKCS_V21).
* If ctx is NULL, the default padding type (MBEDTLS_RSA_PKCS_V15) will be used.
* @param olen Pointer to the output length variable, which will be set to the length of the decrypted data.
* @param input The input data to be decrypted. It should be a pointer to an array of unsigned char.
* @param output The buffer to hold the decrypted output. It should be a pointer to an array of unsigned char.
* @param output_max_len The maximum length of the output buffer. It should be greater than or equal to the expected length of the decrypted data.
* @return int
* - 0 on success
* - -1 on failure
*/
int esp_ds_rsa_decrypt(void *ctx, size_t *olen,
const unsigned char *input, unsigned char *output,
size_t output_max_len);
#ifdef __cplusplus
}
#endif
@@ -1,78 +0,0 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifndef _ESP_RSA_SIGN_ALT_H_
#define _ESP_RSA_SIGN_ALT_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "esp_ds.h"
#include "mbedtls/md.h"
/**
* @brief ESP-DS data context
*
* @note This structure includes encrypted private key parameters such as ciphertext_c, initialization vector, efuse_key_id, RSA key length, which are obtained when DS peripheral is configured.
*/
/* Context for encrypted private key data required for DS */
typedef struct esp_ds_data_ctx {
esp_ds_data_t *esp_ds_data;
uint8_t efuse_key_id; /* efuse block id in which DS_KEY is stored e.g. 0,1*/
uint16_t rsa_length_bits; /* length of RSA private key in bits e.g. 2048 */
} esp_ds_data_ctx_t;
/**
* @brief Initializes internal DS data context
*
* This function allocates and initializes internal ds data context which is used for Digital Signature operation.
*
* @in ds_data ds_data context containing encrypted private key parameters
* @return
* - ESP_OK In case of success
* - ESP_ERR_NO_MEM In case internal context could not be allocated.
* - ESP_ERR_INVALID_ARG in case input parametrers are NULL
*
*/
esp_err_t esp_ds_init_data_ctx(esp_ds_data_ctx_t *ds_data);
/**
*
* @brief Release the ds lock acquired for the DS operation (then the DS peripheral can be used for other TLS connection)
*
*/
void esp_ds_release_ds_lock(void);
/**
*
* @brief Alternate implementation for mbedtls_rsa_rsassa_pkcs1_v15_sign, Internally makes use
* of DS module to perform hardware accelerated RSA sign operation
*/
int esp_ds_rsa_sign(void *ctx,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
mbedtls_md_type_t md_alg, unsigned int hashlen,
const unsigned char *hash, unsigned char *sig);
/*
* @brief Get RSA key length in bytes from internal DS context
*
* @return RSA key length in bytes
*/
size_t esp_ds_get_keylen(void *ctx);
/*
* @brief Set timeout (equal to TLS session timeout), so that DS module usage can be synchronized in case of multiple TLS connections using DS module,
*/
void esp_ds_set_session_timeout(int timeout);
#ifdef __cplusplus
}
#endif
#endif /* _ESP_RSA_SIGN_ALT_H_ */
@@ -1743,6 +1743,13 @@
#undef PSA_WANT_KEY_TYPE_AES
#endif
/* PSA Crypto RSA DS Driver */
#ifdef CONFIG_MBEDTLS_HARDWARE_RSA_DS_PERIPHERAL
#define ESP_RSA_DS_DRIVER_ENABLED
#else
#undef ESP_RSA_DS_DRIVER_ENABLED
#endif
/* The following units have ESP32 hardware support,
uncommenting each _ALT macro will use the
hardware-accelerated implementation. */
@@ -1,21 +0,0 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cpluscplus
extern "C" {
#endif
#include "sdkconfig.h"
#if defined(CONFIG_SOC_DIG_SIGN_SUPPORTED)
#include "esp_ds/esp_ds_rsa.h"
#endif
#ifdef __cpluscplus
}
#endif
@@ -1,21 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cpluscplus
extern "C" {
#endif
#include "sdkconfig.h"
#if defined(CONFIG_SOC_DIG_SIGN_SUPPORTED)
#include "esp_ds/esp_ds_rsa.h"
#endif
#ifdef __cpluscplus
}
#endif
@@ -0,0 +1,98 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "psa/crypto.h"
#define FACTOR_KEYLEN_IN_BYTES 4
#define SWAP_INT32(x) (((x) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | ((x) << 24))
#define MIN_V15_PADDING_LEN 11
/**
* @brief Encodes the hash using PKCS#1 v1.5 padding scheme
*
* @param alg Algorithm identifier
* @param hashlen Length of the hash
* @param hash Pointer to the hash data
* @param dst_len Length of the destination buffer
* @param dst Pointer to the destination buffer
* @return psa_status_t
* PSA_ERROR_INVALID_ARGUMENT if arguments are invalid
* PSA_SUCCESS on success
*/
psa_status_t esp_rsa_ds_pad_v15_encode(psa_algorithm_t alg, unsigned int hashlen,
const unsigned char *hash,
size_t dst_len,
unsigned char *dst);
/**
* @brief Unpads the input data using PKCS#1 v1.5 padding scheme
*
* @param input Pointer to the input data
* @param ilen Length of the input data
* @param output Pointer to the output buffer
* @param output_max_len Maximum length of the output buffer
* @param olen Pointer to the length of the output data
* @return psa_status_t
* PSA_ERROR_INVALID_ARGUMENT if arguments are invalid
* PSA_SUCCESS on success
*/
psa_status_t esp_rsa_ds_pad_v15_unpad(unsigned char *input,
size_t ilen,
unsigned char *output,
size_t output_max_len,
size_t *olen);
#if CONFIG_MBEDTLS_SSL_PROTO_TLS1_3
/**
* @brief Encodes the hash using PKCS#1 v2.2 (PSS) padding scheme
*
* @param hash_alg Hash algorithm identifier
* @param hashlen Length of the hash
* @param hash Pointer to the hash data
* @param saltlen Length of the salt
* @param sig Pointer to the signature buffer
* @param dst_len Length of the destination buffer
* @return psa_status_t
* PSA_ERROR_INVALID_ARGUMENT if arguments are invalid
* PSA_SUCCESS on success
*/
psa_status_t esp_rsa_ds_pad_v21_encode(psa_algorithm_t hash_alg,
unsigned int hashlen,
const unsigned char *hash,
int saltlen,
unsigned char *sig,
size_t dst_len);
/**
* @brief Unpads the input data using PKCS#1 v2.2 (OAEP) padding scheme
*
* @param input Pointer to the input data
* @param ilen Length of the input data
* @param output Pointer to the output buffer
* @param output_max_len Maximum length of the output buffer
* @param olen Pointer to the length of the output data
* @param hash_alg Hash algorithm identifier
* @return psa_status_t
* PSA_ERROR_INVALID_ARGUMENT if arguments are invalid
* PSA_SUCCESS on success
*/
psa_status_t esp_rsa_ds_pad_oaep_unpad(unsigned char *input,
size_t ilen,
unsigned char *output,
size_t output_max_len,
size_t *olen,
psa_algorithm_t hash_alg);
#endif /* CONFIG_MBEDTLS_SSL_PROTO_TLS1_3 */
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,476 @@
/*
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "psa_crypto_driver_esp_rsa_ds.h"
#include "psa_crypto_driver_esp_rsa_ds_contexts.h"
#include "include/psa_crypto_driver_esp_rsa_ds_utilities.h"
#include "esp_log.h"
#include "esp_efuse.h"
#include "soc/soc_caps.h"
#define ESP_RSA_DS_TIMEOUT_BUFFER_MS 1000
static const char *TAG = "PSA_RSA_DS";
static SemaphoreHandle_t s_ds_lock = NULL;
static int s_timeout_ms = 0;
void esp_rsa_ds_release_ds_lock(void);
static int esp_rsa_ds_pad(esp_rsa_ds_padding_t padding, psa_algorithm_t hash_alg, unsigned int hashlen,
const unsigned char *hash,
int saltlen,
unsigned char *sig, size_t dst_len)
{
if (padding == ESP_RSA_DS_PADDING_PKCS_V15) {
(void)saltlen;
return esp_rsa_ds_pad_v15_encode(hash_alg, hashlen, hash, dst_len, sig);
}
#if CONFIG_MBEDTLS_SSL_PROTO_TLS1_3
else if (padding == ESP_RSA_DS_PADDING_PSS) {
return esp_rsa_ds_pad_v21_encode(hash_alg, hashlen, hash, saltlen, sig, dst_len);
}
#endif /* CONFIG_MBEDTLS_SSL_PROTO_TLS1_3 */
else {
return PSA_ERROR_NOT_SUPPORTED;
}
}
/* Lock for the DS session, other TLS connections trying to use the DS peripheral will be blocked
* till this DS session is completed (i.e. TLS handshake for this connection is completed) */
static void __attribute__((constructor)) esp_rsa_ds_conn_lock(void)
{
if ((s_ds_lock = xSemaphoreCreateMutex()) == NULL) {
ESP_EARLY_LOGE(TAG, "Failed to create DS lock");
}
}
void esp_rsa_ds_release_ds_lock(void)
{
if (s_ds_lock == NULL) {
return;
}
if (xSemaphoreGetMutexHolder(s_ds_lock) == xTaskGetCurrentTaskHandle()) {
/* Give back the semaphore (DS lock) */
xSemaphoreGive(s_ds_lock);
}
}
static int esp_rsa_ds_validate_opaque_key(const esp_ds_data_ctx_t *opaque_key)
{
if (opaque_key == NULL) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if (opaque_key->esp_rsa_ds_data == NULL) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if (EFUSE_BLK_KEY0 + opaque_key->efuse_key_id >= EFUSE_BLK_KEY_MAX) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if (opaque_key->rsa_length_bits % 32 != 0) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if (opaque_key->rsa_length_bits < 1024 || opaque_key->rsa_length_bits > SOC_DS_SIGNATURE_MAX_BIT_LEN) {
return PSA_ERROR_INVALID_ARGUMENT;
}
/* DS data rsa_length must match rsa_length_bits so we can use the key's data directly in sign operations */
if (opaque_key->esp_rsa_ds_data->rsa_length != (opaque_key->rsa_length_bits / 32) - 1) {
return PSA_ERROR_INVALID_ARGUMENT;
}
esp_efuse_purpose_t purpose = esp_efuse_get_key_purpose(EFUSE_BLK_KEY0 + opaque_key->efuse_key_id);
if (purpose != ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_DIGITAL_SIGNATURE) {
return PSA_ERROR_NOT_PERMITTED;
}
return PSA_SUCCESS;
}
psa_status_t esp_rsa_ds_opaque_sign_hash_start(
esp_rsa_ds_opaque_sign_hash_operation_t *operation,
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
psa_algorithm_t alg,
const uint8_t *hash,
size_t hash_length)
{
if (!attributes || !key_buffer || !hash || !operation) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if (key_buffer_size < sizeof(esp_ds_data_ctx_t)) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if (!PSA_ALG_IS_RSA_PKCS1V15_SIGN(alg) && !PSA_ALG_IS_RSA_PSS(alg)) {
return PSA_ERROR_NOT_SUPPORTED;
}
operation->alg = alg;
const esp_ds_data_ctx_t *opaque_key = (const esp_ds_data_ctx_t *)key_buffer;
operation->esp_rsa_ds_opaque_key = opaque_key;
if (esp_rsa_ds_validate_opaque_key(opaque_key) != PSA_SUCCESS) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if ((xSemaphoreTake(s_ds_lock, s_timeout_ms / portTICK_PERIOD_MS) != pdTRUE)) {
return PSA_ERROR_GENERIC_ERROR;
}
esp_rsa_ds_padding_t padding = ESP_RSA_DS_PADDING_INVALID;
if (PSA_ALG_IS_RSA_PSS(operation->alg)) {
padding = ESP_RSA_DS_PADDING_PSS;
} else if (PSA_ALG_IS_RSA_PKCS1V15_SIGN(operation->alg)) {
padding = ESP_RSA_DS_PADDING_PKCS_V15;
}
psa_algorithm_t hash_alg = PSA_ALG_SIGN_GET_HASH(operation->alg);
const size_t words_len = (opaque_key->rsa_length_bits / 32);
const size_t rsa_len_bytes = words_len * 4;
operation->sig_buffer_size = rsa_len_bytes;
operation->sig_buffer = NULL;
unsigned char *em = heap_caps_malloc_prefer(rsa_len_bytes, 1, MALLOC_CAP_32BIT | MALLOC_CAP_INTERNAL, MALLOC_CAP_DEFAULT | MALLOC_CAP_INTERNAL);
if (em == NULL) {
esp_rsa_ds_release_ds_lock();
return PSA_ERROR_INSUFFICIENT_MEMORY;
}
psa_status_t status = esp_rsa_ds_pad(
padding, hash_alg, hash_length, hash, -1, em, rsa_len_bytes);
if (status != PSA_SUCCESS) {
goto error;
}
operation->sig_buffer = heap_caps_malloc_prefer(rsa_len_bytes, 2, MALLOC_CAP_32BIT | MALLOC_CAP_INTERNAL, MALLOC_CAP_DEFAULT | MALLOC_CAP_INTERNAL);
if (operation->sig_buffer == NULL) {
status = PSA_ERROR_INSUFFICIENT_MEMORY;
goto error;
}
uint32_t *sig_words = (uint32_t *)operation->sig_buffer;
const uint32_t *em_words = (const uint32_t *)em;
for (unsigned int i = 0; i < words_len; i++) {
sig_words[i] = SWAP_INT32(em_words[words_len - (i + 1)]);
}
esp_err_t err = esp_ds_start_sign((const void *)operation->sig_buffer,
opaque_key->esp_rsa_ds_data,
(hmac_key_id_t) opaque_key->efuse_key_id,
&operation->esp_rsa_ds_ctx);
if (err != ESP_OK) {
status = PSA_ERROR_GENERIC_ERROR;
goto error;
}
error:
if (em) {
heap_caps_free(em);
em = NULL;
}
if (status != PSA_SUCCESS) {
if (operation->sig_buffer) {
heap_caps_free(operation->sig_buffer);
operation->sig_buffer = NULL;
}
esp_rsa_ds_release_ds_lock();
}
return status;
}
psa_status_t esp_rsa_ds_opaque_sign_hash_complete(
esp_rsa_ds_opaque_sign_hash_operation_t *operation,
uint8_t *signature, size_t signature_size,
size_t *signature_length)
{
if (!signature || !signature_length || !operation) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if ((operation->esp_rsa_ds_ctx == NULL) || (operation->sig_buffer == NULL)) {
return PSA_ERROR_BAD_STATE;
}
int expected_signature_size = operation->esp_rsa_ds_opaque_key->rsa_length_bits / 8;
if (signature_size < expected_signature_size) {
return PSA_ERROR_BUFFER_TOO_SMALL;
}
esp_err_t err = esp_ds_finish_sign((void *)operation->sig_buffer, operation->esp_rsa_ds_ctx);
if (err != ESP_OK) {
memset(operation->sig_buffer, 0, operation->sig_buffer_size);
heap_caps_free(operation->sig_buffer);
esp_rsa_ds_release_ds_lock();
return PSA_ERROR_GENERIC_ERROR;
}
unsigned int words_len = expected_signature_size / 4;
uint32_t *out_words = (uint32_t *)signature;
const uint32_t *ds_words = (const uint32_t *)operation->sig_buffer;
for (unsigned int i = 0; i < words_len; i++) {
out_words[i] = SWAP_INT32(ds_words[words_len - (i + 1)]);
}
*signature_length = expected_signature_size;
memset(operation->sig_buffer, 0, operation->sig_buffer_size);
heap_caps_free(operation->sig_buffer);
operation->sig_buffer = NULL;
esp_rsa_ds_release_ds_lock();
return PSA_SUCCESS;
}
psa_status_t esp_rsa_ds_opaque_sign_hash_abort(
esp_rsa_ds_opaque_sign_hash_operation_t *operation)
{
if (!operation) {
return PSA_ERROR_INVALID_ARGUMENT;
}
// Free allocated memory if exists
if (operation->sig_buffer) {
memset(operation->sig_buffer, 0, operation->sig_buffer_size);
heap_caps_free(operation->sig_buffer);
operation->sig_buffer = NULL;
}
// Release the DS lock if held
esp_rsa_ds_release_ds_lock();
// Clear the operation structure
memset(operation, 0, sizeof(esp_rsa_ds_opaque_sign_hash_operation_t));
return PSA_SUCCESS;
}
psa_status_t esp_rsa_ds_opaque_signature_sign_hash(
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
psa_algorithm_t alg,
const uint8_t *hash,
size_t hash_length,
uint8_t *signature,
size_t signature_size,
size_t *signature_length
)
{
esp_rsa_ds_opaque_sign_hash_operation_t operation = {0};
psa_status_t status = esp_rsa_ds_opaque_sign_hash_start(
&operation,
attributes,
key_buffer,
key_buffer_size,
alg,
hash,
hash_length
);
if (status != PSA_SUCCESS) {
esp_rsa_ds_opaque_sign_hash_abort(&operation);
return status;
}
status = esp_rsa_ds_opaque_sign_hash_complete(
&operation,
signature,
signature_size,
signature_length
);
esp_rsa_ds_opaque_sign_hash_abort(&operation);
return status;
}
psa_status_t esp_rsa_ds_opaque_import_key(
const psa_key_attributes_t *attributes,
const uint8_t *data,
size_t data_length,
uint8_t *key_buffer,
size_t key_buffer_size,
size_t *key_buffer_length,
size_t *bits)
{
if (!attributes || !data || data_length < 1 || !key_buffer || !key_buffer_length || !bits) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if (key_buffer_size < sizeof(esp_ds_data_ctx_t)) {
return PSA_ERROR_BUFFER_TOO_SMALL;
}
const esp_ds_data_ctx_t *opaque_key = (const esp_ds_data_ctx_t *)data;
int ret = esp_rsa_ds_validate_opaque_key(opaque_key);
if (ret != PSA_SUCCESS) {
return ret;
}
/* Shallow copy: key buffer holds the context; esp_rsa_ds_data points to the caller's data.
* The key material (esp_ds_data_ctx_t and the esp_ds_data_t it points to) must remain
* valid until psa_destroy_key() is called on this key. */
memcpy(key_buffer, opaque_key, sizeof(esp_ds_data_ctx_t));
*key_buffer_length = sizeof(esp_ds_data_ctx_t);
*bits = opaque_key->rsa_length_bits;
return PSA_SUCCESS;
}
size_t esp_rsa_ds_opaque_size_function(
psa_key_type_t key_type,
size_t key_bits)
{
(void)key_type;
(void)key_bits;
return sizeof(esp_ds_data_ctx_t);
}
void esp_rsa_ds_opaque_set_session_timeout(int timeout_ms)
{
/* add additional offset of ESP_RSA_DS_TIMEOUT_BUFFER_MS ms to have enough time for deleting the TLS connection
* and free the previous ds context after exceeding timeout value
* (this offset also helps when timeout is set to 0)
*/
if (timeout_ms < 0) {
return;
}
if (timeout_ms > s_timeout_ms) {
s_timeout_ms = timeout_ms + ESP_RSA_DS_TIMEOUT_BUFFER_MS;
}
}
psa_status_t esp_rsa_ds_opaque_asymmetric_decrypt(
const psa_key_attributes_t *attributes, const uint8_t *key,
size_t key_length, psa_algorithm_t alg, const uint8_t *input,
size_t input_length, const uint8_t *salt, size_t salt_length,
uint8_t *output, size_t output_size, size_t *output_length)
{
(void)salt;
(void)salt_length;
if (!attributes || !key || key_length < sizeof(esp_ds_data_ctx_t) ||
!input || input_length < 1 || !output || !output_length) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if (!PSA_ALG_IS_RSA_OAEP(alg) && alg != PSA_ALG_RSA_PKCS1V15_CRYPT) {
return PSA_ERROR_NOT_SUPPORTED;
}
const esp_ds_data_ctx_t *opaque_key = (const esp_ds_data_ctx_t *)key;
if (esp_rsa_ds_validate_opaque_key(opaque_key) != PSA_SUCCESS) {
return PSA_ERROR_INVALID_ARGUMENT;
}
size_t key_bits = opaque_key->rsa_length_bits;
if (input_length != (key_bits / 8)) {
return PSA_ERROR_INVALID_ARGUMENT;
}
esp_rsa_ds_padding_t padding = ESP_RSA_DS_PADDING_INVALID;
if (PSA_ALG_IS_RSA_OAEP(alg)) {
padding = ESP_RSA_DS_PADDING_OAEP;
} else if (alg == PSA_ALG_RSA_PKCS1V15_CRYPT) {
padding = ESP_RSA_DS_PADDING_PKCS_V15;
}
if (xSemaphoreTake(s_ds_lock, s_timeout_ms / portTICK_PERIOD_MS) != pdTRUE) {
return PSA_ERROR_GENERIC_ERROR;
}
size_t ilen = key_bits / 8;
size_t data_len = ilen / 4;
uint32_t *em_words = heap_caps_malloc_prefer(sizeof(uint32_t) * data_len, 1, MALLOC_CAP_32BIT | MALLOC_CAP_INTERNAL, MALLOC_CAP_DEFAULT | MALLOC_CAP_INTERNAL);
if (em_words == NULL) {
esp_rsa_ds_release_ds_lock();
return PSA_ERROR_INSUFFICIENT_MEMORY;
}
for (unsigned int i = 0; i < (data_len); i++) {
em_words[i] = SWAP_INT32(((uint32_t *)input)[(data_len) - (i + 1)]);
}
esp_rsa_ds_opaque_sign_hash_operation_t operation = {0};
operation.alg = alg;
operation.esp_rsa_ds_opaque_key = opaque_key;
operation.sig_buffer = em_words;
esp_err_t err = esp_ds_start_sign((const void *)em_words,
opaque_key->esp_rsa_ds_data,
(hmac_key_id_t) opaque_key->efuse_key_id,
&operation.esp_rsa_ds_ctx);
if (err != ESP_OK) {
heap_caps_free(em_words);
esp_rsa_ds_release_ds_lock();
return PSA_ERROR_GENERIC_ERROR;
}
err = esp_ds_finish_sign((void *)em_words, operation.esp_rsa_ds_ctx);
if (err != ESP_OK) {
heap_caps_free(em_words);
esp_rsa_ds_release_ds_lock();
return PSA_ERROR_GENERIC_ERROR;
}
esp_rsa_ds_release_ds_lock();
// Remove padding
uint32_t *out_tmp = heap_caps_malloc_prefer(sizeof(uint32_t) * data_len, 1, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL, MALLOC_CAP_DEFAULT | MALLOC_CAP_INTERNAL);
if (out_tmp == NULL) {
heap_caps_free(em_words);
return PSA_ERROR_INSUFFICIENT_MEMORY;
}
for (unsigned int i = 0; i < (data_len); i++) {
((uint32_t *)out_tmp)[i] = SWAP_INT32(em_words[(data_len) - (i + 1)]);
}
size_t unpadded_len = 0;
psa_status_t ret = PSA_ERROR_NOT_SUPPORTED;
if (padding == ESP_RSA_DS_PADDING_PKCS_V15) {
ret = esp_rsa_ds_pad_v15_unpad((unsigned char *)out_tmp, ilen, (unsigned char *)out_tmp, ilen, &unpadded_len);
}
#if CONFIG_MBEDTLS_SSL_PROTO_TLS1_3
else if (padding == ESP_RSA_DS_PADDING_OAEP) {
ret = esp_rsa_ds_pad_oaep_unpad((unsigned char *)out_tmp, ilen, (unsigned char *)out_tmp, ilen, &unpadded_len, PSA_ALG_RSA_OAEP_GET_HASH(alg));
}
#endif /* CONFIG_MBEDTLS_SSL_PROTO_TLS1_3 */
else {
ret = PSA_ERROR_NOT_SUPPORTED;
goto exit;
}
if (ret != PSA_SUCCESS) {
ret = PSA_ERROR_INVALID_PADDING;
goto exit;
}
if (output_size < unpadded_len) {
ret = PSA_ERROR_BUFFER_TOO_SMALL;
goto exit;
}
memcpy(output, out_tmp, unpadded_len);
*output_length = unpadded_len;
ret = PSA_SUCCESS;
exit:
memset(em_words, 0, sizeof(uint32_t) * data_len);
memset(out_tmp, 0, sizeof(uint32_t) * data_len);
heap_caps_free(em_words);
heap_caps_free(out_tmp);
return ret;
}
@@ -0,0 +1,497 @@
/*
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "include/psa_crypto_driver_esp_rsa_ds_utilities.h"
#include "mbedtls/asn1.h"
#include "mbedtls/psa_util.h"
#include "esp_log.h"
typedef struct {
psa_algorithm_t md_alg;
const char *oid;
size_t oid_len;
} oid_md_mapping_t;
static const oid_md_mapping_t oid_md_table[] = {
#if defined(PSA_WANT_ALG_MD5)
{ PSA_ALG_MD5, "\x2a\x86\x48\x86\xf7\x0d\x02\x05", 8 },
#endif
#if defined(PSA_WANT_ALG_SHA_1)
{ PSA_ALG_SHA_1, "\x2b\x0e\x03\x02\x1a", 5 },
#endif
#if defined(PSA_WANT_ALG_SHA_224)
{ PSA_ALG_SHA_224, "\x60\x86\x48\x01\x65\x03\x04\x02\x04", 9 },
#endif
#if defined(PSA_WANT_ALG_SHA_256)
{ PSA_ALG_SHA_256, "\x60\x86\x48\x01\x65\x03\x04\x02\x01", 9 },
#endif
#if defined(PSA_WANT_ALG_SHA_384)
{ PSA_ALG_SHA_384, "\x60\x86\x48\x01\x65\x03\x04\x02\x02", 9 },
#endif
#if defined(PSA_WANT_ALG_SHA_512)
{ PSA_ALG_SHA_512, "\x60\x86\x48\x01\x65\x03\x04\x02\x03", 9 },
#endif
#if defined(PSA_WANT_ALG_RIPEMD160)
{ PSA_ALG_RIPEMD160, "\x2b\x24\x03\x02\x01", 5 },
#endif
{ PSA_ALG_NONE, NULL, 0 }
};
static int esp_rsa_ds_get_oid_by_psa_alg(psa_algorithm_t md_alg, const char **oid, size_t *olen)
{
for (size_t i = 0; oid_md_table[i].md_alg != PSA_ALG_NONE; i++) {
if (oid_md_table[i].md_alg == md_alg) {
*oid = oid_md_table[i].oid;
*olen = oid_md_table[i].oid_len;
return 0;
}
}
return PSA_ERROR_NOT_SUPPORTED;
}
psa_status_t esp_rsa_ds_pad_v15_encode(psa_algorithm_t alg, unsigned int hashlen,
const unsigned char *hash,
size_t dst_len,
unsigned char *dst)
{
size_t oid_size = 0;
size_t nb_pad = dst_len;
unsigned char *p = dst;
const char *oid = NULL;
/* Are we signing hashed or raw data? */
if (alg != PSA_ALG_NONE) {
if (esp_rsa_ds_get_oid_by_psa_alg(alg, &oid, &oid_size) != PSA_SUCCESS) {
return PSA_ERROR_INVALID_ARGUMENT;
}
hashlen = PSA_HASH_LENGTH(alg);
/* Double-check that 8 + hashlen + oid_size can be used as a
* 1-byte ASN.1 length encoding and that there's no overflow. */
if ( 8 + hashlen + oid_size >= 0x80 ||
10 + hashlen < hashlen ||
10 + hashlen + oid_size < 10 + hashlen ) {
return ( PSA_ERROR_INVALID_ARGUMENT );
}
/*
* Static bounds check:
* - Need 10 bytes for five tag-length pairs.
* (Insist on 1-byte length encodings to protect against variants of
* Bleichenbacher's forgery attack against lax PKCS#1v1.5 verification)
* - Need hashlen bytes for hash
* - Need oid_size bytes for hash alg OID.
*/
if ( nb_pad < 10 + hashlen + oid_size ) {
return ( PSA_ERROR_INVALID_ARGUMENT );
}
nb_pad -= 10 + hashlen + oid_size;
} else {
if ( nb_pad < hashlen ) {
return ( PSA_ERROR_INVALID_ARGUMENT );
}
nb_pad -= hashlen;
}
/* Need space for signature header and padding delimiter (3 bytes),
* and 8 bytes for the minimal padding */
if ( nb_pad < 3 + 8 ) {
return ( PSA_ERROR_INVALID_ARGUMENT );
}
nb_pad -= 3;
/* Now nb_pad is the amount of memory to be filled
* with padding, and at least 8 bytes long. */
/* Write signature header and padding */
*p++ = 0;
*p++ = 1; //MBEDTLS_RSA_SIGN;
memset( p, 0xFF, nb_pad );
p += nb_pad;
*p++ = 0;
/* Are we signing raw data? */
if ( alg == PSA_ALG_NONE ) {
memcpy( p, hash, hashlen );
return ( PSA_SUCCESS );
}
/* Signing hashed data, add corresponding ASN.1 structure
*
* DigestInfo ::= SEQUENCE {
* digestAlgorithm DigestAlgorithmIdentifier,
* digest Digest }
* DigestAlgorithmIdentifier ::= AlgorithmIdentifier
* Digest ::= OCTET STRING
*
* Schematic:
* TAG-SEQ + LEN [ TAG-SEQ + LEN [ TAG-OID + LEN [ OID ]
* TAG-NULL + LEN [ NULL ] ]
* TAG-OCTET + LEN [ HASH ] ]
*/
*p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED;
*p++ = (unsigned char)( 0x08 + oid_size + hashlen );
*p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED;
*p++ = (unsigned char)( 0x04 + oid_size );
*p++ = MBEDTLS_ASN1_OID;
*p++ = (unsigned char) oid_size;
memcpy( p, oid, oid_size );
p += oid_size;
*p++ = MBEDTLS_ASN1_NULL;
*p++ = 0x00;
*p++ = MBEDTLS_ASN1_OCTET_STRING;
*p++ = (unsigned char) hashlen;
memcpy( p, hash, hashlen );
p += hashlen;
/* Just a sanity-check, should be automatic
* after the initial bounds check. */
if ( p != dst + dst_len ) {
mbedtls_platform_zeroize( dst, dst_len );
return ( PSA_ERROR_INVALID_ARGUMENT );
}
return PSA_SUCCESS;
}
psa_status_t esp_rsa_ds_pad_v15_unpad(unsigned char *input,
size_t ilen,
unsigned char *output,
size_t output_max_len,
size_t *olen)
{
if (ilen < MIN_V15_PADDING_LEN) {
return PSA_ERROR_INVALID_ARGUMENT;
}
unsigned char bad = 0;
size_t msg_len = 0;
size_t msg_max_len = 0;
unsigned char pad_done = 0;
size_t pad_count = 0;
msg_max_len = (output_max_len > ilen - MIN_V15_PADDING_LEN) ? ilen - MIN_V15_PADDING_LEN : output_max_len;
/* Check the first byte (0x00) */
bad |= input[0];
/* Check the padding type */
bad |= input[1] ^ 2; // MBEDTLS_RSA_CRYPT;
/* Scan for separator (0x00) and count padding bytes in constant time */
for (size_t i = 2; i < ilen; i++) {
unsigned char found = (input[i] == 0x00);
pad_done = pad_done | found;
pad_count += (pad_done == 0) ? 1 : 0;
}
/* Check if we found a separator and padding is long enough */
bad |= (pad_done == 0); /* No separator found */
bad |= (pad_count < 8); /* Padding too short (need at least 8 non-zero bytes) */
/* Calculate message length */
msg_len = ilen - pad_count - 3;
/* Check if separator is not at the very end */
bad |= (msg_len > output_max_len);
if (bad) {
msg_len = msg_max_len;
}
/* Verify padding bytes are non-zero in constant time */
#if defined(__clang__) && defined(__xtensa__)
#pragma clang loop vectorize(disable)
#endif
for (size_t i = 2; i < ilen; i++) {
unsigned char in_padding = (i < pad_count + 2);
unsigned char is_zero = (input[i] == 0x00);
bad |= in_padding & is_zero;
}
if (bad) {
return PSA_ERROR_INVALID_ARGUMENT;
}
*olen = msg_len;
if (*olen > 0) {
memcpy(output, input + ilen - msg_len, msg_len);
}
return PSA_SUCCESS;
}
#if CONFIG_MBEDTLS_SSL_PROTO_TLS1_3
static psa_status_t esp_rsa_ds_mgf_mask(unsigned char *dst, size_t dlen, unsigned char *src,
size_t slen, psa_algorithm_t hash_alg)
{
unsigned char counter[4];
unsigned char *p;
unsigned int hlen;
size_t i, use_len;
unsigned char mask[PSA_HASH_MAX_SIZE];
psa_hash_operation_t hash_op = PSA_HASH_OPERATION_INIT;
psa_status_t status = PSA_SUCCESS;
hlen = PSA_HASH_LENGTH(hash_alg);
memset(mask, 0, sizeof(mask));
memset(counter, 0, 4);
/* Generate and apply dbMask */
p = dst;
while (dlen > 0) {
use_len = hlen;
if (dlen < hlen) {
use_len = dlen;
}
status = psa_hash_setup(&hash_op, hash_alg);
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_update(&hash_op, src, slen);
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_update(&hash_op, counter, 4);
if (status != PSA_SUCCESS) {
goto exit;
}
size_t out_len = 0;
status = psa_hash_finish(&hash_op, mask, PSA_HASH_LENGTH(hash_alg), &out_len);
if (status != PSA_SUCCESS) {
goto exit;
}
for (i = 0; i < use_len; ++i) {
*p++ ^= mask[i];
}
counter[3]++;
dlen -= use_len;
}
exit:
psa_hash_abort(&hash_op);
mbedtls_platform_zeroize(mask, sizeof(mask));
return status;
}
static psa_status_t esp_rsa_ds_hash_mprime(const unsigned char *hash, size_t hlen,
const unsigned char *salt, size_t slen,
unsigned char *out, psa_algorithm_t hash_alg)
{
const unsigned char zeros[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
psa_hash_operation_t hash_op = PSA_HASH_OPERATION_INIT;
psa_status_t status = psa_hash_setup(&hash_op, hash_alg);
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_update(&hash_op, zeros, sizeof(zeros));
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_update(&hash_op, hash, hlen);
if (status != PSA_SUCCESS) {
goto exit;
}
status = psa_hash_update(&hash_op, salt, slen);
if (status != PSA_SUCCESS) {
goto exit;
}
size_t out_len = 0;
status = psa_hash_finish(&hash_op, out, PSA_HASH_LENGTH(hash_alg), &out_len);
if (status != PSA_SUCCESS) {
goto exit;
}
exit:
psa_hash_abort(&hash_op);
return status;
}
psa_status_t esp_rsa_ds_pad_v21_encode(psa_algorithm_t hash_alg,
unsigned int hashlen,
const unsigned char *hash,
int saltlen,
unsigned char *sig,
size_t dst_len)
{
size_t olen;
unsigned char *p = sig;
unsigned char *salt = NULL;
size_t slen, min_slen, hlen, offset = 0;
psa_status_t ret = PSA_ERROR_INVALID_ARGUMENT;
size_t msb;
if ((hash_alg != PSA_ALG_NONE || hashlen != 0) && hash == NULL) {
return PSA_ERROR_INVALID_ARGUMENT;
}
olen = dst_len;
if (hash_alg != PSA_ALG_NONE) {
/* Gather length of hash to sign */
size_t exp_hashlen = PSA_HASH_LENGTH(hash_alg);
if (exp_hashlen != hashlen) {
return PSA_ERROR_INVALID_ARGUMENT;
}
}
hlen = PSA_HASH_LENGTH(hash_alg);
if (saltlen == -1) {
/* Calculate the largest possible salt length, up to the hash size.
* Normally this is the hash length, which is the maximum salt length
* according to FIPS 185-4 5.5 (e) and common practice. If there is not
* enough room, use the maximum salt length that fits. The constraint is
* that the hash length plus the salt length plus 2 bytes must be at most
* the key length. This complies with FIPS 186-4 5.5 (e) and RFC 8017
* (PKCS#1 v2.2) 9.1.1 step 3. */
min_slen = hlen - 2;
if (olen < hlen + min_slen + 2) {
return PSA_ERROR_INVALID_ARGUMENT;
} else if (olen >= hlen + hlen + 2) {
slen = hlen;
} else {
slen = olen - hlen - 2;
}
} else if ((saltlen < 0) || (saltlen + hlen + 2 > olen)) {
return PSA_ERROR_INVALID_ARGUMENT;
} else {
slen = (size_t) saltlen;
}
memset(sig, 0, olen);
/* Note: EMSA-PSS encoding is over the length of N - 1 bits */
msb = dst_len * 8 - 1;
p += olen - hlen - slen - 2;
*p++ = 0x01;
/* Generate salt of length slen in place in the encoded message */
salt = p;
if ((ret = mbedtls_psa_get_random(MBEDTLS_PSA_RANDOM_STATE, salt, slen)) != 0) {
return PSA_ERROR_INSUFFICIENT_ENTROPY;
}
p += slen;
/* Generate H = Hash( M' ) */
ret = esp_rsa_ds_hash_mprime(hash, hashlen, salt, slen, p, hash_alg);
if (ret != 0) {
return ret;
}
/* Compensate for boundary condition when applying mask */
if (msb % 8 == 0) {
offset = 1;
}
/* maskedDB: Apply dbMask to DB */
ret = esp_rsa_ds_mgf_mask(sig + offset, olen - hlen - 1 - offset, p, hlen, hash_alg);
if (ret != 0) {
return ret;
}
msb = dst_len * 8 - 1;
sig[0] &= 0xFF >> (olen * 8 - msb);
p += hlen;
*p++ = 0xBC;
return ret;
}
psa_status_t esp_rsa_ds_pad_oaep_unpad(unsigned char *input,
size_t ilen,
unsigned char *output,
size_t output_max_len,
size_t *olen,
psa_algorithm_t hash_alg)
{
unsigned int hlen = PSA_HASH_LENGTH(hash_alg);
unsigned char bad = 0;
size_t msg_len = 0;
/* Validate input length */
bad |= (ilen < 2 * hlen + 2);
/* Apply MGF masks */
bad |= esp_rsa_ds_mgf_mask(input + 1, hlen, input + hlen + 1, ilen - hlen - 1, hash_alg) != PSA_SUCCESS;
bad |= esp_rsa_ds_mgf_mask(input + hlen + 1, ilen - hlen - 1, input + 1, hlen, hash_alg) != PSA_SUCCESS;
/* Check first byte (should be 0x00) */
bad |= input[0];
/* Skip the first byte and maskSeed */
unsigned char *db = input + 1 + hlen;
size_t db_len = ilen - hlen - 1;
/* Compute hash, label is NULL and label_len is 0 */
unsigned char lhash[PSA_HASH_MAX_SIZE];
memset(lhash, 0, sizeof(lhash));
size_t lhen = 0;
bad |= psa_hash_compute(hash_alg, NULL, 0, lhash, sizeof(lhash), &lhen) != PSA_SUCCESS;
bad |= (lhen != hlen);
/* Verify hash portion of db against lhash */
for (size_t i = 0; i < hlen && i < db_len; i++) {
bad |= db[i] ^ lhash[i];
}
/* Skip past lhash in DB */
unsigned char *p = db + hlen;
size_t remaining = db_len - hlen;
/*
* Scan PS || 0x01 || M
*/
unsigned char seen_one = 0;
size_t msg_index = 0;
for (size_t i = 0; i < remaining; i++) {
unsigned char is_zero = (p[i] == 0);
unsigned char is_one = (p[i] == 1);
/* Before delimiter, only 0x00 allowed */
bad |= (seen_one == 0) & !(is_zero | is_one);
/* Record first 0x01 */
msg_index |= (seen_one == 0 && is_one) * i;
seen_one |= is_one;
}
/* Must see exactly one delimiter */
bad |= (seen_one == 0);
/* Calculate message length */
msg_len = remaining - msg_index - 1;
bad |= (msg_len == 0);
/* Check output buffer size */
bad |= (output_max_len < msg_len);
if (bad) {
*olen = 0;
return PSA_ERROR_INVALID_ARGUMENT;
}
/* Copy message in constant time */
*olen = msg_len;
if (*olen > 0) {
memcpy(output, p + msg_index + 1, msg_len);
}
return PSA_SUCCESS;
}
#endif /* CONFIG_MBEDTLS_SSL_PROTO_TLS1_3 */
@@ -6,26 +6,14 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/**
* \file psa_crypto_driver_esp_sha_contexts.h
*
* \brief Context structure definitions for ESP SHA hardware driver.
*
* This file contains the context structures used by the ESP SHA driver
* for PSA Crypto API. These definitions are completely standalone and
* do not include any PSA Crypto headers to avoid circular dependencies.
*
* \note This file may not be included directly. It is included by
* crypto_driver_contexts_primitives.h.
*/
#include "esp_types.h"
#include "psa/crypto_driver_common.h"
#ifdef __cplusplus
extern "C" {
#endif
#if defined(ESP_AES_DRIVER_ENABLED)
#define ESP_MBEDTLS_AES_MAX_BLOCK_LENGTH 16
#define ESP_MBEDTLS_AES_MAX_IV_LENGTH 16
@@ -0,0 +1,180 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "sdkconfig.h"
#include "psa/crypto.h"
#if defined(SOC_DIG_SIGN_SUPPORTED) && defined(CONFIG_MBEDTLS_HARDWARE_RSA_DS_PERIPHERAL)
#include "psa_crypto_driver_esp_rsa_ds_contexts.h"
#ifdef __cplusplus
extern "C" {
#endif
#if defined(ESP_RSA_DS_DRIVER_ENABLED)
#ifndef PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT
#define PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT
#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */
#endif /* ESP_RSA_DS_DRIVER_ENABLED */
#define PSA_KEY_LOCATION_ESP_RSA_DS ((psa_key_location_t) 0x800003)
#define PSA_KEY_LIFETIME_ESP_RSA_DS \
PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION( \
PSA_KEY_PERSISTENCE_VOLATILE, \
PSA_KEY_LOCATION_ESP_RSA_DS)
/**
* @brief Start the RSA DS opaque sign hash operation
*
* @param operation Operation context
* @param attributes Key attributes
* @param key_buffer Key buffer
* @param key_buffer_size Key buffer size
* @param alg Algorithm used in the sign operation
* @param hash Hash to sign
* @param hash_length Length of the hash
* @return Status of the start operation
* PSA_SUCCESS if the operation was started successfully
* Error code if the operation was not started successfully, check psa_status_t documentation for more details.
*/
psa_status_t esp_rsa_ds_opaque_sign_hash_start(
esp_rsa_ds_opaque_sign_hash_operation_t *operation,
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
psa_algorithm_t alg,
const uint8_t *hash,
size_t hash_length);
/**
* @brief Complete the RSA DS opaque sign hash operation.
* The signature buffer should be pre-allocated with the size of the RSA key.
* The operation context should be initialised with the start operation.
* @param operation Operation context
* @param signature Signature buffer
* @param signature_size Size of the signature buffer
* @param signature_length Actual length of the signature
* @return Status of the complete operation
* PSA_SUCCESS if the operation was completed successfully
* Error code if the operation was not completed successfully, check psa_status_t documentation for more details.
*/
psa_status_t esp_rsa_ds_opaque_sign_hash_complete(
esp_rsa_ds_opaque_sign_hash_operation_t *operation,
uint8_t *signature, size_t signature_size,
size_t *signature_length);
/**
* @brief Abort the RSA DS opaque sign hash operation.
* The operation context should be initialised with the start operation.
* @param operation Operation context
* @return Status of the abort operation
* PSA_SUCCESS if the operation was aborted successfully
* Error code if the operation was not aborted successfully, check psa_status_t documentation for more details.
*/
psa_status_t esp_rsa_ds_opaque_sign_hash_abort(
esp_rsa_ds_opaque_sign_hash_operation_t *operation);
/**
* @brief Sign the hash using the RSA DS opaque key.
* This is one-shot function that combines the start and complete operations.
*
* @param attributes Key attributes
* @param key_buffer Key buffer
* @param key_buffer_size Key buffer size
* @param alg Algorithm used in the sign operation
* @param hash Hash to sign
* @param hash_length Length of the hash
* @param signature Signature buffer
* @param signature_size Size of the signature buffer
* @param signature_length Actual length of the signature
* @return Status of the sign operation
* PSA_SUCCESS if the operation was completed successfully
* Error code if the operation was not completed successfully, check psa_status_t documentation for more details.
*/
psa_status_t esp_rsa_ds_opaque_signature_sign_hash(
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
psa_algorithm_t alg,
const uint8_t *hash,
size_t hash_length,
uint8_t *signature,
size_t signature_size,
size_t *signature_length
);
/**
* @brief Import the RSA DS opaque key
* The data should be of type esp_ds_data_ctx_t and should be
* already initialised with DS data and efuse key id.
*
* @param attributes Key attributes
* @param data Key data
* @param data_length Key data length
* @param key_buffer Key buffer
* @param key_buffer_size Key buffer size
* @param key_buffer_length Key buffer length
* @param bits Key bits
* @return Status of the import operation
* PSA_SUCCESS if the key was imported successfully
* Error code if the key was not imported successfully, check psa_status_t documentation for more details
*/
psa_status_t esp_rsa_ds_opaque_import_key(
const psa_key_attributes_t *attributes,
const uint8_t *data,
size_t data_length,
uint8_t *key_buffer,
size_t key_buffer_size,
size_t *key_buffer_length,
size_t *bits);
/**
* @brief Return the size of the RSA DS opaque key in bytes
*
* @param key_type Key type
* @param key_bits Key bits
* @return Size of the RSA DS opaque key in bytes
*/
size_t esp_rsa_ds_opaque_size_function(
psa_key_type_t key_type,
size_t key_bits);
/**
* @brief Set the timeout for the RSA DS session
*
* @param timeout_ms Timeout in milliseconds
*/
void esp_rsa_ds_opaque_set_session_timeout(int timeout_ms);
/**
* @brief Decrypt the input using the RSA DS opaque key.
*
* @param attributes Key attributes
* @param key Key buffer
* @param key_length Key buffer size
* @param alg Algorithm used in the decrypt operation
* @param input Input buffer
* @param input_length Length of the input buffer
* @param salt Salt buffer
* @param salt_length Length of the salt buffer
* @param output Output buffer
* @param output_size Size of the output buffer
* @param output_length Actual length of the output
* @return Status of the decrypt operation
* PSA_SUCCESS if the operation was completed successfully
* Error code if the operation was not completed successfully, check psa_status_t documentation for more details.
*/
psa_status_t esp_rsa_ds_opaque_asymmetric_decrypt(
const psa_key_attributes_t *attributes, const uint8_t *key,
size_t key_length, psa_algorithm_t alg, const uint8_t *input,
size_t input_length, const uint8_t *salt, size_t salt_length,
uint8_t *output, size_t output_size, size_t *output_length);
#ifdef __cplusplus
}
#endif
#endif /* SOC_DIG_SIGN_SUPPORTED && CONFIG_MBEDTLS_HARDWARE_RSA_DS_PERIPHERAL */
@@ -0,0 +1,57 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "sdkconfig.h"
#if defined(ESP_RSA_DS_DRIVER_ENABLED)
#include "psa/crypto_driver_common.h"
#include "esp_ds.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief RSA-DS padding options
*/
typedef enum {
ESP_RSA_DS_PADDING_PKCS_V15,
ESP_RSA_DS_PADDING_PSS,
ESP_RSA_DS_PADDING_OAEP,
ESP_RSA_DS_PADDING_INVALID = -1
} esp_rsa_ds_padding_t;
/**
* @brief ESP DS data context
* This context is used to store the ESP DS data.
*
* When passed to psa_import_key() for PSA_KEY_LIFETIME_ESP_RSA_DS, the key material
* (this struct and the esp_ds_data_t pointed to by esp_rsa_ds_data) must remain valid
* until psa_destroy_key() is called on the imported key.
*/
typedef struct {
esp_ds_data_t *esp_rsa_ds_data; /**< Pointer to the esp ds data */
uint8_t efuse_key_id; /**< efuse block id in which DS_KEY is stored e.g. 0,1*/
uint16_t rsa_length_bits; /**< length of RSA private key in bits e.g. 2048 */
} esp_ds_data_ctx_t;
#if !(__DOXYGEN__) // No need to document these structures, these are internal to the driver
/* The buffers are stored in the little-endian format */
typedef struct {
const esp_ds_data_ctx_t *esp_rsa_ds_opaque_key; /**< Pointer to the esp ds opaque key */
psa_algorithm_t alg; /**< Algorithm used in the sign operation */
uint32_t *sig_buffer; /**< Buffer to hold the signature */
size_t sig_buffer_size; /**< Size of the signature buffer */
esp_ds_context_t *esp_rsa_ds_ctx; /**< Pointer to the esp ds context */
} esp_rsa_ds_opaque_sign_hash_operation_t;
#endif /* !(__DOXYGEN__) */
#ifdef __cplusplus
}
#endif
#endif /* ESP_RSA_DS_DRIVER_ENABLED */
@@ -10,6 +10,7 @@
#include "esp_types.h"
#include <stdbool.h>
#include "soc/soc_caps.h"
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
@@ -28,6 +29,9 @@ extern "C" {
* crypto_driver_contexts_primitives.h.
*/
/**
* @brief ESP SHA operation type
*/
typedef enum {
ESP_SHA_OPERATION_TYPE_SHA1,
ESP_SHA_OPERATION_TYPE_SHA256,
@@ -37,24 +41,33 @@ typedef enum {
} esp_sha_operation_type_t;
/**
* \brief ESP SHA1 state enumeration
* @brief ESP SHA1 state enumeration
*/
typedef enum {
ESP_SHA1_STATE_INIT,
ESP_SHA1_STATE_IN_PROCESS
} esp_sha1_state;
/**
* @brief ESP SHA256 state enumeration
*/
typedef enum {
ESP_SHA256_STATE_INIT,
ESP_SHA256_STATE_IN_PROCESS
} esp_sha256_state;
/**
* @brief ESP SHA512 state enumeration
*/
typedef enum {
ESP_SHA512_STATE_INIT,
ESP_SHA512_STATE_IN_PROCESS
} esp_sha512_state;
#if SOC_SHA_SUPPORT_PARALLEL_ENG
#if CONFIG_SOC_SHA_SUPPORT_PARALLEL_ENG
/**
* @brief ESP SHA mode enumeration
*/
typedef enum {
ESP_SHA_MODE_UNUSED,
ESP_SHA_MODE_HARDWARE,
@@ -63,61 +76,65 @@ typedef enum {
#endif /* SOC_SHA_SUPPORT_PARALLEL_ENG */
/**
* \brief ESP SHA1 context structure
* @brief ESP SHA1 context structure
*/
typedef struct {
uint32_t total[2]; /*!< The number of Bytes processed. */
uint32_t state[5]; /*!< The intermediate digest state. */
unsigned char buffer[64]; /*!< The data block being processed. */
bool first_block; /*!< First block flag for hardware initialization */
int sha_state; /*!< SHA operation state */
#if SOC_SHA_SUPPORT_PARALLEL_ENG
uint32_t total[2]; /**< The number of Bytes processed. */
uint32_t state[5]; /**< The intermediate digest state. */
unsigned char buffer[64]; /**< The data block being processed. */
bool first_block; /**< First block flag for hardware initialization */
int sha_state; /**< SHA operation state */
#if CONFIG_SOC_SHA_SUPPORT_PARALLEL_ENG
esp_sha_mode_t operation_mode; /*!< Hardware or Software mode */
#endif /* SOC_SHA_SUPPORT_PARALLEL_ENG */
} esp_sha1_context;
/**
* \brief ESP SHA256 context structure
* @brief ESP SHA256 context structure
*/
typedef struct {
unsigned char buffer[64]; /*!< The data block being processed. */
uint32_t total[2]; /*!< The number of Bytes processed. */
uint32_t state[8]; /*!< The intermediate digest state. */
bool first_block; /*!< First block flag for hardware initialization */
int sha_state; /*!< SHA operation state */
int mode; /*!< SHA2_224 or SHA2_256 */
#if SOC_SHA_SUPPORT_PARALLEL_ENG
unsigned char buffer[64]; /**< The data block being processed. */
uint32_t total[2]; /**< The number of Bytes processed. */
uint32_t state[8]; /**< The intermediate digest state. */
bool first_block; /**< First block flag for hardware initialization */
int sha_state; /**< SHA operation state */
int mode; /**< SHA2_224 or SHA2_256 */
#if CONFIG_SOC_SHA_SUPPORT_PARALLEL_ENG
esp_sha_mode_t operation_mode; /*!< Hardware or Software mode */
#endif /* SOC_SHA_SUPPORT_PARALLEL_ENG */
} esp_sha256_context;
/**
* \brief ESP SHA512 context structure
*
* @brief ESP SHA512 context structure
*/
typedef struct {
uint64_t total[2]; /*!< The number of Bytes processed. */
uint64_t state[8]; /*!< The intermediate digest state. */
unsigned char buffer[128]; /*!< The data block being processed. */
bool first_block;
int sha_state;
int mode;
uint32_t t_val; /*!< t_val for 512/t mode */
#if SOC_SHA_SUPPORT_PARALLEL_ENG
esp_sha_mode_t operation_mode; /*!< Hardware or Software mode */
#endif /* SOC_SHA_SUPPORT_PARALLEL_ENG */
uint64_t total[2]; /**< The number of Bytes processed. */
uint64_t state[8]; /**< The intermediate digest state. */
unsigned char buffer[128]; /**< The data block being processed. */
bool first_block; /**< First block flag for hardware initialization */
int sha_state; /**< SHA operation state */
int mode; /**< SHA2_224 or SHA2_256 */
uint32_t t_val; /**< t_val for 512/t mode */
#if CONFIG_SOC_SHA_SUPPORT_PARALLEL_ENG
esp_sha_mode_t operation_mode; /**< Hardware or Software mode */
#endif /* CONFIG_SOC_SHA_SUPPORT_PARALLEL_ENG */
} esp_sha512_context;
/**
* @brief ESP SHA context type
* This is void pointer to remove any dependency on the actual SHA context structure
* and allows the driver to be used with different SHA context structures.
*/
typedef void *esp_sha_context_t;
/**
* \brief ESP SHA driver operation context
* @brief ESP SHA driver operation context
*
* This structure contains the contexts for different SHA algorithms
* supported by the ESP hardware accelerator.
*/
typedef struct {
esp_sha_context_t sha_ctx;
esp_sha_operation_type_t sha_type;
esp_sha_context_t sha_ctx; /**< Pointer to the SHA context */
esp_sha_operation_type_t sha_type; /**< SHA operation type */
} esp_sha_hash_operation_t;
#ifdef __cplusplus
@@ -20,5 +20,7 @@ target_compile_definitions(${mbedtls} INTERFACE "-DMBEDTLS_DEPRECATED_WARNING")
target_compile_definitions(mbedtls PUBLIC "-DMBEDTLS_DEPRECATED_WARNING")
target_compile_definitions(mbedx509 PUBLIC "-DMBEDTLS_DEPRECATED_WARNING")
# Add linker wrap option to override esp_ds_finish_sign
target_link_options(${COMPONENT_LIB} INTERFACE "-Wl,--wrap=esp_ds_finish_sign,--wrap=esp_ds_start_sign")
target_link_options(
${COMPONENT_LIB} INTERFACE
"-Wl,--wrap=esp_ds_finish_sign,--wrap=esp_ds_start_sign,--wrap=esp_efuse_get_key_purpose"
)
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -9,117 +9,202 @@
#include "mbedtls/private/rsa.h"
#include "esp_random.h"
#include "sdkconfig.h"
#ifdef CONFIG_HEAP_TRACING
#include <esp_heap_trace.h>
#define NUM_RECORDS 100
static heap_trace_record_t trace_record[NUM_RECORDS]; // This buffer must be in internal RAM
#endif
#ifdef SOC_DIG_SIGN_SUPPORTED
#include "soc/soc_caps.h"
#include "esp_ds.h"
#include "esp_ds/esp_ds_rsa.h"
#include "hal/hmac_types.h"
#include "esp_efuse.h"
static int mbedtls_esp_random(void *ctx, unsigned char *output, size_t len)
#ifdef CONFIG_MBEDTLS_HARDWARE_RSA_DS_PERIPHERAL
#include "esp_ds.h"
#include "psa_crypto_driver_esp_rsa_ds.h"
esp_ds_data_ctx_t *esp_secure_cert_get_ds_ctx(void)
{
if (len == 0 || output == NULL) {
return -1;
// In real implementation, this function retrieves the DS key context from secure storage
// For testing purposes, we will create a mock DS key context
esp_ds_data_ctx_t *ds_key = calloc(1, sizeof(esp_ds_data_ctx_t));
if (ds_key == NULL) {
return NULL;
}
esp_fill_random(output, len);
return 0;
// Mock RSA key parameters
ds_key->rsa_length_bits = 2048;
ds_key->efuse_key_id = 0;
ds_key->esp_rsa_ds_data = calloc(1, sizeof(esp_ds_data_t));
if (ds_key->esp_rsa_ds_data != NULL) {
/* rsa_length must match rsa_length_bits for driver validation */
ds_key->esp_rsa_ds_data->rsa_length = (ds_key->rsa_length_bits / 32) - 1;
}
// Fill in other necessary fields as per esp_ds_data_ctx_t definition
// For simplicity, we will leave them zeroed out
return ds_key;
}
TEST_CASE("ds sign test pkcs1_v15", "[ds_rsa]")
void esp_secure_cert_free_ds_ctx(esp_ds_data_ctx_t *ds_key)
{
mbedtls_rsa_context rsa_ctx;
rsa_ctx.MBEDTLS_PRIVATE(padding) = MBEDTLS_RSA_PKCS_V15;
if (ds_key != NULL) {
if (ds_key->esp_rsa_ds_data != NULL) {
free(ds_key->esp_rsa_ds_data);
}
free(ds_key);
}
}
TEST_CASE("ds sign test pkcs1_v15 PSA validation", "[ds_rsa_psa]")
{
psa_key_id_t keyt_id;
psa_status_t status;
psa_algorithm_t alg = PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_SHA_256);
esp_ds_data_ctx_t *ds_key = esp_secure_cert_get_ds_ctx();
TEST_ASSERT_NOT_NULL(ds_key);
ds_key->efuse_key_id = EFUSE_BLK_MAX; // Invalid efuse key id to trigger validation failure
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_set_key_type(&attributes, PSA_KEY_TYPE_RSA_KEY_PAIR);
psa_set_key_bits(&attributes, ds_key->rsa_length_bits);
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH);
psa_set_key_algorithm(&attributes, alg);
psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_ESP_RSA_DS);
status = psa_import_key(&attributes,
(const uint8_t *)ds_key,
sizeof(*ds_key),
&keyt_id);
TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_ARGUMENT, status);
ds_key->efuse_key_id = EFUSE_BLK0 + 0; // Reset to valid efuse key id
ds_key->rsa_length_bits = 1000; // Invalid RSA length to trigger validation failure
status = psa_import_key(&attributes,
(const uint8_t *)ds_key,
sizeof(*ds_key),
&keyt_id);
TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_ARGUMENT, status);
ds_key->rsa_length_bits = 2048; // Reset to valid RSA length
esp_ds_data_t *ds_data_backup = ds_key->esp_rsa_ds_data;
ds_key->esp_rsa_ds_data = NULL; // NULL esp_rsa_ds_data to trigger validation failure
status = psa_import_key(&attributes,
(const uint8_t *)ds_key,
sizeof(*ds_key),
&keyt_id);
TEST_ASSERT_EQUAL(PSA_ERROR_INVALID_ARGUMENT, status);
ds_key->esp_rsa_ds_data = ds_data_backup; // Restore esp_rsa_ds_data
esp_secure_cert_free_ds_ctx(ds_key);
}
TEST_CASE("ds sign test pkcs1_v15 PSA", "[ds_rsa_psa]")
{
psa_key_id_t keyt_id;
psa_status_t status;
psa_algorithm_t alg = PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_SHA_256);
esp_ds_data_ctx_t *ds_key = esp_secure_cert_get_ds_ctx();
TEST_ASSERT_NOT_NULL(ds_key);
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_set_key_type(&attributes, PSA_KEY_TYPE_RSA_KEY_PAIR);
psa_set_key_bits(&attributes, ds_key->rsa_length_bits);
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH);
psa_set_key_algorithm(&attributes, alg);
psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_ESP_RSA_DS);
status = psa_import_key(&attributes,
(const uint8_t *)ds_key,
sizeof(*ds_key),
&keyt_id);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
unsigned char hash[32] = {0};
mbedtls_esp_random(NULL, hash, sizeof(hash)); // Fill hash with random data
unsigned int hashlen = sizeof(hash);
size_t hash_length = 0;
uint8_t input[7] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
status = psa_hash_compute(PSA_ALG_SHA_256, input, 7, hash, sizeof(hash), &hash_length);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
TEST_ASSERT_EQUAL(32, hash_length);
unsigned char signature[256] = {0};
mbedtls_pk_context pk;
mbedtls_pk_init(&pk);
pk.MBEDTLS_PRIVATE(pk_ctx) = &rsa_ctx;
size_t signature_length = 0;
status = psa_sign_hash(keyt_id, alg, hash, hash_length, signature, sizeof(signature), &signature_length);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
TEST_ASSERT_EQUAL(256, signature_length);
// esp_ds is not initialized, so we expect an error
int err = esp_ds_rsa_sign(&pk, mbedtls_esp_random, NULL, MBEDTLS_MD_SHA256, hashlen, hash, signature);
TEST_ASSERT_EQUAL(-1, err);
status = psa_destroy_key(keyt_id);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
// Initialize the esp_ds context
esp_ds_data_ctx_t ctx;
esp_ds_data_t ds_data;
ds_data.rsa_length = ESP_DS_RSA_2048; // Example length
ctx.esp_ds_data = &ds_data;
ctx.efuse_key_id = 1; // Example efuse key ID
ctx.rsa_length_bits = 2048; // Example RSA length in bits
psa_reset_key_attributes(&attributes);
err = esp_ds_init_data_ctx(&ctx);
TEST_ASSERT_EQUAL(ESP_OK, err);
// Now we can call esp_ds_rsa_sign again
err = esp_ds_rsa_sign(&pk, mbedtls_esp_random, NULL, MBEDTLS_MD_SHA256, hashlen, hash, signature);
TEST_ASSERT_EQUAL(0, err);
TEST_ASSERT_NOT_NULL(signature);
err = esp_ds_deinit_data_ctx();
TEST_ASSERT_EQUAL(ESP_OK, err);
// Free the DS context to prevent memory leak
esp_secure_cert_free_ds_ctx(ds_key);
// Because we have wrapped around the ds_start_sign and ds_finish_sign functions,
// we are not actually performing the real signing operation. That test is done in the
// crypto test_apps, so here we just check that the surrounding code works as expected.
// In this test, we have used v15 padding, so we expect the signature to be non-null
// and the hash to be part of the signature.
TEST_ASSERT_EQUAL(0, memcmp(hash, signature + (256 - hashlen), hashlen));
TEST_ASSERT_EQUAL(0, memcmp(hash, signature + (256 - hash_length), hash_length));
// Let's also ensure that signature has correct encoding
// Just before the hash start, it should have size of hash
TEST_ASSERT_EQUAL(hashlen, signature[256 - hashlen - 1]);
TEST_ASSERT_EQUAL(hash_length, signature[256 - hash_length - 1]);
// One byte before should be MBEDTLS_ASN1_OCTET_STRING
TEST_ASSERT_EQUAL(0x04, signature[256 - hashlen - 2]);
TEST_ASSERT_EQUAL(0x04, signature[256 - hash_length - 2]);
// And the first byte should be 0x00, indicating that this is a valid PKCS#1 v1.5 signature
TEST_ASSERT_EQUAL(0x00, signature[0]);
}
const unsigned char message[] = {
0x62, 0x1c, 0xaa, 0x4a, 0xae, 0xf8, 0x1f, 0x4b, 0x59, 0x70, 0xee, 0xcb, 0x0c, 0x91, 0x35, 0xc9,
0x4a, 0xe2, 0x85, 0xf4, 0xfc, 0x21, 0x18, 0x3e, 0xa6, 0xed, 0xa6, 0x71, 0xdb, 0xfe, 0x2b, 0x95,
0x67, 0x45, 0xb7,
};
const size_t message_len = 35;
#ifdef CONFIG_MBEDTLS_SSL_PROTO_TLS1_3
TEST_CASE("ds sign test pkcs1_v21", "[ds_rsa]")
TEST_CASE("ds sign test pkcs1_v21 PSA", "[ds_rsa_psa]")
{
mbedtls_rsa_context rsa_ctx;
rsa_ctx.MBEDTLS_PRIVATE(padding) = MBEDTLS_RSA_PKCS_V21;
psa_key_id_t keyt_id;
psa_status_t status;
psa_algorithm_t alg = PSA_ALG_RSA_PSS(PSA_ALG_SHA_256);
esp_ds_data_ctx_t *ds_key = esp_secure_cert_get_ds_ctx();
TEST_ASSERT_NOT_NULL(ds_key);
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_set_key_type(&attributes, PSA_KEY_TYPE_RSA_KEY_PAIR);
psa_set_key_bits(&attributes, ds_key->rsa_length_bits);
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH);
psa_set_key_algorithm(&attributes, alg);
psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_ESP_RSA_DS);
status = psa_import_key(&attributes,
(const uint8_t *)ds_key,
sizeof(*ds_key),
&keyt_id);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
unsigned char hash[32] = {0};
mbedtls_esp_random(NULL, hash, sizeof(hash)); // Fill hash with random data
unsigned int hashlen = sizeof(hash);
size_t hash_length = 0;
uint8_t input[7] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
status = psa_hash_compute(PSA_ALG_SHA_256, input, 7, hash, sizeof(hash), &hash_length);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
TEST_ASSERT_EQUAL(32, hash_length);
unsigned char signature[256] = {0};
mbedtls_pk_context pk;
mbedtls_pk_init(&pk);
pk.MBEDTLS_PRIVATE(pk_ctx) = &rsa_ctx;
size_t signature_length = 0;
status = psa_sign_hash(keyt_id, alg, hash, hash_length, signature, sizeof(signature), &signature_length);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
TEST_ASSERT_EQUAL(256, signature_length);
// esp_ds is not initialized, so we expect an error
int err = esp_ds_rsa_sign(&pk, mbedtls_esp_random, NULL, MBEDTLS_MD_SHA256, hashlen, hash, signature);
TEST_ASSERT_EQUAL(-1, err);
status = psa_destroy_key(keyt_id);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
// Initialize the esp_ds context
esp_ds_data_ctx_t ctx;
esp_ds_data_t ds_data;
ds_data.rsa_length = ESP_DS_RSA_2048; // Example length
ctx.esp_ds_data = &ds_data;
ctx.efuse_key_id = 1; // Example efuse key ID
ctx.rsa_length_bits = 2048; // Example RSA length in bits
psa_reset_key_attributes(&attributes);
err = esp_ds_init_data_ctx(&ctx);
TEST_ASSERT_EQUAL(ESP_OK, err);
// Now we can call esp_ds_rsa_sign again
err = esp_ds_rsa_sign(&pk, mbedtls_esp_random, NULL, MBEDTLS_MD_SHA256, hashlen, hash, signature);
TEST_ASSERT_EQUAL(0, err);
TEST_ASSERT_NOT_NULL(signature);
err = esp_ds_deinit_data_ctx();
TEST_ASSERT_EQUAL(ESP_OK, err);
// Free the DS context to prevent memory leak
esp_secure_cert_free_ds_ctx(ds_key);
}
#endif // CONFIG_MBEDTLS_SSL_PROTO_TLS1_3
/* Generated external data for OAEP padding */
const unsigned char oaep_padded_v21[] = {
@@ -141,53 +226,48 @@ const unsigned char oaep_padded_v21[] = {
0x3a, 0x1c, 0xf5, 0xe8, 0x9f, 0x17, 0x22, 0x66, 0x3d, 0xc5, 0xab, 0xf6, 0x51, 0xe9, 0x84, 0x73,
};
const unsigned char message[] = {
0x62, 0x1c, 0xaa, 0x4a, 0xae, 0xf8, 0x1f, 0x4b, 0x59, 0x70, 0xee, 0xcb, 0x0c, 0x91, 0x35, 0xc9,
0x4a, 0xe2, 0x85, 0xf4, 0xfc, 0x21, 0x18, 0x3e, 0xa6, 0xed, 0xa6, 0x71, 0xdb, 0xfe, 0x2b, 0x95,
0x67, 0x45, 0xb7,
};
const size_t message_len = 35;
TEST_CASE("ds decrypt test pkcs1_v21", "[ds_rsa]")
TEST_CASE("ds decrypt test pkcs1_v21 PSA", "[ds_rsa]")
{
#ifdef CONFIG_HEAP_TRACING
heap_trace_init_standalone(trace_record, NUM_RECORDS);
heap_trace_start(HEAP_TRACE_LEAKS);
#endif
mbedtls_rsa_context rsa_ctx;
rsa_ctx.MBEDTLS_PRIVATE(padding) = MBEDTLS_RSA_PKCS_V21;
// Initialize the esp_ds context
esp_ds_data_ctx_t ctx;
esp_ds_data_t ds_data;
ds_data.rsa_length = ESP_DS_RSA_2048; // Example length
ctx.esp_ds_data = &ds_data;
ctx.efuse_key_id = 1; // Example efuse key ID
ctx.rsa_length_bits = 2048; // Example RSA length in bits
psa_key_id_t keyt_id;
psa_status_t status;
psa_algorithm_t alg = PSA_ALG_RSA_OAEP(PSA_ALG_SHA_256);
esp_ds_data_ctx_t *ds_key = esp_secure_cert_get_ds_ctx();
TEST_ASSERT_NOT_NULL(ds_key);
printf("DS Key RSA Length Bits: %d\n", ds_key->rsa_length_bits);
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_set_key_type(&attributes, PSA_KEY_TYPE_RSA_KEY_PAIR);
psa_set_key_bits(&attributes, ds_key->rsa_length_bits);
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DECRYPT);
psa_set_key_algorithm(&attributes, alg);
psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_ESP_RSA_DS);
status = psa_import_key(&attributes,
(const uint8_t *)ds_key,
sizeof(*ds_key),
&keyt_id);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
unsigned char decrypted[256] = {0};
size_t decrypted_len = 0;
// esp_ds is not initialized, so we expect an error
int err = esp_ds_rsa_decrypt(&rsa_ctx, &decrypted_len, oaep_padded_v21, decrypted, sizeof(decrypted));
TEST_ASSERT_EQUAL(-1, err);
err = esp_ds_init_data_ctx(&ctx);
TEST_ASSERT_EQUAL(ESP_OK, err);
err = esp_ds_rsa_decrypt(&rsa_ctx, &decrypted_len, oaep_padded_v21, decrypted, sizeof(decrypted));
TEST_ASSERT_EQUAL(0, err);
TEST_ASSERT_NOT_NULL(decrypted);
err = esp_ds_deinit_data_ctx();
TEST_ASSERT_EQUAL(ESP_OK, err);
TEST_ASSERT_EQUAL(decrypted_len, message_len);
status = psa_asymmetric_decrypt(keyt_id, alg, oaep_padded_v21, sizeof(oaep_padded_v21),
NULL, 0,
decrypted, sizeof(decrypted),
&decrypted_len);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
TEST_ASSERT_EQUAL(message_len, decrypted_len);
TEST_ASSERT_EQUAL_MEMORY(decrypted, message, message_len);
#ifdef CONFIG_HEAP_TRACING
heap_trace_stop();
heap_trace_dump();
#endif
status = psa_destroy_key(keyt_id);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
psa_reset_key_attributes(&attributes);
// Free the DS context to prevent memory leak
esp_secure_cert_free_ds_ctx(ds_key);
}
#endif /* CONFIG_MBEDTLS_SSL_PROTO_TLS1_3 */
const unsigned char v15_padded[] = {
0x00, 0x02, 0xdf, 0x36, 0xfc, 0x41, 0x57, 0x40, 0x87, 0x3f, 0x88, 0xa7, 0x7f, 0x7a, 0x33, 0xbe,
@@ -208,32 +288,46 @@ const unsigned char v15_padded[] = {
0xf4, 0xfc, 0x21, 0x18, 0x3e, 0xa6, 0xed, 0xa6, 0x71, 0xdb, 0xfe, 0x2b, 0x95, 0x67, 0x45, 0xb7,
};
TEST_CASE("ds decrypt test pkcs1_v15", "[ds_rsa]")
TEST_CASE("ds decrypt test pkcs1_v15 PSA", "[ds_rsa]")
{
mbedtls_rsa_context rsa_ctx;
rsa_ctx.MBEDTLS_PRIVATE(padding) = MBEDTLS_RSA_PKCS_V15;
// Initialize the esp_ds context
esp_ds_data_ctx_t ctx;
esp_ds_data_t ds_data;
ds_data.rsa_length = ESP_DS_RSA_2048; // Example length
ctx.esp_ds_data = &ds_data;
ctx.efuse_key_id = 1; // Example efuse key ID
ctx.rsa_length_bits = 2048; // Example RSA length in bits
psa_key_id_t keyt_id;
psa_status_t status;
psa_algorithm_t alg = PSA_ALG_RSA_PKCS1V15_CRYPT;
int err = esp_ds_init_data_ctx(&ctx);
TEST_ASSERT_EQUAL(ESP_OK, err);
esp_ds_data_ctx_t *ds_key = esp_secure_cert_get_ds_ctx();
TEST_ASSERT_NOT_NULL(ds_key);
printf("DS Key RSA Length Bits: %d\n", ds_key->rsa_length_bits);
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_set_key_type(&attributes, PSA_KEY_TYPE_RSA_KEY_PAIR);
psa_set_key_bits(&attributes, ds_key->rsa_length_bits);
psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DECRYPT);
psa_set_key_algorithm(&attributes, alg);
psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_ESP_RSA_DS);
status = psa_import_key(&attributes,
(const uint8_t *)ds_key,
sizeof(*ds_key),
&keyt_id);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
unsigned char decrypted[256] = {0};
size_t decrypted_len = 0;
err = esp_ds_rsa_decrypt(&rsa_ctx, &decrypted_len, v15_padded, decrypted, sizeof(decrypted));
TEST_ASSERT_EQUAL(0, err);
TEST_ASSERT_NOT_NULL(decrypted);
err = esp_ds_deinit_data_ctx();
TEST_ASSERT_EQUAL(ESP_OK, err);
TEST_ASSERT_EQUAL(decrypted_len, message_len);
status = psa_asymmetric_decrypt(keyt_id, alg, v15_padded, sizeof(v15_padded),
NULL, 0,
decrypted, sizeof(decrypted),
&decrypted_len);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
TEST_ASSERT_EQUAL(message_len, decrypted_len);
TEST_ASSERT_EQUAL_MEMORY(decrypted, message, message_len);
status = psa_destroy_key(keyt_id);
TEST_ASSERT_EQUAL(PSA_SUCCESS, status);
psa_reset_key_attributes(&attributes);
// Free the DS context to prevent memory leak
esp_secure_cert_free_ds_ctx(ds_key);
}
int __wrap_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)
@@ -262,4 +356,22 @@ int __wrap_esp_ds_finish_sign(void *sig, esp_ds_context_t *ctx)
// Or we can call the real implementation if needed:
// return __real_esp_ds_finish_sign(sig, ctx);
}
#endif /* SOC_DIG_SIGN_SUPPORTED */
#endif /* CONFIG_MBEDTLS_HARDWARE_RSA_DS_PERIPHERAL */
// Forward declaration for linker-wrapped function
extern esp_efuse_purpose_t __real_esp_efuse_get_key_purpose(esp_efuse_block_t block);
esp_efuse_purpose_t __wrap_esp_efuse_get_key_purpose(esp_efuse_block_t block)
{
#if CONFIG_MBEDTLS_HARDWARE_RSA_DS_PERIPHERAL
if (block == EFUSE_BLK_KEY0 + 0) {
printf("Mocked esp_efuse_get_key_purpose called for block %d\n", block);
return ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_DIGITAL_SIGNATURE;
} else
#endif /* CONFIG_MBEDTLS_HARDWARE_RSA_DS_PERIPHERAL */
{
printf("Mocked esp_efuse_get_key_purpose forwarding to real for block %d\n", block);
return __real_esp_efuse_get_key_purpose(block);
}
}
@@ -0,0 +1,4 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
esp_secure_cert, 0x3F, , 0xD000, 0x2000,
factory, app, factory, 0x20000, 1M,
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
3 esp_secure_cert, 0x3F, , 0xD000, 0x2000,
4 factory, app, factory, 0x20000, 1M,
@@ -1 +1,2 @@
CONFIG_MBEDTLS_SSL_PROTO_TLS1_3=y
CONFIG_MBEDTLS_HARDWARE_RSA_DS_PERIPHERAL=y
@@ -367,6 +367,18 @@ config SOC_CPU_WATCHPOINT_MAX_REGION_SIZE
hex
default 0x40
config SOC_DS_SIGNATURE_MAX_BIT_LEN
int
default 4096
config SOC_DS_KEY_PARAM_MD_IV_LENGTH
int
default 16
config SOC_DS_KEY_CHECK_MAX_WAIT_US
int
default 1100
config SOC_DAC_CHAN_NUM
int
default 2
@@ -160,6 +160,17 @@
#define SOC_CPU_WATCHPOINTS_NUM 2
#define SOC_CPU_WATCHPOINT_MAX_REGION_SIZE 0x40 // bytes
/*-------------------------- DIGITAL SIGNATURE CAPS ----------------------------------------*/
/** The maximum length of a Digital Signature in bits. */
#define SOC_DS_SIGNATURE_MAX_BIT_LEN (4096)
/** Initialization vector (IV) length for the RSA key parameter message digest (MD) in bytes. */
#define SOC_DS_KEY_PARAM_MD_IV_LENGTH (16)
/** Maximum wait time for DS parameter decryption key. If overdue, then key error.
See TRM DS chapter for more details */
#define SOC_DS_KEY_CHECK_MAX_WAIT_US (1100)
/*-------------------------- DAC CAPS ----------------------------------------*/
#define SOC_DAC_CHAN_NUM 2
#define SOC_DAC_RESOLUTION 8 // DAC resolution ratio 8 bit
+3
View File
@@ -299,6 +299,9 @@ INPUT = \
$(PROJECT_PATH)/components/mbedtls/esp_crt_bundle/include/esp_crt_bundle.h \
$(PROJECT_PATH)/components/mbedtls/port/psa_driver/include/psa_crypto_driver_esp_ecdsa_contexts.h \
$(PROJECT_PATH)/components/mbedtls/port/psa_driver/include/psa_crypto_driver_esp_hmac_opaque_contexts.h \
$(PROJECT_PATH)/components/mbedtls/port/psa_driver/include/psa_crypto_driver_esp_rsa_ds_contexts.h \
$(PROJECT_PATH)/components/mbedtls/port/psa_driver/include/psa_crypto_driver_esp_sha_contexts.h \
$(PROJECT_PATH)/components/mbedtls/port/psa_driver/include/psa_crypto_driver_esp_aes_contexts.h \
$(PROJECT_PATH)/components/nvs_flash/include/nvs_flash.h \
$(PROJECT_PATH)/components/nvs_flash/include/nvs.h \
$(PROJECT_PATH)/components/nvs_flash/include/nvs_bootloader.h \