Skip to content

Commit 7d85e39

Browse files
Merge pull request #6769 from cconlon/pkcs7ContentType
Support PKCS#7 definition for ContentType content ANY
2 parents 6b6c9f9 + 0bb9b85 commit 7d85e39

2 files changed

Lines changed: 116 additions & 44 deletions

File tree

wolfcrypt/src/pkcs7.c

Lines changed: 115 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -3786,7 +3786,10 @@ static int wc_PKCS7_VerifyContentMessageDigest(PKCS7* pkcs7,
37863786
word32 hashSz)
37873787
{
37883788
int ret = 0, digestSz = 0, innerAttribSz = 0;
3789+
int contentLen = 0;
37893790
word32 idx = 0;
3791+
word32 contentIdx = 0;
3792+
byte* content = NULL;
37903793
byte* digestBuf = NULL;
37913794
#ifdef WOLFSSL_SMALL_STACK
37923795
byte* digest = NULL;
@@ -3845,7 +3848,29 @@ static int wc_PKCS7_VerifyContentMessageDigest(PKCS7* pkcs7,
38453848
#endif
38463849
XMEMSET(digest, 0, MAX_PKCS7_DIGEST_SZ);
38473850

3848-
ret = wc_Hash(hashType, pkcs7->content, pkcs7->contentSz, digest,
3851+
content = pkcs7->content;
3852+
contentLen = pkcs7->contentSz;
3853+
3854+
if (pkcs7->contentIsPkcs7Type == 1) {
3855+
/* Content follows PKCS#7 RFC, which defines type as ANY. CMS
3856+
* mandates OCTET_STRING which has already been stripped off.
3857+
* For PKCS#7 message digest calculation, digest is calculated
3858+
* only on the "value" of the DER encoding. As such, advance past
3859+
* the tag and length */
3860+
if (contentLen > 1) {
3861+
contentIdx++;
3862+
}
3863+
3864+
if (GetLength_ex(content, &contentIdx, &contentLen,
3865+
contentLen, 1) < 0) {
3866+
#ifdef WOLFSSL_SMALL_STACK
3867+
XFREE(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
3868+
#endif
3869+
return ASN_PARSE_E;
3870+
}
3871+
}
3872+
3873+
ret = wc_Hash(hashType, content + contentIdx, contentLen, digest,
38493874
MAX_PKCS7_DIGEST_SZ);
38503875
if (ret < 0) {
38513876
WOLFSSL_MSG("Error hashing PKCS7 content for verification");
@@ -4435,11 +4460,13 @@ static int PKCS7_VerifySignedData(PKCS7* pkcs7, const byte* hashBuf,
44354460
byte* cert = NULL;
44364461
byte* signedAttrib = NULL;
44374462
byte* contentType = NULL;
4463+
int encapContentInfoLen = 0;
44384464
int contentSz = 0, sigSz = 0, certSz = 0, signedAttribSz = 0;
44394465
word32 localIdx, start;
44404466
byte degenerate = 0;
44414467
byte detached = 0;
44424468
byte tag = 0;
4469+
word16 contentIsPkcs7Type = 0;
44434470
#ifdef ASN_BER_TO_DER
44444471
byte* der;
44454472
#endif
@@ -4649,15 +4676,16 @@ static int PKCS7_VerifySignedData(PKCS7* pkcs7, const byte* hashBuf,
46494676

46504677
#endif
46514678
/* Get the inner ContentInfo sequence */
4652-
if (GetSequence_ex(pkiMsg, &idx, &length, pkiMsgSz,
4679+
if (GetSequence_ex(pkiMsg, &idx, &encapContentInfoLen, pkiMsgSz,
46534680
NO_USER_CHECK) < 0)
46544681
ret = ASN_PARSE_E;
46554682

46564683
/* Get the inner ContentInfo contentType */
46574684
if (ret == 0) {
46584685
int isIndef = 0;
46594686
word32 tmpIdx = idx;
4660-
if (length == 0 && pkiMsg[idx-1] == ASN_INDEF_LENGTH) {
4687+
if (encapContentInfoLen == 0 &&
4688+
pkiMsg[idx-1] == ASN_INDEF_LENGTH) {
46614689
isIndef = 1;
46624690
}
46634691
if (GetASNObjectId(pkiMsg, &idx, &length, pkiMsgSz) == 0) {
@@ -4682,83 +4710,122 @@ static int PKCS7_VerifySignedData(PKCS7* pkcs7, const byte* hashBuf,
46824710
if (ret != 0)
46834711
break;
46844712

4685-
/* Check for content info, it could be omitted when degenerate */
4713+
/* Check for content, it could be omitted when degenerate */
46864714
localIdx = idx;
46874715
ret = 0;
46884716
if (localIdx + 1 > pkiMsgSz) {
46894717
ret = BUFFER_E;
46904718
break;
46914719
}
46924720

4721+
/* Set error state if no more data left in ContentInfo, meaning
4722+
* no content - may be detached. Will recover from error below */
4723+
if ((encapContentInfoLen != 0) &&
4724+
(encapContentInfoLen - contentTypeSz == 0)) {
4725+
ret = ASN_PARSE_E;
4726+
}
4727+
4728+
/* PKCS#7 spec:
4729+
* content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL
4730+
* CMS spec:
4731+
* eContent [0] EXPLICIT OCTET STRING OPTIONAL
4732+
*/
46934733
if (ret == 0 && GetASNTag(pkiMsg, &localIdx, &tag, pkiMsgSz) != 0)
46944734
ret = ASN_PARSE_E;
46954735

46964736
if (ret == 0 && tag != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0))
46974737
ret = ASN_PARSE_E;
46984738

4739+
/* Get length of inner eContent payload. For CMS, spec defines
4740+
* OCTET_STRING will be next. If so, we use the length retrieved
4741+
* there. PKCS#7 spec defines ANY as eContent type. In this case
4742+
* we fall back and save this content length for use later */
46994743
if (ret == 0 && GetLength_ex(pkiMsg, &localIdx, &length, pkiMsgSz,
4700-
NO_USER_CHECK) <= 0)
4744+
NO_USER_CHECK) <= 0) {
47014745
ret = ASN_PARSE_E;
4746+
}
47024747

47034748
if (localIdx >= pkiMsgSz) {
47044749
ret = BUFFER_E;
47054750
}
47064751

4752+
/* Save idx to back up in case of PKCS#7 eContent */
4753+
start = localIdx;
4754+
47074755
/* get length of content in the case that there is multiple parts */
47084756
if (ret == 0 && GetASNTag(pkiMsg, &localIdx, &tag, pkiMsgSz) < 0)
47094757
ret = ASN_PARSE_E;
47104758

4711-
if (ret == 0 && tag == (ASN_OCTET_STRING | ASN_CONSTRUCTED)) {
4712-
multiPart = 1;
4759+
if (ret == 0 &&
4760+
(tag != (ASN_OCTET_STRING | ASN_CONSTRUCTED) &&
4761+
(tag != ASN_OCTET_STRING))) {
47134762

4714-
/* Get length of all OCTET_STRINGs. */
4715-
if (GetLength_ex(pkiMsg, &localIdx, &contentLen, pkiMsgSz,
4716-
NO_USER_CHECK) < 0)
4763+
/* If reached end of ContentInfo, or we see the next element
4764+
* ([0] IMPLICIT CertificateSet), set error state. Either
4765+
* true error or detached */
4766+
if (tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) {
47174767
ret = ASN_PARSE_E;
4718-
4719-
/* Check whether there is one OCTET_STRING inside. */
4720-
start = localIdx;
4721-
if (localIdx >= pkiMsgSz) {
4722-
ret = BUFFER_E;
47234768
}
47244769

4725-
if (ret == 0 && GetASNTag(pkiMsg, &localIdx, &tag, pkiMsgSz)
4726-
!= 0)
4727-
ret = ASN_PARSE_E;
4770+
/* Back up before getting tag, process as PKCS#7 ANY and use
4771+
* this as start of content. */
4772+
localIdx = start;
4773+
pkcs7->contentIsPkcs7Type = 1;
4774+
}
4775+
else {
4776+
/* CMS eContent OCTET_STRING */
4777+
if (ret == 0 && tag == (ASN_OCTET_STRING | ASN_CONSTRUCTED)) {
4778+
multiPart = 1;
47284779

4729-
if (ret == 0 && tag != ASN_OCTET_STRING)
4730-
ret = ASN_PARSE_E;
4780+
/* Get length of all OCTET_STRINGs. */
4781+
if (GetLength_ex(pkiMsg, &localIdx, &contentLen, pkiMsgSz,
4782+
NO_USER_CHECK) < 0)
4783+
ret = ASN_PARSE_E;
47314784

4732-
if (ret == 0 && GetLength_ex(pkiMsg, &localIdx, &length,
4733-
pkiMsgSz, NO_USER_CHECK) < 0)
4734-
ret = ASN_PARSE_E;
4785+
/* Check whether there is one OCTET_STRING inside. */
4786+
start = localIdx;
4787+
if (localIdx >= pkiMsgSz) {
4788+
ret = BUFFER_E;
4789+
}
47354790

4736-
if (ret == 0) {
4737-
/* Use single OCTET_STRING directly, or reset length. */
4738-
if (localIdx - start + length == (word32)contentLen) {
4739-
multiPart = 0;
4740-
} else {
4741-
/* reset length to outer OCTET_STRING for bundle size
4742-
* check below */
4743-
length = contentLen;
4791+
if (ret == 0 && GetASNTag(pkiMsg, &localIdx, &tag, pkiMsgSz)
4792+
!= 0)
4793+
ret = ASN_PARSE_E;
4794+
4795+
if (ret == 0 && tag != ASN_OCTET_STRING)
4796+
ret = ASN_PARSE_E;
4797+
4798+
if (ret == 0 && GetLength_ex(pkiMsg, &localIdx, &length,
4799+
pkiMsgSz, NO_USER_CHECK) < 0)
4800+
ret = ASN_PARSE_E;
4801+
4802+
if (ret == 0) {
4803+
/* Use single OCTET_STRING directly, or reset length. */
4804+
if (localIdx - start + length == (word32)contentLen) {
4805+
multiPart = 0;
4806+
} else {
4807+
/* reset length to outer OCTET_STRING for bundle
4808+
* size check below */
4809+
length = contentLen;
4810+
}
4811+
localIdx = start;
47444812
}
4745-
localIdx = start;
4746-
}
47474813

4748-
if (ret != 0) {
4749-
/* failed ASN1 parsing during OCTET_STRING checks */
4750-
break;
4814+
if (ret != 0) {
4815+
/* failed ASN1 parsing during OCTET_STRING checks */
4816+
break;
4817+
}
47514818
}
4752-
}
47534819

4754-
/* get length of content in case of single part */
4755-
if (ret == 0 && !multiPart) {
4756-
if (tag != ASN_OCTET_STRING)
4757-
ret = ASN_PARSE_E;
4820+
/* get length of content in case of single part */
4821+
if (ret == 0 && !multiPart) {
4822+
if (tag != ASN_OCTET_STRING)
4823+
ret = ASN_PARSE_E;
47584824

4759-
if (ret == 0 && GetLength_ex(pkiMsg, &localIdx,
4760-
&length, pkiMsgSz, NO_USER_CHECK) < 0)
4761-
ret = ASN_PARSE_E;
4825+
if (ret == 0 && GetLength_ex(pkiMsg, &localIdx,
4826+
&length, pkiMsgSz, NO_USER_CHECK) < 0)
4827+
ret = ASN_PARSE_E;
4828+
}
47624829
}
47634830

47644831
/* update idx if successful */
@@ -5111,6 +5178,7 @@ static int PKCS7_VerifySignedData(PKCS7* pkcs7, const byte* hashBuf,
51115178
pkcs7->der = NULL;
51125179
#endif
51135180
version = pkcs7->version;
5181+
contentIsPkcs7Type = pkcs7->contentIsPkcs7Type;
51145182

51155183
if (ret == 0) {
51165184
byte isDynamic = (byte)pkcs7->isDynamic;
@@ -5146,6 +5214,9 @@ static int PKCS7_VerifySignedData(PKCS7* pkcs7, const byte* hashBuf,
51465214
contentDynamic = NULL;
51475215
}
51485216

5217+
/* Restore content is PKCS#7 flag */
5218+
pkcs7->contentIsPkcs7Type = contentIsPkcs7Type;
5219+
51495220
#ifndef NO_PKCS7_STREAM
51505221
pkcs7->stream = stream;
51515222
#endif

wolfssl/wolfcrypt/pkcs7.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ struct PKCS7 {
341341
byte* cachedEncryptedContent;
342342
word32 cachedEncryptedContentSz;
343343
word16 contentCRLF:1; /* have content line endings been converted to CRLF */
344+
word16 contentIsPkcs7Type:1; /* eContent follows PKCS#7 RFC not CMS */
344345
/* !! NEW DATA MEMBERS MUST BE ADDED AT END !! */
345346
};
346347

0 commit comments

Comments
 (0)