add support for PKCS7/CMS EnvelopedData with fragmented encrypted content

This commit is contained in:
Chris Conlon
2020-02-27 14:42:57 -07:00
parent c7a2510d97
commit d21e370822
3 changed files with 105 additions and 31 deletions

View File

@@ -18416,7 +18416,7 @@ static void test_wc_PKCS7_BER(void)
XFILE f; XFILE f;
byte der[4096]; byte der[4096];
#ifndef NO_DES3 #ifndef NO_DES3
byte decoded[1024]; byte decoded[2048];
#endif #endif
word32 derSz; word32 derSz;
int ret; int ret;

View File

@@ -1172,6 +1172,11 @@ void wc_PKCS7_Free(PKCS7* pkcs7)
pkcs7->pkcs7Digest = NULL; pkcs7->pkcs7Digest = NULL;
pkcs7->pkcs7DigestSz = 0; pkcs7->pkcs7DigestSz = 0;
} }
if (pkcs7->cachedEncryptedContent != NULL) {
XFREE(pkcs7->cachedEncryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
pkcs7->cachedEncryptedContent = NULL;
pkcs7->cachedEncryptedContentSz = 0;
}
if (pkcs7->isDynamic) { if (pkcs7->isDynamic) {
pkcs7->isDynamic = 0; pkcs7->isDynamic = 0;
@@ -9987,6 +9992,41 @@ WOLFSSL_API int wc_PKCS7_SetKey(PKCS7* pkcs7, byte* key, word32 keySz)
} }
/* append data to encrypted content cache in PKCS7 structure
* return 0 on success, negative on error */
static int PKCS7_CacheEncryptedContent(PKCS7* pkcs7, byte* in, word32 inSz)
{
byte* oldCache;
word32 oldCacheSz;
if (pkcs7 == NULL || in == NULL)
return BAD_FUNC_ARG;
/* save pointer to old cache */
oldCache = pkcs7->cachedEncryptedContent;
oldCacheSz = pkcs7->cachedEncryptedContentSz;
/* re-allocate new buffer to fit appended data */
pkcs7->cachedEncryptedContent = (byte*)XMALLOC(oldCacheSz + inSz,
pkcs7->heap, DYNAMIC_TYPE_PKCS7);
if (pkcs7->cachedEncryptedContent == NULL) {
pkcs7->cachedEncryptedContentSz = 0;
XFREE(oldCache, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
return MEMORY_E;
}
if (oldCache != NULL) {
XMEMCPY(pkcs7->cachedEncryptedContent, oldCache, oldCacheSz);
}
XMEMCPY(pkcs7->cachedEncryptedContent + oldCacheSz, in, inSz);
pkcs7->cachedEncryptedContentSz += inSz;
XFREE(oldCache, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
return 0;
}
/* unwrap and decrypt PKCS#7 envelopedData object, return decoded size */ /* unwrap and decrypt PKCS#7 envelopedData object, return decoded size */
WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* in, WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* in,
word32 inSz, byte* output, word32 inSz, byte* output,
@@ -10009,6 +10049,7 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* in,
byte* pkiMsg = in; byte* pkiMsg = in;
word32 pkiMsgSz = inSz; word32 pkiMsgSz = inSz;
byte* decryptedKey = NULL; byte* decryptedKey = NULL;
int encryptedContentTotalSz = 0;
int encryptedContentSz = 0; int encryptedContentSz = 0;
byte padLen; byte padLen;
byte* encryptedContent = NULL; byte* encryptedContent = NULL;
@@ -10223,27 +10264,51 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* in,
} }
idx++; idx++;
if (ret == 0 && GetLength(pkiMsg, &idx, &encryptedContentSz, if (ret == 0 && GetLength(pkiMsg, &idx, &encryptedContentTotalSz,
pkiMsgSz) <= 0) { pkiMsgSz) <= 0) {
ret = ASN_PARSE_E; ret = ASN_PARSE_E;
} }
if (ret == 0 && explicitOctet) { if (ret == 0 && explicitOctet) {
if (GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) < 0) { /* encrypted content may be fragmented into multiple
ret = ASN_PARSE_E; * consecutive OCTET STRINGs, if so loop through
break; * collecting and caching encrypted content bytes */
} localIdx = idx;
while (idx < (localIdx + encryptedContentTotalSz)) {
if (tag != ASN_OCTET_STRING) { if (GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) < 0) {
ret = ASN_PARSE_E; ret = ASN_PARSE_E;
break; break;
} }
if (ret == 0 && GetLength(pkiMsg, &idx, &encryptedContentSz, if (tag != ASN_OCTET_STRING) {
pkiMsgSz) <= 0) { ret = ASN_PARSE_E;
ret = ASN_PARSE_E; break;
}
if (ret == 0 && GetLength(pkiMsg, &idx,
&encryptedContentSz, pkiMsgSz) <= 0) {
ret = ASN_PARSE_E;
break;
}
ret = PKCS7_CacheEncryptedContent(pkcs7, &pkiMsg[idx],
encryptedContentSz);
if (ret != 0) {
break;
}
/* advance idx past encrypted content */
idx += encryptedContentSz;
}
} else {
/* cache encrypted content, no OCTET STRING */
ret = PKCS7_CacheEncryptedContent(pkcs7, &pkiMsg[idx],
encryptedContentTotalSz);
if (ret != 0) {
break; break;
} }
idx += encryptedContentTotalSz;
} }
if (ret != 0) if (ret != 0)
@@ -10253,10 +10318,9 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* in,
if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) { if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) {
break; break;
} }
pkcs7->stream->expected = encryptedContentSz; pkcs7->stream->expected = 0;
wc_PKCS7_StreamGetVar(pkcs7, &encOID, &expBlockSz, 0); wc_PKCS7_StreamGetVar(pkcs7, &encOID, &expBlockSz, 0);
wc_PKCS7_StreamStoreVar(pkcs7, encOID, expBlockSz, wc_PKCS7_StreamStoreVar(pkcs7, encOID, expBlockSz, 0);
encryptedContentSz);
#endif #endif
wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_ENV_5); wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_ENV_5);
FALL_THROUGH; FALL_THROUGH;
@@ -10269,8 +10333,7 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* in,
return ret; return ret;
} }
wc_PKCS7_StreamGetVar(pkcs7, &encOID, &expBlockSz, wc_PKCS7_StreamGetVar(pkcs7, &encOID, &expBlockSz, NULL);
&encryptedContentSz);
tmpIv = pkcs7->stream->tmpIv; tmpIv = pkcs7->stream->tmpIv;
/* restore decrypted key */ /* restore decrypted key */
@@ -10280,23 +10343,16 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* in,
#else #else
ret = 0; ret = 0;
#endif #endif
encryptedContent = (byte*)XMALLOC(encryptedContentSz, pkcs7->heap,
DYNAMIC_TYPE_PKCS7);
if (encryptedContent == NULL) {
ret = MEMORY_E;
break;
}
if (ret == 0) { /* use cached content */
XMEMCPY(encryptedContent, &pkiMsg[idx], encryptedContentSz); encryptedContent = pkcs7->cachedEncryptedContent;
} encryptedContentSz = pkcs7->cachedEncryptedContentSz;
/* decrypt encryptedContent */ /* decrypt encryptedContent */
ret = wc_PKCS7_DecryptContent(pkcs7, encOID, decryptedKey, ret = wc_PKCS7_DecryptContent(pkcs7, encOID, decryptedKey,
blockKeySz, tmpIv, expBlockSz, NULL, 0, NULL, 0, blockKeySz, tmpIv, expBlockSz, NULL, 0, NULL, 0,
encryptedContent, encryptedContentSz, encryptedContent); encryptedContent, encryptedContentSz, encryptedContent);
if (ret != 0) { if (ret != 0) {
XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
break; break;
} }
@@ -10305,7 +10361,6 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* in,
/* copy plaintext to output */ /* copy plaintext to output */
if (padLen > encryptedContentSz || if (padLen > encryptedContentSz ||
(word32)(encryptedContentSz - padLen) > outputSz) { (word32)(encryptedContentSz - padLen) > outputSz) {
XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
ret = BUFFER_E; ret = BUFFER_E;
break; break;
} }
@@ -10313,9 +10368,13 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* in,
/* free memory, zero out keys */ /* free memory, zero out keys */
ForceZero(decryptedKey, MAX_ENCRYPTED_KEY_SZ); ForceZero(decryptedKey, MAX_ENCRYPTED_KEY_SZ);
ForceZero(encryptedContent, encryptedContentSz);
XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
if (pkcs7->cachedEncryptedContent != NULL) {
XFREE(pkcs7->cachedEncryptedContent, pkcs7->heap,
DYNAMIC_TYPE_PKCS7);
pkcs7->cachedEncryptedContent = NULL;
pkcs7->cachedEncryptedContentSz = 0;
}
ret = encryptedContentSz - padLen; ret = encryptedContentSz - padLen;
#ifndef NO_PKCS7_STREAM #ifndef NO_PKCS7_STREAM
@@ -10335,12 +10394,23 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* in,
if (ret < 0 && ret != WC_PKCS7_WANT_READ_E) { if (ret < 0 && ret != WC_PKCS7_WANT_READ_E) {
wc_PKCS7_ResetStream(pkcs7); wc_PKCS7_ResetStream(pkcs7);
wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_START); wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_START);
if (pkcs7->cachedEncryptedContent != NULL) {
XFREE(pkcs7->cachedEncryptedContent, pkcs7->heap,
DYNAMIC_TYPE_PKCS7);
pkcs7->cachedEncryptedContent = NULL;
pkcs7->cachedEncryptedContentSz = 0;
}
} }
#else #else
if (decryptedKey != NULL && ret < 0) { if (decryptedKey != NULL && ret < 0) {
ForceZero(decryptedKey, MAX_ENCRYPTED_KEY_SZ); ForceZero(decryptedKey, MAX_ENCRYPTED_KEY_SZ);
XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
} }
if (pkcs7->cachedEncryptedContent != NULL && ret < 0) {
XFREE(pkcs7->cachedEncryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
pkcs7->cachedEncryptedContent = NULL;
pkcs7->cachedEncryptedContentSz = 0;
}
#endif #endif
return ret; return ret;
} }

View File

@@ -330,6 +330,10 @@ struct PKCS7 {
#if defined(HAVE_PKCS7_RSA_RAW_SIGN_CALLBACK) && !defined(NO_RSA) #if defined(HAVE_PKCS7_RSA_RAW_SIGN_CALLBACK) && !defined(NO_RSA)
CallbackRsaSignRawDigest rsaSignRawDigestCb; CallbackRsaSignRawDigest rsaSignRawDigestCb;
#endif #endif
/* used by DecodeEnvelopedData with multiple encrypted contents */
byte* cachedEncryptedContent;
word32 cachedEncryptedContentSz;
/* !! NEW DATA MEMBERS MUST BE ADDED AT END !! */ /* !! NEW DATA MEMBERS MUST BE ADDED AT END !! */
}; };