Merge pull request #6769 from cconlon/pkcs7ContentType
Support PKCS#7 definition for ContentType content ANY
This commit is contained in:
commit
7d85e390a9
@ -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;
|
||||
@ -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");
|
||||
@ -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
|
||||
@ -4649,7 +4676,7 @@ 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;
|
||||
|
||||
@ -4657,7 +4684,8 @@ static int PKCS7_VerifySignedData(PKCS7* pkcs7, const byte* hashBuf,
|
||||
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) {
|
||||
@ -4682,7 +4710,7 @@ 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) {
|
||||
@ -4690,75 +4718,114 @@ static int PKCS7_VerifySignedData(PKCS7* pkcs7, const byte* hashBuf,
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
/* failed ASN1 parsing during OCTET_STRING checks */
|
||||
break;
|
||||
}
|
||||
/* 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;
|
||||
|
||||
/* 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 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 && 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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (ret == 0 && GetLength_ex(pkiMsg, &localIdx,
|
||||
&length, pkiMsgSz, NO_USER_CHECK) < 0)
|
||||
ret = ASN_PARSE_E;
|
||||
}
|
||||
}
|
||||
|
||||
/* update idx if successful */
|
||||
@ -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;
|
||||
@ -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
|
||||
|
@ -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 !! */
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user