Skip to content

Commit a222443

Browse files
committed
- asn: reject empty certificatePolicies sequences
must be 1..MAX as per RFC 5280 4.2.1.4; - asn: reject trailing bytes after the last PolicyInformation in certificatePolicies; - minor edit updating the whitebox notes to match with these new changes;
1 parent 437bca8 commit a222443

4 files changed

Lines changed: 70 additions & 5 deletions

File tree

tests/api/test_asn.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1577,6 +1577,60 @@ int test_DecodeCertExtensions_dup_certpol(void)
15771577
return EXPECT_RESULT();
15781578
}
15791579

1580+
/* RFC 5280 4.2.1.4 defines certificatePolicies as SEQUENCE SIZE (1..MAX) OF
1581+
* PolicyInformation, so an empty SEQUENCE must be rejected instead of being
1582+
* accepted as zero policies. */
1583+
int test_DecodeCertExtensions_empty_certpol(void)
1584+
{
1585+
EXPECT_DECLS;
1586+
#if (defined(WOLFSSL_SEP) || defined(WOLFSSL_CERT_EXT)) && \
1587+
!defined(NO_CERTS) && !defined(NO_ASN)
1588+
/* certificatePolicies extnValue carrying no PolicyInformation. */
1589+
static const byte emptyPolicy[] = {
1590+
0x30, 0x00 /* certificatePolicies SEQUENCE */
1591+
};
1592+
DecodedCert cert;
1593+
int isUnknown = 0;
1594+
1595+
wc_InitDecodedCert(&cert, emptyPolicy, (word32)sizeof(emptyPolicy), NULL);
1596+
1597+
ExpectIntEQ(DecodeExtensionType(emptyPolicy, (word32)sizeof(emptyPolicy),
1598+
CERT_POLICY_OID, 0, &cert, &isUnknown),
1599+
WC_NO_ERR_TRACE(ASN_PARSE_E));
1600+
1601+
wc_FreeDecodedCert(&cert);
1602+
#endif
1603+
return EXPECT_RESULT();
1604+
}
1605+
1606+
/* Trailing bytes after the last PolicyInformation must be rejected rather than
1607+
* skipped. */
1608+
int test_DecodeCertExtensions_certpol_trailing_junk(void)
1609+
{
1610+
EXPECT_DECLS;
1611+
#if (defined(WOLFSSL_SEP) || defined(WOLFSSL_CERT_EXT)) && \
1612+
!defined(NO_CERTS) && !defined(NO_ASN)
1613+
/* One valid PolicyInformation followed by two bytes that are not one. */
1614+
static const byte trailingJunk[] = {
1615+
0x30, 0x09, /* certificatePolicies SEQUENCE */
1616+
0x30, 0x05, /* PolicyInformation SEQUENCE */
1617+
0x06, 0x03, 0x2A, 0x03, 0x04,/* policyIdentifier OID 1.2.3.4 */
1618+
0x00, 0x00 /* trailing junk */
1619+
};
1620+
DecodedCert cert;
1621+
int isUnknown = 0;
1622+
1623+
wc_InitDecodedCert(&cert, trailingJunk, (word32)sizeof(trailingJunk), NULL);
1624+
1625+
ExpectIntEQ(DecodeExtensionType(trailingJunk, (word32)sizeof(trailingJunk),
1626+
CERT_POLICY_OID, 0, &cert, &isUnknown),
1627+
WC_NO_ERR_TRACE(ASN_PARSE_E));
1628+
1629+
wc_FreeDecodedCert(&cert);
1630+
#endif
1631+
return EXPECT_RESULT();
1632+
}
1633+
15801634
int test_ParseCert_SM3wSM2_short_pubkey(void)
15811635
{
15821636
EXPECT_DECLS;

tests/api/test_asn.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ int test_wc_DecodeRsaPssParams(void);
3636
int test_SerialNumber0_RootCA(void);
3737
int test_DecodeAltNames_length_underflow(void);
3838
int test_DecodeCertExtensions_dup_certpol(void);
39+
int test_DecodeCertExtensions_empty_certpol(void);
40+
int test_DecodeCertExtensions_certpol_trailing_junk(void);
3941
int test_ParseCert_SM3wSM2_short_pubkey(void);
4042
int test_ParseCert_dnBufferBoundary(void);
4143
int test_wc_DecodeObjectId(void);
@@ -61,6 +63,8 @@ int test_wc_AsnFeatureCoverage(void);
6163
TEST_DECL_GROUP("asn", test_SerialNumber0_RootCA), \
6264
TEST_DECL_GROUP("asn", test_DecodeAltNames_length_underflow), \
6365
TEST_DECL_GROUP("asn", test_DecodeCertExtensions_dup_certpol), \
66+
TEST_DECL_GROUP("asn", test_DecodeCertExtensions_empty_certpol), \
67+
TEST_DECL_GROUP("asn", test_DecodeCertExtensions_certpol_trailing_junk), \
6468
TEST_DECL_GROUP("asn", test_ParseCert_SM3wSM2_short_pubkey), \
6569
TEST_DECL_GROUP("asn", test_ParseCert_dnBufferBoundary), \
6670
TEST_DECL_GROUP("asn", test_wc_DecodeObjectId), \

tests/unit-mcdc/test_asn_ext_whitebox.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1288,7 +1288,8 @@ static void wb_decode_policy_oid(void)
12881288
/* ------------------------------------------------------------------------- *
12891289
* Section 17: DecodeCertPolicy() (static, called directly).
12901290
* Gated on WOLFSSL_SEP || WOLFSSL_CERT_EXT, same as the source.
1291-
* :21346 while ((ret==0) && (idx<total_length) && (extCertPoliciesNb<MAX_CERTPOL_NB))
1291+
* :21346 while ((ret==0) && (idx<sz) && (extCertPoliciesNb<MAX_CERTPOL_NB))
1292+
* total_length==0 empty-SEQUENCE check, reached before that loop
12921293
* :21369 ret==0 && cert->deviceType==NULL (WOLFSSL_SEP)
12931294
* :21401 duplicate-OID scan loop (WOLFSSL_CERT_EXT, !WOLFSSL_DUP_CERTPOL)
12941295
* MAX_CERTPOL_NB is 2, so three policies exercise the count limit.
@@ -1338,10 +1339,11 @@ static void wb_decode_cert_policy(void)
13381339
/* Zero policies. */
13391340
static const byte noPolicies[] = { 0x30, 0x00 };
13401341

1341-
WB_NOTE("DecodeCertPolicy(): zero policies (loop false via idx<total_length) [:21346]");
1342+
WB_NOTE("DecodeCertPolicy(): empty SEQUENCE rejected before the loop (total_length==0)");
13421343
XMEMSET(&cert, 0, sizeof(cert));
13431344
ret = DecodeCertPolicy(noPolicies, sizeof(noPolicies), &cert);
1344-
WB_CHECK(ret == 0, "no policies present");
1345+
WB_CHECK(ret == WC_NO_ERR_TRACE(ASN_PARSE_E),
1346+
"empty SEQUENCE rejected: RFC 5280 4.2.1.4 requires SIZE (1..MAX)");
13451347

13461348
WB_NOTE("DecodeCertPolicy(): one policy (loop true then false) [:21346,:21369]");
13471349
XMEMSET(&cert, 0, sizeof(cert));

wolfcrypt/src/asn.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21481,10 +21481,15 @@ static int DecodeCertPolicy(const byte* input, word32 sz, DecodedCert* cert)
2148121481
{
2148221482
ret = ASN_PARSE_E;
2148321483
}
21484+
/* RFC 5280 4.2.1.4: certificatePolicies is SEQUENCE SIZE (1..MAX). */
21485+
else if (total_length == 0) {
21486+
ret = ASN_PARSE_E;
21487+
}
2148421488
}
2148521489

21486-
/* Unwrap certificatePolicies */
21487-
while ((ret == 0) && ((int)idx < total_length)
21490+
/* Unwrap certificatePolicies. idx is an offset into input, so it is bound
21491+
* by sz. */
21492+
while ((ret == 0) && (idx < sz)
2148821493
#if defined(WOLFSSL_CERT_EXT)
2148921494
&& (cert->extCertPoliciesNb < MAX_CERTPOL_NB)
2149021495
#endif

0 commit comments

Comments
 (0)