Skip to content

Conversation

@dgarske
Copy link
Contributor

@dgarske dgarske commented Jan 6, 2026

Add STSAFE-A120 Support via STSELib

Description

This PR adds support for the ST STSAFE-A120 secure element using the open-source STSELib SDK. The STSAFE-A120 is ST's latest secure element with enhanced cryptographic capabilities and is the successor to the STSAFE-A100/A110 series.

Changes

Files Modified:

  • wolfcrypt/src/port/st/stsafe.c - Added STSAFE-A120/STSELib implementation
  • wolfssl/wolfcrypt/port/st/stsafe.h - Added type abstractions and curve mappings
  • wolfcrypt/src/wc_port.c - Updated STSAFE initialization
  • wolfcrypt/src/port/st/README.md - Added documentation

Features

  • True Random Number Generation (TRNG) - Hardware RNG for seeding wolfSSL's RNG
  • ECC Key Generation - P-256 and P-384 key pair generation in secure element
  • ECDSA Sign/Verify - Hardware-accelerated ECDSA operations
  • ECDH Shared Secret - Elliptic curve Diffie-Hellman key exchange
  • Device Certificate - Read X.509 certificates from secure storage
  • Crypto Callbacks - Full integration with wolfSSL's crypto callback mechanism

Configuration

Enable with:

#define WOLFSSL_STSAFEA120Optional defines:
#define USE_STSAFE_RNG_SEED    /* Use STSAFE for RNG seeding */
#define WOLF_CRYPTO_CB         /* Enable crypto callbacks */
#define STSAFE_I2C_BUS 1       /* I2C bus number (default: 1) */

Dependencies

API Compatibility

The new implementation maintains API compatibility with the existing STSAFE-A100 code:

  • stsafe_interface_init() - Initialize device
  • wolfSSL_STSAFE_CryptoDevCb() - Crypto callback handler
  • SSL_STSAFE_* callback functions for TLS integration

Testing

Tested on Raspberry Pi 5 with STSAFE-A120 connected via I2C:

  • Echo command ✅
  • Random number generation ✅
  • ECC P-256 key generation ✅
  • ECC P-384 key generation ✅
  • ECDSA P-256 sign/verify ✅
  • ECDSA P-384 sign/verify ✅
  • Crypto callback integration ✅

Performance (Raspberry Pi 5)

Operation Time
ECC P-256 KeyGen ~40 ms
ECDSA P-256 Sign ~51 ms
ECDSA P-256 Verify ~79 ms
RNG (256 bytes) <1 ms

Notes

  • The STSELib uses conditional compilation for ECC curves via stse_conf.h
  • Curve ID values in stsafe.h depend on which curves are enabled in stse_conf.h
  • Default configuration enables NIST P-256 and P-384

Related

ZD 20780

@dgarske dgarske self-assigned this Jan 6, 2026
@devin-ai-integration
Copy link
Contributor

🛟 Devin Lifeguard found 3 likely issues in this PR

  • check-all-return-codes snippet: Capture the return value of stsafe_interface_init() in wolfCrypt_Init and, if it is non-zero, propagate or handle the error (e.g., ret = stsafe_interface_init(); if (ret != 0) return ret;).
  • no-memory-leaks snippet: After copying the shared secret, add XFREE(sharedSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER); (and similarly free other SDK-allocated buffers such as pubX/pubY, signature, readBuf, echo_resp) before the function returns.
  • limit-stack-usage snippet: Replace large local buffers (e.g., sigRS, pubKeyX, pubKeyY in SSL_STSAFE_VerifyPeerCertCb) with heap allocations under the WOLFSSL_SMALL_STACK pattern, freeing them before return.

@dgarske
please take a look at the above issues which Devin flagged. Devin will not fix these issues automatically.

@dgarske
Copy link
Contributor Author

dgarske commented Jan 7, 2026

Jenkins retest this please: "AgentOfflineException"

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@dgarske
Copy link
Contributor Author

