diff --git a/tests/api.c b/tests/api.c index a22d0b9fc..b13a4cc3b 100644 --- a/tests/api.c +++ b/tests/api.c @@ -24622,6 +24622,60 @@ static void test_wc_PKCS7_SetOriDecryptCtx (void) printf(resultFmt, passed); #endif } + +static void test_wc_PKCS7_DecodeCompressedData(void) +{ +#if defined(HAVE_PKCS7) && !defined(NO_FILESYSTEM) && !defined(NO_RSA) \ + && !defined(NO_AES) && defined(HAVE_LIBZ) + PKCS7* pkcs7; + void* heap = NULL; + byte out[3072]; + byte *decompressed; + int outSz, decompressedSz; + + const char* cert = "./certs/client-cert.pem"; + byte* cert_buf = NULL; + size_t cert_sz = 0; + + printf(testingFmt, "wc_PKCS7_DecodeCompressedData()"); + + AssertIntEQ(load_file(cert, &cert_buf, &cert_sz), 0); + AssertNotNull((decompressed = + (byte*)XMALLOC(cert_sz, heap, DYNAMIC_TYPE_TMP_BUFFER))); + decompressedSz = (int)cert_sz; + AssertNotNull((pkcs7 = wc_PKCS7_New(heap, devId))); + + pkcs7->content = (byte*)cert; + pkcs7->contentSz = (word32)cert_sz; + pkcs7->contentOID = DATA; + + AssertIntGT((outSz = wc_PKCS7_EncodeCompressedData(pkcs7, out, + sizeof(out))), 0); + wc_PKCS7_Free(pkcs7); + + /* compressed key should be smaller than when started */ + AssertIntLT(outSz, cert_sz); + + /* test decompression */ + AssertNotNull((pkcs7 = wc_PKCS7_New(heap, devId))); + + /* fail case with out buffer too small */ + AssertIntLT(wc_PKCS7_DecodeCompressedData(pkcs7, out, outSz, + decompressed, outSz), 0); + + /* success case */ + AssertIntEQ(wc_PKCS7_DecodeCompressedData(pkcs7, out, outSz, + decompressed, decompressedSz), cert_sz); + AssertIntEQ(XMEMCMP(decompressed, cert, cert_sz), 0); + + if (cert_buf) + free(cert_buf); + XFREE(decompressed, heap, DYNAMIC_TYPE_TMP_BUFFER); + wc_PKCS7_Free(pkcs7); + printf(resultFmt, passed); +#endif +} + static void test_wc_i2d_PKCS12(void) { #if !defined(NO_ASN) && !defined(NO_PWDBASED) && defined(HAVE_PKCS12) \ @@ -39664,6 +39718,7 @@ void ApiTest(void) test_wc_PKCS7_NoDefaultSignedAttribs(); test_wc_PKCS7_SetOriEncryptCtx(); test_wc_PKCS7_SetOriDecryptCtx(); + test_wc_PKCS7_DecodeCompressedData(); test_wc_i2d_PKCS12(); diff --git a/wolfcrypt/src/compress.c b/wolfcrypt/src/compress.c index 28d04f02d..24397d5d3 100644 --- a/wolfcrypt/src/compress.c +++ b/wolfcrypt/src/compress.c @@ -194,5 +194,112 @@ int wc_DeCompress(byte* out, word32 outSz, const byte* in, word32 inSz) } +/* Decompress the input buffer and create output buffer. Free'ing 'out' buffer + * is the callers responsibility on successful return. + * + * out gets set to the output buffer created, *out gets overwritten + * memoryType the memory hint to use for 'out' i.e. DYNAMIC_TYPE_TMP_BUFFER + * in compressed input buffer + * inSz size of 'in' buffer + * windowBits decompression behavior flag (can be 0) + * heap hint to use when mallocing 'out' buffer + * + * return the decompressed size, creates and grows out buffer as needed + */ +int wc_DeCompressDynamic(byte** out, int memoryType, const byte* in, + word32 inSz, int windowBits, void* heap) +{ + z_stream stream; + int result = 0; + word32 tmpSz = 0; + byte* tmp; + + if (out == NULL || in == NULL) { + return BAD_FUNC_ARG; + } + + stream.next_in = (Bytef*)in; + stream.avail_in = (uInt)inSz; + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != inSz) return DECOMPRESS_INIT_E; + + tmpSz = inSz * 2; /* start with output buffer twice the size of input */ + tmp = (byte*)XMALLOC(tmpSz, heap, memoryType); + if (tmp == NULL) + return MEMORY_E; + + stream.next_out = tmp; + stream.avail_out = (uInt)tmpSz; + if ((uLong)stream.avail_out != tmpSz) return DECOMPRESS_INIT_E; + + stream.zalloc = (alloc_func)myAlloc; + stream.zfree = (free_func)myFree; + stream.opaque = (voidpf)0; + + if (inflateInit2(&stream, DEFLATE_DEFAULT_WINDOWBITS | windowBits) != Z_OK) { + return DECOMPRESS_INIT_E; + } + + /* + Wanted to use inflateGetHeader here for uncompressed size but + structure gz_headerp does not contain the ISIZE from RFC1952 + + gz_headerp header; + inflateGetHeader(&stream, &header); + */ + + /* loop through doing the decompression block by block to get full size */ + do { + result = inflate(&stream, Z_BLOCK); + if (result == Z_STREAM_END) { + /* hit end of decompression */ + break; + } + + /* good chance output buffer ran out of space with Z_BUF_ERROR + try increasing output buffer size */ + if (result == Z_BUF_ERROR) { + word32 newSz = tmpSz * 2; /* double size of tmp buffer */ + byte* newTmp; + newTmp = (byte*)XMALLOC(newSz, heap, memoryType); + if (newTmp == NULL) { + XFREE(tmp, heap, memoryType); + return MEMORY_E; + } + XMEMCPY(newTmp, tmp, tmpSz); + XFREE(tmp, heap, memoryType); + tmp = newTmp; + stream.next_out = tmp + stream.total_out; + stream.avail_out = stream.avail_out + (uInt)tmpSz; + tmpSz = newSz; + result = inflate(&stream, Z_BLOCK); + } + } while (result == Z_OK); + + if (result == Z_STREAM_END) { + result = (int)stream.total_out; + *out = (byte*)XMALLOC(result, heap, memoryType); + if (*out != NULL) { + XMEMCPY(*out, tmp, result); + } + else { + result = MEMORY_E; + } + } + else { + result = DECOMPRESS_E; + } + + if (inflateEnd(&stream) != Z_OK) + result = DECOMPRESS_E; + + if (tmp != NULL) { + XFREE(tmp, heap, memoryType); + tmp = NULL; + } + + return result; +} + #endif /* HAVE_LIBZ */ diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index ae67cf6fc..61894dc29 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -12659,17 +12659,10 @@ int wc_PKCS7_DecodeCompressedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; - /* allocate space for decompressed data */ - decompressed = (byte*)XMALLOC(length, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - if (decompressed == NULL) { - WOLFSSL_MSG("Error allocating memory for CMS decompression buffer"); - return MEMORY_E; - } - /* decompress content */ - ret = wc_DeCompress(decompressed, length, &pkiMsg[idx], length); + ret = wc_DeCompressDynamic(&decompressed, DYNAMIC_TYPE_PKCS7, + &pkiMsg[idx], length, 0, pkcs7->heap); if (ret < 0) { - XFREE(decompressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7); return ret; } decompressedSz = (word32)ret; diff --git a/wolfssl/wolfcrypt/compress.h b/wolfssl/wolfcrypt/compress.h index f324a8350..3cfaa58ae 100644 --- a/wolfssl/wolfcrypt/compress.h +++ b/wolfssl/wolfcrypt/compress.h @@ -47,6 +47,8 @@ WOLFSSL_API int wc_Compress_ex(byte* out, word32 outSz, const byte* in, WOLFSSL_API int wc_DeCompress(byte*, word32, const byte*, word32); WOLFSSL_API int wc_DeCompress_ex(byte* out, word32 outSz, const byte* in, word32 inSz, int windowBits); +WOLFSSL_API int wc_DeCompressDynamic(byte** out, int memoryType, const byte* in, + word32 inSz, int windowBits, void* heap); #ifdef __cplusplus } /* extern "C" */