#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <wolfssl/wolfcrypt/settings.h>
#if defined(WOLFSSL_ESPIDF)
#include "sdkconfig.h"
#include <wolfssl/wolfcrypt/port/Espressif/esp32-crypt.h>
#if !defined(NO_SHA) || !defined(NO_SHA256) || defined(WC_SHA384) || \
defined(WC_SHA512)
#if defined(WOLFSSL_ESP32_CRYPT) && \
!defined(NO_WOLFSSL_ESP32_CRYPT_HASH)
#if defined(CONFIG_IDF_TARGET_ESP32C2) || \
defined(CONFIG_IDF_TARGET_ESP8684) || \
defined(CONFIG_IDF_TARGET_ESP32C3) || \
defined(CONFIG_IDF_TARGET_ESP32C6)
#include <hal/sha_hal.h>
#include <hal/sha_ll.h>
#include <hal/clk_gate_ll.h>
#if ESP_IDF_VERSION_MAJOR >= 6
#include "sha/sha_core.h"
#endif
#elif defined(CONFIG_IDF_TARGET_ESP32) || \
defined(CONFIG_IDF_TARGET_ESP32S2) || \
defined(CONFIG_IDF_TARGET_ESP32S3)
#include <hal/clk_gate_ll.h>
#else
#include <hal/clk_gate_ll.h>
#endif
#include <wolfssl/wolfcrypt/logging.h>
#include <wolfssl/wolfcrypt/sha.h>
#include <wolfssl/wolfcrypt/sha256.h>
#include <wolfssl/wolfcrypt/sha512.h>
#include "wolfssl/wolfcrypt/port/Espressif/esp32-crypt.h"
#include "wolfssl/wolfcrypt/error-crypt.h"
#ifdef NO_INLINE
#include <wolfssl/wolfcrypt/misc.h>
#else
#define WOLFSSL_MISC_INCLUDED
#include <wolfcrypt/src/misc.c>
#endif
#define WC_UNKNOWN_SHA (-1)
#define WC_ESP_MAX_IDLE_WAIT 10000
static const char* TAG = "wolf_hw_sha";
#if defined(CONFIG_IDF_TARGET_ESP32C2) || \
defined(CONFIG_IDF_TARGET_ESP8684) || \
defined(CONFIG_IDF_TARGET_ESP32C3) || \
defined(CONFIG_IDF_TARGET_ESP32C6)
const static word32 ** _active_digest_address = 0;
#endif
#ifdef NO_SHA
#define WC_SHA_DIGEST_SIZE 20
#endif
#if defined(DEBUG_WOLFSSL)
static int this_block_num = 0;
#endif
#if defined(SINGLE_THREADED)
static int InUse = 0;
#else
static wolfSSL_Mutex sha_mutex = NULL;
#endif
#ifdef WOLFSSL_DEBUG_MUTEX
#ifdef WOLFSSL_TEST_STRAY
#define WOLFSSL_TEST_STRAY_INJECT (esp_sha_call_count() == 10)
#else
#define WOLFSSL_TEST_STRAY 0
#define WOLFSSL_TEST_STRAY_INJECT 0
#endif
#endif
#ifdef WOLFSSL_HW_METRICS
static unsigned long esp_sha_hw_copy_ct = 0;
static unsigned long esp_sha1_hw_usage_ct = 0;
static unsigned long esp_sha1_sw_fallback_usage_ct = 0;
static unsigned long esp_sha_reverse_words_ct = 0;
static unsigned long esp_sha1_hw_hash_usage_ct = 0;
static unsigned long esp_sha2_224_hw_hash_usage_ct = 0;
static unsigned long esp_sha2_256_hw_hash_usage_ct = 0;
static unsigned long esp_sha256_sw_fallback_usage_ct = 0;
static unsigned long esp_byte_reversal_checks_ct = 0;
static unsigned long esp_byte_reversal_needed_ct = 0;
#endif
static uintptr_t mutex_ctx_owner = NULLPTR;
#if (defined(ESP_MONITOR_HW_TASK_LOCK) && !defined(SINGLE_THREADED)) \
|| defined(WOLFSSL_DEBUG_MUTEX)
static portMUX_TYPE sha_crit_sect = portMUX_INITIALIZER_UNLOCKED;
#endif
#if defined(ESP_MONITOR_HW_TASK_LOCK) || !defined(SINGLE_THREADED)
#ifdef SINGLE_THREADED
uintptr_t esp_sha_mutex_ctx_owner(void)
{
return mutex_ctx_owner;
}
uintptr_t esp_sha_mutex_ctx_owner_set(uintptr_t new_mutex_ctx_owner) {
mutex_ctx_owner = new_mutex_ctx_owner;
return new_mutex_ctx_owner;
}
uintptr_t esp_sha_mutex_ctx_owner_clear(void) {
return esp_sha_mutex_ctx_owner_set(NULLPTR);
}
#else
#if defined(ESP_MONITOR_HW_TASK_LOCK) && !defined(SINGLE_THREADED)
static TaskHandle_t mutex_ctx_task = NULL;
#endif
uintptr_t esp_sha_mutex_ctx_owner(void)
{
uintptr_t ret = 0;
taskENTER_CRITICAL(&sha_crit_sect);
{
ret = mutex_ctx_owner;
}
taskEXIT_CRITICAL(&sha_crit_sect);
return ret;
};
uintptr_t esp_sha_mutex_ctx_owner_set(uintptr_t new_mutex_ctx_owner)
{
taskENTER_CRITICAL(&sha_crit_sect);
{
mutex_ctx_owner = new_mutex_ctx_owner;
}
taskEXIT_CRITICAL(&sha_crit_sect);
return new_mutex_ctx_owner;
};
uintptr_t esp_sha_mutex_ctx_owner_clear(void) {
return esp_sha_mutex_ctx_owner_set(NULLPTR);
}
#endif
#ifdef WOLFSSL_DEBUG_MUTEX
WC_ESP32SHA* stray_ctx;
static int _sha_lock_count = 0;
static int _sha_call_count = 0;
int esp_sha_call_count(void)
{
return _sha_call_count;
}
int esp_sha_lock_count(void)
{
return _sha_lock_count;
}
#endif
#endif
int esp_set_hw(WC_ESP32SHA* ctx)
{
int ret = ESP_FAIL;
if ((uintptr_t)ctx == mutex_ctx_owner || mutex_ctx_owner == NULLPTR) {
ESP_LOGV(TAG, "Initializing current mutext owner!");
if (esp_sha_hw_islocked(ctx)) {
ESP_LOGV(TAG, "esp_set_hw already locked: 0x%x", (intptr_t)ctx);
}
ctx->mode = ESP32_SHA_HW;
#if defined(ESP_MONITOR_HW_TASK_LOCK) || !defined(SINGLE_THREADED)
mutex_ctx_owner = esp_sha_mutex_ctx_owner_set((uintptr_t)ctx);
#else
mutex_ctx_owner = (uintptr_t)ctx;
#endif
ret = ESP_OK;
}
else {
ESP_LOGV(TAG, "esp_sha_init_ctx HW for non-owner 0x%x", (intptr_t)ctx);
}
return ret;
}
int esp_sha_need_byte_reversal(WC_ESP32SHA* ctx)
{
int ret = 1;
CTX_STACK_CHECK(ctx);
#if defined(CONFIG_IDF_TARGET_ESP32C2) || \
defined(CONFIG_IDF_TARGET_ESP8684) || \
defined(CONFIG_IDF_TARGET_ESP32C3) || \
defined(CONFIG_IDF_TARGET_ESP32C6)
if (ctx == NULL) {
ESP_LOGE(TAG, " ctx is null");
}
else {
#ifdef WOLFSSL_HW_METRICS
{
esp_byte_reversal_checks_ct++;
}
#endif
if (ctx->mode == ESP32_SHA_HW) {
ESP_LOGV(TAG, " No reversal, ESP32_SHA_HW");
ret = 0;
}
else {
ret = 1;
ESP_LOGV(TAG, " Need byte reversal, %d", ctx->mode);
#ifdef WOLFSSL_HW_METRICS
{
esp_byte_reversal_needed_ct++;
}
#endif
if (ctx->mode == ESP32_SHA_INIT) {
ESP_LOGW(TAG, "esp_sha_need_byte_reversal during init?");
ESP_LOGW(TAG, "forgot to try HW lock first?");
}
}
}
#else
#endif
CTX_STACK_CHECK(ctx);
return ret;
}
int esp_sha_init(WC_ESP32SHA* ctx, enum wc_HashType hash_type)
{
int ret = ESP_OK;
#ifdef DEBUG_WOLFSSL_SHA_MUTEX
ESP_LOGV(TAG, "\n\nesp_sha_init for ctx %p\n\n", ctx);
#endif
if (ctx == NULL) {
return ESP_FAIL;
}
#if defined(WOLFSSL_STACK_CHECK)
ctx->first_word = 0;
ctx->last_word = 0;
#endif
CTX_STACK_CHECK(ctx);
ret = esp_sha_init_ctx(ctx);
#if defined(CONFIG_IDF_TARGET_ESP32) || \
defined(CONFIG_IDF_TARGET_ESP32S2) || \
defined(CONFIG_IDF_TARGET_ESP32S3)
switch (hash_type) {
#ifndef NO_SHA
case WC_HASH_TYPE_SHA:
ctx->sha_type = SHA1;
break;
#endif
case WC_HASH_TYPE_SHA224:
#if defined(CONFIG_IDF_TARGET_ESP32S2) || \
defined(CONFIG_IDF_TARGET_ESP32S3)
ctx->sha_type = SHA2_224;
#else
ctx->mode = ESP32_SHA_SW;
#endif
break;
case WC_HASH_TYPE_SHA256:
ctx->sha_type = SHA2_256;
break;
#if defined(CONFIG_IDF_TARGET_ESP32S2) || \
defined(CONFIG_IDF_TARGET_ESP32S3)
case WC_HASH_TYPE_SHA384:
ctx->mode = ESP32_SHA_SW;
break;
#else
case WC_HASH_TYPE_SHA384:
ctx->sha_type = SHA2_384;
break;
#endif
case WC_HASH_TYPE_SHA512:
ctx->sha_type = SHA2_512;
break;
#ifndef WOLFSSL_NOSHA512_224
case WC_HASH_TYPE_SHA512_224:
ctx->mode = ESP32_SHA_SW;
break;
#endif
#ifndef WOLFSSL_NOSHA512_256
case WC_HASH_TYPE_SHA512_256:
ctx->mode = ESP32_SHA_SW;
break;
#endif
default:
ctx->mode = ESP32_SHA_SW;
ESP_LOGW(TAG, "Unexpected hash_type in esp_sha_init");
break;
}
#elif defined(CONFIG_IDF_TARGET_ESP32C2) || \
defined(CONFIG_IDF_TARGET_ESP8684) || \
defined(CONFIG_IDF_TARGET_ESP32C3) || \
defined(CONFIG_IDF_TARGET_ESP32C6)
switch (hash_type) {
#ifndef NO_SHA
case WC_HASH_TYPE_SHA:
ctx->sha_type = SHA1;
break;
#endif
case WC_HASH_TYPE_SHA224:
ctx->sha_type = SHA2_224;
break;
case WC_HASH_TYPE_SHA256:
ctx->sha_type = SHA2_256;
break;
default:
ctx->mode = ESP32_SHA_SW;
ESP_LOGW(TAG, "Unsupported hash_type = %d in esp_sha_init, "
"falling back to SW", hash_type);
break;
}
#else
ESP_LOGW(TAG, "SW Fallback; CONFIG_IDF_TARGET = %s", CONFIG_IDF_TARGET);
ctx->mode = ESP32_SHA_SW;
#endif
CTX_STACK_CHECK(ctx);
return ret;
}
int esp_sha_init_ctx(WC_ESP32SHA* ctx)
{
CTX_STACK_CHECK(ctx);
ctx->mode = ESP32_SHA_INIT;
ctx->sha_type = WC_UNKNOWN_SHA;
ctx->isfirstblock = 1;
ctx->lockDepth = 0;
#if defined(MUTEX_DURING_INIT)
if ((uintptr_t)ctx == mutex_ctx_owner || mutex_ctx_owner == NULLPTR) {
ESP_LOGV(TAG, "Initializing current mutext owner!");
if (esp_sha_hw_islocked(ctx)) {
esp_sha_hw_unlock(ctx);
}
mutex_ctx_owner = esp_sha_mutex_ctx_owner_set((uintptr_t)ctx);
}
else {
ESP_LOGI(TAG, "MUTEX_DURING_INIT esp_sha_init_ctx for non-owner: "
"0x%x", (intptr_t)ctx);
}
#endif
CTX_STACK_CHECK(ctx);
return ESP_OK;
}
#ifndef NO_SHA
int esp_sha_ctx_copy(struct wc_Sha* src, struct wc_Sha* dst)
{
int ret;
if (src->ctx.mode == ESP32_SHA_HW) {
ESP_LOGV(TAG, "esp_sha_ctx_copy esp_sha_digest_process");
#ifdef WOLFSSL_HW_METRICS
{
esp_sha_hw_copy_ct++;
}
#endif
ret = esp_sha_digest_process(dst, 0);
if (ret == 0) {
ret = esp_sha_init(&(dst->ctx), WC_HASH_TYPE_SHA);
if (ret != 0) {
ESP_LOGE(TAG, "Error during esp_sha_ctx_copy "
"in esp_sha_init.");
}
dst->ctx.mode = ESP32_SHA_SW;
}
else {
ESP_LOGE(TAG, "Error during esp_sha_ctx_copy "
"in esp_sha_digest_process.");
}
if (dst->ctx.mode == ESP32_SHA_SW) {
#if defined(CONFIG_IDF_TARGET_ESP32C2) || \
defined(CONFIG_IDF_TARGET_ESP8684) || \
defined(CONFIG_IDF_TARGET_ESP32C3) || \
defined(CONFIG_IDF_TARGET_ESP32C6)
ByteReverseWords(dst->digest, dst->digest, WC_SHA_DIGEST_SIZE);
#ifdef WOLFSSL_HW_METRICS
esp_sha_reverse_words_ct++;
#endif
#endif
ESP_LOGV(TAG, "Confirmed SHA Copy set to SW");
}
else {
ESP_LOGW(TAG, "SHA Copy NOT set to SW from %d", dst->ctx.mode);
}
}
else {
dst->ctx.initializer = (uintptr_t)&(dst->ctx);
#if defined(ESP_MONITOR_HW_TASK_LOCK) && !defined(SINGLE_THREADED)
{
dst->ctx.task_owner = 0;
}
#endif
ret = 0;
}
return ret;
}
#endif
#ifndef NO_WOLFSSL_ESP32_CRYPT_HASH_SHA224
int esp_sha224_ctx_copy(struct wc_Sha256* src, struct wc_Sha256* dst)
{
dst->ctx.initializer = (uintptr_t)&dst->ctx;
#if defined(ESP_MONITOR_HW_TASK_LOCK) && !defined(SINGLE_THREADED)
{
dst->ctx.task_owner = 0;
}
#endif
dst->ctx.mode = ESP32_SHA_SW;
return ESP_OK;
}
#endif
#ifndef NO_WOLFSSL_ESP32_CRYPT_HASH_SHA256
int esp_sha256_ctx_copy(struct wc_Sha256* src, struct wc_Sha256* dst)
{
int ret;
if (src->ctx.mode == ESP32_SHA_HW) {
#ifdef WOLFSSL_DEBUG_MUTEX
{
ESP_LOGI(TAG, "esp_sha256_ctx_copy esp_sha512_digest_process");
}
#endif
ret = esp_sha256_digest_process(dst, FALSE);
if (ret == ESP_OK) {
ret = esp_sha_init(&(dst->ctx), WC_HASH_TYPE_SHA256);
dst->ctx.mode = ESP32_SHA_SW;
}
else {
ESP_LOGE(TAG, "Unexpected error during sha256 ctx copy: %d", ret);
}
if (dst->ctx.mode == ESP32_SHA_SW) {
#if defined(CONFIG_IDF_TARGET_ESP32C2) || \
defined(CONFIG_IDF_TARGET_ESP8684) || \
defined(CONFIG_IDF_TARGET_ESP32C3) || \
defined(CONFIG_IDF_TARGET_ESP32C6)
{
ByteReverseWords(dst->digest,
dst->digest,
WC_SHA256_DIGEST_SIZE);
}
#endif
ESP_LOGV(TAG, "Confirmed wc_Sha256 Copy set to SW");
}
else {
ESP_LOGW(TAG, "wc_Sha256 Copy (mode = %d) set to SW",
dst->ctx.mode);
dst->ctx.mode = ESP32_SHA_SW;
}
}
else {
ret = ESP_OK;
dst->ctx.initializer = (uintptr_t)&(dst->ctx);
#if defined(ESP_MONITOR_HW_TASK_LOCK) && !defined(SINGLE_THREADED)
{
dst->ctx.task_owner = 0;
}
#endif
}
return ret;
}
#endif
#if !(defined(NO_WOLFSSL_ESP32_CRYPT_HASH_SHA384) && \
defined(NO_WOLFSSL_ESP32_CRYPT_HASH_SHA512) \
) && \
(defined(WOLFSSL_SHA384) || defined(WOLFSSL_SHA512))
int esp_sha384_ctx_copy(struct wc_Sha512* src, struct wc_Sha512* dst)
{
int ret = 0;
#if defined(CONFIG_IDF_TARGET_ESP32C2) || \
defined(CONFIG_IDF_TARGET_ESP8684) || \
defined(CONFIG_IDF_TARGET_ESP32C3) || \
defined(CONFIG_IDF_TARGET_ESP32C6)
{
ESP_LOGW(TAG, "Warning: esp_sha384_ctx_copy() called for %s!",
CONFIG_IDF_TARGET);
ESP_LOGW(TAG, "There's no SHA384 HW for this CONFIG_IDF_TARGET");
}
#else
if (src->ctx.mode == ESP32_SHA_HW) {
ESP_LOGV(TAG, "esp_sha384_ctx_copy esp_sha512_digest_process");
ret = esp_sha512_digest_process(dst, 0);
if (ret == 0) {
dst->ctx.mode = ESP32_SHA_HW_COPY;
ret = esp_sha_init(&(dst->ctx), WC_HASH_TYPE_SHA384);
if (ret != 0) {
ESP_LOGE(TAG, "Error during esp_sha384_ctx_copy "
"in esp_sha_init.");
}
}
else {
ESP_LOGE(TAG, "Error during esp_sha384_ctx_copy "
"in esp_sha512_digest_process.");
}
if (dst->ctx.mode == ESP32_SHA_SW) {
ESP_LOGV(TAG, "Confirmed wc_Sha512 Copy set to SW");
}
else {
ESP_LOGW(TAG, "wc_Sha512 Copy NOT set to SW");
}
}
else {
ret = 0;
dst->ctx.initializer = (uintptr_t)&(dst->ctx);
#if defined(ESP_MONITOR_HW_TASK_LOCK) && !defined(SINGLE_THREADED)
{
dst->ctx.task_owner = 0;
}
#endif
}
#endif
return ret;
}
#endif
#if !(defined(NO_WOLFSSL_ESP32_CRYPT_HASH_SHA384) && \
defined(NO_WOLFSSL_ESP32_CRYPT_HASH_SHA512) \
) && \
(defined(WOLFSSL_SHA384) || defined(WOLFSSL_SHA512))
int esp_sha512_ctx_copy(struct wc_Sha512* src, struct wc_Sha512* dst)
{
int ret = ESP_OK;
#if defined(CONFIG_IDF_TARGET_ESP32C2) || \
defined(CONFIG_IDF_TARGET_ESP8684) || \
defined(CONFIG_IDF_TARGET_ESP32C3) || \
defined(CONFIG_IDF_TARGET_ESP32C6)
#elif defined(CONFIG_IDF_TARGET_ESP32) || \
defined(CONFIG_IDF_TARGET_ESP32S2) || \
defined(CONFIG_IDF_TARGET_ESP32S3)
if (src->ctx.mode == ESP32_SHA_HW) {
ESP_LOGV(TAG, "esp_sha512_ctx_copy esp_sha512_digest_process");
ret = esp_sha512_digest_process(dst, FALSE);
if (ret == ESP_OK) {
dst->ctx.mode = ESP32_SHA_HW_COPY;
ret = esp_sha_init(&(dst->ctx), WC_HASH_TYPE_SHA512);
}
if (dst->ctx.mode == ESP32_SHA_SW) {
ESP_LOGV(TAG, "Confirmed wc_Sha512 Copy set to SW");
}
else {
ESP_LOGW(TAG, "wc_Sha512 Copy set to SW");
dst->ctx.mode = ESP32_SHA_SW;
}
}
else {
ret = ESP_OK;
#if !defined(CONFIG_IDF_TARGET_ESP32C2) && \
!defined(CONFIG_IDF_TARGET_ESP32C3) && \
!defined(CONFIG_IDF_TARGET_ESP32C6)
dst->ctx.initializer = (uintptr_t)&(dst->ctx);
#endif
#if defined(ESP_MONITOR_HW_TASK_LOCK) && !defined(SINGLE_THREADED)
{
dst->ctx.task_owner = 0;
}
#endif
}
#endif
return ret;
}
#endif
static word32 wc_esp_sha_digest_size(WC_ESP_SHA_TYPE type)
{
int ret = 0;
ESP_LOGV(TAG, " esp_sha_digest_size");
#if CONFIG_IDF_TARGET_ARCH_RISCV
switch (type) {
#ifndef NO_SHA
case SHA1:
ret = WC_SHA_DIGEST_SIZE;
break;
#endif
#ifdef WOLFSSL_SHA224
case SHA2_224:
ret = WC_SHA224_DIGEST_SIZE;
break;
#endif
#ifndef NO_SHA256
case SHA2_256:
ret = WC_SHA256_DIGEST_SIZE;
break;
#endif
default:
ESP_LOGE(TAG, "Bad SHA type in wc_esp_sha_digest_size");
ret = 0;
break;
}
#else
switch (type) {
#ifndef NO_SHA
case SHA1:
ret = WC_SHA_DIGEST_SIZE;
break;
#endif
#ifdef WOLFSSL_SHA224
#if defined(CONFIG_IDF_TARGET_ESP32S2) || \
defined(CONFIG_IDF_TARGET_ESP32S3)
case SHA2_224:
ret = WC_SHA224_DIGEST_SIZE;
break;
#endif
#endif
#ifndef NO_SHA256
case SHA2_256:
ret = WC_SHA256_DIGEST_SIZE;
break;
#endif
#ifdef WOLFSSL_SHA384
case SHA2_384:
ret = WC_SHA384_DIGEST_SIZE;
break;
#endif
#ifdef WOLFSSL_SHA512
case SHA2_512:
ret = WC_SHA512_DIGEST_SIZE;
break;
#endif
default:
ESP_LOGE(TAG, "Bad SHA type in wc_esp_sha_digest_size");
ret = 0;
break;
}
#endif
return ret;
}
static int wc_esp_wait_until_idle(void)
{
int ret = 0;
int loop_ct = WC_ESP_MAX_IDLE_WAIT;
#if defined(CONFIG_IDF_TARGET_ESP32C2) || \
defined(CONFIG_IDF_TARGET_ESP8684) || \
defined(CONFIG_IDF_TARGET_ESP32C3) || \
defined(CONFIG_IDF_TARGET_ESP32C6)
while ((sha_ll_busy() == 1) && (loop_ct > 0)) {
loop_ct--;
}
#elif defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3)
while (REG_READ(SHA_BUSY_REG)) {
}
#else
while ((DPORT_REG_READ(SHA_1_BUSY_REG) != 0) ||
(DPORT_REG_READ(SHA_256_BUSY_REG) != 0) ||
(DPORT_REG_READ(SHA_384_BUSY_REG) != 0) ||
(DPORT_REG_READ(SHA_512_BUSY_REG) != 0)) {
}
#endif
if (loop_ct <= 0)
{
ESP_LOGW(TAG, "Too long to exit wc_esp_wait_until_idle");
}
return ret;
}
int esp_unroll_sha_module_enable(WC_ESP32SHA* ctx)
{
int ret = 0;
int actual_unroll_count = 0;
int max_unroll_count = 1000;
#if defined(CONFIG_IDF_TARGET_ESP32)
word32 this_sha_mask;
#endif
CTX_STACK_CHECK(ctx);
if (ctx == NULL) {
ESP_LOGE(TAG, "esp_unroll_sha_module_enable called with null ctx.");
return BAD_FUNC_ARG;
}
#if defined(CONFIG_IDF_TARGET_ESP32C2) || \
defined(CONFIG_IDF_TARGET_ESP8684) || \
defined(CONFIG_IDF_TARGET_ESP32C3) || \
defined(CONFIG_IDF_TARGET_ESP32C6)
(void)max_unroll_count;
(void)_active_digest_address;
ets_sha_disable();
#else
#if defined(CONFIG_IDF_TARGET_ESP32S2) ||defined(CONFIG_IDF_TARGET_ESP32S3)
while (periph_ll_periph_enabled(PERIPH_SHA_MODULE)) {
#else
this_sha_mask = periph_ll_get_clk_en_mask(PERIPH_SHA_MODULE);
asm volatile("memw");
while ((this_sha_mask & *(uint32_t*)DPORT_PERI_CLK_EN_REG) != 0) {
#endif
periph_module_disable(PERIPH_SHA_MODULE);
asm volatile("memw");
actual_unroll_count++;
ESP_LOGW(TAG, "unroll not yet successful. try #%d",
actual_unroll_count);
if (actual_unroll_count > max_unroll_count) {
ret = ESP_FAIL;
break;
}
}
#endif
if (ret == 0) {
if (ctx->lockDepth != actual_unroll_count) {
ESP_LOGW(TAG, "warning lockDepth mismatch: %d", ctx->lockDepth);
if (actual_unroll_count == 0 && ctx->lockDepth > 2) {
ESP_LOGW(TAG, "Large lockDepth discrepancy often indicates "
"stack overflow or memory corruption");
}
}
ctx->lockDepth = 0;
ctx->mode = ESP32_SHA_INIT;
}
else {
ESP_LOGE(TAG, "Failed to unroll after %d attempts.",
actual_unroll_count);
ESP_LOGI(TAG, "Setting ctx->mode = ESP32_SHA_SW");
ctx->mode = ESP32_SHA_SW;
}
CTX_STACK_CHECK(ctx);
return ret;
}
uintptr_t esp_sha_set_stray(WC_ESP32SHA* ctx)
{
uintptr_t ret = 0;
CTX_STACK_CHECK(ctx);
#ifdef WOLFSSL_DEBUG_MUTEX
stray_ctx = ctx;
ret = (uintptr_t)stray_ctx;
#endif
CTX_STACK_CHECK(ctx);
return ret;
}
int esp_sha_hw_in_use()
{
int ret;
#ifdef SINGLE_THREADED
ret = InUse;
#else
ret = (mutex_ctx_owner != NULLPTR);
ESP_LOGV(TAG, "mutex_ctx_owner is 0x%x", mutex_ctx_owner);
#endif
ESP_LOGV(TAG, "esp_sha_hw_in_use is %d", ret);
return ret;
}
uintptr_t esp_sha_hw_islocked(WC_ESP32SHA* ctx)
{
uintptr_t ret = 0;
#if !defined(WOLFSSL_DEBUG_MUTEX) && !defined(SINGLE_THREADED)
TaskHandle_t mutexHolder;
#endif
CTX_STACK_CHECK(ctx);
#ifdef WOLFSSL_DEBUG_MUTEX
ret = esp_sha_mutex_ctx_owner();
if (ctx == 0) {
ESP_LOGV(TAG, "ctx == 0; Not checking if a given ctx has the lock");
}
else {
if (ret == (uintptr_t)ctx->initializer) {
ESP_LOGV(TAG, "confirmed this object is the owner");
}
else {
ESP_LOGV(TAG, "this object is not the lock owner");
}
}
#else
#ifdef SINGLE_THREADED
{
ret = InUse;
}
#else
{
if (sha_mutex == NULL) {
mutexHolder = NULL;
}
else {
mutexHolder = xSemaphoreGetMutexHolder(sha_mutex);
}
if (mutexHolder == NULL) {
ESP_LOGV(TAG, "multi-threaded esp_mp_hw_islocked = false");
ret = 0;
}
else {
ESP_LOGV(TAG, "multi-threaded esp_mp_hw_islocked = true");
ret = mutex_ctx_owner;
}
if (NULLPTR == mutex_ctx_owner) {
ESP_LOGV(TAG, "not esp_sha_hw_islocked, mutex_ctx_owner is Null");
}
else {
ESP_LOGV(TAG, "esp_sha_hw_islocked for 0x%x", mutex_ctx_owner);
}
}
#endif
return ret;
#endif
#ifdef WOLFSSL_DEBUG_MUTEX
if (ret == 0) {
ESP_LOGV(TAG, ">> NOT LOCKED esp_sha_hw_islocked");
}
else {
ESP_LOGV(TAG, ">> LOCKED esp_sha_hw_islocked for %x",
(int)esp_sha_mutex_ctx_owner());
}
#endif
CTX_STACK_CHECK(ctx);
return ret;
}
uintptr_t esp_sha_release_unfinished_lock(WC_ESP32SHA* ctx)
{
uintptr_t ret = 0;
CTX_STACK_CHECK(ctx);
ret = esp_sha_hw_islocked(ctx);
if (ret == 0) {
#ifdef WOLFSSL_ESP32_HW_LOCK_DEBUG
ESP_LOGV(TAG, "No unfinished lock to clean up for ctx %p.", ctx);
#endif
}
else {
#ifdef WOLFSSL_ESP32_HW_LOCK_DEBUG
ESP_LOGI(TAG, "Unfinished lock clean up: %p.", ctx);
#endif
if (ret == (uintptr_t)ctx) {
if (ret == ctx->initializer) {
ESP_LOGW(TAG, "New mutex_ctx_owner = NULL");
#ifdef ESP_MONITOR_HW_TASK_LOCK
{
esp_sha_mutex_ctx_owner_clear();
}
#endif
}
else {
#if defined(WOLFSSL_DEBUG_MUTEX) || defined(WOLFSSL_ESP32_HW_LOCK_DEBUG)
if (ctx->initializer == 0) {
ESP_LOGW(TAG, "Release already finished lock for %x ?",
ctx->initializer);
}
else {
ESP_LOGW(TAG, "ERROR: Release unfinished lock for %x but "
"found %x", ret, ctx->initializer);
}
#endif
}
#ifdef WOLFSSL_DEBUG_MUTEX
ESP_LOGW(TAG, "\n>>>> esp_sha_release_unfinished_lock %x\n", ret);
#endif
#ifdef SINGLE_THREADED
{
ret = esp_sha_hw_unlock(ctx);
}
#else
#if defined(ESP_MONITOR_HW_TASK_LOCK)
{
if (ctx->task_owner == xTaskGetCurrentTaskHandle()) {
ESP_LOGV(TAG, "esp_sha_hw_unlock!");
}
else {
ctx->mode = ESP32_SHA_FREED;
ESP_LOGV(TAG, "ESP32_SHA_FREED");
}
}
#else
ret = esp_sha_hw_unlock(ctx);
#endif
#endif
}
}
CTX_STACK_CHECK(ctx);
if (ctx->mode != ESP32_SHA_INIT) {
#if defined(WOLFSSL_ESP32_HW_LOCK_DEBUG)
ESP_LOGW(TAG, "esp_sha_release_unfinished_lock mode = %d", ctx->mode);
#endif
if (ctx->mode == ESP32_SHA_HW) {
#if defined(DEBUG_WOLFSSL_ESP32_UNFINISHED_HW)
ESP_LOGW(TAG, "esp_sha_release_unfinished_lock HW!");
#endif
}
}
return ret;
}
int esp_sha_try_hw_lock(WC_ESP32SHA* ctx)
{
int ret = 0;
#if defined(SINGLE_THREADED)
#else
uintptr_t this_mutex_owner;
this_mutex_owner = esp_sha_mutex_ctx_owner();
#endif
CTX_STACK_CHECK(ctx);
#ifdef WOLFSSL_ESP32_HW_LOCK_DEBUG
ESP_LOGI(TAG, "enter esp_sha_hw_lock for %x, initializer %x",
(uintptr_t)ctx, (uintptr_t)ctx->initializer);
#endif
#ifdef WOLFSSL_DEBUG_MUTEX
taskENTER_CRITICAL(&sha_crit_sect);
{
_sha_call_count++;
}
taskEXIT_CRITICAL(&sha_crit_sect);
#endif
if (ctx == NULL) {
ESP_LOGE(TAG, " esp_sha_try_hw_lock called with NULL ctx");
return BAD_FUNC_ARG;
}
#if defined(SINGLE_THREADED)
if (ctx->mode == ESP32_SHA_INIT) {
if (InUse) {
ctx->mode = ESP32_SHA_SW;
}
else {
ctx->mode = ESP32_SHA_HW;
InUse = 1;
#ifdef WOLFSSL_DEBUG_MUTEX
ESP_LOGW(TAG, "\n\nHW in use\n\n");
#endif
}
ret = ESP_OK;
}
else {
ESP_LOGE(TAG, "unexpected error in esp_sha_try_hw_lock.");
return ESP_FAIL;
}
#else
if (sha_mutex == NULL) {
ESP_LOGV(TAG, "Initializing sha_mutex");
ret = esp_CryptHwMutexInit(&sha_mutex);
if (ret == 0) {
ESP_LOGV(TAG, "esp_CryptHwMutexInit sha_mutex init success.");
esp_sha_mutex_ctx_owner_clear();
#ifdef WOLFSSL_DEBUG_MUTEX
{
ret = esp_CryptHwMutexLock(&sha_mutex, (TickType_t)0);
if (ret == ESP_OK) {
ret = esp_CryptHwMutexUnLock(&sha_mutex);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "esp_CryptHwMutexInit fail init lock.");
}
}
else {
ESP_LOGE(TAG, "esp_CryptHwMutexInit fail init unlock.");
}
}
#endif
}
else {
ESP_LOGE(TAG, "esp_CryptHwMutexInit sha_mutex failed.");
#ifdef WOLFSSL_DEBUG_MUTEX
{
ESP_LOGV(TAG, "Current mutext owner = %x", this_mutex_owner);
}
#endif
sha_mutex = NULL;
ESP_LOGV(TAG, "Revert to ctx->mode = ESP32_SHA_SW.");
ctx->mode = ESP32_SHA_SW;
return ESP_OK;
}
}
#if defined(ESP_MONITOR_HW_TASK_LOCK) || \
(defined(WOLFSSL_DEBUG_MUTEX) && WOLFSSL_DEBUG_MUTEX)
if (mutex_ctx_task == 0 || mutex_ctx_owner == 0) {
}
else {
if (mutex_ctx_task == xTaskGetCurrentTaskHandle()) {
ESP_LOGV(TAG, "Found mutex_ctx_task");
if (((WC_ESP32SHA*)mutex_ctx_owner)->mode == ESP32_SHA_FREED) {
ESP_LOGW(TAG, "ESP32_SHA_FREED unlocking mutex_ctx_task = %x"
" for mutex_ctx_owner = %x",
(uintptr_t)mutex_ctx_task,
(uintptr_t)this_mutex_owner);
}
else {
if (ctx->mode == ESP32_SHA_FREED) {
ESP_LOGW(TAG, "ESP32_SHA_FREED unlocking (disabled) "
"ctx = %x for ctx.initializer = %x",
(uintptr_t)ctx,
(uintptr_t)ctx->initializer);
}
else {
if (ctx->mode == ESP32_SHA_INIT) {
ESP_LOGV(TAG, "mutex_ctx_owner = 0x%x",
this_mutex_owner);
ESP_LOGV(TAG, "This ctx = 0x%x is ESP32_SHA_INIT",
(uintptr_t)ctx);
}
else {
ESP_LOGW(TAG, "Not Freed!");
}
}
}
}
else {
#ifdef WOLFSSL_ESP32_HW_LOCK_DEBUG
ESP_LOGW(TAG, "Warning: sha mutex unlock from unexpected task.");
ESP_LOGW(TAG, "Locking task: 0x%x", (word32)mutex_ctx_task);
ESP_LOGW(TAG, "This xTaskGetCurrentTaskHandle: 0x%x",
(word32)xTaskGetCurrentTaskHandle());
#endif
}
}
#endif
if (ctx->mode == ESP32_SHA_INIT) {
#ifdef WOLFSSL_ESP32_HW_LOCK_DEBUG
ESP_LOGI(TAG, "ESP32_SHA_INIT for %x, initializer %x\n",
(uintptr_t)ctx, (uintptr_t)ctx->initializer);
#endif
ESP_LOGV(TAG, "Init; release unfinished ESP32_SHA_INIT lock "
"for ctx 0x%x", (uintptr_t)ctx);
esp_sha_release_unfinished_lock(ctx);
if ((mutex_ctx_owner == NULLPTR) &&
esp_CryptHwMutexLock(&sha_mutex, (TickType_t)0) == ESP_OK) {
this_mutex_owner = (uintptr_t)ctx;
esp_sha_mutex_ctx_owner_set(this_mutex_owner);
ESP_LOGV(TAG, "Assigned mutex_ctx_owner to 0x%x", this_mutex_owner);
#ifdef ESP_MONITOR_HW_TASK_LOCK
mutex_ctx_task = xTaskGetCurrentTaskHandle();
#endif
#ifdef WOLFSSL_DEBUG_MUTEX
if (WOLFSSL_TEST_STRAY_INJECT) {
ESP_LOGW(TAG, "Introducing SHA stray for testing");
taskENTER_CRITICAL(&sha_crit_sect);
{
(void)stray_ctx;
if (stray_ctx == NULL) {
}
else {
stray_ctx->initializer = (intptr_t)stray_ctx;
mutex_ctx_owner = (intptr_t)stray_ctx->initializer;
this_mutex_owner = mutex_ctx_owner;
}
}
taskEXIT_CRITICAL(&sha_crit_sect);
if (stray_ctx == NULL) {
ESP_LOGW(TAG, "WOLFSSL_DEBUG_MUTEX on, but stray_ctx "
"is NULL; are you running the peek task to "
"set the stay test?");
}
else {
ESP_LOGI(TAG, "%x", (uintptr_t)stray_ctx->initializer);
ESP_LOGI(TAG, "%x", (uintptr_t)&stray_ctx);
ESP_LOGW(TAG,
"\n\nLocking with stray\n\n"
"WOLFSSL_DEBUG_MUTEX call count 8, "
"ctx->mode = ESP32_SHA_SW %x\n\n",
this_mutex_owner);
#if defined(ESP_MONITOR_HW_TASK_LOCK) && !defined(SINGLE_THREADED)
ctx->task_owner = xTaskGetCurrentTaskHandle();
#endif
ctx->mode = ESP32_SHA_SW;
return ESP_OK;
}
}
#endif
#ifdef WOLFSSL_ESP32_HW_LOCK_DEBUG
ESP_LOGW(TAG, "Locking for ctx %x, current mutex_ctx_owner = %x",
(uintptr_t)&ctx, this_mutex_owner);
ESP_LOGI(TAG, "ctx->lockDepth = %d", ctx->lockDepth);
#endif
if (ctx->mode == ESP32_SHA_INIT) {
esp_set_hw(ctx);
}
#ifdef WOLFSSL_ESP32_HW_LOCK_DEBUG
ESP_LOGI(TAG, "Hardware Mode Active, lock depth = %d, for %x",
ctx->lockDepth, (uintptr_t)ctx->initializer);
#endif
#ifdef WOLFSSL_DEBUG_MUTEX
taskENTER_CRITICAL(&sha_crit_sect);
{
mutex_ctx_owner = (uintptr_t)ctx->initializer;
_sha_lock_count++;
}
taskEXIT_CRITICAL(&sha_crit_sect);
#endif
if (ctx->lockDepth > 0) {
ESP_LOGW(TAG, "WARNING: Hardware Mode "
"interesting lock depth = %d, for this %x",
ctx->lockDepth, (uintptr_t)ctx->initializer);
}
}
else {
if ((uintptr_t)ctx == this_mutex_owner) {
ESP_LOGV(TAG, "I'm the owner! 0x%x", (uintptr_t)ctx);
ctx->mode = ESP32_SHA_SW;
}
else {
#ifdef WOLFSSL_DEBUG_MUTEX
ESP_LOGW(TAG, "\nHardware in use by %x; "
"Mode REVERT to ESP32_SHA_SW for %x\n",
this_mutex_owner,
(uintptr_t)ctx->initializer);
ESP_LOGI(TAG, "Software Mode, lock depth = %d, for this %x",
ctx->lockDepth, (uintptr_t)ctx->initializer);
ESP_LOGI(TAG, "Current mutext owner = %x",
this_mutex_owner);
#endif
ESP_LOGV(TAG, "I'm not owner! 0x%x; owner = 0x%x",
(uintptr_t)ctx, mutex_ctx_owner);
if (this_mutex_owner) {
#ifdef WOLFSSL_DEBUG_MUTEX
ESP_LOGW(TAG, "revert to SW since mutex_ctx_owner = %x"
" but we are currently ctx = %x",
this_mutex_owner, (intptr_t)ctx);
#endif
}
else {
}
ESP_LOGV(TAG, "Set update ctx->mode = SW (from %d) for 0x%x",
ctx->mode, (uintptr_t)ctx );
ctx->mode = ESP32_SHA_SW;
}
return ESP_OK;
}
}
else {
ESP_LOGE(TAG, "unexpected error in esp_sha_try_hw_lock.");
return ESP_FAIL;
}
#endif
ESP_LOGV(TAG, "ctx->mode = %d", ctx->mode);
if ((ret == ESP_OK) && (ctx->mode == ESP32_SHA_HW)) {
ctx->lockDepth++;
#ifdef WOLFSSL_ESP32_HW_LOCK_DEBUG
{
ESP_LOGI(TAG, "1) Lock depth @ %d = %d for WC_ESP32SHA @ %0x\n",
__LINE__, ctx->lockDepth, (unsigned)ctx);
}
#endif
#if defined(CONFIG_IDF_TARGET_ESP32C2) || \
defined(CONFIG_IDF_TARGET_ESP8684) || \
defined(CONFIG_IDF_TARGET_ESP32C3) || \
defined(CONFIG_IDF_TARGET_ESP32C6)
{
ESP_LOGV(TAG, "ets_sha_enable for RISC-V");
ets_sha_enable();
}
#else
ESP_LOGV(TAG, "ets_sha_enable for Xtensa");
periph_module_enable(PERIPH_SHA_MODULE);
#endif
}
else {
#ifdef WOLFSSL_ESP32_CRYPT_DEBUG
if (ret == ESP_OK) {
ESP_LOGW(TAG, "Normal SHA Software fallback mode.");
}
else {
ESP_LOGW(TAG, "Warning: Unexpected Mode REVERT to ESP32_SHA_SW"
", err = %d", ret);
}
#endif
ctx->mode = ESP32_SHA_SW;
}
ESP_LOGV(TAG, "leave esp_sha_hw_lock");
CTX_STACK_CHECK(ctx);
return ret;
}
int esp_sha_hw_unlock(WC_ESP32SHA* ctx)
{
int ret = ESP_OK;
CTX_STACK_CHECK(ctx);
#ifdef WOLFSSL_ESP32_HW_LOCK_DEBUG
ESP_LOGV(TAG, "enter esp_sha_hw_unlock");
#endif
#ifdef WOLFSSL_ESP32_HW_LOCK_DEBUG
ESP_LOGI(TAG, "2) esp_sha_hw_unlock Lock depth @ %d = %d "
"for WC_ESP32SHA ctx @ %p\n",
__LINE__, ctx->lockDepth, ctx);
#endif
if (ctx->lockDepth > 0) {
#if defined(CONFIG_IDF_TARGET_ESP32C2) || \
defined(CONFIG_IDF_TARGET_ESP8684) || \
defined(CONFIG_IDF_TARGET_ESP32C3) || \
defined(CONFIG_IDF_TARGET_ESP32C6)
ets_sha_disable();
ESP_LOGV(TAG, "ets_sha_disable in esp_sha_hw_unlock()");
#else
periph_module_disable(PERIPH_SHA_MODULE);
#endif
ctx->lockDepth--;
}
else {
ESP_LOGW(TAG, "lockDepth <= 0; Disable SHA module skipped for %x",
(uintptr_t)ctx->initializer);
ctx->lockDepth = 0;
}
#if defined(ESP_MONITOR_HW_TASK_LOCK) && defined(WOLFSSL_ESP32_HW_LOCK_DEBUG)
ESP_LOGI(TAG, "3) esp_sha_hw_unlock Lock depth @ %d = %d "
"for WC_ESP32SHA @ %0x\n",
__LINE__, ctx->lockDepth, (uintptr_t)ctx);
#endif
if (0 != ctx->lockDepth) {
ESP_LOGE(TAG, "ERROR Non-zero lockDepth. Stray code lock?");
ret = ESP_FAIL;
}
else {
#if defined(SINGLE_THREADED)
#ifdef WOLFSSL_ESP32_HW_LOCK_DEBUG
{
ESP_LOGW(TAG, "HW released, not in use.");
}
#endif
InUse = 0;
#else
#ifdef WOLFSSL_ESP32_HW_LOCK_DEBUG
{
ESP_LOGW(TAG, "Unlocking for mutex_ctx_owner %x, from ctx 0x%x",
esp_sha_mutex_ctx_owner(), (uintptr_t)ctx);
ESP_LOGV(TAG, "&sha_mutex = %x", (intptr_t)&sha_mutex);
}
#endif
esp_CryptHwMutexUnLock(&sha_mutex);
#ifdef ESP_MONITOR_HW_TASK_LOCK
mutex_ctx_task = 0;
#endif
#endif
#ifdef WOLFSSL_DEBUG_MUTEX
taskENTER_CRITICAL(&sha_crit_sect);
{
mutex_ctx_owner = 0;
}
taskEXIT_CRITICAL(&sha_crit_sect);
#endif
}
#ifdef WOLFSSL_ESP32_HW_LOCK_DEBUG
ESP_LOGI(TAG, "leave esp_sha_hw_unlock, %x",
(uintptr_t)ctx->initializer);
#endif
CTX_STACK_CHECK(ctx);
return ret;
}
#if defined(CONFIG_IDF_TARGET_ESP32C2) || \
defined(CONFIG_IDF_TARGET_ESP8684) || \
defined(CONFIG_IDF_TARGET_ESP32C3) || \
defined(CONFIG_IDF_TARGET_ESP32C6)
#else
static int esp_sha_start_process(WC_ESP32SHA* sha)
{
int ret = ESP_OK;
#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3)
uint8_t HardwareAlgorithm;
#endif
if (sha == NULL) {
return BAD_FUNC_ARG;
}
CTX_STACK_CHECK(sha);
ESP_LOGV(TAG, " enter esp_sha_start_process");
#if defined(CONFIG_IDF_TARGET_ESP32C2) || \
defined(CONFIG_IDF_TARGET_ESP8684) || \
defined(CONFIG_IDF_TARGET_ESP32C3) || \
defined(CONFIG_IDF_TARGET_ESP32C6)
ESP_LOGV(TAG, "SHA1 SHA_START_REG");
if (sha->isfirstblock) {
sha_ll_start_block(SHA2_256);
sha->isfirstblock = 0;
ESP_LOGV(TAG, " set sha->isfirstblock = 0");
#if defined(DEBUG_WOLFSSL)
this_block_num = 1;
#endif
}
else {
sha_ll_continue_block(SHA2_256);
#if defined(DEBUG_WOLFSSL)
this_block_num++;
ESP_LOGV(TAG, " continue block #%d", this_block_num);
#endif
}
#elif defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3)
HardwareAlgorithm = 0;
switch (sha->sha_type) {
case SHA1:
HardwareAlgorithm = 0;
break;
case SHA2_224:
HardwareAlgorithm = 1;
break;
case SHA2_256:
HardwareAlgorithm = 2;
break;
#if defined(WOLFSSL_SHA384)
case SHA2_384:
HardwareAlgorithm = 3;
break;
#endif
#if defined(WOLFSSL_SHA512)
case SHA2_512:
HardwareAlgorithm = 4;
break;
#endif
default:
sha->mode = ESP32_SHA_FAIL_NEED_UNROLL;
return ESP_FAIL;
}
REG_WRITE(SHA_MODE_REG, HardwareAlgorithm);
if (sha->isfirstblock) {
REG_WRITE(SHA_START_REG, 1);
sha->isfirstblock = 0;
ESP_LOGV(TAG, " set sha->isfirstblock = 0");
#if defined(DEBUG_WOLFSSL)
this_block_num = 1;
#endif
}
else {
REG_WRITE(SHA_CONTINUE_REG, 1);
#if defined(DEBUG_WOLFSSL)
this_block_num++;
ESP_LOGV(TAG, " continue block #%d", this_block_num);
#endif
}
#elif defined(CONFIG_IDF_TARGET_ESP32)
if (sha->isfirstblock) {
switch (sha->sha_type) {
case SHA1:
DPORT_REG_WRITE(SHA_1_START_REG, 1);
break;
case SHA2_256:
DPORT_REG_WRITE(SHA_256_START_REG, 1);
break;
#if defined(WOLFSSL_SHA384)
case SHA2_384:
DPORT_REG_WRITE(SHA_384_START_REG, 1);
break;
#endif
#if defined(WOLFSSL_SHA512)
case SHA2_512:
DPORT_REG_WRITE(SHA_512_START_REG, 1);
break;
#endif
default:
sha->mode = ESP32_SHA_FAIL_NEED_UNROLL;
ret = ESP_FAIL;
break;
}
sha->isfirstblock = 0;
ESP_LOGV(TAG, " set sha->isfirstblock = 0");
#if defined(DEBUG_WOLFSSL)
this_block_num = 1;
#endif
}
else {
switch (sha->sha_type) {
case SHA1:
DPORT_REG_WRITE(SHA_1_CONTINUE_REG, 1);
break;
case SHA2_256:
DPORT_REG_WRITE(SHA_256_CONTINUE_REG, 1);
break;
#if defined(WOLFSSL_SHA384)
case SHA2_384:
DPORT_REG_WRITE(SHA_384_CONTINUE_REG, 1);
break;
#endif
#if defined(WOLFSSL_SHA512)
case SHA2_512:
DPORT_REG_WRITE(SHA_512_CONTINUE_REG, 1);
break;
#endif
default:
sha->mode = ESP32_SHA_FAIL_NEED_UNROLL;
ret = ESP_FAIL;
break;
}
}
#else
ESP_LOGE(TAG, "Unsupported hardware");
#endif
#if defined(DEBUG_WOLFSSL)
this_block_num++;
ESP_LOGV(TAG, " continue block #%d", this_block_num);
#endif
ESP_LOGV(TAG, " leave esp_sha_start_process");
CTX_STACK_CHECK(sha);
return ret;
}
#endif
static int wc_esp_process_block(WC_ESP32SHA* ctx,
const word32* data,
word32 len)
{
int ret = ESP_OK;
word32 word32_to_save = (len) / (sizeof(word32));
#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3)
word32* MessageSource;
word32* AcceleratorMessage;
#define MAX_SHA_VALUE SHA_TYPE_MAX
#elif CONFIG_IDF_TARGET_ESP32
int i;
#define MAX_SHA_VALUE 4
#else
#define MAX_SHA_VALUE SHA_TYPE_MAX
#endif
ESP_LOGV(TAG, " enter esp_process_block");
if ((ctx->sha_type < 0) || (ctx->sha_type > MAX_SHA_VALUE)) {
ESP_LOGE(TAG, "Unexpected sha_type: %d", ctx->sha_type);
}
CTX_STACK_CHECK(ctx);
if (word32_to_save > 0x31) {
word32_to_save = 0x31;
ESP_LOGE(TAG, " ERROR esp_process_block length exceeds 0x31 words.");
}
ret = wc_esp_wait_until_idle();
#if defined(CONFIG_IDF_TARGET_ESP32)
for (i = 0; i < word32_to_save; i++) {
DPORT_REG_WRITE(SHA_TEXT_BASE + (i*sizeof(word32)), *(data + i));
}
ret = esp_sha_start_process(ctx);
#elif defined(CONFIG_IDF_TARGET_ESP32C2) || \
defined(CONFIG_IDF_TARGET_ESP8684) || \
defined(CONFIG_IDF_TARGET_ESP32C3) || \
defined(CONFIG_IDF_TARGET_ESP32C6)
if (&data != _active_digest_address) {
ESP_LOGV(TAG, "Moving alternate ctx->for_digest");
_active_digest_address = &data;
}
if (ctx->isfirstblock) {
ets_sha_enable();
#if ESP_IDF_VERSION_MAJOR >= 6
sha_hal_wait_idle();
switch (ctx->sha_type) {
case SHA1:
sha_hal_set_mode(SHA1);
break;
case SHA2_224:
esp_sha_set_mode(SHA2_224);
break;
case SHA2_256:
esp_sha_set_mode(SHA2_256);
break;
default:
ESP_LOGW(TAG, "Unexpected sha_type", ctx->sha_type);
}
#endif
#if defined(DEBUG_WOLFSSL)
{
this_block_num = 1;
}
#endif
}
else {
#if defined(DEBUG_WOLFSSL)
{
this_block_num++;
}
#endif
}
sha_hal_hash_block(ctx->sha_type,
(void *)(data),
word32_to_save,
ctx->isfirstblock);
ctx->isfirstblock = 0;
#elif defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3)
MessageSource = (word32*)data;
AcceleratorMessage = (word32*)(SHA_TEXT_BASE);
while (word32_to_save--) {
DPORT_REG_WRITE(AcceleratorMessage, __builtin_bswap32(*MessageSource));
++AcceleratorMessage;
++MessageSource;
}
ret = esp_sha_start_process(ctx);
#else
ret = ESP_FAIL;
ESP_LOGE(TAG, "ERROR: (CONFIG_IDF_TARGET not supported");
#endif
#ifdef WOLFSSL_HW_METRICS
switch (ctx->sha_type) {
case SHA1:
esp_sha1_hw_hash_usage_ct++;
break;
#ifndef NO_WOLFSSL_ESP32_CRYPT_HASH_SHA224
case SHA2_224:
esp_sha2_224_hw_hash_usage_ct++;
break;
#endif
case SHA2_256:
esp_sha2_256_hw_hash_usage_ct++;
break;
default:
break;
}
#endif
CTX_STACK_CHECK(ctx);
ESP_LOGV(TAG, " leave esp_process_block");
return ret;
}
int wc_esp_digest_state(WC_ESP32SHA* ctx, byte* hash)
{
word32 digestSz;
#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3)
uint64_t* pHash64Buffer;
uint32_t* pHashDestination;
size_t szHashWords;
size_t szHash64Words;
#endif
ESP_LOGV(TAG, "enter esp_digest_state");
CTX_STACK_CHECK(ctx);
if (ctx == NULL) {
return BAD_FUNC_ARG;
}
#if defined(CONFIG_IDF_TARGET_ESP32)
if (ctx->sha_type == SHA_INVALID) {
#elif defined(CONFIG_IDF_TARGET_ESP32C2) || \
defined(CONFIG_IDF_TARGET_ESP8684) || \
defined(CONFIG_IDF_TARGET_ESP32C3) || \
defined(CONFIG_IDF_TARGET_ESP32S2) || \
defined(CONFIG_IDF_TARGET_ESP32S3) || \
defined(CONFIG_IDF_TARGET_ESP32C6)
if (ctx->sha_type >= SHA_TYPE_MAX) {
#else
ESP_LOGE(TAG, "unexpected target for wc_esp_digest_state");
{
#endif
ctx->mode = ESP32_SHA_FAIL_NEED_UNROLL;
ESP_LOGE(TAG, "error. sha_type %d is invalid.", ctx->sha_type);
return ESP_FAIL;
}
digestSz = wc_esp_sha_digest_size(ctx->sha_type);
if (digestSz == 0) {
ctx->mode = ESP32_SHA_FAIL_NEED_UNROLL;
ESP_LOGE(TAG, "unexpected error. sha_type is invalid.");
return ESP_FAIL;
}
#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3)
if (ctx->isfirstblock == 1) {
return ESP_OK;
}
wc_esp_wait_until_idle();
pHashDestination = (uint32_t*)hash;
szHashWords = wc_esp_sha_digest_size(ctx->sha_type) / sizeof(word32);
esp_dport_access_read_buffer(pHashDestination, SHA_H_BASE, szHashWords);
if (ctx->sha_type == SHA2_512) {
szHash64Words = szHashWords / 2;
pHash64Buffer = (uint64_t*)pHashDestination;
while (szHash64Words--) {
*pHash64Buffer = __builtin_bswap64(*pHash64Buffer);
++pHash64Buffer;
}
}
else {
while (szHashWords--) {
*pHashDestination = __builtin_bswap32(*pHashDestination);
++pHashDestination;
}
}
#elif defined(CONFIG_IDF_TARGET_ESP32C2) || \
defined(CONFIG_IDF_TARGET_ESP8684)
wc_esp_wait_until_idle();
sha_ll_read_digest(
ctx->sha_type,
(void *)hash,
wc_esp_sha_digest_size(ctx->sha_type) / sizeof(word32)
);
#elif defined(CONFIG_IDF_TARGET_ESP32C3) || \
defined(CONFIG_IDF_TARGET_ESP32C6)
wc_esp_wait_until_idle();
sha_ll_read_digest(
ctx->sha_type,
(void *)hash,
wc_esp_sha_digest_size(ctx->sha_type) / sizeof(word32)
);
#else
wc_esp_wait_until_idle();
#if defined(CONFIG_IDF_TARGET_ESP32C2) || \
defined(CONFIG_IDF_TARGET_ESP8684) || \
defined(CONFIG_IDF_TARGET_ESP32C3) || \
defined(CONFIG_IDF_TARGET_ESP32C6)
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
#else
switch (ctx->sha_type) {
case SHA1:
DPORT_REG_WRITE(SHA_1_LOAD_REG, 1);
break;
case SHA2_256:
DPORT_REG_WRITE(SHA_256_LOAD_REG, 1);
break;
#if defined(WOLFSSL_SHA384)
case SHA2_384:
DPORT_REG_WRITE(SHA_384_LOAD_REG, 1);
break;
#endif
#if defined(WOLFSSL_SHA512)
case SHA2_512:
DPORT_REG_WRITE(SHA_512_LOAD_REG, 1);
break;
#endif
default:
ctx->mode = ESP32_SHA_FAIL_NEED_UNROLL;
return ESP_FAIL;
}
if (ctx->isfirstblock == 1) {
return ESP_OK;
}
wc_esp_wait_until_idle();
asm volatile("memw");
#ifdef WOLFSSL_ESP32_CRYPT_DEBUG
ESP_LOGW(TAG, "SHA HW read...");
#endif
esp_dport_access_read_buffer(
#if ESP_IDF_VERSION_MAJOR >= 4
(uint32_t*)(hash),
#else
(word32*)(hash),
#endif
SHA_TEXT_BASE,
digestSz / sizeof(word32)
);
#endif
#if defined(WOLFSSL_SHA512) || defined(WOLFSSL_SHA384)
if (ctx->sha_type == SHA2_384 || ctx->sha_type == SHA2_512) {
word32 i;
word32* pwrd1 = (word32*)(hash);
for (i = 0; i < WC_SHA512_DIGEST_SIZE / 4; i += 2) {
pwrd1[i] ^= pwrd1[i + 1];
pwrd1[i + 1] ^= pwrd1[i];
pwrd1[i] ^= pwrd1[i + 1];
}
}
#endif
#endif
CTX_STACK_CHECK(ctx);
ESP_LOGV(TAG, "leave esp_digest_state");
return ESP_OK;
}
#ifndef NO_SHA
int esp_sha_process(struct wc_Sha* sha, const byte* data)
{
int ret = 0;
ESP_LOGV(TAG, "enter esp_sha_process");
wc_esp_process_block(&sha->ctx, (const word32*)data, WC_SHA_BLOCK_SIZE);
ESP_LOGV(TAG, "leave esp_sha_process");
return ret;
}
int esp_sha_digest_process(struct wc_Sha* sha, byte blockprocess)
{
int ret = 0;
ESP_LOGV(TAG, "enter esp_sha_digest_process");
if (blockprocess) {
wc_esp_process_block(&sha->ctx, sha->buffer, WC_SHA_BLOCK_SIZE);
}
ret = wc_esp_digest_state(&sha->ctx, (byte*)sha->digest);
if (blockprocess) {
ESP_LOGV(TAG, "esp_sha_digest_process NEW UNLOCK");
esp_sha_hw_unlock(&sha->ctx);
ESP_LOGV(TAG, "sha blockprocess mutex_ctx_owner = NULLPTR");
mutex_ctx_owner = NULLPTR;
}
ESP_LOGV(TAG, "leave esp_sha_digest_process");
return ret;
}
#endif
#if !defined(NO_SHA256) && !defined(NO_WOLFSSL_ESP32_CRYPT_HASH_SHA256)
int esp_sha256_process(struct wc_Sha256* sha, const byte* data)
{
int ret = 0;
switch ((&sha->ctx)->sha_type) {
case SHA2_256:
#if defined(DEBUG_WOLFSSL_VERBOSE)
ESP_LOGV(TAG, " confirmed SHA256 type call match");
#endif
wc_esp_process_block(&sha->ctx,
(const word32*)data,
WC_SHA256_BLOCK_SIZE);
break;
#if defined(WOLFSSL_SHA224) && !defined(NO_WOLFSSL_ESP32_CRYPT_HASH_SHA224)
case SHA2_224:
#if defined(DEBUG_WOLFSSL_VERBOSE)
ESP_LOGV(TAG, " confirmed SHA224 type call match");
#endif
wc_esp_process_block(&sha->ctx,
(const word32*)data,
WC_SHA224_BLOCK_SIZE);
break;
#endif
default:
ret = ESP_FAIL;
ESP_LOGE(TAG, " ERROR SHA type call mismatch");
break;
}
ESP_LOGV(TAG, " leave esp_sha256_process");
return ret;
}
int esp_sha256_digest_process(struct wc_Sha256* sha, byte blockprocess)
{
int ret = ESP_OK;
ESP_LOGV(TAG, "enter esp_sha256_digest_process");
#ifndef NO_WOLFSSL_ESP32_CRYPT_HASH_SHA256
if (blockprocess) {
wc_esp_process_block(&sha->ctx, sha->buffer, WC_SHA256_BLOCK_SIZE);
}
wc_esp_digest_state(&sha->ctx, (byte*)sha->digest);
if (blockprocess) {
ESP_LOGV(TAG, "esp_sha256_digest_process blockprocess UNLOCK");
esp_sha_hw_unlock(&sha->ctx);
ESP_LOGV(TAG, "blockprocess mutex_ctx_owner = NULLPTR");
mutex_ctx_owner = NULLPTR;
}
#else
ESP_LOGE(TAG, "Call esp_sha256_digest_process with "
"NO_WOLFSSL_ESP32_CRYPT_HASH_SHA256 ");
#endif
ESP_LOGV(TAG, "leave esp_sha256_digest_process");
return ret;
}
#endif
#if !(defined(NO_WOLFSSL_ESP32_CRYPT_HASH_SHA384) && \
defined(NO_WOLFSSL_ESP32_CRYPT_HASH_SHA512) \
) && \
(defined(WOLFSSL_SHA512) || defined(WOLFSSL_SHA384))
int esp_sha512_block(struct wc_Sha512* sha, const word32* data, byte isfinal)
{
int ret = 0;
ESP_LOGV(TAG, "enter esp_sha512_block");
#if defined(CONFIG_IDF_TARGET_ESP32C2) || \
defined(CONFIG_IDF_TARGET_ESP8684) || \
defined(CONFIG_IDF_TARGET_ESP32C3) || \
defined(CONFIG_IDF_TARGET_ESP32C6)
#else
if (sha->ctx.mode == ESP32_SHA_SW) {
ByteReverseWords64(sha->buffer,
sha->buffer,
WC_SHA512_BLOCK_SIZE);
if (isfinal) {
sha->buffer[WC_SHA512_BLOCK_SIZE / sizeof(word64) - 2] =
sha->hiLen;
sha->buffer[WC_SHA512_BLOCK_SIZE / sizeof(word64) - 1] =
sha->loLen;
}
}
else {
ByteReverseWords((word32*)sha->buffer,
(word32*)sha->buffer,
WC_SHA512_BLOCK_SIZE);
if (isfinal) {
sha->buffer[WC_SHA512_BLOCK_SIZE / sizeof(word64) - 2] =
rotlFixed64(sha->hiLen, 32U);
sha->buffer[WC_SHA512_BLOCK_SIZE / sizeof(word64) - 1] =
rotlFixed64(sha->loLen, 32U);
}
ret = wc_esp_process_block(&sha->ctx, data, WC_SHA512_BLOCK_SIZE);
}
ESP_LOGV(TAG, "leave esp_sha512_block");
#endif
return ret;
}
int esp_sha512_process(struct wc_Sha512* sha)
{
int ret = ESP_OK;
word32 *data = (word32*)sha->buffer;
ESP_LOGV(TAG, "enter esp_sha512_process");
esp_sha512_block(sha, data, 0);
ESP_LOGV(TAG, "leave esp_sha512_process");
return ret;
}
int esp_sha512_digest_process(struct wc_Sha512* sha, byte blockproc)
{
int ret = 0;
ESP_LOGV(TAG, "enter esp_sha512_digest_process");
#if defined(CONFIG_IDF_TARGET_ESP32C2) || \
defined(CONFIG_IDF_TARGET_ESP8684) || \
defined(CONFIG_IDF_TARGET_ESP32C3) || \
defined(CONFIG_IDF_TARGET_ESP32C6)
{
ESP_LOGW(TAG, "Warning: no SHA512 HW to digest on %s",
CONFIG_IDF_TARGET);
}
#else
if (blockproc) {
word32* data = (word32*)sha->buffer;
ret = esp_sha512_block(sha, data, 1);
}
if (sha->ctx.mode == ESP32_SHA_HW) {
ret = wc_esp_digest_state(&sha->ctx, (byte*)sha->digest);
}
else {
ESP_LOGW(TAG, "Call esp_sha512_digest_process in non-HW mode?");
}
if (blockproc) {
ESP_LOGV(TAG, "esp_sha512_digest_process NEW UNLOCK");
esp_sha_hw_unlock(&sha->ctx);
ESP_LOGV(TAG, "mutex_ctx_owner = NULLPTR");
mutex_ctx_owner = NULLPTR;
}
ESP_LOGV(TAG, "leave esp_sha512_digest_process");
#endif
return ret;
}
#endif
#endif
#endif
#if defined(WOLFSSL_ESP32_CRYPT) && defined(WOLFSSL_HW_METRICS)
int esp_sw_sha256_count_add(void) {
int ret = 0;
#if !defined(NO_WOLFSSL_ESP32_CRYPT_HASH)
esp_sha256_sw_fallback_usage_ct++;
ret = esp_sha256_sw_fallback_usage_ct;
#endif
return ret;
}
int esp_hw_show_sha_metrics(void)
{
int ret = 0;
#if defined(WOLFSSL_ESP32_CRYPT) && !defined(NO_WOLFSSL_ESP32_CRYPT_HASH)
ESP_LOGI(TAG, "--------------------------------------------------------");
ESP_LOGI(TAG, "------------- wolfSSL ESP HW SHA Metrics -------------");
ESP_LOGI(TAG, "--------------------------------------------------------");
ESP_LOGI(TAG, "esp_sha_hw_copy_ct = %lu",
esp_sha_hw_copy_ct);
ESP_LOGI(TAG, "esp_sha1_hw_usage_ct = %lu",
esp_sha1_hw_usage_ct);
ESP_LOGI(TAG, "esp_sha1_sw_fallback_usage_ct = %lu",
esp_sha1_sw_fallback_usage_ct);
ESP_LOGI(TAG, "esp_sha_reverse_words_ct = %lu",
esp_sha_reverse_words_ct);
ESP_LOGI(TAG, "esp_sha1_hw_hash_usage_ct = %lu",
esp_sha1_hw_hash_usage_ct);
ESP_LOGI(TAG, "esp_sha2_224_hw_hash_usage_ct = %lu",
esp_sha2_224_hw_hash_usage_ct);
ESP_LOGI(TAG, "esp_sha2_256_hw_hash_usage_ct = %lu",
esp_sha2_256_hw_hash_usage_ct);
ESP_LOGI(TAG, "esp_byte_reversal_checks_ct = %lu",
esp_byte_reversal_checks_ct);
ESP_LOGI(TAG, "esp_byte_reversal_needed_ct = %lu",
esp_byte_reversal_needed_ct);
#else
ret = 0;
#endif
return ret;
}
#endif
#if defined(WOLFSSL_STACK_CHECK)
int esp_sha_stack_check(WC_ESP32SHA* sha) {
int ret = ESP_OK;
if (sha == NULL) {
ESP_LOGW(TAG, "esp_sha_stack_check; sha is NULL");
}
else {
if (sha->first_word != 0 || sha->last_word != 0) {
ESP_LOGE(TAG, "esp_sha_stack_check warning");
ret = ESP_FAIL;
}
}
return ret;
}
#endif
#endif