From 96fb284398dfde9fa349e486aeac3c93e23f514f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Tue, 28 Jul 2026 14:22:45 +0200 Subject: [PATCH] Honour chklen when matching an IP in X509_check_host wolfSSL_X509_check_host takes an explicit length and its own validation accepts a buffer with no NUL terminator, since only an embedded NUL is rejected and a trailing one is merely stripped when present. The iPAddress check then called CheckIPAddr, which drops the length and measures the buffer with XSTRLEN, reading past the end of a caller supplied buffer that is length delimited rather than terminated. This ran on every call, not only when checking an IP address, and is compiled in whenever WOLFSSL_IP_ALT_NAME is defined, which OPENSSL_ALL and WOLFSSL_QT enable. Call CheckHostName directly with the caller's length and the IP flag set. That is what CheckIPAddr does internally, minus the length being recomputed. Behaviour is unchanged for NUL terminated input, because the normalization above already leaves chklen equal to the string length in that case. It also fixes a matching bug, since a length delimited IP address sitting in a longer buffer no longer fails to match an iPAddress entry. Add a regression test covering an interior slice of a longer buffer and a buffer sized exactly to the name with no terminator. Fixes F-7248. --- src/x509.c | 5 ++++- tests/api/test_ossl_x509.c | 34 ++++++++++++++++++++++++++++++++++ tests/api/test_ossl_x509.h | 2 ++ 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/x509.c b/src/x509.c index b98909bd87..839f4317e8 100644 --- a/src/x509.c +++ b/src/x509.c @@ -15737,7 +15737,10 @@ int wolfSSL_X509_check_host(WOLFSSL_X509 *x, const char *chk, size_t chklen, } #ifdef WOLFSSL_IP_ALT_NAME - ret = CheckIPAddr(dCert, (char *)chk); + /* chk is length delimited and may not be NUL terminated, so check it + * against the iPAddress entries directly rather than through the + * NUL terminated CheckIPAddr helper. */ + ret = CheckHostName(dCert, (char *)chk, chklen, 0, 1); if (ret == 0) { goto out; } diff --git a/tests/api/test_ossl_x509.c b/tests/api/test_ossl_x509.c index d0d31b7ab0..b262b72142 100644 --- a/tests/api/test_ossl_x509.c +++ b/tests/api/test_ossl_x509.c @@ -435,6 +435,40 @@ int test_wolfSSL_X509_check_host(void) return EXPECT_RESULT(); } +int test_wolfSSL_X509_check_host_len(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && !defined(NO_FILESYSTEM) \ + && !defined(NO_SHA) && !defined(NO_RSA) && defined(WOLFSSL_IP_ALT_NAME) + /* chk is length delimited and need not be NUL terminated, so nothing + * past chk[chklen - 1] may be read. */ + X509* x509 = NULL; + const char sliced[] = "127.0.0.1extra"; + const size_t ipLen = 9; /* length of "127.0.0.1" */ + char* exact = NULL; + + /* cliCertFile has subjectAltName set to 'example.com', '127.0.0.1' */ + ExpectNotNull(x509 = wolfSSL_X509_load_certificate_file(cliCertFile, + SSL_FILETYPE_PEM)); + + /* An interior slice of a longer buffer must match the iPAddress SAN. */ + ExpectIntEQ(X509_check_host(x509, sliced, ipLen, 0, NULL), + WOLFSSL_SUCCESS); + + /* Same name in a buffer sized exactly to it, with no terminator. */ + ExpectNotNull(exact = (char*)XMALLOC(ipLen, NULL, DYNAMIC_TYPE_TMP_BUFFER)); + if (exact != NULL) { + XMEMCPY(exact, "127.0.0.1", ipLen); + ExpectIntEQ(X509_check_host(x509, exact, ipLen, 0, NULL), + WOLFSSL_SUCCESS); + } + XFREE(exact, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + X509_free(x509); +#endif + return EXPECT_RESULT(); +} + int test_wolfSSL_X509_check_email(void) { EXPECT_DECLS; diff --git a/tests/api/test_ossl_x509.h b/tests/api/test_ossl_x509.h index fa6dd3a6b5..1d3771ca5e 100644 --- a/tests/api/test_ossl_x509.h +++ b/tests/api/test_ossl_x509.h @@ -33,6 +33,7 @@ int test_wolfSSL_i2d_X509_NAME_canon(void); int test_wolfSSL_X509_subject_name_hash(void); int test_wolfSSL_X509_issuer_name_hash(void); int test_wolfSSL_X509_check_host(void); +int test_wolfSSL_X509_check_host_len(void); int test_wolfSSL_X509_check_email(void); int test_wolfSSL_X509(void); int test_wolfSSL_X509_get0_tbs_sigalg(void); @@ -68,6 +69,7 @@ int test_wolfSSL_X509_cmp(void); TEST_DECL_GROUP("ossl_x509", test_wolfSSL_X509_subject_name_hash), \ TEST_DECL_GROUP("ossl_x509", test_wolfSSL_X509_issuer_name_hash), \ TEST_DECL_GROUP("ossl_x509", test_wolfSSL_X509_check_host), \ + TEST_DECL_GROUP("ossl_x509", test_wolfSSL_X509_check_host_len), \ TEST_DECL_GROUP("ossl_x509", test_wolfSSL_X509_check_email), \ TEST_DECL_GROUP("ossl_x509", test_wolfSSL_X509), \ TEST_DECL_GROUP("ossl_x509", test_wolfSSL_X509_get0_tbs_sigalg), \