Merge pull request #8674 from JacobBarthelmeh/pkcs7_stream

Fix to advance past multiple recipients
This commit is contained in:
David Garske
2025-10-06 11:27:03 -07:00
committed by GitHub
6 changed files with 145 additions and 11 deletions

View File

@@ -53,6 +53,7 @@ EXTRA_DIST += \
certs/server-revoked-key.pem \
certs/wolfssl-website-ca.pem \
certs/test-degenerate.p7b \
certs/test-multiple-recipients.p7b \
certs/test-stream-sign.p7b \
certs/test-stream-dec.p7b \
certs/test-ber-exp02-05-2022.p7b \

View File

@@ -888,6 +888,11 @@ run_renewcerts(){
openssl cms -encrypt -in ca-cert.pem -recip client-cert.pem -out test-stream-dec.p7b -outform DER -stream
check_result $? ""
echo "Creating test-multiple-recipients.p7b..."
echo ""
openssl smime -encrypt -binary -aes-256-cbc -in ./client-key.pem -out ./test-multiple-recipients.p7b -outform DER ./client-cert.pem ./server-cert.pem
check_result $? ""
echo "End of section"
echo "---------------------------------------------------------------------"

Binary file not shown.

View File

@@ -2145,6 +2145,91 @@ int test_wc_PKCS7_DecodeEnvelopedData_stream(void)
#endif
} /* END test_wc_PKCS7_DecodeEnvelopedData_stream() */
/*
* Testing wc_PKCS7_DecodeEnvelopedData with streaming
*/
int test_wc_PKCS7_DecodeEnvelopedData_multiple_recipients(void)
{
#if defined(HAVE_PKCS7)
EXPECT_DECLS;
PKCS7* pkcs7 = NULL;
int ret = 0;
XFILE f = XBADFILE;
const char* testFile = "./certs/test-multiple-recipients.p7b";
byte testDerBuffer[8192]; /* test-multiple-recipients is currently 6433
bytes */
size_t testDerBufferSz = 0;
byte decodedData[8192];
ExpectTrue((f = XFOPEN(testFile, "rb")) != XBADFILE);
testDerBufferSz = XFREAD(testDerBuffer, 1,
sizeof(testDerBuffer), f);
ExpectIntNE(testDerBufferSz, 0);
if (f != XBADFILE) {
XFCLOSE(f);
f = XBADFILE;
}
/* test with server cert recipient */
ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId));
if (pkcs7) {
ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, (byte*)server_cert_der_2048,
sizeof_server_cert_der_2048), 0);
ExpectIntEQ(wc_PKCS7_SetKey(pkcs7, (byte*)server_key_der_2048,
sizeof_server_key_der_2048), 0);
ret = wc_PKCS7_DecodeEnvelopedData(pkcs7, testDerBuffer,
(word32)testDerBufferSz, decodedData, sizeof(decodedData));
#if defined(NO_AES) || defined(NO_AES_256)
ExpectIntEQ(ret, ALGO_ID_E);
#else
ExpectIntGT(ret, 0);
#endif
wc_PKCS7_Free(pkcs7);
}
/* test with client cert recipient */
ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId));
if (pkcs7) {
ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, (byte*)client_cert_der_2048,
sizeof_client_cert_der_2048), 0);
ExpectIntEQ(wc_PKCS7_SetKey(pkcs7, (byte*)client_key_der_2048,
sizeof_client_key_der_2048), 0);
ret = wc_PKCS7_DecodeEnvelopedData(pkcs7, testDerBuffer,
(word32)testDerBufferSz, decodedData, sizeof(decodedData));
#if defined(NO_AES) || defined(NO_AES_256)
ExpectIntEQ(ret, ALGO_ID_E);
#else
ExpectIntGT(ret, 0);
#endif
wc_PKCS7_Free(pkcs7);
}
/* test with ca cert recipient (which should fail) */
ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId));
if (pkcs7) {
ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, (byte*)ca_cert_der_2048,
sizeof_ca_cert_der_2048), 0);
ExpectIntEQ(wc_PKCS7_SetKey(pkcs7, (byte*)ca_key_der_2048,
sizeof_ca_key_der_2048), 0);
ret = wc_PKCS7_DecodeEnvelopedData(pkcs7, testDerBuffer,
(word32)testDerBufferSz, decodedData, sizeof(decodedData));
ExpectIntLT(ret, 0);
wc_PKCS7_Free(pkcs7);
}
return EXPECT_RESULT();
#else
return TEST_SKIPPED;
#endif
} /* END test_wc_PKCS7_DecodeEnvelopedData_multiple_recipients() */
/*
* Testing wc_PKCS7_EncodeEnvelopedData(), wc_PKCS7_DecodeEnvelopedData()
*/

View File

@@ -47,6 +47,7 @@ int test_wc_PKCS7_NoDefaultSignedAttribs(void);
int test_wc_PKCS7_SetOriEncryptCtx(void);
int test_wc_PKCS7_SetOriDecryptCtx(void);
int test_wc_PKCS7_DecodeCompressedData(void);
int test_wc_PKCS7_DecodeEnvelopedData_multiple_recipients(void);
#define TEST_PKCS7_DECLS \
@@ -74,7 +75,8 @@ int test_wc_PKCS7_DecodeCompressedData(void);
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_DecodeSymmetricKeyPackage), \
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_DecodeOneSymmetricKey), \
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_SetOriEncryptCtx), \
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_SetOriDecryptCtx)
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_SetOriDecryptCtx), \
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_DecodeEnvelopedData_multiple_recipients)
#define TEST_PKCS7_SIGNED_ENCRYPTED_DATA_DECLS \
TEST_DECL_GROUP("pkcs7_sed", test_wc_PKCS7_signed_enveloped)