dgarske commented Jan 12, 2026

Jenkins retest this please: "AgentOfflineException"

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@dgarske dgarske requested a review from Copilot January 16, 2026 00:18
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 6 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@dgarske
Copy link
Contributor Author

dgarske commented Jan 16, 2026

Jenkins retest this please. AgentOffline

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@dgarske dgarske removed their assignment Jan 16, 2026
@dgarske
Copy link
Contributor Author

dgarske commented Jan 16, 2026

Jenkins retest this please

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +78 to +82
* With only NIST P-256 and P-384 enabled:
* STSE_ECC_KT_NIST_P_256 = 0, STSE_ECC_KT_NIST_P_384 = 1
* NOTE: If other curves are enabled, these values change! */
#define STSAFE_ECC_CURVE_P256 0 /* STSE_ECC_KT_NIST_P_256 */
#define STSAFE_ECC_CURVE_P384 1 /* STSE_ECC_KT_NIST_P_384 */
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comments warn that these curve ID values depend on stse_conf.h settings and change when other curves are enabled, but there's no compile-time validation. Consider adding static assertions or runtime checks in stsafe_interface_init() to verify that the STSE_ECC_KT_NIST_P_256 and STSE_ECC_KT_NIST_P_384 enum values from STSELib actually match the expected 0 and 1 values when WOLFSSL_STSAFEA120 is defined.

Suggested change
* With only NIST P-256 and P-384 enabled:
* STSE_ECC_KT_NIST_P_256 = 0, STSE_ECC_KT_NIST_P_384 = 1
* NOTE: If other curves are enabled, these values change! */
#define STSAFE_ECC_CURVE_P256 0 /* STSE_ECC_KT_NIST_P_256 */
#define STSAFE_ECC_CURVE_P384 1 /* STSE_ECC_KT_NIST_P_384 */
* With only NIST P-256 and P-384 enabled and no other curves:
* STSE_ECC_KT_NIST_P_256 = 0, STSE_ECC_KT_NIST_P_384 = 1
* NOTE: If other curves are enabled or the order changes in STSELib,
* these values may change. In that case, override the defaults
* below by defining STSAFE_ECC_CURVE_P256 / STSAFE_ECC_CURVE_P384
* (for example via compiler -D flags) to match the actual
* STSE_ECC_KT_NIST_P_256 / STSE_ECC_KT_NIST_P_384 enum values. */
#ifndef STSAFE_ECC_CURVE_P256
#define STSAFE_ECC_CURVE_P256 0 /* Default: STSE_ECC_KT_NIST_P_256 */
#endif
#ifndef STSAFE_ECC_CURVE_P384
#define STSAFE_ECC_CURVE_P384 1 /* Default: STSE_ECC_KT_NIST_P_384 */
#endif

Copilot uses AI. Check for mistakes.
Comment on lines +1876 to +1904
byte ephemeralPubKey[STSAFE_MAX_PUBKEY_RAW_LEN];
int key_sz = stsafe_get_key_size(curve_id);
slot = STSAFE_KEY_SLOT_EPHEMERAL;

ret = stse_generate_ecc_key_pair(&g_stse_handler, slot,
(stse_ecc_key_type_t)curve_id,
STSAFE_EPHEMERAL_KEY_USAGE_LIMIT,
ephemeralPubKey);
if (ret != STSE_OK) {
STSAFE_INTERFACE_PRINTF("stse_generate_ecc_key_pair (ephemeral for ECDH) error: %d\n", ret);
rc = (int)ret;
} else {
WOLFSSL_MSG("STSAFE: Generated ephemeral key for ECDH");
/* Update devCtx to reflect ephemeral slot for this key */
if (info->pk.ecdh.private_key != NULL) {
info->pk.ecdh.private_key->devCtx = STSAFE_SLOT_TO_DEVCXT(slot);
}
/* Update the public key in the key structure to match the new ephemeral key */
if (info->pk.ecdh.private_key != NULL && rc == 0) {
void* saved_devCtx = info->pk.ecdh.private_key->devCtx;
rc = wc_ecc_import_unsigned(info->pk.ecdh.private_key,
ephemeralPubKey, &ephemeralPubKey[key_sz],
NULL, ecc_curve);
/* Restore devCtx in case import cleared it */
if (saved_devCtx != NULL && info->pk.ecdh.private_key->devCtx != saved_devCtx) {
info->pk.ecdh.private_key->devCtx = saved_devCtx;
}
}
}
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ephemeralPubKey buffer is declared on stack but could be large (96 bytes for P-384). When WOLFSSL_SMALL_STACK is defined, other buffers in this function are dynamically allocated but ephemeralPubKey is not. For consistency with the WOLFSSL_SMALL_STACK handling elsewhere in the file, consider conditionally allocating this buffer dynamically when WOLFSSL_SMALL_STACK is defined.

