From 54ed37398eb1e256ed0d557df801ee921c883ef4 Mon Sep 17 00:00:00 2001 From: night1rider Date: Mon, 20 Jul 2026 16:29:37 -0600 Subject: [PATCH] Add crypto callback hooks for Ed448, CMAC free, and RSA-PSS verify Add WOLF_CRYPTO_CB dispatch hooks so a device can service: * Ed448 sign and verify, mirroring the existing Ed25519 hooks. * CMAC context free on wc_CmacFree (WOLF_CRYPTO_CB_FREE), letting a device release offload state. * RSA-PSS verify with the digest (WOLF_CRYPTO_CB_RSA_PAD) so the device does the full signature and padding check. On that path *out is set to NULL with a positive return, documented in rsa.h. Includes testwolfcrypt and API unit test coverage for each hook. --- doc/dox_comments/header_files/rsa.h | 5 +- tests/api/test_cmac.c | 77 +++++++ tests/api/test_cmac.h | 4 +- tests/api/test_ed448.c | 126 ++++++++++++ tests/api/test_ed448.h | 4 +- tests/api/test_rsa.c | 154 ++++++++++++++ tests/api/test_rsa.h | 4 +- wolfcrypt/src/cmac.c | 11 + wolfcrypt/src/cryptocb.c | 106 ++++++++++ wolfcrypt/src/ed448.c | 24 +++ wolfcrypt/src/rsa.c | 40 ++++ wolfcrypt/test/test.c | 299 ++++++++++++++++++++++++++++ wolfssl/wolfcrypt/cryptocb.h | 51 +++++ wolfssl/wolfcrypt/rsa.h | 2 + wolfssl/wolfcrypt/types.h | 5 +- 15 files changed, 907 insertions(+), 5 deletions(-) diff --git a/doc/dox_comments/header_files/rsa.h b/doc/dox_comments/header_files/rsa.h index c0cbab28308..8d67d591ce2 100644 --- a/doc/dox_comments/header_files/rsa.h +++ b/doc/dox_comments/header_files/rsa.h @@ -742,10 +742,13 @@ int wc_RsaPSS_VerifyCheck_ex(byte* in, word32 inLen, The key has to be associated with RNG by wc_RsaSetRNG when WC_RSA_BLINDING is enabled. \return the length of the PSS data on success and negative indicates failure. + On the crypto callback path *out is set to NULL though the return stays + positive, so callers must not dereference *out. \param in The byte array to be decrypted. \param inLen The length of in. - \param out The byte array for the decrypted data to be stored. + \param out The byte array for the decrypted data to be stored. Set to NULL + when a crypto callback device performed the verify (see \return). \param digest Hash of the data that is being verified. \param digestLen Length of hash. \param hash The hash type to be in message diff --git a/tests/api/test_cmac.c b/tests/api/test_cmac.c index 5a49fbce64b..16e7fa64e22 100644 --- a/tests/api/test_cmac.c +++ b/tests/api/test_cmac.c @@ -720,3 +720,80 @@ int test_wc_AesCmacVerify_CryptoCb_LenMismatch(void) return EXPECT_RESULT(); } /* END test_wc_AesCmacVerify_CryptoCb_LenMismatch */ +/* Test that wc_CmacFree() dispatches a WC_ALGO_TYPE_FREE / WC_ALGO_TYPE_CMAC + * request to a registered crypto callback (CryptoCb) device. */ +#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_FREE) && \ + defined(WOLFSSL_CMAC) && !defined(NO_AES) && defined(WOLFSSL_AES_DIRECT) +/* Spy device: declines every request (software handles the work) but counts + * CMAC free dispatches. */ +static int cmac_free_test_crypto_cb(int devIdArg, wc_CryptoInfo* info, void* ctx) +{ + int* freeSeen = (int*)ctx; + + (void)devIdArg; + + if (info == NULL) { + return BAD_FUNC_ARG; + } + + if (info->algo_type == WC_ALGO_TYPE_FREE && + info->free.algo == WC_ALGO_TYPE_CMAC) { + if (freeSeen != NULL) { + (*freeSeen)++; + } + } + + return WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); +} +#endif + +int test_wc_CryptoCb_CmacFree(void) +{ + EXPECT_DECLS; +#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_FREE) && \ + defined(WOLFSSL_CMAC) && !defined(NO_AES) && defined(WOLFSSL_AES_DIRECT) + int devId = 4460; + int freeSeen = 0; + byte key16[16] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 + }; + byte in[16] = { + 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, + 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00 + }; + byte tag[WC_AES_BLOCK_SIZE]; + word32 tagSz = (word32)sizeof(tag); + WC_DECLARE_VAR(cmac, Cmac, 1, HEAP_HINT); + + WC_ALLOC_VAR(cmac, Cmac, 1, HEAP_HINT); +#ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC + ExpectNotNull(cmac); +#endif + + ExpectIntEQ(wc_CryptoCb_RegisterDevice(devId, cmac_free_test_crypto_cb, + &freeSeen), 0); + + /* wc_CmacFinal() internally frees the Cmac -> free dispatched to device. */ + ExpectIntEQ(wc_InitCmac_ex(cmac, key16, (word32)sizeof(key16), WC_CMAC_AES, + NULL, HEAP_HINT, devId), 0); + ExpectIntEQ(wc_CmacUpdate(cmac, in, (word32)sizeof(in)), 0); + freeSeen = 0; + ExpectIntEQ(wc_CmacFinal(cmac, tag, &tagSz), 0); + ExpectIntGE(freeSeen, 1); + + /* Explicit wc_CmacFree() also dispatches to the device. */ + tagSz = (word32)sizeof(tag); + ExpectIntEQ(wc_InitCmac_ex(cmac, key16, (word32)sizeof(key16), WC_CMAC_AES, + NULL, HEAP_HINT, devId), 0); + ExpectIntEQ(wc_CmacUpdate(cmac, in, (word32)sizeof(in)), 0); + freeSeen = 0; + ExpectIntEQ(wc_CmacFree(cmac), 0); + ExpectIntGE(freeSeen, 1); + + wc_CryptoCb_UnRegisterDevice(devId); + + WC_FREE_VAR(cmac, HEAP_HINT); +#endif + return EXPECT_RESULT(); +} /* END test_wc_CryptoCb_CmacFree */ diff --git a/tests/api/test_cmac.h b/tests/api/test_cmac.h index e7e4616c0a7..28272c59a64 100644 --- a/tests/api/test_cmac.h +++ b/tests/api/test_cmac.h @@ -34,6 +34,7 @@ int test_wc_InitCmac_Label(void); int test_wc_AesCmacGenerateExDecisionCoverage(void); int test_wc_AesCmacVerifyExDecisionCoverage(void); int test_wc_AesCmacVerify_CryptoCb_LenMismatch(void); +int test_wc_CryptoCb_CmacFree(void); #define TEST_CMAC_DECLS \ TEST_DECL_GROUP("cmac", test_wc_InitCmac), \ @@ -45,6 +46,7 @@ int test_wc_AesCmacVerify_CryptoCb_LenMismatch(void); TEST_DECL_GROUP("cmac", test_wc_InitCmac_Label), \ TEST_DECL_GROUP("cmac", test_wc_AesCmacGenerateExDecisionCoverage), \ TEST_DECL_GROUP("cmac", test_wc_AesCmacVerifyExDecisionCoverage), \ - TEST_DECL_GROUP("cmac", test_wc_AesCmacVerify_CryptoCb_LenMismatch) + TEST_DECL_GROUP("cmac", test_wc_AesCmacVerify_CryptoCb_LenMismatch), \ + TEST_DECL_GROUP("cmac", test_wc_CryptoCb_CmacFree) #endif /* WOLFCRYPT_TEST_CMAC_H */ diff --git a/tests/api/test_ed448.c b/tests/api/test_ed448.c index 2fe404b9c9a..922b027a969 100644 --- a/tests/api/test_ed448.c +++ b/tests/api/test_ed448.c @@ -30,6 +30,9 @@ #include #include +#ifdef WOLF_CRYPTO_CB + #include +#endif #include #include @@ -1369,3 +1372,126 @@ int test_wc_ed448_check_key_decisions(void) return EXPECT_RESULT(); } /* END test_wc_ed448_check_key_decisions */ +/* Test Ed448 sign/verify routed through a crypto callback (CryptoCb) device. */ +#if defined(WOLF_CRYPTO_CB) && defined(HAVE_ED448) && \ + defined(HAVE_ED448_SIGN) && defined(HAVE_ED448_VERIFY) && \ + !defined(WC_NO_RNG) +typedef struct ed448SpyCtx { + int signSeen; + int verifySeen; +} ed448SpyCtx; + +/* Spy device: services Ed448 sign/verify in software (devId cleared) and counts + * each; declines everything else so make_key runs in software. */ +static int ed448_test_crypto_cb(int devIdArg, wc_CryptoInfo* info, void* ctx) +{ + ed448SpyCtx* spy = (ed448SpyCtx*)ctx; + int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + + (void)devIdArg; + + if (info == NULL || spy == NULL) { + return BAD_FUNC_ARG; + } + + if (info->algo_type == WC_ALGO_TYPE_PK) { + #ifdef HAVE_ED448_SIGN + if (info->pk.type == WC_PK_TYPE_ED448) { + int save = info->pk.ed448sign.key->devId; + info->pk.ed448sign.key->devId = INVALID_DEVID; + ret = wc_ed448_sign_msg_ex( + info->pk.ed448sign.in, info->pk.ed448sign.inLen, + info->pk.ed448sign.out, info->pk.ed448sign.outLen, + info->pk.ed448sign.key, info->pk.ed448sign.type, + info->pk.ed448sign.context, info->pk.ed448sign.contextLen); + info->pk.ed448sign.key->devId = save; + spy->signSeen++; + } + #endif + #ifdef HAVE_ED448_VERIFY + if (info->pk.type == WC_PK_TYPE_ED448_VERIFY) { + int save = info->pk.ed448verify.key->devId; + info->pk.ed448verify.key->devId = INVALID_DEVID; + ret = wc_ed448_verify_msg_ex( + info->pk.ed448verify.sig, info->pk.ed448verify.sigLen, + info->pk.ed448verify.msg, info->pk.ed448verify.msgLen, + info->pk.ed448verify.res, info->pk.ed448verify.key, + info->pk.ed448verify.type, info->pk.ed448verify.context, + info->pk.ed448verify.contextLen); + info->pk.ed448verify.key->devId = save; + spy->verifySeen++; + } + #endif + } + + return ret; +} +#endif + +int test_wc_ed448_cryptocb(void) +{ + EXPECT_DECLS; +#if defined(WOLF_CRYPTO_CB) && defined(HAVE_ED448) && \ + defined(HAVE_ED448_SIGN) && defined(HAVE_ED448_VERIFY) && \ + !defined(WC_NO_RNG) + int devId = 4448; + ed448SpyCtx spy; + WC_RNG rng; + byte msg[32]; + word32 sigLen = ED448_SIG_SIZE; + int verify = 0; + WC_DECLARE_VAR(key, ed448_key, 1, HEAP_HINT); + WC_DECLARE_VAR(sig, byte, ED448_SIG_SIZE, HEAP_HINT); + + XMEMSET(&rng, 0, sizeof(rng)); + XMEMSET(&spy, 0, sizeof(spy)); + XMEMSET(msg, 0x5a, sizeof(msg)); + + WC_ALLOC_VAR(key, ed448_key, 1, HEAP_HINT); + WC_ALLOC_VAR(sig, byte, ED448_SIG_SIZE, HEAP_HINT); +#ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC + ExpectNotNull(key); + ExpectNotNull(sig); +#endif + if (WC_VAR_OK(sig)) { + XMEMSET(sig, 0, ED448_SIG_SIZE); + } + + ExpectIntEQ(wc_CryptoCb_RegisterDevice(devId, ed448_test_crypto_cb, &spy), + 0); + ExpectIntEQ(wc_InitRng(&rng), 0); + ExpectIntEQ(wc_ed448_init_ex(key, HEAP_HINT, devId), 0); + ExpectIntEQ(wc_ed448_make_key(&rng, ED448_KEY_SIZE, key), 0); + + /* Sign routes through the device callback. */ + ExpectIntEQ(wc_ed448_sign_msg(msg, (word32)sizeof(msg), sig, &sigLen, key, + NULL, 0), 0); + ExpectIntGE(spy.signSeen, 1); + + /* Verify routes through the device callback. */ + ExpectIntEQ(wc_ed448_verify_msg(sig, sigLen, msg, (word32)sizeof(msg), + &verify, key, NULL, 0), 0); + ExpectIntGE(spy.verifySeen, 1); + ExpectIntEQ(verify, 1); + + /* Negative: corrupt the signature. Ed448 reports a bad signature as + * SIG_VERIFY_E, exercising the device verify error path (verify == 0). */ + if (WC_VAR_OK(sig)) { + sig[0] ^= 0xFF; + } + verify = 1; + ExpectIntEQ(wc_ed448_verify_msg(sig, sigLen, msg, (word32)sizeof(msg), + &verify, key, NULL, 0), + WC_NO_ERR_TRACE(SIG_VERIFY_E)); + ExpectIntGE(spy.verifySeen, 2); + ExpectIntEQ(verify, 0); + + wc_ed448_free(key); + DoExpectIntEQ(wc_FreeRng(&rng), 0); + wc_CryptoCb_UnRegisterDevice(devId); + + WC_FREE_VAR(sig, HEAP_HINT); + WC_FREE_VAR(key, HEAP_HINT); +#endif + return EXPECT_RESULT(); +} diff --git a/tests/api/test_ed448.h b/tests/api/test_ed448.h index 169c88a39ce..a19dab9e013 100644 --- a/tests/api/test_ed448.h +++ b/tests/api/test_ed448.h @@ -42,6 +42,7 @@ int test_wc_Ed448DecisionCoverage(void); int test_wc_Ed448FeatureCoverage(void); int test_wc_ed448_import_private_only(void); int test_wc_ed448_check_key_decisions(void); +int test_wc_ed448_cryptocb(void); #define TEST_ED448_DECLS \ TEST_DECL_GROUP("ed448", test_wc_ed448_make_key), \ @@ -61,6 +62,7 @@ int test_wc_ed448_check_key_decisions(void); TEST_DECL_GROUP("ed448", test_wc_Ed448DecisionCoverage), \ TEST_DECL_GROUP("ed448", test_wc_Ed448FeatureCoverage), \ TEST_DECL_GROUP("ed448", test_wc_ed448_import_private_only), \ - TEST_DECL_GROUP("ed448", test_wc_ed448_check_key_decisions) + TEST_DECL_GROUP("ed448", test_wc_ed448_check_key_decisions), \ + TEST_DECL_GROUP("ed448", test_wc_ed448_cryptocb) #endif /* WOLFCRYPT_TEST_ED448_H */ diff --git a/tests/api/test_rsa.c b/tests/api/test_rsa.c index bd1c6b44827..4bf190f67e5 100644 --- a/tests/api/test_rsa.c +++ b/tests/api/test_rsa.c @@ -36,6 +36,9 @@ #ifdef WOLFSSL_SHA384 #include #endif +#ifdef WOLF_CRYPTO_CB + #include +#endif #include #include @@ -1999,3 +2002,154 @@ int test_wc_RsaFeatureCoverage(void) #endif return EXPECT_RESULT(); } /* END test_wc_RsaFeatureCoverage */ + +/* Test that wc_RsaPSS_VerifyCheck() routes RSA-PSS verification through a + * registered crypto callback (CryptoCb) device. */ +#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_RSA_PAD) && \ + defined(WC_RSA_PSS) && !defined(NO_RSA) && !defined(WC_NO_RNG) && \ + defined(WOLFSSL_KEY_GEN) && !defined(NO_SHA256) +/* Spy device: on RSA-PSS verify counts the request, verifies in software and + * reports via res; declines other pk types so sign / keygen run in software. */ +static int rsa_pss_test_crypto_cb(int devIdArg, wc_CryptoInfo* info, void* ctx) +{ + int* pssVerifySeen = (int*)ctx; + + (void)devIdArg; + + if (info == NULL) { + return BAD_FUNC_ARG; + } + + if (info->algo_type == WC_ALGO_TYPE_PK && + info->pk.type == WC_PK_TYPE_RSA_PSS_VERIFY) { + RsaKey* key = info->pk.rsa_pss_verify.key; + int save; + int v; + byte* outbuf; + word32 outbufSz = 512; + + outbuf = (byte*)XMALLOC(outbufSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + if (outbuf == NULL) { + return MEMORY_E; + } + + if (pssVerifySeen != NULL) { + (*pssVerifySeen)++; + } + + save = key->devId; + key->devId = INVALID_DEVID; + v = wc_RsaPSS_VerifyCheck( + info->pk.rsa_pss_verify.sig, info->pk.rsa_pss_verify.sigSz, + outbuf, outbufSz, + info->pk.rsa_pss_verify.digest, info->pk.rsa_pss_verify.digestSz, + info->pk.rsa_pss_verify.hash, info->pk.rsa_pss_verify.mgf, + key); + key->devId = save; + + XFREE(outbuf, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + + /* Only a real verdict maps to res; a genuine internal error (e.g. + * MEMORY_E) is propagated so it is not masked as a bad signature. */ + if (v > 0) { + if (info->pk.rsa_pss_verify.res != NULL) + *info->pk.rsa_pss_verify.res = 1; + return 0; + } + if (v == WC_NO_ERR_TRACE(BAD_PADDING_E) || + v == WC_NO_ERR_TRACE(SIG_VERIFY_E)) { + if (info->pk.rsa_pss_verify.res != NULL) + *info->pk.rsa_pss_verify.res = 0; + return 0; + } + return v; + } + + return WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); +} +#endif + +int test_wc_CryptoCb_RsaPssVerify(void) +{ + EXPECT_DECLS; +#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_RSA_PAD) && \ + defined(WC_RSA_PSS) && !defined(NO_RSA) && !defined(WC_NO_RNG) && \ + defined(WOLFSSL_KEY_GEN) && !defined(NO_SHA256) + int devId = 4470; + int pssVerifySeen = 0; + WC_RNG rng; + byte digest[WC_SHA256_DIGEST_SIZE]; + word32 sigLen = 0; + int r; + WC_DECLARE_VAR(key, RsaKey, 1, HEAP_HINT); + WC_DECLARE_VAR(sig, byte, 512, HEAP_HINT); + WC_DECLARE_VAR(rec, byte, 512, HEAP_HINT); + + XMEMSET(&rng, 0, sizeof(rng)); + XMEMSET(digest, 0x2b, sizeof(digest)); + + WC_ALLOC_VAR(key, RsaKey, 1, HEAP_HINT); + WC_ALLOC_VAR(sig, byte, 512, HEAP_HINT); + WC_ALLOC_VAR(rec, byte, 512, HEAP_HINT); +#ifdef WC_DECLARE_VAR_IS_HEAP_ALLOC + ExpectNotNull(key); + ExpectNotNull(sig); + ExpectNotNull(rec); +#endif + if (WC_VAR_OK(sig)) { + XMEMSET(sig, 0, 512); + } + if (WC_VAR_OK(rec)) { + XMEMSET(rec, 0, 512); + } + + ExpectIntEQ(wc_CryptoCb_RegisterDevice(devId, rsa_pss_test_crypto_cb, + &pssVerifySeen), 0); + ExpectIntEQ(wc_InitRng(&rng), 0); + ExpectIntEQ(wc_InitRsaKey_ex(key, HEAP_HINT, devId), 0); + ExpectIntEQ(wc_MakeRsaKey(key, 2048, WC_RSA_EXPONENT, &rng), 0); + ExpectIntEQ(wc_RsaSetRNG(key, &rng), 0); + + /* PSS sign runs in software (device declines). */ + ExpectIntGT(sigLen = (word32)wc_RsaPSS_Sign(digest, + (word32)sizeof(digest), sig, 512, WC_HASH_TYPE_SHA256, WC_MGF1SHA256, + key, &rng), 0); + + /* Positive: verify routes through the device and succeeds. */ + pssVerifySeen = 0; + ExpectIntGT(r = wc_RsaPSS_VerifyCheck(sig, sigLen, rec, 512, digest, + (word32)sizeof(digest), WC_HASH_TYPE_SHA256, WC_MGF1SHA256, key), 0); + ExpectIntGE(pssVerifySeen, 1); + + /* Positive: the inline variant also routes through the device; *out is NULL + * on that path. Use a copy of the sig since inline 'in' is reused as out. */ + if (WC_VAR_OK(sig) && WC_VAR_OK(rec)) { + byte* inlineOut = rec; /* non-NULL sentinel, must be cleared to NULL */ + XMEMCPY(rec, sig, sigLen); + pssVerifySeen = 0; + ExpectIntGT(wc_RsaPSS_VerifyCheckInline(rec, sigLen, &inlineOut, digest, + (word32)sizeof(digest), WC_HASH_TYPE_SHA256, WC_MGF1SHA256, key), 0); + ExpectIntGE(pssVerifySeen, 1); + ExpectNull(inlineOut); + } + + /* Negative: corrupt the signature; the device sets res=0 so VerifyCheck + * returns SIG_VERIFY_E (<= 0). */ + if (WC_VAR_OK(sig)) { + sig[0] ^= 0xFF; + } + pssVerifySeen = 0; + ExpectIntLE(wc_RsaPSS_VerifyCheck(sig, sigLen, rec, 512, digest, + (word32)sizeof(digest), WC_HASH_TYPE_SHA256, WC_MGF1SHA256, key), 0); + ExpectIntGE(pssVerifySeen, 1); + + DoExpectIntEQ(wc_FreeRsaKey(key), 0); + DoExpectIntEQ(wc_FreeRng(&rng), 0); + wc_CryptoCb_UnRegisterDevice(devId); + + WC_FREE_VAR(rec, HEAP_HINT); + WC_FREE_VAR(sig, HEAP_HINT); + WC_FREE_VAR(key, HEAP_HINT); +#endif + return EXPECT_RESULT(); +} /* END test_wc_CryptoCb_RsaPssVerify */ diff --git a/tests/api/test_rsa.h b/tests/api/test_rsa.h index 69081a5cc53..13d503101e1 100644 --- a/tests/api/test_rsa.h +++ b/tests/api/test_rsa.h @@ -47,6 +47,7 @@ int test_wc_RsaFunctionCheckIn_OversizedModulus(void); int test_wc_RsaKeyToDer_SizeOverflow(void); int test_wc_RsaDecisionCoverage(void); int test_wc_RsaFeatureCoverage(void); +int test_wc_CryptoCb_RsaPssVerify(void); #define TEST_RSA_DECLS \ TEST_DECL_GROUP("rsa", test_wc_InitRsaKey), \ @@ -71,6 +72,7 @@ int test_wc_RsaFeatureCoverage(void); TEST_DECL_GROUP("rsa", test_wc_RsaFunctionCheckIn_OversizedModulus), \ TEST_DECL_GROUP("rsa", test_wc_RsaKeyToDer_SizeOverflow), \ TEST_DECL_GROUP("rsa", test_wc_RsaDecisionCoverage), \ - TEST_DECL_GROUP("rsa", test_wc_RsaFeatureCoverage) + TEST_DECL_GROUP("rsa", test_wc_RsaFeatureCoverage), \ + TEST_DECL_GROUP("rsa", test_wc_CryptoCb_RsaPssVerify) #endif /* WOLFCRYPT_TEST_RSA_H */ diff --git a/wolfcrypt/src/cmac.c b/wolfcrypt/src/cmac.c index cc05015d65a..202a3d58090 100644 --- a/wolfcrypt/src/cmac.c +++ b/wolfcrypt/src/cmac.c @@ -366,6 +366,17 @@ int wc_CmacFree(Cmac* cmac) { if (cmac == NULL) return BAD_FUNC_ARG; +#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_FREE) + /* Let the device release any per-context state it hung off cmac->devCtx + * before the struct is zeroed (e.g. an offload context never finalized). */ + #ifndef WOLF_CRYPTO_CB_FIND + if (cmac->devId != INVALID_DEVID) + #endif + { + (void)wc_CryptoCb_Free(cmac->devId, WC_ALGO_TYPE_CMAC, (int)cmac->type, + 0, cmac); + } +#endif #if defined(WOLFSSL_HASH_KEEP) /* TODO: msg is leaked if wc_CmacFinal() is not called * e.g. when multiple calls to wc_CmacUpdate() and one fails but diff --git a/wolfcrypt/src/cryptocb.c b/wolfcrypt/src/cryptocb.c index cb155e0c1e9..4e3ad4b6bff 100644 --- a/wolfcrypt/src/cryptocb.c +++ b/wolfcrypt/src/cryptocb.c @@ -145,12 +145,15 @@ static const char* GetPkTypeStr(int pk) { switch (pk) { case WC_PK_TYPE_RSA: return "RSA"; + case WC_PK_TYPE_RSA_PSS_VERIFY: return "RSA-PSS-Verify"; case WC_PK_TYPE_DH: return "DH"; case WC_PK_TYPE_ECDH: return "ECDH"; case WC_PK_TYPE_ECDSA_SIGN: return "ECDSA-Sign"; case WC_PK_TYPE_ECDSA_VERIFY: return "ECDSA-Verify"; case WC_PK_TYPE_ED25519_SIGN: return "ED25519-Sign"; case WC_PK_TYPE_ED25519_VERIFY: return "ED25519-Verify"; + case WC_PK_TYPE_ED448: return "ED448-Sign"; + case WC_PK_TYPE_ED448_VERIFY: return "ED448-Verify"; case WC_PK_TYPE_CURVE25519: return "CURVE25519"; case WC_PK_TYPE_RSA_KEYGEN: return "RSA KeyGen"; case WC_PK_TYPE_EC_KEYGEN: return "ECC KeyGen"; @@ -627,6 +630,42 @@ int wc_CryptoCb_RsaPad(const byte* in, word32 inLen, byte* out, return wc_CryptoCb_TranslateErrorCode(ret); } + +/* Verify an RSA-PSS signature on the device (padding included). Passes both the + * signature and digest so the device does the whole verify and returns a verdict. */ +int wc_CryptoCb_RsaPssVerify(const byte* sig, word32 sigSz, const byte* digest, + word32 digestSz, enum wc_HashType hash, int mgf, int saltLen, RsaKey* key, + int* res) +{ + int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + CryptoCb* dev; + + if (key == NULL) + return ret; + + /* locate registered callback */ + dev = wc_CryptoCb_FindDevice(key->devId, WC_ALGO_TYPE_PK); + + if (dev && dev->cb) { + wc_CryptoInfo cryptoInfo; + XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo)); + cryptoInfo.algo_type = WC_ALGO_TYPE_PK; + cryptoInfo.pk.type = WC_PK_TYPE_RSA_PSS_VERIFY; + cryptoInfo.pk.rsa_pss_verify.sig = sig; + cryptoInfo.pk.rsa_pss_verify.sigSz = sigSz; + cryptoInfo.pk.rsa_pss_verify.digest = digest; + cryptoInfo.pk.rsa_pss_verify.digestSz = digestSz; + cryptoInfo.pk.rsa_pss_verify.hash = hash; + cryptoInfo.pk.rsa_pss_verify.mgf = mgf; + cryptoInfo.pk.rsa_pss_verify.saltLen = saltLen; + cryptoInfo.pk.rsa_pss_verify.key = key; + cryptoInfo.pk.rsa_pss_verify.res = res; + + ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx); + } + + return wc_CryptoCb_TranslateErrorCode(ret); +} #endif /* WOLF_CRYPTO_CB_RSA_PAD */ #ifdef WOLFSSL_KEY_GEN @@ -1227,6 +1266,73 @@ int wc_CryptoCb_Ed25519CheckKey(ed25519_key* key) } #endif /* HAVE_ED25519 */ +#ifdef HAVE_ED448 +int wc_CryptoCb_Ed448Sign(const byte* in, word32 inLen, byte* out, + word32 *outLen, ed448_key* key, byte type, const byte* context, + byte contextLen) +{ + int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + CryptoCb* dev; + + if (key == NULL) + return ret; + + /* locate registered callback */ + dev = wc_CryptoCb_FindDevice(key->devId, WC_ALGO_TYPE_PK); + if (dev && dev->cb) { + wc_CryptoInfo cryptoInfo; + XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo)); + cryptoInfo.algo_type = WC_ALGO_TYPE_PK; + cryptoInfo.pk.type = WC_PK_TYPE_ED448; + cryptoInfo.pk.ed448sign.in = in; + cryptoInfo.pk.ed448sign.inLen = inLen; + cryptoInfo.pk.ed448sign.out = out; + cryptoInfo.pk.ed448sign.outLen = outLen; + cryptoInfo.pk.ed448sign.key = key; + cryptoInfo.pk.ed448sign.type = type; + cryptoInfo.pk.ed448sign.context = context; + cryptoInfo.pk.ed448sign.contextLen = contextLen; + + ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx); + } + + return wc_CryptoCb_TranslateErrorCode(ret); +} + +int wc_CryptoCb_Ed448Verify(const byte* sig, word32 sigLen, + const byte* msg, word32 msgLen, int* res, ed448_key* key, byte type, + const byte* context, byte contextLen) +{ + int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + CryptoCb* dev; + + if (key == NULL) + return ret; + + /* locate registered callback */ + dev = wc_CryptoCb_FindDevice(key->devId, WC_ALGO_TYPE_PK); + if (dev && dev->cb) { + wc_CryptoInfo cryptoInfo; + XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo)); + cryptoInfo.algo_type = WC_ALGO_TYPE_PK; + cryptoInfo.pk.type = WC_PK_TYPE_ED448_VERIFY; + cryptoInfo.pk.ed448verify.sig = sig; + cryptoInfo.pk.ed448verify.sigLen = sigLen; + cryptoInfo.pk.ed448verify.msg = msg; + cryptoInfo.pk.ed448verify.msgLen = msgLen; + cryptoInfo.pk.ed448verify.res = res; + cryptoInfo.pk.ed448verify.key = key; + cryptoInfo.pk.ed448verify.type = type; + cryptoInfo.pk.ed448verify.context = context; + cryptoInfo.pk.ed448verify.contextLen = contextLen; + + ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx); + } + + return wc_CryptoCb_TranslateErrorCode(ret); +} +#endif /* HAVE_ED448 */ + #if defined(WOLFSSL_HAVE_LMS) || defined(WOLFSSL_HAVE_XMSS) int wc_CryptoCb_PqcStatefulSigGetDevId(int type, void* key) { diff --git a/wolfcrypt/src/ed448.c b/wolfcrypt/src/ed448.c index b25e3ff23f6..ba972028498 100644 --- a/wolfcrypt/src/ed448.c +++ b/wolfcrypt/src/ed448.c @@ -47,6 +47,9 @@ #include #include +#ifdef WOLF_CRYPTO_CB + #include +#endif #ifdef NO_INLINE #include #else @@ -447,6 +450,17 @@ int wc_ed448_sign_msg_ex(const byte* in, word32 inLen, byte* out, ((context == NULL) && (contextLen != 0))) { ret = BAD_FUNC_ARG; } + +#ifdef WOLF_CRYPTO_CB + if ((ret == 0) && (key->devId != INVALID_DEVID)) { + ret = wc_CryptoCb_Ed448Sign(in, inLen, out, outLen, key, type, context, + contextLen); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) + return ret; + ret = 0; /* device unavailable: fall back to software */ + } +#endif + if ((ret == 0) && (!key->pubKeySet)) { ret = BAD_FUNC_ARG; } @@ -902,6 +916,16 @@ int wc_ed448_verify_msg_ex(const byte* sig, word32 sigLen, const byte* msg, return BAD_LENGTH_E; } +#ifdef WOLF_CRYPTO_CB + if (key->devId != INVALID_DEVID) { + ret = wc_CryptoCb_Ed448Verify(sig, sigLen, msg, msgLen, res, key, type, + context, contextLen); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) + return ret; + /* device unavailable: fall back to software */ + } +#endif + #ifdef WOLFSSL_ED448_PERSISTENT_SHA sha = &key->sha; #else diff --git a/wolfcrypt/src/rsa.c b/wolfcrypt/src/rsa.c index 096c0e50e21..0702b1727f4 100644 --- a/wolfcrypt/src/rsa.c +++ b/wolfcrypt/src/rsa.c @@ -4635,6 +4635,9 @@ int wc_RsaPSS_CheckPadding_ex(const byte* in, word32 inSz, const byte* sig, * mgf Mask generation function. * key Public RSA key. * returns the length of the PSS data on success and negative indicates failure. + * + * Note: when a crypto callback device performs the verify, *out is set to NULL + * even though a positive length is returned; callers must not dereference *out. */ int wc_RsaPSS_VerifyCheckInline(byte* in, word32 inLen, byte** out, const byte* digest, word32 digestLen, @@ -4670,6 +4673,27 @@ int wc_RsaPSS_VerifyCheckInline(byte* in, word32 inLen, byte** out, saltLen = RSA_PSS_SALT_MAX_SZ; #endif +#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_RSA_PAD) + /* Let a device verify signature + padding in one shot (it gets the digest, + * which the RsaPad path does not). Fall through to software if unavailable. */ + if (key != NULL && key->devId != INVALID_DEVID) { + int res = 0; + ret = wc_CryptoCb_RsaPssVerify(in, inLen, digest, digestLen, hash, mgf, + saltLen, key, &res); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + if (ret == 0) { + /* Device verified internally; no recovered PSS block to expose, + * so report no inline output rather than a misleading pointer. */ + if (out != NULL) + *out = NULL; + ret = (res != 0) ? (int)inLen : SIG_VERIFY_E; + } + return ret; + } + ret = 0; + } +#endif + verify = wc_RsaPSS_VerifyInline_ex(in, inLen, out, hash, mgf, saltLen, key); if (verify > 0) ret = wc_RsaPSS_CheckPadding_ex(digest, digestLen, *out, (word32)verify, @@ -4730,6 +4754,22 @@ int wc_RsaPSS_VerifyCheck(const byte* in, word32 inLen, byte* out, word32 outLen saltLen = RSA_PSS_SALT_MAX_SZ; #endif +#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_RSA_PAD) + /* Let a device verify signature + padding in one shot (it gets the digest, + * which the RsaPad path does not). Fall through to software if unavailable. */ + if (key != NULL && key->devId != INVALID_DEVID) { + int res = 0; + ret = wc_CryptoCb_RsaPssVerify(in, inLen, digest, digestLen, hash, mgf, + saltLen, key, &res); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + if (ret == 0) + ret = (res != 0) ? (int)inLen : SIG_VERIFY_E; + return ret; + } + ret = 0; + } +#endif + verify = wc_RsaPSS_Verify_ex(in, inLen, out, outLen, hash, mgf, saltLen, key); if (verify > 0) diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index def621bde60..647e13cf45a 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -76148,6 +76148,16 @@ typedef struct { * public point, simulating a private scalar * resident in the device (input key->k empty) */ #endif +#ifdef HAVE_ED448 + int ed448SignCount; /* Ed448 sign callback invocations */ + int ed448VerifyCount; /* Ed448 verify callback invocations */ +#endif +#if defined(WOLFSSL_CMAC) && defined(WOLF_CRYPTO_CB_FREE) + int cmacFreeCount; /* CMAC free callback invocations */ +#endif +#if defined(WC_RSA_PSS) && defined(WOLF_CRYPTO_CB_RSA_PAD) + int rsaPssVerifyCount; /* RSA-PSS verify callback invocations */ +#endif } myCryptoDevCtx; #ifdef WOLF_CRYPTO_CB_ONLY_RSA @@ -77108,6 +77118,51 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx) WOLFSSL_MSG_EX("CryptoDevCb: Pk Type %d\n", info->pk.type); #endif + #if defined(WC_RSA_PSS) && defined(WOLF_CRYPTO_CB_RSA_PAD) + if (info->pk.type == WC_PK_TYPE_RSA_PSS_VERIFY) { + RsaKey* pssKey = info->pk.rsa_pss_verify.key; + int pssSaveDevId = pssKey->devId; + int pssVer = 0; + byte* pssOut; + word32 pssOutSz = 512; + + pssOut = (byte*)XMALLOC(pssOutSz, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER); + if (pssOut == NULL) + return MEMORY_E; + + myCtx->rsaPssVerifyCount++; + + /* perform software based RSA-PSS verify */ + pssKey->devId = INVALID_DEVID; + pssVer = wc_RsaPSS_VerifyCheck( + info->pk.rsa_pss_verify.sig, info->pk.rsa_pss_verify.sigSz, + pssOut, pssOutSz, + info->pk.rsa_pss_verify.digest, + info->pk.rsa_pss_verify.digestSz, + info->pk.rsa_pss_verify.hash, info->pk.rsa_pss_verify.mgf, + pssKey); + pssKey->devId = pssSaveDevId; + + XFREE(pssOut, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + + /* Only a real verdict maps to res; a genuine internal error (e.g. + * MEMORY_E) is propagated so it is not masked as a bad signature. */ + if (pssVer > 0) { + if (info->pk.rsa_pss_verify.res != NULL) + *info->pk.rsa_pss_verify.res = 1; + return 0; + } + if (pssVer == WC_NO_ERR_TRACE(BAD_PADDING_E) || + pssVer == WC_NO_ERR_TRACE(SIG_VERIFY_E)) { + if (info->pk.rsa_pss_verify.res != NULL) + *info->pk.rsa_pss_verify.res = 0; + return 0; + } + return pssVer; + } + #endif /* WC_RSA_PSS && WOLF_CRYPTO_CB_RSA_PAD */ + #ifndef NO_RSA if (info->pk.type == WC_PK_TYPE_RSA) { /* set devId to invalid, so software is used */ @@ -77574,6 +77629,43 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx) info->pk.ed25519checkkey.key->devId = devIdArg; } #endif /* HAVE_ED25519 */ + #ifdef HAVE_ED448 + #ifdef HAVE_ED448_SIGN + if (info->pk.type == WC_PK_TYPE_ED448) { + /* set devId to invalid, so software is used */ + info->pk.ed448sign.key->devId = INVALID_DEVID; + + ret = wc_ed448_sign_msg_ex( + info->pk.ed448sign.in, info->pk.ed448sign.inLen, + info->pk.ed448sign.out, info->pk.ed448sign.outLen, + info->pk.ed448sign.key, info->pk.ed448sign.type, + info->pk.ed448sign.context, info->pk.ed448sign.contextLen); + + /* reset devId */ + info->pk.ed448sign.key->devId = devIdArg; + + myCtx->ed448SignCount++; + } + #endif + #ifdef HAVE_ED448_VERIFY + if (info->pk.type == WC_PK_TYPE_ED448_VERIFY) { + /* set devId to invalid, so software is used */ + info->pk.ed448verify.key->devId = INVALID_DEVID; + + ret = wc_ed448_verify_msg_ex( + info->pk.ed448verify.sig, info->pk.ed448verify.sigLen, + info->pk.ed448verify.msg, info->pk.ed448verify.msgLen, + info->pk.ed448verify.res, info->pk.ed448verify.key, + info->pk.ed448verify.type, info->pk.ed448verify.context, + info->pk.ed448verify.contextLen); + + /* reset devId */ + info->pk.ed448verify.key->devId = devIdArg; + + myCtx->ed448VerifyCount++; + } + #endif + #endif /* HAVE_ED448 */ #if defined(WOLFSSL_HAVE_LMS) || defined(WOLFSSL_HAVE_XMSS) if (info->pk.type == WC_PK_TYPE_PQC_STATEFUL_SIG_KEYGEN) { int pqcType = info->pk.pqc_stateful_sig_kg.type; @@ -78817,6 +78909,13 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx) ret = WC_NO_ERR_TRACE(NOT_COMPILED_IN); #endif } +#if defined(WOLFSSL_CMAC) + else if (info->free.algo == WC_ALGO_TYPE_CMAC) { + /* count the CMAC free dispatch and let software do the free */ + myCtx->cmacFreeCount++; + ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + } +#endif else { ret = WC_NO_ERR_TRACE(NOT_COMPILED_IN); } @@ -79434,6 +79533,16 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cryptocb_test(void) myCtx.eccCheckPubSawZeroPoint = 0; myCtx.eccResidentKey = NULL; #endif +#ifdef HAVE_ED448 + myCtx.ed448SignCount = 0; + myCtx.ed448VerifyCount = 0; +#endif +#if defined(WOLFSSL_CMAC) && defined(WOLF_CRYPTO_CB_FREE) + myCtx.cmacFreeCount = 0; +#endif +#if defined(WC_RSA_PSS) && defined(WOLF_CRYPTO_CB_RSA_PAD) + myCtx.rsaPssVerifyCount = 0; +#endif /* set devId to something other than INVALID_DEVID */ devId = 1; @@ -79884,6 +79993,196 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cryptocb_test(void) ret = cmac_test(); #endif + /* Driver coverage for the new CryptoCb hooks: confirm each op is routed + * through myCryptoDevCb (counter bumped) and the round-trip is correct. */ +#if defined(HAVE_ED448) && defined(HAVE_ED448_SIGN) && \ + defined(HAVE_ED448_VERIFY) && !defined(WC_NO_RNG) + if (ret == 0) { + WC_RNG ed448Rng; + int ed448RngInit = 0; + byte ed448Msg[32]; + word32 ed448SigLen = ED448_SIG_SIZE; + int ed448Verify = 0; + WC_DECLARE_VAR(ed448Key, ed448_key, 1, HEAP_HINT); + WC_DECLARE_VAR(ed448Sig, byte, ED448_SIG_SIZE, HEAP_HINT); + + WC_ALLOC_VAR_EX(ed448Key, ed448_key, 1, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER, ret = WC_TEST_RET_ENC_EC(MEMORY_E)); + if (ret == 0) + WC_ALLOC_VAR_EX(ed448Sig, byte, ED448_SIG_SIZE, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER, ret = WC_TEST_RET_ENC_EC(MEMORY_E)); + + XMEMSET(ed448Msg, 0x5a, sizeof(ed448Msg)); + myCtx.ed448SignCount = 0; + myCtx.ed448VerifyCount = 0; + + if (ret == 0) { + ret = wc_InitRng_ex(&ed448Rng, HEAP_HINT, devId); + if (ret == 0) + ed448RngInit = 1; + else + ret = WC_TEST_RET_ENC_EC(ret); + } + if (ret == 0) { + ret = wc_ed448_init_ex(ed448Key, HEAP_HINT, devId); + if (ret != 0) + ret = WC_TEST_RET_ENC_EC(ret); + } + if (ret == 0) { + ret = wc_ed448_make_key(&ed448Rng, ED448_KEY_SIZE, ed448Key); + if (ret != 0) + ret = WC_TEST_RET_ENC_EC(ret); + } + if (ret == 0) { + ret = wc_ed448_sign_msg(ed448Msg, (word32)sizeof(ed448Msg), + ed448Sig, &ed448SigLen, ed448Key, NULL, 0); + if (ret != 0) + ret = WC_TEST_RET_ENC_EC(ret); + } + if (ret == 0 && myCtx.ed448SignCount == 0) + ret = WC_TEST_RET_ENC_NC; + if (ret == 0) { + ret = wc_ed448_verify_msg(ed448Sig, ed448SigLen, ed448Msg, + (word32)sizeof(ed448Msg), &ed448Verify, ed448Key, NULL, 0); + if (ret != 0) + ret = WC_TEST_RET_ENC_EC(ret); + } + if (ret == 0 && (myCtx.ed448VerifyCount == 0 || ed448Verify != 1)) + ret = WC_TEST_RET_ENC_NC; + + if (WC_VAR_OK(ed448Key)) + wc_ed448_free(ed448Key); + if (ed448RngInit) + wc_FreeRng(&ed448Rng); + WC_FREE_VAR_EX(ed448Sig, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + WC_FREE_VAR_EX(ed448Key, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + } +#endif /* HAVE_ED448 */ + +#if defined(WOLFSSL_CMAC) && defined(WOLF_CRYPTO_CB_FREE) && \ + !defined(NO_AES) && defined(WOLFSSL_AES_DIRECT) + if (ret == 0) { + byte cmacKey[16] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 + }; + byte cmacIn[16] = { + 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, + 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00 + }; + byte cmacTag[WC_AES_BLOCK_SIZE]; + word32 cmacTagSz = (word32)sizeof(cmacTag); + WC_DECLARE_VAR(cmac, Cmac, 1, HEAP_HINT); + + WC_ALLOC_VAR_EX(cmac, Cmac, 1, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER, ret = WC_TEST_RET_ENC_EC(MEMORY_E)); + + if (ret == 0) { + ret = wc_InitCmac_ex(cmac, cmacKey, (word32)sizeof(cmacKey), + WC_CMAC_AES, NULL, HEAP_HINT, devId); + if (ret != 0) + ret = WC_TEST_RET_ENC_EC(ret); + } + if (ret == 0) { + ret = wc_CmacUpdate(cmac, cmacIn, (word32)sizeof(cmacIn)); + if (ret != 0) + ret = WC_TEST_RET_ENC_EC(ret); + } + if (ret == 0) { + /* wc_CmacFinal() frees the Cmac -> free dispatched to device */ + myCtx.cmacFreeCount = 0; + ret = wc_CmacFinal(cmac, cmacTag, &cmacTagSz); + if (ret != 0) + ret = WC_TEST_RET_ENC_EC(ret); + } + if (ret == 0 && myCtx.cmacFreeCount == 0) + ret = WC_TEST_RET_ENC_NC; + + WC_FREE_VAR_EX(cmac, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + } +#endif /* WOLFSSL_CMAC && WOLF_CRYPTO_CB_FREE */ + +#if defined(WC_RSA_PSS) && defined(WOLF_CRYPTO_CB_RSA_PAD) && \ + !defined(NO_RSA) && !defined(WC_NO_RNG) && defined(WOLFSSL_KEY_GEN) && \ + !defined(NO_SHA256) + if (ret == 0) { + WC_RNG rsaRng; + int rsaRngInit = 0; + int rsaKeyInit = 0; + byte rsaDigest[WC_SHA256_DIGEST_SIZE]; + word32 rsaSigLen = 0; + int rsaVer; + WC_DECLARE_VAR(rsaKey, RsaKey, 1, HEAP_HINT); + WC_DECLARE_VAR(rsaSig, byte, 512, HEAP_HINT); + WC_DECLARE_VAR(rsaRec, byte, 512, HEAP_HINT); + + WC_ALLOC_VAR_EX(rsaKey, RsaKey, 1, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER, ret = WC_TEST_RET_ENC_EC(MEMORY_E)); + if (ret == 0) + WC_ALLOC_VAR_EX(rsaSig, byte, 512, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER, ret = WC_TEST_RET_ENC_EC(MEMORY_E)); + if (ret == 0) + WC_ALLOC_VAR_EX(rsaRec, byte, 512, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER, ret = WC_TEST_RET_ENC_EC(MEMORY_E)); + + XMEMSET(rsaDigest, 0x2b, sizeof(rsaDigest)); + myCtx.rsaPssVerifyCount = 0; + + if (ret == 0) { + ret = wc_InitRng_ex(&rsaRng, HEAP_HINT, devId); + if (ret == 0) + rsaRngInit = 1; + else + ret = WC_TEST_RET_ENC_EC(ret); + } + if (ret == 0) { + ret = wc_InitRsaKey_ex(rsaKey, HEAP_HINT, devId); + if (ret == 0) + rsaKeyInit = 1; + else + ret = WC_TEST_RET_ENC_EC(ret); + } + if (ret == 0) { + ret = wc_MakeRsaKey(rsaKey, 2048, WC_RSA_EXPONENT, &rsaRng); + if (ret != 0) + ret = WC_TEST_RET_ENC_EC(ret); + } + if (ret == 0) { + ret = wc_RsaSetRNG(rsaKey, &rsaRng); + if (ret != 0) + ret = WC_TEST_RET_ENC_EC(ret); + } + if (ret == 0) { + ret = wc_RsaPSS_Sign(rsaDigest, (word32)sizeof(rsaDigest), rsaSig, + 512, WC_HASH_TYPE_SHA256, WC_MGF1SHA256, rsaKey, &rsaRng); + if (ret > 0) { + rsaSigLen = (word32)ret; + ret = 0; + } + else { + ret = WC_TEST_RET_ENC_EC(ret); + } + } + if (ret == 0) { + rsaVer = wc_RsaPSS_VerifyCheck(rsaSig, rsaSigLen, rsaRec, 512, + rsaDigest, (word32)sizeof(rsaDigest), WC_HASH_TYPE_SHA256, + WC_MGF1SHA256, rsaKey); + if (rsaVer <= 0) + ret = WC_TEST_RET_ENC_EC(rsaVer); + } + if (ret == 0 && myCtx.rsaPssVerifyCount == 0) + ret = WC_TEST_RET_ENC_NC; + + if (rsaKeyInit) + wc_FreeRsaKey(rsaKey); + if (rsaRngInit) + wc_FreeRng(&rsaRng); + WC_FREE_VAR_EX(rsaRec, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + WC_FREE_VAR_EX(rsaSig, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + WC_FREE_VAR_EX(rsaKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + } +#endif /* WC_RSA_PSS && WOLF_CRYPTO_CB_RSA_PAD */ + wc_CryptoCb_UnRegisterDevice(devId); /* restore devId */ diff --git a/wolfssl/wolfcrypt/cryptocb.h b/wolfssl/wolfcrypt/cryptocb.h index 8d2e587e542..3a5299d77e6 100644 --- a/wolfssl/wolfcrypt/cryptocb.h +++ b/wolfssl/wolfcrypt/cryptocb.h @@ -71,6 +71,9 @@ #ifdef HAVE_ED25519 #include #endif +#ifdef HAVE_ED448 + #include +#endif #ifdef HAVE_CURVE25519 #include #endif @@ -197,6 +200,19 @@ typedef struct wc_CryptoInfo { const RsaKey* key; int* keySize; } rsa_get_size; + #ifdef WOLF_CRYPTO_CB_RSA_PAD + struct { + const byte* sig; + word32 sigSz; + const byte* digest; + word32 digestSz; + enum wc_HashType hash; + int mgf; + int saltLen; + RsaKey* key; + int* res; + } rsa_pss_verify; + #endif #endif #ifdef HAVE_ECC #ifdef HAVE_ECC_DHE @@ -325,6 +341,29 @@ typedef struct wc_CryptoInfo { * priv/pub consistency */ } ed25519checkkey; #endif + #ifdef HAVE_ED448 + struct { + const byte* in; + word32 inLen; + byte* out; + word32* outLen; + ed448_key* key; + byte type; + const byte* context; + byte contextLen; + } ed448sign; + struct { + const byte* sig; + word32 sigLen; + const byte* msg; + word32 msgLen; + int* res; + ed448_key* key; + byte type; + const byte* context; + byte contextLen; + } ed448verify; + #endif #if defined(WOLFSSL_HAVE_MLKEM) || defined(WOLFSSL_HAVE_FRODOKEM) struct { WC_RNG* rng; @@ -775,6 +814,9 @@ WOLFSSL_LOCAL int wc_CryptoCb_Rsa(const byte* in, word32 inLen, byte* out, #ifdef WOLF_CRYPTO_CB_RSA_PAD WOLFSSL_LOCAL int wc_CryptoCb_RsaPad(const byte* in, word32 inLen, byte* out, word32* outLen, int type, RsaKey* key, WC_RNG* rng, RsaPadding *padding); +WOLFSSL_LOCAL int wc_CryptoCb_RsaPssVerify(const byte* sig, word32 sigSz, + const byte* digest, word32 digestSz, enum wc_HashType hash, int mgf, + int saltLen, RsaKey* key, int* res); #endif #ifdef WOLFSSL_KEY_GEN @@ -835,6 +877,15 @@ WOLFSSL_LOCAL int wc_CryptoCb_Ed25519MakePub(ed25519_key* key, byte* pubKey, WOLFSSL_LOCAL int wc_CryptoCb_Ed25519CheckKey(ed25519_key* key); #endif /* HAVE_ED25519 */ +#ifdef HAVE_ED448 +WOLFSSL_LOCAL int wc_CryptoCb_Ed448Sign(const byte* in, word32 inLen, + byte* out, word32 *outLen, ed448_key* key, byte type, const byte* context, + byte contextLen); +WOLFSSL_LOCAL int wc_CryptoCb_Ed448Verify(const byte* sig, word32 sigLen, + const byte* msg, word32 msgLen, int* res, ed448_key* key, byte type, + const byte* context, byte contextLen); +#endif /* HAVE_ED448 */ + #if defined(WOLFSSL_HAVE_LMS) || defined(WOLFSSL_HAVE_XMSS) WOLFSSL_LOCAL int wc_CryptoCb_PqcStatefulSigGetDevId(int type, void* key); diff --git a/wolfssl/wolfcrypt/rsa.h b/wolfssl/wolfcrypt/rsa.h index 0d0b0cecb88..4b76c30dac0 100644 --- a/wolfssl/wolfcrypt/rsa.h +++ b/wolfssl/wolfcrypt/rsa.h @@ -414,6 +414,8 @@ WOLFSSL_API int wc_RsaPSS_CheckPadding_ex2(const byte* in, word32 inLen, const byte* sig, word32 sigSz, enum wc_HashType hashType, int saltLen, int bits, void* heap); +/* Crypto callback (WOLF_CRYPTO_CB_RSA_PAD) path: a positive return still means + * success but *out is set to NULL, so callers must not dereference *out. */ WOLFSSL_API int wc_RsaPSS_VerifyCheckInline(byte* in, word32 inLen, byte** out, const byte* digest, word32 digentLen, enum wc_HashType hash, int mgf, diff --git a/wolfssl/wolfcrypt/types.h b/wolfssl/wolfcrypt/types.h index af98e43ba30..34b9aa5ab94 100644 --- a/wolfssl/wolfcrypt/types.h +++ b/wolfssl/wolfcrypt/types.h @@ -1623,8 +1623,11 @@ enum wc_PkType { WC_PK_TYPE_EC_CHECK_PUB_KEY = 35, WC_PK_TYPE_ED25519_MAKE_PUB = 36, WC_PK_TYPE_ED25519_CHECK_KEY = 37, + WC_PK_TYPE_RSA_PSS_VERIFY = 38, + /* Ed448 sign reuses WC_PK_TYPE_ED448 (12); verify needs its own type. */ + WC_PK_TYPE_ED448_VERIFY = 39, #undef _WC_PK_TYPE_MAX - #define _WC_PK_TYPE_MAX WC_PK_TYPE_ED25519_CHECK_KEY + #define _WC_PK_TYPE_MAX WC_PK_TYPE_ED448_VERIFY WC_PK_TYPE_MAX = _WC_PK_TYPE_MAX };