Merge pull request #10203 from Frauschi/pkcs7_fixes

PKCS#7 fixes
This commit is contained in:
Sean Parkinson
2026-04-24 10:13:43 +10:00
committed by GitHub
9 changed files with 2154 additions and 57 deletions
+1
View File
@@ -830,6 +830,7 @@ WOLFSSL_NO_KCAPI_HMAC_SHA256
WOLFSSL_NO_KCAPI_HMAC_SHA384
WOLFSSL_NO_KCAPI_HMAC_SHA512
WOLFSSL_NO_KCAPI_SHA224
WOLFSSL_NO_KTRI_ORACLE_WARNING
WOLFSSL_NO_OCSP_DATE_CHECK
WOLFSSL_NO_OCSP_ISSUER_CHAIN_CHECK
WOLFSSL_NO_OCSP_OPTIONAL_CERTS
+23 -5
View File
@@ -269,24 +269,42 @@ WOLFSSL_STACK* wolfSSL_PKCS7_get0_signers(PKCS7* pkcs7, WOLFSSL_STACK* certs,
WOLFSSL_X509* x509 = NULL;
WOLFSSL_STACK* signers = NULL;
WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7;
byte* signerCert;
word32 signerCertSz;
if (p7 == NULL)
return NULL;
/* Only PKCS#7 messages with a single cert that is the verifying certificate
* is supported.
*/
if (flags & PKCS7_NOINTERN) {
WOLFSSL_MSG("PKCS7_NOINTERN flag not supported");
return NULL;
}
/* Prefer the certificate that actually verified the signature. Falling
* back to singleCert (cert[0]) would let an attacker that bundles a
* trusted cert ahead of their own attacker cert have the trusted cert
* reported as the signer even though it did not produce the signature.
*
* Copy the chosen pointer into a local before passing its address to
* wolfSSL_d2i_X509; d2i_X509 advances *in by the DER length, and if
* we handed it the address of the struct field directly it would
* permanently corrupt the field, producing a heap-OOB read on the
* next use (pointer advanced, singleCertSz unchanged). */
if (p7->pkcs7.verifyCert != NULL && p7->pkcs7.verifyCertSz > 0) {
signerCert = p7->pkcs7.verifyCert;
signerCertSz = p7->pkcs7.verifyCertSz;
}
else {
signerCert = p7->pkcs7.singleCert;
signerCertSz = p7->pkcs7.singleCertSz;
}
signers = wolfSSL_sk_X509_new_null();
if (signers == NULL)
return NULL;
if (wolfSSL_d2i_X509(&x509, (const byte**)&p7->pkcs7.singleCert,
p7->pkcs7.singleCertSz) == NULL) {
if (wolfSSL_d2i_X509(&x509, (const byte**)&signerCert,
signerCertSz) == NULL) {
wolfSSL_sk_X509_pop_free(signers, NULL);
return NULL;
}
+707
View File
@@ -35892,6 +35892,706 @@ static int test_pkcs7_ori_oversized_oid(void)
return EXPECT_RESULT();
}
/* ORI callback that flags if oriValueSz looks like an underflow (>= 0x80000000) */
#if defined(HAVE_PKCS7) && !defined(WOLFSSL_NO_MALLOC)
static int test_ori_underflow_cb(wc_PKCS7* pkcs7, byte* oriType,
word32 oriTypeSz, byte* oriValue,
word32 oriValueSz, byte* decryptedKey,
word32* decryptedKeySz, void* ctx)
{
int* called = (int*)ctx;
(void)pkcs7; (void)oriType; (void)oriTypeSz;
(void)oriValue; (void)decryptedKey; (void)decryptedKeySz;
if (called != NULL)
*called = (int)oriValueSz; /* record what we received */
return -1;
}
#endif
/* Test: PKCS#7 ORI must reject when OID consumption exceeds the [4] implicit
* SEQUENCE length (integer underflow in oriValueSz computation).
*
* With implicit tagging, [4] CONSTRUCTED replaces the SEQUENCE tag, so
* wc_PKCS7_DecryptOri reads seqSz directly from the [4] length field.
* We set [4] length = 5 while the OID inside consumes 22 bytes
* (tag + length + 20 content), triggering oriValueSz = 5 - 22 = underflow.
*
* The buffer includes a dummy EncryptedContentInfo after the RecipientInfos
* so the total message is large enough for the PKCS7 streaming code (which
* requests the full remaining message before parsing the ORI). */
static int test_pkcs7_ori_seqsz_underflow(void)
{
EXPECT_DECLS;
#if defined(HAVE_PKCS7) && !defined(WOLFSSL_NO_MALLOC)
wc_PKCS7* p7 = NULL;
byte out[256];
int cbCalled = 0;
/*
* Byte layout (all outer lengths match actual byte counts on wire):
*
* OID inside [4]: 06 14 <20 bytes> = 22 bytes
* [4] (declared len 5, actual content 22):
* a4 05 <22 bytes> = 24 bytes on wire
* SET: 31 18 <24 bytes> = 26 bytes on wire
* version: 02 01 00 = 3 bytes
* EncryptedContentInfo (filler, never parsed):
* 30 0b { 06 09 <9 bytes OID> } = 13 bytes on wire
* EnvelopedData: 30 2a <3+26+13=42 bytes> = 44 bytes on wire
* [0] EXPLICIT: a0 2c <44 bytes> = 46 bytes on wire
* OID(envelopedData): 06 09 <9 bytes> = 11 bytes on wire
* ContentInfo: 30 39 <11+46=57 bytes> = 59 bytes total
*/
static const byte poc[] = {
/* ContentInfo SEQUENCE (length 57) */
0x30, 0x39,
/* contentType = envelopedData 1.2.840.113549.1.7.3 */
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x03,
/* [0] EXPLICIT (length 44) */
0xa0, 0x2c,
/* EnvelopedData SEQUENCE (length 42) */
0x30, 0x2a,
/* version = 0 */
0x02, 0x01, 0x00,
/* RecipientInfos SET (length 24) */
0x31, 0x18,
/* [4] CONSTRUCTED = ORI implicit SEQUENCE, declared len 5 */
/* Actual OID is 22 bytes -> exceeds declared 5 */
0xa4, 0x05,
/* OID: tag=06, len=0x14(20), content=20 bytes = 22 total */
0x06, 0x14,
0x2a, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
0x12, 0x13, 0x14, 0x15,
/* EncryptedContentInfo SEQUENCE (length 11) - filler so
* streaming has enough data; never actually parsed because
* DecryptOri fails before we get here */
0x30, 0x0b,
/* contentType = data 1.2.840.113549.1.7.1 */
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
0x01
};
p7 = wc_PKCS7_New(NULL, INVALID_DEVID);
ExpectNotNull(p7);
if (p7 != NULL) {
wc_PKCS7_SetOriDecryptCb(p7, test_ori_underflow_cb);
wc_PKCS7_SetOriDecryptCtx(p7, &cbCalled);
/* Must return an error before the callback sees an underflowed size */
ExpectIntLT(wc_PKCS7_DecodeEnvelopedData(p7, (byte*)poc, sizeof(poc),
out, sizeof(out)), 0);
/* The callback must NOT have been invoked with a wrapped oriValueSz.
* cbCalled == 0 means the callback was never reached (ideal).
* cbCalled < 0 would indicate the underflow was passed through. */
ExpectIntGE(cbCalled, 0);
wc_PKCS7_Free(p7);
}
#endif
return EXPECT_RESULT();
}
/* Test: PKCS#7 ORI must reject when seqSz extends oriValue past input buffer.
*
* The first ORI bounds check (OID exceeds SEQUENCE boundary) is covered by
* test_pkcs7_ori_seqsz_underflow. This test covers the *second* check:
* oriValue region extends past the end of the input buffer. We craft a
* message where the [4] SEQUENCE length is valid relative to the OID
* (OID fits inside it), but the remaining oriValue portion extends past
* the end of the actual input buffer.
*
* To bypass GetLength's own bounds validation, we set the outer lengths
* (EnvelopedData SEQUENCE, RecipientInfos SET) to match the [4] claim,
* but truncate the actual buffer we pass to DecodeEnvelopedData. */
static int test_pkcs7_ori_orivalue_overflow(void)
{
EXPECT_DECLS;
#if defined(HAVE_PKCS7) && !defined(WOLFSSL_NO_MALLOC)
wc_PKCS7* p7 = NULL;
byte out[256];
/* EnvelopedData with [4] ORI whose seqSz (40) is valid for the OID
* (6 bytes consumed) but oriValueSz (34) extends past the truncated
* input buffer.
*
* Layout:
* ContentInfo SEQUENCE
* OID envelopedData
* [0] EXPLICIT
* EnvelopedData SEQUENCE
* version = 0
* RecipientInfos SET
* [4] CONSTRUCTED (seqSz = 40)
* OID (tag 06, len 04, 4 content bytes = 6 total)
* oriValue should be 34 bytes but input is truncated
* EncryptedContentInfo (filler for streaming)
*
* We pass the full array to DecodeEnvelopedData, but the actual
* input ends before [4]'s declared 40 bytes are consumed.
*/
static const byte poc[] = {
/* ContentInfo SEQUENCE */
0x30, 0x43,
/* contentType = envelopedData 1.2.840.113549.1.7.3 */
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x03,
/* [0] EXPLICIT */
0xa0, 0x36,
/* EnvelopedData SEQUENCE */
0x30, 0x34,
/* version = 0 */
0x02, 0x01, 0x00,
/* RecipientInfos SET (len = 44 covers [4] tag+len+40) */
0x31, 0x2c,
/* [4] CONSTRUCTED = ORI implicit SEQUENCE, seqSz = 40 */
0xa4, 0x28,
/* OID: tag=06, len=04, 4 content bytes = 6 total */
0x06, 0x04, 0x2a, 0x03, 0x04, 0x05,
/* Only 4 bytes of oriValue here, but seqSz claims 34 more */
0x00, 0x00, 0x00, 0x00,
/* EncryptedContentInfo SEQUENCE (filler) */
0x30, 0x0b,
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
0x01
};
p7 = wc_PKCS7_New(NULL, INVALID_DEVID);
ExpectNotNull(p7);
if (p7 != NULL) {
wc_PKCS7_SetOriDecryptCb(p7, test_dummy_ori_cb);
/* Must return error - oriValue extends past input buffer */
ExpectIntLT(wc_PKCS7_DecodeEnvelopedData(p7, (byte*)poc, sizeof(poc),
out, sizeof(out)), 0);
wc_PKCS7_Free(p7);
}
#endif
return EXPECT_RESULT();
}
/* Test: PKCS#7 KTRI must not match recipient when SKID length differs
* from expected keyIdSize.
*
* The fix adds a `length == keyIdSize` check before comparing the SKID
* bytes. Without this check, XMEMCMP could compare against data beyond
* the SKID content. This test crafts a KTRI RecipientInfo where the
* [0] SubjectKeyIdentifier has length 5 instead of KEYID_SIZE (20).
* The decode must return an error (no matching recipient). */
static int test_pkcs7_ktri_skid_length_mismatch(void)
{
EXPECT_DECLS;
#if defined(HAVE_PKCS7) && !defined(NO_RSA) && !defined(WOLFSSL_NO_MALLOC)
wc_PKCS7* p7 = NULL;
byte out[256];
/* Minimal EnvelopedData with KTRI using version=2 (SKID path).
* The SKID [0] has length 5 instead of 20.
*
* ContentInfo SEQUENCE
* OID envelopedData
* [0] EXPLICIT
* EnvelopedData SEQUENCE
* version = 2
* RecipientInfos SET
* KTRI SEQUENCE
* version = 2
* [0] SKID (5 bytes, should be 20)
* AlgorithmIdentifier (RSA OID)
* OCTET STRING (fake encrypted key)
* EncryptedContentInfo (filler)
*/
static const byte poc[] = {
/* ContentInfo SEQUENCE */
0x30, 0x46,
/* contentType = envelopedData 1.2.840.113549.1.7.3 */
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x03,
/* [0] EXPLICIT */
0xa0, 0x39,
/* EnvelopedData SEQUENCE */
0x30, 0x37,
/* version = 2 (triggers SKID-based recipient identification) */
0x02, 0x01, 0x02,
/* RecipientInfos SET */
0x31, 0x21,
/* KTRI SEQUENCE */
0x30, 0x1f,
/* version = 2 (SKID) */
0x02, 0x01, 0x02,
/* [0] IMPLICIT SubjectKeyIdentifier, length = 5 (wrong!) */
0x80, 0x05, 0x01, 0x02, 0x03, 0x04, 0x05,
/* AlgorithmIdentifier: RSA 1.2.840.113549.1.1.1 */
0x30, 0x0d,
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
0x01, 0x01, 0x01,
0x05, 0x00, /* NULL params */
/* encryptedKey OCTET STRING (2 bytes fake) */
0x04, 0x02, 0xAA, 0xBB,
/* EncryptedContentInfo SEQUENCE (filler) */
0x30, 0x0b,
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
0x01
};
p7 = wc_PKCS7_New(NULL, INVALID_DEVID);
ExpectNotNull(p7);
if (p7 != NULL) {
/* Decode without a cert - SKID will never match, and the
* mismatched SKID length must not cause out-of-bounds reads */
ExpectIntLT(wc_PKCS7_DecodeEnvelopedData(p7, (byte*)poc, sizeof(poc),
out, sizeof(out)), 0);
wc_PKCS7_Free(p7);
}
#endif
return EXPECT_RESULT();
}
/* Test: PKCS#7 KARI must reject BIT STRING with length < 2 in
* OriginatorPublicKey.
*
* The fix adds `if (length < 2) return ASN_PARSE_E` after parsing
* the BIT STRING tag and length. A BIT STRING must have at least
* the unused-bits byte plus one byte of content. This test crafts
* a KARI [1] RecipientInfo where the OriginatorPublicKey's BIT STRING
* has length 1 (degenerate). The PKCS7 object is initialized with a
* real ECC cert so that KariParseRecipCert succeeds and parsing reaches
* the BIT STRING validation. */
static int test_pkcs7_kari_degenerate_bitstring(void)
{
EXPECT_DECLS;
#if defined(HAVE_PKCS7) && defined(HAVE_ECC) && defined(HAVE_X963_KDF) && \
!defined(WOLFSSL_NO_MALLOC)
wc_PKCS7* p7 = NULL;
byte out[256];
byte* eccCert = NULL;
byte* eccPrivKey = NULL;
word32 eccCertSz = 0;
word32 eccPrivKeySz = 0;
#if !defined(USE_CERT_BUFFERS_256) && !defined(NO_FILESYSTEM)
XFILE f = XBADFILE;
#endif
/* Minimal EnvelopedData with KARI [1] containing a degenerate
* BIT STRING (length 1) in OriginatorPublicKey.
*
* ContentInfo SEQUENCE
* OID envelopedData
* [0] EXPLICIT
* EnvelopedData SEQUENCE
* version = 2
* RecipientInfos SET
* [1] CONSTRUCTED (KARI)
* version = 3
* [0] CONSTRUCTED (OriginatorIdentifierOrKey)
* [1] CONSTRUCTED (OriginatorPublicKey)
* AlgorithmIdentifier (ECDSAk)
* BIT STRING length=1 (degenerate!)
* EncryptedContentInfo (filler)
*/
static const byte poc[] = {
/* ContentInfo SEQUENCE */
0x30, 0x44,
/* contentType = envelopedData 1.2.840.113549.1.7.3 */
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x03,
/* [0] EXPLICIT */
0xa0, 0x37,
/* EnvelopedData SEQUENCE */
0x30, 0x35,
/* version = 2 */
0x02, 0x01, 0x02,
/* RecipientInfos SET */
0x31, 0x1f,
/* [1] CONSTRUCTED (KARI implicit) */
0xa1, 0x1d,
/* version = 3 */
0x02, 0x01, 0x03,
/* [0] CONSTRUCTED (OriginatorIdentifierOrKey) */
0xa0, 0x18,
/* [1] CONSTRUCTED (OriginatorPublicKey) */
0xa1, 0x16,
/* AlgorithmIdentifier SEQUENCE */
0x30, 0x13,
/* OID: id-ecPublicKey 1.2.840.10045.2.1 */
0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01,
/* OID: prime256v1 1.2.840.10045.3.1.7 */
0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03,
0x01, 0x07,
/* BIT STRING with length 1 - degenerate! */
0x03, 0x01, 0x00,
/* EncryptedContentInfo SEQUENCE (filler) */
0x30, 0x0b,
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
0x01
};
/* Load ECC cert and key so KariParseRecipCert succeeds and
* parsing reaches the BIT STRING check */
#ifdef USE_CERT_BUFFERS_256
eccCertSz = (word32)sizeof_cliecc_cert_der_256;
ExpectNotNull(eccCert = (byte*)XMALLOC(eccCertSz, HEAP_HINT,
DYNAMIC_TYPE_TMP_BUFFER));
if (eccCert != NULL)
XMEMCPY(eccCert, cliecc_cert_der_256, eccCertSz);
eccPrivKeySz = (word32)sizeof_ecc_clikey_der_256;
ExpectNotNull(eccPrivKey = (byte*)XMALLOC(eccPrivKeySz, HEAP_HINT,
DYNAMIC_TYPE_TMP_BUFFER));
if (eccPrivKey != NULL)
XMEMCPY(eccPrivKey, ecc_clikey_der_256, eccPrivKeySz);
#elif !defined(NO_FILESYSTEM)
eccCertSz = FOURK_BUF;
ExpectNotNull(eccCert = (byte*)XMALLOC(eccCertSz, HEAP_HINT,
DYNAMIC_TYPE_TMP_BUFFER));
ExpectTrue((f = XFOPEN("./certs/client-ecc-cert.der", "rb")) != XBADFILE);
ExpectTrue((eccCertSz = (word32)XFREAD(eccCert, 1, eccCertSz, f)) > 0);
if (f != XBADFILE) {
XFCLOSE(f);
f = XBADFILE;
}
eccPrivKeySz = FOURK_BUF;
ExpectNotNull(eccPrivKey = (byte*)XMALLOC(eccPrivKeySz, HEAP_HINT,
DYNAMIC_TYPE_TMP_BUFFER));
ExpectTrue((f = XFOPEN("./certs/ecc-client-key.der", "rb")) != XBADFILE);
ExpectTrue((eccPrivKeySz = (word32)XFREAD(eccPrivKey, 1, eccPrivKeySz,
f)) > 0);
if (f != XBADFILE)
XFCLOSE(f);
#else
eccCert = NULL;
eccCertSz = 0;
eccPrivKey = NULL;
eccPrivKeySz = 0;
#endif
p7 = wc_PKCS7_New(HEAP_HINT, INVALID_DEVID);
ExpectNotNull(p7);
if (p7 != NULL && eccCert != NULL) {
ExpectIntEQ(wc_PKCS7_InitWithCert(p7, eccCert, eccCertSz), 0);
if (p7 != NULL) {
p7->privateKey = eccPrivKey;
p7->privateKeySz = eccPrivKeySz;
}
/* Must return error - BIT STRING length < 2 is invalid */
ExpectIntLT(wc_PKCS7_DecodeEnvelopedData(p7, (byte*)poc, sizeof(poc),
out, sizeof(out)), 0);
if (p7 != NULL) {
p7->privateKey = NULL;
p7->privateKeySz = 0;
}
wc_PKCS7_Free(p7);
}
else if (p7 != NULL) {
wc_PKCS7_Free(p7);
}
XFREE(eccCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(eccPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
#endif
return EXPECT_RESULT();
}
/* Test: PKCS#7 EncryptedData must reject when encryptedContentSz exceeds
* the remaining input buffer.
*
* The fix adds `encryptedContentSz > (int)(pkiMsgSz - idx)` to the
* existing `encryptedContentSz <= 0` check in stage 6. This test crafts
* a minimal EncryptedData where the [0] IMPLICIT content length claims
* 0x200 (512) bytes but only 32 bytes of ciphertext are present. */
static int test_pkcs7_encrypted_content_size_overflow(void)
{
EXPECT_DECLS;
#if defined(HAVE_PKCS7) && !defined(NO_AES) && defined(HAVE_AES_CBC) && \
defined(WOLFSSL_AES_256) && !defined(NO_PKCS7_ENCRYPTED_DATA) && \
!defined(WOLFSSL_NO_MALLOC)
wc_PKCS7* p7 = NULL;
byte key[32];
byte out[256];
/* EncryptedData with [0] content claiming 512 bytes but only 32 present.
*
* ContentInfo SEQUENCE
* OID encryptedData (1.2.840.113549.1.7.6)
* [0] EXPLICIT
* EncryptedData SEQUENCE
* version = 0
* EncryptedContentInfo SEQUENCE
* OID data (1.2.840.113549.1.7.1)
* AlgorithmIdentifier
* OID AES-256-CBC (2.16.840.1.101.3.4.1.42)
* OCTET STRING IV (16 zero bytes)
* [0] IMPLICIT content (claimed len=0x200, actual=32 bytes)
*/
static const byte poc[] = {
/* ContentInfo SEQUENCE (len covers entire message) */
0x30, 0x50,
/* OID encryptedData 1.2.840.113549.1.7.6 */
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x06,
/* [0] EXPLICIT */
0xa0, 0x43,
/* EncryptedData SEQUENCE */
0x30, 0x41,
/* version = 0 */
0x02, 0x01, 0x00,
/* EncryptedContentInfo SEQUENCE */
0x30, 0x3c,
/* OID data 1.2.840.113549.1.7.1 */
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
0x01,
/* AlgorithmIdentifier SEQUENCE */
0x30, 0x1d,
/* OID AES-256-CBC 2.16.840.1.101.3.4.1.42 */
0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01,
0x2a,
/* IV: OCTET STRING (16 zero bytes) */
0x04, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* [0] IMPLICIT encryptedContent - claims 512 bytes!
* Only 16 bytes of fake ciphertext follow. */
0x80, 0x82, 0x02, 0x00,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA
};
XMEMSET(key, 0, sizeof(key));
p7 = wc_PKCS7_New(NULL, INVALID_DEVID);
ExpectNotNull(p7);
if (p7 != NULL) {
p7->encryptionKey = key;
p7->encryptionKeySz = sizeof(key);
/* Must return error - content extends past input buffer */
ExpectIntLT(wc_PKCS7_DecodeEncryptedData(p7, (byte*)poc, sizeof(poc),
out, sizeof(out)), 0);
wc_PKCS7_Free(p7);
}
#endif
return EXPECT_RESULT();
}
/* Test: PKCS#7 SignedData must reject when the signature field is not
* an OCTET STRING.
*
* The fix adds `else if (ret == 0) { ret = ASN_PARSE_E; }` so that
* when the tag at the signature position is not ASN_OCTET_STRING,
* parsing returns an error instead of silently continuing with no
* signature. This test encodes a valid SignedData, then corrupts
* the signature OCTET STRING tag and verifies that decode fails. */
static int test_pkcs7_signed_bad_sig_tag(void)
{
EXPECT_DECLS;
#if defined(HAVE_PKCS7) && !defined(NO_RSA) && !defined(NO_SHA256) && \
!defined(WOLFSSL_NO_MALLOC)
PKCS7* pkcs7 = NULL;
WC_RNG rng;
byte encoded[FOURK_BUF];
int encodedSz = 0;
int i;
byte* rsaCert = NULL;
byte* rsaPrivKey = NULL;
word32 rsaCertSz = 0;
word32 rsaPrivKeySz = 0;
#if !defined(USE_CERT_BUFFERS_2048) && !defined(USE_CERT_BUFFERS_1024) && \
!defined(NO_FILESYSTEM)
XFILE f = XBADFILE;
#endif
const byte data[] = "Test signed data";
XMEMSET(&rng, 0, sizeof(WC_RNG));
/* Load RSA cert and key */
#if defined(USE_CERT_BUFFERS_2048)
rsaCertSz = (word32)sizeof_client_cert_der_2048;
ExpectNotNull(rsaCert = (byte*)XMALLOC(rsaCertSz, HEAP_HINT,
DYNAMIC_TYPE_TMP_BUFFER));
if (rsaCert != NULL)
XMEMCPY(rsaCert, client_cert_der_2048, rsaCertSz);
rsaPrivKeySz = (word32)sizeof_client_key_der_2048;
ExpectNotNull(rsaPrivKey = (byte*)XMALLOC(rsaPrivKeySz, HEAP_HINT,
DYNAMIC_TYPE_TMP_BUFFER));
if (rsaPrivKey != NULL)
XMEMCPY(rsaPrivKey, client_key_der_2048, rsaPrivKeySz);
#elif defined(USE_CERT_BUFFERS_1024)
rsaCertSz = (word32)sizeof_client_cert_der_1024;
ExpectNotNull(rsaCert = (byte*)XMALLOC(rsaCertSz, HEAP_HINT,
DYNAMIC_TYPE_TMP_BUFFER));
if (rsaCert != NULL)
XMEMCPY(rsaCert, client_cert_der_1024, rsaCertSz);
rsaPrivKeySz = (word32)sizeof_client_key_der_1024;
ExpectNotNull(rsaPrivKey = (byte*)XMALLOC(rsaPrivKeySz, HEAP_HINT,
DYNAMIC_TYPE_TMP_BUFFER));
if (rsaPrivKey != NULL)
XMEMCPY(rsaPrivKey, client_key_der_1024, rsaPrivKeySz);
#elif !defined(NO_FILESYSTEM)
rsaCertSz = FOURK_BUF;
ExpectNotNull(rsaCert = (byte*)XMALLOC(rsaCertSz, HEAP_HINT,
DYNAMIC_TYPE_TMP_BUFFER));
ExpectTrue((f = XFOPEN("./certs/client-cert.der", "rb")) != XBADFILE);
ExpectTrue((rsaCertSz = (word32)XFREAD(rsaCert, 1, rsaCertSz, f)) > 0);
if (f != XBADFILE) { XFCLOSE(f); f = XBADFILE; }
rsaPrivKeySz = FOURK_BUF;
ExpectNotNull(rsaPrivKey = (byte*)XMALLOC(rsaPrivKeySz, HEAP_HINT,
DYNAMIC_TYPE_TMP_BUFFER));
ExpectTrue((f = XFOPEN("./certs/client-key.der", "rb")) != XBADFILE);
ExpectTrue((rsaPrivKeySz = (word32)XFREAD(rsaPrivKey, 1,
rsaPrivKeySz, f)) > 0);
if (f != XBADFILE) XFCLOSE(f);
#else
rsaCert = NULL; rsaCertSz = 0;
rsaPrivKey = NULL; rsaPrivKeySz = 0;
#endif
if (rsaCert == NULL || rsaPrivKey == NULL) {
XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(rsaPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
return TEST_SKIPPED;
}
ExpectIntEQ(wc_InitRng(&rng), 0);
/* Encode a valid SignedData */
ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId));
ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, rsaCert, rsaCertSz), 0);
if (pkcs7 != NULL) {
pkcs7->content = (byte*)data;
pkcs7->contentSz = (word32)sizeof(data);
pkcs7->contentOID = DATA;
pkcs7->hashOID = SHA256h;
pkcs7->encryptOID = RSAk;
pkcs7->privateKey = rsaPrivKey;
pkcs7->privateKeySz = rsaPrivKeySz;
pkcs7->rng = &rng;
}
ExpectIntGT(encodedSz = wc_PKCS7_EncodeSignedData(pkcs7, encoded,
sizeof(encoded)), 0);
wc_PKCS7_Free(pkcs7);
pkcs7 = NULL;
/* Find the signature OCTET STRING tag (0x04) near the end of the
* encoded message and corrupt it. The signature is the last large
* OCTET STRING in the SignerInfo. Search backwards for 0x04 followed
* by a length that looks like an RSA signature (>= 64 bytes).
* This heuristic depends on the signature being the last large
* OCTET STRING; the found==1 assertion below guards against
* silent false passes if encoding changes. */
if (EXPECT_SUCCESS()) {
int found = 0;
for (i = encodedSz - 10; i > 10; i--) {
if (encoded[i] == 0x04) {
int len = 0, lbytes = 0;
if (encoded[i+1] < 0x80) {
len = encoded[i+1]; lbytes = 1;
}
else if (encoded[i+1] == 0x81) {
len = encoded[i+2]; lbytes = 2;
}
else if (encoded[i+1] == 0x82) {
len = (encoded[i+2] << 8) | encoded[i+3]; lbytes = 3;
}
/* RSA signature is typically >= 128 bytes */
if (len >= 64 && i + 1 + lbytes + len <= encodedSz) {
/* Corrupt the OCTET STRING tag to INTEGER */
encoded[i] = 0x02; /* ASN_INTEGER instead of OCTET STRING */
found = 1;
break;
}
}
}
ExpectIntEQ(found, 1);
}
/* Verify the corrupted SignedData - must fail */
if (EXPECT_SUCCESS()) {
ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId));
ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, NULL, 0), 0);
ExpectIntLT(wc_PKCS7_VerifySignedData(pkcs7, encoded,
(word32)encodedSz), 0);
wc_PKCS7_Free(pkcs7);
pkcs7 = NULL;
}
DoExpectIntEQ(wc_FreeRng(&rng), 0);
XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(rsaPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
#endif
return EXPECT_RESULT();
}
/* Test: PKCS#7 EnvelopedData must reject when encryptedContentTotalSz
* exceeds the remaining input buffer.
*
* The fix adds a bounds check under NO_PKCS7_STREAM, but the same
* crafted message should also be properly handled in streaming mode.
* This test crafts an EnvelopedData where the [0] content length
* claims 512 bytes but only minimal data follows. */
static int test_pkcs7_enveloped_content_size_overflow(void)
{
EXPECT_DECLS;
#if defined(HAVE_PKCS7) && !defined(WOLFSSL_NO_MALLOC) && !defined(NO_RSA)
wc_PKCS7* p7 = NULL;
byte out[256];
/* EnvelopedData with KTRI where the EncryptedContentInfo [0] claims
* 512 bytes but only 16 are present.
*
* The outer structure is valid enough to reach the content parsing:
* ContentInfo -> EnvelopedData -> version=0 ->
* RecipientInfos (empty SET) -> EncryptedContentInfo ->
* contentType + AlgorithmIdentifier + [0] oversized content */
static const byte poc[] = {
/* ContentInfo SEQUENCE */
0x30, 0x50,
/* OID envelopedData 1.2.840.113549.1.7.3 */
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x03,
/* [0] EXPLICIT */
0xa0, 0x43,
/* EnvelopedData SEQUENCE */
0x30, 0x41,
/* version = 0 */
0x02, 0x01, 0x00,
/* RecipientInfos SET (empty - no recipients) */
0x31, 0x00,
/* EncryptedContentInfo SEQUENCE */
0x30, 0x3c,
/* OID data 1.2.840.113549.1.7.1 */
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
0x01,
/* AlgorithmIdentifier SEQUENCE */
0x30, 0x1d,
/* OID AES-256-CBC 2.16.840.1.101.3.4.1.42 */
0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01,
0x2a,
/* IV: OCTET STRING (16 zero bytes) */
0x04, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* [0] IMPLICIT encryptedContent - claims 512 bytes! */
0x80, 0x82, 0x02, 0x00,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA
};
p7 = wc_PKCS7_New(NULL, INVALID_DEVID);
ExpectNotNull(p7);
if (p7 != NULL) {
/* With an empty RecipientInfos SET, the function may fail at
* the recipient matching stage before reaching the content-size
* bounds check. The ExpectIntLT assertion ensures the
* oversized content does not cause a buffer over-read. */
ExpectIntLT(wc_PKCS7_DecodeEnvelopedData(p7, (byte*)poc, sizeof(poc),
out, sizeof(out)), 0);
wc_PKCS7_Free(p7);
}
#endif
return EXPECT_RESULT();
}
/* Dilithium verify_ctx_msg must reject absurdly large msgLen */
static int test_dilithium_hash(void)
{
@@ -36834,6 +37534,13 @@ TEST_CASE testCases[] = {
TEST_DECL(test_ed448_rejects_identity_key),
TEST_DECL(test_pkcs7_decode_encrypted_outputsz),
TEST_DECL(test_pkcs7_ori_oversized_oid),
TEST_DECL(test_pkcs7_ori_seqsz_underflow),
TEST_DECL(test_pkcs7_ori_orivalue_overflow),
TEST_DECL(test_pkcs7_ktri_skid_length_mismatch),
TEST_DECL(test_pkcs7_kari_degenerate_bitstring),
TEST_DECL(test_pkcs7_encrypted_content_size_overflow),
TEST_DECL(test_pkcs7_signed_bad_sig_tag),
TEST_DECL(test_pkcs7_enveloped_content_size_overflow),
TEST_DECL(test_pkcs7_padding),
#if defined(WOLFSSL_SNIFFER) && defined(WOLFSSL_SNIFFER_CHAIN_INPUT)
+454
View File
@@ -446,6 +446,460 @@ int test_wolfSSL_PKCS7_sign(void)
return EXPECT_RESULT();
}
/* Regression test for CMS SignedData signer-identity forgery.
*
* The embedded DER is a CMS SignedData message crafted so that the
* certificates SET contains two certificates:
* cert[0] = certs/ca-cert.pem (trusted wolfSSL CA; attacker does NOT hold
* its private key)
* cert[1] = a self-signed "attacker" P-256 certificate (attacker holds
* the private key)
* The signerInfo sid names the attacker certificate, and the signature
* was produced with the attacker's key over "Hello World".
*
* The bug that was present: wolfSSL_PKCS7_verify() iterated all bundled
* certificates trying each public key against the signature. When the
* attacker's key verified, it still reported cert[0] (the trusted CA cert,
* via singleCert) as the signer, and chain validation therefore succeeded
* on an unrelated trusted cert - a full signer-identity forgery.
*
* The expected, correct behavior: the CMS message is rejected because the
* signer certificate named by the sid (the attacker cert) does not chain
* to any certificate in the trust store. */
int test_wolfSSL_PKCS7_verify_signer_forgery(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_ALL) && defined(HAVE_PKCS7) && !defined(NO_BIO) && \
!defined(NO_FILESYSTEM) && !defined(NO_RSA) && defined(HAVE_ECC)
static const byte forgedSignedData[] = {
0x30, 0x82, 0x07, 0x9c, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
0x01, 0x07, 0x02, 0xa0, 0x82, 0x07, 0x8d, 0x30, 0x82, 0x07, 0x89, 0x02,
0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
0x65, 0x03, 0x04, 0x02, 0x01, 0x30, 0x1b, 0x06, 0x09, 0x2a, 0x86, 0x48,
0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x0e, 0x04, 0x0c, 0x48, 0x65,
0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x0a, 0xa0, 0x82,
0x06, 0xab, 0x30, 0x82, 0x04, 0xff, 0x30, 0x82, 0x03, 0xe7, 0xa0, 0x03,
0x02, 0x01, 0x02, 0x02, 0x14, 0x3f, 0x29, 0x11, 0x20, 0x57, 0x71, 0xe7,
0x8e, 0xf9, 0x18, 0x0d, 0xca, 0x70, 0x4d, 0x5b, 0x15, 0x2a, 0x43, 0xd6,
0x24, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0x94, 0x31, 0x0b, 0x30, 0x09, 0x06,
0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, 0x0e,
0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x07, 0x4d, 0x6f, 0x6e, 0x74, 0x61,
0x6e, 0x61, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c,
0x07, 0x42, 0x6f, 0x7a, 0x65, 0x6d, 0x61, 0x6e, 0x31, 0x11, 0x30, 0x0f,
0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x08, 0x53, 0x61, 0x77, 0x74, 0x6f,
0x6f, 0x74, 0x68, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0b,
0x0c, 0x0a, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x74, 0x69, 0x6e, 0x67,
0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0f, 0x77,
0x77, 0x77, 0x2e, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73, 0x6c, 0x2e, 0x63,
0x6f, 0x6d, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6e, 0x66, 0x6f, 0x40,
0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x30,
0x1e, 0x17, 0x0d, 0x32, 0x35, 0x31, 0x31, 0x31, 0x33, 0x32, 0x30, 0x34,
0x31, 0x31, 0x31, 0x5a, 0x17, 0x0d, 0x32, 0x38, 0x30, 0x38, 0x30, 0x39,
0x32, 0x30, 0x34, 0x31, 0x31, 0x31, 0x5a, 0x30, 0x81, 0x94, 0x31, 0x0b,
0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x07, 0x4d, 0x6f,
0x6e, 0x74, 0x61, 0x6e, 0x61, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55,
0x04, 0x07, 0x0c, 0x07, 0x42, 0x6f, 0x7a, 0x65, 0x6d, 0x61, 0x6e, 0x31,
0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x08, 0x53, 0x61,
0x77, 0x74, 0x6f, 0x6f, 0x74, 0x68, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
0x55, 0x04, 0x0b, 0x0c, 0x0a, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x74,
0x69, 0x6e, 0x67, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03,
0x0c, 0x0f, 0x77, 0x77, 0x77, 0x2e, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73,
0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a,
0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6e,
0x66, 0x6f, 0x40, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73, 0x6c, 0x2e, 0x63,
0x6f, 0x6d, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01,
0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xbf,
0x0c, 0xca, 0x2d, 0x14, 0xb2, 0x1e, 0x84, 0x42, 0x5b, 0xcd, 0x38, 0x1f,
0x4a, 0xf2, 0x4d, 0x75, 0x10, 0xf1, 0xb6, 0x35, 0x9f, 0xdf, 0xca, 0x7d,
0x03, 0x98, 0xd3, 0xac, 0xde, 0x03, 0x66, 0xee, 0x2a, 0xf1, 0xd8, 0xb0,
0x7d, 0x6e, 0x07, 0x54, 0x0b, 0x10, 0x98, 0x21, 0x4d, 0x80, 0xcb, 0x12,
0x20, 0xe7, 0xcc, 0x4f, 0xde, 0x45, 0x7d, 0xc9, 0x72, 0x77, 0x32, 0xea,
0xca, 0x90, 0xbb, 0x69, 0x52, 0x10, 0x03, 0x2f, 0xa8, 0xf3, 0x95, 0xc5,
0xf1, 0x8b, 0x62, 0x56, 0x1b, 0xef, 0x67, 0x6f, 0xa4, 0x10, 0x41, 0x95,
0xad, 0x0a, 0x9b, 0xe3, 0xa5, 0xc0, 0xb0, 0xd2, 0x70, 0x76, 0x50, 0x30,
0x5b, 0xa8, 0xe8, 0x08, 0x2c, 0x7c, 0xed, 0xa7, 0xa2, 0x7a, 0x8d, 0x38,
0x29, 0x1c, 0xac, 0xc7, 0xed, 0xf2, 0x7c, 0x95, 0xb0, 0x95, 0x82, 0x7d,
0x49, 0x5c, 0x38, 0xcd, 0x77, 0x25, 0xef, 0xbd, 0x80, 0x75, 0x53, 0x94,
0x3c, 0x3d, 0xca, 0x63, 0x5b, 0x9f, 0x15, 0xb5, 0xd3, 0x1d, 0x13, 0x2f,
0x19, 0xd1, 0x3c, 0xdb, 0x76, 0x3a, 0xcc, 0xb8, 0x7d, 0xc9, 0xe5, 0xc2,
0xd7, 0xda, 0x40, 0x6f, 0xd8, 0x21, 0xdc, 0x73, 0x1b, 0x42, 0x2d, 0x53,
0x9c, 0xfe, 0x1a, 0xfc, 0x7d, 0xab, 0x7a, 0x36, 0x3f, 0x98, 0xde, 0x84,
0x7c, 0x05, 0x67, 0xce, 0x6a, 0x14, 0x38, 0x87, 0xa9, 0xf1, 0x8c, 0xb5,
0x68, 0xcb, 0x68, 0x7f, 0x71, 0x20, 0x2b, 0xf5, 0xa0, 0x63, 0xf5, 0x56,
0x2f, 0xa3, 0x26, 0xd2, 0xb7, 0x6f, 0xb1, 0x5a, 0x17, 0xd7, 0x38, 0x99,
0x08, 0xfe, 0x93, 0x58, 0x6f, 0xfe, 0xc3, 0x13, 0x49, 0x08, 0x16, 0x0b,
0xa7, 0x4d, 0x67, 0x00, 0x52, 0x31, 0x67, 0x23, 0x4e, 0x98, 0xed, 0x51,
0x45, 0x1d, 0xb9, 0x04, 0xd9, 0x0b, 0xec, 0xd8, 0x28, 0xb3, 0x4b, 0xbd,
0xed, 0x36, 0x79, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x45,
0x30, 0x82, 0x01, 0x41, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04,
0x16, 0x04, 0x14, 0x27, 0x8e, 0x67, 0x11, 0x74, 0xc3, 0x26, 0x1d, 0x3f,
0xed, 0x33, 0x63, 0xb3, 0xa4, 0xd8, 0x1d, 0x30, 0xe5, 0xe8, 0xd5, 0x30,
0x81, 0xd4, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x81, 0xcc, 0x30, 0x81,
0xc9, 0x80, 0x14, 0x27, 0x8e, 0x67, 0x11, 0x74, 0xc3, 0x26, 0x1d, 0x3f,
0xed, 0x33, 0x63, 0xb3, 0xa4, 0xd8, 0x1d, 0x30, 0xe5, 0xe8, 0xd5, 0xa1,
0x81, 0x9a, 0xa4, 0x81, 0x97, 0x30, 0x81, 0x94, 0x31, 0x0b, 0x30, 0x09,
0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 0x30,
0x0e, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x07, 0x4d, 0x6f, 0x6e, 0x74,
0x61, 0x6e, 0x61, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07,
0x0c, 0x07, 0x42, 0x6f, 0x7a, 0x65, 0x6d, 0x61, 0x6e, 0x31, 0x11, 0x30,
0x0f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x08, 0x53, 0x61, 0x77, 0x74,
0x6f, 0x6f, 0x74, 0x68, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
0x0b, 0x0c, 0x0a, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x74, 0x69, 0x6e,
0x67, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0f,
0x77, 0x77, 0x77, 0x2e, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73, 0x6c, 0x2e,
0x63, 0x6f, 0x6d, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48,
0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6e, 0x66, 0x6f,
0x40, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d,
0x82, 0x14, 0x3f, 0x29, 0x11, 0x20, 0x57, 0x71, 0xe7, 0x8e, 0xf9, 0x18,
0x0d, 0xca, 0x70, 0x4d, 0x5b, 0x15, 0x2a, 0x43, 0xd6, 0x24, 0x30, 0x0c,
0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff,
0x30, 0x1c, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x15, 0x30, 0x13, 0x82,
0x0b, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
0x87, 0x04, 0x7f, 0x00, 0x00, 0x01, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d,
0x25, 0x04, 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03,
0x02, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x0f, 0xae, 0x89,
0xd5, 0x68, 0xe4, 0x41, 0xf8, 0x9b, 0xe0, 0xc5, 0x61, 0x06, 0x57, 0xff,
0xa0, 0x92, 0x0f, 0xb2, 0xed, 0xd3, 0x99, 0x5b, 0x99, 0x5e, 0x32, 0x7e,
0x97, 0xc7, 0xaf, 0x6c, 0xfe, 0x8c, 0xa6, 0xae, 0x32, 0xa1, 0x0d, 0xca,
0xcd, 0xfc, 0x18, 0xe5, 0xd1, 0xf8, 0x20, 0x5b, 0x5a, 0x38, 0x81, 0x46,
0x5b, 0x48, 0x87, 0xa5, 0x3f, 0x3b, 0x7b, 0xc7, 0xea, 0xf5, 0x35, 0x29,
0x31, 0x15, 0x39, 0x38, 0x5d, 0x48, 0xe6, 0x01, 0x81, 0x5c, 0x5e, 0x7c,
0x10, 0xf5, 0x16, 0xe3, 0x59, 0xaf, 0x44, 0xc8, 0xb5, 0x8d, 0xc1, 0x32,
0x23, 0xb3, 0xb8, 0x12, 0x6e, 0x5c, 0x8d, 0xe6, 0xc2, 0xd2, 0x41, 0x03,
0xeb, 0x17, 0x42, 0xe2, 0x7f, 0xbc, 0x00, 0x5d, 0xa5, 0x31, 0xef, 0xc6,
0x48, 0xee, 0xdb, 0xcc, 0xe0, 0xf1, 0x56, 0xf5, 0xd4, 0xca, 0x45, 0xa1,
0x59, 0xb5, 0xe4, 0xd7, 0x60, 0x9c, 0x57, 0xe0, 0xa7, 0x5a, 0xf2, 0x35,
0x1e, 0xa0, 0x22, 0xdb, 0x5e, 0x1c, 0x0c, 0x61, 0xbd, 0xa1, 0xc5, 0x7b,
0x9f, 0x69, 0xf2, 0xd5, 0x95, 0xe2, 0xbc, 0x52, 0xb9, 0x1d, 0x9c, 0x2c,
0xda, 0xb6, 0x73, 0x75, 0x4a, 0x84, 0xe5, 0x94, 0xb8, 0x19, 0x4d, 0xdd,
0x70, 0xbd, 0x7f, 0x4c, 0xb9, 0x17, 0x6a, 0x58, 0x16, 0x89, 0x22, 0x44,
0x37, 0x57, 0x55, 0x26, 0x42, 0xe3, 0xb7, 0xe5, 0xc7, 0x2b, 0x40, 0x0c,
0xe9, 0xe4, 0x7f, 0x52, 0x75, 0xdf, 0x06, 0xc9, 0xfb, 0x01, 0x44, 0x34,
0xac, 0x20, 0x3c, 0xb4, 0xbe, 0x2b, 0x3e, 0xef, 0x85, 0x38, 0x96, 0x5b,
0x9b, 0x1e, 0x25, 0x86, 0x18, 0x4c, 0xa4, 0x06, 0x70, 0x06, 0x6a, 0xc8,
0x4b, 0x6f, 0x5f, 0xc4, 0x05, 0x1f, 0x03, 0x62, 0x30, 0x11, 0x61, 0xbc,
0xc1, 0x40, 0x31, 0x66, 0xdc, 0x64, 0xf0, 0x4f, 0x6b, 0xb9, 0xec, 0xc8,
0x29, 0x30, 0x82, 0x01, 0xa4, 0x30, 0x82, 0x01, 0x49, 0xa0, 0x03, 0x02,
0x01, 0x02, 0x02, 0x14, 0x62, 0x4d, 0x11, 0x9c, 0xcf, 0x5d, 0xe5, 0x71,
0xa2, 0x82, 0xd9, 0x8f, 0xe0, 0x04, 0xb8, 0x5f, 0x0e, 0x4d, 0x07, 0xad,
0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02,
0x30, 0x27, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
0x08, 0x61, 0x74, 0x74, 0x61, 0x63, 0x6b, 0x65, 0x72, 0x31, 0x12, 0x30,
0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x09, 0x75, 0x6e, 0x74, 0x72,
0x75, 0x73, 0x74, 0x65, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x36, 0x30,
0x34, 0x32, 0x31, 0x31, 0x31, 0x31, 0x36, 0x32, 0x38, 0x5a, 0x17, 0x0d,
0x33, 0x36, 0x30, 0x34, 0x31, 0x38, 0x31, 0x31, 0x31, 0x36, 0x32, 0x38,
0x5a, 0x30, 0x27, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03,
0x0c, 0x08, 0x61, 0x74, 0x74, 0x61, 0x63, 0x6b, 0x65, 0x72, 0x31, 0x12,
0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x09, 0x75, 0x6e, 0x74,
0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07,
0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48,
0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xae, 0xdb, 0xf7,
0x3b, 0x7e, 0x82, 0x88, 0xfc, 0x1a, 0xfb, 0x86, 0x56, 0x83, 0x03, 0xdd,
0x05, 0x14, 0x79, 0x51, 0x0f, 0x3c, 0x86, 0x85, 0x2d, 0xeb, 0x18, 0x17,
0x20, 0x3b, 0x37, 0x6f, 0x7f, 0x78, 0x19, 0x3b, 0xf6, 0x71, 0xad, 0xc9,
0x65, 0x81, 0x7e, 0xe0, 0xa9, 0x29, 0xdd, 0xfd, 0xf0, 0xff, 0x04, 0x7d,
0x5a, 0x59, 0xd6, 0x6c, 0xe2, 0xde, 0xc5, 0xd5, 0xb6, 0x1f, 0x69, 0xd9,
0x33, 0xa3, 0x53, 0x30, 0x51, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
0x04, 0x16, 0x04, 0x14, 0xf7, 0xab, 0x3f, 0x49, 0xcf, 0x7d, 0x48, 0x9c,
0x04, 0x49, 0x1a, 0xac, 0x8f, 0x26, 0x16, 0x09, 0xa8, 0x2a, 0x74, 0xf5,
0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80,
0x14, 0xf7, 0xab, 0x3f, 0x49, 0xcf, 0x7d, 0x48, 0x9c, 0x04, 0x49, 0x1a,
0xac, 0x8f, 0x26, 0x16, 0x09, 0xa8, 0x2a, 0x74, 0xf5, 0x30, 0x0f, 0x06,
0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01,
0x01, 0xff, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04,
0x03, 0x02, 0x03, 0x49, 0x00, 0x30, 0x46, 0x02, 0x21, 0x00, 0x8d, 0xbf,
0x36, 0xe5, 0x51, 0x9a, 0xde, 0xf4, 0x7f, 0xbf, 0xbd, 0x7f, 0x71, 0x66,
0xc1, 0x67, 0xfa, 0x71, 0x0d, 0x79, 0xc6, 0x60, 0x3a, 0x6c, 0xeb, 0x43,
0xc3, 0xf2, 0x5e, 0xe8, 0x74, 0xb6, 0x02, 0x21, 0x00, 0xfa, 0xdb, 0x40,
0x47, 0x72, 0xf0, 0x15, 0x52, 0xc1, 0x78, 0x11, 0x6b, 0x76, 0xc5, 0x1f,
0xcf, 0xb6, 0x09, 0x6d, 0x8f, 0xcb, 0x92, 0x2f, 0x1b, 0x3c, 0xc3, 0x28,
0x48, 0x61, 0x0f, 0x60, 0x71, 0x31, 0x81, 0xa8, 0x30, 0x81, 0xa5, 0x02,
0x01, 0x01, 0x30, 0x3f, 0x30, 0x27, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03,
0x55, 0x04, 0x03, 0x0c, 0x08, 0x61, 0x74, 0x74, 0x61, 0x63, 0x6b, 0x65,
0x72, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x09,
0x75, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x02, 0x14, 0x62,
0x4d, 0x11, 0x9c, 0xcf, 0x5d, 0xe5, 0x71, 0xa2, 0x82, 0xd9, 0x8f, 0xe0,
0x04, 0xb8, 0x5f, 0x0e, 0x4d, 0x07, 0xad, 0x30, 0x0b, 0x06, 0x09, 0x60,
0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x30, 0x0a, 0x06, 0x08,
0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x04, 0x46, 0x30, 0x44,
0x02, 0x20, 0x22, 0x4a, 0x99, 0xb1, 0xbc, 0xa9, 0xee, 0x24, 0x60, 0x81,
0xb9, 0x64, 0xba, 0x86, 0x00, 0xae, 0xb5, 0xd7, 0xb8, 0x72, 0xb9, 0x8c,
0xb3, 0xe7, 0x78, 0x29, 0xdb, 0xa8, 0x27, 0xf7, 0x30, 0xf0, 0x02, 0x20,
0x19, 0x2d, 0xd3, 0x17, 0x9a, 0xc1, 0xf9, 0xd2, 0x63, 0x92, 0x8e, 0x78,
0xcc, 0xa4, 0x0b, 0x91, 0x12, 0xa5, 0xb2, 0xbc, 0x35, 0x87, 0x8e, 0x33,
0xa7, 0xe0, 0x5e, 0xab, 0x95, 0xb2, 0x2a, 0xf4
};
PKCS7* p7 = NULL;
X509_STORE* store = NULL;
X509* caCert = NULL;
WOLFSSL_BIO* caBio = NULL;
const byte* p = forgedSignedData;
const char* ca = "./certs/ca-cert.pem";
/* Load the same CA into the trust store that the attacker bundled at
* cert[0] in the forged message. */
ExpectNotNull(caBio = BIO_new_file(ca, "r"));
ExpectNotNull(caCert = PEM_read_bio_X509(caBio, NULL, 0, NULL));
ExpectNotNull(store = X509_STORE_new());
ExpectIntEQ(X509_STORE_add_cert(store, caCert), 1);
/* Parse the forged message. d2i_PKCS7 internally runs
* wc_PKCS7_VerifySignedData, which must NOT accept the attacker's
* signature under any bundled cert other than the one named by the
* signerInfo sid. Since the sid names the attacker cert (which does
* not chain to the trusted CA), the parse may succeed but verification
* against the trust store must fail. */
ExpectNotNull(p7 = d2i_PKCS7(NULL, &p, (int)sizeof(forgedSignedData)));
/* PKCS7_verify() MUST fail: the only certificate in the trust store
* is the wolfSSL CA - it is bundled at cert[0] but did NOT sign this
* message. The actual signer (the attacker's self-signed cert at
* cert[1]) cannot chain to any trust anchor. */
ExpectIntEQ(PKCS7_verify(p7, NULL, store, NULL, NULL, 0),
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
PKCS7_free(p7);
X509_STORE_free(store);
X509_free(caCert);
BIO_free(caBio);
#endif
return EXPECT_RESULT();
}
/* Exercise the SignerInfo-sid binding enforcement end-to-end.
*
* For both supported sid encodings (v1 = IssuerAndSerialNumber, v3 =
* SubjectKeyIdentifier), this builds a valid CMS SignedData message with
* two certificates in the bundle:
* cert[0] = ca-cert (extra, non-signing)
* cert[1] = server-cert (actual signer)
* and checks that:
* - parsing + signature verification succeeds,
* - chain validation against a trust store containing ca-cert succeeds,
* - PKCS7_get0_signers() returns the *signer* (server-cert), not the
* extra cert at cert[0] - which would be the pre-fix behavior and the
* core of the signer-identity forgery bug. */
int test_wolfSSL_PKCS7_verify_sid_binding(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_ALL) && defined(HAVE_PKCS7) && !defined(NO_BIO) && \
!defined(NO_FILESYSTEM) && !defined(NO_RSA)
const char* signerCertFile = "./certs/server-cert.pem";
const char* signerKeyFile = "./certs/server-key.pem";
const char* caFile = "./certs/ca-cert.pem";
const byte content[] = "sid-binding test content";
/* Build both variants: default v1 (IssuerAndSerialNumber) and v3
* (SubjectKeyIdentifier). */
const int sidTypes[2] = { CMS_ISSUER_AND_SERIAL_NUMBER, CMS_SKID };
int variant;
BIO* signerCertBio = NULL;
BIO* caBio = NULL;
X509* signerCertX509 = NULL;
X509* caX509 = NULL;
byte* signerCertDer = NULL;
byte* caDer = NULL;
byte* signerKey = NULL;
int signerCertDerSz = 0;
int caDerSz = 0;
size_t signerKeySz = 0;
XFILE keyFile = XBADFILE;
WC_RNG rng;
int rngInited = 0;
/* ---- Load signer cert + key and the CA cert. ---- */
ExpectNotNull(signerCertBio = BIO_new_file(signerCertFile, "r"));
ExpectNotNull(signerCertX509 = PEM_read_bio_X509(signerCertBio, NULL, 0,
NULL));
ExpectIntGT(signerCertDerSz = i2d_X509(signerCertX509, &signerCertDer), 0);
ExpectNotNull(caBio = BIO_new_file(caFile, "r"));
ExpectNotNull(caX509 = PEM_read_bio_X509(caBio, NULL, 0, NULL));
ExpectIntGT(caDerSz = i2d_X509(caX509, &caDer), 0);
/* Slurp the DER private key straight from a PEM->DER round-trip via
* wc_KeyPemToDer. The test only needs the bytes in a form
* wc_PKCS7_EncodeSignedData can consume. */
{
long filePemLen = 0;
byte* keyPem = NULL;
int derLen = 0;
ExpectTrue((keyFile = XFOPEN(signerKeyFile, "rb")) != XBADFILE);
if (keyFile != XBADFILE) {
(void)XFSEEK(keyFile, 0, XSEEK_END);
filePemLen = XFTELL(keyFile);
(void)XFSEEK(keyFile, 0, XSEEK_SET);
ExpectIntGT(filePemLen, 0);
keyPem = (byte*)XMALLOC((size_t)filePemLen, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
ExpectNotNull(keyPem);
if (keyPem != NULL) {
ExpectIntEQ(XFREAD(keyPem, 1, (size_t)filePemLen, keyFile),
(size_t)filePemLen);
/* First call sizes the output buffer. */
derLen = wc_KeyPemToDer(keyPem, (word32)filePemLen, NULL, 0,
NULL);
ExpectIntGT(derLen, 0);
if (derLen > 0) {
signerKey = (byte*)XMALLOC((size_t)derLen, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
ExpectNotNull(signerKey);
if (signerKey != NULL) {
derLen = wc_KeyPemToDer(keyPem, (word32)filePemLen,
signerKey, (word32)derLen,
NULL);
ExpectIntGT(derLen, 0);
signerKeySz = (size_t)derLen;
}
}
}
XFREE(keyPem, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFCLOSE(keyFile);
keyFile = XBADFILE;
}
}
ExpectIntEQ(wc_InitRng(&rng), 0);
if (EXPECT_SUCCESS())
rngInited = 1;
for (variant = 0; variant < 2; variant++) {
wc_PKCS7* p7Enc = NULL;
byte encoded[4096];
int encodedSz = 0;
PKCS7* p7Ver = NULL;
X509_STORE* store = NULL;
const byte* encodedPtr = NULL;
STACK_OF(X509)* signers = NULL;
X509* reportedSigner = NULL;
byte* reportedSignerDer = NULL;
int reportedSignerDerSz = 0;
X509* caForStore = NULL;
BIO* caForStoreBio = NULL;
/* ---- Encode: signer=server-cert, extra bundle cert=ca. ---- */
ExpectNotNull(p7Enc = wc_PKCS7_New(HEAP_HINT, INVALID_DEVID));
ExpectIntEQ(wc_PKCS7_Init(p7Enc, HEAP_HINT, INVALID_DEVID), 0);
ExpectIntEQ(wc_PKCS7_InitWithCert(p7Enc, signerCertDer,
(word32)signerCertDerSz), 0);
/* wc_PKCS7_AddCertificate prepends to the cert list - the encoded
* SET therefore ends up [ca, signer], putting the actual signer
* at index 1 and exercising the sid-selection path (cert[0] is
* NOT the signer and must be skipped). */
ExpectIntEQ(wc_PKCS7_AddCertificate(p7Enc, caDer, (word32)caDerSz), 0);
if (p7Enc != NULL) {
p7Enc->content = (byte*)content;
p7Enc->contentSz = (word32)sizeof(content);
p7Enc->encryptOID = RSAk;
p7Enc->hashOID = SHA256h;
p7Enc->privateKey = signerKey;
p7Enc->privateKeySz = (word32)signerKeySz;
p7Enc->rng = &rng;
}
ExpectIntEQ(wc_PKCS7_SetSignerIdentifierType(p7Enc, sidTypes[variant]),
0);
ExpectIntGT((encodedSz = wc_PKCS7_EncodeSignedData(p7Enc, encoded,
sizeof(encoded))),
0);
wc_PKCS7_Free(p7Enc);
p7Enc = NULL;
/* ---- Parse + verify through the OpenSSL compat layer. ---- */
encodedPtr = encoded;
ExpectNotNull(p7Ver = d2i_PKCS7(NULL, &encodedPtr, encodedSz));
/* Trust store holds only ca-cert. Reload it rather than reusing
* caX509, since X509_STORE_free takes ownership-like semantics. */
ExpectNotNull(caForStoreBio = BIO_new_file(caFile, "r"));
ExpectNotNull(caForStore = PEM_read_bio_X509(caForStoreBio, NULL, 0,
NULL));
ExpectNotNull(store = X509_STORE_new());
ExpectIntEQ(X509_STORE_add_cert(store, caForStore), 1);
ExpectIntEQ(PKCS7_verify(p7Ver, NULL, store, NULL, NULL, 0), 1);
/* Snapshot the singleCert / verifyCert pointers and sizes after
* PKCS7_verify has finished re-parsing the message. A buggy
* implementation that passes &p7->pkcs7.singleCert (or verifyCert)
* directly to wolfSSL_d2i_X509 permanently advances the struct
* field, which corrupts it for any subsequent use - producing a
* heap-OOB read on the next call since the size isn't advanced.
* These pointers must stay exactly where they are across repeated
* get0_signers calls. */
if (p7Ver != NULL) {
wc_PKCS7* wcP7 = &((WOLFSSL_PKCS7*)p7Ver)->pkcs7;
byte* singleBefore = wcP7->singleCert;
word32 singleSzBefore = wcP7->singleCertSz;
byte* verifyBefore = wcP7->verifyCert;
word32 verifySzBefore = wcP7->verifyCertSz;
int i;
/* Call get0_signers repeatedly. Each invocation must return
* the correct cert and must not mutate singleCert/verifyCert.
* Three iterations so the "second call reads past the end"
* pattern (the exact OOB the reporter hit) is exercised. */
for (i = 0; i < 3; i++) {
ExpectNotNull(signers = PKCS7_get0_signers(p7Ver, NULL, 0));
ExpectIntEQ(sk_X509_num(signers), 1);
ExpectNotNull(reportedSigner = sk_X509_value(signers, 0));
ExpectIntGT(reportedSignerDerSz = i2d_X509(reportedSigner,
&reportedSignerDer), 0);
/* DER-compare: reportedSigner must equal server-cert and
* must NOT equal ca-cert (the pre-fix signer-confusion
* outcome). */
ExpectIntEQ(reportedSignerDerSz, signerCertDerSz);
if (reportedSignerDer != NULL && signerCertDer != NULL) {
ExpectIntEQ(XMEMCMP(reportedSignerDer, signerCertDer,
(size_t)signerCertDerSz), 0);
if (reportedSignerDerSz == caDerSz) {
ExpectIntNE(XMEMCMP(reportedSignerDer, caDer,
(size_t)caDerSz), 0);
}
}
XFREE(reportedSignerDer, NULL, DYNAMIC_TYPE_OPENSSL);
reportedSignerDer = NULL;
sk_X509_pop_free(signers, NULL);
signers = NULL;
/* Struct fields must survive every call unchanged. */
ExpectPtrEq(wcP7->singleCert, singleBefore);
ExpectIntEQ(wcP7->singleCertSz, singleSzBefore);
ExpectPtrEq(wcP7->verifyCert, verifyBefore);
ExpectIntEQ(wcP7->verifyCertSz, verifySzBefore);
}
}
PKCS7_free(p7Ver);
X509_STORE_free(store);
X509_free(caForStore);
BIO_free(caForStoreBio);
}
if (rngInited)
wc_FreeRng(&rng);
XFREE(signerKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(signerCertDer, NULL, DYNAMIC_TYPE_OPENSSL);
XFREE(caDer, NULL, DYNAMIC_TYPE_OPENSSL);
X509_free(signerCertX509);
X509_free(caX509);
BIO_free(signerCertBio);
BIO_free(caBio);
#endif
return EXPECT_RESULT();
}
int test_wolfSSL_PKCS7_SIGNED_new(void)
{
EXPECT_DECLS;
+4
View File
@@ -27,6 +27,8 @@
int test_wolfssl_PKCS7(void);
int test_wolfSSL_PKCS7_certs(void);
int test_wolfSSL_PKCS7_sign(void);
int test_wolfSSL_PKCS7_verify_signer_forgery(void);
int test_wolfSSL_PKCS7_verify_sid_binding(void);
int test_wolfSSL_PKCS7_SIGNED_new(void);
int test_wolfSSL_PEM_write_bio_PKCS7(void);
int test_wolfSSL_PEM_write_bio_encryptedKey(void);
@@ -38,6 +40,8 @@ int test_wolfSSL_PKCS12(void);
TEST_DECL_GROUP("ossl_p7", test_wolfssl_PKCS7), \
TEST_DECL_GROUP("ossl_p7", test_wolfSSL_PKCS7_certs), \
TEST_DECL_GROUP("ossl_p7", test_wolfSSL_PKCS7_sign), \
TEST_DECL_GROUP("ossl_p7", test_wolfSSL_PKCS7_verify_signer_forgery), \
TEST_DECL_GROUP("ossl_p7", test_wolfSSL_PKCS7_verify_sid_binding), \
TEST_DECL_GROUP("ossl_p7", test_wolfSSL_PKCS7_SIGNED_new), \
TEST_DECL_GROUP("ossl_p7", test_wolfSSL_PEM_write_bio_PKCS7), \
TEST_DECL_GROUP("ossl_p7", test_wolfSSL_PEM_write_bio_encryptedKey), \
+332 -24
View File
@@ -1118,6 +1118,229 @@ int test_wc_PKCS7_EnvelopedData_KTRI_RSA_PSS(void)
#endif
/*
* Bleichenbacher padding-oracle regression: wc_PKCS7_DecryptKtri must not
* return a distinguishable error when RSA PKCS#1 v1.5 unwrap of the
* encrypted CEK fails vs. when it succeeds with a wrong key. The
* mitigation substitutes a deterministic pseudo-random CEK on RSA failure
* so content decryption fails indistinguishably. This test corrupts the
* encryptedKey in a valid EnvelopedData and asserts the error matches
* content corruption rather than surfacing an RSA/recipient-level code.
* Runs for AES-128 and AES-256 because the fake CEK is a fixed 32 bytes:
* AES-128 (key size 16) exercises the path where the fake size differs
* from the real CEK size.
*/
#if defined(HAVE_PKCS7) && !defined(NO_RSA) && !defined(NO_SHA256) && \
!defined(NO_AES) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_128) && \
defined(WOLFSSL_AES_256) && !defined(NO_HMAC) && \
!defined(WOLFSSL_NO_MALLOC) && \
(defined(USE_CERT_BUFFERS_2048) || defined(USE_CERT_BUFFERS_1024) || \
!defined(NO_FILESYSTEM))
static int pkcs7_ktri_bad_pad_case(int encryptOID, byte* rsaCert,
word32 rsaCertSz, byte* rsaPrivKey,
word32 rsaPrivKeySz, byte* encrypted,
word32 encryptedCap, byte* decoded,
word32 decodedCap)
{
EXPECT_DECLS;
PKCS7* pkcs7 = NULL;
byte data[] = "PKCS7 KTRI bad-RSA-padding regression payload.";
int encryptedSz = 0;
int badKeyRet = 0;
int badContentRet = 0;
byte savedKeyByte = 0;
byte savedContentByte = 0;
word32 i;
word32 encryptedKeyOff = 0;
static const byte rsaEncOid[] = {
0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D,
0x01, 0x01, 0x01
};
ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId));
ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, rsaCert, rsaCertSz), 0);
if (pkcs7 != NULL) {
pkcs7->content = data;
pkcs7->contentSz = (word32)sizeof(data);
pkcs7->contentOID = DATA;
pkcs7->encryptOID = encryptOID;
}
ExpectIntGT(encryptedSz = wc_PKCS7_EncodeEnvelopedData(pkcs7,
encrypted, encryptedCap), 0);
wc_PKCS7_Free(pkcs7);
pkcs7 = NULL;
/* Locate the KTRI encryptedKey OCTET STRING. After the rsaEncryption
* OID there are NULL algorithm parameters (05 00), then a 256-byte
* OCTET STRING (tag 04, long-form length 82 01 00 for RSA-2048). */
for (i = 0; (int)(i + sizeof(rsaEncOid)) < encryptedSz; i++) {
if (XMEMCMP(&encrypted[i], rsaEncOid, sizeof(rsaEncOid)) == 0) {
word32 p = i + (word32)sizeof(rsaEncOid);
if (p + 2 < (word32)encryptedSz &&
encrypted[p] == 0x05 && encrypted[p + 1] == 0x00) {
p += 2;
}
if (p + 4 < (word32)encryptedSz && encrypted[p] == 0x04) {
if (encrypted[p + 1] == 0x82) {
encryptedKeyOff = p + 4;
}
else if (encrypted[p + 1] == 0x81) {
encryptedKeyOff = p + 3;
}
else {
encryptedKeyOff = p + 2;
}
}
break;
}
}
ExpectIntGT(encryptedKeyOff, 0);
ExpectIntLT(encryptedKeyOff + 32, (word32)encryptedSz);
/* Case 1: corrupt a byte inside the RSA ciphertext, decode, restore. */
savedKeyByte = encrypted[encryptedKeyOff + 16];
encrypted[encryptedKeyOff + 16] ^= 0xA5;
ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId));
ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, rsaCert, rsaCertSz), 0);
if (pkcs7 != NULL) {
pkcs7->privateKey = rsaPrivKey;
pkcs7->privateKeySz = rsaPrivKeySz;
}
badKeyRet = wc_PKCS7_DecodeEnvelopedData(pkcs7, encrypted,
(word32)encryptedSz, decoded, decodedCap);
wc_PKCS7_Free(pkcs7);
pkcs7 = NULL;
encrypted[encryptedKeyOff + 16] = savedKeyByte;
/* Case 2: corrupt a byte in the second-to-last AES ciphertext block.
* In CBC mode this deterministically XOR-flips the corresponding byte
* in the last plaintext block, invalidating the PKCS#7 padding
* (original pad byte 0x01 becomes 0x01^0xA5 = 0xA4 > blockSz).
* Corrupting the last ciphertext block directly would randomize the
* entire last plaintext block, giving ~1/256 chance of accidentally
* valid padding and intermittent test failures. */
savedContentByte = encrypted[encryptedSz - 17];
encrypted[encryptedSz - 17] ^= 0xA5;
ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId));
ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, rsaCert, rsaCertSz), 0);
if (pkcs7 != NULL) {
pkcs7->privateKey = rsaPrivKey;
pkcs7->privateKeySz = rsaPrivKeySz;
}
badContentRet = wc_PKCS7_DecodeEnvelopedData(pkcs7, encrypted,
(word32)encryptedSz, decoded, decodedCap);
wc_PKCS7_Free(pkcs7);
pkcs7 = NULL;
encrypted[encryptedSz - 17] = savedContentByte;
/* Case 2 must always fail: the CBC-chain corruption deterministically
* invalidates the PKCS#7 padding. */
ExpectIntLT(badContentRet, 0);
/* Bad-key must NOT leak as an RSA- or recipient-level error. */
ExpectIntNE(badKeyRet, WC_NO_ERR_TRACE(PKCS7_RECIP_E));
ExpectIntNE(badKeyRet, WC_NO_ERR_TRACE(RSA_PAD_E));
ExpectIntNE(badKeyRet, WC_NO_ERR_TRACE(RSA_BUFFER_E));
ExpectIntNE(badKeyRet, WC_NO_ERR_TRACE(BAD_PADDING_E));
/* Case 1 (bad RSA key) decrypts content with a random fake CEK,
* producing fully random plaintext. With ~1/256 probability the
* PKCS#7 padding accidentally looks valid, causing a positive
* garbage-length return instead of an error. This does not leak
* RSA key information, so it is acceptable. When both cases do
* fail, verify they fail at the same content-decryption layer. */
if (badKeyRet < 0) {
ExpectIntEQ(badKeyRet, badContentRet);
}
return EXPECT_RESULT();
}
int test_wc_PKCS7_EnvelopedData_KTRI_BadRsaPad(void)
{
EXPECT_DECLS;
byte encrypted[FOURK_BUF];
byte decoded[FOURK_BUF];
byte* rsaCert = NULL;
byte* rsaPrivKey = NULL;
word32 rsaCertSz = 0;
word32 rsaPrivKeySz = 0;
#if !defined(USE_CERT_BUFFERS_1024) && !defined(USE_CERT_BUFFERS_2048) && \
!defined(NO_FILESYSTEM)
XFILE f = XBADFILE;
#endif
/* Load RSA cert and key */
#if defined(USE_CERT_BUFFERS_1024)
rsaCertSz = (word32)sizeof_client_cert_der_1024;
ExpectNotNull(rsaCert = (byte*)XMALLOC(rsaCertSz, HEAP_HINT,
DYNAMIC_TYPE_TMP_BUFFER));
if (rsaCert != NULL)
XMEMCPY(rsaCert, client_cert_der_1024, rsaCertSz);
rsaPrivKeySz = (word32)sizeof_client_key_der_1024;
ExpectNotNull(rsaPrivKey = (byte*)XMALLOC(rsaPrivKeySz, HEAP_HINT,
DYNAMIC_TYPE_TMP_BUFFER));
if (rsaPrivKey != NULL)
XMEMCPY(rsaPrivKey, client_key_der_1024, rsaPrivKeySz);
#elif defined(USE_CERT_BUFFERS_2048)
rsaCertSz = (word32)sizeof_client_cert_der_2048;
ExpectNotNull(rsaCert = (byte*)XMALLOC(rsaCertSz, HEAP_HINT,
DYNAMIC_TYPE_TMP_BUFFER));
if (rsaCert != NULL)
XMEMCPY(rsaCert, client_cert_der_2048, rsaCertSz);
rsaPrivKeySz = (word32)sizeof_client_key_der_2048;
ExpectNotNull(rsaPrivKey = (byte*)XMALLOC(rsaPrivKeySz, HEAP_HINT,
DYNAMIC_TYPE_TMP_BUFFER));
if (rsaPrivKey != NULL)
XMEMCPY(rsaPrivKey, client_key_der_2048, rsaPrivKeySz);
#elif !defined(NO_FILESYSTEM)
rsaCertSz = FOURK_BUF;
ExpectNotNull(rsaCert = (byte*)XMALLOC(rsaCertSz, HEAP_HINT,
DYNAMIC_TYPE_TMP_BUFFER));
ExpectTrue((f = XFOPEN("./certs/client-cert.der", "rb")) != XBADFILE);
ExpectTrue((rsaCertSz = (word32)XFREAD(rsaCert, 1, rsaCertSz, f)) > 0);
if (f != XBADFILE) {
XFCLOSE(f);
f = XBADFILE;
}
rsaPrivKeySz = FOURK_BUF;
ExpectNotNull(rsaPrivKey = (byte*)XMALLOC(rsaPrivKeySz, HEAP_HINT,
DYNAMIC_TYPE_TMP_BUFFER));
ExpectTrue((f = XFOPEN("./certs/client-key.der", "rb")) != XBADFILE);
ExpectTrue((rsaPrivKeySz = (word32)XFREAD(rsaPrivKey, 1,
rsaPrivKeySz, f)) > 0);
if (f != XBADFILE)
XFCLOSE(f);
#endif
if (rsaCert == NULL || rsaPrivKey == NULL) {
XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(rsaPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
return TEST_SKIPPED;
}
/* AES-128: 32-byte fake CEK larger than real CEK size (16 bytes). */
ExpectIntEQ(pkcs7_ktri_bad_pad_case(AES128CBCb, rsaCert, rsaCertSz,
rsaPrivKey, rsaPrivKeySz, encrypted, sizeof(encrypted),
decoded, sizeof(decoded)), TEST_SUCCESS);
#ifdef WOLFSSL_AES_192
/* AES-192: fake CEK (32) vs real CEK (24) - another size mismatch. */
ExpectIntEQ(pkcs7_ktri_bad_pad_case(AES192CBCb, rsaCert, rsaCertSz,
rsaPrivKey, rsaPrivKeySz, encrypted, sizeof(encrypted),
decoded, sizeof(decoded)), TEST_SUCCESS);
#endif
/* AES-256: fake CEK size matches real CEK size (32 bytes). */
ExpectIntEQ(pkcs7_ktri_bad_pad_case(AES256CBCb, rsaCert, rsaCertSz,
rsaPrivKey, rsaPrivKeySz, encrypted, sizeof(encrypted),
decoded, sizeof(decoded)), TEST_SUCCESS);
XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(rsaPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
return EXPECT_RESULT();
} /* END test_wc_PKCS7_EnvelopedData_KTRI_BadRsaPad */
#endif
/*
* Testing wc_PKCS7_EncodeSignedData_ex() and wc_PKCS7_VerifySignedData_ex()
*/
@@ -2397,7 +2620,8 @@ static int myCEKwrapFunc(PKCS7* pkcs7, byte* cek, word32 cekSz, byte* keyId,
HAVE_AES_KEYWRAP */
#if defined(HAVE_PKCS7) && defined(ASN_BER_TO_DER) && !defined(NO_RSA)
#if defined(HAVE_PKCS7) && defined(ASN_BER_TO_DER) && !defined(NO_RSA) && \
!defined(NO_PKCS7_STREAM)
#define MAX_TEST_DECODE_SIZE 6000
static int test_wc_PKCS7_DecodeEnvelopedData_stream_decrypt_cb(wc_PKCS7* pkcs7,
const byte* output, word32 outputSz, void* ctx) {
@@ -2430,7 +2654,8 @@ static int test_wc_PKCS7_DecodeEnvelopedData_stream_decrypt_cb(wc_PKCS7* pkcs7,
int test_wc_PKCS7_DecodeEnvelopedData_stream(void)
{
EXPECT_DECLS;
#if defined(HAVE_PKCS7) && defined(ASN_BER_TO_DER) && !defined(NO_RSA)
#if defined(HAVE_PKCS7) && defined(ASN_BER_TO_DER) && !defined(NO_RSA) && \
!defined(NO_PKCS7_STREAM)
PKCS7* pkcs7 = NULL;
int ret = 0;
XFILE f = XBADFILE;
@@ -2486,6 +2711,72 @@ int test_wc_PKCS7_DecodeEnvelopedData_stream(void)
} /* END test_wc_PKCS7_DecodeEnvelopedData_stream() */
/*
* Regression test: a PKCS#7 EnvelopedData with a forged RecipientInfo SET
* length (parsed via GetSet_ex with NO_USER_CHECK) must not drive an
* uncapped heap allocation through wc_PKCS7_GrowStream(). The decoder
* must reject the oversized allocation rather than attempting it.
*/
int test_wc_PKCS7_DecodeEnvelopedData_forgedRecipientSetLen(void)
{
EXPECT_DECLS;
#if defined(HAVE_PKCS7) && !defined(NO_RSA) && !defined(NO_PKCS7_STREAM)
/* Crafted ContentInfo/EnvelopedData header. All lengths use the
* 4-byte long form for clarity. The RecipientInfo SET length is
* forged to 0x01000001 (16 MB + 1), which exceeds the default
* WOLFSSL_PKCS7_MAX_STREAM_ALLOC cap and should be rejected before
* any allocation succeeds. The body after the SET header is never
* consumed because the decoder fails at the GrowStream() cap. */
static const byte forged[] = {
/* ContentInfo SEQUENCE, body length 0x01000021 */
0x30, 0x84, 0x01, 0x00, 0x00, 0x21,
/* OID 1.2.840.113549.1.7.3 (id-envelopedData) */
0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D,
0x01, 0x07, 0x03,
/* [0] EXPLICIT content, body length 0x01000016 */
0xA0, 0x84, 0x01, 0x00, 0x00, 0x16,
/* EnvelopedData SEQUENCE, body length 0x01000010 */
0x30, 0x84, 0x01, 0x00, 0x00, 0x10,
/* version INTEGER 0 */
0x02, 0x01, 0x00,
/* Forged RecipientInfo SET header: length = 0x01000001 */
0x31, 0x84, 0x01, 0x00, 0x00, 0x01,
/* Padding so that header-parsing states can buffer their
* required lookahead without returning WC_PKCS7_WANT_READ_E.
* These bytes are never interpreted. */
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
PKCS7* pkcs7 = NULL;
byte out[32];
int ret;
ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId));
ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, (byte*)client_cert_der_2048,
sizeof_client_cert_der_2048), 0);
ExpectIntEQ(wc_PKCS7_SetKey(pkcs7, (byte*)client_key_der_2048,
sizeof_client_key_der_2048), 0);
ret = wc_PKCS7_DecodeEnvelopedData(pkcs7, (byte*)forged,
(word32)sizeof(forged), out, (word32)sizeof(out));
/* Must NOT return WC_PKCS7_WANT_READ_E (which would imply the
* oversized allocation succeeded and the decoder is waiting for
* the around 16 MB of SET body). Must NOT return 0 / positive length.
* Expected: BUFFER_E from the GrowStream cap. */
ExpectIntEQ(ret, WC_NO_ERR_TRACE(BUFFER_E));
wc_PKCS7_Free(pkcs7);
#endif
return EXPECT_RESULT();
} /* END test_wc_PKCS7_DecodeEnvelopedData_forgedRecipientSetLen() */
/*
* Testing wc_PKCS7_DecodeEnvelopedData with streaming
*/
@@ -2501,6 +2792,8 @@ int test_wc_PKCS7_DecodeEnvelopedData_multiple_recipients(void)
bytes */
size_t testDerBufferSz = 0;
byte decodedData[8192];
byte serverDecodedData[8192];
int serverRet = 0;
ExpectTrue((f = XFOPEN(testFile, "rb")) != XBADFILE);
if (f != XBADFILE) {
@@ -2520,12 +2813,13 @@ int test_wc_PKCS7_DecodeEnvelopedData_multiple_recipients(void)
ExpectIntEQ(wc_PKCS7_SetKey(pkcs7, (byte*)server_key_der_2048,
sizeof_server_key_der_2048), 0);
ret = wc_PKCS7_DecodeEnvelopedData(pkcs7, testDerBuffer,
(word32)testDerBufferSz, decodedData, sizeof(decodedData));
serverRet = wc_PKCS7_DecodeEnvelopedData(pkcs7, testDerBuffer,
(word32)testDerBufferSz, serverDecodedData,
sizeof(serverDecodedData));
#if defined(NO_AES) || defined(NO_AES_256)
ExpectIntEQ(ret, ALGO_ID_E);
ExpectIntEQ(serverRet, ALGO_ID_E);
#else
ExpectIntGT(ret, 0);
ExpectIntGT(serverRet, 0);
#endif
wc_PKCS7_Free(pkcs7);
pkcs7 = NULL;
@@ -2551,7 +2845,14 @@ int test_wc_PKCS7_DecodeEnvelopedData_multiple_recipients(void)
pkcs7 = NULL;
}
/* test with ca cert recipient (which should fail) */
/* Test with ca cert recipient. The ca cert is not a listed recipient,
* so RSA unwrap fails. The Bleichenbacher mitigation substitutes a
* pseudo-random fake CEK on unwrap failure, so the call normally
* returns a negative error when content decryption rejects the
* resulting garbage padding - but around 1/256 of the time the random
* CEK yields plaintext with accidentally-valid PKCS#7 padding and the
* call returns a non-negative "decrypted" size. That case must not
* produce the real plaintext. */
ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId));
if (pkcs7) {
ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, (byte*)ca_cert_der_2048,
@@ -2560,9 +2861,15 @@ int test_wc_PKCS7_DecodeEnvelopedData_multiple_recipients(void)
ExpectIntEQ(wc_PKCS7_SetKey(pkcs7, (byte*)ca_key_der_2048,
sizeof_ca_key_der_2048), 0);
XMEMSET(decodedData, 0, sizeof(decodedData));
ret = wc_PKCS7_DecodeEnvelopedData(pkcs7, testDerBuffer,
(word32)testDerBufferSz, decodedData, sizeof(decodedData));
ExpectIntLT(ret, 0);
#if defined(NO_AES) || defined(NO_AES_256)
ExpectIntEQ(ret, ALGO_ID_E);
#else
ExpectTrue(ret < 0 || ret != serverRet ||
XMEMCMP(decodedData, serverDecodedData, (size_t)ret) != 0);
#endif
wc_PKCS7_Free(pkcs7);
pkcs7 = NULL;
}
@@ -2579,7 +2886,7 @@ int test_wc_PKCS7_EncodeDecodeEnvelopedData(void)
EXPECT_DECLS;
#if defined(HAVE_PKCS7)
PKCS7* pkcs7 = NULL;
#ifdef ASN_BER_TO_DER
#if defined(ASN_BER_TO_DER) && !defined(NO_PKCS7_STREAM)
int encodedSz = 0;
#endif
#ifdef ECC_TIMING_RESISTANT
@@ -2761,6 +3068,11 @@ int test_wc_PKCS7_EncodeDecodeEnvelopedData(void)
AES128CBCb, AES128_WRAP, dhSinglePass_stdDH_sha1kdf_scheme,
eccCert, eccCertSz, eccPrivKey, eccPrivKeySz},
#endif
#if defined(WOLFSSL_SHA224) && defined(WOLFSSL_AES_128)
{(byte*)input, (word32)(sizeof(input)/sizeof(char)), DATA,
AES128CBCb, AES128_WRAP, dhSinglePass_stdDH_sha224kdf_scheme,
eccCert, eccCertSz, eccPrivKey, eccPrivKeySz},
#endif
#if !defined(NO_SHA256) && defined(WOLFSSL_AES_256)
{(byte*)input, (word32)(sizeof(input)/sizeof(char)), DATA,
AES256CBCb, AES256_WRAP, dhSinglePass_stdDH_sha256kdf_scheme,
@@ -2784,7 +3096,7 @@ int test_wc_PKCS7_EncodeDecodeEnvelopedData(void)
testSz = (int)sizeof(testVectors)/(int)sizeof(pkcs7EnvelopedVector);
for (i = 0; i < testSz; i++) {
#ifdef ASN_BER_TO_DER
#if defined(ASN_BER_TO_DER) && !defined(NO_PKCS7_STREAM)
encodeSignedDataStream strm;
/* test setting stream mode, the first one using IO callbacks */
@@ -2950,17 +3262,11 @@ int test_wc_PKCS7_EncodeDecodeEnvelopedData(void)
pkcs7->singleCert = NULL;
}
#ifndef NO_RSA
#if defined(NO_PKCS7_STREAM)
/* when none streaming mode is used and PKCS7 is in bad state buffer error
* is returned from kari parse which gets set to bad func arg */
ExpectIntEQ(wc_PKCS7_DecodeEnvelopedData(pkcs7, output,
(word32)sizeof(output), decoded, (word32)sizeof(decoded)),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#else
/* With corrupted singleCert, decode should fail with a parse error.
* State is properly reset on error so re-decode starts from scratch. */
ExpectIntEQ(wc_PKCS7_DecodeEnvelopedData(pkcs7, output,
(word32)sizeof(output), decoded, (word32)sizeof(decoded)),
WC_NO_ERR_TRACE(ASN_PARSE_E));
#endif
#endif /* !NO_RSA */
if (pkcs7 != NULL) {
pkcs7->singleCert = tmpBytePtr;
@@ -3991,7 +4297,8 @@ int test_wc_PKCS7_Degenerate(void)
} /* END test_wc_PKCS7_Degenerate() */
#if defined(HAVE_PKCS7) && !defined(NO_FILESYSTEM) && \
defined(ASN_BER_TO_DER) && !defined(NO_DES3) && !defined(NO_SHA)
defined(ASN_BER_TO_DER) && !defined(NO_DES3) && !defined(NO_SHA) && \
!defined(NO_PKCS7_STREAM)
static byte berContent[] = {
0x30, 0x80, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86,
0xF7, 0x0D, 0x01, 0x07, 0x03, 0xA0, 0x80, 0x30,
@@ -4182,7 +4489,7 @@ static byte berContent[] = {
0x00, 0x00, 0x00, 0x00, 0x00
};
#endif /* HAVE_PKCS7 && !NO_FILESYSTEM && ASN_BER_TO_DER &&
* !NO_DES3 && !NO_SHA
* !NO_DES3 && !NO_SHA && !NO_PKCS7_STREAM
*/
/*
@@ -4197,7 +4504,7 @@ int test_wc_PKCS7_BER(void)
char fName[] = "./certs/test-ber-exp02-05-2022.p7b";
XFILE f = XBADFILE;
byte der[4096];
#ifndef NO_DES3
#if !defined(NO_DES3) && !defined(NO_PKCS7_STREAM)
byte decoded[2048];
#endif
word32 derSz = 0;
@@ -4242,8 +4549,9 @@ int test_wc_PKCS7_BER(void)
wc_PKCS7_Free(pkcs7);
pkcs7 = NULL;
#ifndef NO_DES3
/* decode BER content */
#if !defined(NO_DES3) && !defined(NO_PKCS7_STREAM)
/* decode BER content - requires PKCS7 streaming to handle indefinite
* length encoding in the EnvelopedData structure */
ExpectTrue((f = XFOPEN("./certs/1024/client-cert.der", "rb")) != XBADFILE);
ExpectTrue((derSz = (word32)XFREAD(der, 1, sizeof(der), f)) > 0);
if (f != XBADFILE) {
@@ -4280,7 +4588,7 @@ int test_wc_PKCS7_BER(void)
sizeof(berContent), decoded, sizeof(decoded)), WC_NO_ERR_TRACE(NOT_COMPILED_IN));
#endif
wc_PKCS7_Free(pkcs7);
#endif /* !NO_DES3 */
#endif /* !NO_DES3 && !NO_PKCS7_STREAM */
#endif
return EXPECT_RESULT();
} /* END test_wc_PKCS7_BER() */
+24 -1
View File
@@ -38,6 +38,14 @@ int test_wc_PKCS7_EncodeSignedData_RSA_PSS(void);
!defined(NO_AES) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_256)
int test_wc_PKCS7_EnvelopedData_KTRI_RSA_PSS(void);
#endif
#if defined(HAVE_PKCS7) && !defined(NO_RSA) && !defined(NO_SHA256) && \
!defined(NO_AES) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_128) && \
defined(WOLFSSL_AES_256) && !defined(NO_HMAC) && \
!defined(WOLFSSL_NO_MALLOC) && \
(defined(USE_CERT_BUFFERS_2048) || defined(USE_CERT_BUFFERS_1024) || \
!defined(NO_FILESYSTEM))
int test_wc_PKCS7_EnvelopedData_KTRI_BadRsaPad(void);
#endif
int test_wc_PKCS7_EncodeSignedData_ex(void);
int test_wc_PKCS7_VerifySignedData_RSA(void);
int test_wc_PKCS7_VerifySignedData_ECC(void);
@@ -57,6 +65,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_DecodeEnvelopedData_forgedRecipientSetLen(void);
int test_wc_PKCS7_VerifySignedData_PKCS7ContentSeq(void);
int test_wc_PKCS7_VerifySignedData_IndefLenOOB(void);
@@ -82,6 +91,18 @@ int test_wc_PKCS7_VerifySignedData_IndefLenOOB(void);
#define TEST_PKCS7_RSA_PSS_ED_DECL
#endif
#if defined(HAVE_PKCS7) && !defined(NO_RSA) && !defined(NO_SHA256) && \
!defined(NO_AES) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_128) && \
defined(WOLFSSL_AES_256) && !defined(NO_HMAC) && \
!defined(WOLFSSL_NO_MALLOC) && \
(defined(USE_CERT_BUFFERS_2048) || defined(USE_CERT_BUFFERS_1024) || \
!defined(NO_FILESYSTEM))
#define TEST_PKCS7_KTRI_BADRSAPAD_DECL \
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_EnvelopedData_KTRI_BadRsaPad),
#else
#define TEST_PKCS7_KTRI_BADRSAPAD_DECL
#endif
#define TEST_PKCS7_SIGNED_DATA_DECLS \
TEST_DECL_GROUP("pkcs7_sd", test_wc_PKCS7_InitWithCert), \
TEST_DECL_GROUP("pkcs7_sd", test_wc_PKCS7_EncodeData), \
@@ -100,6 +121,7 @@ int test_wc_PKCS7_VerifySignedData_IndefLenOOB(void);
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_DecodeEnvelopedData_stream), \
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_EncodeDecodeEnvelopedData), \
TEST_PKCS7_RSA_PSS_ED_DECL \
TEST_PKCS7_KTRI_BADRSAPAD_DECL \
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_SetAESKeyWrapUnwrapCb), \
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_GetEnvelopedDataKariRid), \
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_EncodeEncryptedData), \
@@ -108,7 +130,8 @@ int test_wc_PKCS7_VerifySignedData_IndefLenOOB(void);
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_DecodeOneSymmetricKey), \
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_SetOriEncryptCtx), \
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_SetOriDecryptCtx), \
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_DecodeEnvelopedData_multiple_recipients)
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_DecodeEnvelopedData_multiple_recipients), \
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_DecodeEnvelopedData_forgedRecipientSetLen)
#define TEST_PKCS7_SIGNED_ENCRYPTED_DATA_DECLS \
TEST_DECL_GROUP("pkcs7_sed", test_wc_PKCS7_signed_enveloped)
+606 -27
View File
File diff suppressed because it is too large Load Diff
+3
View File
@@ -73,6 +73,9 @@
#ifndef CCM_NONCE_MIN_SZ
#define CCM_NONCE_MIN_SZ 7
#endif
#ifndef CCM_NONCE_MAX_SZ
#define CCM_NONCE_MAX_SZ 13
#endif
#endif