Suggested change
byte ephemeralPubKey[STSAFE_MAX_PUBKEY_RAW_LEN];
int key_sz = stsafe_get_key_size(curve_id);
slot = STSAFE_KEY_SLOT_EPHEMERAL;
ret = stse_generate_ecc_key_pair(&g_stse_handler, slot,
(stse_ecc_key_type_t)curve_id,
STSAFE_EPHEMERAL_KEY_USAGE_LIMIT,
ephemeralPubKey);
if (ret != STSE_OK) {
STSAFE_INTERFACE_PRINTF("stse_generate_ecc_key_pair (ephemeral for ECDH) error: %d\n", ret);
rc = (int)ret;
} else {
WOLFSSL_MSG("STSAFE: Generated ephemeral key for ECDH");
/* Update devCtx to reflect ephemeral slot for this key */
if (info->pk.ecdh.private_key != NULL) {
info->pk.ecdh.private_key->devCtx = STSAFE_SLOT_TO_DEVCXT(slot);
}
/* Update the public key in the key structure to match the new ephemeral key */
if (info->pk.ecdh.private_key != NULL && rc == 0) {
void* saved_devCtx = info->pk.ecdh.private_key->devCtx;
rc = wc_ecc_import_unsigned(info->pk.ecdh.private_key,
ephemeralPubKey, &ephemeralPubKey[key_sz],
NULL, ecc_curve);
/* Restore devCtx in case import cleared it */
if (saved_devCtx != NULL && info->pk.ecdh.private_key->devCtx != saved_devCtx) {
info->pk.ecdh.private_key->devCtx = saved_devCtx;
}
}
}
#ifdef WOLFSSL_SMALL_STACK
byte* ephemeralPubKey = NULL;
#else
byte ephemeralPubKey[STSAFE_MAX_PUBKEY_RAW_LEN];
#endif
int key_sz = stsafe_get_key_size(curve_id);
slot = STSAFE_KEY_SLOT_EPHEMERAL;
#ifdef WOLFSSL_SMALL_STACK
ephemeralPubKey = (byte*)XMALLOC(STSAFE_MAX_PUBKEY_RAW_LEN,
NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (ephemeralPubKey == NULL) {
rc = MEMORY_E;
}
#endif
if (rc == 0) {
ret = stse_generate_ecc_key_pair(&g_stse_handler, slot,
(stse_ecc_key_type_t)curve_id,
STSAFE_EPHEMERAL_KEY_USAGE_LIMIT,
ephemeralPubKey);
if (ret != STSE_OK) {
STSAFE_INTERFACE_PRINTF("stse_generate_ecc_key_pair (ephemeral for ECDH) error: %d\n", ret);
rc = (int)ret;
} else {
WOLFSSL_MSG("STSAFE: Generated ephemeral key for ECDH");
/* Update devCtx to reflect ephemeral slot for this key */
if (info->pk.ecdh.private_key != NULL) {
info->pk.ecdh.private_key->devCtx = STSAFE_SLOT_TO_DEVCXT(slot);
}
/* Update the public key in the key structure to match the new ephemeral key */
if (info->pk.ecdh.private_key != NULL && rc == 0) {
void* saved_devCtx = info->pk.ecdh.private_key->devCtx;
rc = wc_ecc_import_unsigned(info->pk.ecdh.private_key,
ephemeralPubKey, &ephemeralPubKey[key_sz],
NULL, ecc_curve);
/* Restore devCtx in case import cleared it */
if (saved_devCtx != NULL && info->pk.ecdh.private_key->devCtx != saved_devCtx) {
info->pk.ecdh.private_key->devCtx = saved_devCtx;
}
}
}
}
#ifdef WOLFSSL_SMALL_STACK
if (ephemeralPubKey != NULL) {
XFREE(ephemeralPubKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
#endif

Copilot uses AI. Check for mistakes.
Comment on lines +84 to +90
#ifndef STSAFE_HOST_KEY_MAC
static const uint8_t g_host_mac_key[16] = {
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
};
#endif
#ifndef STSAFE_HOST_KEY_CIPHER
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The example host MAC and cipher keys are hardcoded with predictable values and visible in the binary. While the comment notes these are examples, production code could accidentally use these insecure defaults. Consider either removing these default keys entirely (requiring users to define STSAFE_HOST_KEY_MAC/CIPHER) or using a more prominent warning marker to prevent production use.

Suggested change
#ifndef STSAFE_HOST_KEY_MAC
static const uint8_t g_host_mac_key[16] = {
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
};
#endif
#ifndef STSAFE_HOST_KEY_CIPHER
#ifndef STSAFE_HOST_KEY_MAC
#if defined(__GNUC__) || defined(__clang__)
#warning "Insecure example STSAFE host MAC key in use. Define STSAFE_HOST_KEY_MAC with a secure, secret key for production builds."
#elif defined(_MSC_VER)
#pragma message("Insecure example STSAFE host MAC key in use. Define STSAFE_HOST_KEY_MAC with a secure, secret key for production builds.")
#endif
static const uint8_t g_host_mac_key[16] = {
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
};
#endif
#ifndef STSAFE_HOST_KEY_CIPHER
#if defined(__GNUC__) || defined(__clang__)
#warning "Insecure example STSAFE host cipher key in use. Define STSAFE_HOST_KEY_CIPHER with a secure, secret key for production builds."
#elif defined(_MSC_VER)
#pragma message("Insecure example STSAFE host cipher key in use. Define STSAFE_HOST_KEY_CIPHER with a secure, secret key for production builds.")
#endif

Copilot uses AI. Check for mistakes.
curve_id = stsafe_get_ecc_curve_id(ecc_curve);
/* Note: STSAFE_ECC_CURVE_P256 is 0, so we can't use STSAFE_DEFAULT_CURVE check.
* Instead, verify the curve_id is valid by checking it's one of the supported curves */
if (curve_id != STSAFE_ECC_CURVE_P256 && curve_id != STSAFE_ECC_CURVE_P384) {
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The curve validation at line 1823 explicitly checks only P256 and P384, which will reject valid Brainpool curves even when STSAFE_ECC_CURVE_BP256/BP384 are defined. This validation should be updated to include the Brainpool curves when they are enabled, or use a more flexible validation approach like checking against the key_sz return value from stsafe_get_key_size().

Suggested change
if (curve_id != STSAFE_ECC_CURVE_P256 && curve_id != STSAFE_ECC_CURVE_P384) {
if (curve_id != STSAFE_ECC_CURVE_P256 &&
curve_id != STSAFE_ECC_CURVE_P384
#ifdef STSAFE_ECC_CURVE_BP256
&& curve_id != STSAFE_ECC_CURVE_BP256
#endif
#ifdef STSAFE_ECC_CURVE_BP384
&& curve_id != STSAFE_ECC_CURVE_BP384
#endif
) {

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants