diff --git a/tests/api.c b/tests/api.c index 39fccc391..97c2cb4fc 100644 --- a/tests/api.c +++ b/tests/api.c @@ -18416,7 +18416,7 @@ static void test_wc_PKCS7_BER(void) XFILE f; byte der[4096]; #ifndef NO_DES3 - byte decoded[1024]; + byte decoded[2048]; #endif word32 derSz; int ret; diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index 3231ce661..12494d970 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -1172,6 +1172,11 @@ void wc_PKCS7_Free(PKCS7* pkcs7) pkcs7->pkcs7Digest = NULL; pkcs7->pkcs7DigestSz = 0; } + if (pkcs7->cachedEncryptedContent != NULL) { + XFREE(pkcs7->cachedEncryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + pkcs7->cachedEncryptedContent = NULL; + pkcs7->cachedEncryptedContentSz = 0; + } if (pkcs7->isDynamic) { pkcs7->isDynamic = 0; @@ -9987,6 +9992,41 @@ WOLFSSL_API int wc_PKCS7_SetKey(PKCS7* pkcs7, byte* key, word32 keySz) } +/* append data to encrypted content cache in PKCS7 structure + * return 0 on success, negative on error */ +static int PKCS7_CacheEncryptedContent(PKCS7* pkcs7, byte* in, word32 inSz) +{ + byte* oldCache; + word32 oldCacheSz; + + if (pkcs7 == NULL || in == NULL) + return BAD_FUNC_ARG; + + /* save pointer to old cache */ + oldCache = pkcs7->cachedEncryptedContent; + oldCacheSz = pkcs7->cachedEncryptedContentSz; + + /* re-allocate new buffer to fit appended data */ + pkcs7->cachedEncryptedContent = (byte*)XMALLOC(oldCacheSz + inSz, + pkcs7->heap, DYNAMIC_TYPE_PKCS7); + if (pkcs7->cachedEncryptedContent == NULL) { + pkcs7->cachedEncryptedContentSz = 0; + XFREE(oldCache, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + return MEMORY_E; + } + + if (oldCache != NULL) { + XMEMCPY(pkcs7->cachedEncryptedContent, oldCache, oldCacheSz); + } + XMEMCPY(pkcs7->cachedEncryptedContent + oldCacheSz, in, inSz); + pkcs7->cachedEncryptedContentSz += inSz; + + XFREE(oldCache, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + + return 0; +} + + /* unwrap and decrypt PKCS#7 envelopedData object, return decoded size */ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* in, word32 inSz, byte* output, @@ -10009,6 +10049,7 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* in, byte* pkiMsg = in; word32 pkiMsgSz = inSz; byte* decryptedKey = NULL; + int encryptedContentTotalSz = 0; int encryptedContentSz = 0; byte padLen; byte* encryptedContent = NULL; @@ -10223,27 +10264,51 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* in, } idx++; - if (ret == 0 && GetLength(pkiMsg, &idx, &encryptedContentSz, + if (ret == 0 && GetLength(pkiMsg, &idx, &encryptedContentTotalSz, pkiMsgSz) <= 0) { ret = ASN_PARSE_E; } if (ret == 0 && explicitOctet) { - if (GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) < 0) { - ret = ASN_PARSE_E; - break; - } + /* encrypted content may be fragmented into multiple + * consecutive OCTET STRINGs, if so loop through + * collecting and caching encrypted content bytes */ + localIdx = idx; + while (idx < (localIdx + encryptedContentTotalSz)) { - if (tag != ASN_OCTET_STRING) { - ret = ASN_PARSE_E; - break; - } + if (GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) < 0) { + ret = ASN_PARSE_E; + break; + } - if (ret == 0 && GetLength(pkiMsg, &idx, &encryptedContentSz, - pkiMsgSz) <= 0) { - ret = ASN_PARSE_E; + if (tag != ASN_OCTET_STRING) { + ret = ASN_PARSE_E; + break; + } + + if (ret == 0 && GetLength(pkiMsg, &idx, + &encryptedContentSz, pkiMsgSz) <= 0) { + ret = ASN_PARSE_E; + break; + } + + ret = PKCS7_CacheEncryptedContent(pkcs7, &pkiMsg[idx], + encryptedContentSz); + if (ret != 0) { + break; + } + + /* advance idx past encrypted content */ + idx += encryptedContentSz; + } + } else { + /* cache encrypted content, no OCTET STRING */ + ret = PKCS7_CacheEncryptedContent(pkcs7, &pkiMsg[idx], + encryptedContentTotalSz); + if (ret != 0) { break; } + idx += encryptedContentTotalSz; } if (ret != 0) @@ -10253,10 +10318,9 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* in, if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) { break; } - pkcs7->stream->expected = encryptedContentSz; + pkcs7->stream->expected = 0; wc_PKCS7_StreamGetVar(pkcs7, &encOID, &expBlockSz, 0); - wc_PKCS7_StreamStoreVar(pkcs7, encOID, expBlockSz, - encryptedContentSz); + wc_PKCS7_StreamStoreVar(pkcs7, encOID, expBlockSz, 0); #endif wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_ENV_5); FALL_THROUGH; @@ -10269,8 +10333,7 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* in, return ret; } - wc_PKCS7_StreamGetVar(pkcs7, &encOID, &expBlockSz, - &encryptedContentSz); + wc_PKCS7_StreamGetVar(pkcs7, &encOID, &expBlockSz, NULL); tmpIv = pkcs7->stream->tmpIv; /* restore decrypted key */ @@ -10280,23 +10343,16 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* in, #else ret = 0; #endif - encryptedContent = (byte*)XMALLOC(encryptedContentSz, pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - if (encryptedContent == NULL) { - ret = MEMORY_E; - break; - } - if (ret == 0) { - XMEMCPY(encryptedContent, &pkiMsg[idx], encryptedContentSz); - } + /* use cached content */ + encryptedContent = pkcs7->cachedEncryptedContent; + encryptedContentSz = pkcs7->cachedEncryptedContentSz; /* decrypt encryptedContent */ ret = wc_PKCS7_DecryptContent(pkcs7, encOID, decryptedKey, blockKeySz, tmpIv, expBlockSz, NULL, 0, NULL, 0, encryptedContent, encryptedContentSz, encryptedContent); if (ret != 0) { - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); break; } @@ -10305,7 +10361,6 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* in, /* copy plaintext to output */ if (padLen > encryptedContentSz || (word32)(encryptedContentSz - padLen) > outputSz) { - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); ret = BUFFER_E; break; } @@ -10313,9 +10368,13 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* in, /* free memory, zero out keys */ ForceZero(decryptedKey, MAX_ENCRYPTED_KEY_SZ); - ForceZero(encryptedContent, encryptedContentSz); - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + if (pkcs7->cachedEncryptedContent != NULL) { + XFREE(pkcs7->cachedEncryptedContent, pkcs7->heap, + DYNAMIC_TYPE_PKCS7); + pkcs7->cachedEncryptedContent = NULL; + pkcs7->cachedEncryptedContentSz = 0; + } ret = encryptedContentSz - padLen; #ifndef NO_PKCS7_STREAM @@ -10335,12 +10394,23 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* in, if (ret < 0 && ret != WC_PKCS7_WANT_READ_E) { wc_PKCS7_ResetStream(pkcs7); wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_START); + if (pkcs7->cachedEncryptedContent != NULL) { + XFREE(pkcs7->cachedEncryptedContent, pkcs7->heap, + DYNAMIC_TYPE_PKCS7); + pkcs7->cachedEncryptedContent = NULL; + pkcs7->cachedEncryptedContentSz = 0; + } } #else if (decryptedKey != NULL && ret < 0) { ForceZero(decryptedKey, MAX_ENCRYPTED_KEY_SZ); XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); } + if (pkcs7->cachedEncryptedContent != NULL && ret < 0) { + XFREE(pkcs7->cachedEncryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + pkcs7->cachedEncryptedContent = NULL; + pkcs7->cachedEncryptedContentSz = 0; + } #endif return ret; } diff --git a/wolfssl/wolfcrypt/pkcs7.h b/wolfssl/wolfcrypt/pkcs7.h index 840d94281..0292d1d07 100644 --- a/wolfssl/wolfcrypt/pkcs7.h +++ b/wolfssl/wolfcrypt/pkcs7.h @@ -330,6 +330,10 @@ struct PKCS7 { #if defined(HAVE_PKCS7_RSA_RAW_SIGN_CALLBACK) && !defined(NO_RSA) CallbackRsaSignRawDigest rsaSignRawDigestCb; #endif + + /* used by DecodeEnvelopedData with multiple encrypted contents */ + byte* cachedEncryptedContent; + word32 cachedEncryptedContentSz; /* !! NEW DATA MEMBERS MUST BE ADDED AT END !! */ };