From 49da94135e1a167d434cb1ac646b727d0b03574c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Fri, 11 Sep 2026 11:22:10 +0200 Subject: [PATCH] Decode the WOLFSSL_CERT_NAME_ALL subject components certNameSubject[] is indexed by id - 3 and holds 20 entries, covering DN tag ids 3 through 22. The four entries WOLFSSL_CERT_NAME_ALL appends are labelled name, givenName, initials and dnQualifier - ids 41, 42, 43 and 46 - but they sit at array positions that make them ids 19, 20, 21 and 22. Two consequences. GetRDN() finds no table entry for the real ids, leaves typeStr NULL and never calls SetSubject(), so subjectN, subjectGN, subjectI and subjectDNQ are never populated and those RDNs are dropped from a parsed certificate or CSR. And a certificate carrying 2.5.4.19 through 2.5.4.22 - physicalDeliveryOfficeName, telephoneNumber, teletexTerminalIdentifier, x121Address - matches those entries instead and is decoded under the wrong name, including into the wrong DecodedCert field and the wrong X509_NAME NID. Drop the four misplaced entries and give the ids their own branches in GetRDN() and SetSubject(), beside the ASN_X500_UNIQUE_ID branch already there for a component whose id falls outside the contiguous range. Without WOLFSSL_CERT_NAME_ALL the table already stopped at id 18, so ids 19 to 22 go back to being unrecognised there, as they were. Add test_wc_CertNameAllSubject(), which generates a self-signed certificate carrying all four RDNs and asserts they come back out of wc_ParseCert() in the matching DecodedCert fields and in the subject string. Nothing covered these paths before: no certificate under certs/ carries any of the four OIDs, and no test referenced the fields. The test fails against the pre-fix decoder. The WOLFSSL_NAME, WOLFSSL_GIVEN_NAME, WOLFSSL_INITIALS and WOLFSSL_DNQUALIFIER macros GetRDN() needs are already defined in asn.h under the same guard, so no new definitions are required. --- tests/api/test_asn.c | 99 ++++++++++++++++++++++++++++++++++ tests/api/test_asn.h | 2 + wolfcrypt/src/asn.c | 126 +++++++++++++++++++------------------------ 3 files changed, 157 insertions(+), 70 deletions(-) diff --git a/tests/api/test_asn.c b/tests/api/test_asn.c index d6f9924e1ee..40543eb1c12 100644 --- a/tests/api/test_asn.c +++ b/tests/api/test_asn.c @@ -3852,6 +3852,105 @@ int test_wc_SignCert_buffer_bounds(void) return EXPECT_RESULT(); } +#if !defined(NO_ASN) && !defined(NO_CERTS) && !defined(NO_RSA) && \ + !defined(NO_SHA256) && defined(WOLFSSL_CERT_GEN) && \ + defined(WOLFSSL_CERT_NAME_ALL) && defined(USE_CERT_BUFFERS_2048) + #define TEST_CERT_NAME_ALL_SUBJECT +#endif + +/* Round trip the WOLFSSL_CERT_NAME_ALL subject RDNs: their ids sit outside the + * range certNameSubject[] covers, so each needs its own decode branch. */ +int test_wc_CertNameAllSubject(void) +{ + EXPECT_DECLS; +#ifdef TEST_CERT_NAME_ALL_SUBJECT + RsaKey key; + WC_RNG rng; + byte* der = NULL; + word32 idx = 0; + int derSz = 0; + int rngInit = 0; + int keyInit = 0; + int dCertInit = 0; + Cert cert; + DecodedCert dCert; + const char* dnName = "Jane Roe"; + const char* givenName = "Jane"; + const char* initials = "JR"; + const char* dnQualifier = "dnq-1"; + + XMEMSET(&rng, 0, sizeof(rng)); + XMEMSET(&key, 0, sizeof(key)); + XMEMSET(&cert, 0, sizeof(cert)); + + ExpectIntEQ(wc_InitRng(&rng), 0); + if (EXPECT_SUCCESS()) rngInit = 1; + + ExpectNotNull(der = (byte*)XMALLOC(FOURK_BUF, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER)); + + ExpectIntEQ(wc_InitRsaKey_ex(&key, HEAP_HINT, testDevId), 0); + if (EXPECT_SUCCESS()) keyInit = 1; + ExpectIntEQ(wc_RsaPrivateKeyDecode(server_key_der_2048, &idx, &key, + sizeof_server_key_der_2048), 0); + + ExpectIntEQ(wc_InitCert(&cert), 0); + if (EXPECT_SUCCESS()) { + cert.sigType = CTC_SHA256wRSA; + XSTRNCPY(cert.subject.country, "US", CTC_NAME_SIZE); + XSTRNCPY(cert.subject.org, "wolfSSL", CTC_NAME_SIZE); + XSTRNCPY(cert.subject.commonName, "certNameAll", CTC_NAME_SIZE); + XSTRNCPY(cert.subject.dnName, dnName, CTC_NAME_SIZE); + XSTRNCPY(cert.subject.givenName, givenName, CTC_NAME_SIZE); + XSTRNCPY(cert.subject.initials, initials, CTC_NAME_SIZE); + XSTRNCPY(cert.subject.dnQualifier, dnQualifier, CTC_NAME_SIZE); + } + ExpectIntGT(derSz = wc_MakeSelfCert(&cert, der, FOURK_BUF, &key, &rng), 0); + + if (EXPECT_SUCCESS() && (der != NULL)) { + wc_InitDecodedCert(&dCert, der, (word32)derSz, HEAP_HINT); + dCertInit = 1; + ExpectIntEQ(wc_ParseCert(&dCert, CERT_TYPE, NO_VERIFY, NULL), 0); + } + + if (EXPECT_SUCCESS() && dCertInit) { + ExpectNotNull(dCert.subjectN); + ExpectIntEQ(dCert.subjectNLen, (int)XSTRLEN(dnName)); + if (dCert.subjectN != NULL) + ExpectIntEQ(XMEMCMP(dCert.subjectN, dnName, XSTRLEN(dnName)), 0); + + ExpectNotNull(dCert.subjectGN); + ExpectIntEQ(dCert.subjectGNLen, (int)XSTRLEN(givenName)); + if (dCert.subjectGN != NULL) + ExpectIntEQ(XMEMCMP(dCert.subjectGN, givenName, + XSTRLEN(givenName)), 0); + + ExpectNotNull(dCert.subjectI); + ExpectIntEQ(dCert.subjectILen, (int)XSTRLEN(initials)); + if (dCert.subjectI != NULL) + ExpectIntEQ(XMEMCMP(dCert.subjectI, initials, XSTRLEN(initials)), + 0); + + ExpectNotNull(dCert.subjectDNQ); + ExpectIntEQ(dCert.subjectDNQLen, (int)XSTRLEN(dnQualifier)); + if (dCert.subjectDNQ != NULL) + ExpectIntEQ(XMEMCMP(dCert.subjectDNQ, dnQualifier, + XSTRLEN(dnQualifier)), 0); + + ExpectNotNull(XSTRSTR(dCert.subject, WOLFSSL_NAME)); + ExpectNotNull(XSTRSTR(dCert.subject, WOLFSSL_GIVEN_NAME)); + ExpectNotNull(XSTRSTR(dCert.subject, WOLFSSL_INITIALS)); + ExpectNotNull(XSTRSTR(dCert.subject, WOLFSSL_DNQUALIFIER)); + } + + if (dCertInit) wc_FreeDecodedCert(&dCert); + if (keyInit) wc_FreeRsaKey(&key); + if (rngInit) wc_FreeRng(&rng); + XFREE(der, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); +#endif /* TEST_CERT_NAME_ALL_SUBJECT */ + return EXPECT_RESULT(); +} + /* * MC/DC wave 2 - decision-targeted negative paths for PKCS#8 wrap/parse * and RSA key decode. Targets argument-check, short-buffer, and diff --git a/tests/api/test_asn.h b/tests/api/test_asn.h index b4dd7c613ac..34b0fda2b70 100644 --- a/tests/api/test_asn.h +++ b/tests/api/test_asn.h @@ -50,6 +50,7 @@ int test_wc_SignCert_buffer_bounds(void); int test_wc_DecodeKeyUsage_decipherOnly(void); int test_wc_DecodeExtKeyUsage_ssh(void); int test_wc_DecodeExtKeyUsage_ssh_oid_collision(void); +int test_wc_CertNameAllSubject(void); int test_wc_AsnDecisionCoverage(void); int test_wc_AsnFeatureCoverage(void); @@ -80,6 +81,7 @@ int test_wc_AsnFeatureCoverage(void); TEST_DECL_GROUP("asn", test_wc_DecodeKeyUsage_decipherOnly), \ TEST_DECL_GROUP("asn", test_wc_DecodeExtKeyUsage_ssh), \ TEST_DECL_GROUP("asn", test_wc_DecodeExtKeyUsage_ssh_oid_collision), \ + TEST_DECL_GROUP("asn", test_wc_CertNameAllSubject), \ TEST_DECL_GROUP("asn", test_wc_AsnDecisionCoverage), \ TEST_DECL_GROUP("asn", test_wc_AsnFeatureCoverage) diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 03dabdf94a9..524b23d3663 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -14690,76 +14690,6 @@ static const CertNameData certNameSubject[] = { WC_NID_userId #endif }, -#ifdef WOLFSSL_CERT_NAME_ALL - /* Name, id 41 */ - { - "/N=", 3, - #if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_EXT) - WC_OFFSETOF(DecodedCert, subjectN), - WC_OFFSETOF(DecodedCert, subjectNLen), - WC_OFFSETOF(DecodedCert, subjectNEnc), -#ifdef WOLFSSL_HAVE_ISSUER_NAMES - 0, - 0, - 0, -#endif - #endif - #ifdef WOLFSSL_X509_NAME_AVAILABLE - WC_NID_name - #endif - }, - /* Given Name, id 42 */ - { - "/GN=", 4, - #if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_EXT) - WC_OFFSETOF(DecodedCert, subjectGN), - WC_OFFSETOF(DecodedCert, subjectGNLen), - WC_OFFSETOF(DecodedCert, subjectGNEnc), -#ifdef WOLFSSL_HAVE_ISSUER_NAMES - 0, - 0, - 0, -#endif - #endif - #ifdef WOLFSSL_X509_NAME_AVAILABLE - WC_NID_givenName - #endif - }, - /* initials, id 43 */ - { - "/initials=", 10, - #if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_EXT) - WC_OFFSETOF(DecodedCert, subjectI), - WC_OFFSETOF(DecodedCert, subjectILen), - WC_OFFSETOF(DecodedCert, subjectIEnc), -#ifdef WOLFSSL_HAVE_ISSUER_NAMES - 0, - 0, - 0, -#endif - #endif - #ifdef WOLFSSL_X509_NAME_AVAILABLE - WC_NID_initials - #endif - }, - /* DN Qualifier Name, id 46 */ - { - "/dnQualifier=", 13, - #if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_EXT) - WC_OFFSETOF(DecodedCert, subjectDNQ), - WC_OFFSETOF(DecodedCert, subjectDNQLen), - WC_OFFSETOF(DecodedCert, subjectDNQEnc), -#ifdef WOLFSSL_HAVE_ISSUER_NAMES - 0, - 0, - 0, -#endif - #endif - #ifdef WOLFSSL_X509_NAME_AVAILABLE - WC_NID_dnQualifier - #endif - }, -#endif /* WOLFSSL_CERT_NAME_ALL */ }; static const int certNameSubjectSz = @@ -15194,6 +15124,31 @@ static int SetSubject(DecodedCert* cert, int id, const byte* str, int strLen, cert->subjectEmailLen = strLen; } #endif +#if (defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_CERT_EXT)) && \ + defined(WOLFSSL_CERT_NAME_ALL) + /* certNameSubject[] is indexed by id - 3 and its last entry is + * ASN_USER_ID, so these ids cannot be reached through it. */ + else if (id == ASN_NAME) { + cert->subjectN = (char*)(wc_ptr_t)str; + cert->subjectNLen = strLen; + cert->subjectNEnc = (char)tag; + } + else if (id == ASN_GIVEN_NAME) { + cert->subjectGN = (char*)(wc_ptr_t)str; + cert->subjectGNLen = strLen; + cert->subjectGNEnc = (char)tag; + } + else if (id == ASN_INITIALS) { + cert->subjectI = (char*)(wc_ptr_t)str; + cert->subjectILen = strLen; + cert->subjectIEnc = (char)tag; + } + else if (id == ASN_DNQUALIFIER) { + cert->subjectDNQ = (char*)(wc_ptr_t)str; + cert->subjectDNQLen = strLen; + cert->subjectDNQEnc = (char)tag; + } +#endif #ifdef WOLFSSL_CERT_EXT /* TODO: consider mapping id to an index and using SetCertNameSubect*(). */ else if (id == ASN_JURIS_C) { @@ -15295,6 +15250,37 @@ static int GetRDN(DecodedCert* cert, char* full, word32* idx, int* nid, *nid = WC_NID_x500UniqueIdentifier; #endif } + #ifdef WOLFSSL_CERT_NAME_ALL + /* Also outside the contiguous range the table covers. */ + else if (id == ASN_NAME) { + typeStr = WOLFSSL_NAME; + typeStrLen = sizeof(WOLFSSL_NAME) - 1; + #ifdef WOLFSSL_X509_NAME_AVAILABLE + *nid = WC_NID_name; + #endif + } + else if (id == ASN_GIVEN_NAME) { + typeStr = WOLFSSL_GIVEN_NAME; + typeStrLen = sizeof(WOLFSSL_GIVEN_NAME) - 1; + #ifdef WOLFSSL_X509_NAME_AVAILABLE + *nid = WC_NID_givenName; + #endif + } + else if (id == ASN_INITIALS) { + typeStr = WOLFSSL_INITIALS; + typeStrLen = sizeof(WOLFSSL_INITIALS) - 1; + #ifdef WOLFSSL_X509_NAME_AVAILABLE + *nid = WC_NID_initials; + #endif + } + else if (id == ASN_DNQUALIFIER) { + typeStr = WOLFSSL_DNQUALIFIER; + typeStrLen = sizeof(WOLFSSL_DNQUALIFIER) - 1; + #ifdef WOLFSSL_X509_NAME_AVAILABLE + *nid = WC_NID_dnQualifier; + #endif + } + #endif /* WOLFSSL_CERT_NAME_ALL */ } else if (oidSz == sizeof(attrEmailOid) && XMEMCMP(oid, attrEmailOid, oidSz) == 0) { /* Set the email id, type string, length and NID. */