@@ -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
0 commit comments