From bc62fbb946085527b4b1c02f337dd10c68c54690 Mon Sep 17 00:00:00 2001
From: Alexander Sosedkin <asosedkin@redhat.com>
Date: Wed, 4 Feb 2026 09:09:46 +0100
Subject: [PATCH] x509/name_constraints: add sorted_view in preparation...

... for actually using it later for performance gains.

Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>

Upstream-Status: Backport [https://gitlab.com/gnutls/gnutls/-/commit/bc62fbb946085527b4b1c02f337dd10c68c54690]
CVE: CVE-2025-14831
Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
---
 lib/x509/name_constraints.c | 62 ++++++++++++++++++++++++++++++-------
 1 file changed, 51 insertions(+), 11 deletions(-)

--- a/lib/x509/name_constraints.c
+++ b/lib/x509/name_constraints.c
@@ -54,6 +54,9 @@ struct name_constraints_node_list_st {
 	struct name_constraints_node_st **data;
 	size_t size;
 	size_t capacity;
+	/* sorted-on-demand view, valid only when dirty == false */
+	bool dirty;
+	struct name_constraints_node_st **sorted_view;
 };
 
 struct gnutls_name_constraints_st {
@@ -342,6 +345,37 @@ static int compare_name_constraint_nodes
 	}
 }
 
+/* Bring the sorted view up to date with the list data; clear the dirty flag. */
+static int ensure_sorted(struct name_constraints_node_list_st *list)
+{
+	struct name_constraints_node_st **new_data;
+
+	if (!list->dirty)
+		return GNUTLS_E_SUCCESS;
+	if (!list->size) {
+		list->dirty = false;
+		return GNUTLS_E_SUCCESS;
+	}
+
+	/* reallocate sorted view to match current size */
+	new_data =
+		_gnutls_reallocarray(list->sorted_view, list->size,
+				     sizeof(struct name_constraints_node_st *));
+	if (!new_data)
+		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+	list->sorted_view = new_data;
+
+	/* copy pointers and sort in-place */
+	memcpy(list->sorted_view, list->data,
+	       list->size * sizeof(struct name_constraints_node_st *));
+	qsort(list->sorted_view, list->size,
+	      sizeof(struct name_constraints_node_st *),
+	      compare_name_constraint_nodes_qsort);
+
+	list->dirty = false;
+	return GNUTLS_E_SUCCESS;
+}
+
 static int
 name_constraints_node_list_add(struct name_constraints_node_list_st *list,
 			       struct name_constraints_node_st *node)
@@ -361,10 +395,23 @@ name_constraints_node_list_add(struct na
 		list->capacity = new_capacity;
 		list->data = new_data;
 	}
+	list->dirty = true;
 	list->data[list->size++] = node;
 	return 0;
 }
 
+static void
+name_constraints_node_list_clear(struct name_constraints_node_list_st *list)
+{
+	gnutls_free(list->data);
+	gnutls_free(list->sorted_view);
+	list->data = NULL;
+	list->sorted_view = NULL;
+	list->capacity = 0;
+	list->size = 0;
+	list->dirty = false;
+}
+
 static int
 name_constraints_node_add_new(gnutls_x509_name_constraints_t nc,
 			      struct name_constraints_node_list_st *list,
@@ -711,6 +758,7 @@ static int name_constraints_node_list_in
 				permitted->data[i] =
 					permitted->data[permitted->size - 1];
 			permitted->size--;
+			permitted->dirty = true;
 			continue;
 		}
 		i++;
@@ -905,17 +953,9 @@ void _gnutls_x509_name_constraints_clear
 		struct name_constraints_node_st *node = nc->nodes.data[i];
 		name_constraints_node_free(node);
 	}
-	gnutls_free(nc->nodes.data);
-	nc->nodes.capacity = 0;
-	nc->nodes.size = 0;
-
-	gnutls_free(nc->permitted.data);
-	nc->permitted.capacity = 0;
-	nc->permitted.size = 0;
-
-	gnutls_free(nc->excluded.data);
-	nc->excluded.capacity = 0;
-	nc->excluded.size = 0;
+	name_constraints_node_list_clear(&nc->nodes);
+	name_constraints_node_list_clear(&nc->permitted);
+	name_constraints_node_list_clear(&nc->excluded);
 }
 
 /**
