Add ESP32 ROM SHA Hardware Acceleration to BearSSL (#23819)

* Add ESP32 ROM SHA Hardware Acceleration to BearSSL

* USE_SHA_ROM by default for all esp32x variants

---------

Co-authored-by: Jason2866 <24528715+Jason2866@users.noreply.github.com>
This commit is contained in:
Christian Baars 2025-08-24 15:32:47 +02:00 committed by GitHub
parent ba6177861a
commit 30f770ca4a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 394 additions and 0 deletions

View File

@ -0,0 +1,393 @@
/* _sha_rom_idf5x.c — BearSSL dropin with ESP32 ROM SHA acceleration
*
* TESTONLY IMPLEMENTATION SERIALIZED VIA GLOBAL SPINLOCK
*
* Overview:
* ---------
* - Provides BearSSL hash functions backed by the ESP32 ROM SHA engine.
* - Uses a single global ROM SHA_CTX instance.
* - Access is serialized with a global portMUX spinlock.
*
* Concurrency Warning:
* --------------------
* - This locking only prevents simultaneous entry into the ROM SHA engine.
* - It does NOT make multiple concurrent hash contexts safe.
* - Interleaving operations from different contexts will corrupt state.
* - Only one hash context may be active at any given time.
*
* Platform Notes:
* ---------------
* - ESP32 (ESP_PLATFORM): Uses ROM SHA acceleration as described above.
* - ESP8266 / other targets: This translation unit compiles to nothing;
* stock BearSSL symbols are provided instead.
*
* SHA256 Limitation on ESP32:
* ----------------------------
* - The ESP32 ROM SHA256 implementation shares internal state with the
* hardware engine; without pause/resume support, state cannot be saved
* and restored safely.
* - In this single global context model, running SHA256 concurrently
* or interleaving with other operations will corrupt the ROM state.
* - Therefore, SHA256 acceleration is only enabled when
* SOC_SHA_SUPPORT_RESUME is available; otherwise it is unsafe here.
* - When unsupported, SHA256 silently falls back to BearSSLs software
* implementation at build time (callers see no behavioral change).
*
* Supported ROM Algorithms (if present in ROM):
* ----------------------------------------------
* SHA1
* SHA224
* SHA256 (see limitation and fallback above)
* SHA384
* SHA512
*/
#include "t_inner.h"
#if defined(USE_SHA_ROM)
#if defined(ESP_PLATFORM) && !defined(ESP8266)
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#if __has_include("soc/sha_caps.h")
# include "soc/sha_caps.h"
#elif __has_include("soc/soc_caps.h")
# include "soc/soc_caps.h"
#else
# error "No SHA capability header found"
#endif
#if __has_include("esp_rom_sha.h")
# include "esp_rom_sha.h"
#elif __has_include("rom/sha.h")
# include "rom/sha.h"
#else
# error "No ROM SHA header found"
#endif
#define HAVE_ROM_SHA1 (SOC_SHA_SUPPORT_SHA1)
#define HAVE_ROM_SHA224 (SOC_SHA_SUPPORT_SHA224)
#define HAVE_ROM_SHA256 (SOC_SHA_SUPPORT_SHA256)
#define HAVE_ROM_SHA384 (SOC_SHA_SUPPORT_SHA384)
#define HAVE_ROM_SHA512 (SOC_SHA_SUPPORT_SHA512)
#if defined(SOC_SHA_SUPPORT_RESUME)
/* Newer chips: mode passed to init, update has no mode */
#define ROM_SHA_ENABLE() ets_sha_enable()
#define ROM_SHA_DISABLE() ets_sha_disable()
#define ROM_SHA_INIT_MODE(ctx, mode) ets_sha_init((ctx), (mode))
#define ROM_SHA_UPDATE_MODE(ctx, mode, d, l, last) \
ets_sha_update((ctx), (const unsigned char*)(d), (uint32_t)(l), (last))
#define ROM_SHA_FINISH_MODE(ctx, mode, out) ets_sha_finish((ctx), (unsigned char*)(out))
#define ROM_SHA_FINALIZE_MODE(ctx, mode, out) \
do { ROM_SHA_UPDATE_MODE((ctx), mode, NULL, 0, true); ROM_SHA_FINISH_MODE((ctx), mode, (out)); } while (0)
#else
/* Old ESP32: mode passed to update/finish, init takes only ctx */
#define ROM_SHA_ENABLE() ets_sha_enable()
#define ROM_SHA_DISABLE() ets_sha_disable()
#define ROM_SHA_INIT_MODE(ctx, mode) ets_sha_init((ctx))
#define ROM_SHA_UPDATE_MODE(ctx, mode, d, l, last) \
ets_sha_update((ctx), (mode), (const uint8_t*)(d), (size_t)((l) * 8))
#define ROM_SHA_FINISH_MODE(ctx, mode, out) ets_sha_finish((ctx), (mode), (uint8_t*)(out))
#define ROM_SHA_FINALIZE_MODE(ctx, mode, out) \
do { ROM_SHA_UPDATE_MODE((ctx), mode, NULL, 0, true); ROM_SHA_FINISH_MODE((ctx), mode, (out)); } while (0)
#endif
/* One global ROM context; accesses serialized across cores/tasks. */
static SHA_CTX rom_ctx;
static portMUX_TYPE s_sha_mux = portMUX_INITIALIZER_UNLOCKED;
#define SHA_ENTER() portENTER_CRITICAL(&s_sha_mux)
#define SHA_EXIT() portEXIT_CRITICAL(&s_sha_mux)
/* ================================================================
* SHA-1 (ROM path, no save/restore)
* ================================================================ */
#if HAVE_ROM_SHA1
void br_sha1_init(br_sha1_context *cc) {
SHA_ENTER();
cc->vtable = &br_sha1_vtable;
cc->count = 0;
ROM_SHA_ENABLE();
ROM_SHA_INIT_MODE(&rom_ctx, SHA1);
SHA_EXIT();
}
void br_sha1_update(br_sha1_context *cc, const void *data, size_t len) {
if (!len) return;
SHA_ENTER();
ROM_SHA_UPDATE_MODE(&rom_ctx, SHA1, data, len, false);
cc->count += len;
SHA_EXIT();
}
void br_sha1_out(const br_sha1_context *cc, void *out) {
(void)cc;
SHA_ENTER();
ROM_SHA_FINALIZE_MODE(&rom_ctx, SHA1, out);
ROM_SHA_INIT_MODE(&rom_ctx, SHA1);
SHA_EXIT();
}
const br_hash_class br_sha1_vtable PROGMEM = {
sizeof(br_sha1_context),
BR_HASHDESC_ID(br_sha1_ID)
| BR_HASHDESC_OUT(20)
| BR_HASHDESC_LBLEN(6)
| BR_HASHDESC_MD_PADDING
| BR_HASHDESC_MD_PADDING_BE,
(void (*)(const br_hash_class **)) &br_sha1_init,
(void (*)(const br_hash_class **, const void *, size_t)) &br_sha1_update,
(void (*)(const br_hash_class *const *, void *)) &br_sha1_out,
NULL,
NULL
};
#endif
/* ================================================================
* SHA-224 (ROM path, no save/restore)
* ================================================================ */
/* ================================================================
* SHA-224 (ROM path, no save/restore)
* ================================================================ */
#if HAVE_ROM_SHA224
void br_sha224_init(br_sha224_context *cc) {
SHA_ENTER();
cc->vtable = &br_sha224_vtable;
cc->count = 0;
ROM_SHA_ENABLE();
ROM_SHA_INIT_MODE(&rom_ctx, SHA2_224);
SHA_EXIT();
}
void br_sha224_update(br_sha224_context *cc, const void *data, size_t len) {
if (!len) return;
SHA_ENTER();
ROM_SHA_UPDATE_MODE(&rom_ctx, SHA2_224, data, len, false);
cc->count += len;
SHA_EXIT();
}
void br_sha224_out(const br_sha224_context *cc, void *out) {
(void)cc;
uint8_t tmp[32];
SHA_ENTER();
ROM_SHA_FINALIZE_MODE(&rom_ctx, SHA2_224, tmp);
memcpy(out, tmp, 28);
ROM_SHA_INIT_MODE(&rom_ctx, SHA2_224);
SHA_EXIT();
}
const br_hash_class br_sha224_vtable PROGMEM = {
sizeof(br_sha224_context),
BR_HASHDESC_ID(br_sha224_ID)
| BR_HASHDESC_OUT(28)
| BR_HASHDESC_LBLEN(6)
| BR_HASHDESC_MD_PADDING
| BR_HASHDESC_MD_PADDING_BE,
(void (*)(const br_hash_class **)) &br_sha224_init,
(void (*)(const br_hash_class **, const void *, size_t)) &br_sha224_update,
(void (*)(const br_hash_class *const *, void *)) &br_sha224_out,
NULL,
NULL
};
#endif /* HAVE_ROM_SHA224 */
/* ================================================================
* SHA-256 with ROM acceleration + per-blob replay save/restore
* ================================================================ */
#if HAVE_ROM_SHA256 && defined(SOC_SHA_SUPPORT_RESUME)
#undef br_sha256_init
#undef br_sha256_update
#undef br_sha256_out
#undef br_sha256_state
#undef br_sha256_set_state
#define S256_CAP 64
/* Capture buffer for current context */
static struct {
uint8_t buf[S256_CAP];
uint8_t len;
} s256_capture;
void br_sha256_init(br_sha256_context *cc)
{
SHA_ENTER();
cc->vtable = &br_sha256_vtable;
cc->count = 0;
s256_capture.len = 0;
ROM_SHA_ENABLE();
ROM_SHA_INIT_MODE(&rom_ctx, SHA2_256);
SHA_EXIT();
}
void br_sha256_update(br_sha256_context *cc, const void *data, size_t len)
{
if (!len) return;
const uint8_t *dp = (const uint8_t *)data;
SHA_ENTER();
ROM_SHA_UPDATE_MODE(&rom_ctx, SHA2_256, dp, len, false);
cc->count += len;
if (s256_capture.len < S256_CAP) {
size_t want = S256_CAP - s256_capture.len;
size_t take = (len < want) ? len : want;
memcpy(s256_capture.buf + s256_capture.len, dp, take);
s256_capture.len += (uint8_t)take;
}
SHA_EXIT();
}
void br_sha256_out(const br_sha256_context *cc, void *out)
{
(void)cc;
SHA_ENTER();
ROM_SHA_FINALIZE_MODE(&rom_ctx, SHA2_256, out);
ROM_SHA_INIT_MODE(&rom_ctx, SHA2_256);
SHA_EXIT();
}
uint64_t br_sha256_state(const br_sha256_context *cc, void *dst)
{
/* Store exactly the captured bytes in the blob */
memset(dst, 0, S256_CAP);
memcpy(dst, s256_capture.buf, s256_capture.len);
return cc->count;
}
void br_sha256_set_state(br_sha256_context *cc, const void *src, uint64_t count)
{
const uint8_t *sp = (const uint8_t *)src;
SHA_ENTER();
ROM_SHA_INIT_MODE(&rom_ctx, SHA2_256);
if (count <= S256_CAP) {
ROM_SHA_UPDATE_MODE(&rom_ctx, SHA2_256, sp, (size_t)count, false);
cc->count = count;
} else {
cc->count = 0;
s256_capture.len = 0;
}
SHA_EXIT();
}
const br_hash_class br_sha256_vtable PROGMEM = {
sizeof(br_sha256_context),
BR_HASHDESC_ID(br_sha256_ID)
| BR_HASHDESC_OUT(32)
| BR_HASHDESC_STATE(S256_CAP) /* store full ipad/opad block */
| BR_HASHDESC_LBLEN(6)
| BR_HASHDESC_MD_PADDING
| BR_HASHDESC_MD_PADDING_BE,
(void (*)(const br_hash_class **)) &br_sha256_init,
(void (*)(const br_hash_class **, const void *, size_t)) &br_sha256_update,
(void (*)(const br_hash_class *const *, void *)) &br_sha256_out,
(uint64_t (*)(const br_hash_class *const *, void *)) &br_sha256_state,
(void (*)(const br_hash_class **, const void *, uint64_t)) &br_sha256_set_state
};
#endif /* HAVE_ROM_SHA256 */
/* ================================================================
* SHA-384 (ROM path, no save/restore)
* ================================================================ */
#if HAVE_ROM_SHA384
void br_sha384_init(br_sha384_context *cc) {
SHA_ENTER();
cc->vtable = &br_sha384_vtable;
cc->count = 0;
ROM_SHA_ENABLE();
ROM_SHA_INIT_MODE(&rom_ctx, SHA2_384);
SHA_EXIT();
}
void br_sha384_update(br_sha384_context *cc, const void *data, size_t len) {
if (!len) return;
SHA_ENTER();
ROM_SHA_UPDATE_MODE(&rom_ctx, SHA2_384, data, len, false);
cc->count += len;
SHA_EXIT();
}
void br_sha384_out(const br_sha384_context *cc, void *out) {
(void)cc;
uint8_t tmp[64];
SHA_ENTER();
ROM_SHA_FINALIZE_MODE(&rom_ctx, SHA2_384, tmp);
memcpy(out, tmp, 48);
ROM_SHA_INIT_MODE(&rom_ctx, SHA2_384);
SHA_EXIT();
}
const br_hash_class br_sha384_vtable PROGMEM = {
sizeof(br_sha384_context),
BR_HASHDESC_ID(br_sha384_ID)
| BR_HASHDESC_OUT(48)
| BR_HASHDESC_LBLEN(7)
| BR_HASHDESC_MD_PADDING
| BR_HASHDESC_MD_PADDING_BE,
(void (*)(const br_hash_class **)) &br_sha384_init,
(void (*)(const br_hash_class **, const void *, size_t)) &br_sha384_update,
(void (*)(const br_hash_class *const *, void *)) &br_sha384_out,
NULL,
NULL
};
#endif
/* ================================================================
* SHA-512 (ROM path, no save/restore)
* ================================================================ */
#if HAVE_ROM_SHA512
#undef br_sha512_update
void br_sha512_init(br_sha512_context *cc) {
SHA_ENTER();
cc->vtable = &br_sha512_vtable;
cc->count = 0;
ROM_SHA_ENABLE();
ROM_SHA_INIT_MODE(&rom_ctx, SHA2_512);
SHA_EXIT();
}
void br_sha512_update(br_sha512_context *cc, const void *data, size_t len) {
if (!len) return;
SHA_ENTER();
ROM_SHA_UPDATE_MODE(&rom_ctx, SHA2_512, data, len, false);
cc->count += len;
SHA_EXIT();
}
void br_sha512_out(const br_sha512_context *cc, void *out) {
(void)cc;
SHA_ENTER();
ROM_SHA_FINALIZE_MODE(&rom_ctx, SHA2_512, out);
ROM_SHA_INIT_MODE(&rom_ctx, SHA2_512);
SHA_EXIT();
}
const br_hash_class br_sha512_vtable PROGMEM = {
sizeof(br_sha512_context),
BR_HASHDESC_ID(br_sha512_ID)
| BR_HASHDESC_OUT(64)
| BR_HASHDESC_LBLEN(7)
| BR_HASHDESC_MD_PADDING
| BR_HASHDESC_MD_PADDING_BE,
(void (*)(const br_hash_class **)) &br_sha512_init,
(void (*)(const br_hash_class **, const void *, size_t)) &br_sha512_update,
(void (*)(const br_hash_class *const *, void *)) &br_sha512_out,
NULL,
NULL
};
#endif
#else
/* ===== ESP8266 - leave it unchanged ===== */
#endif
#endif //USE_SHA_ROM

View File

@ -30,6 +30,7 @@ build_flags = ${esp_defaults.build_flags}
-Dsint16_t=int16_t
-Dmemcpy_P=memcpy
-Dmemcmp_P=memcmp
-DUSE_SHA_ROM
;for TLS we can afford compiling for 4K RSA keys
-DUSE_4K_RSA
-I$PROJECT_DIR/include