Skip to content

Commit faf80c0

Browse files
committed
Reject duplicate certificatePolicies extension in WOLFSSL_CERT_EXT builds
DecodeExtensionType() guarded the certificatePolicies duplicate check (VERIFY_AND_SET_OID) under WOLFSSL_SEP only, because the extCertPolicySet tracking bit was SEP-only. In a WOLFSSL_CERT_EXT-without-WOLFSSL_SEP build a cert with two certificatePolicies extensions was accepted and the second silently overwrote the first (RFC 5280 4.2 forbids repeats). Make the bit and the guard available under WOLFSSL_CERT_EXT too, matching every other non-repeatable extension. Add test_DecodeCertExtensions_dup_certpol (DecodeExtensionType now WOLFSSL_TEST_VIS).
1 parent fedd3ad commit faf80c0

4 files changed

Lines changed: 55 additions & 8 deletions

File tree

tests/api/test_asn.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1495,6 +1495,45 @@ int test_DecodeAltNames_length_underflow(void)
14951495
return EXPECT_RESULT();
14961496
}
14971497

1498+
/* A certificate must not carry two certificatePolicies extensions
1499+
* (non-repeatable per RFC 5280 4.2). DecodeCertExtensions calls
1500+
* DecodeExtensionType once per extension; a second certificatePolicies
1501+
* extension must be rejected (ASN_OBJECT_ID_E) rather than silently
1502+
* overwriting the first - which was the case in WOLFSSL_CERT_EXT builds
1503+
* without WOLFSSL_SEP before the duplicate guard was made unconditional. */
1504+
int test_DecodeCertExtensions_dup_certpol(void)
1505+
{
1506+
EXPECT_DECLS;
1507+
#if (defined(WOLFSSL_SEP) || defined(WOLFSSL_CERT_EXT)) && \
1508+
!defined(WOLFSSL_NO_ASN_STRICT) && !defined(NO_CERTS) && !defined(NO_ASN)
1509+
/* Minimal certificatePolicies extnValue: SEQUENCE OF PolicyInformation
1510+
* with one policyIdentifier OID 1.2.3.4 (encoded 2A 03 04). */
1511+
static const byte policy[] = {
1512+
0x30, 0x07, /* certificatePolicies SEQUENCE */
1513+
0x30, 0x05, /* PolicyInformation SEQUENCE */
1514+
0x06, 0x03, 0x2A, 0x03, 0x04 /* policyIdentifier OID 1.2.3.4 */
1515+
};
1516+
DecodedCert cert;
1517+
int isUnknown = 0;
1518+
1519+
/* DecodeExtensionType only needs an initialized DecodedCert for its
1520+
* bit-fields and policy storage; the source buffer is never parsed here,
1521+
* so any non-NULL pointer/size suffices. */
1522+
wc_InitDecodedCert(&cert, policy, (word32)sizeof(policy), NULL);
1523+
1524+
/* First certificatePolicies extension: accepted. */
1525+
ExpectIntEQ(DecodeExtensionType(policy, (word32)sizeof(policy),
1526+
CERT_POLICY_OID, 0, &cert, &isUnknown), 0);
1527+
/* Duplicate certificatePolicies extension: rejected as non-repeatable. */
1528+
ExpectIntEQ(DecodeExtensionType(policy, (word32)sizeof(policy),
1529+
CERT_POLICY_OID, 0, &cert, &isUnknown),
1530+
WC_NO_ERR_TRACE(ASN_OBJECT_ID_E));
1531+
1532+
wc_FreeDecodedCert(&cert);
1533+
#endif
1534+
return EXPECT_RESULT();
1535+
}
1536+
14981537
int test_ParseCert_SM3wSM2_short_pubkey(void)
14991538
{
15001539
EXPECT_DECLS;

tests/api/test_asn.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ int test_wolfssl_local_MatchUriNameConstraint(void);
3535
int test_wc_DecodeRsaPssParams(void);
3636
int test_SerialNumber0_RootCA(void);
3737
int test_DecodeAltNames_length_underflow(void);
38+
int test_DecodeCertExtensions_dup_certpol(void);
3839
int test_ParseCert_SM3wSM2_short_pubkey(void);
3940
int test_wc_DecodeObjectId(void);
4041
int test_ToTraditional_ex_handcrafted(void);
@@ -54,6 +55,7 @@ int test_ToTraditional_ex_mldsa_bad_params(void);
5455
TEST_DECL_GROUP("asn", test_wc_DecodeRsaPssParams), \
5556
TEST_DECL_GROUP("asn", test_SerialNumber0_RootCA), \
5657
TEST_DECL_GROUP("asn", test_DecodeAltNames_length_underflow), \
58+
TEST_DECL_GROUP("asn", test_DecodeCertExtensions_dup_certpol), \
5759
TEST_DECL_GROUP("asn", test_ParseCert_SM3wSM2_short_pubkey), \
5860
TEST_DECL_GROUP("asn", test_wc_DecodeObjectId), \
5961
TEST_DECL_GROUP("asn", test_ToTraditional_ex_handcrafted), \

wolfcrypt/src/asn.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21036,8 +21036,9 @@ static int DecodeAltSigVal(const byte* input, int sz, DecodedCert* cert)
2103621036
* @return MEMORY_E on dynamic memory allocation failure.
2103721037
* @return Other negative values on error.
2103821038
*/
21039-
int DecodeExtensionType(const byte* input, word32 length, word32 oid,
21040-
byte critical, DecodedCert* cert, int *isUnknownExt)
21039+
WOLFSSL_TEST_VIS int DecodeExtensionType(const byte* input, word32 length,
21040+
word32 oid, byte critical,
21041+
DecodedCert* cert, int *isUnknownExt)
2104121042
{
2104221043
int ret = 0;
2104321044
word32 idx = 0;
@@ -21137,11 +21138,15 @@ int DecodeExtensionType(const byte* input, word32 length, word32 oid,
2113721138

2113821139
/* Certificate policies. */
2113921140
case CERT_POLICY_OID:
21140-
#ifdef WOLFSSL_SEP
21141+
#if defined(WOLFSSL_SEP) || defined(WOLFSSL_CERT_EXT)
21142+
/* certificatePolicies is non-repeatable (RFC 5280 4.2): reject a
21143+
* duplicate extension regardless of WOLFSSL_SEP, otherwise the
21144+
* second one silently overwrites the first (DecodeCertPolicy
21145+
* resets extCertPoliciesNb), a policy-authorization confusion. */
2114121146
VERIFY_AND_SET_OID(cert->extCertPolicySet);
21147+
#ifdef WOLFSSL_SEP
2114221148
cert->extCertPolicyCrit = critical ? 1 : 0;
2114321149
#endif
21144-
#if defined(WOLFSSL_SEP) || defined(WOLFSSL_CERT_EXT)
2114521150
if (DecodeCertPolicy(input, length, cert) < 0) {
2114621151
ret = ASN_PARSE_E;
2114721152
}

wolfssl/wolfcrypt/asn.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2089,7 +2089,7 @@ struct DecodedCert {
20892089
WC_BITFIELD extSubjAltNameSet:1;
20902090
WC_BITFIELD inhibitAnyOidSet:1;
20912091
WC_BITFIELD selfSigned:1; /* Indicates subject and issuer are same */
2092-
#ifdef WOLFSSL_SEP
2092+
#if defined(WOLFSSL_SEP) || defined(WOLFSSL_CERT_EXT)
20932093
WC_BITFIELD extCertPolicySet:1;
20942094
#endif
20952095
WC_BITFIELD extCRLdistCrit:1;
@@ -2369,6 +2369,7 @@ typedef enum MimeStatus
23692369
#define FreeSigner wc_FreeSigner
23702370
#define AllocDer wc_AllocDer
23712371
#define FreeDer wc_FreeDer
2372+
#define DecodeExtensionType wc_DecodeExtensionType
23722373
#endif /* WOLFSSL_API_PREFIX_MAP */
23732374

23742375
WOLFSSL_LOCAL int HashIdAlg(word32 oidSum);
@@ -2412,9 +2413,9 @@ WOLFSSL_LOCAL int DecodePolicyOID(char *out, word32 outSz, const byte *in,
24122413
word32 inSz);
24132414
WOLFSSL_LOCAL int EncodePolicyOID(byte *out, word32 *outSz,
24142415
const char *in, void* heap);
2415-
WOLFSSL_LOCAL int DecodeExtensionType(const byte* input, word32 length,
2416-
word32 oid, byte critical,
2417-
DecodedCert* cert, int *isUnknownExt);
2416+
WOLFSSL_TEST_VIS int DecodeExtensionType(const byte* input, word32 length,
2417+
word32 oid, byte critical,
2418+
DecodedCert* cert, int *isUnknownExt);
24182419
WOLFSSL_LOCAL int CheckCertSignaturePubKey(const byte* cert, word32 certSz,
24192420
void* heap, const byte* pubKey, word32 pubKeySz, int pubKeyOID);
24202421
#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_SMALL_CERT_VERIFY)

0 commit comments

Comments
 (0)