From 244b3b5da31cbce5b4b2b91a9a8bca8e0f549445 Mon Sep 17 00:00:00 2001 From: Reda Chouk Date: Tue, 28 Jul 2026 14:21:52 +0200 Subject: [PATCH] Use the stored DER length when printing SAN directoryName entries --- src/x509.c | 9 ++++++-- tests/api.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/src/x509.c b/src/x509.c index 3842b2feb60..eaced3397b1 100644 --- a/src/x509.c +++ b/src/x509.c @@ -6859,7 +6859,7 @@ static int X509PrintDirType(char * dst, int max_len, const DNS_entry * entry) word32 k = 0; word32 i = 0; const char * src = entry->name; - word32 src_len = (word32)XSTRLEN(src); + word32 src_len; int total_len = 0; int bytes_left = max_len; int fld_len = 0; @@ -6867,6 +6867,11 @@ static int X509PrintDirType(char * dst, int max_len, const DNS_entry * entry) XMEMSET(dst, 0, max_len); + if ((src == NULL) || (entry->len <= 0)) { + return 0; + } + src_len = (word32)entry->len; + /* loop over printable DIR tags. */ for (k = 0; k < ACERT_NUM_DIR_TAGS; ++k) { const char * pfx = acert_dir_print[k].pfx; @@ -6874,7 +6879,7 @@ static int X509PrintDirType(char * dst, int max_len, const DNS_entry * entry) byte asn_tag; /* walk through entry looking for matches. */ - for (i = 0; i < src_len - 5; ++i) { + for (i = 0; i + 5 < src_len; ++i) { if (XMEMCMP(tag, &src[i], 3) == 0) { if (bytes_left < 5) { /* Not enough space left for name oid + tag + len. */ diff --git a/tests/api.c b/tests/api.c index 95551a6c2b8..f2b88295ac0 100644 --- a/tests/api.c +++ b/tests/api.c @@ -28256,6 +28256,71 @@ static int test_wolfSSL_X509_print_ext_key_usage(void) return EXPECT_RESULT(); } +static int test_wolfSSL_X509_print_san_dirname(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_BIO) && !defined(NO_RSA) && \ + defined(XSNPRINTF) && !defined(WC_DISABLE_RADIX_ZERO_PAD) && \ + !defined(NO_SHA) + /* RSA cert (CN="pst.quesada.es") whose Subject Alternative Name holds a + * directoryName next to a dNSName. A directoryName is raw DER rather than + * text, and this one carries an embedded NUL near the start. + * X509_print must bound the entry by its stored length and stay inside it, + * rather than measuring it as a NUL-terminated string and scanning off the + * end of the allocation. */ + static const char sanDirNameCertPem[] = + "-----BEGIN CERTIFICATE-----\n" + "MIIC6DCCAsKgAwIBAgIEPMgubTANBgkqhkiG9w0BAQUFADA2MQswCQYDVQQGEwJF\n" + "UzENMAsGA1UEChMERk5NVDEYMBYGA1UECxMPRk5NVCBDbGFzZSAyIENBMB4XDTEx\n" + "MDIwMjA5MDMzMVoXDTE1MDIwMjA5MDMzMVowdjELMAkGA1UEBhMCRVMxDTALBgNV\n" + "BAoTBEZOTVQxGDAWBgNVBAsTD0ZOTVQgQ2xhc2UgMiBDQTERMA8GA1UECxMIUHVi\n" + "bGljb3MxEjAQBgNVBAsTCTUwMDA3MDAxNTEXMBUGA1UEAxMOcHN0LnF1ZXNhZGEu\n" + "ZXMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANGP1429IWugRmlntpx6oS15\n" + "+9mhrSZ+wwnpWlnIi6L2qR4q/NjDSt0dtbnXnsJ2DlYkkt4fz20B97MppRWWqX23\n" + "HdoU3W8ikXutRUXLO/Cz7v4RiejtPHzhsPH+j7+JY5VnknBuqgX2t5If3Ti1OqRS\n" + "SjSs/F6JHtRKd5GFuC0zAgMBAAGjggEyMIIBLjCBjQYDVR0RBIGFMIGCpHAwbjEY\n" + "/wAAACsGAQQBrGYAEAwgWDM5MTExMTFFMDcxMBkgLxkAGwCsZgEOFCRFWENNQS4g\n" + "RElQVVRBQ0nTTiBQUk9WSU5DSUFMIERFIEpByU4xHTAbBgkrAIAAAKxmAQgTDnBz\n" + "dC5xdWVzYWRhLmVzgg5wc3QucXVlc2FkYS5lczAJBgNVHRMEAjAAMAkGA1UdEAQC\n" + "MAAwCwYDVR0PBAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMBEGCWCGSAGG+EIB\n" + "AQQEAwIGQDAdBgNVHQ4EFgQUjOcPzD3pTI1memRMeTT+hYOlMv4wHwYDVR0jBBgw\n" + "FoAUQJp2RJd0B8SsFMsejU86RXww12EwEQYDVR0fBAowCDAGoASgAqQAMA0GCSqG\n" + "SIb3DQEBBQUAAxEA6rva+ThRrxATPOG7C0FuXA==\n" + "-----END CERTIFICATE-----\n"; + X509* x509 = NULL; + BIO* bio = NULL; + char* data = NULL; + int len = 0; + int ret = 0; + char buf[8192]; + + ExpectNotNull(x509 = wolfSSL_X509_load_certificate_buffer( + (const unsigned char*)sanDirNameCertPem, + (int)XSTRLEN(sanDirNameCertPem), WOLFSSL_FILETYPE_PEM)); + ExpectNotNull(bio = BIO_new(BIO_s_mem())); + + /* This directoryName carries no printable C=/O=/OU=/CN= field, so the + * rendered value is empty and the print may legitimately report failure. + * What must hold is that the scan stays in bounds and returns a defined + * result instead of running off the allocation. */ + ExpectTrue(((ret = X509_print(bio, x509)) == WOLFSSL_SUCCESS) || + (ret == WC_NO_ERR_TRACE(WOLFSSL_FAILURE))); + + /* Printing must have got as far as emitting the SAN extension. */ + ExpectIntGT((len = BIO_get_mem_data(bio, &data)), 0); + ExpectIntLT(len, (int)sizeof(buf)); + if ((data != NULL) && (len > 0) && (len < (int)sizeof(buf))) { + XMEMCPY(buf, data, (size_t)len); + buf[len] = '\0'; + ExpectNotNull(XSTRSTR(buf, "X509v3 Subject Alternative Name")); + } + + BIO_free(bio); + X509_free(x509); +#endif + return EXPECT_RESULT(); +} + static int test_wolfSSL_X509_CRL_print(void) { EXPECT_DECLS; @@ -38291,6 +38356,7 @@ TEST_CASE testCases[] = { TEST_DECL(test_wolfSSL_X509_print), TEST_DECL(test_wolfSSL_X509_print_basic_constraints), TEST_DECL(test_wolfSSL_X509_print_ext_key_usage), + TEST_DECL(test_wolfSSL_X509_print_san_dirname), TEST_DECL(test_wolfSSL_X509_CRL_print), #endif