@@ -42477,7 +42477,8 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t ecc_test(void)
4247742477#if !defined(WOLFSSL_ATECC508A) && !defined(WOLFSSL_ATECC608A) && \
4247842478 !defined(WOLFSSL_MICROCHIP_TA100) && \
4247942479 !defined(WOLFSSL_STM32_PKA) && !defined(WOLFSSL_SILABS_SE_ACCEL) && \
42480- !defined(WOLF_CRYPTO_CB_ONLY_ECC) && !defined(NO_ECC_SECP)
42480+ (!defined(WOLF_CRYPTO_CB_ONLY_ECC) || defined(WOLFSSL_SWDEV)) && \
42481+ !defined(NO_ECC_SECP)
4248142482 ret = ecc_test_make_pub(&rng);
4248242483 if (ret != 0) {
4248342484 printf("ecc_test_make_pub failed!\n");
@@ -71995,6 +71996,17 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t blob_test(void)
7199571996/* Example custom context for crypto callback */
7199671997typedef struct {
7199771998 int exampleVar; /* flag for testing if only crypt is enabled. */
71999+ #ifdef HAVE_ECC
72000+ int eccMakePubCount; /* EC make-pub callback invocations */
72001+ int eccMakePubBadFormat; /* when set, return a malformed (non-uncompressed)
72002+ * point to exercise the wrapper's BUFFER_E path */
72003+ int eccMakePubBadLen; /* when set, claim a result size different from the
72004+ * curve's X9.63 length to exercise the wrapper's
72005+ * size check */
72006+ ecc_key* eccResidentKey; /* when set, the make-pub callback emits this key's
72007+ * public point, simulating a private scalar
72008+ * resident in the device (input key->k empty) */
72009+ #endif
7199872010} myCryptoDevCtx;
7199972011
7200072012#ifdef WOLF_CRYPTO_CB_ONLY_RSA
@@ -72587,6 +72599,33 @@ static wc_test_ret_t aes_onlycb_test(myCryptoDevCtx *ctx)
7258772599}
7258872600#endif /* WOLF_CRYPTO_CB_ONLY_AES */
7258972601
72602+ #if defined(HAVE_ECC) && !defined(WOLFSSL_NO_MALLOC) && \
72603+ defined(HAVE_ECC_KEY_EXPORT)
72604+ /* Serialize pub to X9.63 uncompressed (0x04 || X || Y) using the curve size
72605+ * from dp, so custom-curve keys (idx == ECC_CUSTOM_IDX) work too;
72606+ * wc_ecc_export_point_der rejects negative curve indices. */
72607+ static int myCryptoCbExportPointX963(const ecc_set_type* dp, ecc_point* pub,
72608+ byte* out, word32* outSz)
72609+ {
72610+ int ret;
72611+ word32 curveSz = (word32)dp->size;
72612+ word32 ptSz = 1 + 2 * curveSz;
72613+ word32 xSz = curveSz;
72614+ word32 ySz = curveSz;
72615+
72616+ if (*outSz < ptSz)
72617+ return BUFFER_E;
72618+ out[0] = ECC_POINT_UNCOMP;
72619+ ret = wc_export_int(pub->x, out + 1, &xSz, curveSz, WC_TYPE_UNSIGNED_BIN);
72620+ if (ret == MP_OKAY)
72621+ ret = wc_export_int(pub->y, out + 1 + curveSz, &ySz, curveSz,
72622+ WC_TYPE_UNSIGNED_BIN);
72623+ if (ret == MP_OKAY)
72624+ *outSz = ptSz;
72625+ return ret;
72626+ }
72627+ #endif /* HAVE_ECC && !WOLFSSL_NO_MALLOC && HAVE_ECC_KEY_EXPORT */
72628+
7259072629/* Example crypto dev callback function that calls software version */
7259172630static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx)
7259272631{
@@ -72824,6 +72863,56 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx)
7282472863 ret = 0;
7282572864 }
7282672865 }
72866+ else if (info->pk.type == WC_PK_TYPE_EC_MAKE_PUB) {
72867+ #if !defined(WOLFSSL_NO_MALLOC) && defined(HAVE_ECC_KEY_EXPORT)
72868+ ecc_key* k = info->pk.ecc_make_pub.key;
72869+ ecc_point* pub;
72870+ if (myCtx->eccResidentKey != NULL) {
72871+ /* Secure-element case: the private scalar lives in the device,
72872+ * so the input key's k is empty. Emit the resident key's
72873+ * public point directly. Reaching this code at all proves the
72874+ * dispatch ran before ecc_make_pub_ex's software
72875+ * private-scalar range check. */
72876+ ecc_key* src = myCtx->eccResidentKey;
72877+ ret = myCryptoCbExportPointX963(src->dp, &src->pubkey,
72878+ info->pk.ecc_make_pub.pubOut,
72879+ info->pk.ecc_make_pub.pubOutSz);
72880+ myCtx->eccMakePubCount++;
72881+ }
72882+ else {
72883+ /* set devId to invalid, so software is used */
72884+ k->devId = INVALID_DEVID;
72885+ pub = wc_ecc_new_point_h(HEAP_HINT);
72886+ if (pub == NULL) {
72887+ ret = MEMORY_E;
72888+ }
72889+ else {
72890+ /* derive Q = d*G then emit X9.63 uncompressed bytes */
72891+ ret = wc_ecc_make_pub(k, pub);
72892+ if (ret == 0)
72893+ ret = myCryptoCbExportPointX963(k->dp, pub,
72894+ info->pk.ecc_make_pub.pubOut,
72895+ info->pk.ecc_make_pub.pubOutSz);
72896+ /* negative test: corrupt the X9.63 tag so the wrapper
72897+ * rejects the result with BUFFER_E instead of accepting
72898+ * it */
72899+ if (ret == 0 && myCtx->eccMakePubBadFormat)
72900+ info->pk.ecc_make_pub.pubOut[0] = ECC_POINT_COMP_EVEN;
72901+ /* negative test: claim a result size different from the
72902+ * curve's X9.63 length so the wrapper rejects the result
72903+ * with BUFFER_E instead of accepting it */
72904+ if (ret == 0 && myCtx->eccMakePubBadLen)
72905+ (*info->pk.ecc_make_pub.pubOutSz)++;
72906+ wc_ecc_del_point_h(pub, HEAP_HINT);
72907+ }
72908+ myCtx->eccMakePubCount++;
72909+ /* reset devId */
72910+ k->devId = devIdArg;
72911+ }
72912+ #else
72913+ ret = CRYPTOCB_UNAVAILABLE; /* no software emulation available */
72914+ #endif
72915+ }
7282772916 #endif /* HAVE_ECC */
7282872917 #ifdef HAVE_CURVE25519
7282972918 if (info->pk.type == WC_PK_TYPE_CURVE25519_KEYGEN) {
@@ -74555,6 +74644,12 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cryptocb_test(void)
7455574644
7455674645 /* example data for callback */
7455774646 myCtx.exampleVar = 1;
74647+ #ifdef HAVE_ECC
74648+ myCtx.eccMakePubCount = 0;
74649+ myCtx.eccMakePubBadFormat = 0;
74650+ myCtx.eccMakePubBadLen = 0;
74651+ myCtx.eccResidentKey = NULL;
74652+ #endif
7455874653
7455974654 /* set devId to something other than INVALID_DEVID */
7456074655 devId = 1;
@@ -74586,6 +74681,154 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cryptocb_test(void)
7458674681 if (ret == 0)
7458774682 ret = ecc_test();
7458874683 PRIVATE_KEY_LOCK();
74684+ /* Confirm the new ECC make-pub callback was routed through the device and
74685+ * not silently handled in software. */
74686+ #if !defined(WOLFSSL_ATECC508A) && !defined(WOLFSSL_ATECC608A) && \
74687+ !defined(WOLFSSL_MICROCHIP_TA100) && !defined(WOLFSSL_STM32_PKA) && \
74688+ !defined(WOLFSSL_SILABS_SE_ACCEL) && !defined(WOLF_CRYPTO_CB_ONLY_ECC) && \
74689+ !defined(NO_ECC_SECP) && !defined(WOLFSSL_NO_MALLOC) && \
74690+ !defined(WOLFSSL_CRYPTOCELL) && !defined(NO_ECC256) && \
74691+ defined(HAVE_ECC_KEY_EXPORT)
74692+ if (ret == 0 && myCtx.eccMakePubCount == 0)
74693+ ret = WC_TEST_RET_ENC_NC;
74694+ #endif
74695+ /* Exercise the make-pub wrapper's device-result validation and the
74696+ * resident-key dispatch path. Only meaningful where myCryptoDevCb (not
74697+ * swdev) services the make-pub callback.
74698+ *
74699+ * WOLFSSL_SE050 is excluded: its wc_ecc_make_key generates the key in the
74700+ * element, so srcKey has no host-side scalar (key->k) for the callback's
74701+ * software Q = d*G derivation to use. */
74702+ #if !defined(WOLFSSL_ATECC508A) && !defined(WOLFSSL_ATECC608A) && \
74703+ !defined(WOLFSSL_MICROCHIP_TA100) && !defined(WOLFSSL_STM32_PKA) && \
74704+ !defined(WOLFSSL_SILABS_SE_ACCEL) && !defined(WOLF_CRYPTO_CB_ONLY_ECC) && \
74705+ !defined(WOLFSSL_SWDEV) && !defined(NO_ECC_SECP) && \
74706+ !defined(WOLFSSL_NO_MALLOC) && !defined(WOLFSSL_CRYPTOCELL) && \
74707+ !defined(WOLFSSL_SE050) && \
74708+ !defined(NO_ECC256) && defined(HAVE_ECC_KEY_EXPORT) && !defined(WC_NO_RNG)
74709+ if (ret == 0) {
74710+ /* generated keypair: private scalar for the negative tests, public
74711+ * point for the resident-key test */
74712+ WC_DECLARE_VAR(srcKey, ecc_key, 1, HEAP_HINT);
74713+ /* device-backed key with an empty private scalar */
74714+ WC_DECLARE_VAR(resKey, ecc_key, 1, HEAP_HINT);
74715+ WC_DECLARE_VAR(eccRng, WC_RNG, 1, HEAP_HINT);
74716+ ecc_point* outPub = NULL;
74717+ int haveSrc = 0, haveRes = 0, haveRng = 0;
74718+ int beforeCount = 0;
74719+
74720+ WC_ALLOC_VAR(srcKey, ecc_key, 1, HEAP_HINT);
74721+ WC_ALLOC_VAR(resKey, ecc_key, 1, HEAP_HINT);
74722+ WC_ALLOC_VAR(eccRng, WC_RNG, 1, HEAP_HINT);
74723+ PRIVATE_KEY_UNLOCK();
74724+ if (!WC_VAR_OK(srcKey) || !WC_VAR_OK(resKey) || !WC_VAR_OK(eccRng))
74725+ ret = MEMORY_E;
74726+ else
74727+ ret = wc_InitRng_ex(eccRng, HEAP_HINT, devId);
74728+ if (ret == 0) {
74729+ haveRng = 1;
74730+ ret = wc_ecc_init_ex(srcKey, HEAP_HINT, devId);
74731+ }
74732+ if (ret == 0) {
74733+ haveSrc = 1;
74734+ ret = wc_ecc_make_key(eccRng, 32, srcKey);
74735+ }
74736+ if (ret == 0) {
74737+ outPub = wc_ecc_new_point_h(HEAP_HINT);
74738+ if (outPub == NULL)
74739+ ret = WC_TEST_RET_ENC_NC;
74740+ }
74741+ /* Negative test: when the device returns a malformed
74742+ * (non-uncompressed) point, wc_CryptoCb_EccMakePub must reject it
74743+ * with BUFFER_E rather than accept a bad public key. */
74744+ if (ret == 0) {
74745+ myCtx.eccMakePubBadFormat = 1;
74746+ ret = wc_ecc_make_pub(srcKey, outPub);
74747+ myCtx.eccMakePubBadFormat = 0;
74748+ /* expect the wrapper to reject the malformed point */
74749+ if (ret == WC_NO_ERR_TRACE(BUFFER_E))
74750+ ret = 0;
74751+ else if (ret == 0)
74752+ ret = WC_TEST_RET_ENC_NC; /* must not silently succeed */
74753+ else
74754+ ret = WC_TEST_RET_ENC_EC(ret); /* unexpected error */
74755+ }
74756+ /* Negative test: when the device claims a result size different from
74757+ * the curve's X9.63 length, wc_CryptoCb_EccMakePub must reject it
74758+ * with BUFFER_E rather than silently truncate it. */
74759+ if (ret == 0) {
74760+ myCtx.eccMakePubBadLen = 1;
74761+ ret = wc_ecc_make_pub(srcKey, outPub);
74762+ myCtx.eccMakePubBadLen = 0;
74763+ if (ret == WC_NO_ERR_TRACE(BUFFER_E))
74764+ ret = 0;
74765+ else if (ret == 0)
74766+ ret = WC_TEST_RET_ENC_NC; /* must not silently succeed */
74767+ else
74768+ ret = WC_TEST_RET_ENC_EC(ret); /* unexpected error */
74769+ }
74770+ /* Regression: a key whose private scalar is resident in the device
74771+ * (the input key's k is empty here) must still produce its public
74772+ * key. The make-pub dispatch has to run before ecc_make_pub_ex's
74773+ * software private-scalar range check; otherwise this returns
74774+ * ECC_PRIV_KEY_E and the callback is never reached. */
74775+ if (ret == 0)
74776+ ret = wc_ecc_init_ex(resKey, HEAP_HINT, devId);
74777+ if (ret == 0) {
74778+ haveRes = 1;
74779+ /* device-backed key: same curve, but no private scalar present */
74780+ ret = wc_ecc_set_curve(resKey, 32, ECC_SECP256R1);
74781+ }
74782+ if (ret == 0) {
74783+ /* device serves make-pub from srcKey's resident public point */
74784+ myCtx.eccResidentKey = srcKey;
74785+ beforeCount = myCtx.eccMakePubCount;
74786+ ret = wc_ecc_make_pub(resKey, NULL);
74787+ myCtx.eccResidentKey = NULL;
74788+
74789+ if (ret != 0) {
74790+ /* before the fix this is ECC_PRIV_KEY_E: the empty scalar was
74791+ * rejected before the dispatch could run */
74792+ ret = WC_TEST_RET_ENC_EC(ret);
74793+ }
74794+ else if (myCtx.eccMakePubCount != beforeCount + 1) {
74795+ ret = WC_TEST_RET_ENC_NC; /* callback was bypassed */
74796+ }
74797+ else if (wc_ecc_cmp_point(&resKey->pubkey, &srcKey->pubkey)
74798+ != MP_EQ) {
74799+ ret = WC_TEST_RET_ENC_NC; /* wrong public point produced */
74800+ }
74801+ }
74802+ #ifdef WOLFSSL_CUSTOM_CURVES
74803+ /* Regression: make-pub via the device for a custom-curve key
74804+ * (idx == ECC_CUSTOM_IDX): the handler must serialize the point
74805+ * using key->dp->size, not ecc_sets[key->idx]. Reuse srcKey's P-256
74806+ * parameters under a custom-curve identity. */
74807+ if (ret == 0)
74808+ ret = wc_ecc_set_custom_curve(srcKey,
74809+ wc_ecc_get_curve_params(srcKey->idx));
74810+ if (ret == 0) {
74811+ ret = wc_ecc_make_pub(srcKey, outPub);
74812+ if (ret != 0)
74813+ ret = WC_TEST_RET_ENC_EC(ret);
74814+ else if (wc_ecc_cmp_point(outPub, &srcKey->pubkey) != MP_EQ)
74815+ ret = WC_TEST_RET_ENC_NC; /* wrong public point produced */
74816+ }
74817+ #endif /* WOLFSSL_CUSTOM_CURVES */
74818+ if (outPub != NULL)
74819+ wc_ecc_del_point_h(outPub, HEAP_HINT);
74820+ if (haveRes)
74821+ wc_ecc_free(resKey);
74822+ if (haveSrc)
74823+ wc_ecc_free(srcKey);
74824+ if (haveRng)
74825+ wc_FreeRng(eccRng);
74826+ WC_FREE_VAR(srcKey, HEAP_HINT);
74827+ WC_FREE_VAR(resKey, HEAP_HINT);
74828+ WC_FREE_VAR(eccRng, HEAP_HINT);
74829+ PRIVATE_KEY_LOCK();
74830+ }
74831+ #endif
7458974832#endif
7459074833#if defined(WOLF_CRYPTO_CB_ONLY_ECC) && !defined(WOLFSSL_SWDEV)
7459174834 PRIVATE_KEY_UNLOCK();
0 commit comments