From 8bb6ff8dbbc6ea300998aae431af0a24c8ccc5b5 Mon Sep 17 00:00:00 2001 From: gojimmypi Date: Wed, 6 Jul 2022 09:30:49 -0700 Subject: [PATCH] Espressif HW acceleration update & cleanup --- IDE/Espressif/ESP-IDF/libs/CMakeLists.txt | 41 +- IDE/Espressif/ESP-IDF/libs/component.mk | 54 +- IDE/Espressif/ESP-IDF/user_settings.h | 16 +- wolfcrypt/src/port/Espressif/esp32_aes.c | 54 +- wolfcrypt/src/port/Espressif/esp32_mp.c | 212 ++++-- wolfcrypt/src/port/Espressif/esp32_sha.c | 601 +++++++++++++----- wolfcrypt/src/port/Espressif/esp32_util.c | 42 +- wolfcrypt/src/sha.c | 27 +- wolfcrypt/src/sha256.c | 116 +++- wolfcrypt/src/sha512.c | 8 +- .../wolfcrypt/port/Espressif/esp32-crypt.h | 192 +++--- wolfssl/wolfcrypt/types.h | 4 +- 12 files changed, 994 insertions(+), 373 deletions(-) diff --git a/IDE/Espressif/ESP-IDF/libs/CMakeLists.txt b/IDE/Espressif/ESP-IDF/libs/CMakeLists.txt index b8498e08f..b690fb9fb 100644 --- a/IDE/Espressif/ESP-IDF/libs/CMakeLists.txt +++ b/IDE/Espressif/ESP-IDF/libs/CMakeLists.txt @@ -1,6 +1,24 @@ # +# Copyright (C) 2014-2022 wolfSSL Inc. +# +# This file is part of wolfSSH. +# +# wolfSSH is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# wolfSSH is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with wolfSSH. If not, see . +# +# # cmake for wolfssl -# +# cmake_minimum_required(VERSION 3.5) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSL_USER_SETTINGS") @@ -12,15 +30,24 @@ set(COMPONENT_SRCDIRS "./src/" "./wolfcrypt/src/" "./wolfcrypt/src/port/Espressif/" "./wolfcrypt/src/port/atmel/" +# "$ENV{IDF_PATH}/components/soc/esp32s3/include/soc" ) set(COMPONENT_REQUIRES lwip) + +# RTOS_IDF_PATH is typically: +# "/Users/{username}/Desktop/esp-idf/components/freertos/include/freertos" +# depending on the environment, we may need to swap backslashes with forward slashes +string(REPLACE "\\" "/" RTOS_IDF_PATH "$ENV{IDF_PATH}/components/freertos/include/freertos") +# ESP-IDF after version 4.4x has a different RTOS directory structure +string(REPLACE "\\" "/" RTOS_IDF_PATH5 "$ENV{IDF_PATH}/components/freertos/FreeRTOS-Kernel/include/freertos") + if(IS_DIRECTORY ${IDF_PATH}/components/freertos/FreeRTOS-Kernel/) set(COMPONENT_ADD_INCLUDEDIRS "." "./include" - "../freertos/FreeRTOS-Kernel/include/freertos" + "${RTOS_IDF_PATH5}" "${WOLFSSL_ROOT}" ) else() @@ -28,7 +55,7 @@ else() set(COMPONENT_ADD_INCLUDEDIRS "." "./include" - "../freertos/include/freertos" + "${RTOS_IDF_PATH}" "${WOLFSSL_ROOT}" ) endif() @@ -49,3 +76,11 @@ set(COMPONENT_SRCEXCLUDE ) register_component() + +# check to see if there's both a local copy and EDP-IDF copy of the wolfssl components +if( EXISTS "${CMAKE_HOME_DIRECTORY}/components/wolfssl/" AND EXISTS "$ENV{IDF_PATH}/components/wolfssl/" ) + message(STATUS "") + message(STATUS "WARNING: Found components/wolfssl in both local project and IDF_PATH") + message(STATUS "") +endif() +# end multiple component check diff --git a/IDE/Espressif/ESP-IDF/libs/component.mk b/IDE/Espressif/ESP-IDF/libs/component.mk index 2efebab9b..78b72380d 100644 --- a/IDE/Espressif/ESP-IDF/libs/component.mk +++ b/IDE/Espressif/ESP-IDF/libs/component.mk @@ -1,17 +1,37 @@ -# -# Component Makefile -# - -COMPONENT_ADD_INCLUDEDIRS := . ./include -COMPONENT_ADD_INCLUDEDIRS += ../freertos/include/freertos/ - -COMPONENT_SRCDIRS := src wolfcrypt/src -COMPONENT_SRCDIRS += wolfcrypt/src/port/Espressif -COMPONENT_SRCDIRS += wolfcrypt/src/port/atmel - -CFLAGS +=-DWOLFSSL_USER_SETTINGS - -COMPONENT_OBJEXCLUDE := wolfcrypt/src/aes_asm.o -COMPONENT_OBJEXCLUDE += wolfcrypt/src/evp.o -COMPONENT_OBJEXCLUDE += wolfcrypt/src/misc.o -COMPONENT_OBJEXCLUDE += src/bio.o +# +# Copyright (C) 2014-2022 wolfSSL Inc. +# +# This file is part of wolfSSH. +# +# wolfSSH is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# wolfSSH is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with wolfSSH. If not, see . +# +# +# Component Makefile +# + +COMPONENT_ADD_INCLUDEDIRS := . ./include + +COMPONENT_ADD_INCLUDEDIRS += "$ENV{IDF_PATH}/components/freertos/include/freertos" +# COMPONENT_ADD_INCLUDEDIRS += "$ENV{IDF_PATH}/soc/esp32s3/include/soc" + +COMPONENT_SRCDIRS := src wolfcrypt/src +COMPONENT_SRCDIRS += wolfcrypt/src/port/Espressif +COMPONENT_SRCDIRS += wolfcrypt/src/port/atmel + +CFLAGS +=-DWOLFSSL_USER_SETTINGS + +COMPONENT_OBJEXCLUDE := wolfcrypt/src/aes_asm.o +COMPONENT_OBJEXCLUDE += wolfcrypt/src/evp.o +COMPONENT_OBJEXCLUDE += wolfcrypt/src/misc.o +COMPONENT_OBJEXCLUDE += src/bio.o diff --git a/IDE/Espressif/ESP-IDF/user_settings.h b/IDE/Espressif/ESP-IDF/user_settings.h index 23386646d..7c512dc46 100644 --- a/IDE/Espressif/ESP-IDF/user_settings.h +++ b/IDE/Espressif/ESP-IDF/user_settings.h @@ -1,6 +1,6 @@ /* user_settings.h * - * Copyright (C) 2006-2021 wolfSSL Inc. + * Copyright (C) 2006-2022 wolfSSL Inc. * * This file is part of wolfSSL. * @@ -19,22 +19,24 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ #undef WOLFSSL_ESPIDF +#undef WOLFSSL_ESPWROOM32 +#undef WOLFSSL_ESPWROOM32SE +#undef WOLFSSL_ESPWROOM32 +#undef WOLFSSL_ESP8266 + #define WOLFSSL_ESPIDF /* * choose ONE of these Espressif chips to define: - * + * * WOLFSSL_ESPWROOM32 * WOLFSSL_ESPWROOM32SE * WOLFSSL_ESP8266 - * - * comment out the others: */ #define WOLFSSL_ESPWROOM32 -/* #define WOLFSSL_ESPWROOM32SE */ -/* #define WOLFSSL_ESP8266 */ +/* #define DEBUG_WOLFSSL_VERBOSE */ #define BENCH_EMBEDDED #define USE_CERT_BUFFERS_2048 @@ -88,7 +90,7 @@ /* Define USE_FAST_MATH and SMALL_STACK */ #define ESP32_USE_RSA_PRIMITIVE /* threshold for performance adjustment for hw primitive use */ - /* X bits of G^X mod P greater than */ + /* X bits of G^X mod P greater than */ #define EPS_RSA_EXPT_XBTIS 36 /* X and Y of X * Y mod P greater than */ #define ESP_RSA_MULM_BITS 2000 diff --git a/wolfcrypt/src/port/Espressif/esp32_aes.c b/wolfcrypt/src/port/Espressif/esp32_aes.c index cce7a3016..0256685cb 100644 --- a/wolfcrypt/src/port/Espressif/esp32_aes.c +++ b/wolfcrypt/src/port/Espressif/esp32_aes.c @@ -1,6 +1,6 @@ /* esp32_aes.c * - * Copyright (C) 2006-2021 wolfSSL Inc. + * Copyright (C) 2006-2022 wolfSSL Inc. * * This file is part of wolfSSL. * @@ -19,6 +19,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ +/* + * WOLFSSL_SUCCESS and WOLFSSL_FAILURE values should only + * be used in the ssl layer, not in wolfCrypt + **/ #include #include @@ -36,13 +40,18 @@ #include "wolfssl/wolfcrypt/port/Espressif/esp32-crypt.h" static const char* TAG = "wolf_hw_aes"; + /* mutex */ static wolfSSL_Mutex aes_mutex; + +/* keep track as to whether esp aes is initialized */ static int espaes_CryptHwMutexInit = 0; /* * lock hw engine. * this should be called before using engine. +* +* returns 0 if the hw lock was initialized and mutex lock */ static int esp_aes_hw_InUse() { @@ -50,21 +59,29 @@ static int esp_aes_hw_InUse() ESP_LOGV(TAG, "enter esp_aes_hw_InUse"); - if(espaes_CryptHwMutexInit == 0) { + if (espaes_CryptHwMutexInit == 0) { ret = esp_CryptHwMutexInit(&aes_mutex); - if(ret == 0){ + if (ret == 0) { + /* flag esp aes as initialized */ espaes_CryptHwMutexInit = 1; - } else { - ESP_LOGE(TAG, "aes mutx initialization failed."); + } + else { + ESP_LOGE(TAG, "aes mutex initialization failed."); return -1; } } + else { + /* esp aes has already been initialized */ + } + /* lock hardware */ ret = esp_CryptHwMutexLock(&aes_mutex, portMAX_DELAY); + if(ret != 0) { ESP_LOGE(TAG, "aes engine lock failed."); return -1; } + /* Enable AES hardware */ periph_module_enable(PERIPH_AES_MODULE); @@ -92,23 +109,27 @@ static void esp_aes_hw_Leave( void ) */ static void esp_aes_hw_Set_KeyMode(Aes *ctx, ESP32_AESPROCESS mode) { - int i; + word32 i; word32 mode_ = 0; - ESP_LOGV(TAG, "enter esp_aes_hw_Set_KeyMode"); + ESP_LOGV(TAG, " enter esp_aes_hw_Set_KeyMode"); /* check mode */ if(mode == ESP32_AES_UPDATEKEY_ENCRYPT) { mode_ = 0; - } else if(mode == ESP32_AES_UPDATEKEY_DECRYPT){ - mode_ = 4; - } else { - ESP_LOGE(TAG, "unexpected error."); - return; + } + else { + if (mode == ESP32_AES_UPDATEKEY_DECRYPT) { + mode_ = 4; + } + else { + ESP_LOGE(TAG, " >> unexpected error."); + return; + } } /* update key */ - for(i=0;i<(ctx->keylen)/sizeof(word32);i++){ + for(i=0; i<(ctx->keylen)/sizeof(word32); i++){ DPORT_REG_WRITE(AES_KEY_BASE + (i*4), *(((word32*)ctx->key) + i)); } @@ -127,7 +148,7 @@ static void esp_aes_hw_Set_KeyMode(Aes *ctx, ESP32_AESPROCESS mode) } DPORT_REG_WRITE(AES_MODE_REG, mode_); - ESP_LOGV(TAG, "leave esp_aes_hw_Setkey"); + ESP_LOGV(TAG, " leave esp_aes_hw_Setkey"); } /* @@ -181,6 +202,7 @@ int wc_esp32AesEncrypt(Aes *aes, const byte* in, byte* out) esp_aes_hw_Leave(); return 0; } + /* * wc_esp32AesDecrypt * @brief: a one block decrypt of the input block, into the output block @@ -202,6 +224,7 @@ int wc_esp32AesDecrypt(Aes *aes, const byte* in, byte* out) esp_aes_hw_Leave(); return 0; } + /* * wc_esp32AesCbcEncrypt * @brief: Encrypts a plain text message from the input buffer, and places the @@ -281,8 +304,9 @@ int wc_esp32AesCbcDecrypt(Aes* aes, byte* out, const byte* in, word32 sz) esp_aes_bk((in + offset), (out + offset)); /* XOR block with IV for CBC */ - for (i = 0; i < AES_BLOCK_SIZE; i++) + for (i = 0; i < AES_BLOCK_SIZE; i++) { (out + offset)[i] ^= iv[i]; + } /* store IV for next block */ XMEMCPY(iv, temp_block, AES_BLOCK_SIZE); diff --git a/wolfcrypt/src/port/Espressif/esp32_mp.c b/wolfcrypt/src/port/Espressif/esp32_mp.c index af0192989..a7eb1fdd7 100644 --- a/wolfcrypt/src/port/Espressif/esp32_mp.c +++ b/wolfcrypt/src/port/Espressif/esp32_mp.c @@ -1,6 +1,6 @@ /* esp32_mp.c * - * Copyright (C) 2006-2021 wolfSSL Inc. + * Copyright (C) 2006-2022 wolfSSL Inc. * * This file is part of wolfSSL. * @@ -58,46 +58,91 @@ static wolfSSL_Mutex mp_mutex; static int espmp_CryptHwMutexInit = 0; /* * check if the hw is ready before accessing it +* +* When the RSA Accelerator is released from reset, the register RSA_CLEAN_REG +* reads 0 and an initialization process begins. Hardware initializes the four +* memory blocks by setting them to 0. After initialization is complete, +* RSA_CLEAN_REG reads 1. For this reason, software should query RSA_CLEAN_REG +* after being released from reset, and before writing to any RSA Accelerator +* memory blocks or registers for the first time. */ static int esp_mp_hw_wait_clean() { word32 timeout = 0; - while(!ESP_TIMEOUT(++timeout) && - DPORT_REG_READ(RSA_CLEAN_REG) != 1) { } - if(ESP_TIMEOUT(timeout)) { + while(!ESP_TIMEOUT(++timeout) && + DPORT_REG_READ(RSA_CLEAN_REG) != 1) { + /* wait. expected delay 1 to 2 uS */ + } + + if (ESP_TIMEOUT(timeout)) { ESP_LOGE(TAG, "waiting hw ready is timed out."); return MP_NG; } - return MP_OKAY; + return MP_OKAY; } + /* * lock hw engine. * this should be called before using engine. +* +* returns 0 if the hw lock was initialized and mutex lock +* +* See Chapter 24: +* https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf +* +* The RSA Accelerator is activated by enabling the corresponding peripheral +* clock, and by clearing the DPORT_RSA_PD bit in the DPORT_RSA_PD_CTRL_REG +* register. This releases the RSA Accelerator from reset. +* +* When the RSA Accelerator is released from reset, the register RSA_CLEAN_REG +* reads 0 and an initialization process begins. Hardware initializes the four +* memory blocks by setting them to 0. After initialization is complete, +* RSA_CLEAN_REG reads 1. For this reason, software should query RSA_CLEAN_REG +* after being released from reset, and before writing to any RSA Accelerator +* memory blocks or registers for the first time. */ static int esp_mp_hw_lock() { int ret = 0; - if(espmp_CryptHwMutexInit == 0) { + ESP_LOGV(TAG, "enter esp_mp_hw_lock"); + + if (espmp_CryptHwMutexInit == 0) { ret = esp_CryptHwMutexInit(&mp_mutex); - if(ret == 0){ + if (ret == 0) { + /* flag esp mp as initialized */ espmp_CryptHwMutexInit = 1; - } else { + } + else { ESP_LOGE(TAG, "mp mutx initialization failed."); return MP_NG; } } + else { + /* esp aes has already been iniitlized */ + } + /* lock hardware */ ret = esp_CryptHwMutexLock(&mp_mutex, portMAX_DELAY); - if(ret != 0) { + + if (ret != 0) { ESP_LOGE(TAG, "mp engine lock failed."); return MP_NG; } + /* Enable RSA hardware */ periph_module_enable(PERIPH_RSA_MODULE); + /* clear bit to enable hardware operation; (set to disable) + */ DPORT_REG_CLR_BIT(DPORT_RSA_PD_CTRL_REG, DPORT_RSA_PD); + + /* remionder: wait until RSA_CLEAN_REG reads 1 + * see esp_mp_hw_wait_clean() + */ + + ESP_LOGV(TAG, "leave esp_mp_hw_lock"); return ret; } /* @@ -105,12 +150,17 @@ static int esp_mp_hw_lock() */ static void esp_mp_hw_unlock( void ) { + /* set bit to disabled hardware operation; (clear to enable) + */ + DPORT_REG_SET_BIT(DPORT_RSA_PD_CTRL_REG, DPORT_RSA_PD); + /* Disable RSA hardware */ periph_module_disable(PERIPH_RSA_MODULE); /* unlock */ esp_CryptHwMutexUnLock(&mp_mutex); } + /* this is based on an article by Cetin Kaya Koc, A New Algorithm for Inversion*/ /* mod p^k, June 28 2017. */ static int esp_calc_Mdash(mp_int *M, word32 k, mp_digit* md) @@ -126,9 +176,9 @@ static int esp_calc_Mdash(mp_int *M, word32 k, mp_digit* md) bi = b0; x = 0; - for(i = 0; i < k; i++) { + for (i = 0; i < k; i++) { xi = bi % 2; - if(xi < 0){ + if (xi < 0) { xi *= -1; } bi = (bi - N * xi) / 2; @@ -138,6 +188,7 @@ static int esp_calc_Mdash(mp_int *M, word32 k, mp_digit* md) *md = ~x + 1; return MP_OKAY; } + /* start hw process */ static void process_start(word32 reg) { @@ -146,87 +197,100 @@ static void process_start(word32 reg) /* start process */ DPORT_REG_WRITE(reg, 1); } + /* wait until done */ static int wait_uitil_done(word32 reg) { word32 timeout = 0; /* wait until done && not timeout */ - while(!ESP_TIMEOUT(++timeout) && - DPORT_REG_READ(reg) != 1) { } + while (!ESP_TIMEOUT(++timeout) && + DPORT_REG_READ(reg) != 1) { + /* wait */ + } /* clear interrupt */ DPORT_REG_WRITE(RSA_INTERRUPT_REG, 1); - if(ESP_TIMEOUT(timeout)) { + if (ESP_TIMEOUT(timeout)) { ESP_LOGE(TAG, "rsa operation is timed out."); return MP_NG; } return MP_OKAY; } + /* read data from memory into mp_init */ -static void esp_memblock_to_mpint(word32 mem_address, mp_int* mp, word32 numwords) +static void esp_memblock_to_mpint(word32 mem_address, + mp_int* mp, + word32 numwords) { esp_dport_access_read_buffer((uint32_t*)mp->dp, mem_address, numwords); mp->used = numwords; } -/* write mp_init into memory block */ +/* write mp_init into memory block + */ static void esp_mpint_to_memblock(word32 mem_address, const mp_int* mp, const word32 bits, const word32 hwords) { + /* init */ word32 i; word32 len = (bits / 8 + ((bits & 7) != 0 ? 1 : 0)); - len = (len+sizeof(word32)-1)/sizeof(word32); + len = (len + sizeof(word32)-1) / sizeof(word32); - for(i=0;i < hwords; i++) { - if(i < len) { + for (i=0; i < hwords; i++) { + if (i < len) { DPORT_REG_WRITE(mem_address + (i * sizeof(word32)), mp->dp[i]); - } else { + } + else { DPORT_REG_WRITE(mem_address + (i * sizeof(word32)), 0); } } } -/* return needed hw words. */ -/* supported words length */ -/* words : {16 , 32, 48, 64, 80, 96, 112, 128} */ -/* bits : {512,1024, 1536, 2048, 2560, 3072, 3584, 4096} */ +/* return needed hw words. + * supported words length + * words : {16 , 32, 48, 64, 80, 96, 112, 128} + * bits : {512,1024, 1536, 2048, 2560, 3072, 3584, 4096} + */ static word32 words2hwords(word32 wd) { - const word32 shit_ = 4; + const word32 bit_shift = 4; - return (((wd + 0xf)>>shit_)<> bit_shift) << bit_shift); } + /* count the number of words is needed for bits */ static word32 bits2words(word32 bits) { /* 32 bits */ const word32 d = sizeof(word32) * WOLFSSL_BIT_SIZE; - return((bits + (d - 1))/d); + return ((bits + (d - 1)) / d); } + /* get rinv */ static int esp_get_rinv(mp_int *rinv, mp_int *M, word32 exp) { int ret = 0; /* 2^(exp)*/ - if((ret = mp_2expt(rinv, exp)) != MP_OKAY) { + if ((ret = mp_2expt(rinv, exp)) != MP_OKAY) { ESP_LOGE(TAG, "failed to calculate mp_2expt()"); return ret; } /* r_inv = R^2 mod M(=P) */ - if(ret == 0 && (ret = mp_mod(rinv, M, rinv)) != MP_OKAY){ + if (ret == 0 && (ret = mp_mod(rinv, M, rinv)) != MP_OKAY) { ESP_LOGE(TAG, "failed to calculate mp_mod()"); return ret; } return ret; } -/* Z = X * Y; */ + +/* Z = X * Y; */ int esp_mp_mul(fp_int* X, fp_int* Y, fp_int* Z) { int ret = 0; @@ -268,34 +332,46 @@ int esp_mp_mul(fp_int* X, fp_int* Y, fp_int* Z) * 9. Release the hw engine */ /* lock hw for use */ - if((ret = esp_mp_hw_lock()) != MP_OKAY) + if ((ret = esp_mp_hw_lock()) != MP_OKAY) { return ret; + } - if((ret = esp_mp_hw_wait_clean()) != MP_OKAY){ + if((ret = esp_mp_hw_wait_clean()) != MP_OKAY) { return ret; } /* step.1 (2*N/512) => N/256. 512 bits => 16 words */ DPORT_REG_WRITE(RSA_MULT_MODE_REG, (hwWords_sz >> 3) - 1 + 8); /* step.2 write X, M and r_inv into memory */ - esp_mpint_to_memblock(RSA_MEM_X_BLOCK_BASE, X, Xs, hwWords_sz); + esp_mpint_to_memblock(RSA_MEM_X_BLOCK_BASE, + X, + Xs, + hwWords_sz); /* Y(let-extend) */ - esp_mpint_to_memblock(RSA_MEM_Z_BLOCK_BASE + (hwWords_sz<<2), Y, Ys, hwWords_sz); + esp_mpint_to_memblock(RSA_MEM_Z_BLOCK_BASE + (hwWords_sz<<2), + Y, + Ys, + hwWords_sz); /* step.3 start process */ process_start(RSA_MULT_START_REG); /* step.4,5 wait until done */ - wait_uitil_done(RSA_INTERRUPT_REG); + ret = wait_uitil_done(RSA_INTERRUPT_REG); + if (ret != MP_OKAY) { + ESP_LOGE(TAG, "wait_uitil_done failed."); + return ret; + } /* step.6 read the result form MEM_Z */ esp_memblock_to_mpint(RSA_MEM_Z_BLOCK_BASE, Z, BITS_TO_WORDS(Zs)); /* step.7 clear and release hw */ esp_mp_hw_unlock(); - Z->sign = (Z->used > 0)? neg : MP_ZPOS; + Z->sign = (Z->used > 0) ? neg : MP_ZPOS; return ret; } + /* Z = X * Y (mod M) */ int esp_mp_mulmod(fp_int* X, fp_int* Y, fp_int* M, fp_int* Z) { @@ -313,7 +389,7 @@ int esp_mp_mulmod(fp_int* X, fp_int* Y, fp_int* M, fp_int* Z) mp_digit mp; /* neg check */ - if(X->sign != Y->sign) { + if (X->sign != Y->sign) { /* X*Y becomes negative */ negcheck = 1; } @@ -327,7 +403,7 @@ int esp_mp_mulmod(fp_int* X, fp_int* Y, fp_int* M, fp_int* Z) zwords = bits2words(min(Ms, Xs + Ys)); hwWords_sz = words2hwords(maxWords_sz); - if((hwWords_sz<<5) > ESP_HW_RSAMAX_BIT) { + if ((hwWords_sz << 5) > ESP_HW_RSAMAX_BIT) { ESP_LOGE(TAG, "exceeds hw maximum bits"); return -2; } @@ -336,20 +412,20 @@ int esp_mp_mulmod(fp_int* X, fp_int* Y, fp_int* M, fp_int* Z) * accordingly R^2 = 2^(n*32*2) */ ret = mp_init_multi(&tmpZ, &r_inv, NULL, NULL, NULL, NULL); - if(ret == 0 && (ret = esp_get_rinv(&r_inv, M, (hwWords_sz<<6))) != MP_OKAY) { + if (ret == 0 && (ret = esp_get_rinv(&r_inv, M, (hwWords_sz << 6))) != MP_OKAY) { ESP_LOGE(TAG, "calculate r_inv failed."); mp_clear(&tmpZ); mp_clear(&r_inv); return ret; } /* lock hw for use */ - if((ret = esp_mp_hw_lock()) != MP_OKAY){ + if ((ret = esp_mp_hw_lock()) != MP_OKAY) { mp_clear(&tmpZ); mp_clear(&r_inv); return ret; } /* Calculate M' */ - if((ret = esp_calc_Mdash(M, 32/* bits */, &mp)) != MP_OKAY) { + if ((ret = esp_calc_Mdash(M, 32/* bits */, &mp)) != MP_OKAY) { ESP_LOGE(TAG, "failed to calculate M dash"); mp_clear(&tmpZ); mp_clear(&r_inv); @@ -374,7 +450,7 @@ int esp_mp_mulmod(fp_int* X, fp_int* Y, fp_int* M, fp_int* Z) * 13. Release the hw engine */ - if((ret = esp_mp_hw_wait_clean()) != MP_OKAY){ + if ((ret = esp_mp_hw_wait_clean()) != MP_OKAY) { return ret; } /* step.1 512 bits => 16 words */ @@ -383,8 +459,11 @@ int esp_mp_mulmod(fp_int* X, fp_int* Y, fp_int* M, fp_int* Z) /* step.2 write X, M and r_inv into memory */ esp_mpint_to_memblock(RSA_MEM_X_BLOCK_BASE, X, Xs, hwWords_sz); esp_mpint_to_memblock(RSA_MEM_M_BLOCK_BASE, M, Ms, hwWords_sz); - esp_mpint_to_memblock(RSA_MEM_Z_BLOCK_BASE, &r_inv, mp_count_bits(&r_inv), - hwWords_sz); + esp_mpint_to_memblock(RSA_MEM_Z_BLOCK_BASE, + &r_inv, + mp_count_bits(&r_inv), + hwWords_sz); + /* step.3 write M' into memory */ DPORT_REG_WRITE(RSA_M_DASH_REG, mp); /* step.4 start process */ @@ -409,11 +488,11 @@ int esp_mp_mulmod(fp_int* X, fp_int* Y, fp_int* M, fp_int* Z) /* additional steps */ /* this needs for known issue when Z is greater than M */ - if(mp_cmp(&tmpZ, M)==FP_GT) { - /* Z -= M */ - mp_sub(&tmpZ, M, &tmpZ); + if (mp_cmp(&tmpZ, M) == FP_GT) { + /* Z -= M */ + mp_sub(&tmpZ, M, &tmpZ); } - if(negcheck) { + if (negcheck) { mp_sub(M, &tmpZ, &tmpZ); } @@ -424,7 +503,25 @@ int esp_mp_mulmod(fp_int* X, fp_int* Y, fp_int* M, fp_int* Z) return ret; } -/* Z = X^Y mod M */ + +/* Large Number Modular Exponentiation + * + * Z = X^Y mod M + * + * See Chapter 24: + * https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf + * + * The operation is based on Montgomery multiplication. Aside from the + * arguments X, Y , and M, two additional ones are needed —r and M′ +.* These arguments are calculated in advance by software. +.* +.* The RSA Accelerator supports operand lengths of N ∈ {512, 1024, 1536, 2048, +.* 2560, 3072, 3584, 4096} bits. The bit length of arguments Z, X, Y , M, +.* and r can be any one from the N set, but all numbers in a calculation must +.* be of the same length. The bit length of M′ is always 32. +.* +.* Note some DH references may use: Y = (G ^ X) mod P + */ int esp_mp_exptmod(fp_int* X, fp_int* Y, word32 Ys, fp_int* M, fp_int* Z) { int ret = 0; @@ -444,7 +541,7 @@ int esp_mp_exptmod(fp_int* X, fp_int* Y, word32 Ys, fp_int* M, fp_int* Z) maxWords_sz = bits2words(max(Xs, max(Ys, Ms))); hwWords_sz = words2hwords(maxWords_sz); - if((hwWords_sz<<5) > ESP_HW_RSAMAX_BIT) { + if ((hwWords_sz << 5) > ESP_HW_RSAMAX_BIT) { ESP_LOGE(TAG, "exceeds hw maximum bits"); return -2; } @@ -453,19 +550,19 @@ int esp_mp_exptmod(fp_int* X, fp_int* Y, word32 Ys, fp_int* M, fp_int* Z) * accordingly R^2 = 2^(n*32*2) */ ret = mp_init(&r_inv); - if(ret == 0 && (ret = esp_get_rinv(&r_inv, M, (hwWords_sz<<6))) != MP_OKAY) { + if (ret == 0 && (ret = esp_get_rinv(&r_inv, M, (hwWords_sz << 6))) != MP_OKAY) { ESP_LOGE(TAG, "calculate r_inv failed."); mp_clear(&r_inv); return ret; } /* lock and init the hw */ - if((ret = esp_mp_hw_lock()) != MP_OKAY) { + if ((ret = esp_mp_hw_lock()) != MP_OKAY) { mp_clear(&r_inv); return ret; } /* calc M' */ /* if Pm is odd, uses mp_montgomery_setup() */ - if((ret = esp_calc_Mdash(M, 32/* bits */, &mp)) != MP_OKAY) { + if ((ret = esp_calc_Mdash(M, 32/* bits */, &mp)) != MP_OKAY) { ESP_LOGE(TAG, "failed to calculate M dash"); mp_clear(&r_inv); return -1; @@ -483,7 +580,7 @@ int esp_mp_exptmod(fp_int* X, fp_int* Y, word32 Ys, fp_int* M, fp_int* Z) * 6. Read the result Z(=Y) from Z_MEM * 7. Write 1 to INTERRUPT_REG to clear the interrupt. */ - if((ret = esp_mp_hw_wait_clean()) != MP_OKAY){ + if ((ret = esp_mp_hw_wait_clean()) != MP_OKAY) { return ret; } @@ -493,8 +590,10 @@ int esp_mp_exptmod(fp_int* X, fp_int* Y, word32 Ys, fp_int* M, fp_int* Z) esp_mpint_to_memblock(RSA_MEM_X_BLOCK_BASE, X, Xs, hwWords_sz); esp_mpint_to_memblock(RSA_MEM_Y_BLOCK_BASE, Y, Ys, hwWords_sz); esp_mpint_to_memblock(RSA_MEM_M_BLOCK_BASE, M, Ms, hwWords_sz); - esp_mpint_to_memblock(RSA_MEM_Z_BLOCK_BASE, &r_inv, mp_count_bits(&r_inv), - hwWords_sz); + esp_mpint_to_memblock(RSA_MEM_Z_BLOCK_BASE, + &r_inv, + mp_count_bits(&r_inv), + hwWords_sz); /* step.3 write M' into memory */ DPORT_REG_WRITE(RSA_M_DASH_REG, mp); /* step.4 start process */ @@ -512,4 +611,5 @@ int esp_mp_exptmod(fp_int* X, fp_int* Y, word32 Ys, fp_int* M, fp_int* Z) return ret; } #endif /* !NO_RSA || HAVE_ECC */ + #endif /* (WOLFSS_ESP32WROOM32_CRYPT) && (NO_WOLFSSL_ESP32WROOM32_CRYPT_RES_PRI)*/ diff --git a/wolfcrypt/src/port/Espressif/esp32_sha.c b/wolfcrypt/src/port/Espressif/esp32_sha.c index 2f8f38fd9..63967da00 100644 --- a/wolfcrypt/src/port/Espressif/esp32_sha.c +++ b/wolfcrypt/src/port/Espressif/esp32_sha.c @@ -18,23 +18,28 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ -#include -#include - #ifdef HAVE_CONFIG_H #include #endif -#include +#include +/*****************************************************************************/ +/* this entire file content is excluded when NO_SHA, NO_SHA256 + * or when using WC_SHA384 or WC_SHA512 + */ #if !defined(NO_SHA) || !defined(NO_SHA256) || defined(WC_SHA384) || \ defined(WC_SHA512) #include "wolfssl/wolfcrypt/logging.h" +/* this entire file content is excluded if not using HW hash acceleration */ #if defined(WOLFSSL_ESP32WROOM32_CRYPT) && \ !defined(NO_WOLFSSL_ESP32WROOM32_CRYPT_HASH) +/* TODO this may be chip type dependent: add support for others */ +#include /* ESP32-WROOM */ + #include #include #include @@ -50,20 +55,29 @@ #endif static const char* TAG = "wolf_hw_sha"; -/* continue register offset */ -#define CONTINUE_REG_OFFSET (0x04) /* start_reg + 0x04 */ #ifdef NO_SHA #define WC_SHA_DIGEST_SIZE 20 #endif + /* mutex */ #if defined(SINGLE_THREADED) -static int InUse = 0; + static int InUse = 0; #else -static wolfSSL_Mutex sha_mutex; -static int espsha_CryptHwMutexInit = 0; + static wolfSSL_Mutex sha_mutex; + static int espsha_CryptHwMutexInit = 0; + + #if defined(DEBUG_WOLFSSL) + static int this_block_num = 0; + #endif #endif + /* + * determine the digest size, depending on SHA type. + * + * See FIPS PUB 180-4, Instruction Section 1. + * + * enum SHA_TYPE { SHA1 = 0, SHA2_256, @@ -72,43 +86,112 @@ static int espsha_CryptHwMutexInit = 0; SHA_INVALID = -1, }; */ -static word32 esp_sha_digest_size(enum SHA_TYPE type) +static word32 wc_esp_sha_digest_size(enum SHA_TYPE type) { - ESP_LOGV(TAG, "enter esp_sha_digest_size"); + ESP_LOGV(TAG, " esp_sha_digest_size"); switch(type){ -#ifndef NO_SHA - case SHA1: - return WC_SHA_DIGEST_SIZE; -#endif -#ifndef NO_SHA256 - case SHA2_256: - return WC_SHA256_DIGEST_SIZE; -#endif -#ifdef WOLFSSL_SHA384 - case SHA2_384: - return WC_SHA384_DIGEST_SIZE; -#endif -#ifdef WOLFSSL_SHA512 - case SHA2_512: - return WC_SHA512_DIGEST_SIZE; -#endif + #ifndef NO_SHA + case SHA1: /* typically 20 bytes */ + return WC_SHA_DIGEST_SIZE; + #endif + + #ifndef NO_SHA256 + case SHA2_256: /* typically 32 bytes */ + return WC_SHA256_DIGEST_SIZE; + #endif + + #ifdef WOLFSSL_SHA384 + case SHA2_384: + return WC_SHA384_DIGEST_SIZE; + #endif + + #ifdef WOLFSSL_SHA512 + case SHA2_512: /* typically 64 bytes */ + return WC_SHA512_DIGEST_SIZE; + #endif + default: ESP_LOGE(TAG, "Bad sha type"); return WC_SHA_DIGEST_SIZE; } - ESP_LOGV(TAG, "leave esp_sha_digest_size"); + /* we never get here, as all the above switches should have a return */ } + /* -* wait until engines becomes idle +* wait until all engines becomes idle */ -static void esp_wait_until_idle() +static void wc_esp_wait_until_idle() { - 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)){ } + 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)) { + /* do nothing while waiting. */ + } } + +/* + * hack alert. there really should have been something implemented + * in periph_ctrl.c to detect ref_counts[periph] depth. + * + * since there is not at this time, we have this brute-force method. + * + * when trying to unwrap an arbitrary depth of peripheral-enable(s), + * we'll check the register upon *enable* to see if we actually did. + * + * Note that enable / disable only occurs when ref_counts[periph] == 0 + * + * TODO: check if this works with other ESP32 platforms ESP32-C3, ESP32-S3, etc + */ +int esp_unroll_sha_module_enable(WC_ESP32SHA* ctx) +{ + /* if we end up here, there was a prior unexpected fail and + * we need to unroll enables */ + int ret = 0; /* assume success unless proven otherwise */ + uint32_t this_sha_mask; /* this is the bit-mask for our SHA CLK_EN_REG */ + int actual_unroll_count = 0; + int max_unroll_count = 1000; /* never get stuck in a hardware wait loop */ + + this_sha_mask = periph_ll_get_clk_en_mask(PERIPH_SHA_MODULE); + + /* unwind prior calls to THIS ctx. decrement ref_counts[periph] */ + /* only when ref_counts[periph] == 0 does something actually happen */ + + /* once the value we read is a 0 in the DPORT_PERI_CLK_EN_REG bit + * then we have fully unrolled the enables via ref_counts[periph]==0 */ + while ((this_sha_mask & *(uint32_t*)DPORT_PERI_CLK_EN_REG) != 0) { + periph_module_disable(PERIPH_SHA_MODULE); + actual_unroll_count++; + ESP_LOGI(TAG, "unroll not yet successful. try #%d", + actual_unroll_count); + + /* we'll only try this some unreasonable number of times + * before giving up */ + if (actual_unroll_count > max_unroll_count) { + ret = -1; /* failed to unroll */ + break; + } + } + + if (ret == 0) { + if (ctx->lockDepth != actual_unroll_count) { + /* this could be a warning of wonkiness in RTOS environment. + * we were successful, but not expected depth count*/ + + ESP_LOGE(TAG, "warning lockDepth mismatch."); + } + ctx->lockDepth = 0; + ctx->mode = ESP32_SHA_INIT; + } + else { + ESP_LOGE(TAG, "Failed to unroll after %d attempts.", + actual_unroll_count); + ctx->mode = ESP32_SHA_SW; + } + return ret; +} + /* * lock hw engine. * this should be called before using engine. @@ -119,160 +202,375 @@ int esp_sha_try_hw_lock(WC_ESP32SHA* ctx) ESP_LOGV(TAG, "enter esp_sha_hw_lock"); - /* Init mutex */ + if (ctx == NULL) { + ESP_LOGE(TAG, " esp_sha_try_hw_lock called with NULL ctx"); + return -1; + } + + /* Init mutex + * + * Note that even single thread mode may calculate hashes + * concurrently, so we still need to keep track of the + * engine being busy or not. + **/ #if defined(SINGLE_THREADED) if(ctx->mode == ESP32_SHA_INIT) { if(!InUse) { ctx->mode = ESP32_SHA_HW; InUse = 1; - } else { + } + else { ctx->mode = ESP32_SHA_SW; } - } else { + } + else { /* this should not happens */ ESP_LOGE(TAG, "unexpected error in esp_sha_try_hw_lock."); return -1; } -#else - if(espsha_CryptHwMutexInit == 0){ +#else /* not defined(SINGLE_THREADED) */ + /* + * there's only one SHA engine for all the hash types + * so when any hash is in use, no others can use it. + * fall back to SW. + **/ + + /* + * here is some sample code to test the unrolling of sha enables: + * + periph_module_enable(PERIPH_SHA_MODULE); + ctx->lockDepth++; + periph_module_enable(PERIPH_SHA_MODULE); + ctx->lockDepth++; + ctx->mode = ESP32_FAIL_NEED_INIT; + + */ + + if (espsha_CryptHwMutexInit == 0) { + ESP_LOGV(TAG, "set esp_CryptHwMutexInit"); ret = esp_CryptHwMutexInit(&sha_mutex); - if(ret == 0) { + if (ret == 0) { espsha_CryptHwMutexInit = 1; - } else { - ESP_LOGE(TAG, " mutex initialization failed."); + } + else { + ESP_LOGE(TAG, " mutex initialization failed. revert to software"); ctx->mode = ESP32_SHA_SW; - return 0; + /* espsha_CryptHwMutexInit is still zero */ + return 0; /* success, just not using HW */ } } + /* check if this sha has been operated as sw or hw, or not yet init */ - if(ctx->mode == ESP32_SHA_INIT){ + if (ctx->mode == ESP32_SHA_INIT) { /* try to lock the hw engine */ - if(esp_CryptHwMutexLock(&sha_mutex, (TickType_t)0) == 0) { - ctx->mode = ESP32_SHA_HW; - } else { - ESP_LOGI(TAG, "someone used. hw is locked....."); - ESP_LOGI(TAG, "the rest of operation will use sw implementation for this sha"); - ctx->mode = ESP32_SHA_SW; - return 0; + ESP_LOGV(TAG, "ESP32_SHA_INIT\n"); + + /* we don't wait: + * either the engine is free, or we fall back to SW + */ + if (esp_CryptHwMutexLock(&sha_mutex, (TickType_t)0) == 0) { + /* check to see if we had a prior fail and need to unroll enables */ + ret = esp_unroll_sha_module_enable(ctx); + ESP_LOGV(TAG, "Hardware Mode, lock depth = %d", ctx->lockDepth); } - } else { - /* this should not happens */ + else { + ESP_LOGI(TAG, ">>>> Hardware in use; Mode REVERT to ESP32_SHA_SW"); + ctx->mode = ESP32_SHA_SW; + return 0; /* success, but revert to SW */ + } + } + else { + /* this should not happen: called during mode != ESP32_SHA_INIT */ ESP_LOGE(TAG, "unexpected error in esp_sha_try_hw_lock."); return -1; } -#endif - /* Enable SHA hardware */ - periph_module_enable(PERIPH_SHA_MODULE); +#endif /* not defined(SINGLE_THREADED) */ + + if (ret == 0) { + ctx->lockDepth++; /* depth for THIS ctx (there could be others!) */ + periph_module_enable(PERIPH_SHA_MODULE); + ctx->mode = ESP32_SHA_HW; + } + else { + ESP_LOGI(TAG, ">>>> Other problem; Mode REVERT to ESP32_SHA_SW"); + ctx->mode = ESP32_SHA_SW; + } ESP_LOGV(TAG, "leave esp_sha_hw_lock"); return ret; -} +} /* esp_sha_try_hw_lock */ + /* -* release hw engine +* release hw engine. when we don't have it locked, SHA module is DISABLED */ -void esp_sha_hw_unlock( void ) +int esp_sha_hw_unlock(WC_ESP32SHA* ctx) { ESP_LOGV(TAG, "enter esp_sha_hw_unlock"); /* Disable AES hardware */ periph_module_disable(PERIPH_SHA_MODULE); -#if defined(SINGLE_THREADED) - InUse = 0; -#else - /* unlock hw engine for next use */ - esp_CryptHwMutexUnLock(&sha_mutex); -#endif + + #if defined(SINGLE_THREADED) + InUse = 0; + #else + /* unlock hw engine for next use */ + esp_CryptHwMutexUnLock(&sha_mutex); + #endif + + /* we'll keep track of our lock depth. + * in case of unexpected results, all the periph_module_disable() calls + * and periph_module_disable() need to be unwound. + * + * see ref_counts[periph] in file: periph_ctrl.c */ + if (ctx->lockDepth > 0) { + ctx->lockDepth--; + } + else { + ctx->lockDepth = 0; + } + ESP_LOGV(TAG, "leave esp_sha_hw_unlock"); -} + return 0; +} /* esp_sha_hw_unlock */ + /* -* start sha process by using hw engine +* start sha process by using hw engine. +* assumes register already loaded. */ -static void esp_sha_start_process(WC_ESP32SHA* sha, word32 address) +static int esp_sha_start_process(WC_ESP32SHA* sha) { - ESP_LOGV(TAG, "enter esp_sha_start_process"); + int ret = 0; + if (sha == NULL) { + return -1; + } + + ESP_LOGV(TAG, " enter esp_sha_start_process"); if(sha->isfirstblock){ - /* start first message block */ - DPORT_REG_WRITE(address, 1); + /* start registers for first message block + * we don't make any relational memory position assumptions. + */ + 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 = -1; + break; + } + sha->isfirstblock = 0; - } else { - /* CONTINU_REG */ - DPORT_REG_WRITE(address + CONTINUE_REG_OFFSET , 1); + ESP_LOGV(TAG, " set sha->isfirstblock = 0"); + + #if defined(DEBUG_WOLFSSL) + this_block_num = 1; /* one-based counter, just for debug info */ + #endif + + } + else { + /* continue */ + /* continue registers for next message block. + * we don't make any relational memory position assumptions + * for future chip architecture changes. + */ + 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: + /* error for unsupported other values */ + sha->mode = ESP32_SHA_FAIL_NEED_UNROLL; + ret = -1; + break; + } + #if defined(DEBUG_WOLFSSL) + this_block_num++; /* one-based counter */ + ESP_LOGV(TAG, " continue block #%d", this_block_num); + #endif + } - ESP_LOGV(TAG, "leave esp_sha_start_process"); + ESP_LOGV(TAG, " leave esp_sha_start_process"); + + return ret; } + /* * process message block */ -static void esp_process_block(WC_ESP32SHA* ctx, word32 address, - const word32* data, word32 len) +static void wc_esp_process_block(WC_ESP32SHA* ctx, /* see ctx->sha_type */ + const word32* data, + word32 len) { int i; - - ESP_LOGV(TAG, "enter esp_process_block"); + int word32_to_save = (len) / (sizeof(word32)); + ESP_LOGV(TAG, " enter esp_process_block"); + if (word32_to_save > 0x31) { + word32_to_save = 0x31; + ESP_LOGE(TAG, " ERROR esp_process_block len exceeds 0x31 words"); + } /* check if there are any busy engine */ - esp_wait_until_idle(); - /* load message data into hw */ - for(i=0;i<((len)/(sizeof(word32)));++i){ - DPORT_REG_WRITE(SHA_TEXT_BASE+(i*sizeof(word32)),*(data+i)); + wc_esp_wait_until_idle(); + + /* load [len] words of message data into hw */ + for (i = 0; i < word32_to_save; i++) { + /* by using DPORT_REG_WRITE, we avoid the need + * to call __builtin_bswap32 to address endiness + * + * a useful watch array cast to watch at runtime: + * ((uint32_t[32]) (*(volatile uint32_t *)(SHA_TEXT_BASE))) + * + * Write value to DPORT register (does not require protecting) + */ + DPORT_REG_WRITE(SHA_TEXT_BASE + (i*sizeof(word32)), *(data + i)); + /* memw confirmed auto inserted by compiler here */ } - /* notify hw to start process */ - esp_sha_start_process(ctx, address); - ESP_LOGV(TAG, "leave esp_process_block"); + /* notify hw to start process + * see ctx->sha_type + * reg data does not change until we are ready to read */ + esp_sha_start_process(ctx); + + ESP_LOGV(TAG, " leave esp_process_block"); } -/* -* retrieve sha digest from memory -*/ -static void esp_digest_state(WC_ESP32SHA* ctx, byte* hash, enum SHA_TYPE sha_type) -{ - /* registers */ - word32 SHA_LOAD_REG = SHA_1_LOAD_REG; - word32 SHA_BUSY_REG = SHA_1_BUSY_REG; +/* + * retrieve sha digest from memory + */ +int wc_esp_digest_state(WC_ESP32SHA* ctx, byte* hash) +{ ESP_LOGV(TAG, "enter esp_digest_state"); - /* sanity check */ - if(sha_type == SHA_INVALID) { - ESP_LOGE(TAG, "unexpected error. sha_type is invalid."); - return; + if (ctx == NULL) { + return -1; } - SHA_LOAD_REG += (sha_type << 4); - SHA_BUSY_REG += (sha_type << 4); + /* sanity check */ + if (ctx->sha_type == SHA_INVALID) { + ctx->mode = ESP32_SHA_FAIL_NEED_UNROLL; + ESP_LOGE(TAG, "unexpected error. sha_type is invalid."); + return -1; + } - if(ctx->isfirstblock == 1){ - /* no hardware use yet. Nothing to do yet */ - return ; + if (ctx == NULL) { + return -1; } /* wait until idle */ - esp_wait_until_idle(); + wc_esp_wait_until_idle(); + + /* each sha_type register is at a different location */ + 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: + SHA_LOAD_REG = SHA_384_LOAD_REG; + SHA_BUSY_REG = SHA_384_BUSY_REG; + 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 -1; + break; + } + + + if(ctx->isfirstblock == 1){ + /* no hardware use yet. Nothing to do yet */ + return 0; + } + /* LOAD final digest */ - DPORT_REG_WRITE(SHA_LOAD_REG, 1); - /* wait until done */ - while(DPORT_REG_READ(SHA_BUSY_REG) == 1){ } - esp_dport_access_read_buffer((word32*)(hash), SHA_TEXT_BASE, - esp_sha_digest_size(sha_type)/sizeof(word32)); + wc_esp_wait_until_idle(); + + /* MEMW instructions before volatile memory references to guarantee + * sequential consistency. At least one MEMW should be executed in + * between every load or store to a volatile variable + */ + asm volatile("memw"); + + /* put result in hash variable. + * + * ALERT - hardware specific. See esp_hw_support\port\esp32\dport_access.c + * + * note we read 4-byte word32's here via DPORT_SEQUENCE_REG_READ + * + * example: + * DPORT_SEQUENCE_REG_READ(address + i * 4); + */ + esp_dport_access_read_buffer( + (word32*)(hash), /* the result will be found in hash upon exit */ + SHA_TEXT_BASE, /* there's a fixed reg addy for all SHA */ + wc_esp_sha_digest_size(ctx->sha_type) / sizeof(word32) /* # 4-byte */ + ); #if defined(WOLFSSL_SHA512) || defined(WOLFSSL_SHA384) - if(sha_type==SHA2_384||sha_type==SHA2_512) { + if (ctx->sha_type == SHA2_384 || ctx->sha_type == SHA2_512) { word32 i; word32* pwrd1 = (word32*)(hash); /* swap value */ - for(i = 0; i ctx, SHA_START_REG, (const word32*)data, - WC_SHA_BLOCK_SIZE); + wc_esp_process_block(&sha->ctx, (const word32*)data, WC_SHA_BLOCK_SIZE); ESP_LOGV(TAG, "leave esp_sha_process"); return ret; } + /* * retrieve sha1 digest */ -int esp_sha_digest_process(struct wc_Sha* sha, byte blockproc) +int esp_sha_digest_process(struct wc_Sha* sha, byte blockprocess) { int ret = 0; ESP_LOGV(TAG, "enter esp_sha_digest_process"); - if(blockproc) { - word32 SHA_START_REG = SHA_1_START_REG; - - esp_process_block(&sha->ctx, SHA_START_REG, sha->buffer, - WC_SHA_BLOCK_SIZE); + if (blockprocess) { + wc_esp_process_block(&sha->ctx, sha->buffer, WC_SHA_BLOCK_SIZE); } - esp_digest_state(&sha->ctx, (byte*)sha->digest, SHA1); + wc_esp_digest_state(&sha->ctx, (byte*)sha->digest); ESP_LOGV(TAG, "leave esp_sha_digest_process"); @@ -321,69 +614,79 @@ int esp_sha_digest_process(struct wc_Sha* sha, byte blockproc) #ifndef NO_SHA256 /* * sha256 process +* +* repeatedly call this for [N] blocks of [WC_SHA256_BLOCK_SIZE] bytes of data */ int esp_sha256_process(struct wc_Sha256* sha, const byte* data) { int ret = 0; - word32 SHA_START_REG = SHA_1_START_REG; - ESP_LOGV(TAG, "enter esp_sha256_process"); + ESP_LOGV(TAG, " enter esp_sha256_process"); - /* start register offset */ - SHA_START_REG += (SHA2_256 << 4); + if ((&sha->ctx)->sha_type == SHA2_256) { +#if defined(DEBUG_WOLFSSL_VERBOSE) + ESP_LOGV(TAG, " confirmed sha type call match"); +#endif + } + else { + ret = -1; + ESP_LOGE(TAG, " ERROR sha type call mismatch"); + } - esp_process_block(&sha->ctx, SHA_START_REG, (const word32*)data, - WC_SHA256_BLOCK_SIZE); + wc_esp_process_block(&sha->ctx, (const word32*)data, WC_SHA256_BLOCK_SIZE); - ESP_LOGV(TAG, "leave esp_sha256_process"); + ESP_LOGV(TAG, " leave esp_sha256_process"); return ret; } + /* * retrieve sha256 digest +* +* note that wc_Sha256Final() in sha256.c expects to need to reverse byte +* order, even though we could have returned them in the right order. */ -int esp_sha256_digest_process(struct wc_Sha256* sha, byte blockproc) +int esp_sha256_digest_process(struct wc_Sha256* sha, byte blockprocess) { int ret = 0; ESP_LOGV(TAG, "enter esp_sha256_digest_process"); - if(blockproc) { - word32 SHA_START_REG = SHA_1_START_REG + (SHA2_256 << 4); + if(blockprocess) { - esp_process_block(&sha->ctx, SHA_START_REG, sha->buffer, - WC_SHA256_BLOCK_SIZE); + wc_esp_process_block(&sha->ctx, sha->buffer, WC_SHA256_BLOCK_SIZE); } - esp_digest_state(&sha->ctx, (byte*)sha->digest, SHA2_256); + wc_esp_digest_state(&sha->ctx, (byte*)sha->digest); ESP_LOGV(TAG, "leave esp_sha256_digest_process"); return ret; } + + #endif /* NO_SHA256 */ #if defined(WOLFSSL_SHA512) || defined(WOLFSSL_SHA384) /* -* sha512 proess. this is used for sha384 too. +* sha512 process. this is used for sha384 too. */ void esp_sha512_block(struct wc_Sha512* sha, const word32* data, byte isfinal) { - enum SHA_TYPE sha_type = sha->ctx.sha_type; - word32 SHA_START_REG = SHA_1_START_REG; - ESP_LOGV(TAG, "enter esp_sha512_block"); /* start register offset */ - SHA_START_REG += (sha_type << 4); 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; + 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 { + } + else { ByteReverseWords((word32*)sha->buffer, (word32*)sha->buffer, WC_SHA512_BLOCK_SIZE); if(isfinal){ @@ -393,7 +696,7 @@ void esp_sha512_block(struct wc_Sha512* sha, const word32* data, byte isfinal) rotlFixed64(sha->loLen, 32U); } - esp_process_block(&sha->ctx, SHA_START_REG, data, WC_SHA512_BLOCK_SIZE); + wc_esp_process_block(&sha->ctx, data, WC_SHA512_BLOCK_SIZE); } ESP_LOGV(TAG, "leave esp_sha512_block"); } @@ -424,7 +727,7 @@ int esp_sha512_digest_process(struct wc_Sha512* sha, byte blockproc) esp_sha512_block(sha, data, 1); } if(sha->ctx.mode != ESP32_SHA_SW) - esp_digest_state(&sha->ctx, (byte*)sha->digest, sha->ctx.sha_type); + wc_esp_digest_state(&sha->ctx, (byte*)sha->digest); ESP_LOGV(TAG, "leave esp_sha512_digest_process"); return 0; diff --git a/wolfcrypt/src/port/Espressif/esp32_util.c b/wolfcrypt/src/port/Espressif/esp32_util.c index d73cd2fe8..90d3c617e 100644 --- a/wolfcrypt/src/port/Espressif/esp32_util.c +++ b/wolfcrypt/src/port/Espressif/esp32_util.c @@ -1,6 +1,6 @@ /* esp32_util.c * - * Copyright (C) 2006-2021 wolfSSL Inc. + * Copyright (C) 2006-2022 wolfSSL Inc. * * This file is part of wolfSSL. * @@ -26,21 +26,57 @@ #include #include - +#include +/* + * initialize our mutex used to lock hardware access + * + * returns: + * 0 upon success, + * BAD_MUTEX_E for null mutex + * other value from wc_InitMutex() + * + */ int esp_CryptHwMutexInit(wolfSSL_Mutex* mutex) { + if (mutex == NULL) { + return BAD_MUTEX_E; + } + return wc_InitMutex(mutex); } +/* + * call the ESP-IDF mutex lock; xSemaphoreTake + * + */ int esp_CryptHwMutexLock(wolfSSL_Mutex* mutex, TickType_t xBlockTime) { + if (mutex == NULL) { + WOLFSSL_ERROR_MSG("esp_CryptHwMutexLock called with null mutex"); + return BAD_MUTEX_E; + } + #ifdef SINGLE_THREADED - return wc_LockMutex(mutex); + return wc_LockMutex(mutex); /* xSemaphoreTake take with portMAX_DELAY */ #else return ((xSemaphoreTake( *mutex, xBlockTime ) == pdTRUE) ? 0 : BAD_MUTEX_E); #endif } +/* + * call the ESP-IDF mutex UNlock; xSemaphoreGive + * + */ int esp_CryptHwMutexUnLock(wolfSSL_Mutex* mutex) { + if (mutex == NULL) { + WOLFSSL_ERROR_MSG("esp_CryptHwMutexLock called with null mutex"); + return BAD_MUTEX_E; + } + +#ifdef SINGLE_THREADED return wc_UnLockMutex(mutex); +#else + xSemaphoreGive(*mutex); + return 0; +#endif } #endif diff --git a/wolfcrypt/src/sha.c b/wolfcrypt/src/sha.c index 8113997fa..8a2cece1f 100644 --- a/wolfcrypt/src/sha.c +++ b/wolfcrypt/src/sha.c @@ -1,6 +1,6 @@ /* sha.c * - * Copyright (C) 2006-2021 wolfSSL Inc. + * Copyright (C) 2006-2022 wolfSSL Inc. * * This file is part of wolfSSL. * @@ -311,14 +311,15 @@ sha->ctx.isfirstblock = 1; sha->ctx.sha_type = SHA1; if(sha->ctx.mode == ESP32_SHA_HW){ + sha->ctx.lockDepth = 0; /* release hw engine */ - esp_sha_hw_unlock(); + esp_sha_hw_unlock(&(sha->ctx)); } /* always set mode as INIT * whether using HW or SW is determined at first call of update() */ sha->ctx.mode = ESP32_SHA_INIT; - + sha->ctx.lockDepth = 0; return ret; } @@ -538,6 +539,7 @@ int wc_InitSha_ex(wc_Sha* sha, void* heap, int devId) !defined(NO_WOLFSSL_ESP32WROOM32_CRYPT_HASH) sha->ctx.mode = ESP32_SHA_INIT; sha->ctx.isfirstblock = 1; + sha->ctx.lockDepth = 0; /* keep track of how many times lock is called */ #endif ret = InitSha(sha); if (ret != 0) @@ -616,7 +618,8 @@ int wc_ShaUpdate(wc_Sha* sha, const byte* data, word32 len) } if (sha->ctx.mode == ESP32_SHA_SW) { ret = XTRANSFORM(sha, (const byte*)local); - } else { + } + else { esp_sha_process(sha, (const byte*)local); } #else @@ -670,7 +673,8 @@ int wc_ShaUpdate(wc_Sha* sha, const byte* data, word32 len) } if (sha->ctx.mode == ESP32_SHA_SW){ ret = XTRANSFORM(sha, (const byte*)local32); - } else { + } + else { esp_sha_process(sha, (const byte*)local32); } #else @@ -753,7 +757,8 @@ int wc_ShaFinal(wc_Sha* sha, byte* hash) } if (sha->ctx.mode == ESP32_SHA_SW) { ret = XTRANSFORM(sha, (const byte*)local); - } else { + } + else { ret = esp_sha_process(sha, (const byte*)local); } #else @@ -793,7 +798,8 @@ int wc_ShaFinal(wc_Sha* sha, byte* hash) } if (sha->ctx.mode == ESP32_SHA_SW) { ret = XTRANSFORM(sha, (const byte*)local); - } else { + } + else { ret = esp_sha_digest_process(sha, 1); } #else @@ -886,13 +892,16 @@ int wc_ShaGetHash(wc_Sha* sha, byte* hash) if(sha->ctx.mode == ESP32_SHA_INIT){ esp_sha_try_hw_lock(&sha->ctx); } - if(sha->ctx.mode != ESP32_SHA_SW) + if (sha->ctx.mode != ESP32_SHA_SW) { + /* TODO check SW/HW logic */ esp_sha_digest_process(sha, 0); + } #endif ret = wc_ShaCopy(sha, &tmpSha); if (ret == 0) { - ret = wc_ShaFinal(&tmpSha, hash); + /* if HW failed, use SW */ + ret = wc_ShaFinal(&tmpSha, hash); #if defined(WOLFSSL_ESP32WROOM32_CRYPT) && \ !defined(NO_WOLFSSL_ESP32WROOM32_CRYPT_HASH) sha->ctx.mode = ESP32_SHA_SW; diff --git a/wolfcrypt/src/sha256.c b/wolfcrypt/src/sha256.c index 6da015153..5a1946645 100644 --- a/wolfcrypt/src/sha256.c +++ b/wolfcrypt/src/sha256.c @@ -1,6 +1,6 @@ /* sha256.c * - * Copyright (C) 2006-2021 wolfSSL Inc. + * Copyright (C) 2006-2022 wolfSSL Inc. * * This file is part of wolfSSL. * @@ -19,7 +19,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ -/* For more info on the algorithm, see https://tools.ietf.org/html/rfc6234 */ +/* For more info on the algorithm, see https://tools.ietf.org/html/rfc6234 + * + * For more information on NIST FIPS PUB 180-4, see + * https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf + */ + /* DESCRIPTION @@ -28,7 +33,11 @@ SHA-256 performs processing on message blocks to produce a final hash digest output. It can be used to hash a message, M, having a length of L bits, where 0 <= L < 2^64. +Note that in some cases, hardware acceleration may be enabled, depending +on the specific device platform. + */ + #ifdef HAVE_CONFIG_H #include #endif @@ -74,6 +83,19 @@ where 0 <= L < 2^64. #include #endif +/* determine if we are using Espressif SHA hardware acceleration */ +#if defined(WOLFSSL_ESP32WROOM32_CRYPT) && \ + !defined(NO_WOLFSSL_ESP32WROOM32_CRYPT_HASH) + /* define a single keyword for simplicity & readability + * + * by default the HW acceleration is on for ESP32-WROOM32 + * but individual components can be turned off. + */ + #define WOLFSSL_USE_ESP32WROOM32_CRYPT_HASH_HW +#else + #undef USE_ESP32WROOM32_CRYPT_HASH +#endif + /* fips wrapper calls, user can call direct */ #if defined(HAVE_FIPS) && \ (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2)) @@ -694,14 +716,17 @@ static int InitSha256(wc_Sha256* sha256) return ret; } -#elif defined(WOLFSSL_ESP32WROOM32_CRYPT) && \ - !defined(NO_WOLFSSL_ESP32WROOM32_CRYPT_HASH) +#elif defined(WOLFSSL_USE_ESP32WROOM32_CRYPT_HASH_HW) + /* HW may fail since there's only one, so we still need SW */ #define NEED_SOFT_SHA256 + /* + * soft SHA needs initialization digest, but HW does not. + */ static int InitSha256(wc_Sha256* sha256) { - int ret = 0; + int ret = 0; /* zero = success */ if (sha256 == NULL) return BAD_FUNC_ARG; @@ -725,8 +750,9 @@ static int InitSha256(wc_Sha256* sha256) sha256->ctx.sha_type = SHA2_256; if(sha256->ctx.mode == ESP32_SHA_HW) { /* release hw */ - esp_sha_hw_unlock(); + esp_sha_hw_unlock(&(sha256->ctx)); } + /* always set mode as INIT * whether using HW or SW is determined at first call of update() */ @@ -734,9 +760,13 @@ static int InitSha256(wc_Sha256* sha256) return ret; } + + /* + * wolfCrypt InitSha256 external wrapper + */ int wc_InitSha256_ex(wc_Sha256* sha256, void* heap, int devId) { - int ret = 0; + int ret = 0; /* zero = success */ if (sha256 == NULL) return BAD_FUNC_ARG; @@ -744,6 +774,7 @@ static int InitSha256(wc_Sha256* sha256) XMEMSET(sha256, 0, sizeof(wc_Sha256)); sha256->ctx.mode = ESP32_SHA_INIT; sha256->ctx.isfirstblock = 1; + sha256->ctx.lockDepth = 0; /* we'll keep track of our own lock depth */ (void)devId; ret = InitSha256(sha256); @@ -786,7 +817,6 @@ static int InitSha256(wc_Sha256* sha256) int ret = 0; if (sha256 == NULL) return BAD_FUNC_ARG; - ret = InitSha256(sha256); if (ret != 0) return ret; @@ -1052,14 +1082,16 @@ static int InitSha256(wc_Sha256* sha256) } #endif - #if defined(WOLFSSL_ESP32WROOM32_CRYPT) && \ - !defined(NO_WOLFSSL_ESP32WROOM32_CRYPT_HASH) - if (sha256->ctx.mode == ESP32_SHA_INIT){ + #if defined(WOLFSSL_USE_ESP32WROOM32_CRYPT_HASH_HW) + if (sha256->ctx.mode == ESP32_SHA_INIT || + sha256->ctx.mode == ESP32_SHA_FAIL_NEED_UNROLL) { esp_sha_try_hw_lock(&sha256->ctx); } - if (sha256->ctx.mode == ESP32_SHA_SW){ + + if (sha256->ctx.mode == ESP32_SHA_SW) { ret = XTRANSFORM(sha256, (const byte*)local); - } else { + } + else { esp_sha256_process(sha256, (const byte*)local); } #else @@ -1129,17 +1161,17 @@ static int InitSha256(wc_Sha256* sha256) } #endif - #if defined(WOLFSSL_ESP32WROOM32_CRYPT) && \ - !defined(NO_WOLFSSL_ESP32WROOM32_CRYPT_HASH) + #if defined(WOLFSSL_USE_ESP32WROOM32_CRYPT_HASH_HW) if (sha256->ctx.mode == ESP32_SHA_INIT){ esp_sha_try_hw_lock(&sha256->ctx); } - if (sha256->ctx.mode == ESP32_SHA_SW){ + if (sha256->ctx.mode == ESP32_SHA_SW) { ret = XTRANSFORM(sha256, (const byte*)local32); - } else { + } + else { esp_sha256_process(sha256, (const byte*)local32); } - #else +#else ret = XTRANSFORM(sha256, (const byte*)local32); #endif @@ -1223,14 +1255,14 @@ static int InitSha256(wc_Sha256* sha256) } #endif - #if defined(WOLFSSL_ESP32WROOM32_CRYPT) && \ - !defined(NO_WOLFSSL_ESP32WROOM32_CRYPT_HASH) + #if defined(WOLFSSL_USE_ESP32WROOM32_CRYPT_HASH_HW) if (sha256->ctx.mode == ESP32_SHA_INIT) { esp_sha_try_hw_lock(&sha256->ctx); } if (sha256->ctx.mode == ESP32_SHA_SW) { ret = XTRANSFORM(sha256, (const byte*)local); - } else { + } + else { ret = esp_sha256_process(sha256, (const byte*)local); } #else @@ -1280,14 +1312,14 @@ static int InitSha256(wc_Sha256* sha256) } #endif - #if defined(WOLFSSL_ESP32WROOM32_CRYPT) && \ - !defined(NO_WOLFSSL_ESP32WROOM32_CRYPT_HASH) + #if defined(WOLFSSL_USE_ESP32WROOM32_CRYPT_HASH_HW) if (sha256->ctx.mode == ESP32_SHA_INIT) { esp_sha_try_hw_lock(&sha256->ctx); } if (sha256->ctx.mode == ESP32_SHA_SW) { ret = XTRANSFORM(sha256, (const byte*)local); - } else { + } + else { ret = esp_sha256_digest_process(sha256, 1); } #else @@ -1385,7 +1417,6 @@ static int InitSha256(wc_Sha256* sha256) { if (sha224 == NULL) return BAD_FUNC_ARG; - (void)devId; (void)heap; @@ -1848,9 +1879,15 @@ int wc_Sha256GetHash(wc_Sha256* sha256, byte* hash) if (sha256 == NULL || hash == NULL) return BAD_FUNC_ARG; -#if defined(WOLFSSL_ESP32WROOM32_CRYPT) && \ - !defined(NO_WOLFSSL_ESP32WROOM32_CRYPT_HASH) - if(sha256->ctx.mode == ESP32_SHA_INIT){ +#if defined(WOLFSSL_USE_ESP32WROOM32_CRYPT_HASH_HW) + + /* ESP32 hardware can only handle only 1 active hardware hashing + * at a time. If the mutex lock is acquired the first time then + * that Sha256 instance has exclusive access to hardware. The + * final or free needs to release the mutex. Operations that + * do not get the lock fallback to software based Sha256 */ + + if(sha256->ctx.mode == ESP32_SHA_INIT){ esp_sha_try_hw_lock(&sha256->ctx); } if(sha256->ctx.mode == ESP32_SHA_HW) @@ -1861,13 +1898,20 @@ int wc_Sha256GetHash(wc_Sha256* sha256, byte* hash) ret = wc_Sha256Copy(sha256, &tmpSha256); if (ret == 0) { ret = wc_Sha256Final(&tmpSha256, hash); -#if defined(WOLFSSL_ESP32WROOM32_CRYPT) && \ - !defined(NO_WOLFSSL_ESP32WROOM32_CRYPT_HASH) + +#if defined(WOLFSSL_USE_ESP32WROOM32_CRYPT_HASH_HW) + { sha256->ctx.mode = ESP32_SHA_SW; + } #endif wc_Sha256Free(&tmpSha256); } + +#if defined(WOLFSSL_USE_ESP32WROOM32_CRYPT_HASH_HW) + /* TODO: Make sure the ESP32 crypto mutex is released (in case final is not + * called */ +#endif return ret; } int wc_Sha256Copy(wc_Sha256* src, wc_Sha256* dst) @@ -1893,12 +1937,14 @@ int wc_Sha256Copy(wc_Sha256* src, wc_Sha256* dst) #ifdef WOLFSSL_PIC32MZ_HASH ret = wc_Pic32HashCopy(&src->cache, &dst->cache); #endif -#if defined(WOLFSSL_ESP32WROOM32_CRYPT) && \ - !defined(NO_WOLFSSL_ESP32WROOM32_CRYPT_HASH) - dst->ctx.mode = src->ctx.mode; - dst->ctx.isfirstblock = src->ctx.isfirstblock; - dst->ctx.sha_type = src->ctx.sha_type; + +#if defined(WOLFSSL_USE_ESP32WROOM32_CRYPT_HASH_HW) + dst->ctx.mode = src->ctx.mode; + dst->ctx.isfirstblock = src->ctx.isfirstblock; + dst->ctx.sha_type = src->ctx.sha_type; + dst->ctx.lockDepth = src->ctx.lockDepth; #endif + #ifdef WOLFSSL_HASH_FLAGS dst->flags |= WC_HASH_FLAG_ISCOPY; #endif diff --git a/wolfcrypt/src/sha512.c b/wolfcrypt/src/sha512.c index f6c863665..94164334a 100644 --- a/wolfcrypt/src/sha512.c +++ b/wolfcrypt/src/sha512.c @@ -285,7 +285,7 @@ static int InitSha512(wc_Sha512* sha512) sha512->ctx.isfirstblock = 1; if(sha512->ctx.mode == ESP32_SHA_HW) { /* release hw */ - esp_sha_hw_unlock(); + esp_sha_hw_unlock(&(sha512->ctx)); } /* always set mode as INIT * whether using HW or SW is determined at first call of update() @@ -332,7 +332,7 @@ static int InitSha512_224(wc_Sha512* sha512) sha512->ctx.isfirstblock = 1; if(sha512->ctx.mode == ESP32_SHA_HW) { /* release hw */ - esp_sha_hw_unlock(); + esp_sha_hw_unlock(&(sha512->ctx)); } /* always set mode as INIT * whether using HW or SW is determined at first call of update() @@ -381,7 +381,7 @@ static int InitSha512_256(wc_Sha512* sha512) sha512->ctx.isfirstblock = 1; if(sha512->ctx.mode == ESP32_SHA_HW) { /* release hw */ - esp_sha_hw_unlock(); + esp_sha_hw_unlock(&(sha512->ctx)); } /* always set mode as INIT * whether using HW or SW is determined at first call of update() @@ -1310,7 +1310,7 @@ static int InitSha384(wc_Sha384* sha384) sha384->ctx.isfirstblock = 1; if(sha384->ctx.mode == ESP32_SHA_HW) { /* release hw */ - esp_sha_hw_unlock(); + esp_sha_hw_unlock(&(sha512->ctx)); } /* always set mode as INIT * whether using HW or SW is determined at first call of update() diff --git a/wolfssl/wolfcrypt/port/Espressif/esp32-crypt.h b/wolfssl/wolfcrypt/port/Espressif/esp32-crypt.h index f64d616cb..9b3b79a71 100644 --- a/wolfssl/wolfcrypt/port/Espressif/esp32-crypt.h +++ b/wolfssl/wolfcrypt/port/Espressif/esp32-crypt.h @@ -22,39 +22,44 @@ #define __ESP32_CRYPT_H__ +#ifdef WOLFSSL_USER_SETTINGS + #include "user_settings.h" +#endif + #include "esp_idf_version.h" #include "esp_types.h" #include "esp_log.h" #ifdef WOLFSSL_ESP32WROOM32_CRYPT_DEBUG -#undef LOG_LOCAL_LEVEL -#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG + #undef LOG_LOCAL_LEVEL + #define LOG_LOCAL_LEVEL ESP_LOG_DEBUG #else -#undef LOG_LOCAL_LEVEL -#define LOG_LOCAL_LEVEL ESP_LOG_ERROR + #undef LOG_LOCAL_LEVEL + #define LOG_LOCAL_LEVEL ESP_LOG_DEBUG #endif #include #include "soc/dport_reg.h" #include "soc/hwcrypto_reg.h" + #if ESP_IDF_VERSION_MAJOR < 5 -#include "soc/cpu.h" + #include "soc/cpu.h" #endif #if ESP_IDF_VERSION_MAJOR >= 5 - #include "esp_private/periph_ctrl.h" + #include "esp_private/periph_ctrl.h" #else - #include "driver/periph_ctrl.h" + #include "driver/periph_ctrl.h" #endif #if ESP_IDF_VERSION_MAJOR >= 4 - #include + #include #else - #include + #include #endif #ifdef __cplusplus -extern "C" { + extern "C" { #endif int esp_CryptHwMutexInit(wolfSSL_Mutex* mutex); @@ -63,31 +68,31 @@ int esp_CryptHwMutexUnLock(wolfSSL_Mutex* mutex); #ifndef NO_AES -#if ESP_IDF_VERSION_MAJOR >= 4 -#include "esp32/rom/aes.h" -#else -#include "rom/aes.h" -#endif + #if ESP_IDF_VERSION_MAJOR >= 4 + #include "esp32/rom/aes.h" + #else + #include "rom/aes.h" + #endif -typedef enum tagES32_AES_PROCESS { - ESP32_AES_LOCKHW = 1, - ESP32_AES_UPDATEKEY_ENCRYPT = 2, - ESP32_AES_UPDATEKEY_DECRYPT = 3, - ESP32_AES_UNLOCKHW = 4 -} ESP32_AESPROCESS; + typedef enum tagES32_AES_PROCESS { + ESP32_AES_LOCKHW = 1, + ESP32_AES_UPDATEKEY_ENCRYPT = 2, + ESP32_AES_UPDATEKEY_DECRYPT = 3, + ESP32_AES_UNLOCKHW = 4 + } ESP32_AESPROCESS; -struct Aes; -int wc_esp32AesCbcEncrypt(struct Aes* aes, byte* out, const byte* in, word32 sz); -int wc_esp32AesCbcDecrypt(struct Aes* aes, byte* out, const byte* in, word32 sz); -int wc_esp32AesEncrypt(struct Aes *aes, const byte* in, byte* out); -int wc_esp32AesDecrypt(struct Aes *aes, const byte* in, byte* out); + struct Aes; /* see aes.h */ + int wc_esp32AesCbcEncrypt(struct Aes* aes, byte* out, const byte* in, word32 sz); + int wc_esp32AesCbcDecrypt(struct Aes* aes, byte* out, const byte* in, word32 sz); + int wc_esp32AesEncrypt(struct Aes *aes, const byte* in, byte* out); + int wc_esp32AesDecrypt(struct Aes *aes, const byte* in, byte* out); #endif #ifdef WOLFSSL_ESP32WROOM32_CRYPT_DEBUG -void wc_esp32TimerStart(); -uint64_t wc_esp32elapsedTime(); + void wc_esp32TimerStart(); + uint64_t wc_esp32elapsedTime(); #endif /* WOLFSSL_ESP32WROOM32_CRYPT_DEBUG */ @@ -95,66 +100,107 @@ uint64_t wc_esp32elapsedTime(); defined(WOLFSSL_SHA512)) && \ !defined(NO_WOLFSSL_ESP32WROOM32_CRYPT_HASH) -/* RAW hash function APIs are not implemented with esp32 hardware acceleration*/ -#define WOLFSSL_NO_HASH_RAW -#define SHA_CTX ETS_SHAContext -#if ESP_IDF_VERSION_MAJOR >= 4 -#include "esp32/rom/sha.h" -#else -#include "rom/sha.h" -#endif -#undef SHA_CTX + /* RAW hash function APIs are not implemented with esp32 hardware acceleration*/ + #define WOLFSSL_NO_HASH_RAW + #define SHA_CTX ETS_SHAContext -typedef enum { - ESP32_SHA_INIT = 0, - ESP32_SHA_HW = 1, - ESP32_SHA_SW = 2, -} ESP32_DOSHA; + #if ESP_IDF_VERSION_MAJOR >= 4 + #include "esp32/rom/sha.h" + #else + #include "rom/sha.h" + #endif -typedef struct { - byte isfirstblock; - /* 0 , 1 hard, 2 soft */ - byte mode; - /* sha_type */ - enum SHA_TYPE sha_type; -} WC_ESP32SHA; + #undef SHA_CTX -int esp_sha_try_hw_lock(WC_ESP32SHA* ctx); -void esp_sha_hw_unlock( void ); + typedef enum { + ESP32_SHA_INIT = 0, + ESP32_SHA_HW = 1, + ESP32_SHA_SW = 2, + ESP32_SHA_FAIL_NEED_UNROLL = -1 + } ESP32_MODE; -struct wc_Sha; -int esp_sha_digest_process(struct wc_Sha* sha, byte bockprocess); -int esp_sha_process(struct wc_Sha* sha, const byte* data); + typedef struct { + byte isfirstblock; -#ifndef NO_SHA256 - struct wc_Sha256; - int esp_sha256_digest_process(struct wc_Sha256* sha, byte bockprocess); - int esp_sha256_process(struct wc_Sha256* sha, const byte* data); -#endif + ESP32_MODE mode; /* typically 0 init, 1 HW, 2 SW */ -#if defined(WOLFSSL_SHA512) || defined(WOLFSSL_SHA384) - struct wc_Sha512; - int esp_sha512_process(struct wc_Sha512* sha); - int esp_sha512_digest_process(struct wc_Sha512* sha, byte blockproc); -#endif + /* we'll keep track of our own locks. + * actual enable/disable only occurs for ref_counts[periph] == 0 */ + int lockDepth; /* see ref_counts[periph] in periph_ctrl.c */ + + enum SHA_TYPE sha_type; + } WC_ESP32SHA; + + int esp_sha_try_hw_lock(WC_ESP32SHA* ctx); + int esp_sha_hw_unlock(WC_ESP32SHA* ctx); + + struct wc_Sha; + int esp_sha_digest_process(struct wc_Sha* sha, byte blockprocess); + int esp_sha_process(struct wc_Sha* sha, const byte* data); + + #ifndef NO_SHA256 + struct wc_Sha256; + int esp_sha256_digest_process(struct wc_Sha256* sha, byte blockprocess); + int esp_sha256_process(struct wc_Sha256* sha, const byte* data); + int esp32_Transform_Sha256_demo(struct wc_Sha256* sha256, const byte* data); + + + #endif + + /* TODO do we really call esp_sha512_process for WOLFSSL_SHA384 ? */ + #if defined(WOLFSSL_SHA512) || defined(WOLFSSL_SHA384) + struct wc_Sha512; + int esp_sha512_process(struct wc_Sha512* sha); + int esp_sha512_digest_process(struct wc_Sha512* sha, byte blockproc); + #endif #endif /* NO_SHA && */ + #if !defined(NO_RSA) || defined(HAVE_ECC) -#if !defined(ESP_RSA_TIMEOUT_CNT) - #define ESP_RSA_TIMEOUT_CNT 0x249F00 -#endif + #if !defined(ESP_RSA_TIMEOUT_CNT) + #define ESP_RSA_TIMEOUT_CNT 0x249F00 + #endif -struct fp_int; -int esp_mp_mul(struct fp_int* X, struct fp_int* Y, struct fp_int* Z); -int esp_mp_exptmod(struct fp_int* G, struct fp_int* X, word32 Xbits, struct fp_int* P, - struct fp_int* Y); -int esp_mp_mulmod(struct fp_int* X, struct fp_int* Y, struct fp_int* M, - struct fp_int* Z); + /* operands can be up to 4096 bits long. + * here we store the bits in wolfSSL fp_int struct. + * see wolfCrypt tfm.h + */ + struct fp_int; + + + /* + * The parameter names in the Espressif implementation are arbitrary. + * + * The wolfSSL names come from DH: Y=G^x mod M (see wolfcrypt/tfm.h) + * + * G=base, X is the private exponent, Y is the public value w + **/ + + /* Z = (X ^ Y) mod M : Espressif generic notation */ + /* Y = (G ^ X) mod P : wolfSSL DH reference notation */ + int esp_mp_exptmod(struct fp_int* X, /* G */ + struct fp_int* Y, /* X */ + word32 Xbits, /* Ys typically = fp_count_bits (X) */ + struct fp_int* M, /* P */ + struct fp_int* Z); /* Y */ + + /* Z = X * Y */ + int esp_mp_mul(struct fp_int* X, + struct fp_int* Y, + struct fp_int* Z); + + + /* Z = X * Y (mod M) */ + int esp_mp_mulmod(struct fp_int* X, + struct fp_int* Y, + struct fp_int* M, + struct fp_int* Z); #endif /* NO_RSA || HAVE_ECC*/ +/* end c++ wrapper */ #ifdef __cplusplus } #endif diff --git a/wolfssl/wolfcrypt/types.h b/wolfssl/wolfcrypt/types.h index 13f8d3812..cac7558ff 100644 --- a/wolfssl/wolfcrypt/types.h +++ b/wolfssl/wolfcrypt/types.h @@ -1,6 +1,6 @@ /* types.h * - * Copyright (C) 2006-2021 wolfSSL Inc. + * Copyright (C) 2006-2022 wolfSSL Inc. * * This file is part of wolfSSL. * @@ -714,7 +714,7 @@ typedef struct w64wrapper { /* In cases when truncation is expected the caller needs*/ /* to check the return value from the function so that */ /* compiler doesn't complain. */ - /* xtensa-esp32-elf v8.2.0 warns trancation at */ + /* xtensa-esp32-elf v8.2.0 warns truncation at */ /* GetAsnTimeString() */ static WC_INLINE int _xsnprintf_(char *s, size_t n, const char *format, ...)