mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-01-27 03:12:21 +01:00
Merge pull request #9559 from cconlon/pkcs7SignedNonOctet
Fix PKCS#7 SignedData parsing for non-OCTET_STRING content types
This commit is contained in:
@@ -4383,4 +4383,135 @@ int test_wc_PKCS7_DecodeCompressedData(void)
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/*
|
||||
* Test for PKCS#7 SignedData with non-OCTET_STRING content
|
||||
* (PKCS#7 style vs CMS)
|
||||
*
|
||||
* Tests parsing PKCS#7 SignedData where the encapsulated content
|
||||
* is a SEQUENCE (as allowed by original PKCS#7 spec "ANY DEFINED BY
|
||||
* contentType") rather than an OCTET STRING (as mandated by CMS). This showed
|
||||
* up in use case of Authenticode signatures.
|
||||
*/
|
||||
int test_wc_PKCS7_VerifySignedData_PKCS7ContentSeq(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(HAVE_PKCS7)
|
||||
PKCS7* pkcs7 = NULL;
|
||||
#ifndef NO_PKCS7_STREAM
|
||||
word32 idx;
|
||||
int ret;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Hand-crafted PKCS#7 SignedData (degenerate, no signers) with:
|
||||
* - Content type OID (1.3.6.1.4.1.311.2.1.4 = SPC_INDIRECT_DATA)
|
||||
* - Content is a SEQUENCE, NOT an OCTET STRING
|
||||
* - eContent is encoded as "ANY" type per original PKCS#7 spec.
|
||||
*
|
||||
* This test ensures wolfSSL's PKCS7 streaming code can correctly
|
||||
* parse SignedData types when the encapsulated content is not an OCTET
|
||||
* STRING (as CMS requires) but rather a SEQUENCE or other type
|
||||
* (as PKCS#7's "ANY" type allows). Microsoft Authenticode signatures
|
||||
* use this format with SPC_INDIRECT_DATA content.
|
||||
*
|
||||
* Structure:
|
||||
* ContentInfo SEQUENCE
|
||||
* contentType OID signedData
|
||||
* [0] SignedData SEQUENCE
|
||||
* version INTEGER 1
|
||||
* digestAlgorithms SET { sha256 }
|
||||
* encapContentInfo SEQUENCE
|
||||
* eContentType OID 1.3.6.1.4.1.311.2.1.4
|
||||
* [0] eContent
|
||||
* SEQUENCE { OID, OCTET STRING } - SEQUENCE not OCTET STRING
|
||||
* signerInfos SET {} (empty = degenerate)
|
||||
*/
|
||||
static const byte pkcs7Content[] = {
|
||||
/* ContentInfo SEQUENCE */
|
||||
0x30, 0x56,
|
||||
/* contentType OID: 1.2.840.113549.1.7.2 (signedData) */
|
||||
0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02,
|
||||
/* [0] EXPLICIT - content */
|
||||
0xA0, 0x49,
|
||||
/* SignedData SEQUENCE */
|
||||
0x30, 0x47,
|
||||
/* version INTEGER 1 */
|
||||
0x02, 0x01, 0x01,
|
||||
/* digestAlgorithms SET */
|
||||
0x31, 0x0F,
|
||||
/* AlgorithmIdentifier SEQUENCE */
|
||||
0x30, 0x0D,
|
||||
/* OID sha256: 2.16.840.1.101.3.4.2.1 */
|
||||
0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
|
||||
0x04, 0x02, 0x01,
|
||||
/* NULL */
|
||||
0x05, 0x00,
|
||||
/* encapContentInfo SEQUENCE */
|
||||
0x30, 0x2F,
|
||||
/* eContentType OID: 1.3.6.1.4.1.311.2.1.4 (SPC_INDIRECT_DATA) */
|
||||
0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82,
|
||||
0x37, 0x02, 0x01, 0x04,
|
||||
/* [0] EXPLICIT - eContent */
|
||||
0xA0, 0x21,
|
||||
/* Content SEQUENCE (0x30), not OCTET STRING (0x04)
|
||||
* Following PKCS#7 "ANY" type, not CMS OCTET STRING */
|
||||
0x30, 0x1F,
|
||||
/* Content: SEQUENCE { OID, OCTET STRING with 24 bytes } */
|
||||
0x06, 0x03, 0x55, 0x04, 0x03, /* OID 2.5.4.3 (5 bytes) */
|
||||
0x04, 0x18, /* OCTET STRING length 24 */
|
||||
0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, /* "This is " */
|
||||
0x74, 0x65, 0x73, 0x74, 0x20, 0x63, 0x6F, 0x6E, /* "test con" */
|
||||
0x74, 0x65, 0x6E, 0x74, 0x20, 0x64, 0x61, 0x74, /* "tent dat" */
|
||||
/* signerInfos SET - empty for degenerate */
|
||||
0x31, 0x00
|
||||
};
|
||||
|
||||
/* Test non-streaming verification */
|
||||
ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId));
|
||||
ExpectIntEQ(wc_PKCS7_Init(pkcs7, HEAP_HINT, INVALID_DEVID), 0);
|
||||
ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, NULL, 0), 0);
|
||||
ExpectIntEQ(wc_PKCS7_VerifySignedData(pkcs7, (byte*)pkcs7Content,
|
||||
(word32)sizeof(pkcs7Content)), 0);
|
||||
|
||||
/* Verify content was parsed correctly */
|
||||
if (pkcs7 != NULL) {
|
||||
/* contentIsPkcs7Type should be set */
|
||||
ExpectIntEQ(pkcs7->contentIsPkcs7Type, 1);
|
||||
/* Content should have been parsed (33 bytes) */
|
||||
ExpectIntEQ(pkcs7->contentSz, 33);
|
||||
ExpectNotNull(pkcs7->content);
|
||||
}
|
||||
wc_PKCS7_Free(pkcs7);
|
||||
pkcs7 = NULL;
|
||||
|
||||
#ifndef NO_PKCS7_STREAM
|
||||
/* Test streaming verification - feed data byte by byte */
|
||||
ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId));
|
||||
ExpectIntEQ(wc_PKCS7_Init(pkcs7, HEAP_HINT, INVALID_DEVID), 0);
|
||||
ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, NULL, 0), 0);
|
||||
|
||||
/* Feed data byte by byte to exercise streaming path */
|
||||
ret = WC_NO_ERR_TRACE(WC_PKCS7_WANT_READ_E);
|
||||
for (idx = 0; idx < (word32)sizeof(pkcs7Content) && ret != 0; idx++) {
|
||||
ret = wc_PKCS7_VerifySignedData(pkcs7,
|
||||
(byte*)pkcs7Content + idx, 1);
|
||||
if (ret < 0 && ret != WC_NO_ERR_TRACE(WC_PKCS7_WANT_READ_E)) {
|
||||
/* Unexpected error */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Expecting ret = 0, not ASN_PARSE_E or other negative error */
|
||||
ExpectIntEQ(ret, 0);
|
||||
|
||||
if (pkcs7 != NULL) {
|
||||
ExpectIntEQ(pkcs7->contentIsPkcs7Type, 1);
|
||||
ExpectIntEQ(pkcs7->contentSz, 33);
|
||||
ExpectNotNull(pkcs7->content);
|
||||
}
|
||||
wc_PKCS7_Free(pkcs7);
|
||||
#endif /* !NO_PKCS7_STREAM */
|
||||
#endif /* HAVE_PKCS7 */
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ int test_wc_PKCS7_SetOriEncryptCtx(void);
|
||||
int test_wc_PKCS7_SetOriDecryptCtx(void);
|
||||
int test_wc_PKCS7_DecodeCompressedData(void);
|
||||
int test_wc_PKCS7_DecodeEnvelopedData_multiple_recipients(void);
|
||||
int test_wc_PKCS7_VerifySignedData_PKCS7ContentSeq(void);
|
||||
|
||||
|
||||
#define TEST_PKCS7_DECLS \
|
||||
@@ -63,7 +64,8 @@ int test_wc_PKCS7_DecodeEnvelopedData_multiple_recipients(void);
|
||||
TEST_DECL_GROUP("pkcs7_sd", test_wc_PKCS7_VerifySignedData_ECC), \
|
||||
TEST_DECL_GROUP("pkcs7_sd", test_wc_PKCS7_Degenerate), \
|
||||
TEST_DECL_GROUP("pkcs7_sd", test_wc_PKCS7_BER), \
|
||||
TEST_DECL_GROUP("pkcs7_sd", test_wc_PKCS7_NoDefaultSignedAttribs)
|
||||
TEST_DECL_GROUP("pkcs7_sd", test_wc_PKCS7_NoDefaultSignedAttribs), \
|
||||
TEST_DECL_GROUP("pkcs7_sd", test_wc_PKCS7_VerifySignedData_PKCS7ContentSeq)
|
||||
|
||||
#define TEST_PKCS7_ENCRYPTED_DATA_DECLS \
|
||||
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_DecodeEnvelopedData_stream), \
|
||||
|
||||
@@ -5455,7 +5455,6 @@ static int PKCS7_VerifySignedData(wc_PKCS7* pkcs7, const byte* hashBuf,
|
||||
if (ret == 0 && GetMyVersion(pkiMsg, &idx, &version, pkiMsgSz) < 0)
|
||||
ret = ASN_PARSE_E;
|
||||
|
||||
|
||||
/* version 1 follows RFC 2315 */
|
||||
/* version 3 follows RFC 4108 */
|
||||
if (ret == 0 && (version != 1 && version != 3)) {
|
||||
@@ -5673,6 +5672,15 @@ static int PKCS7_VerifySignedData(wc_PKCS7* pkcs7, const byte* hashBuf,
|
||||
* this as start of content. */
|
||||
localIdx = start;
|
||||
pkcs7->contentIsPkcs7Type = 1;
|
||||
|
||||
#ifndef NO_PKCS7_STREAM
|
||||
/* Set streaming variables for PKCS#7 type content.
|
||||
* length contains the size from [0] EXPLICIT wrapper */
|
||||
pkcs7->stream->multi = 0;
|
||||
pkcs7->stream->currContIdx = localIdx;
|
||||
pkcs7->stream->currContSz = (word32)length;
|
||||
pkcs7->stream->currContRmnSz = (word32)length;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
/* CMS eContent OCTET_STRING */
|
||||
@@ -5762,7 +5770,6 @@ static int PKCS7_VerifySignedData(wc_PKCS7* pkcs7, const byte* hashBuf,
|
||||
idx = localIdx;
|
||||
}
|
||||
else {
|
||||
|
||||
/* If either pkcs7->content and pkcs7->contentSz are set
|
||||
* (detached signature where user has set content explicitly
|
||||
* into pkcs7->content/contentSz) OR pkcs7->hashBuf and
|
||||
@@ -5862,7 +5869,7 @@ static int PKCS7_VerifySignedData(wc_PKCS7* pkcs7, const byte* hashBuf,
|
||||
|
||||
/* copy content to pkcs7->contentDynamic */
|
||||
if (keepContent && pkcs7->stream->content &&
|
||||
pkcs7->stream->contentSz >0) {
|
||||
pkcs7->stream->contentSz > 0) {
|
||||
pkcs7->contentDynamic = (byte*)XMALLOC(pkcs7->stream->contentSz,
|
||||
pkcs7->heap, DYNAMIC_TYPE_PKCS7);
|
||||
if (pkcs7->contentDynamic == NULL) {
|
||||
@@ -6412,6 +6419,17 @@ static int PKCS7_VerifySignedData(wc_PKCS7* pkcs7, const byte* hashBuf,
|
||||
NO_USER_CHECK) < 0)
|
||||
ret = ASN_PARSE_E;
|
||||
|
||||
/* Update degenerate flag based on if signerInfos SET is empty.
|
||||
* The earlier degenerate check at digestAlgorithms is an early
|
||||
* optimization, but depending on degenerate case may not be
|
||||
* detected until here. */
|
||||
if (ret == 0) {
|
||||
degenerate = (length == 0) ? 1 : 0;
|
||||
#ifndef NO_PKCS7_STREAM
|
||||
pkcs7->stream->degenerate = (degenerate != 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (ret != 0)
|
||||
break;
|
||||
#ifndef NO_PKCS7_STREAM
|
||||
|
||||
Reference in New Issue
Block a user