diff --git a/doc/dox_comments/header_files/pkcs7.h b/doc/dox_comments/header_files/pkcs7.h index 2ad33cd43..d68598724 100644 --- a/doc/dox_comments/header_files/pkcs7.h +++ b/doc/dox_comments/header_files/pkcs7.h @@ -174,6 +174,7 @@ WOLFSSL_API int wc_PKCS7_EncodeData(PKCS7* pkcs7, byte* output, PKCS7 pkcs7; int ret; + byte data[] = {}; // initialize with data to sign byte derBuff[] = { }; // initialize with DER-encoded certificate byte pkcs7Buff[FOURK_BUF]; @@ -183,12 +184,16 @@ WOLFSSL_API int wc_PKCS7_EncodeData(PKCS7* pkcs7, byte* output, pkcs7.privateKeySz = keySz; pkcs7.content = data; pkcs7.contentSz = dataSz; + pkcs7.hashOID = SHAh; + pkcs7.rng = &rng; ... etc. ret = wc_PKCS7_EncodeSignedData(&pkcs7, pkcs7Buff, sizeof(pkcs7Buff)); if ( ret != 0 ) { // error encoding into output buffer } + + wc_PKCS7_Free(&pkcs7); \endcode \sa wc_PKCS7_InitWithCert @@ -197,6 +202,107 @@ WOLFSSL_API int wc_PKCS7_EncodeData(PKCS7* pkcs7, byte* output, WOLFSSL_API int wc_PKCS7_EncodeSignedData(PKCS7* pkcs7, byte* output, word32 outputSz); +/*! + \ingroup PKCS7 + + \brief This function builds the PKCS7 signed data content type, encoding + the PKCS7 structure into a header and footer buffer containing a parsable PKCS7 + signed data packet. This does not include the content. + A hash must be computed and provided for the data + + \return 0=Success + \return BAD_FUNC_ARG Returned if the PKCS7 structure is missing one or + more required elements to generate a signed data packet + \return MEMORY_E Returned if there is an error allocating memory + \return PUBLIC_KEY_E Returned if there is an error parsing the public key + \return RSA_BUFFER_E Returned if buffer error, output too small or input + too large + \return BUFFER_E Returned if the given buffer is not large enough to hold + the encoded certificate + \return MP_INIT_E may be returned if there is an error generating + the signature + \return MP_READ_E may be returned if there is an error generating + the signature + \return MP_CMP_E may be returned if there is an error generating + the signature + \return MP_INVMOD_E may be returned if there is an error generating + the signature + \return MP_EXPTMOD_E may be returned if there is an error generating + the signature + \return MP_MOD_E may be returned if there is an error generating + the signature + \return MP_MUL_E may be returned if there is an error generating + the signature + \return MP_ADD_E may be returned if there is an error generating + the signature + \return MP_MULMOD_E may be returned if there is an error generating + the signature + \return MP_TO_E may be returned if there is an error generating + the signature + \return MP_MEM may be returned if there is an error generating the signature + + \param pkcs7 pointer to the PKCS7 structure to encode + \param hashBuf pointer to computed hash for the content data + \param hashSz size of the digest + \param outputHead pointer to the buffer in which to store the + encoded certificate header + \param outputHeadSz pointer populated with size of output header buffer + and returns actual size + \param outputFoot pointer to the buffer in which to store the + encoded certificate footer + \param outputFootSz pointer populated with size of output footer buffer + and returns actual size + + _Example_ + \code + PKCS7 pkcs7; + int ret; + byte derBuff[] = { }; // initialize with DER-encoded certificate + byte data[] = {}; // initialize with data to sign + byte pkcs7HeadBuff[FOURK_BUF/2]; + byte pkcs7FootBuff[FOURK_BUF/2]; + word32 pkcs7HeadSz = (word32)sizeof(pkcs7HeadBuff); + word32 pkcs7FootSz = (word32)sizeof(pkcs7HeadBuff); + enum wc_HashType hashType = WC_HASH_TYPE_SHA; + byte hashBuf[WC_MAX_DIGEST_SIZE]; + word32 hashSz = wc_HashGetDigestSize(hashType); + + wc_PKCS7_InitWithCert(&pkcs7, derBuff, sizeof(derBuff)); + // update message and data to encode + pkcs7.privateKey = key; + pkcs7.privateKeySz = keySz; + pkcs7.content = NULL; + pkcs7.contentSz = dataSz; + pkcs7.hashOID = SHAh; + pkcs7.rng = &rng; + ... etc. + + // 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); + } + + ret = wc_PKCS7_EncodeSignedData_ex(&pkcs7, hashBuf, hashSz, pkcs7HeadBuff, + &pkcs7HeadSz, pkcs7FootBuff, &pkcs7FootSz); + if ( ret != 0 ) { + // error encoding into output buffer + } + + wc_PKCS7_Free(&pkcs7); + \endcode + + \sa wc_PKCS7_InitWithCert + \sa wc_PKCS7_VerifySignedData_ex +*/ +WOLFSSL_API int wc_PKCS7_EncodeSignedData_ex(PKCS7* pkcs7, const byte* hashBuf, + word32 hashSz, byte* outputHead, word32* outputHeadSz, byte* outputFoot, + word32* outputFootSz); + /*! \ingroup PKCS7 @@ -250,11 +356,9 @@ WOLFSSL_API int wc_PKCS7_EncodeSignedData(PKCS7* pkcs7, \code PKCS7 pkcs7; int ret; + byte pkcs7Buff[] = {}; // the PKCS7 signature - byte derBuff[] = { }; // initialize with DER-encoded certificate - byte pkcs7Buff[FOURK_BUF]; - - wc_PKCS7_InitWithCert(&pkcs7, derBuff, sizeof(derBuff)); + wc_PKCS7_InitWithCert(&pkcs7, NULL, 0); // update message and data to encode pkcs7.privateKey = key; pkcs7.privateKeySz = keySz; @@ -262,10 +366,12 @@ WOLFSSL_API int wc_PKCS7_EncodeSignedData(PKCS7* pkcs7, pkcs7.contentSz = dataSz; ... etc. - ret = wc_PKCS7_EncodeSignedData(&pkcs7, pkcs7Buff, sizeof(pkcs7Buff)); + ret = wc_PKCS7_VerifySignedData(&pkcs7, pkcs7Buff, sizeof(pkcs7Buff)); if ( ret != 0 ) { // error encoding into output buffer } + + wc_PKCS7_Free(&pkcs7); \endcode \sa wc_PKCS7_InitWithCert @@ -274,6 +380,107 @@ WOLFSSL_API int wc_PKCS7_EncodeSignedData(PKCS7* pkcs7, WOLFSSL_API int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz); + +/*! + \ingroup PKCS7 + + \brief This function takes in a transmitted PKCS7 signed data message as + hash/header/footer, then extracts the certificate list and certificate + revocation list, and then verifies the signature. It stores the extracted + content in the given PKCS7 structure. + + \return 0 Returned on successfully extracting the information + from the message + \return BAD_FUNC_ARG Returned if one of the input parameters is invalid + \return ASN_PARSE_E Returned if there is an error parsing from the + given pkiMsg + \return PKCS7_OID_E Returned if the given pkiMsg is not a signed data type + \return ASN_VERSION_E Returned if the PKCS7 signer info is not version 1 + \return MEMORY_E Returned if there is an error allocating memory + \return PUBLIC_KEY_E Returned if there is an error parsing the public key + \return RSA_BUFFER_E Returned if buffer error, output too small or + input too large + \return BUFFER_E Returned if the given buffer is not large enough to + hold the encoded certificate + \return MP_INIT_E may be returned if there is an error generating + the signature + \return MP_READ_E may be returned if there is an error generating + the signature + \return MP_CMP_E may be returned if there is an error generating + the signature + \return MP_INVMOD_E may be returned if there is an error generating + the signature + \return MP_EXPTMOD_E may be returned if there is an error generating + the signature + \return MP_MOD_E may be returned if there is an error generating + the signature + \return MP_MUL_E may be returned if there is an error generating + the signature + \return MP_ADD_E may be returned if there is an error generating + the signature + \return MP_MULMOD_E may be returned if there is an error generating + the signature + \return MP_TO_E may be returned if there is an error generating + the signature + \return MP_MEM may be returned if there is an error generating the signature + + \param pkcs7 pointer to the PKCS7 structure in which to store the parsed + certificates + \param hashBuf pointer to computed hash for the content data + \param hashSz size of the digest + \param pkiMsgHead pointer to the buffer containing the signed message header + to verify and decode + \param pkiMsgHeadSz size of the signed message header + \param pkiMsgFoot pointer to the buffer containing the signed message footer + to verify and decode + \param pkiMsgFootSz size of the signed message footer + + _Example_ + \code + PKCS7 pkcs7; + int ret; + byte data[] = {}; // initialize with data to sign + byte pkcs7HeadBuff[] = {}; // initialize with PKCS7 header + byte pkcs7FootBuff[] = {}; // initialize with PKCS7 footer + enum wc_HashType hashType = WC_HASH_TYPE_SHA; + byte hashBuf[WC_MAX_DIGEST_SIZE]; + word32 hashSz = wc_HashGetDigestSize(hashType); + + wc_PKCS7_InitWithCert(&pkcs7, NULL, 0); + // update message and data to encode + pkcs7.privateKey = key; + pkcs7.privateKeySz = keySz; + pkcs7.content = NULL; + pkcs7.contentSz = dataSz; + pkcs7.rng = &rng; + ... etc. + + // 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); + } + + ret = wc_PKCS7_VerifySignedData_ex(&pkcs7, hashBuf, hashSz, pkcs7HeadBuff, + sizeof(pkcs7HeadBuff), pkcs7FootBuff, sizeof(pkcs7FootBuff)); + if ( ret != 0 ) { + // error encoding into output buffer + } + + wc_PKCS7_Free(&pkcs7); + \endcode + + \sa wc_PKCS7_InitWithCert + \sa wc_PKCS7_EncodeSignedData_ex +*/ +WOLFSSL_API int wc_PKCS7_VerifySignedData_ex(PKCS7* pkcs7, const byte* hashBuf, + word32 hashSz, byte* pkiMsgHead, word32 pkiMsgHeadSz, byte* pkiMsgFoot, + word32 pkiMsgFootSz); + /*! \ingroup PKCS7 diff --git a/tests/api.c b/tests/api.c index 4fd5c2903..911659975 100644 --- a/tests/api.c +++ b/tests/api.c @@ -14525,7 +14525,7 @@ static void test_wc_PKCS7_EncodeData (void) /* * Testing wc_PKCS7_EncodeSignedData() */ -static void test_wc_PKCS7_EncodeSignedData (void) +static void test_wc_PKCS7_EncodeSignedData(void) { #if defined(HAVE_PKCS7) PKCS7 pkcs7; @@ -14628,6 +14628,8 @@ static void test_wc_PKCS7_EncodeSignedData (void) AssertIntEQ(wc_PKCS7_EncodeSignedData(&pkcs7, NULL, outputSz), BAD_FUNC_ARG); AssertIntEQ(wc_PKCS7_EncodeSignedData(&pkcs7, badOut, badOutSz), BAD_FUNC_ARG); + pkcs7.hashOID = 0; /* bad hashOID */ + AssertIntEQ(wc_PKCS7_EncodeSignedData(&pkcs7, output, outputSz), BAD_FUNC_ARG); printf(resultFmt, passed); @@ -14637,6 +14639,197 @@ static void test_wc_PKCS7_EncodeSignedData (void) #endif } /* END test_wc_PKCS7_EncodeSignedData */ +/* + * Testing wc_PKCS7_EncodeSignedData_ex() and wc_PKCS7_VerifySignedData_ex() + */ +static void test_wc_PKCS7_EncodeSignedData_ex(void) +{ +#if defined(HAVE_PKCS7) + int ret, i; + PKCS7 pkcs7; + WC_RNG rng; + byte outputHead[FOURK_BUF/2]; + byte outputFoot[FOURK_BUF/2]; + word32 outputHeadSz = (word32)sizeof(outputHead); + word32 outputFootSz = (word32)sizeof(outputFoot); + byte data[FOURK_BUF]; + wc_HashAlg hash; + enum wc_HashType hashType = WC_HASH_TYPE_SHA; + byte hashBuf[WC_MAX_DIGEST_SIZE]; + word32 hashSz = wc_HashGetDigestSize(hashType); + +#ifndef NO_RSA + #if defined(USE_CERT_BUFFERS_2048) + byte key[sizeof_client_key_der_2048]; + byte cert[sizeof_client_cert_der_2048]; + word32 keySz = (word32)sizeof(key); + word32 certSz = (word32)sizeof(cert); + XMEMSET(key, 0, keySz); + XMEMSET(cert, 0, certSz); + XMEMCPY(key, client_key_der_2048, keySz); + XMEMCPY(cert, client_cert_der_2048, certSz); + #elif defined(USE_CERT_BUFFERS_1024) + byte key[sizeof_client_key_der_1024]; + byte cert[sizeof_client_cert_der_1024]; + word32 keySz = (word32)sizeof(key); + word32 certSz = (word32)sizeof(cert); + XMEMSET(key, 0, keySz); + XMEMSET(cert, 0, certSz); + XMEMCPY(key, client_key_der_1024, keySz); + XMEMCPY(cert, client_cert_der_1024, certSz); + #else + unsigned char cert[ONEK_BUF]; + unsigned char key[ONEK_BUF]; + FILE* fp; + int certSz; + int keySz; + + fp = fopen("./certs/1024/client-cert.der", "rb"); + AssertNotNull(fp); + certSz = fread(cert, 1, sizeof_client_cert_der_1024, fp); + fclose(fp); + + fp = fopen("./certs/1024/client-key.der", "rb"); + AssertNotNull(fp); + keySz = fread(key, 1, sizeof_client_key_der_1024, fp); + fclose(fp); + #endif +#elif defined(HAVE_ECC) + #if defined(USE_CERT_BUFFERS_256) + unsigned char cert[sizeof_cliecc_cert_der_256]; + unsigned char key[sizeof_ecc_clikey_der_256]; + int certSz = (int)sizeof(cert); + int keySz = (int)sizeof(key); + XMEMSET(cert, 0, certSz); + XMEMSET(key, 0, keySz); + XMEMCPY(cert, cliecc_cert_der_256, sizeof_cliecc_cert_der_256); + XMEMCPY(key, ecc_clikey_der_256, sizeof_ecc_clikey_der_256); + #else + unsigned char cert[ONEK_BUF]; + unsigned char key[ONEK_BUF]; + FILE* fp; + int certSz, keySz; + + fp = fopen("./certs/client-ecc-cert.der", "rb"); + AssertNotNull(fp); + certSz = fread(cert, 1, sizeof_cliecc_cert_der_256, fp); + fclose(fp); + + fp = fopen("./certs/client-ecc-key.der", "rb"); + AssertNotNull(fp); + keySz = fread(key, 1, sizeof_ecc_clikey_der_256, fp); + fclose(fp); + #endif +#endif + + /* initialize large data with sequence */ + for (i=0; i<(int)sizeof(data); i++) + data[i] = i & 0xff; + + XMEMSET(outputHead, 0, outputHeadSz); + XMEMSET(outputFoot, 0, outputFootSz); + AssertIntEQ(wc_InitRng(&rng), 0); + + AssertIntEQ(wc_PKCS7_Init(&pkcs7, HEAP_HINT, INVALID_DEVID), 0); + + AssertIntEQ(wc_PKCS7_InitWithCert(&pkcs7, cert, certSz), 0); + + printf(testingFmt, "wc_PKCS7_EncodeSignedData()"); + + pkcs7.content = NULL; /* not used for ex */ + pkcs7.contentSz = (word32)sizeof(data); + pkcs7.privateKey = key; + pkcs7.privateKeySz = (word32)sizeof(key); + pkcs7.encryptOID = RSAk; + pkcs7.hashOID = SHAh; + pkcs7.rng = &rng; + + /* 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); + + /* Perform PKCS7 sign using hash directly */ + AssertIntEQ(wc_PKCS7_EncodeSignedData_ex(&pkcs7, hashBuf, hashSz, + outputHead, &outputHeadSz, outputFoot, &outputFootSz), 0); + AssertIntGT(outputHeadSz, 0); + AssertIntGT(outputFootSz, 0); + + wc_PKCS7_Free(&pkcs7); + AssertIntEQ(wc_PKCS7_InitWithCert(&pkcs7, NULL, 0), 0); + + /* required parameter even on verify when using _ex */ + pkcs7.contentSz = (word32)sizeof(data); + AssertIntEQ(wc_PKCS7_VerifySignedData_ex(&pkcs7, hashBuf, hashSz, + outputHead, outputHeadSz, outputFoot, outputFootSz), 0); + + wc_PKCS7_Free(&pkcs7); + + /* assembly complete PKCS7 sign and use normal verify */ + { + byte* output = (byte*)XMALLOC(outputHeadSz + sizeof(data) + outputFootSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + word32 outputSz = 0; + AssertNotNull(output); + XMEMCPY(&output[outputSz], outputHead, outputHeadSz); + outputSz += outputHeadSz; + XMEMCPY(&output[outputSz], data, sizeof(data)); + outputSz += sizeof(data); + XMEMCPY(&output[outputSz], outputFoot, outputFootSz); + outputSz += outputFootSz; + + AssertIntEQ(wc_PKCS7_InitWithCert(&pkcs7, NULL, 0), 0); + AssertIntEQ(wc_PKCS7_VerifySignedData(&pkcs7, output, outputSz), 0); + XFREE(output, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + } + + /* Pass in bad args. */ + AssertIntEQ(wc_PKCS7_EncodeSignedData_ex(NULL, hashBuf, hashSz, outputHead, + &outputHeadSz, outputFoot, &outputFootSz), BAD_FUNC_ARG); + AssertIntEQ(wc_PKCS7_EncodeSignedData_ex(&pkcs7, NULL, hashSz, outputHead, + &outputHeadSz, outputFoot, &outputFootSz), BAD_FUNC_ARG); + AssertIntEQ(wc_PKCS7_EncodeSignedData_ex(&pkcs7, hashBuf, 0, outputHead, + &outputHeadSz, outputFoot, &outputFootSz), BAD_FUNC_ARG); + AssertIntEQ(wc_PKCS7_EncodeSignedData_ex(&pkcs7, hashBuf, hashSz, NULL, + &outputHeadSz, outputFoot, &outputFootSz), BAD_FUNC_ARG); + AssertIntEQ(wc_PKCS7_EncodeSignedData_ex(&pkcs7, hashBuf, hashSz, + outputHead, NULL, outputFoot, &outputFootSz), BAD_FUNC_ARG); + AssertIntEQ(wc_PKCS7_EncodeSignedData_ex(&pkcs7, hashBuf, hashSz, + outputHead, &outputHeadSz, NULL, &outputFootSz), BAD_FUNC_ARG); + AssertIntEQ(wc_PKCS7_EncodeSignedData_ex(&pkcs7, hashBuf, hashSz, + outputHead, &outputHeadSz, outputFoot, NULL), BAD_FUNC_ARG); + pkcs7.hashOID = 0; /* bad hashOID */ + AssertIntEQ(wc_PKCS7_EncodeSignedData_ex(&pkcs7, hashBuf, hashSz, + outputHead, &outputHeadSz, outputFoot, &outputFootSz), BAD_FUNC_ARG); + + AssertIntEQ(wc_PKCS7_VerifySignedData_ex(NULL, hashBuf, hashSz, outputHead, + outputHeadSz, outputFoot, outputFootSz), BAD_FUNC_ARG); + AssertIntEQ(wc_PKCS7_VerifySignedData_ex(&pkcs7, NULL, hashSz, outputHead, + outputHeadSz, outputFoot, outputFootSz), ASN_PARSE_E); + AssertIntEQ(wc_PKCS7_VerifySignedData_ex(&pkcs7, hashBuf, 0, outputHead, + outputHeadSz, outputFoot, outputFootSz), ASN_PARSE_E); + AssertIntEQ(wc_PKCS7_VerifySignedData_ex(&pkcs7, hashBuf, hashSz, NULL, + outputHeadSz, outputFoot, outputFootSz), BAD_FUNC_ARG); + AssertIntEQ(wc_PKCS7_VerifySignedData_ex(&pkcs7, hashBuf, hashSz, + outputHead, 0, outputFoot, outputFootSz), BAD_FUNC_ARG); + AssertIntEQ(wc_PKCS7_VerifySignedData_ex(&pkcs7, hashBuf, hashSz, + outputHead, outputHeadSz, NULL, outputFootSz), ASN_PARSE_E); + AssertIntEQ(wc_PKCS7_VerifySignedData_ex(&pkcs7, hashBuf, hashSz, + outputHead, outputHeadSz, outputFoot, 0), ASN_PARSE_E); + + printf(resultFmt, passed); + + wc_PKCS7_Free(&pkcs7); + wc_FreeRng(&rng); + +#endif +} /* END test_wc_PKCS7_EncodeSignedData_ex */ + /* * Testing wc_PKCS_VerifySignedData() @@ -20656,6 +20849,7 @@ void ApiTest(void) test_wc_PKCS7_InitWithCert(); test_wc_PKCS7_EncodeData(); test_wc_PKCS7_EncodeSignedData(); + test_wc_PKCS7_EncodeSignedData_ex(); test_wc_PKCS7_VerifySignedData(); test_wc_PKCS7_EncodeDecodeEnvelopedData(); test_wc_PKCS7_EncodeEncryptedData(); diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index 7f7293193..4c99db973 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -303,8 +303,7 @@ int wc_PKCS7_InitWithCert(PKCS7* pkcs7, byte* cert, word32 certSz) if (dCert == NULL) return MEMORY_E; #else - DecodedCert stack_dCert; - DecodedCert* dCert = &stack_dCert; + DecodedCert dCert[1]; #endif pkcs7->singleCert = cert; @@ -611,8 +610,7 @@ static int wc_PKCS7_RsaSign(PKCS7* pkcs7, byte* in, word32 inSz, ESD* esd) #ifdef WOLFSSL_SMALL_STACK RsaKey* privKey; #else - RsaKey stack_privKey; - RsaKey* privKey = &stack_privKey; + RsaKey privKey[1]; #endif if (pkcs7 == NULL || pkcs7->rng == NULL || in == NULL || esd == NULL) { @@ -664,8 +662,7 @@ static int wc_PKCS7_EcdsaSign(PKCS7* pkcs7, byte* in, word32 inSz, ESD* esd) #ifdef WOLFSSL_SMALL_STACK ecc_key* privKey; #else - ecc_key stack_privKey; - ecc_key* privKey = &stack_privKey; + ecc_key privKey[1]; #endif if (pkcs7 == NULL || pkcs7->rng == NULL || in == NULL || esd == NULL) { @@ -716,9 +713,9 @@ static int wc_PKCS7_EcdsaSign(PKCS7* pkcs7, byte* in, word32 inSz, ESD* esd) * * return 0 on success, negative on error */ static int wc_PKCS7_BuildSignedAttributes(PKCS7* pkcs7, ESD* esd, - byte* contentTypeOid, word32 contentTypeOidSz, - byte* contentType, word32 contentTypeSz, - byte* messageDigestOid, word32 messageDigestOidSz) + const byte* contentTypeOid, word32 contentTypeOidSz, + const byte* contentType, word32 contentTypeSz, + const byte* messageDigestOid, word32 messageDigestOidSz) { int hashSz; @@ -941,7 +938,7 @@ static int wc_PKCS7_BuildDigestInfo(PKCS7* pkcs7, byte* flatSignedAttribs, /* build SignedData signature over DigestInfo or content digest * - * pkcs7 - pointer to initizlied PKCS7 struct + * pkcs7 - pointer to initialized PKCS7 struct * flatSignedAttribs - flattened, signed attributes * flatSignedAttribsSz - size of flatSignedAttribs, octets * esd - pointer to initialized ESD struct @@ -960,7 +957,7 @@ static int wc_PKCS7_SignedDataBuildSignature(PKCS7* pkcs7, #ifdef WOLFSSL_SMALL_STACK byte* digestInfo; #else - byte digestInfo[MAX_PKCS7_DIGEST_SZ]; + byte digestInfo[MAX_PKCS7_DIGEST_SZ]; #endif if (pkcs7 == NULL || esd == NULL) @@ -1027,88 +1024,55 @@ static int wc_PKCS7_SignedDataBuildSignature(PKCS7* pkcs7, } /* build PKCS#7 signedData content type */ -int wc_PKCS7_EncodeSignedData(PKCS7* pkcs7, byte* output, word32 outputSz) +static int PKCS7_EncodeSigned(PKCS7* pkcs7, ESD* esd, + const byte* hashBuf, word32 hashSz, byte* output, word32* outputSz, + byte* output2, word32* output2Sz) { - static const byte outerOid[] = - { ASN_OBJECT_ID, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, - 0x07, 0x02 }; - static const byte innerOid[] = - { ASN_OBJECT_ID, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, - 0x07, 0x01 }; + const byte outerOid[] = + { ASN_OBJECT_ID, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, + 0x07, 0x02 }; + const byte innerOid[] = + { ASN_OBJECT_ID, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, + 0x07, 0x01 }; - byte contentTypeOid[] = + const byte contentTypeOid[] = { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xF7, 0x0d, 0x01, 0x09, 0x03 }; - byte contentType[] = + const byte contentType[] = { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01 }; - byte messageDigestOid[] = + const byte messageDigestOid[] = { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x04 }; -#ifdef WOLFSSL_SMALL_STACK - ESD* esd = NULL; -#else - ESD stack_esd; - ESD* esd = &stack_esd; -#endif - word32 signerInfoSz = 0; - word32 totalSz = 0; + word32 totalSz, total2Sz; int idx = 0, ret = 0; - int digEncAlgoId, digEncAlgoType, hashSz; + int digEncAlgoId, digEncAlgoType; byte* flatSignedAttribs = NULL; word32 flatSignedAttribsSz = 0; word32 innerOidSz = sizeof(innerOid); word32 outerOidSz = sizeof(outerOid); - if (pkcs7 == NULL || pkcs7->content == NULL || pkcs7->contentSz == 0 || + if (pkcs7 == NULL || pkcs7->contentSz == 0 || pkcs7->encryptOID == 0 || pkcs7->hashOID == 0 || pkcs7->rng == 0 || pkcs7->singleCert == NULL || pkcs7->singleCertSz == 0 || - output == NULL || outputSz == 0) { + output == NULL || outputSz == NULL || *outputSz == 0 || hashSz == 0 || + hashBuf == NULL) { return BAD_FUNC_ARG; } -#ifdef WOLFSSL_SMALL_STACK - esd = (ESD*)XMALLOC(sizeof(ESD), pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - if (esd == NULL) - return MEMORY_E; -#endif - - XMEMSET(esd, 0, sizeof(ESD)); - + /* verify the hash size matches */ esd->hashType = wc_OidGetHash(pkcs7->hashOID); - ret = wc_HashGetDigestSize(esd->hashType); - if (ret < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; + if (wc_HashGetDigestSize(esd->hashType) != (int)hashSz) { + WOLFSSL_MSG("hashSz did not match hashOID"); + return BUFFER_E; } - hashSz = ret; - if (pkcs7->contentSz != 0) - { - ret = wc_HashInit(&esd->hash, esd->hashType); - if (ret == 0) { - ret = wc_HashUpdate(&esd->hash, esd->hashType, - pkcs7->content, pkcs7->contentSz); - if (ret == 0) { - esd->contentDigest[0] = ASN_OCTET_STRING; - esd->contentDigest[1] = (byte)hashSz; - ret = wc_HashFinal(&esd->hash, esd->hashType, - &esd->contentDigest[2]); - } - wc_HashFree(&esd->hash, esd->hashType); - } - - if (ret < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; - } - } + /* include hash */ + esd->contentDigest[0] = ASN_OCTET_STRING; + esd->contentDigest[1] = (byte)hashSz; + XMEMCPY(&esd->contentDigest[2], hashBuf, hashSz); esd->innerOctetsSz = SetOctetString(pkcs7->contentSz, esd->innerOctets); esd->innerContSeqSz = SetExplicit(0, esd->innerOctetsSz + pkcs7->contentSz, @@ -1134,9 +1098,6 @@ int wc_PKCS7_EncodeSignedData(PKCS7* pkcs7, byte* output, word32 outputSz) ret = wc_PKCS7_SignedDataGetEncAlgoId(pkcs7, &digEncAlgoId, &digEncAlgoType); if (ret < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif return ret; } esd->digEncAlgoIdSz = SetAlgoID(digEncAlgoId, esd->digEncAlgoId, @@ -1151,9 +1112,6 @@ int wc_PKCS7_EncodeSignedData(PKCS7* pkcs7, byte* output, word32 outputSz) contentType, sizeof(contentType), messageDigestOid, sizeof(messageDigestOid)); if (ret < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif return MEMORY_E; } @@ -1161,9 +1119,6 @@ int wc_PKCS7_EncodeSignedData(PKCS7* pkcs7, byte* output, word32 outputSz) DYNAMIC_TYPE_PKCS7); flatSignedAttribsSz = esd->signedAttribsSz; if (flatSignedAttribs == NULL) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif return MEMORY_E; } @@ -1179,9 +1134,6 @@ int wc_PKCS7_EncodeSignedData(PKCS7* pkcs7, byte* output, word32 outputSz) if (ret < 0) { if (pkcs7->signedAttribsSz != 0) XFREE(flatSignedAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7); -#ifdef WOLFSSL_SMALL_STACK - XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif return ret; } @@ -1207,23 +1159,30 @@ int wc_PKCS7_EncodeSignedData(PKCS7* pkcs7, byte* output, word32 outputSz) esd->versionSz = SetMyVersion(1, esd->version, 0); totalSz = esd->versionSz + esd->singleDigAlgoIdSz + esd->digAlgoIdSetSz + - esd->contentInfoSeqSz + esd->certsSetSz + pkcs7->singleCertSz + - esd->innerOctetsSz + esd->innerContSeqSz + - innerOidSz + pkcs7->contentSz + - signerInfoSz; - esd->innerSeqSz = SetSequence(totalSz, esd->innerSeq); + esd->contentInfoSeqSz + innerOidSz + esd->innerContSeqSz + + esd->innerOctetsSz + pkcs7->contentSz; + total2Sz = esd->certsSetSz + pkcs7->singleCertSz + signerInfoSz; + + esd->innerSeqSz = SetSequence(totalSz + total2Sz, esd->innerSeq); totalSz += esd->innerSeqSz; - esd->outerContentSz = SetExplicit(0, totalSz, esd->outerContent); + esd->outerContentSz = SetExplicit(0, totalSz + total2Sz, esd->outerContent); totalSz += esd->outerContentSz + outerOidSz; - esd->outerSeqSz = SetSequence(totalSz, esd->outerSeq); + esd->outerSeqSz = SetSequence(totalSz + total2Sz, esd->outerSeq); totalSz += esd->outerSeqSz; - if (outputSz < totalSz) { + /* if using header/footer, we are not returning the content */ + if (output2 && output2Sz) { + if (total2Sz > *output2Sz) { + if (pkcs7->signedAttribsSz != 0) + XFREE(flatSignedAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + return BUFFER_E; + } + totalSz -= pkcs7->contentSz; + } + + if (totalSz > *outputSz) { if (pkcs7->signedAttribsSz != 0) XFREE(flatSignedAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7); -#ifdef WOLFSSL_SMALL_STACK - XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif return BUFFER_E; } @@ -1250,50 +1209,160 @@ int wc_PKCS7_EncodeSignedData(PKCS7* pkcs7, byte* output, word32 outputSz) idx += esd->innerContSeqSz; XMEMCPY(output + idx, esd->innerOctets, esd->innerOctetsSz); idx += esd->innerOctetsSz; - XMEMCPY(output + idx, pkcs7->content, pkcs7->contentSz); - idx += pkcs7->contentSz; - XMEMCPY(output + idx, esd->certsSet, esd->certsSetSz); + + /* support returning header and footer without content */ + if (output2 && output2Sz) { + *outputSz = idx; + idx = 0; + } + else { + XMEMCPY(output + idx, pkcs7->content, pkcs7->contentSz); + idx += pkcs7->contentSz; + output2 = output; + } + XMEMCPY(output2 + idx, esd->certsSet, esd->certsSetSz); idx += esd->certsSetSz; - XMEMCPY(output + idx, pkcs7->singleCert, pkcs7->singleCertSz); + XMEMCPY(output2 + idx, pkcs7->singleCert, pkcs7->singleCertSz); idx += pkcs7->singleCertSz; - XMEMCPY(output + idx, esd->signerInfoSet, esd->signerInfoSetSz); + XMEMCPY(output2 + idx, esd->signerInfoSet, esd->signerInfoSetSz); idx += esd->signerInfoSetSz; - XMEMCPY(output + idx, esd->signerInfoSeq, esd->signerInfoSeqSz); + XMEMCPY(output2 + idx, esd->signerInfoSeq, esd->signerInfoSeqSz); idx += esd->signerInfoSeqSz; - XMEMCPY(output + idx, esd->signerVersion, esd->signerVersionSz); + XMEMCPY(output2 + idx, esd->signerVersion, esd->signerVersionSz); idx += esd->signerVersionSz; - XMEMCPY(output + idx, esd->issuerSnSeq, esd->issuerSnSeqSz); + XMEMCPY(output2 + idx, esd->issuerSnSeq, esd->issuerSnSeqSz); idx += esd->issuerSnSeqSz; - XMEMCPY(output + idx, esd->issuerName, esd->issuerNameSz); + XMEMCPY(output2 + idx, esd->issuerName, esd->issuerNameSz); idx += esd->issuerNameSz; - XMEMCPY(output + idx, pkcs7->issuer, pkcs7->issuerSz); + XMEMCPY(output2 + idx, pkcs7->issuer, pkcs7->issuerSz); idx += pkcs7->issuerSz; - XMEMCPY(output + idx, esd->issuerSn, esd->issuerSnSz); + XMEMCPY(output2 + idx, esd->issuerSn, esd->issuerSnSz); idx += esd->issuerSnSz; - XMEMCPY(output + idx, esd->signerDigAlgoId, esd->signerDigAlgoIdSz); + XMEMCPY(output2 + idx, esd->signerDigAlgoId, esd->signerDigAlgoIdSz); idx += esd->signerDigAlgoIdSz; /* SignerInfo:Attributes */ if (flatSignedAttribsSz > 0) { - XMEMCPY(output + idx, esd->signedAttribSet, esd->signedAttribSetSz); + XMEMCPY(output2 + idx, esd->signedAttribSet, esd->signedAttribSetSz); idx += esd->signedAttribSetSz; - XMEMCPY(output + idx, flatSignedAttribs, flatSignedAttribsSz); + XMEMCPY(output2 + idx, flatSignedAttribs, flatSignedAttribsSz); idx += flatSignedAttribsSz; XFREE(flatSignedAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7); } - XMEMCPY(output + idx, esd->digEncAlgoId, esd->digEncAlgoIdSz); + XMEMCPY(output2 + idx, esd->digEncAlgoId, esd->digEncAlgoIdSz); idx += esd->digEncAlgoIdSz; - XMEMCPY(output + idx, esd->signerDigest, esd->signerDigestSz); + XMEMCPY(output2 + idx, esd->signerDigest, esd->signerDigestSz); idx += esd->signerDigestSz; - XMEMCPY(output + idx, esd->encContentDigest, esd->encContentDigestSz); + XMEMCPY(output2 + idx, esd->encContentDigest, esd->encContentDigestSz); idx += esd->encContentDigestSz; + if (output2 && output2Sz) { + *output2Sz = idx; + idx = 0; /* success */ + } + else { + *outputSz = idx; + } + + return idx; +} + +/* hashBuf: The computed digest for the pkcs7->content + * hashSz: The size of computed digest for the pkcs7->content based on hashOID + * outputHead: The PKCS7 header that goes on top of the raw data signed. + * outputFoot: The PKCS7 footer that goes at the end of the raw data signed. + * pkcs7->content: Not used + * pkcs7->contentSz: Must be provided as actual sign of raw data + * return codes: 0=success, negative=error + */ +int wc_PKCS7_EncodeSignedData_ex(PKCS7* pkcs7, const byte* hashBuf, word32 hashSz, + byte* outputHead, word32* outputHeadSz, byte* outputFoot, word32* outputFootSz) +{ + int ret; +#ifdef WOLFSSL_SMALL_STACK + ESD* esd; +#else + ESD esd[1]; +#endif + + /* other args checked in wc_PKCS7_EncodeSigned_ex */ + if (pkcs7 == NULL || outputFoot == NULL || outputFootSz == NULL) { + return BAD_FUNC_ARG; + } + +#ifdef WOLFSSL_SMALL_STACK + esd = (ESD*)XMALLOC(sizeof(ESD), pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (esd == NULL) + return MEMORY_E; +#endif + + XMEMSET(esd, 0, sizeof(ESD)); + + ret = PKCS7_EncodeSigned(pkcs7, esd, hashBuf, hashSz, + outputHead, outputHeadSz, outputFoot, outputFootSz); + #ifdef WOLFSSL_SMALL_STACK XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); #endif - return idx; + return ret; +} + +/* return codes: >0: Size of signed PKCS7 output buffer, negative: error */ +int wc_PKCS7_EncodeSignedData(PKCS7* pkcs7, byte* output, word32 outputSz) +{ + int ret; + int hashSz; + enum wc_HashType hashType; + byte hashBuf[WC_MAX_DIGEST_SIZE]; +#ifdef WOLFSSL_SMALL_STACK + ESD* esd; +#else + ESD esd[1]; +#endif + + /* other args checked in wc_PKCS7_EncodeSigned_ex */ + if (pkcs7 == NULL || pkcs7->contentSz == 0 || pkcs7->content == NULL) { + return BAD_FUNC_ARG; + } + + /* get hash type and size, validate hashOID */ + hashType = wc_OidGetHash(pkcs7->hashOID); + hashSz = wc_HashGetDigestSize(hashType); + if (hashSz < 0) + return hashSz; + +#ifdef WOLFSSL_SMALL_STACK + esd = (ESD*)XMALLOC(sizeof(ESD), pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (esd == NULL) + return MEMORY_E; +#endif + + XMEMSET(esd, 0, sizeof(ESD)); + esd->hashType = hashType; + + /* calculate hash for content */ + ret = wc_HashInit(&esd->hash, esd->hashType); + if (ret == 0) { + ret = wc_HashUpdate(&esd->hash, esd->hashType, + pkcs7->content, pkcs7->contentSz); + if (ret == 0) { + ret = wc_HashFinal(&esd->hash, esd->hashType, hashBuf); + } + wc_HashFree(&esd->hash, esd->hashType); + } + + if (ret == 0) { + ret = PKCS7_EncodeSigned(pkcs7, esd, hashBuf, hashSz, + output, &outputSz, NULL, NULL); + } + +#ifdef WOLFSSL_SMALL_STACK + XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return ret; } @@ -1310,8 +1379,7 @@ static int wc_PKCS7_RsaVerify(PKCS7* pkcs7, byte* sig, int sigSz, RsaKey* key; #else byte digest[MAX_PKCS7_DIGEST_SZ]; - RsaKey stack_key; - RsaKey* key = &stack_key; + RsaKey key[1]; #endif if (pkcs7 == NULL || sig == NULL || hash == NULL) { @@ -1386,8 +1454,7 @@ static int wc_PKCS7_EcdsaVerify(PKCS7* pkcs7, byte* sig, int sigSz, ecc_key* key; #else byte digest[MAX_PKCS7_DIGEST_SZ]; - ecc_key stack_key; - ecc_key* key = &stack_key; + ecc_key key[1]; #endif word32 idx = 0; @@ -1464,10 +1531,11 @@ static int wc_PKCS7_EcdsaVerify(PKCS7* pkcs7, byte* sig, int sigSz, static int wc_PKCS7_BuildSignedDataDigest(PKCS7* pkcs7, byte* signedAttrib, word32 signedAttribSz, byte* pkcs7Digest, word32* pkcs7DigestSz, byte** plainDigest, - word32* plainDigestSz) + word32* plainDigestSz, + const byte* hashBuf, word32 hashBufSz) { - int ret = 0, digIdx = 0, hashSz; - word32 attribSetSz; + int ret = 0, digIdx = 0; + word32 attribSetSz, hashSz; byte attribSet[MAX_SET_SZ]; byte digest[WC_MAX_DIGEST_SIZE]; byte digestInfoSeq[MAX_SEQ_SZ]; @@ -1477,7 +1545,7 @@ static int wc_PKCS7_BuildSignedDataDigest(PKCS7* pkcs7, byte* signedAttrib, #ifdef WOLFSSL_SMALL_STACK byte* digestInfo; #else - byte digestInfo[MAX_PKCS7_DIGEST_SZ]; + byte digestInfo[MAX_PKCS7_DIGEST_SZ]; #endif wc_HashAlg hash; @@ -1500,7 +1568,11 @@ static int wc_PKCS7_BuildSignedDataDigest(PKCS7* pkcs7, byte* signedAttrib, return BAD_FUNC_ARG; } else { - if (pkcs7->content == NULL) + if (hashBuf && hashBufSz > 0) { + if (hashSz != hashBufSz) + return BAD_FUNC_ARG; + } + else if (pkcs7->content == NULL) return BAD_FUNC_ARG; } @@ -1517,36 +1589,40 @@ static int wc_PKCS7_BuildSignedDataDigest(PKCS7* pkcs7, byte* signedAttrib, /* calculate digest */ - ret = wc_HashInit(&hash, hashType); - if (ret < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(digestInfo, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; + if (hashBuf && hashBufSz > 0 && signedAttribSz == 0) { + XMEMCPY(digest, hashBuf, hashBufSz); } + else { + ret = wc_HashInit(&hash, hashType); + if (ret < 0) { + #ifdef WOLFSSL_SMALL_STACK + XFREE(digestInfo, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + #endif + return ret; + } - if (signedAttribSz > 0) { - attribSetSz = SetSet(signedAttribSz, attribSet); + if (signedAttribSz > 0) { + attribSetSz = SetSet(signedAttribSz, attribSet); - /* calculate digest */ - ret = wc_HashUpdate(&hash, hashType, attribSet, attribSetSz); - if (ret == 0) - ret = wc_HashUpdate(&hash, hashType, signedAttrib, signedAttribSz); - if (ret == 0) - ret = wc_HashFinal(&hash, hashType, digest); - } else { - ret = wc_HashUpdate(&hash, hashType, pkcs7->content, pkcs7->contentSz); - if (ret == 0) - ret = wc_HashFinal(&hash, hashType, digest); - } + /* calculate digest */ + ret = wc_HashUpdate(&hash, hashType, attribSet, attribSetSz); + if (ret == 0) + ret = wc_HashUpdate(&hash, hashType, signedAttrib, signedAttribSz); + if (ret == 0) + ret = wc_HashFinal(&hash, hashType, digest); + } else { + ret = wc_HashUpdate(&hash, hashType, pkcs7->content, pkcs7->contentSz); + if (ret == 0) + ret = wc_HashFinal(&hash, hashType, digest); + } - wc_HashFree(&hash, hashType); - - if (ret < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(digestInfo, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; + wc_HashFree(&hash, hashType); + if (ret < 0) { + #ifdef WOLFSSL_SMALL_STACK + XFREE(digestInfo, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + #endif + return ret; + } } /* Set algoID, with NULL attributes */ @@ -1591,7 +1667,8 @@ static int wc_PKCS7_BuildSignedDataDigest(PKCS7* pkcs7, byte* signedAttrib, * return 0 on success, negative on error */ static int wc_PKCS7_SignedDataVerifySignature(PKCS7* pkcs7, byte* sig, word32 sigSz, byte* signedAttrib, - word32 signedAttribSz) + word32 signedAttribSz, + const byte* hashBuf, word32 hashSz) { int ret = 0; word32 plainDigestSz = 0, pkcs7DigestSz; @@ -1617,7 +1694,7 @@ static int wc_PKCS7_SignedDataVerifySignature(PKCS7* pkcs7, byte* sig, ret = wc_PKCS7_BuildSignedDataDigest(pkcs7, signedAttrib, signedAttribSz, pkcs7Digest, &pkcs7DigestSz, &plainDigest, - &plainDigestSz); + &plainDigestSz, hashBuf, hashSz); if (ret < 0) { #ifdef WOLFSSL_SMALL_STACK XFREE(pkcs7Digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); @@ -1818,17 +1895,19 @@ static int wc_PKCS7_ParseAttribs(PKCS7* pkcs7, byte* in, int inSz) return found; } - /* Finds the certificates in the message and saves it. */ -int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz) +static int PKCS7_VerifySignedData(PKCS7* pkcs7, const byte* hashBuf, + word32 hashSz, byte* pkiMsg, word32 pkiMsgSz, + byte* pkiMsg2, word32 pkiMsg2Sz) { - word32 idx, contentType, hashOID, sigOID; + word32 idx, contentType, hashOID, sigOID, totalSz; int length, version, ret; byte* content = NULL; byte* sig = NULL; byte* cert = NULL; byte* signedAttrib = NULL; int contentSz = 0, sigSz = 0, certSz = 0, signedAttribSz = 0; + word32 localIdx; byte degenerate; #ifdef ASN_BER_TO_DER byte* der; @@ -1839,8 +1918,14 @@ int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz) idx = 0; + /* determine total message size */ + totalSz = pkiMsgSz; + if (pkiMsg2 && pkiMsg2Sz > 0) { + totalSz += pkiMsg2Sz + pkcs7->contentSz; + } + /* Get the contentInfo sequence */ - if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) + if (GetSequence(pkiMsg, &idx, &length, totalSz) < 0) return ASN_PARSE_E; if (length == 0 && pkiMsg[idx-1] == 0x80) { @@ -1880,11 +1965,11 @@ int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz) if (pkiMsg[idx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) return ASN_PARSE_E; - if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) + if (GetLength(pkiMsg, &idx, &length, totalSz) < 0) return ASN_PARSE_E; /* Get the signedData sequence */ - if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) + if (GetSequence(pkiMsg, &idx, &length, totalSz) < 0) return ASN_PARSE_E; /* Get the version */ @@ -1905,7 +1990,7 @@ int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz) degenerate = (length == 0)? 1 : 0; /* Get the inner ContentInfo sequence */ - if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) + if (GetSequence(pkiMsg, &idx, &length, totalSz) < 0) return ASN_PARSE_E; /* Get the inner ContentInfo contentType */ @@ -1918,34 +2003,51 @@ int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz) } /* Check for content info, it could be omitted when degenerate */ - { - word32 localIdx = idx; - ret = 0; - if (pkiMsg[localIdx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) - ret = ASN_PARSE_E; + localIdx = idx; + ret = 0; + if (pkiMsg[localIdx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) + ret = ASN_PARSE_E; - if (ret == 0 && GetLength(pkiMsg, &localIdx, &length, pkiMsgSz) <= 0) - ret = ASN_PARSE_E; + if (ret == 0 && GetLength(pkiMsg, &localIdx, &length, totalSz) <= 0) + ret = ASN_PARSE_E; - if (ret == 0 && pkiMsg[localIdx++] != ASN_OCTET_STRING) - ret = ASN_PARSE_E; + if (ret == 0 && pkiMsg[localIdx++] != ASN_OCTET_STRING) + ret = ASN_PARSE_E; - if (ret == 0 && GetLength(pkiMsg, &localIdx, &length, pkiMsgSz) < 0) - ret = ASN_PARSE_E; + if (ret == 0 && GetLength(pkiMsg, &localIdx, &length, totalSz) < 0) + ret = ASN_PARSE_E; - /* Save the inner data as the content. */ - if (length > 0) { - /* Local pointer for calculating hashes later */ + /* Save the inner data as the content. */ + if (ret == 0 && length > 0) { + contentSz = length; + + /* support using header and footer without content */ + if (pkiMsg2 && pkiMsg2Sz > 0 && hashBuf && hashSz > 0) { + /* Content not provided, use provided pkiMsg2 footer */ + content = NULL; + localIdx = 0; + if (contentSz != (int)pkcs7->contentSz) { + WOLFSSL_MSG("Data signed does not match contentSz provided"); + return BUFFER_E; + } + } + else { + /* Content pointer for calculating hashes later */ content = &pkiMsg[localIdx]; - contentSz = length; localIdx += length; - } - /* update idx if successful */ - if (ret == 0) { - idx = localIdx; + pkiMsg2 = pkiMsg; + pkiMsg2Sz = pkiMsgSz; } } + else { + pkiMsg2 = pkiMsg; + } + + /* update idx if successful */ + if (ret == 0) { + idx = localIdx; + } /* If getting the content info failed with non degenerate then return the * error case. Otherwise with a degenerate it is ok if the content @@ -1955,9 +2057,9 @@ int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz) } /* Get the implicit[0] set of certificates */ - if (pkiMsg[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) { + if (pkiMsg2[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) { idx++; - if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) + if (GetLength(pkiMsg2, &idx, &length, pkiMsg2Sz) < 0) return ASN_PARSE_E; if (length > 0) { @@ -1969,11 +2071,11 @@ int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz) word32 certIdx = idx; - if (pkiMsg[certIdx++] == (ASN_CONSTRUCTED | ASN_SEQUENCE)) { - if (GetLength(pkiMsg, &certIdx, &certSz, pkiMsgSz) < 0) + if (pkiMsg2[certIdx++] == (ASN_CONSTRUCTED | ASN_SEQUENCE)) { + if (GetLength(pkiMsg2, &certIdx, &certSz, pkiMsg2Sz) < 0) return ASN_PARSE_E; - cert = &pkiMsg[idx]; + cert = &pkiMsg2[idx]; certSz += (certIdx - idx); } @@ -1988,7 +2090,6 @@ int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz) /* iterate through any additional certificates */ if (MAX_PKCS7_CERTS > 0) { - word32 localIdx; int sz = 0; int i; @@ -1996,14 +2097,14 @@ int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz) pkcs7->certSz[0] = certSz; certIdx = idx + certSz; - for (i = 1; i < MAX_PKCS7_CERTS && certIdx + 1 < pkiMsgSz; i++) { + for (i = 1; i < MAX_PKCS7_CERTS && certIdx + 1 < pkiMsg2Sz; i++) { localIdx = certIdx; - if (pkiMsg[certIdx++] == (ASN_CONSTRUCTED | ASN_SEQUENCE)) { - if (GetLength(pkiMsg, &certIdx, &sz, pkiMsgSz) < 0) + if (pkiMsg2[certIdx++] == (ASN_CONSTRUCTED | ASN_SEQUENCE)) { + if (GetLength(pkiMsg2, &certIdx, &sz, pkiMsg2Sz) < 0) return ASN_PARSE_E; - pkcs7->cert[i] = &pkiMsg[localIdx]; + pkcs7->cert[i] = &pkiMsg2[localIdx]; pkcs7->certSz[i] = sz + (certIdx - localIdx); certIdx += sz; } @@ -2018,9 +2119,9 @@ int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz) pkcs7->contentSz = contentSz; /* Get the implicit[1] set of crls */ - if (pkiMsg[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) { + if (pkiMsg2[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) { idx++; - if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) + if (GetLength(pkiMsg2, &idx, &length, pkiMsg2Sz) < 0) return ASN_PARSE_E; /* Skip the set */ @@ -2028,16 +2129,16 @@ int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz) } /* Get the set of signerInfos */ - if (GetSet(pkiMsg, &idx, &length, pkiMsgSz) < 0) + if (GetSet(pkiMsg2, &idx, &length, pkiMsg2Sz) < 0) return ASN_PARSE_E; if (length > 0) { /* Get the sequence of the first signerInfo */ - if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) + if (GetSequence(pkiMsg2, &idx, &length, pkiMsg2Sz) < 0) return ASN_PARSE_E; /* Get the version */ - if (GetMyVersion(pkiMsg, &idx, &version, pkiMsgSz) < 0) + if (GetMyVersion(pkiMsg2, &idx, &version, pkiMsg2Sz) < 0) return ASN_PARSE_E; if (version != 1) { @@ -2046,27 +2147,27 @@ int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz) } /* Get the sequence of IssuerAndSerialNumber */ - if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) + if (GetSequence(pkiMsg2, &idx, &length, pkiMsg2Sz) < 0) return ASN_PARSE_E; /* Skip it */ idx += length; /* Get the sequence of digestAlgorithm */ - if (GetAlgoId(pkiMsg, &idx, &hashOID, oidHashType, pkiMsgSz) < 0) { + if (GetAlgoId(pkiMsg2, &idx, &hashOID, oidHashType, pkiMsg2Sz) < 0) { return ASN_PARSE_E; } pkcs7->hashOID = (int)hashOID; /* Get the IMPLICIT[0] SET OF signedAttributes */ - if (pkiMsg[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) { + if (pkiMsg2[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) { idx++; - if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) + if (GetLength(pkiMsg2, &idx, &length, pkiMsg2Sz) < 0) return ASN_PARSE_E; /* save pointer and length */ - signedAttrib = &pkiMsg[idx]; + signedAttrib = &pkiMsg2[idx]; signedAttribSz = length; if (wc_PKCS7_ParseAttribs(pkcs7, signedAttrib, signedAttribSz) <0) { @@ -2078,7 +2179,7 @@ int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz) } /* Get digestEncryptionAlgorithm */ - if (GetAlgoId(pkiMsg, &idx, &sigOID, oidSigType, pkiMsgSz) < 0) { + if (GetAlgoId(pkiMsg2, &idx, &sigOID, oidSigType, pkiMsg2Sz) < 0) { return ASN_PARSE_E; } @@ -2090,14 +2191,14 @@ int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz) } /* Get the signature */ - if (pkiMsg[idx] == ASN_OCTET_STRING) { + if (pkiMsg2[idx] == ASN_OCTET_STRING) { idx++; - if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) + if (GetLength(pkiMsg2, &idx, &length, pkiMsg2Sz) < 0) return ASN_PARSE_E; /* save pointer and length */ - sig = &pkiMsg[idx]; + sig = &pkiMsg2[idx]; sigSz = length; idx += length; @@ -2107,7 +2208,8 @@ int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz) pkcs7->contentSz = contentSz; ret = wc_PKCS7_SignedDataVerifySignature(pkcs7, sig, sigSz, - signedAttrib, signedAttribSz); + signedAttrib, signedAttribSz, + hashBuf, hashSz); if (ret < 0) return ret; } @@ -2116,6 +2218,22 @@ int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz) } +/* variant that allows computed data hash and header/foot, + * which is useful for large data signing */ +int wc_PKCS7_VerifySignedData_ex(PKCS7* pkcs7, const byte* hashBuf, + word32 hashSz, byte* pkiMsgHead, word32 pkiMsgHeadSz, byte* pkiMsgFoot, + word32 pkiMsgFootSz) +{ + return PKCS7_VerifySignedData(pkcs7, hashBuf, hashSz, + pkiMsgHead, pkiMsgHeadSz, pkiMsgFoot, pkiMsgFootSz); +} + +int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz) +{ + return PKCS7_VerifySignedData(pkcs7, NULL, 0, pkiMsg, pkiMsgSz, NULL, 0); +} + + #ifdef HAVE_ECC /* KARI == KeyAgreeRecipientInfo (key agreement) */ @@ -2916,10 +3034,8 @@ static int wc_CreateRecipientInfo(const byte* cert, word32 certSz, byte serial[MAX_SN_SZ]; byte keyAlgArray[MAX_ALGO_SZ]; - RsaKey stack_pubKey; - RsaKey* pubKey = &stack_pubKey; - DecodedCert stack_decoded; - DecodedCert* decoded = &stack_decoded; + RsaKey pubKey[1]; + DecodedCert decoded[1]; #endif InitDecodedCert(decoded, (byte*)cert, certSz, heap); @@ -3346,7 +3462,7 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) #ifdef WOLFSSL_SMALL_STACK byte* contentKeyEnc; #else - byte contentKeyEnc[MAX_ENCRYPTED_KEY_SZ]; + byte contentKeyEnc[MAX_ENCRYPTED_KEY_SZ]; #endif byte* plain; byte* encryptedContent; @@ -3355,7 +3471,7 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) #ifdef WOLFSSL_SMALL_STACK byte* recip; #else - byte recip[MAX_RECIP_SZ]; + byte recip[MAX_RECIP_SZ]; #endif byte recipSet[MAX_SET_SZ]; @@ -3645,12 +3761,9 @@ static int wc_PKCS7_DecodeKtri(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, byte* encryptedKey; RsaKey* privKey; #else - mp_int stack_serialNum; - mp_int* serialNum = &stack_serialNum; + mp_int serialNum[1]; byte encryptedKey[MAX_ENCRYPTED_KEY_SZ]; - - RsaKey stack_privKey; - RsaKey* privKey = &stack_privKey; + RsaKey privKey[1]; #endif /* remove IssuerAndSerialNumber */ @@ -3996,11 +4109,8 @@ static int wc_PKCS7_KariGetIssuerAndSerialNumber(WC_PKCS7_KARI* kari, mp_int* serial; mp_int* recipSerial; #else - mp_int stack_serial; - mp_int* serial = &stack_serial; - - mp_int stack_recipSerial; - mp_int* recipSerial = &stack_recipSerial; + mp_int serial[1]; + mp_int recipSerial[1]; #endif /* remove IssuerAndSerialNumber */ @@ -4148,7 +4258,7 @@ static int wc_PKCS7_DecodeKari(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, #ifdef WOLFSSL_SMALL_STACK byte* encryptedKey; #else - byte encryptedKey[MAX_ENCRYPTED_KEY_SZ]; + byte encryptedKey[MAX_ENCRYPTED_KEY_SZ]; #endif WC_PKCS7_KARI* kari; @@ -4399,7 +4509,7 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg, #ifdef WOLFSSL_SMALL_STACK byte* decryptedKey; #else - byte decryptedKey[MAX_ENCRYPTED_KEY_SZ]; + byte decryptedKey[MAX_ENCRYPTED_KEY_SZ]; #endif int encryptedContentSz; byte padLen; diff --git a/wolfssl/wolfcrypt/pkcs7.h b/wolfssl/wolfcrypt/pkcs7.h index 46ef20e93..2c321dbee 100644 --- a/wolfssl/wolfcrypt/pkcs7.h +++ b/wolfssl/wolfcrypt/pkcs7.h @@ -79,9 +79,9 @@ enum Pkcs7_Misc { typedef struct PKCS7Attrib { - byte* oid; + const byte* oid; word32 oidSz; - byte* value; + const byte* value; word32 valueSz; } PKCS7Attrib; @@ -160,8 +160,14 @@ WOLFSSL_API int wc_PKCS7_EncodeData(PKCS7* pkcs7, byte* output, word32 outputSz); WOLFSSL_API int wc_PKCS7_EncodeSignedData(PKCS7* pkcs7, byte* output, word32 outputSz); +WOLFSSL_API int wc_PKCS7_EncodeSignedData_ex(PKCS7* pkcs7, const byte* hashBuf, + word32 hashSz, byte* outputHead, word32* outputHeadSz, byte* outputFoot, + word32* outputFootSz); WOLFSSL_API int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz); +WOLFSSL_API int wc_PKCS7_VerifySignedData_ex(PKCS7* pkcs7, const byte* hashBuf, + word32 hashSz, byte* pkiMsgHead, word32 pkiMsgHeadSz, byte* pkiMsgFoot, + word32 pkiMsgFootSz); WOLFSSL_API int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz); WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg,