diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index 10eba731316..cb629eea78c 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -6301,6 +6301,15 @@ static int wc_PKCS7_SignedDataVerifySignature(wc_PKCS7* pkcs7, byte* sig, word32 msgSz = 0; int msgAlloc = 0; + /* RFC 9882: without signed attributes there is no digest, and + * the digestAlgorithm field is meaningless and must be + * ignored. Reject caller-supplied hashBuf instead of + * silently ignoring it. */ + if (signedAttrib == NULL && hashBuf != NULL) { + ret = BAD_FUNC_ARG; + break; + } + ret = wc_PKCS7_BuildPureSigMessage(pkcs7, signedAttrib, signedAttribSz, &msg, &msgSz, &msgAlloc); diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 77ef9b47d28..644115b7b71 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -90620,6 +90620,7 @@ static wc_test_ret_t pkcs7signed_mldsa_test(void) word32 certSz, keySz; word32 outHeadSz, outFootSz; int encodedSz; + int preHashSz; int i, testSz; int rngInit = 0; byte preHash[WC_MAX_DIGEST_SIZE]; @@ -90888,6 +90889,61 @@ static wc_test_ret_t pkcs7signed_mldsa_test(void) wc_PKCS7_Free(pkcs7); pkcs7 = NULL; + /* negative: pure-mode ML-DSA (RFC 9882) signs the complete message, + * not a digest, so a caller-supplied hashBuf must be rejected rather + * than silently ignored. Reuses the last vector's cert/key. */ + pkcs7 = wc_PKCS7_New(HEAP_HINT, devId); + if (pkcs7 == NULL) + ERROR_OUT(WC_TEST_RET_ENC_ERRNO, out_lbl); + + ret = wc_PKCS7_InitWithCert(pkcs7, cert, certSz); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out_lbl); + + pkcs7->rng = &rng; + pkcs7->content = (byte*)content; + pkcs7->contentSz = (word32)sizeof(content); + pkcs7->contentOID = DATA; + pkcs7->hashOID = MLDSA_TEST_HASH; + pkcs7->privateKey = key; + pkcs7->privateKeySz = keySz; + + ret = wc_PKCS7_SetDefaultSignedAttribs(pkcs7, WOLFSSL_NO_ATTRIBUTES); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out_lbl); + + encodedSz = wc_PKCS7_EncodeSignedData(pkcs7, out, FOURK_BUF * 5); + if (encodedSz <= 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(encodedSz), out_lbl); + + wc_PKCS7_Free(pkcs7); + pkcs7 = NULL; + + /* preHash is already zeroed above and was never computed over + * content; confirm it gets rejected rather than silently accepted. + * Must match MLDSA_TEST_HASH's digest size, or wc_PKCS7_BuildSignedDataDigest() + * rejects the length mismatch before the guard under test runs. */ + preHashSz = wc_HashGetDigestSize(wc_OidGetHash(MLDSA_TEST_HASH)); + if (preHashSz <= 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(preHashSz), out_lbl); + + pkcs7 = wc_PKCS7_New(HEAP_HINT, devId); + if (pkcs7 == NULL) + ERROR_OUT(WC_TEST_RET_ENC_ERRNO, out_lbl); + + ret = wc_PKCS7_InitWithCert(pkcs7, NULL, 0); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), out_lbl); + + ret = wc_PKCS7_VerifySignedData_ex(pkcs7, preHash, (word32)preHashSz, + out, (word32)encodedSz, NULL, 0); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + ERROR_OUT(WC_TEST_RET_ENC_NC, out_lbl); + ret = 0; + + wc_PKCS7_Free(pkcs7); + pkcs7 = NULL; + ret = 0; out_lbl: