Skip to content

Commit

Permalink
Merge pull request #6769 from cconlon/pkcs7ContentType
Browse files Browse the repository at this point in the history
Support PKCS#7 definition for ContentType content ANY
  • Loading branch information
JacobBarthelmeh authored Sep 14, 2023
2 parents 6b6c9f9 + 0bb9b85 commit 7d85e39
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 44 deletions.
159 changes: 115 additions & 44 deletions wolfcrypt/src/pkcs7.c
Original file line number Diff line number Diff line change
Expand Up @@ -3786,7 +3786,10 @@ static int wc_PKCS7_VerifyContentMessageDigest(PKCS7* pkcs7,
word32 hashSz)
{
int ret = 0, digestSz = 0, innerAttribSz = 0;
int contentLen = 0;
word32 idx = 0;
word32 contentIdx = 0;
byte* content = NULL;
byte* digestBuf = NULL;
#ifdef WOLFSSL_SMALL_STACK
byte* digest = NULL;
Expand Down Expand Up @@ -3845,7 +3848,29 @@ static int wc_PKCS7_VerifyContentMessageDigest(PKCS7* pkcs7,
#endif
XMEMSET(digest, 0, MAX_PKCS7_DIGEST_SZ);

ret = wc_Hash(hashType, pkcs7->content, pkcs7->contentSz, digest,
content = pkcs7->content;
contentLen = pkcs7->contentSz;

if (pkcs7->contentIsPkcs7Type == 1) {
/* Content follows PKCS#7 RFC, which defines type as ANY. CMS
* mandates OCTET_STRING which has already been stripped off.
* For PKCS#7 message digest calculation, digest is calculated
* only on the "value" of the DER encoding. As such, advance past
* the tag and length */
if (contentLen > 1) {
contentIdx++;
}

if (GetLength_ex(content, &contentIdx, &contentLen,
contentLen, 1) < 0) {
#ifdef WOLFSSL_SMALL_STACK
XFREE(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
return ASN_PARSE_E;
}
}

ret = wc_Hash(hashType, content + contentIdx, contentLen, digest,
MAX_PKCS7_DIGEST_SZ);
if (ret < 0) {
WOLFSSL_MSG("Error hashing PKCS7 content for verification");
Expand Down Expand Up @@ -4435,11 +4460,13 @@ static int PKCS7_VerifySignedData(PKCS7* pkcs7, const byte* hashBuf,
byte* cert = NULL;
byte* signedAttrib = NULL;
byte* contentType = NULL;
int encapContentInfoLen = 0;
int contentSz = 0, sigSz = 0, certSz = 0, signedAttribSz = 0;
word32 localIdx, start;
byte degenerate = 0;
byte detached = 0;
byte tag = 0;
word16 contentIsPkcs7Type = 0;
#ifdef ASN_BER_TO_DER
byte* der;
#endif
Expand Down Expand Up @@ -4649,15 +4676,16 @@ static int PKCS7_VerifySignedData(PKCS7* pkcs7, const byte* hashBuf,

#endif
/* Get the inner ContentInfo sequence */
if (GetSequence_ex(pkiMsg, &idx, &length, pkiMsgSz,
if (GetSequence_ex(pkiMsg, &idx, &encapContentInfoLen, pkiMsgSz,
NO_USER_CHECK) < 0)
ret = ASN_PARSE_E;

/* Get the inner ContentInfo contentType */
if (ret == 0) {
int isIndef = 0;
word32 tmpIdx = idx;
if (length == 0 && pkiMsg[idx-1] == ASN_INDEF_LENGTH) {
if (encapContentInfoLen == 0 &&
pkiMsg[idx-1] == ASN_INDEF_LENGTH) {
isIndef = 1;
}
if (GetASNObjectId(pkiMsg, &idx, &length, pkiMsgSz) == 0) {
Expand All @@ -4682,83 +4710,122 @@ static int PKCS7_VerifySignedData(PKCS7* pkcs7, const byte* hashBuf,
if (ret != 0)
break;

/* Check for content info, it could be omitted when degenerate */
/* Check for content, it could be omitted when degenerate */
localIdx = idx;
ret = 0;
if (localIdx + 1 > pkiMsgSz) {
ret = BUFFER_E;
break;
}

/* Set error state if no more data left in ContentInfo, meaning
* no content - may be detached. Will recover from error below */
if ((encapContentInfoLen != 0) &&
(encapContentInfoLen - contentTypeSz == 0)) {
ret = ASN_PARSE_E;
}

/* PKCS#7 spec:
* content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL
* CMS spec:
* eContent [0] EXPLICIT OCTET STRING OPTIONAL
*/
if (ret == 0 && GetASNTag(pkiMsg, &localIdx, &tag, pkiMsgSz) != 0)
ret = ASN_PARSE_E;

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

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

if (localIdx >= pkiMsgSz) {
ret = BUFFER_E;
}

/* Save idx to back up in case of PKCS#7 eContent */
start = localIdx;

/* get length of content in the case that there is multiple parts */
if (ret == 0 && GetASNTag(pkiMsg, &localIdx, &tag, pkiMsgSz) < 0)
ret = ASN_PARSE_E;

if (ret == 0 && tag == (ASN_OCTET_STRING | ASN_CONSTRUCTED)) {
multiPart = 1;
if (ret == 0 &&
(tag != (ASN_OCTET_STRING | ASN_CONSTRUCTED) &&
(tag != ASN_OCTET_STRING))) {

/* Get length of all OCTET_STRINGs. */
if (GetLength_ex(pkiMsg, &localIdx, &contentLen, pkiMsgSz,
NO_USER_CHECK) < 0)
/* If reached end of ContentInfo, or we see the next element
* ([0] IMPLICIT CertificateSet), set error state. Either
* true error or detached */
if (tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) {
ret = ASN_PARSE_E;

/* Check whether there is one OCTET_STRING inside. */
start = localIdx;
if (localIdx >= pkiMsgSz) {
ret = BUFFER_E;
}

if (ret == 0 && GetASNTag(pkiMsg, &localIdx, &tag, pkiMsgSz)
!= 0)
ret = ASN_PARSE_E;
/* Back up before getting tag, process as PKCS#7 ANY and use
* this as start of content. */
localIdx = start;
pkcs7->contentIsPkcs7Type = 1;
}
else {
/* CMS eContent OCTET_STRING */
if (ret == 0 && tag == (ASN_OCTET_STRING | ASN_CONSTRUCTED)) {
multiPart = 1;

if (ret == 0 && tag != ASN_OCTET_STRING)
ret = ASN_PARSE_E;
/* Get length of all OCTET_STRINGs. */
if (GetLength_ex(pkiMsg, &localIdx, &contentLen, pkiMsgSz,
NO_USER_CHECK) < 0)
ret = ASN_PARSE_E;

if (ret == 0 && GetLength_ex(pkiMsg, &localIdx, &length,
pkiMsgSz, NO_USER_CHECK) < 0)
ret = ASN_PARSE_E;
/* Check whether there is one OCTET_STRING inside. */
start = localIdx;
if (localIdx >= pkiMsgSz) {
ret = BUFFER_E;
}

if (ret == 0) {
/* Use single OCTET_STRING directly, or reset length. */
if (localIdx - start + length == (word32)contentLen) {
multiPart = 0;
} else {
/* reset length to outer OCTET_STRING for bundle size
* check below */
length = contentLen;
if (ret == 0 && GetASNTag(pkiMsg, &localIdx, &tag, pkiMsgSz)
!= 0)
ret = ASN_PARSE_E;

if (ret == 0 && tag != ASN_OCTET_STRING)
ret = ASN_PARSE_E;

if (ret == 0 && GetLength_ex(pkiMsg, &localIdx, &length,
pkiMsgSz, NO_USER_CHECK) < 0)
ret = ASN_PARSE_E;

if (ret == 0) {
/* Use single OCTET_STRING directly, or reset length. */
if (localIdx - start + length == (word32)contentLen) {
multiPart = 0;
} else {
/* reset length to outer OCTET_STRING for bundle
* size check below */
length = contentLen;
}
localIdx = start;
}
localIdx = start;
}

if (ret != 0) {
/* failed ASN1 parsing during OCTET_STRING checks */
break;
if (ret != 0) {
/* failed ASN1 parsing during OCTET_STRING checks */
break;
}
}
}

/* get length of content in case of single part */
if (ret == 0 && !multiPart) {
if (tag != ASN_OCTET_STRING)
ret = ASN_PARSE_E;
/* get length of content in case of single part */
if (ret == 0 && !multiPart) {
if (tag != ASN_OCTET_STRING)
ret = ASN_PARSE_E;

if (ret == 0 && GetLength_ex(pkiMsg, &localIdx,
&length, pkiMsgSz, NO_USER_CHECK) < 0)
ret = ASN_PARSE_E;
if (ret == 0 && GetLength_ex(pkiMsg, &localIdx,
&length, pkiMsgSz, NO_USER_CHECK) < 0)
ret = ASN_PARSE_E;
}
}

/* update idx if successful */
Expand Down Expand Up @@ -5111,6 +5178,7 @@ static int PKCS7_VerifySignedData(PKCS7* pkcs7, const byte* hashBuf,
pkcs7->der = NULL;
#endif
version = pkcs7->version;
contentIsPkcs7Type = pkcs7->contentIsPkcs7Type;

if (ret == 0) {
byte isDynamic = (byte)pkcs7->isDynamic;
Expand Down Expand Up @@ -5146,6 +5214,9 @@ static int PKCS7_VerifySignedData(PKCS7* pkcs7, const byte* hashBuf,
contentDynamic = NULL;
}

/* Restore content is PKCS#7 flag */
pkcs7->contentIsPkcs7Type = contentIsPkcs7Type;

#ifndef NO_PKCS7_STREAM
pkcs7->stream = stream;
#endif
Expand Down
1 change: 1 addition & 0 deletions wolfssl/wolfcrypt/pkcs7.h
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,7 @@ struct PKCS7 {
byte* cachedEncryptedContent;
word32 cachedEncryptedContentSz;
word16 contentCRLF:1; /* have content line endings been converted to CRLF */
word16 contentIsPkcs7Type:1; /* eContent follows PKCS#7 RFC not CMS */
/* !! NEW DATA MEMBERS MUST BE ADDED AT END !! */
};

Expand Down

0 comments on commit 7d85e39

Please sign in to comment.