From d0ac999620c8c0aeb6939e1e92d884ca8e40b759 Mon Sep 17 00:00:00 2001
From: Alexander Sosedkin <asosedkin@redhat.com>
Date: Wed, 4 Feb 2026 18:31:37 +0100
Subject: [PATCH] x509/name_constraints: make types_with_empty_intersection a
 bitmask

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

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

diff --git a/lib/x509/name_constraints.c b/lib/x509/name_constraints.c
index de20dd8ef4..1d78d1bc50 100644
--- a/lib/x509/name_constraints.c
+++ b/lib/x509/name_constraints.c
@@ -275,6 +275,7 @@ static enum name_constraint_relation compare_ip_ncs(const gnutls_datum_t *n1,
 
 static inline bool is_supported_type(unsigned type)
 {
+	/* all of these should be under GNUTLS_SAN_MAX (intersect bitmasks) */
 	return type == GNUTLS_SAN_DNSNAME || type == GNUTLS_SAN_RFC822NAME ||
 	       type == GNUTLS_SAN_IPADDRESS;
 }
@@ -683,6 +684,21 @@ name_constraints_node_new(gnutls_x509_name_constraints_t nc, unsigned type,
 	return tmp;
 }
 
+static int
+name_constraints_node_list_union(gnutls_x509_name_constraints_t nc,
+				 struct name_constraints_node_list_st *nodes,
+				 struct name_constraints_node_list_st *nodes2);
+
+#define type_bitmask_t uint8_t /* increase if GNUTLS_SAN_MAX grows */
+#define type_bitmask_set(mask, t) ((mask) |= (1u << (t)))
+#define type_bitmask_clr(mask, t) ((mask) &= ~(1u << (t)))
+#define type_bitmask_in(mask, t) ((mask) & (1u << (t)))
+/* C99-compatible compile-time assertions; gnutls_int.h undefines verify */
+typedef char assert_san_max[(GNUTLS_SAN_MAX < 8) ? 1 : -1];
+typedef char assert_dnsname[(GNUTLS_SAN_DNSNAME <= GNUTLS_SAN_MAX) ? 1 : -1];
+typedef char assert_rfc822[(GNUTLS_SAN_RFC822NAME <= GNUTLS_SAN_MAX) ? 1 : -1];
+typedef char assert_ipaddr[(GNUTLS_SAN_IPADDRESS <= GNUTLS_SAN_MAX) ? 1 : -1];
+
 /*-
  * @brief name_constraints_node_list_intersect:
  * @nc: %gnutls_x509_name_constraints_t
@@ -710,12 +726,9 @@ static int name_constraints_node_list_intersect(
 							 .capacity = 0 };
 	static const unsigned char universal_ip[32] = { 0 };
 
-	/* temporary array to see, if we need to add universal excluded constraints
-	 * (see phase 3 for details)
-	 * indexed directly by (gnutls_x509_subject_alt_name_t enum - 1) */
-	unsigned char types_with_empty_intersection[GNUTLS_SAN_MAX];
-	memset(types_with_empty_intersection, 0,
-	       sizeof(types_with_empty_intersection));
+	/* bitmask to see if we need to add universal excluded constraints
+	 * (see phase 3 for details) */
+	type_bitmask_t types_with_empty_intersection = 0;
 
 	if (permitted->size == 0 || permitted2->size == 0)
 		return 0;
@@ -741,7 +754,8 @@ static int name_constraints_node_list_intersect(
 				// note the possibility of empty intersection for this type
 				// if we add something to the intersection in phase 2,
 				// we will reset this flag back to 0 then
-				types_with_empty_intersection[t->type - 1] = 1;
+				type_bitmask_set(types_with_empty_intersection,
+						 t->type);
 				found = t2;
 				break;
 			}
@@ -798,8 +812,8 @@ static int name_constraints_node_list_intersect(
 						GNUTLS_E_INTERNAL_ERROR);
 				}
 				// we will not add universal excluded constraint for this type
-				types_with_empty_intersection[tmp->type - 1] =
-					0;
+				type_bitmask_clr(types_with_empty_intersection,
+						 tmp->type);
 				// add intersection node to PERMITTED
 				ret = name_constraints_node_list_add(permitted,
 								     tmp);
@@ -827,7 +841,7 @@ static int name_constraints_node_list_intersect(
 	 * excluded constraint with universal wildcard
 	 * (since the intersection of permitted is now empty). */
 	for (type = 1; type <= GNUTLS_SAN_MAX; type++) {
-		if (types_with_empty_intersection[type - 1] == 0)
+		if (!type_bitmask_in(types_with_empty_intersection, type))
 			continue;
 		_gnutls_hard_log(
 			"Adding universal excluded name constraint for type %d.\n",
@@ -871,6 +885,11 @@ cleanup:
 	return ret;
 }
 
+#undef type_bitmask_t
+#undef type_bitmask_set
+#undef type_bitmask_clr
+#undef type_bitmask_in
+
 static int
 name_constraints_node_list_union(gnutls_x509_name_constraints_t nc,
 				 struct name_constraints_node_list_st *nodes,
-- 
GitLab

