From b5eb8dce2f6af56ba1d02518110272712c657ed6 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Thu, 17 Nov 2016 15:44:45 -0700 Subject: [PATCH 1/6] add PKCS#7/CMS EncryptedContent support --- wolfcrypt/src/pkcs7.c | 356 ++++++++++++++++++++++++++++++++++++++ wolfcrypt/test/test.c | 159 ++++++++++++++++- wolfssl/wolfcrypt/pkcs7.h | 15 +- 3 files changed, 521 insertions(+), 9 deletions(-) diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index b80b634ef..4449128c4 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -1982,6 +1982,362 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg, } +/* build PKCS#7 encryptedData content type, return encrypted size */ +int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, byte* output, word32 outputSz) +{ + int i, ret, idx = 0; + int totalSz, padSz, desOutSz; + + int contentInfoSeqSz, outerContentTypeSz, outerContentSz; + byte contentInfoSeq[MAX_SEQ_SZ]; + byte outerContentType[MAX_ALGO_SZ]; + byte outerContent[MAX_SEQ_SZ]; + + int encDataSeqSz, verSz; + byte encDataSeq[MAX_SEQ_SZ]; + byte ver[MAX_VERSION_SZ]; + + WC_RNG rng; + word32 blockSz, blockKeySz; + + byte* plain; + byte* encryptedContent; + + int encContentOctetSz, encContentSeqSz, contentTypeSz; + int contentEncAlgoSz, ivOctetStringSz; + byte encContentSeq[MAX_SEQ_SZ]; + byte contentType[MAX_ALGO_SZ]; + byte contentEncAlgo[MAX_ALGO_SZ]; + byte tmpIv[MAX_CONTENT_IV_SIZE]; + byte ivOctetString[MAX_OCTET_STR_SZ]; + byte encContentOctet[MAX_OCTET_STR_SZ]; + + if (pkcs7 == NULL || pkcs7->content == NULL || pkcs7->contentSz == 0 || + pkcs7->encryptOID == 0 || pkcs7->encryptionKey == NULL || + pkcs7->encryptionKeySz == 0) + return BAD_FUNC_ARG; + + if (output == NULL || outputSz == 0) + return BAD_FUNC_ARG; + + /* wolfCrypt EncryptedData supports AES-128/192/256-CBC, DES 3DES for now */ + switch (pkcs7->encryptOID) { +#ifndef NO_AES + case AES128CBCb: + blockKeySz = 16; + blockSz = AES_BLOCK_SIZE; + break; + + case AES192CBCb: + blockKeySz = 24; + blockSz = AES_BLOCK_SIZE; + break; + + case AES256CBCb: + blockKeySz = 32; + blockSz = AES_BLOCK_SIZE; + break; +#endif + case DESb: + blockKeySz = DES_KEYLEN; + blockSz = DES_BLOCK_SIZE; + break; + + case DES3b: + blockKeySz = DES3_KEYLEN; + blockSz = DES_BLOCK_SIZE; + break; + + default: + WOLFSSL_MSG("Unsupported content cipher type"); + return ALGO_ID_E; + } + + if (pkcs7->encryptionKeySz != blockKeySz) { + WOLFSSL_MSG("Encryption key wrong size for block cipher being used"); + return BAD_FUNC_ARG; + } + + /* outer content type */ + outerContentTypeSz = wc_SetContentType(ENCRYPTED_DATA, outerContentType); + + /* version, 2 if unprotectedAttrs present, 0 if absent */ + verSz = SetMyVersion(0, ver, 0); + + /* generate IV for block cipher */ + ret = wc_InitRng(&rng); + if (ret != 0) + return ret; + + ret = wc_RNG_GenerateBlock(&rng, tmpIv, blockSz); + wc_FreeRng(&rng); + if (ret != 0) + return ret; + + /* EncryptedContentInfo */ + contentTypeSz = wc_SetContentType(pkcs7->contentOID, contentType); + if (contentTypeSz == 0) + return BAD_FUNC_ARG; + + /* allocate encrypted content buffer and PKCS#7 padding */ + padSz = blockSz - (pkcs7->contentSz % blockSz); + desOutSz = pkcs7->contentSz + padSz; + + plain = (byte*)XMALLOC(desOutSz, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (plain == NULL) + return MEMORY_E; + + XMEMCPY(plain, pkcs7->content, pkcs7->contentSz); + + for (i = 0; i < padSz; i++) { + plain[pkcs7->contentSz + i] = (byte)padSz; + } + + encryptedContent = (byte*)XMALLOC(desOutSz, pkcs7->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (encryptedContent == NULL) { + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + return MEMORY_E; + } + + /* put together IV OCTET STRING */ + ivOctetStringSz = SetOctetString(blockSz, ivOctetString); + + /* build up ContentEncryptionAlgorithmIdentifier sequence, + adding (ivOctetStringSz + blockSz) for IV OCTET STRING */ + contentEncAlgoSz = SetAlgoID(pkcs7->encryptOID, contentEncAlgo, + oidBlkType, ivOctetStringSz + blockSz); + if (contentEncAlgoSz == 0) { + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + return BAD_FUNC_ARG; + } + + /* encrypt content */ + ret = wc_PKCS7_EncryptContent(pkcs7->encryptOID, pkcs7->encryptionKey, + pkcs7->encryptionKeySz, tmpIv, blockSz, plain, desOutSz, + encryptedContent); + if (ret != 0) { + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + return ret; + } + + encContentOctetSz = SetImplicit(ASN_OCTET_STRING, 0, + desOutSz, encContentOctet); + + encContentSeqSz = SetSequence(contentTypeSz + contentEncAlgoSz + + ivOctetStringSz + blockSz + + encContentOctetSz + desOutSz, encContentSeq); + + /* keep track of sizes for outer wrapper layering */ + totalSz = verSz + encContentSeqSz + contentTypeSz + contentEncAlgoSz + + ivOctetStringSz + blockSz + encContentOctetSz + desOutSz; + + /* EncryptedData */ + encDataSeqSz = SetSequence(totalSz, encDataSeq); + totalSz += encDataSeqSz; + + /* outer content */ + outerContentSz = SetExplicit(0, totalSz, outerContent); + totalSz += outerContentTypeSz; + totalSz += outerContentSz; + + /* ContentInfo */ + contentInfoSeqSz = SetSequence(totalSz, contentInfoSeq); + totalSz += contentInfoSeqSz; + + if (totalSz > (int)outputSz) { + WOLFSSL_MSG("PKCS#7 output buffer too small"); + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + return BUFFER_E; + } + + XMEMCPY(output + idx, contentInfoSeq, contentInfoSeqSz); + idx += contentInfoSeqSz; + XMEMCPY(output + idx, outerContentType, outerContentTypeSz); + idx += outerContentTypeSz; + XMEMCPY(output + idx, outerContent, outerContentSz); + idx += outerContentSz; + XMEMCPY(output + idx, encDataSeq, encDataSeqSz); + idx += encDataSeqSz; + XMEMCPY(output + idx, ver, verSz); + idx += verSz; + XMEMCPY(output + idx, encContentSeq, encContentSeqSz); + idx += encContentSeqSz; + XMEMCPY(output + idx, contentType, contentTypeSz); + idx += contentTypeSz; + XMEMCPY(output + idx, contentEncAlgo, contentEncAlgoSz); + idx += contentEncAlgoSz; + XMEMCPY(output + idx, ivOctetString, ivOctetStringSz); + idx += ivOctetStringSz; + XMEMCPY(output + idx, tmpIv, blockSz); + idx += blockSz; + XMEMCPY(output + idx, encContentOctet, encContentOctetSz); + idx += encContentOctetSz; + XMEMCPY(output + idx, encryptedContent, desOutSz); + idx += desOutSz; + + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + + return idx; +} + + +/* unwrap and decrypt PKCS#7/CMS encrypted-data object, returned decoded size */ +int wc_PKCS7_DecodeEncryptedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, + byte* output, word32 outputSz) +{ + int ret, version, length; + word32 idx = 0; + word32 contentType, encOID; + + int expBlockSz; + word32 blockKeySz; + byte tmpIv[MAX_CONTENT_IV_SIZE]; + + int encryptedContentSz; + byte padLen; + byte* encryptedContent = NULL; + + if (pkcs7 == NULL || pkcs7->encryptionKey == NULL || + pkcs7->encryptionKeySz == 0) + return BAD_FUNC_ARG; + + if (pkiMsg == NULL || pkiMsgSz == 0 || + output == NULL || outputSz == 0) + return BAD_FUNC_ARG; + + /* read past ContentInfo, verify type is encrypted-data */ + if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + if (wc_GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0) + return ASN_PARSE_E; + + if (contentType != ENCRYPTED_DATA) { + WOLFSSL_MSG("PKCS#7 input not of type EncryptedData"); + return PKCS7_OID_E; + } + + if (pkiMsg[idx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) + return ASN_PARSE_E; + + if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + /* remove EncryptedData and version */ + if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + if (GetMyVersion(pkiMsg, &idx, &version, pkiMsgSz) < 0) + return ASN_PARSE_E; + + if (version != 0) { + WOLFSSL_MSG("PKCS#7 EncryptedData needs to be of version 0"); + return ASN_VERSION_E; + } + + /* remove EncryptedContentInfo */ + if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + if (wc_GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0) + return ASN_PARSE_E; + + if (GetAlgoId(pkiMsg, &idx, &encOID, oidBlkType, pkiMsgSz) < 0) + return ASN_PARSE_E; + + /* wolfCrypt PKCS#7/CMS supports AES-128/192/256-CBC, DES, 3DES for now */ + switch (encOID) { +#ifndef NO_AES + case AES128CBCb: + blockKeySz = 16; + expBlockSz = AES_BLOCK_SIZE; + break; + + case AES192CBCb: + blockKeySz = 24; + expBlockSz = AES_BLOCK_SIZE; + break; + + case AES256CBCb: + blockKeySz = 32; + expBlockSz = AES_BLOCK_SIZE; + break; +#endif + case DESb: + blockKeySz = DES_KEYLEN; + expBlockSz = DES_BLOCK_SIZE; + break; + + case DES3b: + blockKeySz = DES3_KEYLEN; + expBlockSz = DES_BLOCK_SIZE; + break; + + default: + WOLFSSL_MSG("Unsupported content cipher type"); + return ALGO_ID_E; + }; + + if (pkcs7->encryptionKeySz != blockKeySz) { + WOLFSSL_MSG("Encryption key wrong size for block cipher being used"); + return BAD_FUNC_ARG; + } + + /* get block cipher IV, stored in OPTIONAL parameter of AlgoID */ + if (pkiMsg[idx++] != ASN_OCTET_STRING) + return ASN_PARSE_E; + + if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + if (length != expBlockSz) { + WOLFSSL_MSG("Incorrect IV length, must be of content alg block size"); + return ASN_PARSE_E; + } + + XMEMCPY(tmpIv, &pkiMsg[idx], length); + idx += length; + + /* read encryptedContent, cont[0] */ + if (pkiMsg[idx++] != (ASN_CONTEXT_SPECIFIC | 0)) + return ASN_PARSE_E; + + if (GetLength(pkiMsg, &idx, &encryptedContentSz, pkiMsgSz) < 0) + return ASN_PARSE_E; + + encryptedContent = (byte*)XMALLOC(encryptedContentSz, pkcs7->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (encryptedContent == NULL) + return MEMORY_E; + + XMEMCPY(encryptedContent, &pkiMsg[idx], encryptedContentSz); + + /* decrypt encryptedContent */ + ret = wc_PKCS7_DecryptContent(encOID, pkcs7->encryptionKey, + pkcs7->encryptionKeySz, tmpIv, expBlockSz, + encryptedContent, encryptedContentSz, + encryptedContent); + if (ret != 0) { + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + return ret; + } + + padLen = encryptedContent[encryptedContentSz-1]; + + /* copy plaintext to output */ + XMEMCPY(output, encryptedContent, encryptedContentSz - padLen); + + ForceZero(encryptedContent, encryptedContentSz); + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + + return encryptedContentSz - padLen; +} + #else /* HAVE_PKCS7 */ diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index fc0fa086e..ae93f5b91 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -238,6 +238,7 @@ int pbkdf2_test(void); #ifdef HAVE_PKCS7 int pkcs7enveloped_test(void); int pkcs7signed_test(void); + int pkcs7encrypted_test(void); #endif #if defined(WOLFSSL_CERT_EXT) && defined(WOLFSSL_TEST_CERT) int certext_test(void); @@ -707,6 +708,11 @@ int wolfcrypt_test(void* args) return err_sys("PKCS7signed test failed!\n", ret); else printf( "PKCS7signed test passed!\n"); + + if ( (ret = pkcs7encrypted_test()) != 0) + return err_sys("PKCS7encrypted test failed!\n", ret); + else + printf( "PKCS7encrypted test passed!\n"); #endif #if defined(USE_WOLFSSL_MEMORY) && defined(WOLFSSL_TRACK_MEMORY) @@ -9041,7 +9047,9 @@ typedef struct { int encryptOID; byte* privateKey; word32 privateKeySz; -} pkcs7EnvelopedVector; + byte* encryptionKey; + word32 encryptionKeySz; +} pkcs7Vector; int pkcs7enveloped_test(void) { @@ -9065,14 +9073,14 @@ int pkcs7enveloped_test(void) 0x72,0x6c,0x64 }; - pkcs7EnvelopedVector a; + pkcs7Vector a; #ifndef NO_AES - pkcs7EnvelopedVector b, c, d; - pkcs7EnvelopedVector test_pkcs7env[4]; + pkcs7Vector b, c, d; + pkcs7Vector test_pkcs7env[4]; #else - pkcs7EnvelopedVector test_pkcs7env[1]; + pkcs7Vector test_pkcs7env[1]; #endif - int times = sizeof(test_pkcs7env) / sizeof(pkcs7EnvelopedVector), i; + int times = sizeof(test_pkcs7env) / sizeof(pkcs7Vector), i; /* read client cert and key in DER format */ cert = (byte*)XMALLOC(FOURK_BUF, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); @@ -9167,7 +9175,6 @@ int pkcs7enveloped_test(void) if (envelopedSz <= 0) { XFREE(cert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); XFREE(privKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - printf("envelopedSz = %d\n", envelopedSz); return -203; } @@ -9209,6 +9216,144 @@ int pkcs7enveloped_test(void) return ret; } +int pkcs7encrypted_test(void) +{ + int ret, encryptedSz, decodedSz; + PKCS7 pkcs7; + byte encrypted[2048]; + byte decoded[2048]; + FILE* pkcs7File; + + const byte data[] = { /* Hello World */ + 0x48,0x65,0x6c,0x6c,0x6f,0x20,0x57,0x6f, + 0x72,0x6c,0x64 + }; + + byte desKey[] = { + 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef + }; + byte des3Key[] = { + 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef, + 0xfe,0xde,0xba,0x98,0x76,0x54,0x32,0x10, + 0x89,0xab,0xcd,0xef,0x01,0x23,0x45,0x67 + }; + byte aes128Key[] = { + 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08, + 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08 + }; + byte aes192Key[] = { + 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08, + 0x01,0x02,0x03,0x05,0x05,0x06,0x07,0x08, + 0x01,0x02,0x03,0x05,0x05,0x06,0x07,0x08 + }; + byte aes256Key[] = { + 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08, + 0x01,0x02,0x03,0x05,0x05,0x06,0x07,0x08, + 0x01,0x02,0x03,0x05,0x05,0x06,0x07,0x08, + 0x01,0x02,0x03,0x05,0x05,0x06,0x07,0x08 + }; + + pkcs7Vector a, b; +#ifndef NO_AES + pkcs7Vector c, d, e; + pkcs7Vector test_pkcs7enc[4]; +#else + pkcs7Vector test_pkcs7enc[1]; +#endif + int times = sizeof(test_pkcs7enc) / sizeof(pkcs7Vector), i; + + /* set up test vectors */ + a.content = data; + a.contentSz = (word32)sizeof(data); + a.contentOID = DATA; + a.encryptOID = DES3b; + a.encryptionKey = des3Key; + a.encryptionKeySz = sizeof(des3Key); + a.outFileName = "pkcs7encryptedDataDES3.der"; + + b.content = data; + b.contentSz = (word32)sizeof(data); + b.contentOID = DATA; + b.encryptOID = DESb; + b.encryptionKey = desKey; + b.encryptionKeySz = sizeof(desKey); + b.outFileName = "pkcs7encryptedDataDES.der"; + +#ifndef NO_AES + c.content = data; + c.contentSz = (word32)sizeof(data); + c.contentOID = DATA; + c.encryptOID = AES128CBCb; + c.encryptionKey = aes128Key; + c.encryptionKeySz = sizeof(aes128Key); + c.outFileName = "pkcs7encryptedDataAES128CBC.der"; + + d.content = data; + d.contentSz = (word32)sizeof(data); + d.contentOID = DATA; + d.encryptOID = AES192CBCb; + d.encryptionKey = aes192Key; + d.encryptionKeySz = sizeof(aes192Key); + d.outFileName = "pkcs7encryptedDataAES192CBC.der"; + + e.content = data; + e.contentSz = (word32)sizeof(data); + e.contentOID = DATA; + e.encryptOID = AES256CBCb; + e.encryptionKey = aes256Key; + e.encryptionKeySz = sizeof(aes256Key); + e.outFileName = "pkcs7encryptedDataAES256CBC.der"; +#endif + + test_pkcs7enc[0] = a; + test_pkcs7enc[1] = b; +#ifndef NO_AES + test_pkcs7enc[2] = c; + test_pkcs7enc[3] = d; + test_pkcs7enc[4] = e; +#endif + + for (i = 0; i < times; i++) { + pkcs7.content = (byte*)test_pkcs7enc[i].content; + pkcs7.contentSz = test_pkcs7enc[i].contentSz; + pkcs7.contentOID = test_pkcs7enc[i].contentOID; + pkcs7.encryptOID = test_pkcs7enc[i].encryptOID; + pkcs7.encryptionKey = test_pkcs7enc[i].encryptionKey; + pkcs7.encryptionKeySz = test_pkcs7enc[i].encryptionKeySz; + + /* encode encryptedData */ + encryptedSz = wc_PKCS7_EncodeEncryptedData(&pkcs7, encrypted, + sizeof(encrypted)); + if (encryptedSz <= 0) + return -203; + + /* decode encryptedData */ + decodedSz = wc_PKCS7_DecodeEncryptedData(&pkcs7, encrypted, encryptedSz, + decoded, sizeof(decoded)); + if (decodedSz <= 0) + return -204; + + /* test decode result */ + if (XMEMCMP(decoded, data, sizeof(data)) != 0) + return -205; + + /* output pkcs7 envelopedData for external testing */ + pkcs7File = fopen(test_pkcs7enc[i].outFileName, "wb"); + if (!pkcs7File) + return -206; + + ret = (int)fwrite(encrypted, encryptedSz, 1, pkcs7File); + fclose(pkcs7File); + } + + wc_PKCS7_Free(&pkcs7); + + if (ret > 0) + return 0; + + return ret; +} + int pkcs7signed_test(void) { int ret = 0; diff --git a/wolfssl/wolfcrypt/pkcs7.h b/wolfssl/wolfcrypt/pkcs7.h index 931564796..a34060268 100644 --- a/wolfssl/wolfcrypt/pkcs7.h +++ b/wolfssl/wolfcrypt/pkcs7.h @@ -103,6 +103,12 @@ typedef struct PKCS7 { PKCS7Attrib* signedAttribs; word32 signedAttribsSz; + + /* Encrypted-data Content Type */ + byte* encryptionKey; /* block cipher encryption key */ + word32 encryptionKeySz; /* size of key buffer, bytes */ + PKCS7Attrib* unprotectedAttribs; /* optional */ + word32 unprotectedAttribsSz; } PKCS7; @@ -124,7 +130,8 @@ WOLFSSL_LOCAL int wc_PKCS7_DecryptContent(int encryptOID, byte* key, int keySz, WOLFSSL_API int wc_PKCS7_InitWithCert(PKCS7* pkcs7, byte* cert, word32 certSz); WOLFSSL_API void wc_PKCS7_Free(PKCS7* pkcs7); -WOLFSSL_API int wc_PKCS7_EncodeData(PKCS7* pkcs7, byte* output, word32 outputSz); +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_VerifySignedData(PKCS7* pkcs7, @@ -134,7 +141,11 @@ WOLFSSL_API int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, byte* output, word32 outputSz); - +WOLFSSL_API int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, + byte* output, word32 outputSz); +WOLFSSL_API int wc_PKCS7_DecodeEncryptedData(PKCS7* pkcs7, byte* pkiMsg, + word32 pkiMsgSz, byte* output, + word32 outputSz); #ifdef __cplusplus } /* extern "C" */ #endif From abf18858a8058336c3f30020dc8ce75a3b4eeeea Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Fri, 18 Nov 2016 15:10:30 -0700 Subject: [PATCH 2/6] refactor PKCS#7 functionality into separate functions for Enveloped and EncryptedData --- wolfcrypt/src/pkcs7.c | 407 ++++++++++++++++++++------------------ wolfssl/wolfcrypt/pkcs7.h | 7 + 2 files changed, 225 insertions(+), 189 deletions(-) diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index 4449128c4..ef09d9bc8 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -1198,7 +1198,10 @@ int wc_PKCS7_EncryptContent(int encryptOID, byte* key, int keySz, case AES128CBCb: case AES192CBCb: case AES256CBCb: - if (ivSz != AES_BLOCK_SIZE) + if ( (encryptOID == AES128CBCb && keySz != 16 ) || + (encryptOID == AES192CBCb && keySz != 24 ) || + (encryptOID == AES256CBCb && keySz != 32 ) || + (ivSz != AES_BLOCK_SIZE) ) return BAD_FUNC_ARG; ret = wc_AesSetKey(&aes, key, keySz, iv, AES_ENCRYPTION); @@ -1258,7 +1261,10 @@ int wc_PKCS7_DecryptContent(int encryptOID, byte* key, int keySz, case AES128CBCb: case AES192CBCb: case AES256CBCb: - if (ivSz != AES_BLOCK_SIZE) + if ( (encryptOID == AES128CBCb && keySz != 16 ) || + (encryptOID == AES192CBCb && keySz != 24 ) || + (encryptOID == AES256CBCb && keySz != 32 ) || + (ivSz != AES_BLOCK_SIZE) ) return BAD_FUNC_ARG; ret = wc_AesSetKey(&aes, key, keySz, iv, AES_DECRYPTION); @@ -1296,11 +1302,144 @@ int wc_PKCS7_DecryptContent(int encryptOID, byte* key, int keySz, } +/* generate random IV, place in iv, return 0 on success negative on error */ +int wc_PKCS7_GenerateIV(WC_RNG* rng, byte* iv, word32 ivSz) +{ + int ret; + WC_RNG* random; + + if (iv == NULL || ivSz == 0) + return BAD_FUNC_ARG; + + /* input RNG is optional, init local one if input rng is NULL */ + if (rng == NULL) { + random = XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG); + if (random == NULL) + return MEMORY_E; + } else { + random = rng; + } + + ret = wc_InitRng(random); + if (ret == 0) { + ret = wc_RNG_GenerateBlock(random, iv, ivSz); + wc_FreeRng(random); + } + + if (rng == NULL) { + XFREE(random, NULL, DYNAMIC_TYPE_RNG); + } + + return ret; +} + + +/* return size of padded data, padded to blockSz chunks, or negative on error */ +int wc_PKCS7_GetPadSize(word32 inputSz, word32 blockSz) +{ + int padSz; + + if (blockSz == 0) + return BAD_FUNC_ARG; + + padSz = blockSz - (inputSz % blockSz); + + return padSz; +} + + +/* pad input data to blockSz chunk, place in outSz. out must be big enough + * for input + pad bytes. See wc_PKCS7_GetPadLength() helper. */ +int wc_PKCS7_PadData(byte* in, word32 inSz, byte* out, word32 outSz, + word32 blockSz) +{ + int i, padSz; + + if (in == NULL || inSz == 0 || + out == NULL || outSz == 0) + return BAD_FUNC_ARG; + + padSz = blockSz - (inSz % blockSz); + + if (outSz < (inSz + padSz)) + return BAD_FUNC_ARG; + + XMEMCPY(out, in, inSz); + + for (i = 0; i < padSz; i++) { + out[inSz + i] = (byte)padSz; + } + + return inSz + padSz; +} + + +int wc_PKCS7_GetOIDBlockSize(int oid) +{ + int blockSz; + + switch (oid) { +#ifndef NO_AES + case AES128CBCb: + case AES192CBCb: + case AES256CBCb: + blockSz = AES_BLOCK_SIZE; + break; +#endif + case DESb: + case DES3b: + blockSz = DES_BLOCK_SIZE; + break; + + default: + WOLFSSL_MSG("Unsupported content cipher type"); + return ALGO_ID_E; + }; + + return blockSz; +} + + +int wc_PKCS7_GetOIDKeySize(int oid) +{ + int blockKeySz; + + switch (oid) { +#ifndef NO_AES + case AES128CBCb: + blockKeySz = 16; + break; + + case AES192CBCb: + blockKeySz = 24; + break; + + case AES256CBCb: + blockKeySz = 32; + break; +#endif + case DESb: + blockKeySz = DES_KEYLEN; + break; + + case DES3b: + blockKeySz = DES3_KEYLEN; + break; + + default: + WOLFSSL_MSG("Unsupported content cipher type"); + return ALGO_ID_E; + }; + + return blockKeySz; +} + + /* build PKCS#7 envelopedData content type, return enveloped size */ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) { - int i, ret, idx = 0; - int totalSz, padSz, desOutSz; + int ret, idx = 0; + int totalSz, padSz, encryptedOutSz; int contentInfoSeqSz, outerContentTypeSz, outerContentSz; byte contentInfoSeq[MAX_SEQ_SZ]; @@ -1346,38 +1485,13 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) if (output == NULL || outputSz == 0) return BAD_FUNC_ARG; - /* wolfCrypt PKCS#7 supports AES-128/192/256-CBC, DES, 3DES for now */ - switch (pkcs7->encryptOID) { -#ifndef NO_AES - case AES128CBCb: - blockKeySz = 16; - blockSz = AES_BLOCK_SIZE; - break; + blockKeySz = wc_PKCS7_GetOIDKeySize(pkcs7->encryptOID); + if (blockKeySz < 0) + return blockKeySz; - case AES192CBCb: - blockKeySz = 24; - blockSz = AES_BLOCK_SIZE; - break; - - case AES256CBCb: - blockKeySz = 32; - blockSz = AES_BLOCK_SIZE; - break; -#endif - case DESb: - blockKeySz = DES_KEYLEN; - blockSz = DES_BLOCK_SIZE; - break; - - case DES3b: - blockKeySz = DES3_KEYLEN; - blockSz = DES_BLOCK_SIZE; - break; - - default: - WOLFSSL_MSG("Unsupported content cipher type"); - return ALGO_ID_E; - }; + blockSz = wc_PKCS7_GetOIDBlockSize(pkcs7->encryptOID); + if (blockSz < 0) + return blockSz; /* outer content type */ outerContentTypeSz = wc_SetContentType(ENVELOPED_DATA, outerContentType); @@ -1432,7 +1546,7 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) recipSetSz = SetSet(recipSz, recipSet); /* generate IV for block cipher */ - ret = wc_RNG_GenerateBlock(&rng, tmpIv, blockSz); + ret = wc_PKCS7_GenerateIV(&rng, tmpIv, blockSz); wc_FreeRng(&rng); if (ret != 0) { #ifdef WOLFSSL_SMALL_STACK @@ -1451,24 +1565,30 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) } /* allocate encrypted content buffer and PKCS#7 padding */ - padSz = blockSz - (pkcs7->contentSz % blockSz); - desOutSz = pkcs7->contentSz + padSz; + padSz = wc_PKCS7_GetPadSize(pkcs7->contentSz, blockSz); + if (padSz < 0) + return padSz; - plain = (byte*)XMALLOC(desOutSz, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + encryptedOutSz = pkcs7->contentSz + padSz; + + plain = (byte*)XMALLOC(encryptedOutSz, pkcs7->heap, + DYNAMIC_TYPE_TMP_BUFFER); if (plain == NULL) { #ifdef WOLFSSL_SMALL_STACK XFREE(recip, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return MEMORY_E; } - XMEMCPY(plain, pkcs7->content, pkcs7->contentSz); - for (i = 0; i < padSz; i++) { - plain[pkcs7->contentSz + i] = (byte)padSz; + ret = wc_PKCS7_PadData(pkcs7->content, pkcs7->contentSz, plain, + encryptedOutSz, blockSz); + if (ret < 0) { + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + return ret; } - encryptedContent = (byte*)XMALLOC(desOutSz, pkcs7->heap, - DYNAMIC_TYPE_TMP_BUFFER); + encryptedContent = (byte*)XMALLOC(encryptedOutSz, pkcs7->heap, + DYNAMIC_TYPE_TMP_BUFFER); if (encryptedContent == NULL) { XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); #ifdef WOLFSSL_SMALL_STACK @@ -1496,7 +1616,8 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) /* encrypt content */ ret = wc_PKCS7_EncryptContent(pkcs7->encryptOID, contentKeyPlain, - blockKeySz, tmpIv, blockSz, plain, desOutSz, encryptedContent); + blockKeySz, tmpIv, blockSz, plain, encryptedOutSz, + encryptedContent); if (ret != 0) { XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); @@ -1507,17 +1628,18 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) return ret; } - encContentOctetSz = SetImplicit(ASN_OCTET_STRING, 0, - desOutSz, encContentOctet); + encContentOctetSz = SetImplicit(ASN_OCTET_STRING, 0, encryptedOutSz, + encContentOctet); encContentSeqSz = SetSequence(contentTypeSz + contentEncAlgoSz + ivOctetStringSz + blockSz + - encContentOctetSz + desOutSz, encContentSeq); + encContentOctetSz + encryptedOutSz, + encContentSeq); /* keep track of sizes for outer wrapper layering */ totalSz = verSz + recipSetSz + recipSz + encContentSeqSz + contentTypeSz + contentEncAlgoSz + ivOctetStringSz + blockSz + - encContentOctetSz + desOutSz; + encContentOctetSz + encryptedOutSz; /* EnvelopedData */ envDataSeqSz = SetSequence(totalSz, envDataSeq); @@ -1568,8 +1690,8 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) idx += blockSz; XMEMCPY(output + idx, encContentOctet, encContentOctetSz); idx += encContentOctetSz; - XMEMCPY(output + idx, encryptedContent, desOutSz); - idx += desOutSz; + XMEMCPY(output + idx, encryptedContent, encryptedOutSz); + idx += encryptedOutSz; ForceZero(contentKeyPlain, MAX_CONTENT_KEY_LEN); @@ -1804,38 +1926,17 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg, return ASN_PARSE_E; } - /* wolfCrypt PKCS#7 supports AES-128-CBC, DES, 3DES for now */ - switch(encOID) { -#ifndef NO_AES - case AES128CBCb: - blockKeySz = 16; - expBlockSz = AES_BLOCK_SIZE; - break; + blockKeySz = wc_PKCS7_GetOIDKeySize(encOID); + if (blockKeySz < 0) { + XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return blockKeySz; + } - case AES192CBCb: - blockKeySz = 24; - expBlockSz = AES_BLOCK_SIZE; - break; - - case AES256CBCb: - blockKeySz = 32; - expBlockSz = AES_BLOCK_SIZE; - break; -#endif - case DESb: - blockKeySz = DES_KEYLEN; - expBlockSz = DES_BLOCK_SIZE; - break; - - case DES3b: - blockKeySz = DES3_KEYLEN; - expBlockSz = DES_BLOCK_SIZE; - break; - - default: - WOLFSSL_MSG("Unsupported content cipher type"); - return ALGO_ID_E; - }; + expBlockSz = wc_PKCS7_GetOIDBlockSize(encOID); + if (expBlockSz < 0) { + XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return expBlockSz; + } /* get block cipher IV, stored in OPTIONAL parameter of AlgoID */ if (pkiMsg[idx++] != ASN_OCTET_STRING) { @@ -1985,21 +2086,18 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg, /* build PKCS#7 encryptedData content type, return encrypted size */ int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, byte* output, word32 outputSz) { - int i, ret, idx = 0; - int totalSz, padSz, desOutSz; + int ret, idx = 0; + int totalSz, padSz, encryptedOutSz; int contentInfoSeqSz, outerContentTypeSz, outerContentSz; byte contentInfoSeq[MAX_SEQ_SZ]; byte outerContentType[MAX_ALGO_SZ]; byte outerContent[MAX_SEQ_SZ]; - int encDataSeqSz, verSz; + int encDataSeqSz, verSz, blockSz; byte encDataSeq[MAX_SEQ_SZ]; byte ver[MAX_VERSION_SZ]; - WC_RNG rng; - word32 blockSz, blockKeySz; - byte* plain; byte* encryptedContent; @@ -2020,80 +2118,41 @@ int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, byte* output, word32 outputSz) if (output == NULL || outputSz == 0) return BAD_FUNC_ARG; - /* wolfCrypt EncryptedData supports AES-128/192/256-CBC, DES 3DES for now */ - switch (pkcs7->encryptOID) { -#ifndef NO_AES - case AES128CBCb: - blockKeySz = 16; - blockSz = AES_BLOCK_SIZE; - break; - - case AES192CBCb: - blockKeySz = 24; - blockSz = AES_BLOCK_SIZE; - break; - - case AES256CBCb: - blockKeySz = 32; - blockSz = AES_BLOCK_SIZE; - break; -#endif - case DESb: - blockKeySz = DES_KEYLEN; - blockSz = DES_BLOCK_SIZE; - break; - - case DES3b: - blockKeySz = DES3_KEYLEN; - blockSz = DES_BLOCK_SIZE; - break; - - default: - WOLFSSL_MSG("Unsupported content cipher type"); - return ALGO_ID_E; - } - - if (pkcs7->encryptionKeySz != blockKeySz) { - WOLFSSL_MSG("Encryption key wrong size for block cipher being used"); - return BAD_FUNC_ARG; - } - /* outer content type */ outerContentTypeSz = wc_SetContentType(ENCRYPTED_DATA, outerContentType); /* version, 2 if unprotectedAttrs present, 0 if absent */ verSz = SetMyVersion(0, ver, 0); - /* generate IV for block cipher */ - ret = wc_InitRng(&rng); - if (ret != 0) - return ret; - - ret = wc_RNG_GenerateBlock(&rng, tmpIv, blockSz); - wc_FreeRng(&rng); - if (ret != 0) - return ret; - /* EncryptedContentInfo */ contentTypeSz = wc_SetContentType(pkcs7->contentOID, contentType); if (contentTypeSz == 0) return BAD_FUNC_ARG; - /* allocate encrypted content buffer and PKCS#7 padding */ - padSz = blockSz - (pkcs7->contentSz % blockSz); - desOutSz = pkcs7->contentSz + padSz; + /* allocate encrypted content buffer, do PKCS#7 padding */ + blockSz = wc_PKCS7_GetOIDBlockSize(pkcs7->encryptOID); + if (blockSz < 0) + return blockSz; - plain = (byte*)XMALLOC(desOutSz, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + padSz = wc_PKCS7_GetPadSize(pkcs7->contentSz, blockSz); + if (padSz < 0) + return padSz; + + encryptedOutSz = pkcs7->contentSz + padSz; + + plain = (byte*)XMALLOC(encryptedOutSz, pkcs7->heap, + DYNAMIC_TYPE_TMP_BUFFER); if (plain == NULL) return MEMORY_E; - XMEMCPY(plain, pkcs7->content, pkcs7->contentSz); - - for (i = 0; i < padSz; i++) { - plain[pkcs7->contentSz + i] = (byte)padSz; + ret = wc_PKCS7_PadData(pkcs7->content, pkcs7->contentSz, plain, + encryptedOutSz, blockSz); + if (ret < 0) { + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + return ret; } - encryptedContent = (byte*)XMALLOC(desOutSz, pkcs7->heap, + encryptedContent = (byte*)XMALLOC(encryptedOutSz, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); if (encryptedContent == NULL) { XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); @@ -2114,8 +2173,12 @@ int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, byte* output, word32 outputSz) } /* encrypt content */ + ret = wc_PKCS7_GenerateIV(NULL, tmpIv, blockSz); + if (ret != 0) + return ret; + ret = wc_PKCS7_EncryptContent(pkcs7->encryptOID, pkcs7->encryptionKey, - pkcs7->encryptionKeySz, tmpIv, blockSz, plain, desOutSz, + pkcs7->encryptionKeySz, tmpIv, blockSz, plain, encryptedOutSz, encryptedContent); if (ret != 0) { XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); @@ -2124,15 +2187,16 @@ int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, byte* output, word32 outputSz) } encContentOctetSz = SetImplicit(ASN_OCTET_STRING, 0, - desOutSz, encContentOctet); + encryptedOutSz, encContentOctet); encContentSeqSz = SetSequence(contentTypeSz + contentEncAlgoSz + ivOctetStringSz + blockSz + - encContentOctetSz + desOutSz, encContentSeq); + encContentOctetSz + encryptedOutSz, + encContentSeq); /* keep track of sizes for outer wrapper layering */ totalSz = verSz + encContentSeqSz + contentTypeSz + contentEncAlgoSz + - ivOctetStringSz + blockSz + encContentOctetSz + desOutSz; + ivOctetStringSz + blockSz + encContentOctetSz + encryptedOutSz; /* EncryptedData */ encDataSeqSz = SetSequence(totalSz, encDataSeq); @@ -2176,8 +2240,8 @@ int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, byte* output, word32 outputSz) idx += blockSz; XMEMCPY(output + idx, encContentOctet, encContentOctetSz); idx += encContentOctetSz; - XMEMCPY(output + idx, encryptedContent, desOutSz); - idx += desOutSz; + XMEMCPY(output + idx, encryptedContent, encryptedOutSz); + idx += encryptedOutSz; XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); @@ -2195,7 +2259,6 @@ int wc_PKCS7_DecodeEncryptedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, word32 contentType, encOID; int expBlockSz; - word32 blockKeySz; byte tmpIv[MAX_CONTENT_IV_SIZE]; int encryptedContentSz; @@ -2250,43 +2313,9 @@ int wc_PKCS7_DecodeEncryptedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, if (GetAlgoId(pkiMsg, &idx, &encOID, oidBlkType, pkiMsgSz) < 0) return ASN_PARSE_E; - /* wolfCrypt PKCS#7/CMS supports AES-128/192/256-CBC, DES, 3DES for now */ - switch (encOID) { -#ifndef NO_AES - case AES128CBCb: - blockKeySz = 16; - expBlockSz = AES_BLOCK_SIZE; - break; - - case AES192CBCb: - blockKeySz = 24; - expBlockSz = AES_BLOCK_SIZE; - break; - - case AES256CBCb: - blockKeySz = 32; - expBlockSz = AES_BLOCK_SIZE; - break; -#endif - case DESb: - blockKeySz = DES_KEYLEN; - expBlockSz = DES_BLOCK_SIZE; - break; - - case DES3b: - blockKeySz = DES3_KEYLEN; - expBlockSz = DES_BLOCK_SIZE; - break; - - default: - WOLFSSL_MSG("Unsupported content cipher type"); - return ALGO_ID_E; - }; - - if (pkcs7->encryptionKeySz != blockKeySz) { - WOLFSSL_MSG("Encryption key wrong size for block cipher being used"); - return BAD_FUNC_ARG; - } + expBlockSz = wc_PKCS7_GetOIDBlockSize(encOID); + if (expBlockSz < 0) + return expBlockSz; /* get block cipher IV, stored in OPTIONAL parameter of AlgoID */ if (pkiMsg[idx++] != ASN_OCTET_STRING) diff --git a/wolfssl/wolfcrypt/pkcs7.h b/wolfssl/wolfcrypt/pkcs7.h index a34060268..6fba46a1a 100644 --- a/wolfssl/wolfcrypt/pkcs7.h +++ b/wolfssl/wolfcrypt/pkcs7.h @@ -127,6 +127,13 @@ WOLFSSL_LOCAL int wc_PKCS7_EncryptContent(int encryptOID, byte* key, int keySz, WOLFSSL_LOCAL int wc_PKCS7_DecryptContent(int encryptOID, byte* key, int keySz, byte* iv, int ivSz, byte* in, int inSz, byte* out); +WOLFSSL_LOCAL int wc_PKCS7_GenerateIV(WC_RNG* rng, byte* iv, word32 ivSz); +WOLFSSL_LOCAL int wc_PKCS7_GetPadSize(word32 inputSz, word32 blockSz); +WOLFSSL_LOCAL int wc_PKCS7_PadData(byte* in, word32 inSz, byte* out, word32 outSz, + word32 blockSz); +WOLFSSL_LOCAL int wc_PKCS7_GetOIDBlockSize(int oid); +WOLFSSL_LOCAL int wc_PKCS7_GetOIDKeySize(int oid); + WOLFSSL_API int wc_PKCS7_InitWithCert(PKCS7* pkcs7, byte* cert, word32 certSz); WOLFSSL_API void wc_PKCS7_Free(PKCS7* pkcs7); From 5006306bb8bcce0706e427d81061ec087436db57 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Wed, 23 Nov 2016 15:38:27 -0700 Subject: [PATCH 3/6] PKCS#7: add support for optional unprotectedAttributes with EncryptedData --- wolfcrypt/src/pkcs7.c | 240 ++++++++++++++++++++++++++++++++++---- wolfcrypt/test/test.c | 128 +++++++++++++++++--- wolfssl/wolfcrypt/pkcs7.h | 21 +++- 3 files changed, 351 insertions(+), 38 deletions(-) diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index ef09d9bc8..be33c1d84 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -211,7 +211,10 @@ int wc_PKCS7_InitWithCert(PKCS7* pkcs7, byte* cert, word32 certSz) /* releases any memory allocated by a PKCS7 initializer */ void wc_PKCS7_Free(PKCS7* pkcs7) { - (void)pkcs7; + if (pkcs7 == NULL) + return; + + wc_PKCS7_FreeDecodedAttrib(pkcs7->decodedAttrib, pkcs7->heap); } @@ -1306,7 +1309,7 @@ int wc_PKCS7_DecryptContent(int encryptOID, byte* key, int keySz, int wc_PKCS7_GenerateIV(WC_RNG* rng, byte* iv, word32 ivSz) { int ret; - WC_RNG* random; + WC_RNG* random = NULL; if (iv == NULL || ivSz == 0) return BAD_FUNC_ARG; @@ -1316,17 +1319,19 @@ int wc_PKCS7_GenerateIV(WC_RNG* rng, byte* iv, word32 ivSz) random = XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG); if (random == NULL) return MEMORY_E; + + ret = wc_InitRng(random); + if (ret != 0) + return ret; + } else { random = rng; } - ret = wc_InitRng(random); - if (ret == 0) { - ret = wc_RNG_GenerateBlock(random, iv, ivSz); - wc_FreeRng(random); - } + ret = wc_RNG_GenerateBlock(random, iv, ivSz); if (rng == NULL) { + wc_FreeRng(random); XFREE(random, NULL, DYNAMIC_TYPE_RNG); } @@ -2098,8 +2103,8 @@ int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, byte* output, word32 outputSz) byte encDataSeq[MAX_SEQ_SZ]; byte ver[MAX_VERSION_SZ]; - byte* plain; - byte* encryptedContent; + byte* plain = NULL; + byte* encryptedContent = NULL; int encContentOctetSz, encContentSeqSz, contentTypeSz; int contentEncAlgoSz, ivOctetStringSz; @@ -2110,6 +2115,14 @@ int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, byte* output, word32 outputSz) byte ivOctetString[MAX_OCTET_STR_SZ]; byte encContentOctet[MAX_OCTET_STR_SZ]; + byte attribSet[MAX_SET_SZ]; + EncodedAttrib* attribs = NULL; + word32 attribsSz; + word32 attribsCount; + word32 attribsSetSz; + + byte* flatAttribs = NULL; + if (pkcs7 == NULL || pkcs7->content == NULL || pkcs7->contentSz == 0 || pkcs7->encryptOID == 0 || pkcs7->encryptionKey == NULL || pkcs7->encryptionKeySz == 0) @@ -2122,7 +2135,11 @@ int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, byte* output, word32 outputSz) outerContentTypeSz = wc_SetContentType(ENCRYPTED_DATA, outerContentType); /* version, 2 if unprotectedAttrs present, 0 if absent */ - verSz = SetMyVersion(0, ver, 0); + if (pkcs7->unprotectedAttribsSz > 0) { + verSz = SetMyVersion(2, ver, 0); + } else { + verSz = SetMyVersion(0, ver, 0); + } /* EncryptedContentInfo */ contentTypeSz = wc_SetContentType(pkcs7->contentOID, contentType); @@ -2194,9 +2211,49 @@ int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, byte* output, word32 outputSz) encContentOctetSz + encryptedOutSz, encContentSeq); + /* optional UnprotectedAttributes */ + if (pkcs7->unprotectedAttribsSz != 0) { + + if (pkcs7->unprotectedAttribs == NULL) { + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + return BAD_FUNC_ARG; + } + + attribs = (EncodedAttrib*)XMALLOC( + sizeof(EncodedAttrib) * pkcs7->unprotectedAttribsSz, + pkcs7->heap, DYNAMIC_TYPE_PKCS); + if (attribs == NULL) { + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + return MEMORY_E; + } + + attribsCount = pkcs7->unprotectedAttribsSz; + attribsSz = EncodeAttributes(attribs, pkcs7->unprotectedAttribsSz, + pkcs7->unprotectedAttribs, + pkcs7->unprotectedAttribsSz); + + flatAttribs = (byte*)XMALLOC(attribsSz, pkcs7->heap, DYNAMIC_TYPE_PKCS); + if (flatAttribs == NULL) { + XFREE(attribs, pkcs7->heap, DYNAMIC_TYPE_PKCS); + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + return MEMORY_E; + } + + FlattenAttributes(flatAttribs, attribs, attribsCount); + attribsSetSz = SetImplicit(ASN_SET, 1, attribsSz, attribSet); + + } else { + attribsSz = 0; + attribsSetSz = 0; + } + /* keep track of sizes for outer wrapper layering */ totalSz = verSz + encContentSeqSz + contentTypeSz + contentEncAlgoSz + - ivOctetStringSz + blockSz + encContentOctetSz + encryptedOutSz; + ivOctetStringSz + blockSz + encContentOctetSz + encryptedOutSz + + attribsSz + attribsSetSz;; /* EncryptedData */ encDataSeqSz = SetSequence(totalSz, encDataSeq); @@ -2213,6 +2270,10 @@ int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, byte* output, word32 outputSz) if (totalSz > (int)outputSz) { WOLFSSL_MSG("PKCS#7 output buffer too small"); + if (pkcs7->unprotectedAttribsSz != 0) { + XFREE(attribs, pkcs7->heap, DYNAMIC_TYPE_PKCS); + XFREE(attribs, pkcs7->heap, DYNAMIC_TYPE_PKCS); + } XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); return BUFFER_E; @@ -2243,6 +2304,15 @@ int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, byte* output, word32 outputSz) XMEMCPY(output + idx, encryptedContent, encryptedOutSz); idx += encryptedOutSz; + if (pkcs7->unprotectedAttribsSz != 0) { + XMEMCPY(output + idx, attribSet, attribsSetSz); + idx += attribsSetSz; + XMEMCPY(output + idx, flatAttribs, attribsSz); + idx += attribsSz; + XFREE(attribs, pkcs7->heap, DYNAMIC_TYPE_PKCS); + XFREE(flatAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS); + } + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); @@ -2250,11 +2320,120 @@ int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, byte* output, word32 outputSz) } -/* unwrap and decrypt PKCS#7/CMS encrypted-data object, returned decoded size */ -int wc_PKCS7_DecodeEncryptedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, - byte* output, word32 outputSz) +void wc_PKCS7_FreeDecodedAttrib(PKCS7DecodedAttrib* attrib, void* heap) { - int ret, version, length; + PKCS7DecodedAttrib* current; + + if (attrib == NULL) { + return; + } + + current = attrib; + while (current != NULL) { + PKCS7DecodedAttrib* next = current->next; + if (current->oid != NULL) { + XFREE(current->oid, heap, DYNAMIC_TYPE_PKCS7); + } + if (current->value != NULL) { + XFREE(current->value, heap, DYNAMIC_TYPE_PKCS7); + } + XFREE(current, heap, DYNAMIC_TYPE_PKCS7); + current = next; + } + + (void)heap; +} + + +/* decode and store unprotected attributes in PKCS7->decodedAttrib. Return + * 0 on success, negative on error. User must call wc_PKCS7_Free(). */ +int wc_PKCS7_DecodeUnprotectedAttributes(PKCS7* pkcs7, byte* pkiMsg, + word32 pkiMsgSz, word32* inOutIdx) +{ + int length, attribLen; + word32 oid, savedIdx, idx; + PKCS7DecodedAttrib* attrib = NULL; + + if (pkcs7 == NULL || pkiMsg == NULL || + pkiMsgSz == 0 || inOutIdx == NULL) + return BAD_FUNC_ARG; + + idx = *inOutIdx; + + if (pkiMsg[idx] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) + return ASN_PARSE_E; + idx++; + + if (GetLength(pkiMsg, &idx, &attribLen, pkiMsgSz) < 0) + return ASN_PARSE_E; + + /* loop through attributes */ + while (attribLen > 0) { + + if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + attribLen -= (length + 2); /* TAG + LENGTH + DATA */ + savedIdx = idx; + + attrib = (PKCS7DecodedAttrib*)XMALLOC(sizeof(PKCS7DecodedAttrib), + pkcs7->heap, DYNAMIC_TYPE_PKCS); + if (attrib == NULL) { + return MEMORY_E; + } + XMEMSET(attrib, 0, sizeof(PKCS7DecodedAttrib)); + + /* save attribute OID bytes and size */ + if (GetObjectId(pkiMsg, &idx, &oid, oidIgnoreType, pkiMsgSz) < 0) + return ASN_PARSE_E; + + attrib->oidSz = idx - savedIdx; + attrib->oid = (byte*)XMALLOC(attrib->oidSz, pkcs7->heap, + DYNAMIC_TYPE_PKCS); + if (attrib->oid == NULL) { + XFREE(attrib, pkcs7->heap, DYNAMIC_TYPE_PKCS); + return MEMORY_E; + } + XMEMCPY(attrib->oid, pkiMsg + savedIdx, attrib->oidSz); + + /* save attribute value bytes and size */ + if (GetSet(pkiMsg, &idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + if ((pkiMsgSz - idx) < (word32)length) + return ASN_PARSE_E; + + attrib->valueSz = (word32)length; + attrib->value = (byte*)XMALLOC(attrib->valueSz, pkcs7->heap, + DYNAMIC_TYPE_PKCS); + if (attrib->value == NULL) { + XFREE(attrib->oid, pkcs7->heap, DYNAMIC_TYPE_PKCS); + XFREE(attrib, pkcs7->heap, DYNAMIC_TYPE_PKCS); + return MEMORY_E; + } + XMEMCPY(attrib->value, pkiMsg + idx, attrib->valueSz); + idx += length; + + /* store attribute in linked list */ + if (pkcs7->decodedAttrib != NULL) { + attrib->next = pkcs7->decodedAttrib; + pkcs7->decodedAttrib = attrib; + } else { + pkcs7->decodedAttrib = attrib; + } + } + + *inOutIdx = idx; + + return 0; +} + + +/* unwrap and decrypt PKCS#7/CMS encrypted-data object, returned decoded size */ +int wc_PKCS7_DecodeEncryptedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, + byte* output, word32 outputSz) +{ + int ret, version, length, haveAttribs; word32 idx = 0; word32 contentType, encOID; @@ -2295,14 +2474,11 @@ int wc_PKCS7_DecodeEncryptedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; + /* get version, check later */ + haveAttribs = 0; if (GetMyVersion(pkiMsg, &idx, &version, pkiMsgSz) < 0) return ASN_PARSE_E; - if (version != 0) { - WOLFSSL_MSG("PKCS#7 EncryptedData needs to be of version 0"); - return ASN_VERSION_E; - } - /* remove EncryptedContentInfo */ if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; @@ -2345,6 +2521,7 @@ int wc_PKCS7_DecodeEncryptedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, return MEMORY_E; XMEMCPY(encryptedContent, &pkiMsg[idx], encryptedContentSz); + idx += encryptedContentSz; /* decrypt encryptedContent */ ret = wc_PKCS7_DecryptContent(encOID, pkcs7->encryptionKey, @@ -2361,6 +2538,29 @@ int wc_PKCS7_DecodeEncryptedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, /* copy plaintext to output */ XMEMCPY(output, encryptedContent, encryptedContentSz - padLen); + /* get implicit[1] unprotected attributes, optional */ + if (idx < pkiMsgSz) { + + haveAttribs = 1; + pkcs7->decodedAttrib = NULL; + + ret = wc_PKCS7_DecodeUnprotectedAttributes(pkcs7, pkiMsg, + pkiMsgSz, &idx); + if (ret != 0) { + printf("DEBUG: DecodeUnprotectedAttributes failed!\n"); + ForceZero(encryptedContent, encryptedContentSz); + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + return ASN_PARSE_E; + } + } + + /* go back and check the version now that attribs have been processed */ + if ((haveAttribs == 0 && version != 0) || + (haveAttribs == 1 && version != 2) ) { + WOLFSSL_MSG("Wrong PKCS#7 EncryptedData version"); + return ASN_VERSION_E; + } + ForceZero(encryptedContent, encryptedContentSz); XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index ae93f5b91..ab444ef2d 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -9041,14 +9041,16 @@ int compress_test(void) typedef struct { const char* outFileName; - const byte* content; - word32 contentSz; - int contentOID; - int encryptOID; - byte* privateKey; - word32 privateKeySz; - byte* encryptionKey; - word32 encryptionKeySz; + const byte* content; + word32 contentSz; + int contentOID; + int encryptOID; + byte* privateKey; + word32 privateKeySz; + byte* encryptionKey; + word32 encryptionKeySz; + PKCS7Attrib* attribs; + word32 attribsSz; } pkcs7Vector; int pkcs7enveloped_test(void) @@ -9224,6 +9226,9 @@ int pkcs7encrypted_test(void) byte decoded[2048]; FILE* pkcs7File; + PKCS7Attrib* expectedAttrib; + PKCS7DecodedAttrib* decodedAttrib; + const byte data[] = { /* Hello World */ 0x48,0x65,0x6c,0x6c,0x6f,0x20,0x57,0x6f, 0x72,0x6c,0x64 @@ -9248,19 +9253,52 @@ int pkcs7encrypted_test(void) }; byte aes256Key[] = { 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08, - 0x01,0x02,0x03,0x05,0x05,0x06,0x07,0x08, - 0x01,0x02,0x03,0x05,0x05,0x06,0x07,0x08, - 0x01,0x02,0x03,0x05,0x05,0x06,0x07,0x08 + 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08, + 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08, + 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08 + }; + + /* Attribute example from RFC 4134, Section 7.2 + * OID = 1.2.5555 + * OCTET STRING = 'This is a test General ASN Attribute, number 1.' */ + static byte genAttrOid[] = { 0x06, 0x03, 0x2a, 0xab, 0x33 }; + static byte genAttr[] = { 0x04, 47, + 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, + 0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x47, + 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x20, 0x41, + 0x53, 0x4e, 0x20, 0x41, 0x74, 0x74, 0x72, 0x69, + 0x62, 0x75, 0x74, 0x65, 0x2c, 0x20, 0x6e, 0x75, + 0x6d, 0x62, 0x65, 0x72, 0x20, 0x31, 0x2e }; + + static byte genAttrOid2[] = { 0x06, 0x03, 0x2a, 0xab, 0x34 }; + static byte genAttr2[] = { 0x04, 47, + 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, + 0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x47, + 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x20, 0x41, + 0x53, 0x4e, 0x20, 0x41, 0x74, 0x74, 0x72, 0x69, + 0x62, 0x75, 0x74, 0x65, 0x2c, 0x20, 0x6e, 0x75, + 0x6d, 0x62, 0x65, 0x72, 0x20, 0x32, 0x2e }; + + PKCS7Attrib attribs[] = + { + { genAttrOid, sizeof(genAttrOid), genAttr, sizeof(genAttr) } + }; + + PKCS7Attrib multiAttribs[] = + { + { genAttrOid, sizeof(genAttrOid), genAttr, sizeof(genAttr) }, + { genAttrOid2, sizeof(genAttrOid2), genAttr2, sizeof(genAttr2) } }; pkcs7Vector a, b; #ifndef NO_AES - pkcs7Vector c, d, e; - pkcs7Vector test_pkcs7enc[4]; + pkcs7Vector c, d, e, f, g; + pkcs7Vector test_pkcs7enc[7]; #else pkcs7Vector test_pkcs7enc[1]; #endif - int times = sizeof(test_pkcs7enc) / sizeof(pkcs7Vector), i; + int times = sizeof(test_pkcs7enc) / sizeof(pkcs7Vector); + int i, attribIdx; /* set up test vectors */ a.content = data; @@ -9270,6 +9308,8 @@ int pkcs7encrypted_test(void) a.encryptionKey = des3Key; a.encryptionKeySz = sizeof(des3Key); a.outFileName = "pkcs7encryptedDataDES3.der"; + a.attribs = NULL; + a.attribsSz = 0; b.content = data; b.contentSz = (word32)sizeof(data); @@ -9278,6 +9318,8 @@ int pkcs7encrypted_test(void) b.encryptionKey = desKey; b.encryptionKeySz = sizeof(desKey); b.outFileName = "pkcs7encryptedDataDES.der"; + b.attribs = NULL; + b.attribsSz = 0; #ifndef NO_AES c.content = data; @@ -9287,6 +9329,8 @@ int pkcs7encrypted_test(void) c.encryptionKey = aes128Key; c.encryptionKeySz = sizeof(aes128Key); c.outFileName = "pkcs7encryptedDataAES128CBC.der"; + c.attribs = NULL; + c.attribsSz = 0; d.content = data; d.contentSz = (word32)sizeof(data); @@ -9295,6 +9339,8 @@ int pkcs7encrypted_test(void) d.encryptionKey = aes192Key; d.encryptionKeySz = sizeof(aes192Key); d.outFileName = "pkcs7encryptedDataAES192CBC.der"; + d.attribs = NULL; + d.attribsSz = 0; e.content = data; e.contentSz = (word32)sizeof(data); @@ -9303,6 +9349,28 @@ int pkcs7encrypted_test(void) e.encryptionKey = aes256Key; e.encryptionKeySz = sizeof(aes256Key); e.outFileName = "pkcs7encryptedDataAES256CBC.der"; + e.attribs = NULL; + e.attribsSz = 0; + + f.content = data; + f.contentSz = (word32)sizeof(data); + f.contentOID = DATA; + f.encryptOID = AES256CBCb; + f.encryptionKey = aes256Key; + f.encryptionKeySz = sizeof(aes256Key); + f.outFileName = "pkcs7encryptedDataAES256CBC_attribs.der"; + f.attribs = attribs; + f.attribsSz = sizeof(attribs)/sizeof(PKCS7Attrib); + + g.content = data; + g.contentSz = (word32)sizeof(data); + g.contentOID = DATA; + g.encryptOID = AES256CBCb; + g.encryptionKey = aes256Key; + g.encryptionKeySz = sizeof(aes256Key); + g.outFileName = "pkcs7encryptedDataAES256CBC_multi_attribs.der"; + g.attribs = multiAttribs; + g.attribsSz = sizeof(multiAttribs)/sizeof(PKCS7Attrib); #endif test_pkcs7enc[0] = a; @@ -9311,6 +9379,8 @@ int pkcs7encrypted_test(void) test_pkcs7enc[2] = c; test_pkcs7enc[3] = d; test_pkcs7enc[4] = e; + test_pkcs7enc[5] = f; + test_pkcs7enc[6] = g; #endif for (i = 0; i < times; i++) { @@ -9320,6 +9390,8 @@ int pkcs7encrypted_test(void) pkcs7.encryptOID = test_pkcs7enc[i].encryptOID; pkcs7.encryptionKey = test_pkcs7enc[i].encryptionKey; pkcs7.encryptionKeySz = test_pkcs7enc[i].encryptionKeySz; + pkcs7.unprotectedAttribs = test_pkcs7enc[i].attribs; + pkcs7.unprotectedAttribsSz = test_pkcs7enc[i].attribsSz; /* encode encryptedData */ encryptedSz = wc_PKCS7_EncodeEncryptedData(&pkcs7, encrypted, @@ -9337,10 +9409,36 @@ int pkcs7encrypted_test(void) if (XMEMCMP(decoded, data, sizeof(data)) != 0) return -205; + /* verify decoded unprotected attributes */ + if (pkcs7.decodedAttrib != NULL) { + decodedAttrib = pkcs7.decodedAttrib; + attribIdx = 1; + + while (decodedAttrib != NULL) { + + /* expected attribute, stored list is reversed */ + expectedAttrib = &(pkcs7.unprotectedAttribs + [pkcs7.unprotectedAttribsSz - attribIdx]); + + /* verify oid */ + if (XMEMCMP(decodedAttrib->oid, expectedAttrib->oid, + decodedAttrib->oidSz) != 0) + return -206; + + /* verify value */ + if (XMEMCMP(decodedAttrib->value, expectedAttrib->value, + decodedAttrib->valueSz) != 0) + return -207; + + decodedAttrib = decodedAttrib->next; + attribIdx++; + } + } + /* output pkcs7 envelopedData for external testing */ pkcs7File = fopen(test_pkcs7enc[i].outFileName, "wb"); if (!pkcs7File) - return -206; + return -208; ret = (int)fwrite(encrypted, encryptedSz, 1, pkcs7File); fclose(pkcs7File); diff --git a/wolfssl/wolfcrypt/pkcs7.h b/wolfssl/wolfcrypt/pkcs7.h index 6fba46a1a..357b24ea7 100644 --- a/wolfssl/wolfcrypt/pkcs7.h +++ b/wolfssl/wolfcrypt/pkcs7.h @@ -78,6 +78,15 @@ typedef struct PKCS7Attrib { } PKCS7Attrib; +typedef struct PKCS7DecodedAttrib { + byte* oid; + word32 oidSz; + byte* value; + word32 valueSz; + struct PKCS7DecodedAttrib* next; +} PKCS7DecodedAttrib; + + typedef struct PKCS7 { byte* content; /* inner content, not owner */ word32 contentSz; /* content size */ @@ -105,10 +114,11 @@ typedef struct PKCS7 { word32 signedAttribsSz; /* Encrypted-data Content Type */ - byte* encryptionKey; /* block cipher encryption key */ - word32 encryptionKeySz; /* size of key buffer, bytes */ + byte* encryptionKey; /* block cipher encryption key */ + word32 encryptionKeySz; /* size of key buffer, bytes */ PKCS7Attrib* unprotectedAttribs; /* optional */ - word32 unprotectedAttribsSz; + word32 unprotectedAttribsSz; + PKCS7DecodedAttrib* decodedAttrib; /* linked list of decoded attribs */ } PKCS7; @@ -133,6 +143,11 @@ WOLFSSL_LOCAL int wc_PKCS7_PadData(byte* in, word32 inSz, byte* out, word32 outS word32 blockSz); WOLFSSL_LOCAL int wc_PKCS7_GetOIDBlockSize(int oid); WOLFSSL_LOCAL int wc_PKCS7_GetOIDKeySize(int oid); +WOLFSSL_LOCAL int wc_PKCS7_DecodeUnprotectedAttributes(PKCS7* pkcs7, + byte* pkiMsg, word32 pkiMsgSz, + word32* inOutIdx); +WOLFSSL_LOCAL void wc_PKCS7_FreeDecodedAttrib(PKCS7DecodedAttrib* attrib, + void* heap); WOLFSSL_API int wc_PKCS7_InitWithCert(PKCS7* pkcs7, byte* cert, word32 certSz); From dad0cfda92ec15ddbfede240359ea01af7e4132f Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Fri, 9 Dec 2016 17:22:09 -0700 Subject: [PATCH 4/6] add EnvelopedData ECC support, refactor pkcs7 --- Makefile.am | 12 + configure.ac | 10 + wolfcrypt/src/asn.c | 56 + wolfcrypt/src/pkcs7.c | 1912 +++++++++++++++++++++++++++------- wolfcrypt/test/test.c | 519 ++++----- wolfssl/wolfcrypt/asn.h | 18 + wolfssl/wolfcrypt/pkcs7.h | 36 +- wolfssl/wolfcrypt/settings.h | 9 + wolfssl/wolfcrypt/types.h | 3 +- 9 files changed, 1921 insertions(+), 654 deletions(-) diff --git a/Makefile.am b/Makefile.am index 09e1e7219..3ad41c388 100644 --- a/Makefile.am +++ b/Makefile.am @@ -38,6 +38,18 @@ CLEANFILES+= cert.der \ othercert.der \ othercert.pem \ pkcs7cert.der \ + pkcs7encryptedDataAES128CBC.der \ + pkcs7encryptedDataAES192CBC.der \ + pkcs7encryptedDataAES256CBC_attribs.der \ + pkcs7encryptedDataAES256CBC.der \ + pkcs7encryptedDataAES256CBC_multi_attribs.der \ + pkcs7encryptedDataDES3.der \ + pkcs7encryptedDataDES.der \ + pkcs7envelopedDataAES256CBC_ECDH.der \ + pkcs7envelopedDataAES128CBC_ECDH_SHA1KDF.der \ + pkcs7envelopedDataAES256CBC_ECDH_SHA256KDF.der \ + pkcs7envelopedDataAES256CBC_ECDH_SHA512KDF.der \ + pkcs7envelopedDataAES256CBC_ECDH_SHA512KDF_ukm.der \ pkcs7envelopedDataDES3.der \ pkcs7envelopedDataAES128CBC.der \ pkcs7envelopedDataAES192CBC.der \ diff --git a/configure.ac b/configure.ac index 227ed80af..c524b7d3d 100644 --- a/configure.ac +++ b/configure.ac @@ -3011,6 +3011,16 @@ if test "x$ENABLED_PKCS7" = "xyes" then AM_CFLAGS="$AM_CFLAGS -DHAVE_PKCS7" # Enable prereqs if not already enabled + if test "x$ENABLED_AESKEYWRAP" = "xno" + then + ENABLED_AESKEYWRAP="yes" + AM_CFLAGS="$AM_CFLAGS -DHAVE_AES_KEYWRAP -DWOLFSSL_AES_DIRECT" + fi + if test "x$ENABLED_X963KDF" = "xno" + then + ENABLED_X963KDF="yes" + AM_CFLAGS="$AM_CFLAGS -DHAVE_X963_KDF" + fi AS_IF([test "x$ENABLED_DES3" = "xno"], [ENABLED_DES3=yes]) fi diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 28e3cb02a..d5b99a0b0 100755 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -802,6 +802,19 @@ static const byte blkAes256CbcOid[] = {96, 134, 72, 1, 101, 3, 4, 1, 42}; static const byte blkDesCbcOid[] = {43, 14, 3, 2, 7}; static const byte blkDes3CbcOid[] = {42, 134, 72, 134, 247, 13, 3, 7}; +/* keyWrapType */ +static const byte wrapAes128Oid[] = {96, 134, 72, 1, 101, 3, 4, 1, 5}; +static const byte wrapAes192Oid[] = {96, 134, 72, 1, 101, 3, 4, 1, 25}; +static const byte wrapAes256Oid[] = {96, 134, 72, 1, 101, 3, 4, 1, 45}; + +/* cmsKeyAgreeType */ +static const byte dhSinglePass_stdDH_sha1kdf_Oid[] = + {43, 129, 5, 16, 134, 72, 63, 0, 2}; +static const byte dhSinglePass_stdDH_sha224kdf_Oid[] = {43, 129, 4, 1, 11, 0}; +static const byte dhSinglePass_stdDH_sha256kdf_Oid[] = {43, 129, 4, 1, 11, 1}; +static const byte dhSinglePass_stdDH_sha384kdf_Oid[] = {43, 129, 4, 1, 11, 2}; +static const byte dhSinglePass_stdDH_sha512kdf_Oid[] = {43, 129, 4, 1, 11, 3}; + /* ocspType */ #ifdef HAVE_OCSP static const byte ocspBasicOid[] = {43, 6, 1, 5, 5, 7, 48, 1, 1}; @@ -1124,6 +1137,7 @@ static const byte* OidFromId(word32 id, word32 type, word32* oidSz) *oidSz = sizeof(extExtKeyUsageOcspSignOid); break; } + break; case oidKdfType: switch (id) { @@ -1134,6 +1148,48 @@ static const byte* OidFromId(word32 id, word32 type, word32* oidSz) } break; + case oidKeyWrapType: + switch (id) { + case AES128_WRAP: + oid = wrapAes128Oid; + *oidSz = sizeof(wrapAes128Oid); + break; + case AES192_WRAP: + oid = wrapAes192Oid; + *oidSz = sizeof(wrapAes192Oid); + break; + case AES256_WRAP: + oid = wrapAes256Oid; + *oidSz = sizeof(wrapAes256Oid); + break; + } + break; + + case oidCmsKeyAgreeType: + switch (id) { + case dhSinglePass_stdDH_sha1kdf_scheme: + oid = dhSinglePass_stdDH_sha1kdf_Oid; + *oidSz = sizeof(dhSinglePass_stdDH_sha1kdf_Oid); + break; + case dhSinglePass_stdDH_sha224kdf_scheme: + oid = dhSinglePass_stdDH_sha224kdf_Oid; + *oidSz = sizeof(dhSinglePass_stdDH_sha224kdf_Oid); + break; + case dhSinglePass_stdDH_sha256kdf_scheme: + oid = dhSinglePass_stdDH_sha256kdf_Oid; + *oidSz = sizeof(dhSinglePass_stdDH_sha256kdf_Oid); + break; + case dhSinglePass_stdDH_sha384kdf_scheme: + oid = dhSinglePass_stdDH_sha384kdf_Oid; + *oidSz = sizeof(dhSinglePass_stdDH_sha384kdf_Oid); + break; + case dhSinglePass_stdDH_sha512kdf_scheme: + oid = dhSinglePass_stdDH_sha512kdf_Oid; + *oidSz = sizeof(dhSinglePass_stdDH_sha512kdf_Oid); + break; + } + break; + case oidIgnoreType: default: break; diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index be33c1d84..0e534a5a8 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -49,9 +49,16 @@ #endif /* WOLFSSL_HAVE_MIN */ +/* direction for processing, encoding or decoding */ +typedef enum { + WC_PKCS7_ENCODE, + WC_PKCS7_DECODE +} pkcs7Direction; + + /* placed ASN.1 contentType OID into *output, return idx on success, * 0 upon failure */ -WOLFSSL_LOCAL int wc_SetContentType(int pkcs7TypeOID, byte* output) +static int wc_SetContentType(int pkcs7TypeOID, byte* output) { /* PKCS#7 content types, RFC 2315, section 14 */ const byte pkcs7[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, @@ -123,13 +130,12 @@ WOLFSSL_LOCAL int wc_SetContentType(int pkcs7TypeOID, byte* output) idx += typeSz; return idx; - } /* get ASN.1 contentType OID sum, return 0 on success, <0 on failure */ -int wc_GetContentType(const byte* input, word32* inOutIdx, word32* oid, - word32 maxIdx) +static int wc_GetContentType(const byte* input, word32* inOutIdx, word32* oid, + word32 maxIdx) { WOLFSSL_ENTER("wc_GetContentType"); if (GetObjectId(input, inOutIdx, oid, oidIgnoreType, maxIdx) < 0) @@ -139,14 +145,71 @@ int wc_GetContentType(const byte* input, word32* inOutIdx, word32* oid, } -int wc_PKCS7_SetHeap(PKCS7* pkcs7, void* heap) +/* return block size for algorithm represented by oid, or <0 on error */ +static int wc_PKCS7_GetOIDBlockSize(int oid) { - if (pkcs7 == NULL) { - return BAD_FUNC_ARG; - } - pkcs7->heap = heap; + int blockSz; - return 0; + switch (oid) { +#ifndef NO_AES + case AES128CBCb: + case AES192CBCb: + case AES256CBCb: + blockSz = AES_BLOCK_SIZE; + break; +#endif +#ifndef NO_DES3 + case DESb: + case DES3b: + blockSz = DES_BLOCK_SIZE; + break; +#endif + default: + WOLFSSL_MSG("Unsupported content cipher type"); + return ALGO_ID_E; + }; + + return blockSz; +} + + +/* get key size for algorithm represented by oid, or <0 on error */ +static int wc_PKCS7_GetOIDKeySize(int oid) +{ + int blockKeySz; + + switch (oid) { +#ifndef NO_AES + case AES128CBCb: + case AES128_WRAP: + blockKeySz = 16; + break; + + case AES192CBCb: + case AES192_WRAP: + blockKeySz = 24; + break; + + case AES256CBCb: + case AES256_WRAP: + blockKeySz = 32; + break; +#endif +#ifndef NO_DES3 + case DESb: + blockKeySz = DES_KEYLEN; + break; + + case DES3b: + blockKeySz = DES3_KEYLEN; + break; +#endif + default: + WOLFSSL_MSG("Unsupported content cipher type"); + return ALGO_ID_E; + }; + + return blockKeySz; } @@ -169,7 +232,7 @@ int wc_PKCS7_InitWithCert(PKCS7* pkcs7, byte* cert, word32 certSz) DecodedCert* dCert; dCert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, - DYNAMIC_TYPE_TMP_BUFFER); + DYNAMIC_TYPE_PKCS7); if (dCert == NULL) return MEMORY_E; #else @@ -185,13 +248,14 @@ int wc_PKCS7_InitWithCert(PKCS7* pkcs7, byte* cert, word32 certSz) if (ret < 0) { FreeDecodedCert(dCert); #ifdef WOLFSSL_SMALL_STACK - XFREE(dCert, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(dCert, NULL, DYNAMIC_TYPE_PKCS7); #endif return ret; } XMEMCPY(pkcs7->publicKey, dCert->publicKey, dCert->pubKeySize); pkcs7->publicKeySz = dCert->pubKeySize; + pkcs7->publicKeyOID = dCert->keyOID; XMEMCPY(pkcs7->issuerHash, dCert->issuerHash, KEYID_SIZE); pkcs7->issuer = dCert->issuerRaw; pkcs7->issuerSz = dCert->issuerRawLen; @@ -200,7 +264,7 @@ int wc_PKCS7_InitWithCert(PKCS7* pkcs7, byte* cert, word32 certSz) FreeDecodedCert(dCert); #ifdef WOLFSSL_SMALL_STACK - XFREE(dCert, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(dCert, NULL, DYNAMIC_TYPE_PKCS7); #endif } @@ -208,6 +272,32 @@ int wc_PKCS7_InitWithCert(PKCS7* pkcs7, byte* cert, word32 certSz) } +/* free linked list of PKCS7DecodedAttrib structs */ +static void wc_PKCS7_FreeDecodedAttrib(PKCS7DecodedAttrib* attrib, void* heap) +{ + PKCS7DecodedAttrib* current; + + if (attrib == NULL) { + return; + } + + current = attrib; + while (current != NULL) { + PKCS7DecodedAttrib* next = current->next; + if (current->oid != NULL) { + XFREE(current->oid, heap, DYNAMIC_TYPE_PKCS7); + } + if (current->value != NULL) { + XFREE(current->value, heap, DYNAMIC_TYPE_PKCS7); + } + XFREE(current, heap, DYNAMIC_TYPE_PKCS7); + current = next; + } + + (void)heap; +} + + /* releases any memory allocated by a PKCS7 initializer */ void wc_PKCS7_Free(PKCS7* pkcs7) { @@ -959,12 +1049,706 @@ int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz) } +/* KARI == KeyAgreeRecipientInfo (key agreement) */ +typedef struct WC_PKCS7_KARI { + DecodedCert* decoded; /* decoded recip cert */ + ecc_key* recipKey; /* recip key (pub | priv) */ + ecc_key* senderKey; /* sender key (pub | priv) */ + byte* senderKeyExport; /* sender ephemeral key DER */ + word32 senderKeyExportSz; /* size of sender ephemeral key DER */ + byte* kek; /* key encryption key */ + word32 kekSz; /* size of key encryption key */ + byte* ukm; /* OPTIONAL user keying material */ + word32 ukmSz; /* size of user keying material */ + byte ukmOwner; /* do we own ukm buffer? 1:yes, 0:no */ + byte* sharedInfo; /* ECC-CMS-SharedInfo ASN.1 encoded blob */ + word32 sharedInfoSz; /* size of ECC-CMS-SharedInfo encoded */ + byte direction; /* WC_PKCS7_ENCODE | WC_PKCS7_DECODE */ + void* heap; /* user heap, points to PKCS7->heap */ +} WC_PKCS7_KARI; + + +/* wrap CEK (content encryption key) with KEK, 0 on success, < 0 on error */ +static int wc_PKCS7_KariKeyWrap(byte* cek, word32 cekSz, byte* kek, + word32 kekSz, byte* out, word32 outSz, + int keyWrapAlgo, int direction) +{ + int ret; + + if (cek == NULL || kek == NULL || out == NULL) + return BAD_FUNC_ARG; + + switch (keyWrapAlgo) { + case AES128_WRAP: + case AES192_WRAP: + case AES256_WRAP: + + if (direction == AES_ENCRYPTION) { + + ret = wc_AesKeyWrap(kek, kekSz, cek, cekSz, + out, outSz, NULL); + + } else if (direction == AES_DECRYPTION) { + + ret = wc_AesKeyUnWrap(kek, kekSz, cek, cekSz, + out, outSz, NULL); + } else { + WOLFSSL_MSG("Bad key un/wrap direction"); + return BAD_FUNC_ARG; + } + + if (ret <= 0) + return ret; + + break; + + default: + WOLFSSL_MSG("Unsupported key wrap algorithm"); + return BAD_FUNC_ARG; + }; + + return ret; +} + + +/* allocate and create new WC_PKCS7_KARI struct, + * returns struct pointer on success, NULL on failure */ +static WC_PKCS7_KARI* wc_PKCS7_KariNew(PKCS7* pkcs7, byte direction) +{ + WC_PKCS7_KARI* kari = NULL; + + if (pkcs7 == NULL) + return NULL; + + kari = (WC_PKCS7_KARI*)XMALLOC(sizeof(WC_PKCS7_KARI), pkcs7->heap, + DYNAMIC_TYPE_PKCS7); + if (kari == NULL) { + WOLFSSL_MSG("Failed to allocate WC_PKCS7_KARI"); + return NULL; + } + + kari->decoded = (DecodedCert*)XMALLOC(sizeof(DecodedCert), pkcs7->heap, + DYNAMIC_TYPE_PKCS7); + if (kari->decoded == NULL) { + WOLFSSL_MSG("Failed to allocate DecodedCert"); + XFREE(kari, heap, DYNAMIC_TYPE_PKCS7); + return NULL; + } + + kari->recipKey = (ecc_key*)XMALLOC(sizeof(ecc_key), pkcs7->heap, + DYNAMIC_TYPE_PKCS7); + if (kari->recipKey == NULL) { + WOLFSSL_MSG("Failed to allocate recipient ecc_key"); + XFREE(kari->decoded, heap, DYNAMIC_TYPE_PKCS7); + XFREE(kari, heap, DYNAMIC_TYPE_PKCS7); + return NULL; + } + + kari->senderKey = (ecc_key*)XMALLOC(sizeof(ecc_key), pkcs7->heap, + DYNAMIC_TYPE_PKCS7); + if (kari->senderKey == NULL) { + WOLFSSL_MSG("Failed to allocate sender ecc_key"); + XFREE(kari->recipKey, heap, DYNAMIC_TYPE_PKCS7); + XFREE(kari->decoded, heap, DYNAMIC_TYPE_PKCS7); + XFREE(kari, heap, DYNAMIC_TYPE_PKCS7); + return NULL; + } + + kari->senderKeyExport = NULL; + kari->senderKeyExportSz = 0; + kari->kek = NULL; + kari->kekSz = 0; + kari->ukm = NULL; + kari->ukmSz = 0; + kari->ukmOwner = 0; + kari->sharedInfo = NULL; + kari->sharedInfoSz = 0; + kari->direction = direction; + + kari->heap = pkcs7->heap; + + return kari; +} + + +/* free WC_PKCS7_KARI struct, return 0 on success */ +static int wc_PKCS7_KariFree(WC_PKCS7_KARI* kari) +{ + void* heap; + + if (kari) { + heap = kari->heap; + + if (kari->decoded) { + FreeDecodedCert(kari->decoded); + XFREE(kari->decoded, heap, DYNAMIC_TYPE_PKCS7); + } + if (kari->senderKey) { + wc_ecc_free(kari->senderKey); + XFREE(kari->senderKey, heap, DYNAMIC_TYPE_PKCS7); + } + if (kari->recipKey) { + wc_ecc_free(kari->recipKey); + XFREE(kari->recipKey, heap, DYNAMIC_TYPE_PKCS7); + } + if (kari->senderKeyExport) { + ForceZero(kari->senderKeyExport, kari->senderKeyExportSz); + XFREE(kari->senderKeyExport, heap, DYNAMIC_TYPE_PKCS7); + kari->senderKeyExportSz = 0; + } + if (kari->kek) { + ForceZero(kari->kek, kari->kekSz); + XFREE(kari->kek, heap, DYNAMIC_TYPE_PKCS7); + kari->kekSz = 0; + } + if (kari->ukm) { + if (kari->ukmOwner == 1) { + XFREE(kari->ukm, heap, DYNAMIC_TYPE_PKCS7); + } + kari->ukmSz = 0; + } + if (kari->sharedInfo) { + ForceZero(kari->sharedInfo, kari->sharedInfoSz); + XFREE(kari->sharedInfo, heap, DYNAMIC_TYPE_PKCS7); + kari->sharedInfoSz = 0; + } + XFREE(kari, heap, DYNAMIC_TYPE_PKCS7); + } + + (void)heap; + + return 0; +} + + +/* parse recipient cert/key, return 0 on success, negative on error + * key/keySz only needed during decoding (WC_PKCS7_DECODE) */ +static int wc_PKCS7_KariParseRecipCert(WC_PKCS7_KARI* kari, const byte* cert, + word32 certSz, const byte* key, + word32 keySz) +{ + int ret; + word32 idx; + + if (kari == NULL || kari->decoded == NULL || + cert == NULL || certSz == 0) + return BAD_FUNC_ARG; + + if (kari->direction == WC_PKCS7_DECODE && + (key == NULL || keySz == 0)) + return BAD_FUNC_ARG; + + /* decode certificate */ + InitDecodedCert(kari->decoded, (byte*)cert, certSz, kari->heap); + ret = ParseCert(kari->decoded, CA_TYPE, NO_VERIFY, 0); + if (ret < 0) + return ret; + + /* make sure subject key id was read from cert */ + if (kari->decoded->extSubjKeyIdSet == 0) { + WOLFSSL_MSG("Failed to read subject key ID from recipient cert"); + return BAD_FUNC_ARG; + } + + ret = wc_ecc_init(kari->recipKey); + if (ret != 0) + return ret; + + /* get recip public key */ + if (kari->direction == WC_PKCS7_ENCODE) { + + ret = wc_ecc_import_x963(kari->decoded->publicKey, + kari->decoded->pubKeySize, + kari->recipKey); + } + /* get recip private key */ + else if (kari->direction == WC_PKCS7_DECODE) { + + idx = 0; + ret = wc_EccPrivateKeyDecode(key, &idx, kari->recipKey, keySz); + if (ret != 0) + return ret; + + } else { + /* bad direction */ + return BAD_FUNC_ARG; + } + + if (ret != 0) + return ret; + + (void)idx; + + return 0; +} + + +/* create ephemeral ECC key, places ecc_key in kari->senderKey, + * DER encoded in kari->senderKeyExport. return 0 on success, + * negative on error */ +static int wc_PKCS7_KariGenerateEphemeralKey(WC_PKCS7_KARI* kari, RNG* rng) +{ + int ret; + + if (kari == NULL || kari->decoded == NULL || + kari->recipKey == NULL || kari->recipKey->dp == NULL || + rng == NULL) + return BAD_FUNC_ARG; + + kari->senderKeyExport = (byte*)XMALLOC(kari->decoded->pubKeySize, kari->heap, + DYNAMIC_TYPE_PKCS7); + if (kari->senderKeyExport == NULL) + return MEMORY_E; + + kari->senderKeyExportSz = kari->decoded->pubKeySize; + + ret = wc_ecc_init(kari->senderKey); + if (ret != 0) + return ret; + + ret = wc_ecc_make_key_ex(rng, kari->recipKey->dp->size, + kari->senderKey, kari->recipKey->dp->id); + if (ret != 0) + return ret; + + /* dump generated key to X.963 DER for output in CMS bundle */ + ret = wc_ecc_export_x963(kari->senderKey, kari->senderKeyExport, + &kari->senderKeyExportSz); + if (ret != 0) + return ret; + + return 0; +} + + +/* create ASN.1 encoded ECC-CMS-SharedInfo using specified key wrap algorithm, + * place in kari->sharedInfo. returns 0 on success, negative on error */ +static int wc_PKCS7_KariGenerateSharedInfo(WC_PKCS7_KARI* kari, int keyWrapOID) +{ + int idx = 0; + int sharedInfoSeqSz = 0; + int keyInfoSz = 0; + int suppPubInfoSeqSz = 0; + int entityUInfoOctetSz = 0; + int kekOctetSz = 0; + int sharedInfoSz = 0; + + word32 kekBitSz = 0; + + byte sharedInfoSeq[MAX_SEQ_SZ]; + byte keyInfo[MAX_ALGO_SZ]; + byte suppPubInfoSeq[MAX_SEQ_SZ]; + byte entityUInfoOctet[MAX_OCTET_STR_SZ]; + byte kekOctet[MAX_OCTET_STR_SZ]; + + if (kari == NULL) + return BAD_FUNC_ARG; + + if ((kari->ukmSz > 0) && (kari->ukm == NULL)) + return BAD_FUNC_ARG; + + /* kekOctet */ + kekOctetSz = SetOctetString(sizeof(word32), kekOctet); + sharedInfoSz += (kekOctetSz + sizeof(word32)); + + /* suppPubInfo */ + suppPubInfoSeqSz = SetImplicit(ASN_SEQUENCE, 2, + kekOctetSz + sizeof(word32), + suppPubInfoSeq); + sharedInfoSz += suppPubInfoSeqSz; + + /* optional ukm/entityInfo */ + if (kari->ukmSz > 0) { + entityUInfoOctetSz = SetOctetString(kari->ukmSz, entityUInfoOctet); + sharedInfoSz += (entityUInfoOctetSz + kari->ukmSz); + } + + /* keyInfo */ + keyInfoSz = SetAlgoID(keyWrapOID, keyInfo, oidKeyWrapType, 0); + sharedInfoSz += keyInfoSz; + + /* sharedInfo */ + sharedInfoSeqSz = SetSequence(sharedInfoSz, sharedInfoSeq); + sharedInfoSz += sharedInfoSeqSz; + + kari->sharedInfo = (byte*)XMALLOC(sharedInfoSz, kari->heap, + DYNAMIC_TYPE_PKCS7); + if (kari->sharedInfo == NULL) + return MEMORY_E; + + kari->sharedInfoSz = sharedInfoSz; + + XMEMCPY(kari->sharedInfo + idx, sharedInfoSeq, sharedInfoSeqSz); + idx += sharedInfoSeqSz; + XMEMCPY(kari->sharedInfo + idx, keyInfo, keyInfoSz); + idx += keyInfoSz; + if (kari->ukmSz > 0) { + XMEMCPY(kari->sharedInfo + idx, entityUInfoOctet, entityUInfoOctetSz); + idx += entityUInfoOctetSz; + XMEMCPY(kari->sharedInfo + idx, kari->ukm, kari->ukmSz); + idx += kari->ukmSz; + } + XMEMCPY(kari->sharedInfo + idx, suppPubInfoSeq, suppPubInfoSeqSz); + idx += suppPubInfoSeqSz; + XMEMCPY(kari->sharedInfo + idx, kekOctet, kekOctetSz); + idx += kekOctetSz; + + kekBitSz = (kari->kekSz) * 8; /* convert to bits */ +#ifdef LITTLE_ENDIAN_ORDER + kekBitSz = ByteReverseWord32(kekBitSz); /* network byte order */ +#endif + XMEMCPY(kari->sharedInfo + idx, &kekBitSz, sizeof(kekBitSz)); + + return 0; +} + + +/* create key encryption key (KEK) using key wrap algorithm and key encryption + * algorithm, place in kari->kek. return 0 on success, <0 on error. */ +static int wc_PKCS7_KariGenerateKEK(WC_PKCS7_KARI* kari, + int keyWrapOID, int keyEncOID) +{ + int ret; + int kSz, kdfType; + byte* secret; + word32 secretSz; + + if (kari == NULL || kari->recipKey == NULL || + kari->senderKey == NULL || kari->senderKey->dp == NULL) + return BAD_FUNC_ARG; + + /* get KEK size, allocate buff */ + kSz = wc_PKCS7_GetOIDKeySize(keyWrapOID); + if (kSz < 0) + return kSz; + + kari->kek = (byte*)XMALLOC(kSz, kari->heap, DYNAMIC_TYPE_PKCS7); + if (kari->kek == NULL) + return MEMORY_E; + + kari->kekSz = (word32)kSz; + + /* generate ECC-CMS-SharedInfo */ + ret = wc_PKCS7_KariGenerateSharedInfo(kari, keyWrapOID); + if (ret != 0) + return ret; + + /* generate shared secret */ + secretSz = kari->senderKey->dp->size; + secret = (byte*)XMALLOC(secretSz, kari->heap, DYNAMIC_TYPE_PKCS7); + if (secret == NULL) + return MEMORY_E; + + if (kari->direction == WC_PKCS7_ENCODE) { + + ret = wc_ecc_shared_secret(kari->senderKey, kari->recipKey, + secret, &secretSz); + + } else if (kari->direction == WC_PKCS7_DECODE) { + + ret = wc_ecc_shared_secret(kari->recipKey, kari->senderKey, + secret, &secretSz); + + } else { + /* bad direction */ + return BAD_FUNC_ARG; + } + + if (ret != 0) { + XFREE(secret, kari->heap, DYNAMIC_TYPE_PKCS7); + return ret; + } + + /* run through KDF */ + switch (keyEncOID) { + + #ifndef NO_SHA + case dhSinglePass_stdDH_sha1kdf_scheme: + kdfType = WC_HASH_TYPE_SHA; + break; + #endif + #ifndef WOLF_SHA224 + case dhSinglePass_stdDH_sha224kdf_scheme: + kdfType = WC_HASH_TYPE_SHA224; + break; + #endif + #ifndef NO_SHA256 + case dhSinglePass_stdDH_sha256kdf_scheme: + kdfType = WC_HASH_TYPE_SHA256; + break; + #endif + #ifdef WOLFSSL_SHA384 + case dhSinglePass_stdDH_sha384kdf_scheme: + kdfType = WC_HASH_TYPE_SHA384; + break; + #endif + #ifdef WOLFSSL_SHA512 + case dhSinglePass_stdDH_sha512kdf_scheme: + kdfType = WC_HASH_TYPE_SHA512; + break; + #endif + default: + WOLFSSL_MSG("Unsupported key agreement algorithm"); + XFREE(secret, kari->heap, DYNAMIC_TYPE_PKCS7); + return BAD_FUNC_ARG; + }; + + ret = wc_X963_KDF(kdfType, secret, secretSz, kari->sharedInfo, + kari->sharedInfoSz, kari->kek, kari->kekSz); + if (ret != 0) { + XFREE(secret, kari->heap, DYNAMIC_TYPE_PKCS7); + return ret; + } + + XFREE(secret, kari->heap, DYNAMIC_TYPE_PKCS7); + + return 0; +} + + +/* create ASN.1 formatted KeyAgreeRecipientInfo (kari) for use with ECDH, + * return sequence size or negative on error */ +static int wc_CreateKeyAgreeRecipientInfo(PKCS7* pkcs7, const byte* cert, + word32 certSz, int keyAgreeAlgo, int blockKeySz, + int keyWrapAlgo, int keyEncAlgo, WC_RNG* rng, + byte* contentKeyPlain, byte* contentKeyEnc, + int* keyEncSz, byte* out, word32 outSz) +{ + int ret = 0, idx = 0; + int keySz; + + /* ASN.1 layout */ + int totalSz = 0; + int kariSeqSz = 0; + byte kariSeq[MAX_SEQ_SZ]; /* IMPLICIT [1] */ + int verSz = 0; + byte ver[MAX_VERSION_SZ]; + + int origIdOrKeySeqSz = 0; + byte origIdOrKeySeq[MAX_SEQ_SZ]; /* IMPLICIT [0] */ + int origPubKeySeqSz = 0; + byte origPubKeySeq[MAX_SEQ_SZ]; /* IMPLICIT [1] */ + int origAlgIdSz = 0; + byte origAlgId[MAX_ALGO_SZ]; + int origPubKeyStrSz = 0; + byte origPubKeyStr[MAX_OCTET_STR_SZ]; + + /* optional user keying material */ + int ukmOctetSz = 0; + byte ukmOctetStr[MAX_OCTET_STR_SZ]; + int ukmExplicitSz = 0; + byte ukmExplicitSeq[MAX_SEQ_SZ]; + + int keyEncryptAlgoIdSz = 0; + byte keyEncryptAlgoId[MAX_ALGO_SZ]; + int keyWrapAlgSz = 0; + byte keyWrapAlg[MAX_ALGO_SZ]; + + int recipEncKeysSeqSz = 0; + byte recipEncKeysSeq[MAX_SEQ_SZ]; + int recipEncKeySeqSz = 0; + byte recipEncKeySeq[MAX_SEQ_SZ]; + int recipKeyIdSeqSz = 0; + byte recipKeyIdSeq[MAX_SEQ_SZ]; /* IMPLICIT [0] */ + int subjKeyIdOctetSz = 0; + byte subjKeyIdOctet[MAX_OCTET_STR_SZ]; + int encryptedKeyOctetSz = 0; + byte encryptedKeyOctet[MAX_OCTET_STR_SZ]; + + WC_PKCS7_KARI* kari; + + /* only supports ECDSA for now */ + if (keyAgreeAlgo != ECDSAk) + return BAD_FUNC_ARG; + + kari = wc_PKCS7_KariNew(pkcs7, WC_PKCS7_ENCODE); + if (kari == NULL) + return MEMORY_E; + + /* set user keying material if available */ + if ((pkcs7->ukmSz > 0) && (pkcs7->ukm != NULL)) { + kari->ukm = pkcs7->ukm; + kari->ukmSz = pkcs7->ukmSz; + kari->ukmOwner = 0; + } + + /* parse recipient cert, get public key */ + ret = wc_PKCS7_KariParseRecipCert(kari, cert, certSz, NULL, 0); + if (ret != 0) { + wc_PKCS7_KariFree(kari); + return ret; + } + + /* generate sender ephemeral ECC key */ + ret = wc_PKCS7_KariGenerateEphemeralKey(kari, rng); + if (ret != 0) { + wc_PKCS7_KariFree(kari); + return ret; + } + + /* generate KEK (key encryption key) */ + ret = wc_PKCS7_KariGenerateKEK(kari, keyWrapAlgo, keyEncAlgo); + if (ret != 0) { + wc_PKCS7_KariFree(kari); + return ret; + } + + /* encrypt CEK with KEK */ + keySz = wc_PKCS7_KariKeyWrap(contentKeyPlain, blockKeySz, kari->kek, + kari->kekSz, contentKeyEnc, *keyEncSz, keyWrapAlgo, + AES_ENCRYPTION); + if (keySz <= 0) { + wc_PKCS7_KariFree(kari); + return ret; + } + *keyEncSz = (word32)keySz; + + /* Start of RecipientEncryptedKeys */ + + /* EncryptedKey */ + encryptedKeyOctetSz = SetOctetString(*keyEncSz, encryptedKeyOctet); + totalSz += (encryptedKeyOctetSz + *keyEncSz); + + /* SubjectKeyIdentifier */ + subjKeyIdOctetSz = SetOctetString(KEYID_SIZE, subjKeyIdOctet); + totalSz += (subjKeyIdOctetSz + KEYID_SIZE); + + /* RecipientKeyIdentifier IMPLICIT [0] */ + recipKeyIdSeqSz = SetImplicit(ASN_SEQUENCE, 0, subjKeyIdOctetSz + + KEYID_SIZE, recipKeyIdSeq); + totalSz += recipKeyIdSeqSz; + + /* RecipientEncryptedKey */ + recipEncKeySeqSz = SetSequence(totalSz, recipEncKeySeq); + totalSz += recipEncKeySeqSz; + + /* RecipientEncryptedKeys */ + recipEncKeysSeqSz = SetSequence(totalSz, recipEncKeysSeq); + totalSz += recipEncKeysSeqSz; + + /* Start of optional UserKeyingMaterial */ + + if (kari->ukmSz > 0) { + ukmOctetSz = SetOctetString(kari->ukmSz, ukmOctetStr); + totalSz += (ukmOctetSz + kari->ukmSz); + + ukmExplicitSz = SetExplicit(1, ukmOctetSz + kari->ukmSz, + ukmExplicitSeq); + totalSz += ukmExplicitSz; + } + + /* Start of KeyEncryptionAlgorithmIdentifier */ + + /* KeyWrapAlgorithm */ + keyWrapAlgSz = SetAlgoID(keyWrapAlgo, keyWrapAlg, oidKeyWrapType, 0); + totalSz += keyWrapAlgSz; + + /* KeyEncryptionAlgorithmIdentifier */ + keyEncryptAlgoIdSz = SetAlgoID(keyEncAlgo, keyEncryptAlgoId, + oidCmsKeyAgreeType, keyWrapAlgSz); + totalSz += keyEncryptAlgoIdSz; + + /* Start of OriginatorIdentifierOrKey */ + + /* recipient ECPoint, public key */ + XMEMSET(origPubKeyStr, 0, sizeof(origPubKeyStr)); /* no unused bits */ + origPubKeyStr[0] = ASN_BIT_STRING; + origPubKeyStrSz = SetLength(kari->senderKeyExportSz + 1, + origPubKeyStr + 1) + 2; + totalSz += (origPubKeyStrSz + kari->senderKeyExportSz); + + /* Originator AlgorithmIdentifier */ + origAlgIdSz = SetAlgoID(ECDSAk, origAlgId, oidKeyType, 0); + totalSz += origAlgIdSz; + + /* outer OriginatorPublicKey IMPLICIT [1] */ + origPubKeySeqSz = SetImplicit(ASN_SEQUENCE, 1, + origAlgIdSz + origPubKeyStrSz + + kari->senderKeyExportSz, origPubKeySeq); + totalSz += origPubKeySeqSz; + + /* outer OriginatorIdentiferOrKey IMPLICIT [0] */ + origIdOrKeySeqSz = SetImplicit(ASN_SEQUENCE, 0, + origPubKeySeqSz + origAlgIdSz + + origPubKeyStrSz + kari->senderKeyExportSz, + origIdOrKeySeq); + totalSz += origIdOrKeySeqSz; + + /* version, always 3 */ + verSz = SetMyVersion(3, ver, 0); + totalSz += verSz; + + /* outer IMPLICIT [1] kari */ + kariSeqSz = SetImplicit(ASN_SEQUENCE, 1, totalSz, kariSeq); + totalSz += kariSeqSz; + + if ((word32)totalSz > outSz) { + WOLFSSL_MSG("KeyAgreeRecipientInfo output buffer too small"); + wc_PKCS7_KariFree(kari); + + return BUFFER_E; + } + + XMEMCPY(out + idx, kariSeq, kariSeqSz); + idx += kariSeqSz; + XMEMCPY(out + idx, ver, verSz); + idx += verSz; + + XMEMCPY(out + idx, origIdOrKeySeq, origIdOrKeySeqSz); + idx += origIdOrKeySeqSz; + XMEMCPY(out + idx, origPubKeySeq, origPubKeySeqSz); + idx += origPubKeySeqSz; + XMEMCPY(out + idx, origAlgId, origAlgIdSz); + idx += origAlgIdSz; + XMEMCPY(out + idx, origPubKeyStr, origPubKeyStrSz); + idx += origPubKeyStrSz; + /* ephemeral public key */ + XMEMCPY(out + idx, kari->senderKeyExport, kari->senderKeyExportSz); + idx += kari->senderKeyExportSz; + + if (kari->ukmSz > 0) { + XMEMCPY(out + idx, ukmExplicitSeq, ukmExplicitSz); + idx += ukmExplicitSz; + XMEMCPY(out + idx, ukmOctetStr, ukmOctetSz); + idx += ukmOctetSz; + XMEMCPY(out + idx, kari->ukm, kari->ukmSz); + idx += kari->ukmSz; + } + + XMEMCPY(out + idx, keyEncryptAlgoId, keyEncryptAlgoIdSz); + idx += keyEncryptAlgoIdSz; + XMEMCPY(out + idx, keyWrapAlg, keyWrapAlgSz); + idx += keyWrapAlgSz; + + XMEMCPY(out + idx, recipEncKeysSeq, recipEncKeysSeqSz); + idx += recipEncKeysSeqSz; + XMEMCPY(out + idx, recipEncKeySeq, recipEncKeySeqSz); + idx += recipEncKeySeqSz; + XMEMCPY(out + idx, recipKeyIdSeq, recipKeyIdSeqSz); + idx += recipKeyIdSeqSz; + XMEMCPY(out + idx, subjKeyIdOctet, subjKeyIdOctetSz); + idx += subjKeyIdOctetSz; + /* subject key id */ + XMEMCPY(out + idx, kari->decoded->extSubjKeyId, KEYID_SIZE); + idx += KEYID_SIZE; + XMEMCPY(out + idx, encryptedKeyOctet, encryptedKeyOctetSz); + idx += encryptedKeyOctetSz; + /* encrypted CEK */ + XMEMCPY(out + idx, contentKeyEnc, *keyEncSz); + idx += *keyEncSz; + + wc_PKCS7_KariFree(kari); + + return idx; +} + + /* create ASN.1 formatted RecipientInfo structure, returns sequence size */ -WOLFSSL_LOCAL int wc_CreateRecipientInfo(const byte* cert, word32 certSz, - int keyEncAlgo, int blockKeySz, - WC_RNG* rng, byte* contentKeyPlain, - byte* contentKeyEnc, int* keyEncSz, - byte* out, word32 outSz, void* heap) +static int wc_CreateRecipientInfo(const byte* cert, word32 certSz, + int keyEncAlgo, int blockKeySz, + WC_RNG* rng, byte* contentKeyPlain, + byte* contentKeyEnc, int* keyEncSz, + byte* out, word32 outSz, void* heap) { word32 idx = 0; int ret = 0, totalSz = 0; @@ -981,7 +1765,7 @@ WOLFSSL_LOCAL int wc_CreateRecipientInfo(const byte* cert, word32 certSz, #ifdef WOLFSSL_SMALL_STACK byte *serial; byte *keyAlgArray; - + RsaKey* pubKey; DecodedCert* decoded; @@ -996,11 +1780,11 @@ WOLFSSL_LOCAL int wc_CreateRecipientInfo(const byte* cert, word32 certSz, if (decoded) XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER); return MEMORY_E; } - + #else byte serial[MAX_SN_SZ]; byte keyAlgArray[MAX_ALGO_SZ]; - + RsaKey stack_pubKey; RsaKey* pubKey = &stack_pubKey; DecodedCert stack_decoded; @@ -1180,9 +1964,10 @@ WOLFSSL_LOCAL int wc_CreateRecipientInfo(const byte* cert, word32 certSz, } -int wc_PKCS7_EncryptContent(int encryptOID, byte* key, int keySz, - byte* iv, int ivSz, byte* in, int inSz, - byte* out) +/* encrypt content using encryptOID algo */ +static int wc_PKCS7_EncryptContent(int encryptOID, byte* key, int keySz, + byte* iv, int ivSz, byte* in, int inSz, + byte* out) { int ret; #ifndef NO_AES @@ -1243,9 +2028,10 @@ int wc_PKCS7_EncryptContent(int encryptOID, byte* key, int keySz, } -int wc_PKCS7_DecryptContent(int encryptOID, byte* key, int keySz, - byte* iv, int ivSz, byte* in, int inSz, - byte* out) +/* decrypt content using encryptOID algo */ +static int wc_PKCS7_DecryptContent(int encryptOID, byte* key, int keySz, + byte* iv, int ivSz, byte* in, int inSz, + byte* out) { int ret; #ifndef NO_AES @@ -1306,7 +2092,7 @@ int wc_PKCS7_DecryptContent(int encryptOID, byte* key, int keySz, /* generate random IV, place in iv, return 0 on success negative on error */ -int wc_PKCS7_GenerateIV(WC_RNG* rng, byte* iv, word32 ivSz) +static int wc_PKCS7_GenerateIV(WC_RNG* rng, byte* iv, word32 ivSz) { int ret; WC_RNG* random = NULL; @@ -1340,7 +2126,7 @@ int wc_PKCS7_GenerateIV(WC_RNG* rng, byte* iv, word32 ivSz) /* return size of padded data, padded to blockSz chunks, or negative on error */ -int wc_PKCS7_GetPadSize(word32 inputSz, word32 blockSz) +static int wc_PKCS7_GetPadSize(word32 inputSz, word32 blockSz) { int padSz; @@ -1355,8 +2141,8 @@ int wc_PKCS7_GetPadSize(word32 inputSz, word32 blockSz) /* pad input data to blockSz chunk, place in outSz. out must be big enough * for input + pad bytes. See wc_PKCS7_GetPadLength() helper. */ -int wc_PKCS7_PadData(byte* in, word32 inSz, byte* out, word32 outSz, - word32 blockSz) +static int wc_PKCS7_PadData(byte* in, word32 inSz, byte* out, word32 outSz, + word32 blockSz) { int i, padSz; @@ -1379,67 +2165,6 @@ int wc_PKCS7_PadData(byte* in, word32 inSz, byte* out, word32 outSz, } -int wc_PKCS7_GetOIDBlockSize(int oid) -{ - int blockSz; - - switch (oid) { -#ifndef NO_AES - case AES128CBCb: - case AES192CBCb: - case AES256CBCb: - blockSz = AES_BLOCK_SIZE; - break; -#endif - case DESb: - case DES3b: - blockSz = DES_BLOCK_SIZE; - break; - - default: - WOLFSSL_MSG("Unsupported content cipher type"); - return ALGO_ID_E; - }; - - return blockSz; -} - - -int wc_PKCS7_GetOIDKeySize(int oid) -{ - int blockKeySz; - - switch (oid) { -#ifndef NO_AES - case AES128CBCb: - blockKeySz = 16; - break; - - case AES192CBCb: - blockKeySz = 24; - break; - - case AES256CBCb: - blockKeySz = 32; - break; -#endif - case DESb: - blockKeySz = DES_KEYLEN; - break; - - case DES3b: - blockKeySz = DES3_KEYLEN; - break; - - default: - WOLFSSL_MSG("Unsupported content cipher type"); - return ALGO_ID_E; - }; - - return blockKeySz; -} - - /* build PKCS#7 envelopedData content type, return enveloped size */ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) { @@ -1484,7 +2209,8 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) byte encContentOctet[MAX_OCTET_STR_SZ]; if (pkcs7 == NULL || pkcs7->content == NULL || pkcs7->contentSz == 0 || - pkcs7->encryptOID == 0 || pkcs7->singleCert == NULL) + pkcs7->encryptOID == 0 || pkcs7->singleCert == NULL || + pkcs7->publicKeyOID == 0) return BAD_FUNC_ARG; if (output == NULL || outputSz == 0) @@ -1494,7 +2220,7 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) if (blockKeySz < 0) return blockKeySz; - blockSz = wc_PKCS7_GetOIDBlockSize(pkcs7->encryptOID); + blockSz = wc_PKCS7_GetOIDBlockSize(pkcs7->encryptOID); if (blockSz < 0) return blockSz; @@ -1502,7 +2228,11 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) outerContentTypeSz = wc_SetContentType(ENVELOPED_DATA, outerContentType); /* version, defined as 0 in RFC 2315 */ - verSz = SetMyVersion(0, ver, 0); + if (pkcs7->publicKeyOID == ECDSAk) { + verSz = SetMyVersion(2, ver, 0); + } else { + verSz = SetMyVersion(0, ver, 0); + } /* generate random content encryption key */ ret = wc_InitRng(&rng); @@ -1516,35 +2246,56 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) } #ifdef WOLFSSL_SMALL_STACK - recip = (byte*)XMALLOC(MAX_RECIP_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER); - contentKeyEnc = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ, NULL, - DYNAMIC_TYPE_TMP_BUFFER); + recip = (byte*)XMALLOC(MAX_RECIP_SZ, NULL, DYNAMIC_TYPE_PKCS7); + contentKeyEnc = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ, NULL, + DYNAMIC_TYPE_PKCS7); if (contentKeyEnc == NULL || recip == NULL) { - if (recip) XFREE(recip, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (contentKeyEnc) XFREE(contentKeyEnc, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (recip) XFREE(recip, NULL, DYNAMIC_TYPE_PKCS7); + if (contentKeyEnc) XFREE(contentKeyEnc, NULL, DYNAMIC_TYPE_PKCS7); wc_FreeRng(&rng); return MEMORY_E; } - #endif + contentKeyEncSz = MAX_ENCRYPTED_KEY_SZ; /* build RecipientInfo, only handle 1 for now */ - recipSz = wc_CreateRecipientInfo(pkcs7->singleCert, pkcs7->singleCertSz, RSAk, - blockKeySz, &rng, contentKeyPlain, - contentKeyEnc, &contentKeyEncSz, recip, - MAX_RECIP_SZ, pkcs7->heap); - + switch (pkcs7->publicKeyOID) { + + case RSAk: + recipSz = wc_CreateRecipientInfo(pkcs7->singleCert, + pkcs7->singleCertSz, + pkcs7->publicKeyOID, + blockKeySz, &rng, contentKeyPlain, + contentKeyEnc, &contentKeyEncSz, recip, + MAX_RECIP_SZ, pkcs7->heap); + break; + + case ECDSAk: + recipSz = wc_CreateKeyAgreeRecipientInfo(pkcs7, pkcs7->singleCert, + pkcs7->singleCertSz, + pkcs7->publicKeyOID, + blockKeySz, pkcs7->keyWrapOID, + pkcs7->keyAgreeOID, &rng, + contentKeyPlain, contentKeyEnc, + &contentKeyEncSz, recip, MAX_RECIP_SZ); + break; + + default: + WOLFSSL_MSG("Unsupported RecipientInfo public key type"); + return BAD_FUNC_ARG; + }; + ForceZero(contentKeyEnc, MAX_ENCRYPTED_KEY_SZ); - + #ifdef WOLFSSL_SMALL_STACK - XFREE(contentKeyEnc, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(contentKeyEnc, NULL, DYNAMIC_TYPE_PKCS7); #endif if (recipSz < 0) { WOLFSSL_MSG("Failed to create RecipientInfo"); wc_FreeRng(&rng); #ifdef WOLFSSL_SMALL_STACK - XFREE(recip, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER); #endif return recipSz; } @@ -1555,7 +2306,7 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) wc_FreeRng(&rng); if (ret != 0) { #ifdef WOLFSSL_SMALL_STACK - XFREE(recip, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER); #endif return ret; } @@ -1564,7 +2315,7 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) contentTypeSz = wc_SetContentType(pkcs7->contentOID, contentType); if (contentTypeSz == 0) { #ifdef WOLFSSL_SMALL_STACK - XFREE(recip, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER); #endif return BAD_FUNC_ARG; } @@ -1577,27 +2328,23 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) encryptedOutSz = pkcs7->contentSz + padSz; plain = (byte*)XMALLOC(encryptedOutSz, pkcs7->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (plain == NULL) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(recip, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#endif + DYNAMIC_TYPE_PKCS7); + if (plain == NULL) return MEMORY_E; - } ret = wc_PKCS7_PadData(pkcs7->content, pkcs7->contentSz, plain, encryptedOutSz, blockSz); if (ret < 0) { - XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); return ret; } encryptedContent = (byte*)XMALLOC(encryptedOutSz, pkcs7->heap, - DYNAMIC_TYPE_TMP_BUFFER); + DYNAMIC_TYPE_PKCS7); if (encryptedContent == NULL) { - XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); #ifdef WOLFSSL_SMALL_STACK - XFREE(recip, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER); #endif return MEMORY_E; } @@ -1611,10 +2358,10 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) oidBlkType, ivOctetStringSz + blockSz); if (contentEncAlgoSz == 0) { - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); #ifdef WOLFSSL_SMALL_STACK - XFREE(recip, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(recip, NULL, DYNAMIC_TYPE_PKCS7); #endif return BAD_FUNC_ARG; } @@ -1625,10 +2372,10 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) encryptedContent); if (ret != 0) { - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); #ifdef WOLFSSL_SMALL_STACK - XFREE(recip, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(recip, NULL, DYNAMIC_TYPE_PKCS7); #endif return ret; } @@ -1661,10 +2408,10 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) if (totalSz > (int)outputSz) { WOLFSSL_MSG("Pkcs7_encrypt output buffer too small"); - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); #ifdef WOLFSSL_SMALL_STACK - XFREE(recip, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER); #endif return BUFFER_E; } @@ -1700,30 +2447,32 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) ForceZero(contentKeyPlain, MAX_CONTENT_KEY_LEN); - XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); #ifdef WOLFSSL_SMALL_STACK - XFREE(recip, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER); #endif return idx; } -/* unwrap and decrypt PKCS#7 envelopedData object, return decoded size */ -WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg, - word32 pkiMsgSz, byte* output, - word32 outputSz) -{ - int recipFound = 0; - int ret, version, length; - word32 savedIdx = 0, idx = 0; - word32 contentType, encOID; - byte issuerHash[SHA_DIGEST_SIZE]; - int encryptedKeySz, keySz, expBlockSz, blockKeySz; - byte tmpIv[MAX_CONTENT_IV_SIZE]; - byte* decryptedKey = NULL; +/* decode KeyTransRecipientInfo (ktri), return 0 on success, <0 on error */ +static int wc_PKCS7_DecodeKtri(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, + word32* idx, byte* decryptedKey, + word32* decryptedKeySz, int* recipFound) +{ + int length, encryptedKeySz, ret; + int keySz; + word32 encOID; + word32 keyIdx; + byte issuerHash[SHA_DIGEST_SIZE]; + byte* outKey; + +#ifdef WC_RSA_BLINDING + WC_RNG rng; +#endif #ifdef WOLFSSL_SMALL_STACK mp_int* serialNum; @@ -1733,16 +2482,571 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg, mp_int stack_serialNum; mp_int* serialNum = &stack_serialNum; byte encryptedKey[MAX_ENCRYPTED_KEY_SZ]; - + RsaKey stack_privKey; RsaKey* privKey = &stack_privKey; #endif + + /* remove IssuerAndSerialNumber */ + if (GetSequence(pkiMsg, idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + if (GetNameHash(pkiMsg, idx, issuerHash, pkiMsgSz) < 0) + return ASN_PARSE_E; + + /* if we found correct recipient, issuer hashes will match */ + if (XMEMCMP(issuerHash, pkcs7->issuerHash, SHA_DIGEST_SIZE) == 0) { + *recipFound = 1; + } + +#ifdef WOLFSSL_SMALL_STACK + serialNum = (mp_int*)XMALLOC(sizeof(mp_int), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (serialNum == NULL) + return MEMORY_E; +#endif + + if (GetInt(serialNum, pkiMsg, idx, pkiMsgSz) < 0) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(serialNum, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ASN_PARSE_E; + } + + mp_clear(serialNum); + +#ifdef WOLFSSL_SMALL_STACK + XFREE(serialNum, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + if (GetAlgoId(pkiMsg, idx, &encOID, oidKeyType, pkiMsgSz) < 0) + return ASN_PARSE_E; + + /* key encryption algorithm must be RSA for now */ + if (encOID != RSAk) + return ALGO_ID_E; + + /* read encryptedKey */ +#ifdef WOLFSSL_SMALL_STACK + encryptedKey = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (encryptedKey == NULL) + return MEMORY_E; +#endif + + if (pkiMsg[(*idx)++] != ASN_OCTET_STRING) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ASN_PARSE_E; + } + + if (GetLength(pkiMsg, idx, &encryptedKeySz, pkiMsgSz) < 0) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ASN_PARSE_E; + } + + if (*recipFound == 1) + XMEMCPY(encryptedKey, &pkiMsg[*idx], encryptedKeySz); + *idx += encryptedKeySz; + + /* load private key */ +#ifdef WOLFSSL_SMALL_STACK + privKey = (RsaKey*)XMALLOC(sizeof(RsaKey), NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (privKey == NULL) { + XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return MEMORY_E; + } +#endif + + ret = wc_InitRsaKey(privKey, 0); + if (ret != 0) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(privKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ret; + } + + keyIdx = 0; + ret = wc_RsaPrivateKeyDecode(pkcs7->privateKey, &keyIdx, privKey, + pkcs7->privateKeySz); + if (ret != 0) { + WOLFSSL_MSG("Failed to decode RSA private key"); +#ifdef WOLFSSL_SMALL_STACK + XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(privKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ret; + } + + /* decrypt encryptedKey */ + #ifdef WC_RSA_BLINDING + ret = wc_InitRng(&rng); + if (ret == 0) { + ret = wc_RsaSetRNG(privKey, &rng); + } + #endif + if (ret == 0) { + keySz = wc_RsaPrivateDecryptInline(encryptedKey, encryptedKeySz, + &outKey, privKey); + #ifdef WC_RSA_BLINDING + wc_FreeRng(&rng); + #endif + } else { + keySz = ret; + } + wc_FreeRsaKey(privKey); + +#ifdef WOLFSSL_SMALL_STACK + XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(privKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + if (keySz <= 0) { + ForceZero(encryptedKey, MAX_ENCRYPTED_KEY_SZ); + return keySz; + } else { + *decryptedKeySz = keySz; + XMEMCPY(decryptedKey, outKey, keySz); + ForceZero(encryptedKey, MAX_ENCRYPTED_KEY_SZ); + } + + return 0; +} + + +/* remove ASN.1 OriginatorIdentifierOrKey, return 0 on success, <0 on error */ +static int wc_PKCS7_KariGetOriginatorIdentifierOrKey(WC_PKCS7_KARI* kari, + byte* pkiMsg, word32 pkiMsgSz, word32* idx) +{ + int ret, length; + word32 keyOID; + + if (kari == NULL || pkiMsg == NULL || idx == NULL) + return BAD_FUNC_ARG; + + /* remove OriginatorIdentifierOrKey */ + if (pkiMsg[*idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) { + (*idx)++; + if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + } else { + return ASN_PARSE_E; + } + + /* remove OriginatorPublicKey */ + if (pkiMsg[*idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) { + (*idx)++; + if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + } else { + return ASN_PARSE_E; + } + + /* remove AlgorithmIdentifier */ + if (GetAlgoId(pkiMsg, idx, &keyOID, oidKeyType, pkiMsgSz) < 0) + return ASN_PARSE_E; + + if (keyOID != ECDSAk) + return ASN_PARSE_E; + + /* remove ECPoint BIT STRING */ + if ((pkiMsgSz > (*idx + 1)) && (pkiMsg[(*idx)++] != ASN_BIT_STRING)) + return ASN_PARSE_E; + + if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + if ((pkiMsgSz < (*idx + 1)) || (pkiMsg[(*idx)++] != 0x00)) + return ASN_EXPECT_0_E; + + /* get sender ephemeral public ECDSA key */ + ret = wc_ecc_init(kari->senderKey); + if (ret != 0) + return ret; + + /* length-1 for unused bits counter */ + ret = wc_ecc_import_x963(pkiMsg + (*idx), length - 1, kari->senderKey); + if (ret != 0) + return ret; + + (*idx) += length - 1; + + return 0; +} + + +/* remove optional UserKeyingMaterial if available, return 0 on success, + * < 0 on error */ +static int wc_PKCS7_KariGetUserKeyingMaterial(WC_PKCS7_KARI* kari, + byte* pkiMsg, word32 pkiMsgSz, word32* idx) +{ + int length; + word32 savedIdx; + + if (kari == NULL || pkiMsg == NULL || idx == NULL) + return BAD_FUNC_ARG; + + savedIdx = *idx; + + /* starts with EXPLICIT [1] */ + if (pkiMsg[(*idx)++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) { + *idx = savedIdx; + return 0; + } + + if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) { + *idx = savedIdx; + return 0; + } + + /* get OCTET STRING */ + if ( (pkiMsgSz > ((*idx) + 1)) && + (pkiMsg[(*idx)++] != ASN_OCTET_STRING) ) { + *idx = savedIdx; + return 0; + } + + if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) { + *idx = savedIdx; + return 0; + } + + kari->ukm = (byte*)XMALLOC(length, kari->heap, DYNAMIC_TYPE_PKCS7); + if (kari->ukm == NULL) + return MEMORY_E; + + XMEMCPY(kari->ukm, pkiMsg + (*idx), length); + (*idx) += length; + kari->ukmSz = length; + kari->ukmOwner = 1; + + return 0; +} + + +/* remove ASN.1 KeyEncryptionAlgorithmIdentifier, return 0 on success, + * < 0 on error */ +static int wc_PKCS7_KariGetKeyEncryptionAlgorithmId(WC_PKCS7_KARI* kari, + byte* pkiMsg, word32 pkiMsgSz, word32* idx, + word32* keyAgreeOID, word32* keyWrapOID) +{ + if (kari == NULL || pkiMsg == NULL || idx == NULL || + keyAgreeOID == NULL || keyWrapOID == NULL) + return BAD_FUNC_ARG; + + /* remove KeyEncryptionAlgorithmIdentifier */ + if (GetAlgoId(pkiMsg, idx, keyAgreeOID, oidCmsKeyAgreeType, + pkiMsgSz) < 0) + return ASN_PARSE_E; + + /* remove KeyWrapAlgorithm, stored in parameter of KeyEncAlgoId */ + if (GetAlgoId(pkiMsg, idx, keyWrapOID, oidKeyWrapType, pkiMsgSz) < 0) + return ASN_PARSE_E; + + return 0; +} + + +/* remove ASN.1 RecipientEncryptedKeys, return 0 on success, < 0 on error */ +static int wc_PKCS7_KariGetRecipientEncryptedKeys(WC_PKCS7_KARI* kari, + byte* pkiMsg, word32 pkiMsgSz, word32* idx, + int* recipFound, byte* encryptedKey, + int* encryptedKeySz) +{ + int length; + byte subjKeyId[KEYID_SIZE]; + + if (kari == NULL || pkiMsg == NULL || idx == NULL || + recipFound == NULL || encryptedKey == NULL) + return BAD_FUNC_ARG; + + /* remove RecipientEncryptedKeys */ + if (GetSequence(pkiMsg, idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + /* remove RecipientEncryptedKeys */ + if (GetSequence(pkiMsg, idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + /* remove RecipientKeyIdentifier IMPLICIT [0] */ + if ( (pkiMsgSz > (*idx + 1)) && + (pkiMsg[(*idx)++] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) ) { + + if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + } else { + return ASN_PARSE_E; + } + + /* remove SubjectKeyIdentifier */ + if ( (pkiMsgSz > (*idx + 1)) && + (pkiMsg[(*idx)++] != ASN_OCTET_STRING) ) + return ASN_PARSE_E; + + if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + if (length != KEYID_SIZE) + return ASN_PARSE_E; + + XMEMCPY(subjKeyId, pkiMsg + (*idx), KEYID_SIZE); + (*idx) += length; + + /* subject key id should match if recipient found */ + if (XMEMCMP(subjKeyId, kari->decoded->extSubjKeyId, KEYID_SIZE) == 0) { + *recipFound = 1; + } + + /* remove EncryptedKey */ + if ( (pkiMsgSz > (*idx + 1)) && + (pkiMsg[(*idx)++] != ASN_OCTET_STRING) ) + return ASN_PARSE_E; + + if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + /* put encrypted CEK in decryptedKey buffer for now, decrypt later */ + if (length > *encryptedKeySz) + return BUFFER_E; + + XMEMCPY(encryptedKey, pkiMsg + (*idx), length); + *encryptedKeySz = length; + (*idx) += length; + + return 0; +} + + +/* decode ASN.1 KeyAgreeRecipientInfo (kari), return 0 on success, + * < 0 on error */ +static int wc_PKCS7_DecodeKari(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, + word32* idx, byte* decryptedKey, + word32* decryptedKeySz, int* recipFound) +{ + int ret, keySz; + int encryptedKeySz; + word32 keyAgreeOID, keyWrapOID; + +#ifdef WOLFSSL_SMALL_STACK + byte* encryptedKey; +#else + byte encryptedKey[MAX_ENCRYPTED_KEY_SZ]; +#endif + + WC_PKCS7_KARI* kari; + + if (pkcs7 == NULL || pkcs7->singleCert == NULL || + pkcs7->singleCertSz == 0 || pkiMsg == NULL || + idx == NULL || decryptedKey == NULL || decryptedKeySz == NULL) { + return BAD_FUNC_ARG; + } + + kari = wc_PKCS7_KariNew(pkcs7, WC_PKCS7_DECODE); + if (kari == NULL) + return MEMORY_E; + +#ifdef WOLFSSL_SMALL_STACK + encryptedKey = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ, NULL, + DYNAMIC_TYPE_PKCS7); + if (encryptedKey == NULL) { + wc_PKCS7_KariFree(kari); + return MEMORY_E; + } +#endif + encryptedKeySz = MAX_ENCRYPTED_KEY_SZ; + + /* parse cert and key */ + ret = wc_PKCS7_KariParseRecipCert(kari, (byte*)pkcs7->singleCert, + pkcs7->singleCertSz, pkcs7->privateKey, + pkcs7->privateKeySz); + if (ret != 0) { + wc_PKCS7_KariFree(kari); + return ret; + } + + /* remove OriginatorIdentifierOrKey */ + ret = wc_PKCS7_KariGetOriginatorIdentifierOrKey(kari, pkiMsg, + pkiMsgSz, idx); + if (ret != 0) { + wc_PKCS7_KariFree(kari); + #ifdef WOLFSSL_SMALL_STACK + XFREE(encryptedKey, NULL, DYNAMIC_TYPE_PKCS7); + #endif + return ret; + } + + /* try and remove optional UserKeyingMaterial */ + ret = wc_PKCS7_KariGetUserKeyingMaterial(kari, pkiMsg, pkiMsgSz, idx); + if (ret != 0) { + wc_PKCS7_KariFree(kari); + #ifdef WOLFSSL_SMALL_STACK + XFREE(encryptedKey, NULL, DYNAMIC_TYPE_PKCS7); + #endif + return ret; + } + + /* remove KeyEncryptionAlgorithmIdentifier */ + ret = wc_PKCS7_KariGetKeyEncryptionAlgorithmId(kari, pkiMsg, pkiMsgSz, + idx, &keyAgreeOID, + &keyWrapOID); + if (ret != 0) { + wc_PKCS7_KariFree(kari); + #ifdef WOLFSSL_SMALL_STACK + XFREE(encryptedKey, NULL, DYNAMIC_TYPE_PKCS7); + #endif + return ret; + } + + /* remove RecipientEncryptedKeys */ + ret = wc_PKCS7_KariGetRecipientEncryptedKeys(kari, pkiMsg, pkiMsgSz, + idx, recipFound, encryptedKey, &encryptedKeySz); + if (ret != 0) { + wc_PKCS7_KariFree(kari); + #ifdef WOLFSSL_SMALL_STACK + XFREE(encryptedKey, NULL, DYNAMIC_TYPE_PKCS7); + #endif + return ret; + } + + /* create KEK */ + ret = wc_PKCS7_KariGenerateKEK(kari, keyWrapOID, pkcs7->keyAgreeOID); + if (ret != 0) { + wc_PKCS7_KariFree(kari); + #ifdef WOLFSSL_SMALL_STACK + XFREE(encryptedKey, NULL, DYNAMIC_TYPE_PKCS7); + #endif + return ret; + } + + /* decrypt CEK with KEK */ + keySz = wc_PKCS7_KariKeyWrap(encryptedKey, encryptedKeySz, kari->kek, + kari->kekSz, decryptedKey, *decryptedKeySz, + keyWrapOID, AES_DECRYPTION); + if (keySz <= 0) { + wc_PKCS7_KariFree(kari); + #ifdef WOLFSSL_SMALL_STACK + XFREE(encryptedKey, NULL, DYNAMIC_TYPE_PKCS7); + #endif + return keySz; + } + *decryptedKeySz = (word32)keySz; + + wc_PKCS7_KariFree(kari); + #ifdef WOLFSSL_SMALL_STACK + XFREE(encryptedKey, NULL, DYNAMIC_TYPE_PKCS7); + #endif + + return 0; +} + + +/* decode ASN.1 RecipientInfos SET, return 0 on success, < 0 on error */ +static int wc_PKCS7_DecodeRecipientInfos(PKCS7* pkcs7, byte* pkiMsg, + word32 pkiMsgSz, word32* idx, byte* decryptedKey, + word32* decryptedKeySz, int* recipFound) +{ + word32 savedIdx; + int version, ret, length; + + if (pkcs7 == NULL || pkiMsg == NULL || idx == NULL || + decryptedKey == NULL || decryptedKeySz == NULL || + recipFound == NULL) { + return BAD_FUNC_ARG; + } + + savedIdx = *idx; + + /* when looking for next recipient, use first sequence and version to + * indicate there is another, if not, move on */ + while(*recipFound == 0) { + + /* remove RecipientInfo, if we don't have a SEQUENCE, back up idx to + * last good saved one */ + if (GetSequence(pkiMsg, idx, &length, pkiMsgSz) > 0) { + + if (GetMyVersion(pkiMsg, idx, &version, pkiMsgSz) < 0) { + *idx = savedIdx; + break; + } + + if (version != 0) + return ASN_VERSION_E; + + /* found ktri */ + ret = wc_PKCS7_DecodeKtri(pkcs7, pkiMsg, pkiMsgSz, idx, + decryptedKey, decryptedKeySz, + recipFound); + if (ret != 0) + return ret; + } + else { + /* kari is IMPLICIT[1] */ + *idx = savedIdx; + if (pkiMsg[*idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) { + (*idx)++; + + if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + if (GetMyVersion(pkiMsg, idx, &version, pkiMsgSz) < 0) { + *idx = savedIdx; + break; + } + + if (version != 3) + return ASN_VERSION_E; + + /* found kari */ + ret = wc_PKCS7_DecodeKari(pkcs7, pkiMsg, pkiMsgSz, idx, + decryptedKey, decryptedKeySz, + recipFound); + if (ret != 0) + return ret; + } + else { + /* failed to find RecipientInfo, restore idx and continue */ + *idx = savedIdx; + break; + } + } + + /* update good idx */ + savedIdx = *idx; + } + + return 0; +} + + +/* unwrap and decrypt PKCS#7 envelopedData object, return decoded size */ +WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg, + word32 pkiMsgSz, byte* output, + word32 outputSz) +{ + int recipFound = 0; + int ret, version, length; + word32 idx = 0; + word32 contentType, encOID; + word32 decryptedKeySz; + + int expBlockSz, blockKeySz; + byte tmpIv[MAX_CONTENT_IV_SIZE]; + +#ifdef WOLFSSL_SMALL_STACK + byte* decryptedKey; +#else + byte decryptedKey[MAX_ENCRYPTED_KEY_SZ]; +#endif int encryptedContentSz; byte padLen; byte* encryptedContent = NULL; -#ifdef WC_RSA_BLINDING - WC_RNG rng; -#endif if (pkcs7 == NULL || pkcs7->singleCert == NULL || pkcs7->singleCertSz == 0 || pkcs7->privateKey == NULL || @@ -1778,7 +3082,9 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg, if (GetMyVersion(pkiMsg, &idx, &version, pkiMsgSz) < 0) return ASN_PARSE_E; - if (version != 0) { + /* TODO :: make this more accurate */ + if ((pkcs7->publicKeyOID == RSAk && version != 0) || + (pkcs7->publicKeyOID == ECDSAk && version != 2)) { WOLFSSL_MSG("PKCS#7 envelopedData needs to be of version 0"); return ASN_VERSION_E; } @@ -1788,123 +3094,27 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg, return ASN_PARSE_E; #ifdef WOLFSSL_SMALL_STACK - encryptedKey = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ, NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (encryptedKey == NULL) + decryptedKey = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ, NULL, + DYNAMIC_TYPE_PKCS7); + if (decryptedKey == NULL) return MEMORY_E; #endif - - savedIdx = idx; - recipFound = 0; + decryptedKeySz = MAX_ENCRYPTED_KEY_SZ; - /* when looking for next recipient, use first sequence and version to - * indicate there is another, if not, move on */ - while(recipFound == 0) { - - /* remove RecipientInfo, if we don't have a SEQUENCE, back up idx to - * last good saved one */ - if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) { - idx = savedIdx; - break; - } - - if (GetMyVersion(pkiMsg, &idx, &version, pkiMsgSz) < 0) { - idx = savedIdx; - break; - } - - if (version != 0) { + ret = wc_PKCS7_DecodeRecipientInfos(pkcs7, pkiMsg, pkiMsgSz, &idx, + decryptedKey, &decryptedKeySz, + &recipFound); + if (ret != 0) { #ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(decryptedKey, NULL, DYNAMIC_TYPE_PKCS7); #endif - return ASN_VERSION_E; - } - - /* remove IssuerAndSerialNumber */ - if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ASN_PARSE_E; - } - - if (GetNameHash(pkiMsg, &idx, issuerHash, pkiMsgSz) < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ASN_PARSE_E; - } - - /* if we found correct recipient, issuer hashes will match */ - if (XMEMCMP(issuerHash, pkcs7->issuerHash, SHA_DIGEST_SIZE) == 0) { - recipFound = 1; - } - -#ifdef WOLFSSL_SMALL_STACK - serialNum = (mp_int*)XMALLOC(sizeof(mp_int), NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (serialNum == NULL) { - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return MEMORY_E; - } -#endif - - if (GetInt(serialNum, pkiMsg, &idx, pkiMsgSz) < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(serialNum, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ASN_PARSE_E; - } - - mp_clear(serialNum); - -#ifdef WOLFSSL_SMALL_STACK - XFREE(serialNum, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#endif - - if (GetAlgoId(pkiMsg, &idx, &encOID, oidKeyType, pkiMsgSz) < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ASN_PARSE_E; - } - - /* key encryption algorithm must be RSA for now */ - if (encOID != RSAk) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ALGO_ID_E; - } - - /* read encryptedKey */ - if (pkiMsg[idx++] != ASN_OCTET_STRING) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ASN_PARSE_E; - } - - if (GetLength(pkiMsg, &idx, &encryptedKeySz, pkiMsgSz) < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ASN_PARSE_E; - } - - if (recipFound == 1) - XMEMCPY(encryptedKey, &pkiMsg[idx], encryptedKeySz); - idx += encryptedKeySz; - - /* update good idx */ - savedIdx = idx; + return ret; } if (recipFound == 0) { WOLFSSL_MSG("No recipient found in envelopedData that matches input"); #ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(decryptedKey, NULL, DYNAMIC_TYPE_PKCS7); #endif return PKCS7_RECIP_E; } @@ -1912,48 +3122,48 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg, /* remove EncryptedContentInfo */ if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) { #ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(decryptedKey, NULL, DYNAMIC_TYPE_PKCS7); #endif return ASN_PARSE_E; } if (wc_GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0) { #ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(decryptedKey, NULL, DYNAMIC_TYPE_PKCS7); #endif return ASN_PARSE_E; } if (GetAlgoId(pkiMsg, &idx, &encOID, oidBlkType, pkiMsgSz) < 0) { #ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(decryptedKey, NULL, DYNAMIC_TYPE_PKCS7); #endif return ASN_PARSE_E; } blockKeySz = wc_PKCS7_GetOIDKeySize(encOID); if (blockKeySz < 0) { - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(decryptedKey, NULL, DYNAMIC_TYPE_PKCS7); return blockKeySz; } expBlockSz = wc_PKCS7_GetOIDBlockSize(encOID); if (expBlockSz < 0) { - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(decryptedKey, NULL, DYNAMIC_TYPE_PKCS7); return expBlockSz; } /* get block cipher IV, stored in OPTIONAL parameter of AlgoID */ if (pkiMsg[idx++] != ASN_OCTET_STRING) { #ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(decryptedKey, NULL, DYNAMIC_TYPE_PKCS7); #endif return ASN_PARSE_E; } if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) { #ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(decryptedKey, NULL, DYNAMIC_TYPE_PKCS7); #endif return ASN_PARSE_E; } @@ -1961,7 +3171,7 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg, if (length != expBlockSz) { WOLFSSL_MSG("Incorrect IV length, must be of content alg block size"); #ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(decryptedKey, NULL, DYNAMIC_TYPE_PKCS7); #endif return ASN_PARSE_E; } @@ -1972,101 +3182,37 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg, /* read encryptedContent, cont[0] */ if (pkiMsg[idx++] != (ASN_CONTEXT_SPECIFIC | 0)) { #ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(decryptedKey, NULL, DYNAMIC_TYPE_PKCS7); #endif return ASN_PARSE_E; } if (GetLength(pkiMsg, &idx, &encryptedContentSz, pkiMsgSz) < 0) { #ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(decryptedKey, NULL, DYNAMIC_TYPE_PKCS7); #endif return ASN_PARSE_E; } encryptedContent = (byte*)XMALLOC(encryptedContentSz, pkcs7->heap, - DYNAMIC_TYPE_TMP_BUFFER); + DYNAMIC_TYPE_PKCS7); if (encryptedContent == NULL) { #ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(decryptedKey, NULL, DYNAMIC_TYPE_PKCS7); #endif return MEMORY_E; } XMEMCPY(encryptedContent, &pkiMsg[idx], encryptedContentSz); - /* load private key */ -#ifdef WOLFSSL_SMALL_STACK - privKey = (RsaKey*)XMALLOC(sizeof(RsaKey), NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (privKey == NULL) { - XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return MEMORY_E; - } -#endif - - ret = wc_InitRsaKey(privKey, 0); - if (ret != 0) { - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#ifdef WOLFSSL_SMALL_STACK - XFREE(privKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; - } - - idx = 0; - - ret = wc_RsaPrivateKeyDecode(pkcs7->privateKey, &idx, privKey, - pkcs7->privateKeySz); - if (ret != 0) { - WOLFSSL_MSG("Failed to decode RSA private key"); - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#ifdef WOLFSSL_SMALL_STACK - XFREE(privKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; - } - - /* decrypt encryptedKey */ - #ifdef WC_RSA_BLINDING - ret = wc_InitRng(&rng); - if (ret == 0) { - ret = wc_RsaSetRNG(privKey, &rng); - } - #endif - if (ret == 0) { - keySz = wc_RsaPrivateDecryptInline(encryptedKey, encryptedKeySz, - &decryptedKey, privKey); - #ifdef WC_RSA_BLINDING - wc_FreeRng(&rng); - #endif - } else { - keySz = ret; - } - wc_FreeRsaKey(privKey); - -#ifdef WOLFSSL_SMALL_STACK - XFREE(privKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#endif - - if (keySz <= 0) { - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return keySz; - } - /* decrypt encryptedContent */ ret = wc_PKCS7_DecryptContent(encOID, decryptedKey, blockKeySz, tmpIv, expBlockSz, encryptedContent, encryptedContentSz, encryptedContent); if (ret != 0) { - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); #ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(decryptedKey, NULL, DYNAMIC_TYPE_PKCS7); #endif return ret; } @@ -2077,11 +3223,11 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg, XMEMCPY(output, encryptedContent, encryptedContentSz - padLen); /* free memory, zero out keys */ - ForceZero(encryptedKey, MAX_ENCRYPTED_KEY_SZ); + ForceZero(decryptedKey, MAX_ENCRYPTED_KEY_SZ); ForceZero(encryptedContent, encryptedContentSz); - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); #ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(decryptedKey, NULL, DYNAMIC_TYPE_PKCS7); #endif return encryptedContentSz - padLen; @@ -2158,21 +3304,21 @@ int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, byte* output, word32 outputSz) encryptedOutSz = pkcs7->contentSz + padSz; plain = (byte*)XMALLOC(encryptedOutSz, pkcs7->heap, - DYNAMIC_TYPE_TMP_BUFFER); + DYNAMIC_TYPE_PKCS7); if (plain == NULL) return MEMORY_E; ret = wc_PKCS7_PadData(pkcs7->content, pkcs7->contentSz, plain, encryptedOutSz, blockSz); if (ret < 0) { - XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); return ret; } encryptedContent = (byte*)XMALLOC(encryptedOutSz, pkcs7->heap, - DYNAMIC_TYPE_TMP_BUFFER); + DYNAMIC_TYPE_PKCS7); if (encryptedContent == NULL) { - XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); return MEMORY_E; } @@ -2184,8 +3330,8 @@ int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, byte* output, word32 outputSz) contentEncAlgoSz = SetAlgoID(pkcs7->encryptOID, contentEncAlgo, oidBlkType, ivOctetStringSz + blockSz); if (contentEncAlgoSz == 0) { - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); return BAD_FUNC_ARG; } @@ -2198,8 +3344,8 @@ int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, byte* output, word32 outputSz) pkcs7->encryptionKeySz, tmpIv, blockSz, plain, encryptedOutSz, encryptedContent); if (ret != 0) { - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); return ret; } @@ -2215,8 +3361,8 @@ int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, byte* output, word32 outputSz) if (pkcs7->unprotectedAttribsSz != 0) { if (pkcs7->unprotectedAttribs == NULL) { - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); return BAD_FUNC_ARG; } @@ -2224,8 +3370,8 @@ int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, byte* output, word32 outputSz) sizeof(EncodedAttrib) * pkcs7->unprotectedAttribsSz, pkcs7->heap, DYNAMIC_TYPE_PKCS); if (attribs == NULL) { - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); return MEMORY_E; } @@ -2237,8 +3383,8 @@ int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, byte* output, word32 outputSz) flatAttribs = (byte*)XMALLOC(attribsSz, pkcs7->heap, DYNAMIC_TYPE_PKCS); if (flatAttribs == NULL) { XFREE(attribs, pkcs7->heap, DYNAMIC_TYPE_PKCS); - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); return MEMORY_E; } @@ -2274,8 +3420,8 @@ int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, byte* output, word32 outputSz) XFREE(attribs, pkcs7->heap, DYNAMIC_TYPE_PKCS); XFREE(attribs, pkcs7->heap, DYNAMIC_TYPE_PKCS); } - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); return BUFFER_E; } @@ -2313,42 +3459,17 @@ int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, byte* output, word32 outputSz) XFREE(flatAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS); } - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); return idx; } -void wc_PKCS7_FreeDecodedAttrib(PKCS7DecodedAttrib* attrib, void* heap) -{ - PKCS7DecodedAttrib* current; - - if (attrib == NULL) { - return; - } - - current = attrib; - while (current != NULL) { - PKCS7DecodedAttrib* next = current->next; - if (current->oid != NULL) { - XFREE(current->oid, heap, DYNAMIC_TYPE_PKCS7); - } - if (current->value != NULL) { - XFREE(current->value, heap, DYNAMIC_TYPE_PKCS7); - } - XFREE(current, heap, DYNAMIC_TYPE_PKCS7); - current = next; - } - - (void)heap; -} - - /* decode and store unprotected attributes in PKCS7->decodedAttrib. Return * 0 on success, negative on error. User must call wc_PKCS7_Free(). */ -int wc_PKCS7_DecodeUnprotectedAttributes(PKCS7* pkcs7, byte* pkiMsg, - word32 pkiMsgSz, word32* inOutIdx) +static int wc_PKCS7_DecodeUnprotectedAttributes(PKCS7* pkcs7, byte* pkiMsg, + word32 pkiMsgSz, word32* inOutIdx) { int length, attribLen; word32 oid, savedIdx, idx; @@ -2384,8 +3505,10 @@ int wc_PKCS7_DecodeUnprotectedAttributes(PKCS7* pkcs7, byte* pkiMsg, XMEMSET(attrib, 0, sizeof(PKCS7DecodedAttrib)); /* save attribute OID bytes and size */ - if (GetObjectId(pkiMsg, &idx, &oid, oidIgnoreType, pkiMsgSz) < 0) + if (GetObjectId(pkiMsg, &idx, &oid, oidIgnoreType, pkiMsgSz) < 0) { + XFREE(attrib, pkcs7->heap, DYNAMIC_TYPE_PKCS); return ASN_PARSE_E; + } attrib->oidSz = idx - savedIdx; attrib->oid = (byte*)XMALLOC(attrib->oidSz, pkcs7->heap, @@ -2397,11 +3520,17 @@ int wc_PKCS7_DecodeUnprotectedAttributes(PKCS7* pkcs7, byte* pkiMsg, XMEMCPY(attrib->oid, pkiMsg + savedIdx, attrib->oidSz); /* save attribute value bytes and size */ - if (GetSet(pkiMsg, &idx, &length, pkiMsgSz) < 0) + if (GetSet(pkiMsg, &idx, &length, pkiMsgSz) < 0) { return ASN_PARSE_E; + XFREE(attrib->oid, pkcs7->heap, DYNAMIC_TYPE_PKCS); + XFREE(attrib, pkcs7->heap, DYNAMIC_TYPE_PKCS); + } - if ((pkiMsgSz - idx) < (word32)length) + if ((pkiMsgSz - idx) < (word32)length) { + XFREE(attrib->oid, pkcs7->heap, DYNAMIC_TYPE_PKCS); + XFREE(attrib, pkcs7->heap, DYNAMIC_TYPE_PKCS); return ASN_PARSE_E; + } attrib->valueSz = (word32)length; attrib->value = (byte*)XMALLOC(attrib->valueSz, pkcs7->heap, @@ -2516,7 +3645,7 @@ int wc_PKCS7_DecodeEncryptedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, return ASN_PARSE_E; encryptedContent = (byte*)XMALLOC(encryptedContentSz, pkcs7->heap, - DYNAMIC_TYPE_TMP_BUFFER); + DYNAMIC_TYPE_PKCS7); if (encryptedContent == NULL) return MEMORY_E; @@ -2529,7 +3658,7 @@ int wc_PKCS7_DecodeEncryptedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, encryptedContent, encryptedContentSz, encryptedContent); if (ret != 0) { - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); return ret; } @@ -2539,17 +3668,16 @@ int wc_PKCS7_DecodeEncryptedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, XMEMCPY(output, encryptedContent, encryptedContentSz - padLen); /* get implicit[1] unprotected attributes, optional */ + pkcs7->decodedAttrib = NULL; if (idx < pkiMsgSz) { haveAttribs = 1; - pkcs7->decodedAttrib = NULL; ret = wc_PKCS7_DecodeUnprotectedAttributes(pkcs7, pkiMsg, pkiMsgSz, &idx); if (ret != 0) { - printf("DEBUG: DecodeUnprotectedAttributes failed!\n"); ForceZero(encryptedContent, encryptedContentSz); - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); return ASN_PARSE_E; } } @@ -2562,7 +3690,7 @@ int wc_PKCS7_DecodeEncryptedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, } ForceZero(encryptedContent, encryptedContentSz); - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); return encryptedContentSz - padLen; } diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index ab444ef2d..5278f90a7 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -474,7 +474,6 @@ int wolfcrypt_test(void* args) else printf( "HMAC-KDF test passed!\n"); #endif - #endif #ifdef HAVE_X963_KDF @@ -4438,6 +4437,10 @@ byte GetEntropy(ENTROPY_CMD cmd, byte* out) #ifdef FREESCALE_MQX static const char* clientKey = "a:\\certs\\client-key.der"; static const char* clientCert = "a:\\certs\\client-cert.der"; + #ifdef HAVE_PKCS7 + static const char* eccClientKey = "a:\\certs\\ecc-client-key.der"; + static const char* eccClientCert = "a:\\certs\\client-ecc-cert.der"; + #endif #ifdef WOLFSSL_CERT_EXT static const char* clientKeyPub = "a:\\certs\\client-keyPub.der"; #endif @@ -4460,6 +4463,12 @@ byte GetEntropy(ENTROPY_CMD cmd, byte* out) static char* clientCert = "certs/client-cert.der"; void set_clientKey(char *key) { clientKey = key ; } void set_clientCert(char *cert) { clientCert = cert ; } + #ifdef HAVE_PKCS7 + static const char* eccClientKey = "certs/ecc-client-key.der"; + static const char* eccClientCert = "certs/client-ecc-cert.der"; + void set_eccClientKey(char* key) { eccClientKey = key ; } + void set_eccClientCert(char* cert) { eccClientCert = cert ; } + #endif #ifdef WOLFSSL_CERT_EXT static const char* clientKeyPub = "certs/client-keyPub.der"; void set_clientKeyPub(char *key) { clientKeyPub = key ; } @@ -4487,6 +4496,10 @@ byte GetEntropy(ENTROPY_CMD cmd, byte* out) #else static const char* clientKey = "./certs/client-key.der"; static const char* clientCert = "./certs/client-cert.der"; + #ifdef HAVE_PKCS7 + static const char* eccClientKey = "./certs/ecc-client-key.der"; + static const char* eccClientCert = "./certs/client-ecc-cert.der"; + #endif #ifdef WOLFSSL_CERT_EXT static const char* clientKeyPub = "./certs/client-keyPub.der"; #endif @@ -9040,34 +9053,33 @@ int compress_test(void) #ifdef HAVE_PKCS7 typedef struct { - const char* outFileName; const byte* content; word32 contentSz; int contentOID; int encryptOID; + int keyWrapOID; + int keyAgreeOID; + byte* cert; + size_t certSz; byte* privateKey; word32 privateKeySz; - byte* encryptionKey; - word32 encryptionKeySz; - PKCS7Attrib* attribs; - word32 attribsSz; -} pkcs7Vector; + byte* optionalUkm; + word32 optionalUkmSz; + const char* outFileName; +} pkcs7EnvelopedVector; -int pkcs7enveloped_test(void) + +static int pkcs7enveloped_run_vectors(byte* rsaCert, word32 rsaCertSz, + byte* rsaPrivKey, word32 rsaPrivKeySz, + byte* eccCert, word32 eccCertSz, + byte* eccPrivKey, word32 eccPrivKeySz) { - int ret = 0; - + int ret, testSz, i; int envelopedSz, decodedSz; - PKCS7 pkcs7; - byte* cert; - byte* privKey; - byte enveloped[2048]; - byte decoded[2048]; - size_t certSz; - size_t privKeySz; - FILE* certFile; - FILE* keyFile; + byte enveloped[2048]; + byte decoded[2048]; + PKCS7 pkcs7; FILE* pkcs7File; const byte data[] = { /* Hello World */ @@ -9075,152 +9087,251 @@ int pkcs7enveloped_test(void) 0x72,0x6c,0x64 }; - pkcs7Vector a; -#ifndef NO_AES - pkcs7Vector b, c, d; - pkcs7Vector test_pkcs7env[4]; -#else - pkcs7Vector test_pkcs7env[1]; -#endif - int times = sizeof(test_pkcs7env) / sizeof(pkcs7Vector), i; + byte optionalUkm[] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07 + }; - /* read client cert and key in DER format */ - cert = (byte*)XMALLOC(FOURK_BUF, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - if (cert == NULL) + const pkcs7EnvelopedVector testVectors[] = + { + /* key transport key encryption technique */ +#ifndef NO_RSA + {data, (word32)sizeof(data), DATA, DES3b, 0, 0, rsaCert, rsaCertSz, + rsaPrivKey, rsaPrivKeySz, NULL, 0, "pkcs7envelopedDataDES3.der"}, + + #ifndef NO_AES + {data, (word32)sizeof(data), DATA, AES128CBCb, 0, 0, rsaCert, rsaCertSz, + rsaPrivKey, rsaPrivKeySz, NULL, 0, "pkcs7envelopedDataAES128CBC.der"}, + + {data, (word32)sizeof(data), DATA, AES192CBCb, 0, 0, rsaCert, rsaCertSz, + rsaPrivKey, rsaPrivKeySz, NULL, 0, "pkcs7envelopedDataAES192CBC.der"}, + + {data, (word32)sizeof(data), DATA, AES256CBCb, 0, 0, rsaCert, rsaCertSz, + rsaPrivKey, rsaPrivKeySz, NULL, 0, "pkcs7envelopedDataAES256CBC.der"}, + #endif /* NO_AES */ +#endif + + /* key agreement key encryption technique*/ +#ifdef HAVE_ECC + #ifndef NO_AES + #ifndef NO_SHA + {data, (word32)sizeof(data), DATA, AES128CBCb, AES128_WRAP, + dhSinglePass_stdDH_sha1kdf_scheme, eccCert, eccCertSz, eccPrivKey, + eccPrivKeySz, NULL, 0, + "pkcs7envelopedDataAES128CBC_ECDH_SHA1KDF.der"}, + #endif + + #ifndef NO_SHA256 + {data, (word32)sizeof(data), DATA, AES256CBCb, AES256_WRAP, + dhSinglePass_stdDH_sha256kdf_scheme, eccCert, eccCertSz, eccPrivKey, + eccPrivKeySz, NULL, 0, + "pkcs7envelopedDataAES256CBC_ECDH_SHA256KDF.der"}, + #endif /* NO_SHA256 */ + + #ifdef WOLFSSL_SHA512 + {data, (word32)sizeof(data), DATA, AES256CBCb, AES256_WRAP, + dhSinglePass_stdDH_sha512kdf_scheme, eccCert, eccCertSz, eccPrivKey, + eccPrivKeySz, NULL, 0, + "pkcs7envelopedDataAES256CBC_ECDH_SHA512KDF.der"}, + + /* with optional user keying material (ukm) */ + {data, (word32)sizeof(data), DATA, AES256CBCb, AES256_WRAP, + dhSinglePass_stdDH_sha512kdf_scheme, eccCert, eccCertSz, eccPrivKey, + eccPrivKeySz, optionalUkm, sizeof(optionalUkm), + "pkcs7envelopedDataAES256CBC_ECDH_SHA512KDF_ukm.der"}, + #endif /* WOLFSSL_SHA512 */ + #endif /* NO_AES */ +#endif + }; + + testSz = sizeof(testVectors) / sizeof(pkcs7EnvelopedVector); + + for (i = 0; i < testSz; i++) { + + ret = wc_PKCS7_InitWithCert(&pkcs7, testVectors[i].cert, + (word32)testVectors[i].certSz); + if (ret != 0) + return -209; + + pkcs7.content = (byte*)testVectors[i].content; + pkcs7.contentSz = testVectors[i].contentSz; + pkcs7.contentOID = testVectors[i].contentOID; + pkcs7.encryptOID = testVectors[i].encryptOID; + pkcs7.keyWrapOID = testVectors[i].keyWrapOID; + pkcs7.keyAgreeOID = testVectors[i].keyAgreeOID; + pkcs7.privateKey = testVectors[i].privateKey; + pkcs7.privateKeySz = testVectors[i].privateKeySz; + pkcs7.ukm = testVectors[i].optionalUkm; + pkcs7.ukmSz = testVectors[i].optionalUkmSz; + + /* encode envelopedData */ + envelopedSz = wc_PKCS7_EncodeEnvelopedData(&pkcs7, enveloped, + sizeof(enveloped)); + if (envelopedSz <= 0) + return -210; + + /* decode envelopedData */ + decodedSz = wc_PKCS7_DecodeEnvelopedData(&pkcs7, enveloped, envelopedSz, + decoded, sizeof(decoded)); + if (decodedSz <= 0) + return -211; + + /* test decode result */ + if (XMEMCMP(decoded, data, sizeof(data)) != 0) + return -212; + + /* output pkcs7 envelopedData for external testing */ + pkcs7File = fopen(testVectors[i].outFileName, "wb"); + if (!pkcs7File) + return -213; + + ret = (int)fwrite(enveloped, envelopedSz, 1, pkcs7File); + fclose(pkcs7File); + + wc_PKCS7_Free(&pkcs7); + } + + return 0; +} + + +int pkcs7enveloped_test(void) +{ + int ret = 0; + + byte* rsaCert = NULL; + byte* eccCert = NULL; + byte* rsaPrivKey = NULL; + byte* eccPrivKey = NULL; + + size_t rsaCertSz = 0; + size_t eccCertSz = 0; + size_t rsaPrivKeySz = 0; + size_t eccPrivKeySz = 0; + + FILE* certFile; + FILE* keyFile; + +#ifndef NO_RSA + /* read client RSA cert and key in DER format */ + rsaCert = (byte*)XMALLOC(FOURK_BUF, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + if (rsaCert == NULL) return -201; - privKey =(byte*)XMALLOC(FOURK_BUF, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - if (privKey == NULL) { - XFREE(cert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + rsaPrivKey = (byte*)XMALLOC(FOURK_BUF, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + if (rsaPrivKey == NULL) { + XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); return -202; } certFile = fopen(clientCert, "rb"); if (!certFile) { - XFREE(cert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(privKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(rsaPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); err_sys("can't open ./certs/client-cert.der, " "Please run from wolfSSL home dir", -42); - return -42; + return -203; } - certSz = fread(cert, 1, FOURK_BUF, certFile); + rsaCertSz = fread(rsaCert, 1, FOURK_BUF, certFile); fclose(certFile); keyFile = fopen(clientKey, "rb"); if (!keyFile) { - XFREE(cert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(privKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(rsaPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); err_sys("can't open ./certs/client-key.der, " "Please run from wolfSSL home dir", -43); - return -43; + return -204; } - privKeySz = fread(privKey, 1, FOURK_BUF, keyFile); + rsaPrivKeySz = fread(rsaPrivKey, 1, FOURK_BUF, keyFile); fclose(keyFile); +#endif /* NO_RSA */ - wc_PKCS7_InitWithCert(&pkcs7, cert, (word32)certSz); - - /* set up test vectors */ - a.content = data; - a.contentSz = (word32)sizeof(data); - a.contentOID = DATA; - a.encryptOID = DES3b; - a.privateKey = privKey; - a.privateKeySz = (word32)privKeySz; - a.outFileName = "pkcs7envelopedDataDES3.der"; - -#ifndef NO_AES - b.content = data; - b.contentSz = (word32)sizeof(data); - b.contentOID = DATA; - b.encryptOID = AES128CBCb; - b.privateKey = privKey; - b.privateKeySz = (word32)privKeySz; - b.outFileName = "pkcs7envelopedDataAES128CBC.der"; - - c.content = data; - c.contentSz = (word32)sizeof(data); - c.contentOID = DATA; - c.encryptOID = AES192CBCb; - c.privateKey = privKey; - c.privateKeySz = (word32)privKeySz; - c.outFileName = "pkcs7envelopedDataAES192CBC.der"; - - d.content = data; - d.contentSz = (word32)sizeof(data); - d.contentOID = DATA; - d.encryptOID = AES256CBCb; - d.privateKey = privKey; - d.privateKeySz = (word32)privKeySz; - d.outFileName = "pkcs7envelopedDataAES256CBC.der"; -#endif - - test_pkcs7env[0] = a; -#ifndef NO_AES - test_pkcs7env[1] = b; - test_pkcs7env[2] = c; - test_pkcs7env[3] = d; -#endif - - for (i = 0; i < times; i++) { - pkcs7.content = (byte*)test_pkcs7env[i].content; - pkcs7.contentSz = test_pkcs7env[i].contentSz; - pkcs7.contentOID = test_pkcs7env[i].contentOID; - pkcs7.encryptOID = test_pkcs7env[i].encryptOID; - pkcs7.privateKey = test_pkcs7env[i].privateKey; - pkcs7.privateKeySz = test_pkcs7env[i].privateKeySz; - - /* encode envelopedData */ - envelopedSz = wc_PKCS7_EncodeEnvelopedData(&pkcs7, enveloped, - sizeof(enveloped)); - if (envelopedSz <= 0) { - XFREE(cert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(privKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - return -203; - } - - /* decode envelopedData */ - decodedSz = wc_PKCS7_DecodeEnvelopedData(&pkcs7, enveloped, envelopedSz, - decoded, sizeof(decoded)); - if (decodedSz <= 0) { - XFREE(cert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(privKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - return -204; - } - - /* test decode result */ - if (XMEMCMP(decoded, data, sizeof(data)) != 0) { - XFREE(cert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(privKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - return -205; - } - - /* output pkcs7 envelopedData for external testing */ - pkcs7File = fopen(test_pkcs7env[i].outFileName, "wb"); - if (!pkcs7File) { - XFREE(cert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(privKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - return -206; - } - - ret = (int)fwrite(enveloped, envelopedSz, 1, pkcs7File); - fclose(pkcs7File); +#ifdef HAVE_ECC + /* read client ECC cert and key in DER format */ + eccCert = (byte*)XMALLOC(FOURK_BUF, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + if (eccCert == NULL) { + XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(rsaPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + return -205; } - XFREE(cert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(privKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - wc_PKCS7_Free(&pkcs7); + eccPrivKey =(byte*)XMALLOC(FOURK_BUF, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + if (eccPrivKey == NULL) { + XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(rsaPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(eccCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + return -206; + } - if (ret > 0) - return 0; + certFile = fopen(eccClientCert, "rb"); + if (!certFile) { + XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(rsaPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(eccCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(eccPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + err_sys("can't open ./certs/client-ecc-cert.der, " + "Please run from wolfSSL home dir", -42); + return -207; + } - return ret; + eccCertSz = fread(eccCert, 1, FOURK_BUF, certFile); + fclose(certFile); + + keyFile = fopen(eccClientKey, "rb"); + if (!keyFile) { + XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(rsaPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(eccCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(eccPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + err_sys("can't open ./certs/ecc-client-key.der, " + "Please run from wolfSSL home dir", -43); + return -208; + } + + eccPrivKeySz = fread(eccPrivKey, 1, FOURK_BUF, keyFile); + fclose(keyFile); +#endif /* HAVE_ECC */ + + ret = pkcs7enveloped_run_vectors(rsaCert, rsaCertSz, + rsaPrivKey, rsaPrivKeySz, + eccCert, eccCertSz, + eccPrivKey, eccPrivKeySz); + if (ret != 0) { + XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(rsaPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(eccCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(eccPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + return ret; + } + + XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(rsaPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(eccCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(eccPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + + return 0; } + +typedef struct { + const byte* content; + word32 contentSz; + int contentOID; + int encryptOID; + byte* encryptionKey; + word32 encryptionKeySz; + PKCS7Attrib* attribs; + word32 attribsSz; + const char* outFileName; +} pkcs7EncryptedVector; + + int pkcs7encrypted_test(void) { - int ret, encryptedSz, decodedSz; + int ret, i, testSz; + int encryptedSz, decodedSz, attribIdx; PKCS7 pkcs7; byte encrypted[2048]; byte decoded[2048]; @@ -9248,8 +9359,8 @@ int pkcs7encrypted_test(void) }; byte aes192Key[] = { 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08, - 0x01,0x02,0x03,0x05,0x05,0x06,0x07,0x08, - 0x01,0x02,0x03,0x05,0x05,0x06,0x07,0x08 + 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08, + 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08 }; byte aes256Key[] = { 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08, @@ -9290,108 +9401,50 @@ int pkcs7encrypted_test(void) { genAttrOid2, sizeof(genAttrOid2), genAttr2, sizeof(genAttr2) } }; - pkcs7Vector a, b; -#ifndef NO_AES - pkcs7Vector c, d, e, f, g; - pkcs7Vector test_pkcs7enc[7]; -#else - pkcs7Vector test_pkcs7enc[1]; -#endif - int times = sizeof(test_pkcs7enc) / sizeof(pkcs7Vector); - int i, attribIdx; + const pkcs7EncryptedVector testVectors[] = + { +#ifndef NO_DES3 + {data, (word32)sizeof(data), DATA, DES3b, des3Key, sizeof(des3Key), + NULL, 0, "pkcs7encryptedDataDES3.der"}, - /* set up test vectors */ - a.content = data; - a.contentSz = (word32)sizeof(data); - a.contentOID = DATA; - a.encryptOID = DES3b; - a.encryptionKey = des3Key; - a.encryptionKeySz = sizeof(des3Key); - a.outFileName = "pkcs7encryptedDataDES3.der"; - a.attribs = NULL; - a.attribsSz = 0; - - b.content = data; - b.contentSz = (word32)sizeof(data); - b.contentOID = DATA; - b.encryptOID = DESb; - b.encryptionKey = desKey; - b.encryptionKeySz = sizeof(desKey); - b.outFileName = "pkcs7encryptedDataDES.der"; - b.attribs = NULL; - b.attribsSz = 0; + {data, (word32)sizeof(data), DATA, DESb, desKey, sizeof(desKey), + NULL, 0, "pkcs7encryptedDataDES.der"}, +#endif /* NO_DES3 */ #ifndef NO_AES - c.content = data; - c.contentSz = (word32)sizeof(data); - c.contentOID = DATA; - c.encryptOID = AES128CBCb; - c.encryptionKey = aes128Key; - c.encryptionKeySz = sizeof(aes128Key); - c.outFileName = "pkcs7encryptedDataAES128CBC.der"; - c.attribs = NULL; - c.attribsSz = 0; + {data, (word32)sizeof(data), DATA, AES128CBCb, aes128Key, + sizeof(aes128Key), NULL, 0, "pkcs7encryptedDataAES128CBC.der"}, - d.content = data; - d.contentSz = (word32)sizeof(data); - d.contentOID = DATA; - d.encryptOID = AES192CBCb; - d.encryptionKey = aes192Key; - d.encryptionKeySz = sizeof(aes192Key); - d.outFileName = "pkcs7encryptedDataAES192CBC.der"; - d.attribs = NULL; - d.attribsSz = 0; + {data, (word32)sizeof(data), DATA, AES192CBCb, aes192Key, + sizeof(aes192Key), NULL, 0, "pkcs7encryptedDataAES192CBC.der"}, - e.content = data; - e.contentSz = (word32)sizeof(data); - e.contentOID = DATA; - e.encryptOID = AES256CBCb; - e.encryptionKey = aes256Key; - e.encryptionKeySz = sizeof(aes256Key); - e.outFileName = "pkcs7encryptedDataAES256CBC.der"; - e.attribs = NULL; - e.attribsSz = 0; + {data, (word32)sizeof(data), DATA, AES256CBCb, aes256Key, + sizeof(aes256Key), NULL, 0, "pkcs7encryptedDataAES256CBC.der"}, - f.content = data; - f.contentSz = (word32)sizeof(data); - f.contentOID = DATA; - f.encryptOID = AES256CBCb; - f.encryptionKey = aes256Key; - f.encryptionKeySz = sizeof(aes256Key); - f.outFileName = "pkcs7encryptedDataAES256CBC_attribs.der"; - f.attribs = attribs; - f.attribsSz = sizeof(attribs)/sizeof(PKCS7Attrib); + /* test with optional unprotected attributes */ + {data, (word32)sizeof(data), DATA, AES256CBCb, aes256Key, + sizeof(aes256Key), attribs, (sizeof(attribs)/sizeof(PKCS7Attrib)), + "pkcs7encryptedDataAES256CBC_attribs.der"}, - g.content = data; - g.contentSz = (word32)sizeof(data); - g.contentOID = DATA; - g.encryptOID = AES256CBCb; - g.encryptionKey = aes256Key; - g.encryptionKeySz = sizeof(aes256Key); - g.outFileName = "pkcs7encryptedDataAES256CBC_multi_attribs.der"; - g.attribs = multiAttribs; - g.attribsSz = sizeof(multiAttribs)/sizeof(PKCS7Attrib); -#endif + /* test with multiple optional unprotected attributes */ + {data, (word32)sizeof(data), DATA, AES256CBCb, aes256Key, + sizeof(aes256Key), multiAttribs, + (sizeof(multiAttribs)/sizeof(PKCS7Attrib)), + "pkcs7encryptedDataAES256CBC_multi_attribs.der"}, +#endif /* NO_AES */ + }; - test_pkcs7enc[0] = a; - test_pkcs7enc[1] = b; -#ifndef NO_AES - test_pkcs7enc[2] = c; - test_pkcs7enc[3] = d; - test_pkcs7enc[4] = e; - test_pkcs7enc[5] = f; - test_pkcs7enc[6] = g; -#endif + testSz = sizeof(testVectors) / sizeof(pkcs7EncryptedVector); - for (i = 0; i < times; i++) { - pkcs7.content = (byte*)test_pkcs7enc[i].content; - pkcs7.contentSz = test_pkcs7enc[i].contentSz; - pkcs7.contentOID = test_pkcs7enc[i].contentOID; - pkcs7.encryptOID = test_pkcs7enc[i].encryptOID; - pkcs7.encryptionKey = test_pkcs7enc[i].encryptionKey; - pkcs7.encryptionKeySz = test_pkcs7enc[i].encryptionKeySz; - pkcs7.unprotectedAttribs = test_pkcs7enc[i].attribs; - pkcs7.unprotectedAttribsSz = test_pkcs7enc[i].attribsSz; + for (i = 0; i < testSz; i++) { + pkcs7.content = (byte*)testVectors[i].content; + pkcs7.contentSz = testVectors[i].contentSz; + pkcs7.contentOID = testVectors[i].contentOID; + pkcs7.encryptOID = testVectors[i].encryptOID; + pkcs7.encryptionKey = testVectors[i].encryptionKey; + pkcs7.encryptionKeySz = testVectors[i].encryptionKeySz; + pkcs7.unprotectedAttribs = testVectors[i].attribs; + pkcs7.unprotectedAttribsSz = testVectors[i].attribsSz; /* encode encryptedData */ encryptedSz = wc_PKCS7_EncodeEncryptedData(&pkcs7, encrypted, @@ -9436,15 +9489,15 @@ int pkcs7encrypted_test(void) } /* output pkcs7 envelopedData for external testing */ - pkcs7File = fopen(test_pkcs7enc[i].outFileName, "wb"); + pkcs7File = fopen(testVectors[i].outFileName, "wb"); if (!pkcs7File) return -208; ret = (int)fwrite(encrypted, encryptedSz, 1, pkcs7File); fclose(pkcs7File); - } - wc_PKCS7_Free(&pkcs7); + wc_PKCS7_Free(&pkcs7); + } if (ret > 0) return 0; diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index b2f0c67d7..fdb8dc7dc 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -213,6 +213,8 @@ enum Oid_Types { oidCertAltNameType = 9, oidCertKeyUseType = 10, oidKdfType = 11, + oidKeyWrapType = 12, + oidCmsKeyAgreeType = 13, oidIgnoreType }; @@ -245,6 +247,22 @@ enum Key_Sum { }; +enum KeyWrap_Sum { + AES128_WRAP = 417, + AES192_WRAP = 437, + AES256_WRAP = 457 +}; + + +enum Key_Agree { + dhSinglePass_stdDH_sha1kdf_scheme = 464, + dhSinglePass_stdDH_sha224kdf_scheme = 188, + dhSinglePass_stdDH_sha256kdf_scheme = 189, + dhSinglePass_stdDH_sha384kdf_scheme = 190, + dhSinglePass_stdDH_sha512kdf_scheme = 191, +}; + + enum Ecc_Sum { ECC_SECP112R1_OID = 182, ECC_SECP112R2_OID = 183, diff --git a/wolfssl/wolfcrypt/pkcs7.h b/wolfssl/wolfcrypt/pkcs7.h index 357b24ea7..5ffab85ba 100644 --- a/wolfssl/wolfcrypt/pkcs7.h +++ b/wolfssl/wolfcrypt/pkcs7.h @@ -96,6 +96,8 @@ typedef struct PKCS7 { int hashOID; int encryptOID; /* key encryption algorithm OID */ + int keyWrapOID; /* key wrap algorithm OID */ + int keyAgreeOID; /* key agreement algorithm OID */ void* heap; /* heap hint for dynamic memory */ byte* singleCert; /* recipient cert, DER, not owner */ @@ -105,14 +107,20 @@ typedef struct PKCS7 { word32 issuerSz; /* length of issuer name */ byte issuerSn[MAX_SN_SZ]; /* singleCert's serial number */ word32 issuerSnSz; /* length of serial number */ + byte publicKey[512]; word32 publicKeySz; + word32 publicKeyOID; /* key OID (RSAk, ECDSAk, etc) */ byte* privateKey; /* private key, DER, not owner */ word32 privateKeySz; /* size of private key buffer, bytes */ PKCS7Attrib* signedAttribs; word32 signedAttribsSz; + /* Enveloped-data optional ukm, not owner */ + byte* ukm; + word32 ukmSz; + /* Encrypted-data Content Type */ byte* encryptionKey; /* block cipher encryption key */ word32 encryptionKeySz; /* size of key buffer, bytes */ @@ -122,34 +130,6 @@ typedef struct PKCS7 { } PKCS7; -WOLFSSL_LOCAL int wc_PKCS7_SetHeap(PKCS7* pkcs7, void* heap); -WOLFSSL_LOCAL int wc_SetContentType(int pkcs7TypeOID, byte* output); -WOLFSSL_LOCAL int wc_GetContentType(const byte* input, word32* inOutIdx, - word32* oid, word32 maxIdx); -WOLFSSL_LOCAL int wc_CreateRecipientInfo(const byte* cert, word32 certSz, - int keyEncAlgo, int blockKeySz, - WC_RNG* rng, byte* contentKeyPlain, - byte* contentKeyEnc, int* keyEncSz, - byte* out, word32 outSz, void* heap); -WOLFSSL_LOCAL int wc_PKCS7_EncryptContent(int encryptOID, byte* key, int keySz, - byte* iv, int ivSz, byte* in, int inSz, - byte* out); -WOLFSSL_LOCAL int wc_PKCS7_DecryptContent(int encryptOID, byte* key, int keySz, - byte* iv, int ivSz, byte* in, int inSz, - byte* out); -WOLFSSL_LOCAL int wc_PKCS7_GenerateIV(WC_RNG* rng, byte* iv, word32 ivSz); -WOLFSSL_LOCAL int wc_PKCS7_GetPadSize(word32 inputSz, word32 blockSz); -WOLFSSL_LOCAL int wc_PKCS7_PadData(byte* in, word32 inSz, byte* out, word32 outSz, - word32 blockSz); -WOLFSSL_LOCAL int wc_PKCS7_GetOIDBlockSize(int oid); -WOLFSSL_LOCAL int wc_PKCS7_GetOIDKeySize(int oid); -WOLFSSL_LOCAL int wc_PKCS7_DecodeUnprotectedAttributes(PKCS7* pkcs7, - byte* pkiMsg, word32 pkiMsgSz, - word32* inOutIdx); -WOLFSSL_LOCAL void wc_PKCS7_FreeDecodedAttrib(PKCS7DecodedAttrib* attrib, - void* heap); - - WOLFSSL_API int wc_PKCS7_InitWithCert(PKCS7* pkcs7, byte* cert, word32 certSz); WOLFSSL_API void wc_PKCS7_Free(PKCS7* pkcs7); WOLFSSL_API int wc_PKCS7_EncodeData(PKCS7* pkcs7, byte* output, diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index 95fbf5179..a0b238ae8 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -1448,6 +1448,15 @@ static char *fgets(char *buff, int sz, FILE *fp) #endif #endif +#ifdef HAVE_PKCS7 + #ifndef HAVE_AES_KEYWRAP + #error PKCS7 requires AES key wrap please define HAVE_AES_KEYWRAP + #endif + #ifndef HAVE_X963_KDF + #error PKCS7 requires X963 KDF please define HAVE_X963_KDF + #endif +#endif + /* Place any other flags or defines here */ diff --git a/wolfssl/wolfcrypt/types.h b/wolfssl/wolfcrypt/types.h index 8a2022808..e5aa83b3a 100644 --- a/wolfssl/wolfcrypt/types.h +++ b/wolfssl/wolfcrypt/types.h @@ -338,7 +338,8 @@ DYNAMIC_TYPE_DTLS_BUFFER = 56, DYNAMIC_TYPE_SESSION_TICK = 57, DYNAMIC_TYPE_PKCS = 58, - DYNAMIC_TYPE_MUTEX = 59 + DYNAMIC_TYPE_MUTEX = 59, + DYNAMIC_TYPE_PKCS7 = 60 }; /* max error buffer string size */ From e5d1e3ae1019cbaaa58ed644716fbd34c8637ec4 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Tue, 13 Dec 2016 09:52:25 -0700 Subject: [PATCH 5/6] PKCS#7: only output test bundles when PKCS7_OUTPUT_TEST_BUNDLES is defined --- wolfcrypt/src/pkcs7.c | 14 +++++++------- wolfcrypt/test/test.c | 32 +++++++++++++++++++++++++++----- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index 0e534a5a8..bd459e330 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -1052,19 +1052,19 @@ int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz) /* KARI == KeyAgreeRecipientInfo (key agreement) */ typedef struct WC_PKCS7_KARI { DecodedCert* decoded; /* decoded recip cert */ + void* heap; /* user heap, points to PKCS7->heap */ ecc_key* recipKey; /* recip key (pub | priv) */ ecc_key* senderKey; /* sender key (pub | priv) */ byte* senderKeyExport; /* sender ephemeral key DER */ - word32 senderKeyExportSz; /* size of sender ephemeral key DER */ byte* kek; /* key encryption key */ - word32 kekSz; /* size of key encryption key */ byte* ukm; /* OPTIONAL user keying material */ - word32 ukmSz; /* size of user keying material */ - byte ukmOwner; /* do we own ukm buffer? 1:yes, 0:no */ byte* sharedInfo; /* ECC-CMS-SharedInfo ASN.1 encoded blob */ + word32 senderKeyExportSz; /* size of sender ephemeral key DER */ + word32 kekSz; /* size of key encryption key */ + word32 ukmSz; /* size of user keying material */ word32 sharedInfoSz; /* size of ECC-CMS-SharedInfo encoded */ + byte ukmOwner; /* do we own ukm buffer? 1:yes, 0:no */ byte direction; /* WC_PKCS7_ENCODE | WC_PKCS7_DECODE */ - void* heap; /* user heap, points to PKCS7->heap */ } WC_PKCS7_KARI; @@ -2468,7 +2468,7 @@ static int wc_PKCS7_DecodeKtri(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, word32 encOID; word32 keyIdx; byte issuerHash[SHA_DIGEST_SIZE]; - byte* outKey; + byte* outKey = NULL; #ifdef WC_RSA_BLINDING WC_RNG rng; @@ -2605,7 +2605,7 @@ static int wc_PKCS7_DecodeKtri(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, XFREE(privKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif - if (keySz <= 0) { + if (keySz <= 0 || outKey == NULL) { ForceZero(encryptedKey, MAX_ENCRYPTED_KEY_SZ); return keySz; } else { diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 5278f90a7..4270976a5 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -9052,6 +9052,15 @@ int compress_test(void) #ifdef HAVE_PKCS7 +/* External Debugging/Testing Note: + * + * PKCS#7 test functions can output generated PKCS#7/CMS bundles for + * additional testing. To dump bundles to files DER encoded files, please + * define: + * + * #define PKCS7_OUTPUT_TEST_BUNDLES + */ + typedef struct { const byte* content; word32 contentSz; @@ -9080,7 +9089,9 @@ static int pkcs7enveloped_run_vectors(byte* rsaCert, word32 rsaCertSz, byte enveloped[2048]; byte decoded[2048]; PKCS7 pkcs7; +#ifdef PKCS7_OUTPUT_TEST_BUNDLES FILE* pkcs7File; +#endif const byte data[] = { /* Hello World */ 0x48,0x65,0x6c,0x6c,0x6f,0x20,0x57,0x6f, @@ -9179,6 +9190,7 @@ static int pkcs7enveloped_run_vectors(byte* rsaCert, word32 rsaCertSz, if (XMEMCMP(decoded, data, sizeof(data)) != 0) return -212; +#ifdef PKCS7_OUTPUT_TEST_BUNDLES /* output pkcs7 envelopedData for external testing */ pkcs7File = fopen(testVectors[i].outFileName, "wb"); if (!pkcs7File) @@ -9186,6 +9198,7 @@ static int pkcs7enveloped_run_vectors(byte* rsaCert, word32 rsaCertSz, ret = (int)fwrite(enveloped, envelopedSz, 1, pkcs7File); fclose(pkcs7File); +#endif /* PKCS7_OUTPUT_TEST_BUNDLES */ wc_PKCS7_Free(&pkcs7); } @@ -9294,10 +9307,10 @@ int pkcs7enveloped_test(void) fclose(keyFile); #endif /* HAVE_ECC */ - ret = pkcs7enveloped_run_vectors(rsaCert, rsaCertSz, - rsaPrivKey, rsaPrivKeySz, - eccCert, eccCertSz, - eccPrivKey, eccPrivKeySz); + ret = pkcs7enveloped_run_vectors(rsaCert, (word32)rsaCertSz, + rsaPrivKey, (word32)rsaPrivKeySz, + eccCert, (word32)eccCertSz, + eccPrivKey, (word32)eccPrivKeySz); if (ret != 0) { XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); XFREE(rsaPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); @@ -9330,12 +9343,15 @@ typedef struct { int pkcs7encrypted_test(void) { - int ret, i, testSz; + int ret = 0; + int i, testSz; int encryptedSz, decodedSz, attribIdx; PKCS7 pkcs7; byte encrypted[2048]; byte decoded[2048]; +#ifdef PKCS7_OUTPUT_TEST_BUNDLES FILE* pkcs7File; +#endif PKCS7Attrib* expectedAttrib; PKCS7DecodedAttrib* decodedAttrib; @@ -9488,6 +9504,7 @@ int pkcs7encrypted_test(void) } } +#ifdef PKCS7_OUTPUT_TEST_BUNDLES /* output pkcs7 envelopedData for external testing */ pkcs7File = fopen(testVectors[i].outFileName, "wb"); if (!pkcs7File) @@ -9495,6 +9512,7 @@ int pkcs7encrypted_test(void) ret = (int)fwrite(encrypted, encryptedSz, 1, pkcs7File); fclose(pkcs7File); +#endif wc_PKCS7_Free(&pkcs7); } @@ -9646,6 +9664,7 @@ int pkcs7signed_test(void) else outSz = ret; +#ifdef PKCS7_OUTPUT_TEST_BUNDLES /* write PKCS#7 to output file for more testing */ file = fopen("./pkcs7signedData.der", "wb"); if (!file) { @@ -9664,6 +9683,7 @@ int pkcs7signed_test(void) wc_PKCS7_Free(&msg); return -218; } +#endif /* PKCS7_OUTPUT_TEST_BUNDLES */ wc_PKCS7_Free(&msg); wc_PKCS7_InitWithCert(&msg, NULL, 0); @@ -9685,6 +9705,7 @@ int pkcs7signed_test(void) return -215; } +#ifdef PKCS7_OUTPUT_TEST_BUNDLES file = fopen("./pkcs7cert.der", "wb"); if (!file) { XFREE(certDer, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); @@ -9695,6 +9716,7 @@ int pkcs7signed_test(void) } ret = (int)fwrite(msg.singleCert, 1, msg.singleCertSz, file); fclose(file); +#endif /* PKCS7_OUTPUT_TEST_BUNDLES */ XFREE(certDer, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); XFREE(keyDer, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); From 55554b79a9ba779702456a16b4d92c77d3232638 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Wed, 14 Dec 2016 09:15:45 -0700 Subject: [PATCH 6/6] PKCS#7: fix use after free in wc_DecodeKtri --- wolfcrypt/src/pkcs7.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index bd459e330..65351f09f 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -2600,13 +2600,12 @@ static int wc_PKCS7_DecodeKtri(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, } wc_FreeRsaKey(privKey); -#ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(privKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#endif - if (keySz <= 0 || outKey == NULL) { ForceZero(encryptedKey, MAX_ENCRYPTED_KEY_SZ); +#ifdef WOLFSSL_SMALL_STACK + XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(privKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif return keySz; } else { *decryptedKeySz = keySz; @@ -2614,6 +2613,11 @@ static int wc_PKCS7_DecodeKtri(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, ForceZero(encryptedKey, MAX_ENCRYPTED_KEY_SZ); } +#ifdef WOLFSSL_SMALL_STACK + XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(privKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return 0; }