summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArchana Polampalli <archana.polampalli@windriver.com>2025-02-14 10:49:25 +0000
committerSteve Sakoman <steve@sakoman.com>2025-02-24 07:00:53 -0800
commit07305235422e6a255665654ea89c3c734b773f3d (patch)
tree8a7e6f4cc8a54a4e7fe6da64f846dae9fdf63041
parent138ab1c7df95368efdc4b79d656f9f5b16a74b25 (diff)
downloadpoky-07305235422e6a255665654ea89c3c734b773f3d.tar.gz
gnutls: fix CVE-2024-12243
A flaw was found in GnuTLS, which relies on libtasn1 for ASN.1 data processing. Due to an inefficient algorithm in libtasn1, decoding certain DER-encoded certificate data can take excessive time, leading to increased resource consumption. This flaw allows a remote attacker to send a specially crafted certificate, causing GnuTLS to become unresponsive or slow, resulting in a denial-of-service condition. (From OE-Core rev: 5fbe46de6d2e3862316cf486503f18e616c3c0a7) Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com> Signed-off-by: Steve Sakoman <steve@sakoman.com>
-rw-r--r--meta/recipes-support/gnutls/gnutls/CVE-2024-12243.patch1160
-rw-r--r--meta/recipes-support/gnutls/gnutls_3.7.4.bb1
2 files changed, 1161 insertions, 0 deletions
diff --git a/meta/recipes-support/gnutls/gnutls/CVE-2024-12243.patch b/meta/recipes-support/gnutls/gnutls/CVE-2024-12243.patch
new file mode 100644
index 0000000000..c0ff21fd25
--- /dev/null
+++ b/meta/recipes-support/gnutls/gnutls/CVE-2024-12243.patch
@@ -0,0 +1,1160 @@
1From 4760bc63531e3f5039e70ede91a20e1194410892 Mon Sep 17 00:00:00 2001
2From: Daiki Ueno <ueno@gnu.org>
3Date: Mon, 18 Nov 2024 17:23:46 +0900
4Subject: [PATCH] x509: optimize name constraints processing
5
6This switches the representation name constraints from linked lists to
7array lists to optimize the lookup performance from O(n) to O(1), also
8enforces a limit of name constraint checks against subject alternative
9names.
10
11Signed-off-by: Daiki Ueno <ueno@gnu.org>
12
13CVE: CVE-2024-12243
14
15Upstream-Status: Backport [https://gitlab.com/gnutls/gnutls/-/commit/4760bc63531e3f5039e70ede91a20e1194410892]
16
17Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com>
18---
19 lib/datum.c | 7 +-
20 lib/x509/name_constraints.c | 594 +++++++++++++++++++++---------------
21 lib/x509/x509_ext.c | 87 +++---
22 lib/x509/x509_ext_int.h | 5 +
23 lib/x509/x509_int.h | 24 +-
24 5 files changed, 405 insertions(+), 312 deletions(-)
25
26diff --git a/lib/datum.c b/lib/datum.c
27index bd0f216..b0e8d11 100644
28--- a/lib/datum.c
29+++ b/lib/datum.c
30@@ -29,6 +29,7 @@
31 #include <num.h>
32 #include <datum.h>
33 #include "errors.h"
34+#include "intprops.h"
35
36 /* On error, @dat is not changed. */
37 int
38@@ -61,7 +62,11 @@ _gnutls_set_strdatum(gnutls_datum_t * dat, const void *data, size_t data_size)
39 if (data == NULL)
40 return gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
41
42- unsigned char *m = gnutls_malloc(data_size + 1);
43+ size_t capacity;
44+ if (!INT_ADD_OK(data_size, 1, &capacity))
45+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
46+
47+ unsigned char *m = gnutls_malloc(capacity);
48 if (!m)
49 return GNUTLS_E_MEMORY_ERROR;
50
51diff --git a/lib/x509/name_constraints.c b/lib/x509/name_constraints.c
52index 6c1546e..c9eab70 100644
53--- a/lib/x509/name_constraints.c
54+++ b/lib/x509/name_constraints.c
55@@ -33,49 +33,99 @@
56 #include <gnutls/x509-ext.h>
57 #include <x509_b64.h>
58 #include <x509_int.h>
59+#include "x509_ext_int.h"
60 #include <libtasn1.h>
61
62 #include "ip.h"
63 #include "ip-in-cidr.h"
64
65+#include "intprops.h"
66+
67+#define MAX_NC_CHECKS (1 << 20)
68+
69+struct name_constraints_node_st {
70+ unsigned type;
71+ gnutls_datum_t name;
72+};
73+
74+struct name_constraints_node_list_st {
75+ struct name_constraints_node_st **data;
76+ size_t size;
77+ size_t capacity;
78+};
79+
80+struct gnutls_name_constraints_st {
81+ struct name_constraints_node_list_st nodes; /* owns elements */
82+ struct name_constraints_node_list_st permitted; /* borrows elements */
83+ struct name_constraints_node_list_st excluded; /* borrows elements */
84+};
85+
86+static struct name_constraints_node_st *
87+name_constraints_node_new(gnutls_x509_name_constraints_t nc, unsigned type,
88+ unsigned char *data, unsigned int size);
89+
90+static int name_constraints_node_list_add(struct name_constraints_node_list_st *list,
91+ struct name_constraints_node_st *node)
92+{
93+ if (!list->capacity || list->size == list->capacity) {
94+ size_t new_capacity = list->capacity;
95+ struct name_constraints_node_st **new_data;
96+
97+ if (!INT_MULTIPLY_OK(new_capacity, 2, &new_capacity) ||
98+ !INT_ADD_OK(new_capacity, 1, &new_capacity))
99+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
100+ new_data = _gnutls_reallocarray(
101+ list->data, new_capacity,
102+ sizeof(struct name_constraints_node_st *));
103+ if (!new_data)
104+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
105+ list->capacity = new_capacity;
106+ list->data = new_data;
107+ }
108+ list->data[list->size++] = node;
109+ return 0;
110+}
111+
112 // for documentation see the implementation
113-static int name_constraints_intersect_nodes(name_constraints_node_st * nc1,
114- name_constraints_node_st * nc2,
115- name_constraints_node_st ** intersection);
116+static int name_constraints_intersect_nodes(
117+ gnutls_x509_name_constraints_t nc,
118+ const struct name_constraints_node_st *node1,
119+ const struct name_constraints_node_st *node2,
120+ struct name_constraints_node_st **intersection);
121
122 /*-
123- * is_nc_empty:
124+ * _gnutls_x509_name_constraints_is_empty:
125 * @nc: name constraints structure
126- * @type: type (gnutls_x509_subject_alt_name_t)
127+ * @type: type (gnutls_x509_subject_alt_name_t or 0)
128 *
129 * Test whether given name constraints structure has any constraints (permitted
130 * or excluded) of a given type. @nc must be allocated (not NULL) before the call.
131+ * If @type is 0, type checking will be skipped.
132 *
133- * Returns: 0 if @nc contains constraints of type @type, 1 otherwise
134+ * Returns: false if @nc contains constraints of type @type, true otherwise
135 -*/
136-static unsigned is_nc_empty(struct gnutls_name_constraints_st* nc, unsigned type)
137+bool _gnutls_x509_name_constraints_is_empty(gnutls_x509_name_constraints_t nc,
138+ unsigned type)
139 {
140- name_constraints_node_st *t;
141+ if (nc->permitted.size == 0 && nc->excluded.size == 0)
142+ return true;
143
144- if (nc->permitted == NULL && nc->excluded == NULL)
145- return 1;
146+ if (type == 0)
147+ return false;
148
149- t = nc->permitted;
150- while (t != NULL) {
151- if (t->type == type)
152- return 0;
153- t = t->next;
154+ for (size_t i = 0; i < nc->permitted.size; i++) {
155+ if (nc->permitted.data[i]->type == type)
156+ return false;
157 }
158
159- t = nc->excluded;
160- while (t != NULL) {
161- if (t->type == type)
162- return 0;
163- t = t->next;
164+ for (size_t i = 0; i < nc->excluded.size; i++) {
165+ if (nc->excluded.data[i]->type == type)
166+ return false;
167+
168 }
169
170 /* no constraint for that type exists */
171- return 1;
172+ return true;
173 }
174
175 /*-
176@@ -111,21 +161,16 @@ static int validate_name_constraints_node(gnutls_x509_subject_alt_name_t type,
177 return GNUTLS_E_SUCCESS;
178 }
179
180-int _gnutls_extract_name_constraints(asn1_node c2, const char *vstr,
181- name_constraints_node_st ** _nc)
182+static int extract_name_constraints(gnutls_x509_name_constraints_t nc,
183+ asn1_node c2, const char *vstr,
184+ struct name_constraints_node_list_st *nodes)
185 {
186 int ret;
187 char tmpstr[128];
188 unsigned indx;
189 gnutls_datum_t tmp = { NULL, 0 };
190 unsigned int type;
191- struct name_constraints_node_st *nc, *prev;
192-
193- prev = *_nc;
194- if (prev != NULL) {
195- while(prev->next != NULL)
196- prev = prev->next;
197- }
198+ struct name_constraints_node_st *node;
199
200 for (indx=1;;indx++) {
201 snprintf(tmpstr, sizeof(tmpstr), "%s.?%u.base", vstr, indx);
202@@ -144,25 +189,19 @@ int _gnutls_extract_name_constraints(asn1_node c2, const char *vstr,
203 goto cleanup;
204 }
205
206- nc = gnutls_malloc(sizeof(struct name_constraints_node_st));
207- if (nc == NULL) {
208+ node = name_constraints_node_new(nc, type, tmp.data, tmp.size);
209+ _gnutls_free_datum(&tmp);
210+ if (node == NULL) {
211 gnutls_assert();
212 ret = GNUTLS_E_MEMORY_ERROR;
213 goto cleanup;
214 }
215
216- memcpy(&nc->name, &tmp, sizeof(gnutls_datum_t));
217- nc->type = type;
218- nc->next = NULL;
219-
220- if (prev == NULL) {
221- *_nc = prev = nc;
222- } else {
223- prev->next = nc;
224- prev = nc;
225+ ret = name_constraints_node_list_add(nodes, node);
226+ if (ret < 0) {
227+ gnutls_assert();
228+ goto cleanup;
229 }
230-
231- tmp.data = NULL;
232 }
233
234 assert(ret < 0);
235@@ -177,84 +216,102 @@ int _gnutls_extract_name_constraints(asn1_node c2, const char *vstr,
236 return ret;
237 }
238
239+int _gnutls_x509_name_constraints_extract(asn1_node c2,
240+ const char *permitted_name,
241+ const char *excluded_name,
242+ gnutls_x509_name_constraints_t nc)
243+{
244+ int ret;
245+
246+ ret = extract_name_constraints(nc, c2, permitted_name, &nc->permitted);
247+ if (ret < 0)
248+ return gnutls_assert_val(ret);
249+ ret = extract_name_constraints(nc, c2, excluded_name, &nc->excluded);
250+ if (ret < 0)
251+ return gnutls_assert_val(ret);
252+
253+ return ret;
254+}
255+
256 /*-
257- * _gnutls_name_constraints_node_free:
258+ * name_constraints_node_free:
259 * @node: name constraints node
260 *
261- * Deallocate a list of name constraints nodes starting at the given node.
262+ * Deallocate a name constraints node.
263 -*/
264-void _gnutls_name_constraints_node_free(name_constraints_node_st *node)
265+static void name_constraints_node_free(struct name_constraints_node_st *node)
266 {
267- name_constraints_node_st *next, *t;
268-
269- t = node;
270- while (t != NULL) {
271- next = t->next;
272- gnutls_free(t->name.data);
273- gnutls_free(t);
274- t = next;
275+ if (node) {
276+ gnutls_free(node->name.data);
277+ gnutls_free(node);
278 }
279 }
280
281 /*-
282 * name_constraints_node_new:
283 * @type: name constraints type to set (gnutls_x509_subject_alt_name_t)
284+ * @nc: a %gnutls_x509_name_constraints_t
285 * @data: name.data to set or NULL
286 * @size: name.size to set
287 *
288 * Allocate a new name constraints node and set its type, name size and name data.
289- * If @data is set to NULL, name data will be an array of \x00 (the length of @size).
290- * The .next pointer is set to NULL.
291 *
292 * Returns: Pointer to newly allocated node or NULL in case of memory error.
293 -*/
294-static name_constraints_node_st* name_constraints_node_new(unsigned type,
295- unsigned char *data,
296- unsigned int size)
297+static struct name_constraints_node_st *
298+name_constraints_node_new(gnutls_x509_name_constraints_t nc, unsigned type,
299+ unsigned char *data, unsigned int size)
300 {
301- name_constraints_node_st *tmp = gnutls_malloc(sizeof(struct name_constraints_node_st));
302+ struct name_constraints_node_st *tmp;
303+ int ret;
304+
305+ tmp = gnutls_calloc(1, sizeof(struct name_constraints_node_st));
306 if (tmp == NULL)
307 return NULL;
308 tmp->type = type;
309- tmp->next = NULL;
310- tmp->name.size = size;
311- tmp->name.data = NULL;
312- if (tmp->name.size > 0) {
313-
314- tmp->name.data = gnutls_malloc(tmp->name.size);
315- if (tmp->name.data == NULL) {
316+ if (data) {
317+ ret = _gnutls_set_strdatum(&tmp->name, data, size);
318+ if (ret < 0) {
319+ gnutls_assert();
320 gnutls_free(tmp);
321 return NULL;
322 }
323- if (data != NULL) {
324- memcpy(tmp->name.data, data, size);
325- } else {
326- memset(tmp->name.data, 0, size);
327- }
328 }
329+ ret = name_constraints_node_list_add(&nc->nodes, tmp);
330+ if (ret < 0) {
331+ gnutls_assert();
332+ name_constraints_node_free(tmp);
333+ return NULL;
334+ }
335+
336 return tmp;
337 }
338
339 /*-
340- * @brief _gnutls_name_constraints_intersect:
341- * @_nc: first name constraints list (permitted)
342- * @_nc2: name constraints list to merge with (permitted)
343- * @_nc_excluded: Corresponding excluded name constraints list
344+ * @brief name_constraints_node_list_intersect:
345+ * @nc: %gnutls_x509_name_constraints_t
346+ * @permitted: first name constraints list (permitted)
347+ * @permitted2: name constraints list to merge with (permitted)
348+ * @excluded: Corresponding excluded name constraints list
349 *
350- * This function finds the intersection of @_nc and @_nc2. The result is placed in @_nc,
351- * the original @_nc is deallocated. @_nc2 is not changed. If necessary, a universal
352+ * This function finds the intersection of @permitted and @permitted2. The result is placed in @permitted,
353+ * the original @permitted is modified. @permitted2 is not changed. If necessary, a universal
354 * excluded name constraint node of the right type is added to the list provided
355- * in @_nc_excluded.
356+ * in @excluded.
357 *
358 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
359 -*/
360-static
361-int _gnutls_name_constraints_intersect(name_constraints_node_st ** _nc,
362- name_constraints_node_st * _nc2,
363- name_constraints_node_st ** _nc_excluded)
364+static int name_constraints_node_list_intersect(
365+ gnutls_x509_name_constraints_t nc,
366+ struct name_constraints_node_list_st *permitted,
367+ const struct name_constraints_node_list_st *permitted2,
368+ struct name_constraints_node_list_st *excluded)
369 {
370- name_constraints_node_st *nc, *nc2, *t, *tmp, *dest = NULL, *prev = NULL;
371+ struct name_constraints_node_st *tmp;
372 int ret, type, used;
373+ struct name_constraints_node_list_st removed = { .data = NULL,
374+ .size = 0,
375+ .capacity = 0 };
376
377 /* temporary array to see, if we need to add universal excluded constraints
378 * (see phase 3 for details)
379@@ -262,61 +319,73 @@ int _gnutls_name_constraints_intersect(name_constraints_node_st ** _nc,
380 unsigned char types_with_empty_intersection[GNUTLS_SAN_MAX];
381 memset(types_with_empty_intersection, 0, sizeof(types_with_empty_intersection));
382
383- if (*_nc == NULL || _nc2 == NULL)
384+ if (permitted->size == 0 || permitted2->size == 0)
385 return 0;
386
387 /* Phase 1
388- * For each name in _NC, if a _NC2 does not contain a name
389- * with the same type, preserve the original name.
390- * Do this also for node of unknown type (not DNS, email, IP */
391- t = nc = *_nc;
392- while (t != NULL) {
393- name_constraints_node_st *next = t->next;
394- nc2 = _nc2;
395- while (nc2 != NULL) {
396- if (t->type == nc2->type) {
397+ * For each name in PERMITTED, if a PERMITTED2 does not contain a name
398+ * with the same type, move the original name to REMOVED.
399+ * Do this also for node of unknown type (not DNS, email, IP) */
400+ for (size_t i = 0; i < permitted->size;) {
401+ struct name_constraints_node_st *t = permitted->data[i];
402+ const struct name_constraints_node_st *found = NULL;
403+
404+ for (size_t j = 0; j < permitted2->size; j++) {
405+ const struct name_constraints_node_st *t2 =
406+ permitted2->data[j];
407+ if (t->type == t2->type) {
408 // check bounds (we will use 't->type' as index)
409- if (t->type > GNUTLS_SAN_MAX || t->type == 0)
410- return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
411+ if (t->type > GNUTLS_SAN_MAX || t->type == 0) {
412+ gnutls_assert();
413+ ret = GNUTLS_E_INTERNAL_ERROR;
414+ goto cleanup;
415+ }
416 // note the possibility of empty intersection for this type
417 // if we add something to the intersection in phase 2,
418 // we will reset this flag back to 0 then
419 types_with_empty_intersection[t->type - 1] = 1;
420+ found = t2;
421 break;
422 }
423- nc2 = nc2->next;
424 }
425- if (nc2 == NULL ||
426- (t->type != GNUTLS_SAN_DNSNAME &&
427- t->type != GNUTLS_SAN_RFC822NAME &&
428- t->type != GNUTLS_SAN_IPADDRESS)
429- ) {
430- /* move node from NC to DEST */
431- if (prev != NULL)
432- prev->next = next;
433- else
434- prev = nc = next;
435- t->next = dest;
436- dest = t;
437- } else {
438- prev = t;
439+ if (found != NULL && (t->type == GNUTLS_SAN_DNSNAME ||
440+ t->type == GNUTLS_SAN_RFC822NAME ||
441+ t->type == GNUTLS_SAN_IPADDRESS)) {
442+ /* move node from PERMITTED to REMOVED */
443+ ret = name_constraints_node_list_add(&removed, t);
444+ if (ret < 0) {
445+ gnutls_assert();
446+ goto cleanup;
447+ }
448+ /* remove node by swapping */
449+ if (i < permitted->size - 1)
450+ permitted->data[i] =
451+ permitted->data[permitted->size - 1];
452+ permitted->size--;
453+ continue;
454+
455 }
456- t = next;
457+ i++;
458 }
459
460 /* Phase 2
461- * iterate through all combinations from nc2 and nc1
462+ * iterate through all combinations from PERMITTED2 and PERMITTED
463 * and create intersections of nodes with same type */
464- nc2 = _nc2;
465- while (nc2 != NULL) {
466- // current nc2 node has not yet been used for any intersection
467- // (and is not in DEST either)
468+ for (size_t i = 0; i < permitted2->size; i++) {
469+ const struct name_constraints_node_st *t2 = permitted2->data[i];
470+
471+ // current PERMITTED2 node has not yet been used for any intersection
472+ // (and is not in REMOVED either)
473 used = 0;
474- t = nc;
475- while (t != NULL) {
476+ for (size_t j = 0; j < removed.size; j++) {
477+ const struct name_constraints_node_st *t =
478+ removed.data[j];
479 // save intersection of name constraints into tmp
480- ret = name_constraints_intersect_nodes(t, nc2, &tmp);
481- if (ret < 0) return gnutls_assert_val(ret);
482+ ret = name_constraints_intersect_nodes(nc, t, t2, &tmp);
483+ if (ret < 0) {
484+ gnutls_assert();
485+ goto cleanup;
486+ }
487 used = 1;
488 // if intersection is not empty
489 if (tmp != NULL) { // intersection for this type is not empty
490@@ -327,31 +396,35 @@ int _gnutls_name_constraints_intersect(name_constraints_node_st ** _nc,
491 }
492 // we will not add universal excluded constraint for this type
493 types_with_empty_intersection[tmp->type - 1] = 0;
494- // add intersection node to DEST
495- tmp->next = dest;
496- dest = tmp;
497+ // add intersection node to PERMITTED
498+ ret = name_constraints_node_list_add(permitted,
499+ tmp);
500+ if (ret < 0) {
501+ gnutls_assert();
502+ goto cleanup;
503+ }
504+
505 }
506- t = t->next;
507 }
508- // if the node from nc2 was not used for intersection, copy it to DEST
509+ // if the node from PERMITTED2 was not used for intersection, copy it to DEST
510 // Beware: also copies nodes other than DNS, email, IP,
511 // since their counterpart may have been moved in phase 1.
512 if (!used) {
513- tmp = name_constraints_node_new(nc2->type, nc2->name.data, nc2->name.size);
514+ tmp = name_constraints_node_new(nc, t2->type, t2->name.data, t2->name.size);
515 if (tmp == NULL) {
516- _gnutls_name_constraints_node_free(dest);
517- return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
518+ gnutls_assert();
519+ ret = GNUTLS_E_MEMORY_ERROR;
520+ goto cleanup;
521+ }
522+ ret = name_constraints_node_list_add(permitted, tmp);
523+ if (ret < 0) {
524+ gnutls_assert();
525+ goto cleanup;
526+
527 }
528- tmp->next = dest;
529- dest = tmp;
530 }
531- nc2 = nc2->next;
532 }
533
534- /* replace the original with the new */
535- _gnutls_name_constraints_node_free(nc);
536- *_nc = dest;
537-
538 /* Phase 3
539 * For each type: If we have empty permitted name constraints now
540 * and we didn't have at the beginning, we have to add a new
541@@ -364,60 +437,79 @@ int _gnutls_name_constraints_intersect(name_constraints_node_st ** _nc,
542 switch (type) {
543 case GNUTLS_SAN_IPADDRESS:
544 // add universal restricted range for IPv4
545- tmp = name_constraints_node_new(GNUTLS_SAN_IPADDRESS, NULL, 8);
546+ tmp = name_constraints_node_new(
547+ nc, GNUTLS_SAN_IPADDRESS, NULL, 8);
548 if (tmp == NULL) {
549- _gnutls_name_constraints_node_free(dest);
550- return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
551+ gnutls_assert();
552+ ret = GNUTLS_E_MEMORY_ERROR;
553+ goto cleanup;
554+ }
555+ ret = name_constraints_node_list_add(excluded, tmp);
556+ if (ret < 0) {
557+ gnutls_assert();
558+ goto cleanup;
559+
560 }
561- tmp->next = *_nc_excluded;
562- *_nc_excluded = tmp;
563 // add universal restricted range for IPv6
564- tmp = name_constraints_node_new(GNUTLS_SAN_IPADDRESS, NULL, 32);
565+ tmp = name_constraints_node_new(
566+ nc, GNUTLS_SAN_IPADDRESS, NULL, 32);
567 if (tmp == NULL) {
568- _gnutls_name_constraints_node_free(dest);
569- return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
570+ gnutls_assert();
571+ ret = GNUTLS_E_MEMORY_ERROR;
572+ goto cleanup;
573+ }
574+ ret = name_constraints_node_list_add(excluded, tmp);
575+ if (ret < 0) {
576+ gnutls_assert();
577+ goto cleanup;
578 }
579- tmp->next = *_nc_excluded;
580- *_nc_excluded = tmp;
581 break;
582 case GNUTLS_SAN_DNSNAME:
583 case GNUTLS_SAN_RFC822NAME:
584- tmp = name_constraints_node_new(type, NULL, 0);
585+ tmp = name_constraints_node_new(nc, type, NULL, 0);
586 if (tmp == NULL) {
587- _gnutls_name_constraints_node_free(dest);
588- return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
589+ gnutls_assert();
590+ ret = GNUTLS_E_MEMORY_ERROR;
591+ goto cleanup;
592+ }
593+ ret = name_constraints_node_list_add(excluded, tmp);
594+ if (ret < 0) {
595+ gnutls_assert();
596+ goto cleanup;
597 }
598- tmp->next = *_nc_excluded;
599- *_nc_excluded = tmp;
600 break;
601 default: // do nothing, at least one node was already moved in phase 1
602 break;
603 }
604 }
605- return GNUTLS_E_SUCCESS;
606-}
607-
608-static int _gnutls_name_constraints_append(name_constraints_node_st **_nc,
609- name_constraints_node_st *_nc2)
610-{
611- name_constraints_node_st *nc, *nc2;
612- struct name_constraints_node_st *tmp;
613+ ret = GNUTLS_E_SUCCESS;
614
615- if (_nc2 == NULL)
616- return 0;
617+cleanup:
618+ gnutls_free(removed.data);
619+ return ret;
620
621- nc2 = _nc2;
622- while (nc2) {
623- nc = *_nc;
624+}
625
626- tmp = name_constraints_node_new(nc2->type, nc2->name.data, nc2->name.size);
627- if (tmp == NULL)
628+static int name_constraints_node_list_concat(
629+ gnutls_x509_name_constraints_t nc,
630+ struct name_constraints_node_list_st *nodes,
631+ const struct name_constraints_node_list_st *nodes2)
632+{
633+ for (size_t i = 0; i < nodes2->size; i++) {
634+ const struct name_constraints_node_st *node = nodes2->data[i];
635+ struct name_constraints_node_st *tmp;
636+ int ret;
637+
638+ tmp = name_constraints_node_new(nc, node->type, node->name.data,
639+ node->name.size);
640+ if (tmp == NULL) {
641 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
642-
643- tmp->next = nc;
644- *_nc = tmp;
645-
646- nc2 = nc2->next;
647+ }
648+ ret = name_constraints_node_list_add(nodes, tmp);
649+ if (ret < 0) {
650+ name_constraints_node_free(tmp);
651+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
652+ }
653 }
654
655 return 0;
656@@ -487,6 +579,25 @@ int gnutls_x509_crt_get_name_constraints(gnutls_x509_crt_t crt,
657
658 }
659
660+void _gnutls_x509_name_constraints_clear(gnutls_x509_name_constraints_t nc)
661+{
662+ for (size_t i = 0; i < nc->nodes.size; i++) {
663+ struct name_constraints_node_st *node = nc->nodes.data[i];
664+ name_constraints_node_free(node);
665+ }
666+ gnutls_free(nc->nodes.data);
667+ nc->nodes.capacity = 0;
668+ nc->nodes.size = 0;
669+
670+ gnutls_free(nc->permitted.data);
671+ nc->permitted.capacity = 0;
672+ nc->permitted.size = 0;
673+
674+ gnutls_free(nc->excluded.data);
675+ nc->excluded.capacity = 0;
676+ nc->excluded.size = 0;
677+}
678+
679 /**
680 * gnutls_x509_name_constraints_deinit:
681 * @nc: The nameconstraints
682@@ -497,10 +608,9 @@ int gnutls_x509_crt_get_name_constraints(gnutls_x509_crt_t crt,
683 **/
684 void gnutls_x509_name_constraints_deinit(gnutls_x509_name_constraints_t nc)
685 {
686- _gnutls_name_constraints_node_free(nc->permitted);
687- _gnutls_name_constraints_node_free(nc->excluded);
688-
689+ _gnutls_x509_name_constraints_clear(nc);
690 gnutls_free(nc);
691+
692 }
693
694 /**
695@@ -515,12 +625,15 @@ void gnutls_x509_name_constraints_deinit(gnutls_x509_name_constraints_t nc)
696 **/
697 int gnutls_x509_name_constraints_init(gnutls_x509_name_constraints_t *nc)
698 {
699- *nc = gnutls_calloc(1, sizeof(struct gnutls_name_constraints_st));
700- if (*nc == NULL) {
701+ struct gnutls_name_constraints_st *tmp;
702+
703+ tmp = gnutls_calloc(1, sizeof(struct gnutls_name_constraints_st));
704+ if (tmp == NULL) {
705 gnutls_assert();
706 return GNUTLS_E_MEMORY_ERROR;
707 }
708
709+ *nc = tmp;
710 return 0;
711 }
712
713@@ -530,37 +643,23 @@ int name_constraints_add(gnutls_x509_name_constraints_t nc,
714 const gnutls_datum_t * name,
715 unsigned permitted)
716 {
717- struct name_constraints_node_st * tmp, *prev = NULL;
718+ struct name_constraints_node_st *tmp;
719+ struct name_constraints_node_list_st *nodes;
720 int ret;
721
722 ret = validate_name_constraints_node(type, name);
723 if (ret < 0)
724 return gnutls_assert_val(ret);
725
726- if (permitted != 0)
727- prev = tmp = nc->permitted;
728- else
729- prev = tmp = nc->excluded;
730+ nodes = permitted ? &nc->permitted : &nc->excluded;
731
732- while(tmp != NULL) {
733- tmp = tmp->next;
734- if (tmp != NULL)
735- prev = tmp;
736+ tmp = name_constraints_node_new(nc, type, name->data, name->size);
737+ ret = name_constraints_node_list_add(nodes, tmp);
738+ if (ret < 0) {
739+ name_constraints_node_free(tmp);
740+ return gnutls_assert_val(ret);
741 }
742
743- tmp = name_constraints_node_new(type, name->data, name->size);
744- if (tmp == NULL)
745- return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
746- tmp->next = NULL;
747-
748- if (prev == NULL) {
749- if (permitted != 0)
750- nc->permitted = tmp;
751- else
752- nc->excluded = tmp;
753- } else
754- prev->next = tmp;
755-
756 return 0;
757 }
758
759@@ -585,17 +684,15 @@ int _gnutls_x509_name_constraints_merge(gnutls_x509_name_constraints_t nc,
760 {
761 int ret;
762
763- ret =
764- _gnutls_name_constraints_intersect(&nc->permitted,
765- nc2->permitted, &nc->excluded);
766+ ret = name_constraints_node_list_intersect(
767+ nc, &nc->permitted, &nc2->permitted, &nc->excluded);
768 if (ret < 0) {
769 gnutls_assert();
770 return ret;
771 }
772
773- ret =
774- _gnutls_name_constraints_append(&nc->excluded,
775- nc2->excluded);
776+ ret = name_constraints_node_list_concat(nc, &nc->excluded,
777+ &nc2->excluded);
778 if (ret < 0) {
779 gnutls_assert();
780 return ret;
781@@ -767,47 +864,50 @@ static unsigned email_matches(const gnutls_datum_t *name, const gnutls_datum_t *
782 *
783 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
784 -*/
785-static int
786-name_constraints_intersect_nodes(name_constraints_node_st * nc1,
787- name_constraints_node_st * nc2,
788- name_constraints_node_st ** _intersection)
789+static int name_constraints_intersect_nodes(
790+ gnutls_x509_name_constraints_t nc,
791+ const struct name_constraints_node_st *node1,
792+ const struct name_constraints_node_st *node2,
793+ struct name_constraints_node_st **_intersection)
794 {
795 // presume empty intersection
796- name_constraints_node_st *intersection = NULL;
797- name_constraints_node_st *to_copy = NULL;
798+ struct name_constraints_node_st *intersection = NULL;
799+ const struct name_constraints_node_st *to_copy = NULL;
800 unsigned iplength = 0;
801 unsigned byte;
802
803 *_intersection = NULL;
804
805- if (nc1->type != nc2->type) {
806+ if (node1->type != node2->type) {
807 return GNUTLS_E_SUCCESS;
808 }
809- switch (nc1->type) {
810+ switch (node1->type) {
811 case GNUTLS_SAN_DNSNAME:
812- if (!dnsname_matches(&nc2->name, &nc1->name))
813+ if (!dnsname_matches(&node2->name, &node1->name))
814 return GNUTLS_E_SUCCESS;
815- to_copy = nc2;
816 break;
817 case GNUTLS_SAN_RFC822NAME:
818- if (!email_matches(&nc2->name, &nc1->name))
819+ if (!email_matches(&node2->name, &node1->name))
820 return GNUTLS_E_SUCCESS;
821- to_copy = nc2;
822+ to_copy = node2;
823 break;
824 case GNUTLS_SAN_IPADDRESS:
825- if (nc1->name.size != nc2->name.size)
826+ if (node1->name.size != node2->name.size)
827 return GNUTLS_E_SUCCESS;
828- iplength = nc1->name.size/2;
829+ iplength = node1->name.size / 2;
830 for (byte = 0; byte < iplength; byte++) {
831- if (((nc1->name.data[byte]^nc2->name.data[byte]) // XOR of addresses
832- & nc1->name.data[byte+iplength] // AND mask from nc1
833- & nc2->name.data[byte+iplength]) // AND mask from nc2
834+ if (((node1->name.data[byte] ^
835+ node2->name.data[byte]) // XOR of addresses
836+ & node1->name.data[byte +
837+ iplength] // AND mask from nc1
838+ & node2->name.data[byte +
839+ iplength]) // AND mask from nc2
840 != 0) {
841 // CIDRS do not intersect
842 return GNUTLS_E_SUCCESS;
843 }
844 }
845- to_copy = nc2;
846+ to_copy = node2;
847 break;
848 default:
849 // for other types, we don't know how to do the intersection, assume empty
850@@ -816,7 +916,9 @@ name_constraints_intersect_nodes(name_constraints_node_st * nc1,
851
852 // copy existing node if applicable
853 if (to_copy != NULL) {
854- *_intersection = name_constraints_node_new(to_copy->type, to_copy->name.data, to_copy->name.size);
855+ *_intersection = name_constraints_node_new(nc, to_copy->type,
856+ to_copy->name.data,
857+ to_copy->name.size);
858 if (*_intersection == NULL)
859 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
860 intersection = *_intersection;
861@@ -826,10 +928,11 @@ name_constraints_intersect_nodes(name_constraints_node_st * nc1,
862 if (intersection->type == GNUTLS_SAN_IPADDRESS) {
863 // make sure both IP addresses are correctly masked
864 _gnutls_mask_ip(intersection->name.data, intersection->name.data+iplength, iplength);
865- _gnutls_mask_ip(nc1->name.data, nc1->name.data+iplength, iplength);
866+ _gnutls_mask_ip(node1->name.data,
867+ node1->name.data + iplength, iplength);
868 // update intersection, if necessary (we already know one is subset of other)
869 for (byte = 0; byte < 2 * iplength; byte++) {
870- intersection->name.data[byte] |= nc1->name.data[byte];
871+ intersection->name.data[byte] |= node1->name.data[byte];
872 }
873 }
874 }
875@@ -1123,10 +1226,16 @@ int ret;
876 unsigned idx, t, san_type;
877 gnutls_datum_t n;
878 unsigned found_one;
879+size_t checks;
880
881- if (is_nc_empty(nc, type) != 0)
882+ if (_gnutls_x509_name_constraints_is_empty(nc, type) != 0)
883 return 1; /* shortcut; no constraints to check */
884
885+ if (!INT_ADD_OK(nc->permitted.size, nc->excluded.size, &checks) ||
886+ !INT_MULTIPLY_OK(checks, cert->san->size, &checks) ||
887+ checks > MAX_NC_CHECKS) {
888+ return gnutls_assert_val(0);
889+ }
890 if (type == GNUTLS_SAN_RFC822NAME) {
891 found_one = 0;
892 for (idx=0;;idx++) {
893@@ -1315,21 +1424,13 @@ int gnutls_x509_name_constraints_get_permitted(gnutls_x509_name_constraints_t nc
894 unsigned idx,
895 unsigned *type, gnutls_datum_t * name)
896 {
897- unsigned int i;
898- struct name_constraints_node_st * tmp = nc->permitted;
899+ const struct name_constraints_node_st *tmp;
900
901- for (i = 0; i < idx; i++) {
902- if (tmp == NULL)
903- return
904- gnutls_assert_val
905- (GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
906-
907- tmp = tmp->next;
908- }
909-
910- if (tmp == NULL)
911+ if (idx >= nc->permitted.size)
912 return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
913
914+ tmp = nc->permitted.data[idx];
915+
916 *type = tmp->type;
917 *name = tmp->name;
918
919@@ -1359,21 +1460,12 @@ int gnutls_x509_name_constraints_get_excluded(gnutls_x509_name_constraints_t nc,
920 unsigned idx,
921 unsigned *type, gnutls_datum_t * name)
922 {
923- unsigned int i;
924- struct name_constraints_node_st * tmp = nc->excluded;
925-
926- for (i = 0; i < idx; i++) {
927- if (tmp == NULL)
928- return
929- gnutls_assert_val
930- (GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
931-
932- tmp = tmp->next;
933- }
934-
935- if (tmp == NULL)
936+ const struct name_constraints_node_st *tmp;
937+ if (idx >= nc->excluded.size)
938 return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
939
940+ tmp = nc->excluded.data[idx];
941+
942 *type = tmp->type;
943 *name = tmp->name;
944
945diff --git a/lib/x509/x509_ext.c b/lib/x509/x509_ext.c
946index 8bcf183..54741c8 100644
947--- a/lib/x509/x509_ext.c
948+++ b/lib/x509/x509_ext.c
949@@ -34,10 +34,6 @@
950 #include "intprops.h"
951
952 #define MAX_ENTRIES 64
953-struct gnutls_subject_alt_names_st {
954- struct name_st *names;
955- unsigned int size;
956-};
957
958 /**
959 * gnutls_subject_alt_names_init:
960@@ -389,24 +385,15 @@ int gnutls_x509_ext_import_name_constraints(const gnutls_datum_t * ext,
961 }
962
963 if (flags & GNUTLS_NAME_CONSTRAINTS_FLAG_APPEND &&
964- (nc->permitted != NULL || nc->excluded != NULL)) {
965+ !_gnutls_x509_name_constraints_is_empty(nc, 0)) {
966 ret = gnutls_x509_name_constraints_init (&nc2);
967 if (ret < 0) {
968 gnutls_assert();
969 goto cleanup;
970 }
971
972- ret =
973- _gnutls_extract_name_constraints(c2, "permittedSubtrees",
974- &nc2->permitted);
975- if (ret < 0) {
976- gnutls_assert();
977- goto cleanup;
978- }
979-
980- ret =
981- _gnutls_extract_name_constraints(c2, "excludedSubtrees",
982- &nc2->excluded);
983+ ret = _gnutls_x509_name_constraints_extract(
984+ c2, "permittedSubtrees", "excludedSubtrees", nc2);
985 if (ret < 0) {
986 gnutls_assert();
987 goto cleanup;
988@@ -418,20 +405,11 @@ int gnutls_x509_ext_import_name_constraints(const gnutls_datum_t * ext,
989 goto cleanup;
990 }
991 } else {
992- _gnutls_name_constraints_node_free(nc->permitted);
993- _gnutls_name_constraints_node_free(nc->excluded);
994
995- ret =
996- _gnutls_extract_name_constraints(c2, "permittedSubtrees",
997- &nc->permitted);
998- if (ret < 0) {
999- gnutls_assert();
1000- goto cleanup;
1001- }
1002+ _gnutls_x509_name_constraints_clear(nc);
1003
1004- ret =
1005- _gnutls_extract_name_constraints(c2, "excludedSubtrees",
1006- &nc->excluded);
1007+ ret = _gnutls_x509_name_constraints_extract(
1008+ c2, "permittedSubtrees", "excludedSubtrees", nc);
1009 if (ret < 0) {
1010 gnutls_assert();
1011 goto cleanup;
1012@@ -467,9 +445,10 @@ int gnutls_x509_ext_export_name_constraints(gnutls_x509_name_constraints_t nc,
1013 int ret, result;
1014 uint8_t null = 0;
1015 asn1_node c2 = NULL;
1016- struct name_constraints_node_st *tmp;
1017+ unsigned rtype;
1018+ gnutls_datum_t rname;
1019
1020- if (nc->permitted == NULL && nc->excluded == NULL)
1021+ if (_gnutls_x509_name_constraints_is_empty(nc, 0))
1022 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
1023
1024 result = asn1_create_element
1025@@ -479,11 +458,20 @@ int gnutls_x509_ext_export_name_constraints(gnutls_x509_name_constraints_t nc,
1026 return _gnutls_asn2err(result);
1027 }
1028
1029- if (nc->permitted == NULL) {
1030+ ret = gnutls_x509_name_constraints_get_permitted(nc, 0, &rtype, &rname);
1031+ if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
1032 (void)asn1_write_value(c2, "permittedSubtrees", NULL, 0);
1033 } else {
1034- tmp = nc->permitted;
1035- do {
1036+ for (unsigned i = 0;; i++) {
1037+ ret = gnutls_x509_name_constraints_get_permitted(
1038+ nc, i, &rtype, &rname);
1039+ if (ret < 0) {
1040+ if (ret ==
1041+ GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
1042+ break;
1043+ gnutls_assert();
1044+ goto cleanup;
1045+ }
1046 result =
1047 asn1_write_value(c2, "permittedSubtrees", "NEW", 1);
1048 if (result != ASN1_SUCCESS) {
1049@@ -515,22 +503,30 @@ int gnutls_x509_ext_export_name_constraints(gnutls_x509_name_constraints_t nc,
1050 ret =
1051 _gnutls_write_general_name(c2,
1052 "permittedSubtrees.?LAST.base",
1053- tmp->type,
1054- tmp->name.data,
1055- tmp->name.size);
1056+ rtype,
1057+ rname.data,
1058+ rname.size);
1059 if (ret < 0) {
1060 gnutls_assert();
1061 goto cleanup;
1062 }
1063- tmp = tmp->next;
1064- } while (tmp != NULL);
1065+ }
1066 }
1067
1068- if (nc->excluded == NULL) {
1069+ ret = gnutls_x509_name_constraints_get_excluded(nc, 0, &rtype, &rname);
1070+ if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
1071 (void)asn1_write_value(c2, "excludedSubtrees", NULL, 0);
1072 } else {
1073- tmp = nc->excluded;
1074- do {
1075+ for (unsigned i = 0;; i++) {
1076+ ret = gnutls_x509_name_constraints_get_excluded(
1077+ nc, i, &rtype, &rname);
1078+ if (ret < 0) {
1079+ if (ret ==
1080+ GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
1081+ break;
1082+ gnutls_assert();
1083+ goto cleanup;
1084+ }
1085 result =
1086 asn1_write_value(c2, "excludedSubtrees", "NEW", 1);
1087 if (result != ASN1_SUCCESS) {
1088@@ -562,15 +558,14 @@ int gnutls_x509_ext_export_name_constraints(gnutls_x509_name_constraints_t nc,
1089 ret =
1090 _gnutls_write_general_name(c2,
1091 "excludedSubtrees.?LAST.base",
1092- tmp->type,
1093- tmp->name.data,
1094- tmp->name.size);
1095+ rtype,
1096+ rname.data,
1097+ rname.size);
1098 if (ret < 0) {
1099 gnutls_assert();
1100 goto cleanup;
1101 }
1102- tmp = tmp->next;
1103- } while (tmp != NULL);
1104+ }
1105
1106 }
1107
1108diff --git a/lib/x509/x509_ext_int.h b/lib/x509/x509_ext_int.h
1109index 2e3f162..97f0abd 100644
1110--- a/lib/x509/x509_ext_int.h
1111+++ b/lib/x509/x509_ext_int.h
1112@@ -29,6 +29,11 @@ struct name_st {
1113 gnutls_datum_t othername_oid;
1114 };
1115
1116+struct gnutls_subject_alt_names_st {
1117+ struct name_st *names;
1118+ unsigned int size;
1119+};
1120+
1121 int _gnutls_alt_name_process(gnutls_datum_t *out, unsigned type, const gnutls_datum_t *san, unsigned raw);
1122
1123 #endif /* GNUTLS_LIB_X509_X509_EXT_INT_H */
1124diff --git a/lib/x509/x509_int.h b/lib/x509/x509_int.h
1125index acbc185..bf4363e 100644
1126--- a/lib/x509/x509_int.h
1127+++ b/lib/x509/x509_int.h
1128@@ -529,20 +529,16 @@ _gnutls_x509_crt_check_revocation(gnutls_x509_crt_t cert,
1129 int crl_list_length,
1130 gnutls_verify_output_function func);
1131
1132-typedef struct gnutls_name_constraints_st {
1133- struct name_constraints_node_st * permitted;
1134- struct name_constraints_node_st * excluded;
1135-} gnutls_name_constraints_st;
1136-
1137-typedef struct name_constraints_node_st {
1138- unsigned type;
1139- gnutls_datum_t name;
1140- struct name_constraints_node_st *next;
1141-} name_constraints_node_st;
1142-
1143-int _gnutls_extract_name_constraints(asn1_node c2, const char *vstr,
1144- name_constraints_node_st ** _nc);
1145-void _gnutls_name_constraints_node_free (name_constraints_node_st *node);
1146+
1147+
1148+bool _gnutls_x509_name_constraints_is_empty(gnutls_x509_name_constraints_t nc,
1149+ unsigned type);
1150+int _gnutls_x509_name_constraints_extract(asn1_node c2,
1151+ const char *permitted_name,
1152+ const char *excluded_name,
1153+ gnutls_x509_name_constraints_t nc);
1154+void _gnutls_x509_name_constraints_clear(gnutls_x509_name_constraints_t nc);
1155+
1156 int _gnutls_x509_name_constraints_merge(gnutls_x509_name_constraints_t nc,
1157 gnutls_x509_name_constraints_t nc2);
1158
1159--
11602.40.0
diff --git a/meta/recipes-support/gnutls/gnutls_3.7.4.bb b/meta/recipes-support/gnutls/gnutls_3.7.4.bb
index 9f502e3f7c..5cd85c5996 100644
--- a/meta/recipes-support/gnutls/gnutls_3.7.4.bb
+++ b/meta/recipes-support/gnutls/gnutls_3.7.4.bb
@@ -28,6 +28,7 @@ SRC_URI = "https://www.gnupg.org/ftp/gcrypt/gnutls/v${SHRT_VER}/gnutls-${PV}.tar
28 file://CVE-2024-0567.patch \ 28 file://CVE-2024-0567.patch \
29 file://CVE-2024-28834.patch \ 29 file://CVE-2024-28834.patch \
30 file://CVE-2024-28835.patch \ 30 file://CVE-2024-28835.patch \
31 file://CVE-2024-12243.patch \
31 " 32 "
32 33
33SRC_URI[sha256sum] = "e6adbebcfbc95867de01060d93c789938cf89cc1d1f6ef9ef661890f6217451f" 34SRC_URI[sha256sum] = "e6adbebcfbc95867de01060d93c789938cf89cc1d1f6ef9ef661890f6217451f"