From a64d5103ac42c32e04c6422d8be3a901b4d2fcf1 Mon Sep 17 00:00:00 2001
From: Parminder Singh <61920513+parmi93@users.noreply.github.com>
Date: Tue, 16 Jun 2026 15:07:52 +0000
Subject: [PATCH] fix(crc): Make the PAL layer multi-context-safe
Fix https://github.com/STMicroelectronics/STSELib/issues/65 issue
---
CHANGELOG.md | 5 ++
core/stse_frame.c | 26 ++++---
core/stse_platform.h | 39 ++++++++---
.../PAL_files/stse_platform_crc.c.md | 70 ++++++++++++++-----
services/stsafea/stsafea_frame_transfer.c | 22 +++---
5 files changed, 120 insertions(+), 42 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 11b11fd..9b512c1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,19 +19,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **Platform AES API change** — all platform AES cryptographic functions now reference keys by secure storage index (`PLAT_UI32 key_idx`) instead of raw key pointer and length (`PLAT_UI8 *pKey, PLAT_UI16 key_length`). Affected functions: `stse_platform_aes_cmac_init`, `stse_platform_aes_cmac_compute`, `stse_platform_aes_cmac_verify`, `stse_platform_aes_cbc_enc`, `stse_platform_aes_cbc_dec`, `stse_platform_aes_ecb_enc`
- **Renamed** `stsafea_open_host_session` to `stsafea_open_host_session_from_idx` — signature updated to accept key indices (`PLAT_UI32 host_MAC_key_idx`, `PLAT_UI32 host_cypher_key_idx`) instead of raw key pointers
- **printf() calls replaced** with `stse_platform_printf()` in all library code to abstract away standard I/O and allow platform-specific implementations for logging and output
+- **Platform CRC API change** — introduces a context (`stse_crc16_context_t *`) parameter to make the CRC PAL APIs multi-context-safe. Affected functions: `stse_platform_Crc16_Accumulate` (PR [#90](https://github.com/STMicroelectronics/STSELib/pull/90))
### Added
- `stse_platform_store_aes_key()` — new platform function to store an AES key into platform secure storage and retrieve its index
- `stse_platform_delete_aes_key()` — new platform function to delete an AES key from platform secure storage by index
- `stse_platform_printf()` — new platform function for formatted output, replacing all direct calls to `printf()` in the library with this abstraction to allow platform-specific implementations and avoid direct use of standard I/O in library code
+- `stse_platform_Crc16_ContextInit()` — new platform function to initialize a CRC16 context
+- `stse_platform_Crc16_ContextRelease()` — new platform function to release a CRC16 context
### Changed
+- `stse_platform_Crc16_Accumulate()` — Now it takes `stse_crc16_context_t *crc16_context` as param
### Deprecated
### Removed
- `stsafea_open_host_session` function. Now replaced by `stsafea_open_host_session_from_idx` which accepts key indices instead of raw key pointers. Note that you must first store the AES keys in platform secure storage using `stse_platform_store_aes_key()` to obtain the required indices before opening a host session.
+- `stse_platform_Crc16_Calculate()` — Now replaced by `stse_platform_Crc16_ContextInit()` which doesn't calculate a CRC16 but initialize the CRC context which will be used to calculate the CRC via `stse_platform_Crc16_Accumulate()`.
### Fixed
diff --git a/core/stse_frame.c b/core/stse_frame.c
index eac1f53..9056cc1 100644
--- a/core/stse_frame.c
+++ b/core/stse_frame.c
@@ -23,26 +23,32 @@
#include "core/stse_frame.h"
stse_ReturnCode_t stse_frame_crc16_compute(stse_frame_t *pFrame, PLAT_UI16 *pCrc) {
+ stse_ReturnCode_t ret;
stse_frame_element_t *pCurrent_element;
+ stse_crc16_context_t crc_ctx;
if (pFrame == NULL || pCrc == NULL) {
return STSE_CORE_INCONSISTENT_FRAME;
}
- pCurrent_element = pFrame->first_element;
- *pCrc = stse_platform_Crc16_Calculate(pCurrent_element->pData, pCurrent_element->length);
- pCurrent_element = pCurrent_element->next;
- while (pCurrent_element != NULL) {
- if (pCurrent_element->length != 0) {
- if (pCurrent_element->pData == NULL) {
- return STSE_CORE_INCONSISTENT_FRAME;
+ ret = stse_platform_Crc16_ContextInit(&crc_ctx);
+ if (ret == STSE_OK) {
+ pCurrent_element = pFrame->first_element;
+ while (pCurrent_element != NULL) {
+ if (pCurrent_element->length != 0) {
+ if (pCurrent_element->pData == NULL) {
+ ret = STSE_CORE_INCONSISTENT_FRAME;
+ break;
+ }
+ *pCrc = stse_platform_Crc16_Accumulate(pCurrent_element->pData, pCurrent_element->length, &crc_ctx);
}
- *pCrc = stse_platform_Crc16_Accumulate(pCurrent_element->pData, pCurrent_element->length);
+ pCurrent_element = pCurrent_element->next;
}
- pCurrent_element = pCurrent_element->next;
+
+ stse_platform_Crc16_ContextRelease(&crc_ctx);
}
- return STSE_OK;
+ return ret;
}
void stse_frame_element_swap_byte_order(stse_frame_element_t *pElement) {
diff --git a/core/stse_platform.h b/core/stse_platform.h
index 6dafd3a..9553e80 100644
--- a/core/stse_platform.h
+++ b/core/stse_platform.h
@@ -33,6 +33,12 @@
#include "core/stse_util.h"
#include "stse_platform_generic.h"
+typedef struct stse_crc16_context_t stse_crc16_context_t;
+
+struct stse_crc16_context_t {
+ PLAT_UI16 value;
+};
+
/*--------------------- STSAFE platform HAL functions --------------------------- */
/*!
@@ -82,20 +88,37 @@ void stse_platform_printf(const char *format, ...);
PLAT_UI32 stse_platform_generate_random(void);
/*!
- * \brief Compute a 16-bit crc value on specific 8-bit buffer of buffer length
- * \param[in] pbuffer pointer to crc input buffer
- * \param[in] length input buffer length
- * \return 16-bit CRC value
+ * \brief Initializes a CRC16 context.
+ *
+ * Initializes the specified CRC16 context and prepares it for use with `stse_platform_Crc16_Accumulate()`.
+ * The same context instance shall be passed unchanged to all subsequent accumulation calls.
+ *
+ * \param[in] crc16_context Pointer to the CRC16 context to initialize.
+ * \return \ref STSE_OK on success; \ref stse_ReturnCode_t error code otherwise.
*/
-PLAT_UI16 stse_platform_Crc16_Calculate(PLAT_UI8 *pbuffer, PLAT_UI16 length);
+stse_ReturnCode_t stse_platform_Crc16_ContextInit(stse_crc16_context_t *crc16_context);
/*!
* \brief Accumulate an 8-bit buffer of buffer length in crc unit
- * \param[in] pbuffer pointer to crc input buffer
- * \param[in] length input buffer length
+ * \param[in] pbuffer pointer to crc input buffer
+ * \param[in] length input buffer length
+ * \param[in] crc16_context Pointer to the CRC context holder previously initialized successfully
+ * via `stse_platform_Crc16_ContextInit()`. This context is used internally to maintain the state
+ * required for incremental CRC computation across multiple calls to `stse_platform_Crc16_Accumulate()`.
* \return 16-bit CRC value
*/
-PLAT_UI16 stse_platform_Crc16_Accumulate(PLAT_UI8 *pbuffer, PLAT_UI16 length);
+PLAT_UI16 stse_platform_Crc16_Accumulate(PLAT_UI8 *pbuffer, PLAT_UI16 length,
+ stse_crc16_context_t *crc16_context);
+
+/*!
+ * \brief Releases resources associated with a CRC16 context.
+ *
+ * Releases any resources allocated or acquired by `stse_platform_Crc16_ContextInit()`. Once
+ * released, the context shall no longer be used unless it is reinitialized.
+ *
+ * \param[in] crc16_context Pointer to a CRC context previously initialized with `stse_platform_Crc16_ContextInit()`.
+*/
+void stse_platform_Crc16_ContextRelease(stse_crc16_context_t *crc16_context);
/*!
* \brief Perform a delay of "delay_val" ms
diff --git a/doc/resources/Markdown/04_PORTING_GUIDE/PAL_files/stse_platform_crc.c.md b/doc/resources/Markdown/04_PORTING_GUIDE/PAL_files/stse_platform_crc.c.md
index d6b10d9..2876861 100644
--- a/doc/resources/Markdown/04_PORTING_GUIDE/PAL_files/stse_platform_crc.c.md
+++ b/doc/resources/Markdown/04_PORTING_GUIDE/PAL_files/stse_platform_crc.c.md
@@ -11,15 +11,14 @@ The stse_platform_crc.c file provides CRC16 functions for the STSecureElement li
Implementation directives : This abstaction function should implement or call a platform function/driver that perform CRC16 calculation process.
-## stse_platform_Crc16_Calculate:
+## stse_platform_Crc16_ContextInit:
-- Purpose: Calculates the CRC16 checksum for the given buffer.
+- Purpose: Initializes a CRC16 context.
- Parameters:
- - pbuffer: Pointer to the buffer.
- - length: Length of the buffer.
-- Return Value: Returns the calculated CRC16 checksum.
+ - crc16_context: Pointer to the CRC16 context to initialize.
+- Return Value: Returns `STSE_OK` to indicate successful context initialization.
- Implementation directives : This abstaction function should implement or call a platform function/driver that perform CRC16 calculation process.
+ Implementation directives : This abstraction function should implement or call a platform function/driver that perform CRC16 accumulate process.
## stse_platform_Crc16_Accumulate:
@@ -27,10 +26,20 @@ The stse_platform_crc.c file provides CRC16 functions for the STSecureElement li
- Parameters:
- pbuffer: Pointer to the buffer.
- length: Length of the buffer.
+ - crc16_context: Pointer to the CRC context holder previously initialized successfully via `stse_platform_Crc16_ContextInit()`.
+ This context is used internally to maintain the state required for incremental CRC computation across multiple calls to `stse_platform_Crc16_Accumulate()`.
- Return Value: Returns the accumulated CRC16 checksum.
Implementation directives : This abstaction function should implement or call a platform function/driver that perform CRC16 acumulate process.
+## stse_platform_Crc16_ContextRelease:
+
+- Purpose: Releases resources associated with a CRC16 context.
+- Parameters:
+ - crc16_context: Pointer to a CRC context previously initialized with `stse_platform_Crc16_ContextInit()`.
+
+ Implementation directives : This abstraction function should implement or call a platform function/driver that perform CRC16 accumulate process.
+
Please find below an extract
```c
@@ -65,24 +74,53 @@ stse_ReturnCode_t stse_platform_crc16_init(void *pArg)
}
/**
- * \brief Calculates the CRC16 checksum for the given buffer.
- * \param pbuffer Pointer to the buffer.
- * \param length Length of the buffer.
- * \return The calculated CRC16 checksum.
+ * \brief Initializes a CRC16 context.
+ *
+ * Initializes the specified CRC16 context and prepares it for use with `stse_platform_Crc16_Accumulate()`.
+ * The same context instance shall be passed unchanged to all subsequent accumulation calls.
+ *
+ * \param crc16_context Pointer to the CRC16 context to initialize.
+ * \return \ref STSE_OK on success; \ref stse_ReturnCode_t error code otherwise.
*/
-PLAT_UI16 stse_platform_Crc16_Calculate(PLAT_UI8 *pbuffer, PLAT_UI16 length)
+stse_ReturnCode_t stse_platform_Crc16_ContextInit(stse_crc16_context_t *crc16_context)
{
- return crc16_Calculate(pbuffer, length);
+ // If hardware CRC is used...
+ // mutex_lock() if the same CRC hardware module is used by multiple thread
+ __HAL_CRC_DR_RESET(&stm32_crc_hal);
+
+ // or just initialize the context if CRC computation is done in software
+ crc16_context->value = (PLAT_UI16)0xFFFF;
}
/**
* \brief Accumulates the CRC16 checksum for the given buffer.
- * \param pbuffer Pointer to the buffer.
- * \param length Length of the buffer.
+ * \param pbuffer Pointer to the buffer.
+ * \param length Length of the buffer.
+ * \param crc16_context Pointer to the CRC context holder previously initialized successfully
+ * via `stse_platform_Crc16_ContextInit()`. This context is used internally to maintain the state
+ * required for incremental CRC computation across multiple calls to `stse_platform_Crc16_Accumulate()`.
* \return The accumulated CRC16 checksum.
*/
-PLAT_UI16 stse_platform_Crc16_Accumulate(PLAT_UI8 *pbuffer, PLAT_UI16 length)
+PLAT_UI16 stse_platform_Crc16_Accumulate(PLAT_UI8 *pbuffer, PLAT_UI16 length,
+ stse_crc16_context_t *crc16_context);
+{
+ // If hardware CRC computation is used...
+ return ~HAL_CRC_Accumulate(&stm32_crc_hal, (uint32_t *)pbuffer, length);
+
+ // If software CRC computation is used...
+ return crc16_Accumulate(pbuffer, length, crc16_context);
+}
+
+/**
+ * \brief Releases resources associated with a CRC16 context.
+ *
+ * Releases any resources allocated or acquired by `stse_platform_Crc16_ContextInit()`. Once
+ * released, the context shall no longer be used unless it is reinitialized.
+ *
+ * \param crc16_context Pointer to a CRC context previously initialized with `stse_platform_Crc16_ContextInit()`.
+*/
+void stse_platform_Crc16_ContextRelease(stse_crc16_context_t *crc16_context)
{
- return crc16_Accumulate(pbuffer, length);
+ // mutex_unlock() if the same CRC hardware module is used by multiple thread
}
```
diff --git a/services/stsafea/stsafea_frame_transfer.c b/services/stsafea/stsafea_frame_transfer.c
index e07b7f1..894b604 100644
--- a/services/stsafea/stsafea_frame_transfer.c
+++ b/services/stsafea/stsafea_frame_transfer.c
@@ -219,8 +219,21 @@ stse_ReturnCode_t stsafea_frame_receive(stse_Handle_t *pSTSE, stse_frame_t *pFra
/* ====================================================== */
/* ====== compute CRC for response without payload ====== */
- computed_crc = stse_platform_Crc16_Calculate(&received_header, STSE_RSP_FRAME_HEADER_SIZE);
+ stse_crc16_context_t crc_ctx;
+ ret = stse_platform_Crc16_ContextInit(&crc_ctx);
+ if (ret == STSE_OK) {
+ computed_crc = stse_platform_Crc16_Accumulate(&received_header, STSE_RSP_FRAME_HEADER_SIZE, &crc_ctx);
+
+ stse_platform_Crc16_ContextRelease(&crc_ctx);
+ /* - Verify CRC */
+ if (computed_crc != ((received_crc[0] << 8) + received_crc[1])) {
+ ret = STSE_SERVICE_FRAME_CRC_ERROR;
+ } else {
+ ret = (stse_ReturnCode_t)(received_header & STSE_STSAFEA_RSP_STATUS_MASK);
+ }
+ }
+
#ifdef STSE_FRAME_DEBUG_LOG
stse_platform_printf("\n\r STSAFE Frame < (%d-byte) : { 0x%02X } { 0x%02X 0x%02X }\n\r",
received_length + STSE_FRAME_CRC_SIZE,
@@ -228,13 +241,6 @@ stse_ReturnCode_t stsafea_frame_receive(stse_Handle_t *pSTSE, stse_frame_t *pFra
received_crc[0],
received_crc[1]);
#endif /* STSE_FRAME_DEBUG_LOG */
-
- /* - Verify CRC */
- if (computed_crc != ((received_crc[0] << 8) + received_crc[1])) {
- return (STSE_SERVICE_FRAME_CRC_ERROR);
- }
-
- ret = (stse_ReturnCode_t)(received_header & STSE_STSAFEA_RSP_STATUS_MASK);
} else {
/* ======================================================= */
/* ====== Format the frame to handle CRC and filler ====== */