From 38b0fe19a1ee34d2ea5679236776b1e63e28a79d Mon Sep 17 00:00:00 2001 From: David Garske Date: Wed, 21 Jan 2026 00:02:52 +0000 Subject: [PATCH] Improvements to code for ECDHE and peer review fixes. --- .wolfssl_known_macro_extras | 2 + wolfcrypt/src/port/st/stsafe.c | 259 ++++++++------------------------- 2 files changed, 59 insertions(+), 202 deletions(-) diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index 01d989177..3602cf6b5 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -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 diff --git a/wolfcrypt/src/port/st/stsafe.c b/wolfcrypt/src/port/st/stsafe.c index 36afc56c0..7f308d6f1 100644 --- a/wolfcrypt/src/port/st/stsafe.c +++ b/wolfcrypt/src/port/st/stsafe.c @@ -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; - } } } }