@@ -71998,11 +71998,14 @@ typedef struct {
7199871998 int exampleVar; /* flag for testing if only crypt is enabled. */
7199971999#ifdef HAVE_ECC
7200072000 int eccMakePubCount; /* EC make-pub callback invocations */
72001+ int eccCheckPubCount; /* EC check-pubkey callback invocations */
7200172002 int eccMakePubBadFormat; /* when set, return a malformed (non-uncompressed)
7200272003 * point to exercise the wrapper's BUFFER_E path */
7200372004 int eccMakePubBadLen; /* when set, claim a result size different from the
7200472005 * curve's X9.63 length to exercise the wrapper's
7200572006 * size check */
72007+ int eccCheckPubExpectZeroPoint; /* require serialized 0,0 input */
72008+ int eccCheckPubSawZeroPoint; /* EC check-pubkey saw X9.63 0,0 */
7200672009 ecc_key* eccResidentKey; /* when set, the make-pub callback emits this key's
7200772010 * public point, simulating a private scalar
7200872011 * resident in the device (input key->k empty) */
@@ -72913,6 +72916,82 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx)
7291372916 ret = CRYPTOCB_UNAVAILABLE; /* no software emulation available */
7291472917 #endif
7291572918 }
72919+ #ifdef HAVE_ECC_CHECK_KEY
72920+ else if (info->pk.type == WC_PK_TYPE_EC_CHECK_PUB_KEY) {
72921+ ecc_key* k = info->pk.ecc_check_pub.key;
72922+ int validatedFromWire = 0;
72923+ myCtx->eccCheckPubCount++;
72924+ if (info->pk.ecc_check_pub.pubKeySz == 0) {
72925+ /* no host-side public point and this software device holds no
72926+ * resident key, so there is nothing to validate (matches the
72927+ * software answer for a missing public point) */
72928+ ret = ECC_INF_E;
72929+ }
72930+ else {
72931+ ret = 0;
72932+ if (myCtx != NULL && myCtx->eccCheckPubExpectZeroPoint) {
72933+ const byte* pub = info->pk.ecc_check_pub.pubKey;
72934+ word32 curveSz = (word32)k->dp->size;
72935+ word32 ptSz = 1 + 2 * curveSz;
72936+ word32 i;
72937+
72938+ if (info->pk.ecc_check_pub.pubKeySz != ptSz ||
72939+ pub[0] != ECC_POINT_UNCOMP) {
72940+ ret = BAD_STATE_E;
72941+ }
72942+ for (i = 1; ret == 0 && i < ptSz; i++) {
72943+ if (pub[i] != 0)
72944+ ret = BAD_STATE_E;
72945+ }
72946+ if (ret == 0)
72947+ myCtx->eccCheckPubSawZeroPoint = 1;
72948+ }
72949+ #ifdef HAVE_ECC_KEY_IMPORT
72950+ /* vault-style consumption: rebuild the public key from the
72951+ * wire bytes and validate the rebuilt key, proving the
72952+ * serialized point is sufficient and consistent with
72953+ * key->pubkey. The named-curve import does not apply to
72954+ * custom-curve keys (idx == ECC_CUSTOM_IDX). */
72955+ if (k->idx >= 0) {
72956+ WC_DECLARE_VAR(pubOnly, ecc_key, 1, HEAP_HINT);
72957+ WC_ALLOC_VAR(pubOnly, ecc_key, 1, HEAP_HINT);
72958+ if (!WC_VAR_OK(pubOnly))
72959+ ret = MEMORY_E;
72960+ else
72961+ ret = wc_ecc_init_ex(pubOnly, HEAP_HINT, INVALID_DEVID);
72962+ if (ret == 0) {
72963+ ret = wc_ecc_import_x963_ex(
72964+ info->pk.ecc_check_pub.pubKey,
72965+ info->pk.ecc_check_pub.pubKeySz, pubOnly,
72966+ k->dp->id);
72967+ if (ret == 0 && wc_ecc_cmp_point(&pubOnly->pubkey,
72968+ &k->pubkey) != MP_EQ) {
72969+ /* wire bytes disagree with key->pubkey */
72970+ ret = BAD_STATE_E;
72971+ }
72972+ if (ret == 0)
72973+ ret = wc_ecc_check_key(pubOnly);
72974+ wc_ecc_free(pubOnly);
72975+ }
72976+ WC_FREE_VAR(pubOnly, HEAP_HINT);
72977+ validatedFromWire = 1;
72978+ }
72979+ #endif
72980+ /* private/resident part (and custom-curve keys, where the
72981+ * named-curve import above is unavailable): validate via the
72982+ * key handle */
72983+ if (ret == 0 && (!validatedFromWire ||
72984+ (info->pk.ecc_check_pub.checkPriv &&
72985+ k->type == ECC_PRIVATEKEY))) {
72986+ /* set devId to invalid, so software is used */
72987+ k->devId = INVALID_DEVID;
72988+ ret = wc_ecc_check_key(k);
72989+ /* reset devId */
72990+ k->devId = devIdArg;
72991+ }
72992+ }
72993+ }
72994+ #endif
7291672995 #endif /* HAVE_ECC */
7291772996 #ifdef HAVE_CURVE25519
7291872997 if (info->pk.type == WC_PK_TYPE_CURVE25519_KEYGEN) {
@@ -74646,8 +74725,11 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cryptocb_test(void)
7464674725 myCtx.exampleVar = 1;
7464774726#ifdef HAVE_ECC
7464874727 myCtx.eccMakePubCount = 0;
74728+ myCtx.eccCheckPubCount = 0;
7464974729 myCtx.eccMakePubBadFormat = 0;
7465074730 myCtx.eccMakePubBadLen = 0;
74731+ myCtx.eccCheckPubExpectZeroPoint = 0;
74732+ myCtx.eccCheckPubSawZeroPoint = 0;
7465174733 myCtx.eccResidentKey = NULL;
7465274734#endif
7465374735
@@ -74681,8 +74763,60 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cryptocb_test(void)
7468174763 if (ret == 0)
7468274764 ret = ecc_test();
7468374765 PRIVATE_KEY_LOCK();
74684- /* Confirm the new ECC make-pub callback was routed through the device and
74685- * not silently handled in software. */
74766+ /* Confirm the new ECC pubkey callbacks were routed through the device and
74767+ * not silently handled in software. The check-pubkey callback is only
74768+ * exercised when wc_ecc_check_key is built (HAVE_ECC_CHECK_KEY) and the
74769+ * ecc_test calls to it are not skipped (WC_TEST_SKIP_ECC_CHECK_KEY); the
74770+ * counter legitimately stays 0 otherwise. CAAM is excluded because the
74771+ * check-pubkey dispatch in _ecc_validate_public_key is compiled out there
74772+ * (CAAM uses software validation failure to detect black keys). */
74773+ #if !defined(WOLF_CRYPTO_CB_ONLY_ECC) && defined(HAVE_ECC_CHECK_KEY) && \
74774+ !defined(WC_TEST_SKIP_ECC_CHECK_KEY) && !defined(WOLFSSL_CAAM)
74775+ if (ret == 0 && myCtx.eccCheckPubCount == 0)
74776+ ret = WC_TEST_RET_ENC_NC;
74777+ #endif
74778+ /* Regression: an explicit public point with zero coordinates must cross
74779+ * the callback boundary as X9.63 0x04||0||0, not as pubKey = NULL. */
74780+ #if !defined(WOLFSSL_SWDEV) && defined(HAVE_ECC_CHECK_KEY) && \
74781+ !defined(WOLFSSL_CAAM) && !defined(NO_ECC256)
74782+ if (ret == 0) {
74783+ WC_DECLARE_VAR(zeroKey, ecc_key, 1, HEAP_HINT);
74784+ int haveZeroKey = 0;
74785+
74786+ WC_ALLOC_VAR(zeroKey, ecc_key, 1, HEAP_HINT);
74787+ PRIVATE_KEY_UNLOCK();
74788+ if (!WC_VAR_OK(zeroKey))
74789+ ret = MEMORY_E;
74790+ else
74791+ ret = wc_ecc_init_ex(zeroKey, HEAP_HINT, devId);
74792+ if (ret == 0) {
74793+ haveZeroKey = 1;
74794+ ret = wc_ecc_set_curve(zeroKey, 32, ECC_SECP256R1);
74795+ }
74796+ if (ret == 0) {
74797+ zeroKey->type = ECC_PUBLICKEY;
74798+ myCtx.eccCheckPubExpectZeroPoint = 1;
74799+ myCtx.eccCheckPubSawZeroPoint = 0;
74800+ ret = wc_ecc_check_key(zeroKey);
74801+ myCtx.eccCheckPubExpectZeroPoint = 0;
74802+
74803+ if (ret == 0) {
74804+ ret = WC_TEST_RET_ENC_NC; /* invalid point was accepted */
74805+ }
74806+ else if (!myCtx.eccCheckPubSawZeroPoint) {
74807+ ret = WC_TEST_RET_ENC_NC; /* callback saw NULL/other point */
74808+ }
74809+ else {
74810+ ret = 0; /* expected validation failure after serialization */
74811+ }
74812+ }
74813+ myCtx.eccCheckPubExpectZeroPoint = 0;
74814+ if (haveZeroKey)
74815+ wc_ecc_free(zeroKey);
74816+ WC_FREE_VAR(zeroKey, HEAP_HINT);
74817+ PRIVATE_KEY_LOCK();
74818+ }
74819+ #endif
7468674820#if !defined(WOLFSSL_ATECC508A) && !defined(WOLFSSL_ATECC608A) && \
7468774821 !defined(WOLFSSL_MICROCHIP_TA100) && !defined(WOLFSSL_STM32_PKA) && \
7468874822 !defined(WOLFSSL_SILABS_SE_ACCEL) && !defined(WOLF_CRYPTO_CB_ONLY_ECC) && \
0 commit comments