Merge pull request #2829 from cconlon/pkcs7multioctets

PKCS7/CMS EnvelopedData support for fragmented encrypted content
This commit is contained in:
JacobBarthelmeh
2020-03-16 13:12:23 -06:00
committed by GitHub
3 changed files with 120 additions and 39 deletions

View File

@@ -19355,7 +19355,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,10 +10049,11 @@ 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;
int explicitOctet; int explicitOctet = 0;
word32 localIdx; word32 localIdx;
byte tag; byte tag;
@@ -10223,29 +10264,11 @@ 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 (GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) < 0) {
ret = ASN_PARSE_E;
break;
}
if (tag != ASN_OCTET_STRING) {
ret = ASN_PARSE_E;
break;
}
if (ret == 0 && GetLength(pkiMsg, &idx, &encryptedContentSz,
pkiMsgSz) <= 0) {
ret = ASN_PARSE_E;
break;
}
}
if (ret != 0) if (ret != 0)
break; break;
@@ -10253,10 +10276,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 = encryptedContentTotalSz;
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, explicitOctet);
encryptedContentSz);
#endif #endif
wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_ENV_5); wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_ENV_5);
FALL_THROUGH; FALL_THROUGH;
@@ -10269,9 +10291,9 @@ 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, &explicitOctet);
&encryptedContentSz);
tmpIv = pkcs7->stream->tmpIv; tmpIv = pkcs7->stream->tmpIv;
encryptedContentTotalSz = pkcs7->stream->expected;
/* restore decrypted key */ /* restore decrypted key */
decryptedKey = pkcs7->stream->aad; decryptedKey = pkcs7->stream->aad;
@@ -10280,23 +10302,63 @@ 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 (explicitOctet) {
if (encryptedContent == NULL) { /* encrypted content may be fragmented into multiple
ret = MEMORY_E; * consecutive OCTET STRINGs, if so loop through
break; * collecting and caching encrypted content bytes */
localIdx = idx;
while (idx < (localIdx + encryptedContentTotalSz)) {
if (GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) < 0) {
ret = ASN_PARSE_E;
}
if (ret == 0 && (tag != ASN_OCTET_STRING)) {
ret = ASN_PARSE_E;
}
if (ret == 0 && GetLength(pkiMsg, &idx,
&encryptedContentSz, pkiMsgSz) <= 0) {
ret = ASN_PARSE_E;
}
if (ret == 0) {
ret = PKCS7_CacheEncryptedContent(pkcs7, &pkiMsg[idx],
encryptedContentSz);
}
if (ret != 0) {
break;
}
/* advance idx past encrypted content */
idx += encryptedContentSz;
}
if (ret != 0) {
break;
}
} else {
/* cache encrypted content, no OCTET STRING */
ret = PKCS7_CacheEncryptedContent(pkcs7, &pkiMsg[idx],
encryptedContentTotalSz);
if (ret != 0) {
break;
}
idx += encryptedContentTotalSz;
} }
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 +10367,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 +10374,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 +10400,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;
} }
@@ -11386,7 +11462,8 @@ authenv_atrbend:
encodedAttribs = pkcs7->stream->aad; encodedAttribs = pkcs7->stream->aad;
} }
wc_PKCS7_StreamGetVar(pkcs7, &encOID, &blockKeySz, &encryptedContentSz); wc_PKCS7_StreamGetVar(pkcs7, &encOID, &blockKeySz,
&encryptedContentSz);
encryptedContent = pkcs7->stream->bufferPt; encryptedContent = pkcs7->stream->bufferPt;
#ifdef WOLFSSL_SMALL_STACK #ifdef WOLFSSL_SMALL_STACK
decryptedKey = pkcs7->stream->key; decryptedKey = pkcs7->stream->key;

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 !! */
}; };