View File

@@ -106,6 +106,7 @@ struct PKCS7State {
word32 currContSz; /* size of current content */
word32 currContRmnSz; /* remaining size of current content */
word32 accumContSz; /* size of accumulated content size */
int recipientSz; /* size of recipient set */
byte tmpIv[MAX_CONTENT_IV_SIZE]; /* store IV if needed */
#ifdef WC_PKCS7_STREAM_DEBUG
word32 peakUsed; /* most bytes used for struct at any one time */
@@ -10487,6 +10488,14 @@ static int wc_PKCS7_DecryptKtri(wc_PKCS7* pkcs7, byte* in, word32 inSz,
XMEMCPY(encryptedKey, &pkiMsg[*idx], (word32)encryptedKeySz);
*idx += (word32)encryptedKeySz;
/* If this is not the correct recipient then do not try to decode
* the encrypted key */
if (*recipFound == 0) {
XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_WOLF_BIGINT);
ret = PKCS7_RECIP_E;
break;
}
/* load private key */
#ifdef WOLFSSL_SMALL_STACK
privKey = (RsaKey*)XMALLOC(sizeof(RsaKey), pkcs7->heap,
@@ -11973,8 +11982,15 @@ static int wc_PKCS7_DecryptRecipientInfos(wc_PKCS7* pkcs7, byte* in,
ret = wc_PKCS7_DecryptKtri(pkcs7, in, inSz, idx,
decryptedKey, decryptedKeySz,
recipFound);
if (ret != 0)
return ret;
if (ret != 0) {
if (ret != WC_NO_ERR_TRACE(WC_PKCS7_WANT_READ_E) &&
*recipFound == 0) {
continue; /* try next recipient */
}
else {
return ret; /* found recipient and failed decrypt */
}
}
#else
return NOT_COMPILED_IN;
#endif
@@ -12095,8 +12111,8 @@ static int wc_PKCS7_DecryptRecipientInfos(wc_PKCS7* pkcs7, byte* in,
recipFound);
if (ret != 0)
return ret;
} else {
}
else {
/* failed to find RecipientInfo, restore idx and continue */
*idx = savedIdx;
break;
@@ -12315,9 +12331,17 @@ static int wc_PKCS7_ParseToRecipientInfoSet(wc_PKCS7* pkcs7, byte* in,
#ifndef NO_PKCS7_STREAM
pkcs7->stream->expected = (word32)length;
if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) {
break;
}
/* update the stored max length */
if (pkcs7->stream->totalRd + pkcs7->stream->expected >
pkcs7->stream->maxLen) {
pkcs7->stream->maxLen = pkcs7->stream->totalRd +
pkcs7->stream->expected;
}
#endif
if (ret == 0)
@@ -12396,9 +12420,8 @@ int wc_PKCS7_DecodeEnvelopedData(wc_PKCS7* pkcs7, byte* in,
int recipFound = 0;
int ret, length = 0;
word32 idx = 0;
#ifndef NO_PKCS7_STREAM
word32 tmpIdx = 0;
#endif
word32 recipientSetSz = 0;
word32 contentType = 0, encOID = 0;
word32 decryptedKeySz = MAX_ENCRYPTED_KEY_SZ;
@@ -12457,17 +12480,21 @@ int wc_PKCS7_DecodeEnvelopedData(wc_PKCS7* pkcs7, byte* in,
if (decryptedKey == NULL)
return MEMORY_E;
wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_ENV_2);
#ifndef NO_PKCS7_STREAM
tmpIdx = idx;
recipientSetSz = (word32)ret;
#ifndef NO_PKCS7_STREAM
pkcs7->stream->aad = decryptedKey;
/* get the full recipient set */
pkcs7->stream->expected = recipientSetSz;
pkcs7->stream->recipientSz = ret;
#endif
FALL_THROUGH;
case WC_PKCS7_ENV_2:
#ifndef NO_PKCS7_STREAM
/* store up enough buffer for initial info set decode */
if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, MAX_LENGTH_SZ +
MAX_VERSION_SZ + ASN_TAG_SZ, &pkiMsg, &idx)) != 0) {
if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
pkcs7->stream->expected, &pkiMsg, &idx)) != 0) {
return ret;
}
#endif
@@ -12483,8 +12510,8 @@ int wc_PKCS7_DecodeEnvelopedData(wc_PKCS7* pkcs7, byte* in,
#ifndef NO_PKCS7_STREAM
decryptedKey = pkcs7->stream->aad;
decryptedKeySz = MAX_ENCRYPTED_KEY_SZ;
tmpIdx = idx;
#endif
ret = wc_PKCS7_DecryptRecipientInfos(pkcs7, in, inSz, &idx,
decryptedKey, &decryptedKeySz,
&recipFound);
@@ -12497,10 +12524,24 @@ int wc_PKCS7_DecodeEnvelopedData(wc_PKCS7* pkcs7, byte* in,
if (ret != 0)
break;
#ifndef NO_PKCS7_STREAM
/* advance idx past recipient info set if not all recipients
* parsed */
if (pkcs7->stream->totalRd < ((word32)pkcs7->stream->recipientSz +
tmpIdx)) {
idx = tmpIdx + (word32)pkcs7->stream->recipientSz;
/* process additional recipients as read */
if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) {
break;
}
}
tmpIdx = idx;
pkcs7->stream->aadSz = decryptedKeySz;
pkcs7->stream->expected = MAX_LENGTH_SZ + MAX_VERSION_SZ +
ASN_TAG_SZ + MAX_LENGTH_SZ;
#else
idx = tmpIdx + recipientSetSz;
#endif
wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_ENV_3);
FALL_THROUGH;