Skip to content

Commit 0d98a65

Browse files
committed
test: cover the EC make-pub crypto callback
1 parent f787788 commit 0d98a65

1 file changed

Lines changed: 244 additions & 1 deletion

File tree

wolfcrypt/test/test.c

Lines changed: 244 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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 */
7199671997
typedef 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 */
7259172630
static 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

Comments
 (0)