diff --git a/tests/api.c b/tests/api.c index c27e7f7f1..40576a8b1 100644 --- a/tests/api.c +++ b/tests/api.c @@ -27556,7 +27556,8 @@ static void test_wc_PKCS7_EncodeSignedData_ex(void) AssertNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, devId)); AssertIntEQ(wc_PKCS7_InitWithCert(pkcs7, NULL, 0), 0); - /* required parameter even on verify when using _ex */ + /* required parameter even on verify when using _ex, if using outputHead + * and outputFoot */ pkcs7->contentSz = (word32)sizeof(data); AssertIntEQ(wc_PKCS7_VerifySignedData_ex(pkcs7, hashBuf, hashSz, outputHead, outputHeadSz, outputFoot, outputFootSz), 0); @@ -27782,6 +27783,12 @@ static void test_wc_PKCS7_VerifySignedData(void) word32 badOutSz = 0; byte badContent[] = "This is different content than was signed"; + int ret; + wc_HashAlg hash; + enum wc_HashType hashType = WC_HASH_TYPE_SHA; + byte hashBuf[WC_MAX_DIGEST_SIZE]; + word32 hashSz = wc_HashGetDigestSize(hashType); + AssertIntGT((outputSz = CreatePKCS7SignedData(output, outputSz, data, (word32)sizeof(data), 0, 0)), 0); @@ -27825,6 +27832,27 @@ static void test_wc_PKCS7_VerifySignedData(void) AssertIntEQ(wc_PKCS7_VerifySignedData(pkcs7, output, outputSz), 0); wc_PKCS7_Free(pkcs7); + /* verify using pre-computed content digest only (no content) */ + { + /* calculate hash for content */ + ret = wc_HashInit(&hash, hashType); + if (ret == 0) { + ret = wc_HashUpdate(&hash, hashType, data, sizeof(data)); + if (ret == 0) { + ret = wc_HashFinal(&hash, hashType, hashBuf); + } + wc_HashFree(&hash, hashType); + } + AssertIntEQ(ret, 0); + + AssertNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, devId)); + AssertIntEQ(wc_PKCS7_Init(pkcs7, NULL, 0), 0); + AssertIntEQ(wc_PKCS7_VerifySignedData_ex(pkcs7, hashBuf, hashSz, + output, outputSz, + NULL, 0), 0); + wc_PKCS7_Free(pkcs7); + } + printf(resultFmt, passed); #endif } /* END test_wc_PKCS7_VerifySignedData() */ diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index 61d076db0..797b3f218 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -4672,10 +4672,16 @@ static int PKCS7_VerifySignedData(PKCS7* pkcs7, const byte* hashBuf, } else { - /* if pkcs7->content and pkcs7->contentSz are set, try to - process as a detached signature */ + /* If either pkcs7->content and pkcs7->contentSz are set + * (detached signature where user has set content explicitly + * into pkcs7->content/contentSz) OR pkcs7->hashBuf and + * pkcs7->hashSz are set (user has pre-computed content + * digest and passed in instead of content directly), try to + * process as a detached signature */ if (!degenerate && - (pkcs7->content != NULL && pkcs7->contentSz != 0)) { + ((pkcs7->content != NULL && pkcs7->contentSz != 0) || + (hashBuf != NULL && hashSz > 0)) ) { + WOLFSSL_MSG("Trying to process as detached signature"); detached = 1; } @@ -5350,8 +5356,27 @@ int wc_PKCS7_GetSignerSID(PKCS7* pkcs7, byte* out, word32* outSz) } -/* variant that allows computed data hash and header/foot, - * which is useful for large data signing */ +/* SignedData verification function variant that allows pre-computed content + * message digest and optional PKCS7/CMS bundle content header/footer to be + * used for verification. Useful for large data signing. + * + * pkcs7 - pointer to initialized PKCS7 structure + * hashBuf - message digest of content + * hashSz - size of hashBuf, octets + * pkiMsgHead - PKCS7/CMS header that goes on top of the raw data signed, + * as output from wc_PKCS7_EncodeSignedData_ex (if also using + * pkiMsgFoot). Otherwise, PKCS7/CMS bundle with + * detached signature - will use hashBuf/hashSz to verify. + * pkiMsgHeadSz - size of pkiMsgHead, octets + * pkiMsgFoot - PKCS7/CMS footer that goes at the end of the raw data signed, + * as output from wc_PKCS7_EncodeSignedData_ex. Can be NULL + * if pkiMsgHead is a direct detached signature bundle to be used + * with hashBuf/hashSz. + * pkiMsgFootSz - size of pkiMsgFoot, octets. Should be 0 if pkiMsgFoot is NULL. + * + * Returns 0 on success, negative upon error. + * + */ int wc_PKCS7_VerifySignedData_ex(PKCS7* pkcs7, const byte* hashBuf, word32 hashSz, byte* pkiMsgHead, word32 pkiMsgHeadSz, byte* pkiMsgFoot, word32 pkiMsgFootSz)