From 25224b682763c9068e2dc7f5df44395a647e286e Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Thu, 20 Aug 2026 16:05:51 -0400 Subject: [PATCH] Add wc_ecc_key_new_ex (#11160) * Add wc_ecc_key_new_ex Rust wrapper: use wc_ecc_key_new_ex for ECC when available. Fixes F-8300. * Check devId after wc_ecc_key_new_ex() call in unit test --- doc/dox_comments/header_files/ecc.h | 61 +++++++++++++---------- wolfcrypt/src/ecc.c | 20 +++++--- wolfcrypt/src/hpke.c | 10 +--- wolfcrypt/test/test.c | 43 ++++++++++++++++ wolfssl/wolfcrypt/ecc.h | 1 + wrapper/rust/wolfssl-wolfcrypt/build.rs | 1 + wrapper/rust/wolfssl-wolfcrypt/src/ecc.rs | 16 +++--- 7 files changed, 104 insertions(+), 48 deletions(-) diff --git a/doc/dox_comments/header_files/ecc.h b/doc/dox_comments/header_files/ecc.h index 74c700321d..a0210c23ae 100644 --- a/doc/dox_comments/header_files/ecc.h +++ b/doc/dox_comments/header_files/ecc.h @@ -682,7 +682,8 @@ int wc_ecc_init(ecc_key* key); \param key pointer to the ecc_key object to initialize \param heap pointer to a heap identifier - \param devId ID to use with crypto callbacks or async hardware. Set to INVALID_DEVID (-2) if not used + \param devId ID to use with crypto callbacks or async hardware. Set to + INVALID_DEVID if not used _Example_ \code @@ -703,8 +704,11 @@ int wc_ecc_init_ex(ecc_key* key, void* heap, int devId); \brief This function uses a user defined heap and allocates space for the key structure. - \return 0 Returned upon successfully initializing the ecc_key object - \return MEMORY_E Returned if there is an error allocating memory + \param heap pointer to a heap identifier + + \return Non-null returned upon successfully allocating and initializing the + ecc_key object + \return NULL returned if there is an error allocating memory _Example_ @@ -712,6 +716,7 @@ int wc_ecc_init_ex(ecc_key* key, void* heap, int devId); wc_ecc_key_new(&heap); \endcode + \sa wc_ecc_key_new_ex \sa wc_ecc_make_key \sa wc_ecc_key_free \sa wc_ecc_init @@ -719,6 +724,34 @@ int wc_ecc_init_ex(ecc_key* key, void* heap, int devId); ecc_key* wc_ecc_key_new(void* heap); +/*! + \ingroup ECC + + \brief This function uses a user defined heap and allocates space for the + key structure. + + \param heap pointer to a heap identifier + \param devId ID to use with crypto callbacks or async hardware. Set to + INVALID_DEVID if not used + + \return Non-null returned upon successfully allocating and initializing the + ecc_key object + \return NULL returned if there is an error allocating memory + + + _Example_ + \code + wc_ecc_key_new_ex(&heap, MY_DEVID); + \endcode + + \sa wc_ecc_key_new + \sa wc_ecc_make_key + \sa wc_ecc_key_free + \sa wc_ecc_init +*/ + +ecc_key* wc_ecc_key_new_ex(void* heap, int devId); + /*! \ingroup ECC @@ -2298,28 +2331,6 @@ int wc_ecc_set_curve(ecc_key *key, int keysize, int curve_id); */ mp_int* wc_ecc_key_get_priv(ecc_key* key); -/*! - \ingroup ECC - \brief Allocates and initializes new ECC key. - - \return ecc_key pointer on success - \return NULL on failure - - \param heap Heap hint for memory allocation - - _Example_ - \code - ecc_key* key = wc_ecc_key_new(NULL); - if (key != NULL) { - // use key - wc_ecc_key_free(key); - } - \endcode - - \sa wc_ecc_key_free -*/ -ecc_key* wc_ecc_key_new(void* heap); - /*! \ingroup ECC \brief Returns number of supported ECC curve sets. diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index ad6c34b071..069ad9ea9c 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -6366,15 +6366,10 @@ static void wc_ecc_dump_oids(void) WOLFSSL_ABI -ecc_key* wc_ecc_key_new(void* heap) +ecc_key* wc_ecc_key_new_ex(void* heap, int devId) { - int devId = INVALID_DEVID; ecc_key* key; -#if defined(WOLFSSL_QNX_CAAM) || defined(WOLFSSL_IMXRT1170_CAAM) - /* assume all keys are using CAAM for ECC unless explicitly set otherwise */ - devId = WOLFSSL_CAAM_DEVID; -#endif key = (ecc_key*)XMALLOC(sizeof(ecc_key), heap, DYNAMIC_TYPE_ECC); if (key) { if (wc_ecc_init_ex(key, heap, devId) != 0) { @@ -6386,6 +6381,19 @@ ecc_key* wc_ecc_key_new(void* heap) return key; } +WOLFSSL_ABI +ecc_key* wc_ecc_key_new(void* heap) +{ +#if defined(WOLFSSL_QNX_CAAM) || defined(WOLFSSL_IMXRT1170_CAAM) + /* assume all keys are using CAAM for ECC unless explicitly set otherwise */ + int devId = WOLFSSL_CAAM_DEVID; +#else + int devId = INVALID_DEVID; +#endif + + return wc_ecc_key_new_ex(heap, devId); +} + WOLFSSL_ABI void wc_ecc_key_free(ecc_key* key) diff --git a/wolfcrypt/src/hpke.c b/wolfcrypt/src/hpke.c index 472cb03517..12e49dde3b 100644 --- a/wolfcrypt/src/hpke.c +++ b/wolfcrypt/src/hpke.c @@ -1116,18 +1116,10 @@ static int wc_HpkeCopyPrivateKey(Hpke* hpke, void* key, void** copy) ret = wc_ecc_export_private_only((ecc_key*)key, eccPriv, &eccPrivSz); if (ret == 0) { - *copy = wc_ecc_key_new(hpke->heap); + *copy = wc_ecc_key_new_ex(hpke->heap, INVALID_DEVID); if (*copy == NULL) ret = MEMORY_E; } - #if defined(PLUTON_CRYPTO_ECC) || defined(WOLF_CRYPTO_CB) - /* wc_ecc_key_new() adopts a platform default device id on some - * ports. The key being copied has none, so the copy must not gain - * one, or the shared secret would move onto a device the caller - * never asked for. */ - if (ret == 0) - ((ecc_key*)*copy)->devId = INVALID_DEVID; - #endif if (ret == 0) { /* The public part is not needed: the shared secret takes its * point from the ephemeral key. */ diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 4e00e49613..c55dd59556 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -45267,6 +45267,44 @@ static wc_test_ret_t ecc_test_allocator(WC_RNG* rng) (void)rng; #endif +exit: + wc_ecc_key_free(key); + return ret; +} + +/* Test for the wc_ecc_key_new_ex() and wc_ecc_key_free() functions. */ +static wc_test_ret_t ecc_test_allocator_ex(WC_RNG* rng) +{ + wc_test_ret_t ret = 0; + ecc_key* key; +#ifdef WC_NO_RNG + word32 idx = 0; +#endif + + key = wc_ecc_key_new_ex(HEAP_HINT, devId); + if (key == NULL) { + ERROR_OUT(WC_TEST_RET_ENC_ERRNO, exit); + } +#if defined(PLUTON_CRYPTO_ECC) || defined(WOLF_CRYPTO_CB) + if (key->devId != devId) { + ERROR_OUT(WC_TEST_RET_ENC_NC, exit); + } +#endif + +#ifndef WC_NO_RNG + ret = wc_ecc_make_key(rng, ECC_KEYGEN_SIZE, key); +#if defined(WOLFSSL_ASYNC_CRYPT) + ret = wc_AsyncWait(ret, &key->asyncDev, WC_ASYNC_FLAG_NONE); +#endif + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit); +#else + /* use test ECC key */ + ret = wc_EccPrivateKeyDecode(ecc_key_der_256, &idx, key, + (word32)sizeof_ecc_key_der_256); + (void)rng; +#endif + exit: wc_ecc_key_free(key); return ret; @@ -46277,6 +46315,11 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t ecc_test(void) printf("ecc_test_allocator failed!\n"); goto done; } + ret = ecc_test_allocator_ex(&rng); + if (ret != 0) { + printf("ecc_test_allocator_ex failed!\n"); + goto done; + } #endif #if defined(WC_ECC_NONBLOCK) && defined(WOLFSSL_PUBLIC_MP) && \ diff --git a/wolfssl/wolfcrypt/ecc.h b/wolfssl/wolfcrypt/ecc.h index 5fda1c27f5..effe7f72ad 100644 --- a/wolfssl/wolfcrypt/ecc.h +++ b/wolfssl/wolfcrypt/ecc.h @@ -701,6 +701,7 @@ WOLFSSL_API mp_int* wc_ecc_key_get_priv(ecc_key* key); WOLFSSL_ABI WOLFSSL_API ecc_key* wc_ecc_key_new(void* heap); +WOLFSSL_ABI WOLFSSL_API ecc_key* wc_ecc_key_new_ex(void* heap, int devId); WOLFSSL_ABI WOLFSSL_API void wc_ecc_key_free(ecc_key* key); diff --git a/wrapper/rust/wolfssl-wolfcrypt/build.rs b/wrapper/rust/wolfssl-wolfcrypt/build.rs index 3a2669e436..d614a4eafe 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/build.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/build.rs @@ -397,6 +397,7 @@ fn scan_cfg() -> Result<()> { /* ecc */ check_cfg(&binding, "wc_ecc_init", "ecc"); + check_cfg(&binding, "wc_ecc_key_new_ex", "ecc_key_new_ex"); check_cfg(&binding, "wc_ecc_export_point_der_compressed", "ecc_comp_key"); check_cfg(&binding, "wc_ecc_shared_secret", "ecc_dh"); check_cfg(&binding, "wc_ecc_sign_hash", "ecc_sign"); diff --git a/wrapper/rust/wolfssl-wolfcrypt/src/ecc.rs b/wrapper/rust/wolfssl-wolfcrypt/src/ecc.rs index abe77c89ba..1049e7e2a4 100644 --- a/wrapper/rust/wolfssl-wolfcrypt/src/ecc.rs +++ b/wrapper/rust/wolfssl-wolfcrypt/src/ecc.rs @@ -398,19 +398,19 @@ impl ECC { /// Allocate and initialize a new `sys::ecc_key` on the C heap. fn new_ecc_key(heap: *mut core::ffi::c_void, dev_id: i32) -> Result<*mut sys::ecc_key, i32> { + #[cfg(ecc_key_new_ex)] + let key = unsafe { sys::wc_ecc_key_new_ex(heap, dev_id) }; + #[cfg(not(ecc_key_new_ex))] let key = unsafe { sys::wc_ecc_key_new(heap) }; if key.is_null() { return Err(sys::wolfCrypt_ErrorCodes_MEMORY_E); } - // wc_ecc_key_new() always initializes the key with INVALID_DEVID. - // Calling wc_ecc_init_ex() a second time to install the user's dev_id - // would re-run every initialization step (including allocations under - // some build configurations such as async crypto without WOLF_CRYPTO_CB) - // and orphan resources from the first init. Instead, just patch devId - // in place for WOLF_CRYPTO_CB builds. - #[cfg(wolf_crypto_cb)] + // wc_ecc_key_new() does not take a devId argument. Patch devId in + // place for WOLF_CRYPTO_CB builds where wc_ecc_key_new_ex() is not + // available. + #[cfg(all(not(ecc_key_new_ex), wolf_crypto_cb))] unsafe { (*key).devId = dev_id; } - #[cfg(not(wolf_crypto_cb))] + #[cfg(all(not(ecc_key_new_ex), not(wolf_crypto_cb)))] let _ = dev_id; Ok(key) }