From 2cdbd25a6400382f055337c737d504073e80630a Mon Sep 17 00:00:00 2001 From: jackctj117 Date: Wed, 6 May 2026 12:53:46 -0600 Subject: [PATCH] asn: restore serial-0 rejection in DecodeCertInternal for pubkey-extraction paths --- wolfcrypt/src/asn.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 82233ee85a..a77de365d8 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -21395,12 +21395,28 @@ static int DecodeCertInternal(DecodedCert* cert, int verify, int* criticalExt, ret = badDate; } - /* Note: serial-0 rejection is performed in ParseCertRelative (after - * basicConstraints has been parsed and isCA is authoritative), not - * here. Checking isCA at this point would fail-open on a forged - * isCA flag. Callers that invoke DecodeCert/DecodeToKey/wc_GetPubX509 - * directly are pubkey-extraction paths and do not make trust - * decisions; trust-bearing flows go through ParseCertRelative. */ +#if !defined(WOLFSSL_NO_ASN_STRICT) && !defined(WOLFSSL_PYTHON) && \ + !defined(WOLFSSL_ASN_ALLOW_0_SERIAL) + /* Structural serial-0 rejection. RFC 5280 4.1.2.2 requires positive + * serials; reject here so non-trust-bearing pubkey-extraction callers + * (DecodeToKey, wc_GetPubX509, d2i_X509-style decode) do not silently + * accept malformed certs. ParseCertRelative performs the authoritative + * trust-bearing check (with the CA_TYPE/TRUSTED_PEER_TYPE exemption + * for legacy self-signed root CAs); the exemption here is intentionally + * narrow: when extensions are not parsed (stopAtPubKey/stopAfterPubKey) + * isCA is not populated, so the exemption never fires and serial-0 is + * always rejected on those paths. */ + if ((ret == 0) && (cert->serialSz == 1) && (cert->serial[0] == 0)) { + if (!(cert->isCA && cert->selfSigned) +#ifdef WOLFSSL_CERT_REQ + && !cert->isCSR +#endif + ) { + WOLFSSL_MSG("Error serial number of 0 for non-root certificate"); + ret = ASN_PARSE_E; + } + } +#endif return ret; }