Commit 97e3ce610b for openssl.org
commit 97e3ce610ba8b3610f572fcf510e26869ba0e710
Author: jdymitarai <o10040115@gmail.com>
Date: Sat Oct 17 16:27:33 2026 +0900
crypto/x509/x509_vpm.c: copy string verify parameters as strings
When X509_VERIFY_PARAM_inherit() duplicates verification parameter
buffer stacks through replace_buffer_stack(), all the entries were
copied using buffer_from_bytes() since commit f584ae959cbc "Let's
support multiple names for certificate verification". Because
buffer_from_bytes() allocates only the exact byte count
via OPENSSL_memdup() without an extra trailing byte
for NUL-termination, string entries originally created
by buffer_from_string() (such as hostnames and email addresses)
lost their trailing NUL byte upon being copied.
When X509_STORE_CTX_print_verify_cb() or other consumers read these
copied entries as C strings through X509_VERIFY_PARAM_get0_host()
or X509_VERIFY_PARAM_get0_email(), callers like printf() or BIO_printf()
read past the allocated buffer bounds, triggering an AddressSanitizer
heap-buffer-overflow.
Differentiate buffer stack duplication in X509_VERIFY_PARAM_inherit():
duplicate string-backed fields (hosts, rfc822s, smtputf8s) using
buffer_copy_string(), and duplicate byte-backed fields (ips) using
buffer_copy_bytes(). Add test_vpm_copy_string_nul_term()
to verify_extra_test to guard against regressions.
Resolves: https://github.com/openssl/openssl/issues/33236
Fixes: f584ae959cbc "Let's support multiple names for certificate verification"
Assisted-by: Gemini:gemini-3.8-flash
Reviewed-by: Tomas Mraz <tomas@openssl.foundation>
Reviewed-by: Nikola Pajkovsky <nikolap@openssl.org>
Reviewed-by: Eugene Syromiatnikov <esyr@openssl.org>
Merge-date: Wed Oct 28 11:10:37 2026
Merged-from: https://github.com/openssl/openssl/pull/33238
diff --git a/crypto/x509/x509_vpm.c b/crypto/x509/x509_vpm.c
index 44b116923b..ebc969c35f 100644
--- a/crypto/x509/x509_vpm.c
+++ b/crypto/x509/x509_vpm.c
@@ -78,11 +78,16 @@ err:
return ret;
}
-static X509_BUFFER *buffer_copy(const X509_BUFFER *b)
+static X509_BUFFER *buffer_copy_bytes(const X509_BUFFER *b)
{
return buffer_from_bytes(b->data, b->len);
}
+static X509_BUFFER *buffer_copy_string(const X509_BUFFER *b)
+{
+ return buffer_from_string(b->data, b->len);
+}
+
static void buffer_free(X509_BUFFER *b)
{
if (b == NULL)
@@ -91,13 +96,26 @@ static void buffer_free(X509_BUFFER *b)
OPENSSL_free(b);
}
-static int replace_buffer_stack(STACK_OF(X509_BUFFER) **dest,
+static int replace_buffer_stack_bytes(STACK_OF(X509_BUFFER) **dest,
+ STACK_OF(X509_BUFFER) *const *src)
+{
+ sk_X509_BUFFER_pop_free(*dest, buffer_free);
+ *dest = NULL;
+ if (*src != NULL) {
+ *dest = sk_X509_BUFFER_deep_copy(*src, buffer_copy_bytes, buffer_free);
+ if (*dest == NULL)
+ return 0;
+ }
+ return 1;
+}
+
+static int replace_buffer_stack_string(STACK_OF(X509_BUFFER) **dest,
STACK_OF(X509_BUFFER) *const *src)
{
sk_X509_BUFFER_pop_free(*dest, buffer_free);
*dest = NULL;
if (*src != NULL) {
- *dest = sk_X509_BUFFER_deep_copy(*src, buffer_copy, buffer_free);
+ *dest = sk_X509_BUFFER_deep_copy(*src, buffer_copy_string, buffer_free);
if (*dest == NULL)
return 0;
}
@@ -466,25 +484,25 @@ int X509_VERIFY_PARAM_inherit(X509_VERIFY_PARAM *dest,
x509_verify_param_copy(hostflags, 0);
if (test_x509_verify_param_copy(hosts, NULL)) {
- if (!replace_buffer_stack(&dest->hosts, &src->hosts))
+ if (!replace_buffer_stack_string(&dest->hosts, &src->hosts))
return 0;
}
x509_verify_param_copy(validate_host, NULL);
if (test_x509_verify_param_copy(ips, NULL)) {
- if (!replace_buffer_stack(&dest->ips, &src->ips))
+ if (!replace_buffer_stack_bytes(&dest->ips, &src->ips))
return 0;
}
x509_verify_param_copy(validate_ip, NULL);
if (test_x509_verify_param_copy(rfc822s, NULL)) {
- if (!replace_buffer_stack(&dest->rfc822s, &src->rfc822s))
+ if (!replace_buffer_stack_string(&dest->rfc822s, &src->rfc822s))
return 0;
}
x509_verify_param_copy(validate_rfc822, NULL);
if (test_x509_verify_param_copy(smtputf8s, NULL)) {
- if (!replace_buffer_stack(&dest->smtputf8s, &src->smtputf8s))
+ if (!replace_buffer_stack_string(&dest->smtputf8s, &src->smtputf8s))
return 0;
}
x509_verify_param_copy(validate_smtputf8, NULL);
diff --git a/test/verify_extra_test.c b/test/verify_extra_test.c
index 474f87b4c9..9021e31a5a 100644
--- a/test/verify_extra_test.c
+++ b/test/verify_extra_test.c
@@ -680,6 +680,41 @@ err:
return ret;
}
+static int test_vpm_copy_string_nul_term(void)
+{
+ X509_VERIFY_PARAM *src = NULL, *dest = NULL;
+ const char *test_host = "test.example.com";
+ const char *test_email = "user@example.com";
+ const char *ret_host, *ret_email;
+ int ret = 0;
+
+ if (!TEST_ptr(src = X509_VERIFY_PARAM_new())
+ || !TEST_ptr(dest = X509_VERIFY_PARAM_new()))
+ goto err;
+
+ if (!TEST_true(X509_VERIFY_PARAM_set1_host(src, test_host, 0))
+ || !TEST_true(X509_VERIFY_PARAM_set1_email(src, test_email, 0)))
+ goto err;
+
+ if (!TEST_true(X509_VERIFY_PARAM_set1(dest, src)))
+ goto err;
+
+ if (!TEST_ptr(ret_host = X509_VERIFY_PARAM_get0_host(dest, 0))
+ || !TEST_str_eq(ret_host, test_host))
+ goto err;
+
+ if (!TEST_ptr(ret_email = X509_VERIFY_PARAM_get0_email(dest))
+ || !TEST_str_eq(ret_email, test_email))
+ goto err;
+
+ ret = 1;
+
+err:
+ X509_VERIFY_PARAM_free(src);
+ X509_VERIFY_PARAM_free(dest);
+ return ret;
+}
+
static int test_self_signed_good(void)
{
return test_self_signed(root_f, 1, 1);
@@ -1078,6 +1113,7 @@ int setup_tests(void)
ADD_TEST(test_purpose_any);
ADD_TEST(test_multiname_selfsigned);
ADD_TEST(test_vpm_input_validation);
+ ADD_TEST(test_vpm_copy_string_nul_term);
ADD_ALL_TESTS(test_pathlen_chain, OSSL_NELEM(pathlen_chains));
return 1;
err: