@@ -71839,11 +71839,14 @@ typedef struct {
7183971839 int exampleVar; /* flag for testing if only crypt is enabled. */
7184071840#ifdef HAVE_ECC
7184171841 int eccMakePubCount; /* EC make-pub callback invocations */
71842+ int eccCheckPubCount; /* EC check-pubkey callback invocations */
7184271843 int eccMakePubBadFormat; /* when set, return a malformed (non-uncompressed)
7184371844 * point to exercise the wrapper's BUFFER_E path */
7184471845 int eccMakePubBadLen; /* when set, claim a result size different from the
7184571846 * curve's X9.63 length to exercise the wrapper's
7184671847 * size check */
71848+ int eccCheckPubExpectZeroPoint; /* require serialized 0,0 input */
71849+ int eccCheckPubSawZeroPoint; /* EC check-pubkey saw X9.63 0,0 */
7184771850 ecc_key* eccResidentKey; /* when set, the make-pub callback emits this key's
7184871851 * public point, simulating a private scalar
7184971852 * resident in the device (input key->k empty) */
@@ -72754,6 +72757,77 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx)
7275472757 ret = CRYPTOCB_UNAVAILABLE; /* no software emulation available */
7275572758 #endif
7275672759 }
72760+ #ifdef HAVE_ECC_CHECK_KEY
72761+ else if (info->pk.type == WC_PK_TYPE_EC_CHECK_PUB_KEY) {
72762+ ecc_key* k = info->pk.ecc_check_pub.key;
72763+ int validatedFromWire = 0;
72764+ myCtx->eccCheckPubCount++;
72765+ if (info->pk.ecc_check_pub.pubKeySz == 0) {
72766+ /* no host-side public point and this software device holds no
72767+ * resident key, so there is nothing to validate (matches the
72768+ * software answer for a missing public point) */
72769+ ret = ECC_INF_E;
72770+ }
72771+ else {
72772+ ret = 0;
72773+ if (myCtx != NULL && myCtx->eccCheckPubExpectZeroPoint) {
72774+ const byte* pub = info->pk.ecc_check_pub.pubKey;
72775+ word32 curveSz = (word32)k->dp->size;
72776+ word32 ptSz = 1 + 2 * curveSz;
72777+ word32 i;
72778+
72779+ if (info->pk.ecc_check_pub.pubKeySz != ptSz ||
72780+ pub[0] != ECC_POINT_UNCOMP) {
72781+ ret = BAD_STATE_E;
72782+ }
72783+ for (i = 1; ret == 0 && i < ptSz; i++) {
72784+ if (pub[i] != 0)
72785+ ret = BAD_STATE_E;
72786+ }
72787+ if (ret == 0)
72788+ myCtx->eccCheckPubSawZeroPoint = 1;
72789+ }
72790+ #ifdef HAVE_ECC_KEY_IMPORT
72791+ /* vault-style consumption: rebuild the public key from the
72792+ * wire bytes and validate the rebuilt key, proving the
72793+ * serialized point is sufficient and consistent with
72794+ * key->pubkey. The named-curve import does not apply to
72795+ * custom-curve keys (idx == ECC_CUSTOM_IDX). */
72796+ if (k->idx >= 0) {
72797+ ecc_key pubOnly;
72798+ ret = wc_ecc_init_ex(&pubOnly, HEAP_HINT, INVALID_DEVID);
72799+ if (ret == 0) {
72800+ ret = wc_ecc_import_x963_ex(
72801+ info->pk.ecc_check_pub.pubKey,
72802+ info->pk.ecc_check_pub.pubKeySz, &pubOnly,
72803+ k->dp->id);
72804+ if (ret == 0 && wc_ecc_cmp_point(&pubOnly.pubkey,
72805+ &k->pubkey) != MP_EQ) {
72806+ /* wire bytes disagree with key->pubkey */
72807+ ret = BAD_STATE_E;
72808+ }
72809+ if (ret == 0)
72810+ ret = wc_ecc_check_key(&pubOnly);
72811+ wc_ecc_free(&pubOnly);
72812+ }
72813+ validatedFromWire = 1;
72814+ }
72815+ #endif
72816+ /* private/resident part (and custom-curve keys, where the
72817+ * named-curve import above is unavailable): validate via the
72818+ * key handle */
72819+ if (ret == 0 && (!validatedFromWire ||
72820+ (info->pk.ecc_check_pub.checkPriv &&
72821+ k->type == ECC_PRIVATEKEY))) {
72822+ /* set devId to invalid, so software is used */
72823+ k->devId = INVALID_DEVID;
72824+ ret = wc_ecc_check_key(k);
72825+ /* reset devId */
72826+ k->devId = devIdArg;
72827+ }
72828+ }
72829+ }
72830+ #endif
7275772831 #endif /* HAVE_ECC */
7275872832 #ifdef HAVE_CURVE25519
7275972833 if (info->pk.type == WC_PK_TYPE_CURVE25519_KEYGEN) {
@@ -74487,8 +74561,11 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cryptocb_test(void)
7448774561 myCtx.exampleVar = 1;
7448874562#ifdef HAVE_ECC
7448974563 myCtx.eccMakePubCount = 0;
74564+ myCtx.eccCheckPubCount = 0;
7449074565 myCtx.eccMakePubBadFormat = 0;
7449174566 myCtx.eccMakePubBadLen = 0;
74567+ myCtx.eccCheckPubExpectZeroPoint = 0;
74568+ myCtx.eccCheckPubSawZeroPoint = 0;
7449274569 myCtx.eccResidentKey = NULL;
7449374570#endif
7449474571
@@ -74522,8 +74599,55 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cryptocb_test(void)
7452274599 if (ret == 0)
7452374600 ret = ecc_test();
7452474601 PRIVATE_KEY_LOCK();
74525- /* Confirm the new ECC make-pub callback was routed through the device and
74526- * not silently handled in software. */
74602+ /* Confirm the new ECC pubkey callbacks were routed through the device and
74603+ * not silently handled in software. The check-pubkey callback is only
74604+ * exercised when wc_ecc_check_key is built (HAVE_ECC_CHECK_KEY) and the
74605+ * ecc_test calls to it are not skipped (WC_TEST_SKIP_ECC_CHECK_KEY); the
74606+ * counter legitimately stays 0 otherwise. CAAM is excluded because the
74607+ * check-pubkey dispatch in _ecc_validate_public_key is compiled out there
74608+ * (CAAM uses software validation failure to detect black keys). */
74609+ #if !defined(WOLF_CRYPTO_CB_ONLY_ECC) && defined(HAVE_ECC_CHECK_KEY) && \
74610+ !defined(WC_TEST_SKIP_ECC_CHECK_KEY) && !defined(WOLFSSL_CAAM)
74611+ if (ret == 0 && myCtx.eccCheckPubCount == 0)
74612+ ret = WC_TEST_RET_ENC_NC;
74613+ #endif
74614+ /* Regression: an explicit public point with zero coordinates must cross
74615+ * the callback boundary as X9.63 0x04||0||0, not as pubKey = NULL. */
74616+ #if !defined(WOLFSSL_SWDEV) && defined(HAVE_ECC_CHECK_KEY) && \
74617+ !defined(WOLFSSL_CAAM) && !defined(NO_ECC256)
74618+ if (ret == 0) {
74619+ ecc_key zeroKey;
74620+ int haveZeroKey = 0;
74621+
74622+ PRIVATE_KEY_UNLOCK();
74623+ ret = wc_ecc_init_ex(&zeroKey, HEAP_HINT, devId);
74624+ if (ret == 0) {
74625+ haveZeroKey = 1;
74626+ ret = wc_ecc_set_curve(&zeroKey, 32, ECC_SECP256R1);
74627+ }
74628+ if (ret == 0) {
74629+ zeroKey.type = ECC_PUBLICKEY;
74630+ myCtx.eccCheckPubExpectZeroPoint = 1;
74631+ myCtx.eccCheckPubSawZeroPoint = 0;
74632+ ret = wc_ecc_check_key(&zeroKey);
74633+ myCtx.eccCheckPubExpectZeroPoint = 0;
74634+
74635+ if (ret == 0) {
74636+ ret = WC_TEST_RET_ENC_NC; /* invalid point was accepted */
74637+ }
74638+ else if (!myCtx.eccCheckPubSawZeroPoint) {
74639+ ret = WC_TEST_RET_ENC_NC; /* callback saw NULL/other point */
74640+ }
74641+ else {
74642+ ret = 0; /* expected validation failure after serialization */
74643+ }
74644+ }
74645+ myCtx.eccCheckPubExpectZeroPoint = 0;
74646+ if (haveZeroKey)
74647+ wc_ecc_free(&zeroKey);
74648+ PRIVATE_KEY_LOCK();
74649+ }
74650+ #endif
7452774651#if !defined(WOLFSSL_ATECC508A) && !defined(WOLFSSL_ATECC608A) && \
7452874652 !defined(WOLFSSL_MICROCHIP_TA100) && !defined(WOLFSSL_STM32_PKA) && \
7452974653 !defined(WOLFSSL_SILABS_SE_ACCEL) && !defined(WOLF_CRYPTO_CB_ONLY_ECC) && \
0 commit comments