Improvements to code for ECDHE and peer review fixes.

This commit is contained in:
David Garske
2026-01-21 00:02:52 +00:00
parent 16fb84d0d1
commit 38b0fe19a1
2 changed files with 59 additions and 202 deletions

View File

@@ -548,6 +548,8 @@ STM32_NUTTX_RNG
STSAFE_HOST_KEY_CIPHER
STSAFE_HOST_KEY_MAC
STSAFE_I2C_BUS
STSE_CONF_ECC_BRAINPOOL_P_256
STSE_CONF_ECC_BRAINPOOL_P_384
TASK_EXTRA_STACK_SIZE
TCP_NODELAY
TFM_ALREADY_SET

View File

@@ -276,12 +276,11 @@ int stsafe_interface_init(void)
* \details Uses dedicated key slot (slot 1) for persistent keys.
* For ephemeral ECDHE keys, use stsafe_create_ecdhe_key() instead.
*/
static int stsafe_create_key(stsafe_slot_t* pSlot, stsafe_curve_id_t curve_id,
static int stsafe_create_key(stsafe_slot_t slot, stsafe_curve_id_t curve_id,
uint8_t* pPubKeyRaw)
{
int rc = STSAFE_A_OK;
stse_ReturnCode_t ret;
stsafe_slot_t slot = STSAFE_KEY_SLOT_1; /* Use dedicated key slot for persistent keys */
if (pPubKeyRaw == NULL) {
return BAD_FUNC_ARG;
@@ -299,10 +298,6 @@ static int stsafe_create_key(stsafe_slot_t* pSlot, stsafe_curve_id_t curve_id,
rc = (int)ret;
}
if (rc == STSAFE_A_OK && pSlot != NULL) {
*pSlot = slot;
}
return rc;
}
@@ -460,64 +455,6 @@ static int stsafe_shared_secret(stsafe_slot_t slot, stsafe_curve_id_t curve_id,
return rc;
}
/**
* \brief ECDHE shared secret using STSAFE-A120
* \details Computes shared secret using the ephemeral ECDHE private key
* that was generated by stsafe_create_ecdhe_key(). The ephemeral
* private key is stored internally in the STSE device.
*/
static int stsafe_shared_secret_ecdhe(stsafe_curve_id_t curve_id,
uint8_t* pPubKeyX, uint8_t* pPubKeyY,
uint8_t* pSharedSecret,
int32_t* pSharedSecretLen)
{
int rc = STSAFE_A_OK;
stse_ReturnCode_t ret;
int key_sz = stsafe_get_key_size(curve_id);
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
uint8_t* peerPubKey = NULL;
#else
uint8_t peerPubKey[STSAFE_MAX_PUBKEY_RAW_LEN];
#endif
if (pPubKeyX == NULL || pPubKeyY == NULL || pSharedSecret == NULL ||
pSharedSecretLen == NULL || key_sz == 0) {
return BAD_FUNC_ARG;
}
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
peerPubKey = (uint8_t*)XMALLOC(STSAFE_MAX_PUBKEY_RAW_LEN, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (peerPubKey == NULL) {
return MEMORY_E;
}
#endif
/* Combine peer X and Y (X||Y format) */
XMEMCPY(peerPubKey, pPubKeyX, key_sz);
XMEMCPY(peerPubKey + key_sz, pPubKeyY, key_sz);
/* Compute shared secret using ephemeral slot (0xFF)
* The ephemeral private key was generated by stse_generate_ECDHE_key_pair() */
ret = stse_ecc_establish_shared_secret(&g_stse_handler,
STSAFE_KEY_SLOT_EPHEMERAL, (stse_ecc_key_type_t)curve_id, peerPubKey, pSharedSecret);
if (ret != STSE_OK) {
STSAFE_INTERFACE_PRINTF("stse_ecc_establish_shared_secret (ECDHE) error: %d\n",
ret);
rc = (int)ret;
}
if (rc == STSAFE_A_OK) {
*pSharedSecretLen = (int32_t)key_sz;
}
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
XFREE(peerPubKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
return rc;
}
/**
* \brief Read device certificate from STSAFE-A120
*/
@@ -536,11 +473,16 @@ static int stsafe_read_certificate(uint8_t** ppCert, uint32_t* pCertLen)
/* First, get certificate size */
ret = stse_get_device_certificate_size(&g_stse_handler, certZone, &certLen);
if (ret != STSE_OK || certLen == 0) {
if (ret != STSE_OK) {
STSAFE_INTERFACE_PRINTF("stse_get_device_certificate_size error: %d\n",
ret);
rc = (int)ret;
}
else if (certLen == 0) {
/* Certificate size is 0 - invalid certificate data */
STSAFE_INTERFACE_PRINTF("stse_get_device_certificate_size returned zero length\n");
rc = ASN_PARSE_E;
}
/* Allocate buffer */
if (rc == STSAFE_A_OK) {
@@ -988,6 +930,14 @@ static int stsafe_read_certificate(uint8_t** ppCert, uint32_t* pCertLen)
}
break;
}
/* Check if length parsing succeeded */
if (*pCertLen == 0) {
rc = ASN_PARSE_E;
}
}
else {
/* Invalid ASN.1 header - expected SEQUENCE tag */
rc = ASN_PARSE_E;
}
}
else {
@@ -1469,23 +1419,12 @@ int SSL_STSAFE_SharedSecretCb(WOLFSSL* ssl, ecc_key* otherKey,
}
if (err == 0) {
#ifdef WOLFSSL_STSAFEA120
/* Use ECDHE shared secret computation for A120 */
err = stsafe_shared_secret_ecdhe(curve_id, otherKeyX, otherKeyY,
out, (int32_t*)outlen);
if (err != STSAFE_A_OK) {
STSAFE_INTERFACE_PRINTF("stsafe_shared_secret_ecdhe error: %d\n", err);
err = WC_HW_E;
}
#else
/* Legacy A100/A110 uses slot-based shared secret */
err = stsafe_shared_secret(slot, curve_id, otherKeyX, otherKeyY,
out, (int32_t*)outlen);
if (err != STSAFE_A_OK) {
STSAFE_INTERFACE_PRINTF("stsafe_shared_secret error: %d\n", err);
err = WC_HW_E;
}
#endif
}
if (tmpKeyInit) {
@@ -1597,17 +1536,25 @@ int wolfSSL_STSAFE_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx)
key_sz = stsafe_get_key_size(curve_id);
/* For A120, generate keys in slot 1 (persistent slot) by default for ECDSA signing.
* For ECDH operations, ephemeral keys will be generated on-demand in the ECDH callback
* if needed (see WC_PK_TYPE_ECDH handling below). */
* For ECDH operations, the key slot from devCtx will be used directly.
* If ECDH is required, keys should be generated in the ephemeral slot from the start. */
#ifdef WOLFSSL_STSAFEA120
stse_ReturnCode_t ret;
slot = STSAFE_KEY_SLOT_1; /* Use persistent slot for ECDSA signing */
ret = stse_generate_ecc_key_pair(&g_stse_handler, slot,
(stse_ecc_key_type_t)curve_id,
STSAFE_PERSISTENT_KEY_USAGE_LIMIT,
pubKeyRaw);
if (ret != STSE_OK) {
STSAFE_INTERFACE_PRINTF("stse_generate_ecc_key_pair (slot 1) error: %d\n", ret);
/* Retrieve slot from devCtx if available, otherwise use default */
slot = STSAFE_KEY_SLOT_1; /* Default fallback */
if (info->pk.eckg.key != NULL && info->pk.eckg.key->devCtx != NULL) {
slot = STSAFE_DEVCXT_TO_SLOT(info->pk.eckg.key->devCtx);
}
STSAFE_INTERFACE_PRINTF("STSAFE: KeyGen slot %d, curve_id %d\n",
slot, curve_id);
if (slot == STSAFE_KEY_SLOT_EPHEMERAL) {
rc = stsafe_create_ecdhe_key(curve_id, pubKeyRaw);
} else {
rc = stsafe_create_key(slot, curve_id, pubKeyRaw);
}
if (rc != STSE_OK) {
STSAFE_INTERFACE_PRINTF("STSAFE: KeyGen (slot %d) error: %d\n", slot, rc);
rc = WC_HW_E;
} else {
rc = STSAFE_A_OK;
@@ -1624,21 +1571,17 @@ int wolfSSL_STSAFE_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx)
}
if (rc == 0) {
/* Store slot number directly in devCtx (no dynamic allocation) */
info->pk.eckg.key->devCtx = STSAFE_SLOT_TO_DEVCXT(slot);
/* Import public key */
rc = wc_ecc_import_unsigned(info->pk.eckg.key, pubKeyRaw,
&pubKeyRaw[key_sz], NULL, ecc_curve);
}
if (rc == 0) {
/* Import public key - preserve devCtx */
void* saved_devCtx = info->pk.eckg.key->devCtx;
rc = wc_ecc_import_unsigned(info->pk.eckg.key, pubKeyRaw,
&pubKeyRaw[key_sz], NULL, ecc_curve);
/* Restore devCtx in case import cleared it */
if (saved_devCtx != NULL && info->pk.eckg.key->devCtx != saved_devCtx) {
info->pk.eckg.key->devCtx = saved_devCtx;
}
/* Store slot number directly in devCtx */
info->pk.eckg.key->devCtx = STSAFE_SLOT_TO_DEVCXT(slot);
}
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
XFREE(pubKeyRaw, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
@@ -1653,6 +1596,7 @@ int wolfSSL_STSAFE_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx)
#endif
byte* r;
byte* s;
stsafe_slot_t slot;
stsafe_curve_id_t curve_id;
int ecc_curve;
word32 inSz = info->pk.eccsign.inlen;
@@ -1690,12 +1634,12 @@ int wolfSSL_STSAFE_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx)
XMEMSET(sigRS, 0, STSAFE_MAX_SIG_LEN);
/* Retrieve slot from devCtx if available, otherwise use default */
stsafe_slot_t slot = STSAFE_KEY_SLOT_1; /* Default fallback */
slot = STSAFE_KEY_SLOT_1; /* Default fallback */
if (info->pk.eccsign.key != NULL && info->pk.eccsign.key->devCtx != NULL) {
slot = STSAFE_DEVCXT_TO_SLOT(info->pk.eccsign.key->devCtx);
STSAFE_INTERFACE_PRINTF("STSAFE: Using slot %d from devCtx for signing\n", slot);
STSAFE_INTERFACE_PRINTF("STSAFE: Sign using slot %d\n", slot);
} else {
WOLFSSL_MSG("STSAFE: Warning: devCtx not found, using default slot 1");
WOLFSSL_MSG("STSAFE: Sign using default slot 1");
}
rc = stsafe_sign(slot, curve_id, digest, sigRS);
if (rc != STSAFE_A_OK) {
@@ -1815,6 +1759,7 @@ int wolfSSL_STSAFE_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx)
word32 otherKeyX_len = STSAFE_MAX_KEY_LEN;
word32 otherKeyY_len = STSAFE_MAX_KEY_LEN;
stsafe_curve_id_t curve_id;
stsafe_slot_t slot;
int ecc_curve;
WOLFSSL_MSG("STSAFE: ECDH");
@@ -1872,116 +1817,26 @@ int wolfSSL_STSAFE_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx)
if (rc == 0) {
*info->pk.ecdh.outlen = 0;
/* Check if private key is software but public key is hardware.
* In this case, we can't use hardware for computation since the
* private key is not in a slot. Return CRYPTOCB_UNAVAILABLE to
* let software handle it (but software path may also fail if
* public key export fails). */
if (info->pk.ecdh.private_key == NULL ||
info->pk.ecdh.private_key->devId == INVALID_DEVID) {
if (info->pk.ecdh.public_key != NULL &&
info->pk.ecdh.public_key->devId != INVALID_DEVID) {
WOLFSSL_MSG("STSAFE: Private key is software, public key is hardware - cannot use hardware");
rc = CRYPTOCB_UNAVAILABLE;
}
}
if (rc == 0) {
/* For ECDH operations, use ephemeral slot (0xFF).
* Keys are generated in slot 1 by default (for ECDSA signing).
* If the key is in slot 1, generate a new ephemeral key for ECDH.
* If the key is already in the ephemeral slot, use it directly. */
stsafe_slot_t slot;
stsafe_slot_t original_slot = STSAFE_KEY_SLOT_1;
int need_ephemeral_key = 0;
/* For ECDH operations, use the slot from devCtx. */
slot = STSAFE_KEY_SLOT_EPHEMERAL;
if (info->pk.ecdh.private_key != NULL &&
info->pk.ecdh.private_key->devCtx != NULL) {
original_slot = STSAFE_DEVCXT_TO_SLOT(info->pk.ecdh.private_key->devCtx);
/* If key is in slot 1 (for ECDSA), we need to generate ephemeral key for ECDH */
if (original_slot == STSAFE_KEY_SLOT_1) {
need_ephemeral_key = 1;
}
slot = STSAFE_DEVCXT_TO_SLOT(info->pk.ecdh.private_key->devCtx);
}
if (need_ephemeral_key) {
#ifdef WOLFSSL_STSAFEA120
/* Key is in slot 1 (for ECDSA), but ECDH requires ephemeral slot.
* Generate ephemeral key pair for ECDH. Note: This will overwrite any
* existing key in ephemeral slot, so for bidirectional ECDH, both keys
* should be generated in ephemeral slot from the start. */
stse_ReturnCode_t ret;
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
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;
STSAFE_INTERFACE_PRINTF("STSAFE: ECDH with slot %d, curve_id %d\n",
slot, curve_id);
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
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;
}
}
}
}
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
XFREE(ephemeralPubKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
#else /* WOLFSSL_STSAFEA100 */
/* For A100/A110, ephemeral key generation in ECDH callback
* is not supported. Keys must be generated in ephemeral slot
* from the start for ECDH operations. */
WOLFSSL_MSG("STSAFE: ECDH requires ephemeral slot - key must be generated in ephemeral slot");
rc = stsafe_shared_secret(slot, curve_id,
otherKeyX, otherKeyY,
info->pk.ecdh.out, (int32_t*)info->pk.ecdh.outlen);
if (rc != STSAFE_A_OK) {
WOLFSSL_MSG("STSAFE: stsafe_shared_secret failed");
STSAFE_INTERFACE_PRINTF("stsafe_shared_secret "
"error: %d (slot: %d, curve_id: %d)\n",
rc, slot, curve_id);
rc = WC_HW_E;
#endif
} else {
/* Key is already in ephemeral slot, use it */
slot = STSAFE_KEY_SLOT_EPHEMERAL;
}
if (rc == 0) {
STSAFE_INTERFACE_PRINTF("STSAFE: Computing shared secret with ephemeral slot %d, curve_id %d\n",
slot, curve_id);
rc = stsafe_shared_secret(slot, curve_id,
otherKeyX, otherKeyY,
info->pk.ecdh.out, (int32_t*)info->pk.ecdh.outlen);
if (rc != STSAFE_A_OK) {
WOLFSSL_MSG("STSAFE: stsafe_shared_secret failed");
STSAFE_INTERFACE_PRINTF("stsafe_shared_secret error: %d (slot: %d, curve_id: %d)\n",
rc, slot, curve_id);
rc = WC_HW_E;
}
}
}